nucleus-core-ts 0.9.853 → 0.9.855
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/dist/index.js
CHANGED
|
@@ -98,7 +98,7 @@ end
|
|
|
98
98
|
redis.call('ZADD', KEYS[1], now, ARGV[4])
|
|
99
99
|
redis.call('PEXPIRE', KEYS[1], windowMs + 1000)
|
|
100
100
|
return {1, count + 1}
|
|
101
|
-
`,RateLimiterBackendError,DEFAULT_AUTH_LOGIN,DEFAULT_AUTH_REGISTER,DEFAULT_AUTH_PASSWORD_RESET,DEFAULT_AUTH_MAGIC_LINK,DEFAULT_CONFIG4;var init_RateLimiter=__esm(()=>{RateLimiterBackendError=class RateLimiterBackendError extends Error{constructor(message){super(message);this.name="RateLimiterBackendError"}};DEFAULT_AUTH_LOGIN={window:"15m",max:5,blockDuration:"30m"},DEFAULT_AUTH_REGISTER={window:"1h",max:3,blockDuration:"1h"},DEFAULT_AUTH_PASSWORD_RESET={window:"1h",max:3,blockDuration:"1h"},DEFAULT_AUTH_MAGIC_LINK={window:"1h",max:5,blockDuration:"1h"},DEFAULT_CONFIG4={enabled:!0,strategy:"sliding-window",keyPrefix:"rl:",authRoutes:{window:"1m",max:10,login:DEFAULT_AUTH_LOGIN,register:DEFAULT_AUTH_REGISTER,passwordReset:DEFAULT_AUTH_PASSWORD_RESET,magicLink:DEFAULT_AUTH_MAGIC_LINK},publicRoutes:{window:"1m",max:100},privateRoutes:{window:"1m",max:60},byIp:!0,byUserId:!0,byEndpoint:!1,skipSuccessfulRequests:!1,headers:{remaining:"X-RateLimit-Remaining",reset:"X-RateLimit-Reset",limit:"X-RateLimit-Limit"},whitelist:[],blacklist:[]}});import{createCipheriv as createCipheriv2,createDecipheriv as createDecipheriv2,randomBytes as randomBytes4,scryptSync as scryptSync2,timingSafeEqual as timingSafeEqual2}from"crypto";var VERSION="v1",IV_LEN2=12,KEY_LEN=32,SCRYPT_SALT="nucleus-secrets-v1",keyCache,deriveKey2=(masterKey)=>{let cached=keyCache.get(masterKey);if(cached)return cached;let key2=scryptSync2(masterKey,SCRYPT_SALT,KEY_LEN);return keyCache.set(masterKey,key2),key2},encryptSecret=(plaintext,masterKey)=>{if(!masterKey)throw Error("secrets encryption key is empty");let iv=randomBytes4(IV_LEN2),cipher=createCipheriv2("aes-256-gcm",deriveKey2(masterKey),iv),ciphertext=Buffer.concat([cipher.update(plaintext,"utf-8"),cipher.final()]),tag=cipher.getAuthTag();return[VERSION,iv.toString("base64"),tag.toString("base64"),ciphertext.toString("base64")].join(":")},decryptSecret=(envelope,masterKey)=>{if(!masterKey)throw Error("secrets encryption key is empty");let parts=envelope.split(":");if(parts.length!==4||parts[0]!==VERSION)throw Error("not an encrypted secret envelope");let[,ivB64,tagB64,ctB64]=parts,decipher=createDecipheriv2("aes-256-gcm",deriveKey2(masterKey),Buffer.from(ivB64,"base64"));return decipher.setAuthTag(Buffer.from(tagB64,"base64")),Buffer.concat([decipher.update(Buffer.from(ctB64,"base64")),decipher.final()]).toString("utf-8")},previewOf=(plaintext)=>{let len=plaintext.length;if(len===0)return"";if(len<12)return`\u2022\u2022\u2022\u2022${len}`;return`\u2022\u2022\u2022\u2022${plaintext.slice(-4)}`};var init_crypto=__esm(()=>{keyCache=new Map});function discoverSlots(config){let slots=new Map,add=(slot)=>{let id=`${slot.scope}.${slot.key}`;if(!slots.has(id))slots.set(id,slot)},valueAt=(scope,key2)=>{let node=config;for(let segment of scope.split(".")){if(!isPlainObject(node))return;node=node[segment]}if(!isPlainObject(node))return;let value=node[key2];if(typeof value==="string")return value;if(Array.isArray(value)&&value.every((entry)=>typeof entry==="string"))return value.length>0?value.join(","):void 0;return};for(let descriptor of SECRET_SLOT_DESCRIPTORS)for(let scope of expandPath(config,descriptor.path,descriptor.always===!0)){let leaf=scope.split(".").pop()??descriptor.group,group=descriptor.path.endsWith("*")?`${descriptor.group}:${leaf}`:descriptor.group;for(let declared of descriptor.keys)add({scope,key:declared.key,kind:declared.kind??kindFor(declared.key),label:declared.label,group,required:declared.required??!1,requiredWhen:declared.requiredWhen,hint:declared.hint,secret:declared.secret??descriptor.secret??!0,configValue:valueAt(scope,declared.key)})}let walk=(node,path2,depth)=>{if(depth>6)return;for(let[key2,value]of Object.entries(node)){if(SKIP_SECTIONS.has(key2))continue;let childPath=path2?`${path2}.${key2}`:key2;if(isPlainObject(value)){walk(value,childPath,depth+1);continue}if(typeof value!=="string"&&value!==void 0&&value!==null)continue;if(!CREDENTIAL_KEY_PATTERN.test(key2))continue;if(NOT_A_CREDENTIAL.has(key2.toLowerCase()))continue;if(BOOT_ONLY_PATHS.has(`${path2}.${key2}`))continue;let owner=path2.split(".").pop(),label=owner&&owner.toLowerCase()!==key2.toLowerCase()?`${humanize(owner)} \u2014 ${humanize(key2)}`:humanize(key2);add({scope:path2,key:key2,kind:kindFor(key2),label,group:path2.split(".")[0]??"other",required:!1,secret:!0,configValue:typeof value==="string"?value:void 0})}};return walk(config,"",0),[...slots.values()].sort((a,b)=>a.group.localeCompare(b.group)||a.scope.localeCompare(b.scope)||a.key.localeCompare(b.key))}var CREDENTIAL_KEY_PATTERN,NOT_A_CREDENTIAL,BOOT_ONLY_PATHS,SKIP_SECTIONS,kindFor=(key2)=>{let k=key2.toLowerCase();if(k.includes("json"))return"json";if(k.includes("connection"))return"connection_string";if(k.includes("privatekey")||k.includes("private_key"))return"pem";if(k.includes("clientid")||k.includes("client_id"))return"text";return"password"},humanize=(key2)=>key2.replace(/[_-]+/g," ").replace(/([a-z0-9])([A-Z])/g,"$1 $2").replace(/\s+/g," ").trim().replace(/\b\w/g,(c)=>c.toUpperCase()),SECRET_SLOT_DESCRIPTORS,isPlainObject=(value)=>typeof value==="object"&&value!==null&&!Array.isArray(value),expandPath=(config,path2,always=!1)=>{let segments=path2.split("."),scopes2=[{path:"",node:config}];for(let segment of segments){let next=[];for(let current of scopes2){if(!isPlainObject(current.node))continue;if(segment==="*")for(let[childKey,childValue]of Object.entries(current.node))next.push({path:current.path?`${current.path}.${childKey}`:childKey,node:childValue});else if(segment in current.node)next.push({path:current.path?`${current.path}.${segment}`:segment,node:current.node[segment]});else if(always)next.push({path:current.path?`${current.path}.${segment}`:segment,node:{}})}scopes2=next}return scopes2.filter((s)=>isPlainObject(s.node)).map((s)=>s.path)},looksLikeEnvName=(value)=>!!value&&/^[A-Z][A-Z0-9_]{2,}$/.test(value);var init_registry=__esm(()=>{CREDENTIAL_KEY_PATTERN=/(secret|password|passwd|apikey|api_key|accesskey|access_key|privatekey|private_key|token|credential|connection_string|connectionstring|clientid|client_id|encryptionkey|encryption_key|servicekey|service_key|json_file_path|jsonfilepath)$/i,NOT_A_CREDENTIAL=new Set(["preventapikeymanagement","allowapplicationkeys","maxkeysperuser","tokenurl","accesstoken","refreshtoken","sessiontoken"]),BOOT_ONLY_PATHS=new Set(["authorization.godminPassword","authorization.godminEmail","authentication.accessToken.secret","authentication.refreshToken.secret","authentication.sessionToken.secret","backup.encryptionKey","notification.channels.telegram.botToken","notification.channels.webhook.headers","domains.cloudflare.apiToken"]),SKIP_SECTIONS=new Set(["entities","systemTables","system_tables","tables","columns","indexes","routes","cors","swagger","secrets"]),SECRET_SLOT_DESCRIPTORS=[{path:"authentication.oauth.providers.*",group:"oauth",label:"OAuth / SSO",keys:[{key:"clientId",kind:"text",label:"Client ID",required:!0},{key:"clientSecret",kind:"password",label:"Client Secret",required:!0},{key:"tenantId",kind:"text",label:"Tenant ID"},{key:"redirectUri",kind:"text",secret:!1,required:!0,label:"Y\xF6nlendirme adresi (Redirect URI)",hint:"Sa\u011Flay\u0131c\u0131ya kay\u0131tl\u0131 d\xF6n\xFC\u015F adresi. Bu adresin sa\u011Flay\u0131c\u0131 taraf\u0131nda da (\xF6r. Entra > Authentication > Redirect URIs) birebir ayn\u0131 yaz\u0131l\u0131 olmas\u0131 gerekir."}]},{always:!0,path:"email.gmail",group:"email",label:"Gmail (service account)",keys:[{key:"service_account_json",kind:"json",label:"Service Account JSON",required:!0,requiredWhen:"enabled"}]},{always:!0,path:"email.azure",group:"email",label:"Azure Communication Services",keys:[{key:"connection_string",kind:"connection_string",label:"Connection String",required:!0,requiredWhen:"enabled"}]},{always:!0,path:"storage.smb",group:"storage",label:"SMB / CIFS share",keys:[{key:"username",kind:"text",label:"Kullan\u0131c\u0131 ad\u0131",required:!0},{key:"password",kind:"password",label:"Parola",required:!0}]},{secret:!1,always:!0,path:"storage",group:"storage",label:"Dosya deposu",keys:[{key:"provider",kind:"text",label:"Depolama t\xFCr\xFC",hint:"local (sunucunun kendi diski) veya smb (kurumsal dosya sunucusu). De\u011Fi\u015Fiklik an\u0131nda ge\xE7erli olur."}]},{secret:!1,always:!0,path:"storage.smb",group:"storage",label:"SMB / CIFS share",keys:[{key:"url",kind:"text",label:"Payla\u015F\u0131m adresi",hint:"M\xFC\u015Fteriden geldi\u011Fi gibi yap\u0131\u015Ft\u0131r\u0131n: smb://sunucu/paylasim \u2014 sunucu ve payla\u015F\u0131m ad\u0131 buradan \xE7\xF6z\xFCl\xFCr."},{key:"domain",kind:"text",label:"Etki alan\u0131 (domain)",hint:"Kullan\u0131c\u0131 DOMAIN\\kullanici bi\xE7imindeyse domain k\u0131sm\u0131. Gerekmiyorsa bo\u015F b\u0131rak\u0131n."},{key:"base_path",kind:"text",label:"Payla\u015F\u0131m i\xE7i klas\xF6r",hint:"Y\xFCklemelerin toplanaca\u011F\u0131 alt klas\xF6r. Bo\u015Fsa payla\u015F\u0131m\u0131n k\xF6k\xFC kullan\u0131l\u0131r."}]},{path:"payment.providers.*",group:"payment",label:"\xD6deme sa\u011Flay\u0131c\u0131",keys:[{key:"apiKey",kind:"password",label:"API Key",required:!0},{key:"secretKey",kind:"password",label:"Secret Key",required:!0},{key:"webhookSecret",kind:"password",label:"Webhook Secret"}]},{path:"captcha",group:"captcha",label:"Captcha",keys:[{key:"secretKey",kind:"password",label:"Secret Key"}]},{secret:!1,path:"authentication",group:"portal",label:"Portal adresi",keys:[{key:"trustedAppOrigins",kind:"list",label:"G\xFCvenilen adresler",required:!0,hint:"Portal\u0131n kurulu oldu\u011Fu adres(ler). \u015Eifre s\u0131f\u0131rlama ve SSO d\xF6n\xFC\u015F linkleri buraya g\xF6re kurulur. Joker: *.firma.com"}]},{secret:!1,always:!0,path:"email",group:"email",label:"E-posta sa\u011Flay\u0131c\u0131",keys:[{key:"provider",kind:"text",label:"Kullan\u0131lacak sa\u011Flay\u0131c\u0131",hint:"azure veya gmail. Bo\u015F b\u0131rak\u0131l\u0131rsa a\xE7\u0131k olan sa\u011Flay\u0131c\u0131 kullan\u0131l\u0131r."}]},{secret:!1,always:!0,path:"email.azure",group:"email",label:"Azure Communication Services",keys:[{key:"enabled",kind:"boolean",label:"Azure e-posta a\xE7\u0131k",hint:"Ba\u011Flant\u0131 dizesini girmek tek ba\u015F\u0131na yetmez \u2014 g\xF6nderim bu anahtarla a\xE7\u0131l\u0131r."},{key:"sender_address",kind:"text",label:"G\xF6nderen adresi"}]},{secret:!1,always:!0,path:"email.gmail",group:"email",label:"Gmail (service account)",keys:[{key:"enabled",kind:"boolean",label:"Gmail e-posta a\xE7\u0131k"},{key:"from_email",kind:"text",label:"G\xF6nderen adresi"}]}]});import{and as and7,eq as eq12}from"drizzle-orm";class SecretsStore{db;resolveTable;masterKey;constructor(deps){this.db=deps.db,this.resolveTable=deps.resolveTable,this.masterKey=deps.masterKey}table(schemaName){return this.resolveTable(SECRETS_TABLE,schemaName)}async loadAll(schemaName){let values=new Map,failed=[],table=this.table(schemaName);if(!table)return{values,failed,tableMissing:!0};let rows;try{rows=await this.db.select().from(table).where(eq12(col6(table,"isActive"),!0))}catch(error){if(isMissingTableError(error))return{values,failed,tableMissing:!0};throw error}for(let row of rows)try{values.set(cacheKeyOf(row.scope,row.key),decryptSecret(row.valueEnc,this.masterKey))}catch{failed.push(`${row.scope}.${row.key}`)}return{values,failed}}async list(schemaName){let table=this.table(schemaName);if(!table)return[];try{return(await this.db.select().from(table)).filter((r)=>r.isActive!==!1).map(rowToMeta)}catch(error){if(isMissingTableError(error))return[];throw error}}async get(scope,key2,schemaName){let table=this.table(schemaName);if(!table)return null;return(await this.db.select().from(table).where(and7(eq12(col6(table,"scope"),scope),eq12(col6(table,"key"),key2))).limit(1))[0]??null}async set(params,schemaName){let table=this.table(schemaName);if(!table)return null;let existing=await this.get(params.scope,params.key,schemaName),valueEnc=encryptSecret(params.value,this.masterKey),preview=previewOf(params.value),now=new Date;if(existing)await this.db.update(table).set({valueEnc,previousEnc:existing.valueEnc,preview,kind:params.kind??existing.kind??"text",description:params.description??existing.description,version:(existing.version??1)+1,rotatedAt:now,isActive:!0,updatedAt:now,updatedBy:params.actorId??null}).where(eq12(col6(table,"id"),existing.id));else await this.db.insert(table).values({scope:params.scope,key:params.key,valueEnc,preview,kind:params.kind??"text",description:params.description??null,version:1,isActive:!0,createdBy:params.actorId??null,updatedBy:params.actorId??null});let saved=await this.get(params.scope,params.key,schemaName);return saved?rowToMeta(saved):null}async rollback(scope,key2,actorId,schemaName){let table=this.table(schemaName);if(!table)return null;let existing=await this.get(scope,key2,schemaName);if(!existing?.previousEnc)return null;let plaintext=decryptSecret(existing.previousEnc,this.masterKey),now=new Date;await this.db.update(table).set({valueEnc:existing.previousEnc,previousEnc:existing.valueEnc,preview:previewOf(plaintext),version:(existing.version??1)+1,rotatedAt:now,updatedAt:now,updatedBy:actorId??null}).where(eq12(col6(table,"id"),existing.id));let saved=await this.get(scope,key2,schemaName);return saved?rowToMeta(saved):null}async remove(scope,key2,schemaName){let table=this.table(schemaName);if(!table)return!1;let existing=await this.get(scope,key2,schemaName);if(!existing)return!1;return await this.db.delete(table).where(eq12(col6(table,"id"),existing.id)),!0}async touch(scope,key2,schemaName){let table=this.table(schemaName);if(!table)return;await this.db.update(table).set({lastUsedAt:new Date}).where(and7(eq12(col6(table,"scope"),scope),eq12(col6(table,"key"),key2)))}async reencryptAll(newMasterKey,schemaName){let table=this.table(schemaName);if(!table)return{migrated:0,failed:[]};let rows=await this.db.select().from(table),migrated=0,failed=[];for(let row of rows)try{let plaintext=decryptSecret(row.valueEnc,this.masterKey),previous=row.previousEnc?encryptSecret(decryptSecret(row.previousEnc,this.masterKey),newMasterKey):null;await this.db.update(table).set({valueEnc:encryptSecret(plaintext,newMasterKey),previousEnc:previous}).where(eq12(col6(table,"id"),row.id)),migrated++}catch{failed.push(`${row.scope}.${row.key}`)}if(failed.length===0)this.masterKey=newMasterKey;return{migrated,failed}}}var SECRETS_TABLE="nucleusSecrets",col6=(table,key2)=>table[key2],toIso=(value)=>value?new Date(value).toISOString():null,UNDEFINED_TABLE="42P01",isMissingTableError=(error)=>{let seen=new Set,current=error;while(current&&typeof current==="object"&&!seen.has(current)){seen.add(current);let record=current;if(record.code===UNDEFINED_TABLE)return!0;if(typeof record.message==="string"&&/relation .* does not exist/i.test(record.message))return!0;current=record.cause}return!1},rowToMeta=(row)=>({id:row.id,scope:row.scope,key:row.key,kind:row.kind??"text",preview:row.preview??"",description:row.description,version:row.version??1,canRollback:!!row.previousEnc,rotatedAt:toIso(row.rotatedAt),lastUsedAt:toIso(row.lastUsedAt),updatedAt:toIso(row.updatedAt),updatedBy:row.updatedBy}),cacheKeyOf=(scope,key2)=>`${scope}.${key2}`;var init_store=__esm(()=>{init_crypto()});class SecretsService{store;logger;getRedis;refreshIntervalMs;schemaName;cache=new Map;timer=null;localRevision=0;loaded=!1;tableMissing=!1;warnedTableMissing=!1;constructor(deps){this.store=deps.store,this.logger=deps.logger,this.getRedis=deps.getRedis,this.refreshIntervalMs=deps.refreshIntervalMs??DEFAULT_REFRESH_MS,this.schemaName=deps.schemaName}async start(){if(await this.refresh(),this.timer)return;this.timer=setInterval(()=>{this.refreshIfStale()},this.refreshIntervalMs),this.timer.unref?.()}stop(){if(this.timer)clearInterval(this.timer);this.timer=null}isReady(){return this.loaded}size(){return this.cache.size}isTableMissing(){return this.tableMissing}async refresh(){try{let{values,failed,tableMissing}=await this.store.loadAll(this.schemaName);if(tableMissing){if(this.tableMissing=!0,!this.warnedTableMissing)this.warnedTableMissing=!0,this.logger.warn("[Secrets] nucleus_secrets does not exist yet \u2014 env and literal values resolve normally; "+"the store activates automatically once the schema sync creates it");return}if(this.tableMissing)this.tableMissing=!1,this.warnedTableMissing=!1,this.logger.info("[Secrets] nucleus_secrets is now available \u2014 credential store active");if(this.cache=values,this.loaded=!0,failed.length>0)this.logger.error("[Secrets] Credentials failed to decrypt and were skipped",{slots:failed,hint:"master key changed without re-encrypting \u2014 POST /secrets/reencrypt with the old key"})}catch(error){this.logger.warn("[Secrets] Refresh failed, keeping cached values",{error:error instanceof Error?error.message:String(error)})}}async refreshIfStale(){let redis=this.getRedis?.();if(!redis)return this.refresh();try{let result=await redis.read(REVISION_KEY),remote=Number(result.data??0);if(Number.isFinite(remote)&&remote===this.localRevision&&this.loaded)return;await this.refresh(),this.localRevision=Number.isFinite(remote)?remote:this.localRevision}catch{await this.refresh()}}async bumpRevision(){let redis=this.getRedis?.();if(!redis)return;try{let next=Date.now();this.localRevision=next,await redis.create(REVISION_KEY,next)}catch{}}get(scope,key2){return this.cache.get(cacheKeyOf(scope,key2))}has(scope,key2){return this.cache.has(cacheKeyOf(scope,key2))}resolve(scope,key2,configValue){let fromDb=this.cache.get(cacheKeyOf(scope,key2));if(fromDb)return{value:fromDb,source:"db"};if(configValue){let fromEnv=process.env[configValue];if(fromEnv)return{value:fromEnv,source:"env"};if(looksLikeEnvName(configValue))return{value:void 0,source:"missing"};return{value:configValue,source:"literal"}}return{value:void 0,source:"missing"}}value(scope,key2,configValue){return this.resolve(scope,key2,configValue).value}listValue(scope,key2,configValue){let fallback=Array.isArray(configValue)?configValue.join(","):configValue,raw=this.value(scope,key2,fallback);if(!raw)return Array.isArray(configValue)?configValue:[];return raw.split(/[,;\n\r]+/).map((entry)=>entry.trim()).filter(Boolean)}flag(scope,key2,configValue){let raw=this.get(scope,key2);if(raw===void 0)return configValue===!0;return raw==="true"||raw==="1"}liveConfig(scope,node,keys){let live={...node};for(let key2 of keys){let declared=node[key2],configValue=typeof declared==="string"?declared:void 0;Object.defineProperty(live,key2,{get:()=>this.resolve(scope,key2,configValue).value,enumerable:!0,configurable:!0})}return live}async describe(config,slots){let discovered=slots??discoverSlots(config),stored=await this.store.list(this.schemaName),byId=new Map(stored.map((s)=>[cacheKeyOf(s.scope,s.key),s]));return discovered.map((slot)=>{let id=cacheKeyOf(slot.scope,slot.key),record=byId.get(id),{value,source}=this.resolve(slot.scope,slot.key,slot.configValue),envName=looksLikeEnvName(slot.configValue)?slot.configValue:void 0,gate=slot.requiredWhen?this.flag(slot.scope,slot.requiredWhen,configFlagAt(config,slot.scope,slot.requiredWhen)):!0;return{...slot,required:slot.required&&gate,configValue:envName,source,value:slot.secret?void 0:value,preview:slot.secret?source==="db"&&record?record.preview:value?previewOf(value):"":value??"",envName,version:record?.version,rotatedAt:record?.rotatedAt??null,canRollback:record?.canRollback??!1}})}async list(){return this.store.list(this.schemaName)}async set(params){let saved=await this.store.set(params,this.schemaName);return await this.refresh(),await this.bumpRevision(),this.logger.info("[Secrets] Credential stored",{scope:params.scope,key:params.key,version:saved?.version,actor:params.actorId}),saved}async rollback(scope,key2,actorId){let saved=await this.store.rollback(scope,key2,actorId,this.schemaName);if(!saved)return null;return await this.refresh(),await this.bumpRevision(),this.logger.info("[Secrets] Credential rolled back",{scope,key:key2,actor:actorId}),saved}async remove(scope,key2,actorId){if(!await this.store.remove(scope,key2,this.schemaName))return!1;return await this.refresh(),await this.bumpRevision(),this.logger.info("[Secrets] Credential removed",{scope,key:key2,actor:actorId}),!0}async reencryptAll(newMasterKey){let result=await this.store.reencryptAll(newMasterKey,this.schemaName);return await this.refresh(),await this.bumpRevision(),result}}var REVISION_KEY="nucleus:secrets:revision",DEFAULT_REFRESH_MS=30000,configFlagAt=(config,scope,key2)=>{let node=config;for(let segment of scope.split(".")){if(typeof node!=="object"||node===null)return;node=node[segment]}if(typeof node!=="object"||node===null)return;let value=node[key2];if(typeof value==="boolean")return value;if(typeof value==="string")return value==="true"||value==="1";return};var init_SecretsService=__esm(()=>{init_crypto();init_registry();init_store()});var resolveMasterKey=(configured)=>{if(configured){let fromEnv=process.env[configured];if(fromEnv)return fromEnv;if(!/^[A-Z][A-Z0-9_]{2,}$/.test(configured))return configured}return process.env.NUCLEUS_SECRETS_KEY||void 0};var init_Secrets=__esm(()=>{init_crypto();init_registry();init_SecretsService();init_store()});var exports_schema={};__export(exports_schema,{reasonOf:()=>reasonOf,isAdditiveStatement:()=>isAdditiveStatement,ensureSchemaExists:()=>ensureSchemaExists,applySchemaPush:()=>applySchemaPush});import{sql as sql4}from"drizzle-orm";function reasonOf(error){if(!(error instanceof Error))return String(error);let extra=error;return[error.message,extra.detail?`detail: ${String(extra.detail)}`:"",extra.hint?`hint: ${String(extra.hint)}`:"",extra.code?`code: ${String(extra.code)}`:""].filter(Boolean).join(" \u2014 ")}var validateIdentifier=(name)=>{if(!name||name.length>63)throw Error(`Invalid identifier: must be 1-63 characters, got ${name.length}`);if(!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(name))throw Error(`Invalid identifier: "${name}" contains unsafe characters`);return name},ensureSchemaExists=async(db,schemaName)=>{let safeName=validateIdentifier(schemaName),found=await db.execute(sql4`select 1 from pg_catalog.pg_namespace where nspname = ${safeName} limit 1`);if(rowCountOf(found)>0)return;await db.execute(sql4.raw(`CREATE SCHEMA IF NOT EXISTS "${safeName}"`))},rowCountOf=(result)=>{if(Array.isArray(result))return result.length;let rows=result?.rows;return Array.isArray(rows)?rows.length:0},ADDITIVE_PREFIXES,isAdditiveStatement=(statement)=>{let normalized=statement.trim().toUpperCase();if(/^ALTER TABLE .+ ADD COLUMN/.test(normalized))return!0;if(/^ALTER TABLE .+ ALTER COLUMN .+ SET DEFAULT /.test(normalized))return!0;return ADDITIVE_PREFIXES.some((prefix)=>normalized.startsWith(prefix))},applySchemaPush=async(push,opts)=>{let{schemaName,allowDataLoss,logger:logger2,execute}=opts;if(push.hasDataLoss&&!allowDataLoss){let additive=push.statementsToExecute.filter(isAdditiveStatement),blocked=push.statementsToExecute.filter((s)=>!isAdditiveStatement(s));if(logger2.error(`[Schema] Destructive changes detected for schema "${schemaName}" but database.allowDataLoss is not enabled \u2014 ${blocked.length} statement(s) skipped. Set database.allowDataLoss: true to apply them.`,{warnings:push.warnings,statements:blocked}),additive.length===0||!execute)return!1;let applied=0;for(let statement of additive)try{await execute(statement),applied++}catch(error){logger2.warn(`[Schema] ${schemaName}: ${statement} \u2014 ${reasonOf(error)}`)}return logger2.info(`[Schema] Applied ${applied}/${additive.length} additive statement(s) for "${schemaName}" despite the destructive changes being held back`),applied>0}if(push.hasDataLoss)logger2.warn(`[Schema] Applying destructive changes to schema "${schemaName}" (database.allowDataLoss=true)`,{warnings:push.warnings});try{return await push.apply(),!0}catch(error){let message=error instanceof Error?error.message:String(error);if(!execute)return logger2.error(`[Schema] Could not apply schema changes to "${schemaName}": ${message}. The database does not match this build, so queries against the missing columns will fail.`,{warnings:push.warnings}),!1;logger2.error(`[Schema] The schema push for "${schemaName}" failed as a batch (${message}) \u2014 retrying its ${push.statementsToExecute.length} statement(s) one at a time so one bad statement does not hold back the rest.`);let applied=0,failures=[];for(let statement of push.statementsToExecute)try{await execute(statement),applied++}catch(statementError){failures.push(statement),logger2.error(`[Schema] ${schemaName}: ${statement} \u2014 ${reasonOf(statementError)}`)}if(failures.length>0)logger2.error(`[Schema] ${failures.length} of ${push.statementsToExecute.length} statement(s) could not be applied to "${schemaName}". Any query touching what they would have created will fail until they are.`);return applied>0}};var init_schema=__esm(()=>{ADDITIVE_PREFIXES=["CREATE TABLE IF NOT EXISTS","CREATE TABLE","CREATE SCHEMA IF NOT EXISTS","CREATE SCHEMA","CREATE INDEX IF NOT EXISTS","CREATE INDEX","CREATE UNIQUE INDEX IF NOT EXISTS","CREATE UNIQUE INDEX","CREATE TYPE","DO $$"]});var rowToTenantRecord=(row)=>({id:String(row.id||""),subdomain:String(row.subdomain||""),schemaName:String(row.schemaName||row.schema_name||""),companyId:String(row.companyId||row.company_id||""),companyName:row.companyName!=null?String(row.companyName):row.company_name!=null?String(row.company_name):null,godAdminEmail:String(row.godAdminEmail||row.god_admin_email||""),status:parseStatus(row.status),plan:row.plan!=null?String(row.plan):null,domain:row.domain!=null?String(row.domain):null,settings:parseJsonbToConfig(row.settings),trustedSources:parseTrustedSources(row.trustedSources||row.trusted_sources),maxUsers:row.maxUsers!=null?Number(row.maxUsers):row.max_users!=null?Number(row.max_users):null,provisionedAt:row.provisionedAt!=null?String(row.provisionedAt):row.provisioned_at!=null?String(row.provisioned_at):null,suspendedAt:row.suspendedAt!=null?String(row.suspendedAt):row.suspended_at!=null?String(row.suspended_at):null,suspendedReason:row.suspendedReason!=null?String(row.suspendedReason):row.suspended_reason!=null?String(row.suspended_reason):null}),rowToFeatureRecord=(row,parseConfig)=>({id:String(row.id||""),tenantId:String(row.tenantId||row.tenant_id||""),featureName:String(row.featureName||row.feature_name||""),enabled:Boolean(row.enabled),featureConfig:parseConfig(row.config)}),parseStatus=(value)=>{let valid=["provisioning","active","suspended","archived"],str3=String(value||"provisioning");return valid.includes(str3)?str3:"provisioning"},parseJsonbToConfig=(value)=>{if(!value||typeof value!=="object")return{};let result={};for(let[k,v]of Object.entries(value))if(typeof v==="string"||typeof v==="number"||typeof v==="boolean")result[k]=v;return result},parseTrustedSources=(value)=>{if(!Array.isArray(value))return[];return value.map((item)=>{let entry=item;return{allowHeaderAuth:entry.allowHeaderAuth===!0||entry.allow_header_auth===!0,allowedIps:Array.isArray(entry.allowedIps||entry.allowed_ips)?entry.allowedIps||entry.allowed_ips:void 0,allowedServices:Array.isArray(entry.allowedServices||entry.allowed_services)?entry.allowedServices||entry.allowed_services:void 0}})},normalizeHost=(host)=>{return((host||"").split(":")[0]||"").toLowerCase().replace(/\.$/,"")},extractSubdomain=(host)=>{let hostWithoutPort=host.split(":")[0]||"";if(hostWithoutPort==="localhost"||/^\d+\.\d+\.\d+\.\d+$/.test(hostWithoutPort))return null;let parts=hostWithoutPort.split(".");if(parts.length<3)return null;let subdomain=parts[0]||"";if(!subdomain||subdomain==="www")return null;return subdomain},isIpInCidr=(ip,cidr)=>{let[cidrIp,prefixStr]=cidr.split("/");if(!cidrIp||!prefixStr)return!1;let prefix=Number.parseInt(prefixStr,10);if(Number.isNaN(prefix))return!1;let ipParts=ip.split(".").map(Number),cidrParts=cidrIp.split(".").map(Number);if(ipParts.length!==4||cidrParts.length!==4)return!1;let ipNum=(ipParts[0]||0)<<24|(ipParts[1]||0)<<16|(ipParts[2]||0)<<8|(ipParts[3]||0),cidrNum=(cidrParts[0]||0)<<24|(cidrParts[1]||0)<<16|(cidrParts[2]||0)<<8|(cidrParts[3]||0),mask=~((1<<32-prefix)-1);return(ipNum&mask)===(cidrNum&mask)},isTrustedSource=(tenant,request,authMode,fallbackSources,vettedClientIp)=>{let ownSources=tenant.trustedSources,trustedSources=Array.isArray(ownSources)&&ownSources.length>0?ownSources:fallbackSources;if(!trustedSources||!Array.isArray(trustedSources)||trustedSources.length===0)return!1;let clientIp=vettedClientIp?.trim()||"",serviceId=request.headers.get("x-service-id")||"";for(let source of trustedSources){if(!source.allowHeaderAuth)continue;if(source.allowedIps&&source.allowedIps.length>0){if(source.allowedIps.some((allowedIp)=>{if(allowedIp.includes("/"))return isIpInCidr(clientIp,allowedIp);return clientIp===allowedIp}))return!0}if(source.allowedServices&&source.allowedServices.length>0){if(source.allowedServices.includes(serviceId))return!0}}return!1};function getDatabaseAuthMode(){return process.env.DATABASE_AUTH_MODE||"password"}function getRedisAuthMode(){return process.env.REDIS_AUTH_MODE||"password"}async function acquireToken(scope,label){let{DefaultAzureCredential,ManagedIdentityCredential,ClientSecretCredential}=await import("@azure/identity"),authMode=scope===PG_TOKEN_SCOPE?getDatabaseAuthMode():getRedisAuthMode(),clientId=process.env.AZURE_CLIENT_ID||"",tenantId=process.env.AZURE_TENANT_ID||"",clientSecret=process.env.AZURE_CLIENT_SECRET||"",credential;if(authMode==="managed_identity")credential=clientId?new ManagedIdentityCredential(clientId):new DefaultAzureCredential;else if(authMode==="service_principal"){if(!tenantId||!clientId||!clientSecret)throw Error("[azure-auth] service_principal auth requires AZURE_TENANT_ID, AZURE_CLIENT_ID, and AZURE_CLIENT_SECRET");credential=new ClientSecretCredential(tenantId,clientId,clientSecret)}else throw Error(`[azure-auth] Unsupported auth mode: ${authMode}`);let result=await credential.getToken(scope);if(!result)throw Error(`[azure-auth] Failed to acquire token for ${label}`);return logger.scoped("database.connect").info(`[azure-auth] ${label} token acquired`,{expiresAt:new Date(result.expiresOnTimestamp).toISOString(),authMode}),{token:result.token,expiresAt:result.expiresOnTimestamp}}async function getPostgresToken(){let now=Date.now();if(pgCachedToken&&now<pgTokenExpiresAt-REFRESH_BUFFER_MS)return pgCachedToken;let{token,expiresAt}=await acquireToken(PG_TOKEN_SCOPE,"PostgreSQL");return pgCachedToken=token,pgTokenExpiresAt=expiresAt,pgCachedToken}async function getRedisToken(){let now=Date.now();if(redisCachedToken&&now<redisTokenExpiresAt-REFRESH_BUFFER_MS)return redisCachedToken;let{token,expiresAt}=await acquireToken(REDIS_TOKEN_SCOPE,"Redis");return redisCachedToken=token,redisTokenExpiresAt=expiresAt,redisCachedToken}function getRedisTokenExpiresAt(){return redisTokenExpiresAt}var PG_TOKEN_SCOPE="https://ossrdbms-aad.database.windows.net/.default",REDIS_TOKEN_SCOPE="https://redis.azure.com/.default",REFRESH_BUFFER_MS=300000,pgCachedToken=null,pgTokenExpiresAt=0,redisCachedToken=null,redisTokenExpiresAt=0;var init_AzureTokenProvider=__esm(()=>{init_Logger2()});var exports_Azure={};__export(exports_Azure,{getRedisTokenExpiresAt:()=>getRedisTokenExpiresAt,getRedisToken:()=>getRedisToken,getRedisAuthMode:()=>getRedisAuthMode,getPostgresToken:()=>getPostgresToken,getDatabaseAuthMode:()=>getDatabaseAuthMode});var init_Azure=__esm(()=>{init_AzureTokenProvider()});import{access,mkdir as mkdir4}from"fs/promises";import{dirname as dirname3,resolve}from"path";var DEFAULT_CONFIG5,FILE_SIZE_UNITS,resolvePath=(path2)=>{if(!path2||typeof path2!=="string")throw createFileManagerError("INVALID_PATH","Path must be a non-empty string",path2,"resolvePath");return resolve(path2)},extractDirectoryPath=(filePath)=>{let resolvedPath=resolvePath(filePath);return dirname3(resolvedPath)},ensureDirectoryExists=async(dirPath)=>{let resolvedPath=resolve(dirPath);try{await mkdir4(resolvedPath,{recursive:!0})}catch(error){if(error.code!=="EEXIST")throw createFileManagerError("DIRECTORY_CREATE_FAILED",`Failed to create directory: ${resolvedPath}`,resolvedPath,"ensureDirectory")}},formatFileSize=(bytes)=>{let size=bytes,unitIndex=0;while(size>=1024&&unitIndex<FILE_SIZE_UNITS.length-1)size/=1024,unitIndex++;return`${size.toFixed(2)} ${FILE_SIZE_UNITS[unitIndex]}`},validateFileExtension=(fileName,expectedExtension)=>{return fileName.toLowerCase().endsWith(expectedExtension.toLowerCase())},ensureFileExtension=(fileName,extension)=>{let normalizedExtension=extension.startsWith(".")?extension:`.${extension}`;if(validateFileExtension(fileName,normalizedExtension))return fileName;return`${fileName}${normalizedExtension}`},createFileManagerError=(code,message,path2,operation)=>{return{code,message,path:path2,operation:operation||"unknown"}},safeJsonStringify=(data)=>{try{return JSON.stringify(data,null,2)}catch{return"{}"}},executeBulkOperation=async(items,operation,concurrency=DEFAULT_CONFIG5.maxConcurrency)=>{let results=[];for(let i=0;i<items.length;i+=concurrency){let batch3=items.slice(i,i+concurrency),batchPromises=[];for(let item of batch3)batchPromises.push(operation(item));let batchResults=await Promise.allSettled(batchPromises);results.push(...batchResults)}return results},validateConfig=(config,options={})=>{let errors=[],warnings=[],strict=options.strict??!0;if(config.defaultEncoding!==void 0){if(!["utf-8","utf8","ascii","base64","hex"].includes(config.defaultEncoding))errors.push(`Invalid defaultEncoding: ${config.defaultEncoding}`)}if(config.maxConcurrency!==void 0){if(!Number.isInteger(config.maxConcurrency)||config.maxConcurrency<1)errors.push("maxConcurrency must be a positive integer");if(config.maxConcurrency>50)warnings.push("maxConcurrency > 50 may cause performance issues")}if(config.defaultCreateDir!==void 0&&typeof config.defaultCreateDir!=="boolean")errors.push("defaultCreateDir must be a boolean");if(config.defaultRecursive!==void 0&&typeof config.defaultRecursive!=="boolean")errors.push("defaultRecursive must be a boolean");if(strict&&!options.allowUnknownKeys){let validKeys=["defaultEncoding","defaultCreateDir","defaultRecursive","maxConcurrency"],configKeys=Object.keys(config);for(let key2 of configKeys)if(!validKeys.includes(key2))errors.push(`Unknown configuration key: ${key2}`)}return{isValid:errors.length===0,errors,warnings}},mergeConfig=(partial,base=DEFAULT_CONFIG5)=>{let validation=validateConfig(partial);if(!validation.isValid)throw createFileManagerError("CONFIG_VALIDATION_FAILED",`Configuration validation failed: ${validation.errors.join(", ")}`,void 0,"mergeConfig");return{...base,...partial}},parsePermissions=(mode)=>{let parseOctal=(octal)=>({read:Boolean(octal&4),write:Boolean(octal&2),execute:Boolean(octal&1)}),ownerMode=mode>>6&7,groupMode=mode>>3&7,othersMode=mode&7;return{owner:parseOctal(ownerMode),group:parseOctal(groupMode),others:parseOctal(othersMode)}},validatePermissionMode=(mode)=>{return Number.isInteger(mode)&&mode>=0&&mode<=511};var init_utils4=__esm(()=>{DEFAULT_CONFIG5={defaultEncoding:"utf-8",defaultCreateDir:!0,defaultRecursive:!0,maxConcurrency:5},FILE_SIZE_UNITS=["B","KB","MB","GB","TB"]});import{copyFile,rename as rename2,unlink as unlink4}from"fs/promises";import{basename,dirname as dirname4,extname,join as join5}from"path";var DEFAULT_ATOMIC_CONFIG,generateTempPath=(originalPath,suffix=".tmp")=>{let resolvedPath=resolvePath(originalPath),timestamp=Date.now(),random=Math.random().toString(36).substring(2,8);return`${resolvedPath}${suffix}.${timestamp}.${random}`},generateBackupPath=(originalPath,backupDir,useTimestamp=!0)=>{let resolvedPath=resolvePath(originalPath),dir=backupDir?resolvePath(backupDir):dirname4(resolvedPath),name=basename(resolvedPath),ext=extname(name),nameWithoutExt=basename(name,ext),timestamp=useTimestamp?`.${new Date().toISOString().replace(/[:.]/g,"-")}`:"",backupName=`${nameWithoutExt}.backup${timestamp}${ext}`;return join5(dir,backupName)},atomicWrite=async({path:path2,data,tempSuffix=DEFAULT_ATOMIC_CONFIG.tempSuffix,backup=DEFAULT_ATOMIC_CONFIG.backup,sync=DEFAULT_ATOMIC_CONFIG.sync})=>{let resolvedPath=resolvePath(path2),tempPath=generateTempPath(resolvedPath,tempSuffix),backupPath;try{if(await ensureDirectoryExists(extractDirectoryPath(resolvedPath)),backup){if(await Bun.file(resolvedPath).exists())backupPath=generateBackupPath(resolvedPath),await copyFile(resolvedPath,backupPath)}let bytesWritten=await Bun.write(tempPath,data);return await rename2(tempPath,resolvedPath),{success:!0,bytesWritten,tempPath,backupPath}}catch(error){try{await unlink4(tempPath)}catch{}throw createFileManagerError("ATOMIC_WRITE_FAILED",`Atomic write failed: ${error}`,resolvedPath,"atomicWrite")}},atomicJsonWrite=async(path2,data,options={})=>{let jsonString=JSON.stringify(data,null,2);return atomicWrite({path:path2,data:jsonString,...options})},createBackup=async({sourcePath,backupDir,keepOriginal=!0,timestamp=DEFAULT_ATOMIC_CONFIG.timestamp})=>{let resolvedSource=resolvePath(sourcePath);if(!await Bun.file(resolvedSource).exists())throw createFileManagerError("SOURCE_NOT_FOUND",`Source file not found: ${sourcePath}`,resolvedSource,"createBackup");let backupPath=generateBackupPath(resolvedSource,backupDir,timestamp);if(await ensureDirectoryExists(dirname4(backupPath)),keepOriginal)await copyFile(resolvedSource,backupPath);else await rename2(resolvedSource,backupPath);return backupPath},restoreFromBackup=async(backupPath,targetPath,deleteBackup=!1)=>{let resolvedBackup=resolvePath(backupPath),resolvedTarget=resolvePath(targetPath);if(!await Bun.file(resolvedBackup).exists())throw createFileManagerError("BACKUP_NOT_FOUND",`Backup file not found: ${backupPath}`,resolvedBackup,"restoreFromBackup");try{if(await ensureDirectoryExists(extractDirectoryPath(resolvedTarget)),deleteBackup)await rename2(resolvedBackup,resolvedTarget);else await copyFile(resolvedBackup,resolvedTarget);return!0}catch(error){return logger.scoped("storage.fs").error(`Failed to restore from backup ${backupPath}`,error,{backupPath}),!1}},safeUpdate=async(path2,updateFunction,options={})=>{let resolvedPath=resolvePath(path2),file=Bun.file(resolvedPath),backupPath;try{if(await file.exists())backupPath=await createBackup({sourcePath:resolvedPath,keepOriginal:!0,timestamp:!0});let currentData=await file.exists()?await file.text():"",newData=await updateFunction(currentData),result=await atomicWrite({path:resolvedPath,data:newData,backup:!1,...options});return{success:result.success,bytesWritten:result.bytesWritten,tempPath:result.tempPath,backupPath}}catch(error){if(backupPath)try{await restoreFromBackup(backupPath,resolvedPath,!1)}catch(rollbackError){logger.scoped("storage.fs").error("Atomic write rollback failed",rollbackError,{backupPath})}throw error}},batchAtomicWrite=async(operations)=>{let successful=[],failed=[];for(let operation of operations)try{let result=await atomicWrite(operation);successful.push(result)}catch(error){failed.push({operation,error})}return{successful,failed}};var init_atomic=__esm(()=>{init_Logger2();init_utils4();DEFAULT_ATOMIC_CONFIG={tempSuffix:".tmp",backup:!1,sync:!0,timestamp:!0}});import{chmod,stat as stat3}from"fs/promises";var PERMISSION_MODES,setFilePermissions=async(path2,mode)=>{let resolvedPath=resolvePath(path2);if(!validatePermissionMode(mode))throw createFileManagerError("INVALID_PERMISSION_MODE",`Invalid permission mode: ${mode.toString(8)}`,resolvedPath,"setFilePermissions");try{return await chmod(resolvedPath,mode),!0}catch(error){return logger.scoped("storage.fs").error(`Failed to set permissions for ${path2}`,error,{path:path2,mode}),!1}},getFilePermissions=async(path2)=>{let resolvedPath=resolvePath(path2);try{let mode=(await stat3(resolvedPath)).mode&511,permissions=parsePermissions(mode);return{path:resolvedPath,mode,owner:permissions.owner,group:permissions.group,others:permissions.others}}catch(error){throw createFileManagerError("PERMISSION_READ_FAILED",`Failed to read permissions: ${error}`,resolvedPath,"getFilePermissions")}},hasPermissions=async(path2,requiredMode)=>{try{return((await getFilePermissions(path2)).mode&requiredMode)===requiredMode}catch{return!1}},makeReadable=async(path2)=>{let newMode=(await getFilePermissions(path2)).mode|256;return setFilePermissions(path2,newMode)},makeWritable=async(path2)=>{let newMode=(await getFilePermissions(path2)).mode|128;return setFilePermissions(path2,newMode)},makeExecutable=async(path2)=>{let newMode=(await getFilePermissions(path2)).mode|64;return setFilePermissions(path2,newMode)},makeReadOnly=async(path2)=>{let newMode=(await getFilePermissions(path2)).mode&-147;return setFilePermissions(path2,newMode)},setCommonPermissions=async(path2,pattern)=>{let mode=PERMISSION_MODES[pattern];return setFilePermissions(path2,mode)};var init_permissions=__esm(()=>{init_Logger2();init_utils4();PERMISSION_MODES={OWNER_READ_WRITE:384,OWNER_ALL:448,GROUP_READ:416,GROUP_READ_WRITE:432,ALL_READ:420,ALL_READ_WRITE:438,ALL_READ_EXECUTE:493,ALL_FULL:511,READ_ONLY:292,EXECUTABLE:493}});var DEFAULT_STREAM_CONFIG,createFileWriter=async(path2,options={})=>{let resolvedPath=resolvePath(path2),config={...DEFAULT_STREAM_CONFIG,...options};await ensureDirectoryExists(extractDirectoryPath(resolvedPath));let writer=Bun.file(resolvedPath).writer({highWaterMark:config.highWaterMark}),isClosed=!1;return{write:(chunk)=>{if(isClosed)throw createFileManagerError("WRITER_CLOSED","Cannot write to closed writer",resolvedPath,"streamWrite");try{let result=writer.write(chunk);if(config.autoFlush)writer.flush();return result}catch(error){throw createFileManagerError("WRITE_FAILED",`Failed to write chunk: ${error}`,resolvedPath,"streamWrite")}},flush:()=>{if(isClosed)return 0;try{return writer.flush()}catch(error){throw createFileManagerError("FLUSH_FAILED",`Failed to flush writer: ${error}`,resolvedPath,"streamFlush")}},end:async(error)=>{if(isClosed)return 0;try{let result=await writer.end(error);return isClosed=!0,result}catch(err){throw isClosed=!0,createFileManagerError("END_FAILED",`Failed to end writer: ${err}`,resolvedPath,"streamEnd")}},ref:()=>{if(!isClosed)writer.ref()},unref:()=>{if(!isClosed)writer.unref()}}},writeStream=async(path2,chunks,options={})=>{let writer=await createFileWriter(path2,options),totalBytes=0;try{for(let chunk of chunks){let bytesWritten=writer.write(chunk);totalBytes+=bytesWritten}return await writer.flush(),await writer.end(),totalBytes}catch(error){try{await writer.end(error)}catch{}throw error}},appendStream=async(path2,chunks,options={})=>{let resolvedPath=resolvePath(path2),file=Bun.file(resolvedPath),existingContent=await file.exists()?await file.arrayBuffer():new ArrayBuffer(0),allChunks=[];if(existingContent.byteLength>0)allChunks.push(existingContent);return allChunks.push(...chunks),writeStream(resolvedPath,allChunks,options)},copyFileStream=async(sourcePath,destinationPath,options={})=>{let resolvedSource=resolvePath(sourcePath),sourceFile=Bun.file(resolvedSource);if(!await sourceFile.exists())throw createFileManagerError("SOURCE_NOT_FOUND",`Source file not found: ${sourcePath}`,resolvedSource,"copyFileStream");let sourceStream=sourceFile.stream(),writer=await createFileWriter(destinationPath,options),totalBytes=0;try{let reader=sourceStream.getReader();while(!0){let{done,value}=await reader.read();if(done)break;let bytesWritten=writer.write(value);totalBytes+=bytesWritten}return await writer.flush(),await writer.end(),totalBytes}catch(error){try{await writer.end(error)}catch{}throw error}},readFileStream=async(path2,chunkProcessor)=>{let resolvedPath=resolvePath(path2),file=Bun.file(resolvedPath);if(!await file.exists())throw createFileManagerError("FILE_NOT_FOUND",`File not found: ${path2}`,resolvedPath,"readFileStream");let reader=file.stream().getReader();try{while(!0){let{done,value}=await reader.read();if(done)break;await chunkProcessor(value)}}finally{reader.releaseLock()}};var init_streaming=__esm(()=>{init_utils4();DEFAULT_STREAM_CONFIG={highWaterMark:1048576,autoFlush:!0,closeOnEnd:!0}});import{readdir as readdir2,rm,rmdir,stat as stat4}from"fs/promises";import{extname as extname2,join as join6}from"path";class BunFileManager{static instance;config;constructor(){this.config={...DEFAULT_CONFIG5}}static getInstance(){if(!BunFileManager.instance)BunFileManager.instance=new BunFileManager;return BunFileManager.instance}async createFile({dir,name,data,options={}}){let filePath=resolvePath(join6(dir,name));if(options.createDir!==!1)await ensureDirectoryExists(extractDirectoryPath(filePath));let fileData=options.type?new Blob([data],{type:options.type}):data;return await Bun.write(filePath,fileData)}async createJsonFile(dir,name,data){let fileName=ensureFileExtension(name,".json"),jsonString=safeJsonStringify(data);return this.createFile({dir,name:fileName,data:jsonString,options:{type:"application/json"}})}async createDirectory({path:path2}){await ensureDirectoryExists(path2)}async readFile({path:path2,format="text"}){let resolvedPath=resolvePath(path2),file=Bun.file(resolvedPath);if(!await file.exists())throw createFileManagerError("FILE_NOT_FOUND",`File not found: ${path2}`,resolvedPath,"readFile");switch(format){case"text":return await file.text();case"json":return await file.json();case"buffer":return await file.arrayBuffer();case"bytes":return await file.bytes();case"stream":return file.stream();default:return await file.text()}}async readJsonFile(path2){return this.readFile({path:path2,format:"json"})}async getFileInfo(path2){let resolvedPath=resolvePath(path2),file=Bun.file(resolvedPath),fileName=path2.split("/").pop()||path2,stats=null;try{stats=await stat4(resolvedPath)}catch{}return{name:fileName,path:resolvedPath,size:file.size,type:file.type,exists:await file.exists(),extension:extname2(fileName),createdAt:stats?.birthtime,modifiedAt:stats?.mtime}}async readDirectory({path:path2,recursive=!1}){let resolvedPath=resolvePath(path2);return await readdir2(resolvedPath,{recursive,encoding:"utf8"})}async getFilesByExtension(dir,extension){let files=await this.readDirectory({path:dir}),normalizedExt=extension.startsWith(".")?extension:`.${extension}`;return files.filter((file)=>file.endsWith(normalizedExt))}async updateFile({path:path2,data,mode="overwrite"}){let resolvedPath=resolvePath(path2);if(mode==="append"){let combinedData=await this.readFile({path:path2,format:"text"})+data;return await Bun.write(resolvedPath,combinedData)}return await Bun.write(resolvedPath,data)}async updateJsonFile(path2,data,merge=!1){let finalData=data;if(merge)try{let existingData=await this.readJsonFile(path2);if(typeof existingData==="object"&&existingData!==null&&!Array.isArray(existingData)&&typeof data==="object"&&data!==null&&!Array.isArray(data))finalData={...existingData,...data}}catch{}return this.updateFile({path:path2,data:safeJsonStringify(finalData),mode:"overwrite"})}async appendToFile(path2,data){return this.updateFile({path:path2,data,mode:"append"})}async deleteFile(path2){try{let resolvedPath=resolvePath(path2);return await Bun.file(resolvedPath).delete(),!0}catch(error){return logger.scoped("storage.fs").error(`Failed to delete file ${path2}`,error,{path:path2}),!1}}async deleteDirectory({path:path2,recursive=!1}){try{let resolvedPath=resolvePath(path2);if(recursive)await rm(resolvedPath,{recursive:!0,force:!0});else await rmdir(resolvedPath);return!0}catch(error){return logger.scoped("storage.fs").error(`Failed to delete directory ${path2}`,error,{path:path2}),!1}}async deleteFiles(paths){let results=await executeBulkOperation(paths,async(path2)=>{if(!await this.deleteFile(path2))throw Error(`Failed to delete: ${path2}`);return path2}),success=[],failed=[];for(let i=0;i<results.length;i++){let result=results[i],originalPath=paths[i];if(result?.status==="fulfilled")success.push(originalPath||"");else failed.push(originalPath||"")}return{success,failed}}async exists(path2){let resolvedPath=resolvePath(path2);return await Bun.file(resolvedPath).exists()}async copyFile(sourcePath,destinationPath){let resolvedSource=resolvePath(sourcePath),resolvedDestination=resolvePath(destinationPath),sourceFile=Bun.file(resolvedSource);if(!await sourceFile.exists())throw createFileManagerError("SOURCE_NOT_FOUND",`Source file not found: ${sourcePath}`,resolvedSource,"copyFile");return await ensureDirectoryExists(extractDirectoryPath(resolvedDestination)),await Bun.write(resolvedDestination,sourceFile)}async moveFile(sourcePath,destinationPath){try{return await this.copyFile(sourcePath,destinationPath),await this.deleteFile(sourcePath),!0}catch(error){return logger.scoped("storage.fs").error("Failed to move file",error,{sourcePath,destinationPath}),!1}}getFormattedFileSize(bytes){return formatFileSize(bytes)}getConfig(){return{...this.config}}updateConfig(newConfig){let validation=validateConfig(newConfig);if(validation.isValid){let mergedConfig=mergeConfig(newConfig,this.config);Object.assign(this.config,mergedConfig)}return validation}validateConfiguration(config){return validateConfig(config)}async createStreamWriter(path2,options={}){return createFileWriter(path2,options)}async writeStream(path2,chunks,options={}){return writeStream(path2,chunks,options)}async appendStream(path2,chunks,options={}){return appendStream(path2,chunks,options)}async copyFileStream(sourcePath,destinationPath,options={}){return copyFileStream(sourcePath,destinationPath,options)}async readFileStream(path2,chunkProcessor){return readFileStream(path2,chunkProcessor)}async setPermissions(path2,mode){return setFilePermissions(path2,mode)}async setPermissionsAdvanced(options){return setFilePermissions(options.path,options.mode)}async getPermissions(path2){return getFilePermissions(path2)}async checkPermissions(path2,requiredMode){return hasPermissions(path2,requiredMode)}async makeFileReadable(path2){return makeReadable(path2)}async makeFileWritable(path2){return makeWritable(path2)}async makeFileExecutable(path2){return makeExecutable(path2)}async makeFileReadOnly(path2){return makeReadOnly(path2)}async setCommonPermission(path2,pattern){return setCommonPermissions(path2,pattern)}async atomicWrite(options){return atomicWrite(options)}async atomicJsonWrite(path2,data,options={}){return atomicJsonWrite(path2,data,options)}async createFileBackup(options){return createBackup(options)}async restoreFileFromBackup(backupPath,targetPath,deleteBackup=!1){return restoreFromBackup(backupPath,targetPath,deleteBackup)}async safeFileUpdate(path2,updateFunction,options={}){return safeUpdate(path2,updateFunction,options)}async batchAtomicOperations(operations){return batchAtomicWrite(operations)}}var init_core=__esm(()=>{init_Logger2();init_atomic();init_permissions();init_streaming();init_utils4()});var fileManager;var init_File=__esm(()=>{init_core();init_utils4();init_core();fileManager=BunFileManager.getInstance()});import{Pool}from"pg";var init_Postgre=__esm(()=>{init_Logger2()});var init_Managers=__esm(()=>{init_Azure();init_Dapr();init_File();init_Postgre();init_Redis()});var exports_utils={};__export(exports_utils,{warnIfAccessTokenTooLargeForCookie:()=>warnIfAccessTokenTooLargeForCookie,validatePayload:()=>validatePayload,validateEnvVariables:()=>validateEnvVariables,toAudit:()=>toAudit,signNewAccessToken:()=>signNewAccessToken,sanitizePayload:()=>sanitizePayload,resolveDbPoolConfig:()=>resolveDbPoolConfig,resolveConfigCredential:()=>resolveConfigCredential,refreshAccessTokenWithLock:()=>refreshAccessTokenWithLock,redactSensitiveOutput:()=>redactSensitiveOutput,parseTokenValuesFromHeaders:()=>parseTokenValuesFromHeaders,parseTimeToSeconds:()=>parseTimeToSeconds2,parseQueryParams:()=>parseQueryParams,isSensitiveOutputKey:()=>isSensitiveOutputKey,initiateRedisManager:()=>initiateRedisManager,getRedisManager:()=>getRedisManager,ensureDatabaseExists:()=>ensureDatabaseExists,decodeUnverifiedSubject:()=>decodeUnverifiedSubject,createAuditLog:()=>createAuditLog,buildPaginationMeta:()=>buildPaginationMeta,COOKIE_SAFE_TOKEN_BYTES:()=>COOKIE_SAFE_TOKEN_BYTES});function parseTokenValuesFromHeaders(headers,tokenNames){let cookies=(headers.get("cookie")?.split(";")||[]).reduce((acc,cookie)=>{let trimmed=cookie.trim(),eqIndex=trimmed.indexOf("=");if(eqIndex>0)acc[trimmed.slice(0,eqIndex)]=trimmed.slice(eqIndex+1);return acc},{});return{access_token:cookies[tokenNames.access_token]||headers.get("authorization")?.split(" ")[1],refresh_token:cookies[tokenNames.refresh_token],session_token:cookies[tokenNames.session_token]}}async function initiateRedisManager(config){if(!config.redis){logger.info("[Redis] Not configured, skipping");return}let rawWithDapr=config.redis.withDapr,resolvedWithDapr=typeof rawWithDapr==="string"?process.env[rawWithDapr]?.toLowerCase()!=="false":rawWithDapr??!1,resolvedKeyPrefix=config.redis.keyPrefix?process.env[config.redis.keyPrefix]??config.redis.keyPrefix:void 0;if(resolvedWithDapr){redisManagerInstance=new RedisManager({withDapr:!0,stateStoreName:config.redis.stateStoreName,...resolvedKeyPrefix?{keyPrefix:resolvedKeyPrefix}:{}});return}let resolvedUrl=config.redis.url?process.env[config.redis.url]:void 0,resolvedHost=config.redis.host?process.env[config.redis.host]:void 0,resolvedPort=config.redis.port?parseInt(process.env[config.redis.port]||"",10):void 0;if((process.env.REDIS_AUTH_MODE||"password")!=="password"){let{getRedisToken:getRedisToken2,getRedisTokenExpiresAt:getRedisTokenExpiresAt2}=await Promise.resolve().then(() => (init_Azure(),exports_Azure)),clientId=process.env.AZURE_CLIENT_ID||"",initialToken=await getRedisToken2();redisManagerInstance=new RedisManager({host:resolvedHost,port:Number.isNaN(resolvedPort)?void 0:resolvedPort,password:initialToken,username:clientId,tls:!0,...resolvedKeyPrefix?{keyPrefix:resolvedKeyPrefix}:{}});let unref=(t)=>{t.unref?.()},scheduleRedisTokenRefresh=()=>{let expiresAt=getRedisTokenExpiresAt2(),refreshIn=Math.max(expiresAt-Date.now()-300000,30000);unref(setTimeout(async()=>{try{let newToken=await getRedisToken2();if(redisManagerInstance)await redisManagerInstance.reauthenticate(clientId,newToken),logger.info("[Redis] Entra ID token refreshed successfully");scheduleRedisTokenRefresh()}catch(err){logger.error("[Redis] Token refresh failed \u2014 retrying in 30s",err),unref(setTimeout(scheduleRedisTokenRefresh,30000))}},refreshIn))};scheduleRedisTokenRefresh()}else{let resolvedPassword=process.env.REDIS_PASSWORD||void 0;redisManagerInstance=new RedisManager({url:resolvedUrl,host:resolvedHost,port:Number.isNaN(resolvedPort)?void 0:resolvedPort,...resolvedPassword?{password:resolvedPassword}:{},...resolvedKeyPrefix?{keyPrefix:resolvedKeyPrefix}:{}})}}function getRedisManager(){return redisManagerInstance}function parseTimeToSeconds2(timeString){if(typeof timeString==="number")return timeString;if(!timeString||timeString.trim()==="")throw Error("Time string cannot be empty");let match=timeString.trim().match(/^(\d+(?:\.\d+)?)\s*([smhdwMy])$/);if(!match||!match[1]||!match[2])throw Error(`Invalid time format: "${timeString}". Expected format: "75s", "10m", "2h", "1d", "1w", "2M", "1y"`);let value=parseFloat(match[1]),unit=match[2],multiplier={s:1,m:60,h:3600,d:86400,w:604800,M:2592000,y:31536000}[unit];if(multiplier===void 0)throw Error(`Unknown time unit: "${unit}"`);let seconds=Math.floor(value*multiplier);if(seconds<=0)throw Error(`Time value must be positive: "${timeString}"`);return seconds}function warnIfAccessTokenTooLargeForCookie(token,jwtClaimsMode){let bytes=Buffer.byteLength(token,"utf-8");if(bytes<=COOKIE_SAFE_TOKEN_BYTES)return;let now=Date.now();if(now-lastOversizeWarnAt<60000)return;lastOversizeWarnAt=now,logger.warn(`[Auth] access_token is ${bytes} bytes \u2014 at/over the ~4KB per-cookie browser limit, so the cookie may be `+"silently dropped (symptom: appears logged-in but requests are unauthenticated). Shrink it: set authorization.jwtClaimsMode:'resolve' (token carries only roles; claims resolved from the Redis claims cache), or deliver the token off-cookie via authentication.accessToken.setHeadersEnabled:false. "+(jwtClaimsMode?`Current jwtClaimsMode='${jwtClaimsMode}'.`:""))}function signNewAccessToken({sessionData,options,refreshTokenId,roles,claims,tenant,claimScopes,resolveMode}){let secretEnvName=options.authentication?.accessToken?.secret;if(!secretEnvName)throw Error("Access token secret env name is not configured");let secret=process.env[secretEnvName];if(!secret)throw Error(`Access token secret env "${secretEnvName}" is not set`);let token=signJWT({subject:sessionData.userId,issuer:options.authentication?.accessToken?.issuer,audience:options.authentication?.accessToken?.audience,algorithm:options.authentication?.accessToken?.algorithm,expiresInSeconds:parseTimeToSeconds2(options.authentication?.accessToken?.expiresIn??"15m"),sessionId:sessionData.id,customClaims:{refreshTokenId,...roles&&roles.length>0?{roles}:{},...!resolveMode&&claims&&claims.length>0?{claims}:{},...!resolveMode&&claimScopes&&Object.keys(claimScopes).length>0?{claimScopes}:{},...tenant?{tenant}:{}}},secret);return warnIfAccessTokenTooLargeForCookie(token,resolveMode?"resolve":options.authorization?.jwtClaimsMode),token}function resolveDbPoolConfig(pool){return{max:pool?.max!=null&&pool.max>0?pool.max:10,idleTimeoutMillis:pool?.idleTimeoutMillis??30000,connectionTimeoutMillis:pool?.connectionTimeoutMillis??1e4,...pool?.maxUses!=null&&pool.maxUses>0?{maxUses:pool.maxUses}:{}}}function toAudit(payload,summary,opts){return payload?{entityName:payload.entity_name,entityId:payload.entity_id===" - "?null:payload.entity_id,operation:payload.operation_type,userId:opts&&"userId"in opts?opts.userId??null:payload.user_id==="unknown"?null:payload.user_id,summary,severity:opts?.severity,category:opts?.category,ipAddress:payload.ip_address,userAgent:payload.user_agent,path:payload.path,query:payload.query}:void 0}function decodeUnverifiedSubject(token){if(!token)return null;try{let parts=token.split(".");if(parts.length<2)return null;let payloadPart=parts[1];if(!payloadPart)return null;let json=Buffer.from(payloadPart,"base64url").toString("utf-8"),decoded=JSON.parse(json);return typeof decoded.sub==="string"&&decoded.sub?decoded.sub:null}catch{return null}}function reconstructBracketParams(query){let result={},arrayGroups={};for(let[key2,value]of Object.entries(query)){let match=key2.match(/^(\w+)\[\d*\]\[(\w+)\]$/),arrayName=match?.[1],prop=match?.[2];if(arrayName&&prop){if(!arrayGroups[arrayName])arrayGroups[arrayName]={};let group=arrayGroups[arrayName];if(!group[prop])group[prop]=[];let arr=group[prop];if(Array.isArray(value))for(let v of value)arr.push(v);else arr.push(value)}else result[key2]=value}for(let[arrayName,props]of Object.entries(arrayGroups)){let propNames=Object.keys(props);if(propNames.length===0)continue;let maxLen=Math.max(...propNames.map((p)=>(props[p]||[]).length)),items=[];for(let i=0;i<maxLen;i++){let item={};for(let p of propNames)item[p]=(props[p]||[])[i];items.push(item)}result[arrayName]=items}return result}function parseQueryParams(query){let q=reconstructBracketParams(query),parseJSONOrPassthrough=(value)=>{if(value===void 0||value===null)return;if(typeof value==="object")return value;if(typeof value==="string")try{return JSON.parse(value)}catch{return}return},DEFAULT_PAGE_SIZE=20,MAX_PAGE_SIZE=200,rawPage=q.page?parseInt(q.page,10):1,page=Number.isFinite(rawPage)&&rawPage>0?rawPage:1,rawLimit=q.limit?parseInt(q.limit,10):20,limit=Number.isFinite(rawLimit)&&rawLimit>0?Math.min(rawLimit,200):20,rawOffset=q.offset?parseInt(q.offset,10):(page-1)*limit,offset=Number.isFinite(rawOffset)&&rawOffset>=0?rawOffset:0;return{page,limit,offset,search:q.search,searchFields:q.searchFields?q.searchFields.split(","):void 0,filters:parseJSONOrPassthrough(q.filters),sort:parseJSONOrPassthrough(q.sort),select:q.select?q.select.split(","):void 0,with:parseJSONOrPassthrough(q.with),distinct:q.distinct==="true",distinctOn:q.distinctOn?q.distinctOn.split(","):void 0}}function buildPaginationMeta(page,limit,offset,totalItems){let totalPages=Math.ceil(totalItems/limit),hasNextPage=page<totalPages,hasPrevPage=page>1;return{page,limit,offset,totalItems,totalPages,hasNextPage,hasPrevPage,nextPage:hasNextPage?page+1:null,prevPage:hasPrevPage?page-1:null}}function getBaseTypeValidator(type){let stringTypes=["varchar","char","text","uuid","citext","bit","varbit"],numberTypes=["integer","smallint","bigint","serial","smallserial","bigserial","real","doublePrecision","numeric","decimal"],booleanTypes=["boolean"];if(stringTypes.includes(type))return(v)=>({valid:typeof v==="string",expectedType:"string"});if(numberTypes.includes(type))return(v)=>({valid:typeof v==="number",expectedType:"number"});if(booleanTypes.includes(type))return(v)=>({valid:typeof v==="boolean",expectedType:"boolean"});if(type==="json"||type==="jsonb")return(v)=>({valid:typeof v==="object",expectedType:"object"});return()=>({valid:!0,expectedType:"any"})}function validatePayload(payload,columns,isPartial=!1){let errors=[];for(let col7 of columns){let value=payload[col7.name]??payload[col7.name.replace(/_([a-z])/g,(_,l)=>l.toUpperCase())],hasDbDefault=col7.default!==void 0||!!col7.defaultRaw||!!col7.generatedByDefaultAsIdentity||!!col7.generatedAlwaysAsIdentity||!!col7.generatedAlwaysAs,isRequired=col7.notNull&&!col7.nullable&&!hasDbDefault;if(value===void 0||value===null){if(isRequired&&!isPartial)errors.push({field:col7.name,message:col7.validation?.customMessage||`${col7.name} is required`});continue}if(col7.array){let baseValidator=getBaseTypeValidator(col7.type),expectedType=baseValidator(void 0).expectedType;if(!Array.isArray(value)){errors.push({field:col7.name,message:col7.validation?.customMessage||`${col7.name} must be an array of ${expectedType}`});continue}if(value.some((el)=>el!==null&&!baseValidator(el).valid))errors.push({field:col7.name,message:col7.validation?.customMessage||`${col7.name} must be an array of ${expectedType}`});continue}let typeCheck=getBaseTypeValidator(col7.type)(value);if(!typeCheck.valid){errors.push({field:col7.name,message:col7.validation?.customMessage||`${col7.name} must be of type ${typeCheck.expectedType}`});continue}if(typeof value==="string"){let len=value.length;if(col7.length&&len>col7.length)errors.push({field:col7.name,message:col7.validation?.customMessage||`${col7.name} exceeds max length of ${col7.length}`});if(col7.validation?.minLength&&len<col7.validation.minLength)errors.push({field:col7.name,message:col7.validation.customMessage||`${col7.name} must be at least ${col7.validation.minLength} characters`});if(col7.validation?.maxLength&&len>col7.validation.maxLength)errors.push({field:col7.name,message:col7.validation.customMessage||`${col7.name} must be at most ${col7.validation.maxLength} characters`});if(col7.validation?.pattern){if(!new RegExp(col7.validation.pattern).test(value))errors.push({field:col7.name,message:col7.validation.customMessage||`${col7.name} does not match required pattern`})}if(col7.validation?.format){let formatRegex=FORMAT_PATTERNS[col7.validation.format];if(formatRegex&&!formatRegex.test(value))errors.push({field:col7.name,message:col7.validation.customMessage||`${col7.name} must be a valid ${col7.validation.format}`})}}if(typeof value==="number"){if(col7.validation?.min!==void 0&&value<col7.validation.min)errors.push({field:col7.name,message:col7.validation.customMessage||`${col7.name} must be at least ${col7.validation.min}`});if(col7.validation?.max!==void 0&&value>col7.validation.max)errors.push({field:col7.name,message:col7.validation.customMessage||`${col7.name} must be at most ${col7.validation.max}`})}if(col7.enumValues&&col7.enumValues.length>0){if(!col7.enumValues.includes(value))errors.push({field:col7.name,message:col7.validation?.customMessage||`${col7.name} must be one of: ${col7.enumValues.join(", ")}`})}}return{valid:errors.length===0,errors}}function escapeHtml(str3){return str3.replace(/[&<>"'`=/]/g,(char)=>HTML_ENTITIES[char]||char)}function stripTags(str3){return str3.replace(/<[^>]*>/g,"")}function normalizeEmail(email){let parts=email.split("@"),localPart=parts[0],domain=parts[1];if(!localPart||!domain)return email;let beforePlus=localPart.split("+")[0];if(!beforePlus)return email;return`${beforePlus.replace(/\./g,"")}@${domain.toLowerCase()}`}function slugify(str3){return str3.toLowerCase().trim().replace(/[^\w\s-]/g,"").replace(/[\s_-]+/g,"-").replace(/^-+|-+$/g,"")}function applySanitizer(value,sanitizer){if(value===null||value===void 0)return value;switch(sanitizer){case"trim":return typeof value==="string"?value.trim():value;case"lowercase":return typeof value==="string"?value.toLowerCase():value;case"uppercase":return typeof value==="string"?value.toUpperCase():value;case"escapeHtml":return typeof value==="string"?escapeHtml(value):value;case"stripTags":return typeof value==="string"?stripTags(value):value;case"normalizeEmail":return typeof value==="string"?normalizeEmail(value):value;case"toNumber":if(typeof value==="number")return value;if(typeof value==="string"){let num2=Number(value);return Number.isNaN(num2)?value:num2}return value;case"toBoolean":if(typeof value==="boolean")return value;if(typeof value==="string"){let lower=value.toLowerCase();if(lower==="true"||lower==="1"||lower==="yes")return!0;if(lower==="false"||lower==="0"||lower==="no")return!1}if(typeof value==="number")return value!==0;return value;case"slugify":return typeof value==="string"?slugify(value):value;default:return value}}function isSensitiveOutputKey(key2){return SENSITIVE_OUTPUT_KEYS.has(key2)}function redactSensitiveOutput(row){return scrubSensitive(row)}function scrubSensitive(value){if(value===null||typeof value!=="object")return value;if(Array.isArray(value))return value.map(scrubSensitive);let proto=Object.getPrototypeOf(value);if(proto!==Object.prototype&&proto!==null)return value;let out={};for(let[k,v]of Object.entries(value)){if(SENSITIVE_OUTPUT_KEYS.has(k))continue;out[k]=scrubSensitive(v)}return out}function sanitizePayload(payload,columns,opts){let sanitized={},toCamel2=(s)=>s.replace(/_([a-z])/g,(_,l)=>l.toUpperCase()),SERVER_MANAGED=new Set(["id","created_at","updated_at","created_by","updated_by","createdAt","updatedAt","createdBy","updatedBy"]),PROTECTED_SENSITIVE=new Set(["is_god","password","password_hash","email_verified","verified_at","email_verified_at","is_locked","locked_until","failed_login_attempts","login_count","last_login_at","email_verification_token","email_verification_sent_at","email_verification_expires_at","password_reset_token","password_reset_expires_at","password_reset_sent_at","magic_link_token","two_factor_secret"]),STORAGE_MANAGED=opts?.isFormData?new Set(["path","name","original_name","originalName","extension","size","mime_type","mimeType","uploaded_by","uploadedBy"]):null;for(let key2 of Object.keys(payload)){if(SERVER_MANAGED.has(key2))continue;if(STORAGE_MANAGED?.has(key2))continue;let value=payload[key2],snakeKey=key2.replace(/[A-Z]/g,(l)=>`_${l.toLowerCase()}`);if(PROTECTED_SENSITIVE.has(snakeKey))continue;let col7=columns.find((c)=>c.name===key2||c.name===snakeKey);if(col7?.readOnly)continue;if(col7?.sanitize&&col7.sanitize.length>0)for(let sanitizer of col7.sanitize)value=applySanitizer(value,sanitizer);if(col7&&(col7.type==="timestamp"||col7.type==="timestamptz"||col7.type==="date")&&typeof value==="string"){let parsed=new Date(value);if(!Number.isNaN(parsed.getTime()))value=parsed}let normalizedKey=key2.includes("_")?toCamel2(key2):key2;sanitized[normalizedKey]=value}return sanitized}function createAuditLog(db,auditTable,entry){if(!db||!auditTable)return;let logEntry={user_id:entry.user_id,entity_name:entry.entity_name,entity_id:entry.entity_id,operation:entry.operation,old_data:entry.old_data??null,new_data:entry.new_data??null,timestamp:new Date().toISOString()};db.insert(auditTable).values(logEntry).execute().catch((err)=>{logger.error("[Audit] Database audit write failed",err,{entity:logEntry.entity_name,operation:logEntry.operation})})}async function refreshAccessTokenWithLock(userId,sessionId,generateToken){let redis=new RedisManager,lockKey=`${REFRESH_LOCK_PREFIX}${userId}`,cacheKey=`${ACCESS_TOKEN_CACHE_PREFIX}${userId}:${sessionId}`,cachedResult=await redis.read(cacheKey);if(cachedResult.success&&cachedResult.data)return{success:!0,accessToken:cachedResult.data,fromCache:!0};let lockResult=await redis.acquireLock(lockKey,LOCK_TTL_SECONDS);if(!lockResult.success)return{success:!1,error:lockResult.error};if(lockResult.data)try{let newToken=generateToken();return await redis.create(cacheKey,newToken,ACCESS_TOKEN_CACHE_TTL_SECONDS),{success:!0,accessToken:newToken,fromCache:!1}}finally{await redis.releaseLock(lockKey)}let waitResult=await redis.waitForLock(lockKey,LOCK_WAIT_TIMEOUT_MS,50);if(!waitResult.success)return{success:!1,error:waitResult.error};if(!waitResult.data)return{success:!1,error:"Lock wait timeout"};let newCachedResult=await redis.read(cacheKey);if(newCachedResult.success&&newCachedResult.data)return{success:!0,accessToken:newCachedResult.data,fromCache:!0};let fallbackToken=generateToken();return await redis.create(cacheKey,fallbackToken,ACCESS_TOKEN_CACHE_TTL_SECONDS),{success:!0,accessToken:fallbackToken,fromCache:!1}}function resolveConfigCredential(value){if(!value)return;let fromEnv=process.env[value];if(fromEnv)return fromEnv;if(/^[A-Z][A-Z0-9_]{2,}$/.test(value))return;return value}function validateEnvVariables(config){let errors=[],resolved={},databaseAuthMode=process.env.DATABASE_AUTH_MODE||"password",redisAuthMode=process.env.REDIS_AUTH_MODE||"password";resolved.databaseAuthMode=databaseAuthMode,resolved.redisAuthMode=redisAuthMode;let entraIdModes=["managed_identity","service_principal"];if(entraIdModes.includes(databaseAuthMode)||entraIdModes.includes(redisAuthMode)){if(!process.env.AZURE_CLIENT_ID)logger.warn("[Config] AZURE_CLIENT_ID is not set. Required for user-assigned managed identity.");if([databaseAuthMode,redisAuthMode].filter((m)=>m==="service_principal").length>0){if(!process.env.AZURE_TENANT_ID)errors.push({field:"azure.tenantId",envName:"AZURE_TENANT_ID",message:"AZURE_TENANT_ID is required for service_principal auth mode."});if(!process.env.AZURE_CLIENT_SECRET)errors.push({field:"azure.clientSecret",envName:"AZURE_CLIENT_SECRET",message:"AZURE_CLIENT_SECRET is required for service_principal auth mode."})}}if(config.database?.url){let envValue=process.env[config.database.url];if(!envValue)errors.push({field:"database.url",envName:config.database.url,message:`Environment variable "${config.database.url}" is not set. Please set it in your .env file.`});else resolved.databaseUrl=envValue}let validationWithDapr=typeof config.redis?.withDapr==="string"?process.env[config.redis.withDapr]?.toLowerCase()!=="false":config.redis?.withDapr??!1;if(config.redis&&!validationWithDapr)if(config.redis.url){let envValue=process.env[config.redis.url];if(!envValue)errors.push({field:"redis.url",envName:config.redis.url,message:`Environment variable "${config.redis.url}" is not set. Please set it in your .env file.`});else resolved.redisUrl=envValue}else{if(config.redis.host){if(!process.env[config.redis.host])errors.push({field:"redis.host",envName:config.redis.host,message:`Environment variable "${config.redis.host}" is not set. Please set it in your .env file.`})}if(config.redis.port){if(!process.env[config.redis.port])errors.push({field:"redis.port",envName:config.redis.port,message:`Environment variable "${config.redis.port}" is not set. Please set it in your .env file.`})}}if(config.authentication?.enabled){if(!config.authentication.mode)errors.push({field:"authentication.mode",envName:"",message:'authentication.mode is required when authentication is enabled. Use "full" for IDP/standalone services, "consumer" for resource servers.'});if(config.authentication.accessToken?.secret){let envValue=process.env[config.authentication.accessToken.secret];if(!envValue)errors.push({field:"authentication.accessToken.secret",envName:config.authentication.accessToken.secret,message:`Environment variable "${config.authentication.accessToken.secret}" is not set. Please set it in your .env file.`});else resolved.accessTokenSecret=envValue}else errors.push({field:"authentication.accessToken.secret",envName:"",message:"authentication.accessToken.secret is required when authentication is enabled."});let isConsumerMode=config.authentication.mode==="consumer";if(config.authentication.refreshToken?.secret){let envValue=process.env[config.authentication.refreshToken.secret];if(!envValue)errors.push({field:"authentication.refreshToken.secret",envName:config.authentication.refreshToken.secret,message:`Environment variable "${config.authentication.refreshToken.secret}" is not set. Please set it in your .env file.`});else resolved.refreshTokenSecret=envValue}else if(!isConsumerMode)errors.push({field:"authentication.refreshToken.secret",envName:"",message:"authentication.refreshToken.secret is required when authentication is enabled."});if(config.authentication.sessionToken?.secret){let envValue=process.env[config.authentication.sessionToken.secret];if(!envValue)errors.push({field:"authentication.sessionToken.secret",envName:config.authentication.sessionToken.secret,message:`Environment variable "${config.authentication.sessionToken.secret}" is not set. Please set it in your .env file.`});else resolved.sessionTokenSecret=envValue}else if(!isConsumerMode)errors.push({field:"authentication.sessionToken.secret",envName:"",message:"authentication.sessionToken.secret is required when authentication is enabled."})}if(config.authentication?.oauth?.enabled&&config.authentication.oauth.providers){let resolvedProviders={};for(let[providerName,providerConfig]of Object.entries(config.authentication.oauth.providers)){if(!providerConfig)continue;let{clientId:clientIdEnvName,clientSecret:clientSecretEnvName,redirectUri:redirectUriEnvName,tenantId:tenantIdEnvName}=providerConfig,clientId=resolveConfigCredential(clientIdEnvName),clientSecret=resolveConfigCredential(clientSecretEnvName),redirectUri=resolveConfigCredential(redirectUriEnvName),tenantId=resolveConfigCredential(tenantIdEnvName),credentialsMayComeFromDb=config.secrets?.enabled===!0;if(!clientId&&!credentialsMayComeFromDb)errors.push({field:`authentication.oauth.providers.${providerName}.clientId`,envName:clientIdEnvName,message:`Environment variable "${clientIdEnvName}" is not set (OAuth ${providerName} clientId).`});if(!clientSecret&&!credentialsMayComeFromDb)errors.push({field:`authentication.oauth.providers.${providerName}.clientSecret`,envName:clientSecretEnvName,message:`Environment variable "${clientSecretEnvName}" is not set (OAuth ${providerName} clientSecret).`});if(clientId&&clientSecret||credentialsMayComeFromDb)resolvedProviders[providerName]={clientId:clientId??"",clientSecret:clientSecret??"",redirectUri:redirectUri??"",tenantId,scopes:providerConfig.scopes,authorizationUrl:providerConfig.authorizationUrl,tokenUrl:providerConfig.tokenUrl,userInfoUrl:providerConfig.userInfoUrl,extraAuthParams:providerConfig.extraAuthParams}}if(Object.keys(resolvedProviders).length>0)resolved.oauthProviders=resolvedProviders}return{valid:errors.length===0,errors,resolved}}async function ensureDatabaseExists(databaseUrl,logger2,authMode){let{Pool:Pool2}=await import("pg"),targetDb=new URL(databaseUrl).pathname.replace("/","");if(!targetDb)return;let adminUrl=new URL(databaseUrl);adminUrl.pathname="/postgres";let pool;if(authMode&&authMode!=="password"){let{getPostgresToken:getPostgresToken2}=await Promise.resolve().then(() => (init_Azure(),exports_Azure));pool=new Pool2({connectionString:adminUrl.toString(),password:getPostgresToken2,ssl:{rejectUnauthorized:!0}})}else pool=new Pool2({connectionString:adminUrl.toString()});try{if((await pool.query("SELECT 1 FROM pg_database WHERE datname = $1",[targetDb])).rowCount===0)logger2.info(`[Database] Creating database "${targetDb}"...`),await pool.query(`CREATE DATABASE "${targetDb}" TEMPLATE template0`),logger2.info(`[Database] Database "${targetDb}" created successfully`);else logger2.info(`[Database] Database "${targetDb}" exists`)}catch(err){let message=err instanceof Error?err.message:String(err);logger2.warn(`[Database] Could not auto-create database: ${message}`)}finally{await pool.end()}}var redisManagerInstance=null,COOKIE_SAFE_TOKEN_BYTES=3500,lastOversizeWarnAt=0,FORMAT_PATTERNS,HTML_ENTITIES,SENSITIVE_OUTPUT_KEYS,ACCESS_TOKEN_CACHE_PREFIX="access_token:",REFRESH_LOCK_PREFIX="refresh_lock:",LOCK_TTL_SECONDS=5,LOCK_WAIT_TIMEOUT_MS=3000,ACCESS_TOKEN_CACHE_TTL_SECONDS=60;var init_utils5=__esm(()=>{init_Managers();init_Services();init_Logger2();FORMAT_PATTERNS={email:/^[^\s@]+@[^\s@]+\.[^\s@]+$/,url:/^https?:\/\/.+/,uuid:/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i,date:/^\d{4}-\d{2}-\d{2}$/,datetime:/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/,time:/^\d{2}:\d{2}:\d{2}$/,uri:/^[a-z][a-z0-9+.-]*:/i,ipv4:/^(\d{1,3}\.){3}\d{1,3}$/,ipv6:/^([0-9a-f]{1,4}:){7}[0-9a-f]{1,4}$/i};HTML_ENTITIES={"&":"&","<":"<",">":">",'"':""","'":"'","/":"/","`":"`","=":"="};SENSITIVE_OUTPUT_KEYS=new Set(["password","passwordHash","password_hash","emailVerificationToken","email_verification_token","emailVerificationTokenExpiresAt","email_verification_token_expires_at","passwordResetToken","password_reset_token","refreshTokenHash","refresh_token_hash"])});import{eq as eq13,sql as sql5}from"drizzle-orm";import{pgSchema}from"drizzle-orm/pg-core";class TenantRegistry{db;logger;mainSchemaName;mainSchemaTables;mainSchemaRelations;createAllTablesForSchema;createAllRelationsForSchema;appId;authMode;tenantResolution;tenantHeader;redisCacheTtlSeconds;defaultTrustedSources;idpUrl;allowDataLoss;onTenantProvisioned;tenantsBySubdomain=new Map;tenantsBySchemaName=new Map;tenantsById=new Map;schemaContexts=new Map;tenantFeatures=new Map;tenantsByDomainHostname=new Map;constructor(config){this.db=config.db,this.logger=config.logger,this.mainSchemaName=config.mainSchemaName,this.mainSchemaTables=config.mainSchemaTables,this.mainSchemaRelations=config.mainSchemaRelations,this.createAllTablesForSchema=config.createAllTablesForSchema,this.createAllRelationsForSchema=config.createAllRelationsForSchema,this.appId=config.appId,this.authMode=config.authMode,this.tenantResolution=config.tenantResolution,this.tenantHeader=config.tenantHeader,this.redisCacheTtlSeconds=config.redisCacheTtlSeconds,this.defaultTrustedSources=config.defaultTrustedSources,this.idpUrl=config.idpUrl,this.allowDataLoss=config.allowDataLoss===!0,this.onTenantProvisioned=config.onTenantProvisioned}async initialize(){this.logger.info("[TenantRegistry] Initializing..."),this.schemaContexts.set(this.mainSchemaName,{schemaName:this.mainSchemaName,schemaTables:this.mainSchemaTables,schemaRelations:this.mainSchemaRelations,tenant:null});let tenants=await this.loadTenantsFromDb();this.logger.info(`[TenantRegistry] Loaded ${tenants.length} tenants from database`);let features=await this.loadTenantFeaturesFromDb();this.logger.info(`[TenantRegistry] Loaded ${features.length} tenant feature mappings`);for(let tenant of tenants)this.indexTenant(tenant);for(let feature of features){let existing=this.tenantFeatures.get(feature.tenantId)||[];existing.push(feature),this.tenantFeatures.set(feature.tenantId,existing)}let activeTenants=tenants.filter((t)=>t.status==="active");for(let tenant of activeTenants)await this.buildSchemaContext(tenant);await this.loadDomainHostnames(),this.logger.info(`[TenantRegistry] Initialized with ${activeTenants.length} active tenant schemas + main schema`)}resolveFromRequest(request,vettedClientIp){let url=new URL(request.url),host=request.headers.get("host")||url.host||"",normalizedHost=normalizeHost(host);if(normalizedHost){let byHostname=this.tenantsByDomainHostname.get(normalizedHost);if(byHostname)return this.validateAndReturnTenant(byHostname)}if(this.tenantResolution==="subdomain"||this.tenantResolution==="both"){let subdomain=extractSubdomain(host);if(subdomain){let tenant=this.tenantsBySubdomain.get(subdomain);if(tenant)return this.validateAndReturnTenant(tenant);return{resolved:!1,error:`Tenant not found for subdomain: ${subdomain}`,statusCode:404}}}if(this.tenantResolution==="header"||this.tenantResolution==="both"){let tenantIdOrSubdomain=request.headers.get(this.tenantHeader);if(tenantIdOrSubdomain){let result=this.resolveFromHeader(tenantIdOrSubdomain,request,vettedClientIp);if(result)return result}}let mainContext=this.schemaContexts.get(this.mainSchemaName);if(mainContext)return{resolved:!0,context:mainContext};return{resolved:!1,error:"No tenant could be resolved and main schema is unavailable",statusCode:500}}getSchemaContext(schemaName){return this.schemaContexts.get(schemaName)}getMainContext(){let ctx=this.schemaContexts.get(this.mainSchemaName);if(!ctx)throw Error("[TenantRegistry] Main schema context not initialized");return ctx}getActiveTenants(){return Array.from(this.tenantsById.values()).filter((t)=>t.status==="active")}getTenantById(id){return this.tenantsById.get(id)}getTenantBySchemaName(schemaName){return this.tenantsBySchemaName.get(schemaName)}getTenantFeatures(tenantId){return this.tenantFeatures.get(tenantId)||[]}isTenantFeatureEnabled(tenantId,featureName){return(this.tenantFeatures.get(tenantId)||[]).find((f)=>f.featureName===featureName)?.enabled??!1}getTenantIdsWithFeature(featureName){let result=[];for(let[tenantId,features]of this.tenantFeatures)if(features.find((f)=>f.featureName===featureName&&f.enabled))result.push(tenantId);return result}getSchemaNamesWithFeature(featureName){let tenantIds=this.getTenantIdsWithFeature(featureName),schemaNames=[];for(let tenantId of tenantIds){let tenant=this.tenantsById.get(tenantId);if(tenant&&tenant.status==="active")schemaNames.push(tenant.schemaName)}return schemaNames}getAllSchemaNames(){return Array.from(this.schemaContexts.keys())}async provisionTenant(tenant){this.logger.info(`[TenantRegistry] Provisioning tenant: ${tenant.subdomain} \u2192 ${tenant.schemaName}`),await ensureSchemaExists(this.db,tenant.schemaName);let context=await this.buildSchemaContext(tenant);if(this.indexTenant(tenant),await this.syncSchemaToDb(context),this.onTenantProvisioned)try{await this.onTenantProvisioned(context)}catch(err){let msg=err instanceof Error?err.message:String(err);this.logger.warn(`[TenantRegistry] onTenantProvisioned hook failed for ${tenant.schemaName}: ${msg}`)}return this.logger.info(`[TenantRegistry] Tenant provisioned: ${tenant.subdomain}`),context}async syncSchemaToDb(context){let{pushSchema}=await import("drizzle-kit/api"),{applySchemaPush:applySchemaPush2}=await Promise.resolve().then(() => (init_schema(),exports_schema)),targetSchema=pgSchema(context.schemaName);try{let push=await pushSchema({schema:targetSchema,...context.schemaTables},this.db,[context.schemaName]);if(await applySchemaPush2(push,{schemaName:context.schemaName,allowDataLoss:this.allowDataLoss,logger:this.logger,execute:(statement)=>this.db.execute(sql5.raw(statement))}))this.logger.info(`[TenantRegistry] Schema sync completed for: ${context.schemaName}`)}catch(err){let msg=err instanceof Error?err.message:String(err);this.logger.error(`[TenantRegistry] Schema sync FAILED for ${context.schemaName}: ${msg}. The database does not match this build; queries against anything it was going to add will fail.`)}}async syncAllSchemas(){for(let[schemaName,context]of this.schemaContexts)this.logger.info(`[TenantRegistry] Syncing schema: ${schemaName}`),await ensureSchemaExists(this.db,schemaName),await this.syncSchemaToDb(context)}async invalidateCache(subdomain){try{let{getRedisManager:getRedisManager2}=await Promise.resolve().then(() => (init_utils5(),exports_utils)),redis=getRedisManager2();if(redis)await redis.remove(`tenant:${subdomain}`),this.logger.info(`[TenantRegistry] Cache invalidated for: ${subdomain}`)}catch{}}async refreshTenant(tenantId){let tenantsTable=this.mainSchemaTables.tenants;if(!tenantsTable)return;let row=(await this.db.select().from(tenantsTable).where(eq13(tenantsTable.id,tenantId)).limit(1))[0];if(!row)return;let tenant=rowToTenantRecord(row),oldTenant=this.tenantsById.get(tenantId);if(oldTenant)this.tenantsBySubdomain.delete(oldTenant.subdomain),this.tenantsBySchemaName.delete(oldTenant.schemaName);if(this.indexTenant(tenant),tenant.status==="active")await this.buildSchemaContext(tenant);else this.schemaContexts.delete(tenant.schemaName);if(oldTenant)await this.invalidateCache(oldTenant.subdomain);await this.invalidateCache(tenant.subdomain)}async initializeFromIdp(){if(!this.idpUrl){this.logger.error("[TenantRegistry] Consumer multi-tenant requires idpUrl (IDP_URL)");return}this.logger.info(`[TenantRegistry] Initializing from IDP: ${this.idpUrl}`),this.schemaContexts.set(this.mainSchemaName,{schemaName:this.mainSchemaName,schemaTables:this.mainSchemaTables,schemaRelations:this.mainSchemaRelations,tenant:null});let tenants=await this.loadTenantsFromIdp();this.logger.info(`[TenantRegistry] Fetched ${tenants.length} tenants from IDP`);for(let tenant of tenants)this.indexTenant(tenant);let activeTenants=tenants.filter((t)=>t.status==="active");for(let tenant of activeTenants)await this.buildSchemaContext(tenant);await this.loadDomainHostnames(),this.logger.info(`[TenantRegistry] Consumer initialized with ${activeTenants.length} active tenant schemas + main schema`)}isConsumerMode(){return this.authMode==="consumer"&&!!this.idpUrl}async syncFromIdp(){if(!this.isConsumerMode())return{added:[],removed:[],total:this.tenantsById.size};let tenants=await this.loadTenantsFromIdp(),added=[],removed=[],seenSchemaNames=new Set;for(let tenant of tenants){seenSchemaNames.add(tenant.schemaName);let known=this.tenantsById.get(tenant.id);if(known)this.tenantsBySubdomain.delete(known.subdomain),this.tenantsBySchemaName.delete(known.schemaName);if(this.indexTenant(tenant),tenant.status==="active"){if(!this.schemaContexts.has(tenant.schemaName)){await ensureSchemaExists(this.db,tenant.schemaName);let ctx=await this.buildSchemaContext(tenant);await this.syncSchemaToDb(ctx),added.push(tenant.schemaName),await this.invalidateCache(tenant.subdomain),this.logger.info(`[TenantRegistry] Synced new tenant from IDP: ${tenant.subdomain}`)}}else if(this.schemaContexts.has(tenant.schemaName))this.schemaContexts.delete(tenant.schemaName),removed.push(tenant.schemaName),await this.invalidateCache(tenant.subdomain),this.logger.info(`[TenantRegistry] Deactivated tenant context: ${tenant.subdomain}`)}for(let[schemaName,ctx]of this.schemaContexts){if(schemaName===this.mainSchemaName)continue;if(!seenSchemaNames.has(schemaName)){if(this.schemaContexts.delete(schemaName),removed.push(schemaName),ctx.tenant)this.tenantsBySubdomain.delete(ctx.tenant.subdomain),this.tenantsById.delete(ctx.tenant.id),this.tenantsBySchemaName.delete(schemaName),await this.invalidateCache(ctx.tenant.subdomain)}}return{added,removed,total:tenants.length}}registerDomainHostname(hostname,tenantId){let tenant=this.tenantsById.get(tenantId);if(!tenant)return;this.tenantsByDomainHostname.set(normalizeHost(hostname),tenant)}unregisterDomainHostname(hostname){this.tenantsByDomainHostname.delete(normalizeHost(hostname))}async loadDomainHostnames(){let table=this.mainSchemaTables.domainHostnames;if(!table)return 0;try{let rows=await this.db.select().from(table),count=0;this.tenantsByDomainHostname.clear();for(let row of rows){let status=String(row.status??""),tenantId=String(row.tenantId??row.tenant_id??""),hostname=String(row.normalizedHostname??row.normalized_hostname??"");if(status!=="active"||!tenantId||!hostname)continue;let tenant=this.tenantsById.get(tenantId);if(!tenant)continue;this.tenantsByDomainHostname.set(normalizeHost(hostname),tenant),count++}if(count>0)this.logger.info(`[TenantRegistry] Indexed ${count} active custom hostnames`);return count}catch(err){let msg=err instanceof Error?err.message:String(err);return this.logger.warn(`[TenantRegistry] Failed to load custom hostnames: ${msg}`),0}}async loadTenantsFromIdp(){if(!this.idpUrl)return[];try{let response=await fetch(`${this.idpUrl}/tenants`,{method:"GET",headers:{"Content-Type":"application/json"}});if(!response.ok)return this.logger.warn(`[TenantRegistry] IDP tenant fetch failed: ${response.status} ${response.statusText}`),[];return((await response.json())?.data?.items||[]).map((item)=>rowToTenantRecord(item))}catch(err){let msg=err instanceof Error?err.message:String(err);return this.logger.warn(`[TenantRegistry] Failed to fetch tenants from IDP: ${msg}`),[]}}async loadTenantsFromDb(){let tenantsTable=this.mainSchemaTables.tenants;if(!tenantsTable)return this.logger.warn("[TenantRegistry] No tenants table found in main schema"),[];try{return(await this.db.select().from(tenantsTable)).map((row)=>rowToTenantRecord(row))}catch(err){let msg=err instanceof Error?err.message:String(err);return this.logger.warn(`[TenantRegistry] Failed to load tenants: ${msg}`),[]}}async loadTenantFeaturesFromDb(){let featuresTable=this.mainSchemaTables.tenantFeatures;if(!featuresTable)return this.logger.warn("[TenantRegistry] No tenant_features table found in main schema"),[];try{return(await this.db.select().from(featuresTable)).map((row)=>rowToFeatureRecord(row,parseJsonbToConfig))}catch(err){let msg=err instanceof Error?err.message:String(err);return this.logger.warn(`[TenantRegistry] Failed to load tenant features: ${msg}`),[]}}indexTenant(tenant){if(this.tenantsById.set(tenant.id,tenant),this.tenantsBySubdomain.set(tenant.subdomain,tenant),this.tenantsBySchemaName.set(tenant.schemaName,tenant),tenant.domain)this.tenantsBySubdomain.set(tenant.domain,tenant)}async buildSchemaContext(tenant){let schema=pgSchema(tenant.schemaName),schemaTables=this.createAllTablesForSchema(schema),schemaRelations=this.createAllRelationsForSchema?this.createAllRelationsForSchema(schema):{},context={schemaName:tenant.schemaName,schemaTables,schemaRelations,tenant};return this.schemaContexts.set(tenant.schemaName,context),context}resolveFromHeader(tenantIdOrSubdomain,request,vettedClientIp){let tenant=this.tenantsBySubdomain.get(tenantIdOrSubdomain);if(!tenant)tenant=this.tenantsById.get(tenantIdOrSubdomain);if(!tenant)tenant=this.tenantsBySchemaName.get(tenantIdOrSubdomain);if(!tenant)return{resolved:!1,error:`Tenant not found for header value: ${tenantIdOrSubdomain}`,statusCode:404};if(!isTrustedSource(tenant,request,this.authMode,this.defaultTrustedSources,vettedClientIp))return{resolved:!1,error:`Untrusted source for tenant: ${tenant.subdomain}`,statusCode:403};return this.validateAndReturnTenant(tenant)}validateAndReturnTenant(tenant){if(tenant.status==="suspended")return{resolved:!1,error:`Tenant ${tenant.subdomain} is suspended: ${tenant.suspendedReason||"No reason provided"}`,statusCode:403};if(tenant.status==="provisioning")return{resolved:!1,error:`Tenant ${tenant.subdomain} is still being provisioned`,statusCode:503};if(tenant.status==="archived")return{resolved:!1,error:`Tenant ${tenant.subdomain} has been archived`,statusCode:410};let context=this.schemaContexts.get(tenant.schemaName);if(!context)return{resolved:!1,error:`Schema context not found for tenant: ${tenant.subdomain}`,statusCode:500};return{resolved:!0,context}}}var init_TenantRegistry=__esm(()=>{init_schema()});var init_Tenant=__esm(()=>{init_schema();init_TenantRegistry()});var init_types5=()=>{};import{and as and8,desc as desc2,eq as eq14,inArray as inArray2}from"drizzle-orm";function toCamel2(obj){let result={};for(let[key2,value]of Object.entries(obj)){let camelKey=key2.replace(/_([a-z])/g,(_,c)=>c.toUpperCase());result[camelKey]=value}return result}function fromCamel2(obj){let result={};for(let[key2,value]of Object.entries(obj)){let snakeKey=key2.replace(/[A-Z]/g,(c)=>`_${c.toLowerCase()}`);result[snakeKey]=value}return result}class VerificationService{db;schemaTables;config;logger;onNotificationTrigger;constructor(serviceConfig){this.db=serviceConfig.db,this.schemaTables=serviceConfig.schemaTables,this.config=serviceConfig.config,this.logger=serviceConfig.logger}setNotificationHandler(handler){this.onNotificationTrigger=handler}getConnectedNotificationNodeIds(stepNodeId,steps,edges){let result=new Set,getNeighbors=(nid)=>{let neighbors=[];for(let edge of edges){let{sourceNodeId:src,targetNodeId:tgt}=edge;if(src===nid)neighbors.push(tgt);else if(tgt===nid)neighbors.push(src)}return neighbors},directNeighbors=getNeighbors(stepNodeId);for(let neighborId of directNeighbors)if(steps.find((s)=>s.nodeId===neighborId)?.nodeType==="notification")result.add(neighborId);for(let neighborId of directNeighbors)if(steps.find((s)=>s.nodeId===neighborId)?.nodeType==="verifier"){let verifierNeighbors=getNeighbors(neighborId);for(let vNeighborId of verifierNeighbors){if(vNeighborId===stepNodeId)continue;if(steps.find((s)=>s.nodeId===vNeighborId)?.nodeType==="notification")result.add(vNeighborId)}}let ids=[...result];return this.logger.info(`[Verification] Connected notification nodes for step ${stepNodeId}: [${ids.join(", ")}]`),ids}getTable(name){return resolveSchemaTable(this.schemaTables,name,this.logger)}getCol(table,col7){return table[col7]}async listFlows(entityName){let flowsTable=this.getTable("verificationFlows");if(!flowsTable)return[];return(await(entityName?this.db.select().from(flowsTable).where(eq14(this.getCol(flowsTable,"entityName"),entityName)):this.db.select().from(flowsTable))).map((r)=>fromCamel2(r))}async getFlow(flowId){let flowsTable=this.getTable("verificationFlows"),stepsTable=this.getTable("verificationSteps"),edgesTable=this.getTable("verificationEdges"),verifierConfigsTable=this.getTable("verificationVerifierConfigs"),notifRulesTable=this.getTable("verificationNotificationRules"),notifRecipientsTable=this.getTable("verificationNotificationRecipients"),notifChannelsTable=this.getTable("verificationNotificationChannels");if(!flowsTable)return null;let flowRow=(await this.db.select().from(flowsTable).where(eq14(this.getCol(flowsTable,"id"),flowId)).limit(1))[0];if(!flowRow)return null;let flow=fromCamel2(flowRow),steps=(stepsTable?await this.db.select().from(stepsTable).where(eq14(this.getCol(stepsTable,"flowId"),flowId)):[]).map((r)=>fromCamel2(r)),edges=(edgesTable?await this.db.select().from(edgesTable).where(eq14(this.getCol(edgesTable,"flowId"),flowId)):[]).map((r)=>fromCamel2(r)),verifierConfigs=(verifierConfigsTable?await this.db.select().from(verifierConfigsTable).where(eq14(this.getCol(verifierConfigsTable,"flowId"),flowId)):[]).map((r)=>fromCamel2(r)),notifRules=(notifRulesTable?await this.db.select().from(notifRulesTable).where(eq14(this.getCol(notifRulesTable,"flowId"),flowId)):[]).map((r)=>fromCamel2(r)),ruleIds=notifRules.map((r)=>r.id),notifRecipients=(notifRecipientsTable&&ruleIds.length>0?await this.db.select().from(notifRecipientsTable).where(inArray2(this.getCol(notifRecipientsTable,"ruleId"),ruleIds)):[]).map((r)=>fromCamel2(r)),notifChannels=(notifChannelsTable&&ruleIds.length>0?await this.db.select().from(notifChannelsTable).where(inArray2(this.getCol(notifChannelsTable,"ruleId"),ruleIds)):[]).map((r)=>fromCamel2(r));return{flow,graph:{steps,edges,verifier_configs:verifierConfigs,notification_rules:notifRules,notification_recipients:notifRecipients,notification_channels:notifChannels}}}async saveFlow(params){let flowsTable=this.getTable("verificationFlows"),stepsTable=this.getTable("verificationSteps"),edgesTable=this.getTable("verificationEdges"),verifierConfigsTable=this.getTable("verificationVerifierConfigs"),notifRulesTable=this.getTable("verificationNotificationRules"),notifRecipientsTable=this.getTable("verificationNotificationRecipients"),notifChannelsTable=this.getTable("verificationNotificationChannels");if(!flowsTable||!stepsTable||!edgesTable)throw Error("Verification tables not configured");let existingFlows=await this.db.select().from(flowsTable).where(eq14(this.getCol(flowsTable,"id"),params.flow_id)).limit(1),flowId=params.flow_id;if(existingFlows.length>0)await this.db.update(flowsTable).set(toCamel2({entity_name:params.entity_name,name:params.name,description:params.description||null,trigger_on:params.trigger_on,trigger_fields:params.trigger_fields||null,is_draft:params.is_draft,viewport:params.viewport||null})).where(eq14(this.getCol(flowsTable,"id"),flowId));else{let[newFlow]=await this.db.insert(flowsTable).values(toCamel2({id:flowId,entity_name:params.entity_name,name:params.name,description:params.description||null,trigger_on:params.trigger_on,trigger_fields:params.trigger_fields||null,is_draft:params.is_draft,viewport:params.viewport||null})).returning();flowId=newFlow.id}if(await this.db.delete(stepsTable).where(eq14(this.getCol(stepsTable,"flowId"),flowId)),edgesTable)await this.db.delete(edgesTable).where(eq14(this.getCol(edgesTable,"flowId"),flowId));if(verifierConfigsTable)await this.db.delete(verifierConfigsTable).where(eq14(this.getCol(verifierConfigsTable,"flowId"),flowId));if(notifRulesTable){let oldRuleIds=(await this.db.select().from(notifRulesTable).where(eq14(this.getCol(notifRulesTable,"flowId"),flowId))).map((r)=>r.id);if(oldRuleIds.length>0){if(notifRecipientsTable)for(let rid of oldRuleIds)await this.db.delete(notifRecipientsTable).where(eq14(this.getCol(notifRecipientsTable,"ruleId"),rid));if(notifChannelsTable)for(let rid of oldRuleIds)await this.db.delete(notifChannelsTable).where(eq14(this.getCol(notifChannelsTable,"ruleId"),rid))}await this.db.delete(notifRulesTable).where(eq14(this.getCol(notifRulesTable,"flowId"),flowId))}let{graph}=params;if(graph.steps.length>0)await this.db.insert(stepsTable).values(graph.steps.map((s)=>toCamel2({flow_id:flowId,entity_name:params.entity_name,node_id:s.node_id,node_type:s.node_type,step_order:s.step_order,name:s.name||null,description:s.description||null,position_x:s.position_x,position_y:s.position_y,width:s.width||null,height:s.height||null,style:s.style||null,data:s.data||null})));if(graph.edges.length>0&&edgesTable)await this.db.insert(edgesTable).values(graph.edges.map((e)=>toCamel2({flow_id:flowId,edge_id:e.edge_id,source_node_id:e.source_node_id,target_node_id:e.target_node_id,source_handle:e.source_handle||null,target_handle:e.target_handle||null,edge_type:e.edge_type,label:e.label||null,condition:e.condition||null,style:e.style||null,animated:e.animated})));if(graph.verifier_configs.length>0&&verifierConfigsTable)await this.db.insert(verifierConfigsTable).values(graph.verifier_configs.map((vc)=>toCamel2({flow_id:flowId,node_id:vc.node_id,verifier_type:vc.verifier_type,verifier_user_id:vc.verifier_user_id||null,verifier_role:vc.verifier_role||null,require_signature:vc.require_signature,all_must_approve:vc.all_must_approve})));if(this.logger.info(`[Verification] Save: ${graph.notification_rules.length} rules, ${graph.notification_recipients.length} recipients, ${graph.notification_channels.length} channels`),graph.notification_rules.length>0&¬ifRulesTable)for(let rule of graph.notification_rules){this.logger.info(`[Verification] Saving notification rule: node_id=${rule.node_id}, trigger=${rule.trigger}, title_template=${JSON.stringify(rule.title_template)}, body_template=${JSON.stringify(rule.body_template)}`);let[insertedRule]=await this.db.insert(notifRulesTable).values(toCamel2({flow_id:flowId,node_id:rule.node_id,trigger:rule.trigger,title_template:rule.title_template||null,body_template:rule.body_template||null,starts_at:rule.starts_at||null,expires_at:rule.expires_at||null})).returning(),ruleId=insertedRule.id,ruleRecipients=graph.notification_recipients.filter((r)=>r.rule_id===rule.node_id);if(ruleRecipients.length>0&¬ifRecipientsTable)await this.db.insert(notifRecipientsTable).values(ruleRecipients.map((r)=>toCamel2({rule_id:ruleId,recipient_type:r.recipient_type,recipient_user_id:r.recipient_user_id||null,recipient_role:r.recipient_role||null})));let ruleChannels=graph.notification_channels.filter((c)=>c.rule_id===rule.node_id);if(ruleChannels.length>0&¬ifChannelsTable)await this.db.insert(notifChannelsTable).values(ruleChannels.map((c)=>toCamel2({rule_id:ruleId,channel:c.channel})))}return this.logger.info(`[Verification] Flow saved: ${flowId} for ${params.entity_name}`),{success:!0,flow_id:flowId}}async publishFlow(flowId){let flowsTable=this.getTable("verificationFlows");if(!flowsTable)return{success:!1,message:"Flow table not configured"};return await this.db.update(flowsTable).set(toCamel2({is_draft:!1,published_at:new Date})).where(eq14(this.getCol(flowsTable,"id"),flowId)),this.logger.info(`[Verification] Flow published: ${flowId}`),{success:!0,message:"Flow published"}}async deleteFlow(flowId){let flowsTable=this.getTable("verificationFlows");if(!flowsTable)return{success:!1,message:"Flow table not configured"};return await this.db.delete(flowsTable).where(eq14(this.getCol(flowsTable,"id"),flowId)),this.logger.info(`[Verification] Flow deleted: ${flowId}`),{success:!0,message:"Flow deleted"}}async startFlow(params){let flowsTable=this.getTable("verificationFlows"),stepsTable=this.getTable("verificationSteps"),edgesTable=this.getTable("verificationEdges"),verifierConfigsTable=this.getTable("verificationVerifierConfigs"),instancesTable=this.getTable("verificationInstances"),requirementsTable=this.getTable("verificationRequirements"),userRolesTable=this.getTable("userRoles");if(!flowsTable||!stepsTable||!edgesTable||!instancesTable||!requirementsTable)return{success:!1,message:"Verification tables not configured"};let flow=(await this.db.select().from(flowsTable).where(and8(eq14(this.getCol(flowsTable,"id"),params.flow_id),eq14(this.getCol(flowsTable,"isDraft"),!1))).limit(1))[0];if(!flow)return{success:!1,message:"Published flow not found"};if((await this.db.select().from(instancesTable).where(and8(eq14(this.getCol(instancesTable,"entityName"),params.entity_name),eq14(this.getCol(instancesTable,"entityId"),params.entity_id),eq14(this.getCol(instancesTable,"status"),"active"))).limit(1)).length>0)return{success:!1,message:"An active verification instance already exists for this entity"};let steps=await this.db.select().from(stepsTable).where(eq14(this.getCol(stepsTable,"flowId"),params.flow_id)),edges=await this.db.select().from(edgesTable).where(eq14(this.getCol(edgesTable,"flowId"),params.flow_id)),stepNodes=steps.filter((s)=>s.nodeType==="step");if(stepNodes.sort((a,b)=>a.stepOrder-b.stepOrder),stepNodes.length===0)return{success:!1,message:"Flow has no step nodes"};let[instance]=await this.db.insert(instancesTable).values(toCamel2({flow_id:params.flow_id,entity_name:params.entity_name,entity_id:params.entity_id,started_by:params.started_by||null,status:"active",current_step_order:1,started_at:new Date})).returning(),instanceId=instance.id;if(await this.materializeRequirementsForStep(instanceId,params.flow_id,params.entity_name,params.entity_id,1,steps,edges,verifierConfigsTable,requirementsTable,userRolesTable),this.onNotificationTrigger){let firstStep=stepNodes[0],firstStepNodeId=firstStep?.nodeId,connectedNotifIds=firstStepNodeId?this.getConnectedNotificationNodeIds(firstStepNodeId,steps,edges):[],ctx={flow_name:flow.name,step_name:firstStep?.name||"Step 1",step_order:1,total_steps:stepNodes.length};if(connectedNotifIds.length>0)for(let notifNodeId of connectedNotifIds)await this.onNotificationTrigger({trigger:"on_flow_started",flow_id:params.flow_id,entity_name:params.entity_name,entity_id:params.entity_id,node_id:notifNodeId,context:ctx});else await this.onNotificationTrigger({trigger:"on_flow_started",flow_id:params.flow_id,entity_name:params.entity_name,entity_id:params.entity_id,context:ctx})}return this.logger.info(`[Verification] Flow started: instance ${instanceId} for ${params.entity_name}:${params.entity_id}`),{success:!0,instance_id:instanceId,message:"Flow started"}}async materializeRequirementsForStep(instanceId,flowId,entityName,entityId,stepOrder,steps,edges,verifierConfigsTable,requirementsTable,userRolesTable){if(!requirementsTable)return;let stepNode=steps.find((s)=>s.nodeType==="step"&&s.stepOrder===stepOrder);if(!stepNode)return;let stepNodeId=stepNode.nodeId,verifierNodeIds=edges.filter((e)=>e.targetNodeId===stepNodeId).map((e)=>e.sourceNodeId),verifierNodes=steps.filter((s)=>s.nodeType==="verifier"&&verifierNodeIds.includes(s.nodeId));if(verifierNodes.length===0)return;let verifierConfigs=[];if(verifierConfigsTable)verifierConfigs=await this.db.select().from(verifierConfigsTable).where(eq14(this.getCol(verifierConfigsTable,"flowId"),flowId));for(let verifierNode of verifierNodes){let nodeId=verifierNode.nodeId,config=verifierConfigs.find((vc)=>vc.nodeId===nodeId);if(!config)continue;let{verifierType,allMustApprove}=config;if(verifierType==="role"&&allMustApprove&&userRolesTable){let rolesTable=this.getTable("roles");if(rolesTable){let rolesCols=rolesTable,userRolesCols=userRolesTable,role=(await this.db.select().from(rolesTable).where(eq14(rolesCols.name,config.verifierRole)).limit(1))[0];if(role){let usersWithRole=await this.db.select({user_id:userRolesCols.userId}).from(userRolesTable).where(eq14(userRolesCols.roleId,role.id));for(let userRole of usersWithRole)await this.db.insert(requirementsTable).values(toCamel2({instance_id:instanceId,step_node_id:stepNodeId,verifier_node_id:nodeId,entity_name:entityName,entity_id:entityId,verifier_type:"user",verifier_user_id:userRole.user_id,verifier_role:config.verifierRole||null,require_signature:config.requireSignature,all_must_approve:!0,step_order:stepOrder,status:"pending"}))}}}else await this.db.insert(requirementsTable).values(toCamel2({instance_id:instanceId,step_node_id:stepNodeId,verifier_node_id:nodeId,entity_name:entityName,entity_id:entityId,verifier_type:verifierType,verifier_user_id:config.verifierUserId||null,verifier_role:config.verifierRole||null,require_signature:config.requireSignature,all_must_approve:allMustApprove,step_order:stepOrder,status:"pending"}))}if(this.onNotificationTrigger){let connectedNotifIds=this.getConnectedNotificationNodeIds(stepNodeId,steps,edges);if(this.logger.info(`[Verification] on_step_reached: stepNodeId=${stepNodeId}, connectedNotifIds=[${connectedNotifIds.join(", ")}]`),connectedNotifIds.length>0)for(let notifNodeId of connectedNotifIds)this.logger.info(`[Verification] Triggering on_step_reached for notifNodeId=${notifNodeId}`),await this.onNotificationTrigger({trigger:"on_step_reached",flow_id:flowId,entity_name:entityName,entity_id:entityId,node_id:notifNodeId,context:{step_name:stepNode.name||`Step ${stepOrder}`,step_order:stepOrder}});else await this.onNotificationTrigger({trigger:"on_step_reached",flow_id:flowId,entity_name:entityName,entity_id:entityId,context:{step_name:stepNode.name||`Step ${stepOrder}`,step_order:stepOrder}})}}async getStatus(entityName,entityId){let instancesTable=this.getTable("verificationInstances"),flowsTable=this.getTable("verificationFlows"),stepsTable=this.getTable("verificationSteps"),verificationsTable=this.getTable("verifications"),requirementsTable=this.getTable("verificationRequirements"),emptyStatus={entity_name:entityName,entity_id:entityId,instance:null,flow:null,current_step:0,total_steps:0,is_completed:!1,is_rejected:!1,verifications:[],pending_requirements:[]};if(!instancesTable||!flowsTable||!verificationsTable||!requirementsTable)return this.logger.error("[Verification] Required tables not found"),emptyStatus;let instanceRow=(await this.db.select().from(instancesTable).where(and8(eq14(this.getCol(instancesTable,"entityName"),entityName),eq14(this.getCol(instancesTable,"entityId"),entityId))).orderBy(desc2(this.getCol(instancesTable,"createdAt"))).limit(1))[0];if(!instanceRow)return emptyStatus;let instance=fromCamel2(instanceRow),flows=await this.db.select().from(flowsTable).where(eq14(this.getCol(flowsTable,"id"),instance.flow_id)).limit(1),flow=flows[0]?fromCamel2(flows[0]):void 0,totalSteps=(stepsTable?await this.db.select().from(stepsTable).where(and8(eq14(this.getCol(stepsTable,"flowId"),instance.flow_id),eq14(this.getCol(stepsTable,"nodeType"),"step"))):[]).length,verifications=(await this.db.select().from(verificationsTable).where(eq14(this.getCol(verificationsTable,"instanceId"),instance.id)).orderBy(desc2(this.getCol(verificationsTable,"createdAt")))).map((r)=>fromCamel2(r)),pendingRequirements=(await this.db.select().from(requirementsTable).where(and8(eq14(this.getCol(requirementsTable,"instanceId"),instance.id),eq14(this.getCol(requirementsTable,"status"),"pending")))).map((r)=>fromCamel2(r));return{entity_name:entityName,entity_id:entityId,instance,flow:flow||null,current_step:instance.current_step_order,total_steps:totalSteps,is_completed:instance.status==="completed",is_rejected:instance.status==="rejected",verifications,pending_requirements:pendingRequirements}}async decide(params){let{entity_name,entity_id,user_id,decision,reason,signature_id,diff}=params,verificationsTable=this.getTable("verifications"),requirementsTable=this.getTable("verificationRequirements"),instancesTable=this.getTable("verificationInstances"),stepsTable=this.getTable("verificationSteps"),edgesTable=this.getTable("verificationEdges"),verifierConfigsTable=this.getTable("verificationVerifierConfigs"),userRolesTable=this.getTable("userRoles"),rolesTable=this.getTable("roles");if(!verificationsTable||!requirementsTable||!instancesTable)return{success:!1,message:"Verification tables not configured"};let status=await this.getStatus(entity_name,entity_id);if(!status.instance||status.instance.status!=="active")return{success:!1,message:"No active verification instance"};let currentPending=status.pending_requirements.filter((r)=>r.step_order===status.current_step);if(currentPending.length===0)return{success:!1,message:"No pending requirements for current step"};let matchedReq=null;for(let req of currentPending){if(req.verifier_type==="user"&&req.verifier_user_id===user_id){matchedReq=req;break}if(req.verifier_type==="role"&&req.verifier_role&&userRolesTable&&rolesTable){let userRolesCols=userRolesTable,rolesCols=rolesTable;if((await this.db.select({role_name:rolesCols.name}).from(userRolesTable).innerJoin(rolesTable,eq14(userRolesCols.roleId,rolesCols.id)).where(eq14(userRolesCols.userId,user_id))).some((ur)=>ur.role_name===req.verifier_role)){matchedReq=req;break}}}if(!matchedReq)return{success:!1,message:"User is not authorized to verify at this step"};if(matchedReq.require_signature){if(!signature_id)return{success:!1,message:"Signature is required for this verification step"};let filesTable=resolveSchemaTable(this.schemaTables,"files",this.logger);if(filesTable){if((await this.db.select().from(filesTable).where(and8(eq14(this.getCol(filesTable,"id"),signature_id),eq14(this.getCol(filesTable,"uploadedBy"),user_id))).limit(1)).length===0)return{success:!1,message:"Signature file not found or not owned by the verifier"}}}if((await this.db.update(requirementsTable).set({status:decision}).where(and8(eq14(this.getCol(requirementsTable,"id"),matchedReq.id),eq14(this.getCol(requirementsTable,"status"),"pending"))).returning()).length===0)return{success:!1,message:"This requirement has already been decided"};let[newVerification]=await this.db.insert(verificationsTable).values(toCamel2({instance_id:status.instance.id,requirement_id:matchedReq.id,verifier_id:user_id,signature_id:signature_id||null,entity_name,entity_id,step_order:status.current_step,decision,reason:reason||null,diff:diff||null})).returning();if(this.onNotificationTrigger&&status.instance){let stepName=`Step ${status.current_step}`,allSteps=[],allEdges=[];if(stepsTable){allSteps=await this.db.select().from(stepsTable).where(eq14(this.getCol(stepsTable,"flowId"),status.instance.flow_id));let stepRow=allSteps.find((s)=>s.nodeId===matchedReq.step_node_id);if(stepRow?.name)stepName=stepRow.name}if(edgesTable)allEdges=await this.db.select().from(edgesTable).where(eq14(this.getCol(edgesTable,"flowId"),status.instance.flow_id));let triggerName=decision==="approved"?"on_approved":"on_rejected",ctx={flow_name:status.flow?.name||"",step_name:stepName,step_order:status.current_step,total_steps:status.total_steps,decision},connectedNotifIds=this.getConnectedNotificationNodeIds(matchedReq.step_node_id,allSteps,allEdges);if(connectedNotifIds.length>0)for(let notifNodeId of connectedNotifIds)await this.onNotificationTrigger({trigger:triggerName,flow_id:status.instance.flow_id,entity_name,entity_id,node_id:notifNodeId,verifier_id:user_id,decision,context:ctx});else await this.onNotificationTrigger({trigger:triggerName,flow_id:status.instance.flow_id,entity_name,entity_id,verifier_id:user_id,decision,context:ctx})}if(decision==="rejected"){await this.db.update(instancesTable).set(toCamel2({status:"rejected",completed_at:new Date})).where(eq14(this.getCol(instancesTable,"id"),status.instance.id));let newInstanceId;if(this.config.autoResetOnRejection){this.logger.info(`[Verification] Flow rejected for ${entity_name}:${entity_id}, auto-restarting from step 1`);let restartResult=await this.startFlow({flow_id:status.instance.flow_id,entity_name,entity_id,started_by:status.instance.started_by});if(restartResult.success)newInstanceId=restartResult.instance_id}return{success:!0,message:this.config.autoResetOnRejection?"Verification rejected \u2014 flow restarted from step 1":"Verification rejected",verification:newVerification,flow_completed:!1,new_instance_id:newInstanceId}}let matchedReqId=matchedReq.id,remainingPending=currentPending.filter((r)=>r.id!==matchedReqId);if(remainingPending.length>0)return{success:!0,message:`Step ${status.current_step} partially approved, ${remainingPending.length} verifier(s) remaining`,verification:newVerification,flow_completed:!1};let nextStep=status.current_step+1;if(nextStep>status.total_steps){if(await this.db.update(instancesTable).set(toCamel2({status:"completed",completed_at:new Date})).where(eq14(this.getCol(instancesTable,"id"),status.instance.id)),this.onNotificationTrigger){let completedSteps=[],completedEdges=[];if(stepsTable)completedSteps=await this.db.select().from(stepsTable).where(eq14(this.getCol(stepsTable,"flowId"),status.instance.flow_id));if(edgesTable)completedEdges=await this.db.select().from(edgesTable).where(eq14(this.getCol(edgesTable,"flowId"),status.instance.flow_id));let lastStepNodeId=matchedReq.step_node_id,completedNotifIds=this.getConnectedNotificationNodeIds(lastStepNodeId,completedSteps,completedEdges),completedCtx={flow_name:status.flow?.name||"",step_order:status.current_step,total_steps:status.total_steps};if(completedNotifIds.length>0)for(let notifNodeId of completedNotifIds)await this.onNotificationTrigger({trigger:"on_flow_completed",flow_id:status.instance.flow_id,entity_name,entity_id,node_id:notifNodeId,context:completedCtx});else await this.onNotificationTrigger({trigger:"on_flow_completed",flow_id:status.instance.flow_id,entity_name,entity_id,context:completedCtx})}return{success:!0,message:"Verification flow completed",verification:newVerification,flow_completed:!0}}if(await this.db.update(instancesTable).set(toCamel2({current_step_order:nextStep})).where(eq14(this.getCol(instancesTable,"id"),status.instance.id)),stepsTable&&edgesTable){let steps=await this.db.select().from(stepsTable).where(eq14(this.getCol(stepsTable,"flowId"),status.instance.flow_id)),edges=await this.db.select().from(edgesTable).where(eq14(this.getCol(edgesTable,"flowId"),status.instance.flow_id));await this.materializeRequirementsForStep(status.instance.id,status.instance.flow_id,entity_name,entity_id,nextStep,steps,edges,verifierConfigsTable,requirementsTable,userRolesTable)}return{success:!0,message:`Step ${status.current_step} approved, moving to step ${nextStep}`,verification:newVerification,flow_completed:!1,next_step:nextStep}}async startFlowForEntity(params){let flowsTable=this.getTable("verificationFlows");if(!flowsTable)return{success:!1,message:"Flow table not configured"};let flow=(await this.db.select().from(flowsTable).where(and8(eq14(this.getCol(flowsTable,"entityName"),params.entity_name),eq14(this.getCol(flowsTable,"isDraft"),!1))).limit(1))[0];if(!flow)return{success:!1,message:`No published flow found for entity '${params.entity_name}'`};return this.startFlow({flow_id:flow.id,entity_name:params.entity_name,entity_id:params.entity_id,started_by:params.started_by})}async listEntityStatuses(params){let instancesTable=this.getTable("verificationInstances"),flowsTable=this.getTable("verificationFlows"),stepsTable=this.getTable("verificationSteps"),emptyResult={items:[],total:0,page:1,limit:20};if(!instancesTable||!flowsTable)return emptyResult;let page=params.page||1,limit=params.limit||20,offset=(page-1)*limit,conditions=[eq14(this.getCol(instancesTable,"entityName"),params.entity_name)];if(params.status)conditions.push(eq14(this.getCol(instancesTable,"status"),params.status));let whereClause=conditions.length===1?conditions[0]:and8(...conditions),allInstances=(await this.db.select().from(instancesTable).where(whereClause).orderBy(desc2(this.getCol(instancesTable,"createdAt")))).map((r)=>fromCamel2(r)),total=allInstances.length,paged=allInstances.slice(offset,offset+limit),items=[];for(let inst of paged){let flowId=inst.flow_id,flows=await this.db.select().from(flowsTable).where(eq14(this.getCol(flowsTable,"id"),flowId)).limit(1),flow=flows[0]?fromCamel2(flows[0]):void 0,totalSteps=0;if(stepsTable)totalSteps=(await this.db.select().from(stepsTable).where(and8(eq14(this.getCol(stepsTable,"flowId"),flowId),eq14(this.getCol(stepsTable,"nodeType"),"step")))).length;items.push({instance_id:inst.id,entity_name:inst.entity_name,entity_id:inst.entity_id,flow_id:flowId,flow_name:flow?.name||"Unknown",status:inst.status,current_step_order:inst.current_step_order,total_steps:totalSteps,started_by:inst.started_by,started_at:inst.started_at,completed_at:inst.completed_at})}return{items,total,page,limit}}async getPending(userId){let requirementsTable=this.getTable("verificationRequirements"),instancesTable=this.getTable("verificationInstances"),flowsTable=this.getTable("verificationFlows"),stepsTable=this.getTable("verificationSteps"),userRolesTable=this.getTable("userRoles"),rolesTable=this.getTable("roles");if(this.logger.info(`[Verification.getPending] userId=${userId}, tables: req=${!!requirementsTable} inst=${!!instancesTable} flow=${!!flowsTable} steps=${!!stepsTable} roles=${!!rolesTable} userRoles=${!!userRolesTable}`),!requirementsTable||!instancesTable||!flowsTable)return this.logger.warn("[Verification.getPending] Missing required tables, returning empty"),[];let userRolesCols=userRolesTable,rolesCols=rolesTable,userRoleNames=(userRolesTable&&rolesTable?await this.db.select({role_name:rolesCols.name}).from(userRolesTable).innerJoin(rolesTable,eq14(userRolesCols.roleId,rolesCols.id)).where(eq14(userRolesCols.userId,userId)):[]).map((ur)=>ur.role_name),pendingReqs=(await this.db.select().from(requirementsTable).where(eq14(this.getCol(requirementsTable,"status"),"pending"))).map((r)=>fromCamel2(r));this.logger.info(`[Verification.getPending] Found ${pendingReqs.length} pending requirements, userRoles=${JSON.stringify(userRoleNames)}`);for(let req of pendingReqs)this.logger.info(`[Verification.getPending] Req: verifier_type=${req.verifier_type} verifier_user_id=${req.verifier_user_id} verifier_role=${req.verifier_role} step_order=${req.step_order} entity=${req.entity_name}/${req.entity_id}`);let pendingItems=[];for(let req of pendingReqs){if(!(req.verifier_type==="user"&&req.verifier_user_id===userId||req.verifier_type==="role"&&userRoleNames.includes(req.verifier_role))){this.logger.info(`[Verification.getPending] Skipping req: canVerify=false (type=${req.verifier_type}, reqUserId=${req.verifier_user_id}, loggedInUserId=${userId})`);continue}let instances=await this.db.select().from(instancesTable).where(and8(eq14(this.getCol(instancesTable,"id"),req.instance_id),eq14(this.getCol(instancesTable,"status"),"active"))).limit(1),instance=instances[0]?fromCamel2(instances[0]):void 0;if(!instance)continue;if(instance.current_step_order!==req.step_order)continue;let flows=await this.db.select().from(flowsTable).where(eq14(this.getCol(flowsTable,"id"),instance.flow_id)).limit(1),flow=flows[0]?fromCamel2(flows[0]):void 0;if(!flow)continue;let stepName;if(stepsTable&&req.step_node_id){let stepRow=(await this.db.select().from(stepsTable).where(and8(eq14(this.getCol(stepsTable,"flowId"),instance.flow_id),eq14(this.getCol(stepsTable,"nodeId"),req.step_node_id))).limit(1))[0];if(stepRow?.name)stepName=stepRow.name}pendingItems.push({instance_id:instance.id,entity_name:req.entity_name,entity_id:req.entity_id,flow_name:flow.name,step_order:req.step_order,step_name:stepName,require_signature:req.require_signature,created_at:req.created_at})}return pendingItems}}var init_Verification=__esm(()=>{init_types5()});var genLookup=(target)=>{let lookupTemp=typeof Uint8Array>"u"?[]:new Uint8Array(256),len=64;for(let i=0;i<64;i++)lookupTemp[target.charCodeAt(i)]=i;return lookupTemp},lookup,lookupUrl,base64UrlPattern,base64Pattern,base64,base64_default;var init_base64=__esm(()=>{lookup=genLookup("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"),lookupUrl=genLookup("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"),base64UrlPattern=/^[-A-Za-z0-9\-_]*$/,base64Pattern=/^[-A-Za-z0-9+/]*={0,3}$/,base64={};base64.toArrayBuffer=(data,urlMode)=>{let len=data.length,bufferLength=data.length*0.75,i,p=0,encoded1,encoded2,encoded3,encoded4;if(data[data.length-1]==="="){if(bufferLength--,data[data.length-2]==="=")bufferLength--}let arraybuffer=new ArrayBuffer(bufferLength),bytes=new Uint8Array(arraybuffer),target=urlMode?lookupUrl:lookup;for(i=0;i<len;i+=4)encoded1=target[data.charCodeAt(i)],encoded2=target[data.charCodeAt(i+1)],encoded3=target[data.charCodeAt(i+2)],encoded4=target[data.charCodeAt(i+3)],bytes[p++]=encoded1<<2|encoded2>>4,bytes[p++]=(encoded2&15)<<4|encoded3>>2,bytes[p++]=(encoded3&3)<<6|encoded4&63;return arraybuffer};base64.fromArrayBuffer=(arrBuf,urlMode)=>{let bytes=new Uint8Array(arrBuf),i,result="",len=bytes.length,target=urlMode?"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_":"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";for(i=0;i<len;i+=3)result+=target[bytes[i]>>2],result+=target[(bytes[i]&3)<<4|bytes[i+1]>>4],result+=target[(bytes[i+1]&15)<<2|bytes[i+2]>>6],result+=target[bytes[i+2]&63];let remainder=len%3;if(remainder===2)result=result.substring(0,result.length-1)+(urlMode?"":"=");else if(remainder===1)result=result.substring(0,result.length-2)+(urlMode?"":"==");return result};base64.toString=(str3,urlMode)=>{return new TextDecoder().decode(base64.toArrayBuffer(str3,urlMode))};base64.fromString=(str3,urlMode)=>{return base64.fromArrayBuffer(new TextEncoder().encode(str3),urlMode)};base64.validate=(encoded,urlMode)=>{if(!(typeof encoded==="string"||encoded instanceof String))return!1;try{return urlMode?base64UrlPattern.test(encoded):base64Pattern.test(encoded)}catch(_e){return!1}};base64.base64=base64;base64_default=base64});var exports_isoBase64URL={};__export(exports_isoBase64URL,{trimPadding:()=>trimPadding,toUTF8String:()=>toUTF8String,toBuffer:()=>toBuffer,toBase64:()=>toBase64,isBase64URL:()=>isBase64URL,isBase64:()=>isBase64,fromUTF8String:()=>fromUTF8String,fromBuffer:()=>fromBuffer});function toBuffer(base64urlString,from="base64url"){let _buffer=base64_default.toArrayBuffer(base64urlString,from==="base64url");return new Uint8Array(_buffer)}function fromBuffer(buffer,to="base64url"){let _normalized=new Uint8Array(buffer);return base64_default.fromArrayBuffer(_normalized.buffer,to==="base64url")}function toBase64(base64urlString){let fromBase64Url=base64_default.toArrayBuffer(base64urlString,!0);return base64_default.fromArrayBuffer(fromBase64Url)}function fromUTF8String(utf8String){return base64_default.fromString(utf8String,!0)}function toUTF8String(base64urlString){return base64_default.toString(base64urlString,!0)}function isBase64(input){return base64_default.validate(input,!1)}function isBase64URL(input){return input=trimPadding(input),base64_default.validate(input,!0)}function trimPadding(input){return input.replace(/=/g,"")}var init_isoBase64URL=__esm(()=>{init_base64()});function decodeLength(data,argument,index){if(argument<24)return[argument,1];let remainingDataLength=data.byteLength-index-1,view=new DataView(data.buffer,index+1),output,bytes=0;switch(argument){case 24:{if(remainingDataLength>0)output=view.getUint8(0),bytes=2;break}case 25:{if(remainingDataLength>1)output=view.getUint16(0,!1),bytes=3;break}case 26:{if(remainingDataLength>3)output=view.getUint32(0,!1),bytes=5;break}case 27:{if(remainingDataLength>7){let bigOutput=view.getBigUint64(0,!1);if(bigOutput>=24n&&bigOutput<=Number.MAX_SAFE_INTEGER)return[Number(bigOutput),9]}break}}if(output&&output>=24)return[output,bytes];throw Error("Length not supported or not well formed")}function encodeLength(major,argument){let majorEncoded=major<<5;if(argument<0)throw Error("CBOR Data Item argument must not be negative");let bigintArgument;if(typeof argument=="number"){if(!Number.isInteger(argument))throw Error("CBOR Data Item argument must be an integer");bigintArgument=BigInt(argument)}else bigintArgument=argument;if(major==MAJOR_TYPE_NEGATIVE_INTEGER){if(bigintArgument==0n)throw Error("CBOR Data Item argument cannot be zero when negative");bigintArgument=bigintArgument-1n}if(bigintArgument>18446744073709551615n)throw Error("CBOR number out of range");let buffer=new Uint8Array(8);if(new DataView(buffer.buffer).setBigUint64(0,bigintArgument,!1),bigintArgument<=23)return[majorEncoded|buffer[7]];else if(bigintArgument<=255)return[majorEncoded|24,buffer[7]];else if(bigintArgument<=65535)return[majorEncoded|25,...buffer.slice(6)];else if(bigintArgument<=4294967295)return[majorEncoded|26,...buffer.slice(4)];else return[majorEncoded|27,...buffer]}var MAJOR_TYPE_UNSIGNED_INTEGER=0,MAJOR_TYPE_NEGATIVE_INTEGER=1,MAJOR_TYPE_BYTE_STRING=2,MAJOR_TYPE_TEXT_STRING=3,MAJOR_TYPE_ARRAY=4,MAJOR_TYPE_MAP=5,MAJOR_TYPE_TAG=6,MAJOR_TYPE_SIMPLE_OR_FLOAT=7;class CBORTag{constructor(tag,value){Object.defineProperty(this,"tagId",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"tagValue",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.tagId=tag,this.tagValue=value}get tag(){return this.tagId}get value(){return this.tagValue}}function decodeUnsignedInteger(data,argument,index){return decodeLength(data,argument,index)}function decodeNegativeInteger(data,argument,index){let[value,length]=decodeUnsignedInteger(data,argument,index);return[-value-1,length]}function decodeByteString(data,argument,index){let[lengthValue,lengthConsumed]=decodeLength(data,argument,index),dataStartIndex=index+lengthConsumed;return[new Uint8Array(data.buffer.slice(dataStartIndex,dataStartIndex+lengthValue)),lengthConsumed+lengthValue]}function decodeString(data,argument,index){let[value,length]=decodeByteString(data,argument,index);return[TEXT_DECODER.decode(value),length]}function decodeArray(data,argument,index){if(argument===0)return[[],1];let[length,lengthConsumed]=decodeLength(data,argument,index),consumedLength=lengthConsumed,value=[];for(let i=0;i<length;i++){if(data.byteLength-index-consumedLength<=0)throw Error("array is not supported or well formed");let[decodedValue,consumed]=decodeNext(data,index+consumedLength);value.push(decodedValue),consumedLength+=consumed}return[value,consumedLength]}function decodeMap(data,argument,index){if(argument===0)return[new Map,1];let[length,lengthConsumed]=decodeLength(data,argument,index),consumedLength=lengthConsumed,result=new Map;for(let i=0;i<length;i++){let remainingDataLength=data.byteLength-index-consumedLength;if(remainingDataLength<=0)throw Error(MAP_ERROR);let[key2,keyConsumed]=decodeNext(data,index+consumedLength);if(consumedLength+=keyConsumed,remainingDataLength-=keyConsumed,remainingDataLength<=0)throw Error(MAP_ERROR);if(typeof key2!=="string"&&typeof key2!=="number")throw Error(MAP_ERROR);if(result.has(key2))throw Error(MAP_ERROR);let[value,valueConsumed]=decodeNext(data,index+consumedLength);consumedLength+=valueConsumed,result.set(key2,value)}return[result,consumedLength]}function decodeFloat16(data,index){if(index+3>data.byteLength)throw Error("CBOR stream ended before end of Float 16");let result=data.getUint16(index+1,!1);if(result==31744)return[1/0,3];else if(result==32256)return[NaN,3];else if(result==64512)return[-1/0,3];throw Error("Float16 data is unsupported")}function decodeFloat32(data,index){if(index+5>data.byteLength)throw Error("CBOR stream ended before end of Float 32");return[data.getFloat32(index+1,!1),5]}function decodeFloat64(data,index){if(index+9>data.byteLength)throw Error("CBOR stream ended before end of Float 64");return[data.getFloat64(index+1,!1),9]}function decodeTag(data,argument,index){let[tag,tagBytes]=decodeLength(data,argument,index),[value,valueBytes]=decodeNext(data,index+tagBytes);return[new CBORTag(tag,value),tagBytes+valueBytes]}function decodeNext(data,index){if(index>=data.byteLength)throw Error("CBOR stream ended before tag value");let byte=data.getUint8(index),majorType=byte>>5,argument=byte&31;switch(majorType){case MAJOR_TYPE_UNSIGNED_INTEGER:return decodeUnsignedInteger(data,argument,index);case MAJOR_TYPE_NEGATIVE_INTEGER:return decodeNegativeInteger(data,argument,index);case MAJOR_TYPE_BYTE_STRING:return decodeByteString(data,argument,index);case MAJOR_TYPE_TEXT_STRING:return decodeString(data,argument,index);case MAJOR_TYPE_ARRAY:return decodeArray(data,argument,index);case MAJOR_TYPE_MAP:return decodeMap(data,argument,index);case MAJOR_TYPE_TAG:return decodeTag(data,argument,index);case MAJOR_TYPE_SIMPLE_OR_FLOAT:switch(argument){case 20:return[!1,1];case 21:return[!0,1];case 22:return[null,1];case 23:return[void 0,1];case 25:return decodeFloat16(data,index);case 26:return decodeFloat32(data,index);case 27:return decodeFloat64(data,index)}}throw Error(`Unsupported or not well formed at ${index}`)}function encodeSimple(data){if(data===!0)return 245;else if(data===!1)return 244;else if(data===null)return 246;return 247}function encodeFloat(data){if(Math.fround(data)==data||!Number.isFinite(data)||Number.isNaN(data)){let output=new Uint8Array(5);return output[0]=250,new DataView(output.buffer).setFloat32(1,data,!1),output}else{let output=new Uint8Array(9);return output[0]=251,new DataView(output.buffer).setFloat64(1,data,!1),output}}function encodeNumber(data){if(typeof data=="number"){if(Number.isSafeInteger(data))if(data<0)return encodeLength(MAJOR_TYPE_NEGATIVE_INTEGER,Math.abs(data));else return encodeLength(MAJOR_TYPE_UNSIGNED_INTEGER,data);return[encodeFloat(data)]}else if(data<0n)return encodeLength(MAJOR_TYPE_NEGATIVE_INTEGER,data*-1n);else return encodeLength(MAJOR_TYPE_UNSIGNED_INTEGER,data)}function encodeString(data,output){output.push(...encodeLength(MAJOR_TYPE_TEXT_STRING,data.length)),output.push(ENCODER.encode(data))}function encodeBytes(data,output){output.push(...encodeLength(MAJOR_TYPE_BYTE_STRING,data.length)),output.push(data)}function encodeArray(data,output){output.push(...encodeLength(MAJOR_TYPE_ARRAY,data.length));for(let element of data)encodePartialCBOR(element,output)}function encodeMap(data,output){output.push(new Uint8Array(encodeLength(MAJOR_TYPE_MAP,data.size)));for(let[key2,value]of data.entries())encodePartialCBOR(key2,output),encodePartialCBOR(value,output)}function encodeTag(tag,output){output.push(...encodeLength(MAJOR_TYPE_TAG,tag.tag)),encodePartialCBOR(tag.value,output)}function encodePartialCBOR(data,output){if(typeof data=="boolean"||data===null||data==null){output.push(encodeSimple(data));return}if(typeof data=="number"||typeof data=="bigint"){output.push(...encodeNumber(data));return}if(typeof data=="string"){encodeString(data,output);return}if(data instanceof Uint8Array){encodeBytes(data,output);return}if(Array.isArray(data)){encodeArray(data,output);return}if(data instanceof Map){encodeMap(data,output);return}if(data instanceof CBORTag){encodeTag(data,output);return}throw Error("Not implemented")}function decodePartialCBOR(data,index){if(data.byteLength===0||data.byteLength<=index||index<0)throw Error("No data");if(data instanceof Uint8Array)return decodeNext(new DataView(data.buffer),index);else if(data instanceof ArrayBuffer)return decodeNext(new DataView(data),index);return decodeNext(data,index)}function encodeCBOR(data){let results=[];encodePartialCBOR(data,results);let length=0;for(let result of results)if(typeof result=="number")length+=1;else length+=result.length;let output=new Uint8Array(length),index=0;for(let result of results)if(typeof result=="number")output[index]=result,index+=1;else output.set(result,index),index+=result.length;return output}var TEXT_DECODER,MAP_ERROR="Map is not supported or well formed",ENCODER;var init_cbor=__esm(()=>{TEXT_DECODER=new TextDecoder;ENCODER=new TextEncoder});var init_esm=__esm(()=>{init_cbor()});var exports_isoCBOR={};__export(exports_isoCBOR,{encode:()=>encode,decodeFirst:()=>decodeFirst});function decodeFirst(input){let _input=new Uint8Array(input),decoded=decodePartialCBOR(_input,0),[first]=decoded;return first}function encode(input){return encodeCBOR(input)}var init_isoCBOR=__esm(()=>{init_esm()});function isCOSEPublicKeyOKP(cosePublicKey){let kty=cosePublicKey.get(COSEKEYS.kty);return isCOSEKty(kty)&&kty===COSEKTY.OKP}function isCOSEPublicKeyEC2(cosePublicKey){let kty=cosePublicKey.get(COSEKEYS.kty);return isCOSEKty(kty)&&kty===COSEKTY.EC2}function isCOSEPublicKeyRSA(cosePublicKey){let kty=cosePublicKey.get(COSEKEYS.kty);return isCOSEKty(kty)&&kty===COSEKTY.RSA}function isCOSEKty(kty){return Object.values(COSEKTY).indexOf(kty)>=0}function isCOSECrv(crv){return Object.values(COSECRV).indexOf(crv)>=0}function isCOSEAlg(alg){return Object.values(COSEALG).indexOf(alg)>=0}var COSEKEYS,COSEKTY,COSECRV,COSEALG;var init_cose=__esm(()=>{(function(COSEKEYS2){COSEKEYS2[COSEKEYS2.kty=1]="kty",COSEKEYS2[COSEKEYS2.alg=3]="alg",COSEKEYS2[COSEKEYS2.crv=-1]="crv",COSEKEYS2[COSEKEYS2.x=-2]="x",COSEKEYS2[COSEKEYS2.y=-3]="y",COSEKEYS2[COSEKEYS2.n=-1]="n",COSEKEYS2[COSEKEYS2.e=-2]="e"})(COSEKEYS||(COSEKEYS={}));(function(COSEKTY2){COSEKTY2[COSEKTY2.OKP=1]="OKP",COSEKTY2[COSEKTY2.EC2=2]="EC2",COSEKTY2[COSEKTY2.RSA=3]="RSA"})(COSEKTY||(COSEKTY={}));(function(COSECRV2){COSECRV2[COSECRV2.P256=1]="P256",COSECRV2[COSECRV2.P384=2]="P384",COSECRV2[COSECRV2.P521=3]="P521",COSECRV2[COSECRV2.ED25519=6]="ED25519",COSECRV2[COSECRV2.SECP256K1=8]="SECP256K1"})(COSECRV||(COSECRV={}));(function(COSEALG2){COSEALG2[COSEALG2.ES256=-7]="ES256",COSEALG2[COSEALG2.EdDSA=-8]="EdDSA",COSEALG2[COSEALG2.ES384=-35]="ES384",COSEALG2[COSEALG2.ES512=-36]="ES512",COSEALG2[COSEALG2.PS256=-37]="PS256",COSEALG2[COSEALG2.PS384=-38]="PS384",COSEALG2[COSEALG2.PS512=-39]="PS512",COSEALG2[COSEALG2.ES256K=-47]="ES256K",COSEALG2[COSEALG2.RS256=-257]="RS256",COSEALG2[COSEALG2.RS384=-258]="RS384",COSEALG2[COSEALG2.RS512=-259]="RS512",COSEALG2[COSEALG2.RS1=-65535]="RS1"})(COSEALG||(COSEALG={}))});function mapCoseAlgToWebCryptoAlg(alg){if([COSEALG.RS1].indexOf(alg)>=0)return"SHA-1";else if([COSEALG.ES256,COSEALG.PS256,COSEALG.RS256].indexOf(alg)>=0)return"SHA-256";else if([COSEALG.ES384,COSEALG.PS384,COSEALG.RS384].indexOf(alg)>=0)return"SHA-384";else if([COSEALG.ES512,COSEALG.PS512,COSEALG.RS512,COSEALG.EdDSA].indexOf(alg)>=0)return"SHA-512";throw Error(`Could not map COSE alg value of ${alg} to a WebCrypto alg`)}var init_mapCoseAlgToWebCryptoAlg=__esm(()=>{init_cose()});function getWebCrypto(){return new Promise((resolve2,reject)=>{if(webCrypto)return resolve2(webCrypto);let _globalThisCrypto=_getWebCryptoInternals.stubThisGlobalThisCrypto();if(_globalThisCrypto)return webCrypto=_globalThisCrypto,resolve2(webCrypto);return reject(new MissingWebCrypto)})}var webCrypto=void 0,MissingWebCrypto,_getWebCryptoInternals;var init_getWebCrypto=__esm(()=>{MissingWebCrypto=class MissingWebCrypto extends Error{constructor(){super("An instance of the Crypto API could not be located");this.name="MissingWebCrypto"}};_getWebCryptoInternals={stubThisGlobalThisCrypto:()=>globalThis.crypto,setCachedCrypto:(newCrypto)=>{webCrypto=newCrypto}}});async function digest(data,algorithm){let WebCrypto=await getWebCrypto(),subtleAlgorithm=mapCoseAlgToWebCryptoAlg(algorithm),hashed=await WebCrypto.subtle.digest(subtleAlgorithm,data);return new Uint8Array(hashed)}var init_digest=__esm(()=>{init_mapCoseAlgToWebCryptoAlg();init_getWebCrypto()});async function getRandomValues(array){return(await getWebCrypto()).getRandomValues(array),array}var init_getRandomValues=__esm(()=>{init_getWebCrypto()});async function importKey(opts){let WebCrypto=await getWebCrypto(),{keyData,algorithm}=opts;return WebCrypto.subtle.importKey("jwk",keyData,algorithm,!1,["verify"])}var init_importKey=__esm(()=>{init_getWebCrypto()});async function verifyEC2(opts){let{cosePublicKey,signature,data,shaHashOverride}=opts,WebCrypto=await getWebCrypto(),alg=cosePublicKey.get(COSEKEYS.alg),crv=cosePublicKey.get(COSEKEYS.crv),x=cosePublicKey.get(COSEKEYS.x),y=cosePublicKey.get(COSEKEYS.y);if(!alg)throw Error("Public key was missing alg (EC2)");if(!crv)throw Error("Public key was missing crv (EC2)");if(!x)throw Error("Public key was missing x (EC2)");if(!y)throw Error("Public key was missing y (EC2)");let _crv;if(crv===COSECRV.P256)_crv="P-256";else if(crv===COSECRV.P384)_crv="P-384";else if(crv===COSECRV.P521)_crv="P-521";else throw Error(`Unexpected COSE crv value of ${crv} (EC2)`);let keyData={kty:"EC",crv:_crv,x:exports_isoBase64URL.fromBuffer(x),y:exports_isoBase64URL.fromBuffer(y),ext:!1},key2=await importKey({keyData,algorithm:{name:"ECDSA",namedCurve:_crv}}),subtleAlg=mapCoseAlgToWebCryptoAlg(alg);if(shaHashOverride)subtleAlg=mapCoseAlgToWebCryptoAlg(shaHashOverride);let verifyAlgorithm={name:"ECDSA",hash:{name:subtleAlg}};return WebCrypto.subtle.verify(verifyAlgorithm,key2,signature,data)}var init_verifyEC2=__esm(()=>{init_cose();init_mapCoseAlgToWebCryptoAlg();init_importKey();init_iso();init_getWebCrypto()});function mapCoseAlgToWebCryptoKeyAlgName(alg){if([COSEALG.EdDSA].indexOf(alg)>=0)return"Ed25519";else if([COSEALG.ES256,COSEALG.ES384,COSEALG.ES512,COSEALG.ES256K].indexOf(alg)>=0)return"ECDSA";else if([COSEALG.RS256,COSEALG.RS384,COSEALG.RS512,COSEALG.RS1].indexOf(alg)>=0)return"RSASSA-PKCS1-v1_5";else if([COSEALG.PS256,COSEALG.PS384,COSEALG.PS512].indexOf(alg)>=0)return"RSA-PSS";throw Error(`Could not map COSE alg value of ${alg} to a WebCrypto key alg name`)}var init_mapCoseAlgToWebCryptoKeyAlgName=__esm(()=>{init_cose()});async function verifyRSA(opts){let{cosePublicKey,signature,data,shaHashOverride}=opts,WebCrypto=await getWebCrypto(),alg=cosePublicKey.get(COSEKEYS.alg),n=cosePublicKey.get(COSEKEYS.n),e=cosePublicKey.get(COSEKEYS.e);if(!alg)throw Error("Public key was missing alg (RSA)");if(!isCOSEAlg(alg))throw Error(`Public key had invalid alg ${alg} (RSA)`);if(!n)throw Error("Public key was missing n (RSA)");if(!e)throw Error("Public key was missing e (RSA)");let keyData={kty:"RSA",alg:"",n:exports_isoBase64URL.fromBuffer(n),e:exports_isoBase64URL.fromBuffer(e),ext:!1},keyAlgorithm={name:mapCoseAlgToWebCryptoKeyAlgName(alg),hash:{name:mapCoseAlgToWebCryptoAlg(alg)}},verifyAlgorithm={name:mapCoseAlgToWebCryptoKeyAlgName(alg)};if(shaHashOverride)keyAlgorithm.hash.name=mapCoseAlgToWebCryptoAlg(shaHashOverride);if(keyAlgorithm.name==="RSASSA-PKCS1-v1_5"){if(keyAlgorithm.hash.name==="SHA-256")keyData.alg="RS256";else if(keyAlgorithm.hash.name==="SHA-384")keyData.alg="RS384";else if(keyAlgorithm.hash.name==="SHA-512")keyData.alg="RS512";else if(keyAlgorithm.hash.name==="SHA-1")keyData.alg="RS1"}else if(keyAlgorithm.name==="RSA-PSS"){let saltLength=0;if(keyAlgorithm.hash.name==="SHA-256")keyData.alg="PS256",saltLength=32;else if(keyAlgorithm.hash.name==="SHA-384")keyData.alg="PS384",saltLength=48;else if(keyAlgorithm.hash.name==="SHA-512")keyData.alg="PS512",saltLength=64;verifyAlgorithm.saltLength=saltLength}else throw Error(`Unexpected RSA key algorithm ${alg} (${keyAlgorithm.name})`);let key2=await importKey({keyData,algorithm:keyAlgorithm});return WebCrypto.subtle.verify(verifyAlgorithm,key2,signature,data)}var init_verifyRSA=__esm(()=>{init_cose();init_mapCoseAlgToWebCryptoAlg();init_importKey();init_iso();init_mapCoseAlgToWebCryptoKeyAlgName();init_getWebCrypto()});function convertAAGUIDToString(aaguid){let hex=exports_isoUint8Array.toHex(aaguid);return[hex.slice(0,8),hex.slice(8,12),hex.slice(12,16),hex.slice(16,20),hex.slice(20,32)].join("-")}var init_convertAAGUIDToString=__esm(()=>{init_iso()});function convertCertBufferToPEM(certBuffer){let b64cert;if(typeof certBuffer==="string")if(exports_isoBase64URL.isBase64URL(certBuffer))b64cert=exports_isoBase64URL.toBase64(certBuffer);else if(exports_isoBase64URL.isBase64(certBuffer))b64cert=certBuffer;else throw Error("Certificate is not a valid base64 or base64url string");else b64cert=exports_isoBase64URL.fromBuffer(certBuffer,"base64");let PEMKey="";for(let i=0;i<Math.ceil(b64cert.length/64);i+=1){let start=64*i;PEMKey+=`${b64cert.substr(start,64)}
|
|
101
|
+
`,RateLimiterBackendError,DEFAULT_AUTH_LOGIN,DEFAULT_AUTH_REGISTER,DEFAULT_AUTH_PASSWORD_RESET,DEFAULT_AUTH_MAGIC_LINK,DEFAULT_CONFIG4;var init_RateLimiter=__esm(()=>{RateLimiterBackendError=class RateLimiterBackendError extends Error{constructor(message){super(message);this.name="RateLimiterBackendError"}};DEFAULT_AUTH_LOGIN={window:"15m",max:5,blockDuration:"30m"},DEFAULT_AUTH_REGISTER={window:"1h",max:3,blockDuration:"1h"},DEFAULT_AUTH_PASSWORD_RESET={window:"1h",max:3,blockDuration:"1h"},DEFAULT_AUTH_MAGIC_LINK={window:"1h",max:5,blockDuration:"1h"},DEFAULT_CONFIG4={enabled:!0,strategy:"sliding-window",keyPrefix:"rl:",authRoutes:{window:"1m",max:10,login:DEFAULT_AUTH_LOGIN,register:DEFAULT_AUTH_REGISTER,passwordReset:DEFAULT_AUTH_PASSWORD_RESET,magicLink:DEFAULT_AUTH_MAGIC_LINK},publicRoutes:{window:"1m",max:100},privateRoutes:{window:"1m",max:60},byIp:!0,byUserId:!0,byEndpoint:!1,skipSuccessfulRequests:!1,headers:{remaining:"X-RateLimit-Remaining",reset:"X-RateLimit-Reset",limit:"X-RateLimit-Limit"},whitelist:[],blacklist:[]}});import{createCipheriv as createCipheriv2,createDecipheriv as createDecipheriv2,randomBytes as randomBytes4,scryptSync as scryptSync2,timingSafeEqual as timingSafeEqual2}from"crypto";var VERSION="v1",IV_LEN2=12,KEY_LEN=32,SCRYPT_SALT="nucleus-secrets-v1",keyCache,deriveKey2=(masterKey)=>{let cached=keyCache.get(masterKey);if(cached)return cached;let key2=scryptSync2(masterKey,SCRYPT_SALT,KEY_LEN);return keyCache.set(masterKey,key2),key2},encryptSecret=(plaintext,masterKey)=>{if(!masterKey)throw Error("secrets encryption key is empty");let iv=randomBytes4(IV_LEN2),cipher=createCipheriv2("aes-256-gcm",deriveKey2(masterKey),iv),ciphertext=Buffer.concat([cipher.update(plaintext,"utf-8"),cipher.final()]),tag=cipher.getAuthTag();return[VERSION,iv.toString("base64"),tag.toString("base64"),ciphertext.toString("base64")].join(":")},decryptSecret=(envelope,masterKey)=>{if(!masterKey)throw Error("secrets encryption key is empty");let parts=envelope.split(":");if(parts.length!==4||parts[0]!==VERSION)throw Error("not an encrypted secret envelope");let[,ivB64,tagB64,ctB64]=parts,decipher=createDecipheriv2("aes-256-gcm",deriveKey2(masterKey),Buffer.from(ivB64,"base64"));return decipher.setAuthTag(Buffer.from(tagB64,"base64")),Buffer.concat([decipher.update(Buffer.from(ctB64,"base64")),decipher.final()]).toString("utf-8")},previewOf=(plaintext)=>{let len=plaintext.length;if(len===0)return"";if(len<12)return`\u2022\u2022\u2022\u2022${len}`;return`\u2022\u2022\u2022\u2022${plaintext.slice(-4)}`};var init_crypto=__esm(()=>{keyCache=new Map});function discoverSlots(config){let slots=new Map,add=(slot)=>{let id=`${slot.scope}.${slot.key}`;if(!slots.has(id))slots.set(id,slot)},valueAt=(scope,key2)=>{let node=config;for(let segment of scope.split(".")){if(!isPlainObject(node))return;node=node[segment]}if(!isPlainObject(node))return;let value=node[key2];if(typeof value==="string")return value;if(Array.isArray(value)&&value.every((entry)=>typeof entry==="string"))return value.length>0?value.join(","):void 0;return};for(let descriptor of SECRET_SLOT_DESCRIPTORS)for(let scope of expandPath(config,descriptor.path,descriptor.always===!0)){let leaf=scope.split(".").pop()??descriptor.group,group=descriptor.path.endsWith("*")?`${descriptor.group}:${leaf}`:descriptor.group;for(let declared of descriptor.keys)add({scope,key:declared.key,kind:declared.kind??kindFor(declared.key),label:declared.label,group,required:declared.required??!1,requiredWhen:declared.requiredWhen,hint:declared.hint,secret:declared.secret??descriptor.secret??!0,configValue:valueAt(scope,declared.key)})}let walk=(node,path2,depth)=>{if(depth>6)return;for(let[key2,value]of Object.entries(node)){if(SKIP_SECTIONS.has(key2))continue;let childPath=path2?`${path2}.${key2}`:key2;if(isPlainObject(value)){walk(value,childPath,depth+1);continue}if(typeof value!=="string"&&value!==void 0&&value!==null)continue;if(!CREDENTIAL_KEY_PATTERN.test(key2))continue;if(NOT_A_CREDENTIAL.has(key2.toLowerCase()))continue;if(BOOT_ONLY_PATHS.has(`${path2}.${key2}`))continue;let owner=path2.split(".").pop(),label=owner&&owner.toLowerCase()!==key2.toLowerCase()?`${humanize(owner)} \u2014 ${humanize(key2)}`:humanize(key2);add({scope:path2,key:key2,kind:kindFor(key2),label,group:path2.split(".")[0]??"other",required:!1,secret:!0,configValue:typeof value==="string"?value:void 0})}};return walk(config,"",0),[...slots.values()].sort((a,b)=>a.group.localeCompare(b.group)||a.scope.localeCompare(b.scope)||a.key.localeCompare(b.key))}var CREDENTIAL_KEY_PATTERN,NOT_A_CREDENTIAL,BOOT_ONLY_PATHS,SKIP_SECTIONS,kindFor=(key2)=>{let k=key2.toLowerCase();if(k.includes("json"))return"json";if(k.includes("connection"))return"connection_string";if(k.includes("privatekey")||k.includes("private_key"))return"pem";if(k.includes("clientid")||k.includes("client_id"))return"text";return"password"},humanize=(key2)=>key2.replace(/[_-]+/g," ").replace(/([a-z0-9])([A-Z])/g,"$1 $2").replace(/\s+/g," ").trim().replace(/\b\w/g,(c)=>c.toUpperCase()),SECRET_SLOT_DESCRIPTORS,isPlainObject=(value)=>typeof value==="object"&&value!==null&&!Array.isArray(value),expandPath=(config,path2,always=!1)=>{let segments=path2.split("."),scopes2=[{path:"",node:config}];for(let segment of segments){let next=[];for(let current of scopes2){if(!isPlainObject(current.node))continue;if(segment==="*")for(let[childKey,childValue]of Object.entries(current.node))next.push({path:current.path?`${current.path}.${childKey}`:childKey,node:childValue});else if(segment in current.node)next.push({path:current.path?`${current.path}.${segment}`:segment,node:current.node[segment]});else if(always)next.push({path:current.path?`${current.path}.${segment}`:segment,node:{}})}scopes2=next}return scopes2.filter((s)=>isPlainObject(s.node)).map((s)=>s.path)},looksLikeEnvName=(value)=>!!value&&/^[A-Z][A-Z0-9_]{2,}$/.test(value);var init_registry=__esm(()=>{CREDENTIAL_KEY_PATTERN=/(secret|password|passwd|apikey|api_key|accesskey|access_key|privatekey|private_key|token|credential|connection_string|connectionstring|clientid|client_id|encryptionkey|encryption_key|servicekey|service_key|json_file_path|jsonfilepath)$/i,NOT_A_CREDENTIAL=new Set(["preventapikeymanagement","allowapplicationkeys","maxkeysperuser","tokenurl","accesstoken","refreshtoken","sessiontoken"]),BOOT_ONLY_PATHS=new Set(["authorization.godminPassword","authorization.godminEmail","authentication.accessToken.secret","authentication.refreshToken.secret","authentication.sessionToken.secret","backup.encryptionKey","notification.channels.telegram.botToken","notification.channels.webhook.headers","domains.cloudflare.apiToken"]),SKIP_SECTIONS=new Set(["entities","systemTables","system_tables","tables","columns","indexes","routes","cors","swagger","secrets"]),SECRET_SLOT_DESCRIPTORS=[{path:"authentication.oauth.providers.*",group:"oauth",label:"OAuth / SSO",keys:[{key:"clientId",kind:"text",label:"Client ID",required:!0},{key:"clientSecret",kind:"password",label:"Client Secret",required:!0},{key:"tenantId",kind:"text",label:"Tenant ID"},{key:"redirectUri",kind:"text",secret:!1,required:!0,label:"Y\xF6nlendirme adresi (Redirect URI)",hint:"Sa\u011Flay\u0131c\u0131ya kay\u0131tl\u0131 d\xF6n\xFC\u015F adresi. Bu adresin sa\u011Flay\u0131c\u0131 taraf\u0131nda da (\xF6r. Entra > Authentication > Redirect URIs) birebir ayn\u0131 yaz\u0131l\u0131 olmas\u0131 gerekir."}]},{always:!0,path:"email.gmail",group:"email",label:"Gmail (service account)",keys:[{key:"service_account_json",kind:"json",label:"Service Account JSON",required:!0,requiredWhen:"enabled"}]},{always:!0,path:"email.azure",group:"email",label:"Azure Communication Services",keys:[{key:"connection_string",kind:"connection_string",label:"Connection String",required:!0,requiredWhen:"enabled"}]},{always:!0,path:"storage.smb",group:"storage",label:"SMB / CIFS share",keys:[{key:"username",kind:"text",label:"Kullan\u0131c\u0131 ad\u0131",required:!0},{key:"password",kind:"password",label:"Parola",required:!0}]},{secret:!1,always:!0,path:"storage",group:"storage",label:"Dosya deposu",keys:[{key:"provider",kind:"text",label:"Depolama t\xFCr\xFC",hint:"local (sunucunun kendi diski) veya smb (kurumsal dosya sunucusu). De\u011Fi\u015Fiklik an\u0131nda ge\xE7erli olur."}]},{secret:!1,always:!0,path:"storage.smb",group:"storage",label:"SMB / CIFS share",keys:[{key:"url",kind:"text",label:"Payla\u015F\u0131m adresi",hint:"M\xFC\u015Fteriden geldi\u011Fi gibi yap\u0131\u015Ft\u0131r\u0131n: smb://sunucu/paylasim \u2014 sunucu ve payla\u015F\u0131m ad\u0131 buradan \xE7\xF6z\xFCl\xFCr."},{key:"domain",kind:"text",label:"Etki alan\u0131 (domain)",hint:"Kullan\u0131c\u0131 DOMAIN\\kullanici bi\xE7imindeyse domain k\u0131sm\u0131. Gerekmiyorsa bo\u015F b\u0131rak\u0131n."},{key:"base_path",kind:"text",label:"Payla\u015F\u0131m i\xE7i klas\xF6r",hint:"Y\xFCklemelerin toplanaca\u011F\u0131 alt klas\xF6r. Bo\u015Fsa payla\u015F\u0131m\u0131n k\xF6k\xFC kullan\u0131l\u0131r."}]},{path:"payment.providers.*",group:"payment",label:"\xD6deme sa\u011Flay\u0131c\u0131",keys:[{key:"apiKey",kind:"password",label:"API Key",required:!0},{key:"secretKey",kind:"password",label:"Secret Key",required:!0},{key:"webhookSecret",kind:"password",label:"Webhook Secret"}]},{path:"captcha",group:"captcha",label:"Captcha",keys:[{key:"secretKey",kind:"password",label:"Secret Key"}]},{secret:!1,path:"authentication",group:"portal",label:"Portal adresi",keys:[{key:"trustedAppOrigins",kind:"list",label:"G\xFCvenilen adresler",required:!0,hint:"Portal\u0131n kurulu oldu\u011Fu adres(ler). \u015Eifre s\u0131f\u0131rlama ve SSO d\xF6n\xFC\u015F linkleri buraya g\xF6re kurulur. Joker: *.firma.com"}]},{secret:!1,always:!0,path:"email",group:"email",label:"E-posta sa\u011Flay\u0131c\u0131",keys:[{key:"provider",kind:"text",label:"Kullan\u0131lacak sa\u011Flay\u0131c\u0131",hint:"azure veya gmail. Bo\u015F b\u0131rak\u0131l\u0131rsa a\xE7\u0131k olan sa\u011Flay\u0131c\u0131 kullan\u0131l\u0131r."}]},{secret:!1,always:!0,path:"email.azure",group:"email",label:"Azure Communication Services",keys:[{key:"enabled",kind:"boolean",label:"Azure e-posta a\xE7\u0131k",hint:"Ba\u011Flant\u0131 dizesini girmek tek ba\u015F\u0131na yetmez \u2014 g\xF6nderim bu anahtarla a\xE7\u0131l\u0131r."},{key:"sender_address",kind:"text",label:"G\xF6nderen adresi"}]},{secret:!1,always:!0,path:"email.gmail",group:"email",label:"Gmail (service account)",keys:[{key:"enabled",kind:"boolean",label:"Gmail e-posta a\xE7\u0131k"},{key:"from_email",kind:"text",label:"G\xF6nderen adresi"}]}]});import{and as and7,eq as eq12}from"drizzle-orm";class SecretsStore{db;resolveTable;masterKey;constructor(deps){this.db=deps.db,this.resolveTable=deps.resolveTable,this.masterKey=deps.masterKey}table(schemaName){return this.resolveTable(SECRETS_TABLE,schemaName)}async loadAll(schemaName){let values=new Map,failed=[],table=this.table(schemaName);if(!table)return{values,failed,tableMissing:!0};let rows;try{rows=await this.db.select().from(table).where(eq12(col6(table,"isActive"),!0))}catch(error){if(isMissingTableError(error))return{values,failed,tableMissing:!0};throw error}for(let row of rows)try{values.set(cacheKeyOf(row.scope,row.key),decryptSecret(row.valueEnc,this.masterKey))}catch{failed.push(`${row.scope}.${row.key}`)}return{values,failed}}async list(schemaName){let table=this.table(schemaName);if(!table)return[];try{return(await this.db.select().from(table)).filter((r)=>r.isActive!==!1).map(rowToMeta)}catch(error){if(isMissingTableError(error))return[];throw error}}async get(scope,key2,schemaName){let table=this.table(schemaName);if(!table)return null;return(await this.db.select().from(table).where(and7(eq12(col6(table,"scope"),scope),eq12(col6(table,"key"),key2))).limit(1))[0]??null}async set(params,schemaName){let table=this.table(schemaName);if(!table)return null;let existing=await this.get(params.scope,params.key,schemaName),valueEnc=encryptSecret(params.value,this.masterKey),preview=previewOf(params.value),now=new Date;if(existing)await this.db.update(table).set({valueEnc,previousEnc:existing.valueEnc,preview,kind:params.kind??existing.kind??"text",description:params.description??existing.description,version:(existing.version??1)+1,rotatedAt:now,isActive:!0,updatedAt:now,updatedBy:params.actorId??null}).where(eq12(col6(table,"id"),existing.id));else await this.db.insert(table).values({scope:params.scope,key:params.key,valueEnc,preview,kind:params.kind??"text",description:params.description??null,version:1,isActive:!0,createdBy:params.actorId??null,updatedBy:params.actorId??null});let saved=await this.get(params.scope,params.key,schemaName);return saved?rowToMeta(saved):null}async rollback(scope,key2,actorId,schemaName){let table=this.table(schemaName);if(!table)return null;let existing=await this.get(scope,key2,schemaName);if(!existing?.previousEnc)return null;let plaintext=decryptSecret(existing.previousEnc,this.masterKey),now=new Date;await this.db.update(table).set({valueEnc:existing.previousEnc,previousEnc:existing.valueEnc,preview:previewOf(plaintext),version:(existing.version??1)+1,rotatedAt:now,updatedAt:now,updatedBy:actorId??null}).where(eq12(col6(table,"id"),existing.id));let saved=await this.get(scope,key2,schemaName);return saved?rowToMeta(saved):null}async remove(scope,key2,schemaName){let table=this.table(schemaName);if(!table)return!1;let existing=await this.get(scope,key2,schemaName);if(!existing)return!1;return await this.db.delete(table).where(eq12(col6(table,"id"),existing.id)),!0}async touch(scope,key2,schemaName){let table=this.table(schemaName);if(!table)return;await this.db.update(table).set({lastUsedAt:new Date}).where(and7(eq12(col6(table,"scope"),scope),eq12(col6(table,"key"),key2)))}async reencryptAll(newMasterKey,schemaName){let table=this.table(schemaName);if(!table)return{migrated:0,failed:[]};let rows=await this.db.select().from(table),failed=[],planned=[];for(let row of rows)try{let plaintext=decryptSecret(row.valueEnc,this.masterKey),previous=row.previousEnc?encryptSecret(decryptSecret(row.previousEnc,this.masterKey),newMasterKey):null;planned.push({id:row.id,valueEnc:encryptSecret(plaintext,newMasterKey),previousEnc:previous})}catch{failed.push(`${row.scope}.${row.key}`)}if(failed.length>0)return{migrated:0,failed};return await this.db.transaction(async(tx)=>{for(let row of planned)await tx.update(table).set({valueEnc:row.valueEnc,previousEnc:row.previousEnc}).where(eq12(col6(table,"id"),row.id))}),this.masterKey=newMasterKey,{migrated:planned.length,failed}}}var SECRETS_TABLE="nucleusSecrets",col6=(table,key2)=>table[key2],toIso=(value)=>value?new Date(value).toISOString():null,UNDEFINED_TABLE="42P01",isMissingTableError=(error)=>{let seen=new Set,current=error;while(current&&typeof current==="object"&&!seen.has(current)){seen.add(current);let record=current;if(record.code===UNDEFINED_TABLE)return!0;if(typeof record.message==="string"&&/relation .* does not exist/i.test(record.message))return!0;current=record.cause}return!1},rowToMeta=(row)=>({id:row.id,scope:row.scope,key:row.key,kind:row.kind??"text",preview:row.preview??"",description:row.description,version:row.version??1,canRollback:!!row.previousEnc,rotatedAt:toIso(row.rotatedAt),lastUsedAt:toIso(row.lastUsedAt),updatedAt:toIso(row.updatedAt),updatedBy:row.updatedBy}),cacheKeyOf=(scope,key2)=>`${scope}.${key2}`;var init_store=__esm(()=>{init_crypto()});class SecretsService{store;logger;getRedis;refreshIntervalMs;schemaName;cache=new Map;timer=null;localRevision=0;loaded=!1;tableMissing=!1;warnedTableMissing=!1;constructor(deps){this.store=deps.store,this.logger=deps.logger,this.getRedis=deps.getRedis,this.refreshIntervalMs=deps.refreshIntervalMs??DEFAULT_REFRESH_MS,this.schemaName=deps.schemaName}async start(){if(await this.refresh(),this.timer)return;this.timer=setInterval(()=>{this.refreshIfStale()},this.refreshIntervalMs),this.timer.unref?.()}stop(){if(this.timer)clearInterval(this.timer);this.timer=null}isReady(){return this.loaded}size(){return this.cache.size}isTableMissing(){return this.tableMissing}async refresh(){try{let{values,failed,tableMissing}=await this.store.loadAll(this.schemaName);if(tableMissing){if(this.tableMissing=!0,!this.warnedTableMissing)this.warnedTableMissing=!0,this.logger.warn("[Secrets] nucleus_secrets does not exist yet \u2014 env and literal values resolve normally; "+"the store activates automatically once the schema sync creates it");return}if(this.tableMissing)this.tableMissing=!1,this.warnedTableMissing=!1,this.logger.info("[Secrets] nucleus_secrets is now available \u2014 credential store active");if(this.cache=values,this.loaded=!0,failed.length>0)this.logger.error("[Secrets] Credentials failed to decrypt and were skipped",{slots:failed,hint:"master key changed without re-encrypting \u2014 POST /secrets/reencrypt with the old key"})}catch(error){this.logger.warn("[Secrets] Refresh failed, keeping cached values",{error:error instanceof Error?error.message:String(error)})}}async refreshIfStale(){let redis=this.getRedis?.();if(!redis)return this.refresh();try{let result=await redis.read(REVISION_KEY),remote=Number(result.data??0);if(Number.isFinite(remote)&&remote===this.localRevision&&this.loaded)return;await this.refresh(),this.localRevision=Number.isFinite(remote)?remote:this.localRevision}catch{await this.refresh()}}async bumpRevision(){let redis=this.getRedis?.();if(!redis)return;try{let next=Date.now();this.localRevision=next,await redis.create(REVISION_KEY,next)}catch{}}get(scope,key2){return this.cache.get(cacheKeyOf(scope,key2))}has(scope,key2){return this.cache.has(cacheKeyOf(scope,key2))}resolve(scope,key2,configValue){let fromDb=this.cache.get(cacheKeyOf(scope,key2));if(fromDb)return{value:fromDb,source:"db"};if(configValue){let fromEnv=process.env[configValue];if(fromEnv)return{value:fromEnv,source:"env"};if(looksLikeEnvName(configValue))return{value:void 0,source:"missing"};return{value:configValue,source:"literal"}}return{value:void 0,source:"missing"}}value(scope,key2,configValue){return this.resolve(scope,key2,configValue).value}listValue(scope,key2,configValue){let fallback=Array.isArray(configValue)?configValue.join(","):configValue,raw=this.value(scope,key2,fallback);if(!raw)return Array.isArray(configValue)?configValue:[];return raw.split(/[,;\n\r]+/).map((entry)=>entry.trim()).filter(Boolean)}flag(scope,key2,configValue){let raw=this.get(scope,key2);if(raw===void 0)return configValue===!0;return raw==="true"||raw==="1"}liveConfig(scope,node,keys){let live={...node};for(let key2 of keys){let declared=node[key2],configValue=typeof declared==="string"?declared:void 0;Object.defineProperty(live,key2,{get:()=>this.resolve(scope,key2,configValue).value,enumerable:!0,configurable:!0})}return live}async describe(config,slots){let discovered=slots??discoverSlots(config),stored=await this.store.list(this.schemaName),byId=new Map(stored.map((s)=>[cacheKeyOf(s.scope,s.key),s]));return discovered.map((slot)=>{let id=cacheKeyOf(slot.scope,slot.key),record=byId.get(id),{value,source}=this.resolve(slot.scope,slot.key,slot.configValue),envName=looksLikeEnvName(slot.configValue)?slot.configValue:void 0,gate=slot.requiredWhen?this.flag(slot.scope,slot.requiredWhen,configFlagAt(config,slot.scope,slot.requiredWhen)):!0;return{...slot,required:slot.required&&gate,configValue:envName,source,value:slot.secret?void 0:value,preview:slot.secret?source==="db"&&record?record.preview:value?previewOf(value):"":value??"",envName,version:record?.version,rotatedAt:record?.rotatedAt??null,canRollback:record?.canRollback??!1}})}async list(){return this.store.list(this.schemaName)}async set(params){let saved=await this.store.set(params,this.schemaName);return await this.refresh(),await this.bumpRevision(),this.logger.info("[Secrets] Credential stored",{scope:params.scope,key:params.key,version:saved?.version,actor:params.actorId}),saved}async rollback(scope,key2,actorId){let saved=await this.store.rollback(scope,key2,actorId,this.schemaName);if(!saved)return null;return await this.refresh(),await this.bumpRevision(),this.logger.info("[Secrets] Credential rolled back",{scope,key:key2,actor:actorId}),saved}async remove(scope,key2,actorId){if(!await this.store.remove(scope,key2,this.schemaName))return!1;return await this.refresh(),await this.bumpRevision(),this.logger.info("[Secrets] Credential removed",{scope,key:key2,actor:actorId}),!0}async reencryptAll(newMasterKey){let result=await this.store.reencryptAll(newMasterKey,this.schemaName);return await this.refresh(),await this.bumpRevision(),result}}var REVISION_KEY="nucleus:secrets:revision",DEFAULT_REFRESH_MS=30000,configFlagAt=(config,scope,key2)=>{let node=config;for(let segment of scope.split(".")){if(typeof node!=="object"||node===null)return;node=node[segment]}if(typeof node!=="object"||node===null)return;let value=node[key2];if(typeof value==="boolean")return value;if(typeof value==="string")return value==="true"||value==="1";return};var init_SecretsService=__esm(()=>{init_crypto();init_registry();init_store()});var resolveMasterKey=(configured)=>{if(configured){let fromEnv=process.env[configured];if(fromEnv)return fromEnv;if(!/^[A-Z][A-Z0-9_]{2,}$/.test(configured))return configured}return process.env.NUCLEUS_SECRETS_KEY||void 0};var init_Secrets=__esm(()=>{init_crypto();init_registry();init_SecretsService();init_store()});var exports_schema={};__export(exports_schema,{reasonOf:()=>reasonOf,isAdditiveStatement:()=>isAdditiveStatement,ensureSchemaExists:()=>ensureSchemaExists,applySchemaPush:()=>applySchemaPush});import{sql as sql4}from"drizzle-orm";function reasonOf(error){if(!(error instanceof Error))return String(error);let extra=error;return[error.message,extra.detail?`detail: ${String(extra.detail)}`:"",extra.hint?`hint: ${String(extra.hint)}`:"",extra.code?`code: ${String(extra.code)}`:""].filter(Boolean).join(" \u2014 ")}var validateIdentifier=(name)=>{if(!name||name.length>63)throw Error(`Invalid identifier: must be 1-63 characters, got ${name.length}`);if(!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(name))throw Error(`Invalid identifier: "${name}" contains unsafe characters`);return name},ensureSchemaExists=async(db,schemaName)=>{let safeName=validateIdentifier(schemaName),found=await db.execute(sql4`select 1 from pg_catalog.pg_namespace where nspname = ${safeName} limit 1`);if(rowCountOf(found)>0)return;await db.execute(sql4.raw(`CREATE SCHEMA IF NOT EXISTS "${safeName}"`))},rowCountOf=(result)=>{if(Array.isArray(result))return result.length;let rows=result?.rows;return Array.isArray(rows)?rows.length:0},ADDITIVE_PREFIXES,isAdditiveStatement=(statement)=>{let normalized=statement.trim().toUpperCase();if(/^ALTER TABLE .+ ADD COLUMN/.test(normalized))return!0;if(/^ALTER TABLE .+ ALTER COLUMN .+ SET DEFAULT /.test(normalized))return!0;return ADDITIVE_PREFIXES.some((prefix)=>normalized.startsWith(prefix))},applySchemaPush=async(push,opts)=>{let{schemaName,allowDataLoss,logger:logger2,execute}=opts;if(push.hasDataLoss&&!allowDataLoss){let additive=push.statementsToExecute.filter(isAdditiveStatement),blocked=push.statementsToExecute.filter((s)=>!isAdditiveStatement(s));if(logger2.error(`[Schema] Destructive changes detected for schema "${schemaName}" but database.allowDataLoss is not enabled \u2014 ${blocked.length} statement(s) skipped. Set database.allowDataLoss: true to apply them.`,{warnings:push.warnings,statements:blocked}),additive.length===0||!execute)return!1;let applied=0;for(let statement of additive)try{await execute(statement),applied++}catch(error){logger2.warn(`[Schema] ${schemaName}: ${statement} \u2014 ${reasonOf(error)}`)}return logger2.info(`[Schema] Applied ${applied}/${additive.length} additive statement(s) for "${schemaName}" despite the destructive changes being held back`),applied>0}if(push.hasDataLoss)logger2.warn(`[Schema] Applying destructive changes to schema "${schemaName}" (database.allowDataLoss=true)`,{warnings:push.warnings});try{return await push.apply(),!0}catch(error){let message=error instanceof Error?error.message:String(error);if(!execute)return logger2.error(`[Schema] Could not apply schema changes to "${schemaName}": ${message}. The database does not match this build, so queries against the missing columns will fail.`,{warnings:push.warnings}),!1;logger2.error(`[Schema] The schema push for "${schemaName}" failed as a batch (${message}) \u2014 retrying its ${push.statementsToExecute.length} statement(s) one at a time so one bad statement does not hold back the rest.`);let applied=0,failures=[];for(let statement of push.statementsToExecute)try{await execute(statement),applied++}catch(statementError){failures.push(statement),logger2.error(`[Schema] ${schemaName}: ${statement} \u2014 ${reasonOf(statementError)}`)}if(failures.length>0)logger2.error(`[Schema] ${failures.length} of ${push.statementsToExecute.length} statement(s) could not be applied to "${schemaName}". Any query touching what they would have created will fail until they are.`);return applied>0}};var init_schema=__esm(()=>{ADDITIVE_PREFIXES=["CREATE TABLE IF NOT EXISTS","CREATE TABLE","CREATE SCHEMA IF NOT EXISTS","CREATE SCHEMA","CREATE INDEX IF NOT EXISTS","CREATE INDEX","CREATE UNIQUE INDEX IF NOT EXISTS","CREATE UNIQUE INDEX","CREATE TYPE","DO $$"]});var rowToTenantRecord=(row)=>({id:String(row.id||""),subdomain:String(row.subdomain||""),schemaName:String(row.schemaName||row.schema_name||""),companyId:String(row.companyId||row.company_id||""),companyName:row.companyName!=null?String(row.companyName):row.company_name!=null?String(row.company_name):null,godAdminEmail:String(row.godAdminEmail||row.god_admin_email||""),status:parseStatus(row.status),plan:row.plan!=null?String(row.plan):null,domain:row.domain!=null?String(row.domain):null,settings:parseJsonbToConfig(row.settings),trustedSources:parseTrustedSources(row.trustedSources||row.trusted_sources),maxUsers:row.maxUsers!=null?Number(row.maxUsers):row.max_users!=null?Number(row.max_users):null,provisionedAt:row.provisionedAt!=null?String(row.provisionedAt):row.provisioned_at!=null?String(row.provisioned_at):null,suspendedAt:row.suspendedAt!=null?String(row.suspendedAt):row.suspended_at!=null?String(row.suspended_at):null,suspendedReason:row.suspendedReason!=null?String(row.suspendedReason):row.suspended_reason!=null?String(row.suspended_reason):null}),rowToFeatureRecord=(row,parseConfig)=>({id:String(row.id||""),tenantId:String(row.tenantId||row.tenant_id||""),featureName:String(row.featureName||row.feature_name||""),enabled:Boolean(row.enabled),featureConfig:parseConfig(row.config)}),parseStatus=(value)=>{let valid=["provisioning","active","suspended","archived"],str3=String(value||"provisioning");return valid.includes(str3)?str3:"provisioning"},parseJsonbToConfig=(value)=>{if(!value||typeof value!=="object")return{};let result={};for(let[k,v]of Object.entries(value))if(typeof v==="string"||typeof v==="number"||typeof v==="boolean")result[k]=v;return result},parseTrustedSources=(value)=>{if(!Array.isArray(value))return[];return value.map((item)=>{let entry=item;return{allowHeaderAuth:entry.allowHeaderAuth===!0||entry.allow_header_auth===!0,allowedIps:Array.isArray(entry.allowedIps||entry.allowed_ips)?entry.allowedIps||entry.allowed_ips:void 0,allowedServices:Array.isArray(entry.allowedServices||entry.allowed_services)?entry.allowedServices||entry.allowed_services:void 0}})},normalizeHost=(host)=>{return((host||"").split(":")[0]||"").toLowerCase().replace(/\.$/,"")},extractSubdomain=(host)=>{let hostWithoutPort=host.split(":")[0]||"";if(hostWithoutPort==="localhost"||/^\d+\.\d+\.\d+\.\d+$/.test(hostWithoutPort))return null;let parts=hostWithoutPort.split(".");if(parts.length<3)return null;let subdomain=parts[0]||"";if(!subdomain||subdomain==="www")return null;return subdomain},isIpInCidr=(ip,cidr)=>{let[cidrIp,prefixStr]=cidr.split("/");if(!cidrIp||!prefixStr)return!1;let prefix=Number.parseInt(prefixStr,10);if(Number.isNaN(prefix))return!1;let ipParts=ip.split(".").map(Number),cidrParts=cidrIp.split(".").map(Number);if(ipParts.length!==4||cidrParts.length!==4)return!1;let ipNum=(ipParts[0]||0)<<24|(ipParts[1]||0)<<16|(ipParts[2]||0)<<8|(ipParts[3]||0),cidrNum=(cidrParts[0]||0)<<24|(cidrParts[1]||0)<<16|(cidrParts[2]||0)<<8|(cidrParts[3]||0),mask=~((1<<32-prefix)-1);return(ipNum&mask)===(cidrNum&mask)},isTrustedSource=(tenant,request,authMode,fallbackSources,vettedClientIp)=>{let ownSources=tenant.trustedSources,trustedSources=Array.isArray(ownSources)&&ownSources.length>0?ownSources:fallbackSources;if(!trustedSources||!Array.isArray(trustedSources)||trustedSources.length===0)return!1;let clientIp=vettedClientIp?.trim()||"",serviceId=request.headers.get("x-service-id")||"";for(let source of trustedSources){if(!source.allowHeaderAuth)continue;if(source.allowedIps&&source.allowedIps.length>0){if(source.allowedIps.some((allowedIp)=>{if(allowedIp.includes("/"))return isIpInCidr(clientIp,allowedIp);return clientIp===allowedIp}))return!0}if(source.allowedServices&&source.allowedServices.length>0){if(source.allowedServices.includes(serviceId))return!0}}return!1};function getDatabaseAuthMode(){return process.env.DATABASE_AUTH_MODE||"password"}function getRedisAuthMode(){return process.env.REDIS_AUTH_MODE||"password"}async function acquireToken(scope,label){let{DefaultAzureCredential,ManagedIdentityCredential,ClientSecretCredential}=await import("@azure/identity"),authMode=scope===PG_TOKEN_SCOPE?getDatabaseAuthMode():getRedisAuthMode(),clientId=process.env.AZURE_CLIENT_ID||"",tenantId=process.env.AZURE_TENANT_ID||"",clientSecret=process.env.AZURE_CLIENT_SECRET||"",credential;if(authMode==="managed_identity")credential=clientId?new ManagedIdentityCredential(clientId):new DefaultAzureCredential;else if(authMode==="service_principal"){if(!tenantId||!clientId||!clientSecret)throw Error("[azure-auth] service_principal auth requires AZURE_TENANT_ID, AZURE_CLIENT_ID, and AZURE_CLIENT_SECRET");credential=new ClientSecretCredential(tenantId,clientId,clientSecret)}else throw Error(`[azure-auth] Unsupported auth mode: ${authMode}`);let result=await credential.getToken(scope);if(!result)throw Error(`[azure-auth] Failed to acquire token for ${label}`);return logger.scoped("database.connect").info(`[azure-auth] ${label} token acquired`,{expiresAt:new Date(result.expiresOnTimestamp).toISOString(),authMode}),{token:result.token,expiresAt:result.expiresOnTimestamp}}async function getPostgresToken(){let now=Date.now();if(pgCachedToken&&now<pgTokenExpiresAt-REFRESH_BUFFER_MS)return pgCachedToken;let{token,expiresAt}=await acquireToken(PG_TOKEN_SCOPE,"PostgreSQL");return pgCachedToken=token,pgTokenExpiresAt=expiresAt,pgCachedToken}async function getRedisToken(){let now=Date.now();if(redisCachedToken&&now<redisTokenExpiresAt-REFRESH_BUFFER_MS)return redisCachedToken;let{token,expiresAt}=await acquireToken(REDIS_TOKEN_SCOPE,"Redis");return redisCachedToken=token,redisTokenExpiresAt=expiresAt,redisCachedToken}function getRedisTokenExpiresAt(){return redisTokenExpiresAt}var PG_TOKEN_SCOPE="https://ossrdbms-aad.database.windows.net/.default",REDIS_TOKEN_SCOPE="https://redis.azure.com/.default",REFRESH_BUFFER_MS=300000,pgCachedToken=null,pgTokenExpiresAt=0,redisCachedToken=null,redisTokenExpiresAt=0;var init_AzureTokenProvider=__esm(()=>{init_Logger2()});var exports_Azure={};__export(exports_Azure,{getRedisTokenExpiresAt:()=>getRedisTokenExpiresAt,getRedisToken:()=>getRedisToken,getRedisAuthMode:()=>getRedisAuthMode,getPostgresToken:()=>getPostgresToken,getDatabaseAuthMode:()=>getDatabaseAuthMode});var init_Azure=__esm(()=>{init_AzureTokenProvider()});import{access,mkdir as mkdir4}from"fs/promises";import{dirname as dirname3,resolve}from"path";var DEFAULT_CONFIG5,FILE_SIZE_UNITS,resolvePath=(path2)=>{if(!path2||typeof path2!=="string")throw createFileManagerError("INVALID_PATH","Path must be a non-empty string",path2,"resolvePath");return resolve(path2)},extractDirectoryPath=(filePath)=>{let resolvedPath=resolvePath(filePath);return dirname3(resolvedPath)},ensureDirectoryExists=async(dirPath)=>{let resolvedPath=resolve(dirPath);try{await mkdir4(resolvedPath,{recursive:!0})}catch(error){if(error.code!=="EEXIST")throw createFileManagerError("DIRECTORY_CREATE_FAILED",`Failed to create directory: ${resolvedPath}`,resolvedPath,"ensureDirectory")}},formatFileSize=(bytes)=>{let size=bytes,unitIndex=0;while(size>=1024&&unitIndex<FILE_SIZE_UNITS.length-1)size/=1024,unitIndex++;return`${size.toFixed(2)} ${FILE_SIZE_UNITS[unitIndex]}`},validateFileExtension=(fileName,expectedExtension)=>{return fileName.toLowerCase().endsWith(expectedExtension.toLowerCase())},ensureFileExtension=(fileName,extension)=>{let normalizedExtension=extension.startsWith(".")?extension:`.${extension}`;if(validateFileExtension(fileName,normalizedExtension))return fileName;return`${fileName}${normalizedExtension}`},createFileManagerError=(code,message,path2,operation)=>{return{code,message,path:path2,operation:operation||"unknown"}},safeJsonStringify=(data)=>{try{return JSON.stringify(data,null,2)}catch{return"{}"}},executeBulkOperation=async(items,operation,concurrency=DEFAULT_CONFIG5.maxConcurrency)=>{let results=[];for(let i=0;i<items.length;i+=concurrency){let batch3=items.slice(i,i+concurrency),batchPromises=[];for(let item of batch3)batchPromises.push(operation(item));let batchResults=await Promise.allSettled(batchPromises);results.push(...batchResults)}return results},validateConfig=(config,options={})=>{let errors=[],warnings=[],strict=options.strict??!0;if(config.defaultEncoding!==void 0){if(!["utf-8","utf8","ascii","base64","hex"].includes(config.defaultEncoding))errors.push(`Invalid defaultEncoding: ${config.defaultEncoding}`)}if(config.maxConcurrency!==void 0){if(!Number.isInteger(config.maxConcurrency)||config.maxConcurrency<1)errors.push("maxConcurrency must be a positive integer");if(config.maxConcurrency>50)warnings.push("maxConcurrency > 50 may cause performance issues")}if(config.defaultCreateDir!==void 0&&typeof config.defaultCreateDir!=="boolean")errors.push("defaultCreateDir must be a boolean");if(config.defaultRecursive!==void 0&&typeof config.defaultRecursive!=="boolean")errors.push("defaultRecursive must be a boolean");if(strict&&!options.allowUnknownKeys){let validKeys=["defaultEncoding","defaultCreateDir","defaultRecursive","maxConcurrency"],configKeys=Object.keys(config);for(let key2 of configKeys)if(!validKeys.includes(key2))errors.push(`Unknown configuration key: ${key2}`)}return{isValid:errors.length===0,errors,warnings}},mergeConfig=(partial,base=DEFAULT_CONFIG5)=>{let validation=validateConfig(partial);if(!validation.isValid)throw createFileManagerError("CONFIG_VALIDATION_FAILED",`Configuration validation failed: ${validation.errors.join(", ")}`,void 0,"mergeConfig");return{...base,...partial}},parsePermissions=(mode)=>{let parseOctal=(octal)=>({read:Boolean(octal&4),write:Boolean(octal&2),execute:Boolean(octal&1)}),ownerMode=mode>>6&7,groupMode=mode>>3&7,othersMode=mode&7;return{owner:parseOctal(ownerMode),group:parseOctal(groupMode),others:parseOctal(othersMode)}},validatePermissionMode=(mode)=>{return Number.isInteger(mode)&&mode>=0&&mode<=511};var init_utils4=__esm(()=>{DEFAULT_CONFIG5={defaultEncoding:"utf-8",defaultCreateDir:!0,defaultRecursive:!0,maxConcurrency:5},FILE_SIZE_UNITS=["B","KB","MB","GB","TB"]});import{copyFile,rename as rename2,unlink as unlink4}from"fs/promises";import{basename,dirname as dirname4,extname,join as join5}from"path";var DEFAULT_ATOMIC_CONFIG,generateTempPath=(originalPath,suffix=".tmp")=>{let resolvedPath=resolvePath(originalPath),timestamp=Date.now(),random=Math.random().toString(36).substring(2,8);return`${resolvedPath}${suffix}.${timestamp}.${random}`},generateBackupPath=(originalPath,backupDir,useTimestamp=!0)=>{let resolvedPath=resolvePath(originalPath),dir=backupDir?resolvePath(backupDir):dirname4(resolvedPath),name=basename(resolvedPath),ext=extname(name),nameWithoutExt=basename(name,ext),timestamp=useTimestamp?`.${new Date().toISOString().replace(/[:.]/g,"-")}`:"",backupName=`${nameWithoutExt}.backup${timestamp}${ext}`;return join5(dir,backupName)},atomicWrite=async({path:path2,data,tempSuffix=DEFAULT_ATOMIC_CONFIG.tempSuffix,backup=DEFAULT_ATOMIC_CONFIG.backup,sync=DEFAULT_ATOMIC_CONFIG.sync})=>{let resolvedPath=resolvePath(path2),tempPath=generateTempPath(resolvedPath,tempSuffix),backupPath;try{if(await ensureDirectoryExists(extractDirectoryPath(resolvedPath)),backup){if(await Bun.file(resolvedPath).exists())backupPath=generateBackupPath(resolvedPath),await copyFile(resolvedPath,backupPath)}let bytesWritten=await Bun.write(tempPath,data);return await rename2(tempPath,resolvedPath),{success:!0,bytesWritten,tempPath,backupPath}}catch(error){try{await unlink4(tempPath)}catch{}throw createFileManagerError("ATOMIC_WRITE_FAILED",`Atomic write failed: ${error}`,resolvedPath,"atomicWrite")}},atomicJsonWrite=async(path2,data,options={})=>{let jsonString=JSON.stringify(data,null,2);return atomicWrite({path:path2,data:jsonString,...options})},createBackup=async({sourcePath,backupDir,keepOriginal=!0,timestamp=DEFAULT_ATOMIC_CONFIG.timestamp})=>{let resolvedSource=resolvePath(sourcePath);if(!await Bun.file(resolvedSource).exists())throw createFileManagerError("SOURCE_NOT_FOUND",`Source file not found: ${sourcePath}`,resolvedSource,"createBackup");let backupPath=generateBackupPath(resolvedSource,backupDir,timestamp);if(await ensureDirectoryExists(dirname4(backupPath)),keepOriginal)await copyFile(resolvedSource,backupPath);else await rename2(resolvedSource,backupPath);return backupPath},restoreFromBackup=async(backupPath,targetPath,deleteBackup=!1)=>{let resolvedBackup=resolvePath(backupPath),resolvedTarget=resolvePath(targetPath);if(!await Bun.file(resolvedBackup).exists())throw createFileManagerError("BACKUP_NOT_FOUND",`Backup file not found: ${backupPath}`,resolvedBackup,"restoreFromBackup");try{if(await ensureDirectoryExists(extractDirectoryPath(resolvedTarget)),deleteBackup)await rename2(resolvedBackup,resolvedTarget);else await copyFile(resolvedBackup,resolvedTarget);return!0}catch(error){return logger.scoped("storage.fs").error(`Failed to restore from backup ${backupPath}`,error,{backupPath}),!1}},safeUpdate=async(path2,updateFunction,options={})=>{let resolvedPath=resolvePath(path2),file=Bun.file(resolvedPath),backupPath;try{if(await file.exists())backupPath=await createBackup({sourcePath:resolvedPath,keepOriginal:!0,timestamp:!0});let currentData=await file.exists()?await file.text():"",newData=await updateFunction(currentData),result=await atomicWrite({path:resolvedPath,data:newData,backup:!1,...options});return{success:result.success,bytesWritten:result.bytesWritten,tempPath:result.tempPath,backupPath}}catch(error){if(backupPath)try{await restoreFromBackup(backupPath,resolvedPath,!1)}catch(rollbackError){logger.scoped("storage.fs").error("Atomic write rollback failed",rollbackError,{backupPath})}throw error}},batchAtomicWrite=async(operations)=>{let successful=[],failed=[];for(let operation of operations)try{let result=await atomicWrite(operation);successful.push(result)}catch(error){failed.push({operation,error})}return{successful,failed}};var init_atomic=__esm(()=>{init_Logger2();init_utils4();DEFAULT_ATOMIC_CONFIG={tempSuffix:".tmp",backup:!1,sync:!0,timestamp:!0}});import{chmod,stat as stat3}from"fs/promises";var PERMISSION_MODES,setFilePermissions=async(path2,mode)=>{let resolvedPath=resolvePath(path2);if(!validatePermissionMode(mode))throw createFileManagerError("INVALID_PERMISSION_MODE",`Invalid permission mode: ${mode.toString(8)}`,resolvedPath,"setFilePermissions");try{return await chmod(resolvedPath,mode),!0}catch(error){return logger.scoped("storage.fs").error(`Failed to set permissions for ${path2}`,error,{path:path2,mode}),!1}},getFilePermissions=async(path2)=>{let resolvedPath=resolvePath(path2);try{let mode=(await stat3(resolvedPath)).mode&511,permissions=parsePermissions(mode);return{path:resolvedPath,mode,owner:permissions.owner,group:permissions.group,others:permissions.others}}catch(error){throw createFileManagerError("PERMISSION_READ_FAILED",`Failed to read permissions: ${error}`,resolvedPath,"getFilePermissions")}},hasPermissions=async(path2,requiredMode)=>{try{return((await getFilePermissions(path2)).mode&requiredMode)===requiredMode}catch{return!1}},makeReadable=async(path2)=>{let newMode=(await getFilePermissions(path2)).mode|256;return setFilePermissions(path2,newMode)},makeWritable=async(path2)=>{let newMode=(await getFilePermissions(path2)).mode|128;return setFilePermissions(path2,newMode)},makeExecutable=async(path2)=>{let newMode=(await getFilePermissions(path2)).mode|64;return setFilePermissions(path2,newMode)},makeReadOnly=async(path2)=>{let newMode=(await getFilePermissions(path2)).mode&-147;return setFilePermissions(path2,newMode)},setCommonPermissions=async(path2,pattern)=>{let mode=PERMISSION_MODES[pattern];return setFilePermissions(path2,mode)};var init_permissions=__esm(()=>{init_Logger2();init_utils4();PERMISSION_MODES={OWNER_READ_WRITE:384,OWNER_ALL:448,GROUP_READ:416,GROUP_READ_WRITE:432,ALL_READ:420,ALL_READ_WRITE:438,ALL_READ_EXECUTE:493,ALL_FULL:511,READ_ONLY:292,EXECUTABLE:493}});var DEFAULT_STREAM_CONFIG,createFileWriter=async(path2,options={})=>{let resolvedPath=resolvePath(path2),config={...DEFAULT_STREAM_CONFIG,...options};await ensureDirectoryExists(extractDirectoryPath(resolvedPath));let writer=Bun.file(resolvedPath).writer({highWaterMark:config.highWaterMark}),isClosed=!1;return{write:(chunk)=>{if(isClosed)throw createFileManagerError("WRITER_CLOSED","Cannot write to closed writer",resolvedPath,"streamWrite");try{let result=writer.write(chunk);if(config.autoFlush)writer.flush();return result}catch(error){throw createFileManagerError("WRITE_FAILED",`Failed to write chunk: ${error}`,resolvedPath,"streamWrite")}},flush:()=>{if(isClosed)return 0;try{return writer.flush()}catch(error){throw createFileManagerError("FLUSH_FAILED",`Failed to flush writer: ${error}`,resolvedPath,"streamFlush")}},end:async(error)=>{if(isClosed)return 0;try{let result=await writer.end(error);return isClosed=!0,result}catch(err){throw isClosed=!0,createFileManagerError("END_FAILED",`Failed to end writer: ${err}`,resolvedPath,"streamEnd")}},ref:()=>{if(!isClosed)writer.ref()},unref:()=>{if(!isClosed)writer.unref()}}},writeStream=async(path2,chunks,options={})=>{let writer=await createFileWriter(path2,options),totalBytes=0;try{for(let chunk of chunks){let bytesWritten=writer.write(chunk);totalBytes+=bytesWritten}return await writer.flush(),await writer.end(),totalBytes}catch(error){try{await writer.end(error)}catch{}throw error}},appendStream=async(path2,chunks,options={})=>{let resolvedPath=resolvePath(path2),file=Bun.file(resolvedPath),existingContent=await file.exists()?await file.arrayBuffer():new ArrayBuffer(0),allChunks=[];if(existingContent.byteLength>0)allChunks.push(existingContent);return allChunks.push(...chunks),writeStream(resolvedPath,allChunks,options)},copyFileStream=async(sourcePath,destinationPath,options={})=>{let resolvedSource=resolvePath(sourcePath),sourceFile=Bun.file(resolvedSource);if(!await sourceFile.exists())throw createFileManagerError("SOURCE_NOT_FOUND",`Source file not found: ${sourcePath}`,resolvedSource,"copyFileStream");let sourceStream=sourceFile.stream(),writer=await createFileWriter(destinationPath,options),totalBytes=0;try{let reader=sourceStream.getReader();while(!0){let{done,value}=await reader.read();if(done)break;let bytesWritten=writer.write(value);totalBytes+=bytesWritten}return await writer.flush(),await writer.end(),totalBytes}catch(error){try{await writer.end(error)}catch{}throw error}},readFileStream=async(path2,chunkProcessor)=>{let resolvedPath=resolvePath(path2),file=Bun.file(resolvedPath);if(!await file.exists())throw createFileManagerError("FILE_NOT_FOUND",`File not found: ${path2}`,resolvedPath,"readFileStream");let reader=file.stream().getReader();try{while(!0){let{done,value}=await reader.read();if(done)break;await chunkProcessor(value)}}finally{reader.releaseLock()}};var init_streaming=__esm(()=>{init_utils4();DEFAULT_STREAM_CONFIG={highWaterMark:1048576,autoFlush:!0,closeOnEnd:!0}});import{readdir as readdir2,rm,rmdir,stat as stat4}from"fs/promises";import{extname as extname2,join as join6}from"path";class BunFileManager{static instance;config;constructor(){this.config={...DEFAULT_CONFIG5}}static getInstance(){if(!BunFileManager.instance)BunFileManager.instance=new BunFileManager;return BunFileManager.instance}async createFile({dir,name,data,options={}}){let filePath=resolvePath(join6(dir,name));if(options.createDir!==!1)await ensureDirectoryExists(extractDirectoryPath(filePath));let fileData=options.type?new Blob([data],{type:options.type}):data;return await Bun.write(filePath,fileData)}async createJsonFile(dir,name,data){let fileName=ensureFileExtension(name,".json"),jsonString=safeJsonStringify(data);return this.createFile({dir,name:fileName,data:jsonString,options:{type:"application/json"}})}async createDirectory({path:path2}){await ensureDirectoryExists(path2)}async readFile({path:path2,format="text"}){let resolvedPath=resolvePath(path2),file=Bun.file(resolvedPath);if(!await file.exists())throw createFileManagerError("FILE_NOT_FOUND",`File not found: ${path2}`,resolvedPath,"readFile");switch(format){case"text":return await file.text();case"json":return await file.json();case"buffer":return await file.arrayBuffer();case"bytes":return await file.bytes();case"stream":return file.stream();default:return await file.text()}}async readJsonFile(path2){return this.readFile({path:path2,format:"json"})}async getFileInfo(path2){let resolvedPath=resolvePath(path2),file=Bun.file(resolvedPath),fileName=path2.split("/").pop()||path2,stats=null;try{stats=await stat4(resolvedPath)}catch{}return{name:fileName,path:resolvedPath,size:file.size,type:file.type,exists:await file.exists(),extension:extname2(fileName),createdAt:stats?.birthtime,modifiedAt:stats?.mtime}}async readDirectory({path:path2,recursive=!1}){let resolvedPath=resolvePath(path2);return await readdir2(resolvedPath,{recursive,encoding:"utf8"})}async getFilesByExtension(dir,extension){let files=await this.readDirectory({path:dir}),normalizedExt=extension.startsWith(".")?extension:`.${extension}`;return files.filter((file)=>file.endsWith(normalizedExt))}async updateFile({path:path2,data,mode="overwrite"}){let resolvedPath=resolvePath(path2);if(mode==="append"){let combinedData=await this.readFile({path:path2,format:"text"})+data;return await Bun.write(resolvedPath,combinedData)}return await Bun.write(resolvedPath,data)}async updateJsonFile(path2,data,merge=!1){let finalData=data;if(merge)try{let existingData=await this.readJsonFile(path2);if(typeof existingData==="object"&&existingData!==null&&!Array.isArray(existingData)&&typeof data==="object"&&data!==null&&!Array.isArray(data))finalData={...existingData,...data}}catch{}return this.updateFile({path:path2,data:safeJsonStringify(finalData),mode:"overwrite"})}async appendToFile(path2,data){return this.updateFile({path:path2,data,mode:"append"})}async deleteFile(path2){try{let resolvedPath=resolvePath(path2);return await Bun.file(resolvedPath).delete(),!0}catch(error){return logger.scoped("storage.fs").error(`Failed to delete file ${path2}`,error,{path:path2}),!1}}async deleteDirectory({path:path2,recursive=!1}){try{let resolvedPath=resolvePath(path2);if(recursive)await rm(resolvedPath,{recursive:!0,force:!0});else await rmdir(resolvedPath);return!0}catch(error){return logger.scoped("storage.fs").error(`Failed to delete directory ${path2}`,error,{path:path2}),!1}}async deleteFiles(paths){let results=await executeBulkOperation(paths,async(path2)=>{if(!await this.deleteFile(path2))throw Error(`Failed to delete: ${path2}`);return path2}),success=[],failed=[];for(let i=0;i<results.length;i++){let result=results[i],originalPath=paths[i];if(result?.status==="fulfilled")success.push(originalPath||"");else failed.push(originalPath||"")}return{success,failed}}async exists(path2){let resolvedPath=resolvePath(path2);return await Bun.file(resolvedPath).exists()}async copyFile(sourcePath,destinationPath){let resolvedSource=resolvePath(sourcePath),resolvedDestination=resolvePath(destinationPath),sourceFile=Bun.file(resolvedSource);if(!await sourceFile.exists())throw createFileManagerError("SOURCE_NOT_FOUND",`Source file not found: ${sourcePath}`,resolvedSource,"copyFile");return await ensureDirectoryExists(extractDirectoryPath(resolvedDestination)),await Bun.write(resolvedDestination,sourceFile)}async moveFile(sourcePath,destinationPath){try{return await this.copyFile(sourcePath,destinationPath),await this.deleteFile(sourcePath),!0}catch(error){return logger.scoped("storage.fs").error("Failed to move file",error,{sourcePath,destinationPath}),!1}}getFormattedFileSize(bytes){return formatFileSize(bytes)}getConfig(){return{...this.config}}updateConfig(newConfig){let validation=validateConfig(newConfig);if(validation.isValid){let mergedConfig=mergeConfig(newConfig,this.config);Object.assign(this.config,mergedConfig)}return validation}validateConfiguration(config){return validateConfig(config)}async createStreamWriter(path2,options={}){return createFileWriter(path2,options)}async writeStream(path2,chunks,options={}){return writeStream(path2,chunks,options)}async appendStream(path2,chunks,options={}){return appendStream(path2,chunks,options)}async copyFileStream(sourcePath,destinationPath,options={}){return copyFileStream(sourcePath,destinationPath,options)}async readFileStream(path2,chunkProcessor){return readFileStream(path2,chunkProcessor)}async setPermissions(path2,mode){return setFilePermissions(path2,mode)}async setPermissionsAdvanced(options){return setFilePermissions(options.path,options.mode)}async getPermissions(path2){return getFilePermissions(path2)}async checkPermissions(path2,requiredMode){return hasPermissions(path2,requiredMode)}async makeFileReadable(path2){return makeReadable(path2)}async makeFileWritable(path2){return makeWritable(path2)}async makeFileExecutable(path2){return makeExecutable(path2)}async makeFileReadOnly(path2){return makeReadOnly(path2)}async setCommonPermission(path2,pattern){return setCommonPermissions(path2,pattern)}async atomicWrite(options){return atomicWrite(options)}async atomicJsonWrite(path2,data,options={}){return atomicJsonWrite(path2,data,options)}async createFileBackup(options){return createBackup(options)}async restoreFileFromBackup(backupPath,targetPath,deleteBackup=!1){return restoreFromBackup(backupPath,targetPath,deleteBackup)}async safeFileUpdate(path2,updateFunction,options={}){return safeUpdate(path2,updateFunction,options)}async batchAtomicOperations(operations){return batchAtomicWrite(operations)}}var init_core=__esm(()=>{init_Logger2();init_atomic();init_permissions();init_streaming();init_utils4()});var fileManager;var init_File=__esm(()=>{init_core();init_utils4();init_core();fileManager=BunFileManager.getInstance()});import{Pool}from"pg";var init_Postgre=__esm(()=>{init_Logger2()});var init_Managers=__esm(()=>{init_Azure();init_Dapr();init_File();init_Postgre();init_Redis()});var exports_utils={};__export(exports_utils,{warnIfAccessTokenTooLargeForCookie:()=>warnIfAccessTokenTooLargeForCookie,validatePayload:()=>validatePayload,validateEnvVariables:()=>validateEnvVariables,toAudit:()=>toAudit,signNewAccessToken:()=>signNewAccessToken,sanitizePayload:()=>sanitizePayload,resolveDbPoolConfig:()=>resolveDbPoolConfig,resolveConfigCredential:()=>resolveConfigCredential,refreshAccessTokenWithLock:()=>refreshAccessTokenWithLock,redactSensitiveOutput:()=>redactSensitiveOutput,parseTokenValuesFromHeaders:()=>parseTokenValuesFromHeaders,parseTimeToSeconds:()=>parseTimeToSeconds2,parseQueryParams:()=>parseQueryParams,isSensitiveOutputKey:()=>isSensitiveOutputKey,initiateRedisManager:()=>initiateRedisManager,getRedisManager:()=>getRedisManager,ensureDatabaseExists:()=>ensureDatabaseExists,decodeUnverifiedSubject:()=>decodeUnverifiedSubject,createAuditLog:()=>createAuditLog,buildPaginationMeta:()=>buildPaginationMeta,COOKIE_SAFE_TOKEN_BYTES:()=>COOKIE_SAFE_TOKEN_BYTES});function parseTokenValuesFromHeaders(headers,tokenNames){let cookies=(headers.get("cookie")?.split(";")||[]).reduce((acc,cookie)=>{let trimmed=cookie.trim(),eqIndex=trimmed.indexOf("=");if(eqIndex>0)acc[trimmed.slice(0,eqIndex)]=trimmed.slice(eqIndex+1);return acc},{});return{access_token:cookies[tokenNames.access_token]||headers.get("authorization")?.split(" ")[1],refresh_token:cookies[tokenNames.refresh_token],session_token:cookies[tokenNames.session_token]}}async function initiateRedisManager(config){if(!config.redis){logger.info("[Redis] Not configured, skipping");return}let rawWithDapr=config.redis.withDapr,resolvedWithDapr=typeof rawWithDapr==="string"?process.env[rawWithDapr]?.toLowerCase()!=="false":rawWithDapr??!1,resolvedKeyPrefix=config.redis.keyPrefix?process.env[config.redis.keyPrefix]??config.redis.keyPrefix:void 0;if(resolvedWithDapr){redisManagerInstance=new RedisManager({withDapr:!0,stateStoreName:config.redis.stateStoreName,...resolvedKeyPrefix?{keyPrefix:resolvedKeyPrefix}:{}});return}let resolvedUrl=config.redis.url?process.env[config.redis.url]:void 0,resolvedHost=config.redis.host?process.env[config.redis.host]:void 0,resolvedPort=config.redis.port?parseInt(process.env[config.redis.port]||"",10):void 0;if((process.env.REDIS_AUTH_MODE||"password")!=="password"){let{getRedisToken:getRedisToken2,getRedisTokenExpiresAt:getRedisTokenExpiresAt2}=await Promise.resolve().then(() => (init_Azure(),exports_Azure)),clientId=process.env.AZURE_CLIENT_ID||"",initialToken=await getRedisToken2();redisManagerInstance=new RedisManager({host:resolvedHost,port:Number.isNaN(resolvedPort)?void 0:resolvedPort,password:initialToken,username:clientId,tls:!0,...resolvedKeyPrefix?{keyPrefix:resolvedKeyPrefix}:{}});let unref=(t)=>{t.unref?.()},scheduleRedisTokenRefresh=()=>{let expiresAt=getRedisTokenExpiresAt2(),refreshIn=Math.max(expiresAt-Date.now()-300000,30000);unref(setTimeout(async()=>{try{let newToken=await getRedisToken2();if(redisManagerInstance)await redisManagerInstance.reauthenticate(clientId,newToken),logger.info("[Redis] Entra ID token refreshed successfully");scheduleRedisTokenRefresh()}catch(err){logger.error("[Redis] Token refresh failed \u2014 retrying in 30s",err),unref(setTimeout(scheduleRedisTokenRefresh,30000))}},refreshIn))};scheduleRedisTokenRefresh()}else{let resolvedPassword=process.env.REDIS_PASSWORD||void 0;redisManagerInstance=new RedisManager({url:resolvedUrl,host:resolvedHost,port:Number.isNaN(resolvedPort)?void 0:resolvedPort,...resolvedPassword?{password:resolvedPassword}:{},...resolvedKeyPrefix?{keyPrefix:resolvedKeyPrefix}:{}})}}function getRedisManager(){return redisManagerInstance}function parseTimeToSeconds2(timeString){if(typeof timeString==="number")return timeString;if(!timeString||timeString.trim()==="")throw Error("Time string cannot be empty");let match=timeString.trim().match(/^(\d+(?:\.\d+)?)\s*([smhdwMy])$/);if(!match||!match[1]||!match[2])throw Error(`Invalid time format: "${timeString}". Expected format: "75s", "10m", "2h", "1d", "1w", "2M", "1y"`);let value=parseFloat(match[1]),unit=match[2],multiplier={s:1,m:60,h:3600,d:86400,w:604800,M:2592000,y:31536000}[unit];if(multiplier===void 0)throw Error(`Unknown time unit: "${unit}"`);let seconds=Math.floor(value*multiplier);if(seconds<=0)throw Error(`Time value must be positive: "${timeString}"`);return seconds}function warnIfAccessTokenTooLargeForCookie(token,jwtClaimsMode){let bytes=Buffer.byteLength(token,"utf-8");if(bytes<=COOKIE_SAFE_TOKEN_BYTES)return;let now=Date.now();if(now-lastOversizeWarnAt<60000)return;lastOversizeWarnAt=now,logger.warn(`[Auth] access_token is ${bytes} bytes \u2014 at/over the ~4KB per-cookie browser limit, so the cookie may be `+"silently dropped (symptom: appears logged-in but requests are unauthenticated). Shrink it: set authorization.jwtClaimsMode:'resolve' (token carries only roles; claims resolved from the Redis claims cache), or deliver the token off-cookie via authentication.accessToken.setHeadersEnabled:false. "+(jwtClaimsMode?`Current jwtClaimsMode='${jwtClaimsMode}'.`:""))}function signNewAccessToken({sessionData,options,refreshTokenId,roles,claims,tenant,claimScopes,resolveMode}){let secretEnvName=options.authentication?.accessToken?.secret;if(!secretEnvName)throw Error("Access token secret env name is not configured");let secret=process.env[secretEnvName];if(!secret)throw Error(`Access token secret env "${secretEnvName}" is not set`);let token=signJWT({subject:sessionData.userId,issuer:options.authentication?.accessToken?.issuer,audience:options.authentication?.accessToken?.audience,algorithm:options.authentication?.accessToken?.algorithm,expiresInSeconds:parseTimeToSeconds2(options.authentication?.accessToken?.expiresIn??"15m"),sessionId:sessionData.id,customClaims:{refreshTokenId,...roles&&roles.length>0?{roles}:{},...!resolveMode&&claims&&claims.length>0?{claims}:{},...!resolveMode&&claimScopes&&Object.keys(claimScopes).length>0?{claimScopes}:{},...tenant?{tenant}:{}}},secret);return warnIfAccessTokenTooLargeForCookie(token,resolveMode?"resolve":options.authorization?.jwtClaimsMode),token}function resolveDbPoolConfig(pool){return{max:pool?.max!=null&&pool.max>0?pool.max:10,idleTimeoutMillis:pool?.idleTimeoutMillis??30000,connectionTimeoutMillis:pool?.connectionTimeoutMillis??1e4,...pool?.maxUses!=null&&pool.maxUses>0?{maxUses:pool.maxUses}:{}}}function toAudit(payload,summary,opts){return payload?{entityName:payload.entity_name,entityId:payload.entity_id===" - "?null:payload.entity_id,operation:payload.operation_type,userId:opts&&"userId"in opts?opts.userId??null:payload.user_id==="unknown"?null:payload.user_id,summary,severity:opts?.severity,category:opts?.category,ipAddress:payload.ip_address,userAgent:payload.user_agent,path:payload.path,query:payload.query}:void 0}function decodeUnverifiedSubject(token){if(!token)return null;try{let parts=token.split(".");if(parts.length<2)return null;let payloadPart=parts[1];if(!payloadPart)return null;let json=Buffer.from(payloadPart,"base64url").toString("utf-8"),decoded=JSON.parse(json);return typeof decoded.sub==="string"&&decoded.sub?decoded.sub:null}catch{return null}}function reconstructBracketParams(query){let result={},arrayGroups={};for(let[key2,value]of Object.entries(query)){let match=key2.match(/^(\w+)\[\d*\]\[(\w+)\]$/),arrayName=match?.[1],prop=match?.[2];if(arrayName&&prop){if(!arrayGroups[arrayName])arrayGroups[arrayName]={};let group=arrayGroups[arrayName];if(!group[prop])group[prop]=[];let arr=group[prop];if(Array.isArray(value))for(let v of value)arr.push(v);else arr.push(value)}else result[key2]=value}for(let[arrayName,props]of Object.entries(arrayGroups)){let propNames=Object.keys(props);if(propNames.length===0)continue;let maxLen=Math.max(...propNames.map((p)=>(props[p]||[]).length)),items=[];for(let i=0;i<maxLen;i++){let item={};for(let p of propNames)item[p]=(props[p]||[])[i];items.push(item)}result[arrayName]=items}return result}function parseQueryParams(query){let q=reconstructBracketParams(query),parseJSONOrPassthrough=(value)=>{if(value===void 0||value===null)return;if(typeof value==="object")return value;if(typeof value==="string")try{return JSON.parse(value)}catch{return}return},DEFAULT_PAGE_SIZE=20,MAX_PAGE_SIZE=200,rawPage=q.page?parseInt(q.page,10):1,page=Number.isFinite(rawPage)&&rawPage>0?rawPage:1,rawLimit=q.limit?parseInt(q.limit,10):20,limit=Number.isFinite(rawLimit)&&rawLimit>0?Math.min(rawLimit,200):20,rawOffset=q.offset?parseInt(q.offset,10):(page-1)*limit,offset=Number.isFinite(rawOffset)&&rawOffset>=0?rawOffset:0;return{page,limit,offset,search:q.search,searchFields:q.searchFields?q.searchFields.split(","):void 0,filters:parseJSONOrPassthrough(q.filters),sort:parseJSONOrPassthrough(q.sort),select:q.select?q.select.split(","):void 0,with:parseJSONOrPassthrough(q.with),distinct:q.distinct==="true",distinctOn:q.distinctOn?q.distinctOn.split(","):void 0}}function buildPaginationMeta(page,limit,offset,totalItems){let totalPages=Math.ceil(totalItems/limit),hasNextPage=page<totalPages,hasPrevPage=page>1;return{page,limit,offset,totalItems,totalPages,hasNextPage,hasPrevPage,nextPage:hasNextPage?page+1:null,prevPage:hasPrevPage?page-1:null}}function getBaseTypeValidator(type){let stringTypes=["varchar","char","text","uuid","citext","bit","varbit"],numberTypes=["integer","smallint","bigint","serial","smallserial","bigserial","real","doublePrecision","numeric","decimal"],booleanTypes=["boolean"];if(stringTypes.includes(type))return(v)=>({valid:typeof v==="string",expectedType:"string"});if(numberTypes.includes(type))return(v)=>({valid:typeof v==="number",expectedType:"number"});if(booleanTypes.includes(type))return(v)=>({valid:typeof v==="boolean",expectedType:"boolean"});if(type==="json"||type==="jsonb")return(v)=>({valid:typeof v==="object",expectedType:"object"});return()=>({valid:!0,expectedType:"any"})}function validatePayload(payload,columns,isPartial=!1){let errors=[];for(let col7 of columns){let value=payload[col7.name]??payload[col7.name.replace(/_([a-z])/g,(_,l)=>l.toUpperCase())],hasDbDefault=col7.default!==void 0||!!col7.defaultRaw||!!col7.generatedByDefaultAsIdentity||!!col7.generatedAlwaysAsIdentity||!!col7.generatedAlwaysAs,isRequired=col7.notNull&&!col7.nullable&&!hasDbDefault;if(value===void 0||value===null){if(isRequired&&!isPartial)errors.push({field:col7.name,message:col7.validation?.customMessage||`${col7.name} is required`});continue}if(col7.array){let baseValidator=getBaseTypeValidator(col7.type),expectedType=baseValidator(void 0).expectedType;if(!Array.isArray(value)){errors.push({field:col7.name,message:col7.validation?.customMessage||`${col7.name} must be an array of ${expectedType}`});continue}if(value.some((el)=>el!==null&&!baseValidator(el).valid))errors.push({field:col7.name,message:col7.validation?.customMessage||`${col7.name} must be an array of ${expectedType}`});continue}let typeCheck=getBaseTypeValidator(col7.type)(value);if(!typeCheck.valid){errors.push({field:col7.name,message:col7.validation?.customMessage||`${col7.name} must be of type ${typeCheck.expectedType}`});continue}if(typeof value==="string"){let len=value.length;if(col7.length&&len>col7.length)errors.push({field:col7.name,message:col7.validation?.customMessage||`${col7.name} exceeds max length of ${col7.length}`});if(col7.validation?.minLength&&len<col7.validation.minLength)errors.push({field:col7.name,message:col7.validation.customMessage||`${col7.name} must be at least ${col7.validation.minLength} characters`});if(col7.validation?.maxLength&&len>col7.validation.maxLength)errors.push({field:col7.name,message:col7.validation.customMessage||`${col7.name} must be at most ${col7.validation.maxLength} characters`});if(col7.validation?.pattern){if(!new RegExp(col7.validation.pattern).test(value))errors.push({field:col7.name,message:col7.validation.customMessage||`${col7.name} does not match required pattern`})}if(col7.validation?.format){let formatRegex=FORMAT_PATTERNS[col7.validation.format];if(formatRegex&&!formatRegex.test(value))errors.push({field:col7.name,message:col7.validation.customMessage||`${col7.name} must be a valid ${col7.validation.format}`})}}if(typeof value==="number"){if(col7.validation?.min!==void 0&&value<col7.validation.min)errors.push({field:col7.name,message:col7.validation.customMessage||`${col7.name} must be at least ${col7.validation.min}`});if(col7.validation?.max!==void 0&&value>col7.validation.max)errors.push({field:col7.name,message:col7.validation.customMessage||`${col7.name} must be at most ${col7.validation.max}`})}if(col7.enumValues&&col7.enumValues.length>0){if(!col7.enumValues.includes(value))errors.push({field:col7.name,message:col7.validation?.customMessage||`${col7.name} must be one of: ${col7.enumValues.join(", ")}`})}}return{valid:errors.length===0,errors}}function escapeHtml(str3){return str3.replace(/[&<>"'`=/]/g,(char)=>HTML_ENTITIES[char]||char)}function stripTags(str3){return str3.replace(/<[^>]*>/g,"")}function normalizeEmail(email){let parts=email.split("@"),localPart=parts[0],domain=parts[1];if(!localPart||!domain)return email;let beforePlus=localPart.split("+")[0];if(!beforePlus)return email;return`${beforePlus.replace(/\./g,"")}@${domain.toLowerCase()}`}function slugify(str3){return str3.toLowerCase().trim().replace(/[^\w\s-]/g,"").replace(/[\s_-]+/g,"-").replace(/^-+|-+$/g,"")}function applySanitizer(value,sanitizer){if(value===null||value===void 0)return value;switch(sanitizer){case"trim":return typeof value==="string"?value.trim():value;case"lowercase":return typeof value==="string"?value.toLowerCase():value;case"uppercase":return typeof value==="string"?value.toUpperCase():value;case"escapeHtml":return typeof value==="string"?escapeHtml(value):value;case"stripTags":return typeof value==="string"?stripTags(value):value;case"normalizeEmail":return typeof value==="string"?normalizeEmail(value):value;case"toNumber":if(typeof value==="number")return value;if(typeof value==="string"){let num2=Number(value);return Number.isNaN(num2)?value:num2}return value;case"toBoolean":if(typeof value==="boolean")return value;if(typeof value==="string"){let lower=value.toLowerCase();if(lower==="true"||lower==="1"||lower==="yes")return!0;if(lower==="false"||lower==="0"||lower==="no")return!1}if(typeof value==="number")return value!==0;return value;case"slugify":return typeof value==="string"?slugify(value):value;default:return value}}function isSensitiveOutputKey(key2){return SENSITIVE_OUTPUT_KEYS.has(key2)}function redactSensitiveOutput(row){return scrubSensitive(row)}function scrubSensitive(value){if(value===null||typeof value!=="object")return value;if(Array.isArray(value))return value.map(scrubSensitive);let proto=Object.getPrototypeOf(value);if(proto!==Object.prototype&&proto!==null)return value;let out={};for(let[k,v]of Object.entries(value)){if(SENSITIVE_OUTPUT_KEYS.has(k))continue;out[k]=scrubSensitive(v)}return out}function sanitizePayload(payload,columns,opts){let sanitized={},toCamel2=(s)=>s.replace(/_([a-z])/g,(_,l)=>l.toUpperCase()),SERVER_MANAGED=new Set(["id","created_at","updated_at","created_by","updated_by","createdAt","updatedAt","createdBy","updatedBy"]),PROTECTED_SENSITIVE=new Set(["is_god","password","password_hash","email_verified","verified_at","email_verified_at","is_locked","locked_until","failed_login_attempts","login_count","last_login_at","email_verification_token","email_verification_sent_at","email_verification_expires_at","password_reset_token","password_reset_expires_at","password_reset_sent_at","magic_link_token","two_factor_secret"]),STORAGE_MANAGED=opts?.isFormData?new Set(["path","name","original_name","originalName","extension","size","mime_type","mimeType","uploaded_by","uploadedBy"]):null;for(let key2 of Object.keys(payload)){if(SERVER_MANAGED.has(key2))continue;if(STORAGE_MANAGED?.has(key2))continue;let value=payload[key2],snakeKey=key2.replace(/[A-Z]/g,(l)=>`_${l.toLowerCase()}`);if(PROTECTED_SENSITIVE.has(snakeKey))continue;let col7=columns.find((c)=>c.name===key2||c.name===snakeKey);if(col7?.readOnly)continue;if(col7?.sanitize&&col7.sanitize.length>0)for(let sanitizer of col7.sanitize)value=applySanitizer(value,sanitizer);if(col7&&(col7.type==="timestamp"||col7.type==="timestamptz"||col7.type==="date")&&typeof value==="string"){let parsed=new Date(value);if(!Number.isNaN(parsed.getTime()))value=parsed}let normalizedKey=key2.includes("_")?toCamel2(key2):key2;sanitized[normalizedKey]=value}return sanitized}function createAuditLog(db,auditTable,entry){if(!db||!auditTable)return;let logEntry={user_id:entry.user_id,entity_name:entry.entity_name,entity_id:entry.entity_id,operation:entry.operation,old_data:entry.old_data??null,new_data:entry.new_data??null,timestamp:new Date().toISOString()};db.insert(auditTable).values(logEntry).execute().catch((err)=>{logger.error("[Audit] Database audit write failed",err,{entity:logEntry.entity_name,operation:logEntry.operation})})}async function refreshAccessTokenWithLock(userId,sessionId,generateToken){let redis=new RedisManager,lockKey=`${REFRESH_LOCK_PREFIX}${userId}`,cacheKey=`${ACCESS_TOKEN_CACHE_PREFIX}${userId}:${sessionId}`,cachedResult=await redis.read(cacheKey);if(cachedResult.success&&cachedResult.data)return{success:!0,accessToken:cachedResult.data,fromCache:!0};let lockResult=await redis.acquireLock(lockKey,LOCK_TTL_SECONDS);if(!lockResult.success)return{success:!1,error:lockResult.error};if(lockResult.data)try{let newToken=generateToken();return await redis.create(cacheKey,newToken,ACCESS_TOKEN_CACHE_TTL_SECONDS),{success:!0,accessToken:newToken,fromCache:!1}}finally{await redis.releaseLock(lockKey)}let waitResult=await redis.waitForLock(lockKey,LOCK_WAIT_TIMEOUT_MS,50);if(!waitResult.success)return{success:!1,error:waitResult.error};if(!waitResult.data)return{success:!1,error:"Lock wait timeout"};let newCachedResult=await redis.read(cacheKey);if(newCachedResult.success&&newCachedResult.data)return{success:!0,accessToken:newCachedResult.data,fromCache:!0};let fallbackToken=generateToken();return await redis.create(cacheKey,fallbackToken,ACCESS_TOKEN_CACHE_TTL_SECONDS),{success:!0,accessToken:fallbackToken,fromCache:!1}}function resolveConfigCredential(value){if(!value)return;let fromEnv=process.env[value];if(fromEnv)return fromEnv;if(/^[A-Z][A-Z0-9_]{2,}$/.test(value))return;return value}function validateEnvVariables(config){let errors=[],resolved={},databaseAuthMode=process.env.DATABASE_AUTH_MODE||"password",redisAuthMode=process.env.REDIS_AUTH_MODE||"password";resolved.databaseAuthMode=databaseAuthMode,resolved.redisAuthMode=redisAuthMode;let entraIdModes=["managed_identity","service_principal"];if(entraIdModes.includes(databaseAuthMode)||entraIdModes.includes(redisAuthMode)){if(!process.env.AZURE_CLIENT_ID)logger.warn("[Config] AZURE_CLIENT_ID is not set. Required for user-assigned managed identity.");if([databaseAuthMode,redisAuthMode].filter((m)=>m==="service_principal").length>0){if(!process.env.AZURE_TENANT_ID)errors.push({field:"azure.tenantId",envName:"AZURE_TENANT_ID",message:"AZURE_TENANT_ID is required for service_principal auth mode."});if(!process.env.AZURE_CLIENT_SECRET)errors.push({field:"azure.clientSecret",envName:"AZURE_CLIENT_SECRET",message:"AZURE_CLIENT_SECRET is required for service_principal auth mode."})}}if(config.database?.url){let envValue=process.env[config.database.url];if(!envValue)errors.push({field:"database.url",envName:config.database.url,message:`Environment variable "${config.database.url}" is not set. Please set it in your .env file.`});else resolved.databaseUrl=envValue}let validationWithDapr=typeof config.redis?.withDapr==="string"?process.env[config.redis.withDapr]?.toLowerCase()!=="false":config.redis?.withDapr??!1;if(config.redis&&!validationWithDapr)if(config.redis.url){let envValue=process.env[config.redis.url];if(!envValue)errors.push({field:"redis.url",envName:config.redis.url,message:`Environment variable "${config.redis.url}" is not set. Please set it in your .env file.`});else resolved.redisUrl=envValue}else{if(config.redis.host){if(!process.env[config.redis.host])errors.push({field:"redis.host",envName:config.redis.host,message:`Environment variable "${config.redis.host}" is not set. Please set it in your .env file.`})}if(config.redis.port){if(!process.env[config.redis.port])errors.push({field:"redis.port",envName:config.redis.port,message:`Environment variable "${config.redis.port}" is not set. Please set it in your .env file.`})}}if(config.authentication?.enabled){if(!config.authentication.mode)errors.push({field:"authentication.mode",envName:"",message:'authentication.mode is required when authentication is enabled. Use "full" for IDP/standalone services, "consumer" for resource servers.'});if(config.authentication.accessToken?.secret){let envValue=process.env[config.authentication.accessToken.secret];if(!envValue)errors.push({field:"authentication.accessToken.secret",envName:config.authentication.accessToken.secret,message:`Environment variable "${config.authentication.accessToken.secret}" is not set. Please set it in your .env file.`});else resolved.accessTokenSecret=envValue}else errors.push({field:"authentication.accessToken.secret",envName:"",message:"authentication.accessToken.secret is required when authentication is enabled."});let isConsumerMode=config.authentication.mode==="consumer";if(config.authentication.refreshToken?.secret){let envValue=process.env[config.authentication.refreshToken.secret];if(!envValue)errors.push({field:"authentication.refreshToken.secret",envName:config.authentication.refreshToken.secret,message:`Environment variable "${config.authentication.refreshToken.secret}" is not set. Please set it in your .env file.`});else resolved.refreshTokenSecret=envValue}else if(!isConsumerMode)errors.push({field:"authentication.refreshToken.secret",envName:"",message:"authentication.refreshToken.secret is required when authentication is enabled."});if(config.authentication.sessionToken?.secret){let envValue=process.env[config.authentication.sessionToken.secret];if(!envValue)errors.push({field:"authentication.sessionToken.secret",envName:config.authentication.sessionToken.secret,message:`Environment variable "${config.authentication.sessionToken.secret}" is not set. Please set it in your .env file.`});else resolved.sessionTokenSecret=envValue}else if(!isConsumerMode)errors.push({field:"authentication.sessionToken.secret",envName:"",message:"authentication.sessionToken.secret is required when authentication is enabled."})}if(config.authentication?.oauth?.enabled&&config.authentication.oauth.providers){let resolvedProviders={};for(let[providerName,providerConfig]of Object.entries(config.authentication.oauth.providers)){if(!providerConfig)continue;let{clientId:clientIdEnvName,clientSecret:clientSecretEnvName,redirectUri:redirectUriEnvName,tenantId:tenantIdEnvName}=providerConfig,clientId=resolveConfigCredential(clientIdEnvName),clientSecret=resolveConfigCredential(clientSecretEnvName),redirectUri=resolveConfigCredential(redirectUriEnvName),tenantId=resolveConfigCredential(tenantIdEnvName),credentialsMayComeFromDb=config.secrets?.enabled===!0;if(!clientId&&!credentialsMayComeFromDb)errors.push({field:`authentication.oauth.providers.${providerName}.clientId`,envName:clientIdEnvName,message:`Environment variable "${clientIdEnvName}" is not set (OAuth ${providerName} clientId).`});if(!clientSecret&&!credentialsMayComeFromDb)errors.push({field:`authentication.oauth.providers.${providerName}.clientSecret`,envName:clientSecretEnvName,message:`Environment variable "${clientSecretEnvName}" is not set (OAuth ${providerName} clientSecret).`});if(clientId&&clientSecret||credentialsMayComeFromDb)resolvedProviders[providerName]={clientId:clientId??"",clientSecret:clientSecret??"",redirectUri:redirectUri??"",tenantId,scopes:providerConfig.scopes,authorizationUrl:providerConfig.authorizationUrl,tokenUrl:providerConfig.tokenUrl,userInfoUrl:providerConfig.userInfoUrl,extraAuthParams:providerConfig.extraAuthParams}}if(Object.keys(resolvedProviders).length>0)resolved.oauthProviders=resolvedProviders}return{valid:errors.length===0,errors,resolved}}async function ensureDatabaseExists(databaseUrl,logger2,authMode){let{Pool:Pool2}=await import("pg"),targetDb=new URL(databaseUrl).pathname.replace("/","");if(!targetDb)return;let adminUrl=new URL(databaseUrl);adminUrl.pathname="/postgres";let pool;if(authMode&&authMode!=="password"){let{getPostgresToken:getPostgresToken2}=await Promise.resolve().then(() => (init_Azure(),exports_Azure));pool=new Pool2({connectionString:adminUrl.toString(),password:getPostgresToken2,ssl:{rejectUnauthorized:!0}})}else pool=new Pool2({connectionString:adminUrl.toString()});try{if((await pool.query("SELECT 1 FROM pg_database WHERE datname = $1",[targetDb])).rowCount===0)logger2.info(`[Database] Creating database "${targetDb}"...`),await pool.query(`CREATE DATABASE "${targetDb}" TEMPLATE template0`),logger2.info(`[Database] Database "${targetDb}" created successfully`);else logger2.info(`[Database] Database "${targetDb}" exists`)}catch(err){let message=err instanceof Error?err.message:String(err);logger2.warn(`[Database] Could not auto-create database: ${message}`)}finally{await pool.end()}}var redisManagerInstance=null,COOKIE_SAFE_TOKEN_BYTES=3500,lastOversizeWarnAt=0,FORMAT_PATTERNS,HTML_ENTITIES,SENSITIVE_OUTPUT_KEYS,ACCESS_TOKEN_CACHE_PREFIX="access_token:",REFRESH_LOCK_PREFIX="refresh_lock:",LOCK_TTL_SECONDS=5,LOCK_WAIT_TIMEOUT_MS=3000,ACCESS_TOKEN_CACHE_TTL_SECONDS=60;var init_utils5=__esm(()=>{init_Managers();init_Services();init_Logger2();FORMAT_PATTERNS={email:/^[^\s@]+@[^\s@]+\.[^\s@]+$/,url:/^https?:\/\/.+/,uuid:/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i,date:/^\d{4}-\d{2}-\d{2}$/,datetime:/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/,time:/^\d{2}:\d{2}:\d{2}$/,uri:/^[a-z][a-z0-9+.-]*:/i,ipv4:/^(\d{1,3}\.){3}\d{1,3}$/,ipv6:/^([0-9a-f]{1,4}:){7}[0-9a-f]{1,4}$/i};HTML_ENTITIES={"&":"&","<":"<",">":">",'"':""","'":"'","/":"/","`":"`","=":"="};SENSITIVE_OUTPUT_KEYS=new Set(["password","passwordHash","password_hash","emailVerificationToken","email_verification_token","emailVerificationTokenExpiresAt","email_verification_token_expires_at","passwordResetToken","password_reset_token","refreshTokenHash","refresh_token_hash"])});import{eq as eq13,sql as sql5}from"drizzle-orm";import{pgSchema}from"drizzle-orm/pg-core";class TenantRegistry{db;logger;mainSchemaName;mainSchemaTables;mainSchemaRelations;createAllTablesForSchema;createAllRelationsForSchema;appId;authMode;tenantResolution;tenantHeader;redisCacheTtlSeconds;defaultTrustedSources;idpUrl;allowDataLoss;onTenantProvisioned;tenantsBySubdomain=new Map;tenantsBySchemaName=new Map;tenantsById=new Map;schemaContexts=new Map;tenantFeatures=new Map;tenantsByDomainHostname=new Map;constructor(config){this.db=config.db,this.logger=config.logger,this.mainSchemaName=config.mainSchemaName,this.mainSchemaTables=config.mainSchemaTables,this.mainSchemaRelations=config.mainSchemaRelations,this.createAllTablesForSchema=config.createAllTablesForSchema,this.createAllRelationsForSchema=config.createAllRelationsForSchema,this.appId=config.appId,this.authMode=config.authMode,this.tenantResolution=config.tenantResolution,this.tenantHeader=config.tenantHeader,this.redisCacheTtlSeconds=config.redisCacheTtlSeconds,this.defaultTrustedSources=config.defaultTrustedSources,this.idpUrl=config.idpUrl,this.allowDataLoss=config.allowDataLoss===!0,this.onTenantProvisioned=config.onTenantProvisioned}async initialize(){this.logger.info("[TenantRegistry] Initializing..."),this.schemaContexts.set(this.mainSchemaName,{schemaName:this.mainSchemaName,schemaTables:this.mainSchemaTables,schemaRelations:this.mainSchemaRelations,tenant:null});let tenants=await this.loadTenantsFromDb();this.logger.info(`[TenantRegistry] Loaded ${tenants.length} tenants from database`);let features=await this.loadTenantFeaturesFromDb();this.logger.info(`[TenantRegistry] Loaded ${features.length} tenant feature mappings`);for(let tenant of tenants)this.indexTenant(tenant);for(let feature of features){let existing=this.tenantFeatures.get(feature.tenantId)||[];existing.push(feature),this.tenantFeatures.set(feature.tenantId,existing)}let activeTenants=tenants.filter((t)=>t.status==="active");for(let tenant of activeTenants)await this.buildSchemaContext(tenant);await this.loadDomainHostnames(),this.logger.info(`[TenantRegistry] Initialized with ${activeTenants.length} active tenant schemas + main schema`)}resolveFromRequest(request,vettedClientIp){let url=new URL(request.url),host=request.headers.get("host")||url.host||"",normalizedHost=normalizeHost(host);if(normalizedHost){let byHostname=this.tenantsByDomainHostname.get(normalizedHost);if(byHostname)return this.validateAndReturnTenant(byHostname)}if(this.tenantResolution==="subdomain"||this.tenantResolution==="both"){let subdomain=extractSubdomain(host);if(subdomain){let tenant=this.tenantsBySubdomain.get(subdomain);if(tenant)return this.validateAndReturnTenant(tenant);return{resolved:!1,error:`Tenant not found for subdomain: ${subdomain}`,statusCode:404}}}if(this.tenantResolution==="header"||this.tenantResolution==="both"){let tenantIdOrSubdomain=request.headers.get(this.tenantHeader);if(tenantIdOrSubdomain){let result=this.resolveFromHeader(tenantIdOrSubdomain,request,vettedClientIp);if(result)return result}}let mainContext=this.schemaContexts.get(this.mainSchemaName);if(mainContext)return{resolved:!0,context:mainContext};return{resolved:!1,error:"No tenant could be resolved and main schema is unavailable",statusCode:500}}getSchemaContext(schemaName){return this.schemaContexts.get(schemaName)}getMainContext(){let ctx=this.schemaContexts.get(this.mainSchemaName);if(!ctx)throw Error("[TenantRegistry] Main schema context not initialized");return ctx}getActiveTenants(){return Array.from(this.tenantsById.values()).filter((t)=>t.status==="active")}getTenantById(id){return this.tenantsById.get(id)}getTenantBySchemaName(schemaName){return this.tenantsBySchemaName.get(schemaName)}getTenantFeatures(tenantId){return this.tenantFeatures.get(tenantId)||[]}isTenantFeatureEnabled(tenantId,featureName){return(this.tenantFeatures.get(tenantId)||[]).find((f)=>f.featureName===featureName)?.enabled??!1}getTenantIdsWithFeature(featureName){let result=[];for(let[tenantId,features]of this.tenantFeatures)if(features.find((f)=>f.featureName===featureName&&f.enabled))result.push(tenantId);return result}getSchemaNamesWithFeature(featureName){let tenantIds=this.getTenantIdsWithFeature(featureName),schemaNames=[];for(let tenantId of tenantIds){let tenant=this.tenantsById.get(tenantId);if(tenant&&tenant.status==="active")schemaNames.push(tenant.schemaName)}return schemaNames}getAllSchemaNames(){return Array.from(this.schemaContexts.keys())}async provisionTenant(tenant){this.logger.info(`[TenantRegistry] Provisioning tenant: ${tenant.subdomain} \u2192 ${tenant.schemaName}`),await ensureSchemaExists(this.db,tenant.schemaName);let context=await this.buildSchemaContext(tenant);if(this.indexTenant(tenant),await this.syncSchemaToDb(context),this.onTenantProvisioned)try{await this.onTenantProvisioned(context)}catch(err){let msg=err instanceof Error?err.message:String(err);this.logger.warn(`[TenantRegistry] onTenantProvisioned hook failed for ${tenant.schemaName}: ${msg}`)}return this.logger.info(`[TenantRegistry] Tenant provisioned: ${tenant.subdomain}`),context}async syncSchemaToDb(context){let{pushSchema}=await import("drizzle-kit/api"),{applySchemaPush:applySchemaPush2}=await Promise.resolve().then(() => (init_schema(),exports_schema)),targetSchema=pgSchema(context.schemaName);try{let push=await pushSchema({schema:targetSchema,...context.schemaTables},this.db,[context.schemaName]);if(await applySchemaPush2(push,{schemaName:context.schemaName,allowDataLoss:this.allowDataLoss,logger:this.logger,execute:(statement)=>this.db.execute(sql5.raw(statement))}))this.logger.info(`[TenantRegistry] Schema sync completed for: ${context.schemaName}`)}catch(err){let msg=err instanceof Error?err.message:String(err);this.logger.error(`[TenantRegistry] Schema sync FAILED for ${context.schemaName}: ${msg}. The database does not match this build; queries against anything it was going to add will fail.`)}}async syncAllSchemas(){for(let[schemaName,context]of this.schemaContexts)this.logger.info(`[TenantRegistry] Syncing schema: ${schemaName}`),await ensureSchemaExists(this.db,schemaName),await this.syncSchemaToDb(context)}async invalidateCache(subdomain){try{let{getRedisManager:getRedisManager2}=await Promise.resolve().then(() => (init_utils5(),exports_utils)),redis=getRedisManager2();if(redis)await redis.remove(`tenant:${subdomain}`),this.logger.info(`[TenantRegistry] Cache invalidated for: ${subdomain}`)}catch{}}async refreshTenant(tenantId){let tenantsTable=this.mainSchemaTables.tenants;if(!tenantsTable)return;let row=(await this.db.select().from(tenantsTable).where(eq13(tenantsTable.id,tenantId)).limit(1))[0];if(!row)return;let tenant=rowToTenantRecord(row),oldTenant=this.tenantsById.get(tenantId);if(oldTenant)this.tenantsBySubdomain.delete(oldTenant.subdomain),this.tenantsBySchemaName.delete(oldTenant.schemaName);if(this.indexTenant(tenant),tenant.status==="active")await this.buildSchemaContext(tenant);else this.schemaContexts.delete(tenant.schemaName);if(oldTenant)await this.invalidateCache(oldTenant.subdomain);await this.invalidateCache(tenant.subdomain)}async initializeFromIdp(){if(!this.idpUrl){this.logger.error("[TenantRegistry] Consumer multi-tenant requires idpUrl (IDP_URL)");return}this.logger.info(`[TenantRegistry] Initializing from IDP: ${this.idpUrl}`),this.schemaContexts.set(this.mainSchemaName,{schemaName:this.mainSchemaName,schemaTables:this.mainSchemaTables,schemaRelations:this.mainSchemaRelations,tenant:null});let tenants=await this.loadTenantsFromIdp();this.logger.info(`[TenantRegistry] Fetched ${tenants.length} tenants from IDP`);for(let tenant of tenants)this.indexTenant(tenant);let activeTenants=tenants.filter((t)=>t.status==="active");for(let tenant of activeTenants)await this.buildSchemaContext(tenant);await this.loadDomainHostnames(),this.logger.info(`[TenantRegistry] Consumer initialized with ${activeTenants.length} active tenant schemas + main schema`)}isConsumerMode(){return this.authMode==="consumer"&&!!this.idpUrl}async syncFromIdp(){if(!this.isConsumerMode())return{added:[],removed:[],total:this.tenantsById.size};let tenants=await this.loadTenantsFromIdp(),added=[],removed=[],seenSchemaNames=new Set;for(let tenant of tenants){seenSchemaNames.add(tenant.schemaName);let known=this.tenantsById.get(tenant.id);if(known)this.tenantsBySubdomain.delete(known.subdomain),this.tenantsBySchemaName.delete(known.schemaName);if(this.indexTenant(tenant),tenant.status==="active"){if(!this.schemaContexts.has(tenant.schemaName)){await ensureSchemaExists(this.db,tenant.schemaName);let ctx=await this.buildSchemaContext(tenant);await this.syncSchemaToDb(ctx),added.push(tenant.schemaName),await this.invalidateCache(tenant.subdomain),this.logger.info(`[TenantRegistry] Synced new tenant from IDP: ${tenant.subdomain}`)}}else if(this.schemaContexts.has(tenant.schemaName))this.schemaContexts.delete(tenant.schemaName),removed.push(tenant.schemaName),await this.invalidateCache(tenant.subdomain),this.logger.info(`[TenantRegistry] Deactivated tenant context: ${tenant.subdomain}`)}for(let[schemaName,ctx]of this.schemaContexts){if(schemaName===this.mainSchemaName)continue;if(!seenSchemaNames.has(schemaName)){if(this.schemaContexts.delete(schemaName),removed.push(schemaName),ctx.tenant)this.tenantsBySubdomain.delete(ctx.tenant.subdomain),this.tenantsById.delete(ctx.tenant.id),this.tenantsBySchemaName.delete(schemaName),await this.invalidateCache(ctx.tenant.subdomain)}}return{added,removed,total:tenants.length}}registerDomainHostname(hostname,tenantId){let tenant=this.tenantsById.get(tenantId);if(!tenant)return;this.tenantsByDomainHostname.set(normalizeHost(hostname),tenant)}unregisterDomainHostname(hostname){this.tenantsByDomainHostname.delete(normalizeHost(hostname))}async loadDomainHostnames(){let table=this.mainSchemaTables.domainHostnames;if(!table)return 0;try{let rows=await this.db.select().from(table),count=0;this.tenantsByDomainHostname.clear();for(let row of rows){let status=String(row.status??""),tenantId=String(row.tenantId??row.tenant_id??""),hostname=String(row.normalizedHostname??row.normalized_hostname??"");if(status!=="active"||!tenantId||!hostname)continue;let tenant=this.tenantsById.get(tenantId);if(!tenant)continue;this.tenantsByDomainHostname.set(normalizeHost(hostname),tenant),count++}if(count>0)this.logger.info(`[TenantRegistry] Indexed ${count} active custom hostnames`);return count}catch(err){let msg=err instanceof Error?err.message:String(err);return this.logger.warn(`[TenantRegistry] Failed to load custom hostnames: ${msg}`),0}}async loadTenantsFromIdp(){if(!this.idpUrl)return[];try{let response=await fetch(`${this.idpUrl}/tenants`,{method:"GET",headers:{"Content-Type":"application/json"}});if(!response.ok)return this.logger.warn(`[TenantRegistry] IDP tenant fetch failed: ${response.status} ${response.statusText}`),[];return((await response.json())?.data?.items||[]).map((item)=>rowToTenantRecord(item))}catch(err){let msg=err instanceof Error?err.message:String(err);return this.logger.warn(`[TenantRegistry] Failed to fetch tenants from IDP: ${msg}`),[]}}async loadTenantsFromDb(){let tenantsTable=this.mainSchemaTables.tenants;if(!tenantsTable)return this.logger.warn("[TenantRegistry] No tenants table found in main schema"),[];try{return(await this.db.select().from(tenantsTable)).map((row)=>rowToTenantRecord(row))}catch(err){let msg=err instanceof Error?err.message:String(err);return this.logger.warn(`[TenantRegistry] Failed to load tenants: ${msg}`),[]}}async loadTenantFeaturesFromDb(){let featuresTable=this.mainSchemaTables.tenantFeatures;if(!featuresTable)return this.logger.warn("[TenantRegistry] No tenant_features table found in main schema"),[];try{return(await this.db.select().from(featuresTable)).map((row)=>rowToFeatureRecord(row,parseJsonbToConfig))}catch(err){let msg=err instanceof Error?err.message:String(err);return this.logger.warn(`[TenantRegistry] Failed to load tenant features: ${msg}`),[]}}indexTenant(tenant){if(this.tenantsById.set(tenant.id,tenant),this.tenantsBySubdomain.set(tenant.subdomain,tenant),this.tenantsBySchemaName.set(tenant.schemaName,tenant),tenant.domain)this.tenantsBySubdomain.set(tenant.domain,tenant)}async buildSchemaContext(tenant){let schema=pgSchema(tenant.schemaName),schemaTables=this.createAllTablesForSchema(schema),schemaRelations=this.createAllRelationsForSchema?this.createAllRelationsForSchema(schema):{},context={schemaName:tenant.schemaName,schemaTables,schemaRelations,tenant};return this.schemaContexts.set(tenant.schemaName,context),context}resolveFromHeader(tenantIdOrSubdomain,request,vettedClientIp){let tenant=this.tenantsBySubdomain.get(tenantIdOrSubdomain);if(!tenant)tenant=this.tenantsById.get(tenantIdOrSubdomain);if(!tenant)tenant=this.tenantsBySchemaName.get(tenantIdOrSubdomain);if(!tenant)return{resolved:!1,error:`Tenant not found for header value: ${tenantIdOrSubdomain}`,statusCode:404};if(!isTrustedSource(tenant,request,this.authMode,this.defaultTrustedSources,vettedClientIp))return{resolved:!1,error:`Untrusted source for tenant: ${tenant.subdomain}`,statusCode:403};return this.validateAndReturnTenant(tenant)}validateAndReturnTenant(tenant){if(tenant.status==="suspended")return{resolved:!1,error:`Tenant ${tenant.subdomain} is suspended: ${tenant.suspendedReason||"No reason provided"}`,statusCode:403};if(tenant.status==="provisioning")return{resolved:!1,error:`Tenant ${tenant.subdomain} is still being provisioned`,statusCode:503};if(tenant.status==="archived")return{resolved:!1,error:`Tenant ${tenant.subdomain} has been archived`,statusCode:410};let context=this.schemaContexts.get(tenant.schemaName);if(!context)return{resolved:!1,error:`Schema context not found for tenant: ${tenant.subdomain}`,statusCode:500};return{resolved:!0,context}}}var init_TenantRegistry=__esm(()=>{init_schema()});var init_Tenant=__esm(()=>{init_schema();init_TenantRegistry()});var init_types5=()=>{};import{and as and8,desc as desc2,eq as eq14,inArray as inArray2}from"drizzle-orm";function toCamel2(obj){let result={};for(let[key2,value]of Object.entries(obj)){let camelKey=key2.replace(/_([a-z])/g,(_,c)=>c.toUpperCase());result[camelKey]=value}return result}function fromCamel2(obj){let result={};for(let[key2,value]of Object.entries(obj)){let snakeKey=key2.replace(/[A-Z]/g,(c)=>`_${c.toLowerCase()}`);result[snakeKey]=value}return result}class VerificationService{db;schemaTables;config;logger;onNotificationTrigger;constructor(serviceConfig){this.db=serviceConfig.db,this.schemaTables=serviceConfig.schemaTables,this.config=serviceConfig.config,this.logger=serviceConfig.logger}setNotificationHandler(handler){this.onNotificationTrigger=handler}getConnectedNotificationNodeIds(stepNodeId,steps,edges){let result=new Set,getNeighbors=(nid)=>{let neighbors=[];for(let edge of edges){let{sourceNodeId:src,targetNodeId:tgt}=edge;if(src===nid)neighbors.push(tgt);else if(tgt===nid)neighbors.push(src)}return neighbors},directNeighbors=getNeighbors(stepNodeId);for(let neighborId of directNeighbors)if(steps.find((s)=>s.nodeId===neighborId)?.nodeType==="notification")result.add(neighborId);for(let neighborId of directNeighbors)if(steps.find((s)=>s.nodeId===neighborId)?.nodeType==="verifier"){let verifierNeighbors=getNeighbors(neighborId);for(let vNeighborId of verifierNeighbors){if(vNeighborId===stepNodeId)continue;if(steps.find((s)=>s.nodeId===vNeighborId)?.nodeType==="notification")result.add(vNeighborId)}}let ids=[...result];return this.logger.info(`[Verification] Connected notification nodes for step ${stepNodeId}: [${ids.join(", ")}]`),ids}getTable(name){return resolveSchemaTable(this.schemaTables,name,this.logger)}getCol(table,col7){return table[col7]}async listFlows(entityName){let flowsTable=this.getTable("verificationFlows");if(!flowsTable)return[];return(await(entityName?this.db.select().from(flowsTable).where(eq14(this.getCol(flowsTable,"entityName"),entityName)):this.db.select().from(flowsTable))).map((r)=>fromCamel2(r))}async getFlow(flowId){let flowsTable=this.getTable("verificationFlows"),stepsTable=this.getTable("verificationSteps"),edgesTable=this.getTable("verificationEdges"),verifierConfigsTable=this.getTable("verificationVerifierConfigs"),notifRulesTable=this.getTable("verificationNotificationRules"),notifRecipientsTable=this.getTable("verificationNotificationRecipients"),notifChannelsTable=this.getTable("verificationNotificationChannels");if(!flowsTable)return null;let flowRow=(await this.db.select().from(flowsTable).where(eq14(this.getCol(flowsTable,"id"),flowId)).limit(1))[0];if(!flowRow)return null;let flow=fromCamel2(flowRow),steps=(stepsTable?await this.db.select().from(stepsTable).where(eq14(this.getCol(stepsTable,"flowId"),flowId)):[]).map((r)=>fromCamel2(r)),edges=(edgesTable?await this.db.select().from(edgesTable).where(eq14(this.getCol(edgesTable,"flowId"),flowId)):[]).map((r)=>fromCamel2(r)),verifierConfigs=(verifierConfigsTable?await this.db.select().from(verifierConfigsTable).where(eq14(this.getCol(verifierConfigsTable,"flowId"),flowId)):[]).map((r)=>fromCamel2(r)),notifRules=(notifRulesTable?await this.db.select().from(notifRulesTable).where(eq14(this.getCol(notifRulesTable,"flowId"),flowId)):[]).map((r)=>fromCamel2(r)),ruleIds=notifRules.map((r)=>r.id),notifRecipients=(notifRecipientsTable&&ruleIds.length>0?await this.db.select().from(notifRecipientsTable).where(inArray2(this.getCol(notifRecipientsTable,"ruleId"),ruleIds)):[]).map((r)=>fromCamel2(r)),notifChannels=(notifChannelsTable&&ruleIds.length>0?await this.db.select().from(notifChannelsTable).where(inArray2(this.getCol(notifChannelsTable,"ruleId"),ruleIds)):[]).map((r)=>fromCamel2(r));return{flow,graph:{steps,edges,verifier_configs:verifierConfigs,notification_rules:notifRules,notification_recipients:notifRecipients,notification_channels:notifChannels}}}async saveFlow(params){let flowsTable=this.getTable("verificationFlows"),stepsTable=this.getTable("verificationSteps"),edgesTable=this.getTable("verificationEdges"),verifierConfigsTable=this.getTable("verificationVerifierConfigs"),notifRulesTable=this.getTable("verificationNotificationRules"),notifRecipientsTable=this.getTable("verificationNotificationRecipients"),notifChannelsTable=this.getTable("verificationNotificationChannels");if(!flowsTable||!stepsTable||!edgesTable)throw Error("Verification tables not configured");let existingFlows=await this.db.select().from(flowsTable).where(eq14(this.getCol(flowsTable,"id"),params.flow_id)).limit(1),flowId=params.flow_id;if(existingFlows.length>0)await this.db.update(flowsTable).set(toCamel2({entity_name:params.entity_name,name:params.name,description:params.description||null,trigger_on:params.trigger_on,trigger_fields:params.trigger_fields||null,is_draft:params.is_draft,viewport:params.viewport||null})).where(eq14(this.getCol(flowsTable,"id"),flowId));else{let[newFlow]=await this.db.insert(flowsTable).values(toCamel2({id:flowId,entity_name:params.entity_name,name:params.name,description:params.description||null,trigger_on:params.trigger_on,trigger_fields:params.trigger_fields||null,is_draft:params.is_draft,viewport:params.viewport||null})).returning();flowId=newFlow.id}if(await this.db.delete(stepsTable).where(eq14(this.getCol(stepsTable,"flowId"),flowId)),edgesTable)await this.db.delete(edgesTable).where(eq14(this.getCol(edgesTable,"flowId"),flowId));if(verifierConfigsTable)await this.db.delete(verifierConfigsTable).where(eq14(this.getCol(verifierConfigsTable,"flowId"),flowId));if(notifRulesTable){let oldRuleIds=(await this.db.select().from(notifRulesTable).where(eq14(this.getCol(notifRulesTable,"flowId"),flowId))).map((r)=>r.id);if(oldRuleIds.length>0){if(notifRecipientsTable)for(let rid of oldRuleIds)await this.db.delete(notifRecipientsTable).where(eq14(this.getCol(notifRecipientsTable,"ruleId"),rid));if(notifChannelsTable)for(let rid of oldRuleIds)await this.db.delete(notifChannelsTable).where(eq14(this.getCol(notifChannelsTable,"ruleId"),rid))}await this.db.delete(notifRulesTable).where(eq14(this.getCol(notifRulesTable,"flowId"),flowId))}let{graph}=params;if(graph.steps.length>0)await this.db.insert(stepsTable).values(graph.steps.map((s)=>toCamel2({flow_id:flowId,entity_name:params.entity_name,node_id:s.node_id,node_type:s.node_type,step_order:s.step_order,name:s.name||null,description:s.description||null,position_x:s.position_x,position_y:s.position_y,width:s.width||null,height:s.height||null,style:s.style||null,data:s.data||null})));if(graph.edges.length>0&&edgesTable)await this.db.insert(edgesTable).values(graph.edges.map((e)=>toCamel2({flow_id:flowId,edge_id:e.edge_id,source_node_id:e.source_node_id,target_node_id:e.target_node_id,source_handle:e.source_handle||null,target_handle:e.target_handle||null,edge_type:e.edge_type,label:e.label||null,condition:e.condition||null,style:e.style||null,animated:e.animated})));if(graph.verifier_configs.length>0&&verifierConfigsTable)await this.db.insert(verifierConfigsTable).values(graph.verifier_configs.map((vc)=>toCamel2({flow_id:flowId,node_id:vc.node_id,verifier_type:vc.verifier_type,verifier_user_id:vc.verifier_user_id||null,verifier_role:vc.verifier_role||null,require_signature:vc.require_signature,all_must_approve:vc.all_must_approve})));if(this.logger.info(`[Verification] Save: ${graph.notification_rules.length} rules, ${graph.notification_recipients.length} recipients, ${graph.notification_channels.length} channels`),graph.notification_rules.length>0&¬ifRulesTable)for(let rule of graph.notification_rules){this.logger.info(`[Verification] Saving notification rule: node_id=${rule.node_id}, trigger=${rule.trigger}, title_template=${JSON.stringify(rule.title_template)}, body_template=${JSON.stringify(rule.body_template)}`);let[insertedRule]=await this.db.insert(notifRulesTable).values(toCamel2({flow_id:flowId,node_id:rule.node_id,trigger:rule.trigger,title_template:rule.title_template||null,body_template:rule.body_template||null,starts_at:rule.starts_at||null,expires_at:rule.expires_at||null})).returning(),ruleId=insertedRule.id,ruleRecipients=graph.notification_recipients.filter((r)=>r.rule_id===rule.node_id);if(ruleRecipients.length>0&¬ifRecipientsTable)await this.db.insert(notifRecipientsTable).values(ruleRecipients.map((r)=>toCamel2({rule_id:ruleId,recipient_type:r.recipient_type,recipient_user_id:r.recipient_user_id||null,recipient_role:r.recipient_role||null})));let ruleChannels=graph.notification_channels.filter((c)=>c.rule_id===rule.node_id);if(ruleChannels.length>0&¬ifChannelsTable)await this.db.insert(notifChannelsTable).values(ruleChannels.map((c)=>toCamel2({rule_id:ruleId,channel:c.channel})))}return this.logger.info(`[Verification] Flow saved: ${flowId} for ${params.entity_name}`),{success:!0,flow_id:flowId}}async publishFlow(flowId){let flowsTable=this.getTable("verificationFlows");if(!flowsTable)return{success:!1,message:"Flow table not configured"};return await this.db.update(flowsTable).set(toCamel2({is_draft:!1,published_at:new Date})).where(eq14(this.getCol(flowsTable,"id"),flowId)),this.logger.info(`[Verification] Flow published: ${flowId}`),{success:!0,message:"Flow published"}}async deleteFlow(flowId){let flowsTable=this.getTable("verificationFlows");if(!flowsTable)return{success:!1,message:"Flow table not configured"};return await this.db.delete(flowsTable).where(eq14(this.getCol(flowsTable,"id"),flowId)),this.logger.info(`[Verification] Flow deleted: ${flowId}`),{success:!0,message:"Flow deleted"}}async startFlow(params){let flowsTable=this.getTable("verificationFlows"),stepsTable=this.getTable("verificationSteps"),edgesTable=this.getTable("verificationEdges"),verifierConfigsTable=this.getTable("verificationVerifierConfigs"),instancesTable=this.getTable("verificationInstances"),requirementsTable=this.getTable("verificationRequirements"),userRolesTable=this.getTable("userRoles");if(!flowsTable||!stepsTable||!edgesTable||!instancesTable||!requirementsTable)return{success:!1,message:"Verification tables not configured"};let flow=(await this.db.select().from(flowsTable).where(and8(eq14(this.getCol(flowsTable,"id"),params.flow_id),eq14(this.getCol(flowsTable,"isDraft"),!1))).limit(1))[0];if(!flow)return{success:!1,message:"Published flow not found"};if((await this.db.select().from(instancesTable).where(and8(eq14(this.getCol(instancesTable,"entityName"),params.entity_name),eq14(this.getCol(instancesTable,"entityId"),params.entity_id),eq14(this.getCol(instancesTable,"status"),"active"))).limit(1)).length>0)return{success:!1,message:"An active verification instance already exists for this entity"};let steps=await this.db.select().from(stepsTable).where(eq14(this.getCol(stepsTable,"flowId"),params.flow_id)),edges=await this.db.select().from(edgesTable).where(eq14(this.getCol(edgesTable,"flowId"),params.flow_id)),stepNodes=steps.filter((s)=>s.nodeType==="step");if(stepNodes.sort((a,b)=>a.stepOrder-b.stepOrder),stepNodes.length===0)return{success:!1,message:"Flow has no step nodes"};let[instance]=await this.db.insert(instancesTable).values(toCamel2({flow_id:params.flow_id,entity_name:params.entity_name,entity_id:params.entity_id,started_by:params.started_by||null,status:"active",current_step_order:1,started_at:new Date})).returning(),instanceId=instance.id;if(await this.materializeRequirementsForStep(instanceId,params.flow_id,params.entity_name,params.entity_id,1,steps,edges,verifierConfigsTable,requirementsTable,userRolesTable),this.onNotificationTrigger){let firstStep=stepNodes[0],firstStepNodeId=firstStep?.nodeId,connectedNotifIds=firstStepNodeId?this.getConnectedNotificationNodeIds(firstStepNodeId,steps,edges):[],ctx={flow_name:flow.name,step_name:firstStep?.name||"Step 1",step_order:1,total_steps:stepNodes.length};if(connectedNotifIds.length>0)for(let notifNodeId of connectedNotifIds)await this.onNotificationTrigger({trigger:"on_flow_started",flow_id:params.flow_id,entity_name:params.entity_name,entity_id:params.entity_id,node_id:notifNodeId,context:ctx});else await this.onNotificationTrigger({trigger:"on_flow_started",flow_id:params.flow_id,entity_name:params.entity_name,entity_id:params.entity_id,context:ctx})}return this.logger.info(`[Verification] Flow started: instance ${instanceId} for ${params.entity_name}:${params.entity_id}`),{success:!0,instance_id:instanceId,message:"Flow started"}}async materializeRequirementsForStep(instanceId,flowId,entityName,entityId,stepOrder,steps,edges,verifierConfigsTable,requirementsTable,userRolesTable){if(!requirementsTable)return;let stepNode=steps.find((s)=>s.nodeType==="step"&&s.stepOrder===stepOrder);if(!stepNode)return;let stepNodeId=stepNode.nodeId,verifierNodeIds=edges.filter((e)=>e.targetNodeId===stepNodeId).map((e)=>e.sourceNodeId),verifierNodes=steps.filter((s)=>s.nodeType==="verifier"&&verifierNodeIds.includes(s.nodeId));if(verifierNodes.length===0)return;let verifierConfigs=[];if(verifierConfigsTable)verifierConfigs=await this.db.select().from(verifierConfigsTable).where(eq14(this.getCol(verifierConfigsTable,"flowId"),flowId));for(let verifierNode of verifierNodes){let nodeId=verifierNode.nodeId,config=verifierConfigs.find((vc)=>vc.nodeId===nodeId);if(!config)continue;let{verifierType,allMustApprove}=config;if(verifierType==="role"&&allMustApprove&&userRolesTable){let rolesTable=this.getTable("roles");if(rolesTable){let rolesCols=rolesTable,userRolesCols=userRolesTable,role=(await this.db.select().from(rolesTable).where(eq14(rolesCols.name,config.verifierRole)).limit(1))[0];if(role){let usersWithRole=await this.db.select({user_id:userRolesCols.userId}).from(userRolesTable).where(eq14(userRolesCols.roleId,role.id));for(let userRole of usersWithRole)await this.db.insert(requirementsTable).values(toCamel2({instance_id:instanceId,step_node_id:stepNodeId,verifier_node_id:nodeId,entity_name:entityName,entity_id:entityId,verifier_type:"user",verifier_user_id:userRole.user_id,verifier_role:config.verifierRole||null,require_signature:config.requireSignature,all_must_approve:!0,step_order:stepOrder,status:"pending"}))}}}else await this.db.insert(requirementsTable).values(toCamel2({instance_id:instanceId,step_node_id:stepNodeId,verifier_node_id:nodeId,entity_name:entityName,entity_id:entityId,verifier_type:verifierType,verifier_user_id:config.verifierUserId||null,verifier_role:config.verifierRole||null,require_signature:config.requireSignature,all_must_approve:allMustApprove,step_order:stepOrder,status:"pending"}))}if(this.onNotificationTrigger){let connectedNotifIds=this.getConnectedNotificationNodeIds(stepNodeId,steps,edges);if(this.logger.info(`[Verification] on_step_reached: stepNodeId=${stepNodeId}, connectedNotifIds=[${connectedNotifIds.join(", ")}]`),connectedNotifIds.length>0)for(let notifNodeId of connectedNotifIds)this.logger.info(`[Verification] Triggering on_step_reached for notifNodeId=${notifNodeId}`),await this.onNotificationTrigger({trigger:"on_step_reached",flow_id:flowId,entity_name:entityName,entity_id:entityId,node_id:notifNodeId,context:{step_name:stepNode.name||`Step ${stepOrder}`,step_order:stepOrder}});else await this.onNotificationTrigger({trigger:"on_step_reached",flow_id:flowId,entity_name:entityName,entity_id:entityId,context:{step_name:stepNode.name||`Step ${stepOrder}`,step_order:stepOrder}})}}async getStatus(entityName,entityId){let instancesTable=this.getTable("verificationInstances"),flowsTable=this.getTable("verificationFlows"),stepsTable=this.getTable("verificationSteps"),verificationsTable=this.getTable("verifications"),requirementsTable=this.getTable("verificationRequirements"),emptyStatus={entity_name:entityName,entity_id:entityId,instance:null,flow:null,current_step:0,total_steps:0,is_completed:!1,is_rejected:!1,verifications:[],pending_requirements:[]};if(!instancesTable||!flowsTable||!verificationsTable||!requirementsTable)return this.logger.error("[Verification] Required tables not found"),emptyStatus;let instanceRow=(await this.db.select().from(instancesTable).where(and8(eq14(this.getCol(instancesTable,"entityName"),entityName),eq14(this.getCol(instancesTable,"entityId"),entityId))).orderBy(desc2(this.getCol(instancesTable,"createdAt"))).limit(1))[0];if(!instanceRow)return emptyStatus;let instance=fromCamel2(instanceRow),flows=await this.db.select().from(flowsTable).where(eq14(this.getCol(flowsTable,"id"),instance.flow_id)).limit(1),flow=flows[0]?fromCamel2(flows[0]):void 0,totalSteps=(stepsTable?await this.db.select().from(stepsTable).where(and8(eq14(this.getCol(stepsTable,"flowId"),instance.flow_id),eq14(this.getCol(stepsTable,"nodeType"),"step"))):[]).length,verifications=(await this.db.select().from(verificationsTable).where(eq14(this.getCol(verificationsTable,"instanceId"),instance.id)).orderBy(desc2(this.getCol(verificationsTable,"createdAt")))).map((r)=>fromCamel2(r)),pendingRequirements=(await this.db.select().from(requirementsTable).where(and8(eq14(this.getCol(requirementsTable,"instanceId"),instance.id),eq14(this.getCol(requirementsTable,"status"),"pending")))).map((r)=>fromCamel2(r));return{entity_name:entityName,entity_id:entityId,instance,flow:flow||null,current_step:instance.current_step_order,total_steps:totalSteps,is_completed:instance.status==="completed",is_rejected:instance.status==="rejected",verifications,pending_requirements:pendingRequirements}}async decide(params){let{entity_name,entity_id,user_id,decision,reason,signature_id,diff}=params,verificationsTable=this.getTable("verifications"),requirementsTable=this.getTable("verificationRequirements"),instancesTable=this.getTable("verificationInstances"),stepsTable=this.getTable("verificationSteps"),edgesTable=this.getTable("verificationEdges"),verifierConfigsTable=this.getTable("verificationVerifierConfigs"),userRolesTable=this.getTable("userRoles"),rolesTable=this.getTable("roles");if(!verificationsTable||!requirementsTable||!instancesTable)return{success:!1,message:"Verification tables not configured"};let status=await this.getStatus(entity_name,entity_id);if(!status.instance||status.instance.status!=="active")return{success:!1,message:"No active verification instance"};let currentPending=status.pending_requirements.filter((r)=>r.step_order===status.current_step);if(currentPending.length===0)return{success:!1,message:"No pending requirements for current step"};let matchedReq=null;for(let req of currentPending){if(req.verifier_type==="user"&&req.verifier_user_id===user_id){matchedReq=req;break}if(req.verifier_type==="role"&&req.verifier_role&&userRolesTable&&rolesTable){let userRolesCols=userRolesTable,rolesCols=rolesTable;if((await this.db.select({role_name:rolesCols.name}).from(userRolesTable).innerJoin(rolesTable,eq14(userRolesCols.roleId,rolesCols.id)).where(eq14(userRolesCols.userId,user_id))).some((ur)=>ur.role_name===req.verifier_role)){matchedReq=req;break}}}if(!matchedReq)return{success:!1,message:"User is not authorized to verify at this step"};if(matchedReq.require_signature){if(!signature_id)return{success:!1,message:"Signature is required for this verification step"};let filesTable=resolveSchemaTable(this.schemaTables,"files",this.logger);if(filesTable){if((await this.db.select().from(filesTable).where(and8(eq14(this.getCol(filesTable,"id"),signature_id),eq14(this.getCol(filesTable,"uploadedBy"),user_id))).limit(1)).length===0)return{success:!1,message:"Signature file not found or not owned by the verifier"}}}if((await this.db.update(requirementsTable).set({status:decision}).where(and8(eq14(this.getCol(requirementsTable,"id"),matchedReq.id),eq14(this.getCol(requirementsTable,"status"),"pending"))).returning()).length===0)return{success:!1,message:"This requirement has already been decided"};let[newVerification]=await this.db.insert(verificationsTable).values(toCamel2({instance_id:status.instance.id,requirement_id:matchedReq.id,verifier_id:user_id,signature_id:signature_id||null,entity_name,entity_id,step_order:status.current_step,decision,reason:reason||null,diff:diff||null})).returning();if(this.onNotificationTrigger&&status.instance){let stepName=`Step ${status.current_step}`,allSteps=[],allEdges=[];if(stepsTable){allSteps=await this.db.select().from(stepsTable).where(eq14(this.getCol(stepsTable,"flowId"),status.instance.flow_id));let stepRow=allSteps.find((s)=>s.nodeId===matchedReq.step_node_id);if(stepRow?.name)stepName=stepRow.name}if(edgesTable)allEdges=await this.db.select().from(edgesTable).where(eq14(this.getCol(edgesTable,"flowId"),status.instance.flow_id));let triggerName=decision==="approved"?"on_approved":"on_rejected",ctx={flow_name:status.flow?.name||"",step_name:stepName,step_order:status.current_step,total_steps:status.total_steps,decision},connectedNotifIds=this.getConnectedNotificationNodeIds(matchedReq.step_node_id,allSteps,allEdges);if(connectedNotifIds.length>0)for(let notifNodeId of connectedNotifIds)await this.onNotificationTrigger({trigger:triggerName,flow_id:status.instance.flow_id,entity_name,entity_id,node_id:notifNodeId,verifier_id:user_id,decision,context:ctx});else await this.onNotificationTrigger({trigger:triggerName,flow_id:status.instance.flow_id,entity_name,entity_id,verifier_id:user_id,decision,context:ctx})}if(decision==="rejected"){await this.db.update(instancesTable).set(toCamel2({status:"rejected",completed_at:new Date})).where(eq14(this.getCol(instancesTable,"id"),status.instance.id));let newInstanceId;if(this.config.autoResetOnRejection){this.logger.info(`[Verification] Flow rejected for ${entity_name}:${entity_id}, auto-restarting from step 1`);let restartResult=await this.startFlow({flow_id:status.instance.flow_id,entity_name,entity_id,started_by:status.instance.started_by});if(restartResult.success)newInstanceId=restartResult.instance_id}return{success:!0,message:this.config.autoResetOnRejection?"Verification rejected \u2014 flow restarted from step 1":"Verification rejected",verification:newVerification,flow_completed:!1,new_instance_id:newInstanceId}}let matchedReqId=matchedReq.id,remainingPending=currentPending.filter((r)=>r.id!==matchedReqId);if(remainingPending.length>0)return{success:!0,message:`Step ${status.current_step} partially approved, ${remainingPending.length} verifier(s) remaining`,verification:newVerification,flow_completed:!1};let nextStep=status.current_step+1;if(nextStep>status.total_steps){if(await this.db.update(instancesTable).set(toCamel2({status:"completed",completed_at:new Date})).where(eq14(this.getCol(instancesTable,"id"),status.instance.id)),this.onNotificationTrigger){let completedSteps=[],completedEdges=[];if(stepsTable)completedSteps=await this.db.select().from(stepsTable).where(eq14(this.getCol(stepsTable,"flowId"),status.instance.flow_id));if(edgesTable)completedEdges=await this.db.select().from(edgesTable).where(eq14(this.getCol(edgesTable,"flowId"),status.instance.flow_id));let lastStepNodeId=matchedReq.step_node_id,completedNotifIds=this.getConnectedNotificationNodeIds(lastStepNodeId,completedSteps,completedEdges),completedCtx={flow_name:status.flow?.name||"",step_order:status.current_step,total_steps:status.total_steps};if(completedNotifIds.length>0)for(let notifNodeId of completedNotifIds)await this.onNotificationTrigger({trigger:"on_flow_completed",flow_id:status.instance.flow_id,entity_name,entity_id,node_id:notifNodeId,context:completedCtx});else await this.onNotificationTrigger({trigger:"on_flow_completed",flow_id:status.instance.flow_id,entity_name,entity_id,context:completedCtx})}return{success:!0,message:"Verification flow completed",verification:newVerification,flow_completed:!0}}if(await this.db.update(instancesTable).set(toCamel2({current_step_order:nextStep})).where(eq14(this.getCol(instancesTable,"id"),status.instance.id)),stepsTable&&edgesTable){let steps=await this.db.select().from(stepsTable).where(eq14(this.getCol(stepsTable,"flowId"),status.instance.flow_id)),edges=await this.db.select().from(edgesTable).where(eq14(this.getCol(edgesTable,"flowId"),status.instance.flow_id));await this.materializeRequirementsForStep(status.instance.id,status.instance.flow_id,entity_name,entity_id,nextStep,steps,edges,verifierConfigsTable,requirementsTable,userRolesTable)}return{success:!0,message:`Step ${status.current_step} approved, moving to step ${nextStep}`,verification:newVerification,flow_completed:!1,next_step:nextStep}}async startFlowForEntity(params){let flowsTable=this.getTable("verificationFlows");if(!flowsTable)return{success:!1,message:"Flow table not configured"};let flow=(await this.db.select().from(flowsTable).where(and8(eq14(this.getCol(flowsTable,"entityName"),params.entity_name),eq14(this.getCol(flowsTable,"isDraft"),!1))).limit(1))[0];if(!flow)return{success:!1,message:`No published flow found for entity '${params.entity_name}'`};return this.startFlow({flow_id:flow.id,entity_name:params.entity_name,entity_id:params.entity_id,started_by:params.started_by})}async listEntityStatuses(params){let instancesTable=this.getTable("verificationInstances"),flowsTable=this.getTable("verificationFlows"),stepsTable=this.getTable("verificationSteps"),emptyResult={items:[],total:0,page:1,limit:20};if(!instancesTable||!flowsTable)return emptyResult;let page=params.page||1,limit=params.limit||20,offset=(page-1)*limit,conditions=[eq14(this.getCol(instancesTable,"entityName"),params.entity_name)];if(params.status)conditions.push(eq14(this.getCol(instancesTable,"status"),params.status));let whereClause=conditions.length===1?conditions[0]:and8(...conditions),allInstances=(await this.db.select().from(instancesTable).where(whereClause).orderBy(desc2(this.getCol(instancesTable,"createdAt")))).map((r)=>fromCamel2(r)),total=allInstances.length,paged=allInstances.slice(offset,offset+limit),items=[];for(let inst of paged){let flowId=inst.flow_id,flows=await this.db.select().from(flowsTable).where(eq14(this.getCol(flowsTable,"id"),flowId)).limit(1),flow=flows[0]?fromCamel2(flows[0]):void 0,totalSteps=0;if(stepsTable)totalSteps=(await this.db.select().from(stepsTable).where(and8(eq14(this.getCol(stepsTable,"flowId"),flowId),eq14(this.getCol(stepsTable,"nodeType"),"step")))).length;items.push({instance_id:inst.id,entity_name:inst.entity_name,entity_id:inst.entity_id,flow_id:flowId,flow_name:flow?.name||"Unknown",status:inst.status,current_step_order:inst.current_step_order,total_steps:totalSteps,started_by:inst.started_by,started_at:inst.started_at,completed_at:inst.completed_at})}return{items,total,page,limit}}async getPending(userId){let requirementsTable=this.getTable("verificationRequirements"),instancesTable=this.getTable("verificationInstances"),flowsTable=this.getTable("verificationFlows"),stepsTable=this.getTable("verificationSteps"),userRolesTable=this.getTable("userRoles"),rolesTable=this.getTable("roles");if(this.logger.info(`[Verification.getPending] userId=${userId}, tables: req=${!!requirementsTable} inst=${!!instancesTable} flow=${!!flowsTable} steps=${!!stepsTable} roles=${!!rolesTable} userRoles=${!!userRolesTable}`),!requirementsTable||!instancesTable||!flowsTable)return this.logger.warn("[Verification.getPending] Missing required tables, returning empty"),[];let userRolesCols=userRolesTable,rolesCols=rolesTable,userRoleNames=(userRolesTable&&rolesTable?await this.db.select({role_name:rolesCols.name}).from(userRolesTable).innerJoin(rolesTable,eq14(userRolesCols.roleId,rolesCols.id)).where(eq14(userRolesCols.userId,userId)):[]).map((ur)=>ur.role_name),pendingReqs=(await this.db.select().from(requirementsTable).where(eq14(this.getCol(requirementsTable,"status"),"pending"))).map((r)=>fromCamel2(r));this.logger.info(`[Verification.getPending] Found ${pendingReqs.length} pending requirements, userRoles=${JSON.stringify(userRoleNames)}`);for(let req of pendingReqs)this.logger.info(`[Verification.getPending] Req: verifier_type=${req.verifier_type} verifier_user_id=${req.verifier_user_id} verifier_role=${req.verifier_role} step_order=${req.step_order} entity=${req.entity_name}/${req.entity_id}`);let pendingItems=[];for(let req of pendingReqs){if(!(req.verifier_type==="user"&&req.verifier_user_id===userId||req.verifier_type==="role"&&userRoleNames.includes(req.verifier_role))){this.logger.info(`[Verification.getPending] Skipping req: canVerify=false (type=${req.verifier_type}, reqUserId=${req.verifier_user_id}, loggedInUserId=${userId})`);continue}let instances=await this.db.select().from(instancesTable).where(and8(eq14(this.getCol(instancesTable,"id"),req.instance_id),eq14(this.getCol(instancesTable,"status"),"active"))).limit(1),instance=instances[0]?fromCamel2(instances[0]):void 0;if(!instance)continue;if(instance.current_step_order!==req.step_order)continue;let flows=await this.db.select().from(flowsTable).where(eq14(this.getCol(flowsTable,"id"),instance.flow_id)).limit(1),flow=flows[0]?fromCamel2(flows[0]):void 0;if(!flow)continue;let stepName;if(stepsTable&&req.step_node_id){let stepRow=(await this.db.select().from(stepsTable).where(and8(eq14(this.getCol(stepsTable,"flowId"),instance.flow_id),eq14(this.getCol(stepsTable,"nodeId"),req.step_node_id))).limit(1))[0];if(stepRow?.name)stepName=stepRow.name}pendingItems.push({instance_id:instance.id,entity_name:req.entity_name,entity_id:req.entity_id,flow_name:flow.name,step_order:req.step_order,step_name:stepName,require_signature:req.require_signature,created_at:req.created_at})}return pendingItems}}var init_Verification=__esm(()=>{init_types5()});var genLookup=(target)=>{let lookupTemp=typeof Uint8Array>"u"?[]:new Uint8Array(256),len=64;for(let i=0;i<64;i++)lookupTemp[target.charCodeAt(i)]=i;return lookupTemp},lookup,lookupUrl,base64UrlPattern,base64Pattern,base64,base64_default;var init_base64=__esm(()=>{lookup=genLookup("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"),lookupUrl=genLookup("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"),base64UrlPattern=/^[-A-Za-z0-9\-_]*$/,base64Pattern=/^[-A-Za-z0-9+/]*={0,3}$/,base64={};base64.toArrayBuffer=(data,urlMode)=>{let len=data.length,bufferLength=data.length*0.75,i,p=0,encoded1,encoded2,encoded3,encoded4;if(data[data.length-1]==="="){if(bufferLength--,data[data.length-2]==="=")bufferLength--}let arraybuffer=new ArrayBuffer(bufferLength),bytes=new Uint8Array(arraybuffer),target=urlMode?lookupUrl:lookup;for(i=0;i<len;i+=4)encoded1=target[data.charCodeAt(i)],encoded2=target[data.charCodeAt(i+1)],encoded3=target[data.charCodeAt(i+2)],encoded4=target[data.charCodeAt(i+3)],bytes[p++]=encoded1<<2|encoded2>>4,bytes[p++]=(encoded2&15)<<4|encoded3>>2,bytes[p++]=(encoded3&3)<<6|encoded4&63;return arraybuffer};base64.fromArrayBuffer=(arrBuf,urlMode)=>{let bytes=new Uint8Array(arrBuf),i,result="",len=bytes.length,target=urlMode?"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_":"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";for(i=0;i<len;i+=3)result+=target[bytes[i]>>2],result+=target[(bytes[i]&3)<<4|bytes[i+1]>>4],result+=target[(bytes[i+1]&15)<<2|bytes[i+2]>>6],result+=target[bytes[i+2]&63];let remainder=len%3;if(remainder===2)result=result.substring(0,result.length-1)+(urlMode?"":"=");else if(remainder===1)result=result.substring(0,result.length-2)+(urlMode?"":"==");return result};base64.toString=(str3,urlMode)=>{return new TextDecoder().decode(base64.toArrayBuffer(str3,urlMode))};base64.fromString=(str3,urlMode)=>{return base64.fromArrayBuffer(new TextEncoder().encode(str3),urlMode)};base64.validate=(encoded,urlMode)=>{if(!(typeof encoded==="string"||encoded instanceof String))return!1;try{return urlMode?base64UrlPattern.test(encoded):base64Pattern.test(encoded)}catch(_e){return!1}};base64.base64=base64;base64_default=base64});var exports_isoBase64URL={};__export(exports_isoBase64URL,{trimPadding:()=>trimPadding,toUTF8String:()=>toUTF8String,toBuffer:()=>toBuffer,toBase64:()=>toBase64,isBase64URL:()=>isBase64URL,isBase64:()=>isBase64,fromUTF8String:()=>fromUTF8String,fromBuffer:()=>fromBuffer});function toBuffer(base64urlString,from="base64url"){let _buffer=base64_default.toArrayBuffer(base64urlString,from==="base64url");return new Uint8Array(_buffer)}function fromBuffer(buffer,to="base64url"){let _normalized=new Uint8Array(buffer);return base64_default.fromArrayBuffer(_normalized.buffer,to==="base64url")}function toBase64(base64urlString){let fromBase64Url=base64_default.toArrayBuffer(base64urlString,!0);return base64_default.fromArrayBuffer(fromBase64Url)}function fromUTF8String(utf8String){return base64_default.fromString(utf8String,!0)}function toUTF8String(base64urlString){return base64_default.toString(base64urlString,!0)}function isBase64(input){return base64_default.validate(input,!1)}function isBase64URL(input){return input=trimPadding(input),base64_default.validate(input,!0)}function trimPadding(input){return input.replace(/=/g,"")}var init_isoBase64URL=__esm(()=>{init_base64()});function decodeLength(data,argument,index){if(argument<24)return[argument,1];let remainingDataLength=data.byteLength-index-1,view=new DataView(data.buffer,index+1),output,bytes=0;switch(argument){case 24:{if(remainingDataLength>0)output=view.getUint8(0),bytes=2;break}case 25:{if(remainingDataLength>1)output=view.getUint16(0,!1),bytes=3;break}case 26:{if(remainingDataLength>3)output=view.getUint32(0,!1),bytes=5;break}case 27:{if(remainingDataLength>7){let bigOutput=view.getBigUint64(0,!1);if(bigOutput>=24n&&bigOutput<=Number.MAX_SAFE_INTEGER)return[Number(bigOutput),9]}break}}if(output&&output>=24)return[output,bytes];throw Error("Length not supported or not well formed")}function encodeLength(major,argument){let majorEncoded=major<<5;if(argument<0)throw Error("CBOR Data Item argument must not be negative");let bigintArgument;if(typeof argument=="number"){if(!Number.isInteger(argument))throw Error("CBOR Data Item argument must be an integer");bigintArgument=BigInt(argument)}else bigintArgument=argument;if(major==MAJOR_TYPE_NEGATIVE_INTEGER){if(bigintArgument==0n)throw Error("CBOR Data Item argument cannot be zero when negative");bigintArgument=bigintArgument-1n}if(bigintArgument>18446744073709551615n)throw Error("CBOR number out of range");let buffer=new Uint8Array(8);if(new DataView(buffer.buffer).setBigUint64(0,bigintArgument,!1),bigintArgument<=23)return[majorEncoded|buffer[7]];else if(bigintArgument<=255)return[majorEncoded|24,buffer[7]];else if(bigintArgument<=65535)return[majorEncoded|25,...buffer.slice(6)];else if(bigintArgument<=4294967295)return[majorEncoded|26,...buffer.slice(4)];else return[majorEncoded|27,...buffer]}var MAJOR_TYPE_UNSIGNED_INTEGER=0,MAJOR_TYPE_NEGATIVE_INTEGER=1,MAJOR_TYPE_BYTE_STRING=2,MAJOR_TYPE_TEXT_STRING=3,MAJOR_TYPE_ARRAY=4,MAJOR_TYPE_MAP=5,MAJOR_TYPE_TAG=6,MAJOR_TYPE_SIMPLE_OR_FLOAT=7;class CBORTag{constructor(tag,value){Object.defineProperty(this,"tagId",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"tagValue",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.tagId=tag,this.tagValue=value}get tag(){return this.tagId}get value(){return this.tagValue}}function decodeUnsignedInteger(data,argument,index){return decodeLength(data,argument,index)}function decodeNegativeInteger(data,argument,index){let[value,length]=decodeUnsignedInteger(data,argument,index);return[-value-1,length]}function decodeByteString(data,argument,index){let[lengthValue,lengthConsumed]=decodeLength(data,argument,index),dataStartIndex=index+lengthConsumed;return[new Uint8Array(data.buffer.slice(dataStartIndex,dataStartIndex+lengthValue)),lengthConsumed+lengthValue]}function decodeString(data,argument,index){let[value,length]=decodeByteString(data,argument,index);return[TEXT_DECODER.decode(value),length]}function decodeArray(data,argument,index){if(argument===0)return[[],1];let[length,lengthConsumed]=decodeLength(data,argument,index),consumedLength=lengthConsumed,value=[];for(let i=0;i<length;i++){if(data.byteLength-index-consumedLength<=0)throw Error("array is not supported or well formed");let[decodedValue,consumed]=decodeNext(data,index+consumedLength);value.push(decodedValue),consumedLength+=consumed}return[value,consumedLength]}function decodeMap(data,argument,index){if(argument===0)return[new Map,1];let[length,lengthConsumed]=decodeLength(data,argument,index),consumedLength=lengthConsumed,result=new Map;for(let i=0;i<length;i++){let remainingDataLength=data.byteLength-index-consumedLength;if(remainingDataLength<=0)throw Error(MAP_ERROR);let[key2,keyConsumed]=decodeNext(data,index+consumedLength);if(consumedLength+=keyConsumed,remainingDataLength-=keyConsumed,remainingDataLength<=0)throw Error(MAP_ERROR);if(typeof key2!=="string"&&typeof key2!=="number")throw Error(MAP_ERROR);if(result.has(key2))throw Error(MAP_ERROR);let[value,valueConsumed]=decodeNext(data,index+consumedLength);consumedLength+=valueConsumed,result.set(key2,value)}return[result,consumedLength]}function decodeFloat16(data,index){if(index+3>data.byteLength)throw Error("CBOR stream ended before end of Float 16");let result=data.getUint16(index+1,!1);if(result==31744)return[1/0,3];else if(result==32256)return[NaN,3];else if(result==64512)return[-1/0,3];throw Error("Float16 data is unsupported")}function decodeFloat32(data,index){if(index+5>data.byteLength)throw Error("CBOR stream ended before end of Float 32");return[data.getFloat32(index+1,!1),5]}function decodeFloat64(data,index){if(index+9>data.byteLength)throw Error("CBOR stream ended before end of Float 64");return[data.getFloat64(index+1,!1),9]}function decodeTag(data,argument,index){let[tag,tagBytes]=decodeLength(data,argument,index),[value,valueBytes]=decodeNext(data,index+tagBytes);return[new CBORTag(tag,value),tagBytes+valueBytes]}function decodeNext(data,index){if(index>=data.byteLength)throw Error("CBOR stream ended before tag value");let byte=data.getUint8(index),majorType=byte>>5,argument=byte&31;switch(majorType){case MAJOR_TYPE_UNSIGNED_INTEGER:return decodeUnsignedInteger(data,argument,index);case MAJOR_TYPE_NEGATIVE_INTEGER:return decodeNegativeInteger(data,argument,index);case MAJOR_TYPE_BYTE_STRING:return decodeByteString(data,argument,index);case MAJOR_TYPE_TEXT_STRING:return decodeString(data,argument,index);case MAJOR_TYPE_ARRAY:return decodeArray(data,argument,index);case MAJOR_TYPE_MAP:return decodeMap(data,argument,index);case MAJOR_TYPE_TAG:return decodeTag(data,argument,index);case MAJOR_TYPE_SIMPLE_OR_FLOAT:switch(argument){case 20:return[!1,1];case 21:return[!0,1];case 22:return[null,1];case 23:return[void 0,1];case 25:return decodeFloat16(data,index);case 26:return decodeFloat32(data,index);case 27:return decodeFloat64(data,index)}}throw Error(`Unsupported or not well formed at ${index}`)}function encodeSimple(data){if(data===!0)return 245;else if(data===!1)return 244;else if(data===null)return 246;return 247}function encodeFloat(data){if(Math.fround(data)==data||!Number.isFinite(data)||Number.isNaN(data)){let output=new Uint8Array(5);return output[0]=250,new DataView(output.buffer).setFloat32(1,data,!1),output}else{let output=new Uint8Array(9);return output[0]=251,new DataView(output.buffer).setFloat64(1,data,!1),output}}function encodeNumber(data){if(typeof data=="number"){if(Number.isSafeInteger(data))if(data<0)return encodeLength(MAJOR_TYPE_NEGATIVE_INTEGER,Math.abs(data));else return encodeLength(MAJOR_TYPE_UNSIGNED_INTEGER,data);return[encodeFloat(data)]}else if(data<0n)return encodeLength(MAJOR_TYPE_NEGATIVE_INTEGER,data*-1n);else return encodeLength(MAJOR_TYPE_UNSIGNED_INTEGER,data)}function encodeString(data,output){output.push(...encodeLength(MAJOR_TYPE_TEXT_STRING,data.length)),output.push(ENCODER.encode(data))}function encodeBytes(data,output){output.push(...encodeLength(MAJOR_TYPE_BYTE_STRING,data.length)),output.push(data)}function encodeArray(data,output){output.push(...encodeLength(MAJOR_TYPE_ARRAY,data.length));for(let element of data)encodePartialCBOR(element,output)}function encodeMap(data,output){output.push(new Uint8Array(encodeLength(MAJOR_TYPE_MAP,data.size)));for(let[key2,value]of data.entries())encodePartialCBOR(key2,output),encodePartialCBOR(value,output)}function encodeTag(tag,output){output.push(...encodeLength(MAJOR_TYPE_TAG,tag.tag)),encodePartialCBOR(tag.value,output)}function encodePartialCBOR(data,output){if(typeof data=="boolean"||data===null||data==null){output.push(encodeSimple(data));return}if(typeof data=="number"||typeof data=="bigint"){output.push(...encodeNumber(data));return}if(typeof data=="string"){encodeString(data,output);return}if(data instanceof Uint8Array){encodeBytes(data,output);return}if(Array.isArray(data)){encodeArray(data,output);return}if(data instanceof Map){encodeMap(data,output);return}if(data instanceof CBORTag){encodeTag(data,output);return}throw Error("Not implemented")}function decodePartialCBOR(data,index){if(data.byteLength===0||data.byteLength<=index||index<0)throw Error("No data");if(data instanceof Uint8Array)return decodeNext(new DataView(data.buffer),index);else if(data instanceof ArrayBuffer)return decodeNext(new DataView(data),index);return decodeNext(data,index)}function encodeCBOR(data){let results=[];encodePartialCBOR(data,results);let length=0;for(let result of results)if(typeof result=="number")length+=1;else length+=result.length;let output=new Uint8Array(length),index=0;for(let result of results)if(typeof result=="number")output[index]=result,index+=1;else output.set(result,index),index+=result.length;return output}var TEXT_DECODER,MAP_ERROR="Map is not supported or well formed",ENCODER;var init_cbor=__esm(()=>{TEXT_DECODER=new TextDecoder;ENCODER=new TextEncoder});var init_esm=__esm(()=>{init_cbor()});var exports_isoCBOR={};__export(exports_isoCBOR,{encode:()=>encode,decodeFirst:()=>decodeFirst});function decodeFirst(input){let _input=new Uint8Array(input),decoded=decodePartialCBOR(_input,0),[first]=decoded;return first}function encode(input){return encodeCBOR(input)}var init_isoCBOR=__esm(()=>{init_esm()});function isCOSEPublicKeyOKP(cosePublicKey){let kty=cosePublicKey.get(COSEKEYS.kty);return isCOSEKty(kty)&&kty===COSEKTY.OKP}function isCOSEPublicKeyEC2(cosePublicKey){let kty=cosePublicKey.get(COSEKEYS.kty);return isCOSEKty(kty)&&kty===COSEKTY.EC2}function isCOSEPublicKeyRSA(cosePublicKey){let kty=cosePublicKey.get(COSEKEYS.kty);return isCOSEKty(kty)&&kty===COSEKTY.RSA}function isCOSEKty(kty){return Object.values(COSEKTY).indexOf(kty)>=0}function isCOSECrv(crv){return Object.values(COSECRV).indexOf(crv)>=0}function isCOSEAlg(alg){return Object.values(COSEALG).indexOf(alg)>=0}var COSEKEYS,COSEKTY,COSECRV,COSEALG;var init_cose=__esm(()=>{(function(COSEKEYS2){COSEKEYS2[COSEKEYS2.kty=1]="kty",COSEKEYS2[COSEKEYS2.alg=3]="alg",COSEKEYS2[COSEKEYS2.crv=-1]="crv",COSEKEYS2[COSEKEYS2.x=-2]="x",COSEKEYS2[COSEKEYS2.y=-3]="y",COSEKEYS2[COSEKEYS2.n=-1]="n",COSEKEYS2[COSEKEYS2.e=-2]="e"})(COSEKEYS||(COSEKEYS={}));(function(COSEKTY2){COSEKTY2[COSEKTY2.OKP=1]="OKP",COSEKTY2[COSEKTY2.EC2=2]="EC2",COSEKTY2[COSEKTY2.RSA=3]="RSA"})(COSEKTY||(COSEKTY={}));(function(COSECRV2){COSECRV2[COSECRV2.P256=1]="P256",COSECRV2[COSECRV2.P384=2]="P384",COSECRV2[COSECRV2.P521=3]="P521",COSECRV2[COSECRV2.ED25519=6]="ED25519",COSECRV2[COSECRV2.SECP256K1=8]="SECP256K1"})(COSECRV||(COSECRV={}));(function(COSEALG2){COSEALG2[COSEALG2.ES256=-7]="ES256",COSEALG2[COSEALG2.EdDSA=-8]="EdDSA",COSEALG2[COSEALG2.ES384=-35]="ES384",COSEALG2[COSEALG2.ES512=-36]="ES512",COSEALG2[COSEALG2.PS256=-37]="PS256",COSEALG2[COSEALG2.PS384=-38]="PS384",COSEALG2[COSEALG2.PS512=-39]="PS512",COSEALG2[COSEALG2.ES256K=-47]="ES256K",COSEALG2[COSEALG2.RS256=-257]="RS256",COSEALG2[COSEALG2.RS384=-258]="RS384",COSEALG2[COSEALG2.RS512=-259]="RS512",COSEALG2[COSEALG2.RS1=-65535]="RS1"})(COSEALG||(COSEALG={}))});function mapCoseAlgToWebCryptoAlg(alg){if([COSEALG.RS1].indexOf(alg)>=0)return"SHA-1";else if([COSEALG.ES256,COSEALG.PS256,COSEALG.RS256].indexOf(alg)>=0)return"SHA-256";else if([COSEALG.ES384,COSEALG.PS384,COSEALG.RS384].indexOf(alg)>=0)return"SHA-384";else if([COSEALG.ES512,COSEALG.PS512,COSEALG.RS512,COSEALG.EdDSA].indexOf(alg)>=0)return"SHA-512";throw Error(`Could not map COSE alg value of ${alg} to a WebCrypto alg`)}var init_mapCoseAlgToWebCryptoAlg=__esm(()=>{init_cose()});function getWebCrypto(){return new Promise((resolve2,reject)=>{if(webCrypto)return resolve2(webCrypto);let _globalThisCrypto=_getWebCryptoInternals.stubThisGlobalThisCrypto();if(_globalThisCrypto)return webCrypto=_globalThisCrypto,resolve2(webCrypto);return reject(new MissingWebCrypto)})}var webCrypto=void 0,MissingWebCrypto,_getWebCryptoInternals;var init_getWebCrypto=__esm(()=>{MissingWebCrypto=class MissingWebCrypto extends Error{constructor(){super("An instance of the Crypto API could not be located");this.name="MissingWebCrypto"}};_getWebCryptoInternals={stubThisGlobalThisCrypto:()=>globalThis.crypto,setCachedCrypto:(newCrypto)=>{webCrypto=newCrypto}}});async function digest(data,algorithm){let WebCrypto=await getWebCrypto(),subtleAlgorithm=mapCoseAlgToWebCryptoAlg(algorithm),hashed=await WebCrypto.subtle.digest(subtleAlgorithm,data);return new Uint8Array(hashed)}var init_digest=__esm(()=>{init_mapCoseAlgToWebCryptoAlg();init_getWebCrypto()});async function getRandomValues(array){return(await getWebCrypto()).getRandomValues(array),array}var init_getRandomValues=__esm(()=>{init_getWebCrypto()});async function importKey(opts){let WebCrypto=await getWebCrypto(),{keyData,algorithm}=opts;return WebCrypto.subtle.importKey("jwk",keyData,algorithm,!1,["verify"])}var init_importKey=__esm(()=>{init_getWebCrypto()});async function verifyEC2(opts){let{cosePublicKey,signature,data,shaHashOverride}=opts,WebCrypto=await getWebCrypto(),alg=cosePublicKey.get(COSEKEYS.alg),crv=cosePublicKey.get(COSEKEYS.crv),x=cosePublicKey.get(COSEKEYS.x),y=cosePublicKey.get(COSEKEYS.y);if(!alg)throw Error("Public key was missing alg (EC2)");if(!crv)throw Error("Public key was missing crv (EC2)");if(!x)throw Error("Public key was missing x (EC2)");if(!y)throw Error("Public key was missing y (EC2)");let _crv;if(crv===COSECRV.P256)_crv="P-256";else if(crv===COSECRV.P384)_crv="P-384";else if(crv===COSECRV.P521)_crv="P-521";else throw Error(`Unexpected COSE crv value of ${crv} (EC2)`);let keyData={kty:"EC",crv:_crv,x:exports_isoBase64URL.fromBuffer(x),y:exports_isoBase64URL.fromBuffer(y),ext:!1},key2=await importKey({keyData,algorithm:{name:"ECDSA",namedCurve:_crv}}),subtleAlg=mapCoseAlgToWebCryptoAlg(alg);if(shaHashOverride)subtleAlg=mapCoseAlgToWebCryptoAlg(shaHashOverride);let verifyAlgorithm={name:"ECDSA",hash:{name:subtleAlg}};return WebCrypto.subtle.verify(verifyAlgorithm,key2,signature,data)}var init_verifyEC2=__esm(()=>{init_cose();init_mapCoseAlgToWebCryptoAlg();init_importKey();init_iso();init_getWebCrypto()});function mapCoseAlgToWebCryptoKeyAlgName(alg){if([COSEALG.EdDSA].indexOf(alg)>=0)return"Ed25519";else if([COSEALG.ES256,COSEALG.ES384,COSEALG.ES512,COSEALG.ES256K].indexOf(alg)>=0)return"ECDSA";else if([COSEALG.RS256,COSEALG.RS384,COSEALG.RS512,COSEALG.RS1].indexOf(alg)>=0)return"RSASSA-PKCS1-v1_5";else if([COSEALG.PS256,COSEALG.PS384,COSEALG.PS512].indexOf(alg)>=0)return"RSA-PSS";throw Error(`Could not map COSE alg value of ${alg} to a WebCrypto key alg name`)}var init_mapCoseAlgToWebCryptoKeyAlgName=__esm(()=>{init_cose()});async function verifyRSA(opts){let{cosePublicKey,signature,data,shaHashOverride}=opts,WebCrypto=await getWebCrypto(),alg=cosePublicKey.get(COSEKEYS.alg),n=cosePublicKey.get(COSEKEYS.n),e=cosePublicKey.get(COSEKEYS.e);if(!alg)throw Error("Public key was missing alg (RSA)");if(!isCOSEAlg(alg))throw Error(`Public key had invalid alg ${alg} (RSA)`);if(!n)throw Error("Public key was missing n (RSA)");if(!e)throw Error("Public key was missing e (RSA)");let keyData={kty:"RSA",alg:"",n:exports_isoBase64URL.fromBuffer(n),e:exports_isoBase64URL.fromBuffer(e),ext:!1},keyAlgorithm={name:mapCoseAlgToWebCryptoKeyAlgName(alg),hash:{name:mapCoseAlgToWebCryptoAlg(alg)}},verifyAlgorithm={name:mapCoseAlgToWebCryptoKeyAlgName(alg)};if(shaHashOverride)keyAlgorithm.hash.name=mapCoseAlgToWebCryptoAlg(shaHashOverride);if(keyAlgorithm.name==="RSASSA-PKCS1-v1_5"){if(keyAlgorithm.hash.name==="SHA-256")keyData.alg="RS256";else if(keyAlgorithm.hash.name==="SHA-384")keyData.alg="RS384";else if(keyAlgorithm.hash.name==="SHA-512")keyData.alg="RS512";else if(keyAlgorithm.hash.name==="SHA-1")keyData.alg="RS1"}else if(keyAlgorithm.name==="RSA-PSS"){let saltLength=0;if(keyAlgorithm.hash.name==="SHA-256")keyData.alg="PS256",saltLength=32;else if(keyAlgorithm.hash.name==="SHA-384")keyData.alg="PS384",saltLength=48;else if(keyAlgorithm.hash.name==="SHA-512")keyData.alg="PS512",saltLength=64;verifyAlgorithm.saltLength=saltLength}else throw Error(`Unexpected RSA key algorithm ${alg} (${keyAlgorithm.name})`);let key2=await importKey({keyData,algorithm:keyAlgorithm});return WebCrypto.subtle.verify(verifyAlgorithm,key2,signature,data)}var init_verifyRSA=__esm(()=>{init_cose();init_mapCoseAlgToWebCryptoAlg();init_importKey();init_iso();init_mapCoseAlgToWebCryptoKeyAlgName();init_getWebCrypto()});function convertAAGUIDToString(aaguid){let hex=exports_isoUint8Array.toHex(aaguid);return[hex.slice(0,8),hex.slice(8,12),hex.slice(12,16),hex.slice(16,20),hex.slice(20,32)].join("-")}var init_convertAAGUIDToString=__esm(()=>{init_iso()});function convertCertBufferToPEM(certBuffer){let b64cert;if(typeof certBuffer==="string")if(exports_isoBase64URL.isBase64URL(certBuffer))b64cert=exports_isoBase64URL.toBase64(certBuffer);else if(exports_isoBase64URL.isBase64(certBuffer))b64cert=certBuffer;else throw Error("Certificate is not a valid base64 or base64url string");else b64cert=exports_isoBase64URL.fromBuffer(certBuffer,"base64");let PEMKey="";for(let i=0;i<Math.ceil(b64cert.length/64);i+=1){let start=64*i;PEMKey+=`${b64cert.substr(start,64)}
|
|
102
102
|
`}return PEMKey=`-----BEGIN CERTIFICATE-----
|
|
103
103
|
${PEMKey}-----END CERTIFICATE-----
|
|
104
104
|
`,PEMKey}var init_convertCertBufferToPEM=__esm(()=>{init_iso()});function convertCOSEtoPKCS(cosePublicKey){let struct=exports_isoCBOR.decodeFirst(cosePublicKey),tag=Uint8Array.from([4]),x=struct.get(COSEKEYS.x),y=struct.get(COSEKEYS.y);if(!x)throw Error("COSE public key was missing x");if(y)return exports_isoUint8Array.concat([tag,x,y]);return exports_isoUint8Array.concat([tag,x])}var init_convertCOSEtoPKCS=__esm(()=>{init_iso();init_cose()});function decodeAttestationObject(attestationObject){return _decodeAttestationObjectInternals.stubThis(exports_isoCBOR.decodeFirst(attestationObject))}var _decodeAttestationObjectInternals;var init_decodeAttestationObject=__esm(()=>{init_iso();_decodeAttestationObjectInternals={stubThis:(value)=>value}});function decodeClientDataJSON(data){let toString=exports_isoBase64URL.toUTF8String(data),clientData=JSON.parse(toString);return _decodeClientDataJSONInternals.stubThis(clientData)}var _decodeClientDataJSONInternals;var init_decodeClientDataJSON=__esm(()=>{init_iso();_decodeClientDataJSONInternals={stubThis:(value)=>value}});function decodeCredentialPublicKey(publicKey){return _decodeCredentialPublicKeyInternals.stubThis(exports_isoCBOR.decodeFirst(publicKey))}var _decodeCredentialPublicKeyInternals;var init_decodeCredentialPublicKey=__esm(()=>{init_iso();_decodeCredentialPublicKeyInternals={stubThis:(value)=>value}});async function generateUserID(){let newUserID=new Uint8Array(32);return await exports_isoCrypto.getRandomValues(newUserID),_generateUserIDInternals.stubThis(newUserID)}var _generateUserIDInternals;var init_generateUserID=__esm(()=>{init_iso();_generateUserIDInternals={stubThis:(value)=>value}});class BufferSourceConverter{static isArrayBuffer(data){return Object.prototype.toString.call(data)==="[object ArrayBuffer]"}static toArrayBuffer(data){if(this.isArrayBuffer(data))return data;if(data.byteLength===data.buffer.byteLength)return data.buffer;if(data.byteOffset===0&&data.byteLength===data.buffer.byteLength)return data.buffer;return this.toUint8Array(data.buffer).slice(data.byteOffset,data.byteOffset+data.byteLength).buffer}static toUint8Array(data){return this.toView(data,Uint8Array)}static toView(data,type){if(data.constructor===type)return data;if(this.isArrayBuffer(data))return new type(data);if(this.isArrayBufferView(data))return new type(data.buffer,data.byteOffset,data.byteLength);throw TypeError("The provided value is not of type '(ArrayBuffer or ArrayBufferView)'")}static isBufferSource(data){return this.isArrayBufferView(data)||this.isArrayBuffer(data)}static isArrayBufferView(data){return ArrayBuffer.isView(data)||data&&this.isArrayBuffer(data.buffer)}static isEqual(a,b){let aView=BufferSourceConverter.toUint8Array(a),bView=BufferSourceConverter.toUint8Array(b);if(aView.length!==bView.byteLength)return!1;for(let i=0;i<aView.length;i++)if(aView[i]!==bView[i])return!1;return!0}static concat(...args){let buffers;if(Array.isArray(args[0])&&!(args[1]instanceof Function))buffers=args[0];else if(Array.isArray(args[0])&&args[1]instanceof Function)buffers=args[0];else if(args[args.length-1]instanceof Function)buffers=args.slice(0,args.length-1);else buffers=args;let size=0;for(let buffer of buffers)size+=buffer.byteLength;let res=new Uint8Array(size),offset=0;for(let buffer of buffers){let view=this.toUint8Array(buffer);res.set(view,offset),offset+=view.length}if(args[args.length-1]instanceof Function)return this.toView(res,args[args.length-1]);return res.buffer}}class Utf8Converter{static fromString(text){let s=unescape(encodeURIComponent(text)),uintArray=new Uint8Array(s.length);for(let i=0;i<s.length;i++)uintArray[i]=s.charCodeAt(i);return uintArray.buffer}static toString(buffer){let buf=BufferSourceConverter.toUint8Array(buffer),encodedString="";for(let i=0;i<buf.length;i++)encodedString+=String.fromCharCode(buf[i]);return decodeURIComponent(escape(encodedString))}}class Utf16Converter{static toString(buffer,littleEndian=!1){let arrayBuffer=BufferSourceConverter.toArrayBuffer(buffer),dataView=new DataView(arrayBuffer),res="";for(let i=0;i<arrayBuffer.byteLength;i+=2){let code=dataView.getUint16(i,littleEndian);res+=String.fromCharCode(code)}return res}static fromString(text,littleEndian=!1){let res=new ArrayBuffer(text.length*2),dataView=new DataView(res);for(let i=0;i<text.length;i++)dataView.setUint16(i*2,text.charCodeAt(i),littleEndian);return res}}class Convert{static isHex(data){return typeof data===STRING_TYPE&&HEX_REGEX.test(data)}static isBase64(data){return typeof data===STRING_TYPE&&BASE64_REGEX.test(data)}static isBase64Url(data){return typeof data===STRING_TYPE&&BASE64URL_REGEX.test(data)}static ToString(buffer,enc="utf8"){let buf=BufferSourceConverter.toUint8Array(buffer);switch(enc.toLowerCase()){case"utf8":return this.ToUtf8String(buf);case"binary":return this.ToBinary(buf);case"hex":return this.ToHex(buf);case"base64":return this.ToBase64(buf);case"base64url":return this.ToBase64Url(buf);case"utf16le":return Utf16Converter.toString(buf,!0);case"utf16":case"utf16be":return Utf16Converter.toString(buf);default:throw Error(`Unknown type of encoding '${enc}'`)}}static FromString(str3,enc="utf8"){if(!str3)return new ArrayBuffer(0);switch(enc.toLowerCase()){case"utf8":return this.FromUtf8String(str3);case"binary":return this.FromBinary(str3);case"hex":return this.FromHex(str3);case"base64":return this.FromBase64(str3);case"base64url":return this.FromBase64Url(str3);case"utf16le":return Utf16Converter.fromString(str3,!0);case"utf16":case"utf16be":return Utf16Converter.fromString(str3);default:throw Error(`Unknown type of encoding '${enc}'`)}}static ToBase64(buffer){let buf=BufferSourceConverter.toUint8Array(buffer);if(typeof btoa<"u"){let binary=this.ToString(buf,"binary");return btoa(binary)}else return Buffer.from(buf).toString("base64")}static FromBase64(base642){let formatted=this.formatString(base642);if(!formatted)return new ArrayBuffer(0);if(!Convert.isBase64(formatted))throw TypeError("Argument 'base64Text' is not Base64 encoded");if(typeof atob<"u")return this.FromBinary(atob(formatted));else return new Uint8Array(Buffer.from(formatted,"base64")).buffer}static FromBase64Url(base64url){let formatted=this.formatString(base64url);if(!formatted)return new ArrayBuffer(0);if(!Convert.isBase64Url(formatted))throw TypeError("Argument 'base64url' is not Base64Url encoded");return this.FromBase64(this.Base64Padding(formatted.replace(/\-/g,"+").replace(/\_/g,"/")))}static ToBase64Url(data){return this.ToBase64(data).replace(/\+/g,"-").replace(/\//g,"_").replace(/\=/g,"")}static FromUtf8String(text,encoding=Convert.DEFAULT_UTF8_ENCODING){switch(encoding){case"ascii":return this.FromBinary(text);case"utf8":return Utf8Converter.fromString(text);case"utf16":case"utf16be":return Utf16Converter.fromString(text);case"utf16le":case"usc2":return Utf16Converter.fromString(text,!0);default:throw Error(`Unknown type of encoding '${encoding}'`)}}static ToUtf8String(buffer,encoding=Convert.DEFAULT_UTF8_ENCODING){switch(encoding){case"ascii":return this.ToBinary(buffer);case"utf8":return Utf8Converter.toString(buffer);case"utf16":case"utf16be":return Utf16Converter.toString(buffer);case"utf16le":case"usc2":return Utf16Converter.toString(buffer,!0);default:throw Error(`Unknown type of encoding '${encoding}'`)}}static FromBinary(text){let stringLength=text.length,resultView=new Uint8Array(stringLength);for(let i=0;i<stringLength;i++)resultView[i]=text.charCodeAt(i);return resultView.buffer}static ToBinary(buffer){let buf=BufferSourceConverter.toUint8Array(buffer),res="";for(let i=0;i<buf.length;i++)res+=String.fromCharCode(buf[i]);return res}static ToHex(buffer){let buf=BufferSourceConverter.toUint8Array(buffer),result="",len=buf.length;for(let i=0;i<len;i++){let byte=buf[i];if(byte<16)result+="0";result+=byte.toString(16)}return result}static FromHex(hexString){let formatted=this.formatString(hexString);if(!formatted)return new ArrayBuffer(0);if(!Convert.isHex(formatted))throw TypeError("Argument 'hexString' is not HEX encoded");if(formatted.length%2)formatted=`0${formatted}`;let res=new Uint8Array(formatted.length/2);for(let i=0;i<formatted.length;i=i+2){let c=formatted.slice(i,i+2);res[i/2]=parseInt(c,16)}return res.buffer}static ToUtf16String(buffer,littleEndian=!1){return Utf16Converter.toString(buffer,littleEndian)}static FromUtf16String(text,littleEndian=!1){return Utf16Converter.fromString(text,littleEndian)}static Base64Padding(base642){let padCount=4-base642.length%4;if(padCount<4)for(let i=0;i<padCount;i++)base642+="=";return base642}static formatString(data){return(data===null||data===void 0?void 0:data.replace(/[\n\r\t ]/g,""))||""}}function combine(...buf){let totalByteLength=buf.map((item)=>item.byteLength).reduce((prev,cur)=>prev+cur),res=new Uint8Array(totalByteLength),currentPos=0;return buf.map((item)=>new Uint8Array(item)).forEach((arr)=>{for(let item2 of arr)res[currentPos++]=item2}),res.buffer}function isEqual(bytes1,bytes2){if(!(bytes1&&bytes2))return!1;if(bytes1.byteLength!==bytes2.byteLength)return!1;let b1=new Uint8Array(bytes1),b2=new Uint8Array(bytes2);for(let i=0;i<bytes1.byteLength;i++)if(b1[i]!==b2[i])return!1;return!0}var STRING_TYPE="string",HEX_REGEX,BASE64_REGEX,BASE64URL_REGEX;var init_index_es=__esm(()=>{/*!
|
|
@@ -393,7 +393,7 @@ WD9f
|
|
|
393
393
|
-----END CERTIFICATE-----
|
|
394
394
|
`;class BaseSettingsService{constructor(){Object.defineProperty(this,"pemCertificates",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.pemCertificates=new Map}setRootCertificates(opts){let{identifier,certificates}=opts,newCertificates=[];for(let cert of certificates)if(cert instanceof Uint8Array)newCertificates.push(convertCertBufferToPEM(cert));else newCertificates.push(cert);this.pemCertificates.set(identifier,newCertificates)}getRootCertificates(opts){let{identifier}=opts;return this.pemCertificates.get(identifier)??[]}}var SettingsService;var init_settingsService=__esm(()=>{init_convertCertBufferToPEM();SettingsService=new BaseSettingsService;SettingsService.setRootCertificates({identifier:"android-key",certificates:[Google_Hardware_Attestation_Root_1,Google_Hardware_Attestation_Root_2,Google_Hardware_Attestation_Root_3,Google_Hardware_Attestation_Root_4]});SettingsService.setRootCertificates({identifier:"android-safetynet",certificates:[GlobalSign_Root_CA]});SettingsService.setRootCertificates({identifier:"apple",certificates:[Apple_WebAuthn_Root_CA]});SettingsService.setRootCertificates({identifier:"mds",certificates:[GlobalSign_Root_CA_R3]})});async function verifyMDSBlob(blob){let parsedJWT=parseJWT(blob),header=parsedJWT[0],payload=parsedJWT[1],headerCertsPEM=header.x5c.map(convertCertBufferToPEM);try{let rootCerts=SettingsService.getRootCertificates({identifier:"mds"});await validateCertificatePath(headerCertsPEM,rootCerts)}catch(error){throw Error("BLOB certificate path could not be validated",{cause:error})}let leafCert=headerCertsPEM[0];if(!await verifyJWT2(blob,convertPEMToBytes(leafCert)))throw Error("BLOB signature could not be verified");let statements=[];for(let entry of payload.entries)if(entry.aaguid&&entry.metadataStatement)statements.push(entry.metadataStatement);let[year,month,day]=payload.nextUpdate.split("-"),parsedNextUpdate=new Date(parseInt(year,10),parseInt(month,10)-1,parseInt(day,10));return{statements,parsedNextUpdate,payload}}var init_verifyMDSBlob=__esm(()=>{init_parseJWT();init_verifyJWT();init_validateCertificatePath();init_convertCertBufferToPEM();init_convertPEMToBytes();init_settingsService()});var init_helpers=__esm(()=>{init_cose();init_convertAAGUIDToString();init_convertCertBufferToPEM();init_convertCOSEtoPKCS();init_decodeAttestationObject();init_decodeClientDataJSON();init_decodeCredentialPublicKey();init_generateChallenge();init_generateUserID();init_getCertificateInfo();init_isCertRevoked();init_parseAuthenticatorData();init_toHash();init_validateCertificatePath();init_verifySignature();init_iso();init_verifyMDSBlob()});async function verifyOKP(opts){let{cosePublicKey,signature,data}=opts,WebCrypto=await getWebCrypto(),alg=cosePublicKey.get(COSEKEYS.alg),crv=cosePublicKey.get(COSEKEYS.crv),x=cosePublicKey.get(COSEKEYS.x);if(!alg)throw Error("Public key was missing alg (OKP)");if(!isCOSEAlg(alg))throw Error(`Public key had invalid alg ${alg} (OKP)`);if(!crv)throw Error("Public key was missing crv (OKP)");if(!x)throw Error("Public key was missing x (OKP)");let _crv;if(crv===COSECRV.ED25519)_crv="Ed25519";else throw Error(`Unexpected COSE crv value of ${crv} (OKP)`);let keyData={kty:"OKP",crv:_crv,alg:"EdDSA",x:exports_isoBase64URL.fromBuffer(x),ext:!1},key2=await importKey({keyData,algorithm:{name:_crv,namedCurve:_crv}}),verifyAlgorithm={name:_crv};return WebCrypto.subtle.verify(verifyAlgorithm,key2,signature,data)}var init_verifyOKP=__esm(()=>{init_cose();init_helpers();init_importKey();init_getWebCrypto()});function unwrapEC2Signature(signature,crv){let parsedSignature=AsnParser.parse(signature,ECDSASigValue),rBytes=new Uint8Array(parsedSignature.r),sBytes=new Uint8Array(parsedSignature.s),componentLength=getSignatureComponentLength(crv),rNormalizedBytes=toNormalizedBytes(rBytes,componentLength),sNormalizedBytes=toNormalizedBytes(sBytes,componentLength);return exports_isoUint8Array.concat([rNormalizedBytes,sNormalizedBytes])}function getSignatureComponentLength(crv){switch(crv){case COSECRV.P256:return 32;case COSECRV.P384:return 48;case COSECRV.P521:return 66;default:throw Error(`Unexpected COSE crv value of ${crv} (EC2)`)}}function toNormalizedBytes(bytes,componentLength){let normalizedBytes;if(bytes.length<componentLength)normalizedBytes=new Uint8Array(componentLength),normalizedBytes.set(bytes,componentLength-bytes.length);else if(bytes.length===componentLength)normalizedBytes=bytes;else if(bytes.length===componentLength+1&&bytes[0]===0&&(bytes[1]&128)===128)normalizedBytes=bytes.subarray(1);else throw Error(`Invalid signature component length ${bytes.length}, expected ${componentLength}`);return normalizedBytes}var init_unwrapEC2Signature=__esm(()=>{init_es2015();init_es20155();init_cose();init_iso()});function verify(opts){let{cosePublicKey,signature,data,shaHashOverride}=opts;if(isCOSEPublicKeyEC2(cosePublicKey)){let crv=cosePublicKey.get(COSEKEYS.crv);if(!isCOSECrv(crv))throw Error(`unknown COSE curve ${crv}`);let unwrappedSignature=unwrapEC2Signature(signature,crv);return verifyEC2({cosePublicKey,signature:unwrappedSignature,data,shaHashOverride})}else if(isCOSEPublicKeyRSA(cosePublicKey))return verifyRSA({cosePublicKey,signature,data,shaHashOverride});else if(isCOSEPublicKeyOKP(cosePublicKey))return verifyOKP({cosePublicKey,signature,data});let kty=cosePublicKey.get(COSEKEYS.kty);throw Error(`Signature verification with public key of kty ${kty} is not supported by this method`)}var init_verify=__esm(()=>{init_cose();init_verifyEC2();init_verifyRSA();init_verifyOKP();init_unwrapEC2Signature()});var exports_isoCrypto={};__export(exports_isoCrypto,{verify:()=>verify,getRandomValues:()=>getRandomValues,digest:()=>digest});var init_isoCrypto=__esm(()=>{init_digest();init_getRandomValues();init_verify()});var exports_isoUint8Array={};__export(exports_isoUint8Array,{toUTF8String:()=>toUTF8String2,toHex:()=>toHex,toDataView:()=>toDataView,fromUTF8String:()=>fromUTF8String2,fromHex:()=>fromHex,fromASCIIString:()=>fromASCIIString,concat:()=>concat3,areEqual:()=>areEqual});function areEqual(array1,array2){if(array1.length!=array2.length)return!1;return array1.every((val,i)=>val===array2[i])}function toHex(array){return Array.from(array,(i)=>i.toString(16).padStart(2,"0")).join("")}function fromHex(hex2){if(!hex2)return Uint8Array.from([]);if(!(hex2.length!==0&&hex2.length%2===0&&!/[^a-fA-F0-9]/u.test(hex2)))throw Error("Invalid hex string");let byteStrings=hex2.match(/.{1,2}/g)??[];return Uint8Array.from(byteStrings.map((byte)=>parseInt(byte,16)))}function concat3(arrays){let pointer=0,totalLength=arrays.reduce((prev,curr)=>prev+curr.length,0),toReturn=new Uint8Array(totalLength);return arrays.forEach((arr)=>{toReturn.set(arr,pointer),pointer+=arr.length}),toReturn}function toUTF8String2(array){return new globalThis.TextDecoder("utf-8").decode(array)}function fromUTF8String2(utf8String){return new globalThis.TextEncoder().encode(utf8String)}function fromASCIIString(value){return Uint8Array.from(value.split("").map((x)=>x.charCodeAt(0)))}function toDataView(array){return new DataView(array.buffer,array.byteOffset,array.length)}var init_iso=__esm(()=>{init_isoBase64URL();init_isoCBOR();init_isoCrypto()});async function generateChallenge2(){let challenge=new Uint8Array(32);return await exports_isoCrypto.getRandomValues(challenge),_generateChallengeInternals.stubThis(challenge)}var _generateChallengeInternals;var init_generateChallenge=__esm(()=>{init_iso();_generateChallengeInternals={stubThis:(value)=>value}});async function generateRegistrationOptions(options){let{rpName,rpID,userName,userID,challenge=await generateChallenge2(),userDisplayName="",timeout=60000,attestationType="none",excludeCredentials=[],authenticatorSelection=defaultAuthenticatorSelection,extensions:extensions2,supportedAlgorithmIDs=defaultSupportedAlgorithmIDs,preferredAuthenticatorType}=options,pubKeyCredParams=supportedAlgorithmIDs.map((id)=>({alg:id,type:"public-key"}));if(authenticatorSelection.residentKey===void 0){if(authenticatorSelection.requireResidentKey)authenticatorSelection.residentKey="required"}else authenticatorSelection.requireResidentKey=authenticatorSelection.residentKey==="required";let _challenge=challenge;if(typeof _challenge==="string")_challenge=exports_isoUint8Array.fromUTF8String(_challenge);if(typeof userID==="string")throw Error("String values for `userID` are no longer supported. See https://simplewebauthn.dev/docs/advanced/server/custom-user-ids");let _userID=userID;if(!_userID)_userID=await generateUserID();let hints=[];if(preferredAuthenticatorType){if(preferredAuthenticatorType==="securityKey")hints.push("security-key"),authenticatorSelection.authenticatorAttachment="cross-platform";else if(preferredAuthenticatorType==="localDevice")hints.push("client-device"),authenticatorSelection.authenticatorAttachment="platform";else if(preferredAuthenticatorType==="remoteDevice")hints.push("hybrid"),authenticatorSelection.authenticatorAttachment="cross-platform"}return{challenge:exports_isoBase64URL.fromBuffer(_challenge),rp:{name:rpName,id:rpID},user:{id:exports_isoBase64URL.fromBuffer(_userID),name:userName,displayName:userDisplayName},pubKeyCredParams,timeout,attestation:attestationType,excludeCredentials:excludeCredentials.map((cred)=>{if(!exports_isoBase64URL.isBase64URL(cred.id))throw Error(`excludeCredential id "${cred.id}" is not a valid base64url string`);return{...cred,id:exports_isoBase64URL.trimPadding(cred.id),type:"public-key"}}),authenticatorSelection,extensions:{...extensions2,credProps:!0},hints}}var supportedCOSEAlgorithmIdentifiers,defaultAuthenticatorSelection,defaultSupportedAlgorithmIDs;var init_generateRegistrationOptions=__esm(()=>{init_generateChallenge();init_generateUserID();init_iso();supportedCOSEAlgorithmIdentifiers=[-8,-7,-36,-37,-38,-39,-257,-258,-259,-65535],defaultAuthenticatorSelection={residentKey:"preferred",userVerification:"preferred"},defaultSupportedAlgorithmIDs=[-8,-7,-257]});function parseBackupFlags({be,bs}){let credentialBackedUp=bs,credentialDeviceType="singleDevice";if(be)credentialDeviceType="multiDevice";if(credentialDeviceType==="singleDevice"&&credentialBackedUp)throw new InvalidBackupFlags("Single-device credential indicated that it was backed up, which should be impossible.");return{credentialDeviceType,credentialBackedUp}}var InvalidBackupFlags;var init_parseBackupFlags=__esm(()=>{InvalidBackupFlags=class InvalidBackupFlags extends Error{constructor(message){super(message);this.name="InvalidBackupFlags"}}});async function matchExpectedRPID(rpIDHash,expectedRPIDs){try{return await Promise.any(expectedRPIDs.map((expected)=>{return new Promise((resolve2,reject)=>{toHash(exports_isoUint8Array.fromASCIIString(expected)).then((expectedRPIDHash)=>{if(exports_isoUint8Array.areEqual(rpIDHash,expectedRPIDHash))resolve2(expected);else reject()})})}))}catch(err){if(err.name==="AggregateError")throw new UnexpectedRPIDHash;throw err}}var UnexpectedRPIDHash;var init_matchExpectedRPID=__esm(()=>{init_toHash();init_iso();UnexpectedRPIDHash=class UnexpectedRPIDHash extends Error{constructor(){super("Unexpected RP ID hash");this.name="UnexpectedRPIDHash"}}});async function verifyAttestationFIDOU2F(options){let{attStmt,clientDataHash,rpIdHash,credentialID,credentialPublicKey,aaguid,rootCertificates}=options,reservedByte=Uint8Array.from([0]),publicKey=convertCOSEtoPKCS(credentialPublicKey),signatureBase=exports_isoUint8Array.concat([reservedByte,rpIdHash,clientDataHash,credentialID,publicKey]),sig=attStmt.get("sig"),x5c=attStmt.get("x5c");if(!x5c)throw Error("No attestation certificate provided in attestation statement (FIDOU2F)");if(!sig)throw Error("No attestation signature provided in attestation statement (FIDOU2F)");let aaguidToHex=Number.parseInt(exports_isoUint8Array.toHex(aaguid),16);if(aaguidToHex!==0)throw Error(`AAGUID "${aaguidToHex}" was not expected value`);try{await validateCertificatePath(x5c.map(convertCertBufferToPEM),rootCertificates)}catch(err){throw Error(`${err.message} (FIDOU2F)`)}return verifySignature2({signature:sig,data:signatureBase,x509Certificate:x5c[0],hashAlgorithm:COSEALG.ES256})}var init_verifyAttestationFIDOU2F=__esm(()=>{init_convertCOSEtoPKCS();init_convertCertBufferToPEM();init_validateCertificatePath();init_verifySignature();init_iso();init_cose()});function validateExtFIDOGenCEAAGUID(certExtensions,aaguid){if(!certExtensions)return!0;let extFIDOGenCEAAGUID=certExtensions.find((ext)=>ext.extnID===id_fido_gen_ce_aaguid);if(!extFIDOGenCEAAGUID)return!0;let parsedExtFIDOGenCEAAGUID=AsnParser.parse(extFIDOGenCEAAGUID.extnValue,OctetString2),extValue=new Uint8Array(parsedExtFIDOGenCEAAGUID.buffer);if(!exports_isoUint8Array.areEqual(aaguid,extValue)){let _debugExtHex=exports_isoUint8Array.toHex(extValue),_debugAAGUIDHex=exports_isoUint8Array.toHex(aaguid);throw Error(`Certificate extension id-fido-gen-ce-aaguid (${id_fido_gen_ce_aaguid}) value of "${_debugExtHex}" was present but not equal to attestation statement AAGUID value of "${_debugAAGUIDHex}"`)}return!0}var id_fido_gen_ce_aaguid="1.3.6.1.4.1.45724.1.1.4";var init_validateExtFIDOGenCEAAGUID=__esm(()=>{init_es2015();init_iso()});function getLogger(_name){return(_message,..._rest)=>{}}class BaseMetadataService{constructor(){Object.defineProperty(this,"mdsCache",{enumerable:!0,configurable:!0,writable:!0,value:{}}),Object.defineProperty(this,"statementCache",{enumerable:!0,configurable:!0,writable:!0,value:{}}),Object.defineProperty(this,"state",{enumerable:!0,configurable:!0,writable:!0,value:SERVICE_STATE.DISABLED}),Object.defineProperty(this,"verificationMode",{enumerable:!0,configurable:!0,writable:!0,value:"strict"})}async initialize(opts={}){this.statementCache={};let{mdsServers=[defaultURLMDS],statements,verificationMode}=opts;if(this.setState(SERVICE_STATE.REFRESHING),statements?.length){let statementsAdded=0;statements.forEach((statement)=>{if(statement.aaguid)this.statementCache[statement.aaguid]={entry:{metadataStatement:statement,statusReports:[],timeOfLastStatusChange:"1970-01-01"},url:NonRefreshingMDS.url},statementsAdded+=1}),log3(`Cached ${statementsAdded} local statements`)}if(mdsServers?.length){let currentCacheCount=Object.keys(this.statementCache).length,numServers=mdsServers.length;for(let url of mdsServers)try{let cachedMDS={url,no:0,nextUpdate:new Date(0)},blob=await this.downloadBlob(cachedMDS);await this.verifyBlob(blob,cachedMDS)}catch(err){log3(`Could not download BLOB from ${url}:`,err),numServers-=1}let cacheDiff=Object.keys(this.statementCache).length-currentCacheCount;log3(`Cached ${cacheDiff} statements from ${numServers} metadata server(s)`)}if(verificationMode)this.verificationMode=verificationMode;this.setState(SERVICE_STATE.READY)}async getStatement(aaguid){if(this.state===SERVICE_STATE.DISABLED)return;if(!aaguid)return;if(aaguid instanceof Uint8Array)aaguid=convertAAGUIDToString(aaguid);await this.pauseUntilReady();let cachedStatement=this.statementCache[aaguid];if(!cachedStatement){if(this.verificationMode==="strict")throw Error(`No metadata statement found for aaguid "${aaguid}"`);return}if(cachedStatement.url){let mds=this.mdsCache[cachedStatement.url];if(new Date>mds.nextUpdate)try{this.setState(SERVICE_STATE.REFRESHING);let blob=await this.downloadBlob(mds);await this.verifyBlob(blob,mds)}finally{this.setState(SERVICE_STATE.READY)}}let{entry}=cachedStatement;for(let report of entry.statusReports){let{status}=report;if(status==="USER_VERIFICATION_BYPASS"||status==="ATTESTATION_KEY_COMPROMISE"||status==="USER_KEY_REMOTE_COMPROMISE"||status==="USER_KEY_PHYSICAL_COMPROMISE")throw Error(`Detected compromised aaguid "${aaguid}"`)}return entry.metadataStatement}async downloadBlob(cachedMDS){let{url}=cachedMDS;return await(await fetch2(url)).text()}async verifyBlob(blob,cachedMDS){let{url,no}=cachedMDS,{payload,parsedNextUpdate}=await verifyMDSBlob(blob);if(payload.no<=no)throw Error(`Latest BLOB no. ${payload.no} is not greater than previous no. ${no}`);for(let entry of payload.entries)if(entry.aaguid)this.statementCache[entry.aaguid]={entry,url};if(url)this.mdsCache[url]={...cachedMDS,no:payload.no,nextUpdate:parsedNextUpdate};else if(parsedNextUpdate<new Date)log3(`\u26A0\uFE0F This MDS blob (serial: ${payload.no}) contains stale data as of ${parsedNextUpdate.toISOString()}. Please consider re-initializing MetadataService with a newer MDS blob.`)}pauseUntilReady(){if(this.state===SERVICE_STATE.READY)return new Promise((resolve2)=>{resolve2()});return new Promise((resolve2,reject)=>{let iterations=700,intervalID=globalThis.setInterval(()=>{if(iterations<1)clearInterval(intervalID),reject("State did not become ready in 70 seconds");else if(this.state===SERVICE_STATE.READY)clearInterval(intervalID),resolve2();iterations-=1},100)})}setState(newState){if(this.state=newState,newState===SERVICE_STATE.DISABLED)log3("MetadataService is DISABLED");else if(newState===SERVICE_STATE.REFRESHING)log3("MetadataService is REFRESHING");else if(newState===SERVICE_STATE.READY)log3("MetadataService is READY")}}var NonRefreshingMDS,defaultURLMDS="https://mds.fidoalliance.org/",SERVICE_STATE,log3,MetadataService;var init_metadataService=__esm(()=>{init_convertAAGUIDToString();init_verifyMDSBlob();init_fetch();NonRefreshingMDS={url:"",no:0,nextUpdate:new Date(0)};(function(SERVICE_STATE2){SERVICE_STATE2[SERVICE_STATE2.DISABLED=0]="DISABLED",SERVICE_STATE2[SERVICE_STATE2.REFRESHING=1]="REFRESHING",SERVICE_STATE2[SERVICE_STATE2.READY=2]="READY"})(SERVICE_STATE||(SERVICE_STATE={}));log3=getLogger("MetadataService");MetadataService=new BaseMetadataService});async function verifyAttestationWithMetadata({statement,credentialPublicKey,x5c,attestationStatementAlg}){let{authenticationAlgorithms,authenticatorGetInfo,attestationRootCertificates}=statement,keypairCOSEAlgs=new Set;authenticationAlgorithms.forEach((algSign)=>{let algSignCOSEINFO=algSignToCOSEInfoMap[algSign];if(algSignCOSEINFO)keypairCOSEAlgs.add(algSignCOSEINFO)});let decodedPublicKey=decodeCredentialPublicKey(credentialPublicKey),kty=decodedPublicKey.get(COSEKEYS.kty),alg=decodedPublicKey.get(COSEKEYS.alg);if(!kty)throw Error("Credential public key was missing kty");if(!alg)throw Error("Credential public key was missing alg");if(!kty)throw Error("Credential public key was missing kty");let publicKeyCOSEInfo={kty,alg};if(isCOSEPublicKeyEC2(decodedPublicKey)){let crv=decodedPublicKey.get(COSEKEYS.crv);publicKeyCOSEInfo.crv=crv}let foundMatch=!1;for(let keypairAlg of keypairCOSEAlgs){if(keypairAlg.alg===publicKeyCOSEInfo.alg&&keypairAlg.kty===publicKeyCOSEInfo.kty)if((keypairAlg.kty===COSEKTY.EC2||keypairAlg.kty===COSEKTY.OKP)&&keypairAlg.crv===publicKeyCOSEInfo.crv)foundMatch=!0;else foundMatch=!0;if(foundMatch)break}if(!foundMatch){let debugMDSAlgs=authenticationAlgorithms.map((algSign)=>`'${algSign}' (COSE info: ${stringifyCOSEInfo(algSignToCOSEInfoMap[algSign])})`),strMDSAlgs=JSON.stringify(debugMDSAlgs,null,2).replace(/"/g,""),strPubKeyAlg=stringifyCOSEInfo(publicKeyCOSEInfo);throw Error(`Public key parameters ${strPubKeyAlg} did not match any of the following metadata algorithms:
|
|
395
395
|
${strMDSAlgs}`)}if(attestationStatementAlg!==void 0&&authenticatorGetInfo?.algorithms!==void 0){let getInfoAlgs=authenticatorGetInfo.algorithms.map((_alg)=>_alg.alg);if(getInfoAlgs.indexOf(attestationStatementAlg)<0)throw Error(`Attestation statement alg ${attestationStatementAlg} did not match one of ${getInfoAlgs}`)}let authenticatorCerts=x5c.map(convertCertBufferToPEM),statementRootCerts=attestationRootCertificates.map(convertCertBufferToPEM),authenticatorIsSelfReferencing=!1;if(authenticatorCerts.length===1&&statementRootCerts.indexOf(authenticatorCerts[0])>=0)authenticatorIsSelfReferencing=!0;if(!authenticatorIsSelfReferencing)try{await validateCertificatePath(authenticatorCerts,statementRootCerts)}catch(err){throw Error(`Could not validate certificate path with any metadata root certificates: ${err.message}`)}return!0}function stringifyCOSEInfo(info){let{kty,alg,crv}=info,toReturn="";if(kty!==COSEKTY.RSA)toReturn=`{ kty: ${kty}, alg: ${alg}, crv: ${crv} }`;else toReturn=`{ kty: ${kty}, alg: ${alg} }`;return toReturn}var algSignToCOSEInfoMap;var init_verifyAttestationWithMetadata=__esm(()=>{init_convertCertBufferToPEM();init_validateCertificatePath();init_decodeCredentialPublicKey();init_cose();algSignToCOSEInfoMap={secp256r1_ecdsa_sha256_raw:{kty:2,alg:-7,crv:1},secp256r1_ecdsa_sha256_der:{kty:2,alg:-7,crv:1},rsassa_pss_sha256_raw:{kty:3,alg:-37},rsassa_pss_sha256_der:{kty:3,alg:-37},secp256k1_ecdsa_sha256_raw:{kty:2,alg:-47,crv:8},secp256k1_ecdsa_sha256_der:{kty:2,alg:-47,crv:8},rsassa_pss_sha384_raw:{kty:3,alg:-38},rsassa_pkcsv15_sha256_raw:{kty:3,alg:-257},rsassa_pkcsv15_sha384_raw:{kty:3,alg:-258},rsassa_pkcsv15_sha512_raw:{kty:3,alg:-259},rsassa_pkcsv15_sha1_raw:{kty:3,alg:-65535},secp384r1_ecdsa_sha384_raw:{kty:2,alg:-35,crv:2},secp512r1_ecdsa_sha256_raw:{kty:2,alg:-36,crv:3},ed25519_eddsa_sha512_raw:{kty:1,alg:-8,crv:6}}});async function verifyAttestationPacked(options){let{attStmt,clientDataHash,authData,credentialPublicKey,aaguid,rootCertificates}=options,sig=attStmt.get("sig"),x5c=attStmt.get("x5c"),alg=attStmt.get("alg");if(!sig)throw Error("No attestation signature provided in attestation statement (Packed)");if(!alg)throw Error("Attestation statement did not contain alg (Packed)");if(!isCOSEAlg(alg))throw Error(`Attestation statement contained invalid alg ${alg} (Packed)`);let signatureBase=exports_isoUint8Array.concat([authData,clientDataHash]),verified=!1;if(x5c){let{subject,basicConstraintsCA,version,notBefore,notAfter,parsedCertificate}=getCertificateInfo(x5c[0]),{OU,CN,O,C}=subject;if(OU!=="Authenticator Attestation")throw Error('Certificate OU was not "Authenticator Attestation" (Packed|Full)');if(!CN)throw Error("Certificate CN was empty (Packed|Full)");if(!O)throw Error("Certificate O was empty (Packed|Full)");if(!C||C.length!==2)throw Error("Certificate C was not two-character ISO 3166 code (Packed|Full)");if(basicConstraintsCA)throw Error("Certificate basic constraints CA was not `false` (Packed|Full)");if(version!==2)throw Error("Certificate version was not `3` (ASN.1 value of 2) (Packed|Full)");let now=new Date;if(notBefore>now)throw Error(`Certificate not good before "${notBefore.toString()}" (Packed|Full)`);if(now=new Date,notAfter<now)throw Error(`Certificate not good after "${notAfter.toString()}" (Packed|Full)`);try{await validateExtFIDOGenCEAAGUID(parsedCertificate.tbsCertificate.extensions,aaguid)}catch(err){throw Error(`${err.message} (Packed|Full)`)}let statement=await MetadataService.getStatement(aaguid);if(statement){if(statement.attestationTypes.indexOf("basic_full")<0)throw Error("Metadata does not indicate support for full attestations (Packed|Full)");try{await verifyAttestationWithMetadata({statement,credentialPublicKey,x5c,attestationStatementAlg:alg})}catch(err){throw Error(`${err.message} (Packed|Full)`)}}else try{await validateCertificatePath(x5c.map(convertCertBufferToPEM),rootCertificates)}catch(err){throw Error(`${err.message} (Packed|Full)`)}verified=await verifySignature2({signature:sig,data:signatureBase,x509Certificate:x5c[0]})}else verified=await verifySignature2({signature:sig,data:signatureBase,credentialPublicKey,hashAlgorithm:alg});return verified}var init_verifyAttestationPacked=__esm(()=>{init_cose();init_convertCertBufferToPEM();init_validateCertificatePath();init_getCertificateInfo();init_verifySignature();init_iso();init_validateExtFIDOGenCEAAGUID();init_metadataService();init_verifyAttestationWithMetadata()});async function verifyAttestationAndroidSafetyNet(options){let{attStmt,clientDataHash,authData,aaguid,rootCertificates,verifyTimestampMS=!0,credentialPublicKey,attestationSafetyNetEnforceCTSCheck}=options,alg=attStmt.get("alg"),response=attStmt.get("response");if(!attStmt.get("ver"))throw Error("No ver value in attestation (SafetyNet)");if(!response)throw Error("No response was included in attStmt by authenticator (SafetyNet)");let jwtParts=exports_isoUint8Array.toUTF8String(response).split("."),HEADER=JSON.parse(exports_isoBase64URL.toUTF8String(jwtParts[0])),PAYLOAD=JSON.parse(exports_isoBase64URL.toUTF8String(jwtParts[1])),SIGNATURE=jwtParts[2],{nonce,ctsProfileMatch,timestampMs}=PAYLOAD;if(verifyTimestampMS){let now=Date.now();if(timestampMs>Date.now())throw Error(`Payload timestamp "${timestampMs}" was later than "${now}" (SafetyNet)`);let timestampPlusDelay=timestampMs+60000;if(now=Date.now(),timestampPlusDelay<now)throw Error(`Payload timestamp "${timestampPlusDelay}" has expired (SafetyNet)`)}let nonceBase=exports_isoUint8Array.concat([authData,clientDataHash]),nonceBuffer=await toHash(nonceBase),expectedNonce=exports_isoBase64URL.fromBuffer(nonceBuffer,"base64");if(nonce!==expectedNonce)throw Error("Could not verify payload nonce (SafetyNet)");if(attestationSafetyNetEnforceCTSCheck&&!ctsProfileMatch)throw Error("Could not verify device integrity (SafetyNet)");let leafCertBuffer=exports_isoBase64URL.toBuffer(HEADER.x5c[0],"base64"),leafCertInfo=getCertificateInfo(leafCertBuffer),{subject}=leafCertInfo;if(subject.CN!=="attest.android.com")throw Error('Certificate common name was not "attest.android.com" (SafetyNet)');let statement=await MetadataService.getStatement(aaguid);if(statement)try{await verifyAttestationWithMetadata({statement,credentialPublicKey,x5c:HEADER.x5c,attestationStatementAlg:alg})}catch(err){throw Error(`${err.message} (SafetyNet)`)}else try{await validateCertificatePath(HEADER.x5c.map(convertCertBufferToPEM),rootCertificates)}catch(err){throw Error(`${err.message} (SafetyNet)`)}let signatureBaseBuffer=exports_isoUint8Array.fromUTF8String(`${jwtParts[0]}.${jwtParts[1]}`),signatureBuffer=exports_isoBase64URL.toBuffer(SIGNATURE);return await verifySignature2({signature:signatureBuffer,data:signatureBaseBuffer,x509Certificate:leafCertBuffer})}var init_verifyAttestationAndroidSafetyNet=__esm(()=>{init_toHash();init_verifySignature();init_getCertificateInfo();init_validateCertificatePath();init_convertCertBufferToPEM();init_iso();init_metadataService();init_verifyAttestationWithMetadata()});var TPM_ST,TPM_ALG,TPM_ECC_CURVE,TPM_MANUFACTURERS,TPM_ECC_CURVE_COSE_CRV_MAP;var init_constants2=__esm(()=>{TPM_ST={196:"TPM_ST_RSP_COMMAND",32768:"TPM_ST_NULL",32769:"TPM_ST_NO_SESSIONS",32770:"TPM_ST_SESSIONS",32788:"TPM_ST_ATTEST_NV",32789:"TPM_ST_ATTEST_COMMAND_AUDIT",32790:"TPM_ST_ATTEST_SESSION_AUDIT",32791:"TPM_ST_ATTEST_CERTIFY",32792:"TPM_ST_ATTEST_QUOTE",32793:"TPM_ST_ATTEST_TIME",32794:"TPM_ST_ATTEST_CREATION",32801:"TPM_ST_CREATION",32802:"TPM_ST_VERIFIED",32803:"TPM_ST_AUTH_SECRET",32804:"TPM_ST_HASHCHECK",32805:"TPM_ST_AUTH_SIGNED",32809:"TPM_ST_FU_MANIFEST"},TPM_ALG={0:"TPM_ALG_ERROR",1:"TPM_ALG_RSA",4:"TPM_ALG_SHA",4:"TPM_ALG_SHA1",5:"TPM_ALG_HMAC",6:"TPM_ALG_AES",7:"TPM_ALG_MGF1",8:"TPM_ALG_KEYEDHASH",10:"TPM_ALG_XOR",11:"TPM_ALG_SHA256",12:"TPM_ALG_SHA384",13:"TPM_ALG_SHA512",16:"TPM_ALG_NULL",18:"TPM_ALG_SM3_256",19:"TPM_ALG_SM4",20:"TPM_ALG_RSASSA",21:"TPM_ALG_RSAES",22:"TPM_ALG_RSAPSS",23:"TPM_ALG_OAEP",24:"TPM_ALG_ECDSA",25:"TPM_ALG_ECDH",26:"TPM_ALG_ECDAA",27:"TPM_ALG_SM2",28:"TPM_ALG_ECSCHNORR",29:"TPM_ALG_ECMQV",32:"TPM_ALG_KDF1_SP800_56A",33:"TPM_ALG_KDF2",34:"TPM_ALG_KDF1_SP800_108",35:"TPM_ALG_ECC",37:"TPM_ALG_SYMCIPHER",38:"TPM_ALG_CAMELLIA",64:"TPM_ALG_CTR",65:"TPM_ALG_OFB",66:"TPM_ALG_CBC",67:"TPM_ALG_CFB",68:"TPM_ALG_ECB"},TPM_ECC_CURVE={0:"TPM_ECC_NONE",1:"TPM_ECC_NIST_P192",2:"TPM_ECC_NIST_P224",3:"TPM_ECC_NIST_P256",4:"TPM_ECC_NIST_P384",5:"TPM_ECC_NIST_P521",16:"TPM_ECC_BN_P256",17:"TPM_ECC_BN_P638",32:"TPM_ECC_SM2_P256"},TPM_MANUFACTURERS={"id:414D4400":{name:"AMD",id:"AMD"},"id:414E5400":{name:"Ant Group",id:"ANT"},"id:41544D4C":{name:"Atmel",id:"ATML"},"id:4252434D":{name:"Broadcom",id:"BRCM"},"id:4353434F":{name:"Cisco",id:"CSCO"},"id:464C5953":{name:"Flyslice Technologies",id:"FLYS"},"id:524F4343":{name:"Fuzhou Rockchip",id:"ROCC"},"id:474F4F47":{name:"Google",id:"GOOG"},"id:48504900":{name:"HPI",id:"HPI"},"id:48504500":{name:"HPE",id:"HPE"},"id:48495349":{name:"Huawei",id:"HISI"},"id:49424d00":{name:"IBM",id:"IBM"},"id:49424D00":{name:"IBM",id:"IBM"},"id:49465800":{name:"Infineon",id:"IFX"},"id:494E5443":{name:"Intel",id:"INTC"},"id:4C454E00":{name:"Lenovo",id:"LEN"},"id:4D534654":{name:"Microsoft",id:"MSFT"},"id:4E534D20":{name:"National Semiconductor",id:"NSM"},"id:4E545A00":{name:"Nationz",id:"NTZ"},"id:4E534700":{name:"NSING",id:"NSG"},"id:4E544300":{name:"Nuvoton Technology",id:"NTC"},"id:51434F4D":{name:"Qualcomm",id:"QCOM"},"id:534D534E":{name:"Samsung",id:"SMSN"},"id:53454345":{name:"SecEdge",id:"SECE"},"id:534E5300":{name:"Sinosun",id:"SNS"},"id:534D5343":{name:"SMSC",id:"SMSC"},"id:53544D20":{name:"STMicroelectronics",id:"STM"},"id:54584E00":{name:"Texas Instruments",id:"TXN"},"id:57454300":{name:"Winbond",id:"WEC"},"id:5345414C":{name:"Wisekey",id:"SEAL"},"id:FFFFF1D0":{name:"FIDO Alliance",id:"FIDO"}},TPM_ECC_CURVE_COSE_CRV_MAP={TPM_ECC_NIST_P256:1,TPM_ECC_NIST_P384:2,TPM_ECC_NIST_P521:3,TPM_ECC_BN_P256:1,TPM_ECC_SM2_P256:1}});function parseCertInfo(certInfo){let pointer=0,dataView=exports_isoUint8Array.toDataView(certInfo),magic=dataView.getUint32(pointer);pointer+=4;let typeBuffer=dataView.getUint16(pointer);pointer+=2;let type=TPM_ST[typeBuffer],qualifiedSignerLength=dataView.getUint16(pointer);pointer+=2;let qualifiedSigner=certInfo.slice(pointer,pointer+=qualifiedSignerLength),extraDataLength=dataView.getUint16(pointer);pointer+=2;let extraData=certInfo.slice(pointer,pointer+=extraDataLength),clock=certInfo.slice(pointer,pointer+=8),resetCount=dataView.getUint32(pointer);pointer+=4;let restartCount=dataView.getUint32(pointer);pointer+=4;let safe=!!certInfo.slice(pointer,pointer+=1),clockInfo={clock,resetCount,restartCount,safe},firmwareVersion=certInfo.slice(pointer,pointer+=8),attestedNameLength=dataView.getUint16(pointer);pointer+=2;let attestedName=certInfo.slice(pointer,pointer+=attestedNameLength),attestedNameDataView=exports_isoUint8Array.toDataView(attestedName),qualifiedNameLength=dataView.getUint16(pointer);pointer+=2;let qualifiedName=certInfo.slice(pointer,pointer+=qualifiedNameLength),attested={nameAlg:TPM_ALG[attestedNameDataView.getUint16(0)],nameAlgBuffer:attestedName.slice(0,2),name:attestedName,qualifiedName};return{magic,type,qualifiedSigner,extraData,clockInfo,firmwareVersion,attested}}var init_parseCertInfo=__esm(()=>{init_constants2();init_iso()});function parsePubArea(pubArea){let pointer=0,dataView=exports_isoUint8Array.toDataView(pubArea),type=TPM_ALG[dataView.getUint16(pointer)];pointer+=2;let nameAlg=TPM_ALG[dataView.getUint16(pointer)];pointer+=2;let objectAttributesInt=dataView.getUint32(pointer);pointer+=4;let objectAttributes={fixedTPM:!!(objectAttributesInt&1),stClear:!!(objectAttributesInt&2),fixedParent:!!(objectAttributesInt&8),sensitiveDataOrigin:!!(objectAttributesInt&16),userWithAuth:!!(objectAttributesInt&32),adminWithPolicy:!!(objectAttributesInt&64),noDA:!!(objectAttributesInt&512),encryptedDuplication:!!(objectAttributesInt&1024),restricted:!!(objectAttributesInt&32768),decrypt:!!(objectAttributesInt&65536),signOrEncrypt:!!(objectAttributesInt&131072)},authPolicyLength=dataView.getUint16(pointer);pointer+=2;let authPolicy=pubArea.slice(pointer,pointer+=authPolicyLength),parameters2={},unique=Uint8Array.from([]);if(type==="TPM_ALG_RSA"){let symmetric=TPM_ALG[dataView.getUint16(pointer)];pointer+=2;let scheme=TPM_ALG[dataView.getUint16(pointer)];pointer+=2;let keyBits=dataView.getUint16(pointer);pointer+=2;let exponent=dataView.getUint32(pointer);pointer+=4,parameters2.rsa={symmetric,scheme,keyBits,exponent};let uniqueLength=dataView.getUint16(pointer);pointer+=2,unique=pubArea.slice(pointer,pointer+=uniqueLength)}else if(type==="TPM_ALG_ECC"){let symmetric=TPM_ALG[dataView.getUint16(pointer)];pointer+=2;let scheme=TPM_ALG[dataView.getUint16(pointer)];pointer+=2;let curveID=TPM_ECC_CURVE[dataView.getUint16(pointer)];pointer+=2;let kdf=TPM_ALG[dataView.getUint16(pointer)];pointer+=2,parameters2.ecc={symmetric,scheme,curveID,kdf};let uniqueXLength=dataView.getUint16(pointer);pointer+=2;let uniqueX=pubArea.slice(pointer,pointer+=uniqueXLength),uniqueYLength=dataView.getUint16(pointer);pointer+=2;let uniqueY=pubArea.slice(pointer,pointer+=uniqueYLength);unique=exports_isoUint8Array.concat([uniqueX,uniqueY])}else throw Error(`Unexpected type "${type}" (TPM)`);return{type,nameAlg,objectAttributes,authPolicy,parameters:parameters2,unique}}var init_parsePubArea=__esm(()=>{init_constants2();init_iso()});async function verifyAttestationTPM(options){let{aaguid,attStmt,authData,credentialPublicKey,clientDataHash,rootCertificates}=options,ver=attStmt.get("ver"),sig=attStmt.get("sig"),alg=attStmt.get("alg"),x5c=attStmt.get("x5c"),pubArea=attStmt.get("pubArea"),certInfo=attStmt.get("certInfo");if(ver!=="2.0")throw Error(`Unexpected ver "${ver}", expected "2.0" (TPM)`);if(!sig)throw Error("No attestation signature provided in attestation statement (TPM)");if(!alg)throw Error("Attestation statement did not contain alg (TPM)");if(!isCOSEAlg(alg))throw Error(`Attestation statement contained invalid alg ${alg} (TPM)`);if(!x5c)throw Error("No attestation certificate provided in attestation statement (TPM)");if(!pubArea)throw Error("Attestation statement did not contain pubArea (TPM)");if(!certInfo)throw Error("Attestation statement did not contain certInfo (TPM)");let parsedPubArea=parsePubArea(pubArea),{unique,type:pubType,parameters:parameters2}=parsedPubArea,cosePublicKey=decodeCredentialPublicKey(credentialPublicKey);if(pubType==="TPM_ALG_RSA"){if(!isCOSEPublicKeyRSA(cosePublicKey))throw Error(`Credential public key with kty ${cosePublicKey.get(COSEKEYS.kty)} did not match ${pubType}`);let n=cosePublicKey.get(COSEKEYS.n),e=cosePublicKey.get(COSEKEYS.e);if(!n)throw Error("COSE public key missing n (TPM|RSA)");if(!e)throw Error("COSE public key missing e (TPM|RSA)");if(!exports_isoUint8Array.areEqual(unique,n))throw Error("PubArea unique is not same as credentialPublicKey (TPM|RSA)");if(!parameters2.rsa)throw Error("Parsed pubArea type is RSA, but missing parameters.rsa (TPM|RSA)");let eBuffer=e,pubAreaExponent=parameters2.rsa.exponent||65537,eSum=eBuffer[0]+(eBuffer[1]<<8)+(eBuffer[2]<<16);if(pubAreaExponent!==eSum)throw Error(`Unexpected public key exp ${eSum}, expected ${pubAreaExponent} (TPM|RSA)`)}else if(pubType==="TPM_ALG_ECC"){if(!isCOSEPublicKeyEC2(cosePublicKey))throw Error(`Credential public key with kty ${cosePublicKey.get(COSEKEYS.kty)} did not match ${pubType}`);let crv=cosePublicKey.get(COSEKEYS.crv),x=cosePublicKey.get(COSEKEYS.x),y=cosePublicKey.get(COSEKEYS.y);if(!crv)throw Error("COSE public key missing crv (TPM|ECC)");if(!x)throw Error("COSE public key missing x (TPM|ECC)");if(!y)throw Error("COSE public key missing y (TPM|ECC)");if(!exports_isoUint8Array.areEqual(unique,exports_isoUint8Array.concat([x,y])))throw Error("PubArea unique is not same as public key x and y (TPM|ECC)");if(!parameters2.ecc)throw Error("Parsed pubArea type is ECC, but missing parameters.ecc (TPM|ECC)");let pubAreaCurveID=parameters2.ecc.curveID,pubAreaCurveIDMapToCOSECRV=TPM_ECC_CURVE_COSE_CRV_MAP[pubAreaCurveID];if(pubAreaCurveIDMapToCOSECRV!==crv)throw Error(`Public area key curve ID "${pubAreaCurveID}" mapped to "${pubAreaCurveIDMapToCOSECRV}" which did not match public key crv of "${crv}" (TPM|ECC)`)}else throw Error(`Unsupported pubArea.type "${pubType}"`);let parsedCertInfo=parseCertInfo(certInfo),{magic,type:certType,attested,extraData}=parsedCertInfo;if(magic!==4283712327)throw Error(`Unexpected magic value "${magic}", expected "0xff544347" (TPM)`);if(certType!=="TPM_ST_ATTEST_CERTIFY")throw Error(`Unexpected type "${certType}", expected "TPM_ST_ATTEST_CERTIFY" (TPM)`);let pubAreaHash=await toHash(pubArea,attestedNameAlgToCOSEAlg(attested.nameAlg)),attestedName=exports_isoUint8Array.concat([attested.nameAlgBuffer,pubAreaHash]);if(!exports_isoUint8Array.areEqual(attested.name,attestedName))throw Error("Attested name comparison failed (TPM)");let attToBeSigned=exports_isoUint8Array.concat([authData,clientDataHash]),attToBeSignedHash=await toHash(attToBeSigned,alg);if(!exports_isoUint8Array.areEqual(extraData,attToBeSignedHash))throw Error("CertInfo extra data did not equal hashed attestation (TPM)");if(x5c.length<1)throw Error("No certificates present in x5c array (TPM)");let leafCertInfo=getCertificateInfo(x5c[0]),{basicConstraintsCA,version,subject,notAfter,notBefore}=leafCertInfo;if(basicConstraintsCA)throw Error("Certificate basic constraints CA was not `false` (TPM)");if(version!==2)throw Error("Certificate version was not `3` (ASN.1 value of 2) (TPM)");if(subject.combined.length>0)throw Error("Certificate subject was not empty (TPM)");let now=new Date;if(notBefore>now)throw Error(`Certificate not good before "${notBefore.toString()}" (TPM)`);if(now=new Date,notAfter<now)throw Error(`Certificate not good after "${notAfter.toString()}" (TPM)`);let parsedCert=AsnParser.parse(x5c[0],Certificate);if(!parsedCert.tbsCertificate.extensions)throw Error("Certificate was missing extensions (TPM)");let subjectAltNamePresent,extKeyUsage;if(parsedCert.tbsCertificate.extensions.forEach((ext)=>{if(ext.extnID===id_ce_subjectAltName)subjectAltNamePresent=AsnParser.parse(ext.extnValue,SubjectAlternativeName);else if(ext.extnID===id_ce_extKeyUsage)extKeyUsage=AsnParser.parse(ext.extnValue,ExtendedKeyUsage)}),!subjectAltNamePresent)throw Error("Certificate did not contain subjectAltName extension (TPM)");if(!subjectAltNamePresent[0].directoryName?.[0].length)throw Error("Certificate subjectAltName extension directoryName was empty (TPM)");let{tcgAtTpmManufacturer,tcgAtTpmModel,tcgAtTpmVersion}=getTcgAtTpmValues(subjectAltNamePresent[0].directoryName);if(!tcgAtTpmManufacturer||!tcgAtTpmModel||!tcgAtTpmVersion)throw Error("Certificate contained incomplete subjectAltName data (TPM)");if(!extKeyUsage)throw Error("Certificate did not contain ExtendedKeyUsage extension (TPM)");if(!TPM_MANUFACTURERS[tcgAtTpmManufacturer])throw Error(`Could not match TPM manufacturer "${tcgAtTpmManufacturer}" (TPM)`);if(extKeyUsage[0]!=="2.23.133.8.3")throw Error(`Unexpected extKeyUsage "${extKeyUsage[0]}", expected "2.23.133.8.3" (TPM)`);try{await validateExtFIDOGenCEAAGUID(parsedCert.tbsCertificate.extensions,aaguid)}catch(err){throw Error(`${err.message} (TPM)`)}let statement=await MetadataService.getStatement(aaguid);if(statement)try{await verifyAttestationWithMetadata({statement,credentialPublicKey,x5c,attestationStatementAlg:alg})}catch(err){throw Error(`${err.message} (TPM)`)}else try{await validateCertificatePath(x5c.map(convertCertBufferToPEM),rootCertificates)}catch(err){throw Error(`${err.message} (TPM)`)}return verifySignature2({signature:sig,data:certInfo,x509Certificate:x5c[0],hashAlgorithm:alg})}function getTcgAtTpmValues(root){let tcgAtTpmManufacturer,tcgAtTpmModel,tcgAtTpmVersion;return root.forEach((relName)=>{relName.forEach((attr)=>{if(attr.type==="2.23.133.2.1")tcgAtTpmManufacturer=attr.value.toString();else if(attr.type==="2.23.133.2.2")tcgAtTpmModel=attr.value.toString();else if(attr.type==="2.23.133.2.3")tcgAtTpmVersion=attr.value.toString()})}),{tcgAtTpmManufacturer,tcgAtTpmModel,tcgAtTpmVersion}}function attestedNameAlgToCOSEAlg(alg){if(alg==="TPM_ALG_SHA256")return COSEALG.ES256;else if(alg==="TPM_ALG_SHA384")return COSEALG.ES384;else if(alg==="TPM_ALG_SHA512")return COSEALG.ES512;throw Error(`Unexpected TPM attested name alg ${alg}`)}var init_verifyAttestationTPM=__esm(()=>{init_es2015();init_es20152();init_decodeCredentialPublicKey();init_cose();init_toHash();init_convertCertBufferToPEM();init_validateCertificatePath();init_getCertificateInfo();init_verifySignature();init_iso();init_validateExtFIDOGenCEAAGUID();init_metadataService();init_verifyAttestationWithMetadata();init_constants2();init_parseCertInfo();init_parsePubArea()});class RootOfTrust{verifiedBootKey=new OctetString2;deviceLocked=!1;verifiedBootState=VerifiedBootState.verified;verifiedBootHash;constructor(params={}){Object.assign(this,params)}}class AuthorizationList{purpose;algorithm;keySize;digest;padding;ecCurve;rsaPublicExponent;mgfDigest;rollbackResistance;earlyBootOnly;activeDateTime;originationExpireDateTime;usageExpireDateTime;usageCountLimit;noAuthRequired;userAuthType;authTimeout;allowWhileOnBody;trustedUserPresenceRequired;trustedConfirmationRequired;unlockedDeviceRequired;allApplications;applicationId;creationDateTime;origin;rollbackResistant;rootOfTrust;osVersion;osPatchLevel;attestationApplicationId;attestationIdBrand;attestationIdDevice;attestationIdProduct;attestationIdSerial;attestationIdImei;attestationIdMeid;attestationIdManufacturer;attestationIdModel;vendorPatchLevel;bootPatchLevel;deviceUniqueAttestation;attestationIdSecondImei;moduleHash;constructor(params={}){Object.assign(this,params)}}class KeyDescription{attestationVersion=Version3.KM4;attestationSecurityLevel=SecurityLevel.software;keymasterVersion=0;keymasterSecurityLevel=SecurityLevel.software;attestationChallenge=new OctetString2;uniqueId=new OctetString2;softwareEnforced=new AuthorizationList;teeEnforced=new AuthorizationList;constructor(params={}){Object.assign(this,params)}}class KeyMintKeyDescription{attestationVersion=Version3.keyMint4;attestationSecurityLevel=SecurityLevel.software;keyMintVersion=0;keyMintSecurityLevel=SecurityLevel.software;attestationChallenge=new OctetString2;uniqueId=new OctetString2;softwareEnforced=new AuthorizationList;hardwareEnforced=new AuthorizationList;constructor(params={}){Object.assign(this,params)}toLegacyKeyDescription(){return new KeyDescription({attestationVersion:this.attestationVersion,attestationSecurityLevel:this.attestationSecurityLevel,keymasterVersion:this.keyMintVersion,keymasterSecurityLevel:this.keyMintSecurityLevel,attestationChallenge:this.attestationChallenge,uniqueId:this.uniqueId,softwareEnforced:this.softwareEnforced,teeEnforced:this.hardwareEnforced})}static fromLegacyKeyDescription(keyDesc){return new KeyMintKeyDescription({attestationVersion:keyDesc.attestationVersion,attestationSecurityLevel:keyDesc.attestationSecurityLevel,keyMintVersion:keyDesc.keymasterVersion,keyMintSecurityLevel:keyDesc.keymasterSecurityLevel,attestationChallenge:keyDesc.attestationChallenge,uniqueId:keyDesc.uniqueId,softwareEnforced:keyDesc.softwareEnforced,hardwareEnforced:keyDesc.teeEnforced})}}var IntegerSet_1,id_ce_keyDescription="1.3.6.1.4.1.11129.2.1.17",VerifiedBootState,IntegerSet,SecurityLevel,Version3;var init_key_description=__esm(()=>{init_modules();init_es2015();(function(VerifiedBootState2){VerifiedBootState2[VerifiedBootState2.verified=0]="verified",VerifiedBootState2[VerifiedBootState2.selfSigned=1]="selfSigned",VerifiedBootState2[VerifiedBootState2.unverified=2]="unverified",VerifiedBootState2[VerifiedBootState2.failed=3]="failed"})(VerifiedBootState||(VerifiedBootState={}));__decorate([AsnProp({type:OctetString2})],RootOfTrust.prototype,"verifiedBootKey",void 0);__decorate([AsnProp({type:AsnPropTypes.Boolean})],RootOfTrust.prototype,"deviceLocked",void 0);__decorate([AsnProp({type:AsnPropTypes.Enumerated})],RootOfTrust.prototype,"verifiedBootState",void 0);__decorate([AsnProp({type:OctetString2,optional:!0})],RootOfTrust.prototype,"verifiedBootHash",void 0);IntegerSet=IntegerSet_1=class extends AsnArray{constructor(items){super(items);Object.setPrototypeOf(this,IntegerSet_1.prototype)}};IntegerSet=IntegerSet_1=__decorate([AsnType({type:AsnTypeTypes.Set,itemType:AsnPropTypes.Integer})],IntegerSet);__decorate([AsnProp({context:1,type:IntegerSet,optional:!0})],AuthorizationList.prototype,"purpose",void 0);__decorate([AsnProp({context:2,type:AsnPropTypes.Integer,optional:!0})],AuthorizationList.prototype,"algorithm",void 0);__decorate([AsnProp({context:3,type:AsnPropTypes.Integer,optional:!0})],AuthorizationList.prototype,"keySize",void 0);__decorate([AsnProp({context:5,type:IntegerSet,optional:!0})],AuthorizationList.prototype,"digest",void 0);__decorate([AsnProp({context:6,type:IntegerSet,optional:!0})],AuthorizationList.prototype,"padding",void 0);__decorate([AsnProp({context:10,type:AsnPropTypes.Integer,optional:!0})],AuthorizationList.prototype,"ecCurve",void 0);__decorate([AsnProp({context:200,type:AsnPropTypes.Integer,optional:!0})],AuthorizationList.prototype,"rsaPublicExponent",void 0);__decorate([AsnProp({context:203,type:IntegerSet,optional:!0})],AuthorizationList.prototype,"mgfDigest",void 0);__decorate([AsnProp({context:303,type:AsnPropTypes.Null,optional:!0})],AuthorizationList.prototype,"rollbackResistance",void 0);__decorate([AsnProp({context:305,type:AsnPropTypes.Null,optional:!0})],AuthorizationList.prototype,"earlyBootOnly",void 0);__decorate([AsnProp({context:400,type:AsnPropTypes.Integer,optional:!0})],AuthorizationList.prototype,"activeDateTime",void 0);__decorate([AsnProp({context:401,type:AsnPropTypes.Integer,optional:!0})],AuthorizationList.prototype,"originationExpireDateTime",void 0);__decorate([AsnProp({context:402,type:AsnPropTypes.Integer,optional:!0})],AuthorizationList.prototype,"usageExpireDateTime",void 0);__decorate([AsnProp({context:405,type:AsnPropTypes.Integer,optional:!0})],AuthorizationList.prototype,"usageCountLimit",void 0);__decorate([AsnProp({context:503,type:AsnPropTypes.Null,optional:!0})],AuthorizationList.prototype,"noAuthRequired",void 0);__decorate([AsnProp({context:504,type:AsnPropTypes.Integer,optional:!0})],AuthorizationList.prototype,"userAuthType",void 0);__decorate([AsnProp({context:505,type:AsnPropTypes.Integer,optional:!0})],AuthorizationList.prototype,"authTimeout",void 0);__decorate([AsnProp({context:506,type:AsnPropTypes.Null,optional:!0})],AuthorizationList.prototype,"allowWhileOnBody",void 0);__decorate([AsnProp({context:507,type:AsnPropTypes.Null,optional:!0})],AuthorizationList.prototype,"trustedUserPresenceRequired",void 0);__decorate([AsnProp({context:508,type:AsnPropTypes.Null,optional:!0})],AuthorizationList.prototype,"trustedConfirmationRequired",void 0);__decorate([AsnProp({context:509,type:AsnPropTypes.Null,optional:!0})],AuthorizationList.prototype,"unlockedDeviceRequired",void 0);__decorate([AsnProp({context:600,type:AsnPropTypes.Null,optional:!0})],AuthorizationList.prototype,"allApplications",void 0);__decorate([AsnProp({context:601,type:OctetString2,optional:!0})],AuthorizationList.prototype,"applicationId",void 0);__decorate([AsnProp({context:701,type:AsnPropTypes.Integer,optional:!0})],AuthorizationList.prototype,"creationDateTime",void 0);__decorate([AsnProp({context:702,type:AsnPropTypes.Integer,optional:!0})],AuthorizationList.prototype,"origin",void 0);__decorate([AsnProp({context:703,type:AsnPropTypes.Null,optional:!0})],AuthorizationList.prototype,"rollbackResistant",void 0);__decorate([AsnProp({context:704,type:RootOfTrust,optional:!0})],AuthorizationList.prototype,"rootOfTrust",void 0);__decorate([AsnProp({context:705,type:AsnPropTypes.Integer,optional:!0})],AuthorizationList.prototype,"osVersion",void 0);__decorate([AsnProp({context:706,type:AsnPropTypes.Integer,optional:!0})],AuthorizationList.prototype,"osPatchLevel",void 0);__decorate([AsnProp({context:709,type:OctetString2,optional:!0})],AuthorizationList.prototype,"attestationApplicationId",void 0);__decorate([AsnProp({context:710,type:OctetString2,optional:!0})],AuthorizationList.prototype,"attestationIdBrand",void 0);__decorate([AsnProp({context:711,type:OctetString2,optional:!0})],AuthorizationList.prototype,"attestationIdDevice",void 0);__decorate([AsnProp({context:712,type:OctetString2,optional:!0})],AuthorizationList.prototype,"attestationIdProduct",void 0);__decorate([AsnProp({context:713,type:OctetString2,optional:!0})],AuthorizationList.prototype,"attestationIdSerial",void 0);__decorate([AsnProp({context:714,type:OctetString2,optional:!0})],AuthorizationList.prototype,"attestationIdImei",void 0);__decorate([AsnProp({context:715,type:OctetString2,optional:!0})],AuthorizationList.prototype,"attestationIdMeid",void 0);__decorate([AsnProp({context:716,type:OctetString2,optional:!0})],AuthorizationList.prototype,"attestationIdManufacturer",void 0);__decorate([AsnProp({context:717,type:OctetString2,optional:!0})],AuthorizationList.prototype,"attestationIdModel",void 0);__decorate([AsnProp({context:718,type:AsnPropTypes.Integer,optional:!0})],AuthorizationList.prototype,"vendorPatchLevel",void 0);__decorate([AsnProp({context:719,type:AsnPropTypes.Integer,optional:!0})],AuthorizationList.prototype,"bootPatchLevel",void 0);__decorate([AsnProp({context:720,type:AsnPropTypes.Null,optional:!0})],AuthorizationList.prototype,"deviceUniqueAttestation",void 0);__decorate([AsnProp({context:723,type:OctetString2,optional:!0})],AuthorizationList.prototype,"attestationIdSecondImei",void 0);__decorate([AsnProp({context:724,type:OctetString2,optional:!0})],AuthorizationList.prototype,"moduleHash",void 0);(function(SecurityLevel2){SecurityLevel2[SecurityLevel2.software=0]="software",SecurityLevel2[SecurityLevel2.trustedEnvironment=1]="trustedEnvironment",SecurityLevel2[SecurityLevel2.strongBox=2]="strongBox"})(SecurityLevel||(SecurityLevel={}));(function(Version4){Version4[Version4.KM2=1]="KM2",Version4[Version4.KM3=2]="KM3",Version4[Version4.KM4=3]="KM4",Version4[Version4.KM4_1=4]="KM4_1",Version4[Version4.keyMint1=100]="keyMint1",Version4[Version4.keyMint2=200]="keyMint2",Version4[Version4.keyMint3=300]="keyMint3",Version4[Version4.keyMint4=400]="keyMint4"})(Version3||(Version3={}));__decorate([AsnProp({type:AsnPropTypes.Integer})],KeyDescription.prototype,"attestationVersion",void 0);__decorate([AsnProp({type:AsnPropTypes.Enumerated})],KeyDescription.prototype,"attestationSecurityLevel",void 0);__decorate([AsnProp({type:AsnPropTypes.Integer})],KeyDescription.prototype,"keymasterVersion",void 0);__decorate([AsnProp({type:AsnPropTypes.Enumerated})],KeyDescription.prototype,"keymasterSecurityLevel",void 0);__decorate([AsnProp({type:OctetString2})],KeyDescription.prototype,"attestationChallenge",void 0);__decorate([AsnProp({type:OctetString2})],KeyDescription.prototype,"uniqueId",void 0);__decorate([AsnProp({type:AuthorizationList})],KeyDescription.prototype,"softwareEnforced",void 0);__decorate([AsnProp({type:AuthorizationList})],KeyDescription.prototype,"teeEnforced",void 0);__decorate([AsnProp({type:AsnPropTypes.Integer})],KeyMintKeyDescription.prototype,"attestationVersion",void 0);__decorate([AsnProp({type:AsnPropTypes.Enumerated})],KeyMintKeyDescription.prototype,"attestationSecurityLevel",void 0);__decorate([AsnProp({type:AsnPropTypes.Integer})],KeyMintKeyDescription.prototype,"keyMintVersion",void 0);__decorate([AsnProp({type:AsnPropTypes.Enumerated})],KeyMintKeyDescription.prototype,"keyMintSecurityLevel",void 0);__decorate([AsnProp({type:OctetString2})],KeyMintKeyDescription.prototype,"attestationChallenge",void 0);__decorate([AsnProp({type:OctetString2})],KeyMintKeyDescription.prototype,"uniqueId",void 0);__decorate([AsnProp({type:AuthorizationList})],KeyMintKeyDescription.prototype,"softwareEnforced",void 0);__decorate([AsnProp({type:AuthorizationList})],KeyMintKeyDescription.prototype,"hardwareEnforced",void 0)});class NonStandardKeyDescription{attestationVersion=Version3.KM4;attestationSecurityLevel=SecurityLevel.software;keymasterVersion=0;keymasterSecurityLevel=SecurityLevel.software;attestationChallenge=new OctetString2;uniqueId=new OctetString2;softwareEnforced=new NonStandardAuthorizationList;teeEnforced=new NonStandardAuthorizationList;get keyMintVersion(){return this.keymasterVersion}set keyMintVersion(value){this.keymasterVersion=value}get keyMintSecurityLevel(){return this.keymasterSecurityLevel}set keyMintSecurityLevel(value){this.keymasterSecurityLevel=value}get hardwareEnforced(){return this.teeEnforced}set hardwareEnforced(value){this.teeEnforced=value}constructor(params={}){Object.assign(this,params)}}var NonStandardAuthorizationList_1,NonStandardAuthorization,NonStandardAuthorizationList,NonStandardKeyMintKeyDescription;var init_nonstandard=__esm(()=>{init_modules();init_es2015();init_key_description();NonStandardAuthorization=class extends AuthorizationList{};NonStandardAuthorization=__decorate([AsnType({type:AsnTypeTypes.Choice})],NonStandardAuthorization);NonStandardAuthorizationList=NonStandardAuthorizationList_1=class extends AsnArray{constructor(items){super(items);Object.setPrototypeOf(this,NonStandardAuthorizationList_1.prototype)}findProperty(key2){let prop=this.find((o)=>o[key2]!==void 0);if(prop)return prop[key2];return}};NonStandardAuthorizationList=NonStandardAuthorizationList_1=__decorate([AsnType({type:AsnTypeTypes.Sequence,itemType:NonStandardAuthorization})],NonStandardAuthorizationList);__decorate([AsnProp({type:AsnPropTypes.Integer})],NonStandardKeyDescription.prototype,"attestationVersion",void 0);__decorate([AsnProp({type:AsnPropTypes.Enumerated})],NonStandardKeyDescription.prototype,"attestationSecurityLevel",void 0);__decorate([AsnProp({type:AsnPropTypes.Integer})],NonStandardKeyDescription.prototype,"keymasterVersion",void 0);__decorate([AsnProp({type:AsnPropTypes.Enumerated})],NonStandardKeyDescription.prototype,"keymasterSecurityLevel",void 0);__decorate([AsnProp({type:OctetString2})],NonStandardKeyDescription.prototype,"attestationChallenge",void 0);__decorate([AsnProp({type:OctetString2})],NonStandardKeyDescription.prototype,"uniqueId",void 0);__decorate([AsnProp({type:NonStandardAuthorizationList})],NonStandardKeyDescription.prototype,"softwareEnforced",void 0);__decorate([AsnProp({type:NonStandardAuthorizationList})],NonStandardKeyDescription.prototype,"teeEnforced",void 0);NonStandardKeyMintKeyDescription=class extends NonStandardKeyDescription{constructor(params={}){if("keymasterVersion"in params&&!("keyMintVersion"in params))params.keyMintVersion=params.keymasterVersion;if("keymasterSecurityLevel"in params&&!("keyMintSecurityLevel"in params))params.keyMintSecurityLevel=params.keymasterSecurityLevel;if("teeEnforced"in params&&!("hardwareEnforced"in params))params.hardwareEnforced=params.teeEnforced;super(params)}};NonStandardKeyMintKeyDescription=__decorate([AsnType({type:AsnTypeTypes.Sequence})],NonStandardKeyMintKeyDescription)});class AttestationPackageInfo{packageName;version;constructor(params={}){Object.assign(this,params)}}class AttestationApplicationId{packageInfos;signatureDigests;constructor(params={}){Object.assign(this,params)}}var init_attestation=__esm(()=>{init_modules();init_es2015();__decorate([AsnProp({type:AsnPropTypes.OctetString})],AttestationPackageInfo.prototype,"packageName",void 0);__decorate([AsnProp({type:AsnPropTypes.Integer})],AttestationPackageInfo.prototype,"version",void 0);__decorate([AsnProp({type:AttestationPackageInfo,repeated:"set"})],AttestationApplicationId.prototype,"packageInfos",void 0);__decorate([AsnProp({type:AsnPropTypes.OctetString,repeated:"set"})],AttestationApplicationId.prototype,"signatureDigests",void 0)});var init_es201511=__esm(()=>{init_key_description();init_nonstandard();init_attestation()});async function verifyAttestationAndroidKey(options){let{authData,clientDataHash,attStmt,credentialPublicKey,aaguid,rootCertificates}=options,x5c=attStmt.get("x5c"),sig=attStmt.get("sig"),alg=attStmt.get("alg");if(!x5c)throw Error("No attestation certificate provided in attestation statement (Android Key)");if(!sig)throw Error("No attestation signature provided in attestation statement (Android Key)");if(!alg)throw Error("Attestation statement did not contain alg (Android Key)");if(!isCOSEAlg(alg))throw Error(`Attestation statement contained invalid alg ${alg} (Android Key)`);let parsedCert=AsnParser.parse(x5c[0],Certificate),parsedCertPubKey=new Uint8Array(parsedCert.tbsCertificate.subjectPublicKeyInfo.subjectPublicKey),credPubKeyPKCS=convertCOSEtoPKCS(credentialPublicKey);if(!exports_isoUint8Array.areEqual(credPubKeyPKCS,parsedCertPubKey))throw Error("Credential public key does not equal leaf cert public key (Android Key)");let extKeyStore=parsedCert.tbsCertificate.extensions?.find((ext)=>ext.extnID===id_ce_keyDescription);if(!extKeyStore)throw Error("Certificate did not contain extKeyStore (Android Key)");let parsedExtKeyStore=AsnParser.parse(extKeyStore.extnValue,KeyDescription),{attestationChallenge,teeEnforced,softwareEnforced}=parsedExtKeyStore;if(!exports_isoUint8Array.areEqual(new Uint8Array(attestationChallenge.buffer),clientDataHash))throw Error("Attestation challenge was not equal to client data hash (Android Key)");if(teeEnforced.allApplications!==void 0)throw Error('teeEnforced contained "allApplications [600]" tag (Android Key)');if(softwareEnforced.allApplications!==void 0)throw Error('teeEnforced contained "allApplications [600]" tag (Android Key)');let statement=await MetadataService.getStatement(aaguid);if(statement)try{await verifyAttestationWithMetadata({statement,credentialPublicKey,x5c,attestationStatementAlg:alg})}catch(err){let _err=err;throw Error(`${_err.message} (Android Key)`,{cause:_err})}else{let x5cNoRootPEM=x5c.slice(0,-1).map(convertCertBufferToPEM),x5cRootPEM=x5c.slice(-1).map(convertCertBufferToPEM);try{await validateCertificatePath(x5cNoRootPEM,x5cRootPEM)}catch(err){let _err=err;throw Error(`${_err.message} (Android Key)`,{cause:_err})}if(rootCertificates.length>0&&rootCertificates.indexOf(x5cRootPEM[0])<0)throw Error("x5c root certificate was not a known root certificate (Android Key)")}let signatureBase=exports_isoUint8Array.concat([authData,clientDataHash]);return verifySignature2({signature:sig,data:signatureBase,x509Certificate:x5c[0],hashAlgorithm:alg})}var init_verifyAttestationAndroidKey=__esm(()=>{init_es2015();init_es20152();init_es201511();init_convertCertBufferToPEM();init_validateCertificatePath();init_verifySignature();init_convertCOSEtoPKCS();init_cose();init_iso();init_metadataService();init_verifyAttestationWithMetadata()});async function verifyAttestationApple(options){let{attStmt,authData,clientDataHash,credentialPublicKey,rootCertificates}=options,x5c=attStmt.get("x5c");if(!x5c)throw Error("No attestation certificate provided in attestation statement (Apple)");try{await validateCertificatePath(x5c.map(convertCertBufferToPEM),rootCertificates)}catch(err){throw Error(`${err.message} (Apple)`)}let parsedCredCert=AsnParser.parse(x5c[0],Certificate),{extensions:extensions2,subjectPublicKeyInfo}=parsedCredCert.tbsCertificate;if(!extensions2)throw Error("credCert missing extensions (Apple)");let extCertNonce=extensions2.find((ext)=>ext.extnID==="1.2.840.113635.100.8.2");if(!extCertNonce)throw Error('credCert missing "1.2.840.113635.100.8.2" extension (Apple)');let nonceToHash=exports_isoUint8Array.concat([authData,clientDataHash]),nonce=await toHash(nonceToHash),extNonce=new Uint8Array(extCertNonce.extnValue.buffer).slice(6);if(!exports_isoUint8Array.areEqual(nonce,extNonce))throw Error("credCert nonce was not expected value (Apple)");let credPubKeyPKCS=convertCOSEtoPKCS(credentialPublicKey),credCertSubjectPublicKey=new Uint8Array(subjectPublicKeyInfo.subjectPublicKey);if(!exports_isoUint8Array.areEqual(credPubKeyPKCS,credCertSubjectPublicKey))throw Error("Credential public key does not equal credCert public key (Apple)");return!0}var init_verifyAttestationApple=__esm(()=>{init_es2015();init_es20152();init_validateCertificatePath();init_convertCertBufferToPEM();init_toHash();init_convertCOSEtoPKCS();init_iso()});async function verifyRegistrationResponse(options){let{response,expectedChallenge,expectedOrigin,expectedRPID,expectedType,requireUserPresence=!0,requireUserVerification=!0,supportedAlgorithmIDs=supportedCOSEAlgorithmIdentifiers,attestationSafetyNetEnforceCTSCheck=!0}=options,{id,rawId,type:credentialType,response:attestationResponse}=response;if(!id)throw Error("Missing credential ID");if(id!==rawId)throw Error("Credential ID was not base64url-encoded");if(credentialType!=="public-key")throw Error(`Unexpected credential type ${credentialType}, expected "public-key"`);let clientDataJSON=decodeClientDataJSON(attestationResponse.clientDataJSON),{type,origin,challenge,tokenBinding}=clientDataJSON;if(Array.isArray(expectedType)){if(!expectedType.includes(type)){let joinedExpectedType=expectedType.join(", ");throw Error(`Unexpected registration response type "${type}", expected one of: ${joinedExpectedType}`)}}else if(expectedType){if(type!==expectedType)throw Error(`Unexpected registration response type "${type}", expected "${expectedType}"`)}else if(type!=="webauthn.create")throw Error(`Unexpected registration response type: ${type}`);if(typeof expectedChallenge==="function"){if(!await expectedChallenge(challenge))throw Error(`Custom challenge verifier returned false for registration response challenge "${challenge}"`)}else if(challenge!==expectedChallenge)throw Error(`Unexpected registration response challenge "${challenge}", expected "${expectedChallenge}"`);if(Array.isArray(expectedOrigin)){if(!expectedOrigin.includes(origin))throw Error(`Unexpected registration response origin "${origin}", expected one of: ${expectedOrigin.join(", ")}`)}else if(origin!==expectedOrigin)throw Error(`Unexpected registration response origin "${origin}", expected "${expectedOrigin}"`);if(tokenBinding){if(typeof tokenBinding!=="object")throw Error(`Unexpected value for TokenBinding "${tokenBinding}"`);if(["present","supported","not-supported"].indexOf(tokenBinding.status)<0)throw Error(`Unexpected tokenBinding.status value of "${tokenBinding.status}"`)}let attestationObject=exports_isoBase64URL.toBuffer(attestationResponse.attestationObject),decodedAttestationObject=decodeAttestationObject(attestationObject),fmt=decodedAttestationObject.get("fmt"),authData=decodedAttestationObject.get("authData"),attStmt=decodedAttestationObject.get("attStmt"),parsedAuthData=parseAuthenticatorData(authData),{aaguid,rpIdHash,flags,credentialID,counter,credentialPublicKey,extensionsData}=parsedAuthData,matchedRPID;if(expectedRPID){let expectedRPIDs=[];if(typeof expectedRPID==="string")expectedRPIDs=[expectedRPID];else expectedRPIDs=expectedRPID;matchedRPID=await matchExpectedRPID(rpIdHash,expectedRPIDs)}if(requireUserPresence&&!flags.up)throw Error("User presence was required, but user was not present");if(requireUserVerification&&!flags.uv)throw Error("User verification was required, but user could not be verified");if(!credentialID)throw Error("No credential ID was provided by authenticator");if(!credentialPublicKey)throw Error("No public key was provided by authenticator");if(!aaguid)throw Error("No AAGUID was present during registration");let alg=decodeCredentialPublicKey(credentialPublicKey).get(COSEKEYS.alg);if(typeof alg!=="number")throw Error("Credential public key was missing numeric alg");if(!supportedAlgorithmIDs.includes(alg)){let supported=supportedAlgorithmIDs.join(", ");throw Error(`Unexpected public key alg "${alg}", expected one of "${supported}"`)}let clientDataHash=await toHash(exports_isoBase64URL.toBuffer(attestationResponse.clientDataJSON)),rootCertificates=SettingsService.getRootCertificates({identifier:fmt}),verifierOpts={aaguid,attStmt,authData,clientDataHash,credentialID,credentialPublicKey,rootCertificates,rpIdHash,attestationSafetyNetEnforceCTSCheck},verified=!1;if(fmt==="fido-u2f")verified=await verifyAttestationFIDOU2F(verifierOpts);else if(fmt==="packed")verified=await verifyAttestationPacked(verifierOpts);else if(fmt==="android-safetynet")verified=await verifyAttestationAndroidSafetyNet(verifierOpts);else if(fmt==="android-key")verified=await verifyAttestationAndroidKey(verifierOpts);else if(fmt==="tpm")verified=await verifyAttestationTPM(verifierOpts);else if(fmt==="apple")verified=await verifyAttestationApple(verifierOpts);else if(fmt==="none"){if(attStmt.size>0)throw Error("None attestation had unexpected attestation statement");verified=!0}else throw Error(`Unsupported Attestation Format: ${fmt}`);if(!verified)return{verified:!1};let{credentialDeviceType,credentialBackedUp}=parseBackupFlags(flags);return{verified:!0,registrationInfo:{fmt,aaguid:convertAAGUIDToString(aaguid),credentialType,credential:{id:exports_isoBase64URL.fromBuffer(credentialID),publicKey:credentialPublicKey,counter,transports:response.response.transports},attestationObject,userVerified:flags.uv,credentialDeviceType,credentialBackedUp,origin:clientDataJSON.origin,rpID:matchedRPID,authenticatorExtensionResults:extensionsData}}}var init_verifyRegistrationResponse=__esm(()=>{init_decodeAttestationObject();init_decodeClientDataJSON();init_parseAuthenticatorData();init_toHash();init_decodeCredentialPublicKey();init_cose();init_convertAAGUIDToString();init_parseBackupFlags();init_matchExpectedRPID();init_iso();init_settingsService();init_generateRegistrationOptions();init_verifyAttestationFIDOU2F();init_verifyAttestationPacked();init_verifyAttestationAndroidSafetyNet();init_verifyAttestationTPM();init_verifyAttestationAndroidKey();init_verifyAttestationApple()});async function generateAuthenticationOptions(options){let{allowCredentials,challenge=await generateChallenge2(),timeout=60000,userVerification="preferred",extensions:extensions2,rpID}=options,_challenge=challenge;if(typeof _challenge==="string")_challenge=exports_isoUint8Array.fromUTF8String(_challenge);return{rpId:rpID,challenge:exports_isoBase64URL.fromBuffer(_challenge),allowCredentials:allowCredentials?.map((cred)=>{if(!exports_isoBase64URL.isBase64URL(cred.id))throw Error(`allowCredential id "${cred.id}" is not a valid base64url string`);return{...cred,id:exports_isoBase64URL.trimPadding(cred.id),type:"public-key"}}),timeout,userVerification,extensions:extensions2}}var init_generateAuthenticationOptions=__esm(()=>{init_iso();init_generateChallenge()});async function verifyAuthenticationResponse(options){let{response,expectedChallenge,expectedOrigin,expectedRPID,expectedType,credential,requireUserVerification=!0,advancedFIDOConfig}=options,{id,rawId,type:credentialType,response:assertionResponse}=response;if(!id)throw Error("Missing credential ID");if(id!==rawId)throw Error("Credential ID was not base64url-encoded");if(credentialType!=="public-key")throw Error(`Unexpected credential type ${credentialType}, expected "public-key"`);if(!response)throw Error("Credential missing response");if(typeof assertionResponse?.clientDataJSON!=="string")throw Error("Credential response clientDataJSON was not a string");let clientDataJSON=decodeClientDataJSON(assertionResponse.clientDataJSON),{type,origin,challenge,tokenBinding}=clientDataJSON;if(Array.isArray(expectedType)){if(!expectedType.includes(type)){let joinedExpectedType=expectedType.join(", ");throw Error(`Unexpected authentication response type "${type}", expected one of: ${joinedExpectedType}`)}}else if(expectedType){if(type!==expectedType)throw Error(`Unexpected authentication response type "${type}", expected "${expectedType}"`)}else if(type!=="webauthn.get")throw Error(`Unexpected authentication response type: ${type}`);if(typeof expectedChallenge==="function"){if(!await expectedChallenge(challenge))throw Error(`Custom challenge verifier returned false for registration response challenge "${challenge}"`)}else if(challenge!==expectedChallenge)throw Error(`Unexpected authentication response challenge "${challenge}", expected "${expectedChallenge}"`);if(Array.isArray(expectedOrigin)){if(!expectedOrigin.includes(origin)){let joinedExpectedOrigin=expectedOrigin.join(", ");throw Error(`Unexpected authentication response origin "${origin}", expected one of: ${joinedExpectedOrigin}`)}}else if(origin!==expectedOrigin)throw Error(`Unexpected authentication response origin "${origin}", expected "${expectedOrigin}"`);if(!exports_isoBase64URL.isBase64URL(assertionResponse.authenticatorData))throw Error("Credential response authenticatorData was not a base64url string");if(!exports_isoBase64URL.isBase64URL(assertionResponse.signature))throw Error("Credential response signature was not a base64url string");if(assertionResponse.userHandle&&typeof assertionResponse.userHandle!=="string")throw Error("Credential response userHandle was not a string");if(tokenBinding){if(typeof tokenBinding!=="object")throw Error("ClientDataJSON tokenBinding was not an object");if(["present","supported","notSupported"].indexOf(tokenBinding.status)<0)throw Error(`Unexpected tokenBinding status ${tokenBinding.status}`)}let authDataBuffer=exports_isoBase64URL.toBuffer(assertionResponse.authenticatorData),parsedAuthData=parseAuthenticatorData(authDataBuffer),{rpIdHash,flags,counter,extensionsData}=parsedAuthData,expectedRPIDs=[];if(typeof expectedRPID==="string")expectedRPIDs=[expectedRPID];else expectedRPIDs=expectedRPID;let matchedRPID=await matchExpectedRPID(rpIdHash,expectedRPIDs);if(advancedFIDOConfig!==void 0){let{userVerification:fidoUserVerification}=advancedFIDOConfig;if(fidoUserVerification==="required"){if(!flags.uv)throw Error("User verification required, but user could not be verified")}}else{if(!flags.up)throw Error("User not present during authentication");if(requireUserVerification&&!flags.uv)throw Error("User verification required, but user could not be verified")}let clientDataHash=await toHash(exports_isoBase64URL.toBuffer(assertionResponse.clientDataJSON)),signatureBase=exports_isoUint8Array.concat([authDataBuffer,clientDataHash]),signature=exports_isoBase64URL.toBuffer(assertionResponse.signature);if((counter>0||credential.counter>0)&&counter<=credential.counter)throw Error(`Response counter value ${counter} was lower than expected ${credential.counter}`);let{credentialDeviceType,credentialBackedUp}=parseBackupFlags(flags);return{verified:await verifySignature2({signature,data:signatureBase,credentialPublicKey:credential.publicKey}),authenticationInfo:{newCounter:counter,credentialID:credential.id,userVerified:flags.uv,credentialDeviceType,credentialBackedUp,authenticatorExtensionResults:extensionsData,origin:clientDataJSON.origin,rpID:matchedRPID}}}var init_verifyAuthenticationResponse=__esm(()=>{init_decodeClientDataJSON();init_toHash();init_verifySignature();init_parseAuthenticatorData();init_parseBackupFlags();init_matchExpectedRPID();init_iso()});var init_mdsTypes=()=>{};var init_types11=()=>{};var init_esm2=__esm(()=>{init_generateRegistrationOptions();init_verifyRegistrationResponse();init_generateAuthenticationOptions();init_verifyAuthenticationResponse();init_metadataService();init_settingsService();init_mdsTypes();init_types11()});function base64UrlEncode2(buffer){let binary="";for(let byte of buffer)binary+=String.fromCharCode(byte);return(typeof btoa<"u"?btoa(binary):Buffer.from(binary,"binary").toString("base64")).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"")}function base64UrlDecode2(value){let padded=value.replace(/-/g,"+").replace(/_/g,"/").padEnd(value.length+(4-value.length%4)%4,"="),binary=typeof atob<"u"?atob(padded):Buffer.from(padded,"base64").toString("binary"),buffer=new ArrayBuffer(binary.length),out=new Uint8Array(buffer);for(let i=0;i<binary.length;i+=1)out[i]=binary.charCodeAt(i);return out}function parseTransports(value){if(!value)return null;if(Array.isArray(value))return value;if(typeof value==="string")try{let parsed=JSON.parse(value);return Array.isArray(parsed)?parsed:null}catch{return null}return null}function parseDeviceType(value){if(value==="singleDevice"||value==="multiDevice")return value;return null}var exports_WebAuthn={};__export(exports_WebAuthn,{WebAuthnService:()=>WebAuthnService});class WebAuthnService{config;challengeTtlMs;constructor(config){this.config=config,this.challengeTtlMs=config.challengeTtlMs??DEFAULT_CHALLENGE_TTL_MS}async createRegistrationOptions(params){let existing=await this.config.storage.listCredentialsByUser(params.userId,params.schemaName),options=await generateRegistrationOptions({rpName:this.config.rp.rpName,rpID:this.config.rp.rpID,userID:new TextEncoder().encode(params.userId),userName:params.userName,userDisplayName:params.userDisplayName??params.userName,attestationType:"none",authenticatorSelection:{residentKey:"preferred",userVerification:this.config.userVerification??"preferred"},excludeCredentials:existing.filter((cred)=>!cred.revokedAt).map((cred)=>({id:cred.credentialId,transports:cred.transports??void 0}))});return await this.config.storage.storeChallenge({challenge:options.challenge,challengeType:"registration",userId:params.userId,expiresAt:new Date(Date.now()+this.challengeTtlMs)},params.schemaName),options}async verifyRegistration(params){let stored=await this.config.storage.consumeChallenge(params.expectedChallenge,"registration",params.schemaName);if(!stored||stored.userId!==params.userId)return null;if(stored.expiresAt.getTime()<Date.now())return null;let verification=await verifyRegistrationResponse({response:params.response,expectedChallenge:params.expectedChallenge,expectedOrigin:this.config.rp.expectedOrigins,expectedRPID:this.config.rp.rpID,requireUserVerification:this.config.userVerification==="required"});if(!verification.verified||!verification.registrationInfo)return null;let info=verification.registrationInfo,publicKey=base64UrlEncode2(info.credential.publicKey),attachment=params.response.authenticatorAttachment==="platform"||params.response.authenticatorAttachment==="cross-platform"?params.response.authenticatorAttachment:null;return this.config.storage.insertCredential({userId:params.userId,credentialId:info.credential.id,publicKey,counter:info.credential.counter,transports:info.credential.transports??null,deviceType:info.credentialDeviceType,backedUp:info.credentialBackedUp,aaguid:info.aaguid??null,authenticatorAttachment:attachment,nickname:params.nickname??null,lastUsedAt:null,revokedAt:null},params.schemaName)}async createAuthenticationOptions(params){let credentials=params.userId?await this.config.storage.listCredentialsByUser(params.userId,params.schemaName):[],options=await generateAuthenticationOptions({rpID:this.config.rp.rpID,userVerification:this.config.userVerification??"preferred",allowCredentials:credentials.filter((cred)=>!cred.revokedAt).map((cred)=>({id:cred.credentialId,transports:cred.transports??void 0}))});return await this.config.storage.storeChallenge({challenge:options.challenge,challengeType:"authentication",userId:params.userId??null,expiresAt:new Date(Date.now()+this.challengeTtlMs)},params.schemaName),options}async verifyAuthentication(params){let stored=await this.config.storage.consumeChallenge(params.expectedChallenge,"authentication",params.schemaName);if(!stored)return{verified:!1,userId:null,credentialId:null};if(stored.expiresAt.getTime()<Date.now())return{verified:!1,userId:null,credentialId:null};let credential=await this.config.storage.findCredentialById(params.response.id,params.schemaName);if(!credential||credential.revokedAt)return{verified:!1,userId:null,credentialId:null};let verification=await verifyAuthenticationResponse({response:params.response,expectedChallenge:params.expectedChallenge,expectedOrigin:this.config.rp.expectedOrigins,expectedRPID:this.config.rp.rpID,credential:{id:credential.credentialId,publicKey:base64UrlDecode2(credential.publicKey),counter:credential.counter,transports:credential.transports??void 0},requireUserVerification:this.config.userVerification==="required"});if(!verification.verified)return{verified:!1,userId:null,credentialId:null};return await this.config.storage.updateCredentialCounter(credential.credentialId,verification.authenticationInfo.newCounter,params.schemaName),{verified:!0,userId:credential.userId,credentialId:credential.credentialId}}listUserCredentials(userId,schemaName){return this.config.storage.listCredentialsByUser(userId,schemaName)}revokeCredential(credentialId,userId,schemaName){return this.config.storage.revokeCredential(credentialId,userId,schemaName)}renameCredential(credentialId,userId,nickname,schemaName){return this.config.storage.renameCredential(credentialId,userId,nickname,schemaName)}}var DEFAULT_CHALLENGE_TTL_MS=300000;var init_WebAuthn=__esm(()=>{init_esm2()});var init_Services=__esm(()=>{init_ApiKey();init_Auth();init_Authorization();init_Backup();init_Captcha();init_Domain();init_Email();init_Gmail();init_Logger2();init_Monitoring();init_Notification();init_OAuth();init_Payment();init_RateLimiter();init_Secrets();init_Tenant();init_Verification();init_WebAuthn()});function encodeHeaderList(items){return items.map((v)=>encodeURIComponent(v)).join(",")}function decodeHeaderList(header){if(!header)return[];return header.split(",").map((v)=>v.trim()).filter(Boolean).map((v)=>{try{return decodeURIComponent(v)}catch{return v}})}function encodeClaimScopesHeader(claimScopes){if(!claimScopes||Object.keys(claimScopes).length===0)return"";return encodeURIComponent(JSON.stringify(claimScopes))}function decodeClaimScopesHeader(header){if(!header)return;try{let parsed=JSON.parse(decodeURIComponent(header));if(parsed&&typeof parsed==="object"&&!Array.isArray(parsed))return parsed;return}catch{return}}function toCamel3(name2){return name2.replace(/_([a-z])/g,(_,letter)=>letter.toUpperCase())}function readColumn(row,column){if(column in row)return row[column];let camel=toCamel3(column);return camel in row?row[camel]:void 0}function isBlank(value){if(value===null||value===void 0)return!0;if(typeof value==="string")return value.trim().length===0;if(Array.isArray(value))return value.length===0;return!1}function coerce(value){if(isBlank(value))return;if(Array.isArray(value))return coerce(value[0]);if(typeof value==="string")return value.trim();if(typeof value==="number"||typeof value==="boolean")return String(value);return}function readClaim(profile,claim){if(claim in profile)return profile[claim];if(!claim.includes("."))return;let cursor=profile;for(let segment of claim.split(".")){if(cursor===null||typeof cursor!=="object")return;cursor=cursor[segment]}return cursor}function splitTarget(target2){let i=target2.indexOf(".");if(i===-1)return{table:"",column:""};return{table:target2.slice(0,i),column:target2.slice(i+1)}}function resolveProfileSyncUpdates(input){let users={},profiles={},errors2=[];for(let mapping of input.mappings){let{table,column}=splitTarget(mapping.target);if(!table||!column||table!=="users"&&table!=="profiles"){errors2.push(`profileSync mapping target "${mapping.target}" must be "users.<column>" or "profiles.<column>"`);continue}let target2=table==="users"?users:profiles;if(column in target2)continue;let incoming=coerce(readClaim(input.rawProfile,mapping.claim));if(incoming===void 0)continue;let currentRow=table==="users"?input.currentUser:input.currentProfile,current=readColumn(currentRow,column);if(mapping.overwrite===!1&&!isBlank(current))continue;if(current===incoming)continue;target2[column]=incoming}return{users,profiles,errors:errors2}}function validateProfileSyncTargets(mappings,columnsByTable){let errors2=[];for(let mapping of mappings){let{table,column}=splitTarget(mapping.target);if(!table||!column||table!=="users"&&table!=="profiles"){errors2.push(`profileSync mapping target "${mapping.target}" must be "users.<column>" or "profiles.<column>"`);continue}let columns=columnsByTable[table]??[],known=new Set(columns.flatMap((c)=>[c,toCamel3(c)]));if(!known.has(column)&&!known.has(toCamel3(column)))errors2.push(`profileSync maps "${mapping.claim}" to "${mapping.target}", but "${table}" has no column "${column}". Add it via a config entity with "extends": true.`)}return errors2}import{and as and12,eq as eq20}from"drizzle-orm";async function assignDefaultRole(params){let{db,userId,roleName,rolesTable,userRolesTable,logger:logger2}=params;if(!rolesTable||!userRolesTable){logger2.warn("[AUTH] assignDefaultRole called without rolesTable or userRolesTable \u2014 skipping",{userId,roleName});return}try{let rolesCols=rolesTable,userRolesCols=userRolesTable,role=(await db.select().from(rolesTable).where(eq20(rolesCols.name,roleName)).limit(1))[0];if(!role){logger2.warn(`[AUTH] Default role "${roleName}" not found in roles table \u2014 skipping assignment`,{userId});return}let roleId=role.id;if((await db.select().from(userRolesTable).where(and12(eq20(userRolesCols.userId,userId),eq20(userRolesCols.roleId,roleId))).limit(1)).length>0){logger2.debug("[AUTH] User already has default role \u2014 skipping",{userId,roleName});return}await db.insert(userRolesTable).values({userId,roleId}),logger2.info("[AUTH] Default role assigned to new user",{userId,roleName})}catch(err){logger2.warn("[AUTH] Failed to assign default role \u2014 continuing",{userId,roleName,error:err instanceof Error?err.message:String(err)})}}var init_assignDefaultRole=()=>{};import crypto6 from"crypto";var{password:password2}=globalThis.Bun;async function hashPassword(plainPassword){return await password2.hash(plainPassword,{algorithm:"bcrypt",cost:10})}function generateVerificationToken(){return crypto6.randomBytes(32).toString("hex")}function hashVerificationToken(token){return crypto6.createHash("sha256").update(token).digest("hex")}function parseTimeToMs(time2){let match=time2.match(/^(\d+)(s|m|h|d)$/);if(!match||!match[1]||!match[2])return 86400000;let value=Number.parseInt(match[1],10);switch(match[2]){case"s":return value*1000;case"m":return value*60*1000;case"h":return value*60*60*1000;case"d":return value*24*60*60*1000;default:return 86400000}}function validatePasswordStrength(pwd){let errors2=[];if(pwd.length<8)errors2.push("Password must be at least 8 characters");if(!/[A-Z]/.test(pwd))errors2.push("Password must contain uppercase letter");if(!/[a-z]/.test(pwd))errors2.push("Password must contain lowercase letter");if(!/[0-9]/.test(pwd))errors2.push("Password must contain a number");return{valid:errors2.length===0,errors:errors2}}var init_utils6=()=>{};function isEmailExempt(email,exemptDomains){if(!exemptDomains||exemptDomains.length===0)return!1;let domain=email.split("@")[1]?.toLowerCase();if(!domain)return!1;return exemptDomains.some((d)=>domain===d.toLowerCase()||domain.endsWith(`.${d.toLowerCase()}`))}function normalizeTrustedOrigins(raw,env=process.env){if(Array.isArray(raw))return raw.length>0?raw:void 0;if(typeof raw!=="string"||!raw.trim())return;let trimmed=raw.trim(),fromEnv=env[trimmed],isEnvName=/^[A-Z][A-Z0-9_]{2,}$/.test(trimmed),list=(fromEnv??(isEnvName?"":trimmed)).split(/[,;\s]+/).map((entry)=>entry.trim().replace(/\/+$/,"")).filter(Boolean);return list.length>0?list:void 0}function pickTrustedOrigin(candidate,fallbackUrl,allowedOrigins){let fallbackOrigin="";if(fallbackUrl)try{fallbackOrigin=new URL(fallbackUrl).origin}catch{}let trusted=[...fallbackOrigin?[fallbackOrigin]:[],...allowedOrigins??[]];if(candidate&&isOriginTrusted(candidate.replace(/\/+$/,""),trusted))return candidate.replace(/\/+$/,"");return fallbackOrigin}function resolveAppOrigin(request,fallbackUrl,allowedOrigins){let fallbackOrigin="";if(fallbackUrl)try{fallbackOrigin=new URL(fallbackUrl).origin}catch{}let trusted=[...fallbackOrigin?[fallbackOrigin]:[],...allowedOrigins??[]],candidates=[],appOrigin=request.headers.get("x-app-origin");if(appOrigin)candidates.push(appOrigin.replace(/\/+$/,""));let origin=request.headers.get("origin");if(origin)candidates.push(origin.replace(/\/+$/,""));let forwardedHost=request.headers.get("x-forwarded-host")?.split(",")[0]?.trim();if(forwardedHost){let proto=request.headers.get("x-forwarded-proto")?.split(",")[0]?.trim()||"https";candidates.push(`${proto}://${forwardedHost}`)}for(let candidate of candidates)if(isOriginTrusted(candidate,trusted))return candidate;return fallbackOrigin}function extractConfiguredPath(configuredUrl,defaultPath){if(!configuredUrl)return defaultPath;try{return new URL(configuredUrl).pathname}catch{return configuredUrl.startsWith("/")?configuredUrl:defaultPath}}function buildEmailActionLink(params){let{request,configuredUrl,path:path2,query,allowedOrigins}=params,origin=resolveAppOrigin(request,configuredUrl,allowedOrigins),normalizedPath=path2.startsWith("/")?path2:`/${path2}`,queryString=new URLSearchParams(query).toString();return`${origin}${normalizedPath}${queryString?`?${queryString}`:""}`}var originHost=(value)=>{try{return new URL(value).host.toLowerCase()}catch{return value.includes("://")?null:value.toLowerCase().replace(/[/?#].*$/,"")||null}},isOriginTrusted=(candidate,trusted)=>{let candHost=originHost(candidate);if(!candHost)return!1;for(let entry of trusted){let tHost=originHost(entry);if(!tHost)continue;if(tHost.startsWith("*.")){let base=tHost.slice(2);if(candHost===base||candHost.endsWith(`.${base}`))return!0}else if(candHost===tHost)return!0}return!1};var{password:password3}=globalThis.Bun;async function verifyPassword(plainPassword,hashedPassword){try{return await password3.verify(plainPassword,hashedPassword)}catch{return!1}}function labelFromRawUserAgent(userAgent){let ua=(userAgent??"").trim(),lower=ua.toLowerCase();if(!ua||lower==="unknown"||lower==="unknown browser")return;let meaningful=(ua.match(/[A-Za-z][A-Za-z0-9._-]*\/[0-9][^\s;)]*/g)??[]).find((t2)=>!/^mozilla\//i.test(t2));if(meaningful)return meaningful.split("/")[0];return ua.match(/[A-Za-z][A-Za-z0-9 ._-]{2,}/)?.[0]?.trim()||void 0}function parseUserAgentForLogin(userAgent,ipAddress,deviceHint,clientHints){let ua=userAgent.toLowerCase(),headlessIndicators=["headlesschrome","headless","phantomjs","nightmare","selenium","webdriver","puppeteer","playwright"],botIndicators=["bot","crawler","spider","scraper","curl","wget","python-requests","python-urllib","java/","httpclient","go-http-client","node-fetch","axios","postman","insomnia","httpie"],isHeadless=headlessIndicators.some((indicator)=>ua.includes(indicator)),isBot=botIndicators.some((indicator)=>ua.includes(indicator)),isSuspicious=isHeadless||isBot,suspiciousPatterns=[];if(isHeadless)suspiciousPatterns.push("headless_browser");if(isBot)suspiciousPatterns.push("bot_user_agent");if(!ua||ua.length<10)suspiciousPatterns.push("missing_or_short_ua");if(ua==="mozilla/5.0")suspiciousPatterns.push("generic_ua");if(ua.includes("nucleusserveraction")||ua.includes("serveraction"))suspiciousPatterns.push("server_action");let deviceType="unknown";if(ua.includes("ipad"))deviceType="tablet";else if(ua.includes("iphone"))deviceType="mobile";else if(ua.includes("macintosh")||ua.includes("windows")&&!ua.includes("windows phone")||ua.includes("linux")&&!ua.includes("android"))deviceType="desktop";else if(ua.includes("tablet")||ua.includes("android")&&ua.includes("tablet"))deviceType="tablet";else if(ua.includes("mobile")||ua.includes("android"))deviceType="mobile";let browserName,browserVersion;if(isHeadless)browserName="Headless Browser";else if(isBot)browserName="Bot/Crawler";else if(ua.includes("edg")){browserName="Edge";let match=userAgent.match(/Edg\/(\d+\.\d+)/i);if(match?.[1])browserVersion=match[1]}else if(ua.includes("opr/")||ua.includes("opera")){browserName="Opera";let match=userAgent.match(/OPR\/(\d+\.\d+)/i)||userAgent.match(/Opera\/(\d+\.\d+)/i);if(match?.[1])browserVersion=match[1]}else if(ua.includes("samsungbrowser")){browserName="Samsung Internet";let match=userAgent.match(/SamsungBrowser\/(\d+\.\d+)/i);if(match?.[1])browserVersion=match[1]}else if(ua.includes("crios")){browserName="Chrome";let match=userAgent.match(/CriOS\/(\d+\.\d+)/i);if(match?.[1])browserVersion=match[1]}else if(ua.includes("fxios")){browserName="Firefox";let match=userAgent.match(/FxiOS\/(\d+\.\d+)/i);if(match?.[1])browserVersion=match[1]}else if(ua.includes("chrome")){browserName="Chrome";let match=userAgent.match(/Chrome\/(\d+\.\d+)/i);if(match?.[1])browserVersion=match[1]}else if(ua.includes("firefox")){browserName="Firefox";let match=userAgent.match(/Firefox\/(\d+\.\d+)/i);if(match?.[1])browserVersion=match[1]}else if(ua.includes("safari")){browserName="Safari";let match=userAgent.match(/Version\/(\d+\.\d+)/i);if(match?.[1])browserVersion=match[1]}let osName,osVersion;if(ua.includes("windows nt 10"))osName="Windows",osVersion="10/11";else if(ua.includes("windows nt"))osName="Windows";else if(ua.includes("iphone")||ua.includes("ipad")){osName="iOS";let match=userAgent.match(/OS (\d+[._]\d+)/i);if(match?.[1])osVersion=match[1].replace("_",".")}else if(ua.includes("mac os x")){osName="macOS";let match=userAgent.match(/Mac OS X (\d+[._]\d+)/i);if(match?.[1])osVersion=match[1].replace("_",".")}else if(ua.includes("android")){osName="Android";let match=userAgent.match(/Android (\d+\.?\d*)/i);if(match?.[1])osVersion=match[1]}else if(ua.includes("linux"))osName="Linux";if(!browserName&&clientHints?.uaHeader){let brands=[...clientHints.uaHeader.matchAll(/"([^"]+)";v="([^"]+)"/g)].map((m)=>({brand:m[1]??"",version:m[2]??""})).filter((b)=>b.brand&&!/not.?a.?brand/i.test(b.brand)),preferred=brands.find((b)=>/google chrome|microsoft edge|opera|firefox|safari/i.test(b.brand))??brands.find((b)=>!/chromium/i.test(b.brand))??brands[0];if(preferred)browserName=preferred.brand.replace(/^Google /,"").replace(/^Microsoft /,""),browserVersion=preferred.version}if(!osName&&clientHints?.platformHeader)osName=clientHints.platformHeader.replace(/"/g,"").trim()||osName;if(deviceType==="unknown"&&clientHints?.mobileHeader==="?1")deviceType="mobile";return{deviceName:browserName&&osName?`${browserName} on ${osName}`:browserName?browserName:osName?osName:deviceType!=="unknown"?deviceType.charAt(0).toUpperCase()+deviceType.slice(1):labelFromRawUserAgent(userAgent)??"Unknown Device",deviceType,browserName,browserVersion,osName,osVersion,ipAddress,userAgent,deviceHint,locationCountry:void 0,locationCity:void 0,isHeadless,isBot,isSuspicious,suspiciousPatterns}}var init_utils7=()=>{};function deviceContextFromRequest(request){let rawFwd=request.headers.get("x-forwarded-for")?.split(",")[0]?.trim(),isPrivate=(ip)=>!ip||ip==="127.0.0.1"||ip==="::1"||ip==="localhost"||ip.startsWith("10.")||ip.startsWith("192.168.")||ip.startsWith("172.");return{ipAddress:request.headers.get("cf-connecting-ip")?.trim()||request.headers.get("true-client-ip")?.trim()||(!isPrivate(rawFwd)?rawFwd:void 0)||request.headers.get("x-real-ip")?.trim()||rawFwd||"127.0.0.1",userAgent:request.headers.get("user-agent")||"",clientHints:{uaHeader:request.headers.get("sec-ch-ua")??void 0,platformHeader:request.headers.get("sec-ch-ua-platform")??void 0,mobileHeader:request.headers.get("sec-ch-ua-mobile")??void 0}}}function ensureDeviceInfo(info,clientHints){if(info.browserName&&info.osName&&info.deviceName)return info;let parsed=info.userAgent?parseUserAgentForLogin(info.userAgent,info.ipAddress,info.deviceHint,clientHints):void 0;return{ipAddress:info.ipAddress,userAgent:info.userAgent,deviceHint:info.deviceHint,deviceName:info.deviceName??parsed?.deviceName??"Unknown Device",deviceType:info.deviceType&&info.deviceType!=="unknown"?info.deviceType:parsed?.deviceType??info.deviceType??"unknown",browserName:info.browserName??parsed?.browserName,browserVersion:info.browserVersion??parsed?.browserVersion,osName:info.osName??parsed?.osName,osVersion:info.osVersion??parsed?.osVersion,locationCountry:info.locationCountry,locationCity:info.locationCity}}var init_deviceInfo=__esm(()=>{init_utils7()});import{randomUUID as randomUUID5}from"crypto";import path2 from"path";function mergeStorageConfig(config){if(!config)return DEFAULT_STORAGE_CONFIG;return{enabled:config.enabled??DEFAULT_STORAGE_CONFIG.enabled,basePath:config.basePath??DEFAULT_STORAGE_CONFIG.basePath,maxFileSizeBytes:config.maxFileSizeBytes??DEFAULT_STORAGE_CONFIG.maxFileSizeBytes,allowedMimeTypes:config.allowedMimeTypes??DEFAULT_STORAGE_CONFIG.allowedMimeTypes,blockedMimeTypes:config.blockedMimeTypes??DEFAULT_STORAGE_CONFIG.blockedMimeTypes,formData:{filesField:config.formData?.filesField??DEFAULT_STORAGE_CONFIG.formData.filesField,dataField:config.formData?.dataField??DEFAULT_STORAGE_CONFIG.formData.dataField,maxFiles:config.formData?.maxFiles??DEFAULT_STORAGE_CONFIG.formData.maxFiles}}}function parseFormDataBody(body,config){let result={data:{},files:[]};if(!body||typeof body!=="object")return result;let bodyObj=body,dataField=bodyObj[config.formData.dataField];if(dataField){if(typeof dataField==="string")try{result.data=JSON.parse(dataField)}catch{result.data={}}else if(typeof dataField==="object")result.data=dataField}let filesField=bodyObj[config.formData.filesField];if(filesField){if(filesField instanceof File)result.files=[filesField];else if(Array.isArray(filesField))result.files=filesField.filter((f)=>f instanceof File)}return result}function validateFile(file,config){if(file.size>config.maxFileSizeBytes)return{valid:!1,error:`File ${file.name} exceeds maximum size of ${config.maxFileSizeBytes} bytes`};if(config.blockedMimeTypes.length>0&&config.blockedMimeTypes.includes(file.type))return{valid:!1,error:`File type ${file.type} is not allowed`};if(config.allowedMimeTypes.length>0&&!config.allowedMimeTypes.includes(file.type))return{valid:!1,error:`File type ${file.type} is not in allowed list`};return{valid:!0}}function setStorageProvider(provider){activeStorageProvider=provider}function getStorageProvider(){return activeStorageProvider}async function uploadFile(file,config,subFolder){let id=randomUUID5(),ext=path2.extname(file.name),uniqueName=`${id}${ext}`,folderPath=subFolder?path2.join(config.basePath,subFolder):config.basePath,arrayBuffer=await file.arrayBuffer(),buffer=new Uint8Array(arrayBuffer),provider=activeStorageProvider;if(provider&&provider.kind!=="local"){let relative=subFolder?`${subFolder}/${uniqueName}`:uniqueName;await provider.write(relative,buffer)}else await fileManager.createFile({dir:folderPath,name:uniqueName,data:buffer,options:{type:file.type,createDir:!0}});return{id,name:uniqueName,originalName:file.name,path:folderPath,mimeType:file.type,size:file.size,createdAt:new Date}}async function uploadFiles(files,config,subFolder){let success=[],failed=[];for(let file of files.slice(0,config.formData.maxFiles)){let validation=validateFile(file,config);if(!validation.valid){failed.push({file:file.name,error:validation.error||"Unknown error"});continue}try{let result=await uploadFile(file,config,subFolder);success.push(result)}catch(error){failed.push({file:file.name,error:error instanceof Error?error.message:"Upload failed"})}}return{success,failed}}function isPathWithinBase(base,target2){let resolvedBase=path2.resolve(base),resolvedTarget=path2.resolve(target2);return resolvedTarget===resolvedBase||resolvedTarget.startsWith(resolvedBase+path2.sep)}async function deleteFile(filePath,fileName,storageBase){try{let fullPath=path2.join(filePath,fileName);if(storageBase&&!isPathWithinBase(storageBase,fullPath))return!1;let provider=activeStorageProvider;if(provider&&provider.kind!=="local"&&storageBase)return await provider.delete(path2.relative(storageBase,fullPath));return await fileManager.deleteFile(fullPath)}catch{return!1}}var DEFAULT_STORAGE_CONFIG,activeStorageProvider=null;var init_helpers2=__esm(()=>{init_File();DEFAULT_STORAGE_CONFIG={enabled:!1,basePath:"./uploads",maxFileSizeBytes:104857600,allowedMimeTypes:[],blockedMimeTypes:["application/x-executable","application/x-msdos-program","text/html","application/xhtml+xml","image/svg+xml","application/xml","text/xml","application/javascript","text/javascript","application/x-httpd-php"],formData:{filesField:"files",dataField:"data",maxFiles:10}}});var require_is=__commonJS((exports,module)=>{var defined=function(val){return typeof val<"u"&&val!==null},object=function(val){return typeof val==="object"},plainObject=function(val){return Object.prototype.toString.call(val)==="[object Object]"},fn=function(val){return typeof val==="function"},bool=function(val){return typeof val==="boolean"},buffer=function(val){return val instanceof Buffer},typedArray=function(val){if(defined(val))switch(val.constructor){case Uint8Array:case Uint8ClampedArray:case Int8Array:case Uint16Array:case Int16Array:case Uint32Array:case Int32Array:case Float32Array:case Float64Array:return!0}return!1},arrayBuffer=function(val){return val instanceof ArrayBuffer},string=function(val){return typeof val==="string"&&val.length>0},number=function(val){return typeof val==="number"&&!Number.isNaN(val)},integer=function(val){return Number.isInteger(val)},inRange=function(val,min,max){return val>=min&&val<=max},inArray8=function(val,list){return list.includes(val)},invalidParameterError=function(name2,expected,actual){return Error(`Expected ${expected} for ${name2} but received ${actual} of type ${typeof actual}`)},nativeError=function(native,context){return context.message=native.message,context};module.exports={defined,object,plainObject,fn,bool,buffer,typedArray,arrayBuffer,string,number,integer,inRange,inArray:inArray8,invalidParameterError,nativeError}});var require_process=__commonJS((exports,module)=>{var isLinux=()=>process.platform==="linux",report=null,getReport=()=>{if(!report)if(isLinux()&&process.report){let orig=process.report.excludeNetwork;process.report.excludeNetwork=!0,report=process.report.getReport(),process.report.excludeNetwork=orig}else report={};return report};module.exports={isLinux,getReport}});var require_filesystem=__commonJS((exports,module)=>{var fs4=__require("fs"),readFileSync2=(path3)=>{let fd=fs4.openSync(path3,"r"),buffer=Buffer.alloc(2048),bytesRead=fs4.readSync(fd,buffer,0,2048,0);return fs4.close(fd,()=>{}),buffer.subarray(0,bytesRead)},readFile2=(path3)=>new Promise((resolve2,reject)=>{fs4.open(path3,"r",(err,fd)=>{if(err)reject(err);else{let buffer=Buffer.alloc(2048);fs4.read(fd,buffer,0,2048,0,(_,bytesRead)=>{resolve2(buffer.subarray(0,bytesRead)),fs4.close(fd,()=>{})})}})});module.exports={LDD_PATH:"/usr/bin/ldd",SELF_PATH:"/proc/self/exe",readFileSync:readFileSync2,readFile:readFile2}});var require_elf=__commonJS((exports,module)=>{var interpreterPath=(elf)=>{if(elf.length<64)return null;if(elf.readUInt32BE(0)!==2135247942)return null;if(elf.readUInt8(4)!==2)return null;if(elf.readUInt8(5)!==1)return null;let offset=elf.readUInt32LE(32),size=elf.readUInt16LE(54),count2=elf.readUInt16LE(56);for(let i=0;i<count2;i++){let headerOffset=offset+i*size;if(elf.readUInt32LE(headerOffset)===3){let fileOffset=elf.readUInt32LE(headerOffset+8),fileSize=elf.readUInt32LE(headerOffset+32);return elf.subarray(fileOffset,fileOffset+fileSize).toString().replace(/\0.*$/g,"")}}return null};module.exports={interpreterPath}});var require_detect_libc=__commonJS((exports,module)=>{var childProcess=__require("child_process"),{isLinux,getReport}=require_process(),{LDD_PATH,SELF_PATH,readFile:readFile2,readFileSync:readFileSync2}=require_filesystem(),{interpreterPath}=require_elf(),cachedFamilyInterpreter,cachedFamilyFilesystem,cachedVersionFilesystem,commandOut="",safeCommand=()=>{if(!commandOut)return new Promise((resolve2)=>{childProcess.exec("getconf GNU_LIBC_VERSION 2>&1 || true; ldd --version 2>&1 || true",(err,out)=>{commandOut=err?" ":out,resolve2(commandOut)})});return commandOut},safeCommandSync=()=>{if(!commandOut)try{commandOut=childProcess.execSync("getconf GNU_LIBC_VERSION 2>&1 || true; ldd --version 2>&1 || true",{encoding:"utf8"})}catch(_err){commandOut=" "}return commandOut},GLIBC="glibc",RE_GLIBC_VERSION=/LIBC[a-z0-9 \-).]*?(\d+\.\d+)/i,MUSL="musl",isFileMusl=(f)=>f.includes("libc.musl-")||f.includes("ld-musl-"),familyFromReport=()=>{let report=getReport();if(report.header&&report.header.glibcVersionRuntime)return GLIBC;if(Array.isArray(report.sharedObjects)){if(report.sharedObjects.some(isFileMusl))return MUSL}return null},familyFromCommand=(out)=>{let[getconf,ldd1]=out.split(/[\r\n]+/);if(getconf&&getconf.includes(GLIBC))return GLIBC;if(ldd1&&ldd1.includes(MUSL))return MUSL;return null},familyFromInterpreterPath=(path3)=>{if(path3){if(path3.includes("/ld-musl-"))return MUSL;else if(path3.includes("/ld-linux-"))return GLIBC}return null},getFamilyFromLddContent=(content)=>{if(content=content.toString(),content.includes("musl"))return MUSL;if(content.includes("GNU C Library"))return GLIBC;return null},familyFromFilesystem=async()=>{if(cachedFamilyFilesystem!==void 0)return cachedFamilyFilesystem;cachedFamilyFilesystem=null;try{let lddContent=await readFile2(LDD_PATH);cachedFamilyFilesystem=getFamilyFromLddContent(lddContent)}catch(e){}return cachedFamilyFilesystem},familyFromFilesystemSync=()=>{if(cachedFamilyFilesystem!==void 0)return cachedFamilyFilesystem;cachedFamilyFilesystem=null;try{let lddContent=readFileSync2(LDD_PATH);cachedFamilyFilesystem=getFamilyFromLddContent(lddContent)}catch(e){}return cachedFamilyFilesystem},familyFromInterpreter=async()=>{if(cachedFamilyInterpreter!==void 0)return cachedFamilyInterpreter;cachedFamilyInterpreter=null;try{let selfContent=await readFile2(SELF_PATH),path3=interpreterPath(selfContent);cachedFamilyInterpreter=familyFromInterpreterPath(path3)}catch(e){}return cachedFamilyInterpreter},familyFromInterpreterSync=()=>{if(cachedFamilyInterpreter!==void 0)return cachedFamilyInterpreter;cachedFamilyInterpreter=null;try{let selfContent=readFileSync2(SELF_PATH),path3=interpreterPath(selfContent);cachedFamilyInterpreter=familyFromInterpreterPath(path3)}catch(e){}return cachedFamilyInterpreter},family=async()=>{let family2=null;if(isLinux()){if(family2=await familyFromInterpreter(),!family2){if(family2=await familyFromFilesystem(),!family2)family2=familyFromReport();if(!family2){let out=await safeCommand();family2=familyFromCommand(out)}}}return family2},familySync=()=>{let family2=null;if(isLinux()){if(family2=familyFromInterpreterSync(),!family2){if(family2=familyFromFilesystemSync(),!family2)family2=familyFromReport();if(!family2){let out=safeCommandSync();family2=familyFromCommand(out)}}}return family2},isNonGlibcLinux=async()=>isLinux()&&await family()!==GLIBC,isNonGlibcLinuxSync=()=>isLinux()&&familySync()!==GLIBC,versionFromFilesystem=async()=>{if(cachedVersionFilesystem!==void 0)return cachedVersionFilesystem;cachedVersionFilesystem=null;try{let versionMatch=(await readFile2(LDD_PATH)).match(RE_GLIBC_VERSION);if(versionMatch)cachedVersionFilesystem=versionMatch[1]}catch(e){}return cachedVersionFilesystem},versionFromFilesystemSync=()=>{if(cachedVersionFilesystem!==void 0)return cachedVersionFilesystem;cachedVersionFilesystem=null;try{let versionMatch=readFileSync2(LDD_PATH).match(RE_GLIBC_VERSION);if(versionMatch)cachedVersionFilesystem=versionMatch[1]}catch(e){}return cachedVersionFilesystem},versionFromReport=()=>{let report=getReport();if(report.header&&report.header.glibcVersionRuntime)return report.header.glibcVersionRuntime;return null},versionSuffix=(s)=>s.trim().split(/\s+/)[1],versionFromCommand=(out)=>{let[getconf,ldd1,ldd2]=out.split(/[\r\n]+/);if(getconf&&getconf.includes(GLIBC))return versionSuffix(getconf);if(ldd1&&ldd2&&ldd1.includes(MUSL))return versionSuffix(ldd2);return null},version=async()=>{let version2=null;if(isLinux()){if(version2=await versionFromFilesystem(),!version2)version2=versionFromReport();if(!version2){let out=await safeCommand();version2=versionFromCommand(out)}}return version2},versionSync=()=>{let version2=null;if(isLinux()){if(version2=versionFromFilesystemSync(),!version2)version2=versionFromReport();if(!version2){let out=safeCommandSync();version2=versionFromCommand(out)}}return version2};module.exports={GLIBC,MUSL,family,familySync,isNonGlibcLinux,isNonGlibcLinuxSync,version,versionSync}});var require_debug=__commonJS((exports,module)=>{var debug=typeof process==="object"&&process.env&&process.env.NODE_DEBUG&&/\bsemver\b/i.test(process.env.NODE_DEBUG)?(...args)=>console.error("SEMVER",...args):()=>{};module.exports=debug});var require_constants2=__commonJS((exports,module)=>{var MAX_SAFE_INTEGER=Number.MAX_SAFE_INTEGER||9007199254740991,RELEASE_TYPES=["major","premajor","minor","preminor","patch","prepatch","prerelease"];module.exports={MAX_LENGTH:256,MAX_SAFE_COMPONENT_LENGTH:16,MAX_SAFE_BUILD_LENGTH:250,MAX_SAFE_INTEGER,RELEASE_TYPES,SEMVER_SPEC_VERSION:"2.0.0",FLAG_INCLUDE_PRERELEASE:1,FLAG_LOOSE:2}});var require_re=__commonJS((exports,module)=>{var{MAX_SAFE_COMPONENT_LENGTH,MAX_SAFE_BUILD_LENGTH,MAX_LENGTH}=require_constants2(),debug=require_debug();exports=module.exports={};var re=exports.re=[],safeRe=exports.safeRe=[],src=exports.src=[],safeSrc=exports.safeSrc=[],t3=exports.t={},R=0,LETTERDASHNUMBER="[a-zA-Z0-9-]",safeRegexReplacements=[["\\s",1],["\\d",MAX_LENGTH],[LETTERDASHNUMBER,MAX_SAFE_BUILD_LENGTH]],makeSafeRegex=(value)=>{for(let[token,max]of safeRegexReplacements)value=value.split(`${token}*`).join(`${token}{0,${max}}`).split(`${token}+`).join(`${token}{1,${max}}`);return value},createToken=(name2,value,isGlobal)=>{let safe=makeSafeRegex(value),index=R++;debug(name2,index,value),t3[name2]=index,src[index]=value,safeSrc[index]=safe,re[index]=new RegExp(value,isGlobal?"g":void 0),safeRe[index]=new RegExp(safe,isGlobal?"g":void 0)};createToken("NUMERICIDENTIFIER","0|[1-9]\\d*");createToken("NUMERICIDENTIFIERLOOSE","\\d+");createToken("NONNUMERICIDENTIFIER",`\\d*[a-zA-Z-]${LETTERDASHNUMBER}*`);createToken("MAINVERSION",`(${src[t3.NUMERICIDENTIFIER]})\\.(${src[t3.NUMERICIDENTIFIER]})\\.(${src[t3.NUMERICIDENTIFIER]})`);createToken("MAINVERSIONLOOSE",`(${src[t3.NUMERICIDENTIFIERLOOSE]})\\.(${src[t3.NUMERICIDENTIFIERLOOSE]})\\.(${src[t3.NUMERICIDENTIFIERLOOSE]})`);createToken("PRERELEASEIDENTIFIER",`(?:${src[t3.NONNUMERICIDENTIFIER]}|${src[t3.NUMERICIDENTIFIER]})`);createToken("PRERELEASEIDENTIFIERLOOSE",`(?:${src[t3.NONNUMERICIDENTIFIER]}|${src[t3.NUMERICIDENTIFIERLOOSE]})`);createToken("PRERELEASE",`(?:-(${src[t3.PRERELEASEIDENTIFIER]}(?:\\.${src[t3.PRERELEASEIDENTIFIER]})*))`);createToken("PRERELEASELOOSE",`(?:-?(${src[t3.PRERELEASEIDENTIFIERLOOSE]}(?:\\.${src[t3.PRERELEASEIDENTIFIERLOOSE]})*))`);createToken("BUILDIDENTIFIER",`${LETTERDASHNUMBER}+`);createToken("BUILD",`(?:\\+(${src[t3.BUILDIDENTIFIER]}(?:\\.${src[t3.BUILDIDENTIFIER]})*))`);createToken("FULLPLAIN",`v?${src[t3.MAINVERSION]}${src[t3.PRERELEASE]}?${src[t3.BUILD]}?`);createToken("FULL",`^${src[t3.FULLPLAIN]}$`);createToken("LOOSEPLAIN",`[v=\\s]*${src[t3.MAINVERSIONLOOSE]}${src[t3.PRERELEASELOOSE]}?${src[t3.BUILD]}?`);createToken("LOOSE",`^${src[t3.LOOSEPLAIN]}$`);createToken("GTLT","((?:<|>)?=?)");createToken("XRANGEIDENTIFIERLOOSE",`${src[t3.NUMERICIDENTIFIERLOOSE]}|x|X|\\*`);createToken("XRANGEIDENTIFIER",`${src[t3.NUMERICIDENTIFIER]}|x|X|\\*`);createToken("XRANGEPLAIN",`[v=\\s]*(${src[t3.XRANGEIDENTIFIER]})(?:\\.(${src[t3.XRANGEIDENTIFIER]})(?:\\.(${src[t3.XRANGEIDENTIFIER]})(?:${src[t3.PRERELEASE]})?${src[t3.BUILD]}?)?)?`);createToken("XRANGEPLAINLOOSE",`[v=\\s]*(${src[t3.XRANGEIDENTIFIERLOOSE]})(?:\\.(${src[t3.XRANGEIDENTIFIERLOOSE]})(?:\\.(${src[t3.XRANGEIDENTIFIERLOOSE]})(?:${src[t3.PRERELEASELOOSE]})?${src[t3.BUILD]}?)?)?`);createToken("XRANGE",`^${src[t3.GTLT]}\\s*${src[t3.XRANGEPLAIN]}$`);createToken("XRANGELOOSE",`^${src[t3.GTLT]}\\s*${src[t3.XRANGEPLAINLOOSE]}$`);createToken("COERCEPLAIN",`(^|[^\\d])(\\d{1,${MAX_SAFE_COMPONENT_LENGTH}})(?:\\.(\\d{1,${MAX_SAFE_COMPONENT_LENGTH}}))?(?:\\.(\\d{1,${MAX_SAFE_COMPONENT_LENGTH}}))?`);createToken("COERCE",`${src[t3.COERCEPLAIN]}(?:$|[^\\d])`);createToken("COERCEFULL",src[t3.COERCEPLAIN]+`(?:${src[t3.PRERELEASE]})?(?:${src[t3.BUILD]})?(?:$|[^\\d])`);createToken("COERCERTL",src[t3.COERCE],!0);createToken("COERCERTLFULL",src[t3.COERCEFULL],!0);createToken("LONETILDE","(?:~>?)");createToken("TILDETRIM",`(\\s*)${src[t3.LONETILDE]}\\s+`,!0);exports.tildeTrimReplace="$1~";createToken("TILDE",`^${src[t3.LONETILDE]}${src[t3.XRANGEPLAIN]}$`);createToken("TILDELOOSE",`^${src[t3.LONETILDE]}${src[t3.XRANGEPLAINLOOSE]}$`);createToken("LONECARET","(?:\\^)");createToken("CARETTRIM",`(\\s*)${src[t3.LONECARET]}\\s+`,!0);exports.caretTrimReplace="$1^";createToken("CARET",`^${src[t3.LONECARET]}${src[t3.XRANGEPLAIN]}$`);createToken("CARETLOOSE",`^${src[t3.LONECARET]}${src[t3.XRANGEPLAINLOOSE]}$`);createToken("COMPARATORLOOSE",`^${src[t3.GTLT]}\\s*(${src[t3.LOOSEPLAIN]})$|^$`);createToken("COMPARATOR",`^${src[t3.GTLT]}\\s*(${src[t3.FULLPLAIN]})$|^$`);createToken("COMPARATORTRIM",`(\\s*)${src[t3.GTLT]}\\s*(${src[t3.LOOSEPLAIN]}|${src[t3.XRANGEPLAIN]})`,!0);exports.comparatorTrimReplace="$1$2$3";createToken("HYPHENRANGE",`^\\s*(${src[t3.XRANGEPLAIN]})\\s+-\\s+(${src[t3.XRANGEPLAIN]})\\s*$`);createToken("HYPHENRANGELOOSE",`^\\s*(${src[t3.XRANGEPLAINLOOSE]})\\s+-\\s+(${src[t3.XRANGEPLAINLOOSE]})\\s*$`);createToken("STAR","(<|>)?=?\\s*\\*");createToken("GTE0","^\\s*>=\\s*0\\.0\\.0\\s*$");createToken("GTE0PRE","^\\s*>=\\s*0\\.0\\.0-0\\s*$")});var require_parse_options=__commonJS((exports,module)=>{var looseOption=Object.freeze({loose:!0}),emptyOpts=Object.freeze({}),parseOptions=(options)=>{if(!options)return emptyOpts;if(typeof options!=="object")return looseOption;return options};module.exports=parseOptions});var require_identifiers=__commonJS((exports,module)=>{var numeric=/^[0-9]+$/,compareIdentifiers=(a,b)=>{if(typeof a==="number"&&typeof b==="number")return a===b?0:a<b?-1:1;let anum=numeric.test(a),bnum=numeric.test(b);if(anum&&bnum)a=+a,b=+b;return a===b?0:anum&&!bnum?-1:bnum&&!anum?1:a<b?-1:1},rcompareIdentifiers=(a,b)=>compareIdentifiers(b,a);module.exports={compareIdentifiers,rcompareIdentifiers}});var require_semver=__commonJS((exports,module)=>{var debug=require_debug(),{MAX_LENGTH,MAX_SAFE_INTEGER}=require_constants2(),{safeRe:re,t:t3}=require_re(),parseOptions=require_parse_options(),{compareIdentifiers}=require_identifiers();class SemVer{constructor(version,options){if(options=parseOptions(options),version instanceof SemVer)if(version.loose===!!options.loose&&version.includePrerelease===!!options.includePrerelease)return version;else version=version.version;else if(typeof version!=="string")throw TypeError(`Invalid version. Must be a string. Got type "${typeof version}".`);if(version.length>MAX_LENGTH)throw TypeError(`version is longer than ${MAX_LENGTH} characters`);debug("SemVer",version,options),this.options=options,this.loose=!!options.loose,this.includePrerelease=!!options.includePrerelease;let m=version.trim().match(options.loose?re[t3.LOOSE]:re[t3.FULL]);if(!m)throw TypeError(`Invalid Version: ${version}`);if(this.raw=version,this.major=+m[1],this.minor=+m[2],this.patch=+m[3],this.major>MAX_SAFE_INTEGER||this.major<0)throw TypeError("Invalid major version");if(this.minor>MAX_SAFE_INTEGER||this.minor<0)throw TypeError("Invalid minor version");if(this.patch>MAX_SAFE_INTEGER||this.patch<0)throw TypeError("Invalid patch version");if(!m[4])this.prerelease=[];else this.prerelease=m[4].split(".").map((id)=>{if(/^[0-9]+$/.test(id)){let num3=+id;if(num3>=0&&num3<MAX_SAFE_INTEGER)return num3}return id});this.build=m[5]?m[5].split("."):[],this.format()}format(){if(this.version=`${this.major}.${this.minor}.${this.patch}`,this.prerelease.length)this.version+=`-${this.prerelease.join(".")}`;return this.version}toString(){return this.version}compare(other){if(debug("SemVer.compare",this.version,this.options,other),!(other instanceof SemVer)){if(typeof other==="string"&&other===this.version)return 0;other=new SemVer(other,this.options)}if(other.version===this.version)return 0;return this.compareMain(other)||this.comparePre(other)}compareMain(other){if(!(other instanceof SemVer))other=new SemVer(other,this.options);if(this.major<other.major)return-1;if(this.major>other.major)return 1;if(this.minor<other.minor)return-1;if(this.minor>other.minor)return 1;if(this.patch<other.patch)return-1;if(this.patch>other.patch)return 1;return 0}comparePre(other){if(!(other instanceof SemVer))other=new SemVer(other,this.options);if(this.prerelease.length&&!other.prerelease.length)return-1;else if(!this.prerelease.length&&other.prerelease.length)return 1;else if(!this.prerelease.length&&!other.prerelease.length)return 0;let i=0;do{let a=this.prerelease[i],b=other.prerelease[i];if(debug("prerelease compare",i,a,b),a===void 0&&b===void 0)return 0;else if(b===void 0)return 1;else if(a===void 0)return-1;else if(a===b)continue;else return compareIdentifiers(a,b)}while(++i)}compareBuild(other){if(!(other instanceof SemVer))other=new SemVer(other,this.options);let i=0;do{let a=this.build[i],b=other.build[i];if(debug("build compare",i,a,b),a===void 0&&b===void 0)return 0;else if(b===void 0)return 1;else if(a===void 0)return-1;else if(a===b)continue;else return compareIdentifiers(a,b)}while(++i)}inc(release2,identifier,identifierBase){if(release2.startsWith("pre")){if(!identifier&&identifierBase===!1)throw Error("invalid increment argument: identifier is empty");if(identifier){let match=`-${identifier}`.match(this.options.loose?re[t3.PRERELEASELOOSE]:re[t3.PRERELEASE]);if(!match||match[1]!==identifier)throw Error(`invalid identifier: ${identifier}`)}}switch(release2){case"premajor":this.prerelease.length=0,this.patch=0,this.minor=0,this.major++,this.inc("pre",identifier,identifierBase);break;case"preminor":this.prerelease.length=0,this.patch=0,this.minor++,this.inc("pre",identifier,identifierBase);break;case"prepatch":this.prerelease.length=0,this.inc("patch",identifier,identifierBase),this.inc("pre",identifier,identifierBase);break;case"prerelease":if(this.prerelease.length===0)this.inc("patch",identifier,identifierBase);this.inc("pre",identifier,identifierBase);break;case"release":if(this.prerelease.length===0)throw Error(`version ${this.raw} is not a prerelease`);this.prerelease.length=0;break;case"major":if(this.minor!==0||this.patch!==0||this.prerelease.length===0)this.major++;this.minor=0,this.patch=0,this.prerelease=[];break;case"minor":if(this.patch!==0||this.prerelease.length===0)this.minor++;this.patch=0,this.prerelease=[];break;case"patch":if(this.prerelease.length===0)this.patch++;this.prerelease=[];break;case"pre":{let base=Number(identifierBase)?1:0;if(this.prerelease.length===0)this.prerelease=[base];else{let i=this.prerelease.length;while(--i>=0)if(typeof this.prerelease[i]==="number")this.prerelease[i]++,i=-2;if(i===-1){if(identifier===this.prerelease.join(".")&&identifierBase===!1)throw Error("invalid increment argument: identifier already exists");this.prerelease.push(base)}}if(identifier){let prerelease=[identifier,base];if(identifierBase===!1)prerelease=[identifier];if(compareIdentifiers(this.prerelease[0],identifier)===0){if(isNaN(this.prerelease[1]))this.prerelease=prerelease}else this.prerelease=prerelease}break}default:throw Error(`invalid increment argument: ${release2}`)}if(this.raw=this.format(),this.build.length)this.raw+=`+${this.build.join(".")}`;return this}}module.exports=SemVer});var require_parse=__commonJS((exports,module)=>{var SemVer=require_semver(),parse2=(version,options,throwErrors=!1)=>{if(version instanceof SemVer)return version;try{return new SemVer(version,options)}catch(er){if(!throwErrors)return null;throw er}};module.exports=parse2});var require_coerce=__commonJS((exports,module)=>{var SemVer=require_semver(),parse2=require_parse(),{safeRe:re,t:t3}=require_re(),coerce2=(version,options)=>{if(version instanceof SemVer)return version;if(typeof version==="number")version=String(version);if(typeof version!=="string")return null;options=options||{};let match=null;if(!options.rtl)match=version.match(options.includePrerelease?re[t3.COERCEFULL]:re[t3.COERCE]);else{let coerceRtlRegex=options.includePrerelease?re[t3.COERCERTLFULL]:re[t3.COERCERTL],next;while((next=coerceRtlRegex.exec(version))&&(!match||match.index+match[0].length!==version.length)){if(!match||next.index+next[0].length!==match.index+match[0].length)match=next;coerceRtlRegex.lastIndex=next.index+next[1].length+next[2].length}coerceRtlRegex.lastIndex=-1}if(match===null)return null;let major=match[2],minor=match[3]||"0",patch=match[4]||"0",prerelease=options.includePrerelease&&match[5]?`-${match[5]}`:"",build=options.includePrerelease&&match[6]?`+${match[6]}`:"";return parse2(`${major}.${minor}.${patch}${prerelease}${build}`,options)};module.exports=coerce2});var require_compare=__commonJS((exports,module)=>{var SemVer=require_semver(),compare2=(a,b,loose)=>new SemVer(a,loose).compare(new SemVer(b,loose));module.exports=compare2});var require_gte=__commonJS((exports,module)=>{var compare2=require_compare(),gte=(a,b,loose)=>compare2(a,b,loose)>=0;module.exports=gte});var require_lrucache=__commonJS((exports,module)=>{class LRUCache2{constructor(){this.max=1000,this.map=new Map}get(key2){let value=this.map.get(key2);if(value===void 0)return;else return this.map.delete(key2),this.map.set(key2,value),value}delete(key2){return this.map.delete(key2)}set(key2,value){if(!this.delete(key2)&&value!==void 0){if(this.map.size>=this.max){let firstKey=this.map.keys().next().value;this.delete(firstKey)}this.map.set(key2,value)}return this}}module.exports=LRUCache2});var require_eq=__commonJS((exports,module)=>{var compare2=require_compare(),eq28=(a,b,loose)=>compare2(a,b,loose)===0;module.exports=eq28});var require_neq=__commonJS((exports,module)=>{var compare2=require_compare(),neq=(a,b,loose)=>compare2(a,b,loose)!==0;module.exports=neq});var require_gt=__commonJS((exports,module)=>{var compare2=require_compare(),gt=(a,b,loose)=>compare2(a,b,loose)>0;module.exports=gt});var require_lt=__commonJS((exports,module)=>{var compare2=require_compare(),lt2=(a,b,loose)=>compare2(a,b,loose)<0;module.exports=lt2});var require_lte=__commonJS((exports,module)=>{var compare2=require_compare(),lte=(a,b,loose)=>compare2(a,b,loose)<=0;module.exports=lte});var require_cmp=__commonJS((exports,module)=>{var eq28=require_eq(),neq=require_neq(),gt=require_gt(),gte=require_gte(),lt2=require_lt(),lte=require_lte(),cmp=(a,op,b,loose)=>{switch(op){case"===":if(typeof a==="object")a=a.version;if(typeof b==="object")b=b.version;return a===b;case"!==":if(typeof a==="object")a=a.version;if(typeof b==="object")b=b.version;return a!==b;case"":case"=":case"==":return eq28(a,b,loose);case"!=":return neq(a,b,loose);case">":return gt(a,b,loose);case">=":return gte(a,b,loose);case"<":return lt2(a,b,loose);case"<=":return lte(a,b,loose);default:throw TypeError(`Invalid operator: ${op}`)}};module.exports=cmp});var require_comparator=__commonJS((exports,module)=>{var ANY=Symbol("SemVer ANY");class Comparator{static get ANY(){return ANY}constructor(comp,options){if(options=parseOptions(options),comp instanceof Comparator)if(comp.loose===!!options.loose)return comp;else comp=comp.value;if(comp=comp.trim().split(/\s+/).join(" "),debug("comparator",comp,options),this.options=options,this.loose=!!options.loose,this.parse(comp),this.semver===ANY)this.value="";else this.value=this.operator+this.semver.version;debug("comp",this)}parse(comp){let r=this.options.loose?re[t3.COMPARATORLOOSE]:re[t3.COMPARATOR],m=comp.match(r);if(!m)throw TypeError(`Invalid comparator: ${comp}`);if(this.operator=m[1]!==void 0?m[1]:"",this.operator==="=")this.operator="";if(!m[2])this.semver=ANY;else this.semver=new SemVer(m[2],this.options.loose)}toString(){return this.value}test(version){if(debug("Comparator.test",version,this.options.loose),this.semver===ANY||version===ANY)return!0;if(typeof version==="string")try{version=new SemVer(version,this.options)}catch(er){return!1}return cmp(version,this.operator,this.semver,this.options)}intersects(comp,options){if(!(comp instanceof Comparator))throw TypeError("a Comparator is required");if(this.operator===""){if(this.value==="")return!0;return new Range(comp.value,options).test(this.value)}else if(comp.operator===""){if(comp.value==="")return!0;return new Range(this.value,options).test(comp.semver)}if(options=parseOptions(options),options.includePrerelease&&(this.value==="<0.0.0-0"||comp.value==="<0.0.0-0"))return!1;if(!options.includePrerelease&&(this.value.startsWith("<0.0.0")||comp.value.startsWith("<0.0.0")))return!1;if(this.operator.startsWith(">")&&comp.operator.startsWith(">"))return!0;if(this.operator.startsWith("<")&&comp.operator.startsWith("<"))return!0;if(this.semver.version===comp.semver.version&&this.operator.includes("=")&&comp.operator.includes("="))return!0;if(cmp(this.semver,"<",comp.semver,options)&&this.operator.startsWith(">")&&comp.operator.startsWith("<"))return!0;if(cmp(this.semver,">",comp.semver,options)&&this.operator.startsWith("<")&&comp.operator.startsWith(">"))return!0;return!1}}module.exports=Comparator;var parseOptions=require_parse_options(),{safeRe:re,t:t3}=require_re(),cmp=require_cmp(),debug=require_debug(),SemVer=require_semver(),Range=require_range()});var require_range=__commonJS((exports,module)=>{var SPACE_CHARACTERS=/\s+/g;class Range{constructor(range,options){if(options=parseOptions(options),range instanceof Range)if(range.loose===!!options.loose&&range.includePrerelease===!!options.includePrerelease)return range;else return new Range(range.raw,options);if(range instanceof Comparator)return this.raw=range.value,this.set=[[range]],this.formatted=void 0,this;if(this.options=options,this.loose=!!options.loose,this.includePrerelease=!!options.includePrerelease,this.raw=range.trim().replace(SPACE_CHARACTERS," "),this.set=this.raw.split("||").map((r)=>this.parseRange(r.trim())).filter((c)=>c.length),!this.set.length)throw TypeError(`Invalid SemVer Range: ${this.raw}`);if(this.set.length>1){let first=this.set[0];if(this.set=this.set.filter((c)=>!isNullSet(c[0])),this.set.length===0)this.set=[first];else if(this.set.length>1){for(let c of this.set)if(c.length===1&&isAny(c[0])){this.set=[c];break}}}this.formatted=void 0}get range(){if(this.formatted===void 0){this.formatted="";for(let i=0;i<this.set.length;i++){if(i>0)this.formatted+="||";let comps=this.set[i];for(let k=0;k<comps.length;k++){if(k>0)this.formatted+=" ";this.formatted+=comps[k].toString().trim()}}}return this.formatted}format(){return this.range}toString(){return this.range}parseRange(range){let memoKey=((this.options.includePrerelease&&FLAG_INCLUDE_PRERELEASE)|(this.options.loose&&FLAG_LOOSE))+":"+range,cached=cache.get(memoKey);if(cached)return cached;let loose=this.options.loose,hr=loose?re[t3.HYPHENRANGELOOSE]:re[t3.HYPHENRANGE];range=range.replace(hr,hyphenReplace(this.options.includePrerelease)),debug("hyphen replace",range),range=range.replace(re[t3.COMPARATORTRIM],comparatorTrimReplace),debug("comparator trim",range),range=range.replace(re[t3.TILDETRIM],tildeTrimReplace),debug("tilde trim",range),range=range.replace(re[t3.CARETTRIM],caretTrimReplace),debug("caret trim",range);let rangeList=range.split(" ").map((comp)=>parseComparator(comp,this.options)).join(" ").split(/\s+/).map((comp)=>replaceGTE0(comp,this.options));if(loose)rangeList=rangeList.filter((comp)=>{return debug("loose invalid filter",comp,this.options),!!comp.match(re[t3.COMPARATORLOOSE])});debug("range list",rangeList);let rangeMap=new Map,comparators=rangeList.map((comp)=>new Comparator(comp,this.options));for(let comp of comparators){if(isNullSet(comp))return[comp];rangeMap.set(comp.value,comp)}if(rangeMap.size>1&&rangeMap.has(""))rangeMap.delete("");let result=[...rangeMap.values()];return cache.set(memoKey,result),result}intersects(range,options){if(!(range instanceof Range))throw TypeError("a Range is required");return this.set.some((thisComparators)=>{return isSatisfiable(thisComparators,options)&&range.set.some((rangeComparators)=>{return isSatisfiable(rangeComparators,options)&&thisComparators.every((thisComparator)=>{return rangeComparators.every((rangeComparator)=>{return thisComparator.intersects(rangeComparator,options)})})})})}test(version){if(!version)return!1;if(typeof version==="string")try{version=new SemVer(version,this.options)}catch(er){return!1}for(let i=0;i<this.set.length;i++)if(testSet(this.set[i],version,this.options))return!0;return!1}}module.exports=Range;var LRU=require_lrucache(),cache=new LRU,parseOptions=require_parse_options(),Comparator=require_comparator(),debug=require_debug(),SemVer=require_semver(),{safeRe:re,t:t3,comparatorTrimReplace,tildeTrimReplace,caretTrimReplace}=require_re(),{FLAG_INCLUDE_PRERELEASE,FLAG_LOOSE}=require_constants2(),isNullSet=(c)=>c.value==="<0.0.0-0",isAny=(c)=>c.value==="",isSatisfiable=(comparators,options)=>{let result=!0,remainingComparators=comparators.slice(),testComparator=remainingComparators.pop();while(result&&remainingComparators.length)result=remainingComparators.every((otherComparator)=>{return testComparator.intersects(otherComparator,options)}),testComparator=remainingComparators.pop();return result},parseComparator=(comp,options)=>{return comp=comp.replace(re[t3.BUILD],""),debug("comp",comp,options),comp=replaceCarets(comp,options),debug("caret",comp),comp=replaceTildes(comp,options),debug("tildes",comp),comp=replaceXRanges(comp,options),debug("xrange",comp),comp=replaceStars(comp,options),debug("stars",comp),comp},isX=(id)=>!id||id.toLowerCase()==="x"||id==="*",replaceTildes=(comp,options)=>{return comp.trim().split(/\s+/).map((c)=>replaceTilde(c,options)).join(" ")},replaceTilde=(comp,options)=>{let r=options.loose?re[t3.TILDELOOSE]:re[t3.TILDE];return comp.replace(r,(_,M,m,p,pr)=>{debug("tilde",comp,_,M,m,p,pr);let ret;if(isX(M))ret="";else if(isX(m))ret=`>=${M}.0.0 <${+M+1}.0.0-0`;else if(isX(p))ret=`>=${M}.${m}.0 <${M}.${+m+1}.0-0`;else if(pr)debug("replaceTilde pr",pr),ret=`>=${M}.${m}.${p}-${pr} <${M}.${+m+1}.0-0`;else ret=`>=${M}.${m}.${p} <${M}.${+m+1}.0-0`;return debug("tilde return",ret),ret})},replaceCarets=(comp,options)=>{return comp.trim().split(/\s+/).map((c)=>replaceCaret(c,options)).join(" ")},replaceCaret=(comp,options)=>{debug("caret",comp,options);let r=options.loose?re[t3.CARETLOOSE]:re[t3.CARET],z=options.includePrerelease?"-0":"";return comp.replace(r,(_,M,m,p,pr)=>{debug("caret",comp,_,M,m,p,pr);let ret;if(isX(M))ret="";else if(isX(m))ret=`>=${M}.0.0${z} <${+M+1}.0.0-0`;else if(isX(p))if(M==="0")ret=`>=${M}.${m}.0${z} <${M}.${+m+1}.0-0`;else ret=`>=${M}.${m}.0${z} <${+M+1}.0.0-0`;else if(pr)if(debug("replaceCaret pr",pr),M==="0")if(m==="0")ret=`>=${M}.${m}.${p}-${pr} <${M}.${m}.${+p+1}-0`;else ret=`>=${M}.${m}.${p}-${pr} <${M}.${+m+1}.0-0`;else ret=`>=${M}.${m}.${p}-${pr} <${+M+1}.0.0-0`;else if(debug("no pr"),M==="0")if(m==="0")ret=`>=${M}.${m}.${p}${z} <${M}.${m}.${+p+1}-0`;else ret=`>=${M}.${m}.${p}${z} <${M}.${+m+1}.0-0`;else ret=`>=${M}.${m}.${p} <${+M+1}.0.0-0`;return debug("caret return",ret),ret})},replaceXRanges=(comp,options)=>{return debug("replaceXRanges",comp,options),comp.split(/\s+/).map((c)=>replaceXRange(c,options)).join(" ")},replaceXRange=(comp,options)=>{comp=comp.trim();let r=options.loose?re[t3.XRANGELOOSE]:re[t3.XRANGE];return comp.replace(r,(ret,gtlt,M,m,p,pr)=>{debug("xRange",comp,ret,gtlt,M,m,p,pr);let xM=isX(M),xm=xM||isX(m),xp=xm||isX(p),anyX=xp;if(gtlt==="="&&anyX)gtlt="";if(pr=options.includePrerelease?"-0":"",xM)if(gtlt===">"||gtlt==="<")ret="<0.0.0-0";else ret="*";else if(gtlt&&anyX){if(xm)m=0;if(p=0,gtlt===">")if(gtlt=">=",xm)M=+M+1,m=0,p=0;else m=+m+1,p=0;else if(gtlt==="<=")if(gtlt="<",xm)M=+M+1;else m=+m+1;if(gtlt==="<")pr="-0";ret=`${gtlt+M}.${m}.${p}${pr}`}else if(xm)ret=`>=${M}.0.0${pr} <${+M+1}.0.0-0`;else if(xp)ret=`>=${M}.${m}.0${pr} <${M}.${+m+1}.0-0`;return debug("xRange return",ret),ret})},replaceStars=(comp,options)=>{return debug("replaceStars",comp,options),comp.trim().replace(re[t3.STAR],"")},replaceGTE0=(comp,options)=>{return debug("replaceGTE0",comp,options),comp.trim().replace(re[options.includePrerelease?t3.GTE0PRE:t3.GTE0],"")},hyphenReplace=(incPr)=>($0,from,fM,fm,fp,fpr,fb,to,tM,tm,tp,tpr)=>{if(isX(fM))from="";else if(isX(fm))from=`>=${fM}.0.0${incPr?"-0":""}`;else if(isX(fp))from=`>=${fM}.${fm}.0${incPr?"-0":""}`;else if(fpr)from=`>=${from}`;else from=`>=${from}${incPr?"-0":""}`;if(isX(tM))to="";else if(isX(tm))to=`<${+tM+1}.0.0-0`;else if(isX(tp))to=`<${tM}.${+tm+1}.0-0`;else if(tpr)to=`<=${tM}.${tm}.${tp}-${tpr}`;else if(incPr)to=`<${tM}.${tm}.${+tp+1}-0`;else to=`<=${to}`;return`${from} ${to}`.trim()},testSet=(set,version,options)=>{for(let i=0;i<set.length;i++)if(!set[i].test(version))return!1;if(version.prerelease.length&&!options.includePrerelease){for(let i=0;i<set.length;i++){if(debug(set[i].semver),set[i].semver===Comparator.ANY)continue;if(set[i].semver.prerelease.length>0){let allowed=set[i].semver;if(allowed.major===version.major&&allowed.minor===version.minor&&allowed.patch===version.patch)return!0}}return!1}return!0}});var require_satisfies=__commonJS((exports,module)=>{var Range=require_range(),satisfies=(version,range,options)=>{try{range=new Range(range,options)}catch(er){return!1}return range.test(version)};module.exports=satisfies});var require_package=__commonJS((exports,module)=>{module.exports={name:"sharp",description:"High performance Node.js image processing, the fastest module to resize JPEG, PNG, WebP, GIF, AVIF and TIFF images",version:"0.33.5",author:"Lovell Fuller <npm@lovell.info>",homepage:"https://sharp.pixelplumbing.com",contributors:["Pierre Inglebert <pierre.inglebert@gmail.com>","Jonathan Ong <jonathanrichardong@gmail.com>","Chanon Sajjamanochai <chanon.s@gmail.com>","Juliano Julio <julianojulio@gmail.com>","Daniel Gasienica <daniel@gasienica.ch>","Julian Walker <julian@fiftythree.com>","Amit Pitaru <pitaru.amit@gmail.com>","Brandon Aaron <hello.brandon@aaron.sh>","Andreas Lind <andreas@one.com>","Maurus Cuelenaere <mcuelenaere@gmail.com>","Linus Unneb\xE4ck <linus@folkdatorn.se>","Victor Mateevitsi <mvictoras@gmail.com>","Alaric Holloway <alaric.holloway@gmail.com>","Bernhard K. Weisshuhn <bkw@codingforce.com>","Chris Riley <criley@primedia.com>","David Carley <dacarley@gmail.com>","John Tobin <john@limelightmobileinc.com>","Kenton Gray <kentongray@gmail.com>","Felix B\xFCnemann <Felix.Buenemann@gmail.com>","Samy Al Zahrani <samyalzahrany@gmail.com>","Chintan Thakkar <lemnisk8@gmail.com>","F. Orlando Galashan <frulo@gmx.de>","Kleis Auke Wolthuizen <info@kleisauke.nl>","Matt Hirsch <mhirsch@media.mit.edu>","Matthias Thoemmes <thoemmes@gmail.com>","Patrick Paskaris <patrick@paskaris.gr>","J\xE9r\xE9my Lal <kapouer@melix.org>","Rahul Nanwani <r.nanwani@gmail.com>","Alice Monday <alice0meta@gmail.com>","Kristo Jorgenson <kristo.jorgenson@gmail.com>","YvesBos <yves_bos@outlook.com>","Guy Maliar <guy@tailorbrands.com>","Nicolas Coden <nicolas@ncoden.fr>","Matt Parrish <matt.r.parrish@gmail.com>","Marcel Bretschneider <marcel.bretschneider@gmail.com>","Matthew McEachen <matthew+github@mceachen.org>","Jarda Kot\u011B\u0161ovec <jarda.kotesovec@gmail.com>","Kenric D'Souza <kenric.dsouza@gmail.com>","Oleh Aleinyk <oleg.aleynik@gmail.com>","Marcel Bretschneider <marcel.bretschneider@gmail.com>","Andrea Bianco <andrea.bianco@unibas.ch>","Rik Heywood <rik@rik.org>","Thomas Parisot <hi@oncletom.io>","Nathan Graves <nathanrgraves+github@gmail.com>","Tom Lokhorst <tom@lokhorst.eu>","Espen Hovlandsdal <espen@hovlandsdal.com>","Sylvain Dumont <sylvain.dumont35@gmail.com>","Alun Davies <alun.owain.davies@googlemail.com>","Aidan Hoolachan <ajhoolachan21@gmail.com>","Axel Eirola <axel.eirola@iki.fi>","Freezy <freezy@xbmc.org>","Daiz <taneli.vatanen@gmail.com>","Julian Aubourg <j@ubourg.net>","Keith Belovay <keith@picthrive.com>","Michael B. Klein <mbklein@gmail.com>","Jordan Prudhomme <jordan@raboland.fr>","Ilya Ovdin <iovdin@gmail.com>","Andargor <andargor@yahoo.com>","Paul Neave <paul.neave@gmail.com>","Brendan Kennedy <brenwken@gmail.com>","Brychan Bennett-Odlum <git@brychan.io>","Edward Silverton <e.silverton@gmail.com>","Roman Malieiev <aromaleev@gmail.com>","Tomas Szabo <tomas.szabo@deftomat.com>","Robert O'Rourke <robert@o-rourke.org>","Guillermo Alfonso Varela Chouci\xF1o <guillevch@gmail.com>","Christian Flintrup <chr@gigahost.dk>","Manan Jadhav <manan@motionden.com>","Leon Radley <leon@radley.se>","alza54 <alza54@thiocod.in>","Jacob Smith <jacob@frende.me>","Michael Nutt <michael@nutt.im>","Brad Parham <baparham@gmail.com>","Taneli Vatanen <taneli.vatanen@gmail.com>","Joris Dugu\xE9 <zaruike10@gmail.com>","Chris Banks <christopher.bradley.banks@gmail.com>","Ompal Singh <ompal.hitm09@gmail.com>","Brodan <christopher.hranj@gmail.com>","Ankur Parihar <ankur.github@gmail.com>","Brahim Ait elhaj <brahima@gmail.com>","Mart Jansink <m.jansink@gmail.com>","Lachlan Newman <lachnewman007@gmail.com>","Dennis Beatty <dennis@dcbeatty.com>","Ingvar Stepanyan <me@rreverser.com>","Don Denton <don@happycollision.com>"],scripts:{install:"node install/check",clean:"rm -rf src/build/ .nyc_output/ coverage/ test/fixtures/output.*",test:"npm run test-lint && npm run test-unit && npm run test-licensing && npm run test-types","test-lint":"semistandard && cpplint","test-unit":"nyc --reporter=lcov --reporter=text --check-coverage --branches=100 mocha","test-licensing":'license-checker --production --summary --onlyAllow="Apache-2.0;BSD;ISC;LGPL-3.0-or-later;MIT"',"test-leak":"./test/leak/leak.sh","test-types":"tsd","package-from-local-build":"node npm/from-local-build","package-from-github-release":"node npm/from-github-release","docs-build":"node docs/build && node docs/search-index/build","docs-serve":"cd docs && npx serve","docs-publish":"cd docs && npx firebase-tools deploy --project pixelplumbing --only hosting:pixelplumbing-sharp"},type:"commonjs",main:"lib/index.js",types:"lib/index.d.ts",files:["install","lib","src/*.{cc,h,gyp}"],repository:{type:"git",url:"git://github.com/lovell/sharp.git"},keywords:["jpeg","png","webp","avif","tiff","gif","svg","jp2","dzi","image","resize","thumbnail","crop","embed","libvips","vips"],dependencies:{color:"^4.2.3","detect-libc":"^2.0.3",semver:"^7.6.3"},optionalDependencies:{"@img/sharp-darwin-arm64":"0.33.5","@img/sharp-darwin-x64":"0.33.5","@img/sharp-libvips-darwin-arm64":"1.0.4","@img/sharp-libvips-darwin-x64":"1.0.4","@img/sharp-libvips-linux-arm":"1.0.5","@img/sharp-libvips-linux-arm64":"1.0.4","@img/sharp-libvips-linux-s390x":"1.0.4","@img/sharp-libvips-linux-x64":"1.0.4","@img/sharp-libvips-linuxmusl-arm64":"1.0.4","@img/sharp-libvips-linuxmusl-x64":"1.0.4","@img/sharp-linux-arm":"0.33.5","@img/sharp-linux-arm64":"0.33.5","@img/sharp-linux-s390x":"0.33.5","@img/sharp-linux-x64":"0.33.5","@img/sharp-linuxmusl-arm64":"0.33.5","@img/sharp-linuxmusl-x64":"0.33.5","@img/sharp-wasm32":"0.33.5","@img/sharp-win32-ia32":"0.33.5","@img/sharp-win32-x64":"0.33.5"},devDependencies:{"@emnapi/runtime":"^1.2.0","@img/sharp-libvips-dev":"1.0.4","@img/sharp-libvips-dev-wasm32":"1.0.5","@img/sharp-libvips-win32-ia32":"1.0.4","@img/sharp-libvips-win32-x64":"1.0.4","@types/node":"*",async:"^3.2.5",cc:"^3.0.1",emnapi:"^1.2.0","exif-reader":"^2.0.1","extract-zip":"^2.0.1",icc:"^3.0.0","jsdoc-to-markdown":"^8.0.3","license-checker":"^25.0.1",mocha:"^10.7.3","node-addon-api":"^8.1.0",nyc:"^17.0.0",prebuild:"^13.0.1",semistandard:"^17.0.0","tar-fs":"^3.0.6",tsd:"^0.31.1"},license:"Apache-2.0",engines:{node:"^18.17.0 || ^20.3.0 || >=21.0.0"},config:{libvips:">=8.15.3"},funding:{url:"https://opencollective.com/libvips"},binary:{napi_versions:[9]},semistandard:{env:["mocha"]},cc:{linelength:"120",filter:["build/include"]},nyc:{include:["lib"]},tsd:{directory:"test/types/"}}});var require_libvips=__commonJS((exports,module)=>{var{spawnSync}=__require("child_process"),{createHash:createHash2}=__require("crypto"),semverCoerce=require_coerce(),semverGreaterThanOrEqualTo=require_gte(),semverSatisfies=require_satisfies(),detectLibc=require_detect_libc(),{config,engines,optionalDependencies}=require_package(),minimumLibvipsVersionLabelled=process.env.npm_package_config_libvips||config.libvips,minimumLibvipsVersion=semverCoerce(minimumLibvipsVersionLabelled).version,prebuiltPlatforms=["darwin-arm64","darwin-x64","linux-arm","linux-arm64","linux-s390x","linux-x64","linuxmusl-arm64","linuxmusl-x64","win32-ia32","win32-x64"],spawnSyncOptions={encoding:"utf8",shell:!0},log4=(item)=>{if(item instanceof Error)console.error(`sharp: Installation error: ${item.message}`);else console.log(`sharp: ${item}`)},runtimeLibc=()=>detectLibc.isNonGlibcLinuxSync()?detectLibc.familySync():"",runtimePlatformArch=()=>`${process.platform}${runtimeLibc()}-${process.arch}`,buildPlatformArch=()=>{if(isEmscripten())return"wasm32";let{npm_config_arch,npm_config_platform,npm_config_libc}=process.env,libc=typeof npm_config_libc==="string"?npm_config_libc:runtimeLibc();return`${npm_config_platform||process.platform}${libc}-${npm_config_arch||process.arch}`},buildSharpLibvipsIncludeDir=()=>{try{return __require(`@img/sharp-libvips-dev-${buildPlatformArch()}/include`)}catch{try{return (()=>{throw new Error("Cannot require module "+"@img/sharp-libvips-dev/include");})()}catch{}}return""},buildSharpLibvipsCPlusPlusDir=()=>{try{return (()=>{throw new Error("Cannot require module "+"@img/sharp-libvips-dev/cplusplus");})()}catch{}return""},buildSharpLibvipsLibDir=()=>{try{return __require(`@img/sharp-libvips-dev-${buildPlatformArch()}/lib`)}catch{try{return __require(`@img/sharp-libvips-${buildPlatformArch()}/lib`)}catch{}}return""},isUnsupportedNodeRuntime=()=>{if(process.release?.name==="node"&&process.versions){if(!semverSatisfies(process.versions.node,engines.node))return{found:process.versions.node,expected:engines.node}}},isEmscripten=()=>{let{CC}=process.env;return Boolean(CC&&CC.endsWith("/emcc"))},isRosetta=()=>{if(process.platform==="darwin"&&process.arch==="x64")return(spawnSync("sysctl sysctl.proc_translated",spawnSyncOptions).stdout||"").trim()==="sysctl.proc_translated: 1";return!1},sha5122=(s)=>createHash2("sha512").update(s).digest("hex"),yarnLocator=()=>{try{let identHash=sha5122(`imgsharp-libvips-${buildPlatformArch()}`),npmVersion=semverCoerce(optionalDependencies[`@img/sharp-libvips-${buildPlatformArch()}`]).version;return sha5122(`${identHash}npm:${npmVersion}`).slice(0,10)}catch{}return""},spawnRebuild=()=>spawnSync(`node-gyp rebuild --directory=src ${isEmscripten()?"--nodedir=emscripten":""}`,{...spawnSyncOptions,stdio:"inherit"}).status,globalLibvipsVersion=()=>{if(process.platform!=="win32")return(spawnSync("pkg-config --modversion vips-cpp",{...spawnSyncOptions,env:{...process.env,PKG_CONFIG_PATH:pkgConfigPath()}}).stdout||"").trim();else return""},pkgConfigPath=()=>{if(process.platform!=="win32")return[(spawnSync('which brew >/dev/null 2>&1 && brew environment --plain | grep PKG_CONFIG_LIBDIR | cut -d" " -f2',spawnSyncOptions).stdout||"").trim(),process.env.PKG_CONFIG_PATH,"/usr/local/lib/pkgconfig","/usr/lib/pkgconfig","/usr/local/libdata/pkgconfig","/usr/libdata/pkgconfig"].filter(Boolean).join(":");else return""},skipSearch=(status,reason,logger2)=>{if(logger2)logger2(`Detected ${reason}, skipping search for globally-installed libvips`);return status},useGlobalLibvips=(logger2)=>{if(Boolean(process.env.SHARP_IGNORE_GLOBAL_LIBVIPS)===!0)return skipSearch(!1,"SHARP_IGNORE_GLOBAL_LIBVIPS",logger2);if(Boolean(process.env.SHARP_FORCE_GLOBAL_LIBVIPS)===!0)return skipSearch(!0,"SHARP_FORCE_GLOBAL_LIBVIPS",logger2);if(isRosetta())return skipSearch(!1,"Rosetta",logger2);let globalVipsVersion=globalLibvipsVersion();return!!globalVipsVersion&&semverGreaterThanOrEqualTo(globalVipsVersion,minimumLibvipsVersion)};module.exports={minimumLibvipsVersion,prebuiltPlatforms,buildPlatformArch,buildSharpLibvipsIncludeDir,buildSharpLibvipsCPlusPlusDir,buildSharpLibvipsLibDir,isUnsupportedNodeRuntime,runtimePlatformArch,log:log4,yarnLocator,spawnRebuild,globalLibvipsVersion,pkgConfigPath,useGlobalLibvips}});var require_sharp=__commonJS((exports,module)=>{var{familySync,versionSync}=require_detect_libc(),{runtimePlatformArch,isUnsupportedNodeRuntime,prebuiltPlatforms,minimumLibvipsVersion}=require_libvips(),runtimePlatform=runtimePlatformArch(),paths=[`../src/build/Release/sharp-${runtimePlatform}.node`,"../src/build/Release/sharp-wasm32.node",`@img/sharp-${runtimePlatform}/sharp.node`,"@img/sharp-wasm32/sharp.node"],sharp,errors2=[];for(let path3 of paths)try{sharp=__require(path3);break}catch(err){errors2.push(err)}if(sharp)module.exports=sharp;else{let[isLinux,isMacOs,isWindows]=["linux","darwin","win32"].map((os3)=>runtimePlatform.startsWith(os3)),help=[`Could not load the "sharp" module using the ${runtimePlatform} runtime`];errors2.forEach((err)=>{if(err.code!=="MODULE_NOT_FOUND")help.push(`${err.code}: ${err.message}`)});let messages=errors2.map((err)=>err.message).join(" ");if(help.push("Possible solutions:"),isUnsupportedNodeRuntime()){let{found,expected}=isUnsupportedNodeRuntime();help.push("- Please upgrade Node.js:",` Found ${found}`,` Requires ${expected}`)}else if(prebuiltPlatforms.includes(runtimePlatform)){let[os3,cpu]=runtimePlatform.split("-"),libc=os3.endsWith("musl")?" --libc=musl":"";help.push("- Ensure optional dependencies can be installed:"," npm install --include=optional sharp","- Ensure your package manager supports multi-platform installation:"," See https://sharp.pixelplumbing.com/install#cross-platform","- Add platform-specific dependencies:",` npm install --os=${os3.replace("musl","")}${libc} --cpu=${cpu} sharp`)}else help.push(`- Manually install libvips >= ${minimumLibvipsVersion}`,"- Add experimental WebAssembly-based dependencies:"," npm install --cpu=wasm32 sharp"," npm install @img/sharp-wasm32");if(isLinux&&/(symbol not found|CXXABI_)/i.test(messages))try{let{config}=__require(`@img/sharp-libvips-${runtimePlatform}/package`),libcFound=`${familySync()} ${versionSync()}`,libcRequires=`${config.musl?"musl":"glibc"} ${config.musl||config.glibc}`;help.push("- Update your OS:",` Found ${libcFound}`,` Requires ${libcRequires}`)}catch(errEngines){}if(isLinux&&/\/snap\/core[0-9]{2}/.test(messages))help.push("- Remove the Node.js Snap, which does not support native modules"," snap remove node");if(isMacOs&&/Incompatible library version/.test(messages))help.push("- Update Homebrew:"," brew update && brew upgrade vips");if(errors2.some((err)=>err.code==="ERR_DLOPEN_DISABLED"))help.push("- Run Node.js without using the --no-addons flag");if(isWindows&&/The specified procedure could not be found/.test(messages))help.push("- Using the canvas package on Windows?"," See https://sharp.pixelplumbing.com/install#canvas-and-windows","- Check for outdated versions of sharp in the dependency tree:"," npm ls sharp");throw help.push("- Consult the installation documentation:"," See https://sharp.pixelplumbing.com/install"),Error(help.join(`
|
|
396
|
-
`))}});var require_constructor=__commonJS((exports,module)=>{var util=__require("util"),stream=__require("stream"),is2=require_is();require_sharp();var debuglog=util.debuglog("sharp"),Sharp=function(input,options){if(arguments.length===1&&!is2.defined(input))throw Error("Invalid input");if(!(this instanceof Sharp))return new Sharp(input,options);return stream.Duplex.call(this),this.options={topOffsetPre:-1,leftOffsetPre:-1,widthPre:-1,heightPre:-1,topOffsetPost:-1,leftOffsetPost:-1,widthPost:-1,heightPost:-1,width:-1,height:-1,canvas:"crop",position:0,resizeBackground:[0,0,0,255],useExifOrientation:!1,angle:0,rotationAngle:0,rotationBackground:[0,0,0,255],rotateBeforePreExtract:!1,flip:!1,flop:!1,extendTop:0,extendBottom:0,extendLeft:0,extendRight:0,extendBackground:[0,0,0,255],extendWith:"background",withoutEnlargement:!1,withoutReduction:!1,affineMatrix:[],affineBackground:[0,0,0,255],affineIdx:0,affineIdy:0,affineOdx:0,affineOdy:0,affineInterpolator:this.constructor.interpolators.bilinear,kernel:"lanczos3",fastShrinkOnLoad:!0,tint:[-1,0,0,0],flatten:!1,flattenBackground:[0,0,0],unflatten:!1,negate:!1,negateAlpha:!0,medianSize:0,blurSigma:0,precision:"integer",minAmpl:0.2,sharpenSigma:0,sharpenM1:1,sharpenM2:2,sharpenX1:2,sharpenY2:10,sharpenY3:20,threshold:0,thresholdGrayscale:!0,trimBackground:[],trimThreshold:-1,trimLineArt:!1,gamma:0,gammaOut:0,greyscale:!1,normalise:!1,normaliseLower:1,normaliseUpper:99,claheWidth:0,claheHeight:0,claheMaxSlope:3,brightness:1,saturation:1,hue:0,lightness:0,booleanBufferIn:null,booleanFileIn:"",joinChannelIn:[],extractChannel:-1,removeAlpha:!1,ensureAlpha:-1,colourspace:"srgb",colourspacePipeline:"last",composite:[],fileOut:"",formatOut:"input",streamOut:!1,keepMetadata:0,withMetadataOrientation:-1,withMetadataDensity:0,withIccProfile:"",withExif:{},withExifMerge:!0,resolveWithObject:!1,jpegQuality:80,jpegProgressive:!1,jpegChromaSubsampling:"4:2:0",jpegTrellisQuantisation:!1,jpegOvershootDeringing:!1,jpegOptimiseScans:!1,jpegOptimiseCoding:!0,jpegQuantisationTable:0,pngProgressive:!1,pngCompressionLevel:6,pngAdaptiveFiltering:!1,pngPalette:!1,pngQuality:100,pngEffort:7,pngBitdepth:8,pngDither:1,jp2Quality:80,jp2TileHeight:512,jp2TileWidth:512,jp2Lossless:!1,jp2ChromaSubsampling:"4:4:4",webpQuality:80,webpAlphaQuality:100,webpLossless:!1,webpNearLossless:!1,webpSmartSubsample:!1,webpPreset:"default",webpEffort:4,webpMinSize:!1,webpMixed:!1,gifBitdepth:8,gifEffort:7,gifDither:1,gifInterFrameMaxError:0,gifInterPaletteMaxError:3,gifReuse:!0,gifProgressive:!1,tiffQuality:80,tiffCompression:"jpeg",tiffPredictor:"horizontal",tiffPyramid:!1,tiffMiniswhite:!1,tiffBitdepth:8,tiffTile:!1,tiffTileHeight:256,tiffTileWidth:256,tiffXres:1,tiffYres:1,tiffResolutionUnit:"inch",heifQuality:50,heifLossless:!1,heifCompression:"av1",heifEffort:4,heifChromaSubsampling:"4:4:4",heifBitdepth:8,jxlDistance:1,jxlDecodingTier:0,jxlEffort:7,jxlLossless:!1,rawDepth:"uchar",tileSize:256,tileOverlap:0,tileContainer:"fs",tileLayout:"dz",tileFormat:"last",tileDepth:"last",tileAngle:0,tileSkipBlanks:-1,tileBackground:[255,255,255,255],tileCentre:!1,tileId:"https://example.com/iiif",tileBasename:"",timeoutSeconds:0,linearA:[],linearB:[],debuglog:(warning)=>{this.emit("warning",warning),debuglog(warning)},queueListener:function(queueLength){Sharp.queue.emit("change",queueLength)}},this.options.input=this._createInputDescriptor(input,options,{allowStream:!0}),this};Object.setPrototypeOf(Sharp.prototype,stream.Duplex.prototype);Object.setPrototypeOf(Sharp,stream.Duplex);function clone(){let clone2=this.constructor.call(),{debuglog:debuglog2,queueListener,...options}=this.options;if(clone2.options=structuredClone(options),clone2.options.debuglog=debuglog2,clone2.options.queueListener=queueListener,this._isStreamInput())this.on("finish",()=>{this._flattenBufferIn(),clone2.options.input.buffer=this.options.input.buffer,clone2.emit("finish")});return clone2}Object.assign(Sharp.prototype,{clone});module.exports=Sharp});var require_color_name=__commonJS((exports,module)=>{module.exports={aliceblue:[240,248,255],antiquewhite:[250,235,215],aqua:[0,255,255],aquamarine:[127,255,212],azure:[240,255,255],beige:[245,245,220],bisque:[255,228,196],black:[0,0,0],blanchedalmond:[255,235,205],blue:[0,0,255],blueviolet:[138,43,226],brown:[165,42,42],burlywood:[222,184,135],cadetblue:[95,158,160],chartreuse:[127,255,0],chocolate:[210,105,30],coral:[255,127,80],cornflowerblue:[100,149,237],cornsilk:[255,248,220],crimson:[220,20,60],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgoldenrod:[184,134,11],darkgray:[169,169,169],darkgreen:[0,100,0],darkgrey:[169,169,169],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkseagreen:[143,188,143],darkslateblue:[72,61,139],darkslategray:[47,79,79],darkslategrey:[47,79,79],darkturquoise:[0,206,209],darkviolet:[148,0,211],deeppink:[255,20,147],deepskyblue:[0,191,255],dimgray:[105,105,105],dimgrey:[105,105,105],dodgerblue:[30,144,255],firebrick:[178,34,34],floralwhite:[255,250,240],forestgreen:[34,139,34],fuchsia:[255,0,255],gainsboro:[220,220,220],ghostwhite:[248,248,255],gold:[255,215,0],goldenrod:[218,165,32],gray:[128,128,128],green:[0,128,0],greenyellow:[173,255,47],grey:[128,128,128],honeydew:[240,255,240],hotpink:[255,105,180],indianred:[205,92,92],indigo:[75,0,130],ivory:[255,255,240],khaki:[240,230,140],lavender:[230,230,250],lavenderblush:[255,240,245],lawngreen:[124,252,0],lemonchiffon:[255,250,205],lightblue:[173,216,230],lightcoral:[240,128,128],lightcyan:[224,255,255],lightgoldenrodyellow:[250,250,210],lightgray:[211,211,211],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightsalmon:[255,160,122],lightseagreen:[32,178,170],lightskyblue:[135,206,250],lightslategray:[119,136,153],lightslategrey:[119,136,153],lightsteelblue:[176,196,222],lightyellow:[255,255,224],lime:[0,255,0],limegreen:[50,205,50],linen:[250,240,230],magenta:[255,0,255],maroon:[128,0,0],mediumaquamarine:[102,205,170],mediumblue:[0,0,205],mediumorchid:[186,85,211],mediumpurple:[147,112,219],mediumseagreen:[60,179,113],mediumslateblue:[123,104,238],mediumspringgreen:[0,250,154],mediumturquoise:[72,209,204],mediumvioletred:[199,21,133],midnightblue:[25,25,112],mintcream:[245,255,250],mistyrose:[255,228,225],moccasin:[255,228,181],navajowhite:[255,222,173],navy:[0,0,128],oldlace:[253,245,230],olive:[128,128,0],olivedrab:[107,142,35],orange:[255,165,0],orangered:[255,69,0],orchid:[218,112,214],palegoldenrod:[238,232,170],palegreen:[152,251,152],paleturquoise:[175,238,238],palevioletred:[219,112,147],papayawhip:[255,239,213],peachpuff:[255,218,185],peru:[205,133,63],pink:[255,192,203],plum:[221,160,221],powderblue:[176,224,230],purple:[128,0,128],rebeccapurple:[102,51,153],red:[255,0,0],rosybrown:[188,143,143],royalblue:[65,105,225],saddlebrown:[139,69,19],salmon:[250,128,114],sandybrown:[244,164,96],seagreen:[46,139,87],seashell:[255,245,238],sienna:[160,82,45],silver:[192,192,192],skyblue:[135,206,235],slateblue:[106,90,205],slategray:[112,128,144],slategrey:[112,128,144],snow:[255,250,250],springgreen:[0,255,127],steelblue:[70,130,180],tan:[210,180,140],teal:[0,128,128],thistle:[216,191,216],tomato:[255,99,71],turquoise:[64,224,208],violet:[238,130,238],wheat:[245,222,179],white:[255,255,255],whitesmoke:[245,245,245],yellow:[255,255,0],yellowgreen:[154,205,50]}});var require_is_arrayish=__commonJS((exports,module)=>{module.exports=function(obj){if(!obj||typeof obj==="string")return!1;return obj instanceof Array||Array.isArray(obj)||obj.length>=0&&(obj.splice instanceof Function||Object.getOwnPropertyDescriptor(obj,obj.length-1)&&obj.constructor.name!=="String")}});var require_simple_swizzle=__commonJS((exports,module)=>{var isArrayish=require_is_arrayish(),concat4=Array.prototype.concat,slice2=Array.prototype.slice,swizzle=module.exports=function(args){var results=[];for(var i=0,len=args.length;i<len;i++){var arg=args[i];if(isArrayish(arg))results=concat4.call(results,slice2.call(arg));else results.push(arg)}return results};swizzle.wrap=function(fn){return function(){return fn(swizzle(arguments))}}});var require_color_string=__commonJS((exports,module)=>{var colorNames=require_color_name(),swizzle=require_simple_swizzle(),hasOwnProperty=Object.hasOwnProperty,reverseNames=Object.create(null);for(name2 in colorNames)if(hasOwnProperty.call(colorNames,name2))reverseNames[colorNames[name2]]=name2;var name2,cs=module.exports={to:{},get:{}};cs.get=function(string){var prefix=string.substring(0,3).toLowerCase(),val,model;switch(prefix){case"hsl":val=cs.get.hsl(string),model="hsl";break;case"hwb":val=cs.get.hwb(string),model="hwb";break;default:val=cs.get.rgb(string),model="rgb";break}if(!val)return null;return{model,value:val}};cs.get.rgb=function(string){if(!string)return null;var abbr=/^#([a-f0-9]{3,4})$/i,hex2=/^#([a-f0-9]{6})([a-f0-9]{2})?$/i,rgba=/^rgba?\(\s*([+-]?\d+)(?=[\s,])\s*(?:,\s*)?([+-]?\d+)(?=[\s,])\s*(?:,\s*)?([+-]?\d+)\s*(?:[,|\/]\s*([+-]?[\d\.]+)(%?)\s*)?\)$/,per=/^rgba?\(\s*([+-]?[\d\.]+)\%\s*,?\s*([+-]?[\d\.]+)\%\s*,?\s*([+-]?[\d\.]+)\%\s*(?:[,|\/]\s*([+-]?[\d\.]+)(%?)\s*)?\)$/,keyword=/^(\w+)$/,rgb=[0,0,0,1],match,i,hexAlpha;if(match=string.match(hex2)){hexAlpha=match[2],match=match[1];for(i=0;i<3;i++){var i2=i*2;rgb[i]=parseInt(match.slice(i2,i2+2),16)}if(hexAlpha)rgb[3]=parseInt(hexAlpha,16)/255}else if(match=string.match(abbr)){match=match[1],hexAlpha=match[3];for(i=0;i<3;i++)rgb[i]=parseInt(match[i]+match[i],16);if(hexAlpha)rgb[3]=parseInt(hexAlpha+hexAlpha,16)/255}else if(match=string.match(rgba)){for(i=0;i<3;i++)rgb[i]=parseInt(match[i+1],0);if(match[4])if(match[5])rgb[3]=parseFloat(match[4])*0.01;else rgb[3]=parseFloat(match[4])}else if(match=string.match(per)){for(i=0;i<3;i++)rgb[i]=Math.round(parseFloat(match[i+1])*2.55);if(match[4])if(match[5])rgb[3]=parseFloat(match[4])*0.01;else rgb[3]=parseFloat(match[4])}else if(match=string.match(keyword)){if(match[1]==="transparent")return[0,0,0,0];if(!hasOwnProperty.call(colorNames,match[1]))return null;return rgb=colorNames[match[1]],rgb[3]=1,rgb}else return null;for(i=0;i<3;i++)rgb[i]=clamp(rgb[i],0,255);return rgb[3]=clamp(rgb[3],0,1),rgb};cs.get.hsl=function(string){if(!string)return null;var hsl=/^hsla?\(\s*([+-]?(?:\d{0,3}\.)?\d+)(?:deg)?\s*,?\s*([+-]?[\d\.]+)%\s*,?\s*([+-]?[\d\.]+)%\s*(?:[,|\/]\s*([+-]?(?=\.\d|\d)(?:0|[1-9]\d*)?(?:\.\d*)?(?:[eE][+-]?\d+)?)\s*)?\)$/,match=string.match(hsl);if(match){var alpha=parseFloat(match[4]),h=(parseFloat(match[1])%360+360)%360,s=clamp(parseFloat(match[2]),0,100),l=clamp(parseFloat(match[3]),0,100),a=clamp(isNaN(alpha)?1:alpha,0,1);return[h,s,l,a]}return null};cs.get.hwb=function(string){if(!string)return null;var hwb=/^hwb\(\s*([+-]?\d{0,3}(?:\.\d+)?)(?:deg)?\s*,\s*([+-]?[\d\.]+)%\s*,\s*([+-]?[\d\.]+)%\s*(?:,\s*([+-]?(?=\.\d|\d)(?:0|[1-9]\d*)?(?:\.\d*)?(?:[eE][+-]?\d+)?)\s*)?\)$/,match=string.match(hwb);if(match){var alpha=parseFloat(match[4]),h=(parseFloat(match[1])%360+360)%360,w=clamp(parseFloat(match[2]),0,100),b=clamp(parseFloat(match[3]),0,100),a=clamp(isNaN(alpha)?1:alpha,0,1);return[h,w,b,a]}return null};cs.to.hex=function(){var rgba=swizzle(arguments);return"#"+hexDouble(rgba[0])+hexDouble(rgba[1])+hexDouble(rgba[2])+(rgba[3]<1?hexDouble(Math.round(rgba[3]*255)):"")};cs.to.rgb=function(){var rgba=swizzle(arguments);return rgba.length<4||rgba[3]===1?"rgb("+Math.round(rgba[0])+", "+Math.round(rgba[1])+", "+Math.round(rgba[2])+")":"rgba("+Math.round(rgba[0])+", "+Math.round(rgba[1])+", "+Math.round(rgba[2])+", "+rgba[3]+")"};cs.to.rgb.percent=function(){var rgba=swizzle(arguments),r=Math.round(rgba[0]/255*100),g=Math.round(rgba[1]/255*100),b=Math.round(rgba[2]/255*100);return rgba.length<4||rgba[3]===1?"rgb("+r+"%, "+g+"%, "+b+"%)":"rgba("+r+"%, "+g+"%, "+b+"%, "+rgba[3]+")"};cs.to.hsl=function(){var hsla=swizzle(arguments);return hsla.length<4||hsla[3]===1?"hsl("+hsla[0]+", "+hsla[1]+"%, "+hsla[2]+"%)":"hsla("+hsla[0]+", "+hsla[1]+"%, "+hsla[2]+"%, "+hsla[3]+")"};cs.to.hwb=function(){var hwba=swizzle(arguments),a="";if(hwba.length>=4&&hwba[3]!==1)a=", "+hwba[3];return"hwb("+hwba[0]+", "+hwba[1]+"%, "+hwba[2]+"%"+a+")"};cs.to.keyword=function(rgb){return reverseNames[rgb.slice(0,3)]};function clamp(num3,min,max){return Math.min(Math.max(min,num3),max)}function hexDouble(num3){var str4=Math.round(num3).toString(16).toUpperCase();return str4.length<2?"0"+str4:str4}});var require_conversions=__commonJS((exports,module)=>{var cssKeywords=require_color_name(),reverseKeywords={};for(let key2 of Object.keys(cssKeywords))reverseKeywords[cssKeywords[key2]]=key2;var convert2={rgb:{channels:3,labels:"rgb"},hsl:{channels:3,labels:"hsl"},hsv:{channels:3,labels:"hsv"},hwb:{channels:3,labels:"hwb"},cmyk:{channels:4,labels:"cmyk"},xyz:{channels:3,labels:"xyz"},lab:{channels:3,labels:"lab"},lch:{channels:3,labels:"lch"},hex:{channels:1,labels:["hex"]},keyword:{channels:1,labels:["keyword"]},ansi16:{channels:1,labels:["ansi16"]},ansi256:{channels:1,labels:["ansi256"]},hcg:{channels:3,labels:["h","c","g"]},apple:{channels:3,labels:["r16","g16","b16"]},gray:{channels:1,labels:["gray"]}};module.exports=convert2;for(let model of Object.keys(convert2)){if(!("channels"in convert2[model]))throw Error("missing channels property: "+model);if(!("labels"in convert2[model]))throw Error("missing channel labels property: "+model);if(convert2[model].labels.length!==convert2[model].channels)throw Error("channel and label counts mismatch: "+model);let{channels,labels}=convert2[model];delete convert2[model].channels,delete convert2[model].labels,Object.defineProperty(convert2[model],"channels",{value:channels}),Object.defineProperty(convert2[model],"labels",{value:labels})}convert2.rgb.hsl=function(rgb){let r=rgb[0]/255,g=rgb[1]/255,b=rgb[2]/255,min=Math.min(r,g,b),max=Math.max(r,g,b),delta=max-min,h,s;if(max===min)h=0;else if(r===max)h=(g-b)/delta;else if(g===max)h=2+(b-r)/delta;else if(b===max)h=4+(r-g)/delta;if(h=Math.min(h*60,360),h<0)h+=360;let l=(min+max)/2;if(max===min)s=0;else if(l<=0.5)s=delta/(max+min);else s=delta/(2-max-min);return[h,s*100,l*100]};convert2.rgb.hsv=function(rgb){let rdif,gdif,bdif,h,s,r=rgb[0]/255,g=rgb[1]/255,b=rgb[2]/255,v=Math.max(r,g,b),diff=v-Math.min(r,g,b),diffc=function(c){return(v-c)/6/diff+0.5};if(diff===0)h=0,s=0;else{if(s=diff/v,rdif=diffc(r),gdif=diffc(g),bdif=diffc(b),r===v)h=bdif-gdif;else if(g===v)h=0.3333333333333333+rdif-bdif;else if(b===v)h=0.6666666666666666+gdif-rdif;if(h<0)h+=1;else if(h>1)h-=1}return[h*360,s*100,v*100]};convert2.rgb.hwb=function(rgb){let r=rgb[0],g=rgb[1],b=rgb[2],h=convert2.rgb.hsl(rgb)[0],w=0.00392156862745098*Math.min(r,Math.min(g,b));return b=1-0.00392156862745098*Math.max(r,Math.max(g,b)),[h,w*100,b*100]};convert2.rgb.cmyk=function(rgb){let r=rgb[0]/255,g=rgb[1]/255,b=rgb[2]/255,k=Math.min(1-r,1-g,1-b),c=(1-r-k)/(1-k)||0,m=(1-g-k)/(1-k)||0,y=(1-b-k)/(1-k)||0;return[c*100,m*100,y*100,k*100]};function comparativeDistance(x,y){return(x[0]-y[0])**2+(x[1]-y[1])**2+(x[2]-y[2])**2}convert2.rgb.keyword=function(rgb){let reversed=reverseKeywords[rgb];if(reversed)return reversed;let currentClosestDistance=1/0,currentClosestKeyword;for(let keyword of Object.keys(cssKeywords)){let value=cssKeywords[keyword],distance=comparativeDistance(rgb,value);if(distance<currentClosestDistance)currentClosestDistance=distance,currentClosestKeyword=keyword}return currentClosestKeyword};convert2.keyword.rgb=function(keyword){return cssKeywords[keyword]};convert2.rgb.xyz=function(rgb){let r=rgb[0]/255,g=rgb[1]/255,b=rgb[2]/255;r=r>0.04045?((r+0.055)/1.055)**2.4:r/12.92,g=g>0.04045?((g+0.055)/1.055)**2.4:g/12.92,b=b>0.04045?((b+0.055)/1.055)**2.4:b/12.92;let x=r*0.4124+g*0.3576+b*0.1805,y=r*0.2126+g*0.7152+b*0.0722,z=r*0.0193+g*0.1192+b*0.9505;return[x*100,y*100,z*100]};convert2.rgb.lab=function(rgb){let xyz=convert2.rgb.xyz(rgb),x=xyz[0],y=xyz[1],z=xyz[2];x/=95.047,y/=100,z/=108.883,x=x>0.008856?x**0.3333333333333333:7.787*x+0.13793103448275862,y=y>0.008856?y**0.3333333333333333:7.787*y+0.13793103448275862,z=z>0.008856?z**0.3333333333333333:7.787*z+0.13793103448275862;let l=116*y-16,a=500*(x-y),b=200*(y-z);return[l,a,b]};convert2.hsl.rgb=function(hsl){let h=hsl[0]/360,s=hsl[1]/100,l=hsl[2]/100,t22,t3,val;if(s===0)return val=l*255,[val,val,val];if(l<0.5)t22=l*(1+s);else t22=l+s-l*s;let t1=2*l-t22,rgb=[0,0,0];for(let i=0;i<3;i++){if(t3=h+0.3333333333333333*-(i-1),t3<0)t3++;if(t3>1)t3--;if(6*t3<1)val=t1+(t22-t1)*6*t3;else if(2*t3<1)val=t22;else if(3*t3<2)val=t1+(t22-t1)*(0.6666666666666666-t3)*6;else val=t1;rgb[i]=val*255}return rgb};convert2.hsl.hsv=function(hsl){let h=hsl[0],s=hsl[1]/100,l=hsl[2]/100,smin=s,lmin=Math.max(l,0.01);l*=2,s*=l<=1?l:2-l,smin*=lmin<=1?lmin:2-lmin;let v=(l+s)/2,sv=l===0?2*smin/(lmin+smin):2*s/(l+s);return[h,sv*100,v*100]};convert2.hsv.rgb=function(hsv){let h=hsv[0]/60,s=hsv[1]/100,v=hsv[2]/100,hi=Math.floor(h)%6,f=h-Math.floor(h),p=255*v*(1-s),q=255*v*(1-s*f),t3=255*v*(1-s*(1-f));switch(v*=255,hi){case 0:return[v,t3,p];case 1:return[q,v,p];case 2:return[p,v,t3];case 3:return[p,q,v];case 4:return[t3,p,v];case 5:return[v,p,q]}};convert2.hsv.hsl=function(hsv){let h=hsv[0],s=hsv[1]/100,v=hsv[2]/100,vmin=Math.max(v,0.01),sl,l;l=(2-s)*v;let lmin=(2-s)*vmin;return sl=s*vmin,sl/=lmin<=1?lmin:2-lmin,sl=sl||0,l/=2,[h,sl*100,l*100]};convert2.hwb.rgb=function(hwb){let h=hwb[0]/360,wh=hwb[1]/100,bl=hwb[2]/100,ratio=wh+bl,f;if(ratio>1)wh/=ratio,bl/=ratio;let i=Math.floor(6*h),v=1-bl;if(f=6*h-i,(i&1)!==0)f=1-f;let n=wh+f*(v-wh),r,g,b;switch(i){default:case 6:case 0:r=v,g=n,b=wh;break;case 1:r=n,g=v,b=wh;break;case 2:r=wh,g=v,b=n;break;case 3:r=wh,g=n,b=v;break;case 4:r=n,g=wh,b=v;break;case 5:r=v,g=wh,b=n;break}return[r*255,g*255,b*255]};convert2.cmyk.rgb=function(cmyk){let c=cmyk[0]/100,m=cmyk[1]/100,y=cmyk[2]/100,k=cmyk[3]/100,r=1-Math.min(1,c*(1-k)+k),g=1-Math.min(1,m*(1-k)+k),b=1-Math.min(1,y*(1-k)+k);return[r*255,g*255,b*255]};convert2.xyz.rgb=function(xyz){let x=xyz[0]/100,y=xyz[1]/100,z=xyz[2]/100,r,g,b;return r=x*3.2406+y*-1.5372+z*-0.4986,g=x*-0.9689+y*1.8758+z*0.0415,b=x*0.0557+y*-0.204+z*1.057,r=r>0.0031308?1.055*r**0.4166666666666667-0.055:r*12.92,g=g>0.0031308?1.055*g**0.4166666666666667-0.055:g*12.92,b=b>0.0031308?1.055*b**0.4166666666666667-0.055:b*12.92,r=Math.min(Math.max(0,r),1),g=Math.min(Math.max(0,g),1),b=Math.min(Math.max(0,b),1),[r*255,g*255,b*255]};convert2.xyz.lab=function(xyz){let x=xyz[0],y=xyz[1],z=xyz[2];x/=95.047,y/=100,z/=108.883,x=x>0.008856?x**0.3333333333333333:7.787*x+0.13793103448275862,y=y>0.008856?y**0.3333333333333333:7.787*y+0.13793103448275862,z=z>0.008856?z**0.3333333333333333:7.787*z+0.13793103448275862;let l=116*y-16,a=500*(x-y),b=200*(y-z);return[l,a,b]};convert2.lab.xyz=function(lab){let l=lab[0],a=lab[1],b=lab[2],x,y,z;y=(l+16)/116,x=a/500+y,z=y-b/200;let y2=y**3,x2=x**3,z2=z**3;return y=y2>0.008856?y2:(y-0.13793103448275862)/7.787,x=x2>0.008856?x2:(x-0.13793103448275862)/7.787,z=z2>0.008856?z2:(z-0.13793103448275862)/7.787,x*=95.047,y*=100,z*=108.883,[x,y,z]};convert2.lab.lch=function(lab){let l=lab[0],a=lab[1],b=lab[2],h;if(h=Math.atan2(b,a)*360/2/Math.PI,h<0)h+=360;let c=Math.sqrt(a*a+b*b);return[l,c,h]};convert2.lch.lab=function(lch){let l=lch[0],c=lch[1],hr=lch[2]/360*2*Math.PI,a=c*Math.cos(hr),b=c*Math.sin(hr);return[l,a,b]};convert2.rgb.ansi16=function(args,saturation=null){let[r,g,b]=args,value=saturation===null?convert2.rgb.hsv(args)[2]:saturation;if(value=Math.round(value/50),value===0)return 30;let ansi=30+(Math.round(b/255)<<2|Math.round(g/255)<<1|Math.round(r/255));if(value===2)ansi+=60;return ansi};convert2.hsv.ansi16=function(args){return convert2.rgb.ansi16(convert2.hsv.rgb(args),args[2])};convert2.rgb.ansi256=function(args){let r=args[0],g=args[1],b=args[2];if(r===g&&g===b){if(r<8)return 16;if(r>248)return 231;return Math.round((r-8)/247*24)+232}return 16+36*Math.round(r/255*5)+6*Math.round(g/255*5)+Math.round(b/255*5)};convert2.ansi16.rgb=function(args){let color=args%10;if(color===0||color===7){if(args>50)color+=3.5;return color=color/10.5*255,[color,color,color]}let mult=(~~(args>50)+1)*0.5,r=(color&1)*mult*255,g=(color>>1&1)*mult*255,b=(color>>2&1)*mult*255;return[r,g,b]};convert2.ansi256.rgb=function(args){if(args>=232){let c=(args-232)*10+8;return[c,c,c]}args-=16;let rem,r=Math.floor(args/36)/5*255,g=Math.floor((rem=args%36)/6)/5*255,b=rem%6/5*255;return[r,g,b]};convert2.rgb.hex=function(args){let string=(((Math.round(args[0])&255)<<16)+((Math.round(args[1])&255)<<8)+(Math.round(args[2])&255)).toString(16).toUpperCase();return"000000".substring(string.length)+string};convert2.hex.rgb=function(args){let match=args.toString(16).match(/[a-f0-9]{6}|[a-f0-9]{3}/i);if(!match)return[0,0,0];let colorString=match[0];if(match[0].length===3)colorString=colorString.split("").map((char)=>{return char+char}).join("");let integer=parseInt(colorString,16),r=integer>>16&255,g=integer>>8&255,b=integer&255;return[r,g,b]};convert2.rgb.hcg=function(rgb){let r=rgb[0]/255,g=rgb[1]/255,b=rgb[2]/255,max=Math.max(Math.max(r,g),b),min=Math.min(Math.min(r,g),b),chroma=max-min,grayscale,hue;if(chroma<1)grayscale=min/(1-chroma);else grayscale=0;if(chroma<=0)hue=0;else if(max===r)hue=(g-b)/chroma%6;else if(max===g)hue=2+(b-r)/chroma;else hue=4+(r-g)/chroma;return hue/=6,hue%=1,[hue*360,chroma*100,grayscale*100]};convert2.hsl.hcg=function(hsl){let s=hsl[1]/100,l=hsl[2]/100,c=l<0.5?2*s*l:2*s*(1-l),f=0;if(c<1)f=(l-0.5*c)/(1-c);return[hsl[0],c*100,f*100]};convert2.hsv.hcg=function(hsv){let s=hsv[1]/100,v=hsv[2]/100,c=s*v,f=0;if(c<1)f=(v-c)/(1-c);return[hsv[0],c*100,f*100]};convert2.hcg.rgb=function(hcg){let h=hcg[0]/360,c=hcg[1]/100,g=hcg[2]/100;if(c===0)return[g*255,g*255,g*255];let pure=[0,0,0],hi=h%1*6,v=hi%1,w=1-v,mg=0;switch(Math.floor(hi)){case 0:pure[0]=1,pure[1]=v,pure[2]=0;break;case 1:pure[0]=w,pure[1]=1,pure[2]=0;break;case 2:pure[0]=0,pure[1]=1,pure[2]=v;break;case 3:pure[0]=0,pure[1]=w,pure[2]=1;break;case 4:pure[0]=v,pure[1]=0,pure[2]=1;break;default:pure[0]=1,pure[1]=0,pure[2]=w}return mg=(1-c)*g,[(c*pure[0]+mg)*255,(c*pure[1]+mg)*255,(c*pure[2]+mg)*255]};convert2.hcg.hsv=function(hcg){let c=hcg[1]/100,g=hcg[2]/100,v=c+g*(1-c),f=0;if(v>0)f=c/v;return[hcg[0],f*100,v*100]};convert2.hcg.hsl=function(hcg){let c=hcg[1]/100,l=hcg[2]/100*(1-c)+0.5*c,s=0;if(l>0&&l<0.5)s=c/(2*l);else if(l>=0.5&&l<1)s=c/(2*(1-l));return[hcg[0],s*100,l*100]};convert2.hcg.hwb=function(hcg){let c=hcg[1]/100,g=hcg[2]/100,v=c+g*(1-c);return[hcg[0],(v-c)*100,(1-v)*100]};convert2.hwb.hcg=function(hwb){let w=hwb[1]/100,v=1-hwb[2]/100,c=v-w,g=0;if(c<1)g=(v-c)/(1-c);return[hwb[0],c*100,g*100]};convert2.apple.rgb=function(apple){return[apple[0]/65535*255,apple[1]/65535*255,apple[2]/65535*255]};convert2.rgb.apple=function(rgb){return[rgb[0]/255*65535,rgb[1]/255*65535,rgb[2]/255*65535]};convert2.gray.rgb=function(args){return[args[0]/100*255,args[0]/100*255,args[0]/100*255]};convert2.gray.hsl=function(args){return[0,0,args[0]]};convert2.gray.hsv=convert2.gray.hsl;convert2.gray.hwb=function(gray){return[0,100,gray[0]]};convert2.gray.cmyk=function(gray){return[0,0,0,gray[0]]};convert2.gray.lab=function(gray){return[gray[0],0,0]};convert2.gray.hex=function(gray){let val=Math.round(gray[0]/100*255)&255,string=((val<<16)+(val<<8)+val).toString(16).toUpperCase();return"000000".substring(string.length)+string};convert2.rgb.gray=function(rgb){return[(rgb[0]+rgb[1]+rgb[2])/3/255*100]}});var require_route=__commonJS((exports,module)=>{var conversions=require_conversions();function buildGraph(){let graph={},models=Object.keys(conversions);for(let len=models.length,i=0;i<len;i++)graph[models[i]]={distance:-1,parent:null};return graph}function deriveBFS(fromModel){let graph=buildGraph(),queue=[fromModel];graph[fromModel].distance=0;while(queue.length){let current=queue.pop(),adjacents=Object.keys(conversions[current]);for(let len=adjacents.length,i=0;i<len;i++){let adjacent=adjacents[i],node=graph[adjacent];if(node.distance===-1)node.distance=graph[current].distance+1,node.parent=current,queue.unshift(adjacent)}}return graph}function link(from,to){return function(args){return to(from(args))}}function wrapConversion(toModel,graph){let path3=[graph[toModel].parent,toModel],fn=conversions[graph[toModel].parent][toModel],cur=graph[toModel].parent;while(graph[cur].parent)path3.unshift(graph[cur].parent),fn=link(conversions[graph[cur].parent][cur],fn),cur=graph[cur].parent;return fn.conversion=path3,fn}module.exports=function(fromModel){let graph=deriveBFS(fromModel),conversion={},models=Object.keys(graph);for(let len=models.length,i=0;i<len;i++){let toModel=models[i];if(graph[toModel].parent===null)continue;conversion[toModel]=wrapConversion(toModel,graph)}return conversion}});var require_color_convert=__commonJS((exports,module)=>{var conversions=require_conversions(),route=require_route(),convert2={},models=Object.keys(conversions);function wrapRaw(fn){let wrappedFn=function(...args){let arg0=args[0];if(arg0===void 0||arg0===null)return arg0;if(arg0.length>1)args=arg0;return fn(args)};if("conversion"in fn)wrappedFn.conversion=fn.conversion;return wrappedFn}function wrapRounded(fn){let wrappedFn=function(...args){let arg0=args[0];if(arg0===void 0||arg0===null)return arg0;if(arg0.length>1)args=arg0;let result=fn(args);if(typeof result==="object")for(let len=result.length,i=0;i<len;i++)result[i]=Math.round(result[i]);return result};if("conversion"in fn)wrappedFn.conversion=fn.conversion;return wrappedFn}models.forEach((fromModel)=>{convert2[fromModel]={},Object.defineProperty(convert2[fromModel],"channels",{value:conversions[fromModel].channels}),Object.defineProperty(convert2[fromModel],"labels",{value:conversions[fromModel].labels});let routes=route(fromModel);Object.keys(routes).forEach((toModel)=>{let fn=routes[toModel];convert2[fromModel][toModel]=wrapRounded(fn),convert2[fromModel][toModel].raw=wrapRaw(fn)})});module.exports=convert2});var require_color=__commonJS((exports,module)=>{var colorString=require_color_string(),convert2=require_color_convert(),skippedModels=["keyword","gray","hex"],hashedModelKeys={};for(let model of Object.keys(convert2))hashedModelKeys[[...convert2[model].labels].sort().join("")]=model;var limiters={};function Color(object,model){if(!(this instanceof Color))return new Color(object,model);if(model&&model in skippedModels)model=null;if(model&&!(model in convert2))throw Error("Unknown model: "+model);let i,channels;if(object==null)this.model="rgb",this.color=[0,0,0],this.valpha=1;else if(object instanceof Color)this.model=object.model,this.color=[...object.color],this.valpha=object.valpha;else if(typeof object==="string"){let result=colorString.get(object);if(result===null)throw Error("Unable to parse color from string: "+object);this.model=result.model,channels=convert2[this.model].channels,this.color=result.value.slice(0,channels),this.valpha=typeof result.value[channels]==="number"?result.value[channels]:1}else if(object.length>0){this.model=model||"rgb",channels=convert2[this.model].channels;let newArray=Array.prototype.slice.call(object,0,channels);this.color=zeroArray(newArray,channels),this.valpha=typeof object[channels]==="number"?object[channels]:1}else if(typeof object==="number")this.model="rgb",this.color=[object>>16&255,object>>8&255,object&255],this.valpha=1;else{this.valpha=1;let keys=Object.keys(object);if("alpha"in object)keys.splice(keys.indexOf("alpha"),1),this.valpha=typeof object.alpha==="number"?object.alpha:0;let hashedKeys=keys.sort().join("");if(!(hashedKeys in hashedModelKeys))throw Error("Unable to parse color from object: "+JSON.stringify(object));this.model=hashedModelKeys[hashedKeys];let{labels}=convert2[this.model],color=[];for(i=0;i<labels.length;i++)color.push(object[labels[i]]);this.color=zeroArray(color)}if(limiters[this.model]){channels=convert2[this.model].channels;for(i=0;i<channels;i++){let limit=limiters[this.model][i];if(limit)this.color[i]=limit(this.color[i])}}if(this.valpha=Math.max(0,Math.min(1,this.valpha)),Object.freeze)Object.freeze(this)}Color.prototype={toString(){return this.string()},toJSON(){return this[this.model]()},string(places){let self2=this.model in colorString.to?this:this.rgb();self2=self2.round(typeof places==="number"?places:1);let args=self2.valpha===1?self2.color:[...self2.color,this.valpha];return colorString.to[self2.model](args)},percentString(places){let self2=this.rgb().round(typeof places==="number"?places:1),args=self2.valpha===1?self2.color:[...self2.color,this.valpha];return colorString.to.rgb.percent(args)},array(){return this.valpha===1?[...this.color]:[...this.color,this.valpha]},object(){let result={},{channels}=convert2[this.model],{labels}=convert2[this.model];for(let i=0;i<channels;i++)result[labels[i]]=this.color[i];if(this.valpha!==1)result.alpha=this.valpha;return result},unitArray(){let rgb=this.rgb().color;if(rgb[0]/=255,rgb[1]/=255,rgb[2]/=255,this.valpha!==1)rgb.push(this.valpha);return rgb},unitObject(){let rgb=this.rgb().object();if(rgb.r/=255,rgb.g/=255,rgb.b/=255,this.valpha!==1)rgb.alpha=this.valpha;return rgb},round(places){return places=Math.max(places||0,0),new Color([...this.color.map(roundToPlace(places)),this.valpha],this.model)},alpha(value){if(value!==void 0)return new Color([...this.color,Math.max(0,Math.min(1,value))],this.model);return this.valpha},red:getset("rgb",0,maxfn(255)),green:getset("rgb",1,maxfn(255)),blue:getset("rgb",2,maxfn(255)),hue:getset(["hsl","hsv","hsl","hwb","hcg"],0,(value)=>(value%360+360)%360),saturationl:getset("hsl",1,maxfn(100)),lightness:getset("hsl",2,maxfn(100)),saturationv:getset("hsv",1,maxfn(100)),value:getset("hsv",2,maxfn(100)),chroma:getset("hcg",1,maxfn(100)),gray:getset("hcg",2,maxfn(100)),white:getset("hwb",1,maxfn(100)),wblack:getset("hwb",2,maxfn(100)),cyan:getset("cmyk",0,maxfn(100)),magenta:getset("cmyk",1,maxfn(100)),yellow:getset("cmyk",2,maxfn(100)),black:getset("cmyk",3,maxfn(100)),x:getset("xyz",0,maxfn(95.047)),y:getset("xyz",1,maxfn(100)),z:getset("xyz",2,maxfn(108.833)),l:getset("lab",0,maxfn(100)),a:getset("lab",1),b:getset("lab",2),keyword(value){if(value!==void 0)return new Color(value);return convert2[this.model].keyword(this.color)},hex(value){if(value!==void 0)return new Color(value);return colorString.to.hex(this.rgb().round().color)},hexa(value){if(value!==void 0)return new Color(value);let rgbArray=this.rgb().round().color,alphaHex=Math.round(this.valpha*255).toString(16).toUpperCase();if(alphaHex.length===1)alphaHex="0"+alphaHex;return colorString.to.hex(rgbArray)+alphaHex},rgbNumber(){let rgb=this.rgb().color;return(rgb[0]&255)<<16|(rgb[1]&255)<<8|rgb[2]&255},luminosity(){let rgb=this.rgb().color,lum=[];for(let[i,element]of rgb.entries()){let chan=element/255;lum[i]=chan<=0.04045?chan/12.92:((chan+0.055)/1.055)**2.4}return 0.2126*lum[0]+0.7152*lum[1]+0.0722*lum[2]},contrast(color2){let lum1=this.luminosity(),lum2=color2.luminosity();if(lum1>lum2)return(lum1+0.05)/(lum2+0.05);return(lum2+0.05)/(lum1+0.05)},level(color2){let contrastRatio=this.contrast(color2);if(contrastRatio>=7)return"AAA";return contrastRatio>=4.5?"AA":""},isDark(){let rgb=this.rgb().color;return(rgb[0]*2126+rgb[1]*7152+rgb[2]*722)/1e4<128},isLight(){return!this.isDark()},negate(){let rgb=this.rgb();for(let i=0;i<3;i++)rgb.color[i]=255-rgb.color[i];return rgb},lighten(ratio){let hsl=this.hsl();return hsl.color[2]+=hsl.color[2]*ratio,hsl},darken(ratio){let hsl=this.hsl();return hsl.color[2]-=hsl.color[2]*ratio,hsl},saturate(ratio){let hsl=this.hsl();return hsl.color[1]+=hsl.color[1]*ratio,hsl},desaturate(ratio){let hsl=this.hsl();return hsl.color[1]-=hsl.color[1]*ratio,hsl},whiten(ratio){let hwb=this.hwb();return hwb.color[1]+=hwb.color[1]*ratio,hwb},blacken(ratio){let hwb=this.hwb();return hwb.color[2]+=hwb.color[2]*ratio,hwb},grayscale(){let rgb=this.rgb().color,value=rgb[0]*0.3+rgb[1]*0.59+rgb[2]*0.11;return Color.rgb(value,value,value)},fade(ratio){return this.alpha(this.valpha-this.valpha*ratio)},opaquer(ratio){return this.alpha(this.valpha+this.valpha*ratio)},rotate(degrees){let hsl=this.hsl(),hue=hsl.color[0];return hue=(hue+degrees)%360,hue=hue<0?360+hue:hue,hsl.color[0]=hue,hsl},mix(mixinColor,weight){if(!mixinColor||!mixinColor.rgb)throw Error('Argument to "mix" was not a Color instance, but rather an instance of '+typeof mixinColor);let color1=mixinColor.rgb(),color2=this.rgb(),p=weight===void 0?0.5:weight,w=2*p-1,a=color1.alpha()-color2.alpha(),w1=((w*a===-1?w:(w+a)/(1+w*a))+1)/2,w2=1-w1;return Color.rgb(w1*color1.red()+w2*color2.red(),w1*color1.green()+w2*color2.green(),w1*color1.blue()+w2*color2.blue(),color1.alpha()*p+color2.alpha()*(1-p))}};for(let model of Object.keys(convert2)){if(skippedModels.includes(model))continue;let{channels}=convert2[model];Color.prototype[model]=function(...args){if(this.model===model)return new Color(this);if(args.length>0)return new Color(args,model);return new Color([...assertArray(convert2[this.model][model].raw(this.color)),this.valpha],model)},Color[model]=function(...args){let color=args[0];if(typeof color==="number")color=zeroArray(args,channels);return new Color(color,model)}}function roundTo(number,places){return Number(number.toFixed(places))}function roundToPlace(places){return function(number){return roundTo(number,places)}}function getset(model,channel,modifier){model=Array.isArray(model)?model:[model];for(let m of model)(limiters[m]||(limiters[m]=[]))[channel]=modifier;return model=model[0],function(value){let result;if(value!==void 0){if(modifier)value=modifier(value);return result=this[model](),result.color[channel]=value,result}if(result=this[model]().color[channel],modifier)result=modifier(result);return result}}function maxfn(max){return function(v){return Math.max(0,Math.min(max,v))}}function assertArray(value){return Array.isArray(value)?value:[value]}function zeroArray(array,length){for(let i=0;i<length;i++)if(typeof array[i]!=="number")array[i]=0;return array}module.exports=Color});var require_input=__commonJS((exports,module)=>{var color=require_color(),is2=require_is(),sharp=require_sharp(),align={left:"low",center:"centre",centre:"centre",right:"high"};function _inputOptionsFromObject(obj){let{raw,density,limitInputPixels,ignoreIcc,unlimited,sequentialRead,failOn,failOnError,animated,page,pages,subifd}=obj;return[raw,density,limitInputPixels,ignoreIcc,unlimited,sequentialRead,failOn,failOnError,animated,page,pages,subifd].some(is2.defined)?{raw,density,limitInputPixels,ignoreIcc,unlimited,sequentialRead,failOn,failOnError,animated,page,pages,subifd}:void 0}function _createInputDescriptor(input,inputOptions,containerOptions){let inputDescriptor={failOn:"warning",limitInputPixels:Math.pow(16383,2),ignoreIcc:!1,unlimited:!1,sequentialRead:!0};if(is2.string(input))inputDescriptor.file=input;else if(is2.buffer(input)){if(input.length===0)throw Error("Input Buffer is empty");inputDescriptor.buffer=input}else if(is2.arrayBuffer(input)){if(input.byteLength===0)throw Error("Input bit Array is empty");inputDescriptor.buffer=Buffer.from(input,0,input.byteLength)}else if(is2.typedArray(input)){if(input.length===0)throw Error("Input Bit Array is empty");inputDescriptor.buffer=Buffer.from(input.buffer,input.byteOffset,input.byteLength)}else if(is2.plainObject(input)&&!is2.defined(inputOptions)){if(inputOptions=input,_inputOptionsFromObject(inputOptions))inputDescriptor.buffer=[]}else if(!is2.defined(input)&&!is2.defined(inputOptions)&&is2.object(containerOptions)&&containerOptions.allowStream)inputDescriptor.buffer=[];else throw Error(`Unsupported input '${input}' of type ${typeof input}${is2.defined(inputOptions)?` when also providing options of type ${typeof inputOptions}`:""}`);if(is2.object(inputOptions)){if(is2.defined(inputOptions.failOnError))if(is2.bool(inputOptions.failOnError))inputDescriptor.failOn=inputOptions.failOnError?"warning":"none";else throw is2.invalidParameterError("failOnError","boolean",inputOptions.failOnError);if(is2.defined(inputOptions.failOn))if(is2.string(inputOptions.failOn)&&is2.inArray(inputOptions.failOn,["none","truncated","error","warning"]))inputDescriptor.failOn=inputOptions.failOn;else throw is2.invalidParameterError("failOn","one of: none, truncated, error, warning",inputOptions.failOn);if(is2.defined(inputOptions.density))if(is2.inRange(inputOptions.density,1,1e5))inputDescriptor.density=inputOptions.density;else throw is2.invalidParameterError("density","number between 1 and 100000",inputOptions.density);if(is2.defined(inputOptions.ignoreIcc))if(is2.bool(inputOptions.ignoreIcc))inputDescriptor.ignoreIcc=inputOptions.ignoreIcc;else throw is2.invalidParameterError("ignoreIcc","boolean",inputOptions.ignoreIcc);if(is2.defined(inputOptions.limitInputPixels))if(is2.bool(inputOptions.limitInputPixels))inputDescriptor.limitInputPixels=inputOptions.limitInputPixels?Math.pow(16383,2):0;else if(is2.integer(inputOptions.limitInputPixels)&&is2.inRange(inputOptions.limitInputPixels,0,Number.MAX_SAFE_INTEGER))inputDescriptor.limitInputPixels=inputOptions.limitInputPixels;else throw is2.invalidParameterError("limitInputPixels","positive integer",inputOptions.limitInputPixels);if(is2.defined(inputOptions.unlimited))if(is2.bool(inputOptions.unlimited))inputDescriptor.unlimited=inputOptions.unlimited;else throw is2.invalidParameterError("unlimited","boolean",inputOptions.unlimited);if(is2.defined(inputOptions.sequentialRead))if(is2.bool(inputOptions.sequentialRead))inputDescriptor.sequentialRead=inputOptions.sequentialRead;else throw is2.invalidParameterError("sequentialRead","boolean",inputOptions.sequentialRead);if(is2.defined(inputOptions.raw))if(is2.object(inputOptions.raw)&&is2.integer(inputOptions.raw.width)&&inputOptions.raw.width>0&&is2.integer(inputOptions.raw.height)&&inputOptions.raw.height>0&&is2.integer(inputOptions.raw.channels)&&is2.inRange(inputOptions.raw.channels,1,4))switch(inputDescriptor.rawWidth=inputOptions.raw.width,inputDescriptor.rawHeight=inputOptions.raw.height,inputDescriptor.rawChannels=inputOptions.raw.channels,inputDescriptor.rawPremultiplied=!!inputOptions.raw.premultiplied,input.constructor){case Uint8Array:case Uint8ClampedArray:inputDescriptor.rawDepth="uchar";break;case Int8Array:inputDescriptor.rawDepth="char";break;case Uint16Array:inputDescriptor.rawDepth="ushort";break;case Int16Array:inputDescriptor.rawDepth="short";break;case Uint32Array:inputDescriptor.rawDepth="uint";break;case Int32Array:inputDescriptor.rawDepth="int";break;case Float32Array:inputDescriptor.rawDepth="float";break;case Float64Array:inputDescriptor.rawDepth="double";break;default:inputDescriptor.rawDepth="uchar";break}else throw Error("Expected width, height and channels for raw pixel input");if(is2.defined(inputOptions.animated))if(is2.bool(inputOptions.animated))inputDescriptor.pages=inputOptions.animated?-1:1;else throw is2.invalidParameterError("animated","boolean",inputOptions.animated);if(is2.defined(inputOptions.pages))if(is2.integer(inputOptions.pages)&&is2.inRange(inputOptions.pages,-1,1e5))inputDescriptor.pages=inputOptions.pages;else throw is2.invalidParameterError("pages","integer between -1 and 100000",inputOptions.pages);if(is2.defined(inputOptions.page))if(is2.integer(inputOptions.page)&&is2.inRange(inputOptions.page,0,1e5))inputDescriptor.page=inputOptions.page;else throw is2.invalidParameterError("page","integer between 0 and 100000",inputOptions.page);if(is2.defined(inputOptions.level))if(is2.integer(inputOptions.level)&&is2.inRange(inputOptions.level,0,256))inputDescriptor.level=inputOptions.level;else throw is2.invalidParameterError("level","integer between 0 and 256",inputOptions.level);if(is2.defined(inputOptions.subifd))if(is2.integer(inputOptions.subifd)&&is2.inRange(inputOptions.subifd,-1,1e5))inputDescriptor.subifd=inputOptions.subifd;else throw is2.invalidParameterError("subifd","integer between -1 and 100000",inputOptions.subifd);if(is2.defined(inputOptions.create))if(is2.object(inputOptions.create)&&is2.integer(inputOptions.create.width)&&inputOptions.create.width>0&&is2.integer(inputOptions.create.height)&&inputOptions.create.height>0&&is2.integer(inputOptions.create.channels)){if(inputDescriptor.createWidth=inputOptions.create.width,inputDescriptor.createHeight=inputOptions.create.height,inputDescriptor.createChannels=inputOptions.create.channels,is2.defined(inputOptions.create.noise)){if(!is2.object(inputOptions.create.noise))throw Error("Expected noise to be an object");if(!is2.inArray(inputOptions.create.noise.type,["gaussian"]))throw Error("Only gaussian noise is supported at the moment");if(!is2.inRange(inputOptions.create.channels,1,4))throw is2.invalidParameterError("create.channels","number between 1 and 4",inputOptions.create.channels);if(inputDescriptor.createNoiseType=inputOptions.create.noise.type,is2.number(inputOptions.create.noise.mean)&&is2.inRange(inputOptions.create.noise.mean,0,1e4))inputDescriptor.createNoiseMean=inputOptions.create.noise.mean;else throw is2.invalidParameterError("create.noise.mean","number between 0 and 10000",inputOptions.create.noise.mean);if(is2.number(inputOptions.create.noise.sigma)&&is2.inRange(inputOptions.create.noise.sigma,0,1e4))inputDescriptor.createNoiseSigma=inputOptions.create.noise.sigma;else throw is2.invalidParameterError("create.noise.sigma","number between 0 and 10000",inputOptions.create.noise.sigma)}else if(is2.defined(inputOptions.create.background)){if(!is2.inRange(inputOptions.create.channels,3,4))throw is2.invalidParameterError("create.channels","number between 3 and 4",inputOptions.create.channels);let background=color(inputOptions.create.background);inputDescriptor.createBackground=[background.red(),background.green(),background.blue(),Math.round(background.alpha()*255)]}else throw Error("Expected valid noise or background to create a new input image");delete inputDescriptor.buffer}else throw Error("Expected valid width, height and channels to create a new input image");if(is2.defined(inputOptions.text))if(is2.object(inputOptions.text)&&is2.string(inputOptions.text.text)){if(inputDescriptor.textValue=inputOptions.text.text,is2.defined(inputOptions.text.height)&&is2.defined(inputOptions.text.dpi))throw Error("Expected only one of dpi or height");if(is2.defined(inputOptions.text.font))if(is2.string(inputOptions.text.font))inputDescriptor.textFont=inputOptions.text.font;else throw is2.invalidParameterError("text.font","string",inputOptions.text.font);if(is2.defined(inputOptions.text.fontfile))if(is2.string(inputOptions.text.fontfile))inputDescriptor.textFontfile=inputOptions.text.fontfile;else throw is2.invalidParameterError("text.fontfile","string",inputOptions.text.fontfile);if(is2.defined(inputOptions.text.width))if(is2.integer(inputOptions.text.width)&&inputOptions.text.width>0)inputDescriptor.textWidth=inputOptions.text.width;else throw is2.invalidParameterError("text.width","positive integer",inputOptions.text.width);if(is2.defined(inputOptions.text.height))if(is2.integer(inputOptions.text.height)&&inputOptions.text.height>0)inputDescriptor.textHeight=inputOptions.text.height;else throw is2.invalidParameterError("text.height","positive integer",inputOptions.text.height);if(is2.defined(inputOptions.text.align))if(is2.string(inputOptions.text.align)&&is2.string(this.constructor.align[inputOptions.text.align]))inputDescriptor.textAlign=this.constructor.align[inputOptions.text.align];else throw is2.invalidParameterError("text.align","valid alignment",inputOptions.text.align);if(is2.defined(inputOptions.text.justify))if(is2.bool(inputOptions.text.justify))inputDescriptor.textJustify=inputOptions.text.justify;else throw is2.invalidParameterError("text.justify","boolean",inputOptions.text.justify);if(is2.defined(inputOptions.text.dpi))if(is2.integer(inputOptions.text.dpi)&&is2.inRange(inputOptions.text.dpi,1,1e6))inputDescriptor.textDpi=inputOptions.text.dpi;else throw is2.invalidParameterError("text.dpi","integer between 1 and 1000000",inputOptions.text.dpi);if(is2.defined(inputOptions.text.rgba))if(is2.bool(inputOptions.text.rgba))inputDescriptor.textRgba=inputOptions.text.rgba;else throw is2.invalidParameterError("text.rgba","bool",inputOptions.text.rgba);if(is2.defined(inputOptions.text.spacing))if(is2.integer(inputOptions.text.spacing)&&is2.inRange(inputOptions.text.spacing,-1e6,1e6))inputDescriptor.textSpacing=inputOptions.text.spacing;else throw is2.invalidParameterError("text.spacing","integer between -1000000 and 1000000",inputOptions.text.spacing);if(is2.defined(inputOptions.text.wrap))if(is2.string(inputOptions.text.wrap)&&is2.inArray(inputOptions.text.wrap,["word","char","word-char","none"]))inputDescriptor.textWrap=inputOptions.text.wrap;else throw is2.invalidParameterError("text.wrap","one of: word, char, word-char, none",inputOptions.text.wrap);delete inputDescriptor.buffer}else throw Error("Expected a valid string to create an image with text.")}else if(is2.defined(inputOptions))throw Error("Invalid input options "+inputOptions);return inputDescriptor}function _write(chunk,encoding,callback){if(Array.isArray(this.options.input.buffer))if(is2.buffer(chunk)){if(this.options.input.buffer.length===0)this.on("finish",()=>{this.streamInFinished=!0});this.options.input.buffer.push(chunk),callback()}else callback(Error("Non-Buffer data on Writable Stream"));else callback(Error("Unexpected data on Writable Stream"))}function _flattenBufferIn(){if(this._isStreamInput())this.options.input.buffer=Buffer.concat(this.options.input.buffer)}function _isStreamInput(){return Array.isArray(this.options.input.buffer)}function metadata(callback){let stack=Error();if(is2.fn(callback)){if(this._isStreamInput())this.on("finish",()=>{this._flattenBufferIn(),sharp.metadata(this.options,(err,metadata2)=>{if(err)callback(is2.nativeError(err,stack));else callback(null,metadata2)})});else sharp.metadata(this.options,(err,metadata2)=>{if(err)callback(is2.nativeError(err,stack));else callback(null,metadata2)});return this}else if(this._isStreamInput())return new Promise((resolve2,reject)=>{let finished=()=>{this._flattenBufferIn(),sharp.metadata(this.options,(err,metadata2)=>{if(err)reject(is2.nativeError(err,stack));else resolve2(metadata2)})};if(this.writableFinished)finished();else this.once("finish",finished)});else return new Promise((resolve2,reject)=>{sharp.metadata(this.options,(err,metadata2)=>{if(err)reject(is2.nativeError(err,stack));else resolve2(metadata2)})})}function stats(callback){let stack=Error();if(is2.fn(callback)){if(this._isStreamInput())this.on("finish",()=>{this._flattenBufferIn(),sharp.stats(this.options,(err,stats2)=>{if(err)callback(is2.nativeError(err,stack));else callback(null,stats2)})});else sharp.stats(this.options,(err,stats2)=>{if(err)callback(is2.nativeError(err,stack));else callback(null,stats2)});return this}else if(this._isStreamInput())return new Promise((resolve2,reject)=>{this.on("finish",function(){this._flattenBufferIn(),sharp.stats(this.options,(err,stats2)=>{if(err)reject(is2.nativeError(err,stack));else resolve2(stats2)})})});else return new Promise((resolve2,reject)=>{sharp.stats(this.options,(err,stats2)=>{if(err)reject(is2.nativeError(err,stack));else resolve2(stats2)})})}module.exports=function(Sharp){Object.assign(Sharp.prototype,{_inputOptionsFromObject,_createInputDescriptor,_write,_flattenBufferIn,_isStreamInput,metadata,stats}),Sharp.align=align}});var require_resize=__commonJS((exports,module)=>{var is2=require_is(),gravity={center:0,centre:0,north:1,east:2,south:3,west:4,northeast:5,southeast:6,southwest:7,northwest:8},position={top:1,right:2,bottom:3,left:4,"right top":5,"right bottom":6,"left bottom":7,"left top":8},extendWith={background:"background",copy:"copy",repeat:"repeat",mirror:"mirror"},strategy={entropy:16,attention:17},kernel={nearest:"nearest",linear:"linear",cubic:"cubic",mitchell:"mitchell",lanczos2:"lanczos2",lanczos3:"lanczos3"},fit={contain:"contain",cover:"cover",fill:"fill",inside:"inside",outside:"outside"},mapFitToCanvas={contain:"embed",cover:"crop",fill:"ignore_aspect",inside:"max",outside:"min"};function isRotationExpected(options){return options.angle%360!==0||options.useExifOrientation===!0||options.rotationAngle!==0}function isResizeExpected(options){return options.width!==-1||options.height!==-1}function resize(widthOrOptions,height,options){if(isResizeExpected(this.options))this.options.debuglog("ignoring previous resize options");if(this.options.widthPost!==-1)this.options.debuglog("operation order will be: extract, resize, extract");if(is2.defined(widthOrOptions))if(is2.object(widthOrOptions)&&!is2.defined(options))options=widthOrOptions;else if(is2.integer(widthOrOptions)&&widthOrOptions>0)this.options.width=widthOrOptions;else throw is2.invalidParameterError("width","positive integer",widthOrOptions);else this.options.width=-1;if(is2.defined(height))if(is2.integer(height)&&height>0)this.options.height=height;else throw is2.invalidParameterError("height","positive integer",height);else this.options.height=-1;if(is2.object(options)){if(is2.defined(options.width))if(is2.integer(options.width)&&options.width>0)this.options.width=options.width;else throw is2.invalidParameterError("width","positive integer",options.width);if(is2.defined(options.height))if(is2.integer(options.height)&&options.height>0)this.options.height=options.height;else throw is2.invalidParameterError("height","positive integer",options.height);if(is2.defined(options.fit)){let canvas=mapFitToCanvas[options.fit];if(is2.string(canvas))this.options.canvas=canvas;else throw is2.invalidParameterError("fit","valid fit",options.fit)}if(is2.defined(options.position)){let pos=is2.integer(options.position)?options.position:strategy[options.position]||position[options.position]||gravity[options.position];if(is2.integer(pos)&&(is2.inRange(pos,0,8)||is2.inRange(pos,16,17)))this.options.position=pos;else throw is2.invalidParameterError("position","valid position/gravity/strategy",options.position)}if(this._setBackgroundColourOption("resizeBackground",options.background),is2.defined(options.kernel))if(is2.string(kernel[options.kernel]))this.options.kernel=kernel[options.kernel];else throw is2.invalidParameterError("kernel","valid kernel name",options.kernel);if(is2.defined(options.withoutEnlargement))this._setBooleanOption("withoutEnlargement",options.withoutEnlargement);if(is2.defined(options.withoutReduction))this._setBooleanOption("withoutReduction",options.withoutReduction);if(is2.defined(options.fastShrinkOnLoad))this._setBooleanOption("fastShrinkOnLoad",options.fastShrinkOnLoad)}if(isRotationExpected(this.options)&&isResizeExpected(this.options))this.options.rotateBeforePreExtract=!0;return this}function extend(extend2){if(is2.integer(extend2)&&extend2>0)this.options.extendTop=extend2,this.options.extendBottom=extend2,this.options.extendLeft=extend2,this.options.extendRight=extend2;else if(is2.object(extend2)){if(is2.defined(extend2.top))if(is2.integer(extend2.top)&&extend2.top>=0)this.options.extendTop=extend2.top;else throw is2.invalidParameterError("top","positive integer",extend2.top);if(is2.defined(extend2.bottom))if(is2.integer(extend2.bottom)&&extend2.bottom>=0)this.options.extendBottom=extend2.bottom;else throw is2.invalidParameterError("bottom","positive integer",extend2.bottom);if(is2.defined(extend2.left))if(is2.integer(extend2.left)&&extend2.left>=0)this.options.extendLeft=extend2.left;else throw is2.invalidParameterError("left","positive integer",extend2.left);if(is2.defined(extend2.right))if(is2.integer(extend2.right)&&extend2.right>=0)this.options.extendRight=extend2.right;else throw is2.invalidParameterError("right","positive integer",extend2.right);if(this._setBackgroundColourOption("extendBackground",extend2.background),is2.defined(extend2.extendWith))if(is2.string(extendWith[extend2.extendWith]))this.options.extendWith=extendWith[extend2.extendWith];else throw is2.invalidParameterError("extendWith","one of: background, copy, repeat, mirror",extend2.extendWith)}else throw is2.invalidParameterError("extend","integer or object",extend2);return this}function extract(options){let suffix=isResizeExpected(this.options)||this.options.widthPre!==-1?"Post":"Pre";if(this.options[`width${suffix}`]!==-1)this.options.debuglog("ignoring previous extract options");if(["left","top","width","height"].forEach(function(name2){let value=options[name2];if(is2.integer(value)&&value>=0)this.options[name2+(name2==="left"||name2==="top"?"Offset":"")+suffix]=value;else throw is2.invalidParameterError(name2,"integer",value)},this),isRotationExpected(this.options)&&!isResizeExpected(this.options)){if(this.options.widthPre===-1||this.options.widthPost===-1)this.options.rotateBeforePreExtract=!0}return this}function trim(options){if(this.options.trimThreshold=10,is2.defined(options))if(is2.object(options)){if(is2.defined(options.background))this._setBackgroundColourOption("trimBackground",options.background);if(is2.defined(options.threshold))if(is2.number(options.threshold)&&options.threshold>=0)this.options.trimThreshold=options.threshold;else throw is2.invalidParameterError("threshold","positive number",options.threshold);if(is2.defined(options.lineArt))this._setBooleanOption("trimLineArt",options.lineArt)}else throw is2.invalidParameterError("trim","object",options);if(isRotationExpected(this.options))this.options.rotateBeforePreExtract=!0;return this}module.exports=function(Sharp){Object.assign(Sharp.prototype,{resize,extend,extract,trim}),Sharp.gravity=gravity,Sharp.strategy=strategy,Sharp.kernel=kernel,Sharp.fit=fit,Sharp.position=position}});var require_composite=__commonJS((exports,module)=>{var is2=require_is(),blend={clear:"clear",source:"source",over:"over",in:"in",out:"out",atop:"atop",dest:"dest","dest-over":"dest-over","dest-in":"dest-in","dest-out":"dest-out","dest-atop":"dest-atop",xor:"xor",add:"add",saturate:"saturate",multiply:"multiply",screen:"screen",overlay:"overlay",darken:"darken",lighten:"lighten","colour-dodge":"colour-dodge","color-dodge":"colour-dodge","colour-burn":"colour-burn","color-burn":"colour-burn","hard-light":"hard-light","soft-light":"soft-light",difference:"difference",exclusion:"exclusion"};function composite(images){if(!Array.isArray(images))throw is2.invalidParameterError("images to composite","array",images);return this.options.composite=images.map((image)=>{if(!is2.object(image))throw is2.invalidParameterError("image to composite","object",image);let inputOptions=this._inputOptionsFromObject(image),composite2={input:this._createInputDescriptor(image.input,inputOptions,{allowStream:!1}),blend:"over",tile:!1,left:0,top:0,hasOffset:!1,gravity:0,premultiplied:!1};if(is2.defined(image.blend))if(is2.string(blend[image.blend]))composite2.blend=blend[image.blend];else throw is2.invalidParameterError("blend","valid blend name",image.blend);if(is2.defined(image.tile))if(is2.bool(image.tile))composite2.tile=image.tile;else throw is2.invalidParameterError("tile","boolean",image.tile);if(is2.defined(image.left))if(is2.integer(image.left))composite2.left=image.left;else throw is2.invalidParameterError("left","integer",image.left);if(is2.defined(image.top))if(is2.integer(image.top))composite2.top=image.top;else throw is2.invalidParameterError("top","integer",image.top);if(is2.defined(image.top)!==is2.defined(image.left))throw Error("Expected both left and top to be set");else composite2.hasOffset=is2.integer(image.top)&&is2.integer(image.left);if(is2.defined(image.gravity))if(is2.integer(image.gravity)&&is2.inRange(image.gravity,0,8))composite2.gravity=image.gravity;else if(is2.string(image.gravity)&&is2.integer(this.constructor.gravity[image.gravity]))composite2.gravity=this.constructor.gravity[image.gravity];else throw is2.invalidParameterError("gravity","valid gravity",image.gravity);if(is2.defined(image.premultiplied))if(is2.bool(image.premultiplied))composite2.premultiplied=image.premultiplied;else throw is2.invalidParameterError("premultiplied","boolean",image.premultiplied);return composite2}),this}module.exports=function(Sharp){Sharp.prototype.composite=composite,Sharp.blend=blend}});var require_operation=__commonJS((exports,module)=>{var color=require_color(),is2=require_is(),vipsPrecision={integer:"integer",float:"float",approximate:"approximate"};function rotate(angle,options){if(this.options.useExifOrientation||this.options.angle||this.options.rotationAngle)this.options.debuglog("ignoring previous rotate options");if(!is2.defined(angle))this.options.useExifOrientation=!0;else if(is2.integer(angle)&&!(angle%90))this.options.angle=angle;else if(is2.number(angle)){if(this.options.rotationAngle=angle,is2.object(options)&&options.background){let backgroundColour=color(options.background);this.options.rotationBackground=[backgroundColour.red(),backgroundColour.green(),backgroundColour.blue(),Math.round(backgroundColour.alpha()*255)]}}else throw is2.invalidParameterError("angle","numeric",angle);return this}function flip(flip2){return this.options.flip=is2.bool(flip2)?flip2:!0,this}function flop(flop2){return this.options.flop=is2.bool(flop2)?flop2:!0,this}function affine(matrix,options){let flatMatrix=[].concat(...matrix);if(flatMatrix.length===4&&flatMatrix.every(is2.number))this.options.affineMatrix=flatMatrix;else throw is2.invalidParameterError("matrix","1x4 or 2x2 array",matrix);if(is2.defined(options))if(is2.object(options)){if(this._setBackgroundColourOption("affineBackground",options.background),is2.defined(options.idx))if(is2.number(options.idx))this.options.affineIdx=options.idx;else throw is2.invalidParameterError("options.idx","number",options.idx);if(is2.defined(options.idy))if(is2.number(options.idy))this.options.affineIdy=options.idy;else throw is2.invalidParameterError("options.idy","number",options.idy);if(is2.defined(options.odx))if(is2.number(options.odx))this.options.affineOdx=options.odx;else throw is2.invalidParameterError("options.odx","number",options.odx);if(is2.defined(options.ody))if(is2.number(options.ody))this.options.affineOdy=options.ody;else throw is2.invalidParameterError("options.ody","number",options.ody);if(is2.defined(options.interpolator))if(is2.inArray(options.interpolator,Object.values(this.constructor.interpolators)))this.options.affineInterpolator=options.interpolator;else throw is2.invalidParameterError("options.interpolator","valid interpolator name",options.interpolator)}else throw is2.invalidParameterError("options","object",options);return this}function sharpen(options,flat,jagged){if(!is2.defined(options))this.options.sharpenSigma=-1;else if(is2.bool(options))this.options.sharpenSigma=options?-1:0;else if(is2.number(options)&&is2.inRange(options,0.01,1e4)){if(this.options.sharpenSigma=options,is2.defined(flat))if(is2.number(flat)&&is2.inRange(flat,0,1e4))this.options.sharpenM1=flat;else throw is2.invalidParameterError("flat","number between 0 and 10000",flat);if(is2.defined(jagged))if(is2.number(jagged)&&is2.inRange(jagged,0,1e4))this.options.sharpenM2=jagged;else throw is2.invalidParameterError("jagged","number between 0 and 10000",jagged)}else if(is2.plainObject(options)){if(is2.number(options.sigma)&&is2.inRange(options.sigma,0.000001,10))this.options.sharpenSigma=options.sigma;else throw is2.invalidParameterError("options.sigma","number between 0.000001 and 10",options.sigma);if(is2.defined(options.m1))if(is2.number(options.m1)&&is2.inRange(options.m1,0,1e6))this.options.sharpenM1=options.m1;else throw is2.invalidParameterError("options.m1","number between 0 and 1000000",options.m1);if(is2.defined(options.m2))if(is2.number(options.m2)&&is2.inRange(options.m2,0,1e6))this.options.sharpenM2=options.m2;else throw is2.invalidParameterError("options.m2","number between 0 and 1000000",options.m2);if(is2.defined(options.x1))if(is2.number(options.x1)&&is2.inRange(options.x1,0,1e6))this.options.sharpenX1=options.x1;else throw is2.invalidParameterError("options.x1","number between 0 and 1000000",options.x1);if(is2.defined(options.y2))if(is2.number(options.y2)&&is2.inRange(options.y2,0,1e6))this.options.sharpenY2=options.y2;else throw is2.invalidParameterError("options.y2","number between 0 and 1000000",options.y2);if(is2.defined(options.y3))if(is2.number(options.y3)&&is2.inRange(options.y3,0,1e6))this.options.sharpenY3=options.y3;else throw is2.invalidParameterError("options.y3","number between 0 and 1000000",options.y3)}else throw is2.invalidParameterError("sigma","number between 0.01 and 10000",options);return this}function median(size){if(!is2.defined(size))this.options.medianSize=3;else if(is2.integer(size)&&is2.inRange(size,1,1000))this.options.medianSize=size;else throw is2.invalidParameterError("size","integer between 1 and 1000",size);return this}function blur(options){let sigma;if(is2.number(options))sigma=options;else if(is2.plainObject(options)){if(!is2.number(options.sigma))throw is2.invalidParameterError("options.sigma","number between 0.3 and 1000",sigma);if(sigma=options.sigma,"precision"in options)if(is2.string(vipsPrecision[options.precision]))this.options.precision=vipsPrecision[options.precision];else throw is2.invalidParameterError("precision","one of: integer, float, approximate",options.precision);if("minAmplitude"in options)if(is2.number(options.minAmplitude)&&is2.inRange(options.minAmplitude,0.001,1))this.options.minAmpl=options.minAmplitude;else throw is2.invalidParameterError("minAmplitude","number between 0.001 and 1",options.minAmplitude)}if(!is2.defined(options))this.options.blurSigma=-1;else if(is2.bool(options))this.options.blurSigma=options?-1:0;else if(is2.number(sigma)&&is2.inRange(sigma,0.3,1000))this.options.blurSigma=sigma;else throw is2.invalidParameterError("sigma","number between 0.3 and 1000",sigma);return this}function flatten(options){if(this.options.flatten=is2.bool(options)?options:!0,is2.object(options))this._setBackgroundColourOption("flattenBackground",options.background);return this}function unflatten(){return this.options.unflatten=!0,this}function gamma(gamma2,gammaOut){if(!is2.defined(gamma2))this.options.gamma=2.2;else if(is2.number(gamma2)&&is2.inRange(gamma2,1,3))this.options.gamma=gamma2;else throw is2.invalidParameterError("gamma","number between 1.0 and 3.0",gamma2);if(!is2.defined(gammaOut))this.options.gammaOut=this.options.gamma;else if(is2.number(gammaOut)&&is2.inRange(gammaOut,1,3))this.options.gammaOut=gammaOut;else throw is2.invalidParameterError("gammaOut","number between 1.0 and 3.0",gammaOut);return this}function negate(options){if(this.options.negate=is2.bool(options)?options:!0,is2.plainObject(options)&&"alpha"in options)if(!is2.bool(options.alpha))throw is2.invalidParameterError("alpha","should be boolean value",options.alpha);else this.options.negateAlpha=options.alpha;return this}function normalise(options){if(is2.plainObject(options)){if(is2.defined(options.lower))if(is2.number(options.lower)&&is2.inRange(options.lower,0,99))this.options.normaliseLower=options.lower;else throw is2.invalidParameterError("lower","number between 0 and 99",options.lower);if(is2.defined(options.upper))if(is2.number(options.upper)&&is2.inRange(options.upper,1,100))this.options.normaliseUpper=options.upper;else throw is2.invalidParameterError("upper","number between 1 and 100",options.upper)}if(this.options.normaliseLower>=this.options.normaliseUpper)throw is2.invalidParameterError("range","lower to be less than upper",`${this.options.normaliseLower} >= ${this.options.normaliseUpper}`);return this.options.normalise=!0,this}function normalize3(options){return this.normalise(options)}function clahe(options){if(is2.plainObject(options)){if(is2.integer(options.width)&&options.width>0)this.options.claheWidth=options.width;else throw is2.invalidParameterError("width","integer greater than zero",options.width);if(is2.integer(options.height)&&options.height>0)this.options.claheHeight=options.height;else throw is2.invalidParameterError("height","integer greater than zero",options.height);if(is2.defined(options.maxSlope))if(is2.integer(options.maxSlope)&&is2.inRange(options.maxSlope,0,100))this.options.claheMaxSlope=options.maxSlope;else throw is2.invalidParameterError("maxSlope","integer between 0 and 100",options.maxSlope)}else throw is2.invalidParameterError("options","plain object",options);return this}function convolve(kernel){if(!is2.object(kernel)||!Array.isArray(kernel.kernel)||!is2.integer(kernel.width)||!is2.integer(kernel.height)||!is2.inRange(kernel.width,3,1001)||!is2.inRange(kernel.height,3,1001)||kernel.height*kernel.width!==kernel.kernel.length)throw Error("Invalid convolution kernel");if(!is2.integer(kernel.scale))kernel.scale=kernel.kernel.reduce(function(a,b){return a+b},0);if(kernel.scale<1)kernel.scale=1;if(!is2.integer(kernel.offset))kernel.offset=0;return this.options.convKernel=kernel,this}function threshold(threshold2,options){if(!is2.defined(threshold2))this.options.threshold=128;else if(is2.bool(threshold2))this.options.threshold=threshold2?128:0;else if(is2.integer(threshold2)&&is2.inRange(threshold2,0,255))this.options.threshold=threshold2;else throw is2.invalidParameterError("threshold","integer between 0 and 255",threshold2);if(!is2.object(options)||options.greyscale===!0||options.grayscale===!0)this.options.thresholdGrayscale=!0;else this.options.thresholdGrayscale=!1;return this}function boolean(operand,operator,options){if(this.options.boolean=this._createInputDescriptor(operand,options),is2.string(operator)&&is2.inArray(operator,["and","or","eor"]))this.options.booleanOp=operator;else throw is2.invalidParameterError("operator","one of: and, or, eor",operator);return this}function linear(a,b){if(!is2.defined(a)&&is2.number(b))a=1;else if(is2.number(a)&&!is2.defined(b))b=0;if(!is2.defined(a))this.options.linearA=[];else if(is2.number(a))this.options.linearA=[a];else if(Array.isArray(a)&&a.length&&a.every(is2.number))this.options.linearA=a;else throw is2.invalidParameterError("a","number or array of numbers",a);if(!is2.defined(b))this.options.linearB=[];else if(is2.number(b))this.options.linearB=[b];else if(Array.isArray(b)&&b.length&&b.every(is2.number))this.options.linearB=b;else throw is2.invalidParameterError("b","number or array of numbers",b);if(this.options.linearA.length!==this.options.linearB.length)throw Error("Expected a and b to be arrays of the same length");return this}function recomb(inputMatrix){if(!Array.isArray(inputMatrix))throw is2.invalidParameterError("inputMatrix","array",inputMatrix);if(inputMatrix.length!==3&&inputMatrix.length!==4)throw is2.invalidParameterError("inputMatrix","3x3 or 4x4 array",inputMatrix.length);let recombMatrix=inputMatrix.flat().map(Number);if(recombMatrix.length!==9&&recombMatrix.length!==16)throw is2.invalidParameterError("inputMatrix","cardinality of 9 or 16",recombMatrix.length);return this.options.recombMatrix=recombMatrix,this}function modulate(options){if(!is2.plainObject(options))throw is2.invalidParameterError("options","plain object",options);if("brightness"in options)if(is2.number(options.brightness)&&options.brightness>=0)this.options.brightness=options.brightness;else throw is2.invalidParameterError("brightness","number above zero",options.brightness);if("saturation"in options)if(is2.number(options.saturation)&&options.saturation>=0)this.options.saturation=options.saturation;else throw is2.invalidParameterError("saturation","number above zero",options.saturation);if("hue"in options)if(is2.integer(options.hue))this.options.hue=options.hue%360;else throw is2.invalidParameterError("hue","number",options.hue);if("lightness"in options)if(is2.number(options.lightness))this.options.lightness=options.lightness;else throw is2.invalidParameterError("lightness","number",options.lightness);return this}module.exports=function(Sharp){Object.assign(Sharp.prototype,{rotate,flip,flop,affine,sharpen,median,blur,flatten,unflatten,gamma,negate,normalise,normalize:normalize3,clahe,convolve,threshold,boolean,linear,recomb,modulate})}});var require_colour=__commonJS((exports,module)=>{var color=require_color(),is2=require_is(),colourspace={multiband:"multiband","b-w":"b-w",bw:"b-w",cmyk:"cmyk",srgb:"srgb"};function tint(tint2){return this._setBackgroundColourOption("tint",tint2),this}function greyscale(greyscale2){return this.options.greyscale=is2.bool(greyscale2)?greyscale2:!0,this}function grayscale(grayscale2){return this.greyscale(grayscale2)}function pipelineColourspace(colourspace2){if(!is2.string(colourspace2))throw is2.invalidParameterError("colourspace","string",colourspace2);return this.options.colourspacePipeline=colourspace2,this}function pipelineColorspace(colorspace){return this.pipelineColourspace(colorspace)}function toColourspace(colourspace2){if(!is2.string(colourspace2))throw is2.invalidParameterError("colourspace","string",colourspace2);return this.options.colourspace=colourspace2,this}function toColorspace(colorspace){return this.toColourspace(colorspace)}function _setBackgroundColourOption(key2,value){if(is2.defined(value))if(is2.object(value)||is2.string(value)){let colour=color(value);this.options[key2]=[colour.red(),colour.green(),colour.blue(),Math.round(colour.alpha()*255)]}else throw is2.invalidParameterError("background","object or string",value)}module.exports=function(Sharp){Object.assign(Sharp.prototype,{tint,greyscale,grayscale,pipelineColourspace,pipelineColorspace,toColourspace,toColorspace,_setBackgroundColourOption}),Sharp.colourspace=colourspace,Sharp.colorspace=colourspace}});var require_channel=__commonJS((exports,module)=>{var is2=require_is(),bool={and:"and",or:"or",eor:"eor"};function removeAlpha(){return this.options.removeAlpha=!0,this}function ensureAlpha(alpha){if(is2.defined(alpha))if(is2.number(alpha)&&is2.inRange(alpha,0,1))this.options.ensureAlpha=alpha;else throw is2.invalidParameterError("alpha","number between 0 and 1",alpha);else this.options.ensureAlpha=1;return this}function extractChannel(channel){let channelMap={red:0,green:1,blue:2,alpha:3};if(Object.keys(channelMap).includes(channel))channel=channelMap[channel];if(is2.integer(channel)&&is2.inRange(channel,0,4))this.options.extractChannel=channel;else throw is2.invalidParameterError("channel","integer or one of: red, green, blue, alpha",channel);return this}function joinChannel(images,options){if(Array.isArray(images))images.forEach(function(image){this.options.joinChannelIn.push(this._createInputDescriptor(image,options))},this);else this.options.joinChannelIn.push(this._createInputDescriptor(images,options));return this}function bandbool(boolOp){if(is2.string(boolOp)&&is2.inArray(boolOp,["and","or","eor"]))this.options.bandBoolOp=boolOp;else throw is2.invalidParameterError("boolOp","one of: and, or, eor",boolOp);return this}module.exports=function(Sharp){Object.assign(Sharp.prototype,{removeAlpha,ensureAlpha,extractChannel,joinChannel,bandbool}),Sharp.bool=bool}});var require_output=__commonJS((exports,module)=>{var path3=__require("path"),is2=require_is(),sharp=require_sharp(),formats2=new Map([["heic","heif"],["heif","heif"],["avif","avif"],["jpeg","jpeg"],["jpg","jpeg"],["jpe","jpeg"],["tile","tile"],["dz","tile"],["png","png"],["raw","raw"],["tiff","tiff"],["tif","tiff"],["webp","webp"],["gif","gif"],["jp2","jp2"],["jpx","jp2"],["j2k","jp2"],["j2c","jp2"],["jxl","jxl"]]),jp2Regex=/\.(jp[2x]|j2[kc])$/i,errJp2Save=()=>Error("JP2 output requires libvips with support for OpenJPEG"),bitdepthFromColourCount=(colours)=>1<<31-Math.clz32(Math.ceil(Math.log2(colours)));function toFile(fileOut,callback){let err;if(!is2.string(fileOut))err=Error("Missing output file path");else if(is2.string(this.options.input.file)&&path3.resolve(this.options.input.file)===path3.resolve(fileOut))err=Error("Cannot use same file for input and output");else if(jp2Regex.test(path3.extname(fileOut))&&!this.constructor.format.jp2k.output.file)err=errJp2Save();if(err)if(is2.fn(callback))callback(err);else return Promise.reject(err);else{this.options.fileOut=fileOut;let stack=Error();return this._pipeline(callback,stack)}return this}function toBuffer2(options,callback){if(is2.object(options))this._setBooleanOption("resolveWithObject",options.resolveWithObject);else if(this.options.resolveWithObject)this.options.resolveWithObject=!1;this.options.fileOut="";let stack=Error();return this._pipeline(is2.fn(options)?options:callback,stack)}function keepExif(){return this.options.keepMetadata|=1,this}function withExif(exif){if(is2.object(exif))for(let[ifd,entries]of Object.entries(exif))if(is2.object(entries))for(let[k,v]of Object.entries(entries))if(is2.string(v))this.options.withExif[`exif-${ifd.toLowerCase()}-${k}`]=v;else throw is2.invalidParameterError(`${ifd}.${k}`,"string",v);else throw is2.invalidParameterError(ifd,"object",entries);else throw is2.invalidParameterError("exif","object",exif);return this.options.withExifMerge=!1,this.keepExif()}function withExifMerge(exif){return this.withExif(exif),this.options.withExifMerge=!0,this}function keepIccProfile(){return this.options.keepMetadata|=8,this}function withIccProfile(icc,options){if(is2.string(icc))this.options.withIccProfile=icc;else throw is2.invalidParameterError("icc","string",icc);if(this.keepIccProfile(),is2.object(options)){if(is2.defined(options.attach))if(is2.bool(options.attach)){if(!options.attach)this.options.keepMetadata&=-9}else throw is2.invalidParameterError("attach","boolean",options.attach)}return this}function keepMetadata(){return this.options.keepMetadata=31,this}function withMetadata(options){if(this.keepMetadata(),this.withIccProfile("srgb"),is2.object(options)){if(is2.defined(options.orientation))if(is2.integer(options.orientation)&&is2.inRange(options.orientation,1,8))this.options.withMetadataOrientation=options.orientation;else throw is2.invalidParameterError("orientation","integer between 1 and 8",options.orientation);if(is2.defined(options.density))if(is2.number(options.density)&&options.density>0)this.options.withMetadataDensity=options.density;else throw is2.invalidParameterError("density","positive number",options.density);if(is2.defined(options.icc))this.withIccProfile(options.icc);if(is2.defined(options.exif))this.withExifMerge(options.exif)}return this}function toFormat(format2,options){let actualFormat=formats2.get((is2.object(format2)&&is2.string(format2.id)?format2.id:format2).toLowerCase());if(!actualFormat)throw is2.invalidParameterError("format",`one of: ${[...formats2.keys()].join(", ")}`,format2);return this[actualFormat](options)}function jpeg(options){if(is2.object(options)){if(is2.defined(options.quality))if(is2.integer(options.quality)&&is2.inRange(options.quality,1,100))this.options.jpegQuality=options.quality;else throw is2.invalidParameterError("quality","integer between 1 and 100",options.quality);if(is2.defined(options.progressive))this._setBooleanOption("jpegProgressive",options.progressive);if(is2.defined(options.chromaSubsampling))if(is2.string(options.chromaSubsampling)&&is2.inArray(options.chromaSubsampling,["4:2:0","4:4:4"]))this.options.jpegChromaSubsampling=options.chromaSubsampling;else throw is2.invalidParameterError("chromaSubsampling","one of: 4:2:0, 4:4:4",options.chromaSubsampling);let optimiseCoding=is2.bool(options.optimizeCoding)?options.optimizeCoding:options.optimiseCoding;if(is2.defined(optimiseCoding))this._setBooleanOption("jpegOptimiseCoding",optimiseCoding);if(is2.defined(options.mozjpeg))if(is2.bool(options.mozjpeg)){if(options.mozjpeg)this.options.jpegTrellisQuantisation=!0,this.options.jpegOvershootDeringing=!0,this.options.jpegOptimiseScans=!0,this.options.jpegProgressive=!0,this.options.jpegQuantisationTable=3}else throw is2.invalidParameterError("mozjpeg","boolean",options.mozjpeg);let trellisQuantisation=is2.bool(options.trellisQuantization)?options.trellisQuantization:options.trellisQuantisation;if(is2.defined(trellisQuantisation))this._setBooleanOption("jpegTrellisQuantisation",trellisQuantisation);if(is2.defined(options.overshootDeringing))this._setBooleanOption("jpegOvershootDeringing",options.overshootDeringing);let optimiseScans=is2.bool(options.optimizeScans)?options.optimizeScans:options.optimiseScans;if(is2.defined(optimiseScans)){if(this._setBooleanOption("jpegOptimiseScans",optimiseScans),optimiseScans)this.options.jpegProgressive=!0}let quantisationTable=is2.number(options.quantizationTable)?options.quantizationTable:options.quantisationTable;if(is2.defined(quantisationTable))if(is2.integer(quantisationTable)&&is2.inRange(quantisationTable,0,8))this.options.jpegQuantisationTable=quantisationTable;else throw is2.invalidParameterError("quantisationTable","integer between 0 and 8",quantisationTable)}return this._updateFormatOut("jpeg",options)}function png(options){if(is2.object(options)){if(is2.defined(options.progressive))this._setBooleanOption("pngProgressive",options.progressive);if(is2.defined(options.compressionLevel))if(is2.integer(options.compressionLevel)&&is2.inRange(options.compressionLevel,0,9))this.options.pngCompressionLevel=options.compressionLevel;else throw is2.invalidParameterError("compressionLevel","integer between 0 and 9",options.compressionLevel);if(is2.defined(options.adaptiveFiltering))this._setBooleanOption("pngAdaptiveFiltering",options.adaptiveFiltering);let colours=options.colours||options.colors;if(is2.defined(colours))if(is2.integer(colours)&&is2.inRange(colours,2,256))this.options.pngBitdepth=bitdepthFromColourCount(colours);else throw is2.invalidParameterError("colours","integer between 2 and 256",colours);if(is2.defined(options.palette))this._setBooleanOption("pngPalette",options.palette);else if([options.quality,options.effort,options.colours,options.colors,options.dither].some(is2.defined))this._setBooleanOption("pngPalette",!0);if(this.options.pngPalette){if(is2.defined(options.quality))if(is2.integer(options.quality)&&is2.inRange(options.quality,0,100))this.options.pngQuality=options.quality;else throw is2.invalidParameterError("quality","integer between 0 and 100",options.quality);if(is2.defined(options.effort))if(is2.integer(options.effort)&&is2.inRange(options.effort,1,10))this.options.pngEffort=options.effort;else throw is2.invalidParameterError("effort","integer between 1 and 10",options.effort);if(is2.defined(options.dither))if(is2.number(options.dither)&&is2.inRange(options.dither,0,1))this.options.pngDither=options.dither;else throw is2.invalidParameterError("dither","number between 0.0 and 1.0",options.dither)}}return this._updateFormatOut("png",options)}function webp(options){if(is2.object(options)){if(is2.defined(options.quality))if(is2.integer(options.quality)&&is2.inRange(options.quality,1,100))this.options.webpQuality=options.quality;else throw is2.invalidParameterError("quality","integer between 1 and 100",options.quality);if(is2.defined(options.alphaQuality))if(is2.integer(options.alphaQuality)&&is2.inRange(options.alphaQuality,0,100))this.options.webpAlphaQuality=options.alphaQuality;else throw is2.invalidParameterError("alphaQuality","integer between 0 and 100",options.alphaQuality);if(is2.defined(options.lossless))this._setBooleanOption("webpLossless",options.lossless);if(is2.defined(options.nearLossless))this._setBooleanOption("webpNearLossless",options.nearLossless);if(is2.defined(options.smartSubsample))this._setBooleanOption("webpSmartSubsample",options.smartSubsample);if(is2.defined(options.preset))if(is2.string(options.preset)&&is2.inArray(options.preset,["default","photo","picture","drawing","icon","text"]))this.options.webpPreset=options.preset;else throw is2.invalidParameterError("preset","one of: default, photo, picture, drawing, icon, text",options.preset);if(is2.defined(options.effort))if(is2.integer(options.effort)&&is2.inRange(options.effort,0,6))this.options.webpEffort=options.effort;else throw is2.invalidParameterError("effort","integer between 0 and 6",options.effort);if(is2.defined(options.minSize))this._setBooleanOption("webpMinSize",options.minSize);if(is2.defined(options.mixed))this._setBooleanOption("webpMixed",options.mixed)}return trySetAnimationOptions(options,this.options),this._updateFormatOut("webp",options)}function gif(options){if(is2.object(options)){if(is2.defined(options.reuse))this._setBooleanOption("gifReuse",options.reuse);if(is2.defined(options.progressive))this._setBooleanOption("gifProgressive",options.progressive);let colours=options.colours||options.colors;if(is2.defined(colours))if(is2.integer(colours)&&is2.inRange(colours,2,256))this.options.gifBitdepth=bitdepthFromColourCount(colours);else throw is2.invalidParameterError("colours","integer between 2 and 256",colours);if(is2.defined(options.effort))if(is2.number(options.effort)&&is2.inRange(options.effort,1,10))this.options.gifEffort=options.effort;else throw is2.invalidParameterError("effort","integer between 1 and 10",options.effort);if(is2.defined(options.dither))if(is2.number(options.dither)&&is2.inRange(options.dither,0,1))this.options.gifDither=options.dither;else throw is2.invalidParameterError("dither","number between 0.0 and 1.0",options.dither);if(is2.defined(options.interFrameMaxError))if(is2.number(options.interFrameMaxError)&&is2.inRange(options.interFrameMaxError,0,32))this.options.gifInterFrameMaxError=options.interFrameMaxError;else throw is2.invalidParameterError("interFrameMaxError","number between 0.0 and 32.0",options.interFrameMaxError);if(is2.defined(options.interPaletteMaxError))if(is2.number(options.interPaletteMaxError)&&is2.inRange(options.interPaletteMaxError,0,256))this.options.gifInterPaletteMaxError=options.interPaletteMaxError;else throw is2.invalidParameterError("interPaletteMaxError","number between 0.0 and 256.0",options.interPaletteMaxError)}return trySetAnimationOptions(options,this.options),this._updateFormatOut("gif",options)}function jp2(options){if(!this.constructor.format.jp2k.output.buffer)throw errJp2Save();if(is2.object(options)){if(is2.defined(options.quality))if(is2.integer(options.quality)&&is2.inRange(options.quality,1,100))this.options.jp2Quality=options.quality;else throw is2.invalidParameterError("quality","integer between 1 and 100",options.quality);if(is2.defined(options.lossless))if(is2.bool(options.lossless))this.options.jp2Lossless=options.lossless;else throw is2.invalidParameterError("lossless","boolean",options.lossless);if(is2.defined(options.tileWidth))if(is2.integer(options.tileWidth)&&is2.inRange(options.tileWidth,1,32768))this.options.jp2TileWidth=options.tileWidth;else throw is2.invalidParameterError("tileWidth","integer between 1 and 32768",options.tileWidth);if(is2.defined(options.tileHeight))if(is2.integer(options.tileHeight)&&is2.inRange(options.tileHeight,1,32768))this.options.jp2TileHeight=options.tileHeight;else throw is2.invalidParameterError("tileHeight","integer between 1 and 32768",options.tileHeight);if(is2.defined(options.chromaSubsampling))if(is2.string(options.chromaSubsampling)&&is2.inArray(options.chromaSubsampling,["4:2:0","4:4:4"]))this.options.jp2ChromaSubsampling=options.chromaSubsampling;else throw is2.invalidParameterError("chromaSubsampling","one of: 4:2:0, 4:4:4",options.chromaSubsampling)}return this._updateFormatOut("jp2",options)}function trySetAnimationOptions(source,target2){if(is2.object(source)&&is2.defined(source.loop))if(is2.integer(source.loop)&&is2.inRange(source.loop,0,65535))target2.loop=source.loop;else throw is2.invalidParameterError("loop","integer between 0 and 65535",source.loop);if(is2.object(source)&&is2.defined(source.delay))if(is2.integer(source.delay)&&is2.inRange(source.delay,0,65535))target2.delay=[source.delay];else if(Array.isArray(source.delay)&&source.delay.every(is2.integer)&&source.delay.every((v)=>is2.inRange(v,0,65535)))target2.delay=source.delay;else throw is2.invalidParameterError("delay","integer or an array of integers between 0 and 65535",source.delay)}function tiff(options){if(is2.object(options)){if(is2.defined(options.quality))if(is2.integer(options.quality)&&is2.inRange(options.quality,1,100))this.options.tiffQuality=options.quality;else throw is2.invalidParameterError("quality","integer between 1 and 100",options.quality);if(is2.defined(options.bitdepth))if(is2.integer(options.bitdepth)&&is2.inArray(options.bitdepth,[1,2,4,8]))this.options.tiffBitdepth=options.bitdepth;else throw is2.invalidParameterError("bitdepth","1, 2, 4 or 8",options.bitdepth);if(is2.defined(options.tile))this._setBooleanOption("tiffTile",options.tile);if(is2.defined(options.tileWidth))if(is2.integer(options.tileWidth)&&options.tileWidth>0)this.options.tiffTileWidth=options.tileWidth;else throw is2.invalidParameterError("tileWidth","integer greater than zero",options.tileWidth);if(is2.defined(options.tileHeight))if(is2.integer(options.tileHeight)&&options.tileHeight>0)this.options.tiffTileHeight=options.tileHeight;else throw is2.invalidParameterError("tileHeight","integer greater than zero",options.tileHeight);if(is2.defined(options.miniswhite))this._setBooleanOption("tiffMiniswhite",options.miniswhite);if(is2.defined(options.pyramid))this._setBooleanOption("tiffPyramid",options.pyramid);if(is2.defined(options.xres))if(is2.number(options.xres)&&options.xres>0)this.options.tiffXres=options.xres;else throw is2.invalidParameterError("xres","number greater than zero",options.xres);if(is2.defined(options.yres))if(is2.number(options.yres)&&options.yres>0)this.options.tiffYres=options.yres;else throw is2.invalidParameterError("yres","number greater than zero",options.yres);if(is2.defined(options.compression))if(is2.string(options.compression)&&is2.inArray(options.compression,["none","jpeg","deflate","packbits","ccittfax4","lzw","webp","zstd","jp2k"]))this.options.tiffCompression=options.compression;else throw is2.invalidParameterError("compression","one of: none, jpeg, deflate, packbits, ccittfax4, lzw, webp, zstd, jp2k",options.compression);if(is2.defined(options.predictor))if(is2.string(options.predictor)&&is2.inArray(options.predictor,["none","horizontal","float"]))this.options.tiffPredictor=options.predictor;else throw is2.invalidParameterError("predictor","one of: none, horizontal, float",options.predictor);if(is2.defined(options.resolutionUnit))if(is2.string(options.resolutionUnit)&&is2.inArray(options.resolutionUnit,["inch","cm"]))this.options.tiffResolutionUnit=options.resolutionUnit;else throw is2.invalidParameterError("resolutionUnit","one of: inch, cm",options.resolutionUnit)}return this._updateFormatOut("tiff",options)}function avif(options){return this.heif({...options,compression:"av1"})}function heif(options){if(is2.object(options)){if(is2.string(options.compression)&&is2.inArray(options.compression,["av1","hevc"]))this.options.heifCompression=options.compression;else throw is2.invalidParameterError("compression","one of: av1, hevc",options.compression);if(is2.defined(options.quality))if(is2.integer(options.quality)&&is2.inRange(options.quality,1,100))this.options.heifQuality=options.quality;else throw is2.invalidParameterError("quality","integer between 1 and 100",options.quality);if(is2.defined(options.lossless))if(is2.bool(options.lossless))this.options.heifLossless=options.lossless;else throw is2.invalidParameterError("lossless","boolean",options.lossless);if(is2.defined(options.effort))if(is2.integer(options.effort)&&is2.inRange(options.effort,0,9))this.options.heifEffort=options.effort;else throw is2.invalidParameterError("effort","integer between 0 and 9",options.effort);if(is2.defined(options.chromaSubsampling))if(is2.string(options.chromaSubsampling)&&is2.inArray(options.chromaSubsampling,["4:2:0","4:4:4"]))this.options.heifChromaSubsampling=options.chromaSubsampling;else throw is2.invalidParameterError("chromaSubsampling","one of: 4:2:0, 4:4:4",options.chromaSubsampling);if(is2.defined(options.bitdepth))if(is2.integer(options.bitdepth)&&is2.inArray(options.bitdepth,[8,10,12])){if(options.bitdepth!==8&&this.constructor.versions.heif)throw is2.invalidParameterError("bitdepth when using prebuilt binaries",8,options.bitdepth);this.options.heifBitdepth=options.bitdepth}else throw is2.invalidParameterError("bitdepth","8, 10 or 12",options.bitdepth)}else throw is2.invalidParameterError("options","Object",options);return this._updateFormatOut("heif",options)}function jxl(options){if(is2.object(options)){if(is2.defined(options.quality))if(is2.integer(options.quality)&&is2.inRange(options.quality,1,100))this.options.jxlDistance=options.quality>=30?0.1+(100-options.quality)*0.09:0.017666666666666667*options.quality*options.quality-1.15*options.quality+25;else throw is2.invalidParameterError("quality","integer between 1 and 100",options.quality);else if(is2.defined(options.distance))if(is2.number(options.distance)&&is2.inRange(options.distance,0,15))this.options.jxlDistance=options.distance;else throw is2.invalidParameterError("distance","number between 0.0 and 15.0",options.distance);if(is2.defined(options.decodingTier))if(is2.integer(options.decodingTier)&&is2.inRange(options.decodingTier,0,4))this.options.jxlDecodingTier=options.decodingTier;else throw is2.invalidParameterError("decodingTier","integer between 0 and 4",options.decodingTier);if(is2.defined(options.lossless))if(is2.bool(options.lossless))this.options.jxlLossless=options.lossless;else throw is2.invalidParameterError("lossless","boolean",options.lossless);if(is2.defined(options.effort))if(is2.integer(options.effort)&&is2.inRange(options.effort,3,9))this.options.jxlEffort=options.effort;else throw is2.invalidParameterError("effort","integer between 3 and 9",options.effort)}return this._updateFormatOut("jxl",options)}function raw(options){if(is2.object(options)){if(is2.defined(options.depth))if(is2.string(options.depth)&&is2.inArray(options.depth,["char","uchar","short","ushort","int","uint","float","complex","double","dpcomplex"]))this.options.rawDepth=options.depth;else throw is2.invalidParameterError("depth","one of: char, uchar, short, ushort, int, uint, float, complex, double, dpcomplex",options.depth)}return this._updateFormatOut("raw")}function tile(options){if(is2.object(options)){if(is2.defined(options.size))if(is2.integer(options.size)&&is2.inRange(options.size,1,8192))this.options.tileSize=options.size;else throw is2.invalidParameterError("size","integer between 1 and 8192",options.size);if(is2.defined(options.overlap))if(is2.integer(options.overlap)&&is2.inRange(options.overlap,0,8192)){if(options.overlap>this.options.tileSize)throw is2.invalidParameterError("overlap",`<= size (${this.options.tileSize})`,options.overlap);this.options.tileOverlap=options.overlap}else throw is2.invalidParameterError("overlap","integer between 0 and 8192",options.overlap);if(is2.defined(options.container))if(is2.string(options.container)&&is2.inArray(options.container,["fs","zip"]))this.options.tileContainer=options.container;else throw is2.invalidParameterError("container","one of: fs, zip",options.container);if(is2.defined(options.layout))if(is2.string(options.layout)&&is2.inArray(options.layout,["dz","google","iiif","iiif3","zoomify"]))this.options.tileLayout=options.layout;else throw is2.invalidParameterError("layout","one of: dz, google, iiif, iiif3, zoomify",options.layout);if(is2.defined(options.angle))if(is2.integer(options.angle)&&!(options.angle%90))this.options.tileAngle=options.angle;else throw is2.invalidParameterError("angle","positive/negative multiple of 90",options.angle);if(this._setBackgroundColourOption("tileBackground",options.background),is2.defined(options.depth))if(is2.string(options.depth)&&is2.inArray(options.depth,["onepixel","onetile","one"]))this.options.tileDepth=options.depth;else throw is2.invalidParameterError("depth","one of: onepixel, onetile, one",options.depth);if(is2.defined(options.skipBlanks))if(is2.integer(options.skipBlanks)&&is2.inRange(options.skipBlanks,-1,65535))this.options.tileSkipBlanks=options.skipBlanks;else throw is2.invalidParameterError("skipBlanks","integer between -1 and 255/65535",options.skipBlanks);else if(is2.defined(options.layout)&&options.layout==="google")this.options.tileSkipBlanks=5;let centre=is2.bool(options.center)?options.center:options.centre;if(is2.defined(centre))this._setBooleanOption("tileCentre",centre);if(is2.defined(options.id))if(is2.string(options.id))this.options.tileId=options.id;else throw is2.invalidParameterError("id","string",options.id);if(is2.defined(options.basename))if(is2.string(options.basename))this.options.tileBasename=options.basename;else throw is2.invalidParameterError("basename","string",options.basename)}if(is2.inArray(this.options.formatOut,["jpeg","png","webp"]))this.options.tileFormat=this.options.formatOut;else if(this.options.formatOut!=="input")throw is2.invalidParameterError("format","one of: jpeg, png, webp",this.options.formatOut);return this._updateFormatOut("dz")}function timeout(options){if(!is2.plainObject(options))throw is2.invalidParameterError("options","object",options);if(is2.integer(options.seconds)&&is2.inRange(options.seconds,0,3600))this.options.timeoutSeconds=options.seconds;else throw is2.invalidParameterError("seconds","integer between 0 and 3600",options.seconds);return this}function _updateFormatOut(formatOut,options){if(!(is2.object(options)&&options.force===!1))this.options.formatOut=formatOut;return this}function _setBooleanOption(key2,val){if(is2.bool(val))this.options[key2]=val;else throw is2.invalidParameterError(key2,"boolean",val)}function _read(){if(!this.options.streamOut){this.options.streamOut=!0;let stack=Error();this._pipeline(void 0,stack)}}function _pipeline(callback,stack){if(typeof callback==="function"){if(this._isStreamInput())this.on("finish",()=>{this._flattenBufferIn(),sharp.pipeline(this.options,(err,data,info)=>{if(err)callback(is2.nativeError(err,stack));else callback(null,data,info)})});else sharp.pipeline(this.options,(err,data,info)=>{if(err)callback(is2.nativeError(err,stack));else callback(null,data,info)});return this}else if(this.options.streamOut){if(this._isStreamInput()){if(this.once("finish",()=>{this._flattenBufferIn(),sharp.pipeline(this.options,(err,data,info)=>{if(err)this.emit("error",is2.nativeError(err,stack));else this.emit("info",info),this.push(data);this.push(null),this.on("end",()=>this.emit("close"))})}),this.streamInFinished)this.emit("finish")}else sharp.pipeline(this.options,(err,data,info)=>{if(err)this.emit("error",is2.nativeError(err,stack));else this.emit("info",info),this.push(data);this.push(null),this.on("end",()=>this.emit("close"))});return this}else if(this._isStreamInput())return new Promise((resolve2,reject)=>{this.once("finish",()=>{this._flattenBufferIn(),sharp.pipeline(this.options,(err,data,info)=>{if(err)reject(is2.nativeError(err,stack));else if(this.options.resolveWithObject)resolve2({data,info});else resolve2(data)})})});else return new Promise((resolve2,reject)=>{sharp.pipeline(this.options,(err,data,info)=>{if(err)reject(is2.nativeError(err,stack));else if(this.options.resolveWithObject)resolve2({data,info});else resolve2(data)})})}module.exports=function(Sharp){Object.assign(Sharp.prototype,{toFile,toBuffer:toBuffer2,keepExif,withExif,withExifMerge,keepIccProfile,withIccProfile,keepMetadata,withMetadata,toFormat,jpeg,jp2,png,webp,tiff,avif,heif,jxl,gif,raw,tile,timeout,_updateFormatOut,_setBooleanOption,_read,_pipeline})}});var require_utility=__commonJS((exports,module)=>{var events=__require("events"),detectLibc=require_detect_libc(),is2=require_is(),{runtimePlatformArch}=require_libvips(),sharp=require_sharp(),runtimePlatform=runtimePlatformArch(),libvipsVersion=sharp.libvipsVersion(),format2=sharp.format();format2.heif.output.alias=["avif","heic"];format2.jpeg.output.alias=["jpe","jpg"];format2.tiff.output.alias=["tif"];format2.jp2k.output.alias=["j2c","j2k","jp2","jpx"];var interpolators={nearest:"nearest",bilinear:"bilinear",bicubic:"bicubic",locallyBoundedBicubic:"lbb",nohalo:"nohalo",vertexSplitQuadraticBasisSpline:"vsqbs"},versions={vips:libvipsVersion.semver};if(!libvipsVersion.isGlobal)if(!libvipsVersion.isWasm)try{versions=__require(`@img/sharp-${runtimePlatform}/versions`)}catch(_){try{versions=__require(`@img/sharp-libvips-${runtimePlatform}/versions`)}catch(_2){}}else try{versions=(()=>{throw new Error("Cannot require module "+"@img/sharp-wasm32/versions");})()}catch(_){}versions.sharp=require_package().version;if(versions.heif&&format2.heif)format2.heif.input.fileSuffix=[".avif"],format2.heif.output.alias=["avif"];function cache(options){if(is2.bool(options))if(options)return sharp.cache(50,20,100);else return sharp.cache(0,0,0);else if(is2.object(options))return sharp.cache(options.memory,options.files,options.items);else return sharp.cache()}cache(!0);function concurrency(concurrency2){return sharp.concurrency(is2.integer(concurrency2)?concurrency2:null)}if(detectLibc.familySync()===detectLibc.GLIBC&&!sharp._isUsingJemalloc())sharp.concurrency(1);else if(detectLibc.familySync()===detectLibc.MUSL&&sharp.concurrency()===1024)sharp.concurrency(__require("os").availableParallelism());var queue=new events.EventEmitter;function counters(){return sharp.counters()}function simd(simd2){return sharp.simd(is2.bool(simd2)?simd2:null)}function block(options){if(is2.object(options))if(Array.isArray(options.operation)&&options.operation.every(is2.string))sharp.block(options.operation,!0);else throw is2.invalidParameterError("operation","Array<string>",options.operation);else throw is2.invalidParameterError("options","object",options)}function unblock(options){if(is2.object(options))if(Array.isArray(options.operation)&&options.operation.every(is2.string))sharp.block(options.operation,!1);else throw is2.invalidParameterError("operation","Array<string>",options.operation);else throw is2.invalidParameterError("options","object",options)}module.exports=function(Sharp){Sharp.cache=cache,Sharp.concurrency=concurrency,Sharp.counters=counters,Sharp.simd=simd,Sharp.format=format2,Sharp.interpolators=interpolators,Sharp.versions=versions,Sharp.queue=queue,Sharp.block=block,Sharp.unblock=unblock}});var require_lib=__commonJS((exports,module)=>{var Sharp=require_constructor();require_input()(Sharp);require_resize()(Sharp);require_composite()(Sharp);require_operation()(Sharp);require_colour()(Sharp);require_channel()(Sharp);require_output()(Sharp);require_utility()(Sharp);module.exports=Sharp});import{randomUUID as randomUUID6}from"crypto";import{mkdir as mkdir5,rename as rename3,stat as stat5,unlink as unlink5}from"fs/promises";import path3 from"path";function mergeTransformConfig(config){if(!config)return DEFAULT_TRANSFORM;return{enabled:config.enabled??DEFAULT_TRANSFORM.enabled,maxWidth:config.maxWidth??DEFAULT_TRANSFORM.maxWidth,maxHeight:config.maxHeight??DEFAULT_TRANSFORM.maxHeight,defaultQuality:config.defaultQuality??DEFAULT_TRANSFORM.defaultQuality,allowedFormats:config.allowedFormats??DEFAULT_TRANSFORM.allowedFormats,cacheSubdir:config.cacheSubdir??DEFAULT_TRANSFORM.cacheSubdir,maxInputPixels:config.maxInputPixels??DEFAULT_TRANSFORM.maxInputPixels,pregenerate:{enabled:config.pregenerate?.enabled??DEFAULT_PREGENERATE.enabled,widths:config.pregenerate?.widths??DEFAULT_PREGENERATE.widths,formats:config.pregenerate?.formats??DEFAULT_PREGENERATE.formats,quality:config.pregenerate?.quality}}}function isTransformableImage(mimeType){return(mimeType.split(";")[0]?.trim().toLowerCase()??"")in MIME_TO_FORMAT}function clampInt(raw,min,max){if(raw===void 0)return;let n=Number.parseInt(raw,10);if(!Number.isFinite(n))return;return Math.min(max,Math.max(min,n))}function parseTransformParams(query,config){let width=clampInt(query.w,1,config.maxWidth),height=clampInt(query.h,1,config.maxHeight),qualityRaw=clampInt(query.q,1,100),requestedFormat=query.format?.trim().toLowerCase(),format2=requestedFormat&&config.allowedFormats.includes(requestedFormat)?requestedFormat:void 0;if(width===void 0&&height===void 0&&qualityRaw===void 0&&!format2)return null;return{width,height,quality:qualityRaw??config.defaultQuality,format:format2}}function deriveCacheKey(mtimeMs,params,outputFormat){return[`m${Math.floor(mtimeMs)}`,params.width?`w${params.width}`:"w0",params.height?`h${params.height}`:"h0",`q${params.quality}`,outputFormat].join("-")}async function loadSharp(logger2){if(sharpModule!==void 0)return sharpModule;try{let mod=await Promise.resolve().then(() => __toESM(require_lib(),1));sharpModule=mod.default??mod}catch{sharpModule=null,logger2.error('[CDN] storage.cdn.transform.enabled is true but the optional "sharp" dependency is not installed. Run `npm i sharp` to enable image transforms. Serving original files untouched.')}return sharpModule}async function ensureDerivative(args){let{sourcePath,mimeType,params,storagePath,config,logger:logger2}=args;if(!isTransformableImage(mimeType))return null;let outputFormat=params.format??MIME_TO_FORMAT[mimeType.toLowerCase()];if(!outputFormat)return null;let sharp=await loadSharp(logger2);if(!sharp)return null;let idPart=path3.basename(sourcePath).replace(/[^A-Za-z0-9._-]+/g,"_")||"f",srcStat=await stat5(sourcePath).catch(()=>null);if(!srcStat)return null;let key2=deriveCacheKey(srcStat.mtimeMs,params,outputFormat),cacheDir=path3.join(storagePath,config.cacheSubdir,idPart),cachePath=path3.join(cacheDir,`${key2}.${outputFormat}`);if(!isPathWithinBase(storagePath,cachePath))return null;let contentType=FORMAT_TO_MIME[outputFormat],etag=`"${idPart}-${key2}"`,cached=await stat5(cachePath).catch(()=>null);if(cached?.isFile()&&cached.size>0)return{path:cachePath,contentType,etag};let pending=inFlightDerivatives.get(cachePath);if(pending)return pending;let task=(async()=>{let tmpPath=null;try{let pipeline=sharp(sourcePath,{limitInputPixels:config.maxInputPixels,failOn:"none"});if(params.width||params.height)pipeline.resize({width:params.width,height:params.height,fit:"inside",withoutEnlargement:!0});switch(outputFormat){case"webp":pipeline.webp({quality:params.quality});break;case"avif":pipeline.avif({quality:params.quality});break;case"jpeg":pipeline.jpeg({quality:params.quality});break;case"png":pipeline.png({quality:params.quality});break}let buffer=await pipeline.toBuffer();if(buffer.length===0)return logger2.error(`[CDN] image transform produced an empty buffer for ${idPart}; serving original.`),null;return await mkdir5(cacheDir,{recursive:!0}),tmpPath=`${cachePath}.${randomUUID6()}.tmp`,await Bun.write(tmpPath,buffer),await rename3(tmpPath,cachePath),tmpPath=null,{path:cachePath,contentType,etag}}catch(err){if(tmpPath)await unlink5(tmpPath).catch(()=>{});return logger2.error(`[CDN] image transform failed for ${idPart}; serving original. ${String(err)}`),null}})();inFlightDerivatives.set(cachePath,task);try{return await task}finally{inFlightDerivatives.delete(cachePath)}}async function pregenerateImageVariants(args){let{sourcePath,mimeType,storagePath,config,logger:logger2}=args,pg=config.pregenerate;if(!config.enabled||!pg.enabled||!isTransformableImage(mimeType))return 0;if(pg.widths.length===0||pg.formats.length===0)return 0;let quality=pg.quality??config.defaultQuality,made=0;for(let width of pg.widths)for(let format2 of pg.formats)if(await ensureDerivative({sourcePath,mimeType,params:{width,quality,format:format2},storagePath,config,logger:logger2}))made+=1;return made}var DEFAULT_PREGENERATE,DEFAULT_TRANSFORM,MIME_TO_FORMAT,FORMAT_TO_MIME,sharpModule,inFlightDerivatives;var init_imageTransform=__esm(()=>{init_helpers2();DEFAULT_PREGENERATE={enabled:!1,widths:[],formats:["webp"]},DEFAULT_TRANSFORM={enabled:!1,maxWidth:3840,maxHeight:3840,defaultQuality:80,allowedFormats:["webp","avif","jpeg","png"],cacheSubdir:".cache/cdn",maxInputPixels:1e8,pregenerate:DEFAULT_PREGENERATE};MIME_TO_FORMAT={"image/webp":"webp","image/avif":"avif","image/jpeg":"jpeg","image/jpg":"jpeg","image/png":"png"},FORMAT_TO_MIME={webp:"image/webp",avif:"image/avif",jpeg:"image/jpeg",png:"image/png"};inFlightDerivatives=new Map});import{mkdir as mkdir6,stat as stat6}from"fs/promises";import path4 from"path";function mergeVideoConfig(config){if(!config)return DEFAULT_VIDEO;return{enabled:config.enabled??DEFAULT_VIDEO.enabled,transcode:config.transcode??DEFAULT_VIDEO.transcode,poster:config.poster??DEFAULT_VIDEO.poster,posterFormat:config.posterFormat??DEFAULT_VIDEO.posterFormat,crf:config.crf??DEFAULT_VIDEO.crf,maxWidth:config.maxWidth??DEFAULT_VIDEO.maxWidth,ffmpegPath:config.ffmpegPath??DEFAULT_VIDEO.ffmpegPath}}function isTransformableVideo(mimeType){return(mimeType.split(";")[0]?.trim().toLowerCase()??"").startsWith("video/")}function idPartOf(sourcePath){return path4.basename(sourcePath).replace(/[^A-Za-z0-9._-]+/g,"_")||"f"}function variantPath(storagePath,cacheSubdir,sourcePath,mtimeMs,suffix){return path4.join(storagePath,cacheSubdir,idPartOf(sourcePath),`video-m${Math.floor(mtimeMs)}-${suffix}`)}async function checkFfmpeg(ffmpegPath,logger2){if(ffmpegAvailable!==void 0)return ffmpegAvailable;try{ffmpegAvailable=await Bun.spawn({cmd:[ffmpegPath,"-version"],stdout:"ignore",stderr:"ignore"}).exited===0}catch{ffmpegAvailable=!1}if(!ffmpegAvailable)logger2.error(`[CDN] storage.cdn.video.enabled is true but ffmpeg ("${ffmpegPath}") was not found on PATH. Install ffmpeg to enable video transcode/poster. Serving original videos untouched.`);return ffmpegAvailable}async function runFfmpeg(ffmpegPath,args){try{return await Bun.spawn({cmd:[ffmpegPath,...args],stdout:"ignore",stderr:"ignore"}).exited===0}catch{return!1}}async function resolveVideoVariant(args){let{sourcePath,storagePath,cacheSubdir,posterFormat,kind}=args,srcStat=await stat6(sourcePath).catch(()=>null);if(!srcStat)return null;let suffix=kind==="web"?"web.mp4":`poster.${posterFormat==="webp"?"webp":"jpg"}`,p=variantPath(storagePath,cacheSubdir,sourcePath,srcStat.mtimeMs,suffix);if(!isPathWithinBase(storagePath,p))return null;if(!await Bun.file(p).exists())return null;let contentType=kind==="web"?"video/mp4":POSTER_MIME[posterFormat];return{path:p,contentType}}async function processVideoOnUpload(args){let{sourcePath,mimeType,storagePath,cacheSubdir,config,logger:logger2}=args;if(!config.enabled||!isTransformableVideo(mimeType))return;if(!await checkFfmpeg(config.ffmpegPath,logger2))return;let srcStat=await stat6(sourcePath).catch(()=>null);if(!srcStat)return;let dir=path4.join(storagePath,cacheSubdir,idPartOf(sourcePath));if(await mkdir6(dir,{recursive:!0}).catch(()=>{}),config.transcode){let out=variantPath(storagePath,cacheSubdir,sourcePath,srcStat.mtimeMs,"web.mp4");if(isPathWithinBase(storagePath,out)&&!await Bun.file(out).exists()){if(!await runFfmpeg(config.ffmpegPath,["-y","-i",sourcePath,"-vf",`scale='min(${config.maxWidth},iw)':-2`,"-c:v","libx264","-crf",String(config.crf),"-preset","medium","-c:a","aac","-movflags","+faststart",out]))logger2.error(`[CDN] video transcode failed for ${idPartOf(sourcePath)}`)}}if(config.poster){let ext=config.posterFormat==="webp"?"webp":"jpg",out=variantPath(storagePath,cacheSubdir,sourcePath,srcStat.mtimeMs,`poster.${ext}`);if(isPathWithinBase(storagePath,out)&&!await Bun.file(out).exists()){let posterArgs=["-y","-i",sourcePath,"-frames:v","1"];if(config.posterFormat==="webp")posterArgs.push("-c:v","libwebp");else posterArgs.push("-q:v","3");if(posterArgs.push(out),!await runFfmpeg(config.ffmpegPath,posterArgs))logger2.error(`[CDN] video poster failed for ${idPartOf(sourcePath)}`)}}}var DEFAULT_VIDEO,POSTER_MIME,ffmpegAvailable;var init_videoTransform=__esm(()=>{init_helpers2();DEFAULT_VIDEO={enabled:!1,transcode:!0,poster:!0,posterFormat:"jpeg",crf:23,maxWidth:1920,ffmpegPath:"ffmpeg"};POSTER_MIME={jpeg:"image/jpeg",webp:"image/webp"}});import path5 from"path";import Elysia4,{t as t3}from"elysia";function mergeCdnConfig(config){if(!config)return DEFAULT_CDN_CONFIG;return{enabled:config.enabled??DEFAULT_CDN_CONFIG.enabled,basePath:config.basePath??DEFAULT_CDN_CONFIG.basePath,cacheMaxAge:config.cacheMaxAge??DEFAULT_CDN_CONFIG.cacheMaxAge,enableRangeRequests:config.enableRangeRequests??DEFAULT_CDN_CONFIG.enableRangeRequests,enableEtag:config.enableEtag??DEFAULT_CDN_CONFIG.enableEtag,corsOrigins:config.corsOrigins??DEFAULT_CDN_CONFIG.corsOrigins,transform:mergeTransformConfig(config.transform),video:mergeVideoConfig(config.video)}}function getMimeTypeDisposition(mimeType,forceDownload=!1){let normalized=mimeType.split(";")[0]?.trim().toLowerCase()??"";if(NEVER_INLINE.has(normalized))return"attachment";if(forceDownload)return"attachment";let inlineTypes=["image/","video/","audio/","text/","application/pdf"];for(let type of inlineTypes)if(normalized.startsWith(type)||normalized===type)return"inline";return"attachment"}function sanitizeFilename(filename){return filename.replace(/[^A-Za-z0-9._-]+/g,"_").replace(/_{2,}/g,"_").slice(0,200)}function buildContentDisposition(type,fileName){return`${type}; filename="${sanitizeFilename(fileName)}"; filename*=UTF-8''${encodeURIComponent(fileName)}`}function isTraversalId(id){return id.includes("/")||id.includes("\\")||id.includes("..")||id.includes("\x00")}function resolveTenantSchema(request){return request.headers.get("x-tenant-schema")||void 0}function createCdnRoutes(config){let{cdn,storagePath,logger:logger2,getFileRecord,getStorageProvider:getStorageProvider2}=config,materialize=async(absolutePath)=>{let provider=getStorageProvider2?.();if(!provider||provider.kind==="local")return absolutePath;let relative=path5.relative(storagePath,absolutePath);if(!relative||relative.startsWith(".."))return absolutePath;return await provider.localPath(relative)??absolutePath},plugin=new Elysia4({prefix:cdn.basePath});if(!cdn.enabled)return plugin;return plugin.get("/:id",async({params,request,set,query})=>{let{id}=params;if(isTraversalId(id))return set.status=400,{success:!1,message:"Invalid file id"};let schemaName=resolveTenantSchema(request),filePath,fileName,mimeType;if(getFileRecord){let fileRecord=await getFileRecord(id,schemaName);if(!fileRecord)return set.status=404,{success:!1,message:"File not found"};filePath=path5.join(fileRecord.path,fileRecord.name),fileName=fileRecord.name,mimeType=fileRecord.mimeType||fileRecord.mime_type||"application/octet-stream"}else filePath=path5.join(storagePath,id),fileName=id,mimeType="application/octet-stream";if(!isPathWithinBase(storagePath,filePath))return set.status=404,{success:!1,message:"File not found"};if(filePath=await materialize(filePath),!await fileManager.exists(filePath))return set.status=404,{success:!1,message:"Physical file not found"};if(cdn.video.enabled&&isTransformableVideo(mimeType)){let wantPoster=query.poster!==void 0&&query.poster!=="0"&&query.poster!=="false",variant=await resolveVideoVariant({sourcePath:filePath,storagePath,cacheSubdir:cdn.transform.cacheSubdir,posterFormat:cdn.video.posterFormat,kind:wantPoster?"poster":"web"});if(variant)filePath=variant.path,mimeType=variant.contentType}let fileInfo=await fileManager.getFileInfo(filePath),lastModified=new Date(fileInfo.modifiedAt||Date.now()).toUTCString(),etag=cdn.enableEtag?`"${fileInfo.size}-${fileInfo.modifiedAt?.getTime()||Date.now()}"`:void 0,cacheHeaders={"Cache-Control":`public, max-age=${cdn.cacheMaxAge}`,"Last-Modified":lastModified};if(etag)cacheHeaders.ETag=etag;if(cdn.corsOrigins.length>0)cacheHeaders["Access-Control-Allow-Origin"]=cdn.corsOrigins[0]==="*"?"*":cdn.corsOrigins.join(", "),cacheHeaders["Access-Control-Allow-Methods"]="GET, HEAD, OPTIONS";if(cdn.transform.enabled&&isTransformableImage(mimeType)){let transformParams=parseTransformParams(query,cdn.transform);if(transformParams){let derivative=await ensureDerivative({sourcePath:filePath,mimeType,params:transformParams,storagePath,config:cdn.transform,logger:logger2});if(derivative){let derivativeInfo=await fileManager.getFileInfo(derivative.path),derivativeHeaders={...cacheHeaders,"Content-Type":derivative.contentType,"Content-Disposition":`inline; filename="${sanitizeFilename(fileName)}"`,"X-Content-Type-Options":"nosniff"};if(cdn.enableEtag)derivativeHeaders.ETag=derivative.etag;else delete derivativeHeaders.ETag;if(cdn.enableEtag&&request.headers.get("if-none-match")===derivative.etag)return new Response(null,{status:304,headers:derivativeHeaders});return new Response(Bun.file(derivative.path),{status:200,headers:{"Content-Length":derivativeInfo.size.toString(),...derivativeHeaders}})}}}let forceDownload=query.download!==void 0&&query.download!=="0"&&query.download!=="false",dispositionType=getMimeTypeDisposition(mimeType,forceDownload),contentDisposition=buildContentDisposition(dispositionType,fileName),ifNoneMatch=request.headers.get("if-none-match");if(etag&&ifNoneMatch===etag)return new Response(null,{status:304,headers:cacheHeaders});let bunFile=Bun.file(filePath),range=request.headers.get("range");if(cdn.enableRangeRequests&&range){let rangeMatch=range.match(/bytes=(\d*)-(\d*)/);if(!rangeMatch)return set.status=416,new Response("Range not satisfiable",{status:416,headers:{"Content-Range":`bytes */${fileInfo.size}`,"Content-Type":mimeType,"X-Content-Type-Options":"nosniff",...cacheHeaders}});let startStr=rangeMatch[1]||"0",endStr=rangeMatch[2]||"",start=parseInt(startStr,10),end=endStr?parseInt(endStr,10):fileInfo.size-1;if(start>=fileInfo.size||end>=fileInfo.size||start>end)return new Response("Range not satisfiable",{status:416,headers:{"Content-Range":`bytes */${fileInfo.size}`,"Content-Type":mimeType,"X-Content-Type-Options":"nosniff",...cacheHeaders}});let chunkSize=end-start+1,chunkBlob=bunFile.slice(start,end+1);return new Response(chunkBlob,{status:206,headers:{"Content-Range":`bytes ${start}-${end}/${fileInfo.size}`,"Accept-Ranges":"bytes","Content-Length":chunkSize.toString(),"Content-Type":mimeType,"Content-Disposition":contentDisposition,"X-Content-Type-Options":"nosniff",...cacheHeaders}})}return new Response(bunFile,{status:200,headers:{"Content-Length":fileInfo.size.toString(),"Content-Type":mimeType,"Accept-Ranges":cdn.enableRangeRequests?"bytes":"none","Content-Disposition":contentDisposition,"X-Content-Type-Options":"nosniff",...cacheHeaders}})},{params:t3.Object({id:t3.String()}),detail:{tags:["CDN"],summary:"Get file by ID",description:"Serve file with streaming, range requests, and caching support"}}),plugin.head("/:id",async({params,request,set})=>{let{id}=params;if(isTraversalId(id))return set.status=400,new Response(null,{status:400});let schemaName=resolveTenantSchema(request),filePath,mimeType,fileName;if(getFileRecord){let fileRecord=await getFileRecord(id,schemaName);if(!fileRecord)return set.status=404,new Response(null,{status:404});filePath=path5.join(fileRecord.path,fileRecord.name),mimeType=fileRecord.mime_type||"application/octet-stream",fileName=fileRecord.name}else filePath=path5.join(storagePath,id),mimeType="application/octet-stream",fileName=id;if(!isPathWithinBase(storagePath,filePath))return set.status=404,new Response(null,{status:404});if(filePath=await materialize(filePath),!await fileManager.exists(filePath))return set.status=404,new Response(null,{status:404});let fileInfo=await fileManager.getFileInfo(filePath),lastModified=new Date(fileInfo.modifiedAt||Date.now()).toUTCString(),etag=cdn.enableEtag?`"${fileInfo.size}-${fileInfo.modifiedAt?.getTime()||Date.now()}"`:void 0,headers={"Content-Length":fileInfo.size.toString(),"Content-Type":mimeType,"Content-Disposition":buildContentDisposition(getMimeTypeDisposition(mimeType),fileName),"X-Content-Type-Options":"nosniff","Accept-Ranges":cdn.enableRangeRequests?"bytes":"none","Cache-Control":`public, max-age=${cdn.cacheMaxAge}`,"Last-Modified":lastModified};if(etag)headers.ETag=etag;if(cdn.corsOrigins.length>0)headers["Access-Control-Allow-Origin"]=cdn.corsOrigins[0]==="*"?"*":cdn.corsOrigins.join(", "),headers["Access-Control-Allow-Methods"]="GET, HEAD, OPTIONS";return new Response(null,{status:200,headers})},{params:t3.Object({id:t3.String()}),detail:{tags:["CDN"],summary:"Get file metadata",description:"Get file headers without body for preflight checks"}}),logger2.info(`[CDN] Routes enabled at ${cdn.basePath}`),plugin}var DEFAULT_CDN_CONFIG,NEVER_INLINE;var init_cdn=__esm(()=>{init_File();init_helpers2();init_imageTransform();init_videoTransform();DEFAULT_CDN_CONFIG={enabled:!0,basePath:"/cdn",cacheMaxAge:86400,enableRangeRequests:!0,enableEtag:!0,corsOrigins:["*"],transform:mergeTransformConfig(),video:mergeVideoConfig()};NEVER_INLINE=new Set(["text/html","application/xhtml+xml","image/svg+xml","application/xml","text/xml","application/javascript","text/javascript","application/ecmascript","text/ecmascript","application/x-httpd-php"])});function buildFileRecordPayload(upload,userId){return{id:upload.id,name:upload.name,originalName:upload.originalName,path:upload.path,mimeType:upload.mimeType,size:upload.size,extension:upload.originalName.split(".").pop()||"",uploadedBy:userId??null}}async function persistUploadedFiles(args){let{db,filesTable,files,storageConfig,subFolder,userId}=args,uploaded=await uploadFiles(files,storageConfig,subFolder),records=[];for(let upload of uploaded.success){let payload=buildFileRecordPayload(upload,userId);payload.createdBy=userId??null,await db.insert(filesTable).values(payload),records.push({id:upload.id,name:upload.name,originalName:upload.originalName,path:upload.path,mimeType:upload.mimeType,size:upload.size,extension:payload.extension})}return{records,failed:uploaded.failed}}var init_file_record=__esm(()=>{init_helpers2()});import path6 from"path";function scheduleUploadMediaProcessing(records,opts){let{storagePath,media,logger:logger2}=opts,{transform,video}=media,imagesOn=transform.enabled&&transform.pregenerate.enabled,videoOn=video.enabled;if(!imagesOn&&!videoOn)return;for(let record of records){let sourcePath=path6.join(record.path,record.name);if(imagesOn&&isTransformableImage(record.mimeType))pregenerateImageVariants({sourcePath,mimeType:record.mimeType,storagePath,config:transform,logger:logger2}).catch(()=>{});if(videoOn&&isTransformableVideo(record.mimeType))processVideoOnUpload({sourcePath,mimeType:record.mimeType,storagePath,cacheSubdir:transform.cacheSubdir,config:video,logger:logger2}).catch(()=>{})}}var init_mediaPostProcess=__esm(()=>{init_imageTransform();init_videoTransform()});var exports_storage={};__export(exports_storage,{validateFile:()=>validateFile,uploadFiles:()=>uploadFiles,uploadFile:()=>uploadFile,setStorageProvider:()=>setStorageProvider,scheduleUploadMediaProcessing:()=>scheduleUploadMediaProcessing,persistUploadedFiles:()=>persistUploadedFiles,parseFormDataBody:()=>parseFormDataBody,mergeVideoConfig:()=>mergeVideoConfig,mergeTransformConfig:()=>mergeTransformConfig,mergeStorageConfig:()=>mergeStorageConfig,mergeCdnConfig:()=>mergeCdnConfig,getStorageProvider:()=>getStorageProvider,deleteFile:()=>deleteFile,createCdnRoutes:()=>createCdnRoutes,buildFileRecordPayload:()=>buildFileRecordPayload});var init_storage2=__esm(()=>{init_cdn();init_file_record();init_helpers2();init_imageTransform();init_mediaPostProcess();init_videoTransform()});var exports_helpers={};__export(exports_helpers,{scanUndeclaredEnv:()=>scanUndeclaredEnv,scanEnvVars:()=>scanEnvVars,readOverridesFromRedis:()=>readOverridesFromRedis,persistSectionToRedis:()=>persistSectionToRedis,persistConfigToDisk:()=>persistConfigToDisk,maskUrlCredentials:()=>maskUrlCredentials,maskSensitiveFields:()=>maskSensitiveFields,looksSecretValue:()=>looksSecretValue,loadOverridesFromRedis:()=>loadOverridesFromRedis,isRestartRequired:()=>isRestartRequired,hasSection:()=>hasSection,extractSection:()=>extractSection,deepMerge:()=>deepMerge,clearOverridesFromRedis:()=>clearOverridesFromRedis,buildSectionsMeta:()=>buildSectionsMeta,applySectionUpdate:()=>applySectionUpdate});var SENSITIVE_KEY_PATTERNS,FORBIDDEN_SECTION_KEYS,isSensitiveKey=(key2)=>SENSITIVE_KEY_PATTERNS.some((pattern)=>pattern.test(key2)),URL_CREDENTIALS,maskUrlCredentials=(value)=>value.replace(URL_CREDENTIALS,"$1***$2"),B64ISH_VALUE,looksSecretValue=(value)=>{if(!value)return!1;let v=value.trim();if(v.length>=60&&B64ISH_VALUE.test(v))return!0;return v.includes("PRIVATE KEY")||v.includes("BEGIN ")||v.includes('"private_key"')},RESTART_REQUIRED_KEYS,asRecord=(config)=>config,maskSensitiveFields=(obj)=>{let result={};for(let[key2,value]of Object.entries(obj)){if(isSensitiveKey(key2)&&typeof value==="string"){result[key2]="***";continue}if(Array.isArray(value)){result[key2]=value.map((item)=>typeof item==="object"&&item!==null?maskSensitiveFields(item):item);continue}if(typeof value==="object"&&value!==null){result[key2]=maskSensitiveFields(value);continue}result[key2]=typeof value==="string"?maskUrlCredentials(value):value}return result},buildSectionsMeta=(config)=>{let record=asRecord(config);return Object.keys(record).filter((key2)=>record[key2]!==void 0).map((key2)=>{let value=record[key2],type=Array.isArray(value)?"array":typeof value==="object"&&value!==null?"object":"primitive";return{key:key2,type,restartRequired:RESTART_REQUIRED_KEYS.has(key2)}})},extractSection=(config,section)=>asRecord(config)[section],hasSection=(config,section)=>Object.hasOwn(asRecord(config),section),applySectionUpdate=(config,section,value)=>{if(FORBIDDEN_SECTION_KEYS.has(section))return;asRecord(config)[section]=value},isRestartRequired=(section)=>RESTART_REQUIRED_KEYS.has(section),ENV_VAR_PATTERN,scanEnvVars=(obj,parentPath="")=>{let entries=[];for(let[key2,value]of Object.entries(obj)){let currentPath=parentPath?`${parentPath}.${key2}`:key2;if(typeof value==="string"&&ENV_VAR_PATTERN.test(value)){let envValue=process.env[value],valueIsSecret=envValue!==void 0&&looksSecretValue(envValue);entries.push({configPath:currentPath,envName:value,resolved:envValue!==void 0,value:envValue!==void 0?isSensitiveKey(key2)||valueIsSecret?"***":maskUrlCredentials(envValue):null,isSecret:isSensitiveKey(key2)||valueIsSecret,recognized:!0});continue}if(Array.isArray(value)){for(let i=0;i<value.length;i++){let item=value[i];if(typeof item==="object"&&item!==null)entries.push(...scanEnvVars(item,`${currentPath}[${i}]`))}continue}if(typeof value==="object"&&value!==null)entries.push(...scanEnvVars(value,currentPath))}return entries},K8S_LINK_RE,SYSTEM_ENV,SYSTEM_PREFIXES,PROVIDER_KEY_TOKENS,isProviderApiKey=(name2)=>{let upper=name2.toUpperCase();return upper.endsWith("_API_KEY")&&PROVIDER_KEY_TOKENS.some((token)=>upper.includes(token))},isInfraNoise=(name2,value)=>{if(SYSTEM_ENV.has(name2))return!0;if(SYSTEM_PREFIXES.some((prefix)=>name2.startsWith(prefix)))return!0;if(K8S_LINK_RE.test(name2))return!0;if(name2.endsWith("_PORT")&&value.startsWith("tcp://"))return!0;return!1},scanUndeclaredEnv=(declaredNames)=>{let entries=[];for(let[name2,rawValue]of Object.entries(process.env)){if(declaredNames.has(name2))continue;let value=rawValue??"";if(isInfraNoise(name2,value))continue;if(isProviderApiKey(name2))continue;let resolved=value!=="",valueIsSecret=looksSecretValue(value);entries.push({configPath:name2,envName:name2,resolved,value:resolved?isSensitiveKey(name2)||valueIsSecret?"***":maskUrlCredentials(value):null,isSecret:isSensitiveKey(name2)||valueIsSecret,recognized:!1})}return entries},buildRedisKey=(appId)=>`nucleus:config:overrides:${appId}`,persistConfigToDisk=async(configFilePath,config)=>{let fs4=__require("fs"),record=asRecord(config),persistable={};for(let[k,v]of Object.entries(record))if(k!=="configManagement")persistable[k]=v;let content=JSON.stringify(persistable,null,2);fs4.writeFileSync(configFilePath,content,"utf-8")},persistSectionToRedis=async(redis,appId,section,value)=>{let redisKey=buildRedisKey(appId),existing=await redis.read(redisKey),overrides=existing.success&&existing.data?existing.data:{};overrides[section]=value,await redis.create(redisKey,JSON.stringify(overrides))},readOverridesFromRedis=async(redis,appId)=>{let redisKey=buildRedisKey(appId),result=await redis.read(redisKey);if(!result.success||!result.data)return null;return result.data},clearOverridesFromRedis=async(redis,appId)=>{let redisKey=buildRedisKey(appId);await redis.create(redisKey,JSON.stringify({}))},loadOverridesFromRedis=async(redis,appId,config)=>{let redisKey=buildRedisKey(appId),result=await redis.read(redisKey);if(!result.success||!result.data)return[];let overrides=result.data,appliedSections=[],record=asRecord(config);for(let[section,value]of Object.entries(overrides)){if(FORBIDDEN_SECTION_KEYS.has(section))continue;let current=record[section];if(typeof value==="object"&&value!==null&&!Array.isArray(value)&&typeof current==="object"&¤t!==null&&!Array.isArray(current))record[section]=deepMerge(current,value);else record[section]=value;appliedSections.push(section)}return appliedSections},deepMerge=(target2,source)=>{let result={...target2};for(let[key2,sourceValue]of Object.entries(source)){if(FORBIDDEN_SECTION_KEYS.has(key2))continue;let targetValue=target2[key2];if(typeof sourceValue==="object"&&sourceValue!==null&&!Array.isArray(sourceValue)&&typeof targetValue==="object"&&targetValue!==null&&!Array.isArray(targetValue))result[key2]=deepMerge(targetValue,sourceValue);else result[key2]=sourceValue}return result};var init_helpers3=__esm(()=>{SENSITIVE_KEY_PATTERNS=[/secret/i,/password/i,/token/i,/^apiKey$/i,/^secretKey$/i,/^webhookSecret$/i,/connection_string/i,/connectionString/i,/^clientSecret$/i,/json_file_path/i,/key$/i,/salt/i,/passphrase/i,/credential/i],FORBIDDEN_SECTION_KEYS=new Set(["__proto__","constructor","prototype"]),URL_CREDENTIALS=/^([a-z][a-z0-9+.-]*:\/\/[^/\s:@]*:)[^/\s@]+(@)/i,B64ISH_VALUE=/^[A-Za-z0-9+/=_-]{60,}$/,RESTART_REQUIRED_KEYS=new Set(["appId","mode","database","redis","authentication","authorization","email","payment","entities"]),ENV_VAR_PATTERN=/^[A-Z][A-Z0-9_]{2,}$/,K8S_LINK_RE=/(_SERVICE_HOST|_SERVICE_PORT.*|_PORT_\d+_TCP.*)$/,SYSTEM_ENV=new Set(["PATH","HOME","HOSTNAME","PWD","OLDPWD","TERM","SHLVL","_","LANG","TZ","container","VIRTUAL_ENV","DEBIAN_FRONTEND"]),SYSTEM_PREFIXES=["LC_","GPG_","PYTHON","SSL_CERT","KUBERNETES_"],PROVIDER_KEY_TOKENS=["OPENAI","CLAUDE","ANTHROPIC","GEMINI","GOOGLE","XAI","GROQ","COHERE","ZAI","OLLAMA","KIE","DEEPGRAM","ELEVENLABS","AZURE_OPENAI","MISTRAL","PERPLEXITY","TOGETHER","FIREWORKS","REPLICATE","STABILITY","RUNWAY","HUGGINGFACE","VOYAGE","JINA"]});function hasGodminRole(request){return decodeHeaderList(request.headers.get("x-user-roles")).some((r)=>isGodminRole(r))}async function userHasGodminRoleInDb(db,schemaTables,userId,logger2){if(!userId||!db)return!1;let userRolesTable=schemaTables[AUTHORIZATION_TABLE_KEYS.userRoles],rolesTable=schemaTables[AUTHORIZATION_TABLE_KEYS.roles];if(!userRolesTable||!rolesTable)return!1;try{let{eq:eq28}=await import("drizzle-orm"),ur=userRolesTable,r=rolesTable;return(await db.select({roleName:r.name}).from(userRolesTable).innerJoin(rolesTable,eq28(ur.roleId,r.id)).where(eq28(ur.userId,userId))).some((row)=>isGodminRole(String(row.roleName??"")))}catch(err){return logger2.warn("[AdminGuard] Failed to check godmin role from DB",{error:err instanceof Error?err.message:String(err)}),!1}}async function isGodminRequest(request,deps){if(decodeHeaderList(request.headers.get("x-user-roles")).some((r)=>isGodminRole(r)))return!0;let userId=request.headers.get("x-user-id"),{db,schemaTables,logger:logger2}=deps;if(userId&&db&&schemaTables.users)try{let{eq:eq28}=await import("drizzle-orm"),usersTable=schemaTables.users;if((await db.select().from(usersTable).where(eq28(usersTable.id,userId)).limit(1))[0]?.isGod===!0)return!0}catch(err){logger2.warn("[AdminGuard] Failed to check isGod from DB",{error:err instanceof Error?err.message:String(err)})}return!1}function createGodminGuard(deps,label="this operation"){return async({request,set})=>{if(!request.headers.get("x-user-id"))return set.status=401,Response.json({isSuccess:!1,success:!1,message:"Authentication required",data:null});if(!await isGodminRequest(request,deps))return set.status=403,Response.json({isSuccess:!1,success:!1,message:`Forbidden: ${label} requires godmin privileges`,data:null});return}}var init_adminGuard=__esm(()=>{init_Authorization();init_types3()});function toCamel4(name2){return name2.replace(/_([a-z])/g,(_,letter)=>letter.toUpperCase())}function registerSensitiveColumns(names2){for(let name2 of names2)registry.add(name2),registry.add(toCamel4(name2))}function isConfigSensitiveKey(key2){return registry.has(key2)}function sensitiveColumnNames(){return[...registry]}function sensitiveFieldQueryable(field,opts){if(!isConfigSensitiveKey(field))return!0;if(!opts.authEnabled)return!1;return opts.allowedFields?.includes(field)===!0}function stripUnclaimedSensitive(row,allowedFields){if(allowedFields&&allowedFields.length>0)return row;if(registry.size===0)return row;return scrub(row)}function scrub(value){if(value===null||typeof value!=="object")return value;if(Array.isArray(value))return value.map(scrub);let proto=Object.getPrototypeOf(value);if(proto!==Object.prototype&&proto!==null)return value;let out={};for(let[k,v]of Object.entries(value)){if(registry.has(k))continue;out[k]=scrub(v)}return out}var registry;var init_sensitiveColumns=__esm(()=>{registry=new Set});function createGodminGuard2(deps){let{logger:logger2,db,schemaTables,area}=deps,allowedRoles=new Set((deps.allowedRoles??[]).map((role)=>role.toLowerCase()));return async({request,set})=>{let roles=decodeHeaderList(request.headers.get("x-user-roles"));if(roles.includes(GODMIN_ROLE_NAME))return;if(allowedRoles.size>0&&roles.some((role)=>allowedRoles.has(role.toLowerCase())))return;let userId=request.headers.get("x-user-id");if(userId&&db&&schemaTables.users)try{let{eq:eq31}=await import("drizzle-orm"),usersTable=schemaTables.users;if((await db.select().from(usersTable).where(eq31(usersTable.id,userId)).limit(1))[0]?.isGod===!0)return}catch(err){logger2.warn(`[${area}] Failed to check isGod from DB`,{error:err instanceof Error?err.message:String(err)})}return set.status=403,Response.json({isSuccess:!1,message:allowedRoles.size>0?`${area} requires godmin or one of: ${[...allowedRoles].join(", ")}`:`Only godmin users can access ${area}`,data:null})}}var init_godminGuard=__esm(()=>{init_Authorization()});var exports_ack_manager={};__export(exports_ack_manager,{storePendingMessage:()=>storePendingMessage,removePendingMessage:()=>removePendingMessage,recordSent:()=>recordSent,recordFailed:()=>recordFailed,recordAcked:()=>recordAcked,initAckCleanup:()=>initAckCleanup,incrementRetryCount:()=>incrementRetryCount,getPendingMessagesForUser:()=>getPendingMessagesForUser,getPendingMessageCount:()=>getPendingMessageCount,getDeliveryStats:()=>getDeliveryStats,generateMessageId:()=>generateMessageId,destroyAckCleanup:()=>destroyAckCleanup,acknowledgeMessage:()=>acknowledgeMessage});function cleanupRecentAcks(){let now=Date.now();for(let[key2,timestamp]of recentAcks)if(now-timestamp>1e4)recentAcks.delete(key2)}function initAckCleanup(){if(cleanupInterval)return;cleanupInterval=setInterval(cleanupRecentAcks,30000),cleanupInterval.unref?.()}function destroyAckCleanup(){if(cleanupInterval)clearInterval(cleanupInterval),cleanupInterval=null}function generateMessageId(){return`msg_${Date.now()}_${Math.random().toString(36).substring(2,11)}`}async function storePendingMessage(redis,message,ttlSeconds){if(!message.userId)return;let key2=`pubsub:pending:user:${message.userId}:${message.messageId}`,setKey=`pubsub:user:pending-set:${message.userId}`;await redis.create(key2,message,ttlSeconds);let existingResult=await redis.read(setKey),existingSet=existingResult.success&&existingResult.data?existingResult.data:[];if(!existingSet.includes(message.messageId))existingSet.push(message.messageId),await redis.create(setKey,existingSet,ttlSeconds)}async function acknowledgeMessage(redis,userId,messageId,ttlSeconds){let dedupKey=`${userId}:${messageId}`;if(recentAcks.has(dedupKey))return!1;let pendingKey=`pubsub:pending:user:${userId}:${messageId}`,setKey=`pubsub:user:pending-set:${userId}`,ackKey=`pubsub:ack:${userId}:${messageId}`,pendingResult=await redis.read(pendingKey);if(!pendingResult.success||!pendingResult.data)return recentAcks.set(dedupKey,Date.now()),!1;recentAcks.set(dedupKey,Date.now());let pending=pendingResult.data,ack={messageId,clientId:pending.clientId,ackedAt:Date.now()};await redis.create(ackKey,ack,60),await redis.remove(pendingKey);let setResult=await redis.read(setKey),updatedSet=(setResult.success&&setResult.data?setResult.data:[]).filter((id)=>id!==messageId);if(updatedSet.length>0)await redis.create(setKey,updatedSet,ttlSeconds);else await redis.remove(setKey);let latencyMs=Date.now()-pending.sentAt;return recordAcked(latencyMs),!0}async function getPendingMessagesForUser(redis,userId){if(!userId)return[];let setKey=`pubsub:user:pending-set:${userId}`,setResult=await redis.read(setKey),messageIds=setResult.success&&setResult.data?setResult.data:[],messages=[];for(let messageId of messageIds){let key2=`pubsub:pending:user:${userId}:${messageId}`,msgResult=await redis.read(key2);if(msgResult.success&&msgResult.data)messages.push(msgResult.data)}return messages.sort((a,b)=>a.sentAt-b.sentAt),messages}async function getPendingMessageCount(redis,userId){if(!userId)return 0;let setKey=`pubsub:user:pending-set:${userId}`,setResult=await redis.read(setKey);return(setResult.success&&setResult.data?setResult.data:[]).length}async function incrementRetryCount(redis,userId,messageId,ttlSeconds,maxRetries){let key2=`pubsub:pending:user:${userId}:${messageId}`,msgResult=await redis.read(key2);if(!msgResult.success||!msgResult.data)return!1;let message={...msgResult.data,retryCount:msgResult.data.retryCount+1};if(message.retryCount>=maxRetries)return await removePendingMessage(redis,userId,messageId),recordFailed(),!1;return await redis.create(key2,message,ttlSeconds),!0}async function removePendingMessage(redis,userId,messageId){let key2=`pubsub:pending:user:${userId}:${messageId}`,setKey=`pubsub:user:pending-set:${userId}`;await redis.remove(key2);let setResult=await redis.read(setKey),updatedSet=(setResult.success&&setResult.data?setResult.data:[]).filter((id)=>id!==messageId);if(updatedSet.length>0)await redis.create(setKey,updatedSet,300);else await redis.remove(setKey)}function recordSent(){stats.totalSent++}function recordAcked(latencyMs){stats.totalAcked++,stats.averageLatencyMs=(stats.averageLatencyMs*(stats.totalAcked-1)+latencyMs)/stats.totalAcked}function recordFailed(){stats.totalFailed++}function getDeliveryStats(){return{...stats}}var recentAcks,cleanupInterval=null,stats;var init_ack_manager=__esm(()=>{recentAcks=new Map;stats={totalSent:0,totalAcked:0,totalFailed:0,averageLatencyMs:0}});var resolveAuthTablesForRequest=(request,authConfig)=>{let defaults={usersTable:authConfig.usersTable,sessionsTable:authConfig.sessionsTable??null,userRolesTable:authConfig.userRolesTable??void 0,rolesTable:authConfig.rolesTable??void 0,roleClaimsTable:authConfig.roleClaimsTable??void 0,claimsTable:authConfig.claimsTable??void 0,oauthAccountsTable:authConfig.oauthAccountsTable??void 0,apiKeysTable:authConfig.apiKeysTable??void 0,schemaTables:authConfig.schemaTables||{}},registry2=authConfig.getTenantRegistry?authConfig.getTenantRegistry():authConfig.tenantRegistry;if(!registry2)return defaults;let schemaName=request.headers.get("x-tenant-schema");if(!schemaName)return defaults;let ctx=registry2.getSchemaContext(schemaName);if(!ctx)return defaults;let tables=ctx.schemaTables;return{usersTable:tables.users??defaults.usersTable,sessionsTable:tables.userSessions??tables.user_sessions??tables.sessions??defaults.sessionsTable,userRolesTable:tables.userRoles??defaults.userRolesTable,rolesTable:tables.roles??defaults.rolesTable,roleClaimsTable:tables.roleClaims??defaults.roleClaimsTable,claimsTable:tables.claims??defaults.claimsTable,oauthAccountsTable:tables.oauthAccounts??defaults.oauthAccountsTable,apiKeysTable:tables.apiKeys??defaults.apiKeysTable,schemaTables:tables}};function resolveMutationSchema(staticSchema,tenantHeader,registry2){let schema=staticSchema;if(registry2&&tenantHeader){let tctx=registry2.getSchemaContext(tenantHeader);if(!tctx)return{ok:!1,reason:"unknown"};schema=tctx.schemaName}if(!SQL_IDENT.test(schema))return{ok:!1,reason:"invalid"};return{ok:!0,schema}}var SQL_IDENT;var init_resolveMutationSchema=__esm(()=>{SQL_IDENT=/^[a-zA-Z_][a-zA-Z0-9_]*$/});import{eq as eq36,sql as sql8}from"drizzle-orm";import{Elysia as Elysia25,t as t22}from"elysia";function createChangeUserIdRoute(config,schemaName="public"){let{db,logger:logger2}=config,routes=new Elysia25;return routes.post("/auth/admin/change-user-id",async(ctx)=>{let{usersTable}=resolveAuthTablesForRequest(ctx.request,config);if(!db||!usersTable)return{success:!1,message:"Database not configured"};let registry2=config.getTenantRegistry?config.getTenantRegistry():config.tenantRegistry,schemaResult=resolveMutationSchema(schemaName,ctx.request.headers.get("x-tenant-schema"),registry2);if(!schemaResult.ok)return ctx.set.status=400,{success:!1,message:schemaResult.reason==="unknown"?"Unknown tenant schema":"Invalid tenant schema"};let effectiveSchema=schemaResult.schema,requestingUserId=ctx.request.headers.get("x-user-id");if(!requestingUserId)return ctx.set.status=401,{success:!1,message:"Unauthorized"};let requestingUser=(await db.select().from(usersTable).where(eq36(usersTable.id,requestingUserId)).limit(1))[0];if(!requestingUser||!requestingUser.isGod)return ctx.set.status=403,{success:!1,message:"Forbidden: godmin privileges required"};let{currentId,newId}=ctx.body;if(!currentId||!newId)return ctx.set.status=400,{success:!1,message:"currentId and newId are required"};if(currentId===newId)return ctx.set.status=400,{success:!1,message:"New ID must be different from current ID"};let uuidRegex2=/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;if(!uuidRegex2.test(newId))return ctx.set.status=400,{success:!1,message:"newId must be a valid UUID"};if(!uuidRegex2.test(currentId))return ctx.set.status=400,{success:!1,message:"currentId must be a valid UUID"};let targetUser=(await db.select().from(usersTable).where(eq36(usersTable.id,currentId)).limit(1))[0];if(!targetUser)return ctx.set.status=404,{success:!1,message:"User not found"};if((await db.select().from(usersTable).where(eq36(usersTable.id,newId)).limit(1)).length>0)return ctx.set.status=409,{success:!1,message:"A user with this ID already exists"};try{let fkResult=await db.execute(sql8`
|
|
396
|
+
`))}});var require_constructor=__commonJS((exports,module)=>{var util=__require("util"),stream=__require("stream"),is2=require_is();require_sharp();var debuglog=util.debuglog("sharp"),Sharp=function(input,options){if(arguments.length===1&&!is2.defined(input))throw Error("Invalid input");if(!(this instanceof Sharp))return new Sharp(input,options);return stream.Duplex.call(this),this.options={topOffsetPre:-1,leftOffsetPre:-1,widthPre:-1,heightPre:-1,topOffsetPost:-1,leftOffsetPost:-1,widthPost:-1,heightPost:-1,width:-1,height:-1,canvas:"crop",position:0,resizeBackground:[0,0,0,255],useExifOrientation:!1,angle:0,rotationAngle:0,rotationBackground:[0,0,0,255],rotateBeforePreExtract:!1,flip:!1,flop:!1,extendTop:0,extendBottom:0,extendLeft:0,extendRight:0,extendBackground:[0,0,0,255],extendWith:"background",withoutEnlargement:!1,withoutReduction:!1,affineMatrix:[],affineBackground:[0,0,0,255],affineIdx:0,affineIdy:0,affineOdx:0,affineOdy:0,affineInterpolator:this.constructor.interpolators.bilinear,kernel:"lanczos3",fastShrinkOnLoad:!0,tint:[-1,0,0,0],flatten:!1,flattenBackground:[0,0,0],unflatten:!1,negate:!1,negateAlpha:!0,medianSize:0,blurSigma:0,precision:"integer",minAmpl:0.2,sharpenSigma:0,sharpenM1:1,sharpenM2:2,sharpenX1:2,sharpenY2:10,sharpenY3:20,threshold:0,thresholdGrayscale:!0,trimBackground:[],trimThreshold:-1,trimLineArt:!1,gamma:0,gammaOut:0,greyscale:!1,normalise:!1,normaliseLower:1,normaliseUpper:99,claheWidth:0,claheHeight:0,claheMaxSlope:3,brightness:1,saturation:1,hue:0,lightness:0,booleanBufferIn:null,booleanFileIn:"",joinChannelIn:[],extractChannel:-1,removeAlpha:!1,ensureAlpha:-1,colourspace:"srgb",colourspacePipeline:"last",composite:[],fileOut:"",formatOut:"input",streamOut:!1,keepMetadata:0,withMetadataOrientation:-1,withMetadataDensity:0,withIccProfile:"",withExif:{},withExifMerge:!0,resolveWithObject:!1,jpegQuality:80,jpegProgressive:!1,jpegChromaSubsampling:"4:2:0",jpegTrellisQuantisation:!1,jpegOvershootDeringing:!1,jpegOptimiseScans:!1,jpegOptimiseCoding:!0,jpegQuantisationTable:0,pngProgressive:!1,pngCompressionLevel:6,pngAdaptiveFiltering:!1,pngPalette:!1,pngQuality:100,pngEffort:7,pngBitdepth:8,pngDither:1,jp2Quality:80,jp2TileHeight:512,jp2TileWidth:512,jp2Lossless:!1,jp2ChromaSubsampling:"4:4:4",webpQuality:80,webpAlphaQuality:100,webpLossless:!1,webpNearLossless:!1,webpSmartSubsample:!1,webpPreset:"default",webpEffort:4,webpMinSize:!1,webpMixed:!1,gifBitdepth:8,gifEffort:7,gifDither:1,gifInterFrameMaxError:0,gifInterPaletteMaxError:3,gifReuse:!0,gifProgressive:!1,tiffQuality:80,tiffCompression:"jpeg",tiffPredictor:"horizontal",tiffPyramid:!1,tiffMiniswhite:!1,tiffBitdepth:8,tiffTile:!1,tiffTileHeight:256,tiffTileWidth:256,tiffXres:1,tiffYres:1,tiffResolutionUnit:"inch",heifQuality:50,heifLossless:!1,heifCompression:"av1",heifEffort:4,heifChromaSubsampling:"4:4:4",heifBitdepth:8,jxlDistance:1,jxlDecodingTier:0,jxlEffort:7,jxlLossless:!1,rawDepth:"uchar",tileSize:256,tileOverlap:0,tileContainer:"fs",tileLayout:"dz",tileFormat:"last",tileDepth:"last",tileAngle:0,tileSkipBlanks:-1,tileBackground:[255,255,255,255],tileCentre:!1,tileId:"https://example.com/iiif",tileBasename:"",timeoutSeconds:0,linearA:[],linearB:[],debuglog:(warning)=>{this.emit("warning",warning),debuglog(warning)},queueListener:function(queueLength){Sharp.queue.emit("change",queueLength)}},this.options.input=this._createInputDescriptor(input,options,{allowStream:!0}),this};Object.setPrototypeOf(Sharp.prototype,stream.Duplex.prototype);Object.setPrototypeOf(Sharp,stream.Duplex);function clone(){let clone2=this.constructor.call(),{debuglog:debuglog2,queueListener,...options}=this.options;if(clone2.options=structuredClone(options),clone2.options.debuglog=debuglog2,clone2.options.queueListener=queueListener,this._isStreamInput())this.on("finish",()=>{this._flattenBufferIn(),clone2.options.input.buffer=this.options.input.buffer,clone2.emit("finish")});return clone2}Object.assign(Sharp.prototype,{clone});module.exports=Sharp});var require_color_name=__commonJS((exports,module)=>{module.exports={aliceblue:[240,248,255],antiquewhite:[250,235,215],aqua:[0,255,255],aquamarine:[127,255,212],azure:[240,255,255],beige:[245,245,220],bisque:[255,228,196],black:[0,0,0],blanchedalmond:[255,235,205],blue:[0,0,255],blueviolet:[138,43,226],brown:[165,42,42],burlywood:[222,184,135],cadetblue:[95,158,160],chartreuse:[127,255,0],chocolate:[210,105,30],coral:[255,127,80],cornflowerblue:[100,149,237],cornsilk:[255,248,220],crimson:[220,20,60],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgoldenrod:[184,134,11],darkgray:[169,169,169],darkgreen:[0,100,0],darkgrey:[169,169,169],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkseagreen:[143,188,143],darkslateblue:[72,61,139],darkslategray:[47,79,79],darkslategrey:[47,79,79],darkturquoise:[0,206,209],darkviolet:[148,0,211],deeppink:[255,20,147],deepskyblue:[0,191,255],dimgray:[105,105,105],dimgrey:[105,105,105],dodgerblue:[30,144,255],firebrick:[178,34,34],floralwhite:[255,250,240],forestgreen:[34,139,34],fuchsia:[255,0,255],gainsboro:[220,220,220],ghostwhite:[248,248,255],gold:[255,215,0],goldenrod:[218,165,32],gray:[128,128,128],green:[0,128,0],greenyellow:[173,255,47],grey:[128,128,128],honeydew:[240,255,240],hotpink:[255,105,180],indianred:[205,92,92],indigo:[75,0,130],ivory:[255,255,240],khaki:[240,230,140],lavender:[230,230,250],lavenderblush:[255,240,245],lawngreen:[124,252,0],lemonchiffon:[255,250,205],lightblue:[173,216,230],lightcoral:[240,128,128],lightcyan:[224,255,255],lightgoldenrodyellow:[250,250,210],lightgray:[211,211,211],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightsalmon:[255,160,122],lightseagreen:[32,178,170],lightskyblue:[135,206,250],lightslategray:[119,136,153],lightslategrey:[119,136,153],lightsteelblue:[176,196,222],lightyellow:[255,255,224],lime:[0,255,0],limegreen:[50,205,50],linen:[250,240,230],magenta:[255,0,255],maroon:[128,0,0],mediumaquamarine:[102,205,170],mediumblue:[0,0,205],mediumorchid:[186,85,211],mediumpurple:[147,112,219],mediumseagreen:[60,179,113],mediumslateblue:[123,104,238],mediumspringgreen:[0,250,154],mediumturquoise:[72,209,204],mediumvioletred:[199,21,133],midnightblue:[25,25,112],mintcream:[245,255,250],mistyrose:[255,228,225],moccasin:[255,228,181],navajowhite:[255,222,173],navy:[0,0,128],oldlace:[253,245,230],olive:[128,128,0],olivedrab:[107,142,35],orange:[255,165,0],orangered:[255,69,0],orchid:[218,112,214],palegoldenrod:[238,232,170],palegreen:[152,251,152],paleturquoise:[175,238,238],palevioletred:[219,112,147],papayawhip:[255,239,213],peachpuff:[255,218,185],peru:[205,133,63],pink:[255,192,203],plum:[221,160,221],powderblue:[176,224,230],purple:[128,0,128],rebeccapurple:[102,51,153],red:[255,0,0],rosybrown:[188,143,143],royalblue:[65,105,225],saddlebrown:[139,69,19],salmon:[250,128,114],sandybrown:[244,164,96],seagreen:[46,139,87],seashell:[255,245,238],sienna:[160,82,45],silver:[192,192,192],skyblue:[135,206,235],slateblue:[106,90,205],slategray:[112,128,144],slategrey:[112,128,144],snow:[255,250,250],springgreen:[0,255,127],steelblue:[70,130,180],tan:[210,180,140],teal:[0,128,128],thistle:[216,191,216],tomato:[255,99,71],turquoise:[64,224,208],violet:[238,130,238],wheat:[245,222,179],white:[255,255,255],whitesmoke:[245,245,245],yellow:[255,255,0],yellowgreen:[154,205,50]}});var require_is_arrayish=__commonJS((exports,module)=>{module.exports=function(obj){if(!obj||typeof obj==="string")return!1;return obj instanceof Array||Array.isArray(obj)||obj.length>=0&&(obj.splice instanceof Function||Object.getOwnPropertyDescriptor(obj,obj.length-1)&&obj.constructor.name!=="String")}});var require_simple_swizzle=__commonJS((exports,module)=>{var isArrayish=require_is_arrayish(),concat4=Array.prototype.concat,slice2=Array.prototype.slice,swizzle=module.exports=function(args){var results=[];for(var i=0,len=args.length;i<len;i++){var arg=args[i];if(isArrayish(arg))results=concat4.call(results,slice2.call(arg));else results.push(arg)}return results};swizzle.wrap=function(fn){return function(){return fn(swizzle(arguments))}}});var require_color_string=__commonJS((exports,module)=>{var colorNames=require_color_name(),swizzle=require_simple_swizzle(),hasOwnProperty=Object.hasOwnProperty,reverseNames=Object.create(null);for(name2 in colorNames)if(hasOwnProperty.call(colorNames,name2))reverseNames[colorNames[name2]]=name2;var name2,cs=module.exports={to:{},get:{}};cs.get=function(string){var prefix=string.substring(0,3).toLowerCase(),val,model;switch(prefix){case"hsl":val=cs.get.hsl(string),model="hsl";break;case"hwb":val=cs.get.hwb(string),model="hwb";break;default:val=cs.get.rgb(string),model="rgb";break}if(!val)return null;return{model,value:val}};cs.get.rgb=function(string){if(!string)return null;var abbr=/^#([a-f0-9]{3,4})$/i,hex2=/^#([a-f0-9]{6})([a-f0-9]{2})?$/i,rgba=/^rgba?\(\s*([+-]?\d+)(?=[\s,])\s*(?:,\s*)?([+-]?\d+)(?=[\s,])\s*(?:,\s*)?([+-]?\d+)\s*(?:[,|\/]\s*([+-]?[\d\.]+)(%?)\s*)?\)$/,per=/^rgba?\(\s*([+-]?[\d\.]+)\%\s*,?\s*([+-]?[\d\.]+)\%\s*,?\s*([+-]?[\d\.]+)\%\s*(?:[,|\/]\s*([+-]?[\d\.]+)(%?)\s*)?\)$/,keyword=/^(\w+)$/,rgb=[0,0,0,1],match,i,hexAlpha;if(match=string.match(hex2)){hexAlpha=match[2],match=match[1];for(i=0;i<3;i++){var i2=i*2;rgb[i]=parseInt(match.slice(i2,i2+2),16)}if(hexAlpha)rgb[3]=parseInt(hexAlpha,16)/255}else if(match=string.match(abbr)){match=match[1],hexAlpha=match[3];for(i=0;i<3;i++)rgb[i]=parseInt(match[i]+match[i],16);if(hexAlpha)rgb[3]=parseInt(hexAlpha+hexAlpha,16)/255}else if(match=string.match(rgba)){for(i=0;i<3;i++)rgb[i]=parseInt(match[i+1],0);if(match[4])if(match[5])rgb[3]=parseFloat(match[4])*0.01;else rgb[3]=parseFloat(match[4])}else if(match=string.match(per)){for(i=0;i<3;i++)rgb[i]=Math.round(parseFloat(match[i+1])*2.55);if(match[4])if(match[5])rgb[3]=parseFloat(match[4])*0.01;else rgb[3]=parseFloat(match[4])}else if(match=string.match(keyword)){if(match[1]==="transparent")return[0,0,0,0];if(!hasOwnProperty.call(colorNames,match[1]))return null;return rgb=colorNames[match[1]],rgb[3]=1,rgb}else return null;for(i=0;i<3;i++)rgb[i]=clamp(rgb[i],0,255);return rgb[3]=clamp(rgb[3],0,1),rgb};cs.get.hsl=function(string){if(!string)return null;var hsl=/^hsla?\(\s*([+-]?(?:\d{0,3}\.)?\d+)(?:deg)?\s*,?\s*([+-]?[\d\.]+)%\s*,?\s*([+-]?[\d\.]+)%\s*(?:[,|\/]\s*([+-]?(?=\.\d|\d)(?:0|[1-9]\d*)?(?:\.\d*)?(?:[eE][+-]?\d+)?)\s*)?\)$/,match=string.match(hsl);if(match){var alpha=parseFloat(match[4]),h=(parseFloat(match[1])%360+360)%360,s=clamp(parseFloat(match[2]),0,100),l=clamp(parseFloat(match[3]),0,100),a=clamp(isNaN(alpha)?1:alpha,0,1);return[h,s,l,a]}return null};cs.get.hwb=function(string){if(!string)return null;var hwb=/^hwb\(\s*([+-]?\d{0,3}(?:\.\d+)?)(?:deg)?\s*,\s*([+-]?[\d\.]+)%\s*,\s*([+-]?[\d\.]+)%\s*(?:,\s*([+-]?(?=\.\d|\d)(?:0|[1-9]\d*)?(?:\.\d*)?(?:[eE][+-]?\d+)?)\s*)?\)$/,match=string.match(hwb);if(match){var alpha=parseFloat(match[4]),h=(parseFloat(match[1])%360+360)%360,w=clamp(parseFloat(match[2]),0,100),b=clamp(parseFloat(match[3]),0,100),a=clamp(isNaN(alpha)?1:alpha,0,1);return[h,w,b,a]}return null};cs.to.hex=function(){var rgba=swizzle(arguments);return"#"+hexDouble(rgba[0])+hexDouble(rgba[1])+hexDouble(rgba[2])+(rgba[3]<1?hexDouble(Math.round(rgba[3]*255)):"")};cs.to.rgb=function(){var rgba=swizzle(arguments);return rgba.length<4||rgba[3]===1?"rgb("+Math.round(rgba[0])+", "+Math.round(rgba[1])+", "+Math.round(rgba[2])+")":"rgba("+Math.round(rgba[0])+", "+Math.round(rgba[1])+", "+Math.round(rgba[2])+", "+rgba[3]+")"};cs.to.rgb.percent=function(){var rgba=swizzle(arguments),r=Math.round(rgba[0]/255*100),g=Math.round(rgba[1]/255*100),b=Math.round(rgba[2]/255*100);return rgba.length<4||rgba[3]===1?"rgb("+r+"%, "+g+"%, "+b+"%)":"rgba("+r+"%, "+g+"%, "+b+"%, "+rgba[3]+")"};cs.to.hsl=function(){var hsla=swizzle(arguments);return hsla.length<4||hsla[3]===1?"hsl("+hsla[0]+", "+hsla[1]+"%, "+hsla[2]+"%)":"hsla("+hsla[0]+", "+hsla[1]+"%, "+hsla[2]+"%, "+hsla[3]+")"};cs.to.hwb=function(){var hwba=swizzle(arguments),a="";if(hwba.length>=4&&hwba[3]!==1)a=", "+hwba[3];return"hwb("+hwba[0]+", "+hwba[1]+"%, "+hwba[2]+"%"+a+")"};cs.to.keyword=function(rgb){return reverseNames[rgb.slice(0,3)]};function clamp(num3,min,max){return Math.min(Math.max(min,num3),max)}function hexDouble(num3){var str4=Math.round(num3).toString(16).toUpperCase();return str4.length<2?"0"+str4:str4}});var require_conversions=__commonJS((exports,module)=>{var cssKeywords=require_color_name(),reverseKeywords={};for(let key2 of Object.keys(cssKeywords))reverseKeywords[cssKeywords[key2]]=key2;var convert2={rgb:{channels:3,labels:"rgb"},hsl:{channels:3,labels:"hsl"},hsv:{channels:3,labels:"hsv"},hwb:{channels:3,labels:"hwb"},cmyk:{channels:4,labels:"cmyk"},xyz:{channels:3,labels:"xyz"},lab:{channels:3,labels:"lab"},lch:{channels:3,labels:"lch"},hex:{channels:1,labels:["hex"]},keyword:{channels:1,labels:["keyword"]},ansi16:{channels:1,labels:["ansi16"]},ansi256:{channels:1,labels:["ansi256"]},hcg:{channels:3,labels:["h","c","g"]},apple:{channels:3,labels:["r16","g16","b16"]},gray:{channels:1,labels:["gray"]}};module.exports=convert2;for(let model of Object.keys(convert2)){if(!("channels"in convert2[model]))throw Error("missing channels property: "+model);if(!("labels"in convert2[model]))throw Error("missing channel labels property: "+model);if(convert2[model].labels.length!==convert2[model].channels)throw Error("channel and label counts mismatch: "+model);let{channels,labels}=convert2[model];delete convert2[model].channels,delete convert2[model].labels,Object.defineProperty(convert2[model],"channels",{value:channels}),Object.defineProperty(convert2[model],"labels",{value:labels})}convert2.rgb.hsl=function(rgb){let r=rgb[0]/255,g=rgb[1]/255,b=rgb[2]/255,min=Math.min(r,g,b),max=Math.max(r,g,b),delta=max-min,h,s;if(max===min)h=0;else if(r===max)h=(g-b)/delta;else if(g===max)h=2+(b-r)/delta;else if(b===max)h=4+(r-g)/delta;if(h=Math.min(h*60,360),h<0)h+=360;let l=(min+max)/2;if(max===min)s=0;else if(l<=0.5)s=delta/(max+min);else s=delta/(2-max-min);return[h,s*100,l*100]};convert2.rgb.hsv=function(rgb){let rdif,gdif,bdif,h,s,r=rgb[0]/255,g=rgb[1]/255,b=rgb[2]/255,v=Math.max(r,g,b),diff=v-Math.min(r,g,b),diffc=function(c){return(v-c)/6/diff+0.5};if(diff===0)h=0,s=0;else{if(s=diff/v,rdif=diffc(r),gdif=diffc(g),bdif=diffc(b),r===v)h=bdif-gdif;else if(g===v)h=0.3333333333333333+rdif-bdif;else if(b===v)h=0.6666666666666666+gdif-rdif;if(h<0)h+=1;else if(h>1)h-=1}return[h*360,s*100,v*100]};convert2.rgb.hwb=function(rgb){let r=rgb[0],g=rgb[1],b=rgb[2],h=convert2.rgb.hsl(rgb)[0],w=0.00392156862745098*Math.min(r,Math.min(g,b));return b=1-0.00392156862745098*Math.max(r,Math.max(g,b)),[h,w*100,b*100]};convert2.rgb.cmyk=function(rgb){let r=rgb[0]/255,g=rgb[1]/255,b=rgb[2]/255,k=Math.min(1-r,1-g,1-b),c=(1-r-k)/(1-k)||0,m=(1-g-k)/(1-k)||0,y=(1-b-k)/(1-k)||0;return[c*100,m*100,y*100,k*100]};function comparativeDistance(x,y){return(x[0]-y[0])**2+(x[1]-y[1])**2+(x[2]-y[2])**2}convert2.rgb.keyword=function(rgb){let reversed=reverseKeywords[rgb];if(reversed)return reversed;let currentClosestDistance=1/0,currentClosestKeyword;for(let keyword of Object.keys(cssKeywords)){let value=cssKeywords[keyword],distance=comparativeDistance(rgb,value);if(distance<currentClosestDistance)currentClosestDistance=distance,currentClosestKeyword=keyword}return currentClosestKeyword};convert2.keyword.rgb=function(keyword){return cssKeywords[keyword]};convert2.rgb.xyz=function(rgb){let r=rgb[0]/255,g=rgb[1]/255,b=rgb[2]/255;r=r>0.04045?((r+0.055)/1.055)**2.4:r/12.92,g=g>0.04045?((g+0.055)/1.055)**2.4:g/12.92,b=b>0.04045?((b+0.055)/1.055)**2.4:b/12.92;let x=r*0.4124+g*0.3576+b*0.1805,y=r*0.2126+g*0.7152+b*0.0722,z=r*0.0193+g*0.1192+b*0.9505;return[x*100,y*100,z*100]};convert2.rgb.lab=function(rgb){let xyz=convert2.rgb.xyz(rgb),x=xyz[0],y=xyz[1],z=xyz[2];x/=95.047,y/=100,z/=108.883,x=x>0.008856?x**0.3333333333333333:7.787*x+0.13793103448275862,y=y>0.008856?y**0.3333333333333333:7.787*y+0.13793103448275862,z=z>0.008856?z**0.3333333333333333:7.787*z+0.13793103448275862;let l=116*y-16,a=500*(x-y),b=200*(y-z);return[l,a,b]};convert2.hsl.rgb=function(hsl){let h=hsl[0]/360,s=hsl[1]/100,l=hsl[2]/100,t22,t3,val;if(s===0)return val=l*255,[val,val,val];if(l<0.5)t22=l*(1+s);else t22=l+s-l*s;let t1=2*l-t22,rgb=[0,0,0];for(let i=0;i<3;i++){if(t3=h+0.3333333333333333*-(i-1),t3<0)t3++;if(t3>1)t3--;if(6*t3<1)val=t1+(t22-t1)*6*t3;else if(2*t3<1)val=t22;else if(3*t3<2)val=t1+(t22-t1)*(0.6666666666666666-t3)*6;else val=t1;rgb[i]=val*255}return rgb};convert2.hsl.hsv=function(hsl){let h=hsl[0],s=hsl[1]/100,l=hsl[2]/100,smin=s,lmin=Math.max(l,0.01);l*=2,s*=l<=1?l:2-l,smin*=lmin<=1?lmin:2-lmin;let v=(l+s)/2,sv=l===0?2*smin/(lmin+smin):2*s/(l+s);return[h,sv*100,v*100]};convert2.hsv.rgb=function(hsv){let h=hsv[0]/60,s=hsv[1]/100,v=hsv[2]/100,hi=Math.floor(h)%6,f=h-Math.floor(h),p=255*v*(1-s),q=255*v*(1-s*f),t3=255*v*(1-s*(1-f));switch(v*=255,hi){case 0:return[v,t3,p];case 1:return[q,v,p];case 2:return[p,v,t3];case 3:return[p,q,v];case 4:return[t3,p,v];case 5:return[v,p,q]}};convert2.hsv.hsl=function(hsv){let h=hsv[0],s=hsv[1]/100,v=hsv[2]/100,vmin=Math.max(v,0.01),sl,l;l=(2-s)*v;let lmin=(2-s)*vmin;return sl=s*vmin,sl/=lmin<=1?lmin:2-lmin,sl=sl||0,l/=2,[h,sl*100,l*100]};convert2.hwb.rgb=function(hwb){let h=hwb[0]/360,wh=hwb[1]/100,bl=hwb[2]/100,ratio=wh+bl,f;if(ratio>1)wh/=ratio,bl/=ratio;let i=Math.floor(6*h),v=1-bl;if(f=6*h-i,(i&1)!==0)f=1-f;let n=wh+f*(v-wh),r,g,b;switch(i){default:case 6:case 0:r=v,g=n,b=wh;break;case 1:r=n,g=v,b=wh;break;case 2:r=wh,g=v,b=n;break;case 3:r=wh,g=n,b=v;break;case 4:r=n,g=wh,b=v;break;case 5:r=v,g=wh,b=n;break}return[r*255,g*255,b*255]};convert2.cmyk.rgb=function(cmyk){let c=cmyk[0]/100,m=cmyk[1]/100,y=cmyk[2]/100,k=cmyk[3]/100,r=1-Math.min(1,c*(1-k)+k),g=1-Math.min(1,m*(1-k)+k),b=1-Math.min(1,y*(1-k)+k);return[r*255,g*255,b*255]};convert2.xyz.rgb=function(xyz){let x=xyz[0]/100,y=xyz[1]/100,z=xyz[2]/100,r,g,b;return r=x*3.2406+y*-1.5372+z*-0.4986,g=x*-0.9689+y*1.8758+z*0.0415,b=x*0.0557+y*-0.204+z*1.057,r=r>0.0031308?1.055*r**0.4166666666666667-0.055:r*12.92,g=g>0.0031308?1.055*g**0.4166666666666667-0.055:g*12.92,b=b>0.0031308?1.055*b**0.4166666666666667-0.055:b*12.92,r=Math.min(Math.max(0,r),1),g=Math.min(Math.max(0,g),1),b=Math.min(Math.max(0,b),1),[r*255,g*255,b*255]};convert2.xyz.lab=function(xyz){let x=xyz[0],y=xyz[1],z=xyz[2];x/=95.047,y/=100,z/=108.883,x=x>0.008856?x**0.3333333333333333:7.787*x+0.13793103448275862,y=y>0.008856?y**0.3333333333333333:7.787*y+0.13793103448275862,z=z>0.008856?z**0.3333333333333333:7.787*z+0.13793103448275862;let l=116*y-16,a=500*(x-y),b=200*(y-z);return[l,a,b]};convert2.lab.xyz=function(lab){let l=lab[0],a=lab[1],b=lab[2],x,y,z;y=(l+16)/116,x=a/500+y,z=y-b/200;let y2=y**3,x2=x**3,z2=z**3;return y=y2>0.008856?y2:(y-0.13793103448275862)/7.787,x=x2>0.008856?x2:(x-0.13793103448275862)/7.787,z=z2>0.008856?z2:(z-0.13793103448275862)/7.787,x*=95.047,y*=100,z*=108.883,[x,y,z]};convert2.lab.lch=function(lab){let l=lab[0],a=lab[1],b=lab[2],h;if(h=Math.atan2(b,a)*360/2/Math.PI,h<0)h+=360;let c=Math.sqrt(a*a+b*b);return[l,c,h]};convert2.lch.lab=function(lch){let l=lch[0],c=lch[1],hr=lch[2]/360*2*Math.PI,a=c*Math.cos(hr),b=c*Math.sin(hr);return[l,a,b]};convert2.rgb.ansi16=function(args,saturation=null){let[r,g,b]=args,value=saturation===null?convert2.rgb.hsv(args)[2]:saturation;if(value=Math.round(value/50),value===0)return 30;let ansi=30+(Math.round(b/255)<<2|Math.round(g/255)<<1|Math.round(r/255));if(value===2)ansi+=60;return ansi};convert2.hsv.ansi16=function(args){return convert2.rgb.ansi16(convert2.hsv.rgb(args),args[2])};convert2.rgb.ansi256=function(args){let r=args[0],g=args[1],b=args[2];if(r===g&&g===b){if(r<8)return 16;if(r>248)return 231;return Math.round((r-8)/247*24)+232}return 16+36*Math.round(r/255*5)+6*Math.round(g/255*5)+Math.round(b/255*5)};convert2.ansi16.rgb=function(args){let color=args%10;if(color===0||color===7){if(args>50)color+=3.5;return color=color/10.5*255,[color,color,color]}let mult=(~~(args>50)+1)*0.5,r=(color&1)*mult*255,g=(color>>1&1)*mult*255,b=(color>>2&1)*mult*255;return[r,g,b]};convert2.ansi256.rgb=function(args){if(args>=232){let c=(args-232)*10+8;return[c,c,c]}args-=16;let rem,r=Math.floor(args/36)/5*255,g=Math.floor((rem=args%36)/6)/5*255,b=rem%6/5*255;return[r,g,b]};convert2.rgb.hex=function(args){let string=(((Math.round(args[0])&255)<<16)+((Math.round(args[1])&255)<<8)+(Math.round(args[2])&255)).toString(16).toUpperCase();return"000000".substring(string.length)+string};convert2.hex.rgb=function(args){let match=args.toString(16).match(/[a-f0-9]{6}|[a-f0-9]{3}/i);if(!match)return[0,0,0];let colorString=match[0];if(match[0].length===3)colorString=colorString.split("").map((char)=>{return char+char}).join("");let integer=parseInt(colorString,16),r=integer>>16&255,g=integer>>8&255,b=integer&255;return[r,g,b]};convert2.rgb.hcg=function(rgb){let r=rgb[0]/255,g=rgb[1]/255,b=rgb[2]/255,max=Math.max(Math.max(r,g),b),min=Math.min(Math.min(r,g),b),chroma=max-min,grayscale,hue;if(chroma<1)grayscale=min/(1-chroma);else grayscale=0;if(chroma<=0)hue=0;else if(max===r)hue=(g-b)/chroma%6;else if(max===g)hue=2+(b-r)/chroma;else hue=4+(r-g)/chroma;return hue/=6,hue%=1,[hue*360,chroma*100,grayscale*100]};convert2.hsl.hcg=function(hsl){let s=hsl[1]/100,l=hsl[2]/100,c=l<0.5?2*s*l:2*s*(1-l),f=0;if(c<1)f=(l-0.5*c)/(1-c);return[hsl[0],c*100,f*100]};convert2.hsv.hcg=function(hsv){let s=hsv[1]/100,v=hsv[2]/100,c=s*v,f=0;if(c<1)f=(v-c)/(1-c);return[hsv[0],c*100,f*100]};convert2.hcg.rgb=function(hcg){let h=hcg[0]/360,c=hcg[1]/100,g=hcg[2]/100;if(c===0)return[g*255,g*255,g*255];let pure=[0,0,0],hi=h%1*6,v=hi%1,w=1-v,mg=0;switch(Math.floor(hi)){case 0:pure[0]=1,pure[1]=v,pure[2]=0;break;case 1:pure[0]=w,pure[1]=1,pure[2]=0;break;case 2:pure[0]=0,pure[1]=1,pure[2]=v;break;case 3:pure[0]=0,pure[1]=w,pure[2]=1;break;case 4:pure[0]=v,pure[1]=0,pure[2]=1;break;default:pure[0]=1,pure[1]=0,pure[2]=w}return mg=(1-c)*g,[(c*pure[0]+mg)*255,(c*pure[1]+mg)*255,(c*pure[2]+mg)*255]};convert2.hcg.hsv=function(hcg){let c=hcg[1]/100,g=hcg[2]/100,v=c+g*(1-c),f=0;if(v>0)f=c/v;return[hcg[0],f*100,v*100]};convert2.hcg.hsl=function(hcg){let c=hcg[1]/100,l=hcg[2]/100*(1-c)+0.5*c,s=0;if(l>0&&l<0.5)s=c/(2*l);else if(l>=0.5&&l<1)s=c/(2*(1-l));return[hcg[0],s*100,l*100]};convert2.hcg.hwb=function(hcg){let c=hcg[1]/100,g=hcg[2]/100,v=c+g*(1-c);return[hcg[0],(v-c)*100,(1-v)*100]};convert2.hwb.hcg=function(hwb){let w=hwb[1]/100,v=1-hwb[2]/100,c=v-w,g=0;if(c<1)g=(v-c)/(1-c);return[hwb[0],c*100,g*100]};convert2.apple.rgb=function(apple){return[apple[0]/65535*255,apple[1]/65535*255,apple[2]/65535*255]};convert2.rgb.apple=function(rgb){return[rgb[0]/255*65535,rgb[1]/255*65535,rgb[2]/255*65535]};convert2.gray.rgb=function(args){return[args[0]/100*255,args[0]/100*255,args[0]/100*255]};convert2.gray.hsl=function(args){return[0,0,args[0]]};convert2.gray.hsv=convert2.gray.hsl;convert2.gray.hwb=function(gray){return[0,100,gray[0]]};convert2.gray.cmyk=function(gray){return[0,0,0,gray[0]]};convert2.gray.lab=function(gray){return[gray[0],0,0]};convert2.gray.hex=function(gray){let val=Math.round(gray[0]/100*255)&255,string=((val<<16)+(val<<8)+val).toString(16).toUpperCase();return"000000".substring(string.length)+string};convert2.rgb.gray=function(rgb){return[(rgb[0]+rgb[1]+rgb[2])/3/255*100]}});var require_route=__commonJS((exports,module)=>{var conversions=require_conversions();function buildGraph(){let graph={},models=Object.keys(conversions);for(let len=models.length,i=0;i<len;i++)graph[models[i]]={distance:-1,parent:null};return graph}function deriveBFS(fromModel){let graph=buildGraph(),queue=[fromModel];graph[fromModel].distance=0;while(queue.length){let current=queue.pop(),adjacents=Object.keys(conversions[current]);for(let len=adjacents.length,i=0;i<len;i++){let adjacent=adjacents[i],node=graph[adjacent];if(node.distance===-1)node.distance=graph[current].distance+1,node.parent=current,queue.unshift(adjacent)}}return graph}function link(from,to){return function(args){return to(from(args))}}function wrapConversion(toModel,graph){let path3=[graph[toModel].parent,toModel],fn=conversions[graph[toModel].parent][toModel],cur=graph[toModel].parent;while(graph[cur].parent)path3.unshift(graph[cur].parent),fn=link(conversions[graph[cur].parent][cur],fn),cur=graph[cur].parent;return fn.conversion=path3,fn}module.exports=function(fromModel){let graph=deriveBFS(fromModel),conversion={},models=Object.keys(graph);for(let len=models.length,i=0;i<len;i++){let toModel=models[i];if(graph[toModel].parent===null)continue;conversion[toModel]=wrapConversion(toModel,graph)}return conversion}});var require_color_convert=__commonJS((exports,module)=>{var conversions=require_conversions(),route=require_route(),convert2={},models=Object.keys(conversions);function wrapRaw(fn){let wrappedFn=function(...args){let arg0=args[0];if(arg0===void 0||arg0===null)return arg0;if(arg0.length>1)args=arg0;return fn(args)};if("conversion"in fn)wrappedFn.conversion=fn.conversion;return wrappedFn}function wrapRounded(fn){let wrappedFn=function(...args){let arg0=args[0];if(arg0===void 0||arg0===null)return arg0;if(arg0.length>1)args=arg0;let result=fn(args);if(typeof result==="object")for(let len=result.length,i=0;i<len;i++)result[i]=Math.round(result[i]);return result};if("conversion"in fn)wrappedFn.conversion=fn.conversion;return wrappedFn}models.forEach((fromModel)=>{convert2[fromModel]={},Object.defineProperty(convert2[fromModel],"channels",{value:conversions[fromModel].channels}),Object.defineProperty(convert2[fromModel],"labels",{value:conversions[fromModel].labels});let routes=route(fromModel);Object.keys(routes).forEach((toModel)=>{let fn=routes[toModel];convert2[fromModel][toModel]=wrapRounded(fn),convert2[fromModel][toModel].raw=wrapRaw(fn)})});module.exports=convert2});var require_color=__commonJS((exports,module)=>{var colorString=require_color_string(),convert2=require_color_convert(),skippedModels=["keyword","gray","hex"],hashedModelKeys={};for(let model of Object.keys(convert2))hashedModelKeys[[...convert2[model].labels].sort().join("")]=model;var limiters={};function Color(object,model){if(!(this instanceof Color))return new Color(object,model);if(model&&model in skippedModels)model=null;if(model&&!(model in convert2))throw Error("Unknown model: "+model);let i,channels;if(object==null)this.model="rgb",this.color=[0,0,0],this.valpha=1;else if(object instanceof Color)this.model=object.model,this.color=[...object.color],this.valpha=object.valpha;else if(typeof object==="string"){let result=colorString.get(object);if(result===null)throw Error("Unable to parse color from string: "+object);this.model=result.model,channels=convert2[this.model].channels,this.color=result.value.slice(0,channels),this.valpha=typeof result.value[channels]==="number"?result.value[channels]:1}else if(object.length>0){this.model=model||"rgb",channels=convert2[this.model].channels;let newArray=Array.prototype.slice.call(object,0,channels);this.color=zeroArray(newArray,channels),this.valpha=typeof object[channels]==="number"?object[channels]:1}else if(typeof object==="number")this.model="rgb",this.color=[object>>16&255,object>>8&255,object&255],this.valpha=1;else{this.valpha=1;let keys=Object.keys(object);if("alpha"in object)keys.splice(keys.indexOf("alpha"),1),this.valpha=typeof object.alpha==="number"?object.alpha:0;let hashedKeys=keys.sort().join("");if(!(hashedKeys in hashedModelKeys))throw Error("Unable to parse color from object: "+JSON.stringify(object));this.model=hashedModelKeys[hashedKeys];let{labels}=convert2[this.model],color=[];for(i=0;i<labels.length;i++)color.push(object[labels[i]]);this.color=zeroArray(color)}if(limiters[this.model]){channels=convert2[this.model].channels;for(i=0;i<channels;i++){let limit=limiters[this.model][i];if(limit)this.color[i]=limit(this.color[i])}}if(this.valpha=Math.max(0,Math.min(1,this.valpha)),Object.freeze)Object.freeze(this)}Color.prototype={toString(){return this.string()},toJSON(){return this[this.model]()},string(places){let self2=this.model in colorString.to?this:this.rgb();self2=self2.round(typeof places==="number"?places:1);let args=self2.valpha===1?self2.color:[...self2.color,this.valpha];return colorString.to[self2.model](args)},percentString(places){let self2=this.rgb().round(typeof places==="number"?places:1),args=self2.valpha===1?self2.color:[...self2.color,this.valpha];return colorString.to.rgb.percent(args)},array(){return this.valpha===1?[...this.color]:[...this.color,this.valpha]},object(){let result={},{channels}=convert2[this.model],{labels}=convert2[this.model];for(let i=0;i<channels;i++)result[labels[i]]=this.color[i];if(this.valpha!==1)result.alpha=this.valpha;return result},unitArray(){let rgb=this.rgb().color;if(rgb[0]/=255,rgb[1]/=255,rgb[2]/=255,this.valpha!==1)rgb.push(this.valpha);return rgb},unitObject(){let rgb=this.rgb().object();if(rgb.r/=255,rgb.g/=255,rgb.b/=255,this.valpha!==1)rgb.alpha=this.valpha;return rgb},round(places){return places=Math.max(places||0,0),new Color([...this.color.map(roundToPlace(places)),this.valpha],this.model)},alpha(value){if(value!==void 0)return new Color([...this.color,Math.max(0,Math.min(1,value))],this.model);return this.valpha},red:getset("rgb",0,maxfn(255)),green:getset("rgb",1,maxfn(255)),blue:getset("rgb",2,maxfn(255)),hue:getset(["hsl","hsv","hsl","hwb","hcg"],0,(value)=>(value%360+360)%360),saturationl:getset("hsl",1,maxfn(100)),lightness:getset("hsl",2,maxfn(100)),saturationv:getset("hsv",1,maxfn(100)),value:getset("hsv",2,maxfn(100)),chroma:getset("hcg",1,maxfn(100)),gray:getset("hcg",2,maxfn(100)),white:getset("hwb",1,maxfn(100)),wblack:getset("hwb",2,maxfn(100)),cyan:getset("cmyk",0,maxfn(100)),magenta:getset("cmyk",1,maxfn(100)),yellow:getset("cmyk",2,maxfn(100)),black:getset("cmyk",3,maxfn(100)),x:getset("xyz",0,maxfn(95.047)),y:getset("xyz",1,maxfn(100)),z:getset("xyz",2,maxfn(108.833)),l:getset("lab",0,maxfn(100)),a:getset("lab",1),b:getset("lab",2),keyword(value){if(value!==void 0)return new Color(value);return convert2[this.model].keyword(this.color)},hex(value){if(value!==void 0)return new Color(value);return colorString.to.hex(this.rgb().round().color)},hexa(value){if(value!==void 0)return new Color(value);let rgbArray=this.rgb().round().color,alphaHex=Math.round(this.valpha*255).toString(16).toUpperCase();if(alphaHex.length===1)alphaHex="0"+alphaHex;return colorString.to.hex(rgbArray)+alphaHex},rgbNumber(){let rgb=this.rgb().color;return(rgb[0]&255)<<16|(rgb[1]&255)<<8|rgb[2]&255},luminosity(){let rgb=this.rgb().color,lum=[];for(let[i,element]of rgb.entries()){let chan=element/255;lum[i]=chan<=0.04045?chan/12.92:((chan+0.055)/1.055)**2.4}return 0.2126*lum[0]+0.7152*lum[1]+0.0722*lum[2]},contrast(color2){let lum1=this.luminosity(),lum2=color2.luminosity();if(lum1>lum2)return(lum1+0.05)/(lum2+0.05);return(lum2+0.05)/(lum1+0.05)},level(color2){let contrastRatio=this.contrast(color2);if(contrastRatio>=7)return"AAA";return contrastRatio>=4.5?"AA":""},isDark(){let rgb=this.rgb().color;return(rgb[0]*2126+rgb[1]*7152+rgb[2]*722)/1e4<128},isLight(){return!this.isDark()},negate(){let rgb=this.rgb();for(let i=0;i<3;i++)rgb.color[i]=255-rgb.color[i];return rgb},lighten(ratio){let hsl=this.hsl();return hsl.color[2]+=hsl.color[2]*ratio,hsl},darken(ratio){let hsl=this.hsl();return hsl.color[2]-=hsl.color[2]*ratio,hsl},saturate(ratio){let hsl=this.hsl();return hsl.color[1]+=hsl.color[1]*ratio,hsl},desaturate(ratio){let hsl=this.hsl();return hsl.color[1]-=hsl.color[1]*ratio,hsl},whiten(ratio){let hwb=this.hwb();return hwb.color[1]+=hwb.color[1]*ratio,hwb},blacken(ratio){let hwb=this.hwb();return hwb.color[2]+=hwb.color[2]*ratio,hwb},grayscale(){let rgb=this.rgb().color,value=rgb[0]*0.3+rgb[1]*0.59+rgb[2]*0.11;return Color.rgb(value,value,value)},fade(ratio){return this.alpha(this.valpha-this.valpha*ratio)},opaquer(ratio){return this.alpha(this.valpha+this.valpha*ratio)},rotate(degrees){let hsl=this.hsl(),hue=hsl.color[0];return hue=(hue+degrees)%360,hue=hue<0?360+hue:hue,hsl.color[0]=hue,hsl},mix(mixinColor,weight){if(!mixinColor||!mixinColor.rgb)throw Error('Argument to "mix" was not a Color instance, but rather an instance of '+typeof mixinColor);let color1=mixinColor.rgb(),color2=this.rgb(),p=weight===void 0?0.5:weight,w=2*p-1,a=color1.alpha()-color2.alpha(),w1=((w*a===-1?w:(w+a)/(1+w*a))+1)/2,w2=1-w1;return Color.rgb(w1*color1.red()+w2*color2.red(),w1*color1.green()+w2*color2.green(),w1*color1.blue()+w2*color2.blue(),color1.alpha()*p+color2.alpha()*(1-p))}};for(let model of Object.keys(convert2)){if(skippedModels.includes(model))continue;let{channels}=convert2[model];Color.prototype[model]=function(...args){if(this.model===model)return new Color(this);if(args.length>0)return new Color(args,model);return new Color([...assertArray(convert2[this.model][model].raw(this.color)),this.valpha],model)},Color[model]=function(...args){let color=args[0];if(typeof color==="number")color=zeroArray(args,channels);return new Color(color,model)}}function roundTo(number,places){return Number(number.toFixed(places))}function roundToPlace(places){return function(number){return roundTo(number,places)}}function getset(model,channel,modifier){model=Array.isArray(model)?model:[model];for(let m of model)(limiters[m]||(limiters[m]=[]))[channel]=modifier;return model=model[0],function(value){let result;if(value!==void 0){if(modifier)value=modifier(value);return result=this[model](),result.color[channel]=value,result}if(result=this[model]().color[channel],modifier)result=modifier(result);return result}}function maxfn(max){return function(v){return Math.max(0,Math.min(max,v))}}function assertArray(value){return Array.isArray(value)?value:[value]}function zeroArray(array,length){for(let i=0;i<length;i++)if(typeof array[i]!=="number")array[i]=0;return array}module.exports=Color});var require_input=__commonJS((exports,module)=>{var color=require_color(),is2=require_is(),sharp=require_sharp(),align={left:"low",center:"centre",centre:"centre",right:"high"};function _inputOptionsFromObject(obj){let{raw,density,limitInputPixels,ignoreIcc,unlimited,sequentialRead,failOn,failOnError,animated,page,pages,subifd}=obj;return[raw,density,limitInputPixels,ignoreIcc,unlimited,sequentialRead,failOn,failOnError,animated,page,pages,subifd].some(is2.defined)?{raw,density,limitInputPixels,ignoreIcc,unlimited,sequentialRead,failOn,failOnError,animated,page,pages,subifd}:void 0}function _createInputDescriptor(input,inputOptions,containerOptions){let inputDescriptor={failOn:"warning",limitInputPixels:Math.pow(16383,2),ignoreIcc:!1,unlimited:!1,sequentialRead:!0};if(is2.string(input))inputDescriptor.file=input;else if(is2.buffer(input)){if(input.length===0)throw Error("Input Buffer is empty");inputDescriptor.buffer=input}else if(is2.arrayBuffer(input)){if(input.byteLength===0)throw Error("Input bit Array is empty");inputDescriptor.buffer=Buffer.from(input,0,input.byteLength)}else if(is2.typedArray(input)){if(input.length===0)throw Error("Input Bit Array is empty");inputDescriptor.buffer=Buffer.from(input.buffer,input.byteOffset,input.byteLength)}else if(is2.plainObject(input)&&!is2.defined(inputOptions)){if(inputOptions=input,_inputOptionsFromObject(inputOptions))inputDescriptor.buffer=[]}else if(!is2.defined(input)&&!is2.defined(inputOptions)&&is2.object(containerOptions)&&containerOptions.allowStream)inputDescriptor.buffer=[];else throw Error(`Unsupported input '${input}' of type ${typeof input}${is2.defined(inputOptions)?` when also providing options of type ${typeof inputOptions}`:""}`);if(is2.object(inputOptions)){if(is2.defined(inputOptions.failOnError))if(is2.bool(inputOptions.failOnError))inputDescriptor.failOn=inputOptions.failOnError?"warning":"none";else throw is2.invalidParameterError("failOnError","boolean",inputOptions.failOnError);if(is2.defined(inputOptions.failOn))if(is2.string(inputOptions.failOn)&&is2.inArray(inputOptions.failOn,["none","truncated","error","warning"]))inputDescriptor.failOn=inputOptions.failOn;else throw is2.invalidParameterError("failOn","one of: none, truncated, error, warning",inputOptions.failOn);if(is2.defined(inputOptions.density))if(is2.inRange(inputOptions.density,1,1e5))inputDescriptor.density=inputOptions.density;else throw is2.invalidParameterError("density","number between 1 and 100000",inputOptions.density);if(is2.defined(inputOptions.ignoreIcc))if(is2.bool(inputOptions.ignoreIcc))inputDescriptor.ignoreIcc=inputOptions.ignoreIcc;else throw is2.invalidParameterError("ignoreIcc","boolean",inputOptions.ignoreIcc);if(is2.defined(inputOptions.limitInputPixels))if(is2.bool(inputOptions.limitInputPixels))inputDescriptor.limitInputPixels=inputOptions.limitInputPixels?Math.pow(16383,2):0;else if(is2.integer(inputOptions.limitInputPixels)&&is2.inRange(inputOptions.limitInputPixels,0,Number.MAX_SAFE_INTEGER))inputDescriptor.limitInputPixels=inputOptions.limitInputPixels;else throw is2.invalidParameterError("limitInputPixels","positive integer",inputOptions.limitInputPixels);if(is2.defined(inputOptions.unlimited))if(is2.bool(inputOptions.unlimited))inputDescriptor.unlimited=inputOptions.unlimited;else throw is2.invalidParameterError("unlimited","boolean",inputOptions.unlimited);if(is2.defined(inputOptions.sequentialRead))if(is2.bool(inputOptions.sequentialRead))inputDescriptor.sequentialRead=inputOptions.sequentialRead;else throw is2.invalidParameterError("sequentialRead","boolean",inputOptions.sequentialRead);if(is2.defined(inputOptions.raw))if(is2.object(inputOptions.raw)&&is2.integer(inputOptions.raw.width)&&inputOptions.raw.width>0&&is2.integer(inputOptions.raw.height)&&inputOptions.raw.height>0&&is2.integer(inputOptions.raw.channels)&&is2.inRange(inputOptions.raw.channels,1,4))switch(inputDescriptor.rawWidth=inputOptions.raw.width,inputDescriptor.rawHeight=inputOptions.raw.height,inputDescriptor.rawChannels=inputOptions.raw.channels,inputDescriptor.rawPremultiplied=!!inputOptions.raw.premultiplied,input.constructor){case Uint8Array:case Uint8ClampedArray:inputDescriptor.rawDepth="uchar";break;case Int8Array:inputDescriptor.rawDepth="char";break;case Uint16Array:inputDescriptor.rawDepth="ushort";break;case Int16Array:inputDescriptor.rawDepth="short";break;case Uint32Array:inputDescriptor.rawDepth="uint";break;case Int32Array:inputDescriptor.rawDepth="int";break;case Float32Array:inputDescriptor.rawDepth="float";break;case Float64Array:inputDescriptor.rawDepth="double";break;default:inputDescriptor.rawDepth="uchar";break}else throw Error("Expected width, height and channels for raw pixel input");if(is2.defined(inputOptions.animated))if(is2.bool(inputOptions.animated))inputDescriptor.pages=inputOptions.animated?-1:1;else throw is2.invalidParameterError("animated","boolean",inputOptions.animated);if(is2.defined(inputOptions.pages))if(is2.integer(inputOptions.pages)&&is2.inRange(inputOptions.pages,-1,1e5))inputDescriptor.pages=inputOptions.pages;else throw is2.invalidParameterError("pages","integer between -1 and 100000",inputOptions.pages);if(is2.defined(inputOptions.page))if(is2.integer(inputOptions.page)&&is2.inRange(inputOptions.page,0,1e5))inputDescriptor.page=inputOptions.page;else throw is2.invalidParameterError("page","integer between 0 and 100000",inputOptions.page);if(is2.defined(inputOptions.level))if(is2.integer(inputOptions.level)&&is2.inRange(inputOptions.level,0,256))inputDescriptor.level=inputOptions.level;else throw is2.invalidParameterError("level","integer between 0 and 256",inputOptions.level);if(is2.defined(inputOptions.subifd))if(is2.integer(inputOptions.subifd)&&is2.inRange(inputOptions.subifd,-1,1e5))inputDescriptor.subifd=inputOptions.subifd;else throw is2.invalidParameterError("subifd","integer between -1 and 100000",inputOptions.subifd);if(is2.defined(inputOptions.create))if(is2.object(inputOptions.create)&&is2.integer(inputOptions.create.width)&&inputOptions.create.width>0&&is2.integer(inputOptions.create.height)&&inputOptions.create.height>0&&is2.integer(inputOptions.create.channels)){if(inputDescriptor.createWidth=inputOptions.create.width,inputDescriptor.createHeight=inputOptions.create.height,inputDescriptor.createChannels=inputOptions.create.channels,is2.defined(inputOptions.create.noise)){if(!is2.object(inputOptions.create.noise))throw Error("Expected noise to be an object");if(!is2.inArray(inputOptions.create.noise.type,["gaussian"]))throw Error("Only gaussian noise is supported at the moment");if(!is2.inRange(inputOptions.create.channels,1,4))throw is2.invalidParameterError("create.channels","number between 1 and 4",inputOptions.create.channels);if(inputDescriptor.createNoiseType=inputOptions.create.noise.type,is2.number(inputOptions.create.noise.mean)&&is2.inRange(inputOptions.create.noise.mean,0,1e4))inputDescriptor.createNoiseMean=inputOptions.create.noise.mean;else throw is2.invalidParameterError("create.noise.mean","number between 0 and 10000",inputOptions.create.noise.mean);if(is2.number(inputOptions.create.noise.sigma)&&is2.inRange(inputOptions.create.noise.sigma,0,1e4))inputDescriptor.createNoiseSigma=inputOptions.create.noise.sigma;else throw is2.invalidParameterError("create.noise.sigma","number between 0 and 10000",inputOptions.create.noise.sigma)}else if(is2.defined(inputOptions.create.background)){if(!is2.inRange(inputOptions.create.channels,3,4))throw is2.invalidParameterError("create.channels","number between 3 and 4",inputOptions.create.channels);let background=color(inputOptions.create.background);inputDescriptor.createBackground=[background.red(),background.green(),background.blue(),Math.round(background.alpha()*255)]}else throw Error("Expected valid noise or background to create a new input image");delete inputDescriptor.buffer}else throw Error("Expected valid width, height and channels to create a new input image");if(is2.defined(inputOptions.text))if(is2.object(inputOptions.text)&&is2.string(inputOptions.text.text)){if(inputDescriptor.textValue=inputOptions.text.text,is2.defined(inputOptions.text.height)&&is2.defined(inputOptions.text.dpi))throw Error("Expected only one of dpi or height");if(is2.defined(inputOptions.text.font))if(is2.string(inputOptions.text.font))inputDescriptor.textFont=inputOptions.text.font;else throw is2.invalidParameterError("text.font","string",inputOptions.text.font);if(is2.defined(inputOptions.text.fontfile))if(is2.string(inputOptions.text.fontfile))inputDescriptor.textFontfile=inputOptions.text.fontfile;else throw is2.invalidParameterError("text.fontfile","string",inputOptions.text.fontfile);if(is2.defined(inputOptions.text.width))if(is2.integer(inputOptions.text.width)&&inputOptions.text.width>0)inputDescriptor.textWidth=inputOptions.text.width;else throw is2.invalidParameterError("text.width","positive integer",inputOptions.text.width);if(is2.defined(inputOptions.text.height))if(is2.integer(inputOptions.text.height)&&inputOptions.text.height>0)inputDescriptor.textHeight=inputOptions.text.height;else throw is2.invalidParameterError("text.height","positive integer",inputOptions.text.height);if(is2.defined(inputOptions.text.align))if(is2.string(inputOptions.text.align)&&is2.string(this.constructor.align[inputOptions.text.align]))inputDescriptor.textAlign=this.constructor.align[inputOptions.text.align];else throw is2.invalidParameterError("text.align","valid alignment",inputOptions.text.align);if(is2.defined(inputOptions.text.justify))if(is2.bool(inputOptions.text.justify))inputDescriptor.textJustify=inputOptions.text.justify;else throw is2.invalidParameterError("text.justify","boolean",inputOptions.text.justify);if(is2.defined(inputOptions.text.dpi))if(is2.integer(inputOptions.text.dpi)&&is2.inRange(inputOptions.text.dpi,1,1e6))inputDescriptor.textDpi=inputOptions.text.dpi;else throw is2.invalidParameterError("text.dpi","integer between 1 and 1000000",inputOptions.text.dpi);if(is2.defined(inputOptions.text.rgba))if(is2.bool(inputOptions.text.rgba))inputDescriptor.textRgba=inputOptions.text.rgba;else throw is2.invalidParameterError("text.rgba","bool",inputOptions.text.rgba);if(is2.defined(inputOptions.text.spacing))if(is2.integer(inputOptions.text.spacing)&&is2.inRange(inputOptions.text.spacing,-1e6,1e6))inputDescriptor.textSpacing=inputOptions.text.spacing;else throw is2.invalidParameterError("text.spacing","integer between -1000000 and 1000000",inputOptions.text.spacing);if(is2.defined(inputOptions.text.wrap))if(is2.string(inputOptions.text.wrap)&&is2.inArray(inputOptions.text.wrap,["word","char","word-char","none"]))inputDescriptor.textWrap=inputOptions.text.wrap;else throw is2.invalidParameterError("text.wrap","one of: word, char, word-char, none",inputOptions.text.wrap);delete inputDescriptor.buffer}else throw Error("Expected a valid string to create an image with text.")}else if(is2.defined(inputOptions))throw Error("Invalid input options "+inputOptions);return inputDescriptor}function _write(chunk,encoding,callback){if(Array.isArray(this.options.input.buffer))if(is2.buffer(chunk)){if(this.options.input.buffer.length===0)this.on("finish",()=>{this.streamInFinished=!0});this.options.input.buffer.push(chunk),callback()}else callback(Error("Non-Buffer data on Writable Stream"));else callback(Error("Unexpected data on Writable Stream"))}function _flattenBufferIn(){if(this._isStreamInput())this.options.input.buffer=Buffer.concat(this.options.input.buffer)}function _isStreamInput(){return Array.isArray(this.options.input.buffer)}function metadata(callback){let stack=Error();if(is2.fn(callback)){if(this._isStreamInput())this.on("finish",()=>{this._flattenBufferIn(),sharp.metadata(this.options,(err,metadata2)=>{if(err)callback(is2.nativeError(err,stack));else callback(null,metadata2)})});else sharp.metadata(this.options,(err,metadata2)=>{if(err)callback(is2.nativeError(err,stack));else callback(null,metadata2)});return this}else if(this._isStreamInput())return new Promise((resolve2,reject)=>{let finished=()=>{this._flattenBufferIn(),sharp.metadata(this.options,(err,metadata2)=>{if(err)reject(is2.nativeError(err,stack));else resolve2(metadata2)})};if(this.writableFinished)finished();else this.once("finish",finished)});else return new Promise((resolve2,reject)=>{sharp.metadata(this.options,(err,metadata2)=>{if(err)reject(is2.nativeError(err,stack));else resolve2(metadata2)})})}function stats(callback){let stack=Error();if(is2.fn(callback)){if(this._isStreamInput())this.on("finish",()=>{this._flattenBufferIn(),sharp.stats(this.options,(err,stats2)=>{if(err)callback(is2.nativeError(err,stack));else callback(null,stats2)})});else sharp.stats(this.options,(err,stats2)=>{if(err)callback(is2.nativeError(err,stack));else callback(null,stats2)});return this}else if(this._isStreamInput())return new Promise((resolve2,reject)=>{this.on("finish",function(){this._flattenBufferIn(),sharp.stats(this.options,(err,stats2)=>{if(err)reject(is2.nativeError(err,stack));else resolve2(stats2)})})});else return new Promise((resolve2,reject)=>{sharp.stats(this.options,(err,stats2)=>{if(err)reject(is2.nativeError(err,stack));else resolve2(stats2)})})}module.exports=function(Sharp){Object.assign(Sharp.prototype,{_inputOptionsFromObject,_createInputDescriptor,_write,_flattenBufferIn,_isStreamInput,metadata,stats}),Sharp.align=align}});var require_resize=__commonJS((exports,module)=>{var is2=require_is(),gravity={center:0,centre:0,north:1,east:2,south:3,west:4,northeast:5,southeast:6,southwest:7,northwest:8},position={top:1,right:2,bottom:3,left:4,"right top":5,"right bottom":6,"left bottom":7,"left top":8},extendWith={background:"background",copy:"copy",repeat:"repeat",mirror:"mirror"},strategy={entropy:16,attention:17},kernel={nearest:"nearest",linear:"linear",cubic:"cubic",mitchell:"mitchell",lanczos2:"lanczos2",lanczos3:"lanczos3"},fit={contain:"contain",cover:"cover",fill:"fill",inside:"inside",outside:"outside"},mapFitToCanvas={contain:"embed",cover:"crop",fill:"ignore_aspect",inside:"max",outside:"min"};function isRotationExpected(options){return options.angle%360!==0||options.useExifOrientation===!0||options.rotationAngle!==0}function isResizeExpected(options){return options.width!==-1||options.height!==-1}function resize(widthOrOptions,height,options){if(isResizeExpected(this.options))this.options.debuglog("ignoring previous resize options");if(this.options.widthPost!==-1)this.options.debuglog("operation order will be: extract, resize, extract");if(is2.defined(widthOrOptions))if(is2.object(widthOrOptions)&&!is2.defined(options))options=widthOrOptions;else if(is2.integer(widthOrOptions)&&widthOrOptions>0)this.options.width=widthOrOptions;else throw is2.invalidParameterError("width","positive integer",widthOrOptions);else this.options.width=-1;if(is2.defined(height))if(is2.integer(height)&&height>0)this.options.height=height;else throw is2.invalidParameterError("height","positive integer",height);else this.options.height=-1;if(is2.object(options)){if(is2.defined(options.width))if(is2.integer(options.width)&&options.width>0)this.options.width=options.width;else throw is2.invalidParameterError("width","positive integer",options.width);if(is2.defined(options.height))if(is2.integer(options.height)&&options.height>0)this.options.height=options.height;else throw is2.invalidParameterError("height","positive integer",options.height);if(is2.defined(options.fit)){let canvas=mapFitToCanvas[options.fit];if(is2.string(canvas))this.options.canvas=canvas;else throw is2.invalidParameterError("fit","valid fit",options.fit)}if(is2.defined(options.position)){let pos=is2.integer(options.position)?options.position:strategy[options.position]||position[options.position]||gravity[options.position];if(is2.integer(pos)&&(is2.inRange(pos,0,8)||is2.inRange(pos,16,17)))this.options.position=pos;else throw is2.invalidParameterError("position","valid position/gravity/strategy",options.position)}if(this._setBackgroundColourOption("resizeBackground",options.background),is2.defined(options.kernel))if(is2.string(kernel[options.kernel]))this.options.kernel=kernel[options.kernel];else throw is2.invalidParameterError("kernel","valid kernel name",options.kernel);if(is2.defined(options.withoutEnlargement))this._setBooleanOption("withoutEnlargement",options.withoutEnlargement);if(is2.defined(options.withoutReduction))this._setBooleanOption("withoutReduction",options.withoutReduction);if(is2.defined(options.fastShrinkOnLoad))this._setBooleanOption("fastShrinkOnLoad",options.fastShrinkOnLoad)}if(isRotationExpected(this.options)&&isResizeExpected(this.options))this.options.rotateBeforePreExtract=!0;return this}function extend(extend2){if(is2.integer(extend2)&&extend2>0)this.options.extendTop=extend2,this.options.extendBottom=extend2,this.options.extendLeft=extend2,this.options.extendRight=extend2;else if(is2.object(extend2)){if(is2.defined(extend2.top))if(is2.integer(extend2.top)&&extend2.top>=0)this.options.extendTop=extend2.top;else throw is2.invalidParameterError("top","positive integer",extend2.top);if(is2.defined(extend2.bottom))if(is2.integer(extend2.bottom)&&extend2.bottom>=0)this.options.extendBottom=extend2.bottom;else throw is2.invalidParameterError("bottom","positive integer",extend2.bottom);if(is2.defined(extend2.left))if(is2.integer(extend2.left)&&extend2.left>=0)this.options.extendLeft=extend2.left;else throw is2.invalidParameterError("left","positive integer",extend2.left);if(is2.defined(extend2.right))if(is2.integer(extend2.right)&&extend2.right>=0)this.options.extendRight=extend2.right;else throw is2.invalidParameterError("right","positive integer",extend2.right);if(this._setBackgroundColourOption("extendBackground",extend2.background),is2.defined(extend2.extendWith))if(is2.string(extendWith[extend2.extendWith]))this.options.extendWith=extendWith[extend2.extendWith];else throw is2.invalidParameterError("extendWith","one of: background, copy, repeat, mirror",extend2.extendWith)}else throw is2.invalidParameterError("extend","integer or object",extend2);return this}function extract(options){let suffix=isResizeExpected(this.options)||this.options.widthPre!==-1?"Post":"Pre";if(this.options[`width${suffix}`]!==-1)this.options.debuglog("ignoring previous extract options");if(["left","top","width","height"].forEach(function(name2){let value=options[name2];if(is2.integer(value)&&value>=0)this.options[name2+(name2==="left"||name2==="top"?"Offset":"")+suffix]=value;else throw is2.invalidParameterError(name2,"integer",value)},this),isRotationExpected(this.options)&&!isResizeExpected(this.options)){if(this.options.widthPre===-1||this.options.widthPost===-1)this.options.rotateBeforePreExtract=!0}return this}function trim(options){if(this.options.trimThreshold=10,is2.defined(options))if(is2.object(options)){if(is2.defined(options.background))this._setBackgroundColourOption("trimBackground",options.background);if(is2.defined(options.threshold))if(is2.number(options.threshold)&&options.threshold>=0)this.options.trimThreshold=options.threshold;else throw is2.invalidParameterError("threshold","positive number",options.threshold);if(is2.defined(options.lineArt))this._setBooleanOption("trimLineArt",options.lineArt)}else throw is2.invalidParameterError("trim","object",options);if(isRotationExpected(this.options))this.options.rotateBeforePreExtract=!0;return this}module.exports=function(Sharp){Object.assign(Sharp.prototype,{resize,extend,extract,trim}),Sharp.gravity=gravity,Sharp.strategy=strategy,Sharp.kernel=kernel,Sharp.fit=fit,Sharp.position=position}});var require_composite=__commonJS((exports,module)=>{var is2=require_is(),blend={clear:"clear",source:"source",over:"over",in:"in",out:"out",atop:"atop",dest:"dest","dest-over":"dest-over","dest-in":"dest-in","dest-out":"dest-out","dest-atop":"dest-atop",xor:"xor",add:"add",saturate:"saturate",multiply:"multiply",screen:"screen",overlay:"overlay",darken:"darken",lighten:"lighten","colour-dodge":"colour-dodge","color-dodge":"colour-dodge","colour-burn":"colour-burn","color-burn":"colour-burn","hard-light":"hard-light","soft-light":"soft-light",difference:"difference",exclusion:"exclusion"};function composite(images){if(!Array.isArray(images))throw is2.invalidParameterError("images to composite","array",images);return this.options.composite=images.map((image)=>{if(!is2.object(image))throw is2.invalidParameterError("image to composite","object",image);let inputOptions=this._inputOptionsFromObject(image),composite2={input:this._createInputDescriptor(image.input,inputOptions,{allowStream:!1}),blend:"over",tile:!1,left:0,top:0,hasOffset:!1,gravity:0,premultiplied:!1};if(is2.defined(image.blend))if(is2.string(blend[image.blend]))composite2.blend=blend[image.blend];else throw is2.invalidParameterError("blend","valid blend name",image.blend);if(is2.defined(image.tile))if(is2.bool(image.tile))composite2.tile=image.tile;else throw is2.invalidParameterError("tile","boolean",image.tile);if(is2.defined(image.left))if(is2.integer(image.left))composite2.left=image.left;else throw is2.invalidParameterError("left","integer",image.left);if(is2.defined(image.top))if(is2.integer(image.top))composite2.top=image.top;else throw is2.invalidParameterError("top","integer",image.top);if(is2.defined(image.top)!==is2.defined(image.left))throw Error("Expected both left and top to be set");else composite2.hasOffset=is2.integer(image.top)&&is2.integer(image.left);if(is2.defined(image.gravity))if(is2.integer(image.gravity)&&is2.inRange(image.gravity,0,8))composite2.gravity=image.gravity;else if(is2.string(image.gravity)&&is2.integer(this.constructor.gravity[image.gravity]))composite2.gravity=this.constructor.gravity[image.gravity];else throw is2.invalidParameterError("gravity","valid gravity",image.gravity);if(is2.defined(image.premultiplied))if(is2.bool(image.premultiplied))composite2.premultiplied=image.premultiplied;else throw is2.invalidParameterError("premultiplied","boolean",image.premultiplied);return composite2}),this}module.exports=function(Sharp){Sharp.prototype.composite=composite,Sharp.blend=blend}});var require_operation=__commonJS((exports,module)=>{var color=require_color(),is2=require_is(),vipsPrecision={integer:"integer",float:"float",approximate:"approximate"};function rotate(angle,options){if(this.options.useExifOrientation||this.options.angle||this.options.rotationAngle)this.options.debuglog("ignoring previous rotate options");if(!is2.defined(angle))this.options.useExifOrientation=!0;else if(is2.integer(angle)&&!(angle%90))this.options.angle=angle;else if(is2.number(angle)){if(this.options.rotationAngle=angle,is2.object(options)&&options.background){let backgroundColour=color(options.background);this.options.rotationBackground=[backgroundColour.red(),backgroundColour.green(),backgroundColour.blue(),Math.round(backgroundColour.alpha()*255)]}}else throw is2.invalidParameterError("angle","numeric",angle);return this}function flip(flip2){return this.options.flip=is2.bool(flip2)?flip2:!0,this}function flop(flop2){return this.options.flop=is2.bool(flop2)?flop2:!0,this}function affine(matrix,options){let flatMatrix=[].concat(...matrix);if(flatMatrix.length===4&&flatMatrix.every(is2.number))this.options.affineMatrix=flatMatrix;else throw is2.invalidParameterError("matrix","1x4 or 2x2 array",matrix);if(is2.defined(options))if(is2.object(options)){if(this._setBackgroundColourOption("affineBackground",options.background),is2.defined(options.idx))if(is2.number(options.idx))this.options.affineIdx=options.idx;else throw is2.invalidParameterError("options.idx","number",options.idx);if(is2.defined(options.idy))if(is2.number(options.idy))this.options.affineIdy=options.idy;else throw is2.invalidParameterError("options.idy","number",options.idy);if(is2.defined(options.odx))if(is2.number(options.odx))this.options.affineOdx=options.odx;else throw is2.invalidParameterError("options.odx","number",options.odx);if(is2.defined(options.ody))if(is2.number(options.ody))this.options.affineOdy=options.ody;else throw is2.invalidParameterError("options.ody","number",options.ody);if(is2.defined(options.interpolator))if(is2.inArray(options.interpolator,Object.values(this.constructor.interpolators)))this.options.affineInterpolator=options.interpolator;else throw is2.invalidParameterError("options.interpolator","valid interpolator name",options.interpolator)}else throw is2.invalidParameterError("options","object",options);return this}function sharpen(options,flat,jagged){if(!is2.defined(options))this.options.sharpenSigma=-1;else if(is2.bool(options))this.options.sharpenSigma=options?-1:0;else if(is2.number(options)&&is2.inRange(options,0.01,1e4)){if(this.options.sharpenSigma=options,is2.defined(flat))if(is2.number(flat)&&is2.inRange(flat,0,1e4))this.options.sharpenM1=flat;else throw is2.invalidParameterError("flat","number between 0 and 10000",flat);if(is2.defined(jagged))if(is2.number(jagged)&&is2.inRange(jagged,0,1e4))this.options.sharpenM2=jagged;else throw is2.invalidParameterError("jagged","number between 0 and 10000",jagged)}else if(is2.plainObject(options)){if(is2.number(options.sigma)&&is2.inRange(options.sigma,0.000001,10))this.options.sharpenSigma=options.sigma;else throw is2.invalidParameterError("options.sigma","number between 0.000001 and 10",options.sigma);if(is2.defined(options.m1))if(is2.number(options.m1)&&is2.inRange(options.m1,0,1e6))this.options.sharpenM1=options.m1;else throw is2.invalidParameterError("options.m1","number between 0 and 1000000",options.m1);if(is2.defined(options.m2))if(is2.number(options.m2)&&is2.inRange(options.m2,0,1e6))this.options.sharpenM2=options.m2;else throw is2.invalidParameterError("options.m2","number between 0 and 1000000",options.m2);if(is2.defined(options.x1))if(is2.number(options.x1)&&is2.inRange(options.x1,0,1e6))this.options.sharpenX1=options.x1;else throw is2.invalidParameterError("options.x1","number between 0 and 1000000",options.x1);if(is2.defined(options.y2))if(is2.number(options.y2)&&is2.inRange(options.y2,0,1e6))this.options.sharpenY2=options.y2;else throw is2.invalidParameterError("options.y2","number between 0 and 1000000",options.y2);if(is2.defined(options.y3))if(is2.number(options.y3)&&is2.inRange(options.y3,0,1e6))this.options.sharpenY3=options.y3;else throw is2.invalidParameterError("options.y3","number between 0 and 1000000",options.y3)}else throw is2.invalidParameterError("sigma","number between 0.01 and 10000",options);return this}function median(size){if(!is2.defined(size))this.options.medianSize=3;else if(is2.integer(size)&&is2.inRange(size,1,1000))this.options.medianSize=size;else throw is2.invalidParameterError("size","integer between 1 and 1000",size);return this}function blur(options){let sigma;if(is2.number(options))sigma=options;else if(is2.plainObject(options)){if(!is2.number(options.sigma))throw is2.invalidParameterError("options.sigma","number between 0.3 and 1000",sigma);if(sigma=options.sigma,"precision"in options)if(is2.string(vipsPrecision[options.precision]))this.options.precision=vipsPrecision[options.precision];else throw is2.invalidParameterError("precision","one of: integer, float, approximate",options.precision);if("minAmplitude"in options)if(is2.number(options.minAmplitude)&&is2.inRange(options.minAmplitude,0.001,1))this.options.minAmpl=options.minAmplitude;else throw is2.invalidParameterError("minAmplitude","number between 0.001 and 1",options.minAmplitude)}if(!is2.defined(options))this.options.blurSigma=-1;else if(is2.bool(options))this.options.blurSigma=options?-1:0;else if(is2.number(sigma)&&is2.inRange(sigma,0.3,1000))this.options.blurSigma=sigma;else throw is2.invalidParameterError("sigma","number between 0.3 and 1000",sigma);return this}function flatten(options){if(this.options.flatten=is2.bool(options)?options:!0,is2.object(options))this._setBackgroundColourOption("flattenBackground",options.background);return this}function unflatten(){return this.options.unflatten=!0,this}function gamma(gamma2,gammaOut){if(!is2.defined(gamma2))this.options.gamma=2.2;else if(is2.number(gamma2)&&is2.inRange(gamma2,1,3))this.options.gamma=gamma2;else throw is2.invalidParameterError("gamma","number between 1.0 and 3.0",gamma2);if(!is2.defined(gammaOut))this.options.gammaOut=this.options.gamma;else if(is2.number(gammaOut)&&is2.inRange(gammaOut,1,3))this.options.gammaOut=gammaOut;else throw is2.invalidParameterError("gammaOut","number between 1.0 and 3.0",gammaOut);return this}function negate(options){if(this.options.negate=is2.bool(options)?options:!0,is2.plainObject(options)&&"alpha"in options)if(!is2.bool(options.alpha))throw is2.invalidParameterError("alpha","should be boolean value",options.alpha);else this.options.negateAlpha=options.alpha;return this}function normalise(options){if(is2.plainObject(options)){if(is2.defined(options.lower))if(is2.number(options.lower)&&is2.inRange(options.lower,0,99))this.options.normaliseLower=options.lower;else throw is2.invalidParameterError("lower","number between 0 and 99",options.lower);if(is2.defined(options.upper))if(is2.number(options.upper)&&is2.inRange(options.upper,1,100))this.options.normaliseUpper=options.upper;else throw is2.invalidParameterError("upper","number between 1 and 100",options.upper)}if(this.options.normaliseLower>=this.options.normaliseUpper)throw is2.invalidParameterError("range","lower to be less than upper",`${this.options.normaliseLower} >= ${this.options.normaliseUpper}`);return this.options.normalise=!0,this}function normalize3(options){return this.normalise(options)}function clahe(options){if(is2.plainObject(options)){if(is2.integer(options.width)&&options.width>0)this.options.claheWidth=options.width;else throw is2.invalidParameterError("width","integer greater than zero",options.width);if(is2.integer(options.height)&&options.height>0)this.options.claheHeight=options.height;else throw is2.invalidParameterError("height","integer greater than zero",options.height);if(is2.defined(options.maxSlope))if(is2.integer(options.maxSlope)&&is2.inRange(options.maxSlope,0,100))this.options.claheMaxSlope=options.maxSlope;else throw is2.invalidParameterError("maxSlope","integer between 0 and 100",options.maxSlope)}else throw is2.invalidParameterError("options","plain object",options);return this}function convolve(kernel){if(!is2.object(kernel)||!Array.isArray(kernel.kernel)||!is2.integer(kernel.width)||!is2.integer(kernel.height)||!is2.inRange(kernel.width,3,1001)||!is2.inRange(kernel.height,3,1001)||kernel.height*kernel.width!==kernel.kernel.length)throw Error("Invalid convolution kernel");if(!is2.integer(kernel.scale))kernel.scale=kernel.kernel.reduce(function(a,b){return a+b},0);if(kernel.scale<1)kernel.scale=1;if(!is2.integer(kernel.offset))kernel.offset=0;return this.options.convKernel=kernel,this}function threshold(threshold2,options){if(!is2.defined(threshold2))this.options.threshold=128;else if(is2.bool(threshold2))this.options.threshold=threshold2?128:0;else if(is2.integer(threshold2)&&is2.inRange(threshold2,0,255))this.options.threshold=threshold2;else throw is2.invalidParameterError("threshold","integer between 0 and 255",threshold2);if(!is2.object(options)||options.greyscale===!0||options.grayscale===!0)this.options.thresholdGrayscale=!0;else this.options.thresholdGrayscale=!1;return this}function boolean(operand,operator,options){if(this.options.boolean=this._createInputDescriptor(operand,options),is2.string(operator)&&is2.inArray(operator,["and","or","eor"]))this.options.booleanOp=operator;else throw is2.invalidParameterError("operator","one of: and, or, eor",operator);return this}function linear(a,b){if(!is2.defined(a)&&is2.number(b))a=1;else if(is2.number(a)&&!is2.defined(b))b=0;if(!is2.defined(a))this.options.linearA=[];else if(is2.number(a))this.options.linearA=[a];else if(Array.isArray(a)&&a.length&&a.every(is2.number))this.options.linearA=a;else throw is2.invalidParameterError("a","number or array of numbers",a);if(!is2.defined(b))this.options.linearB=[];else if(is2.number(b))this.options.linearB=[b];else if(Array.isArray(b)&&b.length&&b.every(is2.number))this.options.linearB=b;else throw is2.invalidParameterError("b","number or array of numbers",b);if(this.options.linearA.length!==this.options.linearB.length)throw Error("Expected a and b to be arrays of the same length");return this}function recomb(inputMatrix){if(!Array.isArray(inputMatrix))throw is2.invalidParameterError("inputMatrix","array",inputMatrix);if(inputMatrix.length!==3&&inputMatrix.length!==4)throw is2.invalidParameterError("inputMatrix","3x3 or 4x4 array",inputMatrix.length);let recombMatrix=inputMatrix.flat().map(Number);if(recombMatrix.length!==9&&recombMatrix.length!==16)throw is2.invalidParameterError("inputMatrix","cardinality of 9 or 16",recombMatrix.length);return this.options.recombMatrix=recombMatrix,this}function modulate(options){if(!is2.plainObject(options))throw is2.invalidParameterError("options","plain object",options);if("brightness"in options)if(is2.number(options.brightness)&&options.brightness>=0)this.options.brightness=options.brightness;else throw is2.invalidParameterError("brightness","number above zero",options.brightness);if("saturation"in options)if(is2.number(options.saturation)&&options.saturation>=0)this.options.saturation=options.saturation;else throw is2.invalidParameterError("saturation","number above zero",options.saturation);if("hue"in options)if(is2.integer(options.hue))this.options.hue=options.hue%360;else throw is2.invalidParameterError("hue","number",options.hue);if("lightness"in options)if(is2.number(options.lightness))this.options.lightness=options.lightness;else throw is2.invalidParameterError("lightness","number",options.lightness);return this}module.exports=function(Sharp){Object.assign(Sharp.prototype,{rotate,flip,flop,affine,sharpen,median,blur,flatten,unflatten,gamma,negate,normalise,normalize:normalize3,clahe,convolve,threshold,boolean,linear,recomb,modulate})}});var require_colour=__commonJS((exports,module)=>{var color=require_color(),is2=require_is(),colourspace={multiband:"multiband","b-w":"b-w",bw:"b-w",cmyk:"cmyk",srgb:"srgb"};function tint(tint2){return this._setBackgroundColourOption("tint",tint2),this}function greyscale(greyscale2){return this.options.greyscale=is2.bool(greyscale2)?greyscale2:!0,this}function grayscale(grayscale2){return this.greyscale(grayscale2)}function pipelineColourspace(colourspace2){if(!is2.string(colourspace2))throw is2.invalidParameterError("colourspace","string",colourspace2);return this.options.colourspacePipeline=colourspace2,this}function pipelineColorspace(colorspace){return this.pipelineColourspace(colorspace)}function toColourspace(colourspace2){if(!is2.string(colourspace2))throw is2.invalidParameterError("colourspace","string",colourspace2);return this.options.colourspace=colourspace2,this}function toColorspace(colorspace){return this.toColourspace(colorspace)}function _setBackgroundColourOption(key2,value){if(is2.defined(value))if(is2.object(value)||is2.string(value)){let colour=color(value);this.options[key2]=[colour.red(),colour.green(),colour.blue(),Math.round(colour.alpha()*255)]}else throw is2.invalidParameterError("background","object or string",value)}module.exports=function(Sharp){Object.assign(Sharp.prototype,{tint,greyscale,grayscale,pipelineColourspace,pipelineColorspace,toColourspace,toColorspace,_setBackgroundColourOption}),Sharp.colourspace=colourspace,Sharp.colorspace=colourspace}});var require_channel=__commonJS((exports,module)=>{var is2=require_is(),bool={and:"and",or:"or",eor:"eor"};function removeAlpha(){return this.options.removeAlpha=!0,this}function ensureAlpha(alpha){if(is2.defined(alpha))if(is2.number(alpha)&&is2.inRange(alpha,0,1))this.options.ensureAlpha=alpha;else throw is2.invalidParameterError("alpha","number between 0 and 1",alpha);else this.options.ensureAlpha=1;return this}function extractChannel(channel){let channelMap={red:0,green:1,blue:2,alpha:3};if(Object.keys(channelMap).includes(channel))channel=channelMap[channel];if(is2.integer(channel)&&is2.inRange(channel,0,4))this.options.extractChannel=channel;else throw is2.invalidParameterError("channel","integer or one of: red, green, blue, alpha",channel);return this}function joinChannel(images,options){if(Array.isArray(images))images.forEach(function(image){this.options.joinChannelIn.push(this._createInputDescriptor(image,options))},this);else this.options.joinChannelIn.push(this._createInputDescriptor(images,options));return this}function bandbool(boolOp){if(is2.string(boolOp)&&is2.inArray(boolOp,["and","or","eor"]))this.options.bandBoolOp=boolOp;else throw is2.invalidParameterError("boolOp","one of: and, or, eor",boolOp);return this}module.exports=function(Sharp){Object.assign(Sharp.prototype,{removeAlpha,ensureAlpha,extractChannel,joinChannel,bandbool}),Sharp.bool=bool}});var require_output=__commonJS((exports,module)=>{var path3=__require("path"),is2=require_is(),sharp=require_sharp(),formats2=new Map([["heic","heif"],["heif","heif"],["avif","avif"],["jpeg","jpeg"],["jpg","jpeg"],["jpe","jpeg"],["tile","tile"],["dz","tile"],["png","png"],["raw","raw"],["tiff","tiff"],["tif","tiff"],["webp","webp"],["gif","gif"],["jp2","jp2"],["jpx","jp2"],["j2k","jp2"],["j2c","jp2"],["jxl","jxl"]]),jp2Regex=/\.(jp[2x]|j2[kc])$/i,errJp2Save=()=>Error("JP2 output requires libvips with support for OpenJPEG"),bitdepthFromColourCount=(colours)=>1<<31-Math.clz32(Math.ceil(Math.log2(colours)));function toFile(fileOut,callback){let err;if(!is2.string(fileOut))err=Error("Missing output file path");else if(is2.string(this.options.input.file)&&path3.resolve(this.options.input.file)===path3.resolve(fileOut))err=Error("Cannot use same file for input and output");else if(jp2Regex.test(path3.extname(fileOut))&&!this.constructor.format.jp2k.output.file)err=errJp2Save();if(err)if(is2.fn(callback))callback(err);else return Promise.reject(err);else{this.options.fileOut=fileOut;let stack=Error();return this._pipeline(callback,stack)}return this}function toBuffer2(options,callback){if(is2.object(options))this._setBooleanOption("resolveWithObject",options.resolveWithObject);else if(this.options.resolveWithObject)this.options.resolveWithObject=!1;this.options.fileOut="";let stack=Error();return this._pipeline(is2.fn(options)?options:callback,stack)}function keepExif(){return this.options.keepMetadata|=1,this}function withExif(exif){if(is2.object(exif))for(let[ifd,entries]of Object.entries(exif))if(is2.object(entries))for(let[k,v]of Object.entries(entries))if(is2.string(v))this.options.withExif[`exif-${ifd.toLowerCase()}-${k}`]=v;else throw is2.invalidParameterError(`${ifd}.${k}`,"string",v);else throw is2.invalidParameterError(ifd,"object",entries);else throw is2.invalidParameterError("exif","object",exif);return this.options.withExifMerge=!1,this.keepExif()}function withExifMerge(exif){return this.withExif(exif),this.options.withExifMerge=!0,this}function keepIccProfile(){return this.options.keepMetadata|=8,this}function withIccProfile(icc,options){if(is2.string(icc))this.options.withIccProfile=icc;else throw is2.invalidParameterError("icc","string",icc);if(this.keepIccProfile(),is2.object(options)){if(is2.defined(options.attach))if(is2.bool(options.attach)){if(!options.attach)this.options.keepMetadata&=-9}else throw is2.invalidParameterError("attach","boolean",options.attach)}return this}function keepMetadata(){return this.options.keepMetadata=31,this}function withMetadata(options){if(this.keepMetadata(),this.withIccProfile("srgb"),is2.object(options)){if(is2.defined(options.orientation))if(is2.integer(options.orientation)&&is2.inRange(options.orientation,1,8))this.options.withMetadataOrientation=options.orientation;else throw is2.invalidParameterError("orientation","integer between 1 and 8",options.orientation);if(is2.defined(options.density))if(is2.number(options.density)&&options.density>0)this.options.withMetadataDensity=options.density;else throw is2.invalidParameterError("density","positive number",options.density);if(is2.defined(options.icc))this.withIccProfile(options.icc);if(is2.defined(options.exif))this.withExifMerge(options.exif)}return this}function toFormat(format2,options){let actualFormat=formats2.get((is2.object(format2)&&is2.string(format2.id)?format2.id:format2).toLowerCase());if(!actualFormat)throw is2.invalidParameterError("format",`one of: ${[...formats2.keys()].join(", ")}`,format2);return this[actualFormat](options)}function jpeg(options){if(is2.object(options)){if(is2.defined(options.quality))if(is2.integer(options.quality)&&is2.inRange(options.quality,1,100))this.options.jpegQuality=options.quality;else throw is2.invalidParameterError("quality","integer between 1 and 100",options.quality);if(is2.defined(options.progressive))this._setBooleanOption("jpegProgressive",options.progressive);if(is2.defined(options.chromaSubsampling))if(is2.string(options.chromaSubsampling)&&is2.inArray(options.chromaSubsampling,["4:2:0","4:4:4"]))this.options.jpegChromaSubsampling=options.chromaSubsampling;else throw is2.invalidParameterError("chromaSubsampling","one of: 4:2:0, 4:4:4",options.chromaSubsampling);let optimiseCoding=is2.bool(options.optimizeCoding)?options.optimizeCoding:options.optimiseCoding;if(is2.defined(optimiseCoding))this._setBooleanOption("jpegOptimiseCoding",optimiseCoding);if(is2.defined(options.mozjpeg))if(is2.bool(options.mozjpeg)){if(options.mozjpeg)this.options.jpegTrellisQuantisation=!0,this.options.jpegOvershootDeringing=!0,this.options.jpegOptimiseScans=!0,this.options.jpegProgressive=!0,this.options.jpegQuantisationTable=3}else throw is2.invalidParameterError("mozjpeg","boolean",options.mozjpeg);let trellisQuantisation=is2.bool(options.trellisQuantization)?options.trellisQuantization:options.trellisQuantisation;if(is2.defined(trellisQuantisation))this._setBooleanOption("jpegTrellisQuantisation",trellisQuantisation);if(is2.defined(options.overshootDeringing))this._setBooleanOption("jpegOvershootDeringing",options.overshootDeringing);let optimiseScans=is2.bool(options.optimizeScans)?options.optimizeScans:options.optimiseScans;if(is2.defined(optimiseScans)){if(this._setBooleanOption("jpegOptimiseScans",optimiseScans),optimiseScans)this.options.jpegProgressive=!0}let quantisationTable=is2.number(options.quantizationTable)?options.quantizationTable:options.quantisationTable;if(is2.defined(quantisationTable))if(is2.integer(quantisationTable)&&is2.inRange(quantisationTable,0,8))this.options.jpegQuantisationTable=quantisationTable;else throw is2.invalidParameterError("quantisationTable","integer between 0 and 8",quantisationTable)}return this._updateFormatOut("jpeg",options)}function png(options){if(is2.object(options)){if(is2.defined(options.progressive))this._setBooleanOption("pngProgressive",options.progressive);if(is2.defined(options.compressionLevel))if(is2.integer(options.compressionLevel)&&is2.inRange(options.compressionLevel,0,9))this.options.pngCompressionLevel=options.compressionLevel;else throw is2.invalidParameterError("compressionLevel","integer between 0 and 9",options.compressionLevel);if(is2.defined(options.adaptiveFiltering))this._setBooleanOption("pngAdaptiveFiltering",options.adaptiveFiltering);let colours=options.colours||options.colors;if(is2.defined(colours))if(is2.integer(colours)&&is2.inRange(colours,2,256))this.options.pngBitdepth=bitdepthFromColourCount(colours);else throw is2.invalidParameterError("colours","integer between 2 and 256",colours);if(is2.defined(options.palette))this._setBooleanOption("pngPalette",options.palette);else if([options.quality,options.effort,options.colours,options.colors,options.dither].some(is2.defined))this._setBooleanOption("pngPalette",!0);if(this.options.pngPalette){if(is2.defined(options.quality))if(is2.integer(options.quality)&&is2.inRange(options.quality,0,100))this.options.pngQuality=options.quality;else throw is2.invalidParameterError("quality","integer between 0 and 100",options.quality);if(is2.defined(options.effort))if(is2.integer(options.effort)&&is2.inRange(options.effort,1,10))this.options.pngEffort=options.effort;else throw is2.invalidParameterError("effort","integer between 1 and 10",options.effort);if(is2.defined(options.dither))if(is2.number(options.dither)&&is2.inRange(options.dither,0,1))this.options.pngDither=options.dither;else throw is2.invalidParameterError("dither","number between 0.0 and 1.0",options.dither)}}return this._updateFormatOut("png",options)}function webp(options){if(is2.object(options)){if(is2.defined(options.quality))if(is2.integer(options.quality)&&is2.inRange(options.quality,1,100))this.options.webpQuality=options.quality;else throw is2.invalidParameterError("quality","integer between 1 and 100",options.quality);if(is2.defined(options.alphaQuality))if(is2.integer(options.alphaQuality)&&is2.inRange(options.alphaQuality,0,100))this.options.webpAlphaQuality=options.alphaQuality;else throw is2.invalidParameterError("alphaQuality","integer between 0 and 100",options.alphaQuality);if(is2.defined(options.lossless))this._setBooleanOption("webpLossless",options.lossless);if(is2.defined(options.nearLossless))this._setBooleanOption("webpNearLossless",options.nearLossless);if(is2.defined(options.smartSubsample))this._setBooleanOption("webpSmartSubsample",options.smartSubsample);if(is2.defined(options.preset))if(is2.string(options.preset)&&is2.inArray(options.preset,["default","photo","picture","drawing","icon","text"]))this.options.webpPreset=options.preset;else throw is2.invalidParameterError("preset","one of: default, photo, picture, drawing, icon, text",options.preset);if(is2.defined(options.effort))if(is2.integer(options.effort)&&is2.inRange(options.effort,0,6))this.options.webpEffort=options.effort;else throw is2.invalidParameterError("effort","integer between 0 and 6",options.effort);if(is2.defined(options.minSize))this._setBooleanOption("webpMinSize",options.minSize);if(is2.defined(options.mixed))this._setBooleanOption("webpMixed",options.mixed)}return trySetAnimationOptions(options,this.options),this._updateFormatOut("webp",options)}function gif(options){if(is2.object(options)){if(is2.defined(options.reuse))this._setBooleanOption("gifReuse",options.reuse);if(is2.defined(options.progressive))this._setBooleanOption("gifProgressive",options.progressive);let colours=options.colours||options.colors;if(is2.defined(colours))if(is2.integer(colours)&&is2.inRange(colours,2,256))this.options.gifBitdepth=bitdepthFromColourCount(colours);else throw is2.invalidParameterError("colours","integer between 2 and 256",colours);if(is2.defined(options.effort))if(is2.number(options.effort)&&is2.inRange(options.effort,1,10))this.options.gifEffort=options.effort;else throw is2.invalidParameterError("effort","integer between 1 and 10",options.effort);if(is2.defined(options.dither))if(is2.number(options.dither)&&is2.inRange(options.dither,0,1))this.options.gifDither=options.dither;else throw is2.invalidParameterError("dither","number between 0.0 and 1.0",options.dither);if(is2.defined(options.interFrameMaxError))if(is2.number(options.interFrameMaxError)&&is2.inRange(options.interFrameMaxError,0,32))this.options.gifInterFrameMaxError=options.interFrameMaxError;else throw is2.invalidParameterError("interFrameMaxError","number between 0.0 and 32.0",options.interFrameMaxError);if(is2.defined(options.interPaletteMaxError))if(is2.number(options.interPaletteMaxError)&&is2.inRange(options.interPaletteMaxError,0,256))this.options.gifInterPaletteMaxError=options.interPaletteMaxError;else throw is2.invalidParameterError("interPaletteMaxError","number between 0.0 and 256.0",options.interPaletteMaxError)}return trySetAnimationOptions(options,this.options),this._updateFormatOut("gif",options)}function jp2(options){if(!this.constructor.format.jp2k.output.buffer)throw errJp2Save();if(is2.object(options)){if(is2.defined(options.quality))if(is2.integer(options.quality)&&is2.inRange(options.quality,1,100))this.options.jp2Quality=options.quality;else throw is2.invalidParameterError("quality","integer between 1 and 100",options.quality);if(is2.defined(options.lossless))if(is2.bool(options.lossless))this.options.jp2Lossless=options.lossless;else throw is2.invalidParameterError("lossless","boolean",options.lossless);if(is2.defined(options.tileWidth))if(is2.integer(options.tileWidth)&&is2.inRange(options.tileWidth,1,32768))this.options.jp2TileWidth=options.tileWidth;else throw is2.invalidParameterError("tileWidth","integer between 1 and 32768",options.tileWidth);if(is2.defined(options.tileHeight))if(is2.integer(options.tileHeight)&&is2.inRange(options.tileHeight,1,32768))this.options.jp2TileHeight=options.tileHeight;else throw is2.invalidParameterError("tileHeight","integer between 1 and 32768",options.tileHeight);if(is2.defined(options.chromaSubsampling))if(is2.string(options.chromaSubsampling)&&is2.inArray(options.chromaSubsampling,["4:2:0","4:4:4"]))this.options.jp2ChromaSubsampling=options.chromaSubsampling;else throw is2.invalidParameterError("chromaSubsampling","one of: 4:2:0, 4:4:4",options.chromaSubsampling)}return this._updateFormatOut("jp2",options)}function trySetAnimationOptions(source,target2){if(is2.object(source)&&is2.defined(source.loop))if(is2.integer(source.loop)&&is2.inRange(source.loop,0,65535))target2.loop=source.loop;else throw is2.invalidParameterError("loop","integer between 0 and 65535",source.loop);if(is2.object(source)&&is2.defined(source.delay))if(is2.integer(source.delay)&&is2.inRange(source.delay,0,65535))target2.delay=[source.delay];else if(Array.isArray(source.delay)&&source.delay.every(is2.integer)&&source.delay.every((v)=>is2.inRange(v,0,65535)))target2.delay=source.delay;else throw is2.invalidParameterError("delay","integer or an array of integers between 0 and 65535",source.delay)}function tiff(options){if(is2.object(options)){if(is2.defined(options.quality))if(is2.integer(options.quality)&&is2.inRange(options.quality,1,100))this.options.tiffQuality=options.quality;else throw is2.invalidParameterError("quality","integer between 1 and 100",options.quality);if(is2.defined(options.bitdepth))if(is2.integer(options.bitdepth)&&is2.inArray(options.bitdepth,[1,2,4,8]))this.options.tiffBitdepth=options.bitdepth;else throw is2.invalidParameterError("bitdepth","1, 2, 4 or 8",options.bitdepth);if(is2.defined(options.tile))this._setBooleanOption("tiffTile",options.tile);if(is2.defined(options.tileWidth))if(is2.integer(options.tileWidth)&&options.tileWidth>0)this.options.tiffTileWidth=options.tileWidth;else throw is2.invalidParameterError("tileWidth","integer greater than zero",options.tileWidth);if(is2.defined(options.tileHeight))if(is2.integer(options.tileHeight)&&options.tileHeight>0)this.options.tiffTileHeight=options.tileHeight;else throw is2.invalidParameterError("tileHeight","integer greater than zero",options.tileHeight);if(is2.defined(options.miniswhite))this._setBooleanOption("tiffMiniswhite",options.miniswhite);if(is2.defined(options.pyramid))this._setBooleanOption("tiffPyramid",options.pyramid);if(is2.defined(options.xres))if(is2.number(options.xres)&&options.xres>0)this.options.tiffXres=options.xres;else throw is2.invalidParameterError("xres","number greater than zero",options.xres);if(is2.defined(options.yres))if(is2.number(options.yres)&&options.yres>0)this.options.tiffYres=options.yres;else throw is2.invalidParameterError("yres","number greater than zero",options.yres);if(is2.defined(options.compression))if(is2.string(options.compression)&&is2.inArray(options.compression,["none","jpeg","deflate","packbits","ccittfax4","lzw","webp","zstd","jp2k"]))this.options.tiffCompression=options.compression;else throw is2.invalidParameterError("compression","one of: none, jpeg, deflate, packbits, ccittfax4, lzw, webp, zstd, jp2k",options.compression);if(is2.defined(options.predictor))if(is2.string(options.predictor)&&is2.inArray(options.predictor,["none","horizontal","float"]))this.options.tiffPredictor=options.predictor;else throw is2.invalidParameterError("predictor","one of: none, horizontal, float",options.predictor);if(is2.defined(options.resolutionUnit))if(is2.string(options.resolutionUnit)&&is2.inArray(options.resolutionUnit,["inch","cm"]))this.options.tiffResolutionUnit=options.resolutionUnit;else throw is2.invalidParameterError("resolutionUnit","one of: inch, cm",options.resolutionUnit)}return this._updateFormatOut("tiff",options)}function avif(options){return this.heif({...options,compression:"av1"})}function heif(options){if(is2.object(options)){if(is2.string(options.compression)&&is2.inArray(options.compression,["av1","hevc"]))this.options.heifCompression=options.compression;else throw is2.invalidParameterError("compression","one of: av1, hevc",options.compression);if(is2.defined(options.quality))if(is2.integer(options.quality)&&is2.inRange(options.quality,1,100))this.options.heifQuality=options.quality;else throw is2.invalidParameterError("quality","integer between 1 and 100",options.quality);if(is2.defined(options.lossless))if(is2.bool(options.lossless))this.options.heifLossless=options.lossless;else throw is2.invalidParameterError("lossless","boolean",options.lossless);if(is2.defined(options.effort))if(is2.integer(options.effort)&&is2.inRange(options.effort,0,9))this.options.heifEffort=options.effort;else throw is2.invalidParameterError("effort","integer between 0 and 9",options.effort);if(is2.defined(options.chromaSubsampling))if(is2.string(options.chromaSubsampling)&&is2.inArray(options.chromaSubsampling,["4:2:0","4:4:4"]))this.options.heifChromaSubsampling=options.chromaSubsampling;else throw is2.invalidParameterError("chromaSubsampling","one of: 4:2:0, 4:4:4",options.chromaSubsampling);if(is2.defined(options.bitdepth))if(is2.integer(options.bitdepth)&&is2.inArray(options.bitdepth,[8,10,12])){if(options.bitdepth!==8&&this.constructor.versions.heif)throw is2.invalidParameterError("bitdepth when using prebuilt binaries",8,options.bitdepth);this.options.heifBitdepth=options.bitdepth}else throw is2.invalidParameterError("bitdepth","8, 10 or 12",options.bitdepth)}else throw is2.invalidParameterError("options","Object",options);return this._updateFormatOut("heif",options)}function jxl(options){if(is2.object(options)){if(is2.defined(options.quality))if(is2.integer(options.quality)&&is2.inRange(options.quality,1,100))this.options.jxlDistance=options.quality>=30?0.1+(100-options.quality)*0.09:0.017666666666666667*options.quality*options.quality-1.15*options.quality+25;else throw is2.invalidParameterError("quality","integer between 1 and 100",options.quality);else if(is2.defined(options.distance))if(is2.number(options.distance)&&is2.inRange(options.distance,0,15))this.options.jxlDistance=options.distance;else throw is2.invalidParameterError("distance","number between 0.0 and 15.0",options.distance);if(is2.defined(options.decodingTier))if(is2.integer(options.decodingTier)&&is2.inRange(options.decodingTier,0,4))this.options.jxlDecodingTier=options.decodingTier;else throw is2.invalidParameterError("decodingTier","integer between 0 and 4",options.decodingTier);if(is2.defined(options.lossless))if(is2.bool(options.lossless))this.options.jxlLossless=options.lossless;else throw is2.invalidParameterError("lossless","boolean",options.lossless);if(is2.defined(options.effort))if(is2.integer(options.effort)&&is2.inRange(options.effort,3,9))this.options.jxlEffort=options.effort;else throw is2.invalidParameterError("effort","integer between 3 and 9",options.effort)}return this._updateFormatOut("jxl",options)}function raw(options){if(is2.object(options)){if(is2.defined(options.depth))if(is2.string(options.depth)&&is2.inArray(options.depth,["char","uchar","short","ushort","int","uint","float","complex","double","dpcomplex"]))this.options.rawDepth=options.depth;else throw is2.invalidParameterError("depth","one of: char, uchar, short, ushort, int, uint, float, complex, double, dpcomplex",options.depth)}return this._updateFormatOut("raw")}function tile(options){if(is2.object(options)){if(is2.defined(options.size))if(is2.integer(options.size)&&is2.inRange(options.size,1,8192))this.options.tileSize=options.size;else throw is2.invalidParameterError("size","integer between 1 and 8192",options.size);if(is2.defined(options.overlap))if(is2.integer(options.overlap)&&is2.inRange(options.overlap,0,8192)){if(options.overlap>this.options.tileSize)throw is2.invalidParameterError("overlap",`<= size (${this.options.tileSize})`,options.overlap);this.options.tileOverlap=options.overlap}else throw is2.invalidParameterError("overlap","integer between 0 and 8192",options.overlap);if(is2.defined(options.container))if(is2.string(options.container)&&is2.inArray(options.container,["fs","zip"]))this.options.tileContainer=options.container;else throw is2.invalidParameterError("container","one of: fs, zip",options.container);if(is2.defined(options.layout))if(is2.string(options.layout)&&is2.inArray(options.layout,["dz","google","iiif","iiif3","zoomify"]))this.options.tileLayout=options.layout;else throw is2.invalidParameterError("layout","one of: dz, google, iiif, iiif3, zoomify",options.layout);if(is2.defined(options.angle))if(is2.integer(options.angle)&&!(options.angle%90))this.options.tileAngle=options.angle;else throw is2.invalidParameterError("angle","positive/negative multiple of 90",options.angle);if(this._setBackgroundColourOption("tileBackground",options.background),is2.defined(options.depth))if(is2.string(options.depth)&&is2.inArray(options.depth,["onepixel","onetile","one"]))this.options.tileDepth=options.depth;else throw is2.invalidParameterError("depth","one of: onepixel, onetile, one",options.depth);if(is2.defined(options.skipBlanks))if(is2.integer(options.skipBlanks)&&is2.inRange(options.skipBlanks,-1,65535))this.options.tileSkipBlanks=options.skipBlanks;else throw is2.invalidParameterError("skipBlanks","integer between -1 and 255/65535",options.skipBlanks);else if(is2.defined(options.layout)&&options.layout==="google")this.options.tileSkipBlanks=5;let centre=is2.bool(options.center)?options.center:options.centre;if(is2.defined(centre))this._setBooleanOption("tileCentre",centre);if(is2.defined(options.id))if(is2.string(options.id))this.options.tileId=options.id;else throw is2.invalidParameterError("id","string",options.id);if(is2.defined(options.basename))if(is2.string(options.basename))this.options.tileBasename=options.basename;else throw is2.invalidParameterError("basename","string",options.basename)}if(is2.inArray(this.options.formatOut,["jpeg","png","webp"]))this.options.tileFormat=this.options.formatOut;else if(this.options.formatOut!=="input")throw is2.invalidParameterError("format","one of: jpeg, png, webp",this.options.formatOut);return this._updateFormatOut("dz")}function timeout(options){if(!is2.plainObject(options))throw is2.invalidParameterError("options","object",options);if(is2.integer(options.seconds)&&is2.inRange(options.seconds,0,3600))this.options.timeoutSeconds=options.seconds;else throw is2.invalidParameterError("seconds","integer between 0 and 3600",options.seconds);return this}function _updateFormatOut(formatOut,options){if(!(is2.object(options)&&options.force===!1))this.options.formatOut=formatOut;return this}function _setBooleanOption(key2,val){if(is2.bool(val))this.options[key2]=val;else throw is2.invalidParameterError(key2,"boolean",val)}function _read(){if(!this.options.streamOut){this.options.streamOut=!0;let stack=Error();this._pipeline(void 0,stack)}}function _pipeline(callback,stack){if(typeof callback==="function"){if(this._isStreamInput())this.on("finish",()=>{this._flattenBufferIn(),sharp.pipeline(this.options,(err,data,info)=>{if(err)callback(is2.nativeError(err,stack));else callback(null,data,info)})});else sharp.pipeline(this.options,(err,data,info)=>{if(err)callback(is2.nativeError(err,stack));else callback(null,data,info)});return this}else if(this.options.streamOut){if(this._isStreamInput()){if(this.once("finish",()=>{this._flattenBufferIn(),sharp.pipeline(this.options,(err,data,info)=>{if(err)this.emit("error",is2.nativeError(err,stack));else this.emit("info",info),this.push(data);this.push(null),this.on("end",()=>this.emit("close"))})}),this.streamInFinished)this.emit("finish")}else sharp.pipeline(this.options,(err,data,info)=>{if(err)this.emit("error",is2.nativeError(err,stack));else this.emit("info",info),this.push(data);this.push(null),this.on("end",()=>this.emit("close"))});return this}else if(this._isStreamInput())return new Promise((resolve2,reject)=>{this.once("finish",()=>{this._flattenBufferIn(),sharp.pipeline(this.options,(err,data,info)=>{if(err)reject(is2.nativeError(err,stack));else if(this.options.resolveWithObject)resolve2({data,info});else resolve2(data)})})});else return new Promise((resolve2,reject)=>{sharp.pipeline(this.options,(err,data,info)=>{if(err)reject(is2.nativeError(err,stack));else if(this.options.resolveWithObject)resolve2({data,info});else resolve2(data)})})}module.exports=function(Sharp){Object.assign(Sharp.prototype,{toFile,toBuffer:toBuffer2,keepExif,withExif,withExifMerge,keepIccProfile,withIccProfile,keepMetadata,withMetadata,toFormat,jpeg,jp2,png,webp,tiff,avif,heif,jxl,gif,raw,tile,timeout,_updateFormatOut,_setBooleanOption,_read,_pipeline})}});var require_utility=__commonJS((exports,module)=>{var events=__require("events"),detectLibc=require_detect_libc(),is2=require_is(),{runtimePlatformArch}=require_libvips(),sharp=require_sharp(),runtimePlatform=runtimePlatformArch(),libvipsVersion=sharp.libvipsVersion(),format2=sharp.format();format2.heif.output.alias=["avif","heic"];format2.jpeg.output.alias=["jpe","jpg"];format2.tiff.output.alias=["tif"];format2.jp2k.output.alias=["j2c","j2k","jp2","jpx"];var interpolators={nearest:"nearest",bilinear:"bilinear",bicubic:"bicubic",locallyBoundedBicubic:"lbb",nohalo:"nohalo",vertexSplitQuadraticBasisSpline:"vsqbs"},versions={vips:libvipsVersion.semver};if(!libvipsVersion.isGlobal)if(!libvipsVersion.isWasm)try{versions=__require(`@img/sharp-${runtimePlatform}/versions`)}catch(_){try{versions=__require(`@img/sharp-libvips-${runtimePlatform}/versions`)}catch(_2){}}else try{versions=(()=>{throw new Error("Cannot require module "+"@img/sharp-wasm32/versions");})()}catch(_){}versions.sharp=require_package().version;if(versions.heif&&format2.heif)format2.heif.input.fileSuffix=[".avif"],format2.heif.output.alias=["avif"];function cache(options){if(is2.bool(options))if(options)return sharp.cache(50,20,100);else return sharp.cache(0,0,0);else if(is2.object(options))return sharp.cache(options.memory,options.files,options.items);else return sharp.cache()}cache(!0);function concurrency(concurrency2){return sharp.concurrency(is2.integer(concurrency2)?concurrency2:null)}if(detectLibc.familySync()===detectLibc.GLIBC&&!sharp._isUsingJemalloc())sharp.concurrency(1);else if(detectLibc.familySync()===detectLibc.MUSL&&sharp.concurrency()===1024)sharp.concurrency(__require("os").availableParallelism());var queue=new events.EventEmitter;function counters(){return sharp.counters()}function simd(simd2){return sharp.simd(is2.bool(simd2)?simd2:null)}function block(options){if(is2.object(options))if(Array.isArray(options.operation)&&options.operation.every(is2.string))sharp.block(options.operation,!0);else throw is2.invalidParameterError("operation","Array<string>",options.operation);else throw is2.invalidParameterError("options","object",options)}function unblock(options){if(is2.object(options))if(Array.isArray(options.operation)&&options.operation.every(is2.string))sharp.block(options.operation,!1);else throw is2.invalidParameterError("operation","Array<string>",options.operation);else throw is2.invalidParameterError("options","object",options)}module.exports=function(Sharp){Sharp.cache=cache,Sharp.concurrency=concurrency,Sharp.counters=counters,Sharp.simd=simd,Sharp.format=format2,Sharp.interpolators=interpolators,Sharp.versions=versions,Sharp.queue=queue,Sharp.block=block,Sharp.unblock=unblock}});var require_lib=__commonJS((exports,module)=>{var Sharp=require_constructor();require_input()(Sharp);require_resize()(Sharp);require_composite()(Sharp);require_operation()(Sharp);require_colour()(Sharp);require_channel()(Sharp);require_output()(Sharp);require_utility()(Sharp);module.exports=Sharp});import{randomUUID as randomUUID6}from"crypto";import{mkdir as mkdir5,rename as rename3,stat as stat5,unlink as unlink5}from"fs/promises";import path3 from"path";function mergeTransformConfig(config){if(!config)return DEFAULT_TRANSFORM;return{enabled:config.enabled??DEFAULT_TRANSFORM.enabled,maxWidth:config.maxWidth??DEFAULT_TRANSFORM.maxWidth,maxHeight:config.maxHeight??DEFAULT_TRANSFORM.maxHeight,defaultQuality:config.defaultQuality??DEFAULT_TRANSFORM.defaultQuality,allowedFormats:config.allowedFormats??DEFAULT_TRANSFORM.allowedFormats,cacheSubdir:config.cacheSubdir??DEFAULT_TRANSFORM.cacheSubdir,maxInputPixels:config.maxInputPixels??DEFAULT_TRANSFORM.maxInputPixels,pregenerate:{enabled:config.pregenerate?.enabled??DEFAULT_PREGENERATE.enabled,widths:config.pregenerate?.widths??DEFAULT_PREGENERATE.widths,formats:config.pregenerate?.formats??DEFAULT_PREGENERATE.formats,quality:config.pregenerate?.quality}}}function isTransformableImage(mimeType){return(mimeType.split(";")[0]?.trim().toLowerCase()??"")in MIME_TO_FORMAT}function clampInt(raw,min,max){if(raw===void 0)return;let n=Number.parseInt(raw,10);if(!Number.isFinite(n))return;return Math.min(max,Math.max(min,n))}function parseTransformParams(query,config){let width=clampInt(query.w,1,config.maxWidth),height=clampInt(query.h,1,config.maxHeight),qualityRaw=clampInt(query.q,1,100),requestedFormat=query.format?.trim().toLowerCase(),format2=requestedFormat&&config.allowedFormats.includes(requestedFormat)?requestedFormat:void 0;if(width===void 0&&height===void 0&&qualityRaw===void 0&&!format2)return null;return{width,height,quality:qualityRaw??config.defaultQuality,format:format2}}function deriveCacheKey(mtimeMs,params,outputFormat){return[`m${Math.floor(mtimeMs)}`,params.width?`w${params.width}`:"w0",params.height?`h${params.height}`:"h0",`q${params.quality}`,outputFormat].join("-")}async function loadSharp(logger2){if(sharpModule!==void 0)return sharpModule;try{let mod=await Promise.resolve().then(() => __toESM(require_lib(),1));sharpModule=mod.default??mod}catch{sharpModule=null,logger2.error('[CDN] storage.cdn.transform.enabled is true but the optional "sharp" dependency is not installed. Run `npm i sharp` to enable image transforms. Serving original files untouched.')}return sharpModule}async function ensureDerivative(args){let{sourcePath,mimeType,params,storagePath,config,logger:logger2}=args;if(!isTransformableImage(mimeType))return null;let outputFormat=params.format??MIME_TO_FORMAT[mimeType.toLowerCase()];if(!outputFormat)return null;let sharp=await loadSharp(logger2);if(!sharp)return null;let idPart=path3.basename(sourcePath).replace(/[^A-Za-z0-9._-]+/g,"_")||"f",srcStat=await stat5(sourcePath).catch(()=>null);if(!srcStat)return null;let key2=deriveCacheKey(srcStat.mtimeMs,params,outputFormat),cacheDir=path3.join(storagePath,config.cacheSubdir,idPart),cachePath=path3.join(cacheDir,`${key2}.${outputFormat}`);if(!isPathWithinBase(storagePath,cachePath))return null;let contentType=FORMAT_TO_MIME[outputFormat],etag=`"${idPart}-${key2}"`,cached=await stat5(cachePath).catch(()=>null);if(cached?.isFile()&&cached.size>0)return{path:cachePath,contentType,etag};let pending=inFlightDerivatives.get(cachePath);if(pending)return pending;let task=(async()=>{let tmpPath=null;try{let pipeline=sharp(sourcePath,{limitInputPixels:config.maxInputPixels,failOn:"none"});if(params.width||params.height)pipeline.resize({width:params.width,height:params.height,fit:"inside",withoutEnlargement:!0});switch(outputFormat){case"webp":pipeline.webp({quality:params.quality});break;case"avif":pipeline.avif({quality:params.quality});break;case"jpeg":pipeline.jpeg({quality:params.quality});break;case"png":pipeline.png({quality:params.quality});break}let buffer=await pipeline.toBuffer();if(buffer.length===0)return logger2.error(`[CDN] image transform produced an empty buffer for ${idPart}; serving original.`),null;return await mkdir5(cacheDir,{recursive:!0}),tmpPath=`${cachePath}.${randomUUID6()}.tmp`,await Bun.write(tmpPath,buffer),await rename3(tmpPath,cachePath),tmpPath=null,{path:cachePath,contentType,etag}}catch(err){if(tmpPath)await unlink5(tmpPath).catch(()=>{});return logger2.error(`[CDN] image transform failed for ${idPart}; serving original. ${String(err)}`),null}})();inFlightDerivatives.set(cachePath,task);try{return await task}finally{inFlightDerivatives.delete(cachePath)}}async function pregenerateImageVariants(args){let{sourcePath,mimeType,storagePath,config,logger:logger2}=args,pg=config.pregenerate;if(!config.enabled||!pg.enabled||!isTransformableImage(mimeType))return 0;if(pg.widths.length===0||pg.formats.length===0)return 0;let quality=pg.quality??config.defaultQuality,made=0;for(let width of pg.widths)for(let format2 of pg.formats)if(await ensureDerivative({sourcePath,mimeType,params:{width,quality,format:format2},storagePath,config,logger:logger2}))made+=1;return made}var DEFAULT_PREGENERATE,DEFAULT_TRANSFORM,MIME_TO_FORMAT,FORMAT_TO_MIME,sharpModule,inFlightDerivatives;var init_imageTransform=__esm(()=>{init_helpers2();DEFAULT_PREGENERATE={enabled:!1,widths:[],formats:["webp"]},DEFAULT_TRANSFORM={enabled:!1,maxWidth:3840,maxHeight:3840,defaultQuality:80,allowedFormats:["webp","avif","jpeg","png"],cacheSubdir:".cache/cdn",maxInputPixels:1e8,pregenerate:DEFAULT_PREGENERATE};MIME_TO_FORMAT={"image/webp":"webp","image/avif":"avif","image/jpeg":"jpeg","image/jpg":"jpeg","image/png":"png"},FORMAT_TO_MIME={webp:"image/webp",avif:"image/avif",jpeg:"image/jpeg",png:"image/png"};inFlightDerivatives=new Map});import{mkdir as mkdir6,stat as stat6}from"fs/promises";import path4 from"path";function mergeVideoConfig(config){if(!config)return DEFAULT_VIDEO;return{enabled:config.enabled??DEFAULT_VIDEO.enabled,transcode:config.transcode??DEFAULT_VIDEO.transcode,poster:config.poster??DEFAULT_VIDEO.poster,posterFormat:config.posterFormat??DEFAULT_VIDEO.posterFormat,crf:config.crf??DEFAULT_VIDEO.crf,maxWidth:config.maxWidth??DEFAULT_VIDEO.maxWidth,ffmpegPath:config.ffmpegPath??DEFAULT_VIDEO.ffmpegPath}}function isTransformableVideo(mimeType){return(mimeType.split(";")[0]?.trim().toLowerCase()??"").startsWith("video/")}function idPartOf(sourcePath){return path4.basename(sourcePath).replace(/[^A-Za-z0-9._-]+/g,"_")||"f"}function variantPath(storagePath,cacheSubdir,sourcePath,mtimeMs,suffix){return path4.join(storagePath,cacheSubdir,idPartOf(sourcePath),`video-m${Math.floor(mtimeMs)}-${suffix}`)}async function checkFfmpeg(ffmpegPath,logger2){if(ffmpegAvailable!==void 0)return ffmpegAvailable;try{ffmpegAvailable=await Bun.spawn({cmd:[ffmpegPath,"-version"],stdout:"ignore",stderr:"ignore"}).exited===0}catch{ffmpegAvailable=!1}if(!ffmpegAvailable)logger2.error(`[CDN] storage.cdn.video.enabled is true but ffmpeg ("${ffmpegPath}") was not found on PATH. Install ffmpeg to enable video transcode/poster. Serving original videos untouched.`);return ffmpegAvailable}async function runFfmpeg(ffmpegPath,args){try{return await Bun.spawn({cmd:[ffmpegPath,...args],stdout:"ignore",stderr:"ignore"}).exited===0}catch{return!1}}async function resolveVideoVariant(args){let{sourcePath,storagePath,cacheSubdir,posterFormat,kind}=args,srcStat=await stat6(sourcePath).catch(()=>null);if(!srcStat)return null;let suffix=kind==="web"?"web.mp4":`poster.${posterFormat==="webp"?"webp":"jpg"}`,p=variantPath(storagePath,cacheSubdir,sourcePath,srcStat.mtimeMs,suffix);if(!isPathWithinBase(storagePath,p))return null;if(!await Bun.file(p).exists())return null;let contentType=kind==="web"?"video/mp4":POSTER_MIME[posterFormat];return{path:p,contentType}}async function processVideoOnUpload(args){let{sourcePath,mimeType,storagePath,cacheSubdir,config,logger:logger2}=args;if(!config.enabled||!isTransformableVideo(mimeType))return;if(!await checkFfmpeg(config.ffmpegPath,logger2))return;let srcStat=await stat6(sourcePath).catch(()=>null);if(!srcStat)return;let dir=path4.join(storagePath,cacheSubdir,idPartOf(sourcePath));if(await mkdir6(dir,{recursive:!0}).catch(()=>{}),config.transcode){let out=variantPath(storagePath,cacheSubdir,sourcePath,srcStat.mtimeMs,"web.mp4");if(isPathWithinBase(storagePath,out)&&!await Bun.file(out).exists()){if(!await runFfmpeg(config.ffmpegPath,["-y","-i",sourcePath,"-vf",`scale='min(${config.maxWidth},iw)':-2`,"-c:v","libx264","-crf",String(config.crf),"-preset","medium","-c:a","aac","-movflags","+faststart",out]))logger2.error(`[CDN] video transcode failed for ${idPartOf(sourcePath)}`)}}if(config.poster){let ext=config.posterFormat==="webp"?"webp":"jpg",out=variantPath(storagePath,cacheSubdir,sourcePath,srcStat.mtimeMs,`poster.${ext}`);if(isPathWithinBase(storagePath,out)&&!await Bun.file(out).exists()){let posterArgs=["-y","-i",sourcePath,"-frames:v","1"];if(config.posterFormat==="webp")posterArgs.push("-c:v","libwebp");else posterArgs.push("-q:v","3");if(posterArgs.push(out),!await runFfmpeg(config.ffmpegPath,posterArgs))logger2.error(`[CDN] video poster failed for ${idPartOf(sourcePath)}`)}}}var DEFAULT_VIDEO,POSTER_MIME,ffmpegAvailable;var init_videoTransform=__esm(()=>{init_helpers2();DEFAULT_VIDEO={enabled:!1,transcode:!0,poster:!0,posterFormat:"jpeg",crf:23,maxWidth:1920,ffmpegPath:"ffmpeg"};POSTER_MIME={jpeg:"image/jpeg",webp:"image/webp"}});import path5 from"path";import Elysia4,{t as t3}from"elysia";function mergeCdnConfig(config){if(!config)return DEFAULT_CDN_CONFIG;return{enabled:config.enabled??DEFAULT_CDN_CONFIG.enabled,basePath:config.basePath??DEFAULT_CDN_CONFIG.basePath,cacheMaxAge:config.cacheMaxAge??DEFAULT_CDN_CONFIG.cacheMaxAge,enableRangeRequests:config.enableRangeRequests??DEFAULT_CDN_CONFIG.enableRangeRequests,enableEtag:config.enableEtag??DEFAULT_CDN_CONFIG.enableEtag,corsOrigins:config.corsOrigins??DEFAULT_CDN_CONFIG.corsOrigins,transform:mergeTransformConfig(config.transform),video:mergeVideoConfig(config.video)}}function getMimeTypeDisposition(mimeType,forceDownload=!1){let normalized=mimeType.split(";")[0]?.trim().toLowerCase()??"";if(NEVER_INLINE.has(normalized))return"attachment";if(forceDownload)return"attachment";let inlineTypes=["image/","video/","audio/","text/","application/pdf"];for(let type of inlineTypes)if(normalized.startsWith(type)||normalized===type)return"inline";return"attachment"}function sanitizeFilename(filename){return filename.replace(/[^A-Za-z0-9._-]+/g,"_").replace(/_{2,}/g,"_").slice(0,200)}function buildContentDisposition(type,fileName){return`${type}; filename="${sanitizeFilename(fileName)}"; filename*=UTF-8''${encodeURIComponent(fileName)}`}function isTraversalId(id){return id.includes("/")||id.includes("\\")||id.includes("..")||id.includes("\x00")}function resolveTenantSchema(request){return request.headers.get("x-tenant-schema")||void 0}function createCdnRoutes(config){let{cdn,storagePath,logger:logger2,getFileRecord,getStorageProvider:getStorageProvider2}=config,materialize=async(absolutePath)=>{let provider=getStorageProvider2?.();if(!provider||provider.kind==="local")return absolutePath;let relative=path5.relative(storagePath,absolutePath);if(!relative||relative.startsWith(".."))return absolutePath;return await provider.localPath(relative)??absolutePath},plugin=new Elysia4({prefix:cdn.basePath});if(!cdn.enabled)return plugin;return plugin.get("/:id",async({params,request,set,query})=>{let{id}=params;if(isTraversalId(id))return set.status=400,{success:!1,message:"Invalid file id"};let schemaName=resolveTenantSchema(request),filePath,fileName,mimeType;if(getFileRecord){let fileRecord=await getFileRecord(id,schemaName);if(!fileRecord)return set.status=404,{success:!1,message:"File not found"};filePath=path5.join(fileRecord.path,fileRecord.name),fileName=fileRecord.name,mimeType=fileRecord.mimeType||fileRecord.mime_type||"application/octet-stream"}else filePath=path5.join(storagePath,id),fileName=id,mimeType="application/octet-stream";if(!isPathWithinBase(storagePath,filePath))return set.status=404,{success:!1,message:"File not found"};if(filePath=await materialize(filePath),!await fileManager.exists(filePath))return set.status=404,{success:!1,message:"Physical file not found"};if(cdn.video.enabled&&isTransformableVideo(mimeType)){let wantPoster=query.poster!==void 0&&query.poster!=="0"&&query.poster!=="false",variant=await resolveVideoVariant({sourcePath:filePath,storagePath,cacheSubdir:cdn.transform.cacheSubdir,posterFormat:cdn.video.posterFormat,kind:wantPoster?"poster":"web"});if(variant)filePath=variant.path,mimeType=variant.contentType}let fileInfo=await fileManager.getFileInfo(filePath),lastModified=new Date(fileInfo.modifiedAt||Date.now()).toUTCString(),etag=cdn.enableEtag?`"${fileInfo.size}-${fileInfo.modifiedAt?.getTime()||Date.now()}"`:void 0,cacheHeaders={"Cache-Control":`public, max-age=${cdn.cacheMaxAge}`,"Last-Modified":lastModified};if(etag)cacheHeaders.ETag=etag;if(cdn.corsOrigins.length>0)cacheHeaders["Access-Control-Allow-Origin"]=cdn.corsOrigins[0]==="*"?"*":cdn.corsOrigins.join(", "),cacheHeaders["Access-Control-Allow-Methods"]="GET, HEAD, OPTIONS";if(cdn.transform.enabled&&isTransformableImage(mimeType)){let transformParams=parseTransformParams(query,cdn.transform);if(transformParams){let derivative=await ensureDerivative({sourcePath:filePath,mimeType,params:transformParams,storagePath,config:cdn.transform,logger:logger2});if(derivative){let derivativeInfo=await fileManager.getFileInfo(derivative.path),derivativeHeaders={...cacheHeaders,"Content-Type":derivative.contentType,"Content-Disposition":`inline; filename="${sanitizeFilename(fileName)}"`,"X-Content-Type-Options":"nosniff"};if(cdn.enableEtag)derivativeHeaders.ETag=derivative.etag;else delete derivativeHeaders.ETag;if(cdn.enableEtag&&request.headers.get("if-none-match")===derivative.etag)return new Response(null,{status:304,headers:derivativeHeaders});return new Response(Bun.file(derivative.path),{status:200,headers:{"Content-Length":derivativeInfo.size.toString(),...derivativeHeaders}})}}}let forceDownload=query.download!==void 0&&query.download!=="0"&&query.download!=="false",dispositionType=getMimeTypeDisposition(mimeType,forceDownload),contentDisposition=buildContentDisposition(dispositionType,fileName),ifNoneMatch=request.headers.get("if-none-match");if(etag&&ifNoneMatch===etag)return new Response(null,{status:304,headers:cacheHeaders});let bunFile=Bun.file(filePath),range=request.headers.get("range");if(cdn.enableRangeRequests&&range){let rangeMatch=range.match(/bytes=(\d*)-(\d*)/);if(!rangeMatch)return set.status=416,new Response("Range not satisfiable",{status:416,headers:{"Content-Range":`bytes */${fileInfo.size}`,"Content-Type":mimeType,"X-Content-Type-Options":"nosniff",...cacheHeaders}});let startStr=rangeMatch[1]||"0",endStr=rangeMatch[2]||"",start=parseInt(startStr,10),end=endStr?parseInt(endStr,10):fileInfo.size-1;if(start>=fileInfo.size||end>=fileInfo.size||start>end)return new Response("Range not satisfiable",{status:416,headers:{"Content-Range":`bytes */${fileInfo.size}`,"Content-Type":mimeType,"X-Content-Type-Options":"nosniff",...cacheHeaders}});let chunkSize=end-start+1,chunkBlob=bunFile.slice(start,end+1);return new Response(chunkBlob,{status:206,headers:{"Content-Range":`bytes ${start}-${end}/${fileInfo.size}`,"Accept-Ranges":"bytes","Content-Length":chunkSize.toString(),"Content-Type":mimeType,"Content-Disposition":contentDisposition,"X-Content-Type-Options":"nosniff",...cacheHeaders}})}return new Response(bunFile,{status:200,headers:{"Content-Length":fileInfo.size.toString(),"Content-Type":mimeType,"Accept-Ranges":cdn.enableRangeRequests?"bytes":"none","Content-Disposition":contentDisposition,"X-Content-Type-Options":"nosniff",...cacheHeaders}})},{params:t3.Object({id:t3.String()}),detail:{tags:["CDN"],summary:"Get file by ID",description:"Serve file with streaming, range requests, and caching support"}}),plugin.head("/:id",async({params,request,set})=>{let{id}=params;if(isTraversalId(id))return set.status=400,new Response(null,{status:400});let schemaName=resolveTenantSchema(request),filePath,mimeType,fileName;if(getFileRecord){let fileRecord=await getFileRecord(id,schemaName);if(!fileRecord)return set.status=404,new Response(null,{status:404});filePath=path5.join(fileRecord.path,fileRecord.name),mimeType=fileRecord.mime_type||"application/octet-stream",fileName=fileRecord.name}else filePath=path5.join(storagePath,id),mimeType="application/octet-stream",fileName=id;if(!isPathWithinBase(storagePath,filePath))return set.status=404,new Response(null,{status:404});if(filePath=await materialize(filePath),!await fileManager.exists(filePath))return set.status=404,new Response(null,{status:404});let fileInfo=await fileManager.getFileInfo(filePath),lastModified=new Date(fileInfo.modifiedAt||Date.now()).toUTCString(),etag=cdn.enableEtag?`"${fileInfo.size}-${fileInfo.modifiedAt?.getTime()||Date.now()}"`:void 0,headers={"Content-Length":fileInfo.size.toString(),"Content-Type":mimeType,"Content-Disposition":buildContentDisposition(getMimeTypeDisposition(mimeType),fileName),"X-Content-Type-Options":"nosniff","Accept-Ranges":cdn.enableRangeRequests?"bytes":"none","Cache-Control":`public, max-age=${cdn.cacheMaxAge}`,"Last-Modified":lastModified};if(etag)headers.ETag=etag;if(cdn.corsOrigins.length>0)headers["Access-Control-Allow-Origin"]=cdn.corsOrigins[0]==="*"?"*":cdn.corsOrigins.join(", "),headers["Access-Control-Allow-Methods"]="GET, HEAD, OPTIONS";return new Response(null,{status:200,headers})},{params:t3.Object({id:t3.String()}),detail:{tags:["CDN"],summary:"Get file metadata",description:"Get file headers without body for preflight checks"}}),logger2.info(`[CDN] Routes enabled at ${cdn.basePath}`),plugin}var DEFAULT_CDN_CONFIG,NEVER_INLINE;var init_cdn=__esm(()=>{init_File();init_helpers2();init_imageTransform();init_videoTransform();DEFAULT_CDN_CONFIG={enabled:!0,basePath:"/cdn",cacheMaxAge:86400,enableRangeRequests:!0,enableEtag:!0,corsOrigins:["*"],transform:mergeTransformConfig(),video:mergeVideoConfig()};NEVER_INLINE=new Set(["text/html","application/xhtml+xml","image/svg+xml","application/xml","text/xml","application/javascript","text/javascript","application/ecmascript","text/ecmascript","application/x-httpd-php"])});function buildFileRecordPayload(upload,userId){return{id:upload.id,name:upload.name,originalName:upload.originalName,path:upload.path,mimeType:upload.mimeType,size:upload.size,extension:upload.originalName.split(".").pop()||"",uploadedBy:userId??null}}async function persistUploadedFiles(args){let{db,filesTable,files,storageConfig,subFolder,userId}=args,uploaded=await uploadFiles(files,storageConfig,subFolder),records=[];for(let upload of uploaded.success){let payload=buildFileRecordPayload(upload,userId);payload.createdBy=userId??null,await db.insert(filesTable).values(payload),records.push({id:upload.id,name:upload.name,originalName:upload.originalName,path:upload.path,mimeType:upload.mimeType,size:upload.size,extension:payload.extension})}return{records,failed:uploaded.failed}}var init_file_record=__esm(()=>{init_helpers2()});import path6 from"path";function scheduleUploadMediaProcessing(records,opts){let{storagePath,media,logger:logger2}=opts,{transform,video}=media,imagesOn=transform.enabled&&transform.pregenerate.enabled,videoOn=video.enabled;if(!imagesOn&&!videoOn)return;for(let record of records){let sourcePath=path6.join(record.path,record.name);if(imagesOn&&isTransformableImage(record.mimeType))pregenerateImageVariants({sourcePath,mimeType:record.mimeType,storagePath,config:transform,logger:logger2}).catch(()=>{});if(videoOn&&isTransformableVideo(record.mimeType))processVideoOnUpload({sourcePath,mimeType:record.mimeType,storagePath,cacheSubdir:transform.cacheSubdir,config:video,logger:logger2}).catch(()=>{})}}var init_mediaPostProcess=__esm(()=>{init_imageTransform();init_videoTransform()});var exports_storage={};__export(exports_storage,{validateFile:()=>validateFile,uploadFiles:()=>uploadFiles,uploadFile:()=>uploadFile,setStorageProvider:()=>setStorageProvider,scheduleUploadMediaProcessing:()=>scheduleUploadMediaProcessing,persistUploadedFiles:()=>persistUploadedFiles,parseFormDataBody:()=>parseFormDataBody,mergeVideoConfig:()=>mergeVideoConfig,mergeTransformConfig:()=>mergeTransformConfig,mergeStorageConfig:()=>mergeStorageConfig,mergeCdnConfig:()=>mergeCdnConfig,getStorageProvider:()=>getStorageProvider,deleteFile:()=>deleteFile,createCdnRoutes:()=>createCdnRoutes,buildFileRecordPayload:()=>buildFileRecordPayload});var init_storage2=__esm(()=>{init_cdn();init_file_record();init_helpers2();init_imageTransform();init_mediaPostProcess();init_videoTransform()});var exports_helpers={};__export(exports_helpers,{scanUndeclaredEnv:()=>scanUndeclaredEnv,scanEnvVars:()=>scanEnvVars,readOverridesFromRedis:()=>readOverridesFromRedis,persistSectionToRedis:()=>persistSectionToRedis,persistConfigToDisk:()=>persistConfigToDisk,maskUrlCredentials:()=>maskUrlCredentials,maskSensitiveFields:()=>maskSensitiveFields,looksSecretValue:()=>looksSecretValue,loadOverridesFromRedis:()=>loadOverridesFromRedis,isRestartRequired:()=>isRestartRequired,hasSection:()=>hasSection,extractSection:()=>extractSection,deepMerge:()=>deepMerge,clearOverridesFromRedis:()=>clearOverridesFromRedis,buildSectionsMeta:()=>buildSectionsMeta,applySectionUpdate:()=>applySectionUpdate});var SENSITIVE_KEY_PATTERNS,FORBIDDEN_SECTION_KEYS,isSensitiveKey=(key2)=>SENSITIVE_KEY_PATTERNS.some((pattern)=>pattern.test(key2)),HEADER_MAP_KEYS,maskHeaderMap=(value)=>{let masked={};for(let name2 of Object.keys(value))masked[name2]="***";return masked},URL_CREDENTIALS,maskUrlCredentials=(value)=>value.replace(URL_CREDENTIALS,"$1***$2"),B64ISH_VALUE,looksSecretValue=(value)=>{if(!value)return!1;let v=value.trim();if(v.length>=60&&B64ISH_VALUE.test(v))return!0;return v.includes("PRIVATE KEY")||v.includes("BEGIN ")||v.includes('"private_key"')},RESTART_REQUIRED_KEYS,asRecord=(config)=>config,maskSensitiveFields=(obj)=>{let result={};for(let[key2,value]of Object.entries(obj)){if(isSensitiveKey(key2)&&typeof value==="string"){result[key2]="***";continue}if(Array.isArray(value)){result[key2]=value.map((item)=>typeof item==="object"&&item!==null?maskSensitiveFields(item):item);continue}if(typeof value==="object"&&value!==null){result[key2]=HEADER_MAP_KEYS.test(key2)?maskHeaderMap(value):maskSensitiveFields(value);continue}result[key2]=typeof value==="string"?maskUrlCredentials(value):value}return result},buildSectionsMeta=(config)=>{let record=asRecord(config);return Object.keys(record).filter((key2)=>record[key2]!==void 0).map((key2)=>{let value=record[key2],type=Array.isArray(value)?"array":typeof value==="object"&&value!==null?"object":"primitive";return{key:key2,type,restartRequired:RESTART_REQUIRED_KEYS.has(key2)}})},extractSection=(config,section)=>asRecord(config)[section],hasSection=(config,section)=>Object.hasOwn(asRecord(config),section),applySectionUpdate=(config,section,value)=>{if(FORBIDDEN_SECTION_KEYS.has(section))return;asRecord(config)[section]=value},isRestartRequired=(section)=>RESTART_REQUIRED_KEYS.has(section),ENV_VAR_PATTERN,scanEnvVars=(obj,parentPath="")=>{let entries=[];for(let[key2,value]of Object.entries(obj)){let currentPath=parentPath?`${parentPath}.${key2}`:key2;if(typeof value==="string"&&ENV_VAR_PATTERN.test(value)){let envValue=process.env[value],valueIsSecret=envValue!==void 0&&looksSecretValue(envValue);entries.push({configPath:currentPath,envName:value,resolved:envValue!==void 0,value:envValue!==void 0?isSensitiveKey(key2)||valueIsSecret?"***":maskUrlCredentials(envValue):null,isSecret:isSensitiveKey(key2)||valueIsSecret,recognized:!0});continue}if(Array.isArray(value)){for(let i=0;i<value.length;i++){let item=value[i];if(typeof item==="object"&&item!==null)entries.push(...scanEnvVars(item,`${currentPath}[${i}]`))}continue}if(typeof value==="object"&&value!==null)entries.push(...scanEnvVars(value,currentPath))}return entries},K8S_LINK_RE,SYSTEM_ENV,SYSTEM_PREFIXES,PROVIDER_KEY_TOKENS,isProviderApiKey=(name2)=>{let upper=name2.toUpperCase();return upper.endsWith("_API_KEY")&&PROVIDER_KEY_TOKENS.some((token)=>upper.includes(token))},isInfraNoise=(name2,value)=>{if(SYSTEM_ENV.has(name2))return!0;if(SYSTEM_PREFIXES.some((prefix)=>name2.startsWith(prefix)))return!0;if(K8S_LINK_RE.test(name2))return!0;if(name2.endsWith("_PORT")&&value.startsWith("tcp://"))return!0;return!1},scanUndeclaredEnv=(declaredNames)=>{let entries=[];for(let[name2,rawValue]of Object.entries(process.env)){if(declaredNames.has(name2))continue;let value=rawValue??"";if(isInfraNoise(name2,value))continue;if(isProviderApiKey(name2))continue;let resolved=value!=="",valueIsSecret=looksSecretValue(value);entries.push({configPath:name2,envName:name2,resolved,value:resolved?isSensitiveKey(name2)||valueIsSecret?"***":maskUrlCredentials(value):null,isSecret:isSensitiveKey(name2)||valueIsSecret,recognized:!1})}return entries},buildRedisKey=(appId)=>`nucleus:config:overrides:${appId}`,persistConfigToDisk=async(configFilePath,config)=>{let fs4=__require("fs"),record=asRecord(config),persistable={};for(let[k,v]of Object.entries(record))if(k!=="configManagement")persistable[k]=v;let content=JSON.stringify(persistable,null,2);fs4.writeFileSync(configFilePath,content,"utf-8")},persistSectionToRedis=async(redis,appId,section,value)=>{let redisKey=buildRedisKey(appId),existing=await redis.read(redisKey),overrides=existing.success&&existing.data?existing.data:{};overrides[section]=value,await redis.create(redisKey,JSON.stringify(overrides))},readOverridesFromRedis=async(redis,appId)=>{let redisKey=buildRedisKey(appId),result=await redis.read(redisKey);if(!result.success||!result.data)return null;return result.data},clearOverridesFromRedis=async(redis,appId)=>{let redisKey=buildRedisKey(appId);await redis.create(redisKey,JSON.stringify({}))},loadOverridesFromRedis=async(redis,appId,config)=>{let redisKey=buildRedisKey(appId),result=await redis.read(redisKey);if(!result.success||!result.data)return[];let overrides=result.data,appliedSections=[],record=asRecord(config);for(let[section,value]of Object.entries(overrides)){if(FORBIDDEN_SECTION_KEYS.has(section))continue;let current=record[section];if(typeof value==="object"&&value!==null&&!Array.isArray(value)&&typeof current==="object"&¤t!==null&&!Array.isArray(current))record[section]=deepMerge(current,value);else record[section]=value;appliedSections.push(section)}return appliedSections},deepMerge=(target2,source)=>{let result={...target2};for(let[key2,sourceValue]of Object.entries(source)){if(FORBIDDEN_SECTION_KEYS.has(key2))continue;let targetValue=target2[key2];if(typeof sourceValue==="object"&&sourceValue!==null&&!Array.isArray(sourceValue)&&typeof targetValue==="object"&&targetValue!==null&&!Array.isArray(targetValue))result[key2]=deepMerge(targetValue,sourceValue);else result[key2]=sourceValue}return result};var init_helpers3=__esm(()=>{SENSITIVE_KEY_PATTERNS=[/secret/i,/password/i,/token/i,/^apiKey$/i,/^secretKey$/i,/^webhookSecret$/i,/connection_string/i,/connectionString/i,/^clientSecret$/i,/json_file_path/i,/key$/i,/salt/i,/passphrase/i,/credential/i,/^authorization$/i,/^cookie$/i,/^x-api-key$/i],FORBIDDEN_SECTION_KEYS=new Set(["__proto__","constructor","prototype"]),HEADER_MAP_KEYS=/^(headers|extraHeaders|defaultHeaders|requestHeaders)$/i,URL_CREDENTIALS=/^([a-z][a-z0-9+.-]*:\/\/[^/\s:@]*:)[^/\s@]+(@)/i,B64ISH_VALUE=/^[A-Za-z0-9+/=_-]{60,}$/,RESTART_REQUIRED_KEYS=new Set(["appId","mode","database","redis","authentication","authorization","email","payment","entities"]),ENV_VAR_PATTERN=/^[A-Z][A-Z0-9_]{2,}$/,K8S_LINK_RE=/(_SERVICE_HOST|_SERVICE_PORT.*|_PORT_\d+_TCP.*)$/,SYSTEM_ENV=new Set(["PATH","HOME","HOSTNAME","PWD","OLDPWD","TERM","SHLVL","_","LANG","TZ","container","VIRTUAL_ENV","DEBIAN_FRONTEND"]),SYSTEM_PREFIXES=["LC_","GPG_","PYTHON","SSL_CERT","KUBERNETES_"],PROVIDER_KEY_TOKENS=["OPENAI","CLAUDE","ANTHROPIC","GEMINI","GOOGLE","XAI","GROQ","COHERE","ZAI","OLLAMA","KIE","DEEPGRAM","ELEVENLABS","AZURE_OPENAI","MISTRAL","PERPLEXITY","TOGETHER","FIREWORKS","REPLICATE","STABILITY","RUNWAY","HUGGINGFACE","VOYAGE","JINA"]});function hasGodminRole(request){return decodeHeaderList(request.headers.get("x-user-roles")).some((r)=>isGodminRole(r))}async function userHasGodminRoleInDb(db,schemaTables,userId,logger2){if(!userId||!db)return!1;let userRolesTable=schemaTables[AUTHORIZATION_TABLE_KEYS.userRoles],rolesTable=schemaTables[AUTHORIZATION_TABLE_KEYS.roles];if(!userRolesTable||!rolesTable)return!1;try{let{eq:eq28}=await import("drizzle-orm"),ur=userRolesTable,r=rolesTable;return(await db.select({roleName:r.name}).from(userRolesTable).innerJoin(rolesTable,eq28(ur.roleId,r.id)).where(eq28(ur.userId,userId))).some((row)=>isGodminRole(String(row.roleName??"")))}catch(err){return logger2.warn("[AdminGuard] Failed to check godmin role from DB",{error:err instanceof Error?err.message:String(err)}),!1}}async function isGodminRequest(request,deps){if(decodeHeaderList(request.headers.get("x-user-roles")).some((r)=>isGodminRole(r)))return!0;let userId=request.headers.get("x-user-id"),{db,schemaTables,logger:logger2}=deps;if(userId&&db&&schemaTables.users)try{let{eq:eq28}=await import("drizzle-orm"),usersTable=schemaTables.users;if((await db.select().from(usersTable).where(eq28(usersTable.id,userId)).limit(1))[0]?.isGod===!0)return!0}catch(err){logger2.warn("[AdminGuard] Failed to check isGod from DB",{error:err instanceof Error?err.message:String(err)})}return!1}function createGodminGuard(deps,label="this operation"){return async({request,set})=>{if(!request.headers.get("x-user-id"))return set.status=401,Response.json({isSuccess:!1,success:!1,message:"Authentication required",data:null});if(!await isGodminRequest(request,deps))return set.status=403,Response.json({isSuccess:!1,success:!1,message:`Forbidden: ${label} requires godmin privileges`,data:null});return}}var init_adminGuard=__esm(()=>{init_Authorization();init_types3()});function toCamel4(name2){return name2.replace(/_([a-z])/g,(_,letter)=>letter.toUpperCase())}function registerSensitiveColumns(names2){for(let name2 of names2)registry.add(name2),registry.add(toCamel4(name2))}function isConfigSensitiveKey(key2){return registry.has(key2)}function sensitiveColumnNames(){return[...registry]}function sensitiveFieldQueryable(field,opts){if(!isConfigSensitiveKey(field))return!0;if(!opts.authEnabled)return!1;return opts.allowedFields?.includes(field)===!0}function stripUnclaimedSensitive(row,allowedFields){if(allowedFields&&allowedFields.length>0)return row;if(registry.size===0)return row;return scrub(row)}function scrub(value){if(value===null||typeof value!=="object")return value;if(Array.isArray(value))return value.map(scrub);let proto=Object.getPrototypeOf(value);if(proto!==Object.prototype&&proto!==null)return value;let out={};for(let[k,v]of Object.entries(value)){if(registry.has(k))continue;out[k]=scrub(v)}return out}var registry;var init_sensitiveColumns=__esm(()=>{registry=new Set});function createGodminGuard2(deps){let{logger:logger2,db,schemaTables,area}=deps,allowedRoles=new Set((deps.allowedRoles??[]).map((role)=>role.toLowerCase()));return async({request,set})=>{let roles=decodeHeaderList(request.headers.get("x-user-roles"));if(roles.includes(GODMIN_ROLE_NAME))return;if(allowedRoles.size>0&&roles.some((role)=>allowedRoles.has(role.toLowerCase())))return;let userId=request.headers.get("x-user-id");if(userId&&db&&schemaTables.users)try{let{eq:eq31}=await import("drizzle-orm"),usersTable=schemaTables.users;if((await db.select().from(usersTable).where(eq31(usersTable.id,userId)).limit(1))[0]?.isGod===!0)return}catch(err){logger2.warn(`[${area}] Failed to check isGod from DB`,{error:err instanceof Error?err.message:String(err)})}return set.status=403,Response.json({isSuccess:!1,message:allowedRoles.size>0?`${area} requires godmin or one of: ${[...allowedRoles].join(", ")}`:`Only godmin users can access ${area}`,data:null})}}var init_godminGuard=__esm(()=>{init_Authorization()});var exports_ack_manager={};__export(exports_ack_manager,{storePendingMessage:()=>storePendingMessage,removePendingMessage:()=>removePendingMessage,recordSent:()=>recordSent,recordFailed:()=>recordFailed,recordAcked:()=>recordAcked,initAckCleanup:()=>initAckCleanup,incrementRetryCount:()=>incrementRetryCount,getPendingMessagesForUser:()=>getPendingMessagesForUser,getPendingMessageCount:()=>getPendingMessageCount,getDeliveryStats:()=>getDeliveryStats,generateMessageId:()=>generateMessageId,destroyAckCleanup:()=>destroyAckCleanup,acknowledgeMessage:()=>acknowledgeMessage});function cleanupRecentAcks(){let now=Date.now();for(let[key2,timestamp]of recentAcks)if(now-timestamp>1e4)recentAcks.delete(key2)}function initAckCleanup(){if(cleanupInterval)return;cleanupInterval=setInterval(cleanupRecentAcks,30000),cleanupInterval.unref?.()}function destroyAckCleanup(){if(cleanupInterval)clearInterval(cleanupInterval),cleanupInterval=null}function generateMessageId(){return`msg_${Date.now()}_${Math.random().toString(36).substring(2,11)}`}async function storePendingMessage(redis,message,ttlSeconds){if(!message.userId)return;let key2=`pubsub:pending:user:${message.userId}:${message.messageId}`,setKey=`pubsub:user:pending-set:${message.userId}`;await redis.create(key2,message,ttlSeconds);let existingResult=await redis.read(setKey),existingSet=existingResult.success&&existingResult.data?existingResult.data:[];if(!existingSet.includes(message.messageId))existingSet.push(message.messageId),await redis.create(setKey,existingSet,ttlSeconds)}async function acknowledgeMessage(redis,userId,messageId,ttlSeconds){let dedupKey=`${userId}:${messageId}`;if(recentAcks.has(dedupKey))return!1;let pendingKey=`pubsub:pending:user:${userId}:${messageId}`,setKey=`pubsub:user:pending-set:${userId}`,ackKey=`pubsub:ack:${userId}:${messageId}`,pendingResult=await redis.read(pendingKey);if(!pendingResult.success||!pendingResult.data)return recentAcks.set(dedupKey,Date.now()),!1;recentAcks.set(dedupKey,Date.now());let pending=pendingResult.data,ack={messageId,clientId:pending.clientId,ackedAt:Date.now()};await redis.create(ackKey,ack,60),await redis.remove(pendingKey);let setResult=await redis.read(setKey),updatedSet=(setResult.success&&setResult.data?setResult.data:[]).filter((id)=>id!==messageId);if(updatedSet.length>0)await redis.create(setKey,updatedSet,ttlSeconds);else await redis.remove(setKey);let latencyMs=Date.now()-pending.sentAt;return recordAcked(latencyMs),!0}async function getPendingMessagesForUser(redis,userId){if(!userId)return[];let setKey=`pubsub:user:pending-set:${userId}`,setResult=await redis.read(setKey),messageIds=setResult.success&&setResult.data?setResult.data:[],messages=[];for(let messageId of messageIds){let key2=`pubsub:pending:user:${userId}:${messageId}`,msgResult=await redis.read(key2);if(msgResult.success&&msgResult.data)messages.push(msgResult.data)}return messages.sort((a,b)=>a.sentAt-b.sentAt),messages}async function getPendingMessageCount(redis,userId){if(!userId)return 0;let setKey=`pubsub:user:pending-set:${userId}`,setResult=await redis.read(setKey);return(setResult.success&&setResult.data?setResult.data:[]).length}async function incrementRetryCount(redis,userId,messageId,ttlSeconds,maxRetries){let key2=`pubsub:pending:user:${userId}:${messageId}`,msgResult=await redis.read(key2);if(!msgResult.success||!msgResult.data)return!1;let message={...msgResult.data,retryCount:msgResult.data.retryCount+1};if(message.retryCount>=maxRetries)return await removePendingMessage(redis,userId,messageId),recordFailed(),!1;return await redis.create(key2,message,ttlSeconds),!0}async function removePendingMessage(redis,userId,messageId){let key2=`pubsub:pending:user:${userId}:${messageId}`,setKey=`pubsub:user:pending-set:${userId}`;await redis.remove(key2);let setResult=await redis.read(setKey),updatedSet=(setResult.success&&setResult.data?setResult.data:[]).filter((id)=>id!==messageId);if(updatedSet.length>0)await redis.create(setKey,updatedSet,300);else await redis.remove(setKey)}function recordSent(){stats.totalSent++}function recordAcked(latencyMs){stats.totalAcked++,stats.averageLatencyMs=(stats.averageLatencyMs*(stats.totalAcked-1)+latencyMs)/stats.totalAcked}function recordFailed(){stats.totalFailed++}function getDeliveryStats(){return{...stats}}var recentAcks,cleanupInterval=null,stats;var init_ack_manager=__esm(()=>{recentAcks=new Map;stats={totalSent:0,totalAcked:0,totalFailed:0,averageLatencyMs:0}});var resolveAuthTablesForRequest=(request,authConfig)=>{let defaults={usersTable:authConfig.usersTable,sessionsTable:authConfig.sessionsTable??null,userRolesTable:authConfig.userRolesTable??void 0,rolesTable:authConfig.rolesTable??void 0,roleClaimsTable:authConfig.roleClaimsTable??void 0,claimsTable:authConfig.claimsTable??void 0,oauthAccountsTable:authConfig.oauthAccountsTable??void 0,apiKeysTable:authConfig.apiKeysTable??void 0,schemaTables:authConfig.schemaTables||{}},registry2=authConfig.getTenantRegistry?authConfig.getTenantRegistry():authConfig.tenantRegistry;if(!registry2)return defaults;let schemaName=request.headers.get("x-tenant-schema");if(!schemaName)return defaults;let ctx=registry2.getSchemaContext(schemaName);if(!ctx)return defaults;let tables=ctx.schemaTables;return{usersTable:tables.users??defaults.usersTable,sessionsTable:tables.userSessions??tables.user_sessions??tables.sessions??defaults.sessionsTable,userRolesTable:tables.userRoles??defaults.userRolesTable,rolesTable:tables.roles??defaults.rolesTable,roleClaimsTable:tables.roleClaims??defaults.roleClaimsTable,claimsTable:tables.claims??defaults.claimsTable,oauthAccountsTable:tables.oauthAccounts??defaults.oauthAccountsTable,apiKeysTable:tables.apiKeys??defaults.apiKeysTable,schemaTables:tables}};function resolveMutationSchema(staticSchema,tenantHeader,registry2){let schema=staticSchema;if(registry2&&tenantHeader){let tctx=registry2.getSchemaContext(tenantHeader);if(!tctx)return{ok:!1,reason:"unknown"};schema=tctx.schemaName}if(!SQL_IDENT.test(schema))return{ok:!1,reason:"invalid"};return{ok:!0,schema}}var SQL_IDENT;var init_resolveMutationSchema=__esm(()=>{SQL_IDENT=/^[a-zA-Z_][a-zA-Z0-9_]*$/});import{eq as eq36,sql as sql8}from"drizzle-orm";import{Elysia as Elysia25,t as t22}from"elysia";function createChangeUserIdRoute(config,schemaName="public"){let{db,logger:logger2}=config,routes=new Elysia25;return routes.post("/auth/admin/change-user-id",async(ctx)=>{let{usersTable}=resolveAuthTablesForRequest(ctx.request,config);if(!db||!usersTable)return{success:!1,message:"Database not configured"};let registry2=config.getTenantRegistry?config.getTenantRegistry():config.tenantRegistry,schemaResult=resolveMutationSchema(schemaName,ctx.request.headers.get("x-tenant-schema"),registry2);if(!schemaResult.ok)return ctx.set.status=400,{success:!1,message:schemaResult.reason==="unknown"?"Unknown tenant schema":"Invalid tenant schema"};let effectiveSchema=schemaResult.schema,requestingUserId=ctx.request.headers.get("x-user-id");if(!requestingUserId)return ctx.set.status=401,{success:!1,message:"Unauthorized"};let requestingUser=(await db.select().from(usersTable).where(eq36(usersTable.id,requestingUserId)).limit(1))[0];if(!requestingUser||!requestingUser.isGod)return ctx.set.status=403,{success:!1,message:"Forbidden: godmin privileges required"};let{currentId,newId}=ctx.body;if(!currentId||!newId)return ctx.set.status=400,{success:!1,message:"currentId and newId are required"};if(currentId===newId)return ctx.set.status=400,{success:!1,message:"New ID must be different from current ID"};let uuidRegex2=/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;if(!uuidRegex2.test(newId))return ctx.set.status=400,{success:!1,message:"newId must be a valid UUID"};if(!uuidRegex2.test(currentId))return ctx.set.status=400,{success:!1,message:"currentId must be a valid UUID"};let targetUser=(await db.select().from(usersTable).where(eq36(usersTable.id,currentId)).limit(1))[0];if(!targetUser)return ctx.set.status=404,{success:!1,message:"User not found"};if((await db.select().from(usersTable).where(eq36(usersTable.id,newId)).limit(1)).length>0)return ctx.set.status=409,{success:!1,message:"A user with this ID already exists"};try{let fkResult=await db.execute(sql8`
|
|
397
397
|
SELECT
|
|
398
398
|
tc.constraint_name,
|
|
399
399
|
tc.table_name,
|
|
@@ -526,10 +526,10 @@ ${strMDSAlgs}`)}if(attestationStatementAlg!==void 0&&authenticatorGetInfo?.algor
|
|
|
526
526
|
</body>
|
|
527
527
|
</html>
|
|
528
528
|
`},createPaymentRoutes=(config)=>{let{provider,basePath,defaultCurrency,defaultLocale,successRedirectUrl,failedRedirectUrl,errorRedirectUrl,savedMethodsEnabled,threeDSecureEnabled,subMerchantsEnabled,transactionsTable,methodsTable,webhookLogsTable,subMerchantsTable,commissionSplitsTable,productsTable,pricesTable,customersTable,subscriptionsTable,invoicesTable,db,logger:logger2}=config,txTable=transactionsTable,pmTable=methodsTable,whTable=webhookLogsTable,smTable=subMerchantsTable,csTable=commissionSplitsTable,prodTable=productsTable,priceTable=pricesTable,cusTable=customersTable,subTable=subscriptionsTable,invTable=invoicesTable,database=db,app=new Elysia45({prefix:basePath}),customerBelongsToCaller=async(request,customerId)=>{if(hasGodminRole(request))return!0;let uid=request.headers.get("x-user-id");if(!uid||!customerId)return!1;let[c]=await database.select().from(cusTable).where(eq57(cusTable.id,String(customerId)));return!!c&&String(c.user_id)===String(uid)},callerCustomerIds=async(uid)=>{return(await database.select().from(cusTable).where(eq57(cusTable.user_id,uid))).map((r2)=>String(r2.id))};if(app.post("/initialize",async(ctx)=>{if(!threeDSecureEnabled)return ctx.set.status=400,{success:!1,error:"3D Secure is not enabled"};let userId=ctx.request.headers.get("x-user-id"),body=ctx.body;try{let[transaction]=await database.insert(txTable).values({userId:userId??null,orderId:body.orderId??body.conversationId??null,provider:provider.name,amount:Number(body.paidPrice??body.price??0),currency:body.currency??defaultCurrency,status:"pending",statusCode:1000,statusMessage:"3DS initialization started",isThreeDSecure:!0,installment:body.installment??1,ipAddress:ctx.request.headers.get("x-forwarded-for")??ctx.request.headers.get("x-real-ip")??null,metadata:body.metadata??{}}).returning(),result=await provider.initialize3DS({locale:body.locale??defaultLocale,conversationId:transaction.id,price:body.price,paidPrice:body.paidPrice,currency:body.currency??defaultCurrency,installment:body.installment,paymentChannel:body.paymentChannel,basketId:body.basketId,paymentGroup:body.paymentGroup,paymentCard:body.paymentCard,buyer:body.buyer,shippingAddress:body.shippingAddress,billingAddress:body.billingAddress,basketItems:body.basketItems,callbackUrl:body.callbackUrl??config.callbackUrl??`${basePath}/callback`});if(!result.success)return await database.update(txTable).set({status:"failed",statusCode:1003,statusMessage:result.errorMessage??"Initialization failed",providerResponse:result.rawResponse??{},failedAt:new Date}).where(eq57(txTable.id,transaction.id)),ctx.set.status=400,{success:!1,error:result.errorMessage??"Payment initialization failed",errorCode:result.errorCode};return await database.update(txTable).set({status:"processing",statusCode:1001,statusMessage:"3DS initialized, awaiting bank verification",providerPaymentId:result.paymentId,providerResponse:result.rawResponse??{}}).where(eq57(txTable.id,transaction.id)),{success:!0,transactionId:transaction.id,threeDSHtmlContent:result.threeDSHtmlContent,paymentId:result.paymentId}}catch(error3){return logger2.error("[Payment] initialize3DS error",{error:error3 instanceof Error?error3.message:String(error3)}),ctx.set.status=500,{success:!1,error:"Internal payment error"}}}),app.post("/callback",async(ctx)=>{let requestOrigin=new URL(ctx.request.url).origin,htmlHeaders={"Content-Type":"text/html; charset=utf-8","Access-Control-Allow-Origin":requestOrigin,"Access-Control-Allow-Methods":"POST, OPTIONS"};try{let formData=await ctx.request.formData(),rawData={};formData.forEach((value2,key2)=>{rawData[key2]=String(value2)});let parsed=provider.parseCallback(rawData);if(await database.insert(whTable).values({provider:provider.name,eventType:"three_ds_callback",providerPaymentId:parsed.paymentId,rawPayload:rawData,processed:!1,idempotencyKey:`${provider.name}:${parsed.paymentId}:${parsed.mdStatus}`,ipAddress:ctx.request.headers.get("x-forwarded-for")??ctx.request.headers.get("x-real-ip")??null}).onConflictDoNothing(),!parsed.success){if(logger2.warn("[Payment] 3DS callback failed",{mdStatus:parsed.mdStatus,paymentId:parsed.paymentId}),parsed.conversationId)await database.update(txTable).set({status:"failed",statusCode:1003,statusMessage:`3DS verification failed: mdStatus=${parsed.mdStatus}`,failedAt:new Date}).where(eq57(txTable.id,parsed.conversationId)).catch(()=>{});return new Response(generateRedirectHtml(`${requestOrigin}${failedRedirectUrl}`,"Payment Failed"),{headers:htmlHeaders})}let completion=await provider.complete3DS({locale:defaultLocale,conversationId:parsed.conversationId,paymentId:parsed.paymentId});if(!completion.success){if(logger2.error("[Payment] 3DS completion failed",{paymentId:parsed.paymentId,errorCode:completion.errorCode,errorMessage:completion.errorMessage}),parsed.conversationId)await database.update(txTable).set({status:"failed",statusCode:1003,statusMessage:`3DS completion failed: ${completion.errorMessage}`,providerResponse:completion.rawResponse??{},failedAt:new Date}).where(eq57(txTable.id,parsed.conversationId)).catch(()=>{});return new Response(generateRedirectHtml(`${requestOrigin}${failedRedirectUrl}`,"Payment Failed"),{headers:htmlHeaders})}if(parsed.conversationId)await database.update(txTable).set({status:"completed",statusCode:1001,statusMessage:"Payment completed successfully",providerPaymentId:completion.paymentId??parsed.paymentId,providerTransactionId:completion.signature,amount:completion.paidPrice??0,currency:completion.currency??defaultCurrency,paymentMethod:completion.cardAssociation,cardLastFour:completion.lastFourDigits,cardType:completion.cardType,cardAssociation:completion.cardAssociation,installment:completion.installment??1,providerResponse:completion.rawResponse??{},completedAt:new Date}).where(and21(eq57(txTable.id,parsed.conversationId),eq57(txTable.status,"pending"))).catch(()=>{});await database.update(whTable).set({processed:!0,processingResult:{completion}}).where(eq57(whTable.idempotencyKey,`${provider.name}:${parsed.paymentId}:${parsed.mdStatus}`)).catch(()=>{}),logger2.info("[Payment] 3DS payment completed",{paymentId:completion.paymentId,amount:completion.paidPrice,currency:completion.currency});let queryParams=new URLSearchParams;if(parsed.conversationId)queryParams.append("transactionId",parsed.conversationId);if(completion.paymentId)queryParams.append("paymentId",completion.paymentId);if(completion.paidPrice)queryParams.append("amount",String(completion.paidPrice));let redirectUrl=`${requestOrigin}${successRedirectUrl}?${queryParams.toString()}`;return new Response(generateRedirectHtml(redirectUrl,"Payment Successful"),{headers:htmlHeaders})}catch(error3){return logger2.error("[Payment] callback error",{error:error3 instanceof Error?error3.message:String(error3)}),new Response(generateRedirectHtml(`${requestOrigin}${errorRedirectUrl}`,"Payment Error"),{headers:htmlHeaders})}}),app.get("/transactions",async(ctx)=>{let userId=ctx.request.headers.get("x-user-id");if(!userId)return ctx.set.status=401,{success:!1,error:"Unauthorized"};try{return{success:!0,data:{items:await database.select().from(txTable).where(eq57(txTable.userId,userId)).orderBy(txTable.createdAt)}}}catch(error3){return logger2.error("[Payment] list transactions error",{error:error3 instanceof Error?error3.message:String(error3)}),ctx.set.status=500,{success:!1,error:"Failed to list transactions"}}}),app.get("/transactions/:id",async(ctx)=>{let userId=ctx.request.headers.get("x-user-id");if(!userId)return ctx.set.status=401,{success:!1,error:"Unauthorized"};try{let[transaction]=await database.select().from(txTable).where(and21(eq57(txTable.id,ctx.params.id),eq57(txTable.userId,userId))).limit(1);if(!transaction)return ctx.set.status=404,{success:!1,error:"Transaction not found"};return{success:!0,data:transaction}}catch{return ctx.set.status=500,{success:!1,error:"Failed to get transaction"}}}),app.post("/bin-query",async(ctx)=>{let body=ctx.body,binNumber=body.binNumber??body.cardNumber;if(!binNumber||typeof binNumber!=="string")return ctx.set.status=400,{success:!1,error:"binNumber is required"};try{let result=await provider.queryBin({locale:body.locale??defaultLocale,binNumber,price:body.price});if(!result.success)return ctx.set.status=400,{success:!1,error:result.errorMessage??"BIN query failed",errorCode:result.errorCode};return{success:!0,data:result}}catch{return ctx.set.status=500,{success:!1,error:"BIN query failed"}}}),app.post("/payment-detail",async(ctx)=>{let body=ctx.body;if(!body.paymentId)return ctx.set.status=400,{success:!1,error:"paymentId is required"};try{let result=await provider.getPaymentDetail({locale:body.locale??defaultLocale,paymentId:body.paymentId,conversationId:body.conversationId,paymentConversationId:body.paymentConversationId});return{success:result.success,data:result}}catch{return ctx.set.status=500,{success:!1,error:"Payment detail query failed"}}}),app.post("/refund",async(ctx)=>{let userId=ctx.request.headers.get("x-user-id");if(!userId)return ctx.set.status=401,{success:!1,error:"Unauthorized"};let body=ctx.body;if(!body.paymentTransactionId||!body.price)return ctx.set.status=400,{success:!1,error:"paymentTransactionId and price are required"};let refundAmt=validateAmount(body.price,"price");if(!refundAmt.ok)return ctx.set.status=400,{success:!1,error:refundAmt.error};if(!hasGodminRole(ctx.request)){if(!body.transactionId)return ctx.set.status=400,{success:!1,error:"transactionId is required"};let[tx]=await database.select().from(txTable).where(eq57(txTable.id,body.transactionId)).limit(1);if(!tx)return ctx.set.status=404,{success:!1,error:"Transaction not found"};if(String(tx.userId)!==String(userId))return ctx.set.status=403,{success:!1,error:"You can only refund your own transactions"};let ownedProviderId=tx.providerTransactionId??tx.providerPaymentId;if(ownedProviderId&&String(body.paymentTransactionId)!==String(ownedProviderId))return ctx.set.status=403,{success:!1,error:"paymentTransactionId does not match this transaction"};let refundable=Number(tx.amount??0)-Number(tx.refundedAmount??0);if(!(Number(body.price)>0)||Number(body.price)>refundable)return ctx.set.status=400,{success:!1,error:`Refund amount exceeds the refundable balance (${refundable})`}}try{let result=await provider.refund({locale:body.locale??defaultLocale,conversationId:body.conversationId,paymentTransactionId:body.paymentTransactionId,price:String(body.price),currency:body.currency??defaultCurrency,ip:ctx.request.headers.get("x-forwarded-for")??ctx.request.headers.get("x-real-ip")??void 0});if(!result.success)return ctx.set.status=400,{success:!1,error:result.errorMessage??"Refund failed",errorCode:result.errorCode};if(body.transactionId){let price=Number(body.price);await database.update(txTable).set({status:sql11`CASE WHEN COALESCE(${txTable.refundedAmount}, 0) + ${price} >= ${txTable.amount} THEN 'refunded' ELSE 'partially_refunded' END`,refundedAmount:sql11`COALESCE(${txTable.refundedAmount}, 0) + ${price}`,refundedAt:new Date,statusMessage:"Payment refunded"}).where(eq57(txTable.id,body.transactionId)).catch(()=>{})}return logger2.info("[Payment] Refund processed",{paymentId:result.paymentId,price:result.price}),{success:!0,data:result}}catch{return ctx.set.status=500,{success:!1,error:"Refund failed"}}}),savedMethodsEnabled)app.post("/cards/save",async(ctx)=>{let userId=ctx.request.headers.get("x-user-id");if(!userId)return ctx.set.status=401,{success:!1,error:"Unauthorized"};let body=ctx.body;if(!body.email||!body.card)return ctx.set.status=400,{success:!1,error:"email and card are required"};try{let result=await provider.saveCard({locale:body.locale??defaultLocale,email:body.email,externalId:userId,card:body.card});if(!result.success)return ctx.set.status=400,{success:!1,error:result.errorMessage??"Failed to save card",errorCode:result.errorCode};let[saved]=await database.insert(pmTable).values({userId,provider:provider.name,type:"card",alias:result.cardAlias??body.card.cardAlias,cardLastFour:result.lastFourDigits,cardType:result.cardType,cardAssociation:result.cardAssociation,cardFamily:result.cardFamily,cardBankName:result.cardBankName,providerCardUserKey:result.cardUserKey,providerCardToken:result.cardToken,binNumber:result.binNumber}).returning();return logger2.info("[Payment] Card saved",{userId,cardAlias:result.cardAlias}),{success:!0,data:saved}}catch{return ctx.set.status=500,{success:!1,error:"Failed to save card"}}}),app.get("/cards",async(ctx)=>{let userId=ctx.request.headers.get("x-user-id");if(!userId)return ctx.set.status=401,{success:!1,error:"Unauthorized"};try{return{success:!0,data:{items:await database.select().from(pmTable).where(and21(eq57(pmTable.userId,userId),eq57(pmTable.isActive,!0))).orderBy(pmTable.createdAt)}}}catch{return ctx.set.status=500,{success:!1,error:"Failed to list cards"}}}),app.delete("/cards/:id",async(ctx)=>{let userId=ctx.request.headers.get("x-user-id");if(!userId)return ctx.set.status=401,{success:!1,error:"Unauthorized"};try{let[card]=await database.select().from(pmTable).where(and21(eq57(pmTable.id,ctx.params.id),eq57(pmTable.userId,userId))).limit(1);if(!card)return ctx.set.status=404,{success:!1,error:"Card not found"};if(card.providerCardUserKey&&card.providerCardToken){let deleteResult=await provider.deleteCard({locale:defaultLocale,cardUserKey:card.providerCardUserKey,cardToken:card.providerCardToken});if(!deleteResult.success)logger2.warn("[Payment] Provider card delete failed (proceeding with local delete)",{errorCode:deleteResult.errorCode,errorMessage:deleteResult.errorMessage})}return await database.update(pmTable).set({isActive:!1}).where(eq57(pmTable.id,ctx.params.id)),logger2.info("[Payment] Card deleted",{userId,cardId:ctx.params.id}),{success:!0}}catch{return ctx.set.status=500,{success:!1,error:"Failed to delete card"}}}),app.post("/cards/sync",async(ctx)=>{if(!ctx.request.headers.get("x-user-id"))return ctx.set.status=401,{success:!1,error:"Unauthorized"};let body=ctx.body,cardUserKey=body.cardUserKey;if(!cardUserKey)return ctx.set.status=400,{success:!1,error:"cardUserKey is required"};try{let result=await provider.listCards({locale:body.locale??defaultLocale,cardUserKey});if(!result.success)return ctx.set.status=400,{success:!1,error:result.errorMessage??"Failed to list cards from provider"};return{success:!0,data:{cardUserKey:result.cardUserKey,cards:result.cards}}}catch{return ctx.set.status=500,{success:!1,error:"Failed to sync cards"}}});if(app.post("/products",async(ctx)=>{if(!ctx.request.headers.get("x-user-id"))return ctx.set.status=401,{success:!1,error:"Unauthorized"};if(!hasGodminRole(ctx.request))return ctx.set.status=403,{success:!1,error:"Forbidden: operator privileges required"};let body=ctx.body;if(!body.name)return ctx.set.status=400,{success:!1,error:"name is required"};try{let providerResult=await provider.createProduct({name:body.name,description:body.description,type:body.type,images:body.images,unitLabel:body.unitLabel,url:body.url,metadata:body.metadata});if(!providerResult.success)return ctx.set.status=400,{success:!1,error:providerResult.errorMessage??"Failed to create product at provider",errorCode:providerResult.errorCode};let[saved]=await database.insert(prodTable).values({provider:provider.name,providerProductId:providerResult.providerProductId,name:body.name,description:body.description??null,type:body.type??"service",status:"active",images:body.images?JSON.stringify(body.images):"[]",unitLabel:body.unitLabel??null,url:body.url??null,metadata:body.metadata?JSON.stringify(body.metadata):"{}"}).returning();return logger2.info("[Payment] Product created",{id:saved.id,providerProductId:providerResult.providerProductId}),{success:!0,data:saved}}catch(error3){return logger2.error("[Payment] create product error",{error:error3 instanceof Error?error3.message:String(error3)}),ctx.set.status=500,{success:!1,error:"Failed to create product"}}}),app.put("/products/:id",async(ctx)=>{if(!ctx.request.headers.get("x-user-id"))return ctx.set.status=401,{success:!1,error:"Unauthorized"};if(!hasGodminRole(ctx.request))return ctx.set.status=403,{success:!1,error:"Forbidden: operator privileges required"};let body=ctx.body;try{let[existing]=await database.select().from(prodTable).where(eq57(prodTable.id,ctx.params.id)).limit(1);if(!existing)return ctx.set.status=404,{success:!1,error:"Product not found"};if(existing.providerProductId){let providerResult=await provider.updateProduct({providerProductId:existing.providerProductId,name:body.name,description:body.description,images:body.images,unitLabel:body.unitLabel,url:body.url,active:body.status==="active"?!0:body.status==="archived"?!1:void 0,metadata:body.metadata});if(!providerResult.success)logger2.warn("[Payment] Provider product update failed",{errorCode:providerResult.errorCode})}let updateData={};if(body.name)updateData.name=body.name;if(body.description!==void 0)updateData.description=body.description;if(body.type)updateData.type=body.type;if(body.status)updateData.status=body.status;if(body.images)updateData.images=JSON.stringify(body.images);if(body.unitLabel!==void 0)updateData.unitLabel=body.unitLabel;if(body.url!==void 0)updateData.url=body.url;if(body.metadata)updateData.metadata=JSON.stringify(body.metadata);let[updated]=await database.update(prodTable).set(updateData).where(eq57(prodTable.id,ctx.params.id)).returning();return{success:!0,data:updated}}catch{return ctx.set.status=500,{success:!1,error:"Failed to update product"}}}),app.get("/products",async(ctx)=>{if(!ctx.request.headers.get("x-user-id"))return ctx.set.status=401,{success:!1,error:"Unauthorized"};try{let status=new URL(ctx.request.url).searchParams.get("status"),query=database.select().from(prodTable).where(eq57(prodTable.isActive,!0));if(status)query=database.select().from(prodTable).where(and21(eq57(prodTable.isActive,!0),eq57(prodTable.status,status)));return{success:!0,data:{items:await query.orderBy(prodTable.createdAt)}}}catch{return ctx.set.status=500,{success:!1,error:"Failed to list products"}}}),app.get("/products/:id",async(ctx)=>{if(!ctx.request.headers.get("x-user-id"))return ctx.set.status=401,{success:!1,error:"Unauthorized"};try{let[item]=await database.select().from(prodTable).where(eq57(prodTable.id,ctx.params.id)).limit(1);if(!item)return ctx.set.status=404,{success:!1,error:"Product not found"};let prices=await database.select().from(priceTable).where(and21(eq57(priceTable.productId,ctx.params.id),eq57(priceTable.isActive,!0))).orderBy(priceTable.createdAt);return{success:!0,data:{...item,prices}}}catch{return ctx.set.status=500,{success:!1,error:"Failed to get product"}}}),app.delete("/products/:id",async(ctx)=>{if(!ctx.request.headers.get("x-user-id"))return ctx.set.status=401,{success:!1,error:"Unauthorized"};if(!hasGodminRole(ctx.request))return ctx.set.status=403,{success:!1,error:"Forbidden: operator privileges required"};try{let[existing]=await database.select().from(prodTable).where(eq57(prodTable.id,ctx.params.id)).limit(1);if(!existing)return ctx.set.status=404,{success:!1,error:"Product not found"};if(existing.providerProductId)await provider.archiveProduct({providerProductId:existing.providerProductId});let[updated]=await database.update(prodTable).set({status:"archived"}).where(eq57(prodTable.id,ctx.params.id)).returning();return{success:!0,data:updated}}catch{return ctx.set.status=500,{success:!1,error:"Failed to archive product"}}}),app.post("/prices",async(ctx)=>{if(!ctx.request.headers.get("x-user-id"))return ctx.set.status=401,{success:!1,error:"Unauthorized"};if(!hasGodminRole(ctx.request))return ctx.set.status=403,{success:!1,error:"Forbidden: operator privileges required"};let body=ctx.body;if(!body.productId||body.unitAmount===void 0||!body.currency)return ctx.set.status=400,{success:!1,error:"productId, unitAmount, and currency are required"};try{let[product]=await database.select().from(prodTable).where(eq57(prodTable.id,body.productId)).limit(1);if(!product)return ctx.set.status=404,{success:!1,error:"Product not found"};let providerResult=await provider.createPrice({providerProductId:product.providerProductId,currency:body.currency,unitAmount:body.unitAmount,type:body.type,billingScheme:body.billingScheme,nickname:body.nickname,recurring:body.recurring,transformQuantity:body.transformQuantity,unitAmountDecimal:body.unitAmountDecimal,metadata:body.metadata});if(!providerResult.success)return ctx.set.status=400,{success:!1,error:providerResult.errorMessage??"Failed to create price at provider",errorCode:providerResult.errorCode};let[saved]=await database.insert(priceTable).values({productId:body.productId,provider:provider.name,providerPriceId:providerResult.providerPriceId,currency:body.currency,unitAmount:body.unitAmount,unitAmountDecimal:body.unitAmountDecimal??null,type:body.type??"one_time",billingScheme:body.billingScheme??"per_unit",nickname:body.nickname??null,recurringInterval:body.recurring?.interval??null,recurringIntervalCount:body.recurring?.intervalCount??1,recurringUsageType:body.recurring?.usageType??"licensed",recurringAggregateUsage:body.recurring?.aggregateUsage??null,transformQuantityDivideBy:body.transformQuantity?.divideBy??null,transformQuantityRound:body.transformQuantity?.round??null,status:"active",metadata:body.metadata?JSON.stringify(body.metadata):"{}"}).returning();return logger2.info("[Payment] Price created",{id:saved.id,providerPriceId:providerResult.providerPriceId}),{success:!0,data:saved}}catch(error3){return logger2.error("[Payment] create price error",{error:error3 instanceof Error?error3.message:String(error3)}),ctx.set.status=500,{success:!1,error:"Failed to create price"}}}),app.put("/prices/:id",async(ctx)=>{if(!ctx.request.headers.get("x-user-id"))return ctx.set.status=401,{success:!1,error:"Unauthorized"};if(!hasGodminRole(ctx.request))return ctx.set.status=403,{success:!1,error:"Forbidden: operator privileges required"};let body=ctx.body;try{let[existing]=await database.select().from(priceTable).where(eq57(priceTable.id,ctx.params.id)).limit(1);if(!existing)return ctx.set.status=404,{success:!1,error:"Price not found"};if(existing.providerPriceId){let providerResult=await provider.updatePrice({providerPriceId:existing.providerPriceId,nickname:body.nickname,active:body.status==="active"?!0:body.status==="archived"?!1:void 0,metadata:body.metadata});if(!providerResult.success)logger2.warn("[Payment] Provider price update failed",{errorCode:providerResult.errorCode})}let updateData={};if(body.nickname!==void 0)updateData.nickname=body.nickname;if(body.status)updateData.status=body.status;if(body.metadata)updateData.metadata=JSON.stringify(body.metadata);let[updated]=await database.update(priceTable).set(updateData).where(eq57(priceTable.id,ctx.params.id)).returning();return{success:!0,data:updated}}catch{return ctx.set.status=500,{success:!1,error:"Failed to update price"}}}),app.get("/prices",async(ctx)=>{if(!ctx.request.headers.get("x-user-id"))return ctx.set.status=401,{success:!1,error:"Unauthorized"};try{let url=new URL(ctx.request.url),productId=url.searchParams.get("productId"),status=url.searchParams.get("status"),query=database.select().from(priceTable).where(eq57(priceTable.isActive,!0));if(productId&&status)query=database.select().from(priceTable).where(and21(eq57(priceTable.productId,productId),eq57(priceTable.status,status),eq57(priceTable.isActive,!0)));else if(productId)query=database.select().from(priceTable).where(and21(eq57(priceTable.productId,productId),eq57(priceTable.isActive,!0)));else if(status)query=database.select().from(priceTable).where(and21(eq57(priceTable.status,status),eq57(priceTable.isActive,!0)));return{success:!0,data:{items:await query.orderBy(priceTable.createdAt)}}}catch{return ctx.set.status=500,{success:!1,error:"Failed to list prices"}}}),app.get("/prices/:id",async(ctx)=>{if(!ctx.request.headers.get("x-user-id"))return ctx.set.status=401,{success:!1,error:"Unauthorized"};try{let[item]=await database.select().from(priceTable).where(eq57(priceTable.id,ctx.params.id)).limit(1);if(!item)return ctx.set.status=404,{success:!1,error:"Price not found"};return{success:!0,data:item}}catch{return ctx.set.status=500,{success:!1,error:"Failed to get price"}}}),app.delete("/prices/:id",async(ctx)=>{if(!ctx.request.headers.get("x-user-id"))return ctx.set.status=401,{success:!1,error:"Unauthorized"};if(!hasGodminRole(ctx.request))return ctx.set.status=403,{success:!1,error:"Forbidden: operator privileges required"};try{let[existing]=await database.select().from(priceTable).where(eq57(priceTable.id,ctx.params.id)).limit(1);if(!existing)return ctx.set.status=404,{success:!1,error:"Price not found"};if(existing.providerPriceId)await provider.archivePrice({providerPriceId:existing.providerPriceId});let[updated]=await database.update(priceTable).set({status:"archived"}).where(eq57(priceTable.id,ctx.params.id)).returning();return{success:!0,data:updated}}catch{return ctx.set.status=500,{success:!1,error:"Failed to archive price"}}}),app.post("/customers",async(ctx)=>{let userId=ctx.request.headers.get("x-user-id");if(!userId)return ctx.set.status=401,{success:!1,error:"Unauthorized"};try{let body=ctx.body,result=await provider.createCustomer({email:body.email,name:body.name,phone:body.phone,description:body.description,metadata:body.metadata,address:body.address?{line1:body.address?.line1,line2:body.address?.line2,city:body.address?.city,state:body.address?.state,postalCode:body.address?.postalCode,country:body.address?.country}:void 0,taxId:body.taxId});if(!result.success)return ctx.set.status=400,result;let[row]=await database.insert(cusTable).values({user_id:userId,provider:provider.name,provider_customer_id:result.providerCustomerId,email:body.email,name:body.name??null,phone:body.phone??null,description:body.description??null,address:body.address??{},tax_id_type:body.taxId?.type??null,tax_id_value:body.taxId?.value??null,metadata:body.metadata??{}}).returning();return{success:!0,customer:row,providerCustomerId:result.providerCustomerId}}catch(error3){return logger2.error("[Payment] Create customer error",{error:String(error3)}),ctx.set.status=500,{success:!1,error:"Failed to create customer"}}}),app.put("/customers/:id",async(ctx)=>{let userId=ctx.request.headers.get("x-user-id");if(!userId)return ctx.set.status=401,{success:!1,error:"Unauthorized"};try{let{id}=ctx.params,body=ctx.body,[existing]=await database.select().from(cusTable).where(eq57(cusTable.id,id));if(!existing)return ctx.set.status=404,{success:!1,error:"Customer not found"};if(String(existing.user_id)!==String(userId)&&!hasGodminRole(ctx.request))return ctx.set.status=403,{success:!1,error:"Forbidden"};let result=await provider.updateCustomer({providerCustomerId:existing.provider_customer_id,email:body.email,name:body.name,phone:body.phone,description:body.description,metadata:body.metadata,address:body.address?{line1:body.address?.line1,line2:body.address?.line2,city:body.address?.city,state:body.address?.state,postalCode:body.address?.postalCode,country:body.address?.country}:void 0});if(!result.success)return ctx.set.status=400,result;let updates={};if(body.email)updates.email=body.email;if(body.name!==void 0)updates.name=body.name;if(body.phone!==void 0)updates.phone=body.phone;if(body.description!==void 0)updates.description=body.description;if(body.address)updates.address=body.address;if(body.metadata)updates.metadata=body.metadata;let[updated]=await database.update(cusTable).set(updates).where(eq57(cusTable.id,id)).returning();return{success:!0,customer:updated}}catch(error3){return logger2.error("[Payment] Update customer error",{error:String(error3)}),ctx.set.status=500,{success:!1,error:"Failed to update customer"}}}),app.get("/customers",async(ctx)=>{let userId=ctx.request.headers.get("x-user-id");if(!userId)return ctx.set.status=401,{success:!1,error:"Unauthorized"};try{return{success:!0,customers:await database.select().from(cusTable).where(eq57(cusTable.user_id,userId))}}catch(error3){return logger2.error("[Payment] List customers error",{error:String(error3)}),ctx.set.status=500,{success:!1,error:"Failed to list customers"}}}),app.get("/customers/:id",async(ctx)=>{let userId=ctx.request.headers.get("x-user-id");if(!userId)return ctx.set.status=401,{success:!1,error:"Unauthorized"};try{let{id}=ctx.params,[customer]=await database.select().from(cusTable).where(eq57(cusTable.id,id));if(!customer)return ctx.set.status=404,{success:!1,error:"Customer not found"};if(String(customer.user_id)!==String(userId)&&!hasGodminRole(ctx.request))return ctx.set.status=404,{success:!1,error:"Customer not found"};return{success:!0,customer}}catch(error3){return logger2.error("[Payment] Get customer error",{error:String(error3)}),ctx.set.status=500,{success:!1,error:"Failed to get customer"}}}),app.delete("/customers/:id",async(ctx)=>{let userId=ctx.request.headers.get("x-user-id");if(!userId)return ctx.set.status=401,{success:!1,error:"Unauthorized"};try{let{id}=ctx.params,[existing]=await database.select().from(cusTable).where(eq57(cusTable.id,id));if(!existing)return ctx.set.status=404,{success:!1,error:"Customer not found"};if(String(existing.user_id)!==String(userId)&&!hasGodminRole(ctx.request))return ctx.set.status=403,{success:!1,error:"Forbidden"};return await provider.deleteCustomer({providerCustomerId:existing.provider_customer_id}),await database.delete(cusTable).where(eq57(cusTable.id,id)),{success:!0}}catch(error3){return logger2.error("[Payment] Delete customer error",{error:String(error3)}),ctx.set.status=500,{success:!1,error:"Failed to delete customer"}}}),app.post("/subscriptions",async(ctx)=>{let userId=ctx.request.headers.get("x-user-id");if(!userId)return ctx.set.status=401,{success:!1,error:"Unauthorized"};try{let body=ctx.body,customerId=body.customerId,[customer]=await database.select().from(cusTable).where(eq57(cusTable.id,customerId));if(!customer)return ctx.set.status=404,{success:!1,error:"Customer not found"};if(String(customer.user_id)!==String(userId)&&!hasGodminRole(ctx.request))return ctx.set.status=403,{success:!1,error:"Forbidden"};let items=body.items,result=await provider.createSubscription({providerCustomerId:customer.provider_customer_id,items,trialPeriodDays:body.trialPeriodDays,collectionMethod:body.collectionMethod,daysUntilDue:body.daysUntilDue,cancelAtPeriodEnd:body.cancelAtPeriodEnd,metadata:body.metadata,defaultPaymentMethod:body.defaultPaymentMethod});if(!result.success)return ctx.set.status=400,result;let[row]=await database.insert(subTable).values({customer_id:customerId,provider:provider.name,provider_subscription_id:result.providerSubscriptionId,status:result.status??"incomplete",collection_method:body.collectionMethod??"charge_automatically",current_period_start:result.currentPeriodStart?new Date(result.currentPeriodStart):null,current_period_end:result.currentPeriodEnd?new Date(result.currentPeriodEnd):null,cancel_at_period_end:body.cancelAtPeriodEnd??!1,items,metadata:body.metadata??{}}).returning();return{success:!0,subscription:row,clientSecret:result.clientSecret}}catch(error3){return logger2.error("[Payment] Create subscription error",{error:String(error3)}),ctx.set.status=500,{success:!1,error:"Failed to create subscription"}}}),app.put("/subscriptions/:id",async(ctx)=>{if(!ctx.request.headers.get("x-user-id"))return ctx.set.status=401,{success:!1,error:"Unauthorized"};try{let{id}=ctx.params,body=ctx.body,[existing]=await database.select().from(subTable).where(eq57(subTable.id,id));if(!existing)return ctx.set.status=404,{success:!1,error:"Subscription not found"};if(!await customerBelongsToCaller(ctx.request,existing.customer_id))return ctx.set.status=403,{success:!1,error:"Forbidden"};let result=await provider.updateSubscription({providerSubscriptionId:existing.provider_subscription_id,items:body.items,cancelAtPeriodEnd:body.cancelAtPeriodEnd,metadata:body.metadata,collectionMethod:body.collectionMethod,daysUntilDue:body.daysUntilDue,defaultPaymentMethod:body.defaultPaymentMethod,prorationBehavior:body.prorationBehavior});if(!result.success)return ctx.set.status=400,result;let updates={};if(result.status)updates.status=result.status;if(body.cancelAtPeriodEnd!==void 0)updates.cancel_at_period_end=body.cancelAtPeriodEnd;if(body.items)updates.items=body.items;if(body.metadata)updates.metadata=body.metadata;if(body.collectionMethod)updates.collection_method=body.collectionMethod;let[updated]=await database.update(subTable).set(updates).where(eq57(subTable.id,id)).returning();return{success:!0,subscription:updated}}catch(error3){return logger2.error("[Payment] Update subscription error",{error:String(error3)}),ctx.set.status=500,{success:!1,error:"Failed to update subscription"}}}),app.post("/subscriptions/:id/cancel",async(ctx)=>{if(!ctx.request.headers.get("x-user-id"))return ctx.set.status=401,{success:!1,error:"Unauthorized"};try{let{id}=ctx.params,body=ctx.body??{},[existing]=await database.select().from(subTable).where(eq57(subTable.id,id));if(!existing)return ctx.set.status=404,{success:!1,error:"Subscription not found"};if(!await customerBelongsToCaller(ctx.request,existing.customer_id))return ctx.set.status=403,{success:!1,error:"Forbidden"};let result=await provider.cancelSubscription({providerSubscriptionId:existing.provider_subscription_id,cancelAtPeriodEnd:body.cancelAtPeriodEnd,invoiceNow:body.invoiceNow,prorate:body.prorate});if(!result.success)return ctx.set.status=400,result;let updates={status:result.status??"canceled",canceled_at:new Date};if(body.cancelAtPeriodEnd)updates.cancel_at_period_end=!0;let[updated]=await database.update(subTable).set(updates).where(eq57(subTable.id,id)).returning();return{success:!0,subscription:updated}}catch(error3){return logger2.error("[Payment] Cancel subscription error",{error:String(error3)}),ctx.set.status=500,{success:!1,error:"Failed to cancel subscription"}}}),app.get("/subscriptions",async(ctx)=>{let userId=ctx.request.headers.get("x-user-id");if(!userId)return ctx.set.status=401,{success:!1,error:"Unauthorized"};try{let query=ctx.query,conditions=[];if(query.customerId)conditions.push(eq57(subTable.customer_id,query.customerId));if(query.status)conditions.push(eq57(subTable.status,query.status));if(!hasGodminRole(ctx.request)){let ids=await callerCustomerIds(userId);if(ids.length===0)return{success:!0,subscriptions:[]};conditions.push(inArray15(subTable.customer_id,ids))}return{success:!0,subscriptions:conditions.length>0?await database.select().from(subTable).where(and21(...conditions)):await database.select().from(subTable)}}catch(error3){return logger2.error("[Payment] List subscriptions error",{error:String(error3)}),ctx.set.status=500,{success:!1,error:"Failed to list subscriptions"}}}),app.get("/subscriptions/:id",async(ctx)=>{if(!ctx.request.headers.get("x-user-id"))return ctx.set.status=401,{success:!1,error:"Unauthorized"};try{let{id}=ctx.params,[subscription]=await database.select().from(subTable).where(eq57(subTable.id,id));if(!subscription)return ctx.set.status=404,{success:!1,error:"Subscription not found"};if(!await customerBelongsToCaller(ctx.request,subscription.customer_id))return ctx.set.status=403,{success:!1,error:"Forbidden"};return{success:!0,subscription}}catch(error3){return logger2.error("[Payment] Get subscription error",{error:String(error3)}),ctx.set.status=500,{success:!1,error:"Failed to get subscription"}}}),app.post("/usage-records",async(ctx)=>{if(!ctx.request.headers.get("x-user-id"))return ctx.set.status=401,{success:!1,error:"Unauthorized"};try{let body=ctx.body,result=await provider.reportUsage({subscriptionItemId:body.subscriptionItemId,quantity:body.quantity,timestamp:body.timestamp,action:body.action});if(!result.success)return ctx.set.status=400,result;return{success:!0,usageRecord:result}}catch(error3){return logger2.error("[Payment] Report usage error",{error:String(error3)}),ctx.set.status=500,{success:!1,error:"Failed to report usage"}}}),app.get("/usage-records/:subscriptionItemId/summaries",async(ctx)=>{if(!ctx.request.headers.get("x-user-id"))return ctx.set.status=401,{success:!1,error:"Unauthorized"};try{let{subscriptionItemId}=ctx.params,query=ctx.query,result=await provider.listUsageRecordSummaries({subscriptionItemId,limit:query.limit?parseInt(query.limit,10):void 0,startingAfter:query.startingAfter});if(!result.success)return ctx.set.status=400,result;return{success:!0,summaries:result.summaries,hasMore:result.hasMore}}catch(error3){return logger2.error("[Payment] List usage summaries error",{error:String(error3)}),ctx.set.status=500,{success:!1,error:"Failed to list usage summaries"}}}),app.post("/invoices",async(ctx)=>{let userId=ctx.request.headers.get("x-user-id");if(!userId)return ctx.set.status=401,{success:!1,error:"Unauthorized"};try{let body=ctx.body,customerId=body.customerId,[customer]=await database.select().from(cusTable).where(eq57(cusTable.id,customerId));if(!customer)return ctx.set.status=404,{success:!1,error:"Customer not found"};if(String(customer.user_id)!==String(userId)&&!hasGodminRole(ctx.request))return ctx.set.status=403,{success:!1,error:"Forbidden"};let result=await provider.createInvoice({providerCustomerId:customer.provider_customer_id,collectionMethod:body.collectionMethod,daysUntilDue:body.daysUntilDue,description:body.description,metadata:body.metadata,autoAdvance:body.autoAdvance,items:body.items});if(!result.success)return ctx.set.status=400,result;let[row]=await database.insert(invTable).values({customer_id:customerId,subscription_id:body.subscriptionId??null,provider:provider.name,provider_invoice_id:result.providerInvoiceId,status:result.status??"draft",collection_method:body.collectionMethod??"charge_automatically",currency:body.currency??defaultCurrency,description:body.description??null,hosted_invoice_url:result.hostedInvoiceUrl??null,invoice_pdf:result.invoicePdf??null,days_until_due:body.daysUntilDue??null,lines:body.items??[],metadata:body.metadata??{}}).returning();return{success:!0,invoice:row,providerInvoiceId:result.providerInvoiceId}}catch(error3){return logger2.error("[Payment] Create invoice error",{error:String(error3)}),ctx.set.status=500,{success:!1,error:"Failed to create invoice"}}}),app.post("/invoices/:id/finalize",async(ctx)=>{if(!ctx.request.headers.get("x-user-id"))return ctx.set.status=401,{success:!1,error:"Unauthorized"};try{let{id}=ctx.params,body=ctx.body??{},[existing]=await database.select().from(invTable).where(eq57(invTable.id,id));if(!existing)return ctx.set.status=404,{success:!1,error:"Invoice not found"};if(!await customerBelongsToCaller(ctx.request,existing.customer_id))return ctx.set.status=403,{success:!1,error:"Forbidden"};let result=await provider.finalizeInvoice({providerInvoiceId:existing.provider_invoice_id,autoAdvance:body.autoAdvance});if(!result.success)return ctx.set.status=400,result;let[updated]=await database.update(invTable).set({status:result.status??"open",hosted_invoice_url:result.hostedInvoiceUrl??existing.hosted_invoice_url,invoice_pdf:result.invoicePdf??existing.invoice_pdf}).where(eq57(invTable.id,id)).returning();return{success:!0,invoice:updated}}catch(error3){return logger2.error("[Payment] Finalize invoice error",{error:String(error3)}),ctx.set.status=500,{success:!1,error:"Failed to finalize invoice"}}}),app.post("/invoices/:id/send",async(ctx)=>{if(!ctx.request.headers.get("x-user-id"))return ctx.set.status=401,{success:!1,error:"Unauthorized"};try{let{id}=ctx.params,[existing]=await database.select().from(invTable).where(eq57(invTable.id,id));if(!existing)return ctx.set.status=404,{success:!1,error:"Invoice not found"};if(!await customerBelongsToCaller(ctx.request,existing.customer_id))return ctx.set.status=403,{success:!1,error:"Forbidden"};let result=await provider.sendInvoice({providerInvoiceId:existing.provider_invoice_id});if(!result.success)return ctx.set.status=400,result;return{success:!0}}catch(error3){return logger2.error("[Payment] Send invoice error",{error:String(error3)}),ctx.set.status=500,{success:!1,error:"Failed to send invoice"}}}),app.post("/invoices/:id/void",async(ctx)=>{if(!ctx.request.headers.get("x-user-id"))return ctx.set.status=401,{success:!1,error:"Unauthorized"};try{let{id}=ctx.params,[existing]=await database.select().from(invTable).where(eq57(invTable.id,id));if(!existing)return ctx.set.status=404,{success:!1,error:"Invoice not found"};if(!await customerBelongsToCaller(ctx.request,existing.customer_id))return ctx.set.status=403,{success:!1,error:"Forbidden"};let result=await provider.voidInvoice({providerInvoiceId:existing.provider_invoice_id});if(!result.success)return ctx.set.status=400,result;let[updated]=await database.update(invTable).set({status:"void",voided_at:new Date}).where(eq57(invTable.id,id)).returning();return{success:!0,invoice:updated}}catch(error3){return logger2.error("[Payment] Void invoice error",{error:String(error3)}),ctx.set.status=500,{success:!1,error:"Failed to void invoice"}}}),app.post("/invoices/:id/pay",async(ctx)=>{if(!ctx.request.headers.get("x-user-id"))return ctx.set.status=401,{success:!1,error:"Unauthorized"};try{let{id}=ctx.params,body=ctx.body??{},[existing]=await database.select().from(invTable).where(eq57(invTable.id,id));if(!existing)return ctx.set.status=404,{success:!1,error:"Invoice not found"};if(!await customerBelongsToCaller(ctx.request,existing.customer_id))return ctx.set.status=403,{success:!1,error:"Forbidden"};let result=await provider.payInvoice({providerInvoiceId:existing.provider_invoice_id,paymentMethod:body.paymentMethod});if(!result.success)return ctx.set.status=400,result;let[updated]=await database.update(invTable).set({status:result.status??"paid",amount_paid:result.amountPaid??existing.amount_paid,amount_due:result.amountDue??existing.amount_due,paid_at:new Date}).where(eq57(invTable.id,id)).returning();return{success:!0,invoice:updated}}catch(error3){return logger2.error("[Payment] Pay invoice error",{error:String(error3)}),ctx.set.status=500,{success:!1,error:"Failed to pay invoice"}}}),app.get("/invoices",async(ctx)=>{let userId=ctx.request.headers.get("x-user-id");if(!userId)return ctx.set.status=401,{success:!1,error:"Unauthorized"};try{let query=ctx.query,conditions=[];if(query.customerId)conditions.push(eq57(invTable.customer_id,query.customerId));if(query.subscriptionId)conditions.push(eq57(invTable.subscription_id,query.subscriptionId));if(query.status)conditions.push(eq57(invTable.status,query.status));if(!hasGodminRole(ctx.request)){let ids=await callerCustomerIds(userId);if(ids.length===0)return{success:!0,invoices:[]};conditions.push(inArray15(invTable.customer_id,ids))}return{success:!0,invoices:conditions.length>0?await database.select().from(invTable).where(and21(...conditions)):await database.select().from(invTable)}}catch(error3){return logger2.error("[Payment] List invoices error",{error:String(error3)}),ctx.set.status=500,{success:!1,error:"Failed to list invoices"}}}),app.get("/invoices/:id",async(ctx)=>{if(!ctx.request.headers.get("x-user-id"))return ctx.set.status=401,{success:!1,error:"Unauthorized"};try{let{id}=ctx.params,[invoice]=await database.select().from(invTable).where(eq57(invTable.id,id));if(!invoice)return ctx.set.status=404,{success:!1,error:"Invoice not found"};if(!await customerBelongsToCaller(ctx.request,invoice.customer_id))return ctx.set.status=403,{success:!1,error:"Forbidden"};return{success:!0,invoice}}catch(error3){return logger2.error("[Payment] Get invoice error",{error:String(error3)}),ctx.set.status=500,{success:!1,error:"Failed to get invoice"}}}),subMerchantsEnabled)app.post("/sub-merchants",async(ctx)=>{let userId=ctx.request.headers.get("x-user-id");if(!userId)return ctx.set.status=401,{success:!1,error:"Unauthorized"};let body=ctx.body;if(!body.name||!body.email||!body.subMerchantType)return ctx.set.status=400,{success:!1,error:"name, email, and subMerchantType are required"};try{let externalId=body.externalId??`sm-${Date.now().toString(36)}`,result=await provider.registerSubMerchant({locale:body.locale??defaultLocale,subMerchantExternalId:externalId,subMerchantType:body.subMerchantType,name:body.name,email:body.email,gsmNumber:body.gsmNumber,address:body.address,iban:body.iban,contactName:body.contactName,contactSurname:body.contactSurname,identityNumber:body.identityNumber,taxOffice:body.taxOffice,taxNumber:body.taxNumber,legalCompanyTitle:body.legalCompanyTitle,currency:body.currency??defaultCurrency});if(!result.success)return ctx.set.status=400,{success:!1,error:result.errorMessage??"Failed to register sub-merchant",errorCode:result.errorCode};let[saved]=await database.insert(smTable).values({userId:hasGodminRole(ctx.request)?body.userId??userId:userId,provider:provider.name,providerSubMerchantKey:result.subMerchantKey,externalId,type:body.subMerchantType,status:"active",name:body.name,email:body.email,gsmNumber:body.gsmNumber??null,address:body.address??null,iban:body.iban??null,contactName:body.contactName??null,contactSurname:body.contactSurname??null,identityNumber:body.identityNumber??null,taxOffice:body.taxOffice??null,taxNumber:body.taxNumber??null,legalCompanyTitle:body.legalCompanyTitle??null,currency:body.currency??defaultCurrency,commissionRate:hasGodminRole(ctx.request)?body.commissionRate??0:0}).returning();return logger2.info("[Payment] Sub-merchant registered",{externalId,providerKey:result.subMerchantKey}),{success:!0,data:saved}}catch(error3){return logger2.error("[Payment] register sub-merchant error",{error:error3 instanceof Error?error3.message:String(error3)}),ctx.set.status=500,{success:!1,error:"Failed to register sub-merchant"}}}),app.put("/sub-merchants/:id",async(ctx)=>{let userId=ctx.request.headers.get("x-user-id");if(!userId)return ctx.set.status=401,{success:!1,error:"Unauthorized"};let body=ctx.body;try{let[existing]=await database.select().from(smTable).where(eq57(smTable.id,ctx.params.id)).limit(1);if(!existing)return ctx.set.status=404,{success:!1,error:"Sub-merchant not found"};let smIsGodmin=hasGodminRole(ctx.request);if(String(existing.userId)!==String(userId)&&!smIsGodmin)return ctx.set.status=403,{success:!1,error:"Forbidden"};if(existing.providerSubMerchantKey){let providerResult=await provider.updateSubMerchant({locale:body.locale??defaultLocale,subMerchantKey:existing.providerSubMerchantKey,name:body.name,email:body.email,gsmNumber:body.gsmNumber,address:body.address,iban:body.iban,contactName:body.contactName,contactSurname:body.contactSurname,identityNumber:body.identityNumber,taxOffice:body.taxOffice,taxNumber:body.taxNumber,legalCompanyTitle:body.legalCompanyTitle,currency:body.currency});if(!providerResult.success)logger2.warn("[Payment] Provider sub-merchant update failed",{errorCode:providerResult.errorCode})}let updateData={};if(body.name)updateData.name=body.name;if(body.email)updateData.email=body.email;if(body.gsmNumber!==void 0)updateData.gsmNumber=body.gsmNumber;if(body.address!==void 0)updateData.address=body.address;if(body.iban!==void 0)updateData.iban=body.iban;if(body.contactName!==void 0)updateData.contactName=body.contactName;if(body.contactSurname!==void 0)updateData.contactSurname=body.contactSurname;if(body.identityNumber!==void 0)updateData.identityNumber=body.identityNumber;if(body.taxOffice!==void 0)updateData.taxOffice=body.taxOffice;if(body.taxNumber!==void 0)updateData.taxNumber=body.taxNumber;if(body.legalCompanyTitle!==void 0)updateData.legalCompanyTitle=body.legalCompanyTitle;if(body.currency!==void 0)updateData.currency=body.currency;if(body.commissionRate!==void 0&&smIsGodmin)updateData.commissionRate=body.commissionRate;if(body.status!==void 0&&smIsGodmin)updateData.status=body.status;let[updated]=await database.update(smTable).set(updateData).where(eq57(smTable.id,ctx.params.id)).returning();return{success:!0,data:updated}}catch{return ctx.set.status=500,{success:!1,error:"Failed to update sub-merchant"}}}),app.get("/sub-merchants",async(ctx)=>{let userId=ctx.request.headers.get("x-user-id");if(!userId)return ctx.set.status=401,{success:!1,error:"Unauthorized"};try{let smListGodmin=hasGodminRole(ctx.request);return{success:!0,data:{items:await database.select().from(smTable).where(smListGodmin?eq57(smTable.isActive,!0):and21(eq57(smTable.isActive,!0),eq57(smTable.userId,userId))).orderBy(smTable.createdAt)}}}catch{return ctx.set.status=500,{success:!1,error:"Failed to list sub-merchants"}}}),app.get("/sub-merchants/:id",async(ctx)=>{let userId=ctx.request.headers.get("x-user-id");if(!userId)return ctx.set.status=401,{success:!1,error:"Unauthorized"};try{let[item]=await database.select().from(smTable).where(eq57(smTable.id,ctx.params.id)).limit(1);if(!item)return ctx.set.status=404,{success:!1,error:"Sub-merchant not found"};if(String(item.userId)!==String(userId)&&!hasGodminRole(ctx.request))return ctx.set.status=403,{success:!1,error:"Forbidden"};return{success:!0,data:item}}catch{return ctx.set.status=500,{success:!1,error:"Failed to get sub-merchant"}}}),app.post("/splits/:splitId/approve",async(ctx)=>{if(!ctx.request.headers.get("x-user-id"))return ctx.set.status=401,{success:!1,error:"Unauthorized"};if(!hasGodminRole(ctx.request))return ctx.set.status=403,{success:!1,error:"Forbidden: operator privileges required"};try{let[split]=await database.select().from(csTable).where(eq57(csTable.id,ctx.params.splitId)).limit(1);if(!split)return ctx.set.status=404,{success:!1,error:"Split not found"};if(split.status!=="pending")return ctx.set.status=400,{success:!1,error:`Split already ${split.status}`};if(split.providerSplitId){let result=await provider.approveSplit({locale:defaultLocale,paymentTransactionId:split.providerSplitId});if(!result.success)return ctx.set.status=400,{success:!1,error:result.errorMessage??"Provider approval failed",errorCode:result.errorCode}}let[updated]=await database.update(csTable).set({status:"approved",approvedAt:new Date}).where(eq57(csTable.id,ctx.params.splitId)).returning();return logger2.info("[Payment] Split approved",{splitId:ctx.params.splitId}),{success:!0,data:updated}}catch{return ctx.set.status=500,{success:!1,error:"Failed to approve split"}}}),app.post("/splits/:splitId/disapprove",async(ctx)=>{if(!ctx.request.headers.get("x-user-id"))return ctx.set.status=401,{success:!1,error:"Unauthorized"};if(!hasGodminRole(ctx.request))return ctx.set.status=403,{success:!1,error:"Forbidden: operator privileges required"};try{let[split]=await database.select().from(csTable).where(eq57(csTable.id,ctx.params.splitId)).limit(1);if(!split)return ctx.set.status=404,{success:!1,error:"Split not found"};if(split.status!=="pending")return ctx.set.status=400,{success:!1,error:`Split already ${split.status}`};if(split.providerSplitId){let result=await provider.disapproveSplit({locale:defaultLocale,paymentTransactionId:split.providerSplitId});if(!result.success)return ctx.set.status=400,{success:!1,error:result.errorMessage??"Provider disapproval failed",errorCode:result.errorCode}}let[updated]=await database.update(csTable).set({status:"disapproved",disapprovedAt:new Date}).where(eq57(csTable.id,ctx.params.splitId)).returning();return logger2.info("[Payment] Split disapproved",{splitId:ctx.params.splitId}),{success:!0,data:updated}}catch{return ctx.set.status=500,{success:!1,error:"Failed to disapprove split"}}}),app.get("/splits",async(ctx)=>{if(!ctx.request.headers.get("x-user-id"))return ctx.set.status=401,{success:!1,error:"Unauthorized"};if(!hasGodminRole(ctx.request))return ctx.set.status=403,{success:!1,error:"Forbidden: operator privileges required"};try{let url=new URL(ctx.request.url),transactionId=url.searchParams.get("transactionId"),subMerchantId=url.searchParams.get("subMerchantId"),query=database.select().from(csTable);if(transactionId&&subMerchantId)query=query.where(and21(eq57(csTable.transactionId,transactionId),eq57(csTable.subMerchantId,subMerchantId)));else if(transactionId)query=query.where(eq57(csTable.transactionId,transactionId));else if(subMerchantId)query=query.where(eq57(csTable.subMerchantId,subMerchantId));return{success:!0,data:{items:await query.orderBy(csTable.createdAt)}}}catch{return ctx.set.status=500,{success:!1,error:"Failed to list splits"}}});return app.get("/balance",async(ctx)=>{if(!ctx.request.headers.get("x-user-id"))return ctx.set.status=401,{success:!1,error:"Unauthorized"};try{let result=await provider.getBalance();if(!result.success)return ctx.set.status=400,{success:!1,error:result.errorMessage??"Failed to get balance"};return{success:!0,data:{available:result.available,pending:result.pending,connectReserved:result.connectReserved}}}catch{return ctx.set.status=500,{success:!1,error:"Failed to get balance"}}}),app.post("/payouts",async(ctx)=>{if(!ctx.request.headers.get("x-user-id"))return ctx.set.status=401,{success:!1,error:"Unauthorized"};if(!hasGodminRole(ctx.request))return ctx.set.status=403,{success:!1,error:"Forbidden: operator privileges required"};try{let body=ctx.body,payoutAmt=validateAmount(body.amount,"amount");if(!payoutAmt.ok)return ctx.set.status=400,{success:!1,error:payoutAmt.error};if(!isValidCurrency(body.currency))return ctx.set.status=400,{success:!1,error:"currency must be a 3-letter code"};let result=await provider.createPayout({amount:payoutAmt.value,currency:body.currency??defaultCurrency,destination:body.destination,description:body.description,metadata:body.metadata,method:body.method,sourceType:body.sourceType,statementDescriptor:body.statementDescriptor});if(!result.success)return ctx.set.status=400,{success:!1,error:result.errorMessage??"Failed to create payout"};return{success:!0,data:result}}catch{return ctx.set.status=500,{success:!1,error:"Failed to create payout"}}}),app.get("/payouts",async(ctx)=>{if(!ctx.request.headers.get("x-user-id"))return ctx.set.status=401,{success:!1,error:"Unauthorized"};try{let url=new URL(ctx.request.url),result=await provider.listPayouts({status:url.searchParams.get("status")??void 0,destination:url.searchParams.get("destination")??void 0,limit:url.searchParams.get("limit")?Number(url.searchParams.get("limit")):void 0,startingAfter:url.searchParams.get("startingAfter")??void 0});if(!result.success)return ctx.set.status=400,{success:!1,error:result.errorMessage??"Failed to list payouts"};return{success:!0,data:{payouts:result.payouts,hasMore:result.hasMore}}}catch{return ctx.set.status=500,{success:!1,error:"Failed to list payouts"}}}),app.get("/payouts/:id",async(ctx)=>{if(!ctx.request.headers.get("x-user-id"))return ctx.set.status=401,{success:!1,error:"Unauthorized"};try{let result=await provider.getPayout({providerPayoutId:ctx.params.id});if(!result.success)return ctx.set.status=400,{success:!1,error:result.errorMessage??"Failed to get payout"};return{success:!0,data:result}}catch{return ctx.set.status=500,{success:!1,error:"Failed to get payout"}}}),app.post("/payouts/:id/cancel",async(ctx)=>{if(!ctx.request.headers.get("x-user-id"))return ctx.set.status=401,{success:!1,error:"Unauthorized"};if(!hasGodminRole(ctx.request))return ctx.set.status=403,{success:!1,error:"Forbidden: operator privileges required"};try{let result=await provider.cancelPayout({providerPayoutId:ctx.params.id});if(!result.success)return ctx.set.status=400,{success:!1,error:result.errorMessage??"Failed to cancel payout"};return{success:!0,data:result}}catch{return ctx.set.status=500,{success:!1,error:"Failed to cancel payout"}}}),app.post("/transfers",async(ctx)=>{if(!ctx.request.headers.get("x-user-id"))return ctx.set.status=401,{success:!1,error:"Unauthorized"};if(!hasGodminRole(ctx.request))return ctx.set.status=403,{success:!1,error:"Forbidden: operator privileges required"};try{let body=ctx.body,transferAmt=validateAmount(body.amount,"amount");if(!transferAmt.ok)return ctx.set.status=400,{success:!1,error:transferAmt.error};if(!isValidCurrency(body.currency))return ctx.set.status=400,{success:!1,error:"currency must be a 3-letter code"};let result=await provider.createTransfer({amount:transferAmt.value,currency:body.currency??defaultCurrency,destination:body.destination,description:body.description,metadata:body.metadata,sourceTransaction:body.sourceTransaction,transferGroup:body.transferGroup});if(!result.success)return ctx.set.status=400,{success:!1,error:result.errorMessage??"Failed to create transfer"};return{success:!0,data:result}}catch{return ctx.set.status=500,{success:!1,error:"Failed to create transfer"}}}),app.get("/transfers",async(ctx)=>{if(!ctx.request.headers.get("x-user-id"))return ctx.set.status=401,{success:!1,error:"Unauthorized"};try{let url=new URL(ctx.request.url),result=await provider.listTransfers({destination:url.searchParams.get("destination")??void 0,transferGroup:url.searchParams.get("transferGroup")??void 0,limit:url.searchParams.get("limit")?Number(url.searchParams.get("limit")):void 0,startingAfter:url.searchParams.get("startingAfter")??void 0});if(!result.success)return ctx.set.status=400,{success:!1,error:result.errorMessage??"Failed to list transfers"};return{success:!0,data:{transfers:result.transfers,hasMore:result.hasMore}}}catch{return ctx.set.status=500,{success:!1,error:"Failed to list transfers"}}}),app.options("/callback",()=>{return new Response(null,{headers:{"Access-Control-Allow-Origin":"*","Access-Control-Allow-Methods":"GET,POST,OPTIONS","Access-Control-Allow-Headers":"Content-Type"}})}),registerStripeWebhookRoute(app,{provider,webhookSecret:config.webhookSecret,db:database,webhookLogsTable:whTable,transactionsTable:txTable,getPayoutService:config.getPayoutService,logger:logger2}),app};var init_payment=__esm(()=>{init_adminGuard();init_webhook()});var requireUser=(ctx)=>ctx.request.headers.get("x-user-id"),isAdmin=(ctx)=>decodeHeaderList(ctx.request.headers.get("x-user-roles")).some((r2)=>isGodminRole(r2)),canReadOwnerLedger=(ctx,ownerType,ownerId)=>{if(isAdmin(ctx))return!0;let userId=ctx.request.headers.get("x-user-id");return!!userId&&ownerType==="user"&&!!ownerId&&ownerId===userId},failResponse=(ctx,status,message)=>{return ctx.set.status=status,{success:!1,message,data:null}};var init_types22=__esm(()=>{init_Authorization()});import{Elysia as Elysia46,t as t38}from"elysia";function createPayoutRoutes(config){let base=`${config.basePath}/marketplace`,app=new Elysia46;return app.post(`${base}/payout-requests`,async(ctx)=>{let svc=config.getPayoutService();if(!svc)return failResponse(ctx,503,"Marketplace not available");let userId=requireUser(ctx);if(!userId)return failResponse(ctx,401,"Authentication required");let body=ctx.body;if(!canReadOwnerLedger(ctx,body.recipientOwnerType,body.recipientOwnerId))return failResponse(ctx,403,"Forbidden: cannot request a payout for another owner's balance");try{return{success:!0,message:"Payout requested",data:await svc.requestPayout({...body,requestedBy:userId})}}catch(err){return failResponse(ctx,400,err instanceof Error?err.message:"Failed")}},{body:t38.Object({recipientOwnerId:t38.String(),recipientOwnerType:t38.Optional(t38.String()),amount:t38.Number(),currency:t38.Optional(t38.String()),destination:t38.Optional(t38.String()),requestedBy:t38.Optional(t38.String())}),detail:{tags:["Payments Marketplace"],summary:"Request a payout"}}),app.get(`${base}/payout-requests`,async(ctx)=>{let svc=config.getPayoutService();if(!svc)return failResponse(ctx,503,"Marketplace not available");let userId=requireUser(ctx);if(!userId)return failResponse(ctx,401,"Authentication required");let url=new URL(ctx.request.url),requestedOwnerId=url.searchParams.get("recipientOwnerId")??void 0,recipientOwnerId=isAdmin(ctx)?requestedOwnerId:userId,items=await svc.listPayoutRequests({recipientOwnerId,status:url.searchParams.get("status")??void 0});return{success:!0,message:`Found ${items.length} payout requests`,data:{items}}}),app.get(`${base}/payout-requests/:id`,async(ctx)=>{let svc=config.getPayoutService();if(!svc)return failResponse(ctx,503,"Marketplace not available");if(!requireUser(ctx))return failResponse(ctx,401,"Authentication required");let record3=await svc.getPayoutRequest(ctx.params.id);if(!record3)return failResponse(ctx,404,"Payout request not found");let r2=record3;if(!canReadOwnerLedger(ctx,r2.recipientOwnerType,r2.recipientOwnerId))return failResponse(ctx,404,"Payout request not found");return{success:!0,message:"Payout request",data:record3}}),app.post(`${base}/payout-requests/:id/approve`,async(ctx)=>{let svc=config.getPayoutService();if(!svc)return failResponse(ctx,503,"Marketplace not available");let userId=requireUser(ctx);if(!userId)return failResponse(ctx,401,"Authentication required");if(!isAdmin(ctx))return failResponse(ctx,403,"Forbidden: operator privileges required");try{let record3=await svc.approvePayout(ctx.params.id,{deciderId:userId});if(!record3)return failResponse(ctx,404,"Payout request not found");return{success:!0,message:"Payout approved",data:record3}}catch(err){return failResponse(ctx,400,err instanceof Error?err.message:"Failed")}}),app.post(`${base}/payout-requests/:id/reject`,async(ctx)=>{let svc=config.getPayoutService();if(!svc)return failResponse(ctx,503,"Marketplace not available");let userId=requireUser(ctx);if(!userId)return failResponse(ctx,401,"Authentication required");if(!isAdmin(ctx))return failResponse(ctx,403,"Forbidden: operator privileges required");let record3=await svc.rejectPayout(ctx.params.id,userId);if(!record3)return failResponse(ctx,404,"Payout request not found");return{success:!0,message:"Payout rejected",data:record3}}),app.post(`${base}/disputes`,async(ctx)=>{let svc=config.getPayoutService();if(!svc)return failResponse(ctx,503,"Marketplace not available");if(!requireUser(ctx))return failResponse(ctx,401,"Authentication required");if(!isAdmin(ctx))return failResponse(ctx,403,"Forbidden: operator privileges required");let body=ctx.body;return{success:!0,message:"Dispute opened",data:await svc.openDispute(body)}},{body:t38.Object({provider:t38.String(),transactionId:t38.Optional(t38.String()),providerDisputeId:t38.Optional(t38.String()),ownerType:t38.Optional(t38.String()),ownerId:t38.Optional(t38.String()),amount:t38.Optional(t38.Number()),currency:t38.Optional(t38.String()),reason:t38.Optional(t38.String())}),detail:{tags:["Payments Marketplace"],summary:"Open a dispute"}}),app.get(`${base}/disputes`,async(ctx)=>{let svc=config.getPayoutService();if(!svc)return failResponse(ctx,503,"Marketplace not available");let userId=requireUser(ctx);if(!userId)return failResponse(ctx,401,"Authentication required");let url=new URL(ctx.request.url),requestedOwnerId=url.searchParams.get("ownerId")??void 0,ownerId=isAdmin(ctx)?requestedOwnerId:userId,items=await svc.listDisputes({ownerId,status:url.searchParams.get("status")??void 0});return{success:!0,message:`Found ${items.length} disputes`,data:{items}}}),app.post(`${base}/disputes/:id/resolve`,async(ctx)=>{let svc=config.getPayoutService();if(!svc)return failResponse(ctx,503,"Marketplace not available");if(!requireUser(ctx))return failResponse(ctx,401,"Authentication required");if(!isAdmin(ctx))return failResponse(ctx,403,"Forbidden: operator privileges required");let body=ctx.body,record3=await svc.resolveDispute(ctx.params.id,body.outcome);if(!record3)return failResponse(ctx,404,"Dispute not found");return{success:!0,message:"Dispute resolved",data:record3}},{body:t38.Object({outcome:t38.Union([t38.Literal("won"),t38.Literal("lost"),t38.Literal("accepted"),t38.Literal("cancelled")])}),detail:{tags:["Payments Marketplace"],summary:"Resolve a dispute"}}),app}var init_payouts=__esm(()=>{init_types22()});import{Elysia as Elysia47,t as t39}from"elysia";function createSplitRoutes(config){let base=`${config.basePath}/marketplace`,app=new Elysia47;return app.post(`${base}/splits`,async(ctx)=>{let svc=config.getMarketplaceService();if(!svc)return failResponse(ctx,503,"Marketplace not available");if(!requireUser(ctx))return failResponse(ctx,401,"Authentication required");if(!isAdmin(ctx))return failResponse(ctx,403,"Forbidden: operator privileges required");let body=ctx.body;try{return{success:!0,message:"Split recorded",data:await svc.recordSplit(body)}}catch(err){return failResponse(ctx,400,err instanceof Error?err.message:"Failed")}},{body:t39.Object({recipientOwnerId:t39.String(),recipientOwnerType:t39.Optional(t39.String()),provider:t39.String(),grossAmount:t39.Number(),providerFeeAmount:t39.Optional(t39.Number()),platformFeeAmount:t39.Number(),currency:t39.Optional(t39.String()),transactionId:t39.Optional(t39.String()),sourceType:t39.Optional(t39.String()),sourceId:t39.Optional(t39.String()),settlementDelayDays:t39.Optional(t39.Number()),reserveRate:t39.Optional(t39.Number()),isNewSeller:t39.Optional(t39.Boolean())}),detail:{tags:["Payments Marketplace"],summary:"Record a payment split"}}),app.get(`${base}/splits`,async(ctx)=>{let svc=config.getMarketplaceService();if(!svc)return failResponse(ctx,503,"Marketplace not available");let userId=requireUser(ctx);if(!userId)return failResponse(ctx,401,"Authentication required");let url=new URL(ctx.request.url),requestedOwnerId=url.searchParams.get("recipientOwnerId")??void 0,recipientOwnerId=isAdmin(ctx)?requestedOwnerId:userId,items=await svc.listSplits({recipientOwnerId,status:url.searchParams.get("status")??void 0});return{success:!0,message:`Found ${items.length} splits`,data:{items}}}),app.get(`${base}/balance/:ownerId`,async(ctx)=>{let svc=config.getMarketplaceService();if(!svc)return failResponse(ctx,503,"Marketplace not available");if(!requireUser(ctx))return failResponse(ctx,401,"Authentication required");let url=new URL(ctx.request.url),ownerType=url.searchParams.get("ownerType")??"seller",ownerId=ctx.params.ownerId;if(!canReadOwnerLedger(ctx,ownerType,ownerId))return failResponse(ctx,403,"Forbidden: cannot read another owner's balance");return{success:!0,message:"Balance",data:await svc.getBalance(ownerType,ownerId,url.searchParams.get("currency")??void 0)}}),app.post(`${base}/reserves/:id/release`,async(ctx)=>{let svc=config.getMarketplaceService();if(!svc)return failResponse(ctx,503,"Marketplace not available");if(!requireUser(ctx))return failResponse(ctx,401,"Authentication required");if(!isAdmin(ctx))return failResponse(ctx,403,"Forbidden: operator privileges required");if(!await svc.releaseReserve(ctx.params.id))return failResponse(ctx,400,"Reserve not found or not held");return{success:!0,message:"Reserve released",data:{released:!0}}}),app.get(`${base}/settlement-policy`,async(ctx)=>{let svc=config.getMarketplaceService();if(!svc)return failResponse(ctx,503,"Marketplace not available");if(!requireUser(ctx))return failResponse(ctx,401,"Authentication required");let url=new URL(ctx.request.url),ownerType=url.searchParams.get("ownerType")??"tenant",ownerId=url.searchParams.get("ownerId")??"";if(!canReadOwnerLedger(ctx,ownerType,ownerId))return failResponse(ctx,403,"Forbidden: cannot read this settlement policy");return{success:!0,message:"Settlement policy",data:await svc.getSettlementPolicy(ownerType,ownerId)}}),app.post(`${base}/settlement-policy`,async(ctx)=>{let svc=config.getMarketplaceService();if(!svc)return failResponse(ctx,503,"Marketplace not available");if(!requireUser(ctx))return failResponse(ctx,401,"Authentication required");if(!isAdmin(ctx))return failResponse(ctx,403,"Forbidden: operator privileges required");let body=ctx.body;return{success:!0,message:"Settlement policy saved",data:await svc.upsertSettlementPolicy(body)}},{body:t39.Object({ownerType:t39.String(),ownerId:t39.String(),defaultDelayDays:t39.Optional(t39.Number()),newSellerDelayDays:t39.Optional(t39.Number()),reserveRate:t39.Optional(t39.Number()),reserveDays:t39.Optional(t39.Number()),minimumPayoutAmount:t39.Optional(t39.Number()),currency:t39.Optional(t39.String()),earlyPayoutEnabled:t39.Optional(t39.Boolean())}),detail:{tags:["Payments Marketplace"],summary:"Upsert settlement policy"}}),app}var init_splits=__esm(()=>{init_types22()});var exports_marketplace={};__export(exports_marketplace,{createMarketplaceRoutes:()=>createMarketplaceRoutes});function createMarketplaceRoutes(app,config){return app.use(createSplitRoutes(config)),app.use(createPayoutRoutes(config)),app}var init_marketplace=__esm(()=>{init_payouts();init_splits()});function normSegment(input){return input.toLowerCase().replace(/[^a-z0-9]+/g,"_").replace(/_+/g,"_").replace(/^_|_$/g,"")}function normPath(path7){return normSegment(path7.replace(/\{[^}]+\}/g,(m2)=>m2.slice(1,-1)))}function shortHash(input){let h=5381;for(let i=0;i<input.length;i++)h=(h*33^input.charCodeAt(i))>>>0;return h.toString(36)}function capAction(action,max=100){if(action.length<=max)return action;let suffix=`_${shortHash(action)}`;return action.slice(0,Math.max(1,max-suffix.length))+suffix}function resourceFromPath(path7){let segs=path7.split("/").filter(Boolean).filter((s)=>!s.startsWith("{"));for(let s of segs){if(s==="api"||/^v\d+$/i.test(s))continue;return normSegment(s)}return normSegment(segs[0]??"root")}function matchesExclude(path7,patterns3){if(!patterns3?.length)return!1;for(let raw of patterns3){let p=raw.trim();if(!p)continue;if(p.endsWith("/*")){let prefix=p.slice(0,-2);if(path7===prefix||path7.startsWith(`${prefix}/`))return!0}else if(p.endsWith("*")){if(path7.startsWith(p.slice(0,-1)))return!0}else if(path7===p)return!0}return!1}function parseOpenApiToClaims(serviceId,doc,opts={}){let sid=normSegment(serviceId);if(!sid)throw Error("endpointDiscovery: serviceId is empty after normalization");if(RESERVED_SERVICE_IDS.has(sid))throw Error(`endpointDiscovery: serviceId "${serviceId}" collides with an HTTP-method claim prefix; pick another id`);let specs=[],seen=new Set,paths=doc.paths??{};for(let[path7,ops]of Object.entries(paths)){if(!ops||matchesExclude(path7,opts.exclude))continue;for(let method of HTTP_METHODS2){let op=ops[method];if(!op)continue;let tag=(op.tags?.[0]?normSegment(op.tags[0]):"")||resourceFromPath(path7),opToken=(op.operationId?normSegment(op.operationId):"")||`${method}_${normPath(path7)}`,action=capAction(`${sid}.${tag||"root"}.${opToken||method}`);if(seen.has(action)){action=capAction(`${action}_${shortHash(`${method} ${path7}`)}`);while(seen.has(action))action=capAction(`${action}_${shortHash(action)}`)}seen.add(action),specs.push({action,path:path7,method:method.toUpperCase(),description:op.summary||op.description||`${method.toUpperCase()} ${path7}`})}}return specs}function diffClaims(existing,specs){let specByAction=new Map(specs.map((s)=>[s.action,s])),existByAction=new Map(existing.map((e)=>[e.action,e]));return{toInsert:specs.filter((s)=>!existByAction.has(s.action)),toReactivate:specs.filter((s)=>existByAction.get(s.action)?.isActive===!1),toDeactivate:existing.filter((e)=>e.isActive&&!specByAction.has(e.action)),unchanged:specs.filter((s)=>existByAction.get(s.action)?.isActive===!0)}}async function fetchOpenApi(baseUrl,openapiPath,fetchImpl=fetch){let url=`${baseUrl.replace(/\/$/,"")}${openapiPath.startsWith("/")?"":"/"}${openapiPath}`,res=await fetchImpl(url);if(!res.ok)throw Error(`endpointDiscovery: OpenAPI fetch failed ${res.status} for ${url}`);return await res.json()}var HTTP_METHODS2,RESERVED_SERVICE_IDS;var init_EndpointDiscovery=__esm(()=>{HTTP_METHODS2=["get","post","put","patch","delete"],RESERVED_SERVICE_IDS=new Set(["get","post","put","patch","delete","toggle","bulk"])});var exports_seed={};__export(exports_seed,{seedDiscoveredClaims:()=>seedDiscoveredClaims,runEndpointDiscovery:()=>runEndpointDiscovery,getRouteManifest:()=>getRouteManifest,getRoleClaimsManifest:()=>getRoleClaimsManifest});import{eq as eq58,like as like2}from"drizzle-orm";function col16(table,name2){return table[name2]}async function seedDiscoveredClaims(db,claimsTable,serviceId,specs,logger2){let actionCol=col16(claimsTable,"action"),prefix=specs[0]?.action.split(".")[0]??serviceId.toLowerCase(),existing=(await db.select().from(claimsTable).where(like2(actionCol,`${prefix}.%`))).map((r2)=>({action:String(r2.action),isActive:r2.isActive!==!1,path:String(r2.path??""),method:String(r2.method??""),description:String(r2.description??"")})),plan=diffClaims(existing,specs);for(let s of plan.toInsert)await db.insert(claimsTable).values({action:s.action,path:s.path,method:s.method,description:s.description});for(let s of plan.toReactivate)await db.update(claimsTable).set({isActive:!0,path:s.path,method:s.method,description:s.description}).where(eq58(actionCol,s.action));for(let e of plan.toDeactivate)await db.update(claimsTable).set({isActive:!1}).where(eq58(actionCol,e.action));let summary={added:plan.toInsert.length,reactivated:plan.toReactivate.length,deactivated:plan.toDeactivate.length,unchanged:plan.unchanged.length,total:specs.length};return logger2.info(`[Discovery] Reconciled "${serviceId}"`,summary),summary}async function runEndpointDiscovery(db,schemaTables,config,logger2,fetchImpl=fetch){let claimsTable=schemaTables.claims,services=config.services??[],results=[];if(!claimsTable)return logger2.warn("[Discovery] No claims table in schema; skipping endpoint discovery"),{services:[]};for(let svc of services)try{let doc=await fetchOpenApi(svc.baseUrl,svc.openapi??"/openapi.json",fetchImpl),specs=parseOpenApiToClaims(svc.id,doc,{exclude:svc.exclude}),summary=await seedDiscoveredClaims(db,claimsTable,svc.id,specs,logger2);results.push({id:svc.id,...summary})}catch(err){let message=err instanceof Error?err.message:String(err);logger2.error(`[Discovery] Service "${svc.id}" discovery failed`,{error:message}),results.push({id:svc.id,added:0,reactivated:0,deactivated:0,unchanged:0,total:0,error:message})}return{services:results}}async function getRouteManifest(db,claimsTable,serviceId){return(await db.select().from(claimsTable).where(like2(col16(claimsTable,"action"),`${serviceId.toLowerCase()}.%`))).filter((r2)=>r2.isActive!==!1).map((r2)=>({action:String(r2.action),path:String(r2.path??""),method:String(r2.method??"")}))}async function getRoleClaimsManifest(db,schemaTables,serviceId){let{roles:rolesTable,claims:claimsTable}=schemaTables,roleClaimsTable=schemaTables.roleClaims??schemaTables.role_claims;if(!rolesTable||!claimsTable||!roleClaimsTable)return{};let sid=serviceId.toLowerCase(),claimRows=await db.select().from(claimsTable),claimIdToAction=new Map;for(let c of claimRows){if(c.isActive===!1)continue;let action=String(c.action??"");if(action===sid||action.startsWith(`${sid}.`))claimIdToAction.set(String(c.id),action)}if(claimIdToAction.size===0)return{};let roleRows=await db.select().from(rolesTable),roleIdToName=new Map;for(let r2 of roleRows)roleIdToName.set(String(r2.id),String(r2.name??""));let rcRows=await db.select().from(roleClaimsTable),out={};for(let rc of rcRows){if(rc.isActive===!1)continue;let action=claimIdToAction.get(String(rc.claimId??rc.claim_id)),roleName=roleIdToName.get(String(rc.roleId??rc.role_id));if(!action||!roleName)continue;(out[roleName]??=[]).push(action)}return out}var init_seed=__esm(()=>{init_EndpointDiscovery()});var OPS_BY_TYPE;var init_types23=__esm(()=>{OPS_BY_TYPE={int:["gt","gte","lt","lte","eq","ne"],boolean:["eq","ne"],string:["eq","ne"]}});function isRecord(v){return typeof v==="object"&&v!==null}function guardActionFromName(name2){let brace=name2.indexOf("{");return(brace>=0?name2.slice(0,brace):name2).replace(/:$/,"")}function parseGuardCatalogEntry(entry){if(!isRecord(entry))return null;let name2=typeof entry.name==="string"?entry.name.trim():"";if(!name2)return null;let valueType=entry.value;if(typeof valueType!=="string"||!VALUE_TYPES.includes(valueType))return null;let action=guardActionFromName(name2);if(!action)return null;return{action,policy:{kind:"guard",keyTemplate:name2,valueType}}}function parseGuardPolicy(raw){if(!isRecord(raw)||raw.kind!=="guard")return null;if(typeof raw.keyTemplate!=="string"||!raw.keyTemplate)return null;let vt=raw.valueType;if(typeof vt!=="string"||!VALUE_TYPES.includes(vt))return null;return{kind:"guard",keyTemplate:raw.keyTemplate,valueType:vt}}function resolveGuardKey(keyTemplate,ctx){return keyTemplate.replaceAll("{userId}",ctx.userId).replaceAll("{tenant}",ctx.tenant??"default")}function coerceThreshold(value2,type4){if(type4==="int"){if(value2==null)return null;if(typeof value2==="boolean"||typeof value2==="symbol")return null;if(typeof value2==="string"&&value2.trim()==="")return null;if(typeof value2==="object")return null;let n2=Number(value2);return Number.isFinite(n2)?n2:null}if(type4==="boolean"){if(typeof value2==="boolean")return value2;if(value2==="true"||value2===1||value2==="1")return!0;if(value2==="false"||value2===0||value2==="0")return!1;return null}return value2==null?null:String(value2)}function parseGuardCondition(scope,valueType){let raw=scope;if(typeof scope==="string")try{raw=JSON.parse(scope)}catch{return null}if(!isRecord(raw))return null;let op=raw.op;if(typeof op!=="string"||!OPS_BY_TYPE[valueType].includes(op))return null;let value2=coerceThreshold(raw.value,valueType);if(value2===null)return null;let invalidates=Array.isArray(raw.invalidates)?raw.invalidates.filter((a12)=>typeof a12==="string"&&a12.length>0):[];return{op,value:value2,invalidates}}function coerceStateValue(raw,type4){if(raw==null)return null;let v=isRecord(raw)&&"data"in raw?raw.data:raw;if(v==null)return null;if(typeof v==="object")return null;if(type4==="int"&&typeof v==="string"&&v.trim()==="")return null;return coerceThreshold(v,type4)}function guardConditionHolds(rawValue,valueType,condition){let actual=coerceStateValue(rawValue,valueType);if(actual===null)return!1;let target2=condition.value;switch(condition.op){case"gt":return actual>target2;case"gte":return actual>=target2;case"lt":return actual<target2;case"lte":return actual<=target2;case"eq":return actual===target2;case"ne":return actual!==target2;default:return!1}}function parseClaimGuardCatalog(entries){if(!entries?.length)return[];let out=[],seen=new Set;for(let e of entries){let parsed=parseGuardCatalogEntry(e);if(parsed&&!seen.has(parsed.action))seen.add(parsed.action),out.push(parsed)}return out}var VALUE_TYPES;var init_evaluate=__esm(()=>{init_types23();VALUE_TYPES=["int","boolean","string"]});async function resolveClaimGuards(db,schemaTables,userId,read,ctx={}){let claimsTable=schemaTables.claims,roleClaimsTable=schemaTables.roleClaims??schemaTables.role_claims,userRolesTable=schemaTables.userRoles??schemaTables.user_roles;if(!claimsTable||!roleClaimsTable||!userRolesTable)return EMPTY;let claimRows=await db.select().from(claimsTable),guardByClaimId=new Map;for(let c of claimRows){if(c.isActive===!1)continue;let policy=parseGuardPolicy(c.policy);if(policy)guardByClaimId.set(String(c.id),{action:String(c.action??""),policy})}if(guardByClaimId.size===0)return EMPTY;let urRows=await db.select().from(userRolesTable),roleIds=new Set(urRows.filter((r2)=>r2.isActive!==!1&&String(r2.userId??r2.user_id)===userId).map((r2)=>String(r2.roleId??r2.role_id)));if(roleIds.size===0)return EMPTY;let rcRows=await db.select().from(roleClaimsTable),guards=[],suppressed=new Set,firedGuards=[],stateCache=new Map;for(let rc of rcRows){if(rc.isActive===!1)continue;if(!roleIds.has(String(rc.roleId??rc.role_id)))continue;let guard4=guardByClaimId.get(String(rc.claimId??rc.claim_id));if(!guard4)continue;let condition=parseGuardCondition(rc.scope,guard4.policy.valueType);if(!condition)continue;let key2=resolveGuardKey(guard4.policy.keyTemplate,{userId,tenant:ctx.tenant}),value2;if(stateCache.has(key2))value2=stateCache.get(key2);else value2=await read(key2).catch(()=>null),stateCache.set(key2,value2);let holds=guardConditionHolds(value2,guard4.policy.valueType,condition),current=normalizeCurrent(value2,guard4.policy.valueType);if(guards.push({action:guard4.action,key:key2,valueType:guard4.policy.valueType,op:condition.op,threshold:condition.value,current,invalidates:condition.invalidates,holds}),holds&&condition.invalidates.length>0){for(let a12 of condition.invalidates)suppressed.add(a12);firedGuards.push({action:guard4.action,key:key2,invalidates:condition.invalidates})}}return{guards,suppressedClaims:[...suppressed],firedGuards}}function normalizeCurrent(raw,type4){if(raw==null)return null;let v=typeof raw==="object"&&raw!==null&&"data"in raw?raw.data:raw;if(v==null)return null;if(type4==="int"){let n2=Number(v);return Number.isFinite(n2)?n2:null}if(type4==="boolean")return v===!0||v==="true"||v===1||v==="1";return String(v)}var EMPTY;var init_resolve=__esm(()=>{init_evaluate();EMPTY={guards:[],suppressedClaims:[],firedGuards:[]}});import{eq as eq59}from"drizzle-orm";async function seedClaimGuards(db,schemaTables,claimGuards,logger2){let claimsTable=schemaTables.claims;if(!claimsTable)return{created:0,updated:0,deactivated:0};let actionCol=claimsTable.action,desired=parseClaimGuardCatalog(claimGuards),desiredByAction=new Map(desired.map((d)=>[d.action,d.policy])),existing=await db.select().from(claimsTable),existingGuardActions=new Set,result={created:0,updated:0,deactivated:0};for(let row of existing){if(!parseGuardPolicy(row.policy))continue;let action=String(row.action??"");existingGuardActions.add(action);let want=desiredByAction.get(action);if(!want){if(row.isActive!==!1)await db.update(claimsTable).set({isActive:!1}).where(eq59(actionCol,action)),result.deactivated++;continue}let current=row.policy;if(JSON.stringify(current)!==JSON.stringify(want)||row.isActive===!1)await db.update(claimsTable).set({policy:want,isActive:!0,path:want.keyTemplate,method:"GUARD"}).where(eq59(actionCol,action)),result.updated++}for(let{action,policy}of desired){if(existingGuardActions.has(action))continue;await db.insert(claimsTable).values({action,description:`ClaimGuard [${policy.valueType}] key=${policy.keyTemplate}`,path:policy.keyTemplate,method:"GUARD",policy,isActive:!0}),result.created++}return logger2?.info?.(`[Authorization] ClaimGuards seeded (created=${result.created}, updated=${result.updated}, deactivated=${result.deactivated})`),result}var init_seed2=__esm(()=>{init_evaluate()});var exports_ClaimGuard={};__export(exports_ClaimGuard,{seedClaimGuards:()=>seedClaimGuards,resolveGuardKey:()=>resolveGuardKey,resolveClaimGuards:()=>resolveClaimGuards,parseGuardPolicy:()=>parseGuardPolicy,parseGuardCondition:()=>parseGuardCondition,parseGuardCatalogEntry:()=>parseGuardCatalogEntry,parseClaimGuardCatalog:()=>parseClaimGuardCatalog,guardConditionHolds:()=>guardConditionHolds,guardActionFromName:()=>guardActionFromName,OPS_BY_TYPE:()=>OPS_BY_TYPE});var init_ClaimGuard=__esm(()=>{init_evaluate();init_resolve();init_seed2();init_types23()});var exports_dbStorage={};__export(exports_dbStorage,{createDbWebAuthnStorage:()=>createDbWebAuthnStorage});import{and as and22,eq as eq60,isNull as isNull4}from"drizzle-orm";function rowToRecord(row){return{id:row.id,userId:row.userId,credentialId:row.credentialId,publicKey:row.publicKey,counter:typeof row.counter==="bigint"?Number(row.counter):Number(row.counter??0),transports:parseTransports(row.transports),deviceType:parseDeviceType(row.deviceType),backedUp:row.backedUp,aaguid:row.aaguid,authenticatorAttachment:row.authenticatorAttachment==="platform"||row.authenticatorAttachment==="cross-platform"?row.authenticatorAttachment:null,nickname:row.nickname,lastUsedAt:row.lastUsedAt,revokedAt:row.revokedAt,createdAt:row.createdAt}}function col17(table,key2){return table[key2]}function createDbWebAuthnStorage(deps){let{db,resolveTable}=deps,credentialsName="webauthnCredentials",challengesName="webauthnChallenges";return{storeChallenge:async(challenge,schemaName)=>{let table=resolveTable("webauthnChallenges",schemaName);if(!table)return;await db.insert(table).values({userId:challenge.userId??null,challenge:challenge.challenge,challengeType:challenge.challengeType,expiresAt:challenge.expiresAt})},consumeChallenge:async(challenge,challengeType,schemaName)=>{let table=resolveTable("webauthnChallenges",schemaName);if(!table)return null;let row=(await db.update(table).set({consumedAt:new Date}).where(and22(eq60(col17(table,"challenge"),challenge),eq60(col17(table,"challengeType"),challengeType),isNull4(col17(table,"consumedAt")))).returning())[0];if(!row)return null;return{challenge:row.challenge,challengeType:row.challengeType,userId:row.userId,expiresAt:row.expiresAt}},listCredentialsByUser:async(userId,schemaName)=>{let table=resolveTable("webauthnCredentials",schemaName);if(!table)return[];return(await db.select().from(table).where(eq60(col17(table,"userId"),userId))).map(rowToRecord)},findCredentialById:async(credentialId,schemaName)=>{let table=resolveTable("webauthnCredentials",schemaName);if(!table)return null;let rows=await db.select().from(table).where(eq60(col17(table,"credentialId"),credentialId)).limit(1);return rows[0]?rowToRecord(rows[0]):null},insertCredential:async(record3,schemaName)=>{let table=resolveTable("webauthnCredentials",schemaName);if(!table)throw Error("webauthn_credentials table not configured");let row=(await db.insert(table).values({userId:record3.userId,credentialId:record3.credentialId,publicKey:record3.publicKey,counter:record3.counter,transports:record3.transports??null,deviceType:record3.deviceType??null,backedUp:record3.backedUp,aaguid:record3.aaguid??null,authenticatorAttachment:record3.authenticatorAttachment??null,nickname:record3.nickname??null}).returning())[0];if(!row)throw Error("Failed to insert webauthn credential");return rowToRecord(row)},updateCredentialCounter:async(credentialId,counter,schemaName)=>{let table=resolveTable("webauthnCredentials",schemaName);if(!table)return;await db.update(table).set({counter,lastUsedAt:new Date}).where(eq60(col17(table,"credentialId"),credentialId))},revokeCredential:async(credentialId,userId,schemaName)=>{let table=resolveTable("webauthnCredentials",schemaName);if(!table)return!1;return(await db.update(table).set({revokedAt:new Date}).where(and22(eq60(col17(table,"credentialId"),credentialId),eq60(col17(table,"userId"),userId))).returning()).length>0},renameCredential:async(credentialId,userId,nickname,schemaName)=>{let table=resolveTable("webauthnCredentials",schemaName);if(!table)return!1;return(await db.update(table).set({nickname}).where(and22(eq60(col17(table,"credentialId"),credentialId),eq60(col17(table,"userId"),userId))).returning()).length>0}}}var init_dbStorage=()=>{};var exports_authorization={};__export(exports_authorization,{createAuthorizationDiscoveryRoutes:()=>createAuthorizationDiscoveryRoutes});import{timingSafeEqual as timingSafeEqual4}from"crypto";import{Elysia as Elysia48}from"elysia";function tokensMatch2(a12,b){let ba=Buffer.from(a12),bb=Buffer.from(b);if(ba.length!==bb.length)return!1;return timingSafeEqual4(ba,bb)}function createAuthorizationDiscoveryRoutes(cfg){let{db,schemaTables,logger:logger2,discovery,readState}=cfg,token=discovery.token||process.env.NUCLEUS_DISCOVERY_TOKEN,claimsTable=schemaTables.claims,manifestAuthorized=(request)=>{if(hasGodminRole(request))return!0;if(token){let presented=request.headers.get("x-discovery-token")??"";return tokensMatch2(presented,token)}return!1},routes=new Elysia48;routes.post("/authorization/discover",async({request,set:set2})=>{if(!hasGodminRole(request))return fail6(set2,403,"Forbidden: endpoint discovery requires godmin");if(!discovery.enabled)return fail6(set2,400,"endpointDiscovery is not enabled");return{success:!0,message:"Discovery completed",data:await runEndpointDiscovery(db,schemaTables,discovery,logger2)}}),routes.get("/authorization/route-manifest",async({request,query,set:set2})=>{if(!manifestAuthorized(request))return fail6(set2,403,"Forbidden: godmin or a valid x-discovery-token required");if(!claimsTable)return fail6(set2,503,"Claims table unavailable");let service=query.service;if(service){let rows=await getRouteManifest(db,claimsTable,service);return{success:!0,data:{service,routes:rows}}}let all={};for(let svc of discovery.services??[])all[svc.id]=await getRouteManifest(db,claimsTable,svc.id);return{success:!0,data:all}}),routes.get("/authorization/role-claims-manifest",async({request,query,set:set2})=>{if(!manifestAuthorized(request))return fail6(set2,403,"Forbidden: godmin or a valid x-discovery-token required");let service=query.service;if(!service)return fail6(set2,400,"service query param required");let map=await getRoleClaimsManifest(db,schemaTables,service);return{success:!0,data:{service,roleClaims:map}}});let authorizeGuardRead=(request,query,set2)=>{let callerId=request.headers.get("x-user-id")??"",isGodmin3=hasGodminRole(request),requested=query.userId;if(requested&&requested!==callerId&&!isGodmin3)return{error:fail6(set2,403,"Forbidden: only godmin can read another user's guards")};let targetUserId=requested&&isGodmin3?requested:callerId;if(!targetUserId)return{error:fail6(set2,401,"Unauthorized: no user context")};return{userId:targetUserId}},guardsHandler=async({request,query,set:set2})=>{let auth=authorizeGuardRead(request,query,set2);if("error"in auth)return auth.error;let tenant=request.headers.get("x-tenant-id")??void 0;if(!readState)return{success:!0,data:{userId:auth.userId,guards:[]}};let{guards}=await resolveClaimGuards(db,schemaTables,auth.userId,readState,{tenant});return{success:!0,data:{userId:auth.userId,guards}}};return routes.get("/authorization/guards",guardsHandler),routes.get("/authorization/quotas",guardsHandler),routes.get("/authorization/suppressed-claims",async({request,query,set:set2})=>{let auth=authorizeGuardRead(request,query,set2);if("error"in auth)return auth.error;if(!readState)return{success:!0,data:{userId:auth.userId,suppressedClaims:[],firedGuards:[]}};let tenant=request.headers.get("x-tenant-id")??void 0,{suppressedClaims,firedGuards}=await resolveClaimGuards(db,schemaTables,auth.userId,readState,{tenant});return{success:!0,data:{userId:auth.userId,suppressedClaims,firedGuards}}}),routes}var fail6=(set2,status,message)=>{return set2.status=status,{success:!1,message,data:null}};var init_authorization=__esm(()=>{init_ClaimGuard();init_seed();init_adminGuard()});var import_reflect_metadata2=__toESM(require_Reflect(),1);import{batch,createStore}from"h-state";import{useEffectEvent}from"react";function createInitialState(endpoints){let state={};for(let key of Object.keys(endpoints))state[key]={isPending:!1,data:null,error:null,code:null};return state}function createApiHook(endpoints,factory){let{useStore}=createStore(createInitialState(endpoints),{_callEndpoint:(store)=>async(endpointKey,options)=>{if(!store[endpointKey])return;batch(()=>{store[endpointKey].isPending=!0,store[endpointKey].error=null});try{let response=await factory(endpointKey,options.payload);if(batch(()=>{if(store[endpointKey].isPending=!1,store[endpointKey].code=response.code??null,response.isSuccess&&response.data!==void 0)store[endpointKey].data=response.data,store[endpointKey].error=null;else store[endpointKey].error=response.errors??null}),response.isSuccess)options.onAfterHandle?.(response.data??response);else options.onErrorHandle?.(response.errors??{message:"Request failed"},response.code)}catch(err){batch(()=>{store[endpointKey].isPending=!1,store[endpointKey].error={message:err instanceof Error?err.message:"Unknown error"}}),options.onErrorHandle?.({message:err instanceof Error?err.message:"Unknown error"},null)}}});return function(){let store=useStore(),callEndpoint=useEffectEvent((endpointKey,options)=>{store._callEndpoint(endpointKey,options)}),actions={};for(let key of Object.keys(endpoints)){let startFn=(options)=>{callEndpoint(key,options)};actions[key]={state:store[key],start:startFn}}return actions}}var system_tables_default={$schema:"../schemas/nucleus.tables.schema.json",tables:[{table_name:"users",feature_set:["authentication"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:[],bulk_endpoints_enabled:!0,columns:[{name:"email",type:"varchar",length:255},{name:"password",type:"varchar",length:255},{name:"verified_at",type:"timestamp"},{name:"email_verification_token",type:"varchar",length:255},{name:"email_verification_token_expires_at",type:"timestamp"},{name:"email_verification_sent_at",type:"timestamp"},{name:"email_verification_attempts",type:"integer",default:0},{name:"last_login_at",type:"timestamp"},{name:"login_count",type:"integer",default:0},{name:"is_locked",type:"boolean",default:!1},{name:"locked_until",type:"timestamp"},{name:"failed_login_attempts",type:"integer",default:0},{name:"is_god",type:"boolean",default:!1},{name:"cohort_id",type:"uuid",references:{table:"user_cohorts",column:"id",onDelete:"set null"}},{name:"email_verified",type:"boolean",default:!1}],indexes:[{columns:["email"],unique:!0},{columns:["email","is_active"]},{columns:["last_login_at"]},{columns:["is_locked","locked_until"]}]},{table_name:"profiles",feature_set:["authentication"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:[],bulk_endpoints_enabled:!0,columns:[{name:"user_id",type:"uuid",notNull:!0,references:{table:"users",column:"id"}},{name:"first_name",type:"varchar",length:100,notNull:!0},{name:"last_name",type:"varchar",length:100,notNull:!0}],indexes:[{columns:["user_id"],unique:!0},{columns:["first_name","last_name"]}]},{table_name:"roles",feature_set:["authentication","authorization"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:[],bulk_endpoints_enabled:!0,columns:[{name:"name",type:"varchar",length:100,notNull:!0},{name:"description",type:"varchar",length:500}],indexes:[{columns:["name"],unique:!0}]},{table_name:"claims",feature_set:["authentication","authorization"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:[],bulk_endpoints_enabled:!0,columns:[{name:"action",type:"varchar",length:100,notNull:!0},{name:"description",type:"varchar",length:500},{name:"path",type:"varchar",length:200,notNull:!0},{name:"method",type:"varchar",length:10,notNull:!0},{name:"policy",type:"jsonb"}],indexes:[{columns:["action"],unique:!0},{columns:["path","method"]}]},{table_name:"user_roles",feature_set:["authentication","authorization"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:[],bulk_endpoints_enabled:!0,columns:[{name:"user_id",type:"uuid",notNull:!0,references:{table:"users",column:"id",onDelete:"cascade"}},{name:"role_id",type:"uuid",notNull:!0,references:{table:"roles",column:"id",onDelete:"cascade"}}],indexes:[{columns:["user_id"]},{columns:["role_id"]}],constraints:{unique:[{name:"unique_user_role",columns:["user_id","role_id"]}]}},{table_name:"role_claims",feature_set:["authentication","authorization"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:[],bulk_endpoints_enabled:!0,columns:[{name:"role_id",type:"uuid",notNull:!0,references:{table:"roles",column:"id",onDelete:"cascade"}},{name:"claim_id",type:"uuid",notNull:!0,references:{table:"claims",column:"id",onDelete:"cascade"}},{name:"scope",type:"text"}],indexes:[{columns:["role_id"]},{columns:["claim_id"]},{columns:["role_id","claim_id","scope"]}]},{table_name:"files",feature_set:["storage"],add_base_columns:!0,is_form_data:!0,available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:[],bulk_endpoints_enabled:!0,columns:[{name:"name",type:"varchar",length:255,notNull:!0},{name:"original_name",type:"varchar",length:255,notNull:!0},{name:"type",type:"varchar",length:50,enumValues:["image","document","video","audio","profile_picture"]},{name:"path",type:"varchar",length:500,notNull:!0},{name:"size",type:"bigint",mode:"number",notNull:!0},{name:"mime_type",type:"varchar",length:100,notNull:!0},{name:"extension",type:"varchar",length:10,notNull:!0},{name:"uploaded_by",type:"uuid",references:{table:"users",column:"id"}}],indexes:[{columns:["type"]},{columns:["uploaded_by"]},{columns:["size"]}]},{table_name:"addresses",feature_set:["authentication"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:[],bulk_endpoints_enabled:!0,columns:[{name:"owner_type",type:"varchar",length:50,notNull:!0,enumValues:["user","company","contact"]},{name:"owner_id",type:"uuid",notNull:!0},{name:"name",type:"varchar",length:100,notNull:!0},{name:"street",type:"varchar",length:255},{name:"city",type:"varchar",length:100},{name:"state",type:"varchar",length:50},{name:"zip",type:"varchar",length:20},{name:"country",type:"varchar",length:50,default:"US"},{name:"latitude",type:"decimal",precision:10,scale:8},{name:"longitude",type:"decimal",precision:11,scale:8},{name:"neighborhood",type:"varchar",length:100},{name:"apartment",type:"varchar",length:50},{name:"province",type:"varchar",length:100},{name:"district",type:"varchar",length:100},{name:"type",type:"varchar",length:50}],indexes:[{columns:["city","state"]},{columns:["latitude","longitude"]},{columns:["type"]},{columns:["owner_type","owner_id"]}]},{table_name:"phones",feature_set:["authentication"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:[],bulk_endpoints_enabled:!0,columns:[{name:"owner_type",type:"varchar",length:50,notNull:!0,enumValues:["user","company","contact"]},{name:"owner_id",type:"uuid",notNull:!0},{name:"name",type:"varchar",length:100,notNull:!0},{name:"type",type:"varchar",length:50,enumValues:["mobile","office","fax"]},{name:"number",type:"varchar",length:20,notNull:!0},{name:"country_code",type:"varchar",length:10,notNull:!0,default:"+1"},{name:"extension",type:"varchar",length:10}],indexes:[{columns:["number"]},{columns:["type"]},{columns:["owner_type","owner_id"]}]},{table_name:"notifications",feature_set:["notification"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:[],columns:[{name:"user_id",type:"uuid",notNull:!0},{name:"title",type:"varchar",length:255,notNull:!0},{name:"body",type:"varchar",length:1000},{name:"entity_name",type:"varchar",length:100},{name:"entity_id",type:"uuid"},{name:"type",type:"varchar",length:50,notNull:!0,default:"system",enumValues:["verification","system","custom"]},{name:"source",type:"varchar",length:100},{name:"is_seen",type:"boolean",notNull:!0,default:!1},{name:"seen_at",type:"timestamptz"}],indexes:[{columns:["user_id","created_at"]},{columns:["is_seen"]},{columns:["type"]},{columns:["user_id","type","is_seen"]}]},{table_name:"tenants",feature_set:["multi-tenant"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["main"],excluded_schemas:[],excluded_methods:[],columns:[{name:"subdomain",type:"varchar",length:100,notNull:!0,unique:!0},{name:"schema_name",type:"varchar",length:100,notNull:!0,unique:!0},{name:"company_id",type:"uuid",notNull:!0},{name:"company_name",type:"varchar",length:255},{name:"god_admin_email",type:"varchar",length:255,notNull:!0},{name:"status",type:"varchar",length:20,notNull:!0,default:"provisioning"},{name:"plan",type:"varchar",length:50,default:"free"},{name:"domain",type:"varchar",length:255},{name:"settings",type:"jsonb",default:"{}"},{name:"trusted_sources",type:"jsonb",default:"[]"},{name:"max_users",type:"integer"},{name:"provisioned_at",type:"timestamptz"},{name:"suspended_at",type:"timestamptz"},{name:"suspended_reason",type:"text"}],indexes:[{columns:["status"]}]},{table_name:"tenant_events",feature_set:["multi-tenant"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["main"],excluded_schemas:[],excluded_methods:["POST","PUT","PATCH","DELETE"],columns:[{name:"tenant_id",type:"uuid",notNull:!0,references:{table:"tenants",column:"id",onDelete:"cascade"}},{name:"event_type",type:"varchar",length:50,notNull:!0},{name:"event_data",type:"jsonb",default:"{}"},{name:"performed_by",type:"varchar",length:255},{name:"ip_address",type:"varchar",length:45}],indexes:[{columns:["tenant_id"]},{columns:["event_type"]}]},{table_name:"tenant_features",feature_set:["multi-tenant"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["main"],excluded_schemas:[],excluded_methods:[],columns:[{name:"tenant_id",type:"uuid",notNull:!0,references:{table:"tenants",column:"id",onDelete:"cascade"}},{name:"feature_name",type:"varchar",length:100,notNull:!0},{name:"enabled",type:"boolean",notNull:!0,default:!0},{name:"config",type:"jsonb",default:"{}"}],indexes:[{columns:["tenant_id","feature_name"],unique:!0},{columns:["feature_name"]}]},{table_name:"domain_hostnames",feature_set:["domains"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["main"],excluded_schemas:[],excluded_methods:["PUT"],group_name:"Domains",columns:[{name:"owner_type",type:"varchar",length:20,notNull:!0,default:"tenant",comment:"tenant | organization | user | external"},{name:"owner_id",type:"uuid",notNull:!0,comment:"Product-defined owner reference (e.g. band id, org id)"},{name:"tenant_id",type:"uuid",references:{table:"tenants",column:"id",onDelete:"cascade"},comment:"Tenant this hostname routes to; null for non-tenant owners"},{name:"schema_name",type:"varchar",length:100,comment:"Resolved tenant schema for routing"},{name:"hostname",type:"varchar",length:255,notNull:!0,comment:"Original hostname as entered by the user"},{name:"normalized_hostname",type:"varchar",length:255,notNull:!0,unique:!0,comment:"Lowercased, punycode, port-stripped hostname used for matching"},{name:"hostname_kind",type:"varchar",length:20,notNull:!0,default:"apex",comment:"platform_subdomain | apex | www | subdomain"},{name:"status",type:"varchar",length:20,notNull:!0,default:"pending_verification",comment:"draft | pending_verification | verifying | active | failed | disabled | archived"},{name:"routing_status",type:"varchar",length:20,notNull:!0,default:"inactive",comment:"inactive | pending | active | failed"},{name:"certificate_status",type:"varchar",length:20,notNull:!0,default:"pending",comment:"not_required | pending | active | failed"},{name:"verification_status",type:"varchar",length:20,notNull:!0,default:"pending",comment:"pending | verified | failed | expired"},{name:"provider",type:"varchar",length:30,notNull:!0,default:"manual_dns",comment:"manual_dns | cloudflare_for_saas | cloudflare_registrar"},{name:"provider_hostname_id",type:"varchar",length:255},{name:"dns_target",type:"varchar",length:255,comment:"CNAME / A target the customer must point at"},{name:"is_primary",type:"boolean",notNull:!0,default:!1},{name:"redirect_to_hostname_id",type:"uuid",comment:"When set, this hostname 301-redirects to another hostname (e.g. apex to www)"},{name:"activated_at",type:"timestamptz"},{name:"disabled_at",type:"timestamptz"},{name:"failure_reason",type:"text"},{name:"metadata",type:"jsonb",default:"{}"}],indexes:[{columns:["tenant_id"]},{columns:["schema_name"]},{columns:["status"]},{columns:["owner_type","owner_id"]},{columns:["provider","provider_hostname_id"]}]},{table_name:"domain_registrations",feature_set:["domains"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["main"],excluded_schemas:[],excluded_methods:["PUT"],group_name:"Domains",columns:[{name:"owner_type",type:"varchar",length:20,notNull:!0,default:"tenant"},{name:"owner_id",type:"uuid",notNull:!0},{name:"tenant_id",type:"uuid",references:{table:"tenants",column:"id",onDelete:"set null"}},{name:"requested_domain",type:"varchar",length:255,notNull:!0},{name:"registered_domain",type:"varchar",length:255},{name:"provider",type:"varchar",length:30,notNull:!0,default:"cloudflare_registrar"},{name:"provider_registration_id",type:"varchar",length:255},{name:"registrant_owner_type",type:"varchar",length:20,notNull:!0,default:"customer",comment:"customer | platform"},{name:"registrant_contact_snapshot",type:"jsonb",default:"{}"},{name:"status",type:"varchar",length:30,notNull:!0,default:"draft",comment:"draft | availability_checked | awaiting_payment | registering | active | failed | transfer_requested | transferred_out | cancelled | expired"},{name:"price_amount",type:"numeric",precision:12,scale:2},{name:"currency",type:"varchar",length:10},{name:"renewal_date",type:"timestamptz"},{name:"auto_renew",type:"boolean",notNull:!0,default:!0},{name:"terms_version",type:"varchar",length:50},{name:"terms_accepted_at",type:"timestamptz"},{name:"failure_reason",type:"text"},{name:"metadata",type:"jsonb",default:"{}"}],indexes:[{columns:["owner_type","owner_id"]},{columns:["tenant_id"]},{columns:["status"]}]},{table_name:"domain_verification_challenges",feature_set:["domains"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["main"],excluded_schemas:[],excluded_methods:["POST","PUT","PATCH","DELETE"],group_name:"Domains",columns:[{name:"domain_hostname_id",type:"uuid",notNull:!0,references:{table:"domainHostnames",column:"id",onDelete:"cascade"}},{name:"challenge_type",type:"varchar",length:30,notNull:!0,default:"ownership_validation",comment:"hostname_validation | certificate_validation | ownership_validation"},{name:"record_type",type:"varchar",length:10,notNull:!0,default:"TXT",comment:"TXT | CNAME | A | AAAA | HTTP"},{name:"record_name",type:"varchar",length:255,notNull:!0},{name:"record_value",type:"text",notNull:!0},{name:"expected_target",type:"varchar",length:255},{name:"status",type:"varchar",length:20,notNull:!0,default:"pending",comment:"pending | verified | failed | expired"},{name:"expires_at",type:"timestamptz"},{name:"verified_at",type:"timestamptz"},{name:"failure_reason",type:"text"},{name:"metadata",type:"jsonb",default:"{}"}],indexes:[{columns:["domain_hostname_id"]},{columns:["status"]}]},{table_name:"domain_provider_records",feature_set:["domains"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["main"],excluded_schemas:[],excluded_methods:["POST","PUT","PATCH","DELETE"],group_name:"Domains",columns:[{name:"domain_hostname_id",type:"uuid",notNull:!0,references:{table:"domainHostnames",column:"id",onDelete:"cascade"}},{name:"provider",type:"varchar",length:30,notNull:!0},{name:"provider_resource_type",type:"varchar",length:30,notNull:!0,comment:"custom_hostname | certificate | validation | zone | dns_record | registration"},{name:"provider_resource_id",type:"varchar",length:255},{name:"provider_status",type:"varchar",length:50},{name:"last_synced_at",type:"timestamptz"},{name:"raw_status",type:"jsonb",default:"{}"},{name:"metadata",type:"jsonb",default:"{}"}],indexes:[{columns:["domain_hostname_id"]},{columns:["provider","provider_resource_id"]}]},{table_name:"domain_events",feature_set:["domains"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["main"],excluded_schemas:[],excluded_methods:["POST","PUT","PATCH","DELETE"],group_name:"Domains",columns:[{name:"domain_hostname_id",type:"uuid",references:{table:"domainHostnames",column:"id",onDelete:"cascade"}},{name:"domain_registration_id",type:"uuid",references:{table:"domainRegistrations",column:"id",onDelete:"cascade"}},{name:"event_type",type:"varchar",length:50,notNull:!0},{name:"actor_type",type:"varchar",length:20},{name:"actor_id",type:"varchar",length:255},{name:"message",type:"text"},{name:"ip_address",type:"varchar",length:45},{name:"metadata",type:"jsonb",default:"{}"}],indexes:[{columns:["domain_hostname_id"]},{columns:["event_type"]}]},{table_name:"verifications",feature_set:["verification"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:[],columns:[{name:"instance_id",type:"uuid",notNull:!0,references:{table:"verificationInstances",column:"id",onDelete:"cascade"}},{name:"requirement_id",type:"uuid",notNull:!0,references:{table:"verificationRequirements",column:"id"}},{name:"verifier_id",type:"uuid",notNull:!0,references:{table:"users",column:"id"}},{name:"signature_id",type:"uuid",references:{table:"files",column:"id"}},{name:"entity_name",type:"varchar",length:100,notNull:!0},{name:"entity_id",type:"uuid",notNull:!0},{name:"step_order",type:"integer",notNull:!0,default:1},{name:"decision",type:"varchar",length:50,notNull:!0,default:"pending",enumValues:["approved","rejected","pending"]},{name:"reason",type:"text"},{name:"diff",type:"jsonb"}],indexes:[{columns:["instance_id"]},{columns:["requirement_id"]},{columns:["verifier_id"]},{columns:["entity_name","entity_id"]},{columns:["entity_name","entity_id","step_order"]},{columns:["decision"]}]},{table_name:"verificationRequirements",feature_set:["verification"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:[],columns:[{name:"instance_id",type:"uuid",notNull:!0,references:{table:"verificationInstances",column:"id",onDelete:"cascade"}},{name:"step_node_id",type:"varchar",length:100,notNull:!0},{name:"verifier_node_id",type:"varchar",length:100,notNull:!0},{name:"entity_name",type:"varchar",length:100,notNull:!0},{name:"entity_id",type:"uuid",notNull:!0},{name:"verifier_type",type:"varchar",length:30,notNull:!0,enumValues:["user","role"]},{name:"verifier_user_id",type:"uuid"},{name:"verifier_role",type:"varchar",length:100},{name:"require_signature",type:"boolean",notNull:!0,default:!1},{name:"all_must_approve",type:"boolean",notNull:!0,default:!1},{name:"step_order",type:"integer",notNull:!0,default:1},{name:"status",type:"varchar",length:30,notNull:!0,default:"pending",enumValues:["pending","approved","rejected"]}],indexes:[{columns:["instance_id"]},{columns:["instance_id","step_order"]},{columns:["entity_name","entity_id"]},{columns:["verifier_user_id"]},{columns:["status"]}]},{table_name:"verificationFlows",feature_set:["authentication","verification"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:[],columns:[{name:"entity_name",type:"varchar",length:100,notNull:!0},{name:"name",type:"varchar",length:255,notNull:!0},{name:"description",type:"text"},{name:"trigger_on",type:"varchar",length:50,notNull:!0,default:"update",enumValues:["create","update","delete","manual"]},{name:"trigger_fields",type:"jsonb"},{name:"is_draft",type:"boolean",notNull:!0,default:!0},{name:"published_at",type:"timestamptz"},{name:"viewport",type:"jsonb"}],indexes:[{columns:["entity_name"]},{columns:["entity_name","trigger_on"]},{columns:["is_draft"]}]},{table_name:"verificationSteps",feature_set:["authentication","verification"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:[],columns:[{name:"flow_id",type:"uuid",notNull:!0,references:{table:"verificationFlows",column:"id",onDelete:"cascade"}},{name:"entity_name",type:"varchar",length:100,notNull:!0},{name:"node_id",type:"varchar",length:100,notNull:!0},{name:"node_type",type:"varchar",length:50,notNull:!0,default:"step",enumValues:["step","verifier","notification"]},{name:"step_order",type:"integer",notNull:!0,default:1},{name:"name",type:"varchar",length:255},{name:"description",type:"text"},{name:"position_x",type:"numeric",notNull:!0,default:0},{name:"position_y",type:"numeric",notNull:!0,default:0},{name:"width",type:"numeric"},{name:"height",type:"numeric"},{name:"style",type:"jsonb"},{name:"data",type:"jsonb"}],indexes:[{columns:["flow_id"]},{columns:["entity_name"]},{columns:["flow_id","node_id"],unique:!0},{columns:["entity_name","step_order"]}]},{table_name:"verificationEdges",feature_set:["authentication","verification"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:[],columns:[{name:"flow_id",type:"uuid",notNull:!0,references:{table:"verificationFlows",column:"id",onDelete:"cascade"}},{name:"edge_id",type:"varchar",length:100,notNull:!0},{name:"source_node_id",type:"varchar",length:100,notNull:!0},{name:"target_node_id",type:"varchar",length:100,notNull:!0},{name:"source_handle",type:"varchar",length:50},{name:"target_handle",type:"varchar",length:50},{name:"edge_type",type:"varchar",length:50,default:"default",enumValues:["default","conditional","success","failure"]},{name:"label",type:"varchar",length:255},{name:"condition",type:"jsonb"},{name:"style",type:"jsonb"},{name:"animated",type:"boolean",default:!1}],indexes:[{columns:["flow_id"]},{columns:["flow_id","edge_id"],unique:!0},{columns:["source_node_id"]},{columns:["target_node_id"]}]},{table_name:"verificationNotificationRules",feature_set:["verification","notification"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:[],columns:[{name:"flow_id",type:"uuid",notNull:!0,references:{table:"verificationFlows",column:"id",onDelete:"cascade"}},{name:"node_id",type:"varchar",length:100,notNull:!0},{name:"trigger",type:"varchar",length:50,notNull:!0,enumValues:["on_flow_started","on_step_reached","on_approved","on_rejected","on_flow_completed"]},{name:"title_template",type:"varchar",length:255},{name:"body_template",type:"text"},{name:"starts_at",type:"timestamptz"},{name:"expires_at",type:"timestamptz"}],indexes:[{columns:["flow_id"]},{columns:["flow_id","node_id"],unique:!0},{columns:["trigger"]}]},{table_name:"verificationNotificationRecipients",feature_set:["verification","notification"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:[],columns:[{name:"rule_id",type:"uuid",notNull:!0,references:{table:"verificationNotificationRules",column:"id",onDelete:"cascade"}},{name:"recipient_type",type:"varchar",length:30,notNull:!0,enumValues:["user","role","all_verifiers","step_verifier","entity_creator"]},{name:"recipient_user_id",type:"uuid"},{name:"recipient_role",type:"varchar",length:100}],indexes:[{columns:["rule_id"]},{columns:["recipient_type"]}]},{table_name:"verificationVerifierConfigs",feature_set:["verification"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:[],columns:[{name:"flow_id",type:"uuid",notNull:!0,references:{table:"verificationFlows",column:"id",onDelete:"cascade"}},{name:"node_id",type:"varchar",length:100,notNull:!0},{name:"verifier_type",type:"varchar",length:30,notNull:!0,enumValues:["user","role"]},{name:"verifier_user_id",type:"uuid"},{name:"verifier_role",type:"varchar",length:100},{name:"require_signature",type:"boolean",notNull:!0,default:!1},{name:"all_must_approve",type:"boolean",notNull:!0,default:!1}],indexes:[{columns:["flow_id"]},{columns:["flow_id","node_id"],unique:!0},{columns:["verifier_type"]}]},{table_name:"verificationInstances",feature_set:["verification"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:[],columns:[{name:"flow_id",type:"uuid",notNull:!0,references:{table:"verificationFlows",column:"id"}},{name:"entity_name",type:"varchar",length:100,notNull:!0},{name:"entity_id",type:"uuid",notNull:!0},{name:"started_by",type:"uuid",references:{table:"users",column:"id"}},{name:"status",type:"varchar",length:30,notNull:!0,default:"active",enumValues:["active","completed","rejected","cancelled"]},{name:"current_step_order",type:"integer",notNull:!0,default:1},{name:"started_at",type:"timestamptz",notNull:!0,defaultRaw:"now()"},{name:"completed_at",type:"timestamptz"}],indexes:[{columns:["flow_id"]},{columns:["entity_name","entity_id"]},{columns:["entity_name","entity_id","status"]},{columns:["status"]},{columns:["started_by"]}]},{table_name:"verificationNotificationChannels",feature_set:["verification","notification"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:[],columns:[{name:"rule_id",type:"uuid",notNull:!0,references:{table:"verificationNotificationRules",column:"id",onDelete:"cascade"}},{name:"channel",type:"varchar",length:30,notNull:!0,enumValues:["portal","email","sms","telegram","webhook"]}],indexes:[{columns:["rule_id"]},{columns:["rule_id","channel"],unique:!0},{columns:["channel"]}]},{table_name:"user_cohorts",feature_set:["authentication"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:[],columns:[{name:"name",type:"varchar",length:255,notNull:!0},{name:"description",type:"text"},{name:"created_by",type:"uuid",references:{table:"users",column:"id",onDelete:"set null"}},{name:"expires_at",type:"timestamptz"},{name:"user_count",type:"integer",notNull:!0,default:0},{name:"metadata",type:"jsonb",default:"{}"}]},{table_name:"user_sessions",feature_set:["authentication"],add_base_columns:!0,is_form_data:!1,group_name:"Authentication",available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:["POST","PUT","PATCH"],columns:[{name:"user_id",type:"uuid",notNull:!0,references:{table:"users",column:"id",onDelete:"cascade"}},{name:"token_hash",type:"varchar",length:255,notNull:!0},{name:"refresh_token_hash",type:"varchar",length:255},{name:"device_fingerprint",type:"varchar",length:255},{name:"device_name",type:"varchar",length:100},{name:"device_type",type:"varchar",length:50,enumValues:["desktop","mobile","tablet","unknown"]},{name:"browser_name",type:"varchar",length:50},{name:"browser_version",type:"varchar",length:20},{name:"os_name",type:"varchar",length:50},{name:"os_version",type:"varchar",length:20},{name:"ip_address",type:"varchar",length:45,notNull:!0},{name:"location_country",type:"varchar",length:100},{name:"location_city",type:"varchar",length:100},{name:"location_coordinates",type:"varchar",length:50},{name:"last_activity_at",type:"timestamptz",notNull:!0,defaultRaw:"now()"},{name:"expires_at",type:"timestamptz",notNull:!0},{name:"revoked_at",type:"timestamptz"},{name:"revoked_reason",type:"varchar",length:100,enumValues:["user_logout","user_revoked","admin_revoked","security_concern","password_changed","expired","replaced"]},{name:"is_current",type:"boolean",notNull:!0,default:!1},{name:"login_method",type:"varchar",length:50,enumValues:["password","oauth_google","oauth_github","oauth_microsoft","magic_link","sso","api_key"]},{name:"remember_me",type:"boolean",notNull:!0,default:!1},{name:"trust_score",type:"integer",default:100},{name:"approval_status",type:"varchar",length:20,default:"approved",enumValues:["approved","pending","rejected"]},{name:"approval_token",type:"varchar",length:64},{name:"approval_requested_at",type:"timestamptz"},{name:"approval_responded_at",type:"timestamptz"}],indexes:[{columns:["user_id"]},{columns:["token_hash"],unique:!0},{columns:["refresh_token_hash"]},{columns:["user_id","is_active"]},{columns:["expires_at"]},{columns:["device_fingerprint"]},{columns:["ip_address"]},{columns:["last_activity_at"]},{columns:["approval_status"]},{columns:["approval_token"]}]},{table_name:"trusted_devices",feature_set:["authentication"],add_base_columns:!0,is_form_data:!1,group_name:"Authentication",available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:["POST","PUT","PATCH"],columns:[{name:"user_id",type:"uuid",notNull:!0,references:{table:"users",column:"id",onDelete:"cascade"}},{name:"token_hash",type:"varchar",length:64,notNull:!0},{name:"status",type:"varchar",length:20,notNull:!0,default:"pending",enumValues:["pending","trusted","revoked"]},{name:"origin_session_id",type:"uuid"},{name:"label",type:"varchar",length:120},{name:"device_fingerprint",type:"varchar",length:255},{name:"first_seen_ip",type:"varchar",length:45},{name:"last_seen_ip",type:"varchar",length:45},{name:"last_seen_at",type:"timestamptz"},{name:"expires_at",type:"timestamptz"},{name:"revoked_at",type:"timestamptz"},{name:"revoked_reason",type:"varchar",length:30,enumValues:["user_revoked","password_reset","logout","admin_revoked","expired","replaced"]}],indexes:[{columns:["token_hash"],unique:!0},{columns:["user_id"]},{columns:["user_id","status"]},{columns:["origin_session_id"]},{columns:["expires_at"]}]},{table_name:"password_reset_tokens",feature_set:["authentication"],add_base_columns:!0,is_form_data:!1,group_name:"Authentication",requires:["email"],available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:["POST","PUT","PATCH","DELETE"],columns:[{name:"user_id",type:"uuid",notNull:!0,references:{table:"users",column:"id",onDelete:"cascade"}},{name:"token_hash",type:"varchar",length:255,notNull:!0},{name:"expires_at",type:"timestamptz",notNull:!0},{name:"used_at",type:"timestamptz"}],indexes:[{columns:["token_hash"],unique:!0},{columns:["user_id"]},{columns:["expires_at"]}]},{table_name:"magic_link_tokens",feature_set:["authentication"],add_base_columns:!0,is_form_data:!1,group_name:"Authentication",requires:["email"],available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:["POST","PUT","PATCH","DELETE"],columns:[{name:"user_id",type:"uuid",notNull:!0,references:{table:"users",column:"id",onDelete:"cascade"}},{name:"email",type:"varchar",length:255,notNull:!0},{name:"token_hash",type:"varchar",length:255,notNull:!0},{name:"expires_at",type:"timestamptz",notNull:!0},{name:"used_at",type:"timestamptz"}],indexes:[{columns:["token_hash"],unique:!0},{columns:["user_id"]},{columns:["email"]},{columns:["expires_at"]}]},{table_name:"webauthn_credentials",feature_set:["authentication"],add_base_columns:!0,is_form_data:!1,group_name:"Authentication",requires:[],available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:["POST","PUT","PATCH","DELETE"],columns:[{name:"user_id",type:"uuid",notNull:!0,references:{table:"users",column:"id",onDelete:"cascade"}},{name:"credential_id",type:"text",notNull:!0},{name:"public_key",type:"text",notNull:!0},{name:"counter",type:"bigint",mode:"number",notNull:!0,defaultValue:0},{name:"transports",type:"jsonb"},{name:"device_type",type:"varchar",length:32},{name:"backed_up",type:"boolean",notNull:!0,defaultValue:!1},{name:"aaguid",type:"varchar",length:64},{name:"authenticator_attachment",type:"varchar",length:32},{name:"nickname",type:"varchar",length:128},{name:"last_used_at",type:"timestamptz"},{name:"revoked_at",type:"timestamptz"}],indexes:[{columns:["credential_id"],unique:!0},{columns:["user_id"]}]},{table_name:"webauthn_challenges",feature_set:["authentication"],add_base_columns:!0,is_form_data:!1,group_name:"Authentication",requires:[],available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:["POST","PUT","PATCH","DELETE","GET"],columns:[{name:"user_id",type:"uuid",references:{table:"users",column:"id",onDelete:"cascade"}},{name:"challenge",type:"text",notNull:!0},{name:"challenge_type",type:"varchar",length:32,notNull:!0},{name:"expires_at",type:"timestamptz",notNull:!0},{name:"consumed_at",type:"timestamptz"}],indexes:[{columns:["challenge"],unique:!0},{columns:["user_id"]},{columns:["expires_at"]}]},{table_name:"audit_logs",feature_set:["audit"],add_base_columns:!1,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:["POST","PUT","DELETE","PATCH","TOGGLE","VERIFICATION"],columns:[{name:"id",type:"uuid",primaryKey:!0,defaultRaw:"gen_random_uuid()"},{name:"entity_id",type:"uuid"},{name:"entity_name",type:"text",notNull:!0},{name:"operation_type",type:"text",notNull:!0},{name:"user_id",type:"uuid"},{name:"ip_address",type:"text"},{name:"user_agent",type:"text"},{name:"summary",type:"text"},{name:"severity",type:"text",default:"info"},{name:"category",type:"text"},{name:"occurrence_count",type:"integer",default:1},{name:"last_occurrence_at",type:"timestamp"},{name:"old_values",type:"jsonb"},{name:"new_values",type:"jsonb"},{name:"created_at",type:"timestamp",notNull:!0,defaultRaw:"now()"},{name:"path",type:"text"},{name:"query",type:"text"}],indexes:[{columns:["entity_id"]},{columns:["entity_name"]},{columns:["user_id"]},{columns:["created_at"]},{columns:["severity"]},{columns:["category"]}]},{table_name:"monitoring_metrics",feature_set:["monitoring"],add_base_columns:!1,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:["POST","PUT","DELETE","PATCH","TOGGLE","VERIFICATION"],columns:[{name:"id",type:"uuid",primaryKey:!0,defaultRaw:"gen_random_uuid()"},{name:"metric_type",type:"text",notNull:!0},{name:"metric_name",type:"text",notNull:!0},{name:"value",type:"doublePrecision",notNull:!0},{name:"tags",type:"jsonb"},{name:"recorded_at",type:"timestamp",notNull:!0}],indexes:[{columns:["metric_type"]},{columns:["metric_name"]},{columns:["recorded_at"]}]},{table_name:"oauth_accounts",feature_set:["authentication"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:[],bulk_endpoints_enabled:!1,columns:[{name:"user_id",type:"uuid",notNull:!0,references:{table:"users",column:"id",onDelete:"cascade"}},{name:"provider",type:"varchar",length:50,notNull:!0,enumValues:["google","github","microsoft","discord","facebook","twitter","apple","custom"]},{name:"provider_account_id",type:"varchar",length:255,notNull:!0},{name:"provider_email",type:"varchar",length:255},{name:"provider_name",type:"varchar",length:255},{name:"provider_avatar_url",type:"text"},{name:"access_token",type:"text"},{name:"refresh_token",type:"text"},{name:"token_expires_at",type:"timestamp"},{name:"scope",type:"text"},{name:"raw_profile",type:"jsonb"},{name:"is_primary",type:"boolean",notNull:!0,default:!1},{name:"last_used_at",type:"timestamp"}],indexes:[{columns:["user_id"]},{columns:["provider","provider_account_id"],unique:!0},{columns:["provider_email"]},{columns:["user_id","provider"]}],constraints:{unique:[{name:"unique_provider_account",columns:["provider","provider_account_id"]}]}},{table_name:"api_keys",feature_set:["authentication"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:["POST","PUT","PATCH"],bulk_endpoints_enabled:!1,columns:[{name:"user_id",type:"uuid",notNull:!0,references:{table:"users",column:"id",onDelete:"cascade"}},{name:"name",type:"varchar",length:255,notNull:!0},{name:"description",type:"text"},{name:"key_hash",type:"varchar",length:255,notNull:!0},{name:"key_preview",type:"varchar",length:20,notNull:!0},{name:"owner_type",type:"varchar",length:30,notNull:!0,default:"personal",enumValues:["personal","application"]},{name:"application_name",type:"varchar",length:255},{name:"allowed_roles",type:"jsonb",notNull:!0,default:"[]"},{name:"allowed_claims",type:"jsonb",notNull:!0,default:"[]"},{name:"allowed_scopes",type:"jsonb",notNull:!0,default:"[]"},{name:"expires_at",type:"timestamptz"},{name:"last_used_at",type:"timestamptz"},{name:"last_used_ip",type:"varchar",length:45},{name:"usage_count",type:"integer",notNull:!0,default:0},{name:"revoked_at",type:"timestamptz"},{name:"revoked_reason",type:"varchar",length:255}],indexes:[{columns:["key_hash"],unique:!0},{columns:["user_id"]},{columns:["user_id","is_active"]},{columns:["owner_type"]},{columns:["expires_at"]},{columns:["last_used_at"]}]},{table_name:"backup_logs",feature_set:["backup"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["main","all"],excluded_schemas:[],excluded_methods:["PUT","PATCH"],columns:[{name:"backup_name",type:"varchar",length:255,notNull:!0},{name:"file_name",type:"varchar",length:500,notNull:!0},{name:"schema_name",type:"varchar",length:100,notNull:!0},{name:"format",type:"varchar",length:20,notNull:!0,default:"json"},{name:"status",type:"varchar",length:20,notNull:!0,default:"pending"},{name:"trigger",type:"varchar",length:20,notNull:!0,default:"manual"},{name:"size_bytes",type:"integer"},{name:"table_count",type:"integer"},{name:"row_count",type:"integer"},{name:"included_tables",type:"jsonb",default:"[]"},{name:"excluded_tables",type:"jsonb",default:"[]"},{name:"error_message",type:"text"},{name:"started_at",type:"timestamp"},{name:"completed_at",type:"timestamp"},{name:"performed_by",type:"varchar",length:255},{name:"cron_expression",type:"varchar",length:100},{name:"retention_days",type:"integer"}],indexes:[{columns:["schema_name"]},{columns:["status"]},{columns:["trigger"]},{columns:["created_at"]}]},{table_name:"payment_transactions",feature_set:["payment"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:["DELETE"],columns:[{name:"user_id",type:"uuid",references:{table:"users",column:"id"}},{name:"order_id",type:"varchar",length:255},{name:"provider",type:"varchar",length:50,notNull:!0},{name:"provider_transaction_id",type:"varchar",length:255},{name:"provider_payment_id",type:"varchar",length:255},{name:"payment_method",type:"varchar",length:50},{name:"amount",type:"numeric",precision:12,scale:2,notNull:!0,default:0},{name:"currency",type:"varchar",length:10,notNull:!0,default:"TRY"},{name:"status",type:"varchar",length:30,notNull:!0,default:"pending",enumValues:["pending","processing","completed","failed","refunded","partially_refunded","cancelled"]},{name:"status_code",type:"integer"},{name:"status_message",type:"text"},{name:"card_last_four",type:"varchar",length:4},{name:"card_type",type:"varchar",length:50},{name:"card_association",type:"varchar",length:50},{name:"installment",type:"integer",default:1},{name:"is_three_d_secure",type:"boolean",default:!1},{name:"provider_response",type:"jsonb",default:"{}"},{name:"metadata",type:"jsonb",default:"{}"},{name:"refunded_amount",type:"numeric",precision:12,scale:2,default:0},{name:"refunded_at",type:"timestamptz"},{name:"completed_at",type:"timestamptz"},{name:"failed_at",type:"timestamptz"},{name:"ip_address",type:"varchar",length:45}],indexes:[{columns:["user_id"]},{columns:["order_id"]},{columns:["provider"]},{columns:["provider_payment_id"]},{columns:["status"]},{columns:["user_id","status"]}]},{table_name:"payment_methods",feature_set:["payment"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:[],columns:[{name:"user_id",type:"uuid",notNull:!0,references:{table:"users",column:"id",onDelete:"cascade"}},{name:"provider",type:"varchar",length:50,notNull:!0},{name:"type",type:"varchar",length:30,notNull:!0,default:"card",enumValues:["card","bank_account","wallet"]},{name:"alias",type:"varchar",length:100},{name:"card_last_four",type:"varchar",length:4},{name:"card_type",type:"varchar",length:50},{name:"card_association",type:"varchar",length:50},{name:"card_family",type:"varchar",length:100},{name:"card_bank_name",type:"varchar",length:100},{name:"provider_card_user_key",type:"varchar",length:255},{name:"provider_card_token",type:"varchar",length:255},{name:"bin_number",type:"varchar",length:8},{name:"is_default",type:"boolean",default:!1},{name:"metadata",type:"jsonb",default:"{}"}],indexes:[{columns:["user_id"]},{columns:["provider"]},{columns:["user_id","is_default"]},{columns:["provider_card_user_key"]}]},{table_name:"payment_webhook_logs",feature_set:["payment"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:["PUT","PATCH","DELETE"],columns:[{name:"provider",type:"varchar",length:50,notNull:!0},{name:"event_type",type:"varchar",length:100,notNull:!0},{name:"provider_payment_id",type:"varchar",length:255},{name:"raw_payload",type:"jsonb",notNull:!0},{name:"processed",type:"boolean",default:!1},{name:"processing_result",type:"jsonb"},{name:"error_message",type:"text"},{name:"ip_address",type:"varchar",length:45},{name:"idempotency_key",type:"varchar",length:255}],indexes:[{columns:["provider"]},{columns:["event_type"]},{columns:["provider_payment_id"]},{columns:["processed"]},{columns:["idempotency_key"],unique:!0}]},{table_name:"payment_sub_merchants",feature_set:["payment"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:[],columns:[{name:"user_id",type:"uuid",references:{table:"users",column:"id"}},{name:"provider",type:"varchar",length:50,notNull:!0},{name:"provider_sub_merchant_key",type:"varchar",length:255},{name:"external_id",type:"varchar",length:255},{name:"type",type:"varchar",length:50,notNull:!0,default:"personal",enumValues:["personal","private_company","limited_or_joint_stock_company"]},{name:"status",type:"varchar",length:30,notNull:!0,default:"pending",enumValues:["pending","active","suspended","rejected"]},{name:"name",type:"varchar",length:255,notNull:!0},{name:"email",type:"varchar",length:255,notNull:!0},{name:"gsm_number",type:"varchar",length:20},{name:"address",type:"text"},{name:"iban",type:"varchar",length:50},{name:"contact_name",type:"varchar",length:100},{name:"contact_surname",type:"varchar",length:100},{name:"identity_number",type:"varchar",length:20},{name:"tax_office",type:"varchar",length:100},{name:"tax_number",type:"varchar",length:20},{name:"legal_company_title",type:"varchar",length:255},{name:"currency",type:"varchar",length:10,default:"TRY"},{name:"commission_rate",type:"numeric",precision:5,scale:2,default:0},{name:"metadata",type:"jsonb",default:"{}"}],indexes:[{columns:["user_id"]},{columns:["provider"]},{columns:["provider_sub_merchant_key"]},{columns:["external_id"]},{columns:["status"]},{columns:["email"]}]},{table_name:"payment_commission_splits",feature_set:["payment"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:["DELETE"],columns:[{name:"transaction_id",type:"uuid",notNull:!0,references:{table:"payment_transactions",column:"id",onDelete:"cascade"}},{name:"sub_merchant_id",type:"uuid",notNull:!0,references:{table:"payment_sub_merchants",column:"id"}},{name:"basket_item_id",type:"varchar",length:255},{name:"item_price",type:"numeric",precision:12,scale:2,notNull:!0,default:0},{name:"sub_merchant_price",type:"numeric",precision:12,scale:2,notNull:!0,default:0},{name:"platform_commission",type:"numeric",precision:12,scale:2,notNull:!0,default:0},{name:"commission_rate",type:"numeric",precision:5,scale:2,default:0},{name:"provider_split_id",type:"varchar",length:255},{name:"currency",type:"varchar",length:10,notNull:!0,default:"TRY"},{name:"status",type:"varchar",length:30,notNull:!0,default:"pending",enumValues:["pending","approved","disapproved","refunded"]},{name:"approved_at",type:"timestamptz"},{name:"disapproved_at",type:"timestamptz"},{name:"metadata",type:"jsonb",default:"{}"}],indexes:[{columns:["transaction_id"]},{columns:["sub_merchant_id"]},{columns:["status"]},{columns:["transaction_id","sub_merchant_id"]},{columns:["provider_split_id"]}]},{table_name:"payment_products",feature_set:["payment"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:[],columns:[{name:"provider",type:"varchar",length:50,notNull:!0},{name:"provider_product_id",type:"varchar",length:255},{name:"name",type:"varchar",length:255,notNull:!0},{name:"description",type:"text"},{name:"type",type:"varchar",length:30,default:"service",enumValues:["service","good"]},{name:"status",type:"varchar",length:30,notNull:!0,default:"active",enumValues:["active","archived","draft"]},{name:"images",type:"jsonb",default:"[]"},{name:"unit_label",type:"varchar",length:50},{name:"url",type:"varchar",length:500},{name:"metadata",type:"jsonb",default:"{}"}],indexes:[{columns:["provider"]},{columns:["provider_product_id"]},{columns:["name"]},{columns:["status"]},{columns:["type"]}]},{table_name:"payment_prices",feature_set:["payment"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:["DELETE"],columns:[{name:"product_id",type:"uuid",notNull:!0,references:{table:"payment_products",column:"id",onDelete:"cascade"}},{name:"provider",type:"varchar",length:50,notNull:!0},{name:"provider_price_id",type:"varchar",length:255},{name:"currency",type:"varchar",length:10,notNull:!0,default:"USD"},{name:"unit_amount",type:"integer",notNull:!0,default:0},{name:"unit_amount_decimal",type:"varchar",length:30},{name:"type",type:"varchar",length:30,notNull:!0,default:"one_time",enumValues:["one_time","recurring"]},{name:"billing_scheme",type:"varchar",length:30,default:"per_unit",enumValues:["per_unit","tiered"]},{name:"nickname",type:"varchar",length:255},{name:"recurring_interval",type:"varchar",length:20,enumValues:["day","week","month","year"]},{name:"recurring_interval_count",type:"integer",default:1},{name:"recurring_usage_type",type:"varchar",length:20,default:"licensed",enumValues:["licensed","metered"]},{name:"recurring_aggregate_usage",type:"varchar",length:30,enumValues:["sum","last_during_period","last_ever","max"]},{name:"transform_quantity_divide_by",type:"integer"},{name:"transform_quantity_round",type:"varchar",length:10,enumValues:["up","down"]},{name:"status",type:"varchar",length:30,notNull:!0,default:"active",enumValues:["active","archived"]},{name:"metadata",type:"jsonb",default:"{}"}],indexes:[{columns:["product_id"]},{columns:["provider"]},{columns:["provider_price_id"]},{columns:["type"]},{columns:["currency"]},{columns:["status"]},{columns:["product_id","status"]}]},{table_name:"payment_customers",feature_set:["payment"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:[],columns:[{name:"user_id",type:"uuid",references:{table:"users",column:"id"}},{name:"provider",type:"varchar",length:50,notNull:!0},{name:"provider_customer_id",type:"varchar",length:255,notNull:!0},{name:"email",type:"varchar",length:255,notNull:!0},{name:"name",type:"varchar",length:255},{name:"phone",type:"varchar",length:50},{name:"description",type:"text"},{name:"address",type:"jsonb",default:"{}"},{name:"tax_id_type",type:"varchar",length:50},{name:"tax_id_value",type:"varchar",length:100},{name:"metadata",type:"jsonb",default:"{}"}],indexes:[{columns:["user_id"]},{columns:["provider"]},{columns:["provider_customer_id"]},{columns:["email"]},{columns:["user_id","provider"],unique:!0}]},{table_name:"payment_subscriptions",feature_set:["payment"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:["DELETE"],columns:[{name:"customer_id",type:"uuid",notNull:!0,references:{table:"payment_customers",column:"id"}},{name:"provider",type:"varchar",length:50,notNull:!0},{name:"provider_subscription_id",type:"varchar",length:255},{name:"status",type:"varchar",length:30,notNull:!0,default:"incomplete",enumValues:["active","past_due","unpaid","canceled","incomplete","incomplete_expired","trialing","paused"]},{name:"collection_method",type:"varchar",length:30,default:"charge_automatically",enumValues:["charge_automatically","send_invoice"]},{name:"current_period_start",type:"timestamptz"},{name:"current_period_end",type:"timestamptz"},{name:"cancel_at_period_end",type:"boolean",default:!1},{name:"canceled_at",type:"timestamptz"},{name:"trial_start",type:"timestamptz"},{name:"trial_end",type:"timestamptz"},{name:"items",type:"jsonb",default:"[]"},{name:"metadata",type:"jsonb",default:"{}"}],indexes:[{columns:["customer_id"]},{columns:["provider"]},{columns:["provider_subscription_id"]},{columns:["status"]},{columns:["customer_id","status"]}]},{table_name:"payment_invoices",feature_set:["payment"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:["DELETE"],columns:[{name:"customer_id",type:"uuid",notNull:!0,references:{table:"payment_customers",column:"id"}},{name:"subscription_id",type:"uuid",references:{table:"payment_subscriptions",column:"id"}},{name:"provider",type:"varchar",length:50,notNull:!0},{name:"provider_invoice_id",type:"varchar",length:255},{name:"status",type:"varchar",length:30,notNull:!0,default:"draft",enumValues:["draft","open","paid","uncollectible","void"]},{name:"collection_method",type:"varchar",length:30,default:"charge_automatically",enumValues:["charge_automatically","send_invoice"]},{name:"currency",type:"varchar",length:10,notNull:!0,default:"USD"},{name:"amount_due",type:"integer",default:0},{name:"amount_paid",type:"integer",default:0},{name:"amount_remaining",type:"integer",default:0},{name:"description",type:"text"},{name:"hosted_invoice_url",type:"varchar",length:1000},{name:"invoice_pdf",type:"varchar",length:1000},{name:"due_date",type:"timestamptz"},{name:"days_until_due",type:"integer"},{name:"period_start",type:"timestamptz"},{name:"period_end",type:"timestamptz"},{name:"paid_at",type:"timestamptz"},{name:"voided_at",type:"timestamptz"},{name:"lines",type:"jsonb",default:"[]"},{name:"metadata",type:"jsonb",default:"{}"}],indexes:[{columns:["customer_id"]},{columns:["subscription_id"]},{columns:["provider"]},{columns:["provider_invoice_id"]},{columns:["status"]},{columns:["customer_id","status"]}]},{table_name:"chat_conversations",feature_set:["authentication","chat"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:[],columns:[{name:"type",type:"varchar",length:20,notNull:!0,default:"direct",enumValues:["direct","group"]},{name:"title",type:"varchar",length:255},{name:"description",type:"text"},{name:"avatar_file_id",type:"uuid"},{name:"direct_key",type:"varchar",length:255},{name:"last_message_at",type:"timestamptz"},{name:"last_message_preview",type:"varchar",length:500},{name:"last_message_sender_id",type:"uuid",references:{table:"users",column:"id",onDelete:"set null"}}],indexes:[{columns:["direct_key"],unique:!0},{columns:["type"]},{columns:["last_message_at"]}]},{table_name:"chat_participants",feature_set:["authentication","chat"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:[],columns:[{name:"conversation_id",type:"uuid",notNull:!0,references:{table:"chat_conversations",column:"id",onDelete:"cascade"}},{name:"user_id",type:"uuid",notNull:!0,references:{table:"users",column:"id",onDelete:"cascade"}},{name:"role",type:"varchar",length:20,notNull:!0,default:"member",enumValues:["member","admin","owner"]},{name:"last_read_message_id",type:"uuid"},{name:"last_read_at",type:"timestamptz"},{name:"unread_count",type:"integer",notNull:!0,default:0},{name:"muted",type:"boolean",notNull:!0,default:!1},{name:"muted_until",type:"timestamptz"},{name:"notifications_enabled",type:"boolean",notNull:!0,default:!0},{name:"left_at",type:"timestamptz"}],indexes:[{columns:["user_id"]},{columns:["conversation_id"]}],constraints:{unique:[{name:"unique_conversation_participant",columns:["conversation_id","user_id"]}]}},{table_name:"chat_messages",feature_set:["authentication","chat"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:[],columns:[{name:"conversation_id",type:"uuid",notNull:!0,references:{table:"chat_conversations",column:"id",onDelete:"cascade"}},{name:"sender_id",type:"uuid",references:{table:"users",column:"id",onDelete:"set null"}},{name:"content",type:"text"},{name:"content_type",type:"varchar",length:20,notNull:!0,default:"text",enumValues:["text","image","file","video","audio","system"]},{name:"reply_to_id",type:"uuid",references:{table:"chat_messages",column:"id",onDelete:"set null"}},{name:"metadata",type:"jsonb",default:"{}"},{name:"client_message_id",type:"varchar",length:100},{name:"edited_at",type:"timestamptz"},{name:"deleted_at",type:"timestamptz"}],indexes:[{columns:["conversation_id","created_at"]},{columns:["sender_id"]},{columns:["reply_to_id"]}]},{table_name:"chat_message_attachments",feature_set:["authentication","chat","storage"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:[],columns:[{name:"message_id",type:"uuid",notNull:!0,references:{table:"chat_messages",column:"id",onDelete:"cascade"}},{name:"conversation_id",type:"uuid",notNull:!0,references:{table:"chat_conversations",column:"id",onDelete:"cascade"}},{name:"file_id",type:"uuid",notNull:!0,references:{table:"files",column:"id",onDelete:"cascade"}},{name:"kind",type:"varchar",length:20,notNull:!0,default:"file",enumValues:["image","video","audio","file"]},{name:"original_name",type:"varchar",length:255},{name:"mime_type",type:"varchar",length:100},{name:"size",type:"bigint",mode:"number"},{name:"width",type:"integer"},{name:"height",type:"integer"},{name:"duration",type:"integer"}],indexes:[{columns:["message_id"]},{columns:["conversation_id"]},{columns:["file_id"]}]},{table_name:"payment_splits",feature_set:["payment"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:["POST","PUT","PATCH","DELETE"],group_name:"Payments Marketplace",columns:[{name:"transaction_id",type:"uuid",references:{table:"paymentTransactions",column:"id",onDelete:"set null"}},{name:"recipient_owner_type",type:"varchar",length:20,notNull:!0,default:"seller",comment:"seller | platform | tenant | user"},{name:"recipient_owner_id",type:"uuid",notNull:!0},{name:"provider",type:"varchar",length:50,notNull:!0},{name:"gross_amount",type:"bigint",mode:"number",notNull:!0,comment:"Minor units"},{name:"provider_fee_amount",type:"bigint",mode:"number",notNull:!0,default:0},{name:"platform_fee_amount",type:"bigint",mode:"number",notNull:!0,default:0},{name:"reserve_amount",type:"bigint",mode:"number",notNull:!0,default:0},{name:"net_payable_amount",type:"bigint",mode:"number",notNull:!0},{name:"currency",type:"varchar",length:10,notNull:!0},{name:"available_for_payout_at",type:"timestamptz"},{name:"status",type:"varchar",length:20,notNull:!0,default:"pending",comment:"pending | available | payout_requested | paid | held | refunded | disputed | cancelled"},{name:"source_type",type:"varchar",length:50},{name:"source_id",type:"varchar",length:255},{name:"metadata",type:"jsonb",default:"{}"}],indexes:[{columns:["recipient_owner_type","recipient_owner_id"]},{columns:["status"]},{columns:["transaction_id"]}]},{table_name:"payment_ledger_entries",feature_set:["payment"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:["POST","PUT","PATCH","DELETE"],group_name:"Payments Marketplace",columns:[{name:"account",type:"varchar",length:40,notNull:!0,comment:"platform_revenue | provider_fee | seller_payable | reserve | refund_liability | dispute_liability | payout_in_transit | payout_completed"},{name:"owner_type",type:"varchar",length:20},{name:"owner_id",type:"uuid"},{name:"direction",type:"varchar",length:6,notNull:!0,comment:"debit | credit"},{name:"amount",type:"bigint",mode:"number",notNull:!0,comment:"Minor units"},{name:"currency",type:"varchar",length:10,notNull:!0},{name:"entry_type",type:"varchar",length:40,notNull:!0,comment:"split | refund | payout | reserve_hold | reserve_release | dispute | adjustment"},{name:"reference_type",type:"varchar",length:50},{name:"reference_id",type:"varchar",length:255},{name:"split_id",type:"uuid",references:{table:"paymentSplits",column:"id",onDelete:"set null"}},{name:"description",type:"text"},{name:"metadata",type:"jsonb",default:"{}"}],indexes:[{columns:["account"]},{columns:["owner_type","owner_id"]},{columns:["entry_type"]},{columns:["reference_type","reference_id"]}]},{table_name:"payment_settlement_policies",feature_set:["payment"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:[],group_name:"Payments Marketplace",columns:[{name:"owner_type",type:"varchar",length:20,notNull:!0,default:"tenant",comment:"tenant | seller"},{name:"owner_id",type:"uuid",notNull:!0},{name:"default_delay_days",type:"integer",notNull:!0,default:7},{name:"new_seller_delay_days",type:"integer",notNull:!0,default:14},{name:"reserve_rate",type:"numeric",precision:5,scale:4,notNull:!0,default:0,comment:"Fraction 0..1 held as reserve"},{name:"reserve_days",type:"integer",notNull:!0,default:0},{name:"minimum_payout_amount",type:"bigint",mode:"number",notNull:!0,default:0},{name:"currency",type:"varchar",length:10},{name:"early_payout_enabled",type:"boolean",notNull:!0,default:!1},{name:"status",type:"varchar",length:20,notNull:!0,default:"active"},{name:"metadata",type:"jsonb",default:"{}"}],indexes:[{columns:["owner_type","owner_id"],unique:!0}]},{table_name:"payment_reserves",feature_set:["payment"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:["POST","PUT","PATCH","DELETE"],group_name:"Payments Marketplace",columns:[{name:"owner_type",type:"varchar",length:20,notNull:!0,default:"seller"},{name:"owner_id",type:"uuid",notNull:!0},{name:"split_id",type:"uuid",references:{table:"paymentSplits",column:"id",onDelete:"set null"}},{name:"amount",type:"bigint",mode:"number",notNull:!0},{name:"currency",type:"varchar",length:10,notNull:!0},{name:"reason",type:"varchar",length:30,notNull:!0,default:"refund_window",comment:"refund_window | chargeback_risk | new_seller | manual_hold | dispute | compliance_review"},{name:"status",type:"varchar",length:20,notNull:!0,default:"held",comment:"held | released | consumed | cancelled"},{name:"release_at",type:"timestamptz"},{name:"released_at",type:"timestamptz"},{name:"metadata",type:"jsonb",default:"{}"}],indexes:[{columns:["owner_type","owner_id"]},{columns:["status"]},{columns:["release_at"]}]},{table_name:"payment_payout_requests",feature_set:["payment"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:["PUT"],group_name:"Payments Marketplace",columns:[{name:"recipient_owner_type",type:"varchar",length:20,notNull:!0,default:"seller"},{name:"recipient_owner_id",type:"uuid",notNull:!0},{name:"amount",type:"bigint",mode:"number",notNull:!0},{name:"currency",type:"varchar",length:10,notNull:!0},{name:"status",type:"varchar",length:20,notNull:!0,default:"pending",comment:"pending | approved | rejected | processing | completed | failed | cancelled"},{name:"provider",type:"varchar",length:50},{name:"provider_payout_id",type:"varchar",length:255},{name:"provider_transfer_id",type:"varchar",length:255},{name:"destination",type:"varchar",length:255},{name:"requested_by",type:"uuid"},{name:"decided_by",type:"uuid"},{name:"decided_at",type:"timestamptz"},{name:"completed_at",type:"timestamptz"},{name:"failure_reason",type:"text"},{name:"metadata",type:"jsonb",default:"{}"}],indexes:[{columns:["recipient_owner_type","recipient_owner_id"]},{columns:["status"]}]},{table_name:"payment_disputes",feature_set:["payment"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:["PUT"],group_name:"Payments Marketplace",columns:[{name:"transaction_id",type:"uuid",references:{table:"paymentTransactions",column:"id",onDelete:"set null"}},{name:"provider",type:"varchar",length:50,notNull:!0},{name:"provider_dispute_id",type:"varchar",length:255},{name:"owner_type",type:"varchar",length:20},{name:"owner_id",type:"uuid"},{name:"amount",type:"bigint",mode:"number"},{name:"currency",type:"varchar",length:10},{name:"reason",type:"varchar",length:100},{name:"status",type:"varchar",length:30,notNull:!0,default:"open",comment:"open | under_review | won | lost | accepted | cancelled"},{name:"evidence_due_at",type:"timestamptz"},{name:"resolved_at",type:"timestamptz"},{name:"metadata",type:"jsonb",default:"{}"}],indexes:[{columns:["provider","provider_dispute_id"]},{columns:["status"]},{columns:["owner_type","owner_id"]},{columns:["transaction_id"]}]},{table_name:"nucleus_secrets",feature_set:["secrets"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:["GET","POST","PUT","PATCH","DELETE","TOGGLE"],bulk_endpoints_enabled:!1,group_name:"Secrets",columns:[{name:"scope",type:"varchar",length:200,notNull:!0,comment:"Config dot-path that owns the credential, e.g. authentication.oauth.providers.microsoft"},{name:"key",type:"varchar",length:120,notNull:!0,comment:"Leaf key under that path, e.g. clientSecret"},{name:"value_enc",type:"text",notNull:!0,comment:"AES-256-GCM envelope v1:iv:tag:ciphertext \u2014 never returned by any route"},{name:"previous_enc",type:"text",comment:"Value replaced by the last rotation, retained for one-step rollback"},{name:"preview",type:"varchar",length:80},{name:"kind",type:"varchar",length:30,notNull:!0,default:"text",enumValues:["text","password","json","connection_string","pem"]},{name:"description",type:"varchar",length:500},{name:"version",type:"integer",notNull:!0,default:1},{name:"rotated_at",type:"timestamptz"},{name:"last_used_at",type:"timestamptz"}],indexes:[{columns:["scope","key"],unique:!0},{columns:["scope"]}]},{table_name:"integration_sources",feature_set:["integrations"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:[],bulk_endpoints_enabled:!1,group_name:"Integrations",columns:[{name:"name",type:"varchar",length:150,notNull:!0},{name:"slug",type:"varchar",length:150,notNull:!0,comment:"Stable machine name; referenced by exports and by operators in logs"},{name:"base_url",type:"varchar",length:500,notNull:!0,comment:"Any scheme, host and port \u2014 https, plain http, in-cluster DNS, IP. HTTPS is NOT required and must never be enforced: reaching a service inside the same cluster over http is a legitimate deployment."},{name:"description",type:"text"},{name:"enabled",type:"boolean",default:!0},{name:"auth_type",type:"varchar",length:20,notNull:!0,default:"none",enumValues:["none","bearer","api_key","basic","oauth2"]},{name:"auth_token_encrypted",type:"text",sensitive:!0,comment:"Static credential (bearer / api key / basic blob), encrypted at rest"},{name:"auth_token_hint",type:"varchar",length:24},{name:"auth_header_name",type:"varchar",length:80,default:"Authorization"},{name:"auth_query_param",type:"varchar",length:80,comment:"When set, an api_key credential travels as this query parameter instead of a header"},{name:"extra_headers",type:"jsonb",default:{}},{name:"token_url",type:"varchar",length:500},{name:"oauth_grant_type",type:"varchar",length:40,default:"password",enumValues:["password","client_credentials"]},{name:"oauth_client_id",type:"varchar",length:200},{name:"oauth_client_secret_encrypted",type:"text",sensitive:!0},{name:"oauth_client_secret_hint",type:"varchar",length:24},{name:"oauth_username",type:"varchar",length:200},{name:"oauth_password_encrypted",type:"text",sensitive:!0},{name:"oauth_password_hint",type:"varchar",length:24},{name:"oauth_scope",type:"varchar",length:300},{name:"oauth_client_auth",type:"varchar",length:20,default:"basic",enumValues:["basic","body"]},{name:"tls_verify",type:"boolean",notNull:!0,default:!0,comment:"Per-source certificate verification. Turning it off applies to THIS source's connections only \u2014 never to the process, which is what a NODE_TLS_REJECT_UNAUTHORIZED toggle would do."},{name:"timeout_ms",type:"integer",notNull:!0,default:30000},{name:"spec_url",type:"varchar",length:500,comment:"Optional API description document (OpenAPI/Swagger/Postman/Bruno). Discovery is a convenience: every endpoint can always be defined by hand instead."},{name:"spec_format",type:"varchar",length:20,default:"manual",enumValues:["manual","openapi","swagger","postman","bruno","har"]}],constraints:{unique:[{name:"uniq_integration_source_slug",columns:["slug"]}]},indexes:[{columns:["enabled"]}]},{table_name:"integration_endpoints",feature_set:["integrations"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:[],bulk_endpoints_enabled:!1,group_name:"Integrations",columns:[{name:"source_id",type:"uuid",notNull:!0,references:{table:"integrationSources",column:"id",onDelete:"cascade"}},{name:"tag",type:"varchar",length:120,notNull:!0},{name:"name",type:"varchar",length:200},{name:"method",type:"varchar",length:10,notNull:!0,default:"GET",enumValues:["GET","POST","PUT","PATCH","DELETE"]},{name:"path",type:"varchar",length:500,notNull:!0,comment:"Appended to the source base URL. May carry {brace} or :colon path tokens, whose values come from param_bindings."},{name:"description",type:"text"},{name:"query_params",type:"jsonb",default:{}},{name:"request_body",type:"jsonb",default:{}},{name:"param_bindings",type:"jsonb",default:[],comment:"Where each path/query parameter comes from: a static value, another endpoint's records (fan-out), or a column of one of our own tables."},{name:"pagination",type:"jsonb",default:{},comment:"Explicitly chosen paging profile (none/page_number/offset/cursor/link_header). Never guessed \u2014 a wrong guess silently imports one page."},{name:"response_root_path",type:"varchar",length:200},{name:"tree_children_path",type:"varchar",length:200,comment:"Field holding a record's children when the source answers with a shape rather than a list \u2014 each node then becomes its own row and knows its parent"},{name:"sample_response",type:"jsonb",default:{},comment:"A few real records captured by a live test, so the mapping screen still shows fields when the source is unreachable"},{name:"enabled",type:"boolean",default:!0}],indexes:[{columns:["source_id"]},{columns:["source_id","tag"]}]},{table_name:"integration_mappings",feature_set:["integrations"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:[],bulk_endpoints_enabled:!1,group_name:"Integrations",columns:[{name:"endpoint_id",type:"uuid",notNull:!0,references:{table:"integrationEndpoints",column:"id",onDelete:"cascade"}},{name:"name",type:"varchar",length:200,notNull:!0},{name:"target_entity",type:"varchar",length:120,notNull:!0,comment:"snake_case table name this mapping writes into"},{name:"field_mappings",type:"jsonb",notNull:!0,default:[]},{name:"reference_checks",type:"jsonb",notNull:!0,default:[],comment:"Columns whose value must already exist in another entity, and what to do when it does not."},{name:"dedup_source_field",type:"varchar",length:200},{name:"dedup_target_field",type:"varchar",length:200,comment:"Target column that identifies the same record across runs. Without it nothing can be matched and every run appends."},{name:"write_mode",type:"varchar",length:20,notNull:!0,default:"upsert",enumValues:["upsert","append","replace"],comment:"replace is the destructive wipe-and-rewrite; it is no longer the default and is gated by the completeness check."},{name:"missing_record_policy",type:"varchar",length:20,notNull:!0,default:"ignore",enumValues:["ignore","deactivate","delete"],comment:"What happens to a row that exists here but no longer in the source. deactivate is the right answer for most HR data and could not be expressed before."},{name:"missing_record_column",type:"varchar",length:120},{name:"missing_record_value",type:"varchar",length:200},{name:"password_target_column",type:"varchar",length:100,comment:"Column that receives the shared opening password given at run time. The password itself is never stored."},{name:"account_rule",type:"jsonb",comment:"Creates a login alongside each imported record, in the same transaction, and links it. The password belongs to the run, never to this row."},{name:"schedule_cron",type:"varchar",length:120},{name:"schedule_timezone",type:"varchar",length:64,comment:"IANA zone the cron expression is read in. Without it a nightly job drifts with the container's clock."},{name:"schedule_enabled",type:"boolean",notNull:!0,default:!1},{name:"last_run_at",type:"timestamptz"},{name:"enabled",type:"boolean",default:!0}],indexes:[{columns:["endpoint_id"]},{columns:["target_entity"]},{columns:["schedule_enabled"]}]},{table_name:"integration_runs",feature_set:["integrations"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:["POST","PUT","PATCH","DELETE"],bulk_endpoints_enabled:!1,group_name:"Integrations",columns:[{name:"mapping_id",type:"uuid",references:{table:"integrationMappings",column:"id",onDelete:"set null"},comment:"Nullable and NOT cascaded: deleting a mapping must not erase the record that it once rewrote a table."},{name:"target_entity",type:"varchar",length:120},{name:"write_mode",type:"varchar",length:20,enumValues:["upsert","append","replace"]},{name:"status",type:"varchar",length:20,notNull:!0,default:"queued",enumValues:["queued","running","succeeded","failed","cancelled","reverted"],comment:"There is deliberately no 'partial': a run either applied in full or not at all."},{name:"trigger",type:"varchar",length:20,notNull:!0,default:"manual",enumValues:["manual","schedule","api"]},{name:"total_fetched",type:"integer",notNull:!0,default:0},{name:"source_reported_total",type:"integer",comment:"What the source said it had. When this and total_fetched disagree, a destructive run refuses to start."},{name:"created_count",type:"integer",notNull:!0,default:0},{name:"references_created_count",type:"integer",notNull:!0,default:0,comment:"Rows this run added to OTHER tables so its records could point at them."},{name:"accounts_created_count",type:"integer",notNull:!0,default:0,comment:"Logins this run created so its records could be signed in to."},{name:"updated_count",type:"integer",notNull:!0,default:0},{name:"skipped_count",type:"integer",notNull:!0,default:0},{name:"deleted_count",type:"integer",notNull:!0,default:0},{name:"deactivated_count",type:"integer",notNull:!0,default:0},{name:"error_count",type:"integer",notNull:!0,default:0},{name:"external_call_count",type:"integer",notNull:!0,default:0},{name:"issues",type:"jsonb",default:[]},{name:"errors",type:"jsonb",default:[]},{name:"cancel_requested",type:"boolean",notNull:!0,default:!1,comment:"Set by the cancel endpoint; the engine checks it at every batch boundary. A dropped HTTP connection is NOT a cancellation."},{name:"started_at",type:"timestamptz"},{name:"finished_at",type:"timestamptz"},{name:"pre_images_expire_at",type:"timestamptz",comment:"After this, the run can no longer be reverted and the UI says so rather than offering a button that quietly does nothing."},{name:"reverted_at",type:"timestamptz"},{name:"reverted_by",type:"uuid",references:{table:"users",column:"id"}},{name:"reverted_run_id",type:"uuid"}],indexes:[{columns:["mapping_id"]},{columns:["status"]},{columns:["target_entity"]},{columns:["created_at"]}]},{table_name:"integration_run_items",feature_set:["integrations"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:["POST","PUT","PATCH","DELETE"],bulk_endpoints_enabled:!1,group_name:"Integrations",columns:[{name:"run_id",type:"uuid",notNull:!0,references:{table:"integrationRuns",column:"id",onDelete:"cascade"}},{name:"target_entity",type:"varchar",length:120,notNull:!0},{name:"row_id",type:"uuid"},{name:"action",type:"varchar",length:20,notNull:!0,enumValues:["create","update","delete","deactivate"]},{name:"before",type:"jsonb",comment:"The row as it stood before this run touched it. This is what makes a successful run reversible; the bulk delete path already produced these rows and threw them away."},{name:"after",type:"jsonb"}],indexes:[{columns:["run_id"]},{columns:["run_id","action"]},{columns:["target_entity","row_id"]}]}]};var AUTH_ENDPOINT_CONFIGS={login:{key:"LOGIN",method:"POST",defaultRoute:"/auth/login",defaultIsPublic:!0,_payload:void 0,_success:void 0,_error:void 0},register:{key:"REGISTER",method:"POST",defaultRoute:"/auth/register",defaultIsPublic:!0,_payload:void 0,_success:void 0,_error:void 0},logout:{key:"LOGOUT",method:"POST",defaultRoute:"/auth/logout",defaultIsPublic:!1,_payload:void 0,_success:void 0,_error:void 0},refresh:{key:"REFRESH",method:"POST",defaultRoute:"/auth/refresh",defaultIsPublic:!1,_payload:void 0,_success:void 0,_error:void 0},me:{key:"ME",method:"GET",defaultRoute:"/auth/me",defaultIsPublic:!1,_payload:void 0,_success:void 0,_error:void 0},passwordChange:{key:"PASSWORD_CHANGE",method:"POST",defaultRoute:"/auth/password-change",defaultIsPublic:!1,_payload:void 0,_success:void 0,_error:void 0},passwordSet:{key:"PASSWORD_SET",method:"POST",defaultRoute:"/auth/password-set",defaultIsPublic:!1,_payload:void 0,_success:void 0,_error:void 0},passwordReset:{key:"PASSWORD_RESET_REQUEST",method:"POST",defaultRoute:"/auth/password-reset",defaultIsPublic:!0,subEndpoints:[{key:"PASSWORD_RESET_REQUEST",method:"POST",suffix:"/request",_payload:void 0,_success:void 0,_error:void 0},{key:"PASSWORD_RESET_CONFIRM",method:"POST",suffix:"/confirm",_payload:void 0,_success:void 0,_error:void 0}]},sessions:{key:"SESSIONS",method:"GET",defaultRoute:"/auth/sessions",defaultIsPublic:!1,subEndpoints:[{key:"SESSIONS",method:"GET",suffix:"",_payload:void 0,_success:void 0,_error:void 0},{key:"SESSIONS_CURRENT",method:"GET",suffix:"/current",_payload:void 0,_success:void 0,_error:void 0},{key:"SESSIONS_STATS",method:"GET",suffix:"/stats",_payload:void 0,_success:void 0,_error:void 0},{key:"SESSIONS_PENDING",method:"GET",suffix:"/pending",_payload:void 0,_success:void 0,_error:void 0},{key:"SESSIONS_REVOKE",method:"DELETE",suffix:"/:sessionId",_payload:void 0,_success:void 0,_error:void 0},{key:"SESSIONS_REVOKE_ALL",method:"DELETE",suffix:"/all",_payload:void 0,_success:void 0,_error:void 0},{key:"SESSIONS_ADMIN_LIST",method:"GET",suffix:"/admin/:userId",_payload:void 0,_success:void 0,_error:void 0},{key:"SESSIONS_ADMIN_REVOKE",method:"DELETE",suffix:"/admin/:userId",_payload:void 0,_success:void 0,_error:void 0},{key:"SESSIONS_APPROVE",method:"POST",suffix:"/approve",_payload:void 0,_success:void 0,_error:void 0},{key:"SESSIONS_REJECT",method:"POST",suffix:"/reject",_payload:void 0,_success:void 0,_error:void 0}]},magicLink:{key:"MAGIC_LINK",method:"POST",defaultRoute:"/auth/magic-link",defaultIsPublic:!0,subEndpoints:[{key:"MAGIC_LINK",method:"POST",suffix:"",_payload:void 0,_success:void 0,_error:void 0},{key:"MAGIC_LINK_VERIFY",method:"GET",suffix:"/verify",routeKey:"verifyRoute",_payload:void 0,_success:void 0,_error:void 0}]},invite:{key:"INVITE",method:"POST",defaultRoute:"/auth/invite",defaultIsPublic:!1,subEndpoints:[{key:"INVITE",method:"POST",suffix:"",_payload:void 0,_success:void 0,_error:void 0},{key:"INVITE_VERIFY",method:"POST",suffix:"/verify",_payload:void 0,_success:void 0,_error:void 0}]},emailVerification:{key:"VERIFY_EMAIL",method:"GET",defaultRoute:"/verify-email",defaultIsPublic:!0,subEndpoints:[{key:"VERIFY_EMAIL",method:"GET",suffix:"",_payload:void 0,_success:void 0,_error:void 0},{key:"RESEND_VERIFICATION",method:"POST",suffix:"",routeKey:"resendRoute",defaultRoute:"/resend-verification",_payload:void 0,_success:void 0,_error:void 0}]},captcha:{key:"CAPTCHA",method:"GET",defaultRoute:"/auth/captcha",defaultIsPublic:!0,subEndpoints:[{key:"CAPTCHA_GENERATE",method:"GET",suffix:"/generate",_payload:void 0,_success:void 0,_error:void 0},{key:"CAPTCHA_VALIDATE",method:"POST",suffix:"/validate",_payload:void 0,_success:void 0,_error:void 0}]},oauth:{key:"OAUTH_PROVIDERS",method:"GET",defaultRoute:"/auth/oauth/providers",defaultIsPublic:!0,subEndpoints:[{key:"OAUTH_PROVIDERS",method:"GET",suffix:"/providers",_payload:void 0,_success:void 0,_error:void 0},{key:"OAUTH_REDIRECT",method:"GET",suffix:"/:provider",_payload:void 0,_success:void 0,_error:void 0},{key:"OAUTH_ACCOUNTS",method:"GET",suffix:"/accounts",_payload:void 0,_success:void 0,_error:void 0},{key:"OAUTH_UNLINK",method:"DELETE",suffix:"/unlink/:provider",_payload:void 0,_success:void 0,_error:void 0}]},webauthn:{key:"WEBAUTHN",method:"POST",defaultRoute:"/auth/webauthn",defaultIsPublic:!1,subEndpoints:[{key:"WEBAUTHN_REGISTER_OPTIONS",method:"POST",suffix:"/register/options",_payload:void 0,_success:void 0,_error:void 0},{key:"WEBAUTHN_REGISTER_VERIFY",method:"POST",suffix:"/register/verify",_payload:void 0,_success:void 0,_error:void 0},{key:"WEBAUTHN_AUTH_OPTIONS",method:"POST",suffix:"/authenticate/options",_payload:void 0,_success:void 0,_error:void 0},{key:"WEBAUTHN_AUTH_VERIFY",method:"POST",suffix:"/authenticate/verify",_payload:void 0,_success:void 0,_error:void 0},{key:"WEBAUTHN_LIST",method:"GET",suffix:"/credentials",_payload:void 0,_success:void 0,_error:void 0},{key:"WEBAUTHN_REVOKE",method:"DELETE",suffix:"/credentials/:credentialId",_payload:void 0,_success:void 0,_error:void 0},{key:"WEBAUTHN_RENAME",method:"PATCH",suffix:"/credentials/:credentialId",_payload:void 0,_success:void 0,_error:void 0}]},apiKeys:{key:"API_KEYS",method:"GET",defaultRoute:"/auth/api-keys",defaultIsPublic:!1,subEndpoints:[{key:"API_KEYS_CREATE",method:"POST",suffix:"",_payload:void 0,_success:void 0,_error:void 0},{key:"API_KEYS_LIST",method:"GET",suffix:"",_payload:void 0,_success:void 0,_error:void 0},{key:"API_KEYS_DETAIL",method:"GET",suffix:"/:id",_payload:void 0,_success:void 0,_error:void 0},{key:"API_KEYS_UPDATE",method:"PATCH",suffix:"/:id",_payload:void 0,_success:void 0,_error:void 0},{key:"API_KEYS_REVOKE",method:"DELETE",suffix:"/:id",_payload:void 0,_success:void 0,_error:void 0}]}},AUTH_ENDPOINTS={LOGIN:{method:"POST",path:"/auth/login",isPublic:!0,_payload:void 0,_success:void 0,_error:void 0},REGISTER:{method:"POST",path:"/auth/register",isPublic:!0,_payload:void 0,_success:void 0,_error:void 0},LOGOUT:{method:"POST",path:"/auth/logout",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},REFRESH:{method:"POST",path:"/auth/refresh",isPublic:!0,_payload:void 0,_success:void 0,_error:void 0},ME:{method:"GET",path:"/auth/me",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},PASSWORD_CHANGE:{method:"POST",path:"/auth/password/change",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},PASSWORD_SET:{method:"POST",path:"/auth/password/set",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},PASSWORD_RESET_REQUEST:{method:"POST",path:"/auth/password/reset-request",isPublic:!0,_payload:void 0,_success:void 0,_error:void 0},PASSWORD_RESET_CONFIRM:{method:"POST",path:"/auth/password/reset-confirm",isPublic:!0,_payload:void 0,_success:void 0,_error:void 0},SESSIONS:{method:"GET",path:"/auth/sessions",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},SESSIONS_CURRENT:{method:"GET",path:"/auth/sessions/current",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},SESSIONS_STATS:{method:"GET",path:"/auth/sessions/stats",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},SESSIONS_PENDING:{method:"GET",path:"/auth/sessions/pending",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},SESSIONS_REVOKE:{method:"POST",path:"/auth/sessions/revoke",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},SESSIONS_REVOKE_ALL:{method:"POST",path:"/auth/sessions/revoke-all",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},SESSIONS_ADMIN_LIST:{method:"GET",path:"/auth/sessions/admin/:userId",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},SESSIONS_ADMIN_REVOKE:{method:"DELETE",path:"/auth/sessions/admin/:userId",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},SESSIONS_APPROVE:{method:"POST",path:"/auth/sessions/approve",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},SESSIONS_REJECT:{method:"POST",path:"/auth/sessions/reject",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},MAGIC_LINK:{method:"POST",path:"/auth/magic-link",isPublic:!0,_payload:void 0,_success:void 0,_error:void 0},MAGIC_LINK_VERIFY:{method:"POST",path:"/auth/magic-link/verify",isPublic:!0,_payload:void 0,_success:void 0,_error:void 0},INVITE:{method:"POST",path:"/auth/invite",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},INVITE_VERIFY:{method:"POST",path:"/auth/invite/verify",isPublic:!0,_payload:void 0,_success:void 0,_error:void 0},VERIFY_EMAIL:{method:"POST",path:"/auth/verify-email",isPublic:!0,_payload:void 0,_success:void 0,_error:void 0},RESEND_VERIFICATION:{method:"POST",path:"/auth/resend-verification",isPublic:!0,_payload:void 0,_success:void 0,_error:void 0},CAPTCHA_GENERATE:{method:"POST",path:"/auth/captcha/generate",isPublic:!0,_payload:void 0,_success:void 0,_error:void 0},CAPTCHA_VALIDATE:{method:"POST",path:"/auth/captcha/validate",isPublic:!0,_payload:void 0,_success:void 0,_error:void 0},WEBAUTHN_REGISTER_OPTIONS:{method:"POST",path:"/auth/webauthn/register/options",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},WEBAUTHN_REGISTER_VERIFY:{method:"POST",path:"/auth/webauthn/register/verify",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},WEBAUTHN_AUTH_OPTIONS:{method:"POST",path:"/auth/webauthn/authenticate/options",isPublic:!0,_payload:void 0,_success:void 0,_error:void 0},WEBAUTHN_AUTH_VERIFY:{method:"POST",path:"/auth/webauthn/authenticate/verify",isPublic:!0,_payload:void 0,_success:void 0,_error:void 0},WEBAUTHN_LIST:{method:"GET",path:"/auth/webauthn/credentials",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},WEBAUTHN_REVOKE:{method:"DELETE",path:"/auth/webauthn/credentials/:credentialId",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},WEBAUTHN_RENAME:{method:"PATCH",path:"/auth/webauthn/credentials/:credentialId",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},ADMIN_IMPERSONATE:{method:"POST",path:"/auth/admin/impersonate",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},ADMIN_IMPERSONATE_STOP:{method:"POST",path:"/auth/admin/impersonate/stop",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},ADMIN_CHANGE_USER_ID:{method:"POST",path:"/auth/admin/change-user-id",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},ADMIN_CREATE_USER:{method:"POST",path:"/auth/admin/create-user",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},ADMIN_HARD_DELETE_USER:{method:"DELETE",path:"/auth/admin/hard-delete/:userId",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},API_KEYS_CREATE:{method:"POST",path:"/auth/api-keys",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},API_KEYS_LIST:{method:"GET",path:"/auth/api-keys",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},API_KEYS_DETAIL:{method:"GET",path:"/auth/api-keys/:id",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},API_KEYS_UPDATE:{method:"PUT",path:"/auth/api-keys/:id",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},API_KEYS_REVOKE:{method:"DELETE",path:"/auth/api-keys/:id",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0}},CONFIG_ENDPOINTS={CONFIG_GET:{method:"GET",path:"/nucleus/config",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},CONFIG_SECTIONS:{method:"GET",path:"/nucleus/config/sections",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},CONFIG_SECTION_GET:{method:"GET",path:"/nucleus/config/:section",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},CONFIG_SECTION_UPDATE:{method:"PATCH",path:"/nucleus/config/:section",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},CONFIG_ENV:{method:"GET",path:"/nucleus/config/env",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},CONFIG_OVERRIDES_GET:{method:"GET",path:"/nucleus/config/overrides",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},CONFIG_OVERRIDES_CLEAR:{method:"DELETE",path:"/nucleus/config/overrides",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},CONFIG_RESTART:{method:"POST",path:"/nucleus/config/restart",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0}},VERIFICATION_ENDPOINTS={VERIFICATION_STATUS:{method:"GET",path:"/verification/status/:entity_name/:entity_id",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},VERIFICATION_DECIDE:{method:"POST",path:"/verification/decide/:entity_name/:entity_id",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},VERIFICATION_PENDING:{method:"GET",path:"/verification/pending",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},VERIFICATION_HISTORY:{method:"GET",path:"/verification/history/:entity_name/:entity_id",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},VERIFICATION_START:{method:"POST",path:"/verification/start",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},VERIFICATION_START_FOR_ENTITY:{method:"POST",path:"/verification/start-for-entity",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},VERIFICATION_ENTITY_STATUSES:{method:"GET",path:"/verification/entity-statuses/:entity_name",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},FLOW_LIST:{method:"GET",path:"/verification/flows",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},FLOW_GET:{method:"GET",path:"/verification/flows/:flow_id",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},FLOW_SAVE:{method:"POST",path:"/verification/flows",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},FLOW_PUBLISH:{method:"POST",path:"/verification/flows/:flow_id/publish",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},FLOW_DELETE:{method:"DELETE",path:"/verification/flows/:flow_id",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},NOTIFICATION_LIST:{method:"GET",path:"/notifications",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},NOTIFICATION_UNSEEN_COUNT:{method:"GET",path:"/notifications/unseen-count",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},NOTIFICATION_MARK_SEEN:{method:"POST",path:"/notifications/:notification_id/seen",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},NOTIFICATION_MARK_ALL_SEEN:{method:"POST",path:"/notifications/seen-all",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0}},CHAT_ENDPOINTS={CHAT_LIST_CONVERSATIONS:{method:"GET",path:"/chat/conversations",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},CHAT_CREATE_CONVERSATION:{method:"POST",path:"/chat/conversations",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},CHAT_GET_CONVERSATION:{method:"GET",path:"/chat/conversations/:id",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},CHAT_GET_MESSAGES:{method:"GET",path:"/chat/conversations/:id/messages",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},CHAT_SEND_MESSAGE:{method:"POST",path:"/chat/conversations/:id/messages",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},CHAT_MARK_READ:{method:"POST",path:"/chat/conversations/:id/read",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},CHAT_TYPING:{method:"POST",path:"/chat/conversations/:id/typing",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},CHAT_ADD_PARTICIPANTS:{method:"POST",path:"/chat/conversations/:id/participants",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},CHAT_REMOVE_PARTICIPANT:{method:"DELETE",path:"/chat/conversations/:id/participants/:userId",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},CHAT_EDIT_MESSAGE:{method:"PATCH",path:"/chat/messages/:id",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},CHAT_DELETE_MESSAGE:{method:"DELETE",path:"/chat/messages/:id",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0}},MONITORING_ENDPOINTS={MONITORING_HEALTH_CHECK:{method:"GET",path:"/monitoring/health",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},MONITORING_GET_SETTINGS:{method:"GET",path:"/monitoring/settings",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},MONITORING_CHANGE_SETTINGS:{method:"PATCH",path:"/monitoring/settings",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},MONITORING_GET_LOGS:{method:"GET",path:"/monitoring/logs",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0}},PAYMENT_ENDPOINTS={PAYMENT_INITIALIZE:{method:"POST",path:"/payments/initialize",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},PAYMENT_TRANSACTIONS:{method:"GET",path:"/payments/transactions",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},PAYMENT_TRANSACTION_DETAIL:{method:"GET",path:"/payments/transactions/:id",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},PAYMENT_BIN_QUERY:{method:"POST",path:"/payments/bin-query",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},PAYMENT_DETAIL:{method:"POST",path:"/payments/payment-detail",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},PAYMENT_REFUND:{method:"POST",path:"/payments/refund",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},PAYMENT_SAVE_CARD:{method:"POST",path:"/payments/cards/save",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},PAYMENT_LIST_CARDS:{method:"GET",path:"/payments/cards",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},PAYMENT_DELETE_CARD:{method:"DELETE",path:"/payments/cards/:id",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},PAYMENT_SYNC_CARDS:{method:"POST",path:"/payments/cards/sync",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},PAYMENT_REGISTER_SUB_MERCHANT:{method:"POST",path:"/payments/sub-merchants",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},PAYMENT_UPDATE_SUB_MERCHANT:{method:"PUT",path:"/payments/sub-merchants/:id",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},PAYMENT_LIST_SUB_MERCHANTS:{method:"GET",path:"/payments/sub-merchants",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},PAYMENT_GET_SUB_MERCHANT:{method:"GET",path:"/payments/sub-merchants/:id",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},PAYMENT_LIST_SPLITS:{method:"GET",path:"/payments/splits",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},PAYMENT_APPROVE_SPLIT:{method:"POST",path:"/payments/splits/:splitId/approve",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},PAYMENT_DISAPPROVE_SPLIT:{method:"POST",path:"/payments/splits/:splitId/disapprove",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},PAYMENT_CREATE_PRODUCT:{method:"POST",path:"/payments/products",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},PAYMENT_UPDATE_PRODUCT:{method:"PUT",path:"/payments/products/:id",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},PAYMENT_LIST_PRODUCTS:{method:"GET",path:"/payments/products",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},PAYMENT_GET_PRODUCT:{method:"GET",path:"/payments/products/:id",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},PAYMENT_ARCHIVE_PRODUCT:{method:"DELETE",path:"/payments/products/:id",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},PAYMENT_CREATE_PRICE:{method:"POST",path:"/payments/prices",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},PAYMENT_UPDATE_PRICE:{method:"PUT",path:"/payments/prices/:id",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},PAYMENT_LIST_PRICES:{method:"GET",path:"/payments/prices",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},PAYMENT_GET_PRICE:{method:"GET",path:"/payments/prices/:id",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},PAYMENT_ARCHIVE_PRICE:{method:"DELETE",path:"/payments/prices/:id",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},PAYMENT_CREATE_CUSTOMER:{method:"POST",path:"/payments/customers",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},PAYMENT_UPDATE_CUSTOMER:{method:"PUT",path:"/payments/customers/:id",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},PAYMENT_LIST_CUSTOMERS:{method:"GET",path:"/payments/customers",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},PAYMENT_GET_CUSTOMER:{method:"GET",path:"/payments/customers/:id",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},PAYMENT_DELETE_CUSTOMER:{method:"DELETE",path:"/payments/customers/:id",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},PAYMENT_CREATE_SUBSCRIPTION:{method:"POST",path:"/payments/subscriptions",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},PAYMENT_UPDATE_SUBSCRIPTION:{method:"PUT",path:"/payments/subscriptions/:id",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},PAYMENT_CANCEL_SUBSCRIPTION:{method:"POST",path:"/payments/subscriptions/:id/cancel",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},PAYMENT_LIST_SUBSCRIPTIONS:{method:"GET",path:"/payments/subscriptions",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},PAYMENT_GET_SUBSCRIPTION:{method:"GET",path:"/payments/subscriptions/:id",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},PAYMENT_REPORT_USAGE:{method:"POST",path:"/payments/usage-records",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},PAYMENT_LIST_USAGE_SUMMARIES:{method:"GET",path:"/payments/usage-records/:subscriptionItemId/summaries",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},PAYMENT_CREATE_INVOICE:{method:"POST",path:"/payments/invoices",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},PAYMENT_FINALIZE_INVOICE:{method:"POST",path:"/payments/invoices/:id/finalize",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},PAYMENT_SEND_INVOICE:{method:"POST",path:"/payments/invoices/:id/send",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},PAYMENT_VOID_INVOICE:{method:"POST",path:"/payments/invoices/:id/void",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},PAYMENT_PAY_INVOICE:{method:"POST",path:"/payments/invoices/:id/pay",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},PAYMENT_LIST_INVOICES:{method:"GET",path:"/payments/invoices",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},PAYMENT_GET_INVOICE:{method:"GET",path:"/payments/invoices/:id",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},PAYMENT_GET_BALANCE:{method:"GET",path:"/payments/balance",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},PAYMENT_CREATE_PAYOUT:{method:"POST",path:"/payments/payouts",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},PAYMENT_LIST_PAYOUTS:{method:"GET",path:"/payments/payouts",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},PAYMENT_GET_PAYOUT:{method:"GET",path:"/payments/payouts/:id",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},PAYMENT_CANCEL_PAYOUT:{method:"POST",path:"/payments/payouts/:id/cancel",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},PAYMENT_CREATE_TRANSFER:{method:"POST",path:"/payments/transfers",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},PAYMENT_LIST_TRANSFERS:{method:"GET",path:"/payments/transfers",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0}},TENANT_ENDPOINTS={TENANT_CHECK_SUBDOMAIN:{method:"GET",path:"/tenants/check-subdomain/:subdomain",isPublic:!0,_payload:void 0,_success:void 0,_error:void 0},TENANT_PROVISION:{method:"POST",path:"/tenants/provision",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},TENANT_LIST:{method:"GET",path:"/tenants",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},TENANT_DETAIL:{method:"GET",path:"/tenants/:id",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},TENANT_SUSPEND:{method:"POST",path:"/tenants/:id/suspend",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},TENANT_REACTIVATE:{method:"POST",path:"/tenants/:id/reactivate",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},TENANT_SELF_SIGNUP:{method:"POST",path:"/tenants/self-signup",isPublic:!0,_payload:void 0,_success:void 0,_error:void 0}},DOMAIN_ENDPOINTS={DOMAIN_RESOLVE:{method:"GET",path:"/domains/resolve",isPublic:!0,_payload:void 0,_success:void 0,_error:void 0},DOMAIN_CREATE_HOSTNAME:{method:"POST",path:"/domains/hostnames",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},DOMAIN_LIST_HOSTNAMES:{method:"GET",path:"/domains/hostnames",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},DOMAIN_GET_HOSTNAME:{method:"GET",path:"/domains/hostnames/:id",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},DOMAIN_HOSTNAME_INSTRUCTIONS:{method:"GET",path:"/domains/hostnames/:id/instructions",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},DOMAIN_VERIFY_HOSTNAME:{method:"POST",path:"/domains/hostnames/:id/verify",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},DOMAIN_ACTIVATE_HOSTNAME:{method:"POST",path:"/domains/hostnames/:id/activate",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},DOMAIN_DISABLE_HOSTNAME:{method:"POST",path:"/domains/hostnames/:id/disable",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},DOMAIN_MAKE_PRIMARY:{method:"POST",path:"/domains/hostnames/:id/make-primary",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},DOMAIN_REFRESH_HOSTNAME:{method:"POST",path:"/domains/hostnames/:id/refresh-status",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},DOMAIN_CREATE_REGISTRATION:{method:"POST",path:"/domains/registrations",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},DOMAIN_LIST_REGISTRATIONS:{method:"GET",path:"/domains/registrations",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},DOMAIN_GET_REGISTRATION:{method:"GET",path:"/domains/registrations/:id",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},DOMAIN_CANCEL_REGISTRATION:{method:"POST",path:"/domains/registrations/:id/cancel",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},DOMAIN_TRANSFER_OUT:{method:"POST",path:"/domains/registrations/:id/transfer-out",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0}},MARKETPLACE_ENDPOINTS={PAYMENT_MARKETPLACE_RECORD_SPLIT:{method:"POST",path:"/payment/marketplace/splits",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},PAYMENT_MARKETPLACE_LIST_SPLITS:{method:"GET",path:"/payment/marketplace/splits",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},PAYMENT_MARKETPLACE_BALANCE:{method:"GET",path:"/payment/marketplace/balance/:ownerId",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},PAYMENT_MARKETPLACE_RELEASE_RESERVE:{method:"POST",path:"/payment/marketplace/reserves/:id/release",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},PAYMENT_MARKETPLACE_GET_SETTLEMENT_POLICY:{method:"GET",path:"/payment/marketplace/settlement-policy",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},PAYMENT_MARKETPLACE_UPSERT_SETTLEMENT_POLICY:{method:"POST",path:"/payment/marketplace/settlement-policy",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},PAYMENT_MARKETPLACE_REQUEST_PAYOUT:{method:"POST",path:"/payment/marketplace/payout-requests",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},PAYMENT_MARKETPLACE_LIST_PAYOUTS:{method:"GET",path:"/payment/marketplace/payout-requests",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},PAYMENT_MARKETPLACE_GET_PAYOUT:{method:"GET",path:"/payment/marketplace/payout-requests/:id",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},PAYMENT_MARKETPLACE_APPROVE_PAYOUT:{method:"POST",path:"/payment/marketplace/payout-requests/:id/approve",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},PAYMENT_MARKETPLACE_REJECT_PAYOUT:{method:"POST",path:"/payment/marketplace/payout-requests/:id/reject",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},PAYMENT_MARKETPLACE_OPEN_DISPUTE:{method:"POST",path:"/payment/marketplace/disputes",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},PAYMENT_MARKETPLACE_LIST_DISPUTES:{method:"GET",path:"/payment/marketplace/disputes",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},PAYMENT_MARKETPLACE_RESOLVE_DISPUTE:{method:"POST",path:"/payment/marketplace/disputes/:id/resolve",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0}},COHORT_ENDPOINTS={ADMIN_LIST_COHORTS:{method:"GET",path:"/auth/admin/cohorts",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},ADMIN_GET_COHORT:{method:"GET",path:"/auth/admin/cohorts/:id",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},ADMIN_CREATE_COHORT:{method:"POST",path:"/auth/admin/cohorts",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},ADMIN_UPDATE_COHORT:{method:"PATCH",path:"/auth/admin/cohorts/:id",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},ADMIN_DELETE_COHORT:{method:"DELETE",path:"/auth/admin/cohorts/:id",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},ADMIN_COHORT_BULK_CREATE:{method:"POST",path:"/auth/admin/cohorts/:id/bulk-create",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},ADMIN_COHORT_DEACTIVATE:{method:"POST",path:"/auth/admin/cohorts/:id/deactivate-users",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},ADMIN_COHORT_ACTIVATE:{method:"POST",path:"/auth/admin/cohorts/:id/activate-users",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},ADMIN_COHORT_DELETE_USERS:{method:"POST",path:"/auth/admin/cohorts/:id/delete-users",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},ADMIN_COHORT_EXPORT:{method:"GET",path:"/auth/admin/cohorts/:id/export",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0}};var SYSTEM_TABLE_NAMES=["profiles","addresses","phones","files","users","roles","claims","user_roles","role_claims","audit_logs","monitoring_metrics","integration_sources","integration_endpoints","integration_mappings","integration_runs","integration_run_items"],systemTables=system_tables_default.tables.filter((t)=>SYSTEM_TABLE_NAMES.includes(t.table_name));function toUpperSnakeCase(str){return str.replace(/([a-z])([A-Z])/g,"$1_$2").replace(/[\s-]+/g,"_").toUpperCase()}function snakeToCamelCase(str){return str.replace(/_([a-z])/g,(_,letter)=>letter.toUpperCase())}function singularize(str){if(str.endsWith("ies"))return`${str.slice(0,-3)}y`;if(str.endsWith("ses"))return`${str.slice(0,-2)}`;if(str.endsWith("s"))return str.slice(0,-1);return str}function generateEntityEndpointKey(tableName,method){let upperName=toUpperSnakeCase(tableName),singularName=toUpperSnakeCase(singularize(tableName));switch(method){case"GET":return`GET_${upperName}`;case"POST":return`ADD_${singularName}`;case"PUT":return`UPDATE_${singularName}`;case"PATCH":return`PATCH_${singularName}`;case"DELETE":return`DELETE_${singularName}`}}function generateBulkEndpointKey(tableName,method){let upperName=toUpperSnakeCase(tableName);switch(method){case"POST":return`BULK_ADD_${upperName}`;case"PUT":return`BULK_UPDATE_${upperName}`;case"DELETE":return`BULK_DELETE_${upperName}`}}function isMethodExcluded(table,method){if(!table.excluded_methods)return!1;let methodMap={GET:"GET",POST:"POST",PUT:"PUT",PATCH:"PATCH",DELETE:"DELETE"};return table.excluded_methods.includes(methodMap[method])}function generateEndpointsFromConfig(config){let endpoints={};for(let table of config.entities){let tableName=table.table_name,basePath=`/${snakeToCamelCase(tableName)}`,sid=table.serviceId;if(!isMethodExcluded(table,"GET")){endpoints[generateEntityEndpointKey(tableName,"GET")]={method:"GET",path:basePath,isPublic:table.is_public?.GET??!1,serviceId:sid,_payload:void 0,_success:void 0,_error:void 0};let singularName=toUpperSnakeCase(singularize(tableName));endpoints[`GET_${singularName}_BY_ID`]={method:"GET",path:`${basePath}/:id`,isPublic:table.is_public?.GET??!1,serviceId:sid,_payload:void 0,_success:void 0,_error:void 0},endpoints[`GET_${toUpperSnakeCase(tableName)}_DISTINCT`]={method:"GET",path:`${basePath}/distinct/:field`,isPublic:table.is_public?.GET??!1,serviceId:sid,_payload:void 0,_success:void 0,_error:void 0}}if(!isMethodExcluded(table,"POST"))endpoints[generateEntityEndpointKey(tableName,"POST")]={method:"POST",path:basePath,isPublic:table.is_public?.POST??!1,isFormData:table.is_form_data,serviceId:sid,_payload:void 0,_success:void 0,_error:void 0};if(!isMethodExcluded(table,"PUT"))endpoints[generateEntityEndpointKey(tableName,"PUT")]={method:"PUT",path:`${basePath}/:id`,isPublic:table.is_public?.PUT??!1,isFormData:table.is_form_data,serviceId:sid,_payload:void 0,_success:void 0,_error:void 0};if(!isMethodExcluded(table,"PATCH"))endpoints[generateEntityEndpointKey(tableName,"PATCH")]={method:"PATCH",path:`${basePath}/:id`,isPublic:table.is_public?.PATCH??!1,serviceId:sid,_payload:void 0,_success:void 0,_error:void 0};if(!isMethodExcluded(table,"DELETE"))endpoints[generateEntityEndpointKey(tableName,"DELETE")]={method:"DELETE",path:`${basePath}/:id`,isPublic:table.is_public?.DELETE??!1,serviceId:sid,_payload:void 0,_success:void 0,_error:void 0};if(table.bulk_endpoints_enabled){if(!isMethodExcluded(table,"POST"))endpoints[generateBulkEndpointKey(tableName,"POST")]={method:"POST",path:`${basePath}/bulk`,isPublic:table.is_public?.POST??!1,serviceId:sid,_payload:void 0,_success:void 0,_error:void 0};if(!isMethodExcluded(table,"PUT"))endpoints[generateBulkEndpointKey(tableName,"PUT")]={method:"PUT",path:`${basePath}/bulk`,isPublic:table.is_public?.PUT??!1,serviceId:sid,_payload:void 0,_success:void 0,_error:void 0};if(!isMethodExcluded(table,"DELETE"))endpoints[generateBulkEndpointKey(tableName,"DELETE")]={method:"DELETE",path:`${basePath}/bulk`,isPublic:table.is_public?.DELETE??!1,serviceId:sid,_payload:void 0,_success:void 0,_error:void 0}}}return endpoints}function generateAuthEndpoints(config){let endpoints={},auth=config.authentication;if(!auth?.enabled)return endpoints;for(let[featureKey,endpointConfig]of Object.entries(AUTH_ENDPOINT_CONFIGS)){let feature=auth[featureKey];if(!feature?.enabled)continue;let feat=feature,baseRoute=feat.route||endpointConfig.defaultRoute,isPublic=feat.isPublic??endpointConfig.defaultIsPublic;if("subEndpoints"in endpointConfig&&endpointConfig.subEndpoints)for(let sub of endpointConfig.subEndpoints){let subRoute="routeKey"in sub&&sub.routeKey&&feature[sub.routeKey]?String(feature[sub.routeKey]):("defaultRoute"in sub)&&sub.defaultRoute?String(sub.defaultRoute):`${baseRoute}${sub.suffix}`;endpoints[sub.key]={method:sub.method,path:subRoute,isPublic:sub.key==="MAGIC_LINK_VERIFY"?!0:isPublic,_payload:sub._payload,_success:sub._success,_error:sub._error}}else if("_payload"in endpointConfig)endpoints[endpointConfig.key]={method:endpointConfig.method,path:baseRoute,isPublic,_payload:endpointConfig._payload,_success:endpointConfig._success,_error:endpointConfig._error}}return endpoints}function generateSystemTableEndpoints(){let endpoints={};for(let table of systemTables){let tableName=table.table_name,basePath=`/${snakeToCamelCase(tableName)}`,isFormData=tableName==="files";endpoints[generateEntityEndpointKey(tableName,"GET")]={method:"GET",path:basePath,isPublic:!1,_payload:void 0,_success:void 0,_error:void 0};let singularName=toUpperSnakeCase(singularize(tableName));if(endpoints[`GET_${singularName}_BY_ID`]={method:"GET",path:`${basePath}/:id`,isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},!isMethodExcluded(table,"POST"))endpoints[generateEntityEndpointKey(tableName,"POST")]={method:"POST",path:basePath,isPublic:!1,isFormData,_payload:void 0,_success:void 0,_error:void 0};if(!isMethodExcluded(table,"PUT"))endpoints[generateEntityEndpointKey(tableName,"PUT")]={method:"PUT",path:`${basePath}/:id`,isPublic:!1,isFormData,_payload:void 0,_success:void 0,_error:void 0};if(!isMethodExcluded(table,"PATCH"))endpoints[generateEntityEndpointKey(tableName,"PATCH")]={method:"PATCH",path:`${basePath}/:id`,isPublic:!1,_payload:void 0,_success:void 0,_error:void 0};if(!isMethodExcluded(table,"DELETE"))endpoints[generateEntityEndpointKey(tableName,"DELETE")]={method:"DELETE",path:`${basePath}/:id`,isPublic:!1,_payload:void 0,_success:void 0,_error:void 0};if(table.bulk_endpoints_enabled)endpoints[generateBulkEndpointKey(tableName,"POST")]={method:"POST",path:`${basePath}/bulk`,isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},endpoints[generateBulkEndpointKey(tableName,"PUT")]={method:"PUT",path:`${basePath}/bulk`,isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},endpoints[generateBulkEndpointKey(tableName,"DELETE")]={method:"DELETE",path:`${basePath}/bulk`,isPublic:!1,_payload:void 0,_success:void 0,_error:void 0}}return endpoints}function generateMonitoringEndpoints(config){if(!config.liveMonitoring?.enabled)return{};return{...MONITORING_ENDPOINTS}}function generateAdminEndpoints(config){let endpoints={};if(!config.authentication?.enabled)return endpoints;return endpoints.ADMIN_IMPERSONATE={method:"POST",path:"/auth/admin/impersonate",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},endpoints.ADMIN_IMPERSONATE_STOP={method:"POST",path:"/auth/admin/impersonate/stop",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},endpoints.ADMIN_CHANGE_USER_ID={method:"POST",path:"/auth/admin/change-user-id",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},endpoints.ADMIN_CREATE_USER={method:"POST",path:"/auth/admin/create-user",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},endpoints.ADMIN_HARD_DELETE_USER={method:"DELETE",path:"/auth/admin/hard-delete/:userId",isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},endpoints}function generateCohortEndpoints(config){let auth=config.authentication;if(!auth?.enabled||!auth.cohorts?.enabled)return{};return{...COHORT_ENDPOINTS}}function generateVerificationEndpoints(config){let endpoints={},verification=config.verification,notification=config.notification;if(!verification?.enabled)return endpoints;let basePath=verification.endpoints?.basePath||"/verifications",flowBasePath=verification.flowEndpoints?.basePath||"/verification-flows",notifBasePath=notification?.endpoints?.basePath||"/notifications";if(endpoints.VERIFICATION_STATUS={method:"GET",path:`${basePath}/status/:entity_name/:entity_id`,isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},endpoints.VERIFICATION_DECIDE={method:"POST",path:`${basePath}/:entity_name/:entity_id/decide`,isPublic:!1,skipCamelCase:!0,_payload:void 0,_success:void 0,_error:void 0},endpoints.VERIFICATION_PENDING={method:"GET",path:`${basePath}/pending`,isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},endpoints.VERIFICATION_HISTORY={method:"GET",path:`${basePath}/history/:entity_name/:entity_id`,isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},endpoints.VERIFICATION_START={method:"POST",path:`${basePath}/start`,isPublic:!1,skipCamelCase:!0,_payload:void 0,_success:void 0,_error:void 0},endpoints.VERIFICATION_START_FOR_ENTITY={method:"POST",path:`${basePath}/start-for-entity`,isPublic:!1,skipCamelCase:!0,_payload:void 0,_success:void 0,_error:void 0},endpoints.VERIFICATION_ENTITY_STATUSES={method:"GET",path:`${basePath}/statuses/:entity_name`,isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},verification.flowEndpoints?.enabled)endpoints.FLOW_LIST={method:"GET",path:flowBasePath,isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},endpoints.FLOW_GET={method:"GET",path:`${flowBasePath}/:flow_id`,isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},endpoints.FLOW_SAVE={method:"POST",path:flowBasePath,isPublic:!1,skipCamelCase:!0,_payload:void 0,_success:void 0,_error:void 0},endpoints.FLOW_PUBLISH={method:"POST",path:`${flowBasePath}/:flow_id/publish`,isPublic:!1,skipCamelCase:!0,_payload:void 0,_success:void 0,_error:void 0},endpoints.FLOW_DELETE={method:"DELETE",path:`${flowBasePath}/:flow_id`,isPublic:!1,_payload:void 0,_success:void 0,_error:void 0};if(notification?.enabled&¬ification.endpoints?.enabled)endpoints.NOTIFICATION_LIST={method:"GET",path:notifBasePath,isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},endpoints.NOTIFICATION_UNSEEN_COUNT={method:"GET",path:`${notifBasePath}/unseen-count`,isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},endpoints.NOTIFICATION_MARK_SEEN={method:"POST",path:`${notifBasePath}/:notification_id/seen`,isPublic:!1,_payload:void 0,_success:void 0,_error:void 0},endpoints.NOTIFICATION_MARK_ALL_SEEN={method:"POST",path:`${notifBasePath}/seen-all`,isPublic:!1,_payload:void 0,_success:void 0,_error:void 0};return endpoints}function generateTenantEndpoints(config){if(!config.database?.isMultiTenant)return{};return{...TENANT_ENDPOINTS}}function generateChatEndpoints(config){if(!config.chat?.enabled)return{};return{...CHAT_ENDPOINTS}}function generateDomainEndpoints(config){if(!config.domains?.enabled)return{};return{...DOMAIN_ENDPOINTS}}function generateMarketplaceEndpoints(config){let payment=config.payment;if(!payment?.enabled||!payment.marketplace?.enabled)return{};return{...MARKETPLACE_ENDPOINTS}}function generateAllEndpoints(config,extraEndpoints){let entityEndpoints=generateEndpointsFromConfig(config),authEndpoints=generateAuthEndpoints(config),adminEndpoints=generateAdminEndpoints(config),cohortEndpoints=generateCohortEndpoints(config),systemEndpoints=generateSystemTableEndpoints(),monitoringEndpoints=generateMonitoringEndpoints(config),verificationEndpoints=generateVerificationEndpoints(config),chatEndpoints=generateChatEndpoints(config),tenantEndpoints=generateTenantEndpoints(config),domainEndpoints=generateDomainEndpoints(config),marketplaceEndpoints=generateMarketplaceEndpoints(config);return{...entityEndpoints,...authEndpoints,...adminEndpoints,...cohortEndpoints,...systemEndpoints,...monitoringEndpoints,...verificationEndpoints,...chatEndpoints,...tenantEndpoints,...domainEndpoints,...marketplaceEndpoints,...extraEndpoints??{}}}init_Logger();import{randomUUID as randomUUID2}from"crypto";var DEFAULT_CONFIG2={timeout:30000,retries:0,retryDelay:1000,debug:!1};class ServerFetch{config;logger;constructor(config={}){this.config={...DEFAULT_CONFIG2,...config},this.logger=new Logger({service:"ServerFetch",prettyPrint:this.config.debug,colorize:this.config.debug,auditEnabled:!1})}buildUrl(url){if(url.startsWith("http://")||url.startsWith("https://"))return url;return this.config.baseUrl?`${this.config.baseUrl}${url}`:url}buildHeaders(customHeaders){let headers=new Headers;if(this.config.defaultHeaders)for(let[key,value]of Object.entries(this.config.defaultHeaders))headers.set(key,value);if(customHeaders)if(customHeaders instanceof Headers)customHeaders.forEach((value,key)=>{headers.set(key,value)});else if(Array.isArray(customHeaders))for(let[key,value]of customHeaders)headers.set(key,value);else for(let[key,value]of Object.entries(customHeaders))headers.set(key,value);return headers}parseResponseHeaders(headers){let result={};if(headers.forEach((value,key)=>{if(key.toLowerCase()==="set-cookie"){let existing=result[key];result[key]=existing?`${existing}, ${value}`:value}else result[key]=value}),typeof headers.getSetCookie==="function"){let setCookies=headers.getSetCookie();if(setCookies.length>0)result["set-cookie"]=setCookies.join(", ")}return result}async executeWithTimeout(promise,timeoutMs,_requestId){let controller=new AbortController,timeoutId=setTimeout(()=>controller.abort(),timeoutMs);try{return await Promise.race([promise,new Promise((_,reject)=>{controller.signal.addEventListener("abort",()=>{reject(Error(`Request timeout after ${timeoutMs}ms`))})})])}finally{clearTimeout(timeoutId)}}async fetch(options){let requestId=randomUUID2(),startTime=performance.now(),url=this.buildUrl(options.url),headers=this.buildHeaders(options.headers),timeout=options.timeout??this.config.timeout??30000,retries=options.retries??this.config.retries??0,retryDelay=options.retryDelay??this.config.retryDelay??1000,body;if(options.body)if(typeof options.body==="object"&&!(options.body instanceof FormData)&&!(options.body instanceof URLSearchParams)&&!(options.body instanceof Blob)&&!(options.body instanceof ArrayBuffer)){if(body=JSON.stringify(options.body),!headers.has("content-type"))headers.set("content-type","application/json")}else body=options.body;this.logger.debug(`[${requestId}] ${options.method} ${url}`,{method:options.method,url,hasBody:!!body});let lastError=null,attempt=0;while(attempt<=retries)try{let response=await this.executeWithTimeout(fetch(url,{method:options.method,headers,body}),timeout,requestId),durationMs2=performance.now()-startTime,responseHeaders=this.parseResponseHeaders(response.headers),rawSetCookies=typeof response.headers.getSetCookie==="function"?response.headers.getSetCookie():[],responseData,errorData,rawText=await response.text();if(rawText)try{let json=JSON.parse(rawText);if(response.ok)responseData=json;else errorData=json}catch{if(!response.ok)errorData={message:rawText||response.statusText}}else if(!response.ok)errorData={message:response.statusText};let result={isSuccess:response.ok,response:responseData,errors:errorData,code:response.status,headers:responseHeaders,rawSetCookies,durationMs:durationMs2,requestId,createdAt:new Date};if(response.ok)this.logger.info(`[${requestId}] ${options.method} ${url} ${response.status}`,{method:options.method,url,statusCode:response.status,durationMs:Math.round(durationMs2)});else this.logger.warn(`[${requestId}] ${options.method} ${url} ${response.status}`,{method:options.method,url,statusCode:response.status,durationMs:Math.round(durationMs2),error:errorData});return result}catch(error){if(lastError=error instanceof Error?error:Error(String(error)),attempt++,attempt<=retries)this.logger.warn(`[${requestId}] Retry ${attempt}/${retries} after error`,{method:options.method,url,error:lastError.message,attempt,retries}),await new Promise((resolve)=>setTimeout(resolve,retryDelay))}let durationMs=performance.now()-startTime;return this.logger.error(`[${requestId}] ${options.method} ${url} failed`,lastError,{method:options.method,url,durationMs:Math.round(durationMs),attempts:attempt}),{isSuccess:!1,response:void 0,errors:{message:lastError?.message||"Unknown error"},code:null,headers:{},rawSetCookies:[],durationMs,requestId,createdAt:new Date}}async get(url,options){return this.fetch({...options,url,method:"GET"})}async post(url,body,options){return this.fetch({...options,url,method:"POST",body})}async put(url,body,options){return this.fetch({...options,url,method:"PUT",body})}async patch(url,body,options){return this.fetch({...options,url,method:"PATCH",body})}async delete(url,options){return this.fetch({...options,url,method:"DELETE"})}}var serverFetch=new ServerFetch;var DEFAULT_TOKEN_NAMES={accessToken:"access_token",refreshToken:"refresh_token",sessionToken:"session_token"};function splitSetCookieHeader(header){let cookies=[],current="";for(let i=0;i<header.length;i++){let char=header[i];if(char===","){let next=header.slice(i+1).trimStart();if(/^[a-zA-Z0-9_-]+=/.test(next)){cookies.push(current.trim()),current="";continue}}current+=char}if(current.trim())cookies.push(current.trim());return cookies}function buildRequestHeaders(headersStore,tokenNames){let headers={},forwardHeaders=["x-forwarded-for","x-real-ip","user-agent","accept-language","x-request-id","x-client-ip","cf-connecting-ip","true-client-ip","x-tenant-id","x-app-origin"];for(let header of forwardHeaders){let value=headersStore.get(header);if(value)headers[header]=value}if(!headers["user-agent"])headers["user-agent"]="Nucleus-ServerAction/1.0";let accessToken=headersStore.get(`x-${tokenNames.accessToken}`),refreshToken=headersStore.get(`x-${tokenNames.refreshToken}`),sessionToken=headersStore.get(`x-${tokenNames.sessionToken}`);if(accessToken)headers[`x-${tokenNames.accessToken}`]=accessToken;if(refreshToken)headers[`x-${tokenNames.refreshToken}`]=refreshToken;if(sessionToken)headers[`x-${tokenNames.sessionToken}`]=sessionToken;let cookieHeader=headersStore.get("cookie");if(cookieHeader)headers.cookie=cookieHeader;return headers}function toCamelCase(str){return str.replace(/_([a-z])/g,(_,c)=>c.toUpperCase())}function convertKeysToCamelCase(obj){let result={};for(let[key,value]of Object.entries(obj)){let camelKey=key.startsWith("_")?key:toCamelCase(key);if(value instanceof Date)result[camelKey]=value.toISOString();else if(value&&typeof value==="object"&&!Array.isArray(value))result[camelKey]=convertKeysToCamelCase(value);else result[camelKey]=value}return result}var JSON_STRINGIFY_KEYS=new Set(["filters","sort","with","searchFields","select","distinctOn"]);function appendQueryParams(url,params){let searchParams=new URLSearchParams;for(let[key,value]of Object.entries(params)){if(value===void 0||value===null)continue;if(JSON_STRINGIFY_KEYS.has(key)&&typeof value==="object"){searchParams.append(key,JSON.stringify(value));continue}if(value instanceof Date)searchParams.append(key,value.toISOString());else if(Array.isArray(value))searchParams.append(key,value.filter((v)=>v!=null).map(String).join(","));else if(typeof value==="object")searchParams.append(key,JSON.stringify(value));else searchParams.append(key,String(value))}let queryString=searchParams.toString();if(!queryString)return url;return url.includes("?")?`${url}&${queryString}`:`${url}?${queryString}`}function createServerFactory(endpoints,config,getCookies,getHeaders){let tokenNames={...DEFAULT_TOKEN_NAMES,...config.tokenNames},serverFetch2=new ServerFetch({baseUrl:config.baseUrl,debug:config.debug,timeout:30000,retries:0});return async function(endpointKey,payload){let endpoint=endpoints[endpointKey];if(!endpoint)return{isSuccess:!1,errors:{message:`Endpoint "${endpointKey}" not found`},code:404};let cookieStore=await getCookies(),headersStore=await getHeaders(),allHeaders={};if(headersStore.forEach((value,key)=>{allHeaders[key]=value}),(endpoint.path.includes("/auth/login")||endpoint.path.includes("/auth/oauth"))&&endpoint.method==="POST")try{cookieStore.delete(tokenNames.accessToken),cookieStore.delete(tokenNames.refreshToken),cookieStore.delete(tokenNames.sessionToken)}catch(_){}let headers=buildRequestHeaders(headersStore,tokenNames),url=endpoint.path,body,pathParamNames=new Set,pathParamRegex=/:([a-zA-Z_][a-zA-Z0-9_]*)/g,paramMatch=pathParamRegex.exec(url);while(paramMatch!==null){if(paramMatch[1])pathParamNames.add(paramMatch[1]);paramMatch=pathParamRegex.exec(url)}if(payload&&typeof payload==="object"&&!(payload instanceof FormData)){let payloadObj=payload;for(let[key,value]of Object.entries(payloadObj))if(value!=null){if(pathParamNames.has(key))url=url.replace(`:${key}`,String(value));else if(key.startsWith("_")&&pathParamNames.has(key.substring(1)))url=url.replace(`:${key.substring(1)}`,String(value));else if(key==="id"&&pathParamNames.has("id"))url=url.replace(":id",String(value))}}if(endpoint.method==="GET"&&payload&&typeof payload==="object"){let queryPayload={...payload};for(let paramName of pathParamNames)delete queryPayload[paramName],delete queryPayload[`_${paramName}`];url=appendQueryParams(url,queryPayload)}else if(payload!==void 0){if(endpoint.isFormData&&payload instanceof FormData)body=payload;else if(Array.isArray(payload)){if(body=payload.map((item)=>item&&typeof item==="object"?convertKeysToCamelCase(item):item),!headers["content-type"])headers["content-type"]="application/json"}else if(body=endpoint.skipCamelCase?payload:convertKeysToCamelCase(payload),!headers["content-type"])headers["content-type"]="application/json"}let response=await serverFetch2.fetch({url,method:endpoint.method,headers,body}),setCookiesToProcess=response.rawSetCookies.length>0?response.rawSetCookies:response.headers["set-cookie"]?splitSetCookieHeader(response.headers["set-cookie"]):[];if(setCookiesToProcess.length>0)try{for(let cookie of setCookiesToProcess){let[nameValue,...options]=cookie.split(";");if(!nameValue)continue;let eqIdx=nameValue.indexOf("=");if(eqIdx===-1)continue;let name=nameValue.substring(0,eqIdx).trim(),value=nameValue.substring(eqIdx+1).trim();if(name&&value){let cookieOptions={};for(let opt of options){let trimmed=opt.trim(),optEqIdx=trimmed.indexOf("="),optName=optEqIdx===-1?trimmed:trimmed.substring(0,optEqIdx),optValue=optEqIdx===-1?void 0:trimmed.substring(optEqIdx+1);if(!optName)continue;let optNameLower=optName.toLowerCase();if(optNameLower==="path")cookieOptions.path=optValue;else if(optNameLower==="domain")cookieOptions.domain=optValue;else if(optNameLower==="max-age")cookieOptions.maxAge=Number(optValue);else if(optNameLower==="expires"&&optValue)cookieOptions.expires=new Date(optValue);else if(optNameLower==="httponly")cookieOptions.httpOnly=!0;else if(optNameLower==="secure")cookieOptions.secure=!0;else if(optNameLower==="samesite")cookieOptions.sameSite=optValue}cookieStore.set(name,value,cookieOptions)}}}catch(cookieError){console.warn("[ServerFactory] Failed to process Set-Cookie headers:",cookieError instanceof Error?cookieError.message:String(cookieError))}let normalizedResponse=response.response;if(response.isSuccess&&normalizedResponse&&typeof normalizedResponse==="object"&&!Array.isArray(normalizedResponse)){let raw=normalizedResponse;if("success"in raw&&!("data"in raw)){let{success,message,error,...rest}=raw;normalizedResponse={success,...message!==void 0?{message}:{},...error!==void 0?{error}:{},...Object.keys(rest).length>0?{data:rest}:{}}}}return{isSuccess:response.isSuccess,data:normalizedResponse,errors:response.errors,code:response.code,message:response.isSuccess?void 0:response.errors?.message}}}var SYSTEM_TABLES=[{table_name:"users",feature_set:["authentication"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:[],bulk_endpoints_enabled:!0,columns:[{name:"email",type:"varchar",length:255},{name:"password",type:"varchar",length:255},{name:"verified_at",type:"timestamp"},{name:"email_verification_token",type:"varchar",length:255},{name:"email_verification_token_expires_at",type:"timestamp"},{name:"email_verification_sent_at",type:"timestamp"},{name:"email_verification_attempts",type:"integer",default:0},{name:"last_login_at",type:"timestamp"},{name:"login_count",type:"integer",default:0},{name:"is_locked",type:"boolean",default:!1},{name:"locked_until",type:"timestamp"},{name:"failed_login_attempts",type:"integer",default:0},{name:"is_god",type:"boolean",default:!1},{name:"cohort_id",type:"uuid",references:{table:"user_cohorts",column:"id",onDelete:"set null"}},{name:"email_verified",type:"boolean",default:!1}],indexes:[{columns:["email"],unique:!0},{columns:["email","is_active"]},{columns:["last_login_at"]},{columns:["is_locked","locked_until"]}]},{table_name:"profiles",feature_set:["authentication"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:[],bulk_endpoints_enabled:!0,columns:[{name:"user_id",type:"uuid",notNull:!0,references:{table:"users",column:"id"}},{name:"first_name",type:"varchar",length:100,notNull:!0},{name:"last_name",type:"varchar",length:100,notNull:!0}],indexes:[{columns:["user_id"],unique:!0},{columns:["first_name","last_name"]}]},{table_name:"roles",feature_set:["authentication","authorization"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:[],bulk_endpoints_enabled:!0,columns:[{name:"name",type:"varchar",length:100,notNull:!0},{name:"description",type:"varchar",length:500}],indexes:[{columns:["name"],unique:!0}]},{table_name:"claims",feature_set:["authentication","authorization"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:[],bulk_endpoints_enabled:!0,columns:[{name:"action",type:"varchar",length:100,notNull:!0},{name:"description",type:"varchar",length:500},{name:"path",type:"varchar",length:200,notNull:!0},{name:"method",type:"varchar",length:10,notNull:!0},{name:"policy",type:"jsonb"}],indexes:[{columns:["action"],unique:!0},{columns:["path","method"]}]},{table_name:"user_roles",feature_set:["authentication","authorization"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:[],bulk_endpoints_enabled:!0,columns:[{name:"user_id",type:"uuid",notNull:!0,references:{table:"users",column:"id",onDelete:"cascade"}},{name:"role_id",type:"uuid",notNull:!0,references:{table:"roles",column:"id",onDelete:"cascade"}}],indexes:[{columns:["user_id"]},{columns:["role_id"]}],constraints:{unique:[{name:"unique_user_role",columns:["user_id","role_id"]}]}},{table_name:"role_claims",feature_set:["authentication","authorization"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:[],bulk_endpoints_enabled:!0,columns:[{name:"role_id",type:"uuid",notNull:!0,references:{table:"roles",column:"id",onDelete:"cascade"}},{name:"claim_id",type:"uuid",notNull:!0,references:{table:"claims",column:"id",onDelete:"cascade"}},{name:"scope",type:"text"}],indexes:[{columns:["role_id"]},{columns:["claim_id"]},{columns:["role_id","claim_id","scope"]}]},{table_name:"files",feature_set:["storage"],add_base_columns:!0,is_form_data:!0,available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:[],bulk_endpoints_enabled:!0,columns:[{name:"name",type:"varchar",length:255,notNull:!0},{name:"original_name",type:"varchar",length:255,notNull:!0},{name:"type",type:"varchar",length:50,enumValues:["image","document","video","audio","profile_picture"]},{name:"path",type:"varchar",length:500,notNull:!0},{name:"size",type:"bigint",mode:"number",notNull:!0},{name:"mime_type",type:"varchar",length:100,notNull:!0},{name:"extension",type:"varchar",length:10,notNull:!0},{name:"uploaded_by",type:"uuid",references:{table:"users",column:"id"}}],indexes:[{columns:["type"]},{columns:["uploaded_by"]},{columns:["size"]}]},{table_name:"addresses",feature_set:["authentication"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:[],bulk_endpoints_enabled:!0,columns:[{name:"owner_type",type:"varchar",length:50,notNull:!0,enumValues:["user","company","contact"]},{name:"owner_id",type:"uuid",notNull:!0},{name:"name",type:"varchar",length:100,notNull:!0},{name:"street",type:"varchar",length:255},{name:"city",type:"varchar",length:100},{name:"state",type:"varchar",length:50},{name:"zip",type:"varchar",length:20},{name:"country",type:"varchar",length:50,default:"US"},{name:"latitude",type:"decimal",precision:10,scale:8},{name:"longitude",type:"decimal",precision:11,scale:8},{name:"neighborhood",type:"varchar",length:100},{name:"apartment",type:"varchar",length:50},{name:"province",type:"varchar",length:100},{name:"district",type:"varchar",length:100},{name:"type",type:"varchar",length:50}],indexes:[{columns:["city","state"]},{columns:["latitude","longitude"]},{columns:["type"]},{columns:["owner_type","owner_id"]}]},{table_name:"phones",feature_set:["authentication"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:[],bulk_endpoints_enabled:!0,columns:[{name:"owner_type",type:"varchar",length:50,notNull:!0,enumValues:["user","company","contact"]},{name:"owner_id",type:"uuid",notNull:!0},{name:"name",type:"varchar",length:100,notNull:!0},{name:"type",type:"varchar",length:50,enumValues:["mobile","office","fax"]},{name:"number",type:"varchar",length:20,notNull:!0},{name:"country_code",type:"varchar",length:10,notNull:!0,default:"+1"},{name:"extension",type:"varchar",length:10}],indexes:[{columns:["number"]},{columns:["type"]},{columns:["owner_type","owner_id"]}]},{table_name:"notifications",feature_set:["notification"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:[],columns:[{name:"user_id",type:"uuid",notNull:!0},{name:"title",type:"varchar",length:255,notNull:!0},{name:"body",type:"varchar",length:1000},{name:"entity_name",type:"varchar",length:100},{name:"entity_id",type:"uuid"},{name:"type",type:"varchar",length:50,notNull:!0,default:"system",enumValues:["verification","system","custom"]},{name:"source",type:"varchar",length:100},{name:"is_seen",type:"boolean",notNull:!0,default:!1},{name:"seen_at",type:"timestamptz"}],indexes:[{columns:["user_id","created_at"]},{columns:["is_seen"]},{columns:["type"]},{columns:["user_id","type","is_seen"]}]},{table_name:"tenants",feature_set:["multi-tenant"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["main"],excluded_schemas:[],excluded_methods:[],columns:[{name:"subdomain",type:"varchar",length:100,notNull:!0,unique:!0},{name:"schema_name",type:"varchar",length:100,notNull:!0,unique:!0},{name:"company_id",type:"uuid",notNull:!0},{name:"company_name",type:"varchar",length:255},{name:"god_admin_email",type:"varchar",length:255,notNull:!0},{name:"status",type:"varchar",length:20,notNull:!0,default:"provisioning"},{name:"plan",type:"varchar",length:50,default:"free"},{name:"domain",type:"varchar",length:255},{name:"settings",type:"jsonb",default:"{}"},{name:"trusted_sources",type:"jsonb",default:"[]"},{name:"max_users",type:"integer"},{name:"provisioned_at",type:"timestamptz"},{name:"suspended_at",type:"timestamptz"},{name:"suspended_reason",type:"text"}],indexes:[{columns:["status"]}]},{table_name:"tenant_events",feature_set:["multi-tenant"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["main"],excluded_schemas:[],excluded_methods:["POST","PUT","PATCH","DELETE"],columns:[{name:"tenant_id",type:"uuid",notNull:!0,references:{table:"tenants",column:"id",onDelete:"cascade"}},{name:"event_type",type:"varchar",length:50,notNull:!0},{name:"event_data",type:"jsonb",default:"{}"},{name:"performed_by",type:"varchar",length:255},{name:"ip_address",type:"varchar",length:45}],indexes:[{columns:["tenant_id"]},{columns:["event_type"]}]},{table_name:"tenant_features",feature_set:["multi-tenant"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["main"],excluded_schemas:[],excluded_methods:[],columns:[{name:"tenant_id",type:"uuid",notNull:!0,references:{table:"tenants",column:"id",onDelete:"cascade"}},{name:"feature_name",type:"varchar",length:100,notNull:!0},{name:"enabled",type:"boolean",notNull:!0,default:!0},{name:"config",type:"jsonb",default:"{}"}],indexes:[{columns:["tenant_id","feature_name"],unique:!0},{columns:["feature_name"]}]},{table_name:"domain_hostnames",feature_set:["domains"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["main"],excluded_schemas:[],excluded_methods:["PUT"],group_name:"Domains",columns:[{name:"owner_type",type:"varchar",length:20,notNull:!0,default:"tenant",comment:"tenant | organization | user | external"},{name:"owner_id",type:"uuid",notNull:!0,comment:"Product-defined owner reference (e.g. band id, org id)"},{name:"tenant_id",type:"uuid",references:{table:"tenants",column:"id",onDelete:"cascade"},comment:"Tenant this hostname routes to; null for non-tenant owners"},{name:"schema_name",type:"varchar",length:100,comment:"Resolved tenant schema for routing"},{name:"hostname",type:"varchar",length:255,notNull:!0,comment:"Original hostname as entered by the user"},{name:"normalized_hostname",type:"varchar",length:255,notNull:!0,unique:!0,comment:"Lowercased, punycode, port-stripped hostname used for matching"},{name:"hostname_kind",type:"varchar",length:20,notNull:!0,default:"apex",comment:"platform_subdomain | apex | www | subdomain"},{name:"status",type:"varchar",length:20,notNull:!0,default:"pending_verification",comment:"draft | pending_verification | verifying | active | failed | disabled | archived"},{name:"routing_status",type:"varchar",length:20,notNull:!0,default:"inactive",comment:"inactive | pending | active | failed"},{name:"certificate_status",type:"varchar",length:20,notNull:!0,default:"pending",comment:"not_required | pending | active | failed"},{name:"verification_status",type:"varchar",length:20,notNull:!0,default:"pending",comment:"pending | verified | failed | expired"},{name:"provider",type:"varchar",length:30,notNull:!0,default:"manual_dns",comment:"manual_dns | cloudflare_for_saas | cloudflare_registrar"},{name:"provider_hostname_id",type:"varchar",length:255},{name:"dns_target",type:"varchar",length:255,comment:"CNAME / A target the customer must point at"},{name:"is_primary",type:"boolean",notNull:!0,default:!1},{name:"redirect_to_hostname_id",type:"uuid",comment:"When set, this hostname 301-redirects to another hostname (e.g. apex to www)"},{name:"activated_at",type:"timestamptz"},{name:"disabled_at",type:"timestamptz"},{name:"failure_reason",type:"text"},{name:"metadata",type:"jsonb",default:"{}"}],indexes:[{columns:["tenant_id"]},{columns:["schema_name"]},{columns:["status"]},{columns:["owner_type","owner_id"]},{columns:["provider","provider_hostname_id"]}]},{table_name:"domain_registrations",feature_set:["domains"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["main"],excluded_schemas:[],excluded_methods:["PUT"],group_name:"Domains",columns:[{name:"owner_type",type:"varchar",length:20,notNull:!0,default:"tenant"},{name:"owner_id",type:"uuid",notNull:!0},{name:"tenant_id",type:"uuid",references:{table:"tenants",column:"id",onDelete:"set null"}},{name:"requested_domain",type:"varchar",length:255,notNull:!0},{name:"registered_domain",type:"varchar",length:255},{name:"provider",type:"varchar",length:30,notNull:!0,default:"cloudflare_registrar"},{name:"provider_registration_id",type:"varchar",length:255},{name:"registrant_owner_type",type:"varchar",length:20,notNull:!0,default:"customer",comment:"customer | platform"},{name:"registrant_contact_snapshot",type:"jsonb",default:"{}"},{name:"status",type:"varchar",length:30,notNull:!0,default:"draft",comment:"draft | availability_checked | awaiting_payment | registering | active | failed | transfer_requested | transferred_out | cancelled | expired"},{name:"price_amount",type:"numeric",precision:12,scale:2},{name:"currency",type:"varchar",length:10},{name:"renewal_date",type:"timestamptz"},{name:"auto_renew",type:"boolean",notNull:!0,default:!0},{name:"terms_version",type:"varchar",length:50},{name:"terms_accepted_at",type:"timestamptz"},{name:"failure_reason",type:"text"},{name:"metadata",type:"jsonb",default:"{}"}],indexes:[{columns:["owner_type","owner_id"]},{columns:["tenant_id"]},{columns:["status"]}]},{table_name:"domain_verification_challenges",feature_set:["domains"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["main"],excluded_schemas:[],excluded_methods:["POST","PUT","PATCH","DELETE"],group_name:"Domains",columns:[{name:"domain_hostname_id",type:"uuid",notNull:!0,references:{table:"domainHostnames",column:"id",onDelete:"cascade"}},{name:"challenge_type",type:"varchar",length:30,notNull:!0,default:"ownership_validation",comment:"hostname_validation | certificate_validation | ownership_validation"},{name:"record_type",type:"varchar",length:10,notNull:!0,default:"TXT",comment:"TXT | CNAME | A | AAAA | HTTP"},{name:"record_name",type:"varchar",length:255,notNull:!0},{name:"record_value",type:"text",notNull:!0},{name:"expected_target",type:"varchar",length:255},{name:"status",type:"varchar",length:20,notNull:!0,default:"pending",comment:"pending | verified | failed | expired"},{name:"expires_at",type:"timestamptz"},{name:"verified_at",type:"timestamptz"},{name:"failure_reason",type:"text"},{name:"metadata",type:"jsonb",default:"{}"}],indexes:[{columns:["domain_hostname_id"]},{columns:["status"]}]},{table_name:"domain_provider_records",feature_set:["domains"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["main"],excluded_schemas:[],excluded_methods:["POST","PUT","PATCH","DELETE"],group_name:"Domains",columns:[{name:"domain_hostname_id",type:"uuid",notNull:!0,references:{table:"domainHostnames",column:"id",onDelete:"cascade"}},{name:"provider",type:"varchar",length:30,notNull:!0},{name:"provider_resource_type",type:"varchar",length:30,notNull:!0,comment:"custom_hostname | certificate | validation | zone | dns_record | registration"},{name:"provider_resource_id",type:"varchar",length:255},{name:"provider_status",type:"varchar",length:50},{name:"last_synced_at",type:"timestamptz"},{name:"raw_status",type:"jsonb",default:"{}"},{name:"metadata",type:"jsonb",default:"{}"}],indexes:[{columns:["domain_hostname_id"]},{columns:["provider","provider_resource_id"]}]},{table_name:"domain_events",feature_set:["domains"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["main"],excluded_schemas:[],excluded_methods:["POST","PUT","PATCH","DELETE"],group_name:"Domains",columns:[{name:"domain_hostname_id",type:"uuid",references:{table:"domainHostnames",column:"id",onDelete:"cascade"}},{name:"domain_registration_id",type:"uuid",references:{table:"domainRegistrations",column:"id",onDelete:"cascade"}},{name:"event_type",type:"varchar",length:50,notNull:!0},{name:"actor_type",type:"varchar",length:20},{name:"actor_id",type:"varchar",length:255},{name:"message",type:"text"},{name:"ip_address",type:"varchar",length:45},{name:"metadata",type:"jsonb",default:"{}"}],indexes:[{columns:["domain_hostname_id"]},{columns:["event_type"]}]},{table_name:"verifications",feature_set:["verification"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:[],columns:[{name:"instance_id",type:"uuid",notNull:!0,references:{table:"verificationInstances",column:"id",onDelete:"cascade"}},{name:"requirement_id",type:"uuid",notNull:!0,references:{table:"verificationRequirements",column:"id"}},{name:"verifier_id",type:"uuid",notNull:!0,references:{table:"users",column:"id"}},{name:"signature_id",type:"uuid",references:{table:"files",column:"id"}},{name:"entity_name",type:"varchar",length:100,notNull:!0},{name:"entity_id",type:"uuid",notNull:!0},{name:"step_order",type:"integer",notNull:!0,default:1},{name:"decision",type:"varchar",length:50,notNull:!0,default:"pending",enumValues:["approved","rejected","pending"]},{name:"reason",type:"text"},{name:"diff",type:"jsonb"}],indexes:[{columns:["instance_id"]},{columns:["requirement_id"]},{columns:["verifier_id"]},{columns:["entity_name","entity_id"]},{columns:["entity_name","entity_id","step_order"]},{columns:["decision"]}]},{table_name:"verificationRequirements",feature_set:["verification"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:[],columns:[{name:"instance_id",type:"uuid",notNull:!0,references:{table:"verificationInstances",column:"id",onDelete:"cascade"}},{name:"step_node_id",type:"varchar",length:100,notNull:!0},{name:"verifier_node_id",type:"varchar",length:100,notNull:!0},{name:"entity_name",type:"varchar",length:100,notNull:!0},{name:"entity_id",type:"uuid",notNull:!0},{name:"verifier_type",type:"varchar",length:30,notNull:!0,enumValues:["user","role"]},{name:"verifier_user_id",type:"uuid"},{name:"verifier_role",type:"varchar",length:100},{name:"require_signature",type:"boolean",notNull:!0,default:!1},{name:"all_must_approve",type:"boolean",notNull:!0,default:!1},{name:"step_order",type:"integer",notNull:!0,default:1},{name:"status",type:"varchar",length:30,notNull:!0,default:"pending",enumValues:["pending","approved","rejected"]}],indexes:[{columns:["instance_id"]},{columns:["instance_id","step_order"]},{columns:["entity_name","entity_id"]},{columns:["verifier_user_id"]},{columns:["status"]}]},{table_name:"verificationFlows",feature_set:["authentication","verification"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:[],columns:[{name:"entity_name",type:"varchar",length:100,notNull:!0},{name:"name",type:"varchar",length:255,notNull:!0},{name:"description",type:"text"},{name:"trigger_on",type:"varchar",length:50,notNull:!0,default:"update",enumValues:["create","update","delete","manual"]},{name:"trigger_fields",type:"jsonb"},{name:"is_draft",type:"boolean",notNull:!0,default:!0},{name:"published_at",type:"timestamptz"},{name:"viewport",type:"jsonb"}],indexes:[{columns:["entity_name"]},{columns:["entity_name","trigger_on"]},{columns:["is_draft"]}]},{table_name:"verificationSteps",feature_set:["authentication","verification"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:[],columns:[{name:"flow_id",type:"uuid",notNull:!0,references:{table:"verificationFlows",column:"id",onDelete:"cascade"}},{name:"entity_name",type:"varchar",length:100,notNull:!0},{name:"node_id",type:"varchar",length:100,notNull:!0},{name:"node_type",type:"varchar",length:50,notNull:!0,default:"step",enumValues:["step","verifier","notification"]},{name:"step_order",type:"integer",notNull:!0,default:1},{name:"name",type:"varchar",length:255},{name:"description",type:"text"},{name:"position_x",type:"numeric",notNull:!0,default:0},{name:"position_y",type:"numeric",notNull:!0,default:0},{name:"width",type:"numeric"},{name:"height",type:"numeric"},{name:"style",type:"jsonb"},{name:"data",type:"jsonb"}],indexes:[{columns:["flow_id"]},{columns:["entity_name"]},{columns:["flow_id","node_id"],unique:!0},{columns:["entity_name","step_order"]}]},{table_name:"verificationEdges",feature_set:["authentication","verification"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:[],columns:[{name:"flow_id",type:"uuid",notNull:!0,references:{table:"verificationFlows",column:"id",onDelete:"cascade"}},{name:"edge_id",type:"varchar",length:100,notNull:!0},{name:"source_node_id",type:"varchar",length:100,notNull:!0},{name:"target_node_id",type:"varchar",length:100,notNull:!0},{name:"source_handle",type:"varchar",length:50},{name:"target_handle",type:"varchar",length:50},{name:"edge_type",type:"varchar",length:50,default:"default",enumValues:["default","conditional","success","failure"]},{name:"label",type:"varchar",length:255},{name:"condition",type:"jsonb"},{name:"style",type:"jsonb"},{name:"animated",type:"boolean",default:!1}],indexes:[{columns:["flow_id"]},{columns:["flow_id","edge_id"],unique:!0},{columns:["source_node_id"]},{columns:["target_node_id"]}]},{table_name:"verificationNotificationRules",feature_set:["verification","notification"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:[],columns:[{name:"flow_id",type:"uuid",notNull:!0,references:{table:"verificationFlows",column:"id",onDelete:"cascade"}},{name:"node_id",type:"varchar",length:100,notNull:!0},{name:"trigger",type:"varchar",length:50,notNull:!0,enumValues:["on_flow_started","on_step_reached","on_approved","on_rejected","on_flow_completed"]},{name:"title_template",type:"varchar",length:255},{name:"body_template",type:"text"},{name:"starts_at",type:"timestamptz"},{name:"expires_at",type:"timestamptz"}],indexes:[{columns:["flow_id"]},{columns:["flow_id","node_id"],unique:!0},{columns:["trigger"]}]},{table_name:"verificationNotificationRecipients",feature_set:["verification","notification"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:[],columns:[{name:"rule_id",type:"uuid",notNull:!0,references:{table:"verificationNotificationRules",column:"id",onDelete:"cascade"}},{name:"recipient_type",type:"varchar",length:30,notNull:!0,enumValues:["user","role","all_verifiers","step_verifier","entity_creator"]},{name:"recipient_user_id",type:"uuid"},{name:"recipient_role",type:"varchar",length:100}],indexes:[{columns:["rule_id"]},{columns:["recipient_type"]}]},{table_name:"verificationVerifierConfigs",feature_set:["verification"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:[],columns:[{name:"flow_id",type:"uuid",notNull:!0,references:{table:"verificationFlows",column:"id",onDelete:"cascade"}},{name:"node_id",type:"varchar",length:100,notNull:!0},{name:"verifier_type",type:"varchar",length:30,notNull:!0,enumValues:["user","role"]},{name:"verifier_user_id",type:"uuid"},{name:"verifier_role",type:"varchar",length:100},{name:"require_signature",type:"boolean",notNull:!0,default:!1},{name:"all_must_approve",type:"boolean",notNull:!0,default:!1}],indexes:[{columns:["flow_id"]},{columns:["flow_id","node_id"],unique:!0},{columns:["verifier_type"]}]},{table_name:"verificationInstances",feature_set:["verification"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:[],columns:[{name:"flow_id",type:"uuid",notNull:!0,references:{table:"verificationFlows",column:"id"}},{name:"entity_name",type:"varchar",length:100,notNull:!0},{name:"entity_id",type:"uuid",notNull:!0},{name:"started_by",type:"uuid",references:{table:"users",column:"id"}},{name:"status",type:"varchar",length:30,notNull:!0,default:"active",enumValues:["active","completed","rejected","cancelled"]},{name:"current_step_order",type:"integer",notNull:!0,default:1},{name:"started_at",type:"timestamptz",notNull:!0,defaultRaw:"now()"},{name:"completed_at",type:"timestamptz"}],indexes:[{columns:["flow_id"]},{columns:["entity_name","entity_id"]},{columns:["entity_name","entity_id","status"]},{columns:["status"]},{columns:["started_by"]}]},{table_name:"verificationNotificationChannels",feature_set:["verification","notification"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:[],columns:[{name:"rule_id",type:"uuid",notNull:!0,references:{table:"verificationNotificationRules",column:"id",onDelete:"cascade"}},{name:"channel",type:"varchar",length:30,notNull:!0,enumValues:["portal","email","sms","telegram","webhook"]}],indexes:[{columns:["rule_id"]},{columns:["rule_id","channel"],unique:!0},{columns:["channel"]}]},{table_name:"user_cohorts",feature_set:["authentication"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:[],columns:[{name:"name",type:"varchar",length:255,notNull:!0},{name:"description",type:"text"},{name:"created_by",type:"uuid",references:{table:"users",column:"id",onDelete:"set null"}},{name:"expires_at",type:"timestamptz"},{name:"user_count",type:"integer",notNull:!0,default:0},{name:"metadata",type:"jsonb",default:"{}"}]},{table_name:"user_sessions",feature_set:["authentication"],add_base_columns:!0,is_form_data:!1,group_name:"Authentication",available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:["POST","PUT","PATCH"],columns:[{name:"user_id",type:"uuid",notNull:!0,references:{table:"users",column:"id",onDelete:"cascade"}},{name:"token_hash",type:"varchar",length:255,notNull:!0},{name:"refresh_token_hash",type:"varchar",length:255},{name:"device_fingerprint",type:"varchar",length:255},{name:"device_name",type:"varchar",length:100},{name:"device_type",type:"varchar",length:50,enumValues:["desktop","mobile","tablet","unknown"]},{name:"browser_name",type:"varchar",length:50},{name:"browser_version",type:"varchar",length:20},{name:"os_name",type:"varchar",length:50},{name:"os_version",type:"varchar",length:20},{name:"ip_address",type:"varchar",length:45,notNull:!0},{name:"location_country",type:"varchar",length:100},{name:"location_city",type:"varchar",length:100},{name:"location_coordinates",type:"varchar",length:50},{name:"last_activity_at",type:"timestamptz",notNull:!0,defaultRaw:"now()"},{name:"expires_at",type:"timestamptz",notNull:!0},{name:"revoked_at",type:"timestamptz"},{name:"revoked_reason",type:"varchar",length:100,enumValues:["user_logout","user_revoked","admin_revoked","security_concern","password_changed","expired","replaced"]},{name:"is_current",type:"boolean",notNull:!0,default:!1},{name:"login_method",type:"varchar",length:50,enumValues:["password","oauth_google","oauth_github","oauth_microsoft","magic_link","sso","api_key"]},{name:"remember_me",type:"boolean",notNull:!0,default:!1},{name:"trust_score",type:"integer",default:100},{name:"approval_status",type:"varchar",length:20,default:"approved",enumValues:["approved","pending","rejected"]},{name:"approval_token",type:"varchar",length:64},{name:"approval_requested_at",type:"timestamptz"},{name:"approval_responded_at",type:"timestamptz"}],indexes:[{columns:["user_id"]},{columns:["token_hash"],unique:!0},{columns:["refresh_token_hash"]},{columns:["user_id","is_active"]},{columns:["expires_at"]},{columns:["device_fingerprint"]},{columns:["ip_address"]},{columns:["last_activity_at"]},{columns:["approval_status"]},{columns:["approval_token"]}]},{table_name:"trusted_devices",feature_set:["authentication"],add_base_columns:!0,is_form_data:!1,group_name:"Authentication",available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:["POST","PUT","PATCH"],columns:[{name:"user_id",type:"uuid",notNull:!0,references:{table:"users",column:"id",onDelete:"cascade"}},{name:"token_hash",type:"varchar",length:64,notNull:!0},{name:"status",type:"varchar",length:20,notNull:!0,default:"pending",enumValues:["pending","trusted","revoked"]},{name:"origin_session_id",type:"uuid"},{name:"label",type:"varchar",length:120},{name:"device_fingerprint",type:"varchar",length:255},{name:"first_seen_ip",type:"varchar",length:45},{name:"last_seen_ip",type:"varchar",length:45},{name:"last_seen_at",type:"timestamptz"},{name:"expires_at",type:"timestamptz"},{name:"revoked_at",type:"timestamptz"},{name:"revoked_reason",type:"varchar",length:30,enumValues:["user_revoked","password_reset","logout","admin_revoked","expired","replaced"]}],indexes:[{columns:["token_hash"],unique:!0},{columns:["user_id"]},{columns:["user_id","status"]},{columns:["origin_session_id"]},{columns:["expires_at"]}]},{table_name:"password_reset_tokens",feature_set:["authentication"],add_base_columns:!0,is_form_data:!1,group_name:"Authentication",requires:["email"],available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:["POST","PUT","PATCH","DELETE"],columns:[{name:"user_id",type:"uuid",notNull:!0,references:{table:"users",column:"id",onDelete:"cascade"}},{name:"token_hash",type:"varchar",length:255,notNull:!0},{name:"expires_at",type:"timestamptz",notNull:!0},{name:"used_at",type:"timestamptz"}],indexes:[{columns:["token_hash"],unique:!0},{columns:["user_id"]},{columns:["expires_at"]}]},{table_name:"magic_link_tokens",feature_set:["authentication"],add_base_columns:!0,is_form_data:!1,group_name:"Authentication",requires:["email"],available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:["POST","PUT","PATCH","DELETE"],columns:[{name:"user_id",type:"uuid",notNull:!0,references:{table:"users",column:"id",onDelete:"cascade"}},{name:"email",type:"varchar",length:255,notNull:!0},{name:"token_hash",type:"varchar",length:255,notNull:!0},{name:"expires_at",type:"timestamptz",notNull:!0},{name:"used_at",type:"timestamptz"}],indexes:[{columns:["token_hash"],unique:!0},{columns:["user_id"]},{columns:["email"]},{columns:["expires_at"]}]},{table_name:"webauthn_credentials",feature_set:["authentication"],add_base_columns:!0,is_form_data:!1,group_name:"Authentication",requires:[],available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:["POST","PUT","PATCH","DELETE"],columns:[{name:"user_id",type:"uuid",notNull:!0,references:{table:"users",column:"id",onDelete:"cascade"}},{name:"credential_id",type:"text",notNull:!0},{name:"public_key",type:"text",notNull:!0},{name:"counter",type:"bigint",mode:"number",notNull:!0,defaultValue:0},{name:"transports",type:"jsonb"},{name:"device_type",type:"varchar",length:32},{name:"backed_up",type:"boolean",notNull:!0,defaultValue:!1},{name:"aaguid",type:"varchar",length:64},{name:"authenticator_attachment",type:"varchar",length:32},{name:"nickname",type:"varchar",length:128},{name:"last_used_at",type:"timestamptz"},{name:"revoked_at",type:"timestamptz"}],indexes:[{columns:["credential_id"],unique:!0},{columns:["user_id"]}]},{table_name:"webauthn_challenges",feature_set:["authentication"],add_base_columns:!0,is_form_data:!1,group_name:"Authentication",requires:[],available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:["POST","PUT","PATCH","DELETE","GET"],columns:[{name:"user_id",type:"uuid",references:{table:"users",column:"id",onDelete:"cascade"}},{name:"challenge",type:"text",notNull:!0},{name:"challenge_type",type:"varchar",length:32,notNull:!0},{name:"expires_at",type:"timestamptz",notNull:!0},{name:"consumed_at",type:"timestamptz"}],indexes:[{columns:["challenge"],unique:!0},{columns:["user_id"]},{columns:["expires_at"]}]},{table_name:"audit_logs",feature_set:["audit"],add_base_columns:!1,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:["POST","PUT","DELETE","PATCH","TOGGLE","VERIFICATION"],columns:[{name:"id",type:"uuid",primaryKey:!0,defaultRaw:"gen_random_uuid()"},{name:"entity_id",type:"uuid"},{name:"entity_name",type:"text",notNull:!0},{name:"operation_type",type:"text",notNull:!0},{name:"user_id",type:"uuid"},{name:"ip_address",type:"text"},{name:"user_agent",type:"text"},{name:"summary",type:"text"},{name:"severity",type:"text",default:"info"},{name:"category",type:"text"},{name:"occurrence_count",type:"integer",default:1},{name:"last_occurrence_at",type:"timestamp"},{name:"old_values",type:"jsonb"},{name:"new_values",type:"jsonb"},{name:"created_at",type:"timestamp",notNull:!0,defaultRaw:"now()"},{name:"path",type:"text"},{name:"query",type:"text"}],indexes:[{columns:["entity_id"]},{columns:["entity_name"]},{columns:["user_id"]},{columns:["created_at"]},{columns:["severity"]},{columns:["category"]}]},{table_name:"monitoring_metrics",feature_set:["monitoring"],add_base_columns:!1,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:["POST","PUT","DELETE","PATCH","TOGGLE","VERIFICATION"],columns:[{name:"id",type:"uuid",primaryKey:!0,defaultRaw:"gen_random_uuid()"},{name:"metric_type",type:"text",notNull:!0},{name:"metric_name",type:"text",notNull:!0},{name:"value",type:"doublePrecision",notNull:!0},{name:"tags",type:"jsonb"},{name:"recorded_at",type:"timestamp",notNull:!0}],indexes:[{columns:["metric_type"]},{columns:["metric_name"]},{columns:["recorded_at"]}]},{table_name:"oauth_accounts",feature_set:["authentication"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:[],bulk_endpoints_enabled:!1,columns:[{name:"user_id",type:"uuid",notNull:!0,references:{table:"users",column:"id",onDelete:"cascade"}},{name:"provider",type:"varchar",length:50,notNull:!0,enumValues:["google","github","microsoft","discord","facebook","twitter","apple","custom"]},{name:"provider_account_id",type:"varchar",length:255,notNull:!0},{name:"provider_email",type:"varchar",length:255},{name:"provider_name",type:"varchar",length:255},{name:"provider_avatar_url",type:"text"},{name:"access_token",type:"text"},{name:"refresh_token",type:"text"},{name:"token_expires_at",type:"timestamp"},{name:"scope",type:"text"},{name:"raw_profile",type:"jsonb"},{name:"is_primary",type:"boolean",notNull:!0,default:!1},{name:"last_used_at",type:"timestamp"}],indexes:[{columns:["user_id"]},{columns:["provider","provider_account_id"],unique:!0},{columns:["provider_email"]},{columns:["user_id","provider"]}],constraints:{unique:[{name:"unique_provider_account",columns:["provider","provider_account_id"]}]}},{table_name:"api_keys",feature_set:["authentication"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:["POST","PUT","PATCH"],bulk_endpoints_enabled:!1,columns:[{name:"user_id",type:"uuid",notNull:!0,references:{table:"users",column:"id",onDelete:"cascade"}},{name:"name",type:"varchar",length:255,notNull:!0},{name:"description",type:"text"},{name:"key_hash",type:"varchar",length:255,notNull:!0},{name:"key_preview",type:"varchar",length:20,notNull:!0},{name:"owner_type",type:"varchar",length:30,notNull:!0,default:"personal",enumValues:["personal","application"]},{name:"application_name",type:"varchar",length:255},{name:"allowed_roles",type:"jsonb",notNull:!0,default:"[]"},{name:"allowed_claims",type:"jsonb",notNull:!0,default:"[]"},{name:"allowed_scopes",type:"jsonb",notNull:!0,default:"[]"},{name:"expires_at",type:"timestamptz"},{name:"last_used_at",type:"timestamptz"},{name:"last_used_ip",type:"varchar",length:45},{name:"usage_count",type:"integer",notNull:!0,default:0},{name:"revoked_at",type:"timestamptz"},{name:"revoked_reason",type:"varchar",length:255}],indexes:[{columns:["key_hash"],unique:!0},{columns:["user_id"]},{columns:["user_id","is_active"]},{columns:["owner_type"]},{columns:["expires_at"]},{columns:["last_used_at"]}]},{table_name:"backup_logs",feature_set:["backup"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["main","all"],excluded_schemas:[],excluded_methods:["PUT","PATCH"],columns:[{name:"backup_name",type:"varchar",length:255,notNull:!0},{name:"file_name",type:"varchar",length:500,notNull:!0},{name:"schema_name",type:"varchar",length:100,notNull:!0},{name:"format",type:"varchar",length:20,notNull:!0,default:"json"},{name:"status",type:"varchar",length:20,notNull:!0,default:"pending"},{name:"trigger",type:"varchar",length:20,notNull:!0,default:"manual"},{name:"size_bytes",type:"integer"},{name:"table_count",type:"integer"},{name:"row_count",type:"integer"},{name:"included_tables",type:"jsonb",default:"[]"},{name:"excluded_tables",type:"jsonb",default:"[]"},{name:"error_message",type:"text"},{name:"started_at",type:"timestamp"},{name:"completed_at",type:"timestamp"},{name:"performed_by",type:"varchar",length:255},{name:"cron_expression",type:"varchar",length:100},{name:"retention_days",type:"integer"}],indexes:[{columns:["schema_name"]},{columns:["status"]},{columns:["trigger"]},{columns:["created_at"]}]},{table_name:"payment_transactions",feature_set:["payment"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:["DELETE"],columns:[{name:"user_id",type:"uuid",references:{table:"users",column:"id"}},{name:"order_id",type:"varchar",length:255},{name:"provider",type:"varchar",length:50,notNull:!0},{name:"provider_transaction_id",type:"varchar",length:255},{name:"provider_payment_id",type:"varchar",length:255},{name:"payment_method",type:"varchar",length:50},{name:"amount",type:"numeric",precision:12,scale:2,notNull:!0,default:0},{name:"currency",type:"varchar",length:10,notNull:!0,default:"TRY"},{name:"status",type:"varchar",length:30,notNull:!0,default:"pending",enumValues:["pending","processing","completed","failed","refunded","partially_refunded","cancelled"]},{name:"status_code",type:"integer"},{name:"status_message",type:"text"},{name:"card_last_four",type:"varchar",length:4},{name:"card_type",type:"varchar",length:50},{name:"card_association",type:"varchar",length:50},{name:"installment",type:"integer",default:1},{name:"is_three_d_secure",type:"boolean",default:!1},{name:"provider_response",type:"jsonb",default:"{}"},{name:"metadata",type:"jsonb",default:"{}"},{name:"refunded_amount",type:"numeric",precision:12,scale:2,default:0},{name:"refunded_at",type:"timestamptz"},{name:"completed_at",type:"timestamptz"},{name:"failed_at",type:"timestamptz"},{name:"ip_address",type:"varchar",length:45}],indexes:[{columns:["user_id"]},{columns:["order_id"]},{columns:["provider"]},{columns:["provider_payment_id"]},{columns:["status"]},{columns:["user_id","status"]}]},{table_name:"payment_methods",feature_set:["payment"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:[],columns:[{name:"user_id",type:"uuid",notNull:!0,references:{table:"users",column:"id",onDelete:"cascade"}},{name:"provider",type:"varchar",length:50,notNull:!0},{name:"type",type:"varchar",length:30,notNull:!0,default:"card",enumValues:["card","bank_account","wallet"]},{name:"alias",type:"varchar",length:100},{name:"card_last_four",type:"varchar",length:4},{name:"card_type",type:"varchar",length:50},{name:"card_association",type:"varchar",length:50},{name:"card_family",type:"varchar",length:100},{name:"card_bank_name",type:"varchar",length:100},{name:"provider_card_user_key",type:"varchar",length:255},{name:"provider_card_token",type:"varchar",length:255},{name:"bin_number",type:"varchar",length:8},{name:"is_default",type:"boolean",default:!1},{name:"metadata",type:"jsonb",default:"{}"}],indexes:[{columns:["user_id"]},{columns:["provider"]},{columns:["user_id","is_default"]},{columns:["provider_card_user_key"]}]},{table_name:"payment_webhook_logs",feature_set:["payment"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:["PUT","PATCH","DELETE"],columns:[{name:"provider",type:"varchar",length:50,notNull:!0},{name:"event_type",type:"varchar",length:100,notNull:!0},{name:"provider_payment_id",type:"varchar",length:255},{name:"raw_payload",type:"jsonb",notNull:!0},{name:"processed",type:"boolean",default:!1},{name:"processing_result",type:"jsonb"},{name:"error_message",type:"text"},{name:"ip_address",type:"varchar",length:45},{name:"idempotency_key",type:"varchar",length:255}],indexes:[{columns:["provider"]},{columns:["event_type"]},{columns:["provider_payment_id"]},{columns:["processed"]},{columns:["idempotency_key"],unique:!0}]},{table_name:"payment_sub_merchants",feature_set:["payment"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:[],columns:[{name:"user_id",type:"uuid",references:{table:"users",column:"id"}},{name:"provider",type:"varchar",length:50,notNull:!0},{name:"provider_sub_merchant_key",type:"varchar",length:255},{name:"external_id",type:"varchar",length:255},{name:"type",type:"varchar",length:50,notNull:!0,default:"personal",enumValues:["personal","private_company","limited_or_joint_stock_company"]},{name:"status",type:"varchar",length:30,notNull:!0,default:"pending",enumValues:["pending","active","suspended","rejected"]},{name:"name",type:"varchar",length:255,notNull:!0},{name:"email",type:"varchar",length:255,notNull:!0},{name:"gsm_number",type:"varchar",length:20},{name:"address",type:"text"},{name:"iban",type:"varchar",length:50},{name:"contact_name",type:"varchar",length:100},{name:"contact_surname",type:"varchar",length:100},{name:"identity_number",type:"varchar",length:20},{name:"tax_office",type:"varchar",length:100},{name:"tax_number",type:"varchar",length:20},{name:"legal_company_title",type:"varchar",length:255},{name:"currency",type:"varchar",length:10,default:"TRY"},{name:"commission_rate",type:"numeric",precision:5,scale:2,default:0},{name:"metadata",type:"jsonb",default:"{}"}],indexes:[{columns:["user_id"]},{columns:["provider"]},{columns:["provider_sub_merchant_key"]},{columns:["external_id"]},{columns:["status"]},{columns:["email"]}]},{table_name:"payment_commission_splits",feature_set:["payment"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:["DELETE"],columns:[{name:"transaction_id",type:"uuid",notNull:!0,references:{table:"payment_transactions",column:"id",onDelete:"cascade"}},{name:"sub_merchant_id",type:"uuid",notNull:!0,references:{table:"payment_sub_merchants",column:"id"}},{name:"basket_item_id",type:"varchar",length:255},{name:"item_price",type:"numeric",precision:12,scale:2,notNull:!0,default:0},{name:"sub_merchant_price",type:"numeric",precision:12,scale:2,notNull:!0,default:0},{name:"platform_commission",type:"numeric",precision:12,scale:2,notNull:!0,default:0},{name:"commission_rate",type:"numeric",precision:5,scale:2,default:0},{name:"provider_split_id",type:"varchar",length:255},{name:"currency",type:"varchar",length:10,notNull:!0,default:"TRY"},{name:"status",type:"varchar",length:30,notNull:!0,default:"pending",enumValues:["pending","approved","disapproved","refunded"]},{name:"approved_at",type:"timestamptz"},{name:"disapproved_at",type:"timestamptz"},{name:"metadata",type:"jsonb",default:"{}"}],indexes:[{columns:["transaction_id"]},{columns:["sub_merchant_id"]},{columns:["status"]},{columns:["transaction_id","sub_merchant_id"]},{columns:["provider_split_id"]}]},{table_name:"payment_products",feature_set:["payment"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:[],columns:[{name:"provider",type:"varchar",length:50,notNull:!0},{name:"provider_product_id",type:"varchar",length:255},{name:"name",type:"varchar",length:255,notNull:!0},{name:"description",type:"text"},{name:"type",type:"varchar",length:30,default:"service",enumValues:["service","good"]},{name:"status",type:"varchar",length:30,notNull:!0,default:"active",enumValues:["active","archived","draft"]},{name:"images",type:"jsonb",default:"[]"},{name:"unit_label",type:"varchar",length:50},{name:"url",type:"varchar",length:500},{name:"metadata",type:"jsonb",default:"{}"}],indexes:[{columns:["provider"]},{columns:["provider_product_id"]},{columns:["name"]},{columns:["status"]},{columns:["type"]}]},{table_name:"payment_prices",feature_set:["payment"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:["DELETE"],columns:[{name:"product_id",type:"uuid",notNull:!0,references:{table:"payment_products",column:"id",onDelete:"cascade"}},{name:"provider",type:"varchar",length:50,notNull:!0},{name:"provider_price_id",type:"varchar",length:255},{name:"currency",type:"varchar",length:10,notNull:!0,default:"USD"},{name:"unit_amount",type:"integer",notNull:!0,default:0},{name:"unit_amount_decimal",type:"varchar",length:30},{name:"type",type:"varchar",length:30,notNull:!0,default:"one_time",enumValues:["one_time","recurring"]},{name:"billing_scheme",type:"varchar",length:30,default:"per_unit",enumValues:["per_unit","tiered"]},{name:"nickname",type:"varchar",length:255},{name:"recurring_interval",type:"varchar",length:20,enumValues:["day","week","month","year"]},{name:"recurring_interval_count",type:"integer",default:1},{name:"recurring_usage_type",type:"varchar",length:20,default:"licensed",enumValues:["licensed","metered"]},{name:"recurring_aggregate_usage",type:"varchar",length:30,enumValues:["sum","last_during_period","last_ever","max"]},{name:"transform_quantity_divide_by",type:"integer"},{name:"transform_quantity_round",type:"varchar",length:10,enumValues:["up","down"]},{name:"status",type:"varchar",length:30,notNull:!0,default:"active",enumValues:["active","archived"]},{name:"metadata",type:"jsonb",default:"{}"}],indexes:[{columns:["product_id"]},{columns:["provider"]},{columns:["provider_price_id"]},{columns:["type"]},{columns:["currency"]},{columns:["status"]},{columns:["product_id","status"]}]},{table_name:"payment_customers",feature_set:["payment"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:[],columns:[{name:"user_id",type:"uuid",references:{table:"users",column:"id"}},{name:"provider",type:"varchar",length:50,notNull:!0},{name:"provider_customer_id",type:"varchar",length:255,notNull:!0},{name:"email",type:"varchar",length:255,notNull:!0},{name:"name",type:"varchar",length:255},{name:"phone",type:"varchar",length:50},{name:"description",type:"text"},{name:"address",type:"jsonb",default:"{}"},{name:"tax_id_type",type:"varchar",length:50},{name:"tax_id_value",type:"varchar",length:100},{name:"metadata",type:"jsonb",default:"{}"}],indexes:[{columns:["user_id"]},{columns:["provider"]},{columns:["provider_customer_id"]},{columns:["email"]},{columns:["user_id","provider"],unique:!0}]},{table_name:"payment_subscriptions",feature_set:["payment"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:["DELETE"],columns:[{name:"customer_id",type:"uuid",notNull:!0,references:{table:"payment_customers",column:"id"}},{name:"provider",type:"varchar",length:50,notNull:!0},{name:"provider_subscription_id",type:"varchar",length:255},{name:"status",type:"varchar",length:30,notNull:!0,default:"incomplete",enumValues:["active","past_due","unpaid","canceled","incomplete","incomplete_expired","trialing","paused"]},{name:"collection_method",type:"varchar",length:30,default:"charge_automatically",enumValues:["charge_automatically","send_invoice"]},{name:"current_period_start",type:"timestamptz"},{name:"current_period_end",type:"timestamptz"},{name:"cancel_at_period_end",type:"boolean",default:!1},{name:"canceled_at",type:"timestamptz"},{name:"trial_start",type:"timestamptz"},{name:"trial_end",type:"timestamptz"},{name:"items",type:"jsonb",default:"[]"},{name:"metadata",type:"jsonb",default:"{}"}],indexes:[{columns:["customer_id"]},{columns:["provider"]},{columns:["provider_subscription_id"]},{columns:["status"]},{columns:["customer_id","status"]}]},{table_name:"payment_invoices",feature_set:["payment"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:["DELETE"],columns:[{name:"customer_id",type:"uuid",notNull:!0,references:{table:"payment_customers",column:"id"}},{name:"subscription_id",type:"uuid",references:{table:"payment_subscriptions",column:"id"}},{name:"provider",type:"varchar",length:50,notNull:!0},{name:"provider_invoice_id",type:"varchar",length:255},{name:"status",type:"varchar",length:30,notNull:!0,default:"draft",enumValues:["draft","open","paid","uncollectible","void"]},{name:"collection_method",type:"varchar",length:30,default:"charge_automatically",enumValues:["charge_automatically","send_invoice"]},{name:"currency",type:"varchar",length:10,notNull:!0,default:"USD"},{name:"amount_due",type:"integer",default:0},{name:"amount_paid",type:"integer",default:0},{name:"amount_remaining",type:"integer",default:0},{name:"description",type:"text"},{name:"hosted_invoice_url",type:"varchar",length:1000},{name:"invoice_pdf",type:"varchar",length:1000},{name:"due_date",type:"timestamptz"},{name:"days_until_due",type:"integer"},{name:"period_start",type:"timestamptz"},{name:"period_end",type:"timestamptz"},{name:"paid_at",type:"timestamptz"},{name:"voided_at",type:"timestamptz"},{name:"lines",type:"jsonb",default:"[]"},{name:"metadata",type:"jsonb",default:"{}"}],indexes:[{columns:["customer_id"]},{columns:["subscription_id"]},{columns:["provider"]},{columns:["provider_invoice_id"]},{columns:["status"]},{columns:["customer_id","status"]}]},{table_name:"chat_conversations",feature_set:["authentication","chat"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:[],columns:[{name:"type",type:"varchar",length:20,notNull:!0,default:"direct",enumValues:["direct","group"]},{name:"title",type:"varchar",length:255},{name:"description",type:"text"},{name:"avatar_file_id",type:"uuid"},{name:"direct_key",type:"varchar",length:255},{name:"last_message_at",type:"timestamptz"},{name:"last_message_preview",type:"varchar",length:500},{name:"last_message_sender_id",type:"uuid",references:{table:"users",column:"id",onDelete:"set null"}}],indexes:[{columns:["direct_key"],unique:!0},{columns:["type"]},{columns:["last_message_at"]}]},{table_name:"chat_participants",feature_set:["authentication","chat"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:[],columns:[{name:"conversation_id",type:"uuid",notNull:!0,references:{table:"chat_conversations",column:"id",onDelete:"cascade"}},{name:"user_id",type:"uuid",notNull:!0,references:{table:"users",column:"id",onDelete:"cascade"}},{name:"role",type:"varchar",length:20,notNull:!0,default:"member",enumValues:["member","admin","owner"]},{name:"last_read_message_id",type:"uuid"},{name:"last_read_at",type:"timestamptz"},{name:"unread_count",type:"integer",notNull:!0,default:0},{name:"muted",type:"boolean",notNull:!0,default:!1},{name:"muted_until",type:"timestamptz"},{name:"notifications_enabled",type:"boolean",notNull:!0,default:!0},{name:"left_at",type:"timestamptz"}],indexes:[{columns:["user_id"]},{columns:["conversation_id"]}],constraints:{unique:[{name:"unique_conversation_participant",columns:["conversation_id","user_id"]}]}},{table_name:"chat_messages",feature_set:["authentication","chat"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:[],columns:[{name:"conversation_id",type:"uuid",notNull:!0,references:{table:"chat_conversations",column:"id",onDelete:"cascade"}},{name:"sender_id",type:"uuid",references:{table:"users",column:"id",onDelete:"set null"}},{name:"content",type:"text"},{name:"content_type",type:"varchar",length:20,notNull:!0,default:"text",enumValues:["text","image","file","video","audio","system"]},{name:"reply_to_id",type:"uuid",references:{table:"chat_messages",column:"id",onDelete:"set null"}},{name:"metadata",type:"jsonb",default:"{}"},{name:"client_message_id",type:"varchar",length:100},{name:"edited_at",type:"timestamptz"},{name:"deleted_at",type:"timestamptz"}],indexes:[{columns:["conversation_id","created_at"]},{columns:["sender_id"]},{columns:["reply_to_id"]}]},{table_name:"chat_message_attachments",feature_set:["authentication","chat","storage"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:[],columns:[{name:"message_id",type:"uuid",notNull:!0,references:{table:"chat_messages",column:"id",onDelete:"cascade"}},{name:"conversation_id",type:"uuid",notNull:!0,references:{table:"chat_conversations",column:"id",onDelete:"cascade"}},{name:"file_id",type:"uuid",notNull:!0,references:{table:"files",column:"id",onDelete:"cascade"}},{name:"kind",type:"varchar",length:20,notNull:!0,default:"file",enumValues:["image","video","audio","file"]},{name:"original_name",type:"varchar",length:255},{name:"mime_type",type:"varchar",length:100},{name:"size",type:"bigint",mode:"number"},{name:"width",type:"integer"},{name:"height",type:"integer"},{name:"duration",type:"integer"}],indexes:[{columns:["message_id"]},{columns:["conversation_id"]},{columns:["file_id"]}]},{table_name:"payment_splits",feature_set:["payment"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:["POST","PUT","PATCH","DELETE"],group_name:"Payments Marketplace",columns:[{name:"transaction_id",type:"uuid",references:{table:"paymentTransactions",column:"id",onDelete:"set null"}},{name:"recipient_owner_type",type:"varchar",length:20,notNull:!0,default:"seller",comment:"seller | platform | tenant | user"},{name:"recipient_owner_id",type:"uuid",notNull:!0},{name:"provider",type:"varchar",length:50,notNull:!0},{name:"gross_amount",type:"bigint",mode:"number",notNull:!0,comment:"Minor units"},{name:"provider_fee_amount",type:"bigint",mode:"number",notNull:!0,default:0},{name:"platform_fee_amount",type:"bigint",mode:"number",notNull:!0,default:0},{name:"reserve_amount",type:"bigint",mode:"number",notNull:!0,default:0},{name:"net_payable_amount",type:"bigint",mode:"number",notNull:!0},{name:"currency",type:"varchar",length:10,notNull:!0},{name:"available_for_payout_at",type:"timestamptz"},{name:"status",type:"varchar",length:20,notNull:!0,default:"pending",comment:"pending | available | payout_requested | paid | held | refunded | disputed | cancelled"},{name:"source_type",type:"varchar",length:50},{name:"source_id",type:"varchar",length:255},{name:"metadata",type:"jsonb",default:"{}"}],indexes:[{columns:["recipient_owner_type","recipient_owner_id"]},{columns:["status"]},{columns:["transaction_id"]}]},{table_name:"payment_ledger_entries",feature_set:["payment"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:["POST","PUT","PATCH","DELETE"],group_name:"Payments Marketplace",columns:[{name:"account",type:"varchar",length:40,notNull:!0,comment:"platform_revenue | provider_fee | seller_payable | reserve | refund_liability | dispute_liability | payout_in_transit | payout_completed"},{name:"owner_type",type:"varchar",length:20},{name:"owner_id",type:"uuid"},{name:"direction",type:"varchar",length:6,notNull:!0,comment:"debit | credit"},{name:"amount",type:"bigint",mode:"number",notNull:!0,comment:"Minor units"},{name:"currency",type:"varchar",length:10,notNull:!0},{name:"entry_type",type:"varchar",length:40,notNull:!0,comment:"split | refund | payout | reserve_hold | reserve_release | dispute | adjustment"},{name:"reference_type",type:"varchar",length:50},{name:"reference_id",type:"varchar",length:255},{name:"split_id",type:"uuid",references:{table:"paymentSplits",column:"id",onDelete:"set null"}},{name:"description",type:"text"},{name:"metadata",type:"jsonb",default:"{}"}],indexes:[{columns:["account"]},{columns:["owner_type","owner_id"]},{columns:["entry_type"]},{columns:["reference_type","reference_id"]}]},{table_name:"payment_settlement_policies",feature_set:["payment"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:[],group_name:"Payments Marketplace",columns:[{name:"owner_type",type:"varchar",length:20,notNull:!0,default:"tenant",comment:"tenant | seller"},{name:"owner_id",type:"uuid",notNull:!0},{name:"default_delay_days",type:"integer",notNull:!0,default:7},{name:"new_seller_delay_days",type:"integer",notNull:!0,default:14},{name:"reserve_rate",type:"numeric",precision:5,scale:4,notNull:!0,default:0,comment:"Fraction 0..1 held as reserve"},{name:"reserve_days",type:"integer",notNull:!0,default:0},{name:"minimum_payout_amount",type:"bigint",mode:"number",notNull:!0,default:0},{name:"currency",type:"varchar",length:10},{name:"early_payout_enabled",type:"boolean",notNull:!0,default:!1},{name:"status",type:"varchar",length:20,notNull:!0,default:"active"},{name:"metadata",type:"jsonb",default:"{}"}],indexes:[{columns:["owner_type","owner_id"],unique:!0}]},{table_name:"payment_reserves",feature_set:["payment"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:["POST","PUT","PATCH","DELETE"],group_name:"Payments Marketplace",columns:[{name:"owner_type",type:"varchar",length:20,notNull:!0,default:"seller"},{name:"owner_id",type:"uuid",notNull:!0},{name:"split_id",type:"uuid",references:{table:"paymentSplits",column:"id",onDelete:"set null"}},{name:"amount",type:"bigint",mode:"number",notNull:!0},{name:"currency",type:"varchar",length:10,notNull:!0},{name:"reason",type:"varchar",length:30,notNull:!0,default:"refund_window",comment:"refund_window | chargeback_risk | new_seller | manual_hold | dispute | compliance_review"},{name:"status",type:"varchar",length:20,notNull:!0,default:"held",comment:"held | released | consumed | cancelled"},{name:"release_at",type:"timestamptz"},{name:"released_at",type:"timestamptz"},{name:"metadata",type:"jsonb",default:"{}"}],indexes:[{columns:["owner_type","owner_id"]},{columns:["status"]},{columns:["release_at"]}]},{table_name:"payment_payout_requests",feature_set:["payment"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:["PUT"],group_name:"Payments Marketplace",columns:[{name:"recipient_owner_type",type:"varchar",length:20,notNull:!0,default:"seller"},{name:"recipient_owner_id",type:"uuid",notNull:!0},{name:"amount",type:"bigint",mode:"number",notNull:!0},{name:"currency",type:"varchar",length:10,notNull:!0},{name:"status",type:"varchar",length:20,notNull:!0,default:"pending",comment:"pending | approved | rejected | processing | completed | failed | cancelled"},{name:"provider",type:"varchar",length:50},{name:"provider_payout_id",type:"varchar",length:255},{name:"provider_transfer_id",type:"varchar",length:255},{name:"destination",type:"varchar",length:255},{name:"requested_by",type:"uuid"},{name:"decided_by",type:"uuid"},{name:"decided_at",type:"timestamptz"},{name:"completed_at",type:"timestamptz"},{name:"failure_reason",type:"text"},{name:"metadata",type:"jsonb",default:"{}"}],indexes:[{columns:["recipient_owner_type","recipient_owner_id"]},{columns:["status"]}]},{table_name:"payment_disputes",feature_set:["payment"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:["PUT"],group_name:"Payments Marketplace",columns:[{name:"transaction_id",type:"uuid",references:{table:"paymentTransactions",column:"id",onDelete:"set null"}},{name:"provider",type:"varchar",length:50,notNull:!0},{name:"provider_dispute_id",type:"varchar",length:255},{name:"owner_type",type:"varchar",length:20},{name:"owner_id",type:"uuid"},{name:"amount",type:"bigint",mode:"number"},{name:"currency",type:"varchar",length:10},{name:"reason",type:"varchar",length:100},{name:"status",type:"varchar",length:30,notNull:!0,default:"open",comment:"open | under_review | won | lost | accepted | cancelled"},{name:"evidence_due_at",type:"timestamptz"},{name:"resolved_at",type:"timestamptz"},{name:"metadata",type:"jsonb",default:"{}"}],indexes:[{columns:["provider","provider_dispute_id"]},{columns:["status"]},{columns:["owner_type","owner_id"]},{columns:["transaction_id"]}]},{table_name:"nucleus_secrets",feature_set:["secrets"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:["GET","POST","PUT","PATCH","DELETE","TOGGLE"],bulk_endpoints_enabled:!1,group_name:"Secrets",columns:[{name:"scope",type:"varchar",length:200,notNull:!0,comment:"Config dot-path that owns the credential, e.g. authentication.oauth.providers.microsoft"},{name:"key",type:"varchar",length:120,notNull:!0,comment:"Leaf key under that path, e.g. clientSecret"},{name:"value_enc",type:"text",notNull:!0,comment:"AES-256-GCM envelope v1:iv:tag:ciphertext \u2014 never returned by any route"},{name:"previous_enc",type:"text",comment:"Value replaced by the last rotation, retained for one-step rollback"},{name:"preview",type:"varchar",length:80},{name:"kind",type:"varchar",length:30,notNull:!0,default:"text",enumValues:["text","password","json","connection_string","pem"]},{name:"description",type:"varchar",length:500},{name:"version",type:"integer",notNull:!0,default:1},{name:"rotated_at",type:"timestamptz"},{name:"last_used_at",type:"timestamptz"}],indexes:[{columns:["scope","key"],unique:!0},{columns:["scope"]}]},{table_name:"integration_sources",feature_set:["integrations"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:[],bulk_endpoints_enabled:!1,group_name:"Integrations",columns:[{name:"name",type:"varchar",length:150,notNull:!0},{name:"slug",type:"varchar",length:150,notNull:!0,comment:"Stable machine name; referenced by exports and by operators in logs"},{name:"base_url",type:"varchar",length:500,notNull:!0,comment:"Any scheme, host and port \u2014 https, plain http, in-cluster DNS, IP. HTTPS is NOT required and must never be enforced: reaching a service inside the same cluster over http is a legitimate deployment."},{name:"description",type:"text"},{name:"enabled",type:"boolean",default:!0},{name:"auth_type",type:"varchar",length:20,notNull:!0,default:"none",enumValues:["none","bearer","api_key","basic","oauth2"]},{name:"auth_token_encrypted",type:"text",sensitive:!0,comment:"Static credential (bearer / api key / basic blob), encrypted at rest"},{name:"auth_token_hint",type:"varchar",length:24},{name:"auth_header_name",type:"varchar",length:80,default:"Authorization"},{name:"auth_query_param",type:"varchar",length:80,comment:"When set, an api_key credential travels as this query parameter instead of a header"},{name:"extra_headers",type:"jsonb",default:{}},{name:"token_url",type:"varchar",length:500},{name:"oauth_grant_type",type:"varchar",length:40,default:"password",enumValues:["password","client_credentials"]},{name:"oauth_client_id",type:"varchar",length:200},{name:"oauth_client_secret_encrypted",type:"text",sensitive:!0},{name:"oauth_client_secret_hint",type:"varchar",length:24},{name:"oauth_username",type:"varchar",length:200},{name:"oauth_password_encrypted",type:"text",sensitive:!0},{name:"oauth_password_hint",type:"varchar",length:24},{name:"oauth_scope",type:"varchar",length:300},{name:"oauth_client_auth",type:"varchar",length:20,default:"basic",enumValues:["basic","body"]},{name:"tls_verify",type:"boolean",notNull:!0,default:!0,comment:"Per-source certificate verification. Turning it off applies to THIS source's connections only \u2014 never to the process, which is what a NODE_TLS_REJECT_UNAUTHORIZED toggle would do."},{name:"timeout_ms",type:"integer",notNull:!0,default:30000},{name:"spec_url",type:"varchar",length:500,comment:"Optional API description document (OpenAPI/Swagger/Postman/Bruno). Discovery is a convenience: every endpoint can always be defined by hand instead."},{name:"spec_format",type:"varchar",length:20,default:"manual",enumValues:["manual","openapi","swagger","postman","bruno","har"]}],constraints:{unique:[{name:"uniq_integration_source_slug",columns:["slug"]}]},indexes:[{columns:["enabled"]}]},{table_name:"integration_endpoints",feature_set:["integrations"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:[],bulk_endpoints_enabled:!1,group_name:"Integrations",columns:[{name:"source_id",type:"uuid",notNull:!0,references:{table:"integrationSources",column:"id",onDelete:"cascade"}},{name:"tag",type:"varchar",length:120,notNull:!0},{name:"name",type:"varchar",length:200},{name:"method",type:"varchar",length:10,notNull:!0,default:"GET",enumValues:["GET","POST","PUT","PATCH","DELETE"]},{name:"path",type:"varchar",length:500,notNull:!0,comment:"Appended to the source base URL. May carry {brace} or :colon path tokens, whose values come from param_bindings."},{name:"description",type:"text"},{name:"query_params",type:"jsonb",default:{}},{name:"request_body",type:"jsonb",default:{}},{name:"param_bindings",type:"jsonb",default:[],comment:"Where each path/query parameter comes from: a static value, another endpoint's records (fan-out), or a column of one of our own tables."},{name:"pagination",type:"jsonb",default:{},comment:"Explicitly chosen paging profile (none/page_number/offset/cursor/link_header). Never guessed \u2014 a wrong guess silently imports one page."},{name:"response_root_path",type:"varchar",length:200},{name:"sample_response",type:"jsonb",default:{},comment:"A few real records captured by a live test, so the mapping screen still shows fields when the source is unreachable"},{name:"enabled",type:"boolean",default:!0}],indexes:[{columns:["source_id"]},{columns:["source_id","tag"]}]},{table_name:"integration_mappings",feature_set:["integrations"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:[],bulk_endpoints_enabled:!1,group_name:"Integrations",columns:[{name:"endpoint_id",type:"uuid",notNull:!0,references:{table:"integrationEndpoints",column:"id",onDelete:"cascade"}},{name:"name",type:"varchar",length:200,notNull:!0},{name:"target_entity",type:"varchar",length:120,notNull:!0,comment:"snake_case table name this mapping writes into"},{name:"field_mappings",type:"jsonb",notNull:!0,default:[]},{name:"dedup_source_field",type:"varchar",length:200},{name:"dedup_target_field",type:"varchar",length:200,comment:"Target column that identifies the same record across runs. Without it nothing can be matched and every run appends."},{name:"write_mode",type:"varchar",length:20,notNull:!0,default:"upsert",enumValues:["upsert","append","replace"],comment:"replace is the destructive wipe-and-rewrite; it is no longer the default and is gated by the completeness check."},{name:"missing_record_policy",type:"varchar",length:20,notNull:!0,default:"ignore",enumValues:["ignore","deactivate","delete"],comment:"What happens to a row that exists here but no longer in the source. deactivate is the right answer for most HR data and could not be expressed before."},{name:"missing_record_column",type:"varchar",length:120},{name:"missing_record_value",type:"varchar",length:200},{name:"schedule_cron",type:"varchar",length:120},{name:"schedule_timezone",type:"varchar",length:64,comment:"IANA zone the cron expression is read in. Without it a nightly job drifts with the container's clock."},{name:"schedule_enabled",type:"boolean",notNull:!0,default:!1},{name:"last_run_at",type:"timestamptz"},{name:"enabled",type:"boolean",default:!0}],indexes:[{columns:["endpoint_id"]},{columns:["target_entity"]},{columns:["schedule_enabled"]}]},{table_name:"integration_runs",feature_set:["integrations"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:["POST","PUT","PATCH","DELETE"],bulk_endpoints_enabled:!1,group_name:"Integrations",columns:[{name:"mapping_id",type:"uuid",references:{table:"integrationMappings",column:"id",onDelete:"set null"},comment:"Nullable and NOT cascaded: deleting a mapping must not erase the record that it once rewrote a table."},{name:"target_entity",type:"varchar",length:120},{name:"write_mode",type:"varchar",length:20,enumValues:["upsert","append","replace"]},{name:"status",type:"varchar",length:20,notNull:!0,default:"queued",enumValues:["queued","running","succeeded","failed","cancelled","reverted"],comment:"There is deliberately no 'partial': a run either applied in full or not at all."},{name:"trigger",type:"varchar",length:20,notNull:!0,default:"manual",enumValues:["manual","schedule","api"]},{name:"total_fetched",type:"integer",notNull:!0,default:0},{name:"source_reported_total",type:"integer",comment:"What the source said it had. When this and total_fetched disagree, a destructive run refuses to start."},{name:"created_count",type:"integer",notNull:!0,default:0},{name:"updated_count",type:"integer",notNull:!0,default:0},{name:"skipped_count",type:"integer",notNull:!0,default:0},{name:"deleted_count",type:"integer",notNull:!0,default:0},{name:"deactivated_count",type:"integer",notNull:!0,default:0},{name:"error_count",type:"integer",notNull:!0,default:0},{name:"external_call_count",type:"integer",notNull:!0,default:0},{name:"issues",type:"jsonb",default:[]},{name:"errors",type:"jsonb",default:[]},{name:"cancel_requested",type:"boolean",notNull:!0,default:!1,comment:"Set by the cancel endpoint; the engine checks it at every batch boundary. A dropped HTTP connection is NOT a cancellation."},{name:"started_at",type:"timestamptz"},{name:"finished_at",type:"timestamptz"},{name:"pre_images_expire_at",type:"timestamptz",comment:"After this, the run can no longer be reverted and the UI says so rather than offering a button that quietly does nothing."},{name:"reverted_at",type:"timestamptz"},{name:"reverted_by",type:"uuid",references:{table:"users",column:"id"}},{name:"reverted_run_id",type:"uuid"}],indexes:[{columns:["mapping_id"]},{columns:["status"]},{columns:["target_entity"]},{columns:["created_at"]}]},{table_name:"integration_run_items",feature_set:["integrations"],add_base_columns:!0,is_form_data:!1,available_app_ids:["default_be"],available_schemas:["*"],excluded_schemas:[],excluded_methods:["POST","PUT","PATCH","DELETE"],bulk_endpoints_enabled:!1,group_name:"Integrations",columns:[{name:"run_id",type:"uuid",notNull:!0,references:{table:"integrationRuns",column:"id",onDelete:"cascade"}},{name:"target_entity",type:"varchar",length:120,notNull:!0},{name:"row_id",type:"uuid"},{name:"action",type:"varchar",length:20,notNull:!0,enumValues:["create","update","delete","deactivate"]},{name:"before",type:"jsonb",comment:"The row as it stood before this run touched it. This is what makes a successful run reversible; the bulk delete path already produced these rows and threw them away."},{name:"after",type:"jsonb"}],indexes:[{columns:["run_id"]},{columns:["run_id","action"]},{columns:["target_entity","row_id"]}]}];import{batch as batch2,createStore as createStore2}from"h-state";var initialState={connection:{status:"disconnected",clientId:null,subscribedTopics:[],error:null,reconnectAttempt:0},events:[],maxEvents:100},{useStore:usePubSubStore}=createStore2(initialState,{setConnectionStatus:(store)=>(status)=>{store.connection.status=status},setClientId:(store)=>(clientId)=>{store.connection.clientId=clientId},setSubscribedTopics:(store)=>(topics)=>{store.connection.subscribedTopics=topics},setError:(store)=>(error)=>{store.connection.error=error},setReconnectAttempt:(store)=>(attempt)=>{store.connection.reconnectAttempt=attempt},addEvent:(store)=>(event)=>{let updated=[event,...store.events];store.events=updated.slice(0,store.maxEvents)},clearEvents:(store)=>()=>{store.events=[]},reset:(store)=>()=>{batch2(()=>{store.connection.status="disconnected",store.connection.clientId=null,store.connection.subscribedTopics=[],store.connection.error=null,store.connection.reconnectAttempt=0,store.events=[]})}});import{useEffect}from"react";function buildWsUrl(config){let path=config.wsPath||"/api/events/subscribe",topics=(config.topics||["*"]).join(","),query=`?userId=${encodeURIComponent(config.userId)}&topics=${encodeURIComponent(topics)}`;if(config.wsUrl)return`${config.wsUrl.replace(/\/$/,"")}${path}${query}`;if(typeof window>"u")return"";return`${window.location.protocol==="https:"?"wss:":"ws:"}//${window.location.host}${path}${query}`}var connections=new Map,eventIdCounter=0;function log(conn,...args){if(conn.options.debug)console.log("[usePubSub]",...args)}function clearTimers(conn){if(conn.heartbeat)clearInterval(conn.heartbeat),conn.heartbeat=null;if(conn.reconnectTimeout)clearTimeout(conn.reconnectTimeout),conn.reconnectTimeout=null}function detachSocket(conn){let ws=conn.ws;if(!ws)return;if(ws.onopen=null,ws.onmessage=null,ws.onerror=null,ws.onclose=null,ws.readyState===WebSocket.OPEN||ws.readyState===WebSocket.CONNECTING)ws.close();conn.ws=null}function startHeartbeat(conn){if(conn.heartbeat)clearInterval(conn.heartbeat);conn.heartbeat=setInterval(()=>{if(conn.ws?.readyState===WebSocket.OPEN)conn.ws.send(JSON.stringify({type:"ping"}))},conn.options.heartbeatInterval)}function scheduleReconnect(conn){if(!conn.options.autoReconnect)return;if(connections.get(conn.url)!==conn)return;if(conn.reconnectAttempt>=conn.options.maxReconnectAttempts){conn.dispatch.setConnectionStatus("disconnected"),conn.dispatch.setError(Error("Max reconnection attempts reached")),log(conn,"Max reconnect attempts reached");return}let delay=Math.min(conn.options.reconnectBaseDelay*2**conn.reconnectAttempt,conn.options.reconnectMaxDelay);if(conn.reconnectAttempt+=1,conn.dispatch.setConnectionStatus("reconnecting"),conn.dispatch.setReconnectAttempt(conn.reconnectAttempt),log(conn,`Reconnecting in ${delay}ms (attempt ${conn.reconnectAttempt})`),conn.reconnectTimeout)clearTimeout(conn.reconnectTimeout);conn.reconnectTimeout=setTimeout(()=>{if(connections.get(conn.url)===conn)openSocket(conn)},delay)}function handleMessage(conn,raw){let message;try{message=JSON.parse(raw)}catch{log(conn,"Failed to parse message");return}switch(message.type){case"connected":conn.reconnectAttempt=0,conn.dispatch.setConnectionStatus("connected"),conn.dispatch.setClientId(message.clientId),conn.dispatch.setSubscribedTopics(message.subscribedTopics),conn.dispatch.setReconnectAttempt(0),conn.dispatch.setError(null),log(conn,"Connected, clientId:",message.clientId);break;case"subscribed":conn.dispatch.setSubscribedTopics(message.topics),log(conn,"Subscribed to:",message.topics);break;case"event":{if(conn.dispatch.addEvent({id:`evt_${Date.now()}_${eventIdCounter++}`,topic:message.topic,data:message.data,timestamp:message.timestamp,receivedAt:Date.now(),messageId:message.messageId,isRedelivery:message.isRedelivery}),message.messageId&&conn.ws?.readyState===WebSocket.OPEN)conn.ws.send(JSON.stringify({type:"ack",messageId:message.messageId}));break}case"pong":break;case"error":conn.dispatch.setError(Error(message.error)),log(conn,"Server error:",message.error);break}}function openSocket(conn){if(conn.ws?.readyState===WebSocket.OPEN||conn.ws?.readyState===WebSocket.CONNECTING)return;detachSocket(conn),conn.dispatch.setConnectionStatus("connecting"),conn.dispatch.setError(null),log(conn,"Connecting to:",conn.url);let ws=new WebSocket(conn.url);conn.ws=ws,ws.onopen=()=>{log(conn,"WebSocket opened"),startHeartbeat(conn)},ws.onmessage=(event)=>handleMessage(conn,event.data),ws.onerror=()=>{log(conn,"WebSocket error"),conn.dispatch.setError(Error("WebSocket connection error"))},ws.onclose=(event)=>{if(log(conn,"WebSocket closed",event.code,event.reason),conn.heartbeat)clearInterval(conn.heartbeat),conn.heartbeat=null;if(conn.dispatch.setConnectionStatus("disconnected"),conn.dispatch.setClientId(null),connections.get(conn.url)===conn&&event.code!==4001)scheduleReconnect(conn)}}function acquire(url,dispatch,options){let conn=connections.get(url);if(!conn)conn={url,ws:null,refCount:0,reconnectAttempt:0,heartbeat:null,reconnectTimeout:null,dispatch,options},connections.set(url,conn);else conn.dispatch=dispatch,conn.options=options;conn.refCount+=1,openSocket(conn)}function release(url){let conn=connections.get(url);if(!conn)return;if(conn.refCount-=1,conn.refCount>0)return;connections.delete(url),clearTimers(conn),detachSocket(conn),conn.dispatch.setConnectionStatus("disconnected"),conn.dispatch.setClientId(null)}function send(url,payload){let ws=connections.get(url)?.ws;if(ws?.readyState===WebSocket.OPEN)ws.send(JSON.stringify(payload))}function usePubSub(config){let store=usePubSubStore(),url=config.userId?buildWsUrl(config):"";return useEffect(()=>{if(!url)return;let dispatch={setConnectionStatus:store.setConnectionStatus,setClientId:store.setClientId,setSubscribedTopics:store.setSubscribedTopics,setError:store.setError,setReconnectAttempt:store.setReconnectAttempt,addEvent:store.addEvent},options={autoReconnect:config.autoReconnect??!0,maxReconnectAttempts:config.maxReconnectAttempts??10,reconnectBaseDelay:config.reconnectBaseDelay??1000,reconnectMaxDelay:config.reconnectMaxDelay??30000,heartbeatInterval:config.heartbeatInterval??30000,debug:config.debug??!1};return acquire(url,dispatch,options),()=>release(url)},[url]),{isConnected:store.connection.status==="connected",isConnecting:store.connection.status==="connecting"||store.connection.status==="reconnecting",clientId:store.connection.clientId,subscribedTopics:store.connection.subscribedTopics,events:store.events,error:store.connection.error,reconnectAttempt:store.connection.reconnectAttempt,connect:()=>{let conn=connections.get(url);if(conn)openSocket(conn)},disconnect:()=>release(url),subscribe:(topics)=>send(url,{type:"subscribe",topics}),unsubscribe:(topics)=>send(url,{type:"unsubscribe",topics}),clearEvents:store.clearEvents,getEventsByTopic:(topic)=>store.events.filter((e)=>e.topic===topic)}}import{createHash as createHash4,randomUUID as randomUUID8}from"crypto";var import_fast_decode_uri_component=__toESM(require_fast_decode_uri_component(),1);import{Elysia,NotFoundError}from"elysia";var fs,path,isBun=typeof Bun<"u"&&!!Bun.file;function getBuiltinModule(){if(fs||(fs=process.getBuiltinModule("fs/promises")),path||(path=process.getBuiltinModule("path")),!path){console.warn("@elysiajs/static require path to be available.");return}return[fs,path]}async function listHTMLFiles(dir){if(fs||getBuiltinModule(),isBun){let glob=new Bun.Glob("**/*.html"),files=[];for await(let file of glob.scan(dir))files.push(path.join(dir,file));return files}return[]}async function listFiles(dir){if(fs||getBuiltinModule(),isBun){let glob=new Bun.Glob("**/*"),files2=[];for await(let file of glob.scan(dir))files2.push(path.join(dir,file));return files2}let files=await fs.readdir(dir).catch(()=>[]);return(await Promise.all(files.map(async(name)=>{let file=dir+path.sep+name,stats=await fs.stat(file).catch(()=>null);return stats?stats.isDirectory()?await listFiles(file):[path.resolve(dir,file)]:[]}))).flat()}function fileExists(path2){return fs||getBuiltinModule(),fs.stat(path2).then(()=>!0,()=>!1)}class LRUCache{constructor(max=250,ttl=10800){this.max=max,this.ttl=ttl,this.map=new Map}get(key){let entry=this.map.get(key);if(entry)return entry[1]<=Date.now()?void this.delete(key):(this.map.delete(key),this.map.set(key,entry),entry[0])}set(key,value){if(this.interval||(this.interval=setInterval(()=>{let now=Date.now();for(let[key2,entry]of this.map)entry[1]<=now&&this.map.delete(key2)},this.ttl)),this.map.has(key))this.map.delete(key);else if(this.map.size>=this.max){let oldestKey=this.map.keys().next().value;oldestKey!==void 0&&this.delete(oldestKey)}this.map.set(key,[value,Date.now()+this.ttl*1000])}delete(key){this.map.get(key)&&this.map.delete(key)}clear(){this.map.clear()}size(){return this.map.size}[Symbol.dispose](){this.interval&&clearInterval(this.interval)}}function isCached(headers,etag,filePath){if(headers["cache-control"]&&/no-cache|no-store/.test(headers["cache-control"]))return!1;if("if-none-match"in headers){let ifNoneMatch=headers["if-none-match"];return ifNoneMatch==="*"?!0:ifNoneMatch===null||typeof etag!="string"?!1:ifNoneMatch===etag}if(headers["if-modified-since"]){let ifModifiedSince=headers["if-modified-since"];try{return fs.stat(filePath).then((stat)=>{if(stat.mtime!==void 0&&stat.mtime.getTime()<=Date.parse(ifModifiedSince))return!0})}catch{}}return!1}var Crypto;function getFile(path2){return isBun?Bun.file(path2):(fs||getBuiltinModule(),fs.readFile(path2))}async function generateETag(file){return isBun?new Bun.CryptoHasher("md5").update(await file.arrayBuffer()).digest("base64"):(Crypto||(Crypto=process.getBuiltinModule("crypto")),Crypto?Crypto.createHash("md5").update(file).digest("base64"):void console.warn("[@elysiajs/static] crypto is required to generate etag."))}var isNotEmpty=(obj)=>{if(!obj)return!1;for(let _ in obj)return!0;return!1};async function staticPlugin({assets="public",prefix="/public",staticLimit=1024,alwaysStatic=!1,ignorePatterns=[".DS_Store",".git",".env"],headers:initialHeaders,maxAge=86400,directive="public",etag:useETag=!0,extension=!0,indexHTML=!0,decodeURI,silent}={}){if(typeof process>"u"||typeof process.getBuiltinModule>"u")return silent||console.warn("[@elysiajs/static] require process.getBuiltinModule. Static plugin is disabled"),new Elysia;let builtinModule=getBuiltinModule();if(!builtinModule)return new Elysia;let[fs2,path2]=builtinModule,normalizePath=path2.sep!=="/"?(p)=>p.replace(/\\/g,"/"):(p)=>p,fileCache=new LRUCache;prefix===path2.sep&&(prefix="");let assetsDir=path2.resolve(assets),shouldIgnore=ignorePatterns.length?(file)=>ignorePatterns.find((pattern)=>typeof pattern=="string"?pattern.includes(file):pattern.test(file)):()=>!1,app=new Elysia({name:"static",seed:prefix});if(alwaysStatic){let files=await listFiles(path2.resolve(assets));if(files.length<=staticLimit)for(let absolutePath of files){let handleCache2=function({headers:requestHeaders}){if(etag){let cached=isCached(requestHeaders,etag,absolutePath);if(cached===!0)return new Response(null,{status:304,headers:isNotEmpty(initialHeaders)?initialHeaders:void 0});if(cached!==!1){let cache2=fileCache.get(pathName);return cache2?cache2.clone():cached.then((cached2)=>{if(cached2)return new Response(null,{status:304,headers:initialHeaders||void 0});let response2=new Response(file,{headers:Object.assign({"Cache-Control":maxAge?`${directive}, max-age=${maxAge}`:directive},initialHeaders,etag?{Etag:etag}:{})});return fileCache.set(prefix,response2),response2.clone()})}}let cache=fileCache.get(pathName);if(cache)return cache.clone();let response=new Response(file,{headers:Object.assign({"Cache-Control":maxAge?`${directive}, max-age=${maxAge}`:directive},initialHeaders,etag?{Etag:etag}:{})});return fileCache.set(pathName,response),response.clone()};var handleCache=handleCache2;if(!absolutePath||shouldIgnore(absolutePath))continue;let relativePath=absolutePath.replace(assetsDir,"");decodeURI&&(relativePath=import_fast_decode_uri_component.default(relativePath)??relativePath);let pathName=normalizePath(path2.join(prefix,relativePath));if(isBun&&absolutePath.endsWith(".html")){let htmlBundle=await import(absolutePath);app.get(pathName,htmlBundle.default),indexHTML&&pathName.endsWith("/index.html")&&app.get(pathName.replace("/index.html",""),htmlBundle.default);continue}extension||(pathName=normalizePath(pathName.slice(0,pathName.lastIndexOf("."))));let file=isBun?getFile(absolutePath):await getFile(absolutePath);if(!file)return silent||console.warn(`[@elysiajs/static] Failed to load file: ${absolutePath}`),new Elysia;let etag=await generateETag(file);app.get(pathName,useETag?handleCache2:new Response(file,isNotEmpty(initialHeaders)?{headers:initialHeaders}:void 0)),indexHTML&&pathName.endsWith("/index.html")&&app.get(pathName.replace("/index.html",""),useETag?handleCache2:new Response(file,isNotEmpty(initialHeaders)?{headers:initialHeaders}:void 0))}return app}if(!(`GET_${prefix}/*`in app.routeTree)){if(isBun){let htmls=await listHTMLFiles(path2.resolve(assets));for(let absolutePath of htmls){if(!absolutePath||shouldIgnore(absolutePath))continue;let relativePath=absolutePath.replace(assetsDir,""),pathName=normalizePath(path2.join(prefix,relativePath)),htmlBundle=await import(absolutePath);app.get(pathName,htmlBundle.default),indexHTML&&pathName.endsWith("/index.html")&&app.get(pathName.replace("/index.html",""),htmlBundle.default)}}app.onError(()=>{}).get(`${prefix.endsWith("/")?prefix.slice(0,-1):prefix}/*`,async({params,headers:requestHeaders})=>{let pathName=normalizePath(path2.join(assets,decodeURI?import_fast_decode_uri_component.default(params["*"])??params["*"]:params["*"]));if(shouldIgnore(pathName))throw new NotFoundError;let cache=fileCache.get(pathName);if(cache)return cache.clone();try{let fileStat=await fs2.stat(pathName).catch(()=>null);if(!fileStat)throw new NotFoundError;if(!indexHTML&&fileStat.isDirectory())throw new NotFoundError;let file;if(!isBun&&indexHTML){let htmlPath=path2.join(pathName,"index.html"),cache2=fileCache.get(htmlPath);if(cache2)return cache2.clone();await fileExists(htmlPath)&&(file=await getFile(htmlPath))}if(!file&&!fileStat.isDirectory()&&await fileExists(pathName))file=await getFile(pathName);else throw new NotFoundError;if(!useETag)return new Response(file,isNotEmpty(initialHeaders)?{headers:initialHeaders}:void 0);let etag=await generateETag(file);if(etag&&await isCached(requestHeaders,etag,pathName))return new Response(null,{status:304});let response=new Response(file,{headers:Object.assign({"Cache-Control":maxAge?`${directive}, max-age=${maxAge}`:directive},initialHeaders,etag?{Etag:etag}:{})});return fileCache.set(pathName,response),response.clone()}catch(error){throw error instanceof NotFoundError?error:(silent||console.error("[@elysiajs/static]",error),new NotFoundError)}})}return app}import{pushSchema}from"drizzle-kit/api";import{and as and23,eq as eq61,lt as lt3,sql as sql12}from"drizzle-orm";import{drizzle as drizzle2}from"drizzle-orm/node-postgres";import{pgSchema as pgSchema2}from"drizzle-orm/pg-core";import Elysia49 from"elysia";import{join as join3}from"path";class LiveStorageProvider{resolve;constructor(resolve){this.resolve=resolve}get kind(){return this.resolve().kind}get describe(){return this.resolve().describe}isAvailable(){return this.resolve().isAvailable()}exists(relativePath){return this.resolve().exists(relativePath)}stat(relativePath){return this.resolve().stat(relativePath)}read(relativePath){return this.resolve().read(relativePath)}write(relativePath,data){return this.resolve().write(relativePath,data)}delete(relativePath){return this.resolve().delete(relativePath)}ensureDir(relativeDir){return this.resolve().ensureDir(relativeDir)}list(relativeDir){return this.resolve().list(relativeDir)}localPath(relativePath){return this.resolve().localPath(relativePath)}close(){return this.resolve().close()}}import{mkdir,readdir,stat,unlink}from"fs/promises";import{dirname,join}from"path";function normalizeRelativePath(relativePath){let cleaned=relativePath.replace(/\\/g,"/").replace(/^\/+/,""),segments=[];for(let segment of cleaned.split("/")){if(!segment||segment===".")continue;if(segment==="..")throw Error(`Path traversal rejected: ${relativePath}`);segments.push(segment)}return segments.join("/")}class LocalStorageProvider{kind="local";describe;basePath;constructor(basePath,_deps){this.basePath=basePath,this.describe=`local:${basePath}`}resolve(relativePath){return join(this.basePath,normalizeRelativePath(relativePath))}async isAvailable(){try{return await mkdir(this.basePath,{recursive:!0}),!0}catch{return!1}}async exists(relativePath){return Bun.file(this.resolve(relativePath)).exists()}async stat(relativePath){try{let info=await stat(this.resolve(relativePath));return{size:info.size,modifiedAt:info.mtime,isDirectory:info.isDirectory()}}catch{return null}}async read(relativePath){let file=Bun.file(this.resolve(relativePath));if(!await file.exists())return null;return Buffer.from(await file.arrayBuffer())}async write(relativePath,data){let full=this.resolve(relativePath);await mkdir(dirname(full),{recursive:!0}),await Bun.write(full,data)}async delete(relativePath){try{return await unlink(this.resolve(relativePath)),!0}catch{return!1}}async ensureDir(relativeDir){await mkdir(this.resolve(relativeDir),{recursive:!0})}async list(relativeDir){try{return await readdir(this.resolve(relativeDir))}catch{return[]}}async localPath(relativePath){let full=this.resolve(relativePath);return await Bun.file(full).exists()?full:null}async close(){}}import{stat as fsStat,mkdir as mkdir2,rename,unlink as unlink2}from"fs/promises";import{dirname as dirname2,join as join2}from"path";var DEFAULT_TIMEOUT_MS=15000,DEFAULT_CACHE_TTL_SECONDS=300;class SmbStorageProvider{kind="smb";describe;getConfig;logger;client=null;clientFingerprint="";cacheDir;cacheTtlMs;cacheEnabled;inFlight=new Map;constructor(getConfig,deps,defaultCacheDir){this.getConfig=getConfig,this.logger=deps.logger;let config=getConfig();this.cacheEnabled=config.cache?.enabled!==!1,this.cacheDir=config.cache?.path||defaultCacheDir,this.cacheTtlMs=(config.cache?.ttlSeconds??DEFAULT_CACHE_TTL_SECONDS)*1000,this.describe=`smb://${config.host}/${config.share}${config.basePath?`/${config.basePath}`:""}`}async getClient(){let{host,share,domain,username,password,port,timeoutMs}=this.getConfig(),fingerprint=`${host}|${share}|${domain}|${username}|${password}|${port}`;if(this.client&&fingerprint===this.clientFingerprint)return this.client;if(this.client){try{this.client.disconnect()}catch{}this.client=null}let imported=await Promise.resolve().then(() => __toESM(require_smb2(),1)).catch(()=>{throw Error('storage.provider is "smb" but the optional @marsaud/smb2 dependency is not installed \u2014 run: bun add @marsaud/smb2')}),SMB2=imported.default??imported;return this.client=new SMB2({share:`\\\\${host}\\${share}`,domain:domain||"WORKGROUP",username,password,port:port??445,autoCloseTimeout:timeoutMs??DEFAULT_TIMEOUT_MS}),this.clientFingerprint=fingerprint,this.client}async call(fn){let client=await this.getClient(),timeoutMs=this.getConfig().timeoutMs??DEFAULT_TIMEOUT_MS;return new Promise((resolve,reject)=>{let settled=!1,timer=setTimeout(()=>{if(settled)return;settled=!0,reject(Error(`SMB operation timed out after ${timeoutMs}ms (${this.describe})`))},timeoutMs);fn(client,(err,value)=>{if(settled)return;if(settled=!0,clearTimeout(timer),err)reject(err);else resolve(value)})})}remotePath(relativePath){let normalized=normalizeRelativePath(relativePath),configuredBase=this.getConfig().basePath,base=configuredBase?normalizeRelativePath(configuredBase):"";return(base?`${base}/${normalized}`:normalized).replace(/\//g,"\\")}cachePath(relativePath){return join2(this.cacheDir,normalizeRelativePath(relativePath))}async isAvailable(){try{return await this.call((client,cb)=>client.readdir(this.getConfig().basePath?this.remotePath(""):"",cb)),!0}catch(error){return this.logger.warn("[Storage/SMB] Share is not reachable",{target:this.describe,error:error instanceof Error?error.message:String(error)}),!1}}async exists(relativePath){try{return await this.call((client,cb)=>client.exists(this.remotePath(relativePath),cb))}catch{return!1}}async stat(relativePath){try{let info=await this.call((client,cb)=>client.stat(this.remotePath(relativePath),cb));return{size:Number(info.size),modifiedAt:new Date(info.mtime),isDirectory:typeof info.isDirectory==="function"?info.isDirectory():await this.looksLikeDirectory(relativePath)}}catch{return null}}async read(relativePath){try{return await this.call((client,cb)=>client.readFile(this.remotePath(relativePath),cb))}catch(error){return this.logger.warn("[Storage/SMB] Read failed",{path:relativePath,error:error instanceof Error?error.message:String(error)}),null}}async write(relativePath,data){let parent=normalizeRelativePath(relativePath).split("/").slice(0,-1).join("/");if(parent)await this.ensureDir(parent);let payload=typeof data==="string"?Buffer.from(data,"utf-8"):Buffer.from(data);if(await this.call((client,cb)=>client.writeFile(this.remotePath(relativePath),payload,cb)),this.cacheEnabled){let target=this.cachePath(relativePath);await mkdir2(dirname2(target),{recursive:!0}).catch(()=>{}),await Bun.write(target,payload).catch(()=>{})}}async delete(relativePath){try{if(await this.call((client,cb)=>client.unlink(this.remotePath(relativePath),cb)),this.cacheEnabled)await unlink2(this.cachePath(relativePath)).catch(()=>{});return!0}catch{return!1}}async ensureDir(relativeDir){let normalized=normalizeRelativePath(relativeDir);if(!normalized)return;let segments=normalized.split("/");for(let i=1;i<=segments.length;i++){let partial=segments.slice(0,i).join("/");try{await this.call((client,cb)=>client.mkdir(this.remotePath(partial),cb))}catch{}}}async looksLikeDirectory(relativePath){try{return await this.call((client,cb)=>client.readdir(this.remotePath(relativePath),cb)),!0}catch{return!1}}async list(relativeDir){try{return await this.call((client,cb)=>client.readdir(this.remotePath(relativeDir),cb))}catch{return[]}}async localPath(relativePath){if(!this.cacheEnabled)return null;let target=this.cachePath(relativePath),cached=await fsStat(target).catch(()=>null);if(cached&&Date.now()-cached.mtimeMs<this.cacheTtlMs)return target;let pending=this.inFlight.get(target);if(pending)return pending;let download=(async()=>{let data=await this.read(relativePath);if(!data)return null;await mkdir2(dirname2(target),{recursive:!0}).catch(()=>{});let tmp=`${target}.${process.pid}.tmp`;try{return await Bun.write(tmp,data),await rename(tmp,target),target}catch(error){return await unlink2(tmp).catch(()=>{}),this.logger.warn("[Storage/SMB] Could not cache file locally",{path:relativePath,error:error instanceof Error?error.message:String(error)}),null}})().finally(()=>{this.inFlight.delete(target)});return this.inFlight.set(target,download),download}async close(){try{this.client?.disconnect()}catch{}this.client=null}}var DEFAULT_EXCLUDES=[".cache",".tmp","lost+found"];async function migrateStorage(options,deps){let{from,to,onProgress}=options,exclude=new Set([...DEFAULT_EXCLUDES,...options.exclude??[]]),maxFiles=options.maxFiles??50000,report={copied:0,skipped:0,failed:0,bytes:0,failures:[],truncated:!1},walk=async(dir)=>{if(report.truncated)return;let entries=await from.list(dir);for(let entry of entries){if(report.truncated)return;if(!entry||entry==="."||entry==="..")continue;let relative=dir?`${dir}/${entry}`:entry;if(exclude.has(entry))continue;let info=await from.stat(relative);if(!info){if(report.failed+=1,report.failures.length<50)report.failures.push(relative);continue}if(info.isDirectory){await walk(relative);continue}if(report.copied+report.skipped>=maxFiles){report.truncated=!0;return}if(await to.exists(relative)){report.skipped+=1;continue}try{let bytes=await from.read(relative);if(!bytes){if(report.failed+=1,report.failures.length<50)report.failures.push(relative);continue}let parent=relative.includes("/")?relative.slice(0,relative.lastIndexOf("/")):"";if(parent)await to.ensureDir(parent);await to.write(relative,bytes),report.copied+=1,report.bytes+=bytes.length,onProgress?.(report.copied,relative)}catch(error){if(report.failed+=1,report.failures.length<50)report.failures.push(relative);deps.logger.warn("[Storage] Migration copy failed",{path:relative,error:error instanceof Error?error.message:String(error)})}}};return await walk(""),deps.logger.info("[Storage] Migration finished",{from:from.describe,to:to.describe,copied:report.copied,skipped:report.skipped,failed:report.failed,truncated:report.truncated}),report}function parseSmbUrl(value){let raw=(value??"").trim();if(!raw)return{host:"",share:""};let withoutScheme=raw.replace(/^smb:\/\//i,"").replace(/^\\\\/,"").replace(/\\/g,"/"),[host="",share="",...rest]=withoutScheme.split("/").filter(Boolean);return{host,share,basePath:rest.length>0?rest.join("/"):void 0}}function createStorageProvider(options,deps){let{basePath,smb,resolveCredential}=options,setting=(key,configValue)=>resolveCredential?.("storage.smb",key,configValue)??configValue,resolveSmbConfig=()=>{let fromUrl=parseSmbUrl(setting("url"));return{...smb,host:fromUrl.host||setting("host",smb?.host)||"",share:fromUrl.share||setting("share",smb?.share)||"",basePath:fromUrl.basePath??setting("base_path",smb?.basePath),domain:setting("domain",smb?.domain),username:setting("username",smb?.username),password:setting("password",smb?.password)}},resolveKind=()=>{let chosen=resolveCredential?.("storage","provider",options.provider);return chosen==="smb"?"smb":chosen==="local"?"local":options.provider??"local"},local=new LocalStorageProvider(basePath,deps),smbProvider=null,smbSignature="",warnedIncomplete=!1;return new LiveStorageProvider(()=>{if(resolveKind()!=="smb")return local;let config=resolveSmbConfig();if(!config.host||!config.share){if(!warnedIncomplete)warnedIncomplete=!0,deps.logger.error('[Storage] provider is "smb" but the host/share are not set \u2014 using local storage until they are');return local}warnedIncomplete=!1;let signature=JSON.stringify([config.host,config.share,config.basePath,config.domain,config.username,config.password,config.port]);if(!smbProvider||signature!==smbSignature)smbProvider?.close(),smbProvider=new SmbStorageProvider(resolveSmbConfig,deps,join3(basePath,".cache","smb")),smbSignature=signature,deps.logger.info("[Storage] SMB target configured",{target:smbProvider.describe});return smbProvider})}init_Services();init_ApiKey();init_Middleware();init_Captcha();init_Domain();init_Secrets();async function withDeadline(promise,timeoutMs,message){promise.catch(()=>{});let timer,deadline=new Promise((_resolve,reject)=>{timer=setTimeout(()=>reject(Error(message)),timeoutMs)});try{return await Promise.race([promise,deadline])}finally{if(timer)clearTimeout(timer)}}import{and as and10,desc as desc3,eq as eq16,inArray as inArray4}from"drizzle-orm";var DEFAULT_CHAT_CONFIG={enabled:!1,basePath:"/chat",groupsEnabled:!0,maxGroupParticipants:256,maxMessageLength:8000,editingEnabled:!0,deletionEnabled:!0,typingIndicators:!0,readReceipts:!0,presence:!0,realtimeTopicPrefix:"chat",messagePageSize:50,moderatorRoles:[],attachments:{enabled:!0,maxPerMessage:10,maxFileSizeBytes:null,allowedMimeTypes:[]}};function mergeChatConfig(input){let base=DEFAULT_CHAT_CONFIG;if(!input)return base;return{enabled:input.enabled??base.enabled,basePath:input.basePath??base.basePath,groupsEnabled:input.groupsEnabled??base.groupsEnabled,maxGroupParticipants:input.maxGroupParticipants??base.maxGroupParticipants,maxMessageLength:input.maxMessageLength??base.maxMessageLength,editingEnabled:input.editingEnabled??base.editingEnabled,deletionEnabled:input.deletionEnabled??base.deletionEnabled,typingIndicators:input.typingIndicators??base.typingIndicators,readReceipts:input.readReceipts??base.readReceipts,presence:input.presence??base.presence,realtimeTopicPrefix:input.realtimeTopicPrefix??base.realtimeTopicPrefix,messagePageSize:input.messagePageSize??base.messagePageSize,moderatorRoles:input.moderatorRoles??base.moderatorRoles,attachments:{enabled:input.attachments?.enabled??base.attachments.enabled,maxPerMessage:input.attachments?.maxPerMessage??base.attachments.maxPerMessage,maxFileSizeBytes:input.attachments?.maxFileSizeBytes??base.attachments.maxFileSizeBytes,allowedMimeTypes:input.attachments?.allowedMimeTypes??base.attachments.allowedMimeTypes}}}function getCol(table,col7){return table[col7]}function getTable(schemaTables,name2,logger2){return resolveSchemaTable(schemaTables,name2,logger2)}function computeDirectKey(userA,userB){return[userA,userB].sort().join(":")}function kindFromMime(mime){if(!mime)return"file";if(mime.startsWith("image/"))return"image";if(mime.startsWith("video/"))return"video";if(mime.startsWith("audio/"))return"audio";return"file"}function str3(value){return typeof value==="string"?value:null}function num2(value){return typeof value==="number"?value:null}function date(value){if(value instanceof Date)return value;if(typeof value==="string")return new Date(value);return null}function cdnUrl(cdnBasePath,fileId){if(!fileId)return null;return`${cdnBasePath}/${fileId}`}function mapConversation(row,cdnBasePath){let avatarFileId=str3(row.avatarFileId);return{id:String(row.id),type:str3(row.type)??"direct",title:str3(row.title),description:str3(row.description),avatarFileId,avatarUrl:cdnUrl(cdnBasePath,avatarFileId),directKey:str3(row.directKey),lastMessageAt:date(row.lastMessageAt),lastMessagePreview:str3(row.lastMessagePreview),lastMessageSenderId:str3(row.lastMessageSenderId),createdBy:str3(row.createdBy),createdAt:date(row.createdAt)??new Date(0),updatedAt:date(row.updatedAt)??new Date(0),isActive:row.isActive!==!1}}function mapParticipant(row){return{id:String(row.id),conversationId:String(row.conversationId),userId:String(row.userId),role:str3(row.role)??"member",lastReadMessageId:str3(row.lastReadMessageId),lastReadAt:date(row.lastReadAt),unreadCount:num2(row.unreadCount)??0,muted:row.muted===!0,mutedUntil:date(row.mutedUntil),notificationsEnabled:row.notificationsEnabled!==!1,leftAt:date(row.leftAt),joinedAt:date(row.createdAt)??new Date(0)}}function mapAttachment(row,cdnBasePath){let fileId=String(row.fileId);return{id:String(row.id),messageId:String(row.messageId),conversationId:String(row.conversationId),fileId,kind:str3(row.kind)??"file",originalName:str3(row.originalName),mimeType:str3(row.mimeType),size:num2(row.size),width:num2(row.width),height:num2(row.height),duration:num2(row.duration),url:`${cdnBasePath}/${fileId}`}}function mapMessage(row,attachments){let metadata=row.metadata;return{id:String(row.id),conversationId:String(row.conversationId),senderId:str3(row.senderId),content:str3(row.content),contentType:str3(row.contentType)??"text",replyToId:str3(row.replyToId),metadata:metadata&&typeof metadata==="object"?metadata:null,clientMessageId:str3(row.clientMessageId),editedAt:date(row.editedAt),deletedAt:date(row.deletedAt),createdAt:date(row.createdAt)??new Date(0),updatedAt:date(row.updatedAt)??new Date(0),attachments}}function buildPreview(content,contentType,attachmentCount){if(content&&content.trim().length>0){let trimmed=content.trim();return trimmed.length>280?`${trimmed.slice(0,277)}...`:trimmed}if(attachmentCount>0){if(contentType==="image")return attachmentCount>1?`${attachmentCount} photos`:"Photo";if(contentType==="video")return attachmentCount>1?`${attachmentCount} videos`:"Video";if(contentType==="audio")return"Audio";return attachmentCount>1?`${attachmentCount} files`:"File"}if(contentType==="system")return"System message";return""}import{and as and9,eq as eq15,inArray as inArray3}from"drizzle-orm";class ChatError extends Error{code;constructor(code,message){super(message);this.code=code,this.name="ChatError"}}function resolveChatTables(ctx){let conversations=getTable(ctx.schemaTables,"chat_conversations",ctx.logger),participants=getTable(ctx.schemaTables,"chat_participants",ctx.logger),messages=getTable(ctx.schemaTables,"chat_messages",ctx.logger);if(!conversations||!participants||!messages)throw new ChatError("disabled","Chat tables are not available in this schema");let attachments=getTable(ctx.schemaTables,"chat_message_attachments")??null,files=getTable(ctx.schemaTables,"files")??null;return{conversations,participants,messages,attachments,files}}function chatTopic(ctx){return ctx.config.realtimeTopicPrefix||"chat"}async function getConversationRow(ctx,tables,conversationId){return(await ctx.db.select().from(tables.conversations).where(eq15(getCol(tables.conversations,"id"),conversationId)).limit(1))[0]??null}async function getParticipant(ctx,tables,conversationId,userId){let row=(await ctx.db.select().from(tables.participants).where(and9(eq15(getCol(tables.participants,"conversationId"),conversationId),eq15(getCol(tables.participants,"userId"),userId))).limit(1))[0];return row?mapParticipant(row):null}async function requireActiveMembership(ctx,tables,conversationId,userId){let participant=await getParticipant(ctx,tables,conversationId,userId);if(!participant||participant.leftAt)throw new ChatError("forbidden","You are not a participant of this conversation");return participant}async function listParticipants(ctx,tables,conversationId,includeLeft=!1){let all=(await ctx.db.select().from(tables.participants).where(eq15(getCol(tables.participants,"conversationId"),conversationId))).map(mapParticipant);return includeLeft?all:all.filter((p)=>!p.leftAt)}async function assertUsersExist(ctx,userIds){let unique=[...new Set(userIds)];if(unique.length===0)return;let usersTable=getTable(ctx.schemaTables,"users",ctx.logger);if(!usersTable)throw new ChatError("disabled","Users table is not available in this schema");let rows=await ctx.db.select({id:getCol(usersTable,"id")}).from(usersTable).where(inArray3(getCol(usersTable,"id"),unique)),found=new Set(rows.map((r)=>r.id));for(let id of unique)if(!found.has(id))throw new ChatError("not_found",`User ${id} does not exist`)}function deliverToParticipants(ctx,participants,event,exceptUserId){if(!ctx.broadcaster)return;let topic=chatTopic(ctx);for(let participant of participants){if(participant.leftAt)continue;if(exceptUserId&&participant.userId===exceptUserId)continue;ctx.broadcaster.broadcastToUser(participant.userId,topic,event)}}async function buildSummary(ctx,tables,conversationRow,userId,participantsOverride){let conversation=mapConversation(conversationRow,ctx.cdnBasePath),participants=participantsOverride??await listParticipants(ctx,tables,conversation.id),myParticipant=participants.find((p)=>p.userId===userId)??null;return{...conversation,participants,myParticipant,unreadCount:myParticipant?.unreadCount??0}}async function getOrCreateDirect(ctx,params){let tables=resolveChatTables(ctx),{userId,targetUserId}=params;if(!targetUserId||targetUserId===userId)throw new ChatError("validation","A different target user is required");await assertUsersExist(ctx,[targetUserId]);let directKey=computeDirectKey(userId,targetUserId),existing=(await ctx.db.select().from(tables.conversations).where(eq16(getCol(tables.conversations,"directKey"),directKey)).limit(1))[0];if(existing)return await rejoinIfNeeded(ctx,tables,String(existing.id),[userId,targetUserId]),buildSummary(ctx,tables,existing,userId);let now=new Date,conversationRow;try{conversationRow=(await ctx.db.insert(tables.conversations).values({type:"direct",directKey,createdBy:userId,lastMessageAt:now,lastMessagePreview:""}).returning())[0]}catch(_err){let raced=(await ctx.db.select().from(tables.conversations).where(eq16(getCol(tables.conversations,"directKey"),directKey)).limit(1))[0];if(!raced)throw new ChatError("conflict","Failed to create direct conversation");return await rejoinIfNeeded(ctx,tables,String(raced.id),[userId,targetUserId]),buildSummary(ctx,tables,raced,userId)}let conversationId=String(conversationRow.id);await ctx.db.insert(tables.participants).values([{conversationId,userId,role:"member",createdBy:userId},{conversationId,userId:targetUserId,role:"member",createdBy:userId}]);let summary=await buildSummary(ctx,tables,conversationRow,userId);return deliverToParticipants(ctx,summary.participants,{type:"conversation.created",conversationId,conversation:summary},userId),summary}async function createGroup(ctx,params){if(!ctx.config.groupsEnabled)throw new ChatError("disabled","Group conversations are disabled");let tables=resolveChatTables(ctx),{creatorId,title}=params;if(!title||title.trim().length===0)throw new ChatError("validation","A group title is required");let memberIds=[...new Set([creatorId,...params.participantIds])];if(memberIds.length>ctx.config.maxGroupParticipants)throw new ChatError("validation",`A group cannot exceed ${ctx.config.maxGroupParticipants} participants`);if(await assertUsersExist(ctx,memberIds),params.avatarFileId){if(!tables.files)throw new ChatError("disabled","Avatar files require storage to be enabled");let avatarRow=(await ctx.db.select().from(tables.files).where(eq16(getCol(tables.files,"id"),params.avatarFileId)).limit(1))[0],owner=avatarRow?String(avatarRow.uploadedBy??avatarRow.createdBy??""):"";if(!avatarRow||owner!==creatorId)throw new ChatError("forbidden","Avatar file is not owned by the creator")}let now=new Date,conversationRow=(await ctx.db.insert(tables.conversations).values({type:"group",title:title.trim(),description:params.description??null,avatarFileId:params.avatarFileId??null,createdBy:creatorId,lastMessageAt:now,lastMessagePreview:""}).returning())[0],conversationId=String(conversationRow.id);await ctx.db.insert(tables.participants).values(memberIds.map((memberId)=>({conversationId,userId:memberId,role:memberId===creatorId?"owner":"member",createdBy:creatorId})));let summary=await buildSummary(ctx,tables,conversationRow,creatorId);return deliverToParticipants(ctx,summary.participants,{type:"conversation.created",conversationId,conversation:summary},creatorId),summary}async function listConversations(ctx,params){let tables=resolveChatTables(ctx),limit=Math.min(Math.max(params.limit??30,1),100),offset=Math.max(params.offset??0,0),myParticipants=(await ctx.db.select().from(tables.participants).where(eq16(getCol(tables.participants,"userId"),params.userId))).map(mapParticipant).filter((p)=>!p.leftAt);if(myParticipants.length===0)return[];let conversationIds=myParticipants.map((p)=>p.conversationId),pageRows=await ctx.db.select().from(tables.conversations).where(and10(inArray4(getCol(tables.conversations,"id"),conversationIds),eq16(getCol(tables.conversations,"isActive"),!0))).orderBy(desc3(getCol(tables.conversations,"lastMessageAt"))).limit(limit).offset(offset);if(pageRows.length===0)return[];let pageIds=pageRows.map((r)=>String(r.id)),participantRows=await ctx.db.select().from(tables.participants).where(inArray4(getCol(tables.participants,"conversationId"),pageIds)),byConversation=new Map;for(let row of participantRows){let mapped=mapParticipant(row);if(mapped.leftAt)continue;let list=byConversation.get(mapped.conversationId)??[];list.push(mapped),byConversation.set(mapped.conversationId,list)}let summaries=[];for(let row of pageRows){let id=String(row.id);summaries.push(await buildSummary(ctx,tables,row,params.userId,byConversation.get(id)??[]))}return summaries}async function getConversation(ctx,conversationId,userId){let tables=resolveChatTables(ctx);await requireActiveMembership(ctx,tables,conversationId,userId);let row=await getConversationRow(ctx,tables,conversationId);if(!row)throw new ChatError("not_found","Conversation not found");return buildSummary(ctx,tables,row,userId)}async function rejoinIfNeeded(ctx,tables,conversationId,userIds){for(let userId of userIds){let participant=await getParticipant(ctx,tables,conversationId,userId);if(!participant)await ctx.db.insert(tables.participants).values({conversationId,userId,role:"member",createdBy:userId});else if(participant.leftAt)await ctx.db.update(tables.participants).set({leftAt:null}).where(eq16(getCol(tables.participants,"id"),participant.id))}}function assertCanManage(actor){if(actor.role!=="owner"&&actor.role!=="admin")throw new ChatError("forbidden","Only group admins can manage participants")}async function addParticipants(ctx,conversationId,actorId,userIds){let tables=resolveChatTables(ctx),conversation=await getConversationRow(ctx,tables,conversationId);if(!conversation)throw new ChatError("not_found","Conversation not found");if(mapConversation(conversation,ctx.cdnBasePath).type!=="group")throw new ChatError("validation","Participants can only be managed in group conversations");let actor=await requireActiveMembership(ctx,tables,conversationId,actorId);assertCanManage(actor);let toAdd=[...new Set(userIds)];await assertUsersExist(ctx,toAdd);let current=await listParticipants(ctx,tables,conversationId,!0),activeCount=current.filter((p)=>!p.leftAt).length,newOnes=toAdd.filter((id)=>!current.some((p)=>p.userId===id&&!p.leftAt));if(activeCount+newOnes.length>ctx.config.maxGroupParticipants)throw new ChatError("validation","Group participant limit exceeded");for(let userId of toAdd)await rejoinIfNeeded(ctx,tables,conversationId,[userId]);let participants=await listParticipants(ctx,tables,conversationId);return deliverToParticipants(ctx,participants,{type:"participant.added",conversationId,userIds:toAdd,by:actorId}),participants}async function removeParticipant(ctx,conversationId,actorId,targetUserId){let tables=resolveChatTables(ctx),actor=await requireActiveMembership(ctx,tables,conversationId,actorId);if(actorId!==targetUserId)assertCanManage(actor);let target2=await getParticipant(ctx,tables,conversationId,targetUserId);if(!target2||target2.leftAt)throw new ChatError("not_found","Participant not found in conversation");await ctx.db.update(tables.participants).set({leftAt:new Date}).where(eq16(getCol(tables.participants,"id"),target2.id));let participants=await listParticipants(ctx,tables,conversationId),event={type:"participant.removed",conversationId,userId:targetUserId,by:actorId};if(deliverToParticipants(ctx,participants,event),ctx.broadcaster)ctx.broadcaster.broadcastToUser(targetUserId,ctx.config.realtimeTopicPrefix||"chat",event)}import{and as and11,desc as desc4,eq as eq17,inArray as inArray5,isNull,lt,ne,sql as sql6}from"drizzle-orm";async function loadAttachments(ctx,tables,messageIds){let grouped=new Map;if(!tables.attachments||messageIds.length===0)return grouped;let rows=await ctx.db.select().from(tables.attachments).where(inArray5(getCol(tables.attachments,"messageId"),messageIds));for(let row of rows){let attachment=mapAttachment(row,ctx.cdnBasePath),list=grouped.get(attachment.messageId)??[];list.push(attachment),grouped.set(attachment.messageId,list)}return grouped}function inferContentType(explicit,attachments){if(explicit)return explicit;if(attachments.length===0)return"text";let kind=attachments[0]?.kind;if(kind==="image")return"image";if(kind==="video")return"video";if(kind==="audio")return"audio";return"file"}async function persistAttachments(ctx,tables,conversationId,messageId,params){let inputs=params.attachments??[];if(inputs.length===0)return[];if(!ctx.attachmentsAvailable||!tables.attachments||!tables.files)throw new ChatError("disabled","File attachments require storage and CDN to be enabled");if(inputs.length>ctx.config.attachments.maxPerMessage)throw new ChatError("validation",`A message cannot have more than ${ctx.config.attachments.maxPerMessage} attachments`);let fileIds=inputs.map((a)=>a.fileId),fileRows=await ctx.db.select().from(tables.files).where(inArray5(getCol(tables.files,"id"),fileIds)),filesById=new Map;for(let row of fileRows)filesById.set(String(row.id),row);let payloads=inputs.map((input)=>{let fileRow=filesById.get(input.fileId);if(!fileRow)throw new ChatError("not_found",`Attachment file ${input.fileId} was not found`);if(String(fileRow.uploadedBy??fileRow.createdBy??"")!==params.senderId)throw new ChatError("forbidden",`Attachment file ${input.fileId} is not owned by the sender`);let mimeType=fileRow.mimeType??input.mimeType??null;return{conversationId,messageId,fileId:input.fileId,kind:input.kind??kindFromMime(mimeType),originalName:fileRow.originalName??input.originalName??null,mimeType,size:fileRow.size??input.size??null,width:input.width??null,height:input.height??null,duration:input.duration??null,createdBy:params.senderId}});return(await ctx.db.insert(tables.attachments).values(payloads).returning()).map((row)=>mapAttachment(row,ctx.cdnBasePath))}async function sendMessage(ctx,params){let tables=resolveChatTables(ctx);await requireActiveMembership(ctx,tables,params.conversationId,params.senderId);let content=params.content?.trim()?params.content:null,hasAttachments=(params.attachments?.length??0)>0;if(!content&&!hasAttachments)throw new ChatError("validation","A message must contain text or at least one attachment");if(content&&content.length>ctx.config.maxMessageLength)throw new ChatError("validation",`Message exceeds the maximum length of ${ctx.config.maxMessageLength} characters`);if(params.metadata!==void 0&¶ms.metadata!==null){if(JSON.stringify(params.metadata).length>4096)throw new ChatError("validation","Message metadata exceeds the maximum size of 4096 bytes")}let{message,participants}=await ctx.db.transaction(async(tx)=>{let txCtx={...ctx,db:tx},messageRow=(await tx.insert(tables.messages).values({conversationId:params.conversationId,senderId:params.senderId,content,contentType:params.contentType??"text",replyToId:params.replyToId??null,clientMessageId:params.clientMessageId??null,metadata:params.metadata??{},createdBy:params.senderId}).returning())[0],messageId=String(messageRow.id),attachments=await persistAttachments(txCtx,tables,params.conversationId,messageId,params),contentType=inferContentType(params.contentType,attachments);if(contentType!==messageRow.contentType)await tx.update(tables.messages).set({contentType}).where(eq17(getCol(tables.messages,"id"),messageId)),messageRow.contentType=contentType;let mappedMessage=mapMessage(messageRow,attachments),preview=buildPreview(mappedMessage.content,mappedMessage.contentType,attachments.length),now=mappedMessage.createdAt;await tx.update(tables.conversations).set({lastMessageAt:now,lastMessagePreview:preview,lastMessageSenderId:params.senderId,updatedAt:new Date}).where(eq17(getCol(tables.conversations,"id"),params.conversationId)),await tx.update(tables.participants).set({unreadCount:sql6`${getCol(tables.participants,"unreadCount")} + 1`}).where(and11(eq17(getCol(tables.participants,"conversationId"),params.conversationId),ne(getCol(tables.participants,"userId"),params.senderId),isNull(getCol(tables.participants,"leftAt"))));let parts=await listParticipants(txCtx,tables,params.conversationId);return{message:mappedMessage,participants:parts}});return deliverToParticipants(ctx,participants,{type:"message.created",conversationId:params.conversationId,message}),message}async function getMessages(ctx,params){let tables=resolveChatTables(ctx);await requireActiveMembership(ctx,tables,params.conversationId,params.userId);let limit=Math.min(Math.max(params.limit??ctx.config.messagePageSize,1),100),conditions=[eq17(getCol(tables.messages,"conversationId"),params.conversationId)];if(params.before){let cursor=(await ctx.db.select().from(tables.messages).where(eq17(getCol(tables.messages,"id"),params.before)).limit(1))[0];if(cursor?.createdAt)conditions.push(lt(getCol(tables.messages,"createdAt"),cursor.createdAt))}let rows=await ctx.db.select().from(tables.messages).where(and11(...conditions)).orderBy(desc4(getCol(tables.messages,"createdAt"))).limit(limit+1),pageRows=rows.slice(0,limit),hasMore=rows.length>limit,attachmentsByMessage=await loadAttachments(ctx,tables,pageRows.map((r)=>String(r.id)));return{messages:pageRows.map((row)=>mapMessage(row,attachmentsByMessage.get(String(row.id))??[])),hasMore}}async function markRead(ctx,conversationId,userId,messageId){let tables=resolveChatTables(ctx),participant=await requireActiveMembership(ctx,tables,conversationId,userId),targetMessageId=messageId??null;if(!targetMessageId){let latestRow=(await ctx.db.select().from(tables.messages).where(eq17(getCol(tables.messages,"conversationId"),conversationId)).orderBy(desc4(getCol(tables.messages,"createdAt"))).limit(1))[0];targetMessageId=latestRow?String(latestRow.id):null}let readAt=new Date;if(await ctx.db.update(tables.participants).set({lastReadMessageId:targetMessageId,lastReadAt:readAt,unreadCount:0}).where(eq17(getCol(tables.participants,"id"),participant.id)),ctx.config.readReceipts){let participants=await listParticipants(ctx,tables,conversationId);deliverToParticipants(ctx,participants,{type:"conversation.read",conversationId,userId,lastReadMessageId:targetMessageId,readAt:readAt.toISOString()},userId)}return{lastReadMessageId:targetMessageId,readAt}}async function editMessage(ctx,messageId,userId,content){if(!ctx.config.editingEnabled)throw new ChatError("disabled","Message editing is disabled");let tables=resolveChatTables(ctx),row=(await ctx.db.select().from(tables.messages).where(eq17(getCol(tables.messages,"id"),messageId)).limit(1))[0];if(!row||row.deletedAt)throw new ChatError("not_found","Message not found");if(String(row.senderId)!==userId)throw new ChatError("forbidden","You can only edit your own messages");let trimmed=content.trim();if(!trimmed)throw new ChatError("validation","Message content cannot be empty");if(trimmed.length>ctx.config.maxMessageLength)throw new ChatError("validation","Message exceeds the maximum length");let editedAt=new Date,updated=await ctx.db.update(tables.messages).set({content:trimmed,editedAt,updatedAt:editedAt}).where(eq17(getCol(tables.messages,"id"),messageId)).returning(),attachments=await loadAttachments(ctx,tables,[messageId]),message=mapMessage(updated[0],attachments.get(messageId)??[]),participants=await listParticipants(ctx,tables,String(row.conversationId));return deliverToParticipants(ctx,participants,{type:"message.updated",conversationId:String(row.conversationId),message}),message}async function deleteMessage(ctx,messageId,userId,asModerator=!1){if(!ctx.config.deletionEnabled&&!asModerator)throw new ChatError("disabled","Message deletion is disabled");let tables=resolveChatTables(ctx),row=(await ctx.db.select().from(tables.messages).where(eq17(getCol(tables.messages,"id"),messageId)).limit(1))[0];if(!row||row.deletedAt)throw new ChatError("not_found","Message not found");if(!asModerator&&String(row.senderId)!==userId)throw new ChatError("forbidden","You can only delete your own messages");let deletedAt=new Date;await ctx.db.update(tables.messages).set({content:null,deletedAt,updatedAt:deletedAt}).where(eq17(getCol(tables.messages,"id"),messageId));let participants=await listParticipants(ctx,tables,String(row.conversationId));deliverToParticipants(ctx,participants,{type:"message.deleted",conversationId:String(row.conversationId),messageId})}async function setTyping(ctx,conversationId,userId,isTyping=!0){if(!ctx.config.typingIndicators)return;let tables=resolveChatTables(ctx),participants=await listParticipants(ctx,tables,conversationId);if(!participants.some((p)=>p.userId===userId))throw new ChatError("forbidden","You are not a participant of this conversation");deliverToParticipants(ctx,participants,{type:"typing",conversationId,userId,isTyping},userId)}class ChatService{ctx;constructor(init){this.ctx={db:init.db,schemaTables:init.schemaTables,config:init.config,logger:init.logger,broadcaster:init.broadcaster??null,cdnBasePath:init.cdnBasePath??"/cdn",attachmentsAvailable:init.attachmentsAvailable??!1}}get config(){return this.ctx.config}getOrCreateDirect(userId,targetUserId){return getOrCreateDirect(this.ctx,{userId,targetUserId})}createGroup(params){return createGroup(this.ctx,params)}listConversations(userId,opts){return listConversations(this.ctx,{userId,limit:opts?.limit,offset:opts?.offset})}getConversation(conversationId,userId){return getConversation(this.ctx,conversationId,userId)}addParticipants(conversationId,actorId,userIds){return addParticipants(this.ctx,conversationId,actorId,userIds)}removeParticipant(conversationId,actorId,targetUserId){return removeParticipant(this.ctx,conversationId,actorId,targetUserId)}sendMessage(params){return sendMessage(this.ctx,params)}getMessages(params){return getMessages(this.ctx,params)}markRead(conversationId,userId,messageId){return markRead(this.ctx,conversationId,userId,messageId)}editMessage(messageId,userId,content){return editMessage(this.ctx,messageId,userId,content)}deleteMessage(messageId,userId,asModerator=!1){return deleteMessage(this.ctx,messageId,userId,asModerator)}setTyping(conversationId,userId,isTyping){return setTyping(this.ctx,conversationId,userId,isTyping)}}var EXTEND_ALLOWED_KEYS=new Set(["table_name","extends","columns","indexes"]);function hasDbDefault(column){return column.default!==void 0||column.defaultRaw!==void 0||column.generatedAlwaysAs!==void 0||column.generatedAlwaysAsIdentity===!0||column.generatedByDefaultAsIdentity===!0}var AUTH_FEATURES=new Set(["authentication","authorization"]);function resolveEntities(systemTables2,configEntities,options={}){let errors2=[],warnings=[],consumed=new Set,entities=[];for(let system of systemTables2){let config=configEntities.find((c)=>c.table_name===system.table_name);if(!config){entities.push(system);continue}if(consumed.add(config.table_name),!config.extends){warnings.push(`[Schema] "${config.table_name}" is declared in config.entities AND ships as a system table. Using YOUR definition and skipping the built-in one. Add "extends": true to inherit the built-in columns and route policy instead.`),entities.push(config);continue}for(let key2 of Object.keys(config))if(!EXTEND_ALLOWED_KEYS.has(key2))warnings.push(`[Schema] "${config.table_name}" sets "${key2}" alongside "extends": true \u2014 ignored. `+"An extending entry inherits every table-level setting from the built-in definition.");if(options.enabledTableNames&&!options.enabledTableNames.has(system.table_name))errors2.push({code:"E5_FEATURE_DISABLED",table:system.table_name,message:`"${system.table_name}" is extended but its feature is disabled, so the table is never created. Enable the feature or remove the extending entry.`});if(options.consumerMode&&(system.feature_set??[]).some((f)=>AUTH_FEATURES.has(f)))errors2.push({code:"E3_CONSUMER_AUTH_TABLE",table:system.table_name,message:`"${system.table_name}" is an auth system table and cannot be extended in consumer mode \u2014 `+"the identity tables live in the IDP. Extending it would create a local copy here."});let builtInNames=new Set((system.columns??[]).map((c)=>c.name));if(system.add_base_columns!==!1)for(let name2 of options.baseColumnNames??[])builtInNames.add(name2);for(let column of config.columns??[]){if(builtInNames.has(column.name))errors2.push({code:"E1_COLUMN_COLLISION",table:system.table_name,column:column.name,message:`"${system.table_name}.${column.name}" already exists in the built-in definition. An extending entry may only ADD columns; rename yours.`});if(column.notNull===!0&&column.nullable!==!0&&!hasDbDefault(column))errors2.push({code:"E2_NOT_NULL_WITHOUT_DEFAULT",table:system.table_name,column:column.name,message:`"${system.table_name}.${column.name}" is notNull without a default. The framework writes this table from fixed-column inserts (register, invite, admin create-user, godmin seed, `+"tenant provisioning) that cannot supply it \u2014 every one of them would fail. Make it "+"nullable or give it a default."})}let merged={...system,columns:[...system.columns??[],...config.columns??[]],indexes:[...system.indexes??[],...config.indexes??[]]};entities.push(merged)}for(let config of configEntities){if(consumed.has(config.table_name))continue;if(config.extends){errors2.push({code:"E4_UNKNOWN_SYSTEM_TABLE",table:config.table_name,message:`"${config.table_name}" sets "extends": true but there is no system table with that name. Remove the flag to declare it as an ordinary entity.`});continue}entities.push(config)}return{entities,errors:errors2,warnings}}function resolveAuthType(pathname,auth){let at=(route)=>pathname===route||pathname.endsWith(route)||pathname.includes(`${route}/`);if(at(auth?.login?.route||"/auth/login"))return"login";if(at(auth?.register?.route||"/auth/register"))return"register";if(at(auth?.passwordReset?.route||"/auth/password-reset"))return"passwordReset";if(at(auth?.magicLink?.route||"/auth/magic-link"))return"magicLink";if(at(auth?.invite?.route||"/auth/invite"))return"other";if(at("/sessions/approve")||at("/sessions/reject"))return"login";return}init_Logger2();var METHOD_MAP={GET:["GET"],POST:["POST"],PUT:["PUT"],DELETE:["DELETE"],PATCH:["PATCH"],TOGGLE:["PATCH"],VERIFICATION:["POST"]};function buildAuthPublicRoutes(config,basePath){let routes=[],auth=config.authentication;if(!auth)return routes;if(auth.login?.enabled&&auth.login?.isPublic)routes.push({path:auth.login.route||`${basePath}/auth/login`,method:"POST",source:"auth"});if(auth.register?.enabled&&auth.register?.isPublic)routes.push({path:auth.register.route||`${basePath}/auth/register`,method:"POST",source:"auth"});if(auth.logout?.enabled&&auth.logout?.isPublic)routes.push({path:auth.logout.route||`${basePath}/auth/logout`,method:"POST",source:"auth"});if(auth.refresh?.enabled&&auth.refresh?.isPublic)routes.push({path:auth.refresh.route||`${basePath}/auth/refresh`,method:"POST",source:"auth"});if(auth.passwordReset?.enabled&&auth.passwordReset?.isPublic){let baseRoute=auth.passwordReset.route||`${basePath}/auth/password-reset`;routes.push({path:`${baseRoute}/request`,method:"POST",source:"auth"},{path:`${baseRoute}/confirm`,method:"POST",source:"auth"})}if(auth.passwordChange?.enabled&&auth.passwordChange?.isPublic)routes.push({path:auth.passwordChange.route||`${basePath}/auth/password-change`,method:"POST",source:"auth"});if(auth.magicLink?.enabled&&auth.magicLink?.isPublic)routes.push({path:auth.magicLink.route||`${basePath}/auth/magic-link`,method:"POST",source:"auth"},{path:auth.magicLink.verifyRoute||`${basePath}/auth/magic-link/verify`,method:"GET",source:"auth"});if(auth.register?.enabled&&auth.register?.emailVerification?.enabled)routes.push({path:`${basePath}/verify-email`,method:"GET",source:"auth"},{path:`${basePath}/resend-verification`,method:"POST",source:"auth"});if(auth.invite?.enabled&&auth.invite?.isPublic)routes.push({path:auth.invite.route||`${basePath}/auth/invite`,method:"POST",source:"auth"});if(auth.invite?.enabled){let inviteRoute=auth.invite.route||`${basePath}/auth/invite`;routes.push({path:`${inviteRoute}/verify`,method:"POST",source:"auth"})}if(auth.passwordSet?.enabled)routes.push({path:auth.passwordSet.route||`${basePath}/auth/password-set`,method:"POST",source:"auth"});if(auth.webauthn?.enabled){let webauthnRoute=auth.webauthn.route||`${basePath}/auth/webauthn`;routes.push({path:`${webauthnRoute}/authenticate/options`,method:"POST",source:"auth"},{path:`${webauthnRoute}/authenticate/verify`,method:"POST",source:"auth"})}if(auth.captcha?.enabled&&auth.captcha?.isPublic){let baseRoute=auth.captcha.route||`${basePath}/auth/captcha`;routes.push({path:`${baseRoute}/generate`,method:"GET",source:"auth"},{path:`${baseRoute}/validate`,method:"POST",source:"auth"})}if(auth.sessions?.enabled){let sessionsRoute=auth.sessions.route||`${basePath}/auth/sessions`;routes.push({path:`${sessionsRoute}/approve`,method:"POST",source:"auth"},{path:`${sessionsRoute}/reject`,method:"POST",source:"auth"},{path:`${sessionsRoute}/approve-page`,method:"GET",source:"auth"},{path:`${sessionsRoute}/reject-page`,method:"GET",source:"auth"},{path:`${sessionsRoute}/approval-status`,method:"GET",source:"auth"})}if(auth.oauth?.enabled){let oauthBase=auth.oauth.basePath||`${basePath}/auth/oauth`,knownProviders=["google","github","microsoft","discord","facebook","twitter","apple","custom"];routes.push({path:`${oauthBase}/providers`,method:"GET",source:"auth"});for(let provider of knownProviders)routes.push({path:`${oauthBase}/${provider}`,method:"GET",source:"auth"},{path:`${oauthBase}/${provider}/callback`,method:"GET",source:"auth"})}return routes}function buildEntityPublicRoutes(entities,basePath,_schema){let routes=[];for(let entity of entities){if(!entity.is_public)continue;let camelName=entity.table_name.replace(/_([a-z])/g,(_,l)=>l.toUpperCase()),entityPath=`${basePath}/${camelName}`;for(let[nucleusMethod,isPublic]of Object.entries(entity.is_public)){if(!isPublic)continue;let httpMethods=METHOD_MAP[nucleusMethod];if(!httpMethods)continue;for(let method of httpMethods)if(method==="GET")routes.push({path:entityPath,method:"GET",source:"entity"}),routes.push({path:`${entityPath}/:id`,method:"GET",source:"entity"});else if(method==="POST")routes.push({path:entityPath,method:"POST",source:"entity"});else if(method==="PUT"||method==="PATCH")routes.push({path:`${entityPath}/:id`,method,source:"entity"});else if(method==="DELETE")routes.push({path:`${entityPath}/:id`,method:"DELETE",source:"entity"})}}return routes}function buildSystemTablePublicRoutes(systemTables2,basePath,schema){return buildEntityPublicRoutes(systemTables2,basePath,schema)}function buildPublicRoutes(config,systemTables2,basePath="",schema="public"){let authRoutes=buildAuthPublicRoutes(config,basePath),entityRoutes=buildEntityPublicRoutes(config.entities||[],basePath,schema),systemRoutes=buildSystemTablePublicRoutes(systemTables2,basePath,schema),pubsubRoutes=[];if(config.pubsub?.enabled){let pubsubBasePath=config.pubsub.basePath||"/subs",wsPath=config.pubsub.wsPath||"/api/events/subscribe";pubsubRoutes.push({path:`${pubsubBasePath}/:topic`,method:"POST",source:"system"},{path:wsPath,method:"GET",source:"system"})}let paymentRoutes=[];if(config.payment?.enabled){let paymentBasePath=config.payment.basePath||"/payment";paymentRoutes.push({path:`${paymentBasePath}/callback`,method:"POST",source:"system"},{path:`${paymentBasePath}/callback`,method:"OPTIONS",source:"system"},{path:`${paymentBasePath}/bin-query`,method:"POST",source:"system"},{path:`${paymentBasePath}/webhook`,method:"POST",source:"system"})}let discoveryRoutes=[];if(config.authorization?.endpointDiscovery?.enabled)discoveryRoutes.push({path:"/authorization/route-manifest",method:"GET",source:"system"},{path:"/authorization/route-manifest",method:"OPTIONS",source:"system"},{path:"/authorization/role-claims-manifest",method:"GET",source:"system"},{path:"/authorization/role-claims-manifest",method:"OPTIONS",source:"system"});let domainRoutes=[];if(config.domains?.enabled){let domainsBasePath=config.domains.basePath||"/domains";domainRoutes.push({path:`${basePath}${domainsBasePath}/resolve`,method:"GET",source:"system"})}let tenantRoutes=[];if(config.database?.isMultiTenant)tenantRoutes.push({path:`${basePath}/tenants`,method:"GET",source:"system"}),tenantRoutes.push({path:`${basePath}/tenants/check-subdomain/:subdomain`,method:"GET",source:"system"}),tenantRoutes.push({path:`${basePath}/tenants/self-signup`,method:"POST",source:"system"}),tenantRoutes.push({path:`${basePath}/tenants/refresh`,method:"POST",source:"system"});let customRoutes=[{path:"/nucleus-core",method:"GET",source:"custom"},{path:"/public",method:"GET",source:"custom"},{path:"/docs",method:"GET",source:"custom"},{path:"/docs/json",method:"GET",source:"custom"},{path:"/swagger",method:"GET",source:"custom"},{path:"/swagger/json",method:"GET",source:"custom"}],configPublicPaths=config.authorization?.publicPaths||[],ALL_PUBLIC_METHODS=["GET","POST","PUT","PATCH","DELETE","OPTIONS"],configPublicRoutes=configPublicPaths.flatMap((entry)=>{let trimmed=entry.trim(),qualified=trimmed.match(/^(GET|POST|PUT|PATCH|DELETE|OPTIONS)\s+(.+)$/i);if(qualified?.[1]&&qualified[2]){let method=qualified[1].toUpperCase(),path2=qualified[2].trim(),routes=[{path:path2,method,source:"custom"}];if(method!=="OPTIONS")routes.push({path:path2,method:"OPTIONS",source:"custom"});return routes}if(trimmed.startsWith("/auth/"))return ALL_PUBLIC_METHODS.map((method)=>({path:trimmed,method,source:"custom"}));return logger.warn(`[Security] publicPaths entry "${trimmed}" is unqualified \u2014 exposing GET + OPTIONS only. To make a write method public, use the explicit form, e.g. "POST ${trimmed}".`),[{path:trimmed,method:"GET",source:"custom"},{path:trimmed,method:"OPTIONS",source:"custom"}]});return[...authRoutes,...entityRoutes,...systemRoutes,...pubsubRoutes,...paymentRoutes,...discoveryRoutes,...domainRoutes,...tenantRoutes,...customRoutes,...configPublicRoutes]}function isPublicRoute(publicRoutes,path2,method){if(/\/\/|\\|%2f|%2e|%5c/i.test(path2))return!1;let normalizedPath=path2.replace(/\/$/,""),normalizedMethod=method.toUpperCase();for(let route of publicRoutes){if(route.method!==normalizedMethod)continue;if(matchPath(route.path,normalizedPath))return!0}return!1}function matchPath(pattern,path2){if(pattern===path2)return!0;let patternParts=pattern.split("/").filter(Boolean),pathParts=path2.split("/").filter(Boolean);if(patternParts.length!==pathParts.length)return!1;for(let i=0;i<patternParts.length;i++){let patternPart=patternParts[i],pathPart=pathParts[i];if(patternPart?.startsWith(":"))continue;if(patternPart!==pathPart)return!1}return!0}import{Elysia as Elysia2}from"elysia";import{eq as eq19}from"drizzle-orm";import{eq as eq18}from"drizzle-orm";var col7=(table,name2)=>{let tableRecord=table,snakeCase=name2.replace(/([A-Z])/g,"_$1").toLowerCase();return tableRecord[name2]||tableRecord[snakeCase]};async function requireGodmin(db,usersTable,userId){let user=(await db.select().from(usersTable).where(eq18(col7(usersTable,"id"),userId)).limit(1))[0];return Boolean(user?.isGod)}function validatePassword(pwd,policy){let errors2=[],minLen=policy?.minLength??8,maxLen=policy?.maxLength??128,needUpper=policy?.requireUppercase??!0,needLower=policy?.requireLowercase??!0,needDigit=policy?.requireNumber??!0,needSpecial=policy?.requireSpecialChar??!1;if(pwd.length<minLen)errors2.push(`Password must be at least ${minLen} characters`);if(pwd.length>maxLen)errors2.push(`Password must be at most ${maxLen} characters`);if(needUpper&&!/[A-Z]/.test(pwd))errors2.push("Password must contain uppercase letter");if(needLower&&!/[a-z]/.test(pwd))errors2.push("Password must contain lowercase letter");if(needDigit&&!/[0-9]/.test(pwd))errors2.push("Password must contain a number");if(needSpecial&&!/[!@#$%^&*()_+\-=[\]{};':"\\|,.<>/?]/.test(pwd))errors2.push("Password must contain a special character");return{valid:errors2.length===0,errors:errors2}}var handleActivateUsers=(db,usersTable,logger2)=>async(ctx)=>{let userId=ctx.request.headers.get("x-user-id");if(!userId||!await requireGodmin(db,usersTable,userId))return ctx.set.status=403,{success:!1,message:"Forbidden"};let result=await db.update(usersTable).set({isLocked:!1,lockedUntil:null,failedLoginAttempts:0,updatedAt:new Date}).where(eq19(col7(usersTable,"cohortId"),ctx.params.id)).returning();return logger2.audit({entityName:"user_cohorts",entityId:ctx.params.id,operation:"COHORT_ACTIVATE_USERS",userId,summary:`Activated ${result.length} users in cohort`}),{success:!0,data:{affected:result.length}}};init_assignDefaultRole();init_utils6();import{count,eq as eq21,inArray as inArray6}from"drizzle-orm";var handleBulkCreateUsers=(config,logger2)=>{let{db,usersTable,cohortsTable,rolesTable,userRolesTable,profilesTable}=config;return async(ctx)=>{if(!db||!usersTable||!cohortsTable)return ctx.set.status=500,{success:!1,message:"Server misconfigured"};let callerId=ctx.request.headers.get("x-user-id");if(!callerId||!await requireGodmin(db,usersTable,callerId))return ctx.set.status=403,{success:!1,message:"Forbidden"};let cohortId=ctx.params.id;if((await db.select().from(cohortsTable).where(eq21(col7(cohortsTable,"id"),cohortId)).limit(1)).length===0)return ctx.set.status=404,{success:!1,message:"Cohort not found"};let{users:explicitUsers,emailPrefix,emailDomain,sharedPassword,count:userCount,roleIds}=ctx.body,userList=[];if(explicitUsers&&explicitUsers.length>0)for(let u of explicitUsers)userList.push({email:u.email.toLowerCase().trim(),password:u.password,firstName:u.profile?.firstName,lastName:u.profile?.lastName});else if(emailPrefix&&emailDomain&&sharedPassword&&userCount){let padLen=String(userCount).length;for(let i=1;i<=userCount;i++){let paddedNum=String(i).padStart(padLen,"0");userList.push({email:`${emailPrefix}-${paddedNum}@${emailDomain}`.toLowerCase(),password:sharedPassword})}}else return ctx.set.status=400,{success:!1,message:'Provide either "users" array or "emailPrefix" + "emailDomain" + "sharedPassword" + "count"'};if(userList.length>500)return ctx.set.status=400,{success:!1,message:"Maximum 500 users per batch"};for(let entry of userList){let validation=validatePassword(entry.password,config.passwordPolicy);if(!validation.valid)return ctx.set.status=400,{success:!1,message:`Password too weak for ${entry.email}`,errors:validation.errors}}let emails=userList.map((u)=>u.email),existingRows=await db.select({email:col7(usersTable,"email")}).from(usersTable).where(inArray6(col7(usersTable,"email"),emails)),existingEmails=new Set(existingRows.map((r)=>String(r.email).toLowerCase())),created=[],skipped=[],now=new Date;for(let entry of userList){if(existingEmails.has(entry.email)){skipped.push(entry.email);continue}let hashedPw=await hashPassword(entry.password),newUser=(await db.insert(usersTable).values({email:entry.email,password:hashedPw,emailVerified:!0,verifiedAt:now,isLocked:!1,cohortId,createdAt:now,updatedAt:now}).returning())[0];if(!newUser)continue;let newUserId=String(newUser.id);if(created.push({id:newUserId,email:entry.email,password:entry.password}),roleIds&&roleIds.length>0&&rolesTable&&userRolesTable){let validIds=(await db.select({id:col7(rolesTable,"id")}).from(rolesTable).where(inArray6(col7(rolesTable,"id"),roleIds))).map((r)=>String(r.id));if(validIds.length>0)await db.insert(userRolesTable).values(validIds.map((roleId)=>({userId:newUserId,roleId})))}else if(config.defaultRole)await assignDefaultRole({db,userId:newUserId,roleName:config.defaultRole,rolesTable,userRolesTable,logger:logger2});if((entry.firstName||entry.lastName)&&profilesTable)await db.insert(profilesTable).values({userId:newUserId,firstName:entry.firstName??null,lastName:entry.lastName??null,createdAt:now,updatedAt:now}).catch((err)=>{logger2.warn("[Cohort] Failed to create profile for user",{userId:newUserId,error:err.message})})}let countResult=await db.select({count:count()}).from(usersTable).where(eq21(col7(usersTable,"cohortId"),cohortId)),totalUsers=Number(countResult[0]?.count)||0;return await db.update(cohortsTable).set({userCount:totalUsers,updatedAt:new Date}).where(eq21(col7(cohortsTable,"id"),cohortId)),logger2.audit({entityName:"user_cohorts",entityId:cohortId,operation:"COHORT_BULK_CREATE",userId:callerId,summary:`Bulk created ${created.length} users in cohort (${skipped.length} skipped)`}),{success:!0,data:{created:created.length,skipped:skipped.length,skippedEmails:skipped,users:created}}}};var handleCreateCohort=(db,usersTable,cohortsTable,logger2)=>async(ctx)=>{let userId=ctx.request.headers.get("x-user-id");if(!userId||!await requireGodmin(db,usersTable,userId))return ctx.set.status=403,{success:!1,message:"Forbidden"};let{name:name2,description,expiresAt,metadata}=ctx.body,now=new Date,inserted=await db.insert(cohortsTable).values({name:name2,description:description??null,createdBy:userId,expiresAt:expiresAt?new Date(expiresAt):null,userCount:0,metadata:metadata??{},createdAt:now,updatedAt:now}).returning();return logger2.audit({entityName:"user_cohorts",entityId:inserted[0]?.id,operation:"COHORT_CREATE",userId,summary:`Created cohort "${name2}"`}),{success:!0,data:inserted[0]}};import{eq as eq22}from"drizzle-orm";var handleDeactivateUsers=(db,usersTable,logger2)=>async(ctx)=>{let userId=ctx.request.headers.get("x-user-id");if(!userId||!await requireGodmin(db,usersTable,userId))return ctx.set.status=403,{success:!1,message:"Forbidden"};let result=await db.update(usersTable).set({isLocked:!0,updatedAt:new Date}).where(eq22(col7(usersTable,"cohortId"),ctx.params.id)).returning();return logger2.audit({entityName:"user_cohorts",entityId:ctx.params.id,operation:"COHORT_DEACTIVATE_USERS",userId,summary:`Deactivated ${result.length} users in cohort`}),{success:!0,data:{affected:result.length}}};import{eq as eq23,inArray as inArray7}from"drizzle-orm";var handleDeleteUsers=(db,usersTable,cohortsTable,userRolesTable,profilesTable,logger2)=>async(ctx)=>{let userId=ctx.request.headers.get("x-user-id");if(!userId||!await requireGodmin(db,usersTable,userId))return ctx.set.status=403,{success:!1,message:"Forbidden"};let userIds=(await db.select({id:col7(usersTable,"id")}).from(usersTable).where(eq23(col7(usersTable,"cohortId"),ctx.params.id))).map((u)=>String(u.id));if(userIds.length>0){if(userRolesTable)await db.delete(userRolesTable).where(inArray7(col7(userRolesTable,"userId"),userIds));if(profilesTable)await db.delete(profilesTable).where(inArray7(col7(profilesTable,"userId"),userIds));await db.delete(usersTable).where(inArray7(col7(usersTable,"id"),userIds))}return await db.update(cohortsTable).set({userCount:0,updatedAt:new Date}).where(eq23(col7(cohortsTable,"id"),ctx.params.id)),logger2.audit({entityName:"user_cohorts",entityId:ctx.params.id,operation:"COHORT_DELETE_USERS",userId,summary:`Deleted ${userIds.length} users from cohort`}),{success:!0,data:{deleted:userIds.length}}};import{eq as eq24}from"drizzle-orm";var handleGetCohort=(db,usersTable,cohortsTable)=>async(ctx)=>{let userId=ctx.request.headers.get("x-user-id");if(!userId||!await requireGodmin(db,usersTable,userId))return ctx.set.status=403,{success:!1,message:"Forbidden"};let rows=await db.select().from(cohortsTable).where(eq24(col7(cohortsTable,"id"),ctx.params.id)).limit(1);if(rows.length===0)return ctx.set.status=404,{success:!1,message:"Cohort not found"};let userRows=await db.select().from(usersTable).where(eq24(col7(usersTable,"cohortId"),ctx.params.id));return{success:!0,data:{...rows[0],users:userRows}}};import{eq as eq25}from"drizzle-orm";var csvCell=(value)=>{let s=value==null?"":String(value);if(/^[=+\-@\t\r]/.test(s))s=`'${s}`;if(/[",\n\r]/.test(s))s=`"${s.replace(/"/g,'""')}"`;return s},handleExportUsers=(db,usersTable)=>async(ctx)=>{let userId=ctx.request.headers.get("x-user-id");if(!userId||!await requireGodmin(db,usersTable,userId))return ctx.set.status=403,{success:!1,message:"Forbidden"};let userRows=await db.select().from(usersTable).where(eq25(col7(usersTable,"cohortId"),ctx.params.id)),lines=["email,status,locked,created_at"];for(let row of userRows){let u=row;lines.push([csvCell(u.email),csvCell(u.isActive?"active":"inactive"),csvCell(u.isLocked?"yes":"no"),csvCell(u.createdAt)].join(","))}return ctx.set.headers["content-type"]="text/csv",ctx.set.headers["content-disposition"]=`attachment; filename="cohort-${ctx.params.id}-users.csv"`,lines.join(`
|
|
529
|
-
`)};var handleListCohorts=(db,usersTable,cohortsTable)=>async(ctx)=>{let userId=ctx.request.headers.get("x-user-id");if(!userId||!await requireGodmin(db,usersTable,userId))return ctx.set.status=403,{success:!1,message:"Forbidden"};let rows=await db.select().from(cohortsTable);return{success:!0,data:{items:rows,meta:{totalItems:rows.length}}}};import{eq as eq26}from"drizzle-orm";var handleDeleteCohort=(db,usersTable,cohortsTable,logger2)=>async(ctx)=>{let userId=ctx.request.headers.get("x-user-id");if(!userId||!await requireGodmin(db,usersTable,userId))return ctx.set.status=403,{success:!1,message:"Forbidden"};return await db.update(usersTable).set({cohortId:null,updatedAt:new Date}).where(eq26(col7(usersTable,"cohortId"),ctx.params.id)),await db.delete(cohortsTable).where(eq26(col7(cohortsTable,"id"),ctx.params.id)),logger2.audit({entityName:"user_cohorts",entityId:ctx.params.id,operation:"COHORT_DELETE",userId,summary:`Deleted cohort ${ctx.params.id}`}),{success:!0,data:null}};import{eq as eq27}from"drizzle-orm";var handleUpdateCohort=(db,usersTable,cohortsTable)=>async(ctx)=>{let userId=ctx.request.headers.get("x-user-id");if(!userId||!await requireGodmin(db,usersTable,userId))return ctx.set.status=403,{success:!1,message:"Forbidden"};let updates={updatedAt:new Date};if(ctx.body.name!==void 0)updates.name=ctx.body.name;if(ctx.body.description!==void 0)updates.description=ctx.body.description;if(ctx.body.expiresAt!==void 0)updates.expiresAt=ctx.body.expiresAt?new Date(ctx.body.expiresAt):null;if(ctx.body.metadata!==void 0)updates.metadata=ctx.body.metadata;if(ctx.body.isActive!==void 0)updates.isActive=ctx.body.isActive;let updated=await db.update(cohortsTable).set(updates).where(eq27(col7(cohortsTable,"id"),ctx.params.id)).returning();if(updated.length===0)return ctx.set.status=404,{success:!1,message:"Cohort not found"};return{success:!0,data:updated[0]}};import{t}from"elysia";var CohortBodySchema=t.Object({name:t.String({minLength:1,maxLength:255}),description:t.Optional(t.String()),expiresAt:t.Optional(t.String()),metadata:t.Optional(t.Record(t.String(),t.Unknown()))}),CohortUpdateSchema=t.Object({name:t.Optional(t.String({minLength:1,maxLength:255})),description:t.Optional(t.String()),expiresAt:t.Optional(t.Union([t.String(),t.Null()])),metadata:t.Optional(t.Record(t.String(),t.Unknown())),isActive:t.Optional(t.Boolean())}),BulkCreateUserItem=t.Object({email:t.String({format:"email"}),password:t.String({minLength:8}),profile:t.Optional(t.Object({firstName:t.Optional(t.String()),lastName:t.Optional(t.String())}))}),BulkCreateSchema=t.Object({users:t.Optional(t.Array(BulkCreateUserItem)),emailPrefix:t.Optional(t.String()),emailDomain:t.Optional(t.String()),sharedPassword:t.Optional(t.String({minLength:8})),count:t.Optional(t.Integer({minimum:1,maximum:500})),roleIds:t.Optional(t.Array(t.String()))});function createCohortRoutes(config){let{db,logger:logger2,cohortsTable,usersTable,userRolesTable,profilesTable,basePath}=config,routes=new Elysia2;if(!db||!cohortsTable||!usersTable)return logger2.warn("[Cohort] Skipped \u2014 missing tables",{hasDb:!!db,hasCohortsTable:!!cohortsTable,hasUsersTable:!!usersTable}),routes;return routes.get(basePath,handleListCohorts(db,usersTable,cohortsTable)),routes.get(`${basePath}/:id`,handleGetCohort(db,usersTable,cohortsTable)),routes.post(basePath,handleCreateCohort(db,usersTable,cohortsTable,logger2),{body:CohortBodySchema}),routes.patch(`${basePath}/:id`,handleUpdateCohort(db,usersTable,cohortsTable),{body:CohortUpdateSchema}),routes.delete(`${basePath}/:id`,handleDeleteCohort(db,usersTable,cohortsTable,logger2)),routes.post(`${basePath}/:id/bulk-create`,handleBulkCreateUsers(config,logger2),{body:BulkCreateSchema}),routes.post(`${basePath}/:id/deactivate-users`,handleDeactivateUsers(db,usersTable,logger2)),routes.post(`${basePath}/:id/activate-users`,handleActivateUsers(db,usersTable,logger2)),routes.post(`${basePath}/:id/delete-users`,handleDeleteUsers(db,usersTable,cohortsTable,userRolesTable,profilesTable,logger2)),routes.get(`${basePath}/:id/export`,handleExportUsers(db,usersTable)),routes}init_deviceInfo();import{Elysia as Elysia6}from"elysia";import{Elysia as Elysia3,t as t2}from"elysia";init_Authorization();function getUserId(request){return request.headers.get("x-user-id")}function isChatModerator(request,moderatorRoles){let roles=decodeHeaderList(request.headers.get("x-user-roles"));if(roles.includes(GODMIN_ROLE_NAME))return!0;if(moderatorRoles.length===0)return!1;let allowed=new Set(moderatorRoles.map((role)=>role.toLowerCase()));return roles.some((role)=>allowed.has(role.toLowerCase()))}function chatErrorStatus(code){switch(code){case"forbidden":return 403;case"not_found":return 404;case"validation":return 400;case"conflict":return 409;case"disabled":return 409;default:return 400}}async function guard(set,logger2,fn){try{return{success:!0,data:await fn()}}catch(err){if(err instanceof ChatError)return set.status=chatErrorStatus(err.code),{success:!1,message:err.message};return logger2.error("[Chat] Unhandled route error",{error:err instanceof Error?err.message:String(err)}),set.status=500,{success:!1,message:"Internal server error"}}}function unauthorized(set){return set.status=401,{success:!1,message:"Authentication required"}}function createConversationRoutes(deps){let{logger:logger2,getService}=deps,app=new Elysia3({prefix:deps.config.basePath});return app.get("/conversations",({request,query,set})=>{let userId=getUserId(request);if(!userId)return unauthorized(set);let{service}=getService(request);return guard(set,logger2,()=>service.listConversations(userId,{limit:query.limit?Number(query.limit):void 0,offset:query.offset?Number(query.offset):void 0}))},{query:t2.Object({limit:t2.Optional(t2.String()),offset:t2.Optional(t2.String())}),detail:{tags:["Chat"],summary:"List my conversations"}}),app.post("/conversations",({request,body,set})=>{let userId=getUserId(request);if(!userId)return unauthorized(set);let{service}=getService(request),input=body;return guard(set,logger2,()=>{if(input.type==="group"){if(!input.title)throw new ChatError("validation","A group title is required");return service.createGroup({creatorId:userId,title:input.title,description:input.description,avatarFileId:input.avatarFileId,participantIds:input.participantIds??[]})}if(!input.targetUserId)throw new ChatError("validation","targetUserId is required for a direct conversation");return service.getOrCreateDirect(userId,input.targetUserId)})},{body:t2.Object({type:t2.Optional(t2.Union([t2.Literal("direct"),t2.Literal("group")])),targetUserId:t2.Optional(t2.String()),title:t2.Optional(t2.String()),description:t2.Optional(t2.String()),avatarFileId:t2.Optional(t2.String()),participantIds:t2.Optional(t2.Array(t2.String()))}),detail:{tags:["Chat"],summary:"Create or open a conversation"}}),app.get("/conversations/:id",({request,params,set})=>{let userId=getUserId(request);if(!userId)return unauthorized(set);let{service}=getService(request);return guard(set,logger2,()=>service.getConversation(params.id,userId))},{params:t2.Object({id:t2.String()}),detail:{tags:["Chat"],summary:"Get a conversation"}}),app.post("/conversations/:id/participants",({request,params,body,set})=>{let userId=getUserId(request);if(!userId)return unauthorized(set);let{service}=getService(request),{userIds}=body;return guard(set,logger2,()=>service.addParticipants(params.id,userId,userIds))},{params:t2.Object({id:t2.String()}),body:t2.Object({userIds:t2.Array(t2.String())}),detail:{tags:["Chat"],summary:"Add group participants"}}),app.delete("/conversations/:id/participants/:userId",({request,params,set})=>{let userId=getUserId(request);if(!userId)return unauthorized(set);let{service}=getService(request);return guard(set,logger2,async()=>{return await service.removeParticipant(params.id,userId,params.userId),{removed:params.userId}})},{params:t2.Object({id:t2.String(),userId:t2.String()}),detail:{tags:["Chat"],summary:"Remove a participant / leave group"}}),app}import{Elysia as Elysia5,t as t4}from"elysia";init_storage2();var CONTENT_TYPE_SCHEMA=t4.Optional(t4.Union([t4.Literal("text"),t4.Literal("image"),t4.Literal("file"),t4.Literal("video"),t4.Literal("audio")]));function createMessageRoutes(deps){let{logger:logger2,getService}=deps,app=new Elysia5({prefix:deps.config.basePath});return app.get("/conversations/:id/messages",({request,params,query,set})=>{let userId=getUserId(request);if(!userId)return unauthorized(set);let{service}=getService(request);return guard(set,logger2,()=>service.getMessages({conversationId:params.id,userId,limit:query.limit?Number(query.limit):void 0,before:query.before||void 0}))},{params:t4.Object({id:t4.String()}),query:t4.Object({limit:t4.Optional(t4.String()),before:t4.Optional(t4.String())}),detail:{tags:["Chat"],summary:"Get conversation messages (newest first)"}}),app.post("/conversations/:id/messages",({request,params,body,set})=>{let userId=getUserId(request);if(!userId)return unauthorized(set);let{service}=getService(request),input=body;return guard(set,logger2,()=>service.sendMessage({conversationId:params.id,senderId:userId,content:input.content,contentType:input.contentType,replyToId:input.replyToId,clientMessageId:input.clientMessageId,attachments:input.attachmentIds?.map((fileId)=>({fileId})),metadata:input.metadata}))},{params:t4.Object({id:t4.String()}),body:t4.Object({content:t4.Optional(t4.String()),contentType:CONTENT_TYPE_SCHEMA,replyToId:t4.Optional(t4.String()),clientMessageId:t4.Optional(t4.String()),attachmentIds:t4.Optional(t4.Array(t4.String())),metadata:t4.Optional(t4.Any())}),detail:{tags:["Chat"],summary:"Send a message (link pre-uploaded attachments)"}}),app.post("/conversations/:id/messages/upload",({request,params,body,set})=>{let userId=getUserId(request);if(!userId)return unauthorized(set);if(!deps.attachmentsAvailable)return set.status=409,{success:!1,message:"File attachments require storage and CDN to be enabled"};let{service,schemaTables}=getService(request);return guard(set,logger2,async()=>{let filesTable=resolveSchemaTable(schemaTables,"files",logger2);if(!filesTable)throw new ChatError("disabled","Files table unavailable in this schema");let{data,files}=parseFormDataBody(body,deps.storageConfig);if(files.length===0)throw new ChatError("validation","At least one file is required");let{records,failed}=await persistUploadedFiles({db:deps.db,filesTable,files,storageConfig:deps.storageConfig,subFolder:"chat",userId});if(records.length===0)throw new ChatError("validation",failed[0]?.error??"File upload failed");if(deps.cdnMedia)scheduleUploadMediaProcessing(records,{storagePath:deps.storageConfig.basePath,media:deps.cdnMedia,logger:logger2});let content=typeof data.content==="string"?data.content:void 0,replyToId=typeof data.replyToId==="string"?data.replyToId:void 0,clientMessageId=typeof data.clientMessageId==="string"?data.clientMessageId:void 0;return service.sendMessage({conversationId:params.id,senderId:userId,content,replyToId,clientMessageId,attachments:records.map((record)=>({fileId:record.id,originalName:record.originalName,mimeType:record.mimeType,size:record.size}))})})},{type:"formdata",params:t4.Object({id:t4.String()}),body:t4.Object({[deps.storageConfig.formData.dataField]:t4.Optional(t4.Union([t4.String(),t4.Any()])),[deps.storageConfig.formData.filesField]:t4.Optional(t4.Union([t4.File(),t4.Array(t4.File())]))}),detail:{tags:["Chat"],summary:"Send a message with uploaded file attachments"}}),app.post("/conversations/:id/read",({request,params,body,set})=>{let userId=getUserId(request);if(!userId)return unauthorized(set);let{service}=getService(request),{messageId}=body;return guard(set,logger2,()=>service.markRead(params.id,userId,messageId))},{params:t4.Object({id:t4.String()}),body:t4.Object({messageId:t4.Optional(t4.String())}),detail:{tags:["Chat"],summary:"Mark a conversation as read"}}),app.post("/conversations/:id/typing",({request,params,body,set})=>{let userId=getUserId(request);if(!userId)return unauthorized(set);let{service}=getService(request),{isTyping}=body;return guard(set,logger2,async()=>{return await service.setTyping(params.id,userId,isTyping??!0),{ok:!0}})},{params:t4.Object({id:t4.String()}),body:t4.Object({isTyping:t4.Optional(t4.Boolean())}),detail:{tags:["Chat"],summary:"Broadcast a typing indicator"}}),app.patch("/messages/:id",({request,params,body,set})=>{let userId=getUserId(request);if(!userId)return unauthorized(set);let{service}=getService(request),{content}=body;return guard(set,logger2,()=>service.editMessage(params.id,userId,content))},{params:t4.Object({id:t4.String()}),body:t4.Object({content:t4.String()}),detail:{tags:["Chat"],summary:"Edit a message"}}),app.delete("/messages/:id",({request,params,set})=>{let userId=getUserId(request);if(!userId)return unauthorized(set);let{service}=getService(request),asModerator=isChatModerator(request,deps.config.moderatorRoles??[]);return guard(set,logger2,async()=>{if(await service.deleteMessage(params.id,userId,asModerator),asModerator)logger2.warn("[CHAT] Message deleted by a moderator",{actorId:userId,messageId:params.id});return{deleted:params.id}})},{params:t4.Object({id:t4.String()}),detail:{tags:["Chat"],summary:"Delete a message",description:"Sender-only, unless the caller is godmin or holds a role from chat.moderatorRoles \u2014 then any message, and `deletionEnabled` does not apply."}}),app}function createChatRoutes(routeConfig){let{db,schemaTables,config,logger:logger2,broadcaster,tenantRegistry,storageConfig,attachmentsAvailable,cdnBasePath,cdnMedia}=routeConfig,buildService=(tables)=>new ChatService({db,schemaTables:tables,config,logger:logger2,broadcaster,cdnBasePath,attachmentsAvailable}),defaultService=buildService(schemaTables),deps={db,config,logger:logger2,storageConfig,attachmentsAvailable,getService:(request)=>{if(!tenantRegistry)return{service:defaultService,schemaTables};let schemaName=request.headers.get("x-tenant-schema");if(!schemaName)return{service:defaultService,schemaTables};let ctx=tenantRegistry.getSchemaContext(schemaName);if(!ctx)return{service:defaultService,schemaTables};return{service:buildService(ctx.schemaTables),schemaTables:ctx.schemaTables}},cdnMedia},routes=new Elysia6;return routes.use(createConversationRoutes(deps)),routes.use(createMessageRoutes(deps)),logger2.info(`[Chat] Routes registered at ${config.basePath}`,{attachmentsAvailable,groupsEnabled:config.groupsEnabled}),{routes,chatService:defaultService}}init_Authorization();init_helpers3();import Elysia7,{t as t5}from"elysia";function createConfigRoutes(routeConfig){let{logger:logger2,resolvedOptions,configFilePath,basePath,onConfigUpdate,db,schemaTables,getRedis}=routeConfig,plugin=new Elysia7({prefix:basePath});return plugin.onBeforeHandle(async({request,set})=>{if(decodeHeaderList(request.headers.get("x-user-roles")).includes(GODMIN_ROLE_NAME))return;let userId=request.headers.get("x-user-id");if(userId&&db&&schemaTables.users)try{let{eq:eq28}=await import("drizzle-orm"),usersTable=schemaTables.users;if((await db.select().from(usersTable).where(eq28(usersTable.id,userId)).limit(1))[0]?.isGod===!0)return}catch(err){logger2.warn("[ConfigManagement] Failed to check isGod from DB",{error:err instanceof Error?err.message:String(err)})}return set.status=403,Response.json({isSuccess:!1,message:"Only godmin users can access config management",data:null})}),plugin.get("/",()=>{let configCopy=JSON.parse(JSON.stringify(resolvedOptions));return{isSuccess:!0,message:"Current running configuration",data:{config:maskSensitiveFields(configCopy),configFilePath,sections:buildSectionsMeta(resolvedOptions)}}},{detail:{tags:["Config Management"],summary:"Get full running configuration",description:"Returns the full running configuration with sensitive fields masked."}}),plugin.get("/sections",()=>({isSuccess:!0,message:"Config section metadata",data:{sections:buildSectionsMeta(resolvedOptions)}}),{detail:{tags:["Config Management"],summary:"List all config sections with metadata",description:"Section list is derived at runtime from the config object \u2014 no hardcoding."}}),plugin.get("/env",()=>{let configCopy=JSON.parse(JSON.stringify(resolvedOptions)),declared=scanEnvVars(configCopy),declaredNames=new Set(declared.map((e)=>e.envName)),undeclared=scanUndeclaredEnv(declaredNames),entries=[...declared,...undeclared],resolvedCount=entries.filter((e)=>e.resolved).length,missingCount=entries.length-resolvedCount,unrecognizedCount=undeclared.length;return{isSuccess:!0,message:`Found ${entries.length} env vars (${resolvedCount} resolved, ${missingCount} missing, ${unrecognizedCount} unrecognized)`,data:{entries,totalCount:entries.length,resolvedCount,missingCount,unrecognizedCount}}},{detail:{tags:["Config Management"],summary:"Get environment variables (declared + undeclared)",description:"Surfaces both (a) DECLARED env vars \u2014 UPPER_SNAKE_CASE references found in the config tree (recognized:true) \u2014 and (b) UNDECLARED env vars actually present in process.env but not declared (recognized:false), minus Kubernetes service-link and OS/interpreter infra noise, so orphaned / junk config surfaces for cleanup. Sensitive values are masked; AI-provider *_API_KEY vars are never surfaced."}}),plugin.get("/overrides",async()=>{let redis=getRedis();if(!redis)return{isSuccess:!0,message:"Redis not available \u2014 no overrides stored",data:{overrides:null,sectionCount:0,sections:[]}};let overrides=await readOverridesFromRedis(redis,resolvedOptions.appId||"nucleus"),sections=overrides?Object.keys(overrides).filter((k)=>{let v=overrides[k];return v!==void 0&&v!==null&&(typeof v!=="object"||Object.keys(v).length>0)}):[];return{isSuccess:!0,message:sections.length>0?`${sections.length} section override(s) stored in Redis`:"No overrides in Redis",data:{overrides:overrides?maskSensitiveFields(overrides):null,sectionCount:sections.length,sections}}},{detail:{tags:["Config Management"],summary:"View Redis config overrides",description:"Returns overrides stored in Redis that will be merged on next restart."}}),plugin.delete("/overrides",async()=>{let redis=getRedis();if(!redis)return{isSuccess:!1,message:"Redis not available",data:null};let existing=await readOverridesFromRedis(redis,resolvedOptions.appId||"nucleus"),clearedSections=existing?Object.keys(existing):[];return await clearOverridesFromRedis(redis,resolvedOptions.appId||"nucleus"),logger2.info("[ConfigManagement] Redis overrides cleared",{clearedSections}),{isSuccess:!0,message:clearedSections.length>0?`Cleared ${clearedSections.length} override(s) from Redis. Restart to revert to config.json defaults.`:"No overrides to clear.",data:{message:"Redis overrides cleared",clearedSections}}},{detail:{tags:["Config Management"],summary:"Clear all Redis config overrides",description:"Removes all stored overrides from Redis. Restart to revert to config.json defaults."}}),plugin.get("/:section",({params})=>{let{section}=params;if(!hasSection(resolvedOptions,section))return{isSuccess:!1,message:`Unknown config section: ${section}`,data:null};let sectionValue=extractSection(resolvedOptions,section),restart=isRestartRequired(section),maskedValue=sectionValue;if(typeof sectionValue==="object"&§ionValue!==null&&!Array.isArray(sectionValue))maskedValue=maskSensitiveFields({[section]:sectionValue})[section];return{isSuccess:!0,message:`Config section: ${section}`,data:{section,config:maskedValue??null,restartRequired:restart}}},{params:t5.Object({section:t5.String()}),detail:{tags:["Config Management"],summary:"Get a specific config section",description:"Returns a specific config section with sensitive fields masked."}}),plugin.patch("/:section",async({params,body})=>{let{section}=params,payload=body;if(!hasSection(resolvedOptions,section))return{isSuccess:!1,message:`Unknown config section: ${section}`,data:null};if(!payload.config||typeof payload.config!=="object")return{isSuccess:!1,message:'Request body must contain a "config" object',data:null};let restart=isRestartRequired(section),currentValue=extractSection(resolvedOptions,section),newValue;if(Array.isArray(currentValue))newValue=payload.config.value!==void 0?payload.config.value:payload.config;else if(typeof currentValue==="object"&¤tValue!==null)newValue=deepMerge(currentValue,payload.config);else if(currentValue===void 0||typeof currentValue==="string"||typeof currentValue==="number"||typeof currentValue==="boolean")newValue=payload.config.value!==void 0?payload.config.value:payload.config;else newValue=payload.config;if(applySectionUpdate(resolvedOptions,section,newValue),!restart)onConfigUpdate(section,newValue);let persistMethod="memory-only",persistWarning=null;if(configFilePath)try{await persistConfigToDisk(configFilePath,resolvedOptions),persistMethod="disk",logger2.info(`[ConfigManagement] Section "${section}" persisted to disk`)}catch(diskErr){let diskMsg=diskErr instanceof Error?diskErr.message:String(diskErr);logger2.warn(`[ConfigManagement] Disk persist failed: ${diskMsg}`);let redis=getRedis();if(redis)try{await persistSectionToRedis(redis,resolvedOptions.appId||"nucleus",section,newValue),persistMethod="redis",logger2.info(`[ConfigManagement] Section "${section}" persisted to Redis (disk unavailable)`)}catch(redisErr){let redisMsg=redisErr instanceof Error?redisErr.message:String(redisErr);logger2.error(`[ConfigManagement] Redis persist also failed: ${redisMsg}`),persistWarning=`Disk: ${diskMsg}. Redis: ${redisMsg}. Changes are in-memory only and will be lost on restart.`}else persistWarning=`Disk: ${diskMsg}. Redis not available. Changes are in-memory only and will be lost on restart.`}logger2.info(`[ConfigManagement] Section "${section}" updated (persist: ${persistMethod}, restart-required: ${restart})`);let updatedValue=extractSection(resolvedOptions,section),maskedUpdated=updatedValue;if(typeof updatedValue==="object"&&updatedValue!==null&&!Array.isArray(updatedValue))maskedUpdated=maskSensitiveFields({[section]:updatedValue})[section];let baseMsg=restart?`Config section "${section}" saved (${persistMethod}). Restart required for changes to take effect.`:`Config section "${section}" updated and applied (${persistMethod}).`;return{isSuccess:!0,message:persistWarning?`${baseMsg} Warning: ${persistWarning}`:baseMsg,data:{section,applied:!restart,restartRequired:restart,config:maskedUpdated}}},{params:t5.Object({section:t5.String()}),body:t5.Object({config:t5.Record(t5.String(),t5.Unknown())}),detail:{tags:["Config Management"],summary:"Update a config section",description:"Deep-merges the payload into the section. Hot-reloadable sections apply immediately. Restart-required sections are saved to disk only."}}),plugin.post("/restart",({body})=>{let delayMs=body.delayMs??1000;logger2.info(`[ConfigManagement] Restart scheduled in ${delayMs}ms`);let scheduledAt=new Date().toISOString();return setTimeout(()=>{logger2.info("[ConfigManagement] Restarting process..."),process.exit(0)},delayMs),{isSuccess:!0,message:`Server restart scheduled in ${delayMs}ms`,data:{message:`Process will exit in ${delayMs}ms. Orchestrator (K8s/PM2/systemd) will restart it.`,scheduledAt}}},{body:t5.Optional(t5.Object({delayMs:t5.Optional(t5.Number())})),detail:{tags:["Config Management"],summary:"Restart the server process",description:"Triggers a graceful process exit after a configurable delay. The orchestrator (K8s, PM2, systemd) is expected to restart the process automatically."}}),logger2.info(`[ConfigManagement] Routes enabled at ${basePath}`),plugin}init_adminGuard();import{Elysia as Elysia8,t as t6}from"elysia";var requireAuth=(ctx)=>ctx.request.headers.get("x-user-id"),fail=(ctx,status,message)=>{return ctx.set.status=status,{success:!1,message,data:null}},callerSchemaOf=(ctx)=>ctx.request.headers.get("x-tenant-schema"),isGodmin=(ctx)=>hasGodminRole(ctx.request),ownsHostname=(ctx,record)=>{if(isGodmin(ctx))return!0;let caller=callerSchemaOf(ctx);return record.schemaName!=null&&record.schemaName===caller};function createHostnameRoutes(config){let base=config.basePath,app=new Elysia8,svc=(ctx)=>{let s=config.getDomainService();if(!s)return ctx.set.status=503,null;return s};app.post(`${base}/hostnames`,async(ctx)=>{let service=svc(ctx);if(!service)return{success:!1,message:"Domains not available",data:null};if(!requireAuth(ctx))return fail(ctx,401,"Authentication required");let body=ctx.body,callerSchema=callerSchemaOf(ctx),schemaName=body.schemaName??null,tenantId=body.tenantId??null;if(!hasGodminRole(ctx.request)){if(schemaName&&schemaName!==callerSchema)return fail(ctx,403,"Cannot bind a hostname to another tenant's schema");schemaName=callerSchema;let ownTenantId=config.resolveTenantIdForSchema?.(callerSchema)??null;if(tenantId&&tenantId!==ownTenantId)return fail(ctx,403,"Cannot bind a hostname to another tenant");tenantId=ownTenantId}try{let result=await service.createHostname({hostname:body.hostname,ownerId:body.ownerId,ownerType:body.ownerType,tenantId,schemaName,isPrimary:body.isPrimary});return{success:!0,message:"Custom hostname created",data:{hostname:result.hostname,instructions:result.instructions}}}catch(err){return fail(ctx,400,err instanceof Error?err.message:"Failed to create hostname")}},{body:t6.Object({hostname:t6.String(),ownerId:t6.String(),ownerType:t6.Optional(t6.Union([t6.Literal("tenant"),t6.Literal("organization"),t6.Literal("user"),t6.Literal("external")])),tenantId:t6.Optional(t6.String()),schemaName:t6.Optional(t6.String()),isPrimary:t6.Optional(t6.Boolean())}),detail:{tags:["Domains"],summary:"Create custom hostname"}}),app.get(`${base}/hostnames`,async(ctx)=>{let service=svc(ctx);if(!service)return{success:!1,message:"Domains not available",data:null};if(!requireAuth(ctx))return fail(ctx,401,"Authentication required");let url=new URL(ctx.request.url),items;if(isGodmin(ctx))items=await service.listHostnames({ownerId:url.searchParams.get("ownerId")??void 0,tenantId:url.searchParams.get("tenantId")??void 0});else{let ownTenantId=config.resolveTenantIdForSchema?.(callerSchemaOf(ctx))??null;items=ownTenantId?await service.listHostnames({tenantId:ownTenantId}):[]}return{success:!0,message:`Found ${items.length} hostnames`,data:{items}}}),app.get(`${base}/hostnames/:id`,async(ctx)=>{let service=svc(ctx);if(!service)return{success:!1,message:"Domains not available",data:null};if(!requireAuth(ctx))return fail(ctx,401,"Authentication required");let record=await service.getHostname(ctx.params.id);if(!record||!ownsHostname(ctx,record))return fail(ctx,404,"Hostname not found");return{success:!0,message:"Hostname found",data:record}}),app.get(`${base}/hostnames/:id/instructions`,async(ctx)=>{let service=svc(ctx);if(!service)return{success:!1,message:"Domains not available",data:null};if(!requireAuth(ctx))return fail(ctx,401,"Authentication required");let id=ctx.params.id,record=await service.getHostname(id);if(!record||!ownsHostname(ctx,record))return fail(ctx,404,"Hostname not found");return{success:!0,message:"DNS instructions",data:{instructions:await service.getInstructions(id)}}});let lifecycle=(suffix,run,summary)=>{app.post(`${base}/hostnames/:id/${suffix}`,async(ctx)=>{let service=svc(ctx);if(!service)return{success:!1,message:"Domains not available",data:null};if(!requireAuth(ctx))return fail(ctx,401,"Authentication required");let id=ctx.params.id,record=await service.getHostname(id);if(!record||!ownsHostname(ctx,record))return fail(ctx,404,"Hostname not found");try{let data=await run(service,id);if(!data)return fail(ctx,404,"Hostname not found");return{success:!0,message:summary,data}}catch(err){return fail(ctx,400,err instanceof Error?err.message:summary)}})};return lifecycle("verify",(s,id)=>s.verifyHostname(id),"Verification processed"),lifecycle("activate",(s,id)=>s.activateHostname(id),"Hostname activated"),lifecycle("disable",(s,id)=>s.disableHostname(id),"Hostname disabled"),lifecycle("make-primary",(s,id)=>s.makePrimary(id),"Primary hostname set"),lifecycle("refresh-status",(s,id)=>s.refreshStatus(id),"Status refreshed"),app}init_adminGuard();import{Elysia as Elysia9,t as t7}from"elysia";var requireAuth2=(ctx)=>ctx.request.headers.get("x-user-id"),fail2=(ctx,status,message)=>{return ctx.set.status=status,{success:!1,message,data:null}},callerSchemaOf2=(ctx)=>ctx.request.headers.get("x-tenant-schema"),isGodmin2=(ctx)=>hasGodminRole(ctx.request);function createRegistrationRoutes(config){let base=config.basePath,app=new Elysia9,svc=(ctx)=>{let s=config.getRegistrationService();if(!s)return ctx.set.status=503,null;return s},ownTenantId=(ctx)=>config.resolveTenantIdForSchema?.(callerSchemaOf2(ctx))??null,ownsRegistration=(ctx,record)=>{if(isGodmin2(ctx))return!0;let own=ownTenantId(ctx);return record.tenantId!=null&&own!=null&&record.tenantId===own};return app.post(`${base}/registrations`,async(ctx)=>{let service=svc(ctx);if(!service)return{success:!1,message:"Domains not available",data:null};if(!requireAuth2(ctx))return fail2(ctx,401,"Authentication required");let body=ctx.body,tenantId=body.tenantId??null,registrantOwnerType=body.registrantOwnerType;if(!isGodmin2(ctx)){let own=ownTenantId(ctx);if(tenantId&&tenantId!==own)return fail2(ctx,403,"Cannot register a domain for another tenant");if(tenantId=own,registrantOwnerType==="platform")return fail2(ctx,403,"Only a platform admin may register as 'platform'");registrantOwnerType="customer"}try{return{success:!0,message:"Registration requested",data:await service.createRequest({requestedDomain:body.requestedDomain,ownerId:body.ownerId,ownerType:body.ownerType,tenantId,registrantOwnerType,termsVersion:body.termsVersion,termsAccepted:body.termsAccepted,autoRenew:body.autoRenew})}}catch(err){return fail2(ctx,400,err instanceof Error?err.message:"Failed to request registration")}},{body:t7.Object({requestedDomain:t7.String(),ownerId:t7.String(),ownerType:t7.Optional(t7.Union([t7.Literal("tenant"),t7.Literal("organization"),t7.Literal("user"),t7.Literal("external")])),tenantId:t7.Optional(t7.String()),registrantOwnerType:t7.Optional(t7.Union([t7.Literal("customer"),t7.Literal("platform")])),termsVersion:t7.String(),termsAccepted:t7.Boolean(),autoRenew:t7.Optional(t7.Boolean())}),detail:{tags:["Domains"],summary:"Request managed domain registration"}}),app.get(`${base}/registrations`,async(ctx)=>{let service=svc(ctx);if(!service)return{success:!1,message:"Domains not available",data:null};if(!requireAuth2(ctx))return fail2(ctx,401,"Authentication required");let url=new URL(ctx.request.url),items;if(isGodmin2(ctx))items=await service.listRegistrations({ownerId:url.searchParams.get("ownerId")??void 0,tenantId:url.searchParams.get("tenantId")??void 0});else{let own=ownTenantId(ctx);items=own?await service.listRegistrations({tenantId:own}):[]}return{success:!0,message:`Found ${items.length} registrations`,data:{items}}}),app.get(`${base}/registrations/:id`,async(ctx)=>{let service=svc(ctx);if(!service)return{success:!1,message:"Domains not available",data:null};if(!requireAuth2(ctx))return fail2(ctx,401,"Authentication required");let record=await service.getRegistration(ctx.params.id);if(!record||!ownsRegistration(ctx,record))return fail2(ctx,404,"Registration not found");return{success:!0,message:"Registration found",data:record}}),app.post(`${base}/registrations/:id/cancel`,async(ctx)=>{let service=svc(ctx);if(!service)return{success:!1,message:"Domains not available",data:null};if(!requireAuth2(ctx))return fail2(ctx,401,"Authentication required");let id=ctx.params.id,record=await service.getRegistration(id);if(!record||!ownsRegistration(ctx,record))return fail2(ctx,404,"Registration not found");let cancelled=await service.cancel(id);if(!cancelled)return fail2(ctx,404,"Registration not found");return{success:!0,message:"Registration cancelled",data:cancelled}}),app.post(`${base}/registrations/:id/transfer-out`,async(ctx)=>{let service=svc(ctx);if(!service)return{success:!1,message:"Domains not available",data:null};if(!requireAuth2(ctx))return fail2(ctx,401,"Authentication required");let id=ctx.params.id,record=await service.getRegistration(id);if(!record||!ownsRegistration(ctx,record))return fail2(ctx,404,"Registration not found");let out=await service.requestTransferOut(id);if(!out)return fail2(ctx,404,"Registration not found");return{success:!0,message:"Transfer-out requested",data:out}}),app}import{Elysia as Elysia10}from"elysia";function createResolveRoute(config){let base=config.basePath,app=new Elysia10;return app.get(`${base}/resolve`,async(ctx)=>{let service=config.getDomainService();if(!service)return ctx.set.status=503,{success:!1,message:"Domains not available",data:null};let hostname=new URL(ctx.request.url).searchParams.get("hostname")||ctx.request.headers.get("host")||"";if(!hostname)return ctx.set.status=400,{success:!1,message:"hostname is required",data:null};let match=await service.resolveHostname(hostname);if(!match)return ctx.set.status=404,{success:!1,message:"No active hostname matched",data:null};return{success:!0,message:"Resolved",data:match}},{detail:{tags:["Domains"],summary:"Resolve hostname to tenant",description:"Public."}}),app}function createDomainRoutes(app,config){return app.use(createResolveRoute(config)),app.use(createHostnameRoutes(config)),app.use(createRegistrationRoutes(config)),app}import{and as and13,arrayContains,arrayOverlaps,asc,createTableRelationsHelpers,desc as desc5,eq as eq28,getTableName,gt,gte,ilike,inArray as inArray8,isNotNull,isNull as isNull2,like,lt as lt2,lte,ne as ne2,notInArray,or as or2,sql as sql7}from"drizzle-orm";import{drizzle}from"drizzle-orm/node-postgres";import{Elysia as Elysia11,t as t9}from"elysia";init_Authorization();init_utils5();init_adminGuard();init_sensitiveColumns();var snakeToCamel2=(s)=>s.replace(/_([a-z])/g,(_,l)=>l.toUpperCase()),SENSITIVE_SYSTEM_TABLE_SNAKE=["domain_hostnames","domain_registrations","domain_provider_records","domain_verification_challenges","domain_events","payment_sub_merchants","payment_invoices","payment_subscriptions","payment_customers","payment_transactions","payment_methods","payment_products","payment_prices","payment_commission_splits","payment_splits","payment_reserves","payment_ledger_entries","payment_payout_requests","payment_settlement_policies","payment_disputes","payment_webhook_logs","verifications","api_keys","magic_link_tokens","user_sessions","trusted_devices","integration_sources","integration_endpoints","integration_mappings"],SENSITIVE_SYSTEM_TABLES=new Set(SENSITIVE_SYSTEM_TABLE_SNAKE.flatMap((name2)=>[name2,snakeToCamel2(name2)]));function isSensitiveSystemTable(tableName){return SENSITIVE_SYSTEM_TABLES.has(tableName)}function delegatedWriteRoles(question){if(question.isRbacTable)return new Set;let roles=(question.featureSet??[]).flatMap((feature)=>question.featureAdminRoles?.[feature]??[]);return new Set(roles.map((role)=>role.toLowerCase()))}function isFeatureAdmin(question){let allowed=delegatedWriteRoles(question);if(allowed.size===0)return!1;return question.callerRoles.some((role)=>allowed.has(role.toLowerCase()))}init_storage2();function isAnonymousCreate(table,payload){let rule=table.anonymous_create;if(!rule)return!1;if(rule===!0)return!0;let column=rule.column;if(!column)return!1;let value=payload[column]??payload[toCamelCase3(column)]??payload[toSnakeCase2(column)];return isTruthy(value)}function isTruthy(value){if(typeof value==="boolean")return value;if(typeof value==="number")return value!==0;if(typeof value==="string"){let normalized=value.trim().toLowerCase();return normalized==="true"||normalized==="1"||normalized==="yes"||normalized==="on"}return!1}function createAuditIdentity(anonymous,userId,headers){if(anonymous)return{userId:void 0,ipAddress:"anonymous",userAgent:"anonymous"};return{userId:userId||void 0,ipAddress:headers.get("x-forwarded-for")?.split(",")[0]?.trim()||headers.get("x-real-ip")?.trim()||"unknown",userAgent:headers.get("user-agent")||"unknown"}}function toCamelCase3(value){return value.replace(/_([a-z0-9])/g,(_m,c)=>c.toUpperCase())}function toSnakeCase2(value){return value.replace(/[A-Z]/g,(c)=>`_${c.toLowerCase()}`)}var snakeToCamel3=(s)=>s.replace(/_([a-z])/g,(_,l)=>l.toUpperCase());function forceCreateScope(payload,authResult,resolveColumn){let scopeFilters=authResult?.scopeFilters;if(!scopeFilters)return{ok:!0};for(let[field,value]of Object.entries(scopeFilters)){if(!resolveColumn(field))return{ok:!1,field};payload[snakeToCamel3(field)]=value}return{ok:!0}}function decideRelationExpansion(params){let{authEnabled,targetTable,relAuth,isTargetPublicGet}=params;if(!authEnabled||!targetTable)return{expand:!0};if(relAuth===null)return isTargetPublicGet?{expand:!0}:{expand:!1};if(!relAuth.authorized)return{expand:!1};let scope=relAuth.scopeFilters;if(scope&&Object.keys(scope).length>0)return{expand:!0,scope};return{expand:!0}}function resolveRelationScopeColumn(fields,key2,toCamel5){if(Object.hasOwn(fields,key2))return fields[key2];let camel=toCamel5(key2);return Object.hasOwn(fields,camel)?fields[camel]:void 0}import{t as t8}from"elysia";function buildBodySchemaFromEntityColumns(entityColumns){let properties={};if(!entityColumns||entityColumns.length===0)return t8.Object({},{additionalProperties:!0});for(let col8 of entityColumns)switch(col8.type?.toLowerCase()||"string"){case"integer":case"int":case"serial":case"bigserial":case"numeric":case"decimal":properties[col8.name]=col8.notNull?t8.Number():t8.Optional(t8.Number());break;case"boolean":properties[col8.name]=col8.notNull?t8.Boolean():t8.Optional(t8.Boolean());break;case"timestamp":case"timestamptz":case"date":properties[col8.name]=col8.notNull?t8.String({format:"date-time"}):t8.Optional(t8.String({format:"date-time"}));break;case"json":case"jsonb":properties[col8.name]=t8.Optional(t8.Unknown());break;case"uuid":properties[col8.name]=col8.notNull?t8.String({format:"uuid"}):t8.Optional(t8.String({format:"uuid"}));break;default:properties[col8.name]=col8.notNull?t8.String():t8.Optional(t8.String())}return t8.Object(properties,{additionalProperties:!0})}function createBulkUpdateSchema(entityColumns){return t8.Array(t8.Object({id:t8.String(),data:buildBodySchemaFromEntityColumns(entityColumns)}))}var MAX_BULK_ITEMS=500;function collectFilterFields(filter,out=[]){if(filter.operator==="or"||filter.operator==="and"){let group=Array.isArray(filter.value)?filter.value:[];for(let f of group)collectFilterFields(f,out)}else if(filter.field)out.push(String(filter.field));return out}function buildFilterCondition(filter,resolveCol){if(filter.operator==="or"||filter.operator==="and"){let subs=(Array.isArray(filter.value)?filter.value:[]).map((f)=>buildFilterCondition(f,resolveCol)).filter((c)=>c!==null);if(subs.length===0)return null;return(filter.operator==="or"?or2(...subs):and13(...subs))??null}if(!filter.field)return null;let col8=resolveCol(filter.field);if(!col8)return null;let sqlCol=col8,dataType=col8.dataType,coerce2=(v)=>dataType==="date"&&(typeof v==="string"||typeof v==="number")?new Date(v):v;switch(filter.operator){case"eq":return eq28(sqlCol,coerce2(filter.value));case"neq":return ne2(sqlCol,coerce2(filter.value));case"gt":return gt(sqlCol,coerce2(filter.value));case"gte":return gte(sqlCol,coerce2(filter.value));case"lt":return lt2(sqlCol,coerce2(filter.value));case"lte":return lte(sqlCol,coerce2(filter.value));case"like":return like(sqlCol,filter.value);case"ilike":return ilike(sqlCol,filter.value);case"in":return inArray8(sqlCol,filter.value);case"notIn":return notInArray(sqlCol,filter.value);case"arrayOverlaps":return arrayOverlaps(sqlCol,filter.value??[]);case"arrayContains":return arrayContains(sqlCol,filter.value??[]);case"arrayEmpty":return sql7`cardinality(${sqlCol}) = 0`;case"isNull":return isNull2(sqlCol);case"isNotNull":return isNotNull(sqlCol);default:return null}}function createEntityRoutes(app,config){let{db,schemaTables,schemaRelations,entities,logger:logger2,dbPool,storage,cdnMedia,authorization,authMode,idpUrl,featureAdminRoles}=config,getRegistry=()=>config.getTenantRegistry?config.getTenantRegistry():config.tenantRegistry??null,getReqSchema=(request)=>{let tenantRegistry=getRegistry();if(!tenantRegistry)return{tables:schemaTables,relations:schemaRelations};let schemaName=request.headers.get("x-tenant-schema");if(!schemaName)return{tables:schemaTables,relations:schemaRelations};let ctx=tenantRegistry.getSchemaContext(schemaName);return ctx?{tables:ctx.schemaTables,relations:ctx.schemaRelations}:{tables:schemaTables,relations:schemaRelations}},storageConfig=mergeStorageConfig(storage),warmUploadedMedia=(uploaded)=>{if(!cdnMedia||!uploaded||uploaded.success.length===0)return;scheduleUploadMediaProcessing(uploaded.success,{storagePath:storageConfig.basePath,media:cdnMedia,logger:logger2})},authEnabled=authorization?.enabled??!1,enforceFieldWrites=authEnabled&&authorization?.enforceFieldWriteClaims!==!1,isConsumerMode=authMode==="consumer",filterWritePayload=(payload,authResult)=>{if(!enforceFieldWrites||!authResult?.allowedFields)return payload;return filterResponseFields(payload,authResult.allowedFields)},auditPathContext=(request)=>{let url=new URL(request.url);return{path:url.pathname,query:url.search}},auditIdentityFor=(table,payload,userId,headers)=>createAuditIdentity(isAnonymousCreate(table,payload),userId,headers),UUID_RE=/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i,auditEntityId=(id)=>{let s=id==null?"":String(id);return UUID_RE.test(s)?s:null},projectWrittenRow=(row,authResult)=>{let scoped2=authEnabled&&authResult?.allowedFields?filterResponseFields(row,[...authResult.allowedFields,...authResult.allowedRelations??[]]):row;return stripUnclaimedSensitive(redactSensitiveOutput(scoped2),authResult?.allowedFields)};if(!db)return app;function snakeToCamel4(s){return s.replace(/_([a-z])/g,(_,l)=>l.toUpperCase())}let{entities:mergedEntities}=resolveEntities(SYSTEM_TABLES,entities),extendedByName=new Map(mergedEntities.filter((t10)=>entities.some((e)=>e.table_name===t10.table_name&&e.extends===!0)).map((t10)=>[t10.table_name,t10])),effectiveEntities=entities.map((e)=>extendedByName.get(e.table_name)??e),allTables=Object.keys(schemaTables),entityTableNames=effectiveEntities.map((e)=>snakeToCamel4(e.table_name)),systemTableNames=allTables.filter((tbl)=>!entityTableNames.includes(tbl)),systemTableDefMap=new Map(SYSTEM_TABLES.map((t10)=>[snakeToCamel4(t10.table_name),t10])),asMeta=(def)=>def??void 0,hasUnmetRequirement=(def)=>{let requires=def?.requires;if(!requires||requires.length===0)return null;for(let req of requires)if(req==="email"&&!config.isEmailServiceAvailable?.())return"email";return null},deriveGroupName=(def,fallback)=>{if(def?.group_name)return def.group_name;let primaryFeature=def?.feature_set?.[0];if(!primaryFeature)return fallback;return primaryFeature.charAt(0).toUpperCase()+primaryFeature.slice(1)},systemTables2=systemTableNames.filter((name2)=>{let unmet=hasUnmetRequirement(asMeta(systemTableDefMap.get(name2)));if(unmet)return logger2.info(`Skipping ${name2} routes - missing required dependency: ${unmet}`),!1;return!0}).map((name2)=>{let def=systemTableDefMap.get(name2),meta=asMeta(def);return{table_name:def?.table_name??name2,group_name:deriveGroupName(meta,name2),is_form_data:def?.is_form_data===!0,bulk_endpoints_enabled:def?.bulk_endpoints_enabled??!1,excluded_methods:def?.excluded_methods?[...def.excluded_methods]:[],columns:def?.columns?[...def.columns]:void 0}}),allEntities=[...effectiveEntities,...systemTables2],publicGetEntities=new Set;for(let e of allEntities)if(e.is_public?.GET===!0)publicGetEntities.add(e.table_name),publicGetEntities.add(snakeToCamel4(e.table_name));logger2.info(`All entities: ${allEntities.map((e)=>e.table_name).join(", ")}`);for(let table of allEntities){let rawTableName=table.table_name,tableName=snakeToCamel4(rawTableName),swaggerTag=table.group_name||rawTableName,writeFields=enforceFieldWrites?table.columns?.map((c)=>c.name):void 0,defaultDrizzleTable=schemaTables[tableName];if(!defaultDrizzleTable)continue;let tableRelations=schemaRelations[`${tableName}Relations`];logger2.info(`Creating routes for table: ${tableName}`);let relationTargetTable={};{let rels=tableRelations;if(rels?.table&&typeof rels?.config==="function")try{let built=rels.config(createTableRelationsHelpers(rels.table));for(let[relName,rel]of Object.entries(built))if(rel?.referencedTable)relationTargetTable[relName]=getTableName(rel.referencedTable)}catch(err){logger2.warn(`[Authorization] Could not map relations for ${tableName}`,{error:err instanceof Error?err.message:String(err)})}}let defaultTableColumns=defaultDrizzleTable,defaultIdCol=defaultTableColumns.id,database=db,drizzleTable=defaultDrizzleTable,tableColumns=defaultTableColumns,idCol=defaultIdCol,resolveCol=(field)=>{if(Object.hasOwn(tableColumns,field))return tableColumns[field];let camel=snakeToCamel4(field);return Object.hasOwn(tableColumns,camel)?tableColumns[camel]:void 0},getTableForRequest=(request)=>{if(!getRegistry())return{drizzleTable,tableColumns,idCol,resolveCol,schemaTables,schemaRelations};let reqSchema=getReqSchema(request),reqTable=reqSchema.tables[tableName]||drizzleTable,reqCols=reqTable,reqIdCol=reqCols.id;return{drizzleTable:reqTable,tableColumns:reqCols,idCol:reqIdCol,resolveCol:(field)=>{if(Object.hasOwn(reqCols,field))return reqCols[field];let camel=snakeToCamel4(field);return Object.hasOwn(reqCols,camel)?reqCols[camel]:void 0},schemaTables:reqSchema.tables,schemaRelations:reqSchema.relations}},bulkUpdateSchema=createBulkUpdateSchema(table.columns),bulkDeleteSchema=t9.Array(t9.String()),authzLog=logger2.scoped("authorization.check"),performAuthCheck=async(request,method,reqFields,reqRelations)=>{let result=await runAuthCheck(request,method,reqFields,reqRelations);if(result){let userId=request.headers.get("x-user-id"),requestId=request.headers.get("x-request-id")||void 0;if(!result.authorized)authzLog.warn(`Denied ${method} ${table.table_name}`,{requestId,userId,entity:table.table_name,method,reason:result.reason||"no reason provided",mode:isConsumerMode?idpUrl?"idp":"jwt":"local"});else if(result.scopeFilters||result.allowedFields||result.allowedRelations)authzLog.debug(`Allowed ${method} ${table.table_name} (restricted)`,{requestId,userId,entity:table.table_name,method,scopeFilters:result.scopeFilters,allowedFieldCount:result.allowedFields?.length,allowedRelations:result.allowedRelations})}return result},scopeConditionsFor=(authResult,resolveColumn)=>{if(!authEnabled||!authResult?.scopeFilters)return[];let{conditions,unresolvedFields}=buildScopeConditions(authResult.scopeFilters,resolveColumn);if(unresolvedFields.length>0)authzLog.error(`Scope references unknown column(s) on ${table.table_name}; failing closed (0 rows)`,{entity:table.table_name,unresolvedFields});return conditions},runAuthCheck=async(request,method,reqFields,reqRelations,entityName=table.table_name)=>{let userId=request.headers.get("x-user-id");if(!authEnabled||!userId)return null;if(isConsumerMode){let userClaims=decodeHeaderList(request.headers.get("x-user-claims")),userRoles=decodeHeaderList(request.headers.get("x-user-roles")),userClaimScopes=decodeClaimScopesHeader(request.headers.get("x-user-claim-scopes"));if(idpUrl&&authorization?.jwtClaimsMode==="resolve"){let accessToken=request.headers.get("x-access-token")||(request.headers.get("cookie")||"").match(/access_token=([^;]+)/)?.[1]||"";return checkAuthorizationViaIDP({idpUrl,accessToken,method,entity:entityName,requestedFields:reqFields,requestedRelations:reqRelations,logger:logger2})}return checkAuthorizationFromJWT({userClaims,userRoles,method,entity:entityName,requestedFields:reqFields,requestedRelations:reqRelations,logger:logger2,requireClaimSpecificity:authorization?.requireClaimSpecificity,claimScopes:userClaimScopes})}let reqCtx=getTableForRequest(request);return checkAuthorization({userId,method,entity:entityName,requestedFields:reqFields,requestedRelations:reqRelations,db:database,schemaTables:reqCtx.schemaTables,logger:logger2,requireClaimSpecificity:authorization?.requireClaimSpecificity,getUserData:async()=>{if(!database)return;let usersTbl=reqCtx.schemaTables[AUTHORIZATION_TABLE_KEYS.users];if(!usersTbl)return;let idCol2=usersTbl.id;if(!idCol2)return;return(await database.select().from(usersTbl).where(eq28(idCol2,userId)).limit(1))[0]}})},entityRoutes=new Elysia11({prefix:`/${tableName}`}),listLog=logger2.scoped("entity.list"),isRbacTable=tableName===AUTHORIZATION_TABLE_KEYS.roles||tableName===AUTHORIZATION_TABLE_KEYS.claims||tableName===AUTHORIZATION_TABLE_KEYS.userRoles||tableName===AUTHORIZATION_TABLE_KEYS.roleClaims;if(isRbacTable||isSensitiveSystemTable(tableName)){let denyMessage=isRbacTable?"Forbidden: managing roles and claims requires godmin privileges":`Forbidden: writing to '${tableName}' via the generic entity API requires godmin privileges \u2014 use the dedicated route`;entityRoutes.onBeforeHandle(async({request,set})=>{let method=request.method.toUpperCase();if(method==="GET"||method==="HEAD"||method==="OPTIONS")return;if(hasGodminRole(request))return;if(isFeatureAdmin({isRbacTable,featureSet:table.feature_set,featureAdminRoles,callerRoles:decodeHeaderList(request.headers.get("x-user-roles"))}))return;if(await userHasGodminRoleInDb(db,schemaTables,request.headers.get("x-user-id"),logger2))return;return set.status=403,{success:!1,message:denyMessage}})}if(!table.excluded_methods?.includes("GET"))entityRoutes.get("/",async(ctx)=>{if(!database)return{success:!1,message:"DB not initialized"};let{drizzleTable:drizzleTable2,resolveCol:resolveCol2,schemaRelations:schemaRelations2}=getTableForRequest(ctx.request),requestedFields=table.columns?.map((c)=>c.name),requestedRelations=Object.keys(schemaRelations2).filter((k)=>k.startsWith(`${tableName}Relations`)).map((k)=>k.replace("Relations","")),authResult=await performAuthCheck(ctx.request,"GET",requestedFields,requestedRelations);if(authResult&&!authResult.authorized)return ctx.set.status=403,{success:!1,message:authResult.reason||"Forbidden"};let fieldQueryable=(field)=>{if(isSensitiveOutputKey(field))return!1;if(!sensitiveFieldQueryable(field,{authEnabled,allowedFields:authResult?.allowedFields}))return!1;if(authEnabled&&authResult?.allowedFields&&!authResult.allowedFields.includes(field))return!1;return!0},q=parseQueryParams(ctx.query),conditions=[];if(conditions.push(...scopeConditionsFor(authResult,resolveCol2)),q.search&&q.searchFields){for(let f of q.searchFields)if(!fieldQueryable(f.trim()))return ctx.set.status=403,{success:!1,message:`Cannot search on field: ${f.trim()}`};let searchConditions=q.searchFields.map((f)=>{let trimmed=f.trim(),col8=resolveCol2(trimmed);return col8?ilike(col8,`%${q.search}%`):null}).filter((c)=>c!==null);if(searchConditions.length>0){let orCondition=or2(...searchConditions);if(orCondition)conditions.push(orCondition)}}if(Array.isArray(q.filters))for(let filter of q.filters){for(let f of collectFilterFields(filter))if(!fieldQueryable(f))return ctx.set.status=403,{success:!1,message:`Cannot filter on field: ${f}`};let cond=buildFilterCondition(filter,resolveCol2);if(cond)conditions.push(cond)}let projection;if(q.select&&q.select.length>0){let requested=[...new Set(["id",...q.select.map((f)=>f.trim())])].filter(Boolean),columns={};for(let field of requested){if(!fieldQueryable(field))return ctx.set.status=403,{success:!1,message:`Cannot select field: ${field}`};let col8=resolveCol2(field);if(!col8)return ctx.set.status=400,{success:!1,message:`Unknown field in select: ${field}`};columns[field]=col8}if(Object.keys(columns).length>0)projection=columns}let unprojected=database.select().from(drizzleTable2),baseQuery=projection?database.select(projection).from(drizzleTable2):unprojected;if(conditions.length>0){let combined=and13(...conditions);if(combined)baseQuery=baseQuery.where(combined)}if(q.sort&&q.sort.length>0){for(let s of q.sort)if(!fieldQueryable(s.field))return ctx.set.status=403,{success:!1,message:`Cannot sort on field: ${s.field}`};let orderClauses=q.sort.map((s)=>{let col8=resolveCol2(s.field);if(!col8)return null;return s.direction==="desc"?desc5(col8):asc(col8)}).filter((o)=>o!==null);if(orderClauses.length>0)baseQuery=baseQuery.orderBy(...orderClauses)}let page=q.page??1,limit=q.limit??20,offset=q.offset??(page-1)*limit,queryStart=performance.now(),combinedCount=conditions.length>0?and13(...conditions):void 0,countResult=await database.select({n:sql7`count(*)::int`}).from(drizzleTable2).where(combinedCount),totalItems=Number(countResult[0]?.n??0);baseQuery=baseQuery.limit(limit).offset(offset);let items=await baseQuery,meta=buildPaginationMeta(page,limit,offset,totalItems);if(listLog.debug(`List ${rawTableName}: ${items.length}/${totalItems} rows`,{requestId:ctx.request.headers.get("x-request-id")||void 0,table:rawTableName,page,limit,totalItems,returned:items.length,conditionCount:conditions.length,search:q.search||void 0,sort:Array.isArray(q.sort)?q.sort.map((s)=>`${s.field}:${s.direction}`):void 0,queryMs:Math.round(performance.now()-queryStart)}),authEnabled&&authResult?.allowedFields)items=filterResponseFields(items,authResult.allowedFields);return{success:!0,data:{items:items.map((r)=>stripUnclaimedSensitive(redactSensitiveOutput(r),authResult?.allowedFields)),meta}}},{detail:{tags:[swaggerTag],summary:`List ${tableName}`,description:`Get paginated list of ${tableName} records with filtering, sorting, and search`}}),entityRoutes.get("/:id",async(ctx)=>{let{drizzleTable:drizzleTable2,idCol:idCol2,schemaTables:schemaTables2,schemaRelations:schemaRelations2,resolveCol:resolveCol2}=getTableForRequest(ctx.request);if(!database||!idCol2)return{success:!1,message:"No id column or DB"};let params=ctx.params,q=parseQueryParams(ctx.query),requestedFields=table.columns?.map((c)=>c.name),requestedRelations=q.with?.map((w)=>w.name),authResult=await performAuthCheck(ctx.request,"GET",requestedFields,requestedRelations);if(authResult&&!authResult.authorized)return ctx.set.status=403,{success:!1,message:authResult.reason||"Forbidden"};let getScope=scopeConditionsFor(authResult,resolveCol2),getWhere=getScope.length>0?and13(eq28(idCol2,params.id),...getScope):eq28(idCol2,params.id);if(q.with&&q.with.length>0&&tableRelations&&dbPool){let allowedWith=authEnabled&&authResult?.allowedRelations?q.with.filter((w)=>authResult.allowedRelations?.includes(w.name)??!1):q.with,dbWithRelations=drizzle(dbPool,{schema:{...schemaTables2,...schemaRelations2}}),withClause={};for(let rel of allowedWith){let targetTable=relationTargetTable[rel.name],relAuth=authEnabled&&targetTable?await runAuthCheck(ctx.request,"GET",void 0,void 0,targetTable):null,decision=decideRelationExpansion({authEnabled,targetTable,relAuth,isTargetPublicGet:targetTable?publicGetEntities.has(targetTable):!1});if(!decision.expand)continue;let relScope=decision.scope;if(relScope&&Object.keys(relScope).length>0)withClause[rel.name]={...rel.limit?{limit:rel.limit}:{},where:(fields,ops)=>{let preds=[],unresolved=!1;for(let[k,v]of Object.entries(relScope)){let col8=resolveRelationScopeColumn(fields,k,snakeToCamel4);if(col8)preds.push(ops.eq(col8,v));else unresolved=!0}if(unresolved)return sql7`1 = 0`;return preds.length>0?ops.and(...preds):void 0}};else withClause[rel.name]=rel.limit?{limit:rel.limit}:!0}let result2=await dbWithRelations.query[tableName]?.findFirst({where:getWhere,with:withClause});if(authEnabled&&authResult?.allowedFields&&result2)result2=filterResponseFields(result2,[...authResult.allowedFields,...authResult.allowedRelations??[]]);if(authEnabled&&authResult?.allowedRelations&&result2)result2=filterResponseRelations(result2,authResult.allowedRelations);return{success:!0,data:stripUnclaimedSensitive(redactSensitiveOutput(result2||null),authResult?.allowedFields)}}let result=(await database.select().from(drizzleTable2).where(getWhere))[0]||null;if(authEnabled&&authResult?.allowedFields&&result)result=filterResponseFields(result,authResult.allowedFields);return{success:!0,data:stripUnclaimedSensitive(redactSensitiveOutput(result),authResult?.allowedFields)}},{detail:{tags:[swaggerTag],summary:`Get ${tableName} by ID`,description:`Get a single ${tableName} record by its ID with optional relations`}}),entityRoutes.get("/distinct/:field",async(ctx)=>{let{drizzleTable:drizzleTable2,resolveCol:resolveCol2}=getTableForRequest(ctx.request);if(!database)return{success:!1,message:"DB not initialized"};let params=ctx.params,authResult=await performAuthCheck(ctx.request,"GET",[params.field],[]);if(authResult&&!authResult.authorized)return ctx.set.status=403,{success:!1,message:authResult.reason||"Forbidden"};if(authEnabled&&authResult?.allowedFields&&!authResult.allowedFields.includes(params.field))return ctx.set.status=403,{success:!1,message:"Forbidden: field not permitted"};if(isSensitiveOutputKey(params.field))return ctx.set.status=403,{success:!1,message:"Forbidden: field not permitted"};if(!sensitiveFieldQueryable(params.field,{authEnabled,allowedFields:authResult?.allowedFields}))return ctx.set.status=403,{success:!1,message:"Forbidden: field not permitted"};let col8=resolveCol2(params.field);if(!col8)return{success:!1,message:"Field not found"};let distinctScope=scopeConditionsFor(authResult,resolveCol2),distinctQuery=database.selectDistinct({value:col8}).from(drizzleTable2);return{success:!0,data:distinctScope.length>0?await distinctQuery.where(and13(...distinctScope)):await distinctQuery}},{detail:{tags:[swaggerTag],summary:`Get distinct ${tableName} values`,description:`Get distinct values for a specific field in ${tableName}`}});if(!table.excluded_methods?.includes("POST"))if(table.is_form_data&&storageConfig.enabled)entityRoutes.post("/",async(ctx)=>{let{drizzleTable:drizzleTable2,resolveCol:resolveCol2}=getTableForRequest(ctx.request);if(!database)return{success:!1,message:"DB not initialized"};let userId=ctx.request.headers.get("x-user-id"),postFormAuthResult=await performAuthCheck(ctx.request,"POST",writeFields);if(postFormAuthResult&&!postFormAuthResult.authorized)return ctx.set.status=403,{success:!1,message:postFormAuthResult.reason||"Forbidden"};let{data,files}=parseFormDataBody(ctx.body,storageConfig),payload=data,uploadedFiles=null;if(files.length>0){if(uploadedFiles=await uploadFiles(files,storageConfig,table.table_name),uploadedFiles.failed.length>0&&uploadedFiles.success.length===0)return{success:!1,message:"File upload failed",errors:uploadedFiles.failed};warmUploadedMedia(uploadedFiles)}let mergeUploadedMetadata=()=>{let firstFile=uploadedFiles?.success[0];if(firstFile)payload={...payload,...buildFileRecordPayload(firstFile,userId)}};if(table.columns)payload=sanitizePayload(payload,table.columns,{isFormData:table.is_form_data===!0}),payload=filterWritePayload(payload,postFormAuthResult),mergeUploadedMetadata();else mergeUploadedMetadata();let scopedForm=forceCreateScope(payload,postFormAuthResult,resolveCol2);if(!scopedForm.ok)return ctx.set.status=403,{success:!1,message:`Forbidden: ownership scope references a column '${scopedForm.field}' this entity does not have`};if(table.columns){let validation=validatePayload(payload,table.columns,!1);if(!validation.valid)return{success:!1,message:"Validation failed",errors:validation.errors}}let anonymous=isAnonymousCreate(table,payload);if(userId&&!anonymous)payload.createdBy=userId;let result=await database.insert(drizzleTable2).values(payload).returning();{let reqUrl=new URL(ctx.request.url);logger2.audit({entityName:table.table_name,entityId:String(result[0]?.id??""),operation:"CREATE",summary:`Created ${table.table_name}`,newValues:result[0],...createAuditIdentity(anonymous,userId,ctx.request.headers),path:reqUrl.pathname,query:reqUrl.search})}return{success:!0,data:stripUnclaimedSensitive(redactSensitiveOutput(result[0]),postFormAuthResult?.allowedFields)}},{type:"formdata",body:t9.Object({[storageConfig.formData.dataField]:t9.Optional(t9.Union([t9.String(),t9.Any()])),[storageConfig.formData.filesField]:t9.Optional(t9.Union([t9.File(),t9.Array(t9.File())]))}),detail:{tags:[swaggerTag],summary:`Create ${tableName} with files`,description:`Create a new ${tableName} record with file upload support`}});else entityRoutes.post("/",async(ctx)=>{let{drizzleTable:drizzleTable2,schemaTables:schemaTables2,resolveCol:resolveCol2}=getTableForRequest(ctx.request);if(!database)return{success:!1,message:"DB not initialized"};let payload=ctx.body,userId=ctx.request.headers.get("x-user-id"),postAuthResult=await performAuthCheck(ctx.request,"POST",writeFields);if(postAuthResult&&!postAuthResult.authorized)return ctx.set.status=403,{success:!1,message:postAuthResult.reason||"Forbidden"};if(table.columns)payload=sanitizePayload(payload,table.columns,{isFormData:table.is_form_data===!0}),payload=filterWritePayload(payload,postAuthResult);let scoped2=forceCreateScope(payload,postAuthResult,resolveCol2);if(!scoped2.ok)return ctx.set.status=403,{success:!1,message:`Forbidden: ownership scope references a column '${scoped2.field}' this entity does not have`};if(table.columns){let validation=validatePayload(payload,table.columns,!1);if(!validation.valid)return{success:!1,message:"Validation failed",errors:validation.errors}}let anonymous=isAnonymousCreate(table,payload);if(userId&&!anonymous)payload.createdBy=userId;if(tableName===AUTHORIZATION_TABLE_KEYS.userRoles&&payload.userId&&payload.roleId){let cols=drizzleTable2,existing=await database.select().from(drizzleTable2).where(and13(eq28(cols.userId,payload.userId),eq28(cols.roleId,payload.roleId))).limit(1);if(existing.length>0)return{success:!0,data:existing[0]}}let result=await database.insert(drizzleTable2).values(payload).returning();if(tableName===AUTHORIZATION_TABLE_KEYS.roleClaims&&config.claimsCache)config.claimsCache.invalidate().catch(()=>{});if(tableName===AUTHORIZATION_TABLE_KEYS.userRoles&&payload.roleId&&payload.userId)try{let rolesTable=schemaTables2[AUTHORIZATION_TABLE_KEYS.roles],usersTable=schemaTables2[AUTHORIZATION_TABLE_KEYS.users];if(rolesTable&&usersTable){if((await database.select().from(rolesTable).where(eq28(rolesTable.id,payload.roleId)).limit(1))[0]?.name===GODMIN_ROLE_NAME)await database.update(usersTable).set({isGod:!0}).where(eq28(usersTable.id,payload.userId))}}catch(_e){logger2.warn("[Entity] Failed to sync is_god flag on userRole create")}{let reqUrl=new URL(ctx.request.url);logger2.audit({entityName:table.table_name,entityId:String(result[0]?.id??""),operation:"CREATE",summary:`Created ${table.table_name}`,newValues:result[0],...createAuditIdentity(anonymous,userId,ctx.request.headers),path:reqUrl.pathname,query:reqUrl.search})}return{success:!0,data:stripUnclaimedSensitive(redactSensitiveOutput(result[0]),postAuthResult?.allowedFields)}},{body:t9.Object({},{additionalProperties:!0}),detail:{tags:[swaggerTag],summary:`Create ${tableName}`,description:`Create a new ${tableName} record`}});if(!table.excluded_methods?.includes("PUT"))if(table.is_form_data&&storageConfig.enabled)entityRoutes.put("/:id",async(ctx)=>{let{drizzleTable:drizzleTable2,idCol:idCol2,resolveCol:resolveCol2}=getTableForRequest(ctx.request);if(!database||!idCol2)return{success:!1,message:"No id column or DB"};let params=ctx.params,userId=ctx.request.headers.get("x-user-id"),putFormAuthResult=await performAuthCheck(ctx.request,"PUT",writeFields);if(putFormAuthResult&&!putFormAuthResult.authorized)return ctx.set.status=403,{success:!1,message:putFormAuthResult.reason||"Forbidden"};let putFormScope=scopeConditionsFor(putFormAuthResult,resolveCol2),putFormWhere=putFormScope.length>0?and13(eq28(idCol2,params.id),...putFormScope):eq28(idCol2,params.id),{data,files}=parseFormDataBody(ctx.body,storageConfig),payload=data,oldRecord=await database.select().from(drizzleTable2).where(putFormWhere).limit(1);if(putFormScope.length>0&&oldRecord.length===0)return ctx.set.status=403,{success:!1,message:"Forbidden"};if(table.columns){payload=sanitizePayload(payload,table.columns,{isFormData:table.is_form_data===!0}),payload=filterWritePayload(payload,putFormAuthResult);let validation=validatePayload(payload,table.columns,!1);if(!validation.valid)return{success:!1,message:"Validation failed",errors:validation.errors}}let uploadedFiles=null;if(files.length>0)uploadedFiles=await uploadFiles(files,storageConfig,table.table_name),warmUploadedMedia(uploadedFiles);let result=await database.update(drizzleTable2).set(payload).where(putFormWhere).returning();{let reqUrl=new URL(ctx.request.url);logger2.audit({entityName:table.table_name,entityId:params.id,operation:"UPDATE",userId:userId||void 0,summary:`Updated ${table.table_name} (${params.id})`,oldValues:oldRecord[0],newValues:result[0],ipAddress:ctx.request.headers.get("x-forwarded-for")?.split(",")[0]?.trim()||ctx.request.headers.get("x-real-ip")?.trim()||"unknown",userAgent:ctx.request.headers.get("user-agent")||"unknown",path:reqUrl.pathname,query:reqUrl.search})}return{success:!0,data:{record:result[0],files:uploadedFiles?.success||[],fileErrors:uploadedFiles?.failed||[]}}},{type:"formdata",body:t9.Object({[storageConfig.formData.dataField]:t9.Optional(t9.Union([t9.String(),t9.Any()])),[storageConfig.formData.filesField]:t9.Optional(t9.Union([t9.File(),t9.Array(t9.File())]))}),detail:{tags:[swaggerTag],summary:`Update ${tableName} with files`,description:`Full update of ${tableName} record with file upload support`}});else entityRoutes.put("/:id",async(ctx)=>{let{drizzleTable:drizzleTable2,idCol:idCol2,resolveCol:resolveCol2}=getTableForRequest(ctx.request);if(!database||!idCol2)return{success:!1,message:"No id column or DB"};let{params,body:payload}=ctx,userId=ctx.request.headers.get("x-user-id"),putAuthResult=await performAuthCheck(ctx.request,"PUT",writeFields);if(putAuthResult&&!putAuthResult.authorized)return ctx.set.status=403,{success:!1,message:putAuthResult.reason||"Forbidden"};let putScope=scopeConditionsFor(putAuthResult,resolveCol2),putWhere=putScope.length>0?and13(eq28(idCol2,params.id),...putScope):eq28(idCol2,params.id),oldRecord=await database.select().from(drizzleTable2).where(putWhere).limit(1);if(putScope.length>0&&oldRecord.length===0)return ctx.set.status=403,{success:!1,message:"Forbidden"};if(table.columns){payload=sanitizePayload(payload,table.columns,{isFormData:table.is_form_data===!0}),payload=filterWritePayload(payload,putAuthResult);let validation=validatePayload(payload,table.columns,!1);if(!validation.valid)return{success:!1,message:"Validation failed",errors:validation.errors}}if(payload.updatedAt=new Date,userId)payload.updatedBy=userId;let result=await database.update(drizzleTable2).set(payload).where(putWhere).returning();{let reqUrl=new URL(ctx.request.url);logger2.audit({entityName:table.table_name,entityId:params.id,operation:"UPDATE",userId:userId||void 0,summary:`Updated ${table.table_name} (${params.id})`,oldValues:oldRecord[0],newValues:result[0],ipAddress:ctx.request.headers.get("x-forwarded-for")?.split(",")[0]?.trim()||ctx.request.headers.get("x-real-ip")?.trim()||"unknown",userAgent:ctx.request.headers.get("user-agent")||"unknown",path:reqUrl.pathname,query:reqUrl.search})}return{success:!0,data:stripUnclaimedSensitive(redactSensitiveOutput(result[0]),putAuthResult?.allowedFields)}},{body:t9.Object({},{additionalProperties:!0}),detail:{tags:[swaggerTag],summary:`Update ${tableName}`,description:`Full update of ${tableName} record`}});if(!table.excluded_methods?.includes("PATCH"))entityRoutes.patch("/:id",async(ctx)=>{let{drizzleTable:drizzleTable2,idCol:idCol2,resolveCol:resolveCol2}=getTableForRequest(ctx.request);if(!database||!idCol2)return{success:!1,message:"No id column or DB"};let{params,body:payload}=ctx,userId=ctx.request.headers.get("x-user-id"),patchAuthResult=await performAuthCheck(ctx.request,"PATCH",writeFields);if(patchAuthResult&&!patchAuthResult.authorized)return ctx.set.status=403,{success:!1,message:patchAuthResult.reason||"Forbidden"};let patchScope=scopeConditionsFor(patchAuthResult,resolveCol2),patchWhere=patchScope.length>0?and13(eq28(idCol2,params.id),...patchScope):eq28(idCol2,params.id),oldRecord=await database.select().from(drizzleTable2).where(patchWhere).limit(1);if(patchScope.length>0&&oldRecord.length===0)return ctx.set.status=403,{success:!1,message:"Forbidden"};if(table.columns){payload=sanitizePayload(payload,table.columns,{isFormData:table.is_form_data===!0}),payload=filterWritePayload(payload,patchAuthResult);let validation=validatePayload(payload,table.columns,!0);if(!validation.valid)return{success:!1,message:"Validation failed",errors:validation.errors}}if(payload.updatedAt=new Date,userId)payload.updatedBy=userId;let result=await database.update(drizzleTable2).set(payload).where(patchWhere).returning();{let reqUrl=new URL(ctx.request.url);logger2.audit({entityName:table.table_name,entityId:params.id,operation:"PATCH",userId:userId||void 0,summary:`Patched ${table.table_name} (${params.id})`,oldValues:oldRecord[0],newValues:result[0],ipAddress:ctx.request.headers.get("x-forwarded-for")?.split(",")[0]?.trim()||ctx.request.headers.get("x-real-ip")?.trim()||"unknown",userAgent:ctx.request.headers.get("user-agent")||"unknown",path:reqUrl.pathname,query:reqUrl.search})}return{success:!0,data:stripUnclaimedSensitive(redactSensitiveOutput(result[0]),patchAuthResult?.allowedFields)}},{body:t9.Object({},{additionalProperties:!0}),detail:{tags:[swaggerTag],summary:`Patch ${tableName}`,description:`Partial update of ${tableName} record`}});if(!table.excluded_methods?.includes("DELETE"))entityRoutes.delete("/:id",async(ctx)=>{let{drizzleTable:drizzleTable2,idCol:idCol2,schemaTables:schemaTables2,resolveCol:resolveCol2}=getTableForRequest(ctx.request);if(!database||!idCol2)return{success:!1,message:"No id column or DB"};let params=ctx.params,userId=ctx.request.headers.get("x-user-id"),deleteAuthResult=await performAuthCheck(ctx.request,"DELETE");if(deleteAuthResult&&!deleteAuthResult.authorized)return ctx.set.status=403,{success:!1,message:deleteAuthResult.reason||"Forbidden"};let deleteScope=scopeConditionsFor(deleteAuthResult,resolveCol2),deleteWhere=deleteScope.length>0?and13(eq28(idCol2,params.id),...deleteScope):eq28(idCol2,params.id),oldRecord=await database.select().from(drizzleTable2).where(deleteWhere).limit(1);if(deleteScope.length>0&&oldRecord.length===0)return ctx.set.status=403,{success:!1,message:"Forbidden"};if(await database.delete(drizzleTable2).where(deleteWhere),table.is_form_data&&storageConfig.enabled&&oldRecord[0]){let rec=oldRecord[0],filePath=rec.path,fileName=rec.name;if(typeof filePath==="string"&&typeof fileName==="string"){if(!await deleteFile(filePath,fileName,storageConfig.basePath))logger2.warn(`[Entity] Blob cleanup failed for ${table.table_name} (${params.id})`)}}if(tableName===AUTHORIZATION_TABLE_KEYS.roleClaims&&config.claimsCache)config.claimsCache.invalidate().catch(()=>{});if(tableName===AUTHORIZATION_TABLE_KEYS.userRoles&&oldRecord[0])try{let deletedUserRole=oldRecord[0],rolesTable=schemaTables2[AUTHORIZATION_TABLE_KEYS.roles],usersTable=schemaTables2[AUTHORIZATION_TABLE_KEYS.users];if(rolesTable&&usersTable&&deletedUserRole.roleId&&deletedUserRole.userId){if((await database.select().from(rolesTable).where(eq28(rolesTable.id,deletedUserRole.roleId)).limit(1))[0]?.name===GODMIN_ROLE_NAME)await database.update(usersTable).set({isGod:!1}).where(eq28(usersTable.id,deletedUserRole.userId))}}catch(_e){logger2.warn("[Entity] Failed to sync is_god flag on userRole delete")}{let reqUrl=new URL(ctx.request.url);logger2.audit({entityName:table.table_name,entityId:params.id,operation:"DELETE",userId:userId||void 0,summary:`Deleted ${table.table_name} (${params.id})`,oldValues:oldRecord[0],ipAddress:ctx.request.headers.get("x-forwarded-for")?.split(",")[0]?.trim()||ctx.request.headers.get("x-real-ip")?.trim()||"unknown",userAgent:ctx.request.headers.get("user-agent")||"unknown",path:reqUrl.pathname,query:reqUrl.search})}return{success:!0,data:null}},{detail:{tags:[swaggerTag],summary:`Delete ${tableName}`,description:`Delete a ${tableName} record`}});if(table.bulk_endpoints_enabled){if(!table.excluded_methods?.includes("POST"))entityRoutes.post("/bulk",async(ctx)=>{let{drizzleTable:drizzleTable2,resolveCol:resolveCol2}=getTableForRequest(ctx.request);if(!database)return{success:!1,message:"DB not initialized"};let items=ctx.body;if(!Array.isArray(items))return{success:!1,message:"Body must be an array"};if(items.length>MAX_BULK_ITEMS)return ctx.set.status=400,{success:!1,message:`Bulk request exceeds ${MAX_BULK_ITEMS} items`};let userId=ctx.request.headers.get("x-user-id"),bulkPostAuth=await performAuthCheck(ctx.request,"POST",writeFields);if(bulkPostAuth&&!bulkPostAuth.authorized)return ctx.set.status=403,{success:!1,message:bulkPostAuth.reason||"Forbidden"};let sanitizedItems=[];for(let raw of items){let payload=raw;if(table.columns)payload=sanitizePayload(payload,table.columns,{isFormData:table.is_form_data===!0}),payload=filterWritePayload(payload,bulkPostAuth);let scopedItem=forceCreateScope(payload,bulkPostAuth,resolveCol2);if(!scopedItem.ok)return ctx.set.status=403,{success:!1,message:`Forbidden: ownership scope references a column '${scopedItem.field}' this entity does not have`};if(table.columns){let validation=validatePayload(payload,table.columns,!1);if(!validation.valid)return ctx.set.status=400,{success:!1,message:"Validation failed",errors:validation.errors}}if(userId&&!isAnonymousCreate(table,payload))payload.createdBy=userId;sanitizedItems.push(payload)}let txResult=await database.transaction(async(tx)=>{let results=[];for(let payload of sanitizedItems){let result=await tx.insert(drizzleTable2).values(payload).returning();results.push(result[0])}return results}),auditPath=auditPathContext(ctx.request);for(let[i,row]of txResult.entries())await logger2.audit({entityName:table.table_name,entityId:auditEntityId(row.id),operation:"CREATE",summary:`Bulk created ${table.table_name} (${row.id})`,newValues:row,...auditIdentityFor(table,sanitizedItems[i]??{},userId,ctx.request.headers),...auditPath});return{success:!0,data:txResult.map((r)=>projectWrittenRow(r,bulkPostAuth))}},{body:t9.Array(t9.Object({},{additionalProperties:!0})),detail:{tags:[swaggerTag],summary:`Bulk create ${tableName}`,description:`Create multiple ${tableName} records`}});if(!table.excluded_methods?.includes("PUT"))entityRoutes.put("/bulk",async(ctx)=>{let{drizzleTable:drizzleTable2,idCol:idCol2,resolveCol:resolveCol2}=getTableForRequest(ctx.request);if(!database||!idCol2)return{success:!1,message:"No id column or DB"};let items=ctx.body;if(!Array.isArray(items))return{success:!1,message:"Body must be an array"};if(items.length>MAX_BULK_ITEMS)return ctx.set.status=400,{success:!1,message:`Bulk request exceeds ${MAX_BULK_ITEMS} items`};let userId=ctx.request.headers.get("x-user-id"),bulkPutAuth=await performAuthCheck(ctx.request,"PUT",writeFields);if(bulkPutAuth&&!bulkPutAuth.authorized)return ctx.set.status=403,{success:!1,message:bulkPutAuth.reason||"Forbidden"};let bulkPutScope=scopeConditionsFor(bulkPutAuth,resolveCol2),prepared=[];for(let item of items){let payload=item.data;if(table.columns){payload=sanitizePayload(payload,table.columns,{isFormData:table.is_form_data===!0}),payload=filterWritePayload(payload,bulkPutAuth);let validation=validatePayload(payload,table.columns,!0);if(!validation.valid)return ctx.set.status=400,{success:!1,message:"Validation failed",errors:validation.errors}}if(payload.updatedAt=new Date,userId)payload.updatedBy=userId;prepared.push({id:item.id,payload})}let beforeById=new Map,txResult=await database.transaction(async(tx)=>{if(prepared.length>0){let idFilter=inArray8(idCol2,prepared.map((p)=>p.id)),beforeRows=await tx.select().from(drizzleTable2).where(bulkPutScope.length>0?and13(idFilter,...bulkPutScope):idFilter);for(let row of beforeRows)if(row.id!=null)beforeById.set(String(row.id),row)}let results=[];for(let{id,payload}of prepared){let result=await tx.update(drizzleTable2).set(payload).where(bulkPutScope.length>0?and13(eq28(idCol2,id),...bulkPutScope):eq28(idCol2,id)).returning();if(result[0])results.push(result[0])}return results}),auditPath=auditPathContext(ctx.request);for(let row of txResult){let rowId=String(row.id);await logger2.audit({entityName:table.table_name,entityId:auditEntityId(row.id),operation:"UPDATE",userId:userId||void 0,summary:`Bulk updated ${table.table_name} (${rowId})`,oldValues:beforeById.get(rowId),newValues:row,...auditPath})}return{success:!0,data:txResult.map((r)=>projectWrittenRow(r,bulkPutAuth))}},{body:bulkUpdateSchema,detail:{tags:[swaggerTag],summary:`Bulk update ${tableName}`,description:`Update multiple ${tableName} records`}});if(!table.excluded_methods?.includes("DELETE"))entityRoutes.delete("/bulk",async(ctx)=>{let{drizzleTable:drizzleTable2,idCol:idCol2,resolveCol:resolveCol2}=getTableForRequest(ctx.request);if(!database||!idCol2)return{success:!1,message:"No id column or DB"};let ids=ctx.body;if(!Array.isArray(ids))return{success:!1,message:"Body must be an array of ids"};if(ids.length>MAX_BULK_ITEMS)return ctx.set.status=400,{success:!1,message:`Bulk request exceeds ${MAX_BULK_ITEMS} items`};let bulkDeleteAuth=await performAuthCheck(ctx.request,"DELETE");if(bulkDeleteAuth&&!bulkDeleteAuth.authorized)return ctx.set.status=403,{success:!1,message:bulkDeleteAuth.reason||"Forbidden"};let bulkDeleteScope=scopeConditionsFor(bulkDeleteAuth,resolveCol2),userId=ctx.request.headers.get("x-user-id"),removed=[];await database.transaction(async(tx)=>{for(let id of ids){let r=await tx.delete(drizzleTable2).where(bulkDeleteScope.length>0?and13(eq28(idCol2,id),...bulkDeleteScope):eq28(idCol2,id)).returning();removed.push(...r)}});let auditPath=auditPathContext(ctx.request);for(let row of removed)await logger2.audit({entityName:table.table_name,entityId:auditEntityId(row.id),operation:"DELETE",userId:userId||void 0,summary:`Bulk deleted ${table.table_name} (${row.id})`,oldValues:row,...auditPath});return{success:!0,data:{deleted:removed.length}}},{body:bulkDeleteSchema,detail:{tags:[swaggerTag],summary:`Bulk delete ${tableName}`,description:`Delete multiple ${tableName} records`}})}app.use(entityRoutes)}return app}import Elysia13,{t as t11}from"elysia";import{randomUUID as randomUUID7}from"crypto";var LOCK_TTL_SECONDS2=60,RENEW_INTERVAL_MS=20000,lockKeyFor=(mappingId)=>`integrations:run:${mappingId}`;async function acquireRunLock(store,mappingId,deps={}){let key2=lockKeyFor(mappingId),now=deps.now??Date.now,ttl=deps.ttlSeconds??LOCK_TTL_SECONDS2,token=randomUUID7(),existing=await store.read(key2);if(!existing.success)return{ok:!1,reason:"unavailable",error:existing.error};if(existing.data)return{ok:!1,reason:"held",heldSince:existing.data.acquiredAt??null};let created=await store.create(key2,{token,acquiredAt:now()},ttl);if(!created.success)return{ok:!1,reason:"unavailable",error:created.error};let readBack=await store.read(key2);if(!readBack.success)return{ok:!1,reason:"unavailable",error:readBack.error};if(readBack.data?.token!==token)return{ok:!1,reason:"held",heldSince:readBack.data?.acquiredAt??null};let held=!0,timer=setInterval(()=>{(async()=>{let current=await store.read(key2);if(!current.success)return;if(current.data?.token!==token){held=!1,clearInterval(timer),deps.logger?.warn("[Integrations] Run lock was taken over",{mappingId});return}await store.update(key2,current.data,!1)})()},RENEW_INTERVAL_MS);return timer.unref?.(),{ok:!0,handle:{token,isHeld:()=>held,release:async()=>{if(clearInterval(timer),!held)return;held=!1;let current=await store.read(key2);if(current.success&¤t.data?.token===token)await store.remove(key2)}}}}import{createHash as createHash2}from"crypto";function buildUrl(baseUrl,path7,params){let base=baseUrl.trim().replace(/\/+$/,"");if(!base)return{ok:!1,error:"The source has no base address."};let raw=(path7??"").trim();if(/^[a-z][a-z0-9+.-]*:\/\//i.test(raw)||raw.startsWith("//"))return{ok:!1,error:`The endpoint path points at another host (${raw}). A path must be relative to the source address.`};let suffix=raw===""?"":raw.startsWith("/")?raw:`/${raw}`,url;try{url=new URL(`${base}${suffix}`)}catch{return{ok:!1,error:`The source address is not a valid URL: ${baseUrl}`}}for(let[key2,value]of Object.entries(params??{})){if(value==null)continue;url.searchParams.set(key2,String(value))}return{ok:!0,url}}function applyAuth(source,url){let headers={accept:"application/json",...source.extraHeaders??{}},token=source.token?.trim();if(!token)return{headers};switch(source.authType){case"bearer":case"oauth2":headers[source.authHeaderName||"Authorization"]=`Bearer ${token}`;break;case"api_key":if(source.authQueryParam)url.searchParams.set(source.authQueryParam,token);else headers[source.authHeaderName||"X-API-Key"]=token;break;case"basic":headers.Authorization=`Basic ${token}`;break;default:break}return{headers}}function describeTransportError(error){let message=error instanceof Error?error.message:String(error),cause=error?.cause,code=cause?.code??"",blob=`${message} ${code} ${cause?.message??""}`;if(/UNABLE_TO_GET_ISSUER_CERT|SELF_SIGNED|self.signed|CERT_|unable to verify|ERR_TLS|altnames/i.test(blob))return`Certificate verification failed (${code||"incomplete chain"}). If this server's certificate is knowingly self-signed or incomplete, turn off certificate verification for this source and try again.`;if(/ENOTFOUND|EAI_AGAIN|getaddrinfo|Unable to resolve/i.test(blob))return`The address could not be resolved (DNS${code?`: ${code}`:""}). Check the source address.`;if(/ECONNREFUSED/i.test(blob))return`The connection was refused (${code||"ECONNREFUSED"}). The address and port are reachable but nothing is listening.`;if(/ETIMEDOUT|timeout|timed out|aborted|AbortError|UND_ERR/i.test(blob))return`The connection timed out (${code||"timeout"}). Check network and firewall access to this address.`;if(/ECONNRESET|EPIPE/i.test(blob))return`The connection was closed by the other side (${code||"ECONNRESET"}).`;return`Connection error: ${message}`}async function fetchOnce(source,request,deps={}){let impl=deps.fetchImpl??fetch,headers={...request.headers},method=request.method.toUpperCase(),hasBody=request.body!==void 0&&method!=="GET"&&method!=="HEAD";if(hasBody&&!headers["content-type"]&&!headers["Content-Type"])headers["content-type"]="application/json";let init={method,headers,cache:"no-store",signal:AbortSignal.timeout(source.timeoutMs??30000),tls:{rejectUnauthorized:source.tlsVerify!==!1},...hasBody?{body:typeof request.body==="string"?request.body:JSON.stringify(request.body)}:{}},response;try{response=await impl(request.url.toString(),init)}catch(error){return deps.logger?.warn("[Integrations] Outbound request failed",{sourceId:source.id,url:request.url.origin+request.url.pathname,error:error instanceof Error?error.message:String(error)}),{ok:!1,status:0,body:null,linkHeader:null,error:describeTransportError(error)}}let text=await response.text().catch(()=>""),body=null;if(text)try{body=JSON.parse(text)}catch{body=text}let linkHeader=response.headers.get("link");if(!response.ok){let detail=typeof body==="string"?body:body==null?"":JSON.stringify(body);return{ok:!1,status:response.status,body,linkHeader,error:`The source returned HTTP ${response.status}${detail?` \u2014 ${detail.slice(0,300)}`:""}`}}return{ok:!0,status:response.status,body,linkHeader}}var EXPIRY_SKEW_MS=5000,DEFAULT_TTL_MS=300000,DEFAULT_REFRESH_TTL_MS=1800000,FIELD_SEPARATOR="\x00";function credentialFingerprint(config){let material=[config.tokenUrl,config.grantType,config.clientId??"",config.clientSecret??"",config.username??"",config.password??"",config.scope??"",config.clientAuth??"basic"].join(FIELD_SEPARATOR);return createHash2("sha256").update(material).digest("hex").slice(0,32)}class TokenCache{entries=new Map;get(sourceId,fingerprint){let entry=this.entries.get(sourceId);if(!entry)return null;if(entry.fingerprint!==fingerprint)return this.entries.delete(sourceId),null;return entry}set(sourceId,token){this.entries.set(sourceId,token)}invalidate(sourceId){this.entries.delete(sourceId)}clear(){this.entries.clear()}}var isUsable=(token,now)=>token.expiresAt>now+EXPIRY_SKEW_MS,canRefresh=(token,now)=>Boolean(token.refreshToken)&&(token.refreshExpiresAt??0)>now+EXPIRY_SKEW_MS;function buildTokenRequest(config,form){let headers={"content-type":"application/x-www-form-urlencoded",accept:"application/json"};if(config.scope&&!form.has("scope"))form.set("scope",config.scope);let clientId=config.clientId??"",clientSecret=config.clientSecret??"";if((config.clientAuth??"basic")==="basic")headers.authorization=`Basic ${Buffer.from(`${clientId}:${clientSecret}`).toString("base64")}`;else{if(clientId)form.set("client_id",clientId);if(clientSecret)form.set("client_secret",clientSecret)}return{headers,body:form.toString()}}async function requestToken(config,form,now,fetchImpl){let{headers,body}=buildTokenRequest(config,form),response;try{response=await fetchImpl(config.tokenUrl,{method:"POST",headers,body,cache:"no-store",signal:AbortSignal.timeout(config.timeoutMs??30000),tls:{rejectUnauthorized:config.tlsVerify!==!1}})}catch(error){return{ok:!1,error:`Token request failed \u2014 ${describeTransportError(error)}`}}let text=await response.text().catch(()=>""),json={};try{json=text?JSON.parse(text):{}}catch{}if(!response.ok||!json.access_token){let detail=json.error_description||json.error||text.slice(0,200);return{ok:!1,error:`Could not obtain an OAuth2 token (HTTP ${response.status})${detail?`: ${detail}`:""}`}}return{ok:!0,token:{accessToken:json.access_token,expiresAt:now+(json.expires_in?json.expires_in*1000:DEFAULT_TTL_MS),refreshToken:json.refresh_token,refreshExpiresAt:json.refresh_token?now+(json.refresh_expires_in?json.refresh_expires_in*1000:DEFAULT_REFRESH_TTL_MS):void 0,fingerprint:credentialFingerprint(config)}}}async function getAccessToken(config,cache,deps={}){let fetchImpl=deps.fetchImpl??fetch,now=deps.now?.()??Date.now();if(!config.tokenUrl?.trim())return{ok:!1,error:"No token URL is configured for this source."};let fingerprint=credentialFingerprint(config),cached=cache.get(config.sourceId,fingerprint);if(cached&&isUsable(cached,now))return{ok:!0,accessToken:cached.accessToken,fromCache:!0};if(cached&&canRefresh(cached,now)){let refreshed=await requestToken(config,new URLSearchParams({grant_type:"refresh_token",refresh_token:cached.refreshToken}),now,fetchImpl);if(refreshed.ok)return cache.set(config.sourceId,refreshed.token),{ok:!0,accessToken:refreshed.token.accessToken,fromCache:!1}}let form=new URLSearchParams({grant_type:config.grantType});if(config.grantType==="password")form.set("username",config.username??""),form.set("password",config.password??"");let minted=await requestToken(config,form,now,fetchImpl);if(!minted.ok)return{ok:!1,error:minted.error};return cache.set(config.sourceId,minted.token),{ok:!0,accessToken:minted.token.accessToken,fromCache:!1}}import{and as and14,eq as eq29,inArray as inArray9}from"drizzle-orm";var DEFAULT_IGNORED=["updatedAt","updated_at","updatedBy","updated_by"];function planRevert(input){let ignored=new Set([...DEFAULT_IGNORED,...input.ignoreColumns??[]]),ops={deletes:[],restores:[],reinserts:[],conflicts:[]};for(let image of input.preImages)switch(image.action){case"create":{if(!image.rowId)break;let now=input.current.get(image.rowId);if(!now)break;if(!input.force&&changedSince(image.after,now,ignored)){ops.conflicts.push({id:image.rowId,reason:"This record was edited after the import; deleting it would discard that edit."});break}ops.deletes.push(image.rowId);break}case"update":case"deactivate":{if(!image.rowId||!image.before)break;let now=input.current.get(image.rowId);if(!now)break;if(!input.force&&changedSince(image.after,now,ignored)){ops.conflicts.push({id:image.rowId,reason:"This record was edited after the import; restoring it would discard that edit."});break}ops.restores.push({id:image.rowId,row:image.before});break}case"delete":{if(!image.before)break;if(image.rowId&&input.current.has(image.rowId)){ops.conflicts.push({id:image.rowId,reason:"A record with this identifier exists again; it was not replaced."});break}ops.reinserts.push(image.before);break}default:break}return ops}function changedSince(after,now,ignored){if(!after)return!1;for(let[key2,value]of Object.entries(after)){if(ignored.has(key2))continue;if(!sameValue(value,now[key2]))return!0}return!1}function sameValue(a,b){if(a===b)return!0;if(a==null&&b==null)return!0;if(a instanceof Date&&b instanceof Date)return a.getTime()===b.getTime();if(a instanceof Date||b instanceof Date){let da=a instanceof Date?a:new Date(String(a)),db=b instanceof Date?b:new Date(String(b));return!Number.isNaN(da.getTime())&&!Number.isNaN(db.getTime())?da.getTime()===db.getTime():!1}if(typeof a==="object"||typeof b==="object")try{return JSON.stringify(a)===JSON.stringify(b)}catch{return!1}return String(a)===String(b)}var CHUNK=500;async function applyRevert(deps,ops,meta){let idCol=deps.resolveCol("id");if(!idCol)return{ok:!1,conflicts:ops.conflicts.length,error:`"${meta.targetEntity}" has no id column; its rows cannot be addressed.`};let now=new Date;try{return{ok:!0,...await deps.db.transaction(async(tx)=>{let deleted=0,restored=0,reinserted=0;for(let i=0;i<ops.deletes.length;i+=CHUNK){let chunk=ops.deletes.slice(i,i+CHUNK),removed=await tx.delete(deps.drizzleTable).where(inArray9(idCol,chunk)).returning();deleted+=removed.length}for(let restore of ops.restores){let{id:_id,createdAt:_c,createdBy:_cb,...rest}=restore.row,written=await tx.update(deps.drizzleTable).set({...rest,updatedAt:now,updatedBy:meta.userId}).where(and14(eq29(idCol,restore.id))).returning();restored+=written.length}if(ops.reinserts.length>0)for(let i=0;i<ops.reinserts.length;i+=CHUNK){let chunk=ops.reinserts.slice(i,i+CHUNK),written=await tx.insert(deps.drizzleTable).values(chunk).returning();reinserted+=written.length}return{deleted,restored,reinserted}}),conflicts:ops.conflicts.length}}catch(error){return deps.logger.error("[Integrations] Revert transaction failed",{targetEntity:meta.targetEntity,error:error instanceof Error?error.message:String(error)}),{ok:!1,conflicts:ops.conflicts.length,error:"The database rejected this undo; it was rolled back and nothing changed."}}}function groupPreImagesByEntity(preImages){let byEntity=new Map;for(let image of preImages){let list=byEntity.get(image.targetEntity);if(list)list.push(image);else byEntity.set(image.targetEntity,[image])}return[...byEntity.entries()].map(([targetEntity,images])=>({targetEntity,preImages:images}))}function touchedRowIds(preImages){let ids=new Set;for(let image of preImages)if(image.rowId)ids.add(image.rowId);return[...ids]}function getByPath(obj,path7){if(!path7)return;let cur=obj;for(let part of path7.split(".")){if(cur==null||typeof cur!=="object")return;cur=cur[part]}return cur}function readSourceValue(external,parent,path7){return readOne(external,parent,path7)}function readOne(external,parent,path7){return path7.startsWith("__parent.")?getByPath(parent,path7.slice(9)):getByPath(external,path7)}var TEMPLATE_TOKEN=/\{([^{}]+)\}/g;function isTemplateSource(source){return TEMPLATE_TOKEN.lastIndex=0,TEMPLATE_TOKEN.test(source)}function renderTemplate(template,external,parent){return template.replace(TEMPLATE_TOKEN,(_match,path7)=>{let value=readOne(external,parent,path7.trim());return value==null?"":String(value)})}function extractRecords(body,rootPath){if(rootPath){let at=getByPath(body,rootPath);if(Array.isArray(at))return at;return at&&typeof at==="object"?[at]:[]}let candidate=firstArrayLike(body)??deepFirstArrayOfObjects(body);return Array.isArray(candidate)?candidate:[]}var ENVELOPE_KEYS=["content","items","data","results","records","rows","list","value","responseObject"];function firstArrayLike(body){if(Array.isArray(body))return body;if(!body||typeof body!=="object")return;let b=body;for(let key2 of ENVELOPE_KEYS){let v=b[key2];if(Array.isArray(v))return v;if(v&&typeof v==="object"){let nested=v.items;if(Array.isArray(nested))return nested}}return}function deepFirstArrayOfObjects(body,depth=0){if(depth>5||body==null||typeof body!=="object"||body instanceof Date)return;if(Array.isArray(body))return body.length>0&&typeof body[0]==="object"&&body[0]!==null?body:void 0;let entries=Object.values(body);for(let v of entries)if(Array.isArray(v)&&v.length>0&&typeof v[0]==="object"&&v[0]!==null)return v;for(let v of entries)if(v&&typeof v==="object"&&!Array.isArray(v)){let found=deepFirstArrayOfObjects(v,depth+1);if(found)return found}for(let v of entries)if(Array.isArray(v))return v;return}var FOLD={\u{131}:"i",\u{130}:"I",\u{15f}:"s",\u{15e}:"S",\u{11f}:"g",\u{11e}:"G",\u{f8}:"o",\u{d8}:"O",\u{e6}:"ae",\u{c6}:"AE",\u{df}:"ss",\u{111}:"d",\u{110}:"D",\u{142}:"l",\u{141}:"L"};function foldToAscii(value){return value.replace(/[\u0131\u0130\u015F\u015E\u011F\u011E\u00F8\u00D8\u00E6\u00C6\u00DF\u0111\u0110\u0142\u0141]/g,(ch)=>FOLD[ch]??ch).normalize("NFD").replace(/[\u0300-\u036f]/g,"")}var TRUTHY=new Set(["true","1","yes","y","evet","e","on"]),FALSY=new Set(["false","0","no","n","hayir","hay\u0131r","h","off"]);function applyTransform(value,transform){if(value==null)return{ok:!0,value};switch(transform){case"trim":return{ok:!0,value:String(value).trim()};case"upper":return{ok:!0,value:String(value).trim().toLocaleUpperCase("tr-TR")};case"lower":return{ok:!0,value:String(value).trim().toLocaleLowerCase("tr-TR")};case"toString":return{ok:!0,value:String(value)};case"toNumber":{if(typeof value==="boolean")return{ok:!1,reason:"not a number",raw:value};let s=String(value).trim();if(s==="")return{ok:!0,value:null};let n=Number(s);return Number.isFinite(n)?{ok:!0,value:n}:{ok:!1,reason:"not a number",raw:value}}case"toBoolean":{if(typeof value==="boolean")return{ok:!0,value};let s=String(value).trim().toLocaleLowerCase("tr-TR");if(s==="")return{ok:!0,value:null};if(TRUTHY.has(s))return{ok:!0,value:!0};if(FALSY.has(s))return{ok:!0,value:!1};return{ok:!1,reason:"not a yes/no value",raw:value}}case"emailSafe":return{ok:!0,value:foldToAscii(String(value)).toLowerCase().trim().replace(/[^a-z0-9._@+-]+/g,".").replace(/\.{2,}/g,".").replace(/\.*@\.*/g,"@").replace(/^[.\-_]+|[.\-_]+$/g,"")};case"pathLeaf":{let parts=String(value).split(/[/\\>\u203A\u00BB]|->/).map((part)=>part.trim()).filter((part)=>part!=="");return{ok:!0,value:parts.length>0?parts[parts.length-1]:""}}case"toList":{if(Array.isArray(value))return{ok:!0,value};let s=String(value).trim();if(s==="")return{ok:!0,value:[]};return{ok:!0,value:s.split(",").map((part)=>part.trim()).filter((part)=>part!=="")}}case"dateOnly":{let s=String(value).trim();if(s==="")return{ok:!0,value:null};let leading=s.match(/^\d{4}-\d{2}-\d{2}/);if(leading)return{ok:!0,value:leading[0]};let d=new Date(s);return Number.isNaN(d.getTime())?{ok:!1,reason:"not a date",raw:value}:{ok:!0,value:d.toISOString().slice(0,10)}}default:return{ok:!0,value}}}function isEmpty(v){return v==null||typeof v==="string"&&v.trim()===""}function mapRecord(external,mappings,parent){let row={},problems=[];for(let fm of mappings){if(!fm.target)continue;let value;if(fm.constant!=null&&fm.constant!=="")value=fm.constant;else{let raw=isTemplateSource(fm.source)?renderTemplate(fm.source,external,parent):readOne(external,parent,fm.source),result=applyTransform(raw,fm.transform);if(!result.ok)problems.push(`${fm.source} \u2192 ${fm.target}: ${result.reason} (${String(result.raw)})`),value=null;else value=result.value}if(isEmpty(value)&&fm.fallback!=null&&fm.fallback!==""){let raw=isTemplateSource(fm.fallback)?renderTemplate(fm.fallback,external,parent):fm.fallback,result=applyTransform(raw,fm.transform);if(result.ok)value=result.value;else problems.push(`fallback \u2192 ${fm.target}: ${result.reason} (${String(result.raw)})`),value=null}if(value!==void 0)row[fm.target]=value}return{row,problems}}function buildMappedRecords(externalRecords,mappings,dedupTargetField,parents){let records=[],issues=[];return externalRecords.forEach((ext,i)=>{let{row,problems}=mapRecord(ext,mappings,parents?.[i]);for(let message of problems)issues.push({sourceIndex:i,kind:"invalid_value",message});let dedupKey=dedupTargetField&&!isEmpty(row[dedupTargetField])?String(row[dedupTargetField]).trim():null;records.push({data:row,dedupKey,sourceIndex:i,external:ext,parent:parents?.[i]})}),{records,issues}}function flattenKeys(obj,prefix="",out=[],depth=0){if(out.length>200||depth>4||obj==null||typeof obj!=="object")return out;if(Array.isArray(obj)){if(prefix)out.push(prefix);return out}for(let[k,v]of Object.entries(obj)){let path7=prefix?`${prefix}.${k}`:k;if(v!=null&&typeof v==="object"&&!Array.isArray(v))flattenKeys(v,path7,out,depth+1);else out.push(path7)}return out}var MAX_FANOUT_COMBINATIONS=5000;function resolvePath2(rawPath,values){let missing=new Set,used=new Set;return{path:rawPath.replace(/\{([a-zA-Z_][\w-]*)\}|:([a-zA-Z_]\w*)/g,(_full,brace,colon)=>{let key2=brace??colon,v=values[key2];if(v==null||v==="")return missing.add(key2),brace?`{${key2}}`:`:${key2}`;return used.add(key2),encodeURIComponent(String(v))}),missing:[...missing],used}}function planFetchOrder(endpoints,roots){let byId=new Map(endpoints.map((e)=>[e.id,e])),order=[],settled=new Set,onPath=[],onPathSet=new Set,visit=(id,requiredBy)=>{if(settled.has(id))return null;if(onPathSet.has(id))return{ok:!1,reason:"cycle",chain:[...onPath.slice(onPath.indexOf(id)),id]};let node=byId.get(id);if(!node)return{ok:!1,reason:"unknown_endpoint",missing:id,requiredBy:requiredBy??id};onPath.push(id),onPathSet.add(id);for(let binding of node.paramBindings??[]){if(binding.from!=="endpoint")continue;let failure=visit(binding.endpointId,id);if(failure)return failure}return onPath.pop(),onPathSet.delete(id),settled.add(id),order.push(id),null};for(let id of roots??endpoints.map((e)=>e.id)){let failure=visit(id,null);if(failure)return failure}return{ok:!0,order}}function expandBindings(bindings,sources,limit=MAX_FANOUT_COMBINATIONS){if(!bindings||bindings.length===0)return{ok:!0,calls:[{values:{}}]};let axes=[];for(let binding of bindings){if(binding.from==="static"){axes.push({param:binding.param,options:[{value:binding.value}]});continue}if(binding.from==="endpoint"){let options=(sources.parents?.[binding.endpointId]??[]).map((record)=>({value:getByPath(record,binding.field),parent:record})).filter((o)=>o.value!=null&&o.value!=="");axes.push({param:binding.param,options});continue}let values=sources.entityValues?.[`${binding.entity}.${binding.field}`]??[];axes.push({param:binding.param,options:values.filter((v)=>v!=null&&v!=="").map((value)=>({value}))})}if(axes.some((a)=>a.options.length===0))return{ok:!0,calls:[]};let combinations=axes.reduce((n,a)=>n*a.options.length,1);if(combinations>limit)return{ok:!1,reason:"too_many",combinations,limit};let calls=[{values:{}}];for(let axis of axes){let next=[];for(let call of calls)for(let option of axis.options)next.push({values:{...call.values,[axis.param]:option.value},parent:option.parent??call.parent});calls=next}return{ok:!0,calls}}function parentEndpointIds(bindings){let ids=new Set;for(let b of bindings??[])if(b.from==="endpoint")ids.add(b.endpointId);return[...ids]}function entityValueKeys(bindings){let keys=new Set;for(let b of bindings??[])if(b.from==="entity")keys.add(`${b.entity}.${b.field}`);return[...keys]}var MAX_PAGES=1000,DEFAULT_PAGE_SIZE=200,initialState2=()=>({pagesFetched:0,recordsFetched:0,cursor:null});function firstPageParams(profile){switch(profile.kind){case"page_number":{let params={[profile.pageParam]:String(profile.firstPage??0)};if(profile.sizeParam)params[profile.sizeParam]=String(pageSize(profile));return params}case"offset":return{[profile.offsetParam]:"0",[profile.limitParam]:String(pageSize(profile))};case"cursor":{let params={};if(profile.sizeParam)params[profile.sizeParam]=String(pageSize(profile));return params}case"link_header":{let params={};if(profile.sizeParam)params[profile.sizeParam]=String(pageSize(profile));return params}default:return{}}}function reportedTotal(profile,body){let path7=profile.kind==="page_number"||profile.kind==="offset"?profile.totalPath:void 0;if(!path7)return null;let raw=getByPath(body,path7);if(typeof raw==="number"&&Number.isFinite(raw)&&raw>=0)return Math.floor(raw);if(typeof raw==="string"&&raw.trim()!==""){let n=Number(raw);if(Number.isFinite(n)&&n>=0)return Math.floor(n)}return null}function nextPage(profile,state,observed){if(profile.kind==="none")return{kind:"done",reason:"single request"};if(state.pagesFetched>=MAX_PAGES)return{kind:"failed",reason:`Paging stopped after ${MAX_PAGES} requests without reaching the end. The source may not be honouring the paging parameters; importing this would be a partial read.`};if(observed.recordCount===0)return{kind:"done",reason:"empty page"};switch(profile.kind){case"page_number":{if(isLastPage(profile.lastPagePath,observed.body))return{kind:"done",reason:"source reported the last page"};let total=reportedTotal(profile,observed.body);if(total!==null&&state.recordsFetched>=total)return{kind:"done",reason:"reported total reached"};if(observed.recordCount<pageSize(profile))return{kind:"done",reason:"short page"};let next=(profile.firstPage??0)+state.pagesFetched,params={[profile.pageParam]:String(next)};if(profile.sizeParam)params[profile.sizeParam]=String(pageSize(profile));return{kind:"params",params}}case"offset":{let total=reportedTotal(profile,observed.body);if(total!==null&&state.recordsFetched>=total)return{kind:"done",reason:"reported total reached"};if(observed.recordCount<pageSize(profile))return{kind:"done",reason:"short page"};return{kind:"params",params:{[profile.offsetParam]:String(state.recordsFetched),[profile.limitParam]:String(pageSize(profile))}}}case"cursor":{let raw=getByPath(observed.body,profile.nextCursorPath),next=raw==null?"":String(raw).trim();if(next==="")return{kind:"done",reason:"no further cursor"};if(state.cursor!=null&&next===state.cursor)return{kind:"failed",reason:`The source returned the same cursor twice (${next}); paging would not advance.`};let params={[profile.cursorParam]:next};if(profile.sizeParam)params[profile.sizeParam]=String(pageSize(profile));return{kind:"params",params}}case"link_header":{let url=parseNextLink(observed.linkHeader);if(!url)return{kind:"done",reason:"no rel=next link"};return{kind:"url",url}}default:return{kind:"done",reason:"single request"}}}function pageSize(profile){let declared="pageSize"in profile?profile.pageSize:void 0;return declared&&declared>0?declared:DEFAULT_PAGE_SIZE}function isLastPage(path7,body){if(!path7)return!1;let raw=getByPath(body,path7);if(typeof raw==="boolean")return raw;if(typeof raw==="string")return raw.trim().toLowerCase()==="true";return!1}function parseNextLink(header){if(!header)return null;for(let part of splitLinks(header)){let match=part.match(/<([^>]*)>(.*)/);if(!match)continue;let url=(match[1]??"").trim(),attrs=match[2]??"";if(!url)continue;if(/;\s*rel\s*=\s*["']?\s*next\s*["']?(\s*;|\s*$)/i.test(attrs))return url}return null}function splitLinks(header){let parts=[],depth=0,current="";for(let ch of header){if(ch==="<")depth++;else if(ch===">")depth--;if(ch===","&&depth===0){parts.push(current),current="";continue}current+=ch}if(current.trim()!=="")parts.push(current);return parts}function isComplete(fetched,reported){if(reported===null)return!0;return fetched>=reported}function flattenTree(records,childrenPath){let out=[],truncated=!1,visit=(node,parent,depth)=>{if(!node||typeof node!=="object")return;if(depth>64){truncated=!0;return}let source=node,children=source[childrenPath],{[childrenPath]:_nested,...own}=source;if(out.push({...own,["__depth"]:depth,["__treeParent"]:parent??null}),!Array.isArray(children))return;for(let child of children)visit(child,own,depth+1)};for(let root of records)visit(root,null,0);return{records:out,truncated}}function treeChildrenPath(value){let trimmed=(value??"").trim();return trimmed.length>0?trimmed:null}var DEFAULT_MAX_CONCURRENT=4,DEFAULT_MAX_RECORDS=50000;async function collectOne(source,endpoint,params,deps,counters){let profile=endpoint.pagination??{kind:"none"},maxRecords=deps.maxRecords??DEFAULT_MAX_RECORDS,values={...endpoint.queryParams??{},...params.values},resolved=resolvePath2(endpoint.path,values);if(resolved.missing.length>0)return{ok:!1,error:`This endpoint needs path parameter(s) ${resolved.missing.map((m)=>`{${m}}`).join(", ")} and nothing supplies them. Add a parameter binding, or a static value.`};let baseQuery={};for(let[key2,value]of Object.entries(values)){if(value==null||resolved.used.has(key2))continue;baseQuery[key2]=value}let records=[],total=null,state=initialState2(),pageParams=firstPageParams(profile),absoluteUrl=null;for(;;){if(deps.isCancelled?.())return{ok:!1,error:"Cancelled."};let url;if(absoluteUrl)try{url=new URL(absoluteUrl)}catch{return{ok:!1,error:`The source returned an unusable next-page link: ${absoluteUrl}`}}else{let built=buildUrl(source.baseUrl,resolved.path,{...baseQuery,...pageParams});if(!built.ok)return{ok:!1,error:built.error};url=built.url}let headers={accept:"application/json"};if(deps.bearerToken)headers.Authorization=`Bearer ${deps.bearerToken}`;counters.calls++;let outcome=await fetchOnce({...source,token:deps.bearerToken??source.token},{method:endpoint.method,url,headers,body:endpoint.method.toUpperCase()==="GET"?void 0:endpoint.requestBody??{}},{fetchImpl:deps.fetchImpl});if(!outcome.ok)return{ok:!1,error:outcome.error??`HTTP ${outcome.status}`};let raw=extractRecords(outcome.body,endpoint.responseRootPath),childrenPath=treeChildrenPath(endpoint.treeChildrenPath),flattened=childrenPath?flattenTree(raw,childrenPath):null;if(flattened?.truncated)return{ok:!1,error:"This source answered with a structure that nests into itself. Nothing was imported \u2014 a company that contains itself has no order to write it in."};let page=flattened?flattened.records:raw;if(records.push(...page),counters.records+=page.length,total===null)total=reportedTotal(profile,outcome.body);if(counters.records>maxRecords)return{ok:!1,error:`This run would hold more than ${maxRecords} records at once. Narrow the source with a filter, or raise maxRecordsPerRun.`};deps.onProgress?.(counters.records),state={pagesFetched:state.pagesFetched+1,recordsFetched:records.length,cursor:pageParams[cursorParamOf(profile)??""]??state.cursor};let next=nextPage(profile,state,{recordCount:page.length,body:outcome.body,linkHeader:outcome.linkHeader});if(next.kind==="done")break;if(next.kind==="failed")return{ok:!1,error:next.reason};if(next.kind==="url"){absoluteUrl=next.url,pageParams={};continue}absoluteUrl=null,pageParams=next.params}return{ok:!0,records,total}}function cursorParamOf(profile){return profile.kind==="cursor"?profile.cursorParam:null}async function collectEndpoint(source,endpoint,sources,deps={}){let counters={calls:0,records:0},expansion=expandBindings(endpoint.paramBindings??void 0,sources);if(!expansion.ok)return{ok:!1,callCount:0,error:`This endpoint would be called ${expansion.combinations} times (the ceiling is ${expansion.limit}). Narrow the parent list, or remove one of the parameter bindings.`};if(expansion.calls.length===0)return{ok:!0,records:[],reportedTotal:null,callCount:0};let limit=Math.max(1,deps.maxConcurrent??DEFAULT_MAX_CONCURRENT),collected=[],total=null,failure=null,cursor=0,worker=async()=>{for(;;){if(failure||deps.isCancelled?.())return;let index=cursor++,call=expansion.calls[index];if(!call)return;let result=await collectOne(source,endpoint,call,deps,counters);if(!result.ok){failure??=result.error;return}for(let record of result.records)collected.push({record,parent:call.parent});if(expansion.calls.length===1)total=result.total}};if(await Promise.all(Array.from({length:Math.min(limit,expansion.calls.length)},worker)),failure)return{ok:!1,error:failure,callCount:counters.calls};if(deps.isCancelled?.())return{ok:!1,error:"Cancelled.",callCount:counters.calls};return{ok:!0,records:collected,reportedTotal:total,callCount:counters.calls}}var referenceKey=(check)=>`${check.entity}.${check.entityColumn}`,pointsAtOwnTable=(check,targetEntity)=>check.entity===targetEntity;function referenceValuesOf(raw){if(Array.isArray(raw))return{values:raw.map((item)=>String(item??"").trim()).filter((item)=>item!==""),wasList:!0};if(raw===null||raw===void 0)return{values:[],wasList:!1};let single=String(raw).trim();return{values:single===""?[]:[single],wasList:!1}}function resolveReference(raw,ids){let{values,wasList}=referenceValuesOf(raw),found=[],unmatched=[];for(let value of values){let id=ids?.[value];if(id===void 0)unmatched.push(value);else if(!found.includes(id))found.push(id)}return{ids:found,unmatched,wasList}}function resolvedColumnValue(resolution){return resolution.wasList?resolution.ids:resolution.ids[0]??null}function applyReferenceIds(row,references,ids,targetEntity){let next={...row},deferred=[];for(let check of references){if(!check.writeIdTo)continue;let raw=row[check.column];if(pointsAtOwnTable(check,targetEntity)){next[check.writeIdTo]=Array.isArray(raw)?[]:null,deferred.push({check,raw});continue}next[check.writeIdTo]=resolvedColumnValue(resolveReference(raw,ids[referenceKey(check)]))}return{row:next,deferred}}var isEmpty2=(v)=>v==null||typeof v==="string"&&v.trim()==="";function displayValue(value){if(value!==null&&typeof value==="object")try{return JSON.stringify(value)}catch{return"(a value that cannot be shown)"}return String(value)}function missingReferences(row,references,known){let broken=[];for(let check of references){let raw=row[check.column];if(isEmpty2(raw))continue;let value=displayValue(raw).trim(),present=known[`${check.entity}.${check.entityColumn}`];if(!present)continue;if(!present.has(value))broken.push({check,value,raw})}return broken}async function loadReferenceValues(references,read){let values={};for(let check of references){let key2=`${check.entity}.${check.entityColumn}`;if(values[key2])continue;let rows=await read(check.entity,check.entityColumn);values[key2]=new Set(rows.filter((v)=>!isEmpty2(v)).map((v)=>String(v).trim()))}return values}async function loadReferenceIds(references,targetEntity,read){let ids={};for(let check of references){if(!check.writeIdTo)continue;if(pointsAtOwnTable(check,targetEntity))continue;let key2=referenceKey(check);if(ids[key2])continue;ids[key2]=await read(check.entity,check.entityColumn)}return ids}function planWrites(input){let{records,existing,dedupTargetField,writeMode,missingPolicy,missingColumn,missingValue,requiredFields=[],uniqueFields=[],createDefaults={},accountRule=null,existingAccounts={},references=[],referenceValues={},referenceIds={},targetEntity=""}=input,issues=[],warnings=[],creates=[],referenceInserts=[],accountInserts=[],accountJoinInserts=[],plannedAccounts=new Set,plannedRefs=new Set,updates=[],deletes=[],deactivates=[],deferredLinks=[],dedupConfigured=Boolean(dedupTargetField),accountClaims=new Map,accountIdIsUnique=accountRule?uniqueFields.includes(accountRule.idColumn):!1,withAccount=(record,data)=>{if(!accountRule)return data;let raw=data[accountRule.matchFrom];if(isEmpty2(raw))return issues.push({sourceIndex:record.sourceIndex,kind:"account_unmatched",message:`${accountRule.matchFrom} is empty, so this record gets no account \u2014 it is imported without one.`,dedupKey:record.dedupKey,row:data}),data;let value=String(raw).trim(),claimedBy=accountClaims.get(value);if(claimedBy&&accountIdIsUnique)return issues.push({sourceIndex:record.sourceIndex,kind:"duplicate_value",message:`${accountRule.matchFrom} is \u201C${value}\u201D, which another record in this import already uses \u2014 and ${accountRule.idColumn} allows one record per account. This one is left out.`,dedupKey:record.dedupKey,row:data,keptRow:claimedBy.data}),null;accountClaims.set(value,record);let existingId=existingAccounts[value];if(existingId)return{...data,[accountRule.idColumn]:existingId};if(!plannedAccounts.has(value)){plannedAccounts.add(value);let accountData={[accountRule.matchColumn]:value};for(let pair of accountRule.values??[]){let from=data[pair.from];if(!isEmpty2(from))accountData[pair.column]=from}accountInserts.push({entity:accountRule.entity,matchColumn:accountRule.matchColumn,matchValue:value,data:accountData});for(let join7 of accountRule.joins??[])accountJoinInserts.push({entity:join7.entity,accountColumn:join7.accountColumn,values:join7.values,matchValue:value})}return data},hasDefaults=Object.keys(createDefaults).length>0,newRecord=(data)=>hasDefaults?{...createDefaults,...data}:data,existingByKey=new Map;if(dedupTargetField)for(let row of existing){let value=row.row[dedupTargetField];if(!isEmpty2(value))existingByKey.set(String(value).trim(),row)}let claimedUnique=new Map;for(let field of uniqueFields){let taken=new Map;for(let existingRow of existing){let value=existingRow.row[field];if(!isEmpty2(value))taken.set(String(value).trim(),existingRow.id)}claimedUnique.set(field,taken)}let matchedIds=new Set,seenInBatch=new Map;for(let sourceRecord of records){let broken=missingReferences(sourceRecord.data,references,referenceValues),resolvedRow=applyReferenceIds(sourceRecord.data,references,referenceIds,targetEntity),record={...sourceRecord,data:resolvedRow.row};for(let link of resolvedRow.deferred){if(!dedupTargetField)continue;let matchValue=record.data[dedupTargetField];if(isEmpty2(matchValue))continue;deferredLinks.push({matchColumn:dedupTargetField,matchValue:String(matchValue).trim(),writeIdTo:link.check.writeIdTo,lookupColumn:link.check.entityColumn,raw:link.raw,isList:Array.isArray(link.raw)})}let blocking=broken.find((b)=>b.check.onMissing==="skipRecord");if(blocking){let{check,value}=blocking;issues.push({sourceIndex:record.sourceIndex,kind:"missing_reference",message:typeof blocking.raw==="object"&&blocking.raw!==null?`${check.column} is not a single value but a whole object \u2014 ${value}. Point the mapping at one field of it, e.g. \`${check.column}.code\`, and it will have something to match against ${check.entity}.${check.entityColumn}.`:`${check.column} is \u201C${value}\u201D, which does not exist in ${check.entity}.${check.entityColumn} \u2014 this record is left out.`,dedupKey:record.dedupKey,row:record.data,reference:{column:check.column,value,entity:check.entity,entityColumn:check.entityColumn}});continue}let keepReferences=()=>{for(let{check,value}of broken){if(check.onMissing!=="create")continue;let token=`${check.entity}.${check.entityColumn}::${value}`;if(plannedRefs.has(token))continue;plannedRefs.add(token);let data={};for(let pair of check.createValues??[]){let fromSource=isTemplateSource(pair.from)?renderTemplate(pair.from,record.external,record.parent):readSourceValue(record.external,record.parent,pair.from),value2=isEmpty2(fromSource)?record.data[pair.from]:fromSource;if(!isEmpty2(value2))data[pair.column]=value2}referenceInserts.push({entity:check.entity,column:check.entityColumn,value,...Object.keys(data).length>0?{data}:{}})}},uniqueCollision=(data,ownRowId)=>{for(let field of uniqueFields){let raw=data[field];if(isEmpty2(raw))continue;let value=String(raw).trim(),holder2=claimedUnique.get(field)?.get(value);if(holder2===void 0)continue;if(holder2!==null&&holder2===ownRowId)continue;return{field,value}}return null},claimUnique=(data,rowId)=>{for(let field of uniqueFields){let raw=data[field];if(isEmpty2(raw))continue;claimedUnique.get(field)?.set(String(raw).trim(),rowId)}},collide=(field,value)=>{issues.push({sourceIndex:record.sourceIndex,kind:"duplicate_value",message:`${field} is \u201C${value}\u201D, which something else already has \u2014 ${field} has to be unique, so this record is left out.`,dedupKey:record.dedupKey,row:record.data})},missingRequired=requiredFields.filter((f)=>isEmpty2(record.data[f])&&isEmpty2(createDefaults[f]));if(missingRequired.length>0){issues.push({sourceIndex:record.sourceIndex,kind:"missing_required",message:`Required field(s) empty: ${missingRequired.join(", ")}`,dedupKey:record.dedupKey,row:record.data});continue}if(!dedupConfigured){let clash2=uniqueCollision(record.data,null);if(clash2){collide(clash2.field,clash2.value);continue}keepReferences(),claimUnique(record.data,null);let withLogin=withAccount(record,newRecord(record.data));if(!withLogin)continue;creates.push({data:withLogin,sourceIndex:record.sourceIndex});continue}if(record.dedupKey==null){let clash2=uniqueCollision(record.data,null);if(clash2){collide(clash2.field,clash2.value);continue}issues.push({sourceIndex:record.sourceIndex,kind:"missing_dedup_key",message:"Deduplication field is empty on this record \u2014 it will be added as new."}),keepReferences(),claimUnique(record.data,null);let withLogin=withAccount(record,newRecord(record.data));if(!withLogin)continue;creates.push({data:withLogin,sourceIndex:record.sourceIndex});continue}let claimedBy=seenInBatch.get(record.dedupKey);if(claimedBy){issues.push({sourceIndex:record.sourceIndex,kind:"duplicate_in_batch",message:`The source carries this key more than once: ${record.dedupKey} \u2014 this occurrence is skipped.`,dedupKey:record.dedupKey,row:record.data,keptRow:claimedBy});continue}if(seenInBatch.set(record.dedupKey,record.data),writeMode==="replace"||writeMode==="append"){let clash2=uniqueCollision(record.data,null);if(clash2&&!(writeMode==="replace"&&claimedUnique.get(clash2.field)?.get(clash2.value))){collide(clash2.field,clash2.value);continue}keepReferences(),claimUnique(record.data,null);let withLogin=withAccount(record,newRecord(record.data));if(!withLogin)continue;creates.push({data:withLogin,sourceIndex:record.sourceIndex});continue}let match=existingByKey.get(record.dedupKey),clash=uniqueCollision(record.data,match?.id??null);if(clash){collide(clash.field,clash.value);continue}if(keepReferences(),claimUnique(record.data,match?.id??null),match)matchedIds.add(match.id),updates.push({id:match.id,data:record.data,before:match.row,sourceIndex:record.sourceIndex});else{let withLogin=withAccount(record,newRecord(record.data));if(!withLogin)continue;creates.push({data:withLogin,sourceIndex:record.sourceIndex})}}if(writeMode==="replace")deletes.push(...existing);else if(writeMode==="upsert"&&missingPolicy!=="ignore"){let gone=existing.filter((row)=>!matchedIds.has(row.id));if(missingPolicy==="delete")deletes.push(...gone);else deactivates.push(...gone)}if(!dedupConfigured&&writeMode==="upsert")warnings.push("No deduplication field is set. Nothing can be matched against what is already here, so every record is added as new and each run will duplicate the last.");if(dedupConfigured&&records.length>0&&records.every((r)=>r.dedupKey==null))warnings.push(`The deduplication field is empty on every record \u2014 it is probably not among the mapped fields. As it stands nothing can ever match: all ${records.length} records will be re-added on every run.`);if(writeMode==="append"&&dedupConfigured)warnings.push("Append mode ignores the deduplication field: records already here will be added again.");if(writeMode==="replace"){if(warnings.push(`Replace mode: all ${existing.length} rows currently in the table are deleted and rebuilt from the source. Row identifiers change, so anything referring to them by id breaks.`),dedupConfigured)warnings.push('A deduplication field is set, so "update existing" would keep the current rows and their identifiers. Replace mode is only necessary when records cannot be matched at all.')}if(deactivates.length>0&&(!missingColumn||isEmpty2(missingValue)))warnings.push('The policy for records missing from the source is "deactivate", but no column and value are configured \u2014 those rows will be left untouched.'),deactivates.length=0;return{creates,updates,deletes,deactivates,deferredLinks,issues,warnings,referenceInserts,accountInserts,accountJoinInserts}}function summarize(ops,meta){let sampleSize=meta.sampleSize??8,sample=[...ops.creates.map((c)=>c.data),...ops.updates.map((u)=>u.data)].slice(0,sampleSize);return{targetEntity:meta.targetEntity,writeMode:meta.writeMode,totalFetched:meta.totalFetched,reportedTotal:meta.reportedTotal,toCreate:ops.creates.length,toUpdate:ops.updates.length,toSkip:ops.issues.filter((i)=>i.kind==="missing_required"||i.kind==="duplicate_in_batch"||i.kind==="duplicate_value"||i.kind==="invalid_value"||i.kind==="missing_reference").length,missing:ops.deletes.length+ops.deactivates.length,missingPolicy:meta.missingPolicy,existingCount:meta.existingCount,dedupConfigured:meta.dedupConfigured,issues:ops.issues,warnings:ops.warnings,referenceInserts:ops.referenceInserts,accountsToCreate:ops.accountInserts.length,sample}}import{and as and15,eq as eq30,inArray as inArray10}from"drizzle-orm";var INSERT_CHUNK=500,DELETE_CHUNK=1000;function validateAll(ops,columns,validatePayload2){let issues=[];for(let op of ops.creates){let result=validatePayload2(op.data,columns,!1);if(!result.valid)issues.push({sourceIndex:op.sourceIndex,kind:"invalid_value",message:result.errors.map((e)=>`${e.field}: ${e.message}`).join("; "),row:op.data})}for(let op of ops.updates){let result=validatePayload2(op.data,columns,!0);if(!result.valid)issues.push({sourceIndex:op.sourceIndex,kind:"invalid_value",message:result.errors.map((e)=>`${e.field}: ${e.message}`).join("; "),row:op.data})}return issues}function referenceRow(columns,column,value,extra){let row={...extra,[column]:value},unfillable=[];for(let col8 of columns){let name2=camel(col8.name);if(name2===column)continue;if(SYSTEM_COLUMNS.has(name2))continue;if(row[name2]!==void 0)continue;if(!(col8.notNull===!0&&col8.default===void 0&&!col8.defaultRaw&&!col8.nullable))continue;if(TEXTUAL_TYPES.has(String(col8.type)))row[name2]=value;else unfillable.push(name2)}return unfillable.length>0?{ok:!1,unfillable}:{ok:!0,row}}var SYSTEM_COLUMNS=new Set(["id","createdAt","updatedAt","createdBy","updatedBy"]),TEXTUAL_TYPES=new Set(["text","varchar","char"]),camel=(s)=>s.replace(/_([a-z])/g,(_m,l)=>l.toUpperCase());function linkAccount(data,rule,idByValue){let value=data[rule.matchFrom];if(value==null)return{};let id=idByValue.get(String(value).trim());return id?{[rule.idColumn]:id}:{}}function groupDeferred(links){let groups=new Map;for(let link of links){let key2=`${link.writeIdTo}|${link.lookupColumn}|${link.matchColumn}`,group=groups.get(key2)??{writeIdTo:link.writeIdTo,lookupColumn:link.lookupColumn,matchColumn:link.matchColumn,links:[]};group.links.push(link),groups.set(key2,group)}return[...groups.values()]}async function applyWrites(deps,input){let{ops,targetEntity,userId}=input,scope=input.scopeConditions??[],cancelled=()=>input.isCancelled?.()===!0,invalid=validateAll(ops,deps.columns,deps.validatePayload);if(invalid.length>0)return{ok:!1,failure:{kind:"validation_failed",message:`${invalid.length} record(s) did not pass validation; nothing was written.`,issues:invalid}};let refGroups=new Map;for(let insert of ops.referenceInserts){let resolved=deps.resolveEntity?.(insert.entity);if(!resolved)return{ok:!1,failure:{kind:"write_failed",message:`This mapping would add \u201C${insert.value}\u201D to "${insert.entity}", which does not exist.`}};let built=referenceRow(resolved.columns,insert.column,insert.value,insert.data);if(!built.ok)return{ok:!1,failure:{kind:"write_failed",message:`\u201C${insert.value}\u201D cannot be added to "${insert.entity}" automatically: ${built.unfillable.join(", ")} is required and cannot be filled from a ${insert.column}. Add the missing ${insert.entity} by hand, or set this reference to leave those records out.`}};let group=refGroups.get(insert.entity)??{table:resolved.table,rows:[]};group.rows.push(built.row),refGroups.set(insert.entity,group)}let accountRule=input.account??null,accountEntity=ops.accountInserts[0]?.entity,accountTable=accountEntity?deps.resolveEntity?.(accountEntity):null;if(ops.accountInserts.length>0&&(!accountRule||!accountTable))return{ok:!1,failure:{kind:"write_failed",message:accountRule?`This import creates accounts in "${accountEntity}", which does not exist.`:"This import creates accounts but no password was supplied, so nothing was written."}};if(cancelled())return{ok:!1,failure:{kind:"cancelled",message:"Cancelled before writing."}};let idCol=deps.resolveCol("id");if(!idCol)return{ok:!1,failure:{kind:"write_failed",message:`Target "${targetEntity}" has no id column; the engine cannot address its rows.`}};let preImages=[],now=new Date,deactivating=ops.deactivates.length>0&&input.missingColumn&&input.missingValue!=null?{column:input.missingColumn,value:input.missingValue}:null;try{let linksMade=0;return{ok:!0,...await deps.db.transaction(async(tx)=>{let created=0,accountsCreated=0,referencesCreated=0,updated=0,deleted=0,deactivated=0;if(ops.deletes.length>0){let ids=ops.deletes.map((r)=>r.id);for(let i=0;i<ids.length;i+=DELETE_CHUNK){if(cancelled())throw new CancelledError;let chunk=ids.slice(i,i+DELETE_CHUNK),where=scope.length?and15(inArray10(idCol,chunk),...scope):inArray10(idCol,chunk),removed=await tx.delete(deps.drizzleTable).where(where).returning();deleted+=removed.length;for(let row of removed)preImages.push({targetEntity,rowId:String(row.id),action:"delete",before:row,after:null})}}for(let op of ops.updates){if(cancelled())throw new CancelledError;let where=scope.length?and15(eq30(idCol,op.id),...scope):eq30(idCol,op.id),written=await tx.update(deps.drizzleTable).set({...op.data,updatedAt:now,updatedBy:userId}).where(where).returning();if(written.length===0)throw new ScopeError(op.id);updated+=written.length,preImages.push({targetEntity,rowId:op.id,action:"update",before:op.before,after:written[0]??null})}if(deactivating){let ids=ops.deactivates.map((r)=>r.id);for(let i=0;i<ids.length;i+=DELETE_CHUNK){if(cancelled())throw new CancelledError;let chunk=ids.slice(i,i+DELETE_CHUNK),where=scope.length?and15(inArray10(idCol,chunk),...scope):inArray10(idCol,chunk),written=await tx.update(deps.drizzleTable).set({[deactivating.column]:deactivating.value,updatedAt:now,updatedBy:userId}).where(where).returning();deactivated+=written.length;let beforeById=new Map(ops.deactivates.map((r)=>[r.id,r.row]));for(let row of written){let id=String(row.id);preImages.push({targetEntity,rowId:id,action:"deactivate",before:beforeById.get(id)??null,after:row})}}}for(let[entity,group]of refGroups){let rows=group.rows.map((r)=>({...r,createdAt:now,updatedAt:now,createdBy:userId}));for(let i=0;i<rows.length;i+=INSERT_CHUNK){if(cancelled())throw new CancelledError;let written=await tx.insert(group.table).values(rows.slice(i,i+INSERT_CHUNK)).returning();referencesCreated+=written.length;for(let row of written)preImages.push({targetEntity:entity,rowId:row.id?String(row.id):null,action:"create",before:null,after:row})}}let accountIdByValue=new Map;if(accountRule&&accountTable&&ops.accountInserts.length>0){let rows=ops.accountInserts.map((account)=>({...account.data,[accountRule.passwordColumn]:accountRule.passwordHash,createdAt:now,updatedAt:now,createdBy:userId}));for(let i=0;i<rows.length;i+=INSERT_CHUNK){if(cancelled())throw new CancelledError;let written=await tx.insert(accountTable.table).values(rows.slice(i,i+INSERT_CHUNK)).returning();accountsCreated+=written.length;for(let row of written){let value=row[accountRule.matchColumn];if(row.id!=null&&value!=null)accountIdByValue.set(String(value).trim(),String(row.id));preImages.push({targetEntity:ops.accountInserts[0]?.entity??"",rowId:row.id?String(row.id):null,action:"create",before:null,after:row})}}}if(accountRule&&ops.accountJoinInserts.length>0){let byEntity=new Map;for(let join7 of ops.accountJoinInserts){let accountId=accountIdByValue.get(join7.matchValue);if(!accountId)continue;let rows=byEntity.get(join7.entity)??[];rows.push({...join7.values,[join7.accountColumn]:accountId,createdAt:now,updatedAt:now,createdBy:userId}),byEntity.set(join7.entity,rows)}for(let[entity,rows]of byEntity){let resolved=deps.resolveEntity?.(entity);if(!resolved)continue;for(let i=0;i<rows.length;i+=INSERT_CHUNK){if(cancelled())throw new CancelledError;let written=await tx.insert(resolved.table).values(rows.slice(i,i+INSERT_CHUNK)).returning();for(let row of written)preImages.push({targetEntity:entity,rowId:row.id?String(row.id):null,action:"create",before:null,after:row})}}}if(ops.creates.length>0){let rows=ops.creates.map((c)=>({...c.data,...accountRule&&c.data[accountRule.idColumn]==null?linkAccount(c.data,accountRule,accountIdByValue):{},createdAt:now,updatedAt:now,createdBy:userId}));for(let i=0;i<rows.length;i+=INSERT_CHUNK){if(cancelled())throw new CancelledError;let chunk=rows.slice(i,i+INSERT_CHUNK),written=await tx.insert(deps.drizzleTable).values(chunk).returning();created+=written.length;for(let row of written)preImages.push({targetEntity,rowId:row.id?String(row.id):null,action:"create",before:null,after:row})}}if(ops.deferredLinks.length>0)for(let group of groupDeferred(ops.deferredLinks)){if(cancelled())throw new CancelledError;let lookupCol=deps.resolveCol(group.lookupColumn),matchCol=deps.resolveCol(group.matchColumn),targetCol=deps.resolveCol(group.writeIdTo);if(!lookupCol||!matchCol||!targetCol){deps.logger.error(`[Integrations] Cannot fill "${group.writeIdTo}": ${[!lookupCol?group.lookupColumn:null,!matchCol?group.matchColumn:null,!targetCol?group.writeIdTo:null].filter(Boolean).join(", ")} is not a column of "${targetEntity}".`);continue}let rows=await tx.select({v:lookupCol,id:idCol}).from(deps.drizzleTable),idByValue={};for(let row of rows){if(row.v==null||row.v===""||row.id==null)continue;let key2=String(row.v).trim();if(!idByValue[key2])idByValue[key2]=String(row.id)}for(let link of group.links){let resolution=resolveReference(link.raw,idByValue);if(resolution.ids.length===0)continue;let value=link.isList?resolution.ids:resolution.ids[0],where=scope.length?and15(eq30(matchCol,link.matchValue),...scope):eq30(matchCol,link.matchValue);await tx.update(deps.drizzleTable).set({[group.writeIdTo]:value}).where(where),linksMade+=1}}return{created,accountsCreated,referencesCreated,updated,deleted,deactivated,linksMade}}),preImages}}catch(error){if(error instanceof CancelledError)return{ok:!1,failure:{kind:"cancelled",message:"Cancelled while writing; the transaction was rolled back and nothing changed."}};if(error instanceof ScopeError)return{ok:!1,failure:{kind:"write_failed",message:`Row ${error.rowId} is outside what this account may write. Nothing was written.`}};return deps.logger.error(`[Integrations] Write transaction failed for "${targetEntity}": ${reasonOf2(error)}`),{ok:!1,failure:{kind:"write_failed",message:"The database rejected this import; it was rolled back and nothing changed."}}}}function reasonOf2(error){if(!(error instanceof Error))return String(error);let extra=error;return[error.message,extra.detail?`detail: ${String(extra.detail)}`:"",extra.constraint?`constraint: ${String(extra.constraint)}`:"",extra.hint?`hint: ${String(extra.hint)}`:"",extra.code?`code: ${String(extra.code)}`:""].filter(Boolean).join(" \u2014 ")}class CancelledError extends Error{constructor(){super("cancelled");this.name="CancelledError"}}class ScopeError extends Error{rowId;constructor(rowId){super(`row ${rowId} outside scope`);this.rowId=rowId;this.name="ScopeError"}}var DAY_MS=86400000;async function executeRun(context,deps,lock){let{mapping,source}=context,empty={runId:null,status:"failed",failure:null,plan:null,created:0,accountsCreated:0,referencesCreated:0,updated:0,deleted:0,deactivated:0,externalCalls:0,issues:[]},opened=await deps.repo.openRun({mappingId:mapping.id,targetEntity:mapping.targetEntity,writeMode:mapping.writeMode,trigger:context.trigger,userId:context.userId});if(!opened.ok)return{...empty,failure:{kind:"write_failed",message:`Could not open a run record: ${opened.error}`}};let runId=opened.runId;deps.onRunOpened?.(runId);let cancelChecked=0,cancelSeen=!1,isCancelled=()=>{if(cancelSeen)return!0;if(deps.abortSignal?.aborted)return cancelSeen=!0,!0;if(!lock.isHeld())return cancelSeen=!0,!0;return!1},refreshCancelFlag=async()=>{if(cancelChecked++,await deps.repo.isCancelRequested(runId))cancelSeen=!0},progress=(p)=>deps.publishProgress?.({runId,...p}),finish=async(outcome)=>{let revertible=outcome.status==="succeeded";return await deps.repo.closeRun(runId,{status:outcome.status,totalFetched:outcome.plan?.totalFetched??0,sourceReportedTotal:outcome.plan?.reportedTotal??null,createdCount:outcome.created,accountsCreatedCount:outcome.accountsCreated,referencesCreatedCount:outcome.referencesCreated,updatedCount:outcome.updated,skippedCount:outcome.plan?.toSkip??0,deletedCount:outcome.deleted,deactivatedCount:outcome.deactivated,errorCount:outcome.failure?1:0,externalCallCount:outcome.externalCalls,issues:outcome.issues,errors:outcome.failure?[outcome.failure.message]:[],finishedAt:new Date,preImagesExpireAt:revertible?new Date(Date.now()+(deps.retainPreImagesMs??30*DAY_MS)):null}),progress({phase:"done",message:outcome.failure?.message}),{runId,...outcome}};progress({phase:"fetching"});let nodes=context.endpoints.map((e)=>({id:e.id,paramBindings:e.paramBindings??void 0})),order=planFetchOrder(nodes,[context.rootEndpointId]);if(!order.ok){let failure=order.reason==="cycle"?{kind:"cycle_detected",message:`These endpoints depend on each other in a loop (${order.chain.join(" \u2192 ")}), so there is no correct place to start.`,chain:order.chain}:{kind:"fetch_failed",message:`"${order.requiredBy}" takes a parameter from an endpoint that no longer exists (${order.missing}).`};return finish({...empty,failure,status:"failed"})}let bearerToken=null;if(context.oauth){let token=await getAccessToken(context.oauth,deps.tokenCache,{fetchImpl:deps.fetchImpl});if(!token.ok)return finish({...empty,failure:{kind:"fetch_failed",message:token.error}});bearerToken=token.accessToken}let byId=new Map(context.endpoints.map((e)=>[e.id,e])),parents={},entityValues={},externalCalls=0,rootRecords=[],reportedTotal2=null;for(let endpointId of order.order){let endpoint=byId.get(endpointId);if(!endpoint)continue;if(await refreshCancelFlag(),isCancelled())return finish({...empty,status:"cancelled",externalCalls,failure:{kind:"cancelled",message:"Cancelled before anything was written."}});for(let key2 of entityValueKeys(endpoint.paramBindings??void 0)){if(entityValues[key2])continue;let[entity,field]=key2.split(".");entityValues[key2]=await deps.repo.readEntityColumn(entity,field)}let collected=await collectEndpoint(source,endpoint,{parents,entityValues},{fetchImpl:deps.fetchImpl,bearerToken,maxConcurrent:deps.maxConcurrentFanout,maxRecords:deps.maxRecordsPerRun,isCancelled,onProgress:(n)=>progress({phase:"fetching",processed:n})});if(externalCalls+=collected.callCount,!collected.ok){let cancelled=isCancelled();return finish({...empty,externalCalls,status:cancelled?"cancelled":"failed",failure:cancelled?{kind:"cancelled",message:"Cancelled before anything was written."}:{kind:"fetch_failed",message:collected.error}})}if(parents[endpointId]=collected.records.map((r)=>r.record),endpointId===context.rootEndpointId)rootRecords=collected.records,reportedTotal2=collected.reportedTotal}for(let id of Object.keys(parents))if(!(id===context.rootEndpointId||context.endpoints.some((e)=>parentEndpointIds(e.paramBindings??void 0).includes(id))))delete parents[id];if((mapping.writeMode==="replace"||mapping.missingPolicy==="delete")&&!isComplete(rootRecords.length,reportedTotal2))return finish({...empty,externalCalls,failure:{kind:"incomplete_source",message:`The source reports ${reportedTotal2} records but only ${rootRecords.length} were read. This run deletes what the source does not send, so it will not proceed on a partial read. Check the paging settings for this endpoint.`,fetched:rootRecords.length,reported:reportedTotal2??0}});progress({phase:"mapping",total:rootRecords.length});let mapped=buildMappedRecords(rootRecords.map((r)=>r.record),mapping.fieldMappings,mapping.dedupTargetField,rootRecords.map((r)=>r.parent));if(await refreshCancelFlag(),isCancelled())return finish({...empty,externalCalls,status:"cancelled",failure:{kind:"cancelled",message:"Cancelled before anything was written."}});let existing=await deps.repo.readExistingRows(mapping.targetEntity),referenceValues=await loadReferenceValues(mapping.references??[],(entity,column)=>deps.repo.readEntityColumn(entity,column)),referenceIds=await loadReferenceIds(mapping.references??[],mapping.targetEntity,(entity,column)=>deps.repo.readEntityIdsBy(entity,column)),existingAccounts=mapping.accountRule?await deps.repo.readEntityIdsBy(mapping.accountRule.entity,mapping.accountRule.matchColumn):{},ops=planWrites({records:mapped.records,existing,dedupTargetField:mapping.dedupTargetField,writeMode:mapping.writeMode,missingPolicy:mapping.missingPolicy,missingColumn:mapping.missingColumn,missingValue:mapping.missingValue,requiredFields:deps.repo.requiredFields(mapping.targetEntity),uniqueFields:deps.repo.uniqueFields(mapping.targetEntity),createDefaults:context.createDefaults??{},accountRule:mapping.accountRule??null,existingAccounts,references:mapping.references??[],referenceValues,referenceIds,targetEntity:mapping.targetEntity});ops.issues.unshift(...mapped.issues);let plan=summarize(ops,{targetEntity:mapping.targetEntity,writeMode:mapping.writeMode,missingPolicy:mapping.missingPolicy,totalFetched:rootRecords.length,reportedTotal:reportedTotal2,existingCount:existing.length,dedupConfigured:Boolean(mapping.dedupTargetField)});progress({phase:"writing",total:ops.creates.length+ops.updates.length});let applied=await applyWrites(deps.writer,{ops,targetEntity:mapping.targetEntity,userId:context.userId,account:mapping.accountRule&&context.accountPasswordHash?{idColumn:mapping.accountRule.idColumn,matchColumn:mapping.accountRule.matchColumn,matchFrom:mapping.accountRule.matchFrom,passwordColumn:mapping.accountRule.passwordColumn,passwordHash:context.accountPasswordHash}:null,missingColumn:mapping.missingColumn,missingValue:mapping.missingValue,isCancelled});if(!applied.ok){let failureIssues=applied.failure.kind==="validation_failed"?applied.failure.issues:[];return finish({...empty,plan,externalCalls,issues:[...ops.issues,...failureIssues],status:applied.failure.kind==="cancelled"?"cancelled":"failed",failure:applied.failure})}return await deps.repo.savePreImages(runId,applied.preImages),deps.logger.info("[Integrations] Run finished",{runId,mappingId:mapping.id,targetEntity:mapping.targetEntity,created:applied.created,accountsCreated:applied.accountsCreated,referencesCreated:applied.referencesCreated,updated:applied.updated,deleted:applied.deleted,deactivated:applied.deactivated,externalCalls,cancelChecks:cancelChecked}),finish({...empty,status:"succeeded",plan,failure:null,created:applied.created,accountsCreated:applied.accountsCreated,referencesCreated:applied.referencesCreated,updated:applied.updated,deleted:applied.deleted,deactivated:applied.deactivated,externalCalls,issues:ops.issues})}var RANGES=[[0,59],[0,23],[1,31],[1,12],[0,6]],NAMES=["minute","hour","day of month","month","day of week"];function expandField(raw,[min,max]){let values=new Set;for(let part of raw.split(",")){let[spec,stepText]=part.split("/"),step=stepText===void 0?1:Number(stepText);if(!Number.isInteger(step)||step<1)return null;let from,to;if(spec==="*")from=min,to=max;else if(spec?.includes("-")){let[a,b]=spec.split("-").map(Number);if(!Number.isInteger(a)||!Number.isInteger(b))return null;from=a,to=b}else{let one=Number(spec);if(!Number.isInteger(one))return null;from=one,to=stepText===void 0?one:max}if(from<min||to>max||from>to)return null;for(let v=from;v<=to;v+=step)values.add(v)}return values.size>0?values:null}function parseCron2(expression){let parts=expression.trim().split(/\s+/);if(parts.length!==5)return{ok:!1,error:`A schedule has five parts \u2014 minute hour day-of-month month day-of-week \u2014 and this has ${parts.length}. "0 2 * * *" is every night at 02:00.`};let sets=[];for(let i=0;i<5;i++){let field=expandField(parts[i],RANGES[i]);if(!field)return{ok:!1,error:`The ${NAMES[i]} part ("${parts[i]}") is not something I can read.`};sets.push(field)}return{ok:!0,fields:{minutes:sets[0],hours:sets[1],daysOfMonth:sets[2],months:sets[3],daysOfWeek:sets[4],anyDayOfMonth:parts[2]==="*",anyDayOfWeek:parts[4]==="*"}}}function partsIn2(when,timeZone){let formatter=new Intl.DateTimeFormat("en-US",{timeZone,hour12:!1,year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",weekday:"short"}),parts={};for(let part of formatter.formatToParts(when))parts[part.type]=part.value;let weekdays=["Sun","Mon","Tue","Wed","Thu","Fri","Sat"];return{year:Number(parts.year),month:Number(parts.month),day:Number(parts.day),hour:Number(parts.hour)%24,minute:Number(parts.minute),weekday:Math.max(0,weekdays.indexOf(parts.weekday??"Sun"))}}function matchesCron(fields,when,timeZone){let at=partsIn2(when,timeZone);if(!fields.minutes.has(at.minute))return!1;if(!fields.hours.has(at.hour))return!1;if(!fields.months.has(at.month))return!1;let dayOfMonthMatches=fields.daysOfMonth.has(at.day),dayOfWeekMatches=fields.daysOfWeek.has(at.weekday);if(fields.anyDayOfMonth&&fields.anyDayOfWeek)return!0;if(fields.anyDayOfMonth)return dayOfWeekMatches;if(fields.anyDayOfWeek)return dayOfMonthMatches;return dayOfMonthMatches||dayOfWeekMatches}function isDue(input){let parsed=parseCron2(input.expression);if(!parsed.ok)return{due:!1,error:parsed.error};let zone=input.timeZone?.trim()||"UTC",matches;try{matches=matchesCron(parsed.fields,input.now,zone)}catch{return{due:!1,error:`"${zone}" is not a timezone this system knows.`}}if(!matches)return{due:!1};if(input.lastRunAt){if(Math.floor(input.lastRunAt.getTime()/60000)===Math.floor(input.now.getTime()/60000))return{due:!1}}return{due:!0}}var MINUTE2=60000;function dueMappings(mappings,now){let due=[],problems=[];for(let mapping of mappings){if(!mapping.scheduleCron?.trim())continue;let answer=isDue({expression:mapping.scheduleCron,timeZone:mapping.scheduleTimezone,now,lastRunAt:mapping.lastRunAt??null});if(answer.error){problems.push({mapping,error:answer.error});continue}if(answer.due)due.push(mapping)}return{due,problems}}function startScheduler(deps){let now=deps.now??(()=>new Date),reported=new Set,stopped=!1,tick=async()=>{if(stopped)return;let mappings;try{mappings=await deps.listScheduled()}catch(error){deps.logger.error("[Integrations] Could not read the schedules",{error:error instanceof Error?error.message:String(error)});return}let{due,problems}=dueMappings(mappings,now());for(let problem of problems){let token=`${problem.mapping.id}:${problem.error}`;if(reported.has(token))continue;reported.add(token),deps.logger.error(`[Integrations] "${problem.mapping.name}" has a schedule that cannot run: ${problem.error}`)}for(let mapping of due)try{if(await deps.startRun(mapping.id))deps.logger.info(`[Integrations] Scheduled import started: ${mapping.name}`)}catch(error){deps.logger.error(`[Integrations] Scheduled import failed to start: ${mapping.name}`,{error:error instanceof Error?error.message:String(error)})}},timer=setInterval(()=>{tick()},MINUTE2);if(typeof timer==="object"&&timer&&"unref"in timer)timer.unref();return{stop:()=>{stopped=!0,clearInterval(timer)}}}var asObject=(value)=>value&&typeof value==="object"&&!Array.isArray(value)?value:null,asArray=(value)=>Array.isArray(value)?value:[],text=(value)=>{if(value==null)return null;let s=String(value);return s===""?null:s};function buildTransferDocument(input){let{source,endpoints,mappings}=input,nameById=new Map;for(let endpoint of endpoints){let id=text(endpoint.id),name2=text(endpoint.name);if(id&&name2)nameById.set(id,name2)}return{version:1,exportedAt:input.exportedAt,secretsExcluded:!0,connection:{name:String(source.name??""),slug:String(source.slug??""),baseUrl:String(source.baseUrl??""),description:text(source.description),authType:String(source.authType??"none"),authHeaderName:text(source.authHeaderName),authQueryParam:text(source.authQueryParam),extraHeaders:asObject(source.extraHeaders),tokenUrl:text(source.tokenUrl),oauthGrantType:text(source.oauthGrantType),oauthClientId:text(source.oauthClientId),oauthUsername:text(source.oauthUsername),oauthScope:text(source.oauthScope),oauthClientAuth:text(source.oauthClientAuth),tlsVerify:source.tlsVerify!==!1,timeoutMs:typeof source.timeoutMs==="number"?source.timeoutMs:null,enabled:source.enabled!==!1},endpoints:endpoints.map((endpoint)=>({name:String(endpoint.name??""),tag:String(endpoint.tag??""),method:String(endpoint.method??"GET"),path:String(endpoint.path??""),description:text(endpoint.description),queryParams:asObject(endpoint.queryParams),requestBody:asObject(endpoint.requestBody),responseRootPath:text(endpoint.responseRootPath),treeChildrenPath:text(endpoint.treeChildrenPath),pagination:asObject(endpoint.pagination),paramBindings:asArray(endpoint.paramBindings).map((binding)=>{if(binding.from!=="endpoint")return{...binding};let{endpointId,...rest}=binding;return{...rest,endpointName:nameById.get(String(endpointId))??null}}),enabled:endpoint.enabled!==!1})),mappings:mappings.map((mapping)=>({name:String(mapping.name??""),endpointName:nameById.get(String(mapping.endpointId))??null,targetEntity:String(mapping.targetEntity??""),fieldMappings:asArray(mapping.fieldMappings),referenceChecks:asArray(mapping.referenceChecks),dedupSourceField:text(mapping.dedupSourceField),dedupTargetField:text(mapping.dedupTargetField),writeMode:String(mapping.writeMode??"upsert")??"upsert",missingRecordPolicy:String(mapping.missingRecordPolicy??"ignore")??"ignore",missingRecordColumn:text(mapping.missingRecordColumn),missingRecordValue:text(mapping.missingRecordValue),passwordTargetColumn:text(mapping.passwordTargetColumn),accountRule:mapping.accountRule??null,scheduleEnabled:mapping.scheduleEnabled===!0,scheduleCron:text(mapping.scheduleCron),scheduleTimezone:text(mapping.scheduleTimezone),enabled:mapping.enabled!==!1}))}}function validateTransferDocument(value){let problems=[],doc=asObject(value);if(!doc)return{ok:!1,document:null,problems:[{path:"",message:"This is not an integration export file."}]};if(typeof doc.version!=="number")problems.push({path:"version",message:"The file does not say which format it is in."});else if(doc.version>1)problems.push({path:"version",message:`This file was written by a newer version (${doc.version}); this one understands up to 1.`});let connection=asObject(doc.connection);if(!connection)problems.push({path:"connection",message:"The file has no connection."});else{if(!text(connection.name))problems.push({path:"connection.name",message:"Missing name."});if(!text(connection.slug))problems.push({path:"connection.slug",message:"Missing slug."});if(!text(connection.baseUrl))problems.push({path:"connection.baseUrl",message:"Missing base URL."})}let endpoints=asArray(doc.endpoints),endpointNames=new Set;return endpoints.forEach((endpoint,index)=>{let name2=text(endpoint.name);if(!name2){problems.push({path:`endpoints[${index}].name`,message:"Missing name."});return}if(endpointNames.has(name2))problems.push({path:`endpoints[${index}].name`,message:`Two endpoints are called "${name2}"; names are how the rest of the file refers to them.`});if(endpointNames.add(name2),!text(endpoint.path))problems.push({path:`endpoints[${index}].path`,message:"Missing path."});if(!text(endpoint.tag))problems.push({path:`endpoints[${index}].tag`,message:"Missing tag."})}),endpoints.forEach((endpoint,index)=>{asArray(endpoint.paramBindings).forEach((binding,bindingIndex)=>{if(binding.from!=="endpoint")return;let target2=text(binding.endpointName);if(!target2||!endpointNames.has(target2))problems.push({path:`endpoints[${index}].paramBindings[${bindingIndex}]`,message:`Takes its value from an endpoint called "${target2??"?"}", which is not in this file.`})})}),asArray(doc.mappings).forEach((mapping,index)=>{if(!text(mapping.name))problems.push({path:`mappings[${index}].name`,message:"Missing name."});if(!text(mapping.targetEntity))problems.push({path:`mappings[${index}].targetEntity`,message:"Missing target table."});let endpointName=text(mapping.endpointName);if(!endpointName||!endpointNames.has(endpointName))problems.push({path:`mappings[${index}].endpointName`,message:`Reads from an endpoint called "${endpointName??"?"}", which is not in this file.`})}),{ok:problems.length===0,document:problems.length===0?doc:null,problems}}init_crypto();init_utils5();init_utils6();init_godminGuard();init_utils5();import Elysia12,{t as t10}from"elysia";async function testConnection(chain,tokenCache,deps={}){let{source,oauth}=chain,fetchImpl=deps.fetchImpl;if(oauth){tokenCache.invalidate(source.id);let token=await getAccessToken(oauth,tokenCache,{fetchImpl});return token.ok?{ok:!0,detail:`A token was issued (${token.accessToken.length} characters). The credentials and token address are valid.`}:{ok:!1,error:token.error}}let built=buildUrl(source.baseUrl,"");if(!built.ok)return{ok:!1,error:built.error};let{headers}=applyAuth(source,built.url),outcome=await fetchOnce(source,{method:"GET",url:built.url,headers},{fetchImpl});if(outcome.status===0)return{ok:!1,error:outcome.error};return{ok:outcome.status<500,detail:`The address answered: HTTP ${outcome.status}.`,error:outcome.status>=500?outcome.error:void 0}}var PREVIEW_LIMIT=1500;async function sampleEndpoint(source,endpoint,pathParams,tokenCache,oauth,deps={}){let fetchImpl=deps.fetchImpl,bearerToken=null;if(oauth){let token=await getAccessToken(oauth,tokenCache,{fetchImpl});if(!token.ok)return blank({error:token.error});bearerToken=token.accessToken}let values={...endpoint.queryParams??{},...pathParams??{}},resolved=resolvePath2(endpoint.path,values);if(resolved.missing.length>0)return blank({error:`This endpoint needs a value for ${resolved.missing.map((m)=>`{${m}}`).join(", ")}. Enter an example value to test it (e.g. ${resolved.missing[0]} = 12345).`});let query={};for(let[key2,value]of Object.entries(values)){if(value==null||resolved.used.has(key2))continue;query[key2]=value}let built=buildUrl(source.baseUrl,resolved.path,query);if(!built.ok)return blank({error:built.error});let{headers}=applyAuth({...source,token:bearerToken??source.token},built.url);if(bearerToken)headers.Authorization=`Bearer ${bearerToken}`;let outcome=await fetchOnce(source,{method:endpoint.method,url:built.url,headers,body:endpoint.method.toUpperCase()==="GET"?void 0:endpoint.requestBody??{}},{fetchImpl}),bodyKeys=outcome.body&&typeof outcome.body==="object"&&!Array.isArray(outcome.body)?Object.keys(outcome.body).slice(0,40):[];if(!outcome.ok)return blank({status:outcome.status,error:outcome.error??`HTTP ${outcome.status}`,bodyKeys,bodyPreview:previewBody(outcome.body)});let records=extractRecords(outcome.body,endpoint.responseRootPath);return{ok:!0,status:outcome.status,error:records.length===0?bodyKeys.length>0?`No record array was found. The response's top-level keys are: ${bodyKeys.join(", ")} \u2014 set the response root path to whichever holds the list.`:"No record array was found in the response.":null,recordCount:records.length,sample:records.slice(0,5),fields:records.length>0?flattenKeys(records[0]):[],bodyKeys,bodyPreview:previewBody(outcome.body)}}function blank(over){return{ok:!1,status:0,error:null,recordCount:0,sample:[],fields:[],bodyKeys:[],bodyPreview:null,...over}}function previewBody(body){if(body==null)return null;try{let text2=typeof body==="string"?body:JSON.stringify(body);return text2.length>PREVIEW_LIMIT?`${text2.slice(0,PREVIEW_LIMIT)}\u2026`:text2}catch{return null}}async function previewRun(chain,tokenCache,lookups,deps={}){let fetchImpl=deps.fetchImpl,{mapping,source,oauth}=chain,bearerToken=null;if(oauth){let token=await getAccessToken(oauth,tokenCache,{fetchImpl});if(!token.ok)return{ok:!1,error:token.error};bearerToken=token.accessToken}let root=chain.endpoints.find((e)=>e.id===chain.rootEndpointId);if(!root)return{ok:!1,error:"The endpoint this mapping reads no longer exists."};let parents={},entityValues={},externalCalls=0;for(let binding of root.paramBindings??[]){if(binding.from==="endpoint"&&!parents[binding.endpointId]){let parentSpec=chain.endpoints.find((e)=>e.id===binding.endpointId);if(!parentSpec)continue;let collected2=await collectEndpoint(source,parentSpec,{},{fetchImpl,bearerToken,maxConcurrent:deps.maxConcurrent,maxRecords:deps.maxRecords});if(externalCalls+=collected2.callCount,!collected2.ok)return{ok:!1,error:collected2.error};parents[binding.endpointId]=collected2.records.map((r)=>r.record)}if(binding.from==="entity"){let key2=`${binding.entity}.${binding.field}`;if(!entityValues[key2])entityValues[key2]=await lookups.readEntityColumn(binding.entity,binding.field)}}let collected=await collectEndpoint(source,root,{parents,entityValues},{fetchImpl,bearerToken,maxConcurrent:deps.maxConcurrent,maxRecords:deps.maxRecords});if(externalCalls+=collected.callCount,!collected.ok)return{ok:!1,error:collected.error};let mapped=buildMappedRecords(collected.records.map((r)=>r.record),mapping.fieldMappings,mapping.dedupTargetField,collected.records.map((r)=>r.parent)),existing=await lookups.readExistingRows(mapping.targetEntity),referenceValues=await loadReferenceValues(mapping.references??[],(entity,column)=>lookups.readEntityColumn(entity,column)),referenceIds=await loadReferenceIds(mapping.references??[],mapping.targetEntity,(entity,column)=>lookups.readEntityIdsBy(entity,column)),existingAccounts=mapping.accountRule?await lookups.readEntityIdsBy(mapping.accountRule.entity,mapping.accountRule.matchColumn):{},ops=planWrites({records:mapped.records,existing,dedupTargetField:mapping.dedupTargetField,writeMode:mapping.writeMode,missingPolicy:mapping.missingPolicy,missingColumn:mapping.missingColumn,missingValue:mapping.missingValue,requiredFields:lookups.requiredFields(mapping.targetEntity),uniqueFields:lookups.uniqueFields(mapping.targetEntity),createDefaults:mapping.passwordColumn?{[mapping.passwordColumn]:"\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022"}:{},accountRule:mapping.accountRule??null,existingAccounts,references:mapping.references??[],referenceValues,referenceIds,targetEntity:mapping.targetEntity});ops.issues.unshift(...mapped.issues);let invalid=lookups.validateRows?.(ops.creates)??[];for(let problem of invalid){let create3=ops.creates.find((c)=>c.sourceIndex===problem.sourceIndex);ops.issues.push({sourceIndex:problem.sourceIndex,kind:"invalid_value",message:problem.message,row:create3?.data})}if(invalid.length>0){let refused=new Set(invalid.map((problem)=>problem.sourceIndex));ops.creates=ops.creates.filter((create3)=>!refused.has(create3.sourceIndex))}return{ok:!0,externalCalls,plan:summarize(ops,{targetEntity:mapping.targetEntity,writeMode:mapping.writeMode,missingPolicy:mapping.missingPolicy,totalFetched:collected.records.length,reportedTotal:collected.reportedTotal,existingCount:existing.length,dedupConfigured:Boolean(mapping.dedupTargetField)})}}init_crypto();import{and as and16,eq as eq31,inArray as inArray11}from"drizzle-orm";var camel2=(s)=>s.replace(/_([a-z])/g,(_,l)=>l.toUpperCase());function tableFor(deps,entity){return deps.schemaTables[camel2(entity)]??null}var col8=(table,field)=>table?.[field]??table?.[camel2(field)];function open(deps,envelope,where){if(typeof envelope!=="string"||envelope==="")return"";let key2=deps.getEncryptionKey();if(!key2)return deps.logger.error("[Integrations] A stored credential cannot be read: no encryption key",{column:where}),"";try{return decryptSecret(envelope,key2)}catch{return deps.logger.error("[Integrations] A stored credential could not be decrypted \u2014 the encryption key has changed since it was saved. Re-enter it in the panel.",{column:where}),""}}async function resolveChain(deps,mappingId){let mappings=tableFor(deps,"integration_mappings"),endpoints=tableFor(deps,"integration_endpoints"),sources=tableFor(deps,"integration_sources");if(!mappings||!endpoints||!sources)return{ok:!1,error:"The integration tables are not present in this schema."};let[mappingRow]=await deps.db.select().from(mappings).where(eq31(col8(mappings,"id"),mappingId)).limit(1);if(!mappingRow)return{ok:!1,error:"This mapping no longer exists."};let row=mappingRow,[endpointRow]=await deps.db.select().from(endpoints).where(eq31(col8(endpoints,"id"),String(row.endpointId))).limit(1);if(!endpointRow)return{ok:!1,error:"The endpoint this mapping reads no longer exists."};let sourceId=String(endpointRow.sourceId),siblingRows=await deps.db.select().from(endpoints).where(eq31(col8(endpoints,"sourceId"),sourceId)),[sourceRow]=await deps.db.select().from(sources).where(eq31(col8(sources,"id"),sourceId)).limit(1);if(!sourceRow)return{ok:!1,error:"The source this mapping reads no longer exists."};let s=sourceRow;if(s.enabled===!1)return{ok:!1,error:"This source is switched off."};let authType=String(s.authType??"none"),source={id:String(s.id),baseUrl:String(s.baseUrl??""),authType,token:authType==="oauth2"?null:open(deps,s.authTokenEncrypted,"auth_token_encrypted"),authHeaderName:s.authHeaderName??null,authQueryParam:s.authQueryParam??null,extraHeaders:s.extraHeaders??null,tlsVerify:s.tlsVerify!==!1,timeoutMs:Number(s.timeoutMs??30000)},oauth=authType==="oauth2"?{sourceId:source.id,tokenUrl:String(s.tokenUrl??""),grantType:String(s.oauthGrantType??"password")==="client_credentials"?"client_credentials":"password",clientId:s.oauthClientId??null,clientSecret:open(deps,s.oauthClientSecretEncrypted,"oauth_client_secret_encrypted"),username:s.oauthUsername??null,password:open(deps,s.oauthPasswordEncrypted,"oauth_password_encrypted"),scope:s.oauthScope??null,clientAuth:String(s.oauthClientAuth??"basic")==="body"?"body":"basic",tlsVerify:source.tlsVerify,timeoutMs:source.timeoutMs}:null;return{ok:!0,chain:{mapping:toMappingSpec(row),endpoints:siblingRows.map((e)=>toEndpointSpec(e)),rootEndpointId:String(endpointRow.id),source,oauth}}}async function resolveEndpointContext(deps,by){let sources=tableFor(deps,"integration_sources"),endpoints=tableFor(deps,"integration_endpoints");if(!sources||!endpoints)return{ok:!1,error:"The integration tables are not present in this schema."};let endpointRow=null,sourceId=by.sourceId;if(by.endpointId){let[row]=await deps.db.select().from(endpoints).where(eq31(col8(endpoints,"id"),by.endpointId)).limit(1);if(!row)return{ok:!1,error:"This endpoint no longer exists."};endpointRow=row,sourceId=String(endpointRow.sourceId)}if(!sourceId)return{ok:!1,error:"No source was named."};let[sourceRow]=await deps.db.select().from(sources).where(eq31(col8(sources,"id"),sourceId)).limit(1);if(!sourceRow)return{ok:!1,error:"This source no longer exists."};let{source,oauth}=toConnection(deps,sourceRow);return{ok:!0,context:{source,oauth,endpoint:endpointRow?toEndpointSpec(endpointRow):null}}}async function cacheEndpointSample(deps,endpointId,records){let endpoints=tableFor(deps,"integration_endpoints");if(!endpoints||records.length===0)return;try{await deps.db.update(endpoints).set({sampleResponse:{records:records.slice(0,3)},updatedAt:new Date}).where(eq31(col8(endpoints,"id"),endpointId))}catch(error){deps.logger.warn("[Integrations] Could not cache the endpoint sample",{endpointId,error:error instanceof Error?error.message:String(error)})}}function toConnection(deps,s){let authType=String(s.authType??"none"),source={id:String(s.id),baseUrl:String(s.baseUrl??""),authType,token:authType==="oauth2"?null:open(deps,s.authTokenEncrypted,"auth_token_encrypted"),authHeaderName:s.authHeaderName??null,authQueryParam:s.authQueryParam??null,extraHeaders:s.extraHeaders??null,tlsVerify:s.tlsVerify!==!1,timeoutMs:Number(s.timeoutMs??30000)},oauth=authType==="oauth2"?{sourceId:source.id,tokenUrl:String(s.tokenUrl??""),grantType:String(s.oauthGrantType??"password")==="client_credentials"?"client_credentials":"password",clientId:s.oauthClientId??null,clientSecret:open(deps,s.oauthClientSecretEncrypted,"oauth_client_secret_encrypted"),username:s.oauthUsername??null,password:open(deps,s.oauthPasswordEncrypted,"oauth_password_encrypted"),scope:s.oauthScope??null,clientAuth:String(s.oauthClientAuth??"basic")==="body"?"body":"basic",tlsVerify:source.tlsVerify,timeoutMs:source.timeoutMs}:null;return{source,oauth}}function toMappingSpec(row){return{id:String(row.id),name:String(row.name??""),targetEntity:String(row.targetEntity??""),fieldMappings:Array.isArray(row.fieldMappings)?row.fieldMappings:[],references:Array.isArray(row.referenceChecks)?row.referenceChecks:[],dedupTargetField:row.dedupTargetField||null,writeMode:String(row.writeMode??"upsert")??"upsert",missingPolicy:String(row.missingRecordPolicy??"ignore")??"ignore",missingColumn:row.missingRecordColumn??null,missingValue:row.missingRecordValue??null,passwordColumn:row.passwordTargetColumn||null,accountRule:row.accountRule??null}}function toEndpointSpec(row){let pagination=row.pagination;return{id:String(row.id),method:String(row.method??"GET"),path:String(row.path??""),queryParams:row.queryParams??null,requestBody:row.requestBody??null,responseRootPath:row.responseRootPath||null,treeChildrenPath:row.treeChildrenPath||null,pagination:pagination&&typeof pagination==="object"&&"kind"in pagination?pagination:{kind:"none"},paramBindings:Array.isArray(row.paramBindings)?row.paramBindings:null}}async function readConnectionBundle(deps,sourceId){let sources=tableFor(deps,"integration_sources"),endpoints=tableFor(deps,"integration_endpoints"),mappings=tableFor(deps,"integration_mappings");if(!sources||!endpoints||!mappings)return null;let[sourceRow]=await deps.db.select().from(sources).where(eq31(col8(sources,"id"),sourceId)).limit(1);if(!sourceRow)return null;let endpointRows=await deps.db.select().from(endpoints).where(eq31(col8(endpoints,"sourceId"),sourceId)),ids=new Set(endpointRows.map((row)=>String(row.id))),allMappings=await deps.db.select().from(mappings);return{source:sourceRow,endpoints:endpointRows,mappings:allMappings.filter((row)=>ids.has(String(row.endpointId)))}}async function applyTransferDocument(deps,document2,userId){let sources=tableFor(deps,"integration_sources"),endpoints=tableFor(deps,"integration_endpoints"),mappings=tableFor(deps,"integration_mappings");if(!sources||!endpoints||!mappings)return{ok:!1,error:"The integration tables are not present in this schema."};return deps.db.transaction(async(tx)=>{let now=new Date,c=document2.connection,connectionValues={name:c.name,slug:c.slug,baseUrl:c.baseUrl,description:c.description??null,authType:c.authType,authHeaderName:c.authHeaderName??null,authQueryParam:c.authQueryParam??null,extraHeaders:c.extraHeaders??null,tokenUrl:c.tokenUrl??null,oauthGrantType:c.oauthGrantType??null,oauthClientId:c.oauthClientId??null,oauthUsername:c.oauthUsername??null,oauthScope:c.oauthScope??null,oauthClientAuth:c.oauthClientAuth??null,tlsVerify:c.tlsVerify!==!1,timeoutMs:c.timeoutMs??null,enabled:c.enabled!==!1,updatedAt:now,updatedBy:userId},[existingSource]=await tx.select().from(sources).where(eq31(col8(sources,"slug"),c.slug)).limit(1),sourceId,created=!1;if(existingSource)sourceId=String(existingSource.id),await tx.update(sources).set(connectionValues).where(eq31(col8(sources,"id"),sourceId));else{let[row]=await tx.insert(sources).values({...connectionValues,createdAt:now,createdBy:userId}).returning();if(!row?.id)return{ok:!1,error:"The connection could not be created."};sourceId=String(row.id),created=!0}let existingEndpoints=await tx.select().from(endpoints).where(eq31(col8(endpoints,"sourceId"),sourceId)),endpointIdByName=new Map;for(let row of existingEndpoints)endpointIdByName.set(String(row.name),String(row.id));for(let endpoint of document2.endpoints){let values={sourceId,name:endpoint.name,tag:endpoint.tag,method:endpoint.method,path:endpoint.path,description:endpoint.description??null,queryParams:endpoint.queryParams??null,requestBody:endpoint.requestBody??null,responseRootPath:endpoint.responseRootPath??null,treeChildrenPath:endpoint.treeChildrenPath??null,pagination:endpoint.pagination??null,enabled:endpoint.enabled!==!1,updatedAt:now,updatedBy:userId},existingId=endpointIdByName.get(endpoint.name);if(existingId)await tx.update(endpoints).set(values).where(eq31(col8(endpoints,"id"),existingId));else{let[row]=await tx.insert(endpoints).values({...values,paramBindings:[],createdAt:now,createdBy:userId}).returning();if(row?.id)endpointIdByName.set(endpoint.name,String(row.id))}}for(let endpoint of document2.endpoints){let id=endpointIdByName.get(endpoint.name);if(!id)continue;let bindings=(endpoint.paramBindings??[]).map((binding)=>{if(binding.from!=="endpoint")return binding;let{endpointName,...rest}=binding;return{...rest,endpointId:endpointIdByName.get(String(endpointName))??""}});await tx.update(endpoints).set({paramBindings:bindings,updatedAt:now}).where(eq31(col8(endpoints,"id"),id))}let allMappings=await tx.select().from(mappings),ownIds=new Set(endpointIdByName.values()),mappingIdByName=new Map;for(let row of allMappings)if(ownIds.has(String(row.endpointId)))mappingIdByName.set(String(row.name),String(row.id));let mappingCount=0;for(let mapping of document2.mappings){let endpointId=mapping.endpointName?endpointIdByName.get(mapping.endpointName):void 0;if(!endpointId)continue;let values={endpointId,name:mapping.name,targetEntity:mapping.targetEntity,fieldMappings:mapping.fieldMappings??[],referenceChecks:mapping.referenceChecks??[],dedupSourceField:mapping.dedupSourceField??null,dedupTargetField:mapping.dedupTargetField??null,writeMode:mapping.writeMode,missingRecordPolicy:mapping.missingRecordPolicy,missingRecordColumn:mapping.missingRecordColumn??null,missingRecordValue:mapping.missingRecordValue??null,passwordTargetColumn:mapping.passwordTargetColumn??null,accountRule:mapping.accountRule??null,scheduleEnabled:mapping.scheduleEnabled===!0,scheduleCron:mapping.scheduleCron??null,scheduleTimezone:mapping.scheduleTimezone??null,enabled:mapping.enabled!==!1,updatedAt:now,updatedBy:userId},existingId=mappingIdByName.get(mapping.name);if(existingId)await tx.update(mappings).set(values).where(eq31(col8(mappings,"id"),existingId));else await tx.insert(mappings).values({...values,createdAt:now,createdBy:userId});mappingCount++}return{ok:!0,sourceId,created,endpoints:endpointIdByName.size,mappings:mappingCount}})}async function readScheduledMappings(deps){let mappings=tableFor(deps,"integration_mappings");if(!mappings)return[];return(await deps.db.select().from(mappings)).filter((row)=>row.scheduleEnabled===!0&&row.enabled!==!1).filter((row)=>typeof row.scheduleCron==="string"&&row.scheduleCron.trim()!=="").map((row)=>({id:String(row.id),name:String(row.name??""),scheduleCron:String(row.scheduleCron),scheduleTimezone:row.scheduleTimezone??null,lastRunAt:row.lastRunAt?new Date(row.lastRunAt):null,needsPassword:Boolean(row.passwordTargetColumn)||row.accountRule!=null}))}function requiredFieldsOf(entities,targetEntity){return(entities.find((e)=>e.table_name===targetEntity)?.columns??[]).filter((c)=>c.notNull===!0&&c.default===void 0&&!c.defaultRaw&&!c.nullable).map((c)=>camel2(c.name))}function uniqueFieldsOf(entities,targetEntity){let entity=entities.find((e)=>e.table_name===targetEntity),columns=entity?.columns??[],fields=new Set;for(let column of columns)if(column.unique===!0||column.primaryKey===!0)fields.add(camel2(column.name));for(let index of entity?.indexes??[])if(index.unique===!0&&index.columns.length===1&&index.columns[0])fields.add(camel2(index.columns[0]));return fields.delete("id"),[...fields]}function createRunRepository(deps,entities){let runs=()=>tableFor(deps,"integration_runs"),runItems=()=>tableFor(deps,"integration_run_items");return{async openRun(input){let table=runs();if(!table)return{ok:!1,error:"integration_runs is missing from this schema."};try{let id=(await deps.db.insert(table).values({mappingId:input.mappingId,targetEntity:input.targetEntity,writeMode:input.writeMode,trigger:input.trigger,status:"running",startedAt:new Date,createdBy:input.userId}).returning())[0]?.id;return id?{ok:!0,runId:String(id)}:{ok:!1,error:"The run record was created but returned no identifier."}}catch(error){return{ok:!1,error:error instanceof Error?error.message:String(error)}}},async closeRun(runId,patch){let table=runs();if(!table)return{ok:!1,error:"integration_runs is missing from this schema."};try{let mappingId=(await deps.db.update(table).set({...patch,updatedAt:new Date}).where(eq31(col8(table,"id"),runId)).returning())[0]?.mappingId,finishedAt=patch.finishedAt,mappings=tableFor(deps,"integration_mappings");if(mappings&&mappingId&&finishedAt)await deps.db.update(mappings).set({lastRunAt:finishedAt,updatedAt:new Date}).where(eq31(col8(mappings,"id"),String(mappingId)));return{ok:!0}}catch(error){return deps.logger.error("[Integrations] Could not close the run record",{runId,error:error instanceof Error?error.message:String(error)}),{ok:!1,error:"Could not write the run record."}}},async savePreImages(runId,images){let table=runItems();if(!table||images.length===0)return;let CHUNK2=500;try{for(let i=0;i<images.length;i+=CHUNK2)await deps.db.insert(table).values(images.slice(i,i+CHUNK2).map((image)=>({runId,targetEntity:image.targetEntity,rowId:image.rowId,action:image.action,before:image.before,after:image.after})))}catch(error){deps.logger.error("[Integrations] The run succeeded but its before-images could not be stored; it cannot be undone",{runId,error:error instanceof Error?error.message:String(error)})}},async isCancelRequested(runId){let table=runs();if(!table)return!1;try{let[row]=await deps.db.select().from(table).where(eq31(col8(table,"id"),runId)).limit(1);return row?.cancelRequested===!0}catch{return!1}},async readExistingRows(targetEntity){let table=tableFor(deps,targetEntity);if(!table)return[];return(await deps.db.select().from(table)).map((row)=>({id:String(row.id),row}))},async readEntityColumn(entity,field){let table=tableFor(deps,entity),column=table?col8(table,field):void 0;if(!table||!column)return[];return(await deps.db.selectDistinct({v:column}).from(table)).map((r)=>r.v).filter((v)=>v!=null&&v!=="")},async readEntityIdsBy(entity,field){let table=tableFor(deps,entity),column=table?col8(table,field):void 0,idColumn=table?col8(table,"id"):void 0;if(!table||!column||!idColumn)return{};let rows=await deps.db.select({v:column,id:idColumn}).from(table),map={};for(let row of rows){if(row.v==null||row.v===""||row.id==null)continue;let key2=String(row.v).trim();if(!map[key2])map[key2]=String(row.id)}return map},requiredFields:(targetEntity)=>requiredFieldsOf(entities,targetEntity),uniqueFields:(targetEntity)=>uniqueFieldsOf(entities,targetEntity)}}async function readRowsById(deps,targetEntity,ids){let table=tableFor(deps,targetEntity),result=new Map;if(!table||ids.length===0)return result;let CHUNK2=1000;for(let i=0;i<ids.length;i+=CHUNK2){let rows=await deps.db.select().from(table).where(inArray11(col8(table,"id"),ids.slice(i,i+CHUNK2)));for(let row of rows)result.set(String(row.id),row)}return result}async function readPreImages(deps,runId){let table=tableFor(deps,"integration_run_items");if(!table)return[];return(await deps.db.select().from(table).where(eq31(col8(table,"runId"),runId))).map((row)=>({targetEntity:String(row.targetEntity),rowId:row.rowId?String(row.rowId):null,action:String(row.action),before:row.before??null,after:row.after??null}))}async function readRun(deps,runId){let table=tableFor(deps,"integration_runs");if(!table)return null;let[row]=await deps.db.select().from(table).where(eq31(col8(table,"id"),runId)).limit(1);return row??null}async function requestCancel(deps,runId){let table=tableFor(deps,"integration_runs");if(!table)return!1;return(await deps.db.update(table).set({cancelRequested:!0,updatedAt:new Date}).where(and16(eq31(col8(table,"id"),runId),eq31(col8(table,"status"),"running"))).returning()).length>0}var fail3=(set,status,message)=>{return set.status=status,{isSuccess:!1,message,data:null}};function createInspectRoutes(routeConfig,deps,tokenCache){let plugin=new Elysia12,settings=routeConfig.resolvedOptions.integrations??{};return plugin.post("/sources/:id/test",async({params,set})=>{let repoDeps=deps();if(!repoDeps)return fail3(set,503,"The database is not available.");let context=await resolveEndpointContext(repoDeps,{sourceId:params.id});if(!context.ok)return fail3(set,404,context.error);let result=await testConnection(context.context,tokenCache);return{isSuccess:result.ok,message:result.ok?result.detail??"Connected.":result.error??"Could not connect.",data:result}},{detail:{tags:["Integrations"],summary:"Check a source is reachable and its credentials are accepted"}}),plugin.post("/endpoints/:id/sample",async({params,body,set})=>{let repoDeps=deps();if(!repoDeps)return fail3(set,503,"The database is not available.");let context=await resolveEndpointContext(repoDeps,{endpointId:params.id});if(!context.ok)return fail3(set,404,context.error);let{source,oauth,endpoint}=context.context;if(!endpoint)return fail3(set,404,"This endpoint no longer exists.");let result=await sampleEndpoint(source,endpoint,body?.pathParams,tokenCache,oauth);if(result.ok&&result.sample.length>0)await cacheEndpointSample(repoDeps,params.id,result.sample);return{isSuccess:result.ok,message:result.error??"Sampled.",data:result}},{body:t10.Optional(t10.Object({pathParams:t10.Optional(t10.Record(t10.String(),t10.Unknown()))})),detail:{tags:["Integrations"],summary:"Call one endpoint once and report its real shape"}}),plugin.post("/preview",async({body,set})=>{let repoDeps=deps();if(!repoDeps)return fail3(set,503,"The database is not available.");let chain=await resolveChain(repoDeps,body.mappingId);if(!chain.ok)return fail3(set,404,chain.error);let repo=createRunRepository(repoDeps,repoDeps.entities),result=await previewRun(chain.chain,tokenCache,{readExistingRows:repo.readExistingRows,readEntityColumn:repo.readEntityColumn,requiredFields:repo.requiredFields,uniqueFields:repo.uniqueFields,readEntityIdsBy:repo.readEntityIdsBy,validateRows:(rows)=>{let columns=repoDeps.entities.find((e)=>e.table_name===chain.chain.mapping.targetEntity)?.columns??[],problems=[];for(let row of rows){let result2=validatePayload(row.data,columns,!1);if(!result2.valid)problems.push({sourceIndex:row.sourceIndex,message:result2.errors.map((e)=>`${e.field}: ${e.message}`).join("; ")})}return problems}},{maxRecords:settings.maxRecordsPerRun,maxConcurrent:settings.maxConcurrentFanout});if(!result.ok)return fail3(set,422,result.error);return{isSuccess:!0,message:"Nothing was written.",data:{plan:result.plan,externalCalls:result.externalCalls}}},{body:t10.Object({mappingId:t10.String()}),detail:{tags:["Integrations"],summary:"Dry-run an import: counts, warnings and a sample, with no writes"}}),plugin}var fail4=(set,status,message)=>{return set.status=status,{isSuccess:!1,message,data:null}},tokenCache=new TokenCache;function createIntegrationRoutes(routeConfig){let{logger:logger2,basePath,db,schemaTables,resolvedOptions,getEncryptionKey,getLockStore,publish}=routeConfig,plugin=new Elysia13({prefix:basePath}),entities=resolvedOptions.entities??[],settings=resolvedOptions.integrations??{},topicPrefix=settings.realtimeTopicPrefix||"integrations",guard2=createGodminGuard2({logger:logger2,db,schemaTables,area:"data integrations",allowedRoles:routeConfig.adminRoles??settings.adminRoles});plugin.onBeforeHandle(guard2);let deps=()=>db?{db,schemaTables,entities,logger:logger2,getEncryptionKey}:null;plugin.use(createInspectRoutes(routeConfig,deps,tokenCache));let writerFor=(repoDeps,targetEntity)=>{let table=tableFor(repoDeps,targetEntity);if(!table)return null;let entity=entities.find((e)=>e.table_name===targetEntity);return{db:repoDeps.db,drizzleTable:table,resolveCol:(field)=>table[field]??table[field.replace(/_([a-z])/g,(_m,l)=>l.toUpperCase())],columns:entity?.columns??[],logger:logger2,validatePayload,resolveEntity:(name2)=>{let refTable=tableFor(repoDeps,name2);if(!refTable)return null;let refEntity=entities.find((e)=>e.table_name===name2);return{table:refTable,columns:refEntity?.columns??[]}}}};plugin.post("/runs",async({body,set,request})=>{let repoDeps=deps();if(!repoDeps)return fail4(set,503,"The database is not available.");let chain=await resolveChain(repoDeps,body.mappingId);if(!chain.ok)return fail4(set,404,chain.error);let declared=chain.chain.mapping,answer=body.referenceMode,mapping=answer?{...declared,references:(declared.references??[]).map((check)=>check.onMissing==="ignore"?check:{...check,onMissing:answer})}:declared,wantsPassword=Boolean(mapping.passwordColumn||mapping.accountRule),createDefaults,accountPasswordHash=null;if(wantsPassword){let supplied=typeof body.sharedPassword==="string"?body.sharedPassword:"";if(supplied.length<8)return fail4(set,422,mapping.accountRule?"This import creates a login for every new record, so it needs a password to create them with: send sharedPassword, at least 8 characters. It is used once, for this run, and is stored nowhere.":`This mapping writes a password into "${mapping.passwordColumn}", so it needs one to write: send sharedPassword, at least 8 characters. It is used for the accounts this run creates and is not stored anywhere.`);let hash=await hashPassword(supplied);if(accountPasswordHash=hash,mapping.passwordColumn)createDefaults={[mapping.passwordColumn]:hash}}if((mapping.writeMode==="replace"||mapping.missingPolicy==="delete")&&body.confirm!==!0)return set.status=428,{isSuccess:!1,message:mapping.writeMode==="replace"?"This mapping rebuilds the whole table. Send confirm: true to proceed.":"This mapping deletes records the source no longer carries. Send confirm: true to proceed.",data:null};let lockStore=getLockStore();if(!lockStore)return fail4(set,503,"The lock service is unavailable, so a second run of this mapping could not be prevented. Runs are refused until it is back.");let lock=await acquireRunLock(lockStore,mapping.id,{logger:logger2});if(!lock.ok){if(lock.reason==="unavailable")return fail4(set,503,`The lock service is unavailable: ${lock.error}`);return set.status=409,{isSuccess:!1,message:"This mapping is already importing. Wait for it to finish, or cancel it.",data:{heldSince:lock.heldSince}}}let writer=writerFor(repoDeps,mapping.targetEntity);if(!writer)return await lock.handle.release(),fail4(set,422,`This mapping targets "${mapping.targetEntity}", which does not exist.`);let userId=request.headers.get("x-user-id")??"unknown",repo=createRunRepository(repoDeps,entities),announce=()=>{},runIdReady=new Promise((resolve2)=>{announce=resolve2}),started=executeRun({...chain.chain,mapping,userId,trigger:"manual",createDefaults,accountPasswordHash},{repo,writer,logger:logger2,tokenCache,publishProgress:(progress)=>publish?.(`${topicPrefix}.run`,progress),onRunOpened:(id)=>announce(id),maxRecordsPerRun:settings.maxRecordsPerRun,maxConcurrentFanout:settings.maxConcurrentFanout,retainPreImagesMs:parseDuration(settings.retainPreImagesFor)},lock.handle),runId=await Promise.race([runIdReady,started.then((outcome)=>outcome.runId)]);return started.catch((error)=>{logger2.error("[Integrations] Run threw outside its own error handling",{mappingId:mapping.id,error:error instanceof Error?error.message:String(error)})}).finally(()=>lock.handle.release()),set.status=202,{isSuccess:!0,message:"The import has started.",data:{runId,mappingId:mapping.id,targetEntity:mapping.targetEntity}}},{body:t11.Object({mappingId:t11.String(),confirm:t11.Optional(t11.Boolean()),sharedPassword:t11.Optional(t11.String()),referenceMode:t11.Optional(t11.Union([t11.Literal("create"),t11.Literal("skipRecord")]))}),detail:{tags:["Integrations"],summary:"Start an import; answers 202 with the run identifier"}});let startScheduledRun=async(mappingId)=>{let repoDeps=deps();if(!repoDeps)return!1;let chain=await resolveChain(repoDeps,mappingId);if(!chain.ok)return logger2.error(`[Integrations] Scheduled import cannot run: ${chain.error}`),!1;let lockStore=getLockStore();if(!lockStore)return!1;let lock=await acquireRunLock(lockStore,mappingId,{logger:logger2});if(!lock.ok)return!1;let writer=writerFor(repoDeps,chain.chain.mapping.targetEntity);if(!writer)return await lock.handle.release(),logger2.error(`[Integrations] Scheduled import targets "${chain.chain.mapping.targetEntity}", which does not exist.`),!1;return executeRun({...chain.chain,userId:"schedule",trigger:"schedule"},{repo:createRunRepository(repoDeps,entities),writer,logger:logger2,tokenCache,publishProgress:(progress)=>publish?.(`${topicPrefix}.run`,progress),maxRecordsPerRun:settings.maxRecordsPerRun,maxConcurrentFanout:settings.maxConcurrentFanout,retainPreImagesMs:parseDuration(settings.retainPreImagesFor)},lock.handle).then((outcome)=>{if(outcome.status!=="succeeded")logger2.error(`[Integrations] Scheduled import "${chain.chain.mapping.name}" ${outcome.status}: ${outcome.failure?.message??"no reason recorded"}`)}).catch((error)=>{logger2.error("[Integrations] Scheduled import threw outside its own error handling",{mappingId,error:error instanceof Error?error.message:String(error)})}).finally(()=>lock.handle.release()),!0},unattendable=new Set;if(settings.schedulesEnabled!==!1)startScheduler({logger:logger2,listScheduled:async()=>{let repoDeps=deps();if(!repoDeps)return[];return(await readScheduledMappings(repoDeps)).filter((row)=>{if(!row.needsPassword)return!0;if(!unattendable.has(row.id))unattendable.add(row.id),logger2.error(`[Integrations] "${row.name}" is scheduled but creates logins, which need a password nobody can type at that hour. It will not run on its own \u2014 start it by hand, or turn the login off.`);return!1})},startRun:(mappingId)=>startScheduledRun(mappingId)});return plugin.get("/sources/:id/export",async({params,set})=>{let repoDeps=deps();if(!repoDeps)return fail4(set,503,"The database is not available.");let bundle=await readConnectionBundle(repoDeps,params.id);if(!bundle)return fail4(set,404,"This connection no longer exists.");let document2=buildTransferDocument({...bundle,exportedAt:new Date().toISOString()});return{isSuccess:!0,message:`${document2.endpoints.length} call(s) and ${document2.mappings.length} mapping(s). Credentials are NOT included \u2014 they are asked for again on the other side.`,data:document2}},{detail:{tags:["Integrations"],summary:"Export a connection, its calls and its mappings \u2014 without any secret"}}),plugin.post("/import",async({body,set,request})=>{let repoDeps=deps();if(!repoDeps)return fail4(set,503,"The database is not available.");let checked=validateTransferDocument(body?.document);if(!checked.ok||!checked.document)return set.status=422,{isSuccess:!1,message:"This file cannot be imported as it stands.",data:{problems:checked.problems}};let userId=request.headers.get("x-user-id")??"unknown",result=await applyTransferDocument(repoDeps,checked.document,userId);if(!result.ok)return fail4(set,422,result.error);return{isSuccess:!0,message:`Connection "${checked.document.connection.name}" is here: ${result.endpoints} call(s) and ${result.mappings} mapping(s). Its credentials are not \u2014 enter them before running anything.`,data:result}},{body:t11.Object({document:t11.Unknown()}),detail:{tags:["Integrations"],summary:"Bring in an exported connection; re-running it updates rather than duplicates"}}),plugin.post("/runs/:id/cancel",async({params,set})=>{let repoDeps=deps();if(!repoDeps)return fail4(set,503,"The database is not available.");if(!await requestCancel(repoDeps,params.id))return fail4(set,409,"This run is not running, so there is nothing to cancel.");return{isSuccess:!0,message:"Cancellation requested. The import stops at its next checkpoint and anything it had written is rolled back.",data:{runId:params.id}}},{detail:{tags:["Integrations"],summary:"Ask a running import to stop"}}),plugin.post("/runs/:id/revert",async({params,body,set,request})=>{let repoDeps=deps();if(!repoDeps)return fail4(set,503,"The database is not available.");let run=await readRun(repoDeps,params.id);if(!run)return fail4(set,404,"This run no longer exists.");if(run.status!=="succeeded")return fail4(set,409,`Only a run that finished successfully can be undone; this one is "${String(run.status)}".`);let expiry=run.preImagesExpireAt?new Date(String(run.preImagesExpireAt)):null;if(expiry&&expiry.getTime()<Date.now())return fail4(set,410,"This run is too old to undo: the records of what it replaced have been cleared.");let targetEntity=String(run.targetEntity??""),preImages=await readPreImages(repoDeps,params.id);if(preImages.length===0)return fail4(set,410,"There is no record of what this run replaced, so it cannot be undone.");let groups=groupPreImagesByEntity(preImages).sort((a,b)=>a.targetEntity===targetEntity?-1:b.targetEntity===targetEntity?1:0),planned=[];for(let group of groups){let current=await readRowsById(repoDeps,group.targetEntity,touchedRowIds(group.preImages));planned.push({targetEntity:group.targetEntity,ops:planRevert({preImages:group.preImages,current,force:body?.force===!0})})}let ops={deletes:planned.flatMap((p)=>p.ops.deletes),restores:planned.flatMap((p)=>p.ops.restores),reinserts:planned.flatMap((p)=>p.ops.reinserts),conflicts:planned.flatMap((p)=>p.ops.conflicts)};if(ops.deletes.length===0&&ops.restores.length===0&&ops.reinserts.length===0&&ops.conflicts.length>0)return set.status=409,{isSuccess:!1,message:"Every record this run touched has been edited since. Undoing would discard those edits; send force: true to overwrite them anyway.",data:{conflicts:ops.conflicts}};let userId=request.headers.get("x-user-id")??"unknown",undone={deleted:0,restored:0,reinserted:0};for(let group of planned){let groupWriter=writerFor(repoDeps,group.targetEntity);if(!groupWriter)return fail4(set,422,`"${group.targetEntity}" no longer exists.`);let result2=await applyRevert(groupWriter,group.ops,{targetEntity:group.targetEntity,userId});if(!result2.ok)return fail4(set,500,result2.error);undone={deleted:undone.deleted+(result2.deleted??0),restored:undone.restored+(result2.restored??0),reinserted:undone.reinserted+(result2.reinserted??0)}}let result={ok:!0,...undone,conflicts:ops.conflicts.length},runsTable=tableFor(repoDeps,"integration_runs");if(runsTable){let{eq:eq32}=await import("drizzle-orm");await repoDeps.db.update(runsTable).set({status:"reverted",revertedAt:new Date,revertedBy:userId}).where(eq32(runsTable.id,params.id))}return{isSuccess:!0,message:"The import was undone.",data:{deleted:result.deleted,restored:result.restored,reinserted:result.reinserted,conflicts:ops.conflicts}}},{body:t11.Optional(t11.Object({force:t11.Optional(t11.Boolean())})),detail:{tags:["Integrations"],summary:"Undo a run that succeeded"}}),plugin.put("/sources/:id/credentials",async({params,body,set})=>{let repoDeps=deps();if(!repoDeps)return fail4(set,503,"The database is not available.");let key2=getEncryptionKey();if(!key2)return fail4(set,503,"No encryption key is configured, so a credential stored now could never be read back.");let table=tableFor(repoDeps,"integration_sources");if(!table)return fail4(set,503,"The integration tables are not present in this schema.");let patch={},hints={},apply=(value,column,hintColumn,name2)=>{if(value===void 0)return;let trimmed=value.trim();if(trimmed===""){patch[column]=null,patch[hintColumn]=null,hints[name2]=null;return}patch[column]=encryptSecret(trimmed,key2),patch[hintColumn]=previewOf(trimmed),hints[name2]=previewOf(trimmed)};if(apply(body.token,"authTokenEncrypted","authTokenHint","token"),apply(body.oauthClientSecret,"oauthClientSecretEncrypted","oauthClientSecretHint","clientSecret"),apply(body.oauthPassword,"oauthPasswordEncrypted","oauthPasswordHint","password"),Object.keys(patch).length===0)return{isSuccess:!0,message:"Nothing to change.",data:{hints}};let{eq:eq32}=await import("drizzle-orm");return await repoDeps.db.update(table).set({...patch,updatedAt:new Date}).where(eq32(table.id,params.id)),tokenCache.invalidate(params.id),{isSuccess:!0,message:"Saved.",data:{hints}}},{body:t11.Object({token:t11.Optional(t11.String()),oauthClientSecret:t11.Optional(t11.String()),oauthPassword:t11.Optional(t11.String())}),detail:{tags:["Integrations"],summary:"Store a source credential; only a masked preview is returned"}}),logger2.info(`[Integrations] Routes enabled at ${basePath}`),plugin}function parseDuration(value){if(!value)return;let match=value.trim().match(/^(\d+)\s*([smhd])$/i);if(!match)return;let amount=Number(match[1]),unit=(match[2]??"d").toLowerCase();return amount*(unit==="s"?1000:unit==="m"?60000:unit==="h"?3600000:86400000)}init_adminGuard();import Elysia14,{t as t12}from"elysia";function parseTimeToMs2(time2){let match=time2.match(/^(\d+)(ms|s|m|h)$/);if(!match||!match[1]||!match[2])return 5000;let value=parseInt(match[1],10);switch(match[2]){case"ms":return value;case"s":return value*1000;case"m":return value*60*1000;case"h":return value*60*60*1000;default:return 5000}}function createMonitoringRoutes(config){let{monitoringService,logger:logger2,endpoints,db,schemaTables}=config,plugin=new Elysia14({prefix:endpoints.basePath});if(plugin.onBeforeHandle(createGodminGuard({db:db??null,schemaTables:schemaTables??{},logger:logger2},"monitoring")),!endpoints.enabled)return plugin;if(endpoints.stream.enabled)plugin.get(endpoints.stream.path,async function*({request}){logger2.info("[Monitoring] SSE stream connected");let intervalMs=parseTimeToMs2(endpoints.stream.interval),isConnected=!0;request.signal.addEventListener("abort",()=>{isConnected=!1,logger2.info("[Monitoring] SSE stream disconnected")});let initialSnapshot=await monitoringService.getLatestSnapshot();if(initialSnapshot)yield{event:"snapshot",data:JSON.stringify(initialSnapshot)};while(isConnected){if(await new Promise((resolve2)=>setTimeout(resolve2,intervalMs)),!isConnected)break;let snapshot=await monitoringService.getLatestSnapshot();if(snapshot)yield{event:"snapshot",data:JSON.stringify(snapshot)};let alerts=monitoringService.getActiveAlerts();if(alerts.length>0)yield{event:"alerts",data:JSON.stringify(alerts)}}},{detail:{tags:["Monitoring"],summary:"Stream real-time monitoring data",description:"Server-Sent Events stream for real-time monitoring metrics"}});if(endpoints.snapshot.enabled)plugin.get(endpoints.snapshot.path,async()=>{let snapshot=await monitoringService.getLatestSnapshot();if(!snapshot)return{isSuccess:!1,message:"No monitoring data available",data:null};return{isSuccess:!0,message:"Current monitoring snapshot",data:snapshot}},{detail:{tags:["Monitoring"],summary:"Get current monitoring snapshot",description:"Returns the latest monitoring metrics snapshot"}});if(endpoints.history.enabled)plugin.get(endpoints.history.path,async({query})=>{let minutes=Math.min(query.minutes?parseInt(String(query.minutes),10):60,endpoints.history.maxMinutes),history=await monitoringService.getHistory(minutes);return{isSuccess:!0,message:`Monitoring history for last ${minutes} minutes`,data:{minutes,count:history.length,snapshots:history}}},{query:t12.Object({minutes:t12.Optional(t12.Numeric())}),detail:{tags:["Monitoring"],summary:"Get monitoring history",description:"Returns historical monitoring data for the specified time range"}});if(endpoints.alerts.enabled)plugin.get(endpoints.alerts.path,()=>{let alerts=monitoringService.getActiveAlerts();return{isSuccess:!0,message:"Active alerts",data:{count:alerts.length,alerts}}},{detail:{tags:["Monitoring"],summary:"Get active alerts",description:"Returns all currently active monitoring alerts"}}),plugin.post(`${endpoints.alerts.path}/:alertId/acknowledge`,({params})=>{if(!monitoringService.acknowledgeAlert(params.alertId))return{isSuccess:!1,message:"Alert not found",data:null};return{isSuccess:!0,message:"Alert acknowledged",data:{alertId:params.alertId}}},{params:t12.Object({alertId:t12.String()}),detail:{tags:["Monitoring"],summary:"Acknowledge an alert",description:"Mark an alert as acknowledged"}});return logger2.info(`[Monitoring] Routes enabled at ${endpoints.basePath} (stream: ${endpoints.stream.enabled}, snapshot: ${endpoints.snapshot.enabled}, history: ${endpoints.history.enabled}, alerts: ${endpoints.alerts.enabled})`),plugin}init_adminGuard();import Elysia15,{t as t13}from"elysia";var STREAM_HEADERS={"Content-Type":"text/event-stream; charset=utf-8","Cache-Control":"no-cache, no-transform",Connection:"keep-alive"},textEncoder=new TextEncoder,encodeEvent=(event,data)=>{let payload=typeof data==="string"?data:JSON.stringify(data);return textEncoder.encode(`event: ${event}
|
|
529
|
+
`)};var handleListCohorts=(db,usersTable,cohortsTable)=>async(ctx)=>{let userId=ctx.request.headers.get("x-user-id");if(!userId||!await requireGodmin(db,usersTable,userId))return ctx.set.status=403,{success:!1,message:"Forbidden"};let rows=await db.select().from(cohortsTable);return{success:!0,data:{items:rows,meta:{totalItems:rows.length}}}};import{eq as eq26}from"drizzle-orm";var handleDeleteCohort=(db,usersTable,cohortsTable,logger2)=>async(ctx)=>{let userId=ctx.request.headers.get("x-user-id");if(!userId||!await requireGodmin(db,usersTable,userId))return ctx.set.status=403,{success:!1,message:"Forbidden"};return await db.update(usersTable).set({cohortId:null,updatedAt:new Date}).where(eq26(col7(usersTable,"cohortId"),ctx.params.id)),await db.delete(cohortsTable).where(eq26(col7(cohortsTable,"id"),ctx.params.id)),logger2.audit({entityName:"user_cohorts",entityId:ctx.params.id,operation:"COHORT_DELETE",userId,summary:`Deleted cohort ${ctx.params.id}`}),{success:!0,data:null}};import{eq as eq27}from"drizzle-orm";var handleUpdateCohort=(db,usersTable,cohortsTable)=>async(ctx)=>{let userId=ctx.request.headers.get("x-user-id");if(!userId||!await requireGodmin(db,usersTable,userId))return ctx.set.status=403,{success:!1,message:"Forbidden"};let updates={updatedAt:new Date};if(ctx.body.name!==void 0)updates.name=ctx.body.name;if(ctx.body.description!==void 0)updates.description=ctx.body.description;if(ctx.body.expiresAt!==void 0)updates.expiresAt=ctx.body.expiresAt?new Date(ctx.body.expiresAt):null;if(ctx.body.metadata!==void 0)updates.metadata=ctx.body.metadata;if(ctx.body.isActive!==void 0)updates.isActive=ctx.body.isActive;let updated=await db.update(cohortsTable).set(updates).where(eq27(col7(cohortsTable,"id"),ctx.params.id)).returning();if(updated.length===0)return ctx.set.status=404,{success:!1,message:"Cohort not found"};return{success:!0,data:updated[0]}};import{t}from"elysia";var CohortBodySchema=t.Object({name:t.String({minLength:1,maxLength:255}),description:t.Optional(t.String()),expiresAt:t.Optional(t.String()),metadata:t.Optional(t.Record(t.String(),t.Unknown()))}),CohortUpdateSchema=t.Object({name:t.Optional(t.String({minLength:1,maxLength:255})),description:t.Optional(t.String()),expiresAt:t.Optional(t.Union([t.String(),t.Null()])),metadata:t.Optional(t.Record(t.String(),t.Unknown())),isActive:t.Optional(t.Boolean())}),BulkCreateUserItem=t.Object({email:t.String({format:"email"}),password:t.String({minLength:8}),profile:t.Optional(t.Object({firstName:t.Optional(t.String()),lastName:t.Optional(t.String())}))}),BulkCreateSchema=t.Object({users:t.Optional(t.Array(BulkCreateUserItem)),emailPrefix:t.Optional(t.String()),emailDomain:t.Optional(t.String()),sharedPassword:t.Optional(t.String({minLength:8})),count:t.Optional(t.Integer({minimum:1,maximum:500})),roleIds:t.Optional(t.Array(t.String()))});function createCohortRoutes(config){let{db,logger:logger2,cohortsTable,usersTable,userRolesTable,profilesTable,basePath}=config,routes=new Elysia2;if(!db||!cohortsTable||!usersTable)return logger2.warn("[Cohort] Skipped \u2014 missing tables",{hasDb:!!db,hasCohortsTable:!!cohortsTable,hasUsersTable:!!usersTable}),routes;return routes.get(basePath,handleListCohorts(db,usersTable,cohortsTable)),routes.get(`${basePath}/:id`,handleGetCohort(db,usersTable,cohortsTable)),routes.post(basePath,handleCreateCohort(db,usersTable,cohortsTable,logger2),{body:CohortBodySchema}),routes.patch(`${basePath}/:id`,handleUpdateCohort(db,usersTable,cohortsTable),{body:CohortUpdateSchema}),routes.delete(`${basePath}/:id`,handleDeleteCohort(db,usersTable,cohortsTable,logger2)),routes.post(`${basePath}/:id/bulk-create`,handleBulkCreateUsers(config,logger2),{body:BulkCreateSchema}),routes.post(`${basePath}/:id/deactivate-users`,handleDeactivateUsers(db,usersTable,logger2)),routes.post(`${basePath}/:id/activate-users`,handleActivateUsers(db,usersTable,logger2)),routes.post(`${basePath}/:id/delete-users`,handleDeleteUsers(db,usersTable,cohortsTable,userRolesTable,profilesTable,logger2)),routes.get(`${basePath}/:id/export`,handleExportUsers(db,usersTable)),routes}init_deviceInfo();import{Elysia as Elysia6}from"elysia";import{Elysia as Elysia3,t as t2}from"elysia";init_Authorization();function getUserId(request){return request.headers.get("x-user-id")}function isChatModerator(request,moderatorRoles){let roles=decodeHeaderList(request.headers.get("x-user-roles"));if(roles.includes(GODMIN_ROLE_NAME))return!0;if(moderatorRoles.length===0)return!1;let allowed=new Set(moderatorRoles.map((role)=>role.toLowerCase()));return roles.some((role)=>allowed.has(role.toLowerCase()))}function chatErrorStatus(code){switch(code){case"forbidden":return 403;case"not_found":return 404;case"validation":return 400;case"conflict":return 409;case"disabled":return 409;default:return 400}}async function guard(set,logger2,fn){try{return{success:!0,data:await fn()}}catch(err){if(err instanceof ChatError)return set.status=chatErrorStatus(err.code),{success:!1,message:err.message};return logger2.error("[Chat] Unhandled route error",{error:err instanceof Error?err.message:String(err)}),set.status=500,{success:!1,message:"Internal server error"}}}function unauthorized(set){return set.status=401,{success:!1,message:"Authentication required"}}function createConversationRoutes(deps){let{logger:logger2,getService}=deps,app=new Elysia3({prefix:deps.config.basePath});return app.get("/conversations",({request,query,set})=>{let userId=getUserId(request);if(!userId)return unauthorized(set);let{service}=getService(request);return guard(set,logger2,()=>service.listConversations(userId,{limit:query.limit?Number(query.limit):void 0,offset:query.offset?Number(query.offset):void 0}))},{query:t2.Object({limit:t2.Optional(t2.String()),offset:t2.Optional(t2.String())}),detail:{tags:["Chat"],summary:"List my conversations"}}),app.post("/conversations",({request,body,set})=>{let userId=getUserId(request);if(!userId)return unauthorized(set);let{service}=getService(request),input=body;return guard(set,logger2,()=>{if(input.type==="group"){if(!input.title)throw new ChatError("validation","A group title is required");return service.createGroup({creatorId:userId,title:input.title,description:input.description,avatarFileId:input.avatarFileId,participantIds:input.participantIds??[]})}if(!input.targetUserId)throw new ChatError("validation","targetUserId is required for a direct conversation");return service.getOrCreateDirect(userId,input.targetUserId)})},{body:t2.Object({type:t2.Optional(t2.Union([t2.Literal("direct"),t2.Literal("group")])),targetUserId:t2.Optional(t2.String()),title:t2.Optional(t2.String()),description:t2.Optional(t2.String()),avatarFileId:t2.Optional(t2.String()),participantIds:t2.Optional(t2.Array(t2.String()))}),detail:{tags:["Chat"],summary:"Create or open a conversation"}}),app.get("/conversations/:id",({request,params,set})=>{let userId=getUserId(request);if(!userId)return unauthorized(set);let{service}=getService(request);return guard(set,logger2,()=>service.getConversation(params.id,userId))},{params:t2.Object({id:t2.String()}),detail:{tags:["Chat"],summary:"Get a conversation"}}),app.post("/conversations/:id/participants",({request,params,body,set})=>{let userId=getUserId(request);if(!userId)return unauthorized(set);let{service}=getService(request),{userIds}=body;return guard(set,logger2,()=>service.addParticipants(params.id,userId,userIds))},{params:t2.Object({id:t2.String()}),body:t2.Object({userIds:t2.Array(t2.String())}),detail:{tags:["Chat"],summary:"Add group participants"}}),app.delete("/conversations/:id/participants/:userId",({request,params,set})=>{let userId=getUserId(request);if(!userId)return unauthorized(set);let{service}=getService(request);return guard(set,logger2,async()=>{return await service.removeParticipant(params.id,userId,params.userId),{removed:params.userId}})},{params:t2.Object({id:t2.String(),userId:t2.String()}),detail:{tags:["Chat"],summary:"Remove a participant / leave group"}}),app}import{Elysia as Elysia5,t as t4}from"elysia";init_storage2();var CONTENT_TYPE_SCHEMA=t4.Optional(t4.Union([t4.Literal("text"),t4.Literal("image"),t4.Literal("file"),t4.Literal("video"),t4.Literal("audio")]));function createMessageRoutes(deps){let{logger:logger2,getService}=deps,app=new Elysia5({prefix:deps.config.basePath});return app.get("/conversations/:id/messages",({request,params,query,set})=>{let userId=getUserId(request);if(!userId)return unauthorized(set);let{service}=getService(request);return guard(set,logger2,()=>service.getMessages({conversationId:params.id,userId,limit:query.limit?Number(query.limit):void 0,before:query.before||void 0}))},{params:t4.Object({id:t4.String()}),query:t4.Object({limit:t4.Optional(t4.String()),before:t4.Optional(t4.String())}),detail:{tags:["Chat"],summary:"Get conversation messages (newest first)"}}),app.post("/conversations/:id/messages",({request,params,body,set})=>{let userId=getUserId(request);if(!userId)return unauthorized(set);let{service}=getService(request),input=body;return guard(set,logger2,()=>service.sendMessage({conversationId:params.id,senderId:userId,content:input.content,contentType:input.contentType,replyToId:input.replyToId,clientMessageId:input.clientMessageId,attachments:input.attachmentIds?.map((fileId)=>({fileId})),metadata:input.metadata}))},{params:t4.Object({id:t4.String()}),body:t4.Object({content:t4.Optional(t4.String()),contentType:CONTENT_TYPE_SCHEMA,replyToId:t4.Optional(t4.String()),clientMessageId:t4.Optional(t4.String()),attachmentIds:t4.Optional(t4.Array(t4.String())),metadata:t4.Optional(t4.Any())}),detail:{tags:["Chat"],summary:"Send a message (link pre-uploaded attachments)"}}),app.post("/conversations/:id/messages/upload",({request,params,body,set})=>{let userId=getUserId(request);if(!userId)return unauthorized(set);if(!deps.attachmentsAvailable)return set.status=409,{success:!1,message:"File attachments require storage and CDN to be enabled"};let{service,schemaTables}=getService(request);return guard(set,logger2,async()=>{let filesTable=resolveSchemaTable(schemaTables,"files",logger2);if(!filesTable)throw new ChatError("disabled","Files table unavailable in this schema");let{data,files}=parseFormDataBody(body,deps.storageConfig);if(files.length===0)throw new ChatError("validation","At least one file is required");let{records,failed}=await persistUploadedFiles({db:deps.db,filesTable,files,storageConfig:deps.storageConfig,subFolder:"chat",userId});if(records.length===0)throw new ChatError("validation",failed[0]?.error??"File upload failed");if(deps.cdnMedia)scheduleUploadMediaProcessing(records,{storagePath:deps.storageConfig.basePath,media:deps.cdnMedia,logger:logger2});let content=typeof data.content==="string"?data.content:void 0,replyToId=typeof data.replyToId==="string"?data.replyToId:void 0,clientMessageId=typeof data.clientMessageId==="string"?data.clientMessageId:void 0;return service.sendMessage({conversationId:params.id,senderId:userId,content,replyToId,clientMessageId,attachments:records.map((record)=>({fileId:record.id,originalName:record.originalName,mimeType:record.mimeType,size:record.size}))})})},{type:"formdata",params:t4.Object({id:t4.String()}),body:t4.Object({[deps.storageConfig.formData.dataField]:t4.Optional(t4.Union([t4.String(),t4.Any()])),[deps.storageConfig.formData.filesField]:t4.Optional(t4.Union([t4.File(),t4.Array(t4.File())]))}),detail:{tags:["Chat"],summary:"Send a message with uploaded file attachments"}}),app.post("/conversations/:id/read",({request,params,body,set})=>{let userId=getUserId(request);if(!userId)return unauthorized(set);let{service}=getService(request),{messageId}=body;return guard(set,logger2,()=>service.markRead(params.id,userId,messageId))},{params:t4.Object({id:t4.String()}),body:t4.Object({messageId:t4.Optional(t4.String())}),detail:{tags:["Chat"],summary:"Mark a conversation as read"}}),app.post("/conversations/:id/typing",({request,params,body,set})=>{let userId=getUserId(request);if(!userId)return unauthorized(set);let{service}=getService(request),{isTyping}=body;return guard(set,logger2,async()=>{return await service.setTyping(params.id,userId,isTyping??!0),{ok:!0}})},{params:t4.Object({id:t4.String()}),body:t4.Object({isTyping:t4.Optional(t4.Boolean())}),detail:{tags:["Chat"],summary:"Broadcast a typing indicator"}}),app.patch("/messages/:id",({request,params,body,set})=>{let userId=getUserId(request);if(!userId)return unauthorized(set);let{service}=getService(request),{content}=body;return guard(set,logger2,()=>service.editMessage(params.id,userId,content))},{params:t4.Object({id:t4.String()}),body:t4.Object({content:t4.String()}),detail:{tags:["Chat"],summary:"Edit a message"}}),app.delete("/messages/:id",({request,params,set})=>{let userId=getUserId(request);if(!userId)return unauthorized(set);let{service}=getService(request),asModerator=isChatModerator(request,deps.config.moderatorRoles??[]);return guard(set,logger2,async()=>{if(await service.deleteMessage(params.id,userId,asModerator),asModerator)logger2.warn("[CHAT] Message deleted by a moderator",{actorId:userId,messageId:params.id});return{deleted:params.id}})},{params:t4.Object({id:t4.String()}),detail:{tags:["Chat"],summary:"Delete a message",description:"Sender-only, unless the caller is godmin or holds a role from chat.moderatorRoles \u2014 then any message, and `deletionEnabled` does not apply."}}),app}function createChatRoutes(routeConfig){let{db,schemaTables,config,logger:logger2,broadcaster,tenantRegistry,storageConfig,attachmentsAvailable,cdnBasePath,cdnMedia}=routeConfig,buildService=(tables)=>new ChatService({db,schemaTables:tables,config,logger:logger2,broadcaster,cdnBasePath,attachmentsAvailable}),defaultService=buildService(schemaTables),deps={db,config,logger:logger2,storageConfig,attachmentsAvailable,getService:(request)=>{if(!tenantRegistry)return{service:defaultService,schemaTables};let schemaName=request.headers.get("x-tenant-schema");if(!schemaName)return{service:defaultService,schemaTables};let ctx=tenantRegistry.getSchemaContext(schemaName);if(!ctx)return{service:defaultService,schemaTables};return{service:buildService(ctx.schemaTables),schemaTables:ctx.schemaTables}},cdnMedia},routes=new Elysia6;return routes.use(createConversationRoutes(deps)),routes.use(createMessageRoutes(deps)),logger2.info(`[Chat] Routes registered at ${config.basePath}`,{attachmentsAvailable,groupsEnabled:config.groupsEnabled}),{routes,chatService:defaultService}}init_Authorization();init_helpers3();import Elysia7,{t as t5}from"elysia";function createConfigRoutes(routeConfig){let{logger:logger2,resolvedOptions,configFilePath,basePath,onConfigUpdate,db,schemaTables,getRedis}=routeConfig,plugin=new Elysia7({prefix:basePath});return plugin.onBeforeHandle(async({request,set})=>{if(decodeHeaderList(request.headers.get("x-user-roles")).includes(GODMIN_ROLE_NAME))return;let userId=request.headers.get("x-user-id");if(userId&&db&&schemaTables.users)try{let{eq:eq28}=await import("drizzle-orm"),usersTable=schemaTables.users;if((await db.select().from(usersTable).where(eq28(usersTable.id,userId)).limit(1))[0]?.isGod===!0)return}catch(err){logger2.warn("[ConfigManagement] Failed to check isGod from DB",{error:err instanceof Error?err.message:String(err)})}return set.status=403,Response.json({isSuccess:!1,message:"Only godmin users can access config management",data:null})}),plugin.get("/",()=>{let configCopy=JSON.parse(JSON.stringify(resolvedOptions));return{isSuccess:!0,message:"Current running configuration",data:{config:maskSensitiveFields(configCopy),configFilePath,sections:buildSectionsMeta(resolvedOptions)}}},{detail:{tags:["Config Management"],summary:"Get full running configuration",description:"Returns the full running configuration with sensitive fields masked."}}),plugin.get("/sections",()=>({isSuccess:!0,message:"Config section metadata",data:{sections:buildSectionsMeta(resolvedOptions)}}),{detail:{tags:["Config Management"],summary:"List all config sections with metadata",description:"Section list is derived at runtime from the config object \u2014 no hardcoding."}}),plugin.get("/env",()=>{let configCopy=JSON.parse(JSON.stringify(resolvedOptions)),declared=scanEnvVars(configCopy),declaredNames=new Set(declared.map((e)=>e.envName)),undeclared=scanUndeclaredEnv(declaredNames),entries=[...declared,...undeclared],resolvedCount=entries.filter((e)=>e.resolved).length,missingCount=entries.length-resolvedCount,unrecognizedCount=undeclared.length;return{isSuccess:!0,message:`Found ${entries.length} env vars (${resolvedCount} resolved, ${missingCount} missing, ${unrecognizedCount} unrecognized)`,data:{entries,totalCount:entries.length,resolvedCount,missingCount,unrecognizedCount}}},{detail:{tags:["Config Management"],summary:"Get environment variables (declared + undeclared)",description:"Surfaces both (a) DECLARED env vars \u2014 UPPER_SNAKE_CASE references found in the config tree (recognized:true) \u2014 and (b) UNDECLARED env vars actually present in process.env but not declared (recognized:false), minus Kubernetes service-link and OS/interpreter infra noise, so orphaned / junk config surfaces for cleanup. Sensitive values are masked; AI-provider *_API_KEY vars are never surfaced."}}),plugin.get("/overrides",async()=>{let redis=getRedis();if(!redis)return{isSuccess:!0,message:"Redis not available \u2014 no overrides stored",data:{overrides:null,sectionCount:0,sections:[]}};let overrides=await readOverridesFromRedis(redis,resolvedOptions.appId||"nucleus"),sections=overrides?Object.keys(overrides).filter((k)=>{let v=overrides[k];return v!==void 0&&v!==null&&(typeof v!=="object"||Object.keys(v).length>0)}):[];return{isSuccess:!0,message:sections.length>0?`${sections.length} section override(s) stored in Redis`:"No overrides in Redis",data:{overrides:overrides?maskSensitiveFields(overrides):null,sectionCount:sections.length,sections}}},{detail:{tags:["Config Management"],summary:"View Redis config overrides",description:"Returns overrides stored in Redis that will be merged on next restart."}}),plugin.delete("/overrides",async()=>{let redis=getRedis();if(!redis)return{isSuccess:!1,message:"Redis not available",data:null};let existing=await readOverridesFromRedis(redis,resolvedOptions.appId||"nucleus"),clearedSections=existing?Object.keys(existing):[];return await clearOverridesFromRedis(redis,resolvedOptions.appId||"nucleus"),logger2.info("[ConfigManagement] Redis overrides cleared",{clearedSections}),{isSuccess:!0,message:clearedSections.length>0?`Cleared ${clearedSections.length} override(s) from Redis. Restart to revert to config.json defaults.`:"No overrides to clear.",data:{message:"Redis overrides cleared",clearedSections}}},{detail:{tags:["Config Management"],summary:"Clear all Redis config overrides",description:"Removes all stored overrides from Redis. Restart to revert to config.json defaults."}}),plugin.get("/:section",({params})=>{let{section}=params;if(!hasSection(resolvedOptions,section))return{isSuccess:!1,message:`Unknown config section: ${section}`,data:null};let sectionValue=extractSection(resolvedOptions,section),restart=isRestartRequired(section),maskedValue=sectionValue;if(typeof sectionValue==="object"&§ionValue!==null&&!Array.isArray(sectionValue))maskedValue=maskSensitiveFields({[section]:sectionValue})[section];return{isSuccess:!0,message:`Config section: ${section}`,data:{section,config:maskedValue??null,restartRequired:restart}}},{params:t5.Object({section:t5.String()}),detail:{tags:["Config Management"],summary:"Get a specific config section",description:"Returns a specific config section with sensitive fields masked."}}),plugin.patch("/:section",async({params,body})=>{let{section}=params,payload=body;if(!hasSection(resolvedOptions,section))return{isSuccess:!1,message:`Unknown config section: ${section}`,data:null};if(!payload.config||typeof payload.config!=="object")return{isSuccess:!1,message:'Request body must contain a "config" object',data:null};let restart=isRestartRequired(section),currentValue=extractSection(resolvedOptions,section),newValue;if(Array.isArray(currentValue))newValue=payload.config.value!==void 0?payload.config.value:payload.config;else if(typeof currentValue==="object"&¤tValue!==null)newValue=deepMerge(currentValue,payload.config);else if(currentValue===void 0||typeof currentValue==="string"||typeof currentValue==="number"||typeof currentValue==="boolean")newValue=payload.config.value!==void 0?payload.config.value:payload.config;else newValue=payload.config;if(applySectionUpdate(resolvedOptions,section,newValue),!restart)onConfigUpdate(section,newValue);let persistMethod="memory-only",persistWarning=null;if(configFilePath)try{await persistConfigToDisk(configFilePath,resolvedOptions),persistMethod="disk",logger2.info(`[ConfigManagement] Section "${section}" persisted to disk`)}catch(diskErr){let diskMsg=diskErr instanceof Error?diskErr.message:String(diskErr);logger2.warn(`[ConfigManagement] Disk persist failed: ${diskMsg}`);let redis=getRedis();if(redis)try{await persistSectionToRedis(redis,resolvedOptions.appId||"nucleus",section,newValue),persistMethod="redis",logger2.info(`[ConfigManagement] Section "${section}" persisted to Redis (disk unavailable)`)}catch(redisErr){let redisMsg=redisErr instanceof Error?redisErr.message:String(redisErr);logger2.error(`[ConfigManagement] Redis persist also failed: ${redisMsg}`),persistWarning=`Disk: ${diskMsg}. Redis: ${redisMsg}. Changes are in-memory only and will be lost on restart.`}else persistWarning=`Disk: ${diskMsg}. Redis not available. Changes are in-memory only and will be lost on restart.`}logger2.info(`[ConfigManagement] Section "${section}" updated (persist: ${persistMethod}, restart-required: ${restart})`);let updatedValue=extractSection(resolvedOptions,section),maskedUpdated=updatedValue;if(typeof updatedValue==="object"&&updatedValue!==null&&!Array.isArray(updatedValue))maskedUpdated=maskSensitiveFields({[section]:updatedValue})[section];let baseMsg=restart?`Config section "${section}" saved (${persistMethod}). Restart required for changes to take effect.`:`Config section "${section}" updated and applied (${persistMethod}).`;return{isSuccess:!0,message:persistWarning?`${baseMsg} Warning: ${persistWarning}`:baseMsg,data:{section,applied:!restart,restartRequired:restart,config:maskedUpdated}}},{params:t5.Object({section:t5.String()}),body:t5.Object({config:t5.Record(t5.String(),t5.Unknown())}),detail:{tags:["Config Management"],summary:"Update a config section",description:"Deep-merges the payload into the section. Hot-reloadable sections apply immediately. Restart-required sections are saved to disk only."}}),plugin.post("/restart",({body})=>{let delayMs=body.delayMs??1000;logger2.info(`[ConfigManagement] Restart scheduled in ${delayMs}ms`);let scheduledAt=new Date().toISOString();return setTimeout(()=>{logger2.info("[ConfigManagement] Restarting process..."),process.exit(0)},delayMs),{isSuccess:!0,message:`Server restart scheduled in ${delayMs}ms`,data:{message:`Process will exit in ${delayMs}ms. Orchestrator (K8s/PM2/systemd) will restart it.`,scheduledAt}}},{body:t5.Optional(t5.Object({delayMs:t5.Optional(t5.Number())})),detail:{tags:["Config Management"],summary:"Restart the server process",description:"Triggers a graceful process exit after a configurable delay. The orchestrator (K8s, PM2, systemd) is expected to restart the process automatically."}}),logger2.info(`[ConfigManagement] Routes enabled at ${basePath}`),plugin}init_adminGuard();import{Elysia as Elysia8,t as t6}from"elysia";var requireAuth=(ctx)=>ctx.request.headers.get("x-user-id"),fail=(ctx,status,message)=>{return ctx.set.status=status,{success:!1,message,data:null}},callerSchemaOf=(ctx)=>ctx.request.headers.get("x-tenant-schema"),isGodmin=(ctx)=>hasGodminRole(ctx.request),ownsHostname=(ctx,record)=>{if(isGodmin(ctx))return!0;let caller=callerSchemaOf(ctx);return record.schemaName!=null&&record.schemaName===caller};function createHostnameRoutes(config){let base=config.basePath,app=new Elysia8,svc=(ctx)=>{let s=config.getDomainService();if(!s)return ctx.set.status=503,null;return s};app.post(`${base}/hostnames`,async(ctx)=>{let service=svc(ctx);if(!service)return{success:!1,message:"Domains not available",data:null};if(!requireAuth(ctx))return fail(ctx,401,"Authentication required");let body=ctx.body,callerSchema=callerSchemaOf(ctx),schemaName=body.schemaName??null,tenantId=body.tenantId??null;if(!hasGodminRole(ctx.request)){if(schemaName&&schemaName!==callerSchema)return fail(ctx,403,"Cannot bind a hostname to another tenant's schema");schemaName=callerSchema;let ownTenantId=config.resolveTenantIdForSchema?.(callerSchema)??null;if(tenantId&&tenantId!==ownTenantId)return fail(ctx,403,"Cannot bind a hostname to another tenant");tenantId=ownTenantId}try{let result=await service.createHostname({hostname:body.hostname,ownerId:body.ownerId,ownerType:body.ownerType,tenantId,schemaName,isPrimary:body.isPrimary});return{success:!0,message:"Custom hostname created",data:{hostname:result.hostname,instructions:result.instructions}}}catch(err){return fail(ctx,400,err instanceof Error?err.message:"Failed to create hostname")}},{body:t6.Object({hostname:t6.String(),ownerId:t6.String(),ownerType:t6.Optional(t6.Union([t6.Literal("tenant"),t6.Literal("organization"),t6.Literal("user"),t6.Literal("external")])),tenantId:t6.Optional(t6.String()),schemaName:t6.Optional(t6.String()),isPrimary:t6.Optional(t6.Boolean())}),detail:{tags:["Domains"],summary:"Create custom hostname"}}),app.get(`${base}/hostnames`,async(ctx)=>{let service=svc(ctx);if(!service)return{success:!1,message:"Domains not available",data:null};if(!requireAuth(ctx))return fail(ctx,401,"Authentication required");let url=new URL(ctx.request.url),items;if(isGodmin(ctx))items=await service.listHostnames({ownerId:url.searchParams.get("ownerId")??void 0,tenantId:url.searchParams.get("tenantId")??void 0});else{let ownTenantId=config.resolveTenantIdForSchema?.(callerSchemaOf(ctx))??null;items=ownTenantId?await service.listHostnames({tenantId:ownTenantId}):[]}return{success:!0,message:`Found ${items.length} hostnames`,data:{items}}}),app.get(`${base}/hostnames/:id`,async(ctx)=>{let service=svc(ctx);if(!service)return{success:!1,message:"Domains not available",data:null};if(!requireAuth(ctx))return fail(ctx,401,"Authentication required");let record=await service.getHostname(ctx.params.id);if(!record||!ownsHostname(ctx,record))return fail(ctx,404,"Hostname not found");return{success:!0,message:"Hostname found",data:record}}),app.get(`${base}/hostnames/:id/instructions`,async(ctx)=>{let service=svc(ctx);if(!service)return{success:!1,message:"Domains not available",data:null};if(!requireAuth(ctx))return fail(ctx,401,"Authentication required");let id=ctx.params.id,record=await service.getHostname(id);if(!record||!ownsHostname(ctx,record))return fail(ctx,404,"Hostname not found");return{success:!0,message:"DNS instructions",data:{instructions:await service.getInstructions(id)}}});let lifecycle=(suffix,run,summary)=>{app.post(`${base}/hostnames/:id/${suffix}`,async(ctx)=>{let service=svc(ctx);if(!service)return{success:!1,message:"Domains not available",data:null};if(!requireAuth(ctx))return fail(ctx,401,"Authentication required");let id=ctx.params.id,record=await service.getHostname(id);if(!record||!ownsHostname(ctx,record))return fail(ctx,404,"Hostname not found");try{let data=await run(service,id);if(!data)return fail(ctx,404,"Hostname not found");return{success:!0,message:summary,data}}catch(err){return fail(ctx,400,err instanceof Error?err.message:summary)}})};return lifecycle("verify",(s,id)=>s.verifyHostname(id),"Verification processed"),lifecycle("activate",(s,id)=>s.activateHostname(id),"Hostname activated"),lifecycle("disable",(s,id)=>s.disableHostname(id),"Hostname disabled"),lifecycle("make-primary",(s,id)=>s.makePrimary(id),"Primary hostname set"),lifecycle("refresh-status",(s,id)=>s.refreshStatus(id),"Status refreshed"),app}init_adminGuard();import{Elysia as Elysia9,t as t7}from"elysia";var requireAuth2=(ctx)=>ctx.request.headers.get("x-user-id"),fail2=(ctx,status,message)=>{return ctx.set.status=status,{success:!1,message,data:null}},callerSchemaOf2=(ctx)=>ctx.request.headers.get("x-tenant-schema"),isGodmin2=(ctx)=>hasGodminRole(ctx.request);function createRegistrationRoutes(config){let base=config.basePath,app=new Elysia9,svc=(ctx)=>{let s=config.getRegistrationService();if(!s)return ctx.set.status=503,null;return s},ownTenantId=(ctx)=>config.resolveTenantIdForSchema?.(callerSchemaOf2(ctx))??null,ownsRegistration=(ctx,record)=>{if(isGodmin2(ctx))return!0;let own=ownTenantId(ctx);return record.tenantId!=null&&own!=null&&record.tenantId===own};return app.post(`${base}/registrations`,async(ctx)=>{let service=svc(ctx);if(!service)return{success:!1,message:"Domains not available",data:null};if(!requireAuth2(ctx))return fail2(ctx,401,"Authentication required");let body=ctx.body,tenantId=body.tenantId??null,registrantOwnerType=body.registrantOwnerType;if(!isGodmin2(ctx)){let own=ownTenantId(ctx);if(tenantId&&tenantId!==own)return fail2(ctx,403,"Cannot register a domain for another tenant");if(tenantId=own,registrantOwnerType==="platform")return fail2(ctx,403,"Only a platform admin may register as 'platform'");registrantOwnerType="customer"}try{return{success:!0,message:"Registration requested",data:await service.createRequest({requestedDomain:body.requestedDomain,ownerId:body.ownerId,ownerType:body.ownerType,tenantId,registrantOwnerType,termsVersion:body.termsVersion,termsAccepted:body.termsAccepted,autoRenew:body.autoRenew})}}catch(err){return fail2(ctx,400,err instanceof Error?err.message:"Failed to request registration")}},{body:t7.Object({requestedDomain:t7.String(),ownerId:t7.String(),ownerType:t7.Optional(t7.Union([t7.Literal("tenant"),t7.Literal("organization"),t7.Literal("user"),t7.Literal("external")])),tenantId:t7.Optional(t7.String()),registrantOwnerType:t7.Optional(t7.Union([t7.Literal("customer"),t7.Literal("platform")])),termsVersion:t7.String(),termsAccepted:t7.Boolean(),autoRenew:t7.Optional(t7.Boolean())}),detail:{tags:["Domains"],summary:"Request managed domain registration"}}),app.get(`${base}/registrations`,async(ctx)=>{let service=svc(ctx);if(!service)return{success:!1,message:"Domains not available",data:null};if(!requireAuth2(ctx))return fail2(ctx,401,"Authentication required");let url=new URL(ctx.request.url),items;if(isGodmin2(ctx))items=await service.listRegistrations({ownerId:url.searchParams.get("ownerId")??void 0,tenantId:url.searchParams.get("tenantId")??void 0});else{let own=ownTenantId(ctx);items=own?await service.listRegistrations({tenantId:own}):[]}return{success:!0,message:`Found ${items.length} registrations`,data:{items}}}),app.get(`${base}/registrations/:id`,async(ctx)=>{let service=svc(ctx);if(!service)return{success:!1,message:"Domains not available",data:null};if(!requireAuth2(ctx))return fail2(ctx,401,"Authentication required");let record=await service.getRegistration(ctx.params.id);if(!record||!ownsRegistration(ctx,record))return fail2(ctx,404,"Registration not found");return{success:!0,message:"Registration found",data:record}}),app.post(`${base}/registrations/:id/cancel`,async(ctx)=>{let service=svc(ctx);if(!service)return{success:!1,message:"Domains not available",data:null};if(!requireAuth2(ctx))return fail2(ctx,401,"Authentication required");let id=ctx.params.id,record=await service.getRegistration(id);if(!record||!ownsRegistration(ctx,record))return fail2(ctx,404,"Registration not found");let cancelled=await service.cancel(id);if(!cancelled)return fail2(ctx,404,"Registration not found");return{success:!0,message:"Registration cancelled",data:cancelled}}),app.post(`${base}/registrations/:id/transfer-out`,async(ctx)=>{let service=svc(ctx);if(!service)return{success:!1,message:"Domains not available",data:null};if(!requireAuth2(ctx))return fail2(ctx,401,"Authentication required");let id=ctx.params.id,record=await service.getRegistration(id);if(!record||!ownsRegistration(ctx,record))return fail2(ctx,404,"Registration not found");let out=await service.requestTransferOut(id);if(!out)return fail2(ctx,404,"Registration not found");return{success:!0,message:"Transfer-out requested",data:out}}),app}import{Elysia as Elysia10}from"elysia";function createResolveRoute(config){let base=config.basePath,app=new Elysia10;return app.get(`${base}/resolve`,async(ctx)=>{let service=config.getDomainService();if(!service)return ctx.set.status=503,{success:!1,message:"Domains not available",data:null};let hostname=new URL(ctx.request.url).searchParams.get("hostname")||ctx.request.headers.get("host")||"";if(!hostname)return ctx.set.status=400,{success:!1,message:"hostname is required",data:null};let match=await service.resolveHostname(hostname);if(!match)return ctx.set.status=404,{success:!1,message:"No active hostname matched",data:null};return{success:!0,message:"Resolved",data:match}},{detail:{tags:["Domains"],summary:"Resolve hostname to tenant",description:"Public."}}),app}function createDomainRoutes(app,config){return app.use(createResolveRoute(config)),app.use(createHostnameRoutes(config)),app.use(createRegistrationRoutes(config)),app}import{and as and13,arrayContains,arrayOverlaps,asc,createTableRelationsHelpers,desc as desc5,eq as eq28,getTableName,gt,gte,ilike,inArray as inArray8,isNotNull,isNull as isNull2,like,lt as lt2,lte,ne as ne2,notInArray,or as or2,sql as sql7}from"drizzle-orm";import{drizzle}from"drizzle-orm/node-postgres";import{Elysia as Elysia11,t as t9}from"elysia";init_Authorization();init_utils5();init_adminGuard();init_sensitiveColumns();var snakeToCamel2=(s)=>s.replace(/_([a-z])/g,(_,l)=>l.toUpperCase()),SENSITIVE_SYSTEM_TABLE_SNAKE=["domain_hostnames","domain_registrations","domain_provider_records","domain_verification_challenges","domain_events","payment_sub_merchants","payment_invoices","payment_subscriptions","payment_customers","payment_transactions","payment_methods","payment_products","payment_prices","payment_commission_splits","payment_splits","payment_reserves","payment_ledger_entries","payment_payout_requests","payment_settlement_policies","payment_disputes","payment_webhook_logs","verifications","api_keys","magic_link_tokens","user_sessions","trusted_devices","integration_sources","integration_endpoints","integration_mappings"],SENSITIVE_SYSTEM_TABLES=new Set(SENSITIVE_SYSTEM_TABLE_SNAKE.flatMap((name2)=>[name2,snakeToCamel2(name2)]));function isSensitiveSystemTable(tableName){return SENSITIVE_SYSTEM_TABLES.has(tableName)}function delegatedWriteRoles(question){if(question.isRbacTable)return new Set;let roles=(question.featureSet??[]).flatMap((feature)=>question.featureAdminRoles?.[feature]??[]);return new Set(roles.map((role)=>role.toLowerCase()))}function isFeatureAdmin(question){let allowed=delegatedWriteRoles(question);if(allowed.size===0)return!1;return question.callerRoles.some((role)=>allowed.has(role.toLowerCase()))}init_storage2();function isAnonymousCreate(table,payload){let rule=table.anonymous_create;if(!rule)return!1;if(rule===!0)return!0;let column=rule.column;if(!column)return!1;let value=payload[column]??payload[toCamelCase3(column)]??payload[toSnakeCase2(column)];return isTruthy(value)}function isTruthy(value){if(typeof value==="boolean")return value;if(typeof value==="number")return value!==0;if(typeof value==="string"){let normalized=value.trim().toLowerCase();return normalized==="true"||normalized==="1"||normalized==="yes"||normalized==="on"}return!1}function createAuditIdentity(anonymous,userId,headers){if(anonymous)return{userId:void 0,ipAddress:"anonymous",userAgent:"anonymous"};return{userId:userId||void 0,ipAddress:headers.get("x-forwarded-for")?.split(",")[0]?.trim()||headers.get("x-real-ip")?.trim()||"unknown",userAgent:headers.get("user-agent")||"unknown"}}function toCamelCase3(value){return value.replace(/_([a-z0-9])/g,(_m,c)=>c.toUpperCase())}function toSnakeCase2(value){return value.replace(/[A-Z]/g,(c)=>`_${c.toLowerCase()}`)}var snakeToCamel3=(s)=>s.replace(/_([a-z])/g,(_,l)=>l.toUpperCase());function forceCreateScope(payload,authResult,resolveColumn){let scopeFilters=authResult?.scopeFilters;if(!scopeFilters)return{ok:!0};for(let[field,value]of Object.entries(scopeFilters)){if(!resolveColumn(field))return{ok:!1,field};payload[snakeToCamel3(field)]=value}return{ok:!0}}function decideRelationExpansion(params){let{authEnabled,targetTable,relAuth,isTargetPublicGet}=params;if(!authEnabled||!targetTable)return{expand:!0};if(relAuth===null)return isTargetPublicGet?{expand:!0}:{expand:!1};if(!relAuth.authorized)return{expand:!1};let scope=relAuth.scopeFilters;if(scope&&Object.keys(scope).length>0)return{expand:!0,scope};return{expand:!0}}function resolveRelationScopeColumn(fields,key2,toCamel5){if(Object.hasOwn(fields,key2))return fields[key2];let camel=toCamel5(key2);return Object.hasOwn(fields,camel)?fields[camel]:void 0}import{t as t8}from"elysia";function buildBodySchemaFromEntityColumns(entityColumns){let properties={};if(!entityColumns||entityColumns.length===0)return t8.Object({},{additionalProperties:!0});for(let col8 of entityColumns)switch(col8.type?.toLowerCase()||"string"){case"integer":case"int":case"serial":case"bigserial":case"numeric":case"decimal":properties[col8.name]=col8.notNull?t8.Number():t8.Optional(t8.Number());break;case"boolean":properties[col8.name]=col8.notNull?t8.Boolean():t8.Optional(t8.Boolean());break;case"timestamp":case"timestamptz":case"date":properties[col8.name]=col8.notNull?t8.String({format:"date-time"}):t8.Optional(t8.String({format:"date-time"}));break;case"json":case"jsonb":properties[col8.name]=t8.Optional(t8.Unknown());break;case"uuid":properties[col8.name]=col8.notNull?t8.String({format:"uuid"}):t8.Optional(t8.String({format:"uuid"}));break;default:properties[col8.name]=col8.notNull?t8.String():t8.Optional(t8.String())}return t8.Object(properties,{additionalProperties:!0})}function createBulkUpdateSchema(entityColumns){return t8.Array(t8.Object({id:t8.String(),data:buildBodySchemaFromEntityColumns(entityColumns)}))}var MAX_BULK_ITEMS=500;function collectFilterFields(filter,out=[]){if(filter.operator==="or"||filter.operator==="and"){let group=Array.isArray(filter.value)?filter.value:[];for(let f of group)collectFilterFields(f,out)}else if(filter.field)out.push(String(filter.field));return out}function buildFilterCondition(filter,resolveCol){if(filter.operator==="or"||filter.operator==="and"){let subs=(Array.isArray(filter.value)?filter.value:[]).map((f)=>buildFilterCondition(f,resolveCol)).filter((c)=>c!==null);if(subs.length===0)return null;return(filter.operator==="or"?or2(...subs):and13(...subs))??null}if(!filter.field)return null;let col8=resolveCol(filter.field);if(!col8)return null;let sqlCol=col8,dataType=col8.dataType,coerce2=(v)=>dataType==="date"&&(typeof v==="string"||typeof v==="number")?new Date(v):v;switch(filter.operator){case"eq":return eq28(sqlCol,coerce2(filter.value));case"neq":return ne2(sqlCol,coerce2(filter.value));case"gt":return gt(sqlCol,coerce2(filter.value));case"gte":return gte(sqlCol,coerce2(filter.value));case"lt":return lt2(sqlCol,coerce2(filter.value));case"lte":return lte(sqlCol,coerce2(filter.value));case"like":return like(sqlCol,filter.value);case"ilike":return ilike(sqlCol,filter.value);case"in":return inArray8(sqlCol,filter.value);case"notIn":return notInArray(sqlCol,filter.value);case"arrayOverlaps":return arrayOverlaps(sqlCol,filter.value??[]);case"arrayContains":return arrayContains(sqlCol,filter.value??[]);case"arrayEmpty":return sql7`cardinality(${sqlCol}) = 0`;case"isNull":return isNull2(sqlCol);case"isNotNull":return isNotNull(sqlCol);default:return null}}function createEntityRoutes(app,config){let{db,schemaTables,schemaRelations,entities,logger:logger2,dbPool,storage,cdnMedia,authorization,authMode,idpUrl,featureAdminRoles}=config,getRegistry=()=>config.getTenantRegistry?config.getTenantRegistry():config.tenantRegistry??null,getReqSchema=(request)=>{let tenantRegistry=getRegistry();if(!tenantRegistry)return{tables:schemaTables,relations:schemaRelations};let schemaName=request.headers.get("x-tenant-schema");if(!schemaName)return{tables:schemaTables,relations:schemaRelations};let ctx=tenantRegistry.getSchemaContext(schemaName);return ctx?{tables:ctx.schemaTables,relations:ctx.schemaRelations}:{tables:schemaTables,relations:schemaRelations}},storageConfig=mergeStorageConfig(storage),warmUploadedMedia=(uploaded)=>{if(!cdnMedia||!uploaded||uploaded.success.length===0)return;scheduleUploadMediaProcessing(uploaded.success,{storagePath:storageConfig.basePath,media:cdnMedia,logger:logger2})},authEnabled=authorization?.enabled??!1,enforceFieldWrites=authEnabled&&authorization?.enforceFieldWriteClaims!==!1,isConsumerMode=authMode==="consumer",filterWritePayload=(payload,authResult)=>{if(!enforceFieldWrites||!authResult?.allowedFields)return payload;return filterResponseFields(payload,authResult.allowedFields)},auditPathContext=(request)=>{let url=new URL(request.url);return{path:url.pathname,query:url.search}},auditIdentityFor=(table,payload,userId,headers)=>createAuditIdentity(isAnonymousCreate(table,payload),userId,headers),UUID_RE=/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i,auditEntityId=(id)=>{let s=id==null?"":String(id);return UUID_RE.test(s)?s:null},projectWrittenRow=(row,authResult)=>{let scoped2=authEnabled&&authResult?.allowedFields?filterResponseFields(row,[...authResult.allowedFields,...authResult.allowedRelations??[]]):row;return stripUnclaimedSensitive(redactSensitiveOutput(scoped2),authResult?.allowedFields)};if(!db)return app;function snakeToCamel4(s){return s.replace(/_([a-z])/g,(_,l)=>l.toUpperCase())}let{entities:mergedEntities}=resolveEntities(SYSTEM_TABLES,entities),extendedByName=new Map(mergedEntities.filter((t10)=>entities.some((e)=>e.table_name===t10.table_name&&e.extends===!0)).map((t10)=>[t10.table_name,t10])),effectiveEntities=entities.map((e)=>extendedByName.get(e.table_name)??e),allTables=Object.keys(schemaTables),entityTableNames=effectiveEntities.map((e)=>snakeToCamel4(e.table_name)),systemTableNames=allTables.filter((tbl)=>!entityTableNames.includes(tbl)),systemTableDefMap=new Map(SYSTEM_TABLES.map((t10)=>[snakeToCamel4(t10.table_name),t10])),asMeta=(def)=>def??void 0,hasUnmetRequirement=(def)=>{let requires=def?.requires;if(!requires||requires.length===0)return null;for(let req of requires)if(req==="email"&&!config.isEmailServiceAvailable?.())return"email";return null},deriveGroupName=(def,fallback)=>{if(def?.group_name)return def.group_name;let primaryFeature=def?.feature_set?.[0];if(!primaryFeature)return fallback;return primaryFeature.charAt(0).toUpperCase()+primaryFeature.slice(1)},systemTables2=systemTableNames.filter((name2)=>{let unmet=hasUnmetRequirement(asMeta(systemTableDefMap.get(name2)));if(unmet)return logger2.info(`Skipping ${name2} routes - missing required dependency: ${unmet}`),!1;return!0}).map((name2)=>{let def=systemTableDefMap.get(name2),meta=asMeta(def);return{table_name:def?.table_name??name2,group_name:deriveGroupName(meta,name2),is_form_data:def?.is_form_data===!0,bulk_endpoints_enabled:def?.bulk_endpoints_enabled??!1,excluded_methods:def?.excluded_methods?[...def.excluded_methods]:[],columns:def?.columns?[...def.columns]:void 0}}),allEntities=[...effectiveEntities,...systemTables2],publicGetEntities=new Set;for(let e of allEntities)if(e.is_public?.GET===!0)publicGetEntities.add(e.table_name),publicGetEntities.add(snakeToCamel4(e.table_name));logger2.info(`All entities: ${allEntities.map((e)=>e.table_name).join(", ")}`);for(let table of allEntities){let rawTableName=table.table_name,tableName=snakeToCamel4(rawTableName),swaggerTag=table.group_name||rawTableName,writeFields=enforceFieldWrites?table.columns?.map((c)=>c.name):void 0,defaultDrizzleTable=schemaTables[tableName];if(!defaultDrizzleTable)continue;let tableRelations=schemaRelations[`${tableName}Relations`];logger2.info(`Creating routes for table: ${tableName}`);let relationTargetTable={};{let rels=tableRelations;if(rels?.table&&typeof rels?.config==="function")try{let built=rels.config(createTableRelationsHelpers(rels.table));for(let[relName,rel]of Object.entries(built))if(rel?.referencedTable)relationTargetTable[relName]=getTableName(rel.referencedTable)}catch(err){logger2.warn(`[Authorization] Could not map relations for ${tableName}`,{error:err instanceof Error?err.message:String(err)})}}let defaultTableColumns=defaultDrizzleTable,defaultIdCol=defaultTableColumns.id,database=db,drizzleTable=defaultDrizzleTable,tableColumns=defaultTableColumns,idCol=defaultIdCol,resolveCol=(field)=>{if(Object.hasOwn(tableColumns,field))return tableColumns[field];let camel=snakeToCamel4(field);return Object.hasOwn(tableColumns,camel)?tableColumns[camel]:void 0},getTableForRequest=(request)=>{if(!getRegistry())return{drizzleTable,tableColumns,idCol,resolveCol,schemaTables,schemaRelations};let reqSchema=getReqSchema(request),reqTable=reqSchema.tables[tableName]||drizzleTable,reqCols=reqTable,reqIdCol=reqCols.id;return{drizzleTable:reqTable,tableColumns:reqCols,idCol:reqIdCol,resolveCol:(field)=>{if(Object.hasOwn(reqCols,field))return reqCols[field];let camel=snakeToCamel4(field);return Object.hasOwn(reqCols,camel)?reqCols[camel]:void 0},schemaTables:reqSchema.tables,schemaRelations:reqSchema.relations}},bulkUpdateSchema=createBulkUpdateSchema(table.columns),bulkDeleteSchema=t9.Array(t9.String()),authzLog=logger2.scoped("authorization.check"),performAuthCheck=async(request,method,reqFields,reqRelations)=>{let result=await runAuthCheck(request,method,reqFields,reqRelations);if(result){let userId=request.headers.get("x-user-id"),requestId=request.headers.get("x-request-id")||void 0;if(!result.authorized)authzLog.warn(`Denied ${method} ${table.table_name}`,{requestId,userId,entity:table.table_name,method,reason:result.reason||"no reason provided",mode:isConsumerMode?idpUrl?"idp":"jwt":"local"});else if(result.scopeFilters||result.allowedFields||result.allowedRelations)authzLog.debug(`Allowed ${method} ${table.table_name} (restricted)`,{requestId,userId,entity:table.table_name,method,scopeFilters:result.scopeFilters,allowedFieldCount:result.allowedFields?.length,allowedRelations:result.allowedRelations})}return result},scopeConditionsFor=(authResult,resolveColumn)=>{if(!authEnabled||!authResult?.scopeFilters)return[];let{conditions,unresolvedFields}=buildScopeConditions(authResult.scopeFilters,resolveColumn);if(unresolvedFields.length>0)authzLog.error(`Scope references unknown column(s) on ${table.table_name}; failing closed (0 rows)`,{entity:table.table_name,unresolvedFields});return conditions},runAuthCheck=async(request,method,reqFields,reqRelations,entityName=table.table_name)=>{let userId=request.headers.get("x-user-id");if(!authEnabled||!userId)return null;if(isConsumerMode){let userClaims=decodeHeaderList(request.headers.get("x-user-claims")),userRoles=decodeHeaderList(request.headers.get("x-user-roles")),userClaimScopes=decodeClaimScopesHeader(request.headers.get("x-user-claim-scopes"));if(idpUrl&&authorization?.jwtClaimsMode==="resolve"){let accessToken=request.headers.get("x-access-token")||(request.headers.get("cookie")||"").match(/access_token=([^;]+)/)?.[1]||"";return checkAuthorizationViaIDP({idpUrl,accessToken,method,entity:entityName,requestedFields:reqFields,requestedRelations:reqRelations,logger:logger2})}return checkAuthorizationFromJWT({userClaims,userRoles,method,entity:entityName,requestedFields:reqFields,requestedRelations:reqRelations,logger:logger2,requireClaimSpecificity:authorization?.requireClaimSpecificity,claimScopes:userClaimScopes})}let reqCtx=getTableForRequest(request);return checkAuthorization({userId,method,entity:entityName,requestedFields:reqFields,requestedRelations:reqRelations,db:database,schemaTables:reqCtx.schemaTables,logger:logger2,requireClaimSpecificity:authorization?.requireClaimSpecificity,getUserData:async()=>{if(!database)return;let usersTbl=reqCtx.schemaTables[AUTHORIZATION_TABLE_KEYS.users];if(!usersTbl)return;let idCol2=usersTbl.id;if(!idCol2)return;return(await database.select().from(usersTbl).where(eq28(idCol2,userId)).limit(1))[0]}})},entityRoutes=new Elysia11({prefix:`/${tableName}`}),listLog=logger2.scoped("entity.list"),isRbacTable=tableName===AUTHORIZATION_TABLE_KEYS.roles||tableName===AUTHORIZATION_TABLE_KEYS.claims||tableName===AUTHORIZATION_TABLE_KEYS.userRoles||tableName===AUTHORIZATION_TABLE_KEYS.roleClaims;if(isRbacTable||isSensitiveSystemTable(tableName)){let denyMessage=isRbacTable?"Forbidden: managing roles and claims requires godmin privileges":`Forbidden: writing to '${tableName}' via the generic entity API requires godmin privileges \u2014 use the dedicated route`;entityRoutes.onBeforeHandle(async({request,set})=>{let method=request.method.toUpperCase();if(method==="GET"||method==="HEAD"||method==="OPTIONS")return;if(hasGodminRole(request))return;if(isFeatureAdmin({isRbacTable,featureSet:table.feature_set,featureAdminRoles,callerRoles:decodeHeaderList(request.headers.get("x-user-roles"))}))return;if(await userHasGodminRoleInDb(db,schemaTables,request.headers.get("x-user-id"),logger2))return;return set.status=403,{success:!1,message:denyMessage}})}if(!table.excluded_methods?.includes("GET"))entityRoutes.get("/",async(ctx)=>{if(!database)return{success:!1,message:"DB not initialized"};let{drizzleTable:drizzleTable2,resolveCol:resolveCol2,schemaRelations:schemaRelations2}=getTableForRequest(ctx.request),requestedFields=table.columns?.map((c)=>c.name),requestedRelations=Object.keys(schemaRelations2).filter((k)=>k.startsWith(`${tableName}Relations`)).map((k)=>k.replace("Relations","")),authResult=await performAuthCheck(ctx.request,"GET",requestedFields,requestedRelations);if(authResult&&!authResult.authorized)return ctx.set.status=403,{success:!1,message:authResult.reason||"Forbidden"};let fieldQueryable=(field)=>{if(isSensitiveOutputKey(field))return!1;if(!sensitiveFieldQueryable(field,{authEnabled,allowedFields:authResult?.allowedFields}))return!1;if(authEnabled&&authResult?.allowedFields&&!authResult.allowedFields.includes(field))return!1;return!0},q=parseQueryParams(ctx.query),conditions=[];if(conditions.push(...scopeConditionsFor(authResult,resolveCol2)),q.search&&q.searchFields){for(let f of q.searchFields)if(!fieldQueryable(f.trim()))return ctx.set.status=403,{success:!1,message:`Cannot search on field: ${f.trim()}`};let searchConditions=q.searchFields.map((f)=>{let trimmed=f.trim(),col8=resolveCol2(trimmed);return col8?ilike(col8,`%${q.search}%`):null}).filter((c)=>c!==null);if(searchConditions.length>0){let orCondition=or2(...searchConditions);if(orCondition)conditions.push(orCondition)}}if(Array.isArray(q.filters))for(let filter of q.filters){for(let f of collectFilterFields(filter))if(!fieldQueryable(f))return ctx.set.status=403,{success:!1,message:`Cannot filter on field: ${f}`};let cond=buildFilterCondition(filter,resolveCol2);if(cond)conditions.push(cond)}let projection;if(q.select&&q.select.length>0){let requested=[...new Set(["id",...q.select.map((f)=>f.trim())])].filter(Boolean),columns={};for(let field of requested){if(!fieldQueryable(field))return ctx.set.status=403,{success:!1,message:`Cannot select field: ${field}`};let col8=resolveCol2(field);if(!col8)return ctx.set.status=400,{success:!1,message:`Unknown field in select: ${field}`};columns[field]=col8}if(Object.keys(columns).length>0)projection=columns}let unprojected=database.select().from(drizzleTable2),baseQuery=projection?database.select(projection).from(drizzleTable2):unprojected;if(conditions.length>0){let combined=and13(...conditions);if(combined)baseQuery=baseQuery.where(combined)}if(q.sort&&q.sort.length>0){for(let s of q.sort)if(!fieldQueryable(s.field))return ctx.set.status=403,{success:!1,message:`Cannot sort on field: ${s.field}`};let orderClauses=q.sort.map((s)=>{let col8=resolveCol2(s.field);if(!col8)return null;return s.direction==="desc"?desc5(col8):asc(col8)}).filter((o)=>o!==null);if(orderClauses.length>0)baseQuery=baseQuery.orderBy(...orderClauses)}let page=q.page??1,limit=q.limit??20,offset=q.offset??(page-1)*limit,queryStart=performance.now(),combinedCount=conditions.length>0?and13(...conditions):void 0,countResult=await database.select({n:sql7`count(*)::int`}).from(drizzleTable2).where(combinedCount),totalItems=Number(countResult[0]?.n??0);baseQuery=baseQuery.limit(limit).offset(offset);let items=await baseQuery,meta=buildPaginationMeta(page,limit,offset,totalItems);if(listLog.debug(`List ${rawTableName}: ${items.length}/${totalItems} rows`,{requestId:ctx.request.headers.get("x-request-id")||void 0,table:rawTableName,page,limit,totalItems,returned:items.length,conditionCount:conditions.length,search:q.search||void 0,sort:Array.isArray(q.sort)?q.sort.map((s)=>`${s.field}:${s.direction}`):void 0,queryMs:Math.round(performance.now()-queryStart)}),authEnabled&&authResult?.allowedFields)items=filterResponseFields(items,authResult.allowedFields);return{success:!0,data:{items:items.map((r)=>stripUnclaimedSensitive(redactSensitiveOutput(r),authResult?.allowedFields)),meta}}},{detail:{tags:[swaggerTag],summary:`List ${tableName}`,description:`Get paginated list of ${tableName} records with filtering, sorting, and search`}}),entityRoutes.get("/:id",async(ctx)=>{let{drizzleTable:drizzleTable2,idCol:idCol2,schemaTables:schemaTables2,schemaRelations:schemaRelations2,resolveCol:resolveCol2}=getTableForRequest(ctx.request);if(!database||!idCol2)return{success:!1,message:"No id column or DB"};let params=ctx.params,q=parseQueryParams(ctx.query),requestedFields=table.columns?.map((c)=>c.name),requestedRelations=q.with?.map((w)=>w.name),authResult=await performAuthCheck(ctx.request,"GET",requestedFields,requestedRelations);if(authResult&&!authResult.authorized)return ctx.set.status=403,{success:!1,message:authResult.reason||"Forbidden"};let getScope=scopeConditionsFor(authResult,resolveCol2),getWhere=getScope.length>0?and13(eq28(idCol2,params.id),...getScope):eq28(idCol2,params.id);if(q.with&&q.with.length>0&&tableRelations&&dbPool){let allowedWith=authEnabled&&authResult?.allowedRelations?q.with.filter((w)=>authResult.allowedRelations?.includes(w.name)??!1):q.with,dbWithRelations=drizzle(dbPool,{schema:{...schemaTables2,...schemaRelations2}}),withClause={};for(let rel of allowedWith){let targetTable=relationTargetTable[rel.name],relAuth=authEnabled&&targetTable?await runAuthCheck(ctx.request,"GET",void 0,void 0,targetTable):null,decision=decideRelationExpansion({authEnabled,targetTable,relAuth,isTargetPublicGet:targetTable?publicGetEntities.has(targetTable):!1});if(!decision.expand)continue;let relScope=decision.scope;if(relScope&&Object.keys(relScope).length>0)withClause[rel.name]={...rel.limit?{limit:rel.limit}:{},where:(fields,ops)=>{let preds=[],unresolved=!1;for(let[k,v]of Object.entries(relScope)){let col8=resolveRelationScopeColumn(fields,k,snakeToCamel4);if(col8)preds.push(ops.eq(col8,v));else unresolved=!0}if(unresolved)return sql7`1 = 0`;return preds.length>0?ops.and(...preds):void 0}};else withClause[rel.name]=rel.limit?{limit:rel.limit}:!0}let result2=await dbWithRelations.query[tableName]?.findFirst({where:getWhere,with:withClause});if(authEnabled&&authResult?.allowedFields&&result2)result2=filterResponseFields(result2,[...authResult.allowedFields,...authResult.allowedRelations??[]]);if(authEnabled&&authResult?.allowedRelations&&result2)result2=filterResponseRelations(result2,authResult.allowedRelations);return{success:!0,data:stripUnclaimedSensitive(redactSensitiveOutput(result2||null),authResult?.allowedFields)}}let result=(await database.select().from(drizzleTable2).where(getWhere))[0]||null;if(authEnabled&&authResult?.allowedFields&&result)result=filterResponseFields(result,authResult.allowedFields);return{success:!0,data:stripUnclaimedSensitive(redactSensitiveOutput(result),authResult?.allowedFields)}},{detail:{tags:[swaggerTag],summary:`Get ${tableName} by ID`,description:`Get a single ${tableName} record by its ID with optional relations`}}),entityRoutes.get("/distinct/:field",async(ctx)=>{let{drizzleTable:drizzleTable2,resolveCol:resolveCol2}=getTableForRequest(ctx.request);if(!database)return{success:!1,message:"DB not initialized"};let params=ctx.params,authResult=await performAuthCheck(ctx.request,"GET",[params.field],[]);if(authResult&&!authResult.authorized)return ctx.set.status=403,{success:!1,message:authResult.reason||"Forbidden"};if(authEnabled&&authResult?.allowedFields&&!authResult.allowedFields.includes(params.field))return ctx.set.status=403,{success:!1,message:"Forbidden: field not permitted"};if(isSensitiveOutputKey(params.field))return ctx.set.status=403,{success:!1,message:"Forbidden: field not permitted"};if(!sensitiveFieldQueryable(params.field,{authEnabled,allowedFields:authResult?.allowedFields}))return ctx.set.status=403,{success:!1,message:"Forbidden: field not permitted"};let col8=resolveCol2(params.field);if(!col8)return{success:!1,message:"Field not found"};let distinctScope=scopeConditionsFor(authResult,resolveCol2),distinctQuery=database.selectDistinct({value:col8}).from(drizzleTable2);return{success:!0,data:distinctScope.length>0?await distinctQuery.where(and13(...distinctScope)):await distinctQuery}},{detail:{tags:[swaggerTag],summary:`Get distinct ${tableName} values`,description:`Get distinct values for a specific field in ${tableName}`}});if(!table.excluded_methods?.includes("POST"))if(table.is_form_data&&storageConfig.enabled)entityRoutes.post("/",async(ctx)=>{let{drizzleTable:drizzleTable2,resolveCol:resolveCol2}=getTableForRequest(ctx.request);if(!database)return{success:!1,message:"DB not initialized"};let userId=ctx.request.headers.get("x-user-id"),postFormAuthResult=await performAuthCheck(ctx.request,"POST",writeFields);if(postFormAuthResult&&!postFormAuthResult.authorized)return ctx.set.status=403,{success:!1,message:postFormAuthResult.reason||"Forbidden"};let{data,files}=parseFormDataBody(ctx.body,storageConfig),payload=data,uploadedFiles=null;if(files.length>0){if(uploadedFiles=await uploadFiles(files,storageConfig,table.table_name),uploadedFiles.failed.length>0&&uploadedFiles.success.length===0)return{success:!1,message:"File upload failed",errors:uploadedFiles.failed};warmUploadedMedia(uploadedFiles)}let mergeUploadedMetadata=()=>{let firstFile=uploadedFiles?.success[0];if(firstFile)payload={...payload,...buildFileRecordPayload(firstFile,userId)}};if(table.columns)payload=sanitizePayload(payload,table.columns,{isFormData:table.is_form_data===!0}),payload=filterWritePayload(payload,postFormAuthResult),mergeUploadedMetadata();else mergeUploadedMetadata();let scopedForm=forceCreateScope(payload,postFormAuthResult,resolveCol2);if(!scopedForm.ok)return ctx.set.status=403,{success:!1,message:`Forbidden: ownership scope references a column '${scopedForm.field}' this entity does not have`};if(table.columns){let validation=validatePayload(payload,table.columns,!1);if(!validation.valid)return{success:!1,message:"Validation failed",errors:validation.errors}}let anonymous=isAnonymousCreate(table,payload);if(userId&&!anonymous)payload.createdBy=userId;let result=await database.insert(drizzleTable2).values(payload).returning();{let reqUrl=new URL(ctx.request.url);logger2.audit({entityName:table.table_name,entityId:String(result[0]?.id??""),operation:"CREATE",summary:`Created ${table.table_name}`,newValues:result[0],...createAuditIdentity(anonymous,userId,ctx.request.headers),path:reqUrl.pathname,query:reqUrl.search})}return{success:!0,data:stripUnclaimedSensitive(redactSensitiveOutput(result[0]),postFormAuthResult?.allowedFields)}},{type:"formdata",body:t9.Object({[storageConfig.formData.dataField]:t9.Optional(t9.Union([t9.String(),t9.Any()])),[storageConfig.formData.filesField]:t9.Optional(t9.Union([t9.File(),t9.Array(t9.File())]))}),detail:{tags:[swaggerTag],summary:`Create ${tableName} with files`,description:`Create a new ${tableName} record with file upload support`}});else entityRoutes.post("/",async(ctx)=>{let{drizzleTable:drizzleTable2,schemaTables:schemaTables2,resolveCol:resolveCol2}=getTableForRequest(ctx.request);if(!database)return{success:!1,message:"DB not initialized"};let payload=ctx.body,userId=ctx.request.headers.get("x-user-id"),postAuthResult=await performAuthCheck(ctx.request,"POST",writeFields);if(postAuthResult&&!postAuthResult.authorized)return ctx.set.status=403,{success:!1,message:postAuthResult.reason||"Forbidden"};if(table.columns)payload=sanitizePayload(payload,table.columns,{isFormData:table.is_form_data===!0}),payload=filterWritePayload(payload,postAuthResult);let scoped2=forceCreateScope(payload,postAuthResult,resolveCol2);if(!scoped2.ok)return ctx.set.status=403,{success:!1,message:`Forbidden: ownership scope references a column '${scoped2.field}' this entity does not have`};if(table.columns){let validation=validatePayload(payload,table.columns,!1);if(!validation.valid)return{success:!1,message:"Validation failed",errors:validation.errors}}let anonymous=isAnonymousCreate(table,payload);if(userId&&!anonymous)payload.createdBy=userId;if(tableName===AUTHORIZATION_TABLE_KEYS.userRoles&&payload.userId&&payload.roleId){let cols=drizzleTable2,existing=await database.select().from(drizzleTable2).where(and13(eq28(cols.userId,payload.userId),eq28(cols.roleId,payload.roleId))).limit(1);if(existing.length>0)return{success:!0,data:existing[0]}}let result=await database.insert(drizzleTable2).values(payload).returning();if(tableName===AUTHORIZATION_TABLE_KEYS.roleClaims&&config.claimsCache)config.claimsCache.invalidate().catch(()=>{});if(tableName===AUTHORIZATION_TABLE_KEYS.userRoles&&payload.roleId&&payload.userId)try{let rolesTable=schemaTables2[AUTHORIZATION_TABLE_KEYS.roles],usersTable=schemaTables2[AUTHORIZATION_TABLE_KEYS.users];if(rolesTable&&usersTable){if((await database.select().from(rolesTable).where(eq28(rolesTable.id,payload.roleId)).limit(1))[0]?.name===GODMIN_ROLE_NAME)await database.update(usersTable).set({isGod:!0}).where(eq28(usersTable.id,payload.userId))}}catch(_e){logger2.warn("[Entity] Failed to sync is_god flag on userRole create")}{let reqUrl=new URL(ctx.request.url);logger2.audit({entityName:table.table_name,entityId:String(result[0]?.id??""),operation:"CREATE",summary:`Created ${table.table_name}`,newValues:result[0],...createAuditIdentity(anonymous,userId,ctx.request.headers),path:reqUrl.pathname,query:reqUrl.search})}return{success:!0,data:stripUnclaimedSensitive(redactSensitiveOutput(result[0]),postAuthResult?.allowedFields)}},{body:t9.Object({},{additionalProperties:!0}),detail:{tags:[swaggerTag],summary:`Create ${tableName}`,description:`Create a new ${tableName} record`}});if(!table.excluded_methods?.includes("PUT"))if(table.is_form_data&&storageConfig.enabled)entityRoutes.put("/:id",async(ctx)=>{let{drizzleTable:drizzleTable2,idCol:idCol2,resolveCol:resolveCol2}=getTableForRequest(ctx.request);if(!database||!idCol2)return{success:!1,message:"No id column or DB"};let params=ctx.params,userId=ctx.request.headers.get("x-user-id"),putFormAuthResult=await performAuthCheck(ctx.request,"PUT",writeFields);if(putFormAuthResult&&!putFormAuthResult.authorized)return ctx.set.status=403,{success:!1,message:putFormAuthResult.reason||"Forbidden"};let putFormScope=scopeConditionsFor(putFormAuthResult,resolveCol2),putFormWhere=putFormScope.length>0?and13(eq28(idCol2,params.id),...putFormScope):eq28(idCol2,params.id),{data,files}=parseFormDataBody(ctx.body,storageConfig),payload=data,oldRecord=await database.select().from(drizzleTable2).where(putFormWhere).limit(1);if(putFormScope.length>0&&oldRecord.length===0)return ctx.set.status=403,{success:!1,message:"Forbidden"};if(table.columns){payload=sanitizePayload(payload,table.columns,{isFormData:table.is_form_data===!0}),payload=filterWritePayload(payload,putFormAuthResult);let validation=validatePayload(payload,table.columns,!1);if(!validation.valid)return{success:!1,message:"Validation failed",errors:validation.errors}}let uploadedFiles=null;if(files.length>0)uploadedFiles=await uploadFiles(files,storageConfig,table.table_name),warmUploadedMedia(uploadedFiles);let result=await database.update(drizzleTable2).set(payload).where(putFormWhere).returning();{let reqUrl=new URL(ctx.request.url);logger2.audit({entityName:table.table_name,entityId:params.id,operation:"UPDATE",userId:userId||void 0,summary:`Updated ${table.table_name} (${params.id})`,oldValues:oldRecord[0],newValues:result[0],ipAddress:ctx.request.headers.get("x-forwarded-for")?.split(",")[0]?.trim()||ctx.request.headers.get("x-real-ip")?.trim()||"unknown",userAgent:ctx.request.headers.get("user-agent")||"unknown",path:reqUrl.pathname,query:reqUrl.search})}return{success:!0,data:{record:result[0],files:uploadedFiles?.success||[],fileErrors:uploadedFiles?.failed||[]}}},{type:"formdata",body:t9.Object({[storageConfig.formData.dataField]:t9.Optional(t9.Union([t9.String(),t9.Any()])),[storageConfig.formData.filesField]:t9.Optional(t9.Union([t9.File(),t9.Array(t9.File())]))}),detail:{tags:[swaggerTag],summary:`Update ${tableName} with files`,description:`Full update of ${tableName} record with file upload support`}});else entityRoutes.put("/:id",async(ctx)=>{let{drizzleTable:drizzleTable2,idCol:idCol2,resolveCol:resolveCol2}=getTableForRequest(ctx.request);if(!database||!idCol2)return{success:!1,message:"No id column or DB"};let{params,body:payload}=ctx,userId=ctx.request.headers.get("x-user-id"),putAuthResult=await performAuthCheck(ctx.request,"PUT",writeFields);if(putAuthResult&&!putAuthResult.authorized)return ctx.set.status=403,{success:!1,message:putAuthResult.reason||"Forbidden"};let putScope=scopeConditionsFor(putAuthResult,resolveCol2),putWhere=putScope.length>0?and13(eq28(idCol2,params.id),...putScope):eq28(idCol2,params.id),oldRecord=await database.select().from(drizzleTable2).where(putWhere).limit(1);if(putScope.length>0&&oldRecord.length===0)return ctx.set.status=403,{success:!1,message:"Forbidden"};if(table.columns){payload=sanitizePayload(payload,table.columns,{isFormData:table.is_form_data===!0}),payload=filterWritePayload(payload,putAuthResult);let validation=validatePayload(payload,table.columns,!1);if(!validation.valid)return{success:!1,message:"Validation failed",errors:validation.errors}}if(payload.updatedAt=new Date,userId)payload.updatedBy=userId;let result=await database.update(drizzleTable2).set(payload).where(putWhere).returning();{let reqUrl=new URL(ctx.request.url);logger2.audit({entityName:table.table_name,entityId:params.id,operation:"UPDATE",userId:userId||void 0,summary:`Updated ${table.table_name} (${params.id})`,oldValues:oldRecord[0],newValues:result[0],ipAddress:ctx.request.headers.get("x-forwarded-for")?.split(",")[0]?.trim()||ctx.request.headers.get("x-real-ip")?.trim()||"unknown",userAgent:ctx.request.headers.get("user-agent")||"unknown",path:reqUrl.pathname,query:reqUrl.search})}return{success:!0,data:stripUnclaimedSensitive(redactSensitiveOutput(result[0]),putAuthResult?.allowedFields)}},{body:t9.Object({},{additionalProperties:!0}),detail:{tags:[swaggerTag],summary:`Update ${tableName}`,description:`Full update of ${tableName} record`}});if(!table.excluded_methods?.includes("PATCH"))entityRoutes.patch("/:id",async(ctx)=>{let{drizzleTable:drizzleTable2,idCol:idCol2,resolveCol:resolveCol2}=getTableForRequest(ctx.request);if(!database||!idCol2)return{success:!1,message:"No id column or DB"};let{params,body:payload}=ctx,userId=ctx.request.headers.get("x-user-id"),patchAuthResult=await performAuthCheck(ctx.request,"PATCH",writeFields);if(patchAuthResult&&!patchAuthResult.authorized)return ctx.set.status=403,{success:!1,message:patchAuthResult.reason||"Forbidden"};let patchScope=scopeConditionsFor(patchAuthResult,resolveCol2),patchWhere=patchScope.length>0?and13(eq28(idCol2,params.id),...patchScope):eq28(idCol2,params.id),oldRecord=await database.select().from(drizzleTable2).where(patchWhere).limit(1);if(patchScope.length>0&&oldRecord.length===0)return ctx.set.status=403,{success:!1,message:"Forbidden"};if(table.columns){payload=sanitizePayload(payload,table.columns,{isFormData:table.is_form_data===!0}),payload=filterWritePayload(payload,patchAuthResult);let validation=validatePayload(payload,table.columns,!0);if(!validation.valid)return{success:!1,message:"Validation failed",errors:validation.errors}}if(payload.updatedAt=new Date,userId)payload.updatedBy=userId;let result=await database.update(drizzleTable2).set(payload).where(patchWhere).returning();{let reqUrl=new URL(ctx.request.url);logger2.audit({entityName:table.table_name,entityId:params.id,operation:"PATCH",userId:userId||void 0,summary:`Patched ${table.table_name} (${params.id})`,oldValues:oldRecord[0],newValues:result[0],ipAddress:ctx.request.headers.get("x-forwarded-for")?.split(",")[0]?.trim()||ctx.request.headers.get("x-real-ip")?.trim()||"unknown",userAgent:ctx.request.headers.get("user-agent")||"unknown",path:reqUrl.pathname,query:reqUrl.search})}return{success:!0,data:stripUnclaimedSensitive(redactSensitiveOutput(result[0]),patchAuthResult?.allowedFields)}},{body:t9.Object({},{additionalProperties:!0}),detail:{tags:[swaggerTag],summary:`Patch ${tableName}`,description:`Partial update of ${tableName} record`}});if(!table.excluded_methods?.includes("DELETE"))entityRoutes.delete("/:id",async(ctx)=>{let{drizzleTable:drizzleTable2,idCol:idCol2,schemaTables:schemaTables2,resolveCol:resolveCol2}=getTableForRequest(ctx.request);if(!database||!idCol2)return{success:!1,message:"No id column or DB"};let params=ctx.params,userId=ctx.request.headers.get("x-user-id"),deleteAuthResult=await performAuthCheck(ctx.request,"DELETE");if(deleteAuthResult&&!deleteAuthResult.authorized)return ctx.set.status=403,{success:!1,message:deleteAuthResult.reason||"Forbidden"};let deleteScope=scopeConditionsFor(deleteAuthResult,resolveCol2),deleteWhere=deleteScope.length>0?and13(eq28(idCol2,params.id),...deleteScope):eq28(idCol2,params.id),oldRecord=await database.select().from(drizzleTable2).where(deleteWhere).limit(1);if(deleteScope.length>0&&oldRecord.length===0)return ctx.set.status=403,{success:!1,message:"Forbidden"};if(await database.delete(drizzleTable2).where(deleteWhere),table.is_form_data&&storageConfig.enabled&&oldRecord[0]){let rec=oldRecord[0],filePath=rec.path,fileName=rec.name;if(typeof filePath==="string"&&typeof fileName==="string"){if(!await deleteFile(filePath,fileName,storageConfig.basePath))logger2.warn(`[Entity] Blob cleanup failed for ${table.table_name} (${params.id})`)}}if(tableName===AUTHORIZATION_TABLE_KEYS.roleClaims&&config.claimsCache)config.claimsCache.invalidate().catch(()=>{});if(tableName===AUTHORIZATION_TABLE_KEYS.userRoles&&oldRecord[0])try{let deletedUserRole=oldRecord[0],rolesTable=schemaTables2[AUTHORIZATION_TABLE_KEYS.roles],usersTable=schemaTables2[AUTHORIZATION_TABLE_KEYS.users];if(rolesTable&&usersTable&&deletedUserRole.roleId&&deletedUserRole.userId){if((await database.select().from(rolesTable).where(eq28(rolesTable.id,deletedUserRole.roleId)).limit(1))[0]?.name===GODMIN_ROLE_NAME)await database.update(usersTable).set({isGod:!1}).where(eq28(usersTable.id,deletedUserRole.userId))}}catch(_e){logger2.warn("[Entity] Failed to sync is_god flag on userRole delete")}{let reqUrl=new URL(ctx.request.url);logger2.audit({entityName:table.table_name,entityId:params.id,operation:"DELETE",userId:userId||void 0,summary:`Deleted ${table.table_name} (${params.id})`,oldValues:oldRecord[0],ipAddress:ctx.request.headers.get("x-forwarded-for")?.split(",")[0]?.trim()||ctx.request.headers.get("x-real-ip")?.trim()||"unknown",userAgent:ctx.request.headers.get("user-agent")||"unknown",path:reqUrl.pathname,query:reqUrl.search})}return{success:!0,data:null}},{detail:{tags:[swaggerTag],summary:`Delete ${tableName}`,description:`Delete a ${tableName} record`}});if(table.bulk_endpoints_enabled){if(!table.excluded_methods?.includes("POST"))entityRoutes.post("/bulk",async(ctx)=>{let{drizzleTable:drizzleTable2,resolveCol:resolveCol2}=getTableForRequest(ctx.request);if(!database)return{success:!1,message:"DB not initialized"};let items=ctx.body;if(!Array.isArray(items))return{success:!1,message:"Body must be an array"};if(items.length>MAX_BULK_ITEMS)return ctx.set.status=400,{success:!1,message:`Bulk request exceeds ${MAX_BULK_ITEMS} items`};let userId=ctx.request.headers.get("x-user-id"),bulkPostAuth=await performAuthCheck(ctx.request,"POST",writeFields);if(bulkPostAuth&&!bulkPostAuth.authorized)return ctx.set.status=403,{success:!1,message:bulkPostAuth.reason||"Forbidden"};let sanitizedItems=[];for(let raw of items){let payload=raw;if(table.columns)payload=sanitizePayload(payload,table.columns,{isFormData:table.is_form_data===!0}),payload=filterWritePayload(payload,bulkPostAuth);let scopedItem=forceCreateScope(payload,bulkPostAuth,resolveCol2);if(!scopedItem.ok)return ctx.set.status=403,{success:!1,message:`Forbidden: ownership scope references a column '${scopedItem.field}' this entity does not have`};if(table.columns){let validation=validatePayload(payload,table.columns,!1);if(!validation.valid)return ctx.set.status=400,{success:!1,message:"Validation failed",errors:validation.errors}}if(userId&&!isAnonymousCreate(table,payload))payload.createdBy=userId;sanitizedItems.push(payload)}let txResult=await database.transaction(async(tx)=>{let results=[];for(let payload of sanitizedItems){let result=await tx.insert(drizzleTable2).values(payload).returning();results.push(result[0])}return results}),auditPath=auditPathContext(ctx.request);for(let[i,row]of txResult.entries())await logger2.audit({entityName:table.table_name,entityId:auditEntityId(row.id),operation:"CREATE",summary:`Bulk created ${table.table_name} (${row.id})`,newValues:row,...auditIdentityFor(table,sanitizedItems[i]??{},userId,ctx.request.headers),...auditPath});return{success:!0,data:txResult.map((r)=>projectWrittenRow(r,bulkPostAuth))}},{body:t9.Array(t9.Object({},{additionalProperties:!0})),detail:{tags:[swaggerTag],summary:`Bulk create ${tableName}`,description:`Create multiple ${tableName} records`}});if(!table.excluded_methods?.includes("PUT"))entityRoutes.put("/bulk",async(ctx)=>{let{drizzleTable:drizzleTable2,idCol:idCol2,resolveCol:resolveCol2}=getTableForRequest(ctx.request);if(!database||!idCol2)return{success:!1,message:"No id column or DB"};let items=ctx.body;if(!Array.isArray(items))return{success:!1,message:"Body must be an array"};if(items.length>MAX_BULK_ITEMS)return ctx.set.status=400,{success:!1,message:`Bulk request exceeds ${MAX_BULK_ITEMS} items`};let userId=ctx.request.headers.get("x-user-id"),bulkPutAuth=await performAuthCheck(ctx.request,"PUT",writeFields);if(bulkPutAuth&&!bulkPutAuth.authorized)return ctx.set.status=403,{success:!1,message:bulkPutAuth.reason||"Forbidden"};let bulkPutScope=scopeConditionsFor(bulkPutAuth,resolveCol2),prepared=[];for(let item of items){let payload=item.data;if(table.columns){payload=sanitizePayload(payload,table.columns,{isFormData:table.is_form_data===!0}),payload=filterWritePayload(payload,bulkPutAuth);let validation=validatePayload(payload,table.columns,!0);if(!validation.valid)return ctx.set.status=400,{success:!1,message:"Validation failed",errors:validation.errors}}if(payload.updatedAt=new Date,userId)payload.updatedBy=userId;prepared.push({id:item.id,payload})}let beforeById=new Map,txResult=await database.transaction(async(tx)=>{if(prepared.length>0){let idFilter=inArray8(idCol2,prepared.map((p)=>p.id)),beforeRows=await tx.select().from(drizzleTable2).where(bulkPutScope.length>0?and13(idFilter,...bulkPutScope):idFilter);for(let row of beforeRows)if(row.id!=null)beforeById.set(String(row.id),row)}let results=[];for(let{id,payload}of prepared){let result=await tx.update(drizzleTable2).set(payload).where(bulkPutScope.length>0?and13(eq28(idCol2,id),...bulkPutScope):eq28(idCol2,id)).returning();if(result[0])results.push(result[0])}return results}),auditPath=auditPathContext(ctx.request);for(let row of txResult){let rowId=String(row.id);await logger2.audit({entityName:table.table_name,entityId:auditEntityId(row.id),operation:"UPDATE",userId:userId||void 0,summary:`Bulk updated ${table.table_name} (${rowId})`,oldValues:beforeById.get(rowId),newValues:row,...auditPath})}return{success:!0,data:txResult.map((r)=>projectWrittenRow(r,bulkPutAuth))}},{body:bulkUpdateSchema,detail:{tags:[swaggerTag],summary:`Bulk update ${tableName}`,description:`Update multiple ${tableName} records`}});if(!table.excluded_methods?.includes("DELETE"))entityRoutes.delete("/bulk",async(ctx)=>{let{drizzleTable:drizzleTable2,idCol:idCol2,resolveCol:resolveCol2}=getTableForRequest(ctx.request);if(!database||!idCol2)return{success:!1,message:"No id column or DB"};let ids=ctx.body;if(!Array.isArray(ids))return{success:!1,message:"Body must be an array of ids"};if(ids.length>MAX_BULK_ITEMS)return ctx.set.status=400,{success:!1,message:`Bulk request exceeds ${MAX_BULK_ITEMS} items`};let bulkDeleteAuth=await performAuthCheck(ctx.request,"DELETE");if(bulkDeleteAuth&&!bulkDeleteAuth.authorized)return ctx.set.status=403,{success:!1,message:bulkDeleteAuth.reason||"Forbidden"};let bulkDeleteScope=scopeConditionsFor(bulkDeleteAuth,resolveCol2),userId=ctx.request.headers.get("x-user-id"),removed=[];await database.transaction(async(tx)=>{for(let id of ids){let r=await tx.delete(drizzleTable2).where(bulkDeleteScope.length>0?and13(eq28(idCol2,id),...bulkDeleteScope):eq28(idCol2,id)).returning();removed.push(...r)}});let auditPath=auditPathContext(ctx.request);for(let row of removed)await logger2.audit({entityName:table.table_name,entityId:auditEntityId(row.id),operation:"DELETE",userId:userId||void 0,summary:`Bulk deleted ${table.table_name} (${row.id})`,oldValues:row,...auditPath});return{success:!0,data:{deleted:removed.length}}},{body:bulkDeleteSchema,detail:{tags:[swaggerTag],summary:`Bulk delete ${tableName}`,description:`Delete multiple ${tableName} records`}})}app.use(entityRoutes)}return app}import Elysia13,{t as t11}from"elysia";import{randomUUID as randomUUID7}from"crypto";var LOCK_TTL_SECONDS2=60,RENEW_INTERVAL_MS=20000,lockKeyFor=(mappingId)=>`integrations:run:${mappingId}`;async function acquireRunLock(store,mappingId,deps={}){let key2=lockKeyFor(mappingId),now=deps.now??Date.now,ttl=deps.ttlSeconds??LOCK_TTL_SECONDS2,token=randomUUID7(),existing=await store.read(key2);if(!existing.success)return{ok:!1,reason:"unavailable",error:existing.error};if(existing.data)return{ok:!1,reason:"held",heldSince:existing.data.acquiredAt??null};let created=await store.create(key2,{token,acquiredAt:now()},ttl);if(!created.success)return{ok:!1,reason:"unavailable",error:created.error};let readBack=await store.read(key2);if(!readBack.success)return{ok:!1,reason:"unavailable",error:readBack.error};if(readBack.data?.token!==token)return{ok:!1,reason:"held",heldSince:readBack.data?.acquiredAt??null};let held=!0,timer=setInterval(()=>{(async()=>{let current=await store.read(key2);if(!current.success)return;if(current.data?.token!==token){held=!1,clearInterval(timer),deps.logger?.warn("[Integrations] Run lock was taken over",{mappingId});return}await store.update(key2,current.data,!1)})()},RENEW_INTERVAL_MS);return timer.unref?.(),{ok:!0,handle:{token,isHeld:()=>held,release:async()=>{if(clearInterval(timer),!held)return;held=!1;let current=await store.read(key2);if(current.success&¤t.data?.token===token)await store.remove(key2)}}}}import{createHash as createHash2}from"crypto";function buildUrl(baseUrl,path7,params){let base=baseUrl.trim().replace(/\/+$/,"");if(!base)return{ok:!1,error:"The source has no base address."};let raw=(path7??"").trim();if(/^[a-z][a-z0-9+.-]*:\/\//i.test(raw)||raw.startsWith("//"))return{ok:!1,error:`The endpoint path points at another host (${raw}). A path must be relative to the source address.`};let suffix=raw===""?"":raw.startsWith("/")?raw:`/${raw}`,url;try{url=new URL(`${base}${suffix}`)}catch{return{ok:!1,error:`The source address is not a valid URL: ${baseUrl}`}}for(let[key2,value]of Object.entries(params??{})){if(value==null)continue;url.searchParams.set(key2,String(value))}return{ok:!0,url}}function applyAuth(source,url){let headers={accept:"application/json",...source.extraHeaders??{}},token=source.token?.trim();if(!token)return{headers};switch(source.authType){case"bearer":case"oauth2":headers[source.authHeaderName||"Authorization"]=`Bearer ${token}`;break;case"api_key":if(source.authQueryParam)url.searchParams.set(source.authQueryParam,token);else headers[source.authHeaderName||"X-API-Key"]=token;break;case"basic":headers.Authorization=`Basic ${token}`;break;default:break}return{headers}}function describeTransportError(error){let message=error instanceof Error?error.message:String(error),cause=error?.cause,code=cause?.code??"",blob=`${message} ${code} ${cause?.message??""}`;if(/UNABLE_TO_GET_ISSUER_CERT|SELF_SIGNED|self.signed|CERT_|unable to verify|ERR_TLS|altnames/i.test(blob))return`Certificate verification failed (${code||"incomplete chain"}). If this server's certificate is knowingly self-signed or incomplete, turn off certificate verification for this source and try again.`;if(/ENOTFOUND|EAI_AGAIN|getaddrinfo|Unable to resolve/i.test(blob))return`The address could not be resolved (DNS${code?`: ${code}`:""}). Check the source address.`;if(/ECONNREFUSED/i.test(blob))return`The connection was refused (${code||"ECONNREFUSED"}). The address and port are reachable but nothing is listening.`;if(/ETIMEDOUT|timeout|timed out|aborted|AbortError|UND_ERR/i.test(blob))return`The connection timed out (${code||"timeout"}). Check network and firewall access to this address.`;if(/ECONNRESET|EPIPE/i.test(blob))return`The connection was closed by the other side (${code||"ECONNRESET"}).`;return`Connection error: ${message}`}async function fetchOnce(source,request,deps={}){let impl=deps.fetchImpl??fetch,headers={...request.headers},method=request.method.toUpperCase(),hasBody=request.body!==void 0&&method!=="GET"&&method!=="HEAD";if(hasBody&&!headers["content-type"]&&!headers["Content-Type"])headers["content-type"]="application/json";let init={method,headers,cache:"no-store",signal:AbortSignal.timeout(source.timeoutMs??30000),tls:{rejectUnauthorized:source.tlsVerify!==!1},...hasBody?{body:typeof request.body==="string"?request.body:JSON.stringify(request.body)}:{}},response;try{response=await impl(request.url.toString(),init)}catch(error){return deps.logger?.warn("[Integrations] Outbound request failed",{sourceId:source.id,url:request.url.origin+request.url.pathname,error:error instanceof Error?error.message:String(error)}),{ok:!1,status:0,body:null,linkHeader:null,error:describeTransportError(error)}}let text=await response.text().catch(()=>""),body=null;if(text)try{body=JSON.parse(text)}catch{body=text}let linkHeader=response.headers.get("link");if(!response.ok){let detail=typeof body==="string"?body:body==null?"":JSON.stringify(body);return{ok:!1,status:response.status,body,linkHeader,error:`The source returned HTTP ${response.status}${detail?` \u2014 ${detail.slice(0,300)}`:""}`}}return{ok:!0,status:response.status,body,linkHeader}}var EXPIRY_SKEW_MS=5000,DEFAULT_TTL_MS=300000,DEFAULT_REFRESH_TTL_MS=1800000,FIELD_SEPARATOR="\x00";function credentialFingerprint(config){let material=[config.tokenUrl,config.grantType,config.clientId??"",config.clientSecret??"",config.username??"",config.password??"",config.scope??"",config.clientAuth??"basic"].join(FIELD_SEPARATOR);return createHash2("sha256").update(material).digest("hex").slice(0,32)}class TokenCache{entries=new Map;get(sourceId,fingerprint){let entry=this.entries.get(sourceId);if(!entry)return null;if(entry.fingerprint!==fingerprint)return this.entries.delete(sourceId),null;return entry}set(sourceId,token){this.entries.set(sourceId,token)}invalidate(sourceId){this.entries.delete(sourceId)}clear(){this.entries.clear()}}var isUsable=(token,now)=>token.expiresAt>now+EXPIRY_SKEW_MS,canRefresh=(token,now)=>Boolean(token.refreshToken)&&(token.refreshExpiresAt??0)>now+EXPIRY_SKEW_MS;function buildTokenRequest(config,form){let headers={"content-type":"application/x-www-form-urlencoded",accept:"application/json"};if(config.scope&&!form.has("scope"))form.set("scope",config.scope);let clientId=config.clientId??"",clientSecret=config.clientSecret??"";if((config.clientAuth??"basic")==="basic")headers.authorization=`Basic ${Buffer.from(`${clientId}:${clientSecret}`).toString("base64")}`;else{if(clientId)form.set("client_id",clientId);if(clientSecret)form.set("client_secret",clientSecret)}return{headers,body:form.toString()}}async function requestToken(config,form,now,fetchImpl){let{headers,body}=buildTokenRequest(config,form),response;try{response=await fetchImpl(config.tokenUrl,{method:"POST",headers,body,cache:"no-store",signal:AbortSignal.timeout(config.timeoutMs??30000),tls:{rejectUnauthorized:config.tlsVerify!==!1}})}catch(error){return{ok:!1,error:`Token request failed \u2014 ${describeTransportError(error)}`}}let text=await response.text().catch(()=>""),json={};try{json=text?JSON.parse(text):{}}catch{}if(!response.ok||!json.access_token){let detail=json.error_description||json.error||text.slice(0,200);return{ok:!1,error:`Could not obtain an OAuth2 token (HTTP ${response.status})${detail?`: ${detail}`:""}`}}return{ok:!0,token:{accessToken:json.access_token,expiresAt:now+(json.expires_in?json.expires_in*1000:DEFAULT_TTL_MS),refreshToken:json.refresh_token,refreshExpiresAt:json.refresh_token?now+(json.refresh_expires_in?json.refresh_expires_in*1000:DEFAULT_REFRESH_TTL_MS):void 0,fingerprint:credentialFingerprint(config)}}}async function getAccessToken(config,cache,deps={}){let fetchImpl=deps.fetchImpl??fetch,now=deps.now?.()??Date.now();if(!config.tokenUrl?.trim())return{ok:!1,error:"No token URL is configured for this source."};let fingerprint=credentialFingerprint(config),cached=cache.get(config.sourceId,fingerprint);if(cached&&isUsable(cached,now))return{ok:!0,accessToken:cached.accessToken,fromCache:!0};if(cached&&canRefresh(cached,now)){let refreshed=await requestToken(config,new URLSearchParams({grant_type:"refresh_token",refresh_token:cached.refreshToken}),now,fetchImpl);if(refreshed.ok)return cache.set(config.sourceId,refreshed.token),{ok:!0,accessToken:refreshed.token.accessToken,fromCache:!1}}let form=new URLSearchParams({grant_type:config.grantType});if(config.grantType==="password")form.set("username",config.username??""),form.set("password",config.password??"");let minted=await requestToken(config,form,now,fetchImpl);if(!minted.ok)return{ok:!1,error:minted.error};return cache.set(config.sourceId,minted.token),{ok:!0,accessToken:minted.token.accessToken,fromCache:!1}}import{and as and14,eq as eq29,inArray as inArray9}from"drizzle-orm";var DEFAULT_IGNORED=["updatedAt","updated_at","updatedBy","updated_by"];function planRevert(input){let ignored=new Set([...DEFAULT_IGNORED,...input.ignoreColumns??[]]),ops={deletes:[],restores:[],reinserts:[],conflicts:[]};for(let image of input.preImages)switch(image.action){case"create":{if(!image.rowId)break;let now=input.current.get(image.rowId);if(!now)break;if(!input.force&&changedSince(image.after,now,ignored)){ops.conflicts.push({id:image.rowId,reason:"This record was edited after the import; deleting it would discard that edit."});break}ops.deletes.push(image.rowId);break}case"update":case"deactivate":{if(!image.rowId||!image.before)break;let now=input.current.get(image.rowId);if(!now)break;if(!input.force&&changedSince(image.after,now,ignored)){ops.conflicts.push({id:image.rowId,reason:"This record was edited after the import; restoring it would discard that edit."});break}ops.restores.push({id:image.rowId,row:image.before});break}case"delete":{if(!image.before)break;if(image.rowId&&input.current.has(image.rowId)){ops.conflicts.push({id:image.rowId,reason:"A record with this identifier exists again; it was not replaced."});break}ops.reinserts.push(image.before);break}default:break}return ops}function changedSince(after,now,ignored){if(!after)return!1;for(let[key2,value]of Object.entries(after)){if(ignored.has(key2))continue;if(!sameValue(value,now[key2]))return!0}return!1}function sameValue(a,b){if(a===b)return!0;if(a==null&&b==null)return!0;if(a instanceof Date&&b instanceof Date)return a.getTime()===b.getTime();if(a instanceof Date||b instanceof Date){let da=a instanceof Date?a:new Date(String(a)),db=b instanceof Date?b:new Date(String(b));return!Number.isNaN(da.getTime())&&!Number.isNaN(db.getTime())?da.getTime()===db.getTime():!1}if(typeof a==="object"||typeof b==="object")try{return JSON.stringify(a)===JSON.stringify(b)}catch{return!1}return String(a)===String(b)}var CHUNK=500;async function applyRevert(deps,ops,meta){let idCol=deps.resolveCol("id");if(!idCol)return{ok:!1,conflicts:ops.conflicts.length,error:`"${meta.targetEntity}" has no id column; its rows cannot be addressed.`};let now=new Date;try{return{ok:!0,...await deps.db.transaction(async(tx)=>{let deleted=0,restored=0,reinserted=0;for(let i=0;i<ops.deletes.length;i+=CHUNK){let chunk=ops.deletes.slice(i,i+CHUNK),removed=await tx.delete(deps.drizzleTable).where(inArray9(idCol,chunk)).returning();deleted+=removed.length}for(let restore of ops.restores){let{id:_id,createdAt:_c,createdBy:_cb,...rest}=restore.row,written=await tx.update(deps.drizzleTable).set({...rest,updatedAt:now,updatedBy:meta.userId}).where(and14(eq29(idCol,restore.id))).returning();restored+=written.length}if(ops.reinserts.length>0)for(let i=0;i<ops.reinserts.length;i+=CHUNK){let chunk=ops.reinserts.slice(i,i+CHUNK),written=await tx.insert(deps.drizzleTable).values(chunk).returning();reinserted+=written.length}return{deleted,restored,reinserted}}),conflicts:ops.conflicts.length}}catch(error){return deps.logger.error("[Integrations] Revert transaction failed",{targetEntity:meta.targetEntity,error:error instanceof Error?error.message:String(error)}),{ok:!1,conflicts:ops.conflicts.length,error:"The database rejected this undo; it was rolled back and nothing changed."}}}function groupPreImagesByEntity(preImages){let byEntity=new Map;for(let image of preImages){let list=byEntity.get(image.targetEntity);if(list)list.push(image);else byEntity.set(image.targetEntity,[image])}return[...byEntity.entries()].map(([targetEntity,images])=>({targetEntity,preImages:images}))}function touchedRowIds(preImages){let ids=new Set;for(let image of preImages)if(image.rowId)ids.add(image.rowId);return[...ids]}function getByPath(obj,path7){if(!path7)return;let cur=obj;for(let part of path7.split(".")){if(cur==null||typeof cur!=="object")return;cur=cur[part]}return cur}function readSourceValue(external,parent,path7){return readOne(external,parent,path7)}function readOne(external,parent,path7){return path7.startsWith("__parent.")?getByPath(parent,path7.slice(9)):getByPath(external,path7)}var TEMPLATE_TOKEN=/\{([^{}]+)\}/g;function isTemplateSource(source){return TEMPLATE_TOKEN.lastIndex=0,TEMPLATE_TOKEN.test(source)}function renderTemplate(template,external,parent){return template.replace(TEMPLATE_TOKEN,(_match,path7)=>{let value=readOne(external,parent,path7.trim());return value==null?"":String(value)})}function extractRecords(body,rootPath){if(rootPath){let at=getByPath(body,rootPath);if(Array.isArray(at))return at;return at&&typeof at==="object"?[at]:[]}let candidate=firstArrayLike(body)??deepFirstArrayOfObjects(body);return Array.isArray(candidate)?candidate:[]}var ENVELOPE_KEYS=["content","items","data","results","records","rows","list","value","responseObject"];function firstArrayLike(body){if(Array.isArray(body))return body;if(!body||typeof body!=="object")return;let b=body;for(let key2 of ENVELOPE_KEYS){let v=b[key2];if(Array.isArray(v))return v;if(v&&typeof v==="object"){let nested=v.items;if(Array.isArray(nested))return nested}}return}function deepFirstArrayOfObjects(body,depth=0){if(depth>5||body==null||typeof body!=="object"||body instanceof Date)return;if(Array.isArray(body))return body.length>0&&typeof body[0]==="object"&&body[0]!==null?body:void 0;let entries=Object.values(body);for(let v of entries)if(Array.isArray(v)&&v.length>0&&typeof v[0]==="object"&&v[0]!==null)return v;for(let v of entries)if(v&&typeof v==="object"&&!Array.isArray(v)){let found=deepFirstArrayOfObjects(v,depth+1);if(found)return found}for(let v of entries)if(Array.isArray(v))return v;return}var FOLD={\u{131}:"i",\u{130}:"I",\u{15f}:"s",\u{15e}:"S",\u{11f}:"g",\u{11e}:"G",\u{f8}:"o",\u{d8}:"O",\u{e6}:"ae",\u{c6}:"AE",\u{df}:"ss",\u{111}:"d",\u{110}:"D",\u{142}:"l",\u{141}:"L"};function foldToAscii(value){return value.replace(/[\u0131\u0130\u015F\u015E\u011F\u011E\u00F8\u00D8\u00E6\u00C6\u00DF\u0111\u0110\u0142\u0141]/g,(ch)=>FOLD[ch]??ch).normalize("NFD").replace(/[\u0300-\u036f]/g,"")}var TRUTHY=new Set(["true","1","yes","y","evet","e","on"]),FALSY=new Set(["false","0","no","n","hayir","hay\u0131r","h","off"]);function applyTransform(value,transform){if(value==null)return{ok:!0,value};switch(transform){case"trim":return{ok:!0,value:String(value).trim()};case"upper":return{ok:!0,value:String(value).trim().toLocaleUpperCase("tr-TR")};case"lower":return{ok:!0,value:String(value).trim().toLocaleLowerCase("tr-TR")};case"toString":return{ok:!0,value:String(value)};case"toNumber":{if(typeof value==="boolean")return{ok:!1,reason:"not a number",raw:value};let s=String(value).trim();if(s==="")return{ok:!0,value:null};let n=Number(s);return Number.isFinite(n)?{ok:!0,value:n}:{ok:!1,reason:"not a number",raw:value}}case"toBoolean":{if(typeof value==="boolean")return{ok:!0,value};let s=String(value).trim().toLocaleLowerCase("tr-TR");if(s==="")return{ok:!0,value:null};if(TRUTHY.has(s))return{ok:!0,value:!0};if(FALSY.has(s))return{ok:!0,value:!1};return{ok:!1,reason:"not a yes/no value",raw:value}}case"emailSafe":return{ok:!0,value:foldToAscii(String(value)).toLowerCase().trim().replace(/[^a-z0-9._@+-]+/g,".").replace(/\.{2,}/g,".").replace(/\.*@\.*/g,"@").replace(/^[.\-_]+|[.\-_]+$/g,"")};case"pathLeaf":{let parts=String(value).split(/[/\\>\u203A\u00BB]|->/).map((part)=>part.trim()).filter((part)=>part!=="");return{ok:!0,value:parts.length>0?parts[parts.length-1]:""}}case"toList":{if(Array.isArray(value))return{ok:!0,value};let s=String(value).trim();if(s==="")return{ok:!0,value:[]};return{ok:!0,value:s.split(",").map((part)=>part.trim()).filter((part)=>part!=="")}}case"dateOnly":{let s=String(value).trim();if(s==="")return{ok:!0,value:null};let leading=s.match(/^\d{4}-\d{2}-\d{2}/);if(leading)return{ok:!0,value:leading[0]};let d=new Date(s);return Number.isNaN(d.getTime())?{ok:!1,reason:"not a date",raw:value}:{ok:!0,value:d.toISOString().slice(0,10)}}default:return{ok:!0,value}}}function isEmpty(v){return v==null||typeof v==="string"&&v.trim()===""}function mapRecord(external,mappings,parent){let row={},problems=[];for(let fm of mappings){if(!fm.target)continue;let value;if(fm.constant!=null&&fm.constant!=="")value=fm.constant;else{let raw=isTemplateSource(fm.source)?renderTemplate(fm.source,external,parent):readOne(external,parent,fm.source),result=applyTransform(raw,fm.transform);if(!result.ok)problems.push(`${fm.source} \u2192 ${fm.target}: ${result.reason} (${String(result.raw)})`),value=null;else value=result.value}if(isEmpty(value)&&fm.fallback!=null&&fm.fallback!==""){let raw=isTemplateSource(fm.fallback)?renderTemplate(fm.fallback,external,parent):fm.fallback,result=applyTransform(raw,fm.transform);if(result.ok)value=result.value;else problems.push(`fallback \u2192 ${fm.target}: ${result.reason} (${String(result.raw)})`),value=null}if(value!==void 0)row[fm.target]=value}return{row,problems}}function buildMappedRecords(externalRecords,mappings,dedupTargetField,parents){let records=[],issues=[];return externalRecords.forEach((ext,i)=>{let{row,problems}=mapRecord(ext,mappings,parents?.[i]);for(let message of problems)issues.push({sourceIndex:i,kind:"invalid_value",message});let dedupKey=dedupTargetField&&!isEmpty(row[dedupTargetField])?String(row[dedupTargetField]).trim():null;records.push({data:row,dedupKey,sourceIndex:i,external:ext,parent:parents?.[i]})}),{records,issues}}function flattenKeys(obj,prefix="",out=[],depth=0){if(out.length>200||depth>4||obj==null||typeof obj!=="object")return out;if(Array.isArray(obj)){if(prefix)out.push(prefix);return out}for(let[k,v]of Object.entries(obj)){let path7=prefix?`${prefix}.${k}`:k;if(v!=null&&typeof v==="object"&&!Array.isArray(v))flattenKeys(v,path7,out,depth+1);else out.push(path7)}return out}var MAX_FANOUT_COMBINATIONS=5000;function resolvePath2(rawPath,values){let missing=new Set,used=new Set;return{path:rawPath.replace(/\{([a-zA-Z_][\w-]*)\}|:([a-zA-Z_]\w*)/g,(_full,brace,colon)=>{let key2=brace??colon,v=values[key2];if(v==null||v==="")return missing.add(key2),brace?`{${key2}}`:`:${key2}`;return used.add(key2),encodeURIComponent(String(v))}),missing:[...missing],used}}function planFetchOrder(endpoints,roots){let byId=new Map(endpoints.map((e)=>[e.id,e])),order=[],settled=new Set,onPath=[],onPathSet=new Set,visit=(id,requiredBy)=>{if(settled.has(id))return null;if(onPathSet.has(id))return{ok:!1,reason:"cycle",chain:[...onPath.slice(onPath.indexOf(id)),id]};let node=byId.get(id);if(!node)return{ok:!1,reason:"unknown_endpoint",missing:id,requiredBy:requiredBy??id};onPath.push(id),onPathSet.add(id);for(let binding of node.paramBindings??[]){if(binding.from!=="endpoint")continue;let failure=visit(binding.endpointId,id);if(failure)return failure}return onPath.pop(),onPathSet.delete(id),settled.add(id),order.push(id),null};for(let id of roots??endpoints.map((e)=>e.id)){let failure=visit(id,null);if(failure)return failure}return{ok:!0,order}}function expandBindings(bindings,sources,limit=MAX_FANOUT_COMBINATIONS){if(!bindings||bindings.length===0)return{ok:!0,calls:[{values:{}}]};let axes=[];for(let binding of bindings){if(binding.from==="static"){axes.push({param:binding.param,options:[{value:binding.value}]});continue}if(binding.from==="endpoint"){let options=(sources.parents?.[binding.endpointId]??[]).map((record)=>({value:getByPath(record,binding.field),parent:record})).filter((o)=>o.value!=null&&o.value!=="");axes.push({param:binding.param,options});continue}let values=sources.entityValues?.[`${binding.entity}.${binding.field}`]??[];axes.push({param:binding.param,options:values.filter((v)=>v!=null&&v!=="").map((value)=>({value}))})}if(axes.some((a)=>a.options.length===0))return{ok:!0,calls:[]};let combinations=axes.reduce((n,a)=>n*a.options.length,1);if(combinations>limit)return{ok:!1,reason:"too_many",combinations,limit};let calls=[{values:{}}];for(let axis of axes){let next=[];for(let call of calls)for(let option of axis.options)next.push({values:{...call.values,[axis.param]:option.value},parent:option.parent??call.parent});calls=next}return{ok:!0,calls}}function parentEndpointIds(bindings){let ids=new Set;for(let b of bindings??[])if(b.from==="endpoint")ids.add(b.endpointId);return[...ids]}function entityValueKeys(bindings){let keys=new Set;for(let b of bindings??[])if(b.from==="entity")keys.add(`${b.entity}.${b.field}`);return[...keys]}var MAX_PAGES=1000,DEFAULT_PAGE_SIZE=200,initialState2=()=>({pagesFetched:0,recordsFetched:0,cursor:null});function firstPageParams(profile){switch(profile.kind){case"page_number":{let params={[profile.pageParam]:String(profile.firstPage??0)};if(profile.sizeParam)params[profile.sizeParam]=String(pageSize(profile));return params}case"offset":return{[profile.offsetParam]:"0",[profile.limitParam]:String(pageSize(profile))};case"cursor":{let params={};if(profile.sizeParam)params[profile.sizeParam]=String(pageSize(profile));return params}case"link_header":{let params={};if(profile.sizeParam)params[profile.sizeParam]=String(pageSize(profile));return params}default:return{}}}function reportedTotal(profile,body){let path7=profile.kind==="page_number"||profile.kind==="offset"?profile.totalPath:void 0;if(!path7)return null;let raw=getByPath(body,path7);if(typeof raw==="number"&&Number.isFinite(raw)&&raw>=0)return Math.floor(raw);if(typeof raw==="string"&&raw.trim()!==""){let n=Number(raw);if(Number.isFinite(n)&&n>=0)return Math.floor(n)}return null}function nextPage(profile,state,observed){if(profile.kind==="none")return{kind:"done",reason:"single request"};if(state.pagesFetched>=MAX_PAGES)return{kind:"failed",reason:`Paging stopped after ${MAX_PAGES} requests without reaching the end. The source may not be honouring the paging parameters; importing this would be a partial read.`};if(observed.recordCount===0)return{kind:"done",reason:"empty page"};switch(profile.kind){case"page_number":{if(isLastPage(profile.lastPagePath,observed.body))return{kind:"done",reason:"source reported the last page"};let total=reportedTotal(profile,observed.body);if(total!==null&&state.recordsFetched>=total)return{kind:"done",reason:"reported total reached"};if(observed.recordCount<pageSize(profile))return{kind:"done",reason:"short page"};let next=(profile.firstPage??0)+state.pagesFetched,params={[profile.pageParam]:String(next)};if(profile.sizeParam)params[profile.sizeParam]=String(pageSize(profile));return{kind:"params",params}}case"offset":{let total=reportedTotal(profile,observed.body);if(total!==null&&state.recordsFetched>=total)return{kind:"done",reason:"reported total reached"};if(observed.recordCount<pageSize(profile))return{kind:"done",reason:"short page"};return{kind:"params",params:{[profile.offsetParam]:String(state.recordsFetched),[profile.limitParam]:String(pageSize(profile))}}}case"cursor":{let raw=getByPath(observed.body,profile.nextCursorPath),next=raw==null?"":String(raw).trim();if(next==="")return{kind:"done",reason:"no further cursor"};if(state.cursor!=null&&next===state.cursor)return{kind:"failed",reason:`The source returned the same cursor twice (${next}); paging would not advance.`};let params={[profile.cursorParam]:next};if(profile.sizeParam)params[profile.sizeParam]=String(pageSize(profile));return{kind:"params",params}}case"link_header":{let url=parseNextLink(observed.linkHeader);if(!url)return{kind:"done",reason:"no rel=next link"};return{kind:"url",url}}default:return{kind:"done",reason:"single request"}}}function pageSize(profile){let declared="pageSize"in profile?profile.pageSize:void 0;return declared&&declared>0?declared:DEFAULT_PAGE_SIZE}function isLastPage(path7,body){if(!path7)return!1;let raw=getByPath(body,path7);if(typeof raw==="boolean")return raw;if(typeof raw==="string")return raw.trim().toLowerCase()==="true";return!1}function parseNextLink(header){if(!header)return null;for(let part of splitLinks(header)){let match=part.match(/<([^>]*)>(.*)/);if(!match)continue;let url=(match[1]??"").trim(),attrs=match[2]??"";if(!url)continue;if(/;\s*rel\s*=\s*["']?\s*next\s*["']?(\s*;|\s*$)/i.test(attrs))return url}return null}function splitLinks(header){let parts=[],depth=0,current="";for(let ch of header){if(ch==="<")depth++;else if(ch===">")depth--;if(ch===","&&depth===0){parts.push(current),current="";continue}current+=ch}if(current.trim()!=="")parts.push(current);return parts}function isComplete(fetched,reported){if(reported===null)return!0;return fetched>=reported}function flattenTree(records,childrenPath){let out=[],truncated=!1,visit=(node,parent,depth)=>{if(!node||typeof node!=="object")return;if(depth>64){truncated=!0;return}let source=node,children=source[childrenPath],{[childrenPath]:_nested,...own}=source;if(out.push({...own,["__depth"]:depth,["__treeParent"]:parent??null}),!Array.isArray(children))return;for(let child of children)visit(child,own,depth+1)};for(let root of records)visit(root,null,0);return{records:out,truncated}}function treeChildrenPath(value){let trimmed=(value??"").trim();return trimmed.length>0?trimmed:null}var DEFAULT_MAX_CONCURRENT=4,DEFAULT_MAX_RECORDS=50000;async function collectOne(source,endpoint,params,deps,counters){let profile=endpoint.pagination??{kind:"none"},maxRecords=deps.maxRecords??DEFAULT_MAX_RECORDS,values={...endpoint.queryParams??{},...params.values},resolved=resolvePath2(endpoint.path,values);if(resolved.missing.length>0)return{ok:!1,error:`This endpoint needs path parameter(s) ${resolved.missing.map((m)=>`{${m}}`).join(", ")} and nothing supplies them. Add a parameter binding, or a static value.`};let baseQuery={};for(let[key2,value]of Object.entries(values)){if(value==null||resolved.used.has(key2))continue;baseQuery[key2]=value}let records=[],total=null,state=initialState2(),pageParams=firstPageParams(profile),absoluteUrl=null;for(;;){if(deps.isCancelled?.())return{ok:!1,error:"Cancelled."};let url;if(absoluteUrl)try{url=new URL(absoluteUrl)}catch{return{ok:!1,error:`The source returned an unusable next-page link: ${absoluteUrl}`}}else{let built=buildUrl(source.baseUrl,resolved.path,{...baseQuery,...pageParams});if(!built.ok)return{ok:!1,error:built.error};url=built.url}let headers={accept:"application/json"};if(deps.bearerToken)headers.Authorization=`Bearer ${deps.bearerToken}`;counters.calls++;let outcome=await fetchOnce({...source,token:deps.bearerToken??source.token},{method:endpoint.method,url,headers,body:endpoint.method.toUpperCase()==="GET"?void 0:endpoint.requestBody??{}},{fetchImpl:deps.fetchImpl});if(!outcome.ok)return{ok:!1,error:outcome.error??`HTTP ${outcome.status}`};let raw=extractRecords(outcome.body,endpoint.responseRootPath),childrenPath=treeChildrenPath(endpoint.treeChildrenPath),flattened=childrenPath?flattenTree(raw,childrenPath):null;if(flattened?.truncated)return{ok:!1,error:"This source answered with a structure that nests into itself. Nothing was imported \u2014 a company that contains itself has no order to write it in."};let page=flattened?flattened.records:raw;if(records.push(...page),counters.records+=page.length,total===null)total=reportedTotal(profile,outcome.body);if(counters.records>maxRecords)return{ok:!1,error:`This run would hold more than ${maxRecords} records at once. Narrow the source with a filter, or raise maxRecordsPerRun.`};deps.onProgress?.(counters.records),state={pagesFetched:state.pagesFetched+1,recordsFetched:records.length,cursor:pageParams[cursorParamOf(profile)??""]??state.cursor};let next=nextPage(profile,state,{recordCount:page.length,body:outcome.body,linkHeader:outcome.linkHeader});if(next.kind==="done")break;if(next.kind==="failed")return{ok:!1,error:next.reason};if(next.kind==="url"){absoluteUrl=next.url,pageParams={};continue}absoluteUrl=null,pageParams=next.params}return{ok:!0,records,total}}function cursorParamOf(profile){return profile.kind==="cursor"?profile.cursorParam:null}async function collectEndpoint(source,endpoint,sources,deps={}){let counters={calls:0,records:0},expansion=expandBindings(endpoint.paramBindings??void 0,sources);if(!expansion.ok)return{ok:!1,callCount:0,error:`This endpoint would be called ${expansion.combinations} times (the ceiling is ${expansion.limit}). Narrow the parent list, or remove one of the parameter bindings.`};if(expansion.calls.length===0)return{ok:!0,records:[],reportedTotal:null,callCount:0};let limit=Math.max(1,deps.maxConcurrent??DEFAULT_MAX_CONCURRENT),collected=[],total=null,failure=null,cursor=0,worker=async()=>{for(;;){if(failure||deps.isCancelled?.())return;let index=cursor++,call=expansion.calls[index];if(!call)return;let result=await collectOne(source,endpoint,call,deps,counters);if(!result.ok){failure??=result.error;return}for(let record of result.records)collected.push({record,parent:call.parent});if(expansion.calls.length===1)total=result.total}};if(await Promise.all(Array.from({length:Math.min(limit,expansion.calls.length)},worker)),failure)return{ok:!1,error:failure,callCount:counters.calls};if(deps.isCancelled?.())return{ok:!1,error:"Cancelled.",callCount:counters.calls};return{ok:!0,records:collected,reportedTotal:total,callCount:counters.calls}}var referenceKey=(check)=>`${check.entity}.${check.entityColumn}`,pointsAtOwnTable=(check,targetEntity)=>check.entity===targetEntity;function referenceValuesOf(raw){if(Array.isArray(raw))return{values:raw.map((item)=>String(item??"").trim()).filter((item)=>item!==""),wasList:!0};if(raw===null||raw===void 0)return{values:[],wasList:!1};let single=String(raw).trim();return{values:single===""?[]:[single],wasList:!1}}function resolveReference(raw,ids){let{values,wasList}=referenceValuesOf(raw),found=[],unmatched=[];for(let value of values){let id=ids?.[value];if(id===void 0)unmatched.push(value);else if(!found.includes(id))found.push(id)}return{ids:found,unmatched,wasList}}function resolvedColumnValue(resolution){return resolution.wasList?resolution.ids:resolution.ids[0]??null}function applyReferenceIds(row,references,ids,targetEntity){let next={...row},deferred=[];for(let check of references){if(!check.writeIdTo)continue;let raw=row[check.column];if(pointsAtOwnTable(check,targetEntity)){next[check.writeIdTo]=Array.isArray(raw)?[]:null,deferred.push({check,raw});continue}next[check.writeIdTo]=resolvedColumnValue(resolveReference(raw,ids[referenceKey(check)]))}return{row:next,deferred}}var isEmpty2=(v)=>v==null||typeof v==="string"&&v.trim()==="";function displayValue(value){if(value!==null&&typeof value==="object")try{return JSON.stringify(value)}catch{return"(a value that cannot be shown)"}return String(value)}function missingReferences(row,references,known){let broken=[];for(let check of references){let raw=row[check.column];if(isEmpty2(raw))continue;let value=displayValue(raw).trim(),present=known[`${check.entity}.${check.entityColumn}`];if(!present)continue;if(!present.has(value))broken.push({check,value,raw})}return broken}async function loadReferenceValues(references,read){let values={};for(let check of references){let key2=`${check.entity}.${check.entityColumn}`;if(values[key2])continue;let rows=await read(check.entity,check.entityColumn);values[key2]=new Set(rows.filter((v)=>!isEmpty2(v)).map((v)=>String(v).trim()))}return values}async function loadReferenceIds(references,targetEntity,read){let ids={};for(let check of references){if(!check.writeIdTo)continue;if(pointsAtOwnTable(check,targetEntity))continue;let key2=referenceKey(check);if(ids[key2])continue;ids[key2]=await read(check.entity,check.entityColumn)}return ids}function planWrites(input){let{records,existing,dedupTargetField,writeMode,missingPolicy,missingColumn,missingValue,requiredFields=[],uniqueFields=[],createDefaults={},accountRule=null,existingAccounts={},references=[],referenceValues={},referenceIds={},targetEntity=""}=input,issues=[],warnings=[],creates=[],referenceInserts=[],accountInserts=[],accountJoinInserts=[],plannedAccounts=new Set,plannedRefs=new Set,updates=[],deletes=[],deactivates=[],deferredLinks=[],dedupConfigured=Boolean(dedupTargetField),accountClaims=new Map,accountIdIsUnique=accountRule?uniqueFields.includes(accountRule.idColumn):!1,withAccount=(record,data)=>{if(!accountRule)return data;let raw=data[accountRule.matchFrom];if(isEmpty2(raw))return issues.push({sourceIndex:record.sourceIndex,kind:"account_unmatched",message:`${accountRule.matchFrom} is empty, so this record gets no account \u2014 it is imported without one.`,dedupKey:record.dedupKey,row:data}),data;let value=String(raw).trim(),claimedBy=accountClaims.get(value);if(claimedBy&&accountIdIsUnique)return issues.push({sourceIndex:record.sourceIndex,kind:"duplicate_value",message:`${accountRule.matchFrom} is \u201C${value}\u201D, which another record in this import already uses \u2014 and ${accountRule.idColumn} allows one record per account. This one is left out.`,dedupKey:record.dedupKey,row:data,keptRow:claimedBy.data}),null;accountClaims.set(value,record);let existingId=existingAccounts[value];if(existingId)return{...data,[accountRule.idColumn]:existingId};if(!plannedAccounts.has(value)){plannedAccounts.add(value);let accountData={[accountRule.matchColumn]:value};for(let pair of accountRule.values??[]){let from=data[pair.from];if(!isEmpty2(from))accountData[pair.column]=from}accountInserts.push({entity:accountRule.entity,matchColumn:accountRule.matchColumn,matchValue:value,data:accountData});for(let join7 of accountRule.joins??[])accountJoinInserts.push({entity:join7.entity,accountColumn:join7.accountColumn,values:join7.values,matchValue:value})}return data},hasDefaults=Object.keys(createDefaults).length>0,newRecord=(data)=>hasDefaults?{...createDefaults,...data}:data,existingByKey=new Map;if(dedupTargetField)for(let row of existing){let value=row.row[dedupTargetField];if(!isEmpty2(value))existingByKey.set(String(value).trim(),row)}let claimedUnique=new Map;for(let field of uniqueFields){let taken=new Map;for(let existingRow of existing){let value=existingRow.row[field];if(!isEmpty2(value))taken.set(String(value).trim(),existingRow.id)}claimedUnique.set(field,taken)}let matchedIds=new Set,seenInBatch=new Map;for(let sourceRecord of records){let broken=missingReferences(sourceRecord.data,references,referenceValues),resolvedRow=applyReferenceIds(sourceRecord.data,references,referenceIds,targetEntity),record={...sourceRecord,data:resolvedRow.row};for(let link of resolvedRow.deferred){if(!dedupTargetField)continue;let matchValue=record.data[dedupTargetField];if(isEmpty2(matchValue))continue;deferredLinks.push({matchColumn:dedupTargetField,matchValue:String(matchValue).trim(),writeIdTo:link.check.writeIdTo,lookupColumn:link.check.entityColumn,raw:link.raw,isList:Array.isArray(link.raw)})}let blocking=broken.find((b)=>b.check.onMissing==="skipRecord");if(blocking){let{check,value}=blocking;issues.push({sourceIndex:record.sourceIndex,kind:"missing_reference",message:typeof blocking.raw==="object"&&blocking.raw!==null?`${check.column} is not a single value but a whole object \u2014 ${value}. Point the mapping at one field of it, e.g. \`${check.column}.code\`, and it will have something to match against ${check.entity}.${check.entityColumn}.`:`${check.column} is \u201C${value}\u201D, which does not exist in ${check.entity}.${check.entityColumn} \u2014 this record is left out.`,dedupKey:record.dedupKey,row:record.data,reference:{column:check.column,value,entity:check.entity,entityColumn:check.entityColumn}});continue}let keepReferences=()=>{for(let{check,value}of broken){if(check.onMissing!=="create")continue;let token=`${check.entity}.${check.entityColumn}::${value}`;if(plannedRefs.has(token))continue;plannedRefs.add(token);let data={};for(let pair of check.createValues??[]){let fromSource=isTemplateSource(pair.from)?renderTemplate(pair.from,record.external,record.parent):readSourceValue(record.external,record.parent,pair.from),value2=isEmpty2(fromSource)?record.data[pair.from]:fromSource;if(!isEmpty2(value2))data[pair.column]=value2}referenceInserts.push({entity:check.entity,column:check.entityColumn,value,...Object.keys(data).length>0?{data}:{}})}},uniqueCollision=(data,ownRowId)=>{for(let field of uniqueFields){let raw=data[field];if(isEmpty2(raw))continue;let value=String(raw).trim(),holder2=claimedUnique.get(field)?.get(value);if(holder2===void 0)continue;if(holder2!==null&&holder2===ownRowId)continue;return{field,value}}return null},claimUnique=(data,rowId)=>{for(let field of uniqueFields){let raw=data[field];if(isEmpty2(raw))continue;claimedUnique.get(field)?.set(String(raw).trim(),rowId)}},collide=(field,value)=>{issues.push({sourceIndex:record.sourceIndex,kind:"duplicate_value",message:`${field} is \u201C${value}\u201D, which something else already has \u2014 ${field} has to be unique, so this record is left out.`,dedupKey:record.dedupKey,row:record.data})},missingRequired=requiredFields.filter((f)=>isEmpty2(record.data[f])&&isEmpty2(createDefaults[f]));if(missingRequired.length>0){issues.push({sourceIndex:record.sourceIndex,kind:"missing_required",message:`Required field(s) empty: ${missingRequired.join(", ")}`,dedupKey:record.dedupKey,row:record.data});continue}if(!dedupConfigured){let clash2=uniqueCollision(record.data,null);if(clash2){collide(clash2.field,clash2.value);continue}keepReferences(),claimUnique(record.data,null);let withLogin=withAccount(record,newRecord(record.data));if(!withLogin)continue;creates.push({data:withLogin,sourceIndex:record.sourceIndex});continue}if(record.dedupKey==null){let clash2=uniqueCollision(record.data,null);if(clash2){collide(clash2.field,clash2.value);continue}issues.push({sourceIndex:record.sourceIndex,kind:"missing_dedup_key",message:"Deduplication field is empty on this record \u2014 it will be added as new."}),keepReferences(),claimUnique(record.data,null);let withLogin=withAccount(record,newRecord(record.data));if(!withLogin)continue;creates.push({data:withLogin,sourceIndex:record.sourceIndex});continue}let claimedBy=seenInBatch.get(record.dedupKey);if(claimedBy){issues.push({sourceIndex:record.sourceIndex,kind:"duplicate_in_batch",message:`The source carries this key more than once: ${record.dedupKey} \u2014 this occurrence is skipped.`,dedupKey:record.dedupKey,row:record.data,keptRow:claimedBy});continue}if(seenInBatch.set(record.dedupKey,record.data),writeMode==="replace"||writeMode==="append"){let clash2=uniqueCollision(record.data,null);if(clash2&&!(writeMode==="replace"&&claimedUnique.get(clash2.field)?.get(clash2.value))){collide(clash2.field,clash2.value);continue}keepReferences(),claimUnique(record.data,null);let withLogin=withAccount(record,newRecord(record.data));if(!withLogin)continue;creates.push({data:withLogin,sourceIndex:record.sourceIndex});continue}let match=existingByKey.get(record.dedupKey),clash=uniqueCollision(record.data,match?.id??null);if(clash){collide(clash.field,clash.value);continue}if(keepReferences(),claimUnique(record.data,match?.id??null),match)matchedIds.add(match.id),updates.push({id:match.id,data:record.data,before:match.row,sourceIndex:record.sourceIndex});else{let withLogin=withAccount(record,newRecord(record.data));if(!withLogin)continue;creates.push({data:withLogin,sourceIndex:record.sourceIndex})}}if(writeMode==="replace")deletes.push(...existing);else if(writeMode==="upsert"&&missingPolicy!=="ignore"){let gone=existing.filter((row)=>!matchedIds.has(row.id));if(missingPolicy==="delete")deletes.push(...gone);else deactivates.push(...gone)}if(!dedupConfigured&&writeMode==="upsert")warnings.push("No deduplication field is set. Nothing can be matched against what is already here, so every record is added as new and each run will duplicate the last.");if(dedupConfigured&&records.length>0&&records.every((r)=>r.dedupKey==null))warnings.push(`The deduplication field is empty on every record \u2014 it is probably not among the mapped fields. As it stands nothing can ever match: all ${records.length} records will be re-added on every run.`);if(writeMode==="append"&&dedupConfigured)warnings.push("Append mode ignores the deduplication field: records already here will be added again.");if(writeMode==="replace"){if(warnings.push(`Replace mode: all ${existing.length} rows currently in the table are deleted and rebuilt from the source. Row identifiers change, so anything referring to them by id breaks.`),dedupConfigured)warnings.push('A deduplication field is set, so "update existing" would keep the current rows and their identifiers. Replace mode is only necessary when records cannot be matched at all.')}if(deactivates.length>0&&(!missingColumn||isEmpty2(missingValue)))warnings.push('The policy for records missing from the source is "deactivate", but no column and value are configured \u2014 those rows will be left untouched.'),deactivates.length=0;return{creates,updates,deletes,deactivates,deferredLinks,issues,warnings,referenceInserts,accountInserts,accountJoinInserts}}function summarize(ops,meta){let sampleSize=meta.sampleSize??8,sample=[...ops.creates.map((c)=>c.data),...ops.updates.map((u)=>u.data)].slice(0,sampleSize);return{targetEntity:meta.targetEntity,writeMode:meta.writeMode,totalFetched:meta.totalFetched,reportedTotal:meta.reportedTotal,toCreate:ops.creates.length,toUpdate:ops.updates.length,toSkip:ops.issues.filter((i)=>i.kind==="missing_required"||i.kind==="duplicate_in_batch"||i.kind==="duplicate_value"||i.kind==="invalid_value"||i.kind==="missing_reference").length,missing:ops.deletes.length+ops.deactivates.length,missingPolicy:meta.missingPolicy,existingCount:meta.existingCount,dedupConfigured:meta.dedupConfigured,issues:ops.issues,warnings:ops.warnings,referenceInserts:ops.referenceInserts,accountsToCreate:ops.accountInserts.length,sample}}import{and as and15,eq as eq30,inArray as inArray10}from"drizzle-orm";var INSERT_CHUNK=500,DELETE_CHUNK=1000;function validateAll(ops,columns,validatePayload2){let issues=[];for(let op of ops.creates){let result=validatePayload2(op.data,columns,!1);if(!result.valid)issues.push({sourceIndex:op.sourceIndex,kind:"invalid_value",message:result.errors.map((e)=>`${e.field}: ${e.message}`).join("; "),row:op.data})}for(let op of ops.updates){let result=validatePayload2(op.data,columns,!0);if(!result.valid)issues.push({sourceIndex:op.sourceIndex,kind:"invalid_value",message:result.errors.map((e)=>`${e.field}: ${e.message}`).join("; "),row:op.data})}return issues}function referenceRow(columns,column,value,extra){let row={...extra,[column]:value},unfillable=[];for(let col8 of columns){let name2=camel(col8.name);if(name2===column)continue;if(SYSTEM_COLUMNS.has(name2))continue;if(row[name2]!==void 0)continue;if(!(col8.notNull===!0&&col8.default===void 0&&!col8.defaultRaw&&!col8.nullable))continue;if(TEXTUAL_TYPES.has(String(col8.type)))row[name2]=value;else unfillable.push(name2)}return unfillable.length>0?{ok:!1,unfillable}:{ok:!0,row}}var SYSTEM_COLUMNS=new Set(["id","createdAt","updatedAt","createdBy","updatedBy"]),TEXTUAL_TYPES=new Set(["text","varchar","char"]),camel=(s)=>s.replace(/_([a-z])/g,(_m,l)=>l.toUpperCase());function linkAccount(data,rule,idByValue){let value=data[rule.matchFrom];if(value==null)return{};let id=idByValue.get(String(value).trim());return id?{[rule.idColumn]:id}:{}}function groupDeferred(links){let groups=new Map;for(let link of links){let key2=`${link.writeIdTo}|${link.lookupColumn}|${link.matchColumn}`,group=groups.get(key2)??{writeIdTo:link.writeIdTo,lookupColumn:link.lookupColumn,matchColumn:link.matchColumn,links:[]};group.links.push(link),groups.set(key2,group)}return[...groups.values()]}async function applyWrites(deps,input){let{ops,targetEntity,userId}=input,scope=input.scopeConditions??[],writeIssues=[],cancelled=()=>input.isCancelled?.()===!0,invalid=validateAll(ops,deps.columns,deps.validatePayload);if(invalid.length>0)return{ok:!1,failure:{kind:"validation_failed",message:`${invalid.length} record(s) did not pass validation; nothing was written.`,issues:invalid}};let refGroups=new Map;for(let insert of ops.referenceInserts){let resolved=deps.resolveEntity?.(insert.entity);if(!resolved)return{ok:!1,failure:{kind:"write_failed",message:`This mapping would add \u201C${insert.value}\u201D to "${insert.entity}", which does not exist.`}};let built=referenceRow(resolved.columns,insert.column,insert.value,insert.data);if(!built.ok)return{ok:!1,failure:{kind:"write_failed",message:`\u201C${insert.value}\u201D cannot be added to "${insert.entity}" automatically: ${built.unfillable.join(", ")} is required and cannot be filled from a ${insert.column}. Add the missing ${insert.entity} by hand, or set this reference to leave those records out.`}};let group=refGroups.get(insert.entity)??{table:resolved.table,rows:[]};group.rows.push(built.row),refGroups.set(insert.entity,group)}let accountRule=input.account??null,accountEntity=ops.accountInserts[0]?.entity,accountTable=accountEntity?deps.resolveEntity?.(accountEntity):null;if(ops.accountInserts.length>0&&(!accountRule||!accountTable))return{ok:!1,failure:{kind:"write_failed",message:accountRule?`This import creates accounts in "${accountEntity}", which does not exist.`:"This import creates accounts but no password was supplied, so nothing was written."}};if(cancelled())return{ok:!1,failure:{kind:"cancelled",message:"Cancelled before writing."}};let idCol=deps.resolveCol("id");if(!idCol)return{ok:!1,failure:{kind:"write_failed",message:`Target "${targetEntity}" has no id column; the engine cannot address its rows.`}};let preImages=[],now=new Date,deactivating=ops.deactivates.length>0&&input.missingColumn&&input.missingValue!=null?{column:input.missingColumn,value:input.missingValue}:null;try{let linksMade=0;return{ok:!0,...await deps.db.transaction(async(tx)=>{let created=0,accountsCreated=0,referencesCreated=0,updated=0,deleted=0,deactivated=0;if(ops.deletes.length>0){let ids=ops.deletes.map((r)=>r.id);for(let i=0;i<ids.length;i+=DELETE_CHUNK){if(cancelled())throw new CancelledError;let chunk=ids.slice(i,i+DELETE_CHUNK),where=scope.length?and15(inArray10(idCol,chunk),...scope):inArray10(idCol,chunk),removed=await tx.delete(deps.drizzleTable).where(where).returning();deleted+=removed.length;for(let row of removed)preImages.push({targetEntity,rowId:String(row.id),action:"delete",before:row,after:null})}}for(let op of ops.updates){if(cancelled())throw new CancelledError;let where=scope.length?and15(eq30(idCol,op.id),...scope):eq30(idCol,op.id),written=await tx.update(deps.drizzleTable).set({...op.data,updatedAt:now,updatedBy:userId}).where(where).returning();if(written.length===0)throw new ScopeError(op.id);updated+=written.length,preImages.push({targetEntity,rowId:op.id,action:"update",before:op.before,after:written[0]??null})}if(deactivating){let ids=ops.deactivates.map((r)=>r.id);for(let i=0;i<ids.length;i+=DELETE_CHUNK){if(cancelled())throw new CancelledError;let chunk=ids.slice(i,i+DELETE_CHUNK),where=scope.length?and15(inArray10(idCol,chunk),...scope):inArray10(idCol,chunk),written=await tx.update(deps.drizzleTable).set({[deactivating.column]:deactivating.value,updatedAt:now,updatedBy:userId}).where(where).returning();deactivated+=written.length;let beforeById=new Map(ops.deactivates.map((r)=>[r.id,r.row]));for(let row of written){let id=String(row.id);preImages.push({targetEntity,rowId:id,action:"deactivate",before:beforeById.get(id)??null,after:row})}}}for(let[entity,group]of refGroups){let rows=group.rows.map((r)=>({...r,createdAt:now,updatedAt:now,createdBy:userId}));for(let i=0;i<rows.length;i+=INSERT_CHUNK){if(cancelled())throw new CancelledError;let written=await tx.insert(group.table).values(rows.slice(i,i+INSERT_CHUNK)).returning();referencesCreated+=written.length;for(let row of written)preImages.push({targetEntity:entity,rowId:row.id?String(row.id):null,action:"create",before:null,after:row})}}let accountIdByValue=new Map;if(accountRule&&accountTable&&ops.accountInserts.length>0){let rows=ops.accountInserts.map((account)=>({...account.data,[accountRule.passwordColumn]:accountRule.passwordHash,createdAt:now,updatedAt:now,createdBy:userId}));for(let i=0;i<rows.length;i+=INSERT_CHUNK){if(cancelled())throw new CancelledError;let written=await tx.insert(accountTable.table).values(rows.slice(i,i+INSERT_CHUNK)).returning();accountsCreated+=written.length;for(let row of written){let value=row[accountRule.matchColumn];if(row.id!=null&&value!=null)accountIdByValue.set(String(value).trim(),String(row.id));preImages.push({targetEntity:ops.accountInserts[0]?.entity??"",rowId:row.id?String(row.id):null,action:"create",before:null,after:row})}}}if(accountRule&&ops.accountJoinInserts.length>0){let byEntity=new Map;for(let join7 of ops.accountJoinInserts){let accountId=accountIdByValue.get(join7.matchValue);if(!accountId){writeIssues.push({sourceIndex:-1,kind:"account_role_missing",message:`No account was found for \u201C${join7.matchValue}\u201D, so its ${join7.entity} row was not written \u2014 that person can sign in and do nothing.`});continue}let rows=byEntity.get(join7.entity)??[];rows.push({...join7.values,[join7.accountColumn]:accountId,createdAt:now,updatedAt:now,createdBy:userId}),byEntity.set(join7.entity,rows)}for(let[entity,rows]of byEntity){let resolved=deps.resolveEntity?.(entity);if(!resolved){writeIssues.push({sourceIndex:-1,kind:"account_role_missing",message:`The \u201C${entity}\u201D table is not available here, so ${rows.length} role membership(s) were not written. The accounts exist but hold no role.`});continue}for(let i=0;i<rows.length;i+=INSERT_CHUNK){if(cancelled())throw new CancelledError;let written=await tx.insert(resolved.table).values(rows.slice(i,i+INSERT_CHUNK)).returning();for(let row of written)preImages.push({targetEntity:entity,rowId:row.id?String(row.id):null,action:"create",before:null,after:row})}}}if(ops.creates.length>0){let rows=ops.creates.map((c)=>({...c.data,...accountRule&&c.data[accountRule.idColumn]==null?linkAccount(c.data,accountRule,accountIdByValue):{},createdAt:now,updatedAt:now,createdBy:userId}));for(let i=0;i<rows.length;i+=INSERT_CHUNK){if(cancelled())throw new CancelledError;let chunk=rows.slice(i,i+INSERT_CHUNK),written=await tx.insert(deps.drizzleTable).values(chunk).returning();created+=written.length;for(let row of written)preImages.push({targetEntity,rowId:row.id?String(row.id):null,action:"create",before:null,after:row})}}if(ops.deferredLinks.length>0)for(let group of groupDeferred(ops.deferredLinks)){if(cancelled())throw new CancelledError;let lookupCol=deps.resolveCol(group.lookupColumn),matchCol=deps.resolveCol(group.matchColumn),targetCol=deps.resolveCol(group.writeIdTo);if(!lookupCol||!matchCol||!targetCol){deps.logger.error(`[Integrations] Cannot fill "${group.writeIdTo}": ${[!lookupCol?group.lookupColumn:null,!matchCol?group.matchColumn:null,!targetCol?group.writeIdTo:null].filter(Boolean).join(", ")} is not a column of "${targetEntity}".`);continue}let rows=await tx.select({v:lookupCol,id:idCol}).from(deps.drizzleTable),idByValue={};for(let row of rows){if(row.v==null||row.v===""||row.id==null)continue;let key2=String(row.v).trim();if(!idByValue[key2])idByValue[key2]=String(row.id)}for(let link of group.links){let resolution=resolveReference(link.raw,idByValue);if(resolution.ids.length===0)continue;let value=link.isList?resolution.ids:resolution.ids[0],where=scope.length?and15(eq30(matchCol,link.matchValue),...scope):eq30(matchCol,link.matchValue);await tx.update(deps.drizzleTable).set({[group.writeIdTo]:value}).where(where),linksMade+=1}}return{created,accountsCreated,referencesCreated,updated,deleted,deactivated,linksMade}}),preImages,issues:writeIssues}}catch(error){if(error instanceof CancelledError)return{ok:!1,failure:{kind:"cancelled",message:"Cancelled while writing; the transaction was rolled back and nothing changed."}};if(error instanceof ScopeError)return{ok:!1,failure:{kind:"write_failed",message:`Row ${error.rowId} is outside what this account may write. Nothing was written.`}};return deps.logger.error(`[Integrations] Write transaction failed for "${targetEntity}": ${reasonOf2(error)}`),{ok:!1,failure:{kind:"write_failed",message:"The database rejected this import; it was rolled back and nothing changed."}}}}function reasonOf2(error){if(!(error instanceof Error))return String(error);let extra=error;return[error.message,extra.detail?`detail: ${String(extra.detail)}`:"",extra.constraint?`constraint: ${String(extra.constraint)}`:"",extra.hint?`hint: ${String(extra.hint)}`:"",extra.code?`code: ${String(extra.code)}`:""].filter(Boolean).join(" \u2014 ")}class CancelledError extends Error{constructor(){super("cancelled");this.name="CancelledError"}}class ScopeError extends Error{rowId;constructor(rowId){super(`row ${rowId} outside scope`);this.rowId=rowId;this.name="ScopeError"}}var DAY_MS=86400000;async function executeRun(context,deps,lock){let{mapping,source}=context,empty={runId:null,status:"failed",failure:null,plan:null,created:0,accountsCreated:0,referencesCreated:0,updated:0,deleted:0,deactivated:0,externalCalls:0,issues:[]},opened=await deps.repo.openRun({mappingId:mapping.id,targetEntity:mapping.targetEntity,writeMode:mapping.writeMode,trigger:context.trigger,userId:context.userId});if(!opened.ok)return{...empty,failure:{kind:"write_failed",message:`Could not open a run record: ${opened.error}`}};let runId=opened.runId;deps.onRunOpened?.(runId);let cancelChecked=0,cancelSeen=!1,isCancelled=()=>{if(cancelSeen)return!0;if(deps.abortSignal?.aborted)return cancelSeen=!0,!0;if(!lock.isHeld())return cancelSeen=!0,!0;return!1},refreshCancelFlag=async()=>{if(cancelChecked++,await deps.repo.isCancelRequested(runId))cancelSeen=!0},progress=(p)=>deps.publishProgress?.({runId,...p}),finish=async(outcome)=>{let revertible=outcome.status==="succeeded";return await deps.repo.closeRun(runId,{status:outcome.status,totalFetched:outcome.plan?.totalFetched??0,sourceReportedTotal:outcome.plan?.reportedTotal??null,createdCount:outcome.created,accountsCreatedCount:outcome.accountsCreated,referencesCreatedCount:outcome.referencesCreated,updatedCount:outcome.updated,skippedCount:outcome.plan?.toSkip??0,deletedCount:outcome.deleted,deactivatedCount:outcome.deactivated,errorCount:outcome.failure?1:0,externalCallCount:outcome.externalCalls,issues:outcome.issues,errors:outcome.failure?[outcome.failure.message]:[],finishedAt:new Date,preImagesExpireAt:revertible?new Date(Date.now()+(deps.retainPreImagesMs??30*DAY_MS)):null}),progress({phase:"done",message:outcome.failure?.message}),{runId,...outcome}};progress({phase:"fetching"});let nodes=context.endpoints.map((e)=>({id:e.id,paramBindings:e.paramBindings??void 0})),order=planFetchOrder(nodes,[context.rootEndpointId]);if(!order.ok){let failure=order.reason==="cycle"?{kind:"cycle_detected",message:`These endpoints depend on each other in a loop (${order.chain.join(" \u2192 ")}), so there is no correct place to start.`,chain:order.chain}:{kind:"fetch_failed",message:`"${order.requiredBy}" takes a parameter from an endpoint that no longer exists (${order.missing}).`};return finish({...empty,failure,status:"failed"})}let bearerToken=null;if(context.oauth){let token=await getAccessToken(context.oauth,deps.tokenCache,{fetchImpl:deps.fetchImpl});if(!token.ok)return finish({...empty,failure:{kind:"fetch_failed",message:token.error}});bearerToken=token.accessToken}let byId=new Map(context.endpoints.map((e)=>[e.id,e])),parents={},entityValues={},externalCalls=0,rootRecords=[],reportedTotal2=null;for(let endpointId of order.order){let endpoint=byId.get(endpointId);if(!endpoint)continue;if(await refreshCancelFlag(),isCancelled())return finish({...empty,status:"cancelled",externalCalls,failure:{kind:"cancelled",message:"Cancelled before anything was written."}});for(let key2 of entityValueKeys(endpoint.paramBindings??void 0)){if(entityValues[key2])continue;let[entity,field]=key2.split(".");entityValues[key2]=await deps.repo.readEntityColumn(entity,field)}let collected=await collectEndpoint(source,endpoint,{parents,entityValues},{fetchImpl:deps.fetchImpl,bearerToken,maxConcurrent:deps.maxConcurrentFanout,maxRecords:deps.maxRecordsPerRun,isCancelled,onProgress:(n)=>progress({phase:"fetching",processed:n})});if(externalCalls+=collected.callCount,!collected.ok){let cancelled=isCancelled();return finish({...empty,externalCalls,status:cancelled?"cancelled":"failed",failure:cancelled?{kind:"cancelled",message:"Cancelled before anything was written."}:{kind:"fetch_failed",message:collected.error}})}if(parents[endpointId]=collected.records.map((r)=>r.record),endpointId===context.rootEndpointId)rootRecords=collected.records,reportedTotal2=collected.reportedTotal}for(let id of Object.keys(parents))if(!(id===context.rootEndpointId||context.endpoints.some((e)=>parentEndpointIds(e.paramBindings??void 0).includes(id))))delete parents[id];if((mapping.writeMode==="replace"||mapping.missingPolicy==="delete")&&!isComplete(rootRecords.length,reportedTotal2))return finish({...empty,externalCalls,failure:{kind:"incomplete_source",message:`The source reports ${reportedTotal2} records but only ${rootRecords.length} were read. This run deletes what the source does not send, so it will not proceed on a partial read. Check the paging settings for this endpoint.`,fetched:rootRecords.length,reported:reportedTotal2??0}});progress({phase:"mapping",total:rootRecords.length});let mapped=buildMappedRecords(rootRecords.map((r)=>r.record),mapping.fieldMappings,mapping.dedupTargetField,rootRecords.map((r)=>r.parent));if(await refreshCancelFlag(),isCancelled())return finish({...empty,externalCalls,status:"cancelled",failure:{kind:"cancelled",message:"Cancelled before anything was written."}});let existing=await deps.repo.readExistingRows(mapping.targetEntity),referenceValues=await loadReferenceValues(mapping.references??[],(entity,column)=>deps.repo.readEntityColumn(entity,column)),referenceIds=await loadReferenceIds(mapping.references??[],mapping.targetEntity,(entity,column)=>deps.repo.readEntityIdsBy(entity,column)),existingAccounts=mapping.accountRule?await deps.repo.readEntityIdsBy(mapping.accountRule.entity,mapping.accountRule.matchColumn):{},ops=planWrites({records:mapped.records,existing,dedupTargetField:mapping.dedupTargetField,writeMode:mapping.writeMode,missingPolicy:mapping.missingPolicy,missingColumn:mapping.missingColumn,missingValue:mapping.missingValue,requiredFields:deps.repo.requiredFields(mapping.targetEntity),uniqueFields:deps.repo.uniqueFields(mapping.targetEntity),createDefaults:context.createDefaults??{},accountRule:mapping.accountRule??null,existingAccounts,references:mapping.references??[],referenceValues,referenceIds,targetEntity:mapping.targetEntity});ops.issues.unshift(...mapped.issues);let plan=summarize(ops,{targetEntity:mapping.targetEntity,writeMode:mapping.writeMode,missingPolicy:mapping.missingPolicy,totalFetched:rootRecords.length,reportedTotal:reportedTotal2,existingCount:existing.length,dedupConfigured:Boolean(mapping.dedupTargetField)});progress({phase:"writing",total:ops.creates.length+ops.updates.length});let applied=await applyWrites(deps.writer,{ops,targetEntity:mapping.targetEntity,userId:context.userId,account:mapping.accountRule&&context.accountPasswordHash?{idColumn:mapping.accountRule.idColumn,matchColumn:mapping.accountRule.matchColumn,matchFrom:mapping.accountRule.matchFrom,passwordColumn:mapping.accountRule.passwordColumn,passwordHash:context.accountPasswordHash}:null,missingColumn:mapping.missingColumn,missingValue:mapping.missingValue,isCancelled});if(!applied.ok){let failureIssues=applied.failure.kind==="validation_failed"?applied.failure.issues:[];return finish({...empty,plan,externalCalls,issues:[...ops.issues,...failureIssues],status:applied.failure.kind==="cancelled"?"cancelled":"failed",failure:applied.failure})}return await deps.repo.savePreImages(runId,applied.preImages),deps.logger.info("[Integrations] Run finished",{runId,mappingId:mapping.id,targetEntity:mapping.targetEntity,created:applied.created,accountsCreated:applied.accountsCreated,referencesCreated:applied.referencesCreated,updated:applied.updated,deleted:applied.deleted,deactivated:applied.deactivated,externalCalls,cancelChecks:cancelChecked}),finish({...empty,status:"succeeded",plan,failure:null,created:applied.created,accountsCreated:applied.accountsCreated,referencesCreated:applied.referencesCreated,updated:applied.updated,deleted:applied.deleted,deactivated:applied.deactivated,externalCalls,issues:[...ops.issues,...applied.issues]})}var RANGES=[[0,59],[0,23],[1,31],[1,12],[0,6]],NAMES=["minute","hour","day of month","month","day of week"];function expandField(raw,[min,max]){let values=new Set;for(let part of raw.split(",")){let[spec,stepText]=part.split("/"),step=stepText===void 0?1:Number(stepText);if(!Number.isInteger(step)||step<1)return null;let from,to;if(spec==="*")from=min,to=max;else if(spec?.includes("-")){let[a,b]=spec.split("-").map(Number);if(!Number.isInteger(a)||!Number.isInteger(b))return null;from=a,to=b}else{let one=Number(spec);if(!Number.isInteger(one))return null;from=one,to=stepText===void 0?one:max}if(from<min||to>max||from>to)return null;for(let v=from;v<=to;v+=step)values.add(v)}return values.size>0?values:null}function parseCron2(expression){let parts=expression.trim().split(/\s+/);if(parts.length!==5)return{ok:!1,error:`A schedule has five parts \u2014 minute hour day-of-month month day-of-week \u2014 and this has ${parts.length}. "0 2 * * *" is every night at 02:00.`};let sets=[];for(let i=0;i<5;i++){let field=expandField(parts[i],RANGES[i]);if(!field)return{ok:!1,error:`The ${NAMES[i]} part ("${parts[i]}") is not something I can read.`};sets.push(field)}return{ok:!0,fields:{minutes:sets[0],hours:sets[1],daysOfMonth:sets[2],months:sets[3],daysOfWeek:sets[4],anyDayOfMonth:parts[2]==="*",anyDayOfWeek:parts[4]==="*"}}}function partsIn2(when,timeZone){let formatter=new Intl.DateTimeFormat("en-US",{timeZone,hour12:!1,year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",weekday:"short"}),parts={};for(let part of formatter.formatToParts(when))parts[part.type]=part.value;let weekdays=["Sun","Mon","Tue","Wed","Thu","Fri","Sat"];return{year:Number(parts.year),month:Number(parts.month),day:Number(parts.day),hour:Number(parts.hour)%24,minute:Number(parts.minute),weekday:Math.max(0,weekdays.indexOf(parts.weekday??"Sun"))}}function matchesCron(fields,when,timeZone){let at=partsIn2(when,timeZone);if(!fields.minutes.has(at.minute))return!1;if(!fields.hours.has(at.hour))return!1;if(!fields.months.has(at.month))return!1;let dayOfMonthMatches=fields.daysOfMonth.has(at.day),dayOfWeekMatches=fields.daysOfWeek.has(at.weekday);if(fields.anyDayOfMonth&&fields.anyDayOfWeek)return!0;if(fields.anyDayOfMonth)return dayOfWeekMatches;if(fields.anyDayOfWeek)return dayOfMonthMatches;return dayOfMonthMatches||dayOfWeekMatches}var CATCH_UP_MINUTES=1500,MINUTE_MS=60000;function isDue(input){let parsed=parseCron2(input.expression);if(!parsed.ok)return{due:!1,error:parsed.error};let zone=input.timeZone?.trim()||"UTC",nowMinute=Math.floor(input.now.getTime()/MINUTE_MS),lookBack=0;if(input.lastRunAt){let lastMinute=Math.floor(input.lastRunAt.getTime()/MINUTE_MS);if(lastMinute>=nowMinute)return{due:!1};lookBack=Math.min(nowMinute-lastMinute-1,CATCH_UP_MINUTES)}try{for(let back=0;back<=lookBack;back++){let at=new Date((nowMinute-back)*MINUTE_MS);if(matchesCron(parsed.fields,at,zone))return{due:!0}}}catch{return{due:!1,error:`"${zone}" is not a timezone this system knows.`}}return{due:!1}}var MINUTE2=60000;function dueMappings(mappings,now){let due=[],problems=[];for(let mapping of mappings){if(!mapping.scheduleCron?.trim())continue;let answer=isDue({expression:mapping.scheduleCron,timeZone:mapping.scheduleTimezone,now,lastRunAt:mapping.lastRunAt??null});if(answer.error){problems.push({mapping,error:answer.error});continue}if(answer.due)due.push(mapping)}return{due,problems}}function startScheduler(deps){let now=deps.now??(()=>new Date),reported=new Set,stopped=!1,tick=async()=>{if(stopped)return;let mappings;try{mappings=await deps.listScheduled()}catch(error){deps.logger.error("[Integrations] Could not read the schedules",{error:error instanceof Error?error.message:String(error)});return}let{due,problems}=dueMappings(mappings,now());for(let problem of problems){let token=`${problem.mapping.id}:${problem.error}`;if(reported.has(token))continue;reported.add(token),deps.logger.error(`[Integrations] "${problem.mapping.name}" has a schedule that cannot run: ${problem.error}`)}for(let mapping of due)try{if(await deps.startRun(mapping.id))deps.logger.info(`[Integrations] Scheduled import started: ${mapping.name}`)}catch(error){deps.logger.error(`[Integrations] Scheduled import failed to start: ${mapping.name}`,{error:error instanceof Error?error.message:String(error)})}},timer=setInterval(()=>{tick()},MINUTE2);if(typeof timer==="object"&&timer&&"unref"in timer)timer.unref();return{stop:()=>{stopped=!0,clearInterval(timer)}}}var asObject=(value)=>value&&typeof value==="object"&&!Array.isArray(value)?value:null,asArray=(value)=>Array.isArray(value)?value:[],text=(value)=>{if(value==null)return null;let s=String(value);return s===""?null:s};function buildTransferDocument(input){let{source,endpoints,mappings}=input,nameById=new Map;for(let endpoint of endpoints){let id=text(endpoint.id),name2=text(endpoint.name);if(id&&name2)nameById.set(id,name2)}return{version:1,exportedAt:input.exportedAt,secretsExcluded:!0,connection:{name:String(source.name??""),slug:String(source.slug??""),baseUrl:String(source.baseUrl??""),description:text(source.description),authType:String(source.authType??"none"),authHeaderName:text(source.authHeaderName),authQueryParam:text(source.authQueryParam),extraHeaders:asObject(source.extraHeaders),tokenUrl:text(source.tokenUrl),oauthGrantType:text(source.oauthGrantType),oauthClientId:text(source.oauthClientId),oauthUsername:text(source.oauthUsername),oauthScope:text(source.oauthScope),oauthClientAuth:text(source.oauthClientAuth),tlsVerify:source.tlsVerify!==!1,timeoutMs:typeof source.timeoutMs==="number"?source.timeoutMs:null,enabled:source.enabled!==!1},endpoints:endpoints.map((endpoint)=>({name:String(endpoint.name??""),tag:String(endpoint.tag??""),method:String(endpoint.method??"GET"),path:String(endpoint.path??""),description:text(endpoint.description),queryParams:asObject(endpoint.queryParams),requestBody:asObject(endpoint.requestBody),responseRootPath:text(endpoint.responseRootPath),treeChildrenPath:text(endpoint.treeChildrenPath),pagination:asObject(endpoint.pagination),paramBindings:asArray(endpoint.paramBindings).map((binding)=>{if(binding.from!=="endpoint")return{...binding};let{endpointId,...rest}=binding;return{...rest,endpointName:nameById.get(String(endpointId))??null}}),enabled:endpoint.enabled!==!1})),mappings:mappings.map((mapping)=>({name:String(mapping.name??""),endpointName:nameById.get(String(mapping.endpointId))??null,targetEntity:String(mapping.targetEntity??""),fieldMappings:asArray(mapping.fieldMappings),referenceChecks:asArray(mapping.referenceChecks),dedupSourceField:text(mapping.dedupSourceField),dedupTargetField:text(mapping.dedupTargetField),writeMode:String(mapping.writeMode??"upsert")??"upsert",missingRecordPolicy:String(mapping.missingRecordPolicy??"ignore")??"ignore",missingRecordColumn:text(mapping.missingRecordColumn),missingRecordValue:text(mapping.missingRecordValue),passwordTargetColumn:text(mapping.passwordTargetColumn),accountRule:mapping.accountRule??null,scheduleEnabled:mapping.scheduleEnabled===!0,scheduleCron:text(mapping.scheduleCron),scheduleTimezone:text(mapping.scheduleTimezone),enabled:mapping.enabled!==!1}))}}function validateTransferDocument(value){let problems=[],doc=asObject(value);if(!doc)return{ok:!1,document:null,problems:[{path:"",message:"This is not an integration export file."}]};if(typeof doc.version!=="number")problems.push({path:"version",message:"The file does not say which format it is in."});else if(doc.version>1)problems.push({path:"version",message:`This file was written by a newer version (${doc.version}); this one understands up to 1.`});let connection=asObject(doc.connection);if(!connection)problems.push({path:"connection",message:"The file has no connection."});else{if(!text(connection.name))problems.push({path:"connection.name",message:"Missing name."});if(!text(connection.slug))problems.push({path:"connection.slug",message:"Missing slug."});if(!text(connection.baseUrl))problems.push({path:"connection.baseUrl",message:"Missing base URL."})}let endpoints=asArray(doc.endpoints),endpointNames=new Set;return endpoints.forEach((endpoint,index)=>{let name2=text(endpoint.name);if(!name2){problems.push({path:`endpoints[${index}].name`,message:"Missing name."});return}if(endpointNames.has(name2))problems.push({path:`endpoints[${index}].name`,message:`Two endpoints are called "${name2}"; names are how the rest of the file refers to them.`});if(endpointNames.add(name2),!text(endpoint.path))problems.push({path:`endpoints[${index}].path`,message:"Missing path."});if(!text(endpoint.tag))problems.push({path:`endpoints[${index}].tag`,message:"Missing tag."})}),endpoints.forEach((endpoint,index)=>{asArray(endpoint.paramBindings).forEach((binding,bindingIndex)=>{if(binding.from!=="endpoint")return;let target2=text(binding.endpointName);if(!target2||!endpointNames.has(target2))problems.push({path:`endpoints[${index}].paramBindings[${bindingIndex}]`,message:`Takes its value from an endpoint called "${target2??"?"}", which is not in this file.`})})}),asArray(doc.mappings).forEach((mapping,index)=>{if(!text(mapping.name))problems.push({path:`mappings[${index}].name`,message:"Missing name."});if(!text(mapping.targetEntity))problems.push({path:`mappings[${index}].targetEntity`,message:"Missing target table."});let endpointName=text(mapping.endpointName);if(!endpointName||!endpointNames.has(endpointName))problems.push({path:`mappings[${index}].endpointName`,message:`Reads from an endpoint called "${endpointName??"?"}", which is not in this file.`})}),{ok:problems.length===0,document:problems.length===0?doc:null,problems}}init_crypto();init_utils5();init_utils6();init_godminGuard();init_utils5();import Elysia12,{t as t10}from"elysia";async function testConnection(chain,tokenCache,deps={}){let{source,oauth}=chain,fetchImpl=deps.fetchImpl;if(oauth){tokenCache.invalidate(source.id);let token=await getAccessToken(oauth,tokenCache,{fetchImpl});return token.ok?{ok:!0,detail:`A token was issued (${token.accessToken.length} characters). The credentials and token address are valid.`}:{ok:!1,error:token.error}}let built=buildUrl(source.baseUrl,"");if(!built.ok)return{ok:!1,error:built.error};let{headers}=applyAuth(source,built.url),outcome=await fetchOnce(source,{method:"GET",url:built.url,headers},{fetchImpl});if(outcome.status===0)return{ok:!1,error:outcome.error};return{ok:outcome.status<500,detail:`The address answered: HTTP ${outcome.status}.`,error:outcome.status>=500?outcome.error:void 0}}var PREVIEW_LIMIT=1500;async function sampleEndpoint(source,endpoint,pathParams,tokenCache,oauth,deps={}){let fetchImpl=deps.fetchImpl,bearerToken=null;if(oauth){let token=await getAccessToken(oauth,tokenCache,{fetchImpl});if(!token.ok)return blank({error:token.error});bearerToken=token.accessToken}let values={...endpoint.queryParams??{},...pathParams??{}},resolved=resolvePath2(endpoint.path,values);if(resolved.missing.length>0)return blank({error:`This endpoint needs a value for ${resolved.missing.map((m)=>`{${m}}`).join(", ")}. Enter an example value to test it (e.g. ${resolved.missing[0]} = 12345).`});let query={};for(let[key2,value]of Object.entries(values)){if(value==null||resolved.used.has(key2))continue;query[key2]=value}let built=buildUrl(source.baseUrl,resolved.path,query);if(!built.ok)return blank({error:built.error});let{headers}=applyAuth({...source,token:bearerToken??source.token},built.url);if(bearerToken)headers.Authorization=`Bearer ${bearerToken}`;let outcome=await fetchOnce(source,{method:endpoint.method,url:built.url,headers,body:endpoint.method.toUpperCase()==="GET"?void 0:endpoint.requestBody??{}},{fetchImpl}),bodyKeys=outcome.body&&typeof outcome.body==="object"&&!Array.isArray(outcome.body)?Object.keys(outcome.body).slice(0,40):[];if(!outcome.ok)return blank({status:outcome.status,error:outcome.error??`HTTP ${outcome.status}`,bodyKeys,bodyPreview:previewBody(outcome.body)});let childrenPath=treeChildrenPath(endpoint.treeChildrenPath),extracted=extractRecords(outcome.body,endpoint.responseRootPath),flattened=childrenPath?flattenTree(extracted,childrenPath):null;if(flattened?.truncated)return blank({status:outcome.status,error:"This source answered with a structure that nests into itself, so it cannot be walked. Check the field named as the children.",bodyKeys,bodyPreview:previewBody(outcome.body)});let records=flattened?flattened.records:extracted;return{ok:!0,status:outcome.status,error:records.length===0?bodyKeys.length>0?`No record array was found. The response's top-level keys are: ${bodyKeys.join(", ")} \u2014 set the response root path to whichever holds the list.`:"No record array was found in the response.":null,recordCount:records.length,sample:records.slice(0,5),fields:records.length>0?flattenKeys(records[0]):[],bodyKeys,bodyPreview:previewBody(outcome.body)}}function blank(over){return{ok:!1,status:0,error:null,recordCount:0,sample:[],fields:[],bodyKeys:[],bodyPreview:null,...over}}function previewBody(body){if(body==null)return null;try{let text2=typeof body==="string"?body:JSON.stringify(body);return text2.length>PREVIEW_LIMIT?`${text2.slice(0,PREVIEW_LIMIT)}\u2026`:text2}catch{return null}}async function previewRun(chain,tokenCache,lookups,deps={}){let fetchImpl=deps.fetchImpl,{mapping,source,oauth}=chain,bearerToken=null;if(oauth){let token=await getAccessToken(oauth,tokenCache,{fetchImpl});if(!token.ok)return{ok:!1,error:token.error};bearerToken=token.accessToken}let root=chain.endpoints.find((e)=>e.id===chain.rootEndpointId);if(!root)return{ok:!1,error:"The endpoint this mapping reads no longer exists."};let parents={},entityValues={},externalCalls=0;for(let binding of root.paramBindings??[]){if(binding.from==="endpoint"&&!parents[binding.endpointId]){let parentSpec=chain.endpoints.find((e)=>e.id===binding.endpointId);if(!parentSpec)continue;let collected2=await collectEndpoint(source,parentSpec,{},{fetchImpl,bearerToken,maxConcurrent:deps.maxConcurrent,maxRecords:deps.maxRecords});if(externalCalls+=collected2.callCount,!collected2.ok)return{ok:!1,error:collected2.error};parents[binding.endpointId]=collected2.records.map((r)=>r.record)}if(binding.from==="entity"){let key2=`${binding.entity}.${binding.field}`;if(!entityValues[key2])entityValues[key2]=await lookups.readEntityColumn(binding.entity,binding.field)}}let collected=await collectEndpoint(source,root,{parents,entityValues},{fetchImpl,bearerToken,maxConcurrent:deps.maxConcurrent,maxRecords:deps.maxRecords});if(externalCalls+=collected.callCount,!collected.ok)return{ok:!1,error:collected.error};let mapped=buildMappedRecords(collected.records.map((r)=>r.record),mapping.fieldMappings,mapping.dedupTargetField,collected.records.map((r)=>r.parent)),existing=await lookups.readExistingRows(mapping.targetEntity),referenceValues=await loadReferenceValues(mapping.references??[],(entity,column)=>lookups.readEntityColumn(entity,column)),referenceIds=await loadReferenceIds(mapping.references??[],mapping.targetEntity,(entity,column)=>lookups.readEntityIdsBy(entity,column)),existingAccounts=mapping.accountRule?await lookups.readEntityIdsBy(mapping.accountRule.entity,mapping.accountRule.matchColumn):{},ops=planWrites({records:mapped.records,existing,dedupTargetField:mapping.dedupTargetField,writeMode:mapping.writeMode,missingPolicy:mapping.missingPolicy,missingColumn:mapping.missingColumn,missingValue:mapping.missingValue,requiredFields:lookups.requiredFields(mapping.targetEntity),uniqueFields:lookups.uniqueFields(mapping.targetEntity),createDefaults:mapping.passwordColumn?{[mapping.passwordColumn]:"\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022"}:{},accountRule:mapping.accountRule??null,existingAccounts,references:mapping.references??[],referenceValues,referenceIds,targetEntity:mapping.targetEntity});ops.issues.unshift(...mapped.issues);let invalid=lookups.validateRows?.(ops.creates)??[];for(let problem of invalid){let create3=ops.creates.find((c)=>c.sourceIndex===problem.sourceIndex);ops.issues.push({sourceIndex:problem.sourceIndex,kind:"invalid_value",message:problem.message,row:create3?.data})}if(invalid.length>0){let refused=new Set(invalid.map((problem)=>problem.sourceIndex));ops.creates=ops.creates.filter((create3)=>!refused.has(create3.sourceIndex))}return{ok:!0,externalCalls,plan:summarize(ops,{targetEntity:mapping.targetEntity,writeMode:mapping.writeMode,missingPolicy:mapping.missingPolicy,totalFetched:collected.records.length,reportedTotal:collected.reportedTotal,existingCount:existing.length,dedupConfigured:Boolean(mapping.dedupTargetField)})}}init_crypto();import{and as and16,eq as eq31,inArray as inArray11}from"drizzle-orm";var camel2=(s)=>s.replace(/_([a-z])/g,(_,l)=>l.toUpperCase());function tableFor(deps,entity){return deps.schemaTables[camel2(entity)]??null}var col8=(table,field)=>table?.[field]??table?.[camel2(field)];function open(deps,envelope,where){if(typeof envelope!=="string"||envelope==="")return"";let key2=deps.getEncryptionKey();if(!key2)return deps.logger.error("[Integrations] A stored credential cannot be read: no encryption key",{column:where}),"";try{return decryptSecret(envelope,key2)}catch{return deps.logger.error("[Integrations] A stored credential could not be decrypted \u2014 the encryption key has changed since it was saved. Re-enter it in the panel.",{column:where}),""}}async function resolveChain(deps,mappingId){let mappings=tableFor(deps,"integration_mappings"),endpoints=tableFor(deps,"integration_endpoints"),sources=tableFor(deps,"integration_sources");if(!mappings||!endpoints||!sources)return{ok:!1,error:"The integration tables are not present in this schema."};let[mappingRow]=await deps.db.select().from(mappings).where(eq31(col8(mappings,"id"),mappingId)).limit(1);if(!mappingRow)return{ok:!1,error:"This mapping no longer exists."};let row=mappingRow,[endpointRow]=await deps.db.select().from(endpoints).where(eq31(col8(endpoints,"id"),String(row.endpointId))).limit(1);if(!endpointRow)return{ok:!1,error:"The endpoint this mapping reads no longer exists."};if(endpointRow.enabled===!1)return{ok:!1,error:"The call this mapping reads is switched off."};if(row.enabled===!1)return{ok:!1,error:"This mapping is switched off."};let sourceId=String(endpointRow.sourceId),siblingRows=await deps.db.select().from(endpoints).where(eq31(col8(endpoints,"sourceId"),sourceId)),[sourceRow]=await deps.db.select().from(sources).where(eq31(col8(sources,"id"),sourceId)).limit(1);if(!sourceRow)return{ok:!1,error:"The source this mapping reads no longer exists."};let s=sourceRow;if(s.enabled===!1)return{ok:!1,error:"This source is switched off."};let authType=String(s.authType??"none"),source={id:String(s.id),baseUrl:String(s.baseUrl??""),authType,token:authType==="oauth2"?null:open(deps,s.authTokenEncrypted,"auth_token_encrypted"),authHeaderName:s.authHeaderName??null,authQueryParam:s.authQueryParam??null,extraHeaders:s.extraHeaders??null,tlsVerify:s.tlsVerify!==!1,timeoutMs:Number(s.timeoutMs??30000)},oauth=authType==="oauth2"?{sourceId:source.id,tokenUrl:String(s.tokenUrl??""),grantType:String(s.oauthGrantType??"password")==="client_credentials"?"client_credentials":"password",clientId:s.oauthClientId??null,clientSecret:open(deps,s.oauthClientSecretEncrypted,"oauth_client_secret_encrypted"),username:s.oauthUsername??null,password:open(deps,s.oauthPasswordEncrypted,"oauth_password_encrypted"),scope:s.oauthScope??null,clientAuth:String(s.oauthClientAuth??"basic")==="body"?"body":"basic",tlsVerify:source.tlsVerify,timeoutMs:source.timeoutMs}:null;return{ok:!0,chain:{mapping:toMappingSpec(row),endpoints:siblingRows.map((e)=>toEndpointSpec(e)),rootEndpointId:String(endpointRow.id),source,oauth}}}async function resolveEndpointContext(deps,by){let sources=tableFor(deps,"integration_sources"),endpoints=tableFor(deps,"integration_endpoints");if(!sources||!endpoints)return{ok:!1,error:"The integration tables are not present in this schema."};let endpointRow=null,sourceId=by.sourceId;if(by.endpointId){let[row]=await deps.db.select().from(endpoints).where(eq31(col8(endpoints,"id"),by.endpointId)).limit(1);if(!row)return{ok:!1,error:"This endpoint no longer exists."};endpointRow=row,sourceId=String(endpointRow.sourceId)}if(!sourceId)return{ok:!1,error:"No source was named."};let[sourceRow]=await deps.db.select().from(sources).where(eq31(col8(sources,"id"),sourceId)).limit(1);if(!sourceRow)return{ok:!1,error:"This source no longer exists."};let{source,oauth}=toConnection(deps,sourceRow);return{ok:!0,context:{source,oauth,endpoint:endpointRow?toEndpointSpec(endpointRow):null}}}async function cacheEndpointSample(deps,endpointId,records){let endpoints=tableFor(deps,"integration_endpoints");if(!endpoints||records.length===0)return;try{await deps.db.update(endpoints).set({sampleResponse:{records:records.slice(0,3)},updatedAt:new Date}).where(eq31(col8(endpoints,"id"),endpointId))}catch(error){deps.logger.warn("[Integrations] Could not cache the endpoint sample",{endpointId,error:error instanceof Error?error.message:String(error)})}}function toConnection(deps,s){let authType=String(s.authType??"none"),source={id:String(s.id),baseUrl:String(s.baseUrl??""),authType,token:authType==="oauth2"?null:open(deps,s.authTokenEncrypted,"auth_token_encrypted"),authHeaderName:s.authHeaderName??null,authQueryParam:s.authQueryParam??null,extraHeaders:s.extraHeaders??null,tlsVerify:s.tlsVerify!==!1,timeoutMs:Number(s.timeoutMs??30000)},oauth=authType==="oauth2"?{sourceId:source.id,tokenUrl:String(s.tokenUrl??""),grantType:String(s.oauthGrantType??"password")==="client_credentials"?"client_credentials":"password",clientId:s.oauthClientId??null,clientSecret:open(deps,s.oauthClientSecretEncrypted,"oauth_client_secret_encrypted"),username:s.oauthUsername??null,password:open(deps,s.oauthPasswordEncrypted,"oauth_password_encrypted"),scope:s.oauthScope??null,clientAuth:String(s.oauthClientAuth??"basic")==="body"?"body":"basic",tlsVerify:source.tlsVerify,timeoutMs:source.timeoutMs}:null;return{source,oauth}}function toMappingSpec(row){return{id:String(row.id),name:String(row.name??""),targetEntity:String(row.targetEntity??""),fieldMappings:Array.isArray(row.fieldMappings)?row.fieldMappings:[],references:Array.isArray(row.referenceChecks)?row.referenceChecks:[],dedupTargetField:row.dedupTargetField||null,writeMode:String(row.writeMode??"upsert")??"upsert",missingPolicy:String(row.missingRecordPolicy??"ignore")??"ignore",missingColumn:row.missingRecordColumn??null,missingValue:row.missingRecordValue??null,passwordColumn:row.passwordTargetColumn||null,accountRule:row.accountRule??null}}function toEndpointSpec(row){let pagination=row.pagination;return{id:String(row.id),method:String(row.method??"GET"),path:String(row.path??""),queryParams:row.queryParams??null,requestBody:row.requestBody??null,responseRootPath:row.responseRootPath||null,treeChildrenPath:row.treeChildrenPath||null,pagination:pagination&&typeof pagination==="object"&&"kind"in pagination?pagination:{kind:"none"},paramBindings:Array.isArray(row.paramBindings)?row.paramBindings:null}}async function readConnectionBundle(deps,sourceId){let sources=tableFor(deps,"integration_sources"),endpoints=tableFor(deps,"integration_endpoints"),mappings=tableFor(deps,"integration_mappings");if(!sources||!endpoints||!mappings)return null;let[sourceRow]=await deps.db.select().from(sources).where(eq31(col8(sources,"id"),sourceId)).limit(1);if(!sourceRow)return null;let endpointRows=await deps.db.select().from(endpoints).where(eq31(col8(endpoints,"sourceId"),sourceId)),ids=new Set(endpointRows.map((row)=>String(row.id))),allMappings=await deps.db.select().from(mappings);return{source:sourceRow,endpoints:endpointRows,mappings:allMappings.filter((row)=>ids.has(String(row.endpointId)))}}async function applyTransferDocument(deps,document2,userId){let sources=tableFor(deps,"integration_sources"),endpoints=tableFor(deps,"integration_endpoints"),mappings=tableFor(deps,"integration_mappings");if(!sources||!endpoints||!mappings)return{ok:!1,error:"The integration tables are not present in this schema."};return deps.db.transaction(async(tx)=>{let now=new Date,c=document2.connection,connectionValues={name:c.name,slug:c.slug,baseUrl:c.baseUrl,description:c.description??null,authType:c.authType,authHeaderName:c.authHeaderName??null,authQueryParam:c.authQueryParam??null,extraHeaders:c.extraHeaders??null,tokenUrl:c.tokenUrl??null,oauthGrantType:c.oauthGrantType??null,oauthClientId:c.oauthClientId??null,oauthUsername:c.oauthUsername??null,oauthScope:c.oauthScope??null,oauthClientAuth:c.oauthClientAuth??null,tlsVerify:c.tlsVerify!==!1,timeoutMs:c.timeoutMs??null,enabled:c.enabled!==!1,updatedAt:now,updatedBy:userId},[existingSource]=await tx.select().from(sources).where(eq31(col8(sources,"slug"),c.slug)).limit(1),sourceId,created=!1;if(existingSource)sourceId=String(existingSource.id),await tx.update(sources).set(connectionValues).where(eq31(col8(sources,"id"),sourceId));else{let[row]=await tx.insert(sources).values({...connectionValues,createdAt:now,createdBy:userId}).returning();if(!row?.id)return{ok:!1,error:"The connection could not be created."};sourceId=String(row.id),created=!0}let existingEndpoints=await tx.select().from(endpoints).where(eq31(col8(endpoints,"sourceId"),sourceId)),endpointIdByName=new Map;for(let row of existingEndpoints)endpointIdByName.set(String(row.name),String(row.id));for(let endpoint of document2.endpoints){let values={sourceId,name:endpoint.name,tag:endpoint.tag,method:endpoint.method,path:endpoint.path,description:endpoint.description??null,queryParams:endpoint.queryParams??null,requestBody:endpoint.requestBody??null,responseRootPath:endpoint.responseRootPath??null,treeChildrenPath:endpoint.treeChildrenPath??null,pagination:endpoint.pagination??null,enabled:endpoint.enabled!==!1,updatedAt:now,updatedBy:userId},existingId=endpointIdByName.get(endpoint.name);if(existingId)await tx.update(endpoints).set(values).where(eq31(col8(endpoints,"id"),existingId));else{let[row]=await tx.insert(endpoints).values({...values,paramBindings:[],createdAt:now,createdBy:userId}).returning();if(row?.id)endpointIdByName.set(endpoint.name,String(row.id))}}for(let endpoint of document2.endpoints){let id=endpointIdByName.get(endpoint.name);if(!id)continue;let bindings=(endpoint.paramBindings??[]).map((binding)=>{if(binding.from!=="endpoint")return binding;let{endpointName,...rest}=binding;return{...rest,endpointId:endpointIdByName.get(String(endpointName))??""}});await tx.update(endpoints).set({paramBindings:bindings,updatedAt:now}).where(eq31(col8(endpoints,"id"),id))}let allMappings=await tx.select().from(mappings),ownIds=new Set(endpointIdByName.values()),mappingIdByName=new Map;for(let row of allMappings)if(ownIds.has(String(row.endpointId)))mappingIdByName.set(String(row.name),String(row.id));let mappingCount=0;for(let mapping of document2.mappings){let endpointId=mapping.endpointName?endpointIdByName.get(mapping.endpointName):void 0;if(!endpointId)continue;let values={endpointId,name:mapping.name,targetEntity:mapping.targetEntity,fieldMappings:mapping.fieldMappings??[],referenceChecks:mapping.referenceChecks??[],dedupSourceField:mapping.dedupSourceField??null,dedupTargetField:mapping.dedupTargetField??null,writeMode:mapping.writeMode,missingRecordPolicy:mapping.missingRecordPolicy,missingRecordColumn:mapping.missingRecordColumn??null,missingRecordValue:mapping.missingRecordValue??null,passwordTargetColumn:mapping.passwordTargetColumn??null,accountRule:mapping.accountRule??null,scheduleEnabled:mapping.scheduleEnabled===!0,scheduleCron:mapping.scheduleCron??null,scheduleTimezone:mapping.scheduleTimezone??null,enabled:mapping.enabled!==!1,updatedAt:now,updatedBy:userId},existingId=mappingIdByName.get(mapping.name);if(existingId)await tx.update(mappings).set(values).where(eq31(col8(mappings,"id"),existingId));else await tx.insert(mappings).values({...values,createdAt:now,createdBy:userId});mappingCount++}return{ok:!0,sourceId,created,endpoints:endpointIdByName.size,mappings:mappingCount}})}async function readScheduledMappings(deps){let mappings=tableFor(deps,"integration_mappings");if(!mappings)return[];return(await deps.db.select().from(mappings)).filter((row)=>row.scheduleEnabled===!0&&row.enabled!==!1).filter((row)=>typeof row.scheduleCron==="string"&&row.scheduleCron.trim()!=="").map((row)=>({id:String(row.id),name:String(row.name??""),scheduleCron:String(row.scheduleCron),scheduleTimezone:row.scheduleTimezone??null,lastRunAt:row.lastRunAt?new Date(row.lastRunAt):null,needsPassword:Boolean(row.passwordTargetColumn)||row.accountRule!=null}))}function requiredFieldsOf(entities,targetEntity){return(entities.find((e)=>e.table_name===targetEntity)?.columns??[]).filter((c)=>c.notNull===!0&&c.default===void 0&&!c.defaultRaw&&!c.nullable).map((c)=>camel2(c.name))}function uniqueFieldsOf(entities,targetEntity){let entity=entities.find((e)=>e.table_name===targetEntity),columns=entity?.columns??[],fields=new Set;for(let column of columns)if(column.unique===!0||column.primaryKey===!0)fields.add(camel2(column.name));for(let index of entity?.indexes??[])if(index.unique===!0&&index.columns.length===1&&index.columns[0])fields.add(camel2(index.columns[0]));return fields.delete("id"),[...fields]}function createRunRepository(deps,entities){let runs=()=>tableFor(deps,"integration_runs"),runItems=()=>tableFor(deps,"integration_run_items");return{async openRun(input){let table=runs();if(!table)return{ok:!1,error:"integration_runs is missing from this schema."};try{let id=(await deps.db.insert(table).values({mappingId:input.mappingId,targetEntity:input.targetEntity,writeMode:input.writeMode,trigger:input.trigger,status:"running",startedAt:new Date,createdBy:input.userId}).returning())[0]?.id;return id?{ok:!0,runId:String(id)}:{ok:!1,error:"The run record was created but returned no identifier."}}catch(error){return{ok:!1,error:error instanceof Error?error.message:String(error)}}},async closeRun(runId,patch){let table=runs();if(!table)return{ok:!1,error:"integration_runs is missing from this schema."};try{let mappingId=(await deps.db.update(table).set({...patch,updatedAt:new Date}).where(eq31(col8(table,"id"),runId)).returning())[0]?.mappingId,finishedAt=patch.finishedAt,mappings=tableFor(deps,"integration_mappings");if(mappings&&mappingId&&finishedAt)await deps.db.update(mappings).set({lastRunAt:finishedAt,updatedAt:new Date}).where(eq31(col8(mappings,"id"),String(mappingId)));return{ok:!0}}catch(error){return deps.logger.error("[Integrations] Could not close the run record",{runId,error:error instanceof Error?error.message:String(error)}),{ok:!1,error:"Could not write the run record."}}},async savePreImages(runId,images){let table=runItems();if(!table||images.length===0)return;let CHUNK2=500;try{for(let i=0;i<images.length;i+=CHUNK2)await deps.db.insert(table).values(images.slice(i,i+CHUNK2).map((image)=>({runId,targetEntity:image.targetEntity,rowId:image.rowId,action:image.action,before:image.before,after:image.after})))}catch(error){deps.logger.error("[Integrations] The run succeeded but its before-images could not be stored; it cannot be undone",{runId,error:error instanceof Error?error.message:String(error)})}},async isCancelRequested(runId){let table=runs();if(!table)return!1;try{let[row]=await deps.db.select().from(table).where(eq31(col8(table,"id"),runId)).limit(1);return row?.cancelRequested===!0}catch{return!1}},async readExistingRows(targetEntity){let table=tableFor(deps,targetEntity);if(!table)return[];return(await deps.db.select().from(table)).map((row)=>({id:String(row.id),row}))},async readEntityColumn(entity,field){let table=tableFor(deps,entity),column=table?col8(table,field):void 0;if(!table||!column)return[];return(await deps.db.selectDistinct({v:column}).from(table)).map((r)=>r.v).filter((v)=>v!=null&&v!=="")},async readEntityIdsBy(entity,field){let table=tableFor(deps,entity),column=table?col8(table,field):void 0,idColumn=table?col8(table,"id"):void 0;if(!table||!column||!idColumn)return{};let rows=await deps.db.select({v:column,id:idColumn}).from(table),map={};for(let row of rows){if(row.v==null||row.v===""||row.id==null)continue;let key2=String(row.v).trim();if(!map[key2])map[key2]=String(row.id)}return map},requiredFields:(targetEntity)=>requiredFieldsOf(entities,targetEntity),uniqueFields:(targetEntity)=>uniqueFieldsOf(entities,targetEntity)}}async function readRowsById(deps,targetEntity,ids){let table=tableFor(deps,targetEntity),result=new Map;if(!table||ids.length===0)return result;let CHUNK2=1000;for(let i=0;i<ids.length;i+=CHUNK2){let rows=await deps.db.select().from(table).where(inArray11(col8(table,"id"),ids.slice(i,i+CHUNK2)));for(let row of rows)result.set(String(row.id),row)}return result}async function readPreImages(deps,runId){let table=tableFor(deps,"integration_run_items");if(!table)return[];return(await deps.db.select().from(table).where(eq31(col8(table,"runId"),runId))).map((row)=>({targetEntity:String(row.targetEntity),rowId:row.rowId?String(row.rowId):null,action:String(row.action),before:row.before??null,after:row.after??null}))}async function readRun(deps,runId){let table=tableFor(deps,"integration_runs");if(!table)return null;let[row]=await deps.db.select().from(table).where(eq31(col8(table,"id"),runId)).limit(1);return row??null}async function requestCancel(deps,runId){let table=tableFor(deps,"integration_runs");if(!table)return!1;return(await deps.db.update(table).set({cancelRequested:!0,updatedAt:new Date}).where(and16(eq31(col8(table,"id"),runId),eq31(col8(table,"status"),"running"))).returning()).length>0}var fail3=(set,status,message)=>{return set.status=status,{isSuccess:!1,message,data:null}};function createInspectRoutes(routeConfig,deps,tokenCache){let plugin=new Elysia12,settings=routeConfig.resolvedOptions.integrations??{};return plugin.post("/sources/:id/test",async({params,set})=>{let repoDeps=deps();if(!repoDeps)return fail3(set,503,"The database is not available.");let context=await resolveEndpointContext(repoDeps,{sourceId:params.id});if(!context.ok)return fail3(set,404,context.error);let result=await testConnection(context.context,tokenCache);return{isSuccess:result.ok,message:result.ok?result.detail??"Connected.":result.error??"Could not connect.",data:result}},{detail:{tags:["Integrations"],summary:"Check a source is reachable and its credentials are accepted"}}),plugin.post("/endpoints/:id/sample",async({params,body,set})=>{let repoDeps=deps();if(!repoDeps)return fail3(set,503,"The database is not available.");let context=await resolveEndpointContext(repoDeps,{endpointId:params.id});if(!context.ok)return fail3(set,404,context.error);let{source,oauth,endpoint}=context.context;if(!endpoint)return fail3(set,404,"This endpoint no longer exists.");let result=await sampleEndpoint(source,endpoint,body?.pathParams,tokenCache,oauth);if(result.ok&&result.sample.length>0)await cacheEndpointSample(repoDeps,params.id,result.sample);return{isSuccess:result.ok,message:result.error??"Sampled.",data:result}},{body:t10.Optional(t10.Object({pathParams:t10.Optional(t10.Record(t10.String(),t10.Unknown()))})),detail:{tags:["Integrations"],summary:"Call one endpoint once and report its real shape"}}),plugin.post("/preview",async({body,set})=>{let repoDeps=deps();if(!repoDeps)return fail3(set,503,"The database is not available.");let chain=await resolveChain(repoDeps,body.mappingId);if(!chain.ok)return fail3(set,404,chain.error);let repo=createRunRepository(repoDeps,repoDeps.entities),result=await previewRun(chain.chain,tokenCache,{readExistingRows:repo.readExistingRows,readEntityColumn:repo.readEntityColumn,requiredFields:repo.requiredFields,uniqueFields:repo.uniqueFields,readEntityIdsBy:repo.readEntityIdsBy,validateRows:(rows)=>{let columns=repoDeps.entities.find((e)=>e.table_name===chain.chain.mapping.targetEntity)?.columns??[],problems=[];for(let row of rows){let result2=validatePayload(row.data,columns,!1);if(!result2.valid)problems.push({sourceIndex:row.sourceIndex,message:result2.errors.map((e)=>`${e.field}: ${e.message}`).join("; ")})}return problems}},{maxRecords:settings.maxRecordsPerRun,maxConcurrent:settings.maxConcurrentFanout});if(!result.ok)return fail3(set,422,result.error);return{isSuccess:!0,message:"Nothing was written.",data:{plan:result.plan,externalCalls:result.externalCalls}}},{body:t10.Object({mappingId:t10.String()}),detail:{tags:["Integrations"],summary:"Dry-run an import: counts, warnings and a sample, with no writes"}}),plugin}var fail4=(set,status,message)=>{return set.status=status,{isSuccess:!1,message,data:null}},tokenCache=new TokenCache;function createIntegrationRoutes(routeConfig){let{logger:logger2,basePath,db,schemaTables,resolvedOptions,getEncryptionKey,getLockStore,publish}=routeConfig,plugin=new Elysia13({prefix:basePath}),entities=resolvedOptions.entities??[],settings=resolvedOptions.integrations??{},topicPrefix=settings.realtimeTopicPrefix||"integrations",guard2=createGodminGuard2({logger:logger2,db,schemaTables,area:"data integrations",allowedRoles:routeConfig.adminRoles??settings.adminRoles});plugin.onBeforeHandle(guard2);let deps=()=>db?{db,schemaTables,entities,logger:logger2,getEncryptionKey}:null;plugin.use(createInspectRoutes(routeConfig,deps,tokenCache));let writerFor=(repoDeps,targetEntity)=>{let table=tableFor(repoDeps,targetEntity);if(!table)return null;let entity=entities.find((e)=>e.table_name===targetEntity);return{db:repoDeps.db,drizzleTable:table,resolveCol:(field)=>table[field]??table[field.replace(/_([a-z])/g,(_m,l)=>l.toUpperCase())],columns:entity?.columns??[],logger:logger2,validatePayload,resolveEntity:(name2)=>{let refTable=tableFor(repoDeps,name2);if(!refTable)return null;let refEntity=entities.find((e)=>e.table_name===name2);return{table:refTable,columns:refEntity?.columns??[]}}}};plugin.post("/runs",async({body,set,request})=>{let repoDeps=deps();if(!repoDeps)return fail4(set,503,"The database is not available.");let chain=await resolveChain(repoDeps,body.mappingId);if(!chain.ok)return fail4(set,404,chain.error);let declared=chain.chain.mapping,answer=body.referenceMode,mapping=answer?{...declared,references:(declared.references??[]).map((check)=>check.onMissing==="ignore"?check:{...check,onMissing:answer})}:declared,wantsPassword=Boolean(mapping.passwordColumn||mapping.accountRule),createDefaults,accountPasswordHash=null;if(wantsPassword){let supplied=typeof body.sharedPassword==="string"?body.sharedPassword:"";if(supplied.length<8)return fail4(set,422,mapping.accountRule?"This import creates a login for every new record, so it needs a password to create them with: send sharedPassword, at least 8 characters. It is used once, for this run, and is stored nowhere.":`This mapping writes a password into "${mapping.passwordColumn}", so it needs one to write: send sharedPassword, at least 8 characters. It is used for the accounts this run creates and is not stored anywhere.`);let hash=await hashPassword(supplied);if(accountPasswordHash=hash,mapping.passwordColumn)createDefaults={[mapping.passwordColumn]:hash}}if((mapping.writeMode==="replace"||mapping.missingPolicy==="delete")&&body.confirm!==!0)return set.status=428,{isSuccess:!1,message:mapping.writeMode==="replace"?"This mapping rebuilds the whole table. Send confirm: true to proceed.":"This mapping deletes records the source no longer carries. Send confirm: true to proceed.",data:null};let lockStore=getLockStore();if(!lockStore)return fail4(set,503,"The lock service is unavailable, so a second run of this mapping could not be prevented. Runs are refused until it is back.");let lock=await acquireRunLock(lockStore,mapping.id,{logger:logger2});if(!lock.ok){if(lock.reason==="unavailable")return fail4(set,503,`The lock service is unavailable: ${lock.error}`);return set.status=409,{isSuccess:!1,message:"This mapping is already importing. Wait for it to finish, or cancel it.",data:{heldSince:lock.heldSince}}}let writer=writerFor(repoDeps,mapping.targetEntity);if(!writer)return await lock.handle.release(),fail4(set,422,`This mapping targets "${mapping.targetEntity}", which does not exist.`);let userId=request.headers.get("x-user-id")??"unknown",repo=createRunRepository(repoDeps,entities),announce=()=>{},runIdReady=new Promise((resolve2)=>{announce=resolve2}),started=executeRun({...chain.chain,mapping,userId,trigger:"manual",createDefaults,accountPasswordHash},{repo,writer,logger:logger2,tokenCache,publishProgress:(progress)=>publish?.(`${topicPrefix}.run`,progress),onRunOpened:(id)=>announce(id),maxRecordsPerRun:settings.maxRecordsPerRun,maxConcurrentFanout:settings.maxConcurrentFanout,retainPreImagesMs:parseDuration(settings.retainPreImagesFor)},lock.handle),runId=await Promise.race([runIdReady,started.then((outcome)=>outcome.runId)]);return started.catch(async(error)=>{let reason=error instanceof Error?error.message:String(error);logger2.error("[Integrations] Run threw outside its own error handling",{mappingId:mapping.id,error:reason});let openedId=await runIdReady.catch(()=>null);if(openedId)await repo.closeRun(openedId,{status:"failed",finishedAt:new Date,errors:[reason]}).catch(()=>{})}).finally(()=>lock.handle.release()),set.status=202,{isSuccess:!0,message:"The import has started.",data:{runId,mappingId:mapping.id,targetEntity:mapping.targetEntity}}},{body:t11.Object({mappingId:t11.String(),confirm:t11.Optional(t11.Boolean()),sharedPassword:t11.Optional(t11.String()),referenceMode:t11.Optional(t11.Union([t11.Literal("create"),t11.Literal("skipRecord")]))}),detail:{tags:["Integrations"],summary:"Start an import; answers 202 with the run identifier"}});let startScheduledRun=async(mappingId)=>{let repoDeps=deps();if(!repoDeps)return!1;let chain=await resolveChain(repoDeps,mappingId);if(!chain.ok)return logger2.error(`[Integrations] Scheduled import cannot run: ${chain.error}`),!1;let lockStore=getLockStore();if(!lockStore)return!1;let lock=await acquireRunLock(lockStore,mappingId,{logger:logger2});if(!lock.ok)return!1;let writer=writerFor(repoDeps,chain.chain.mapping.targetEntity);if(!writer)return await lock.handle.release(),logger2.error(`[Integrations] Scheduled import targets "${chain.chain.mapping.targetEntity}", which does not exist.`),!1;return executeRun({...chain.chain,userId:"schedule",trigger:"schedule"},{repo:createRunRepository(repoDeps,entities),writer,logger:logger2,tokenCache,publishProgress:(progress)=>publish?.(`${topicPrefix}.run`,progress),maxRecordsPerRun:settings.maxRecordsPerRun,maxConcurrentFanout:settings.maxConcurrentFanout,retainPreImagesMs:parseDuration(settings.retainPreImagesFor)},lock.handle).then((outcome)=>{if(outcome.status!=="succeeded")logger2.error(`[Integrations] Scheduled import "${chain.chain.mapping.name}" ${outcome.status}: ${outcome.failure?.message??"no reason recorded"}`)}).catch((error)=>{logger2.error("[Integrations] Scheduled import threw outside its own error handling",{mappingId,error:error instanceof Error?error.message:String(error)})}).finally(()=>lock.handle.release()),!0},unattendable=new Set;if(settings.schedulesEnabled!==!1)startScheduler({logger:logger2,listScheduled:async()=>{let repoDeps=deps();if(!repoDeps)return[];return(await readScheduledMappings(repoDeps)).filter((row)=>{if(!row.needsPassword)return!0;if(!unattendable.has(row.id))unattendable.add(row.id),logger2.error(`[Integrations] "${row.name}" is scheduled but creates logins, which need a password nobody can type at that hour. It will not run on its own \u2014 start it by hand, or turn the login off.`);return!1})},startRun:(mappingId)=>startScheduledRun(mappingId)});return plugin.get("/sources/:id/export",async({params,set})=>{let repoDeps=deps();if(!repoDeps)return fail4(set,503,"The database is not available.");let bundle=await readConnectionBundle(repoDeps,params.id);if(!bundle)return fail4(set,404,"This connection no longer exists.");let document2=buildTransferDocument({...bundle,exportedAt:new Date().toISOString()});return{isSuccess:!0,message:`${document2.endpoints.length} call(s) and ${document2.mappings.length} mapping(s). Credentials are NOT included \u2014 they are asked for again on the other side.`,data:document2}},{detail:{tags:["Integrations"],summary:"Export a connection, its calls and its mappings \u2014 without any secret"}}),plugin.post("/import",async({body,set,request})=>{let repoDeps=deps();if(!repoDeps)return fail4(set,503,"The database is not available.");let checked=validateTransferDocument(body?.document);if(!checked.ok||!checked.document)return set.status=422,{isSuccess:!1,message:"This file cannot be imported as it stands.",data:{problems:checked.problems}};let userId=request.headers.get("x-user-id")??"unknown",result=await applyTransferDocument(repoDeps,checked.document,userId);if(!result.ok)return fail4(set,422,result.error);return{isSuccess:!0,message:`Connection "${checked.document.connection.name}" is here: ${result.endpoints} call(s) and ${result.mappings} mapping(s). Its credentials are not \u2014 enter them before running anything.`,data:result}},{body:t11.Object({document:t11.Unknown()}),detail:{tags:["Integrations"],summary:"Bring in an exported connection; re-running it updates rather than duplicates"}}),plugin.post("/runs/:id/cancel",async({params,set})=>{let repoDeps=deps();if(!repoDeps)return fail4(set,503,"The database is not available.");if(!await requestCancel(repoDeps,params.id))return fail4(set,409,"This run is not running, so there is nothing to cancel.");return{isSuccess:!0,message:"Cancellation requested. The import stops at its next checkpoint and anything it had written is rolled back.",data:{runId:params.id}}},{detail:{tags:["Integrations"],summary:"Ask a running import to stop"}}),plugin.post("/runs/:id/revert",async({params,body,set,request})=>{let repoDeps=deps();if(!repoDeps)return fail4(set,503,"The database is not available.");let run=await readRun(repoDeps,params.id);if(!run)return fail4(set,404,"This run no longer exists.");if(run.status!=="succeeded")return fail4(set,409,`Only a run that finished successfully can be undone; this one is "${String(run.status)}".`);let expiry=run.preImagesExpireAt?new Date(String(run.preImagesExpireAt)):null;if(expiry&&expiry.getTime()<Date.now())return fail4(set,410,"This run is too old to undo: the records of what it replaced have been cleared.");let targetEntity=String(run.targetEntity??""),preImages=await readPreImages(repoDeps,params.id);if(preImages.length===0)return fail4(set,410,"There is no record of what this run replaced, so it cannot be undone.");let groups=groupPreImagesByEntity(preImages).sort((a,b)=>a.targetEntity===targetEntity?-1:b.targetEntity===targetEntity?1:0),planned=[];for(let group of groups){let current=await readRowsById(repoDeps,group.targetEntity,touchedRowIds(group.preImages));planned.push({targetEntity:group.targetEntity,ops:planRevert({preImages:group.preImages,current,force:body?.force===!0})})}let ops={deletes:planned.flatMap((p)=>p.ops.deletes),restores:planned.flatMap((p)=>p.ops.restores),reinserts:planned.flatMap((p)=>p.ops.reinserts),conflicts:planned.flatMap((p)=>p.ops.conflicts)};if(ops.deletes.length===0&&ops.restores.length===0&&ops.reinserts.length===0&&ops.conflicts.length>0)return set.status=409,{isSuccess:!1,message:"Every record this run touched has been edited since. Undoing would discard those edits; send force: true to overwrite them anyway.",data:{conflicts:ops.conflicts}};let userId=request.headers.get("x-user-id")??"unknown",undone={deleted:0,restored:0,reinserted:0};for(let group of planned){let groupWriter=writerFor(repoDeps,group.targetEntity);if(!groupWriter)return fail4(set,422,`"${group.targetEntity}" no longer exists.`);let result2=await applyRevert(groupWriter,group.ops,{targetEntity:group.targetEntity,userId});if(!result2.ok)return fail4(set,500,result2.error);undone={deleted:undone.deleted+(result2.deleted??0),restored:undone.restored+(result2.restored??0),reinserted:undone.reinserted+(result2.reinserted??0)}}let result={ok:!0,...undone,conflicts:ops.conflicts.length},finished=ops.conflicts.length===0,runsTable=tableFor(repoDeps,"integration_runs");if(runsTable&&finished){let{eq:eq32}=await import("drizzle-orm");await repoDeps.db.update(runsTable).set({status:"reverted",revertedAt:new Date,revertedBy:userId}).where(eq32(runsTable.id,params.id))}return{isSuccess:!0,message:finished?"The import was undone.":`Undone except for ${ops.conflicts.length} record(s) edited since the import. They were left as they are \u2014 send force: true to overwrite them too.`,data:{deleted:result.deleted,restored:result.restored,reinserted:result.reinserted,conflicts:ops.conflicts}}},{body:t11.Optional(t11.Object({force:t11.Optional(t11.Boolean())})),detail:{tags:["Integrations"],summary:"Undo a run that succeeded"}}),plugin.put("/sources/:id/credentials",async({params,body,set})=>{let repoDeps=deps();if(!repoDeps)return fail4(set,503,"The database is not available.");let key2=getEncryptionKey();if(!key2)return fail4(set,503,"No encryption key is configured, so a credential stored now could never be read back.");let table=tableFor(repoDeps,"integration_sources");if(!table)return fail4(set,503,"The integration tables are not present in this schema.");let patch={},hints={},apply=(value,column,hintColumn,name2)=>{if(value===void 0)return;let trimmed=value.trim();if(trimmed===""){patch[column]=null,patch[hintColumn]=null,hints[name2]=null;return}patch[column]=encryptSecret(trimmed,key2),patch[hintColumn]=previewOf(trimmed),hints[name2]=previewOf(trimmed)};if(apply(body.token,"authTokenEncrypted","authTokenHint","token"),apply(body.oauthClientSecret,"oauthClientSecretEncrypted","oauthClientSecretHint","clientSecret"),apply(body.oauthPassword,"oauthPasswordEncrypted","oauthPasswordHint","password"),Object.keys(patch).length===0)return{isSuccess:!0,message:"Nothing to change.",data:{hints}};let{eq:eq32}=await import("drizzle-orm");return await repoDeps.db.update(table).set({...patch,updatedAt:new Date}).where(eq32(table.id,params.id)),tokenCache.invalidate(params.id),{isSuccess:!0,message:"Saved.",data:{hints}}},{body:t11.Object({token:t11.Optional(t11.String()),oauthClientSecret:t11.Optional(t11.String()),oauthPassword:t11.Optional(t11.String())}),detail:{tags:["Integrations"],summary:"Store a source credential; only a masked preview is returned"}}),logger2.info(`[Integrations] Routes enabled at ${basePath}`),plugin}function parseDuration(value){if(!value)return;let match=value.trim().match(/^(\d+)\s*([smhd])$/i);if(!match)return;let amount=Number(match[1]),unit=(match[2]??"d").toLowerCase();return amount*(unit==="s"?1000:unit==="m"?60000:unit==="h"?3600000:86400000)}init_adminGuard();import Elysia14,{t as t12}from"elysia";function parseTimeToMs2(time2){let match=time2.match(/^(\d+)(ms|s|m|h)$/);if(!match||!match[1]||!match[2])return 5000;let value=parseInt(match[1],10);switch(match[2]){case"ms":return value;case"s":return value*1000;case"m":return value*60*1000;case"h":return value*60*60*1000;default:return 5000}}function createMonitoringRoutes(config){let{monitoringService,logger:logger2,endpoints,db,schemaTables}=config,plugin=new Elysia14({prefix:endpoints.basePath});if(plugin.onBeforeHandle(createGodminGuard({db:db??null,schemaTables:schemaTables??{},logger:logger2},"monitoring")),!endpoints.enabled)return plugin;if(endpoints.stream.enabled)plugin.get(endpoints.stream.path,async function*({request}){logger2.info("[Monitoring] SSE stream connected");let intervalMs=parseTimeToMs2(endpoints.stream.interval),isConnected=!0;request.signal.addEventListener("abort",()=>{isConnected=!1,logger2.info("[Monitoring] SSE stream disconnected")});let initialSnapshot=await monitoringService.getLatestSnapshot();if(initialSnapshot)yield{event:"snapshot",data:JSON.stringify(initialSnapshot)};while(isConnected){if(await new Promise((resolve2)=>setTimeout(resolve2,intervalMs)),!isConnected)break;let snapshot=await monitoringService.getLatestSnapshot();if(snapshot)yield{event:"snapshot",data:JSON.stringify(snapshot)};let alerts=monitoringService.getActiveAlerts();if(alerts.length>0)yield{event:"alerts",data:JSON.stringify(alerts)}}},{detail:{tags:["Monitoring"],summary:"Stream real-time monitoring data",description:"Server-Sent Events stream for real-time monitoring metrics"}});if(endpoints.snapshot.enabled)plugin.get(endpoints.snapshot.path,async()=>{let snapshot=await monitoringService.getLatestSnapshot();if(!snapshot)return{isSuccess:!1,message:"No monitoring data available",data:null};return{isSuccess:!0,message:"Current monitoring snapshot",data:snapshot}},{detail:{tags:["Monitoring"],summary:"Get current monitoring snapshot",description:"Returns the latest monitoring metrics snapshot"}});if(endpoints.history.enabled)plugin.get(endpoints.history.path,async({query})=>{let minutes=Math.min(query.minutes?parseInt(String(query.minutes),10):60,endpoints.history.maxMinutes),history=await monitoringService.getHistory(minutes);return{isSuccess:!0,message:`Monitoring history for last ${minutes} minutes`,data:{minutes,count:history.length,snapshots:history}}},{query:t12.Object({minutes:t12.Optional(t12.Numeric())}),detail:{tags:["Monitoring"],summary:"Get monitoring history",description:"Returns historical monitoring data for the specified time range"}});if(endpoints.alerts.enabled)plugin.get(endpoints.alerts.path,()=>{let alerts=monitoringService.getActiveAlerts();return{isSuccess:!0,message:"Active alerts",data:{count:alerts.length,alerts}}},{detail:{tags:["Monitoring"],summary:"Get active alerts",description:"Returns all currently active monitoring alerts"}}),plugin.post(`${endpoints.alerts.path}/:alertId/acknowledge`,({params})=>{if(!monitoringService.acknowledgeAlert(params.alertId))return{isSuccess:!1,message:"Alert not found",data:null};return{isSuccess:!0,message:"Alert acknowledged",data:{alertId:params.alertId}}},{params:t12.Object({alertId:t12.String()}),detail:{tags:["Monitoring"],summary:"Acknowledge an alert",description:"Mark an alert as acknowledged"}});return logger2.info(`[Monitoring] Routes enabled at ${endpoints.basePath} (stream: ${endpoints.stream.enabled}, snapshot: ${endpoints.snapshot.enabled}, history: ${endpoints.history.enabled}, alerts: ${endpoints.alerts.enabled})`),plugin}init_adminGuard();import Elysia15,{t as t13}from"elysia";var STREAM_HEADERS={"Content-Type":"text/event-stream; charset=utf-8","Cache-Control":"no-cache, no-transform",Connection:"keep-alive"},textEncoder=new TextEncoder,encodeEvent=(event,data)=>{let payload=typeof data==="string"?data:JSON.stringify(data);return textEncoder.encode(`event: ${event}
|
|
530
530
|
data: ${payload}
|
|
531
531
|
|
|
532
|
-
`)};function createLiveMonitoringRoutes(config){let{getService,logger:logger2,basePath,streamInterval,db,schemaTables}=config,plugin=new Elysia15({prefix:basePath});plugin.onBeforeHandle(createGodminGuard({db:db??null,schemaTables:schemaTables??{},logger:logger2},"live monitoring"));let requireService=()=>{let svc=getService();if(!svc)throw Error("Live monitoring service not initialized");return svc};return plugin.get("/health",()=>{let svc=getService();return{status:svc?"ok":"initializing",timestamp:Date.now(),monitoring:svc?.isEnabled()??!1}},{detail:{tags:["Live Monitoring"],summary:"Health check for live monitoring"}}),plugin.get("/settings",()=>{return requireService().getSettings()},{detail:{tags:["Live Monitoring"],summary:"Get live monitoring settings"}}),plugin.patch("/settings",({body})=>{return requireService().changeSettings(body)},{body:t13.Partial(t13.Object({logMemory:t13.Boolean(),logCpu:t13.Boolean(),logDapr:t13.Boolean(),logWebSocket:t13.Boolean(),memoryLogInterval:t13.Number(),cpuLogInterval:t13.Number(),memoryLogLimit:t13.Number(),cpuLogLimit:t13.Number(),daprLogLimit:t13.Number(),wsLogLimit:t13.Number(),requestLogLimit:t13.Number()})),detail:{tags:["Live Monitoring"],summary:"Change live monitoring settings"}}),plugin.get("/logs",()=>{return requireService().getLogs()},{detail:{tags:["Live Monitoring"],summary:"Get all live monitoring logs"}}),plugin.get("/logs/stream",({request})=>{let abortSignal=request.signal,cleanup,svc=requireService(),snapshot=svc.getSnapshot(),lastTimestamps={memory:snapshot.memory.length?snapshot.memory[snapshot.memory.length-1]?.timestamp??0:0,cpu:snapshot.cpu.length?snapshot.cpu[snapshot.cpu.length-1]?.timestamp??0:0,request:snapshot.requests.length?snapshot.requests[snapshot.requests.length-1]?.timestamp??0:0,dapr:snapshot.dapr.length?snapshot.dapr[snapshot.dapr.length-1]?.timestamp??0:0,ws:snapshot.ws.length?snapshot.ws[snapshot.ws.length-1]?.timestamp??0:0},stream=new ReadableStream({start(controller){let closed=!1;controller.enqueue(encodeEvent("snapshot",snapshot));let interval=setInterval(()=>{if(closed)return;let update=svc.getUpdatesSince(lastTimestamps);if(!update){controller.enqueue(encodeEvent("heartbeat",{timestamp:Date.now()}));return}if(update.memory.length)lastTimestamps.memory=update.memory[update.memory.length-1]?.timestamp??lastTimestamps.memory;if(update.cpu.length)lastTimestamps.cpu=update.cpu[update.cpu.length-1]?.timestamp??lastTimestamps.cpu;if(update.requests.length)lastTimestamps.request=update.requests[update.requests.length-1]?.timestamp??lastTimestamps.request;if(update.dapr.length)lastTimestamps.dapr=update.dapr[update.dapr.length-1]?.timestamp??lastTimestamps.dapr;if(update.ws.length)lastTimestamps.ws=update.ws[update.ws.length-1]?.timestamp??lastTimestamps.ws;controller.enqueue(encodeEvent("update",update))},streamInterval),cleanupHandler=()=>{if(closed)return;closed=!0,clearInterval(interval),abortSignal?.removeEventListener("abort",cleanupHandler);try{controller.close()}catch{}};cleanup=cleanupHandler,abortSignal?.addEventListener("abort",cleanupHandler)},cancel(){cleanup?.()}});return new Response(stream,{headers:STREAM_HEADERS})},{detail:{tags:["Live Monitoring"],summary:"Stream real-time live monitoring data via SSE"}}),logger2.info(`[LiveMonitoring] Routes enabled at ${basePath} (stream interval: ${streamInterval}ms)`),plugin}init_Notification();init_adminGuard();import{Elysia as Elysia16,t as t14}from"elysia";var CHANNELS=["portal","email","telegram","webhook"];function createNotificationRoutes(routeConfig){let{db,schemaTables,config,logger:logger2,tenantRegistry,getEmailService}=routeConfig,basePath=routeConfig.basePath||config.endpoints?.basePath||"/notifications",buildService=(tables)=>new NotificationService({db,schemaTables:tables,config,logger:logger2,getEmailService}),defaultService=buildService(schemaTables),serviceFor=(request)=>{if(!tenantRegistry)return defaultService;let schemaName=request.headers.get("x-tenant-schema");if(!schemaName)return defaultService;let ctx=tenantRegistry.getSchemaContext(schemaName);return ctx?buildService(ctx.schemaTables):defaultService},allowedSendRoles=new Set((config.endpoints?.sendRoles??[]).map((role)=>role.toLowerCase())),canSend=async(request)=>{if(allowedSendRoles.size>0){if(decodeHeaderList(request.headers.get("x-user-roles")).some((role)=>allowedSendRoles.has(role.toLowerCase())))return!0}return isGodminRequest(request,{db,schemaTables,logger:logger2})},routes=new Elysia16({prefix:basePath}),requireUser=(request,set)=>{let userId=request.headers.get("x-user-id");if(!userId)return set.status=401,null;return userId};return routes.get("/",async({request,query,set})=>{let userId=requireUser(request,set);if(!userId)return{success:!1,message:"User ID required"};return{success:!0,data:await serviceFor(request).getNotifications(userId,{limit:query.limit?Number(query.limit):void 0,offset:query.offset?Number(query.offset):void 0,type:query.type||void 0})}},{query:t14.Object({limit:t14.Optional(t14.String()),offset:t14.Optional(t14.String()),type:t14.Optional(t14.String())}),detail:{tags:["Notifications"],summary:"List the caller\u2019s notifications"}}),routes.get("/unseen-count",async({request,set})=>{let userId=requireUser(request,set);if(!userId)return{success:!1,message:"User ID required"};return{success:!0,data:{count:await serviceFor(request).getUnseenCount(userId)}}},{detail:{tags:["Notifications"],summary:"Unseen notification count"}}),routes.post("/:notification_id/seen",async({params,request,set})=>{let userId=requireUser(request,set);if(!userId)return{success:!1,message:"User ID required"};let marked=await serviceFor(request).markAsSeen(params.notification_id,userId);return{success:marked,message:marked?"Marked as seen":"Failed"}},{params:t14.Object({notification_id:t14.String()}),detail:{tags:["Notifications"],summary:"Mark one notification as seen"}}),routes.post("/seen-all",async({request,set})=>{let userId=requireUser(request,set);if(!userId)return{success:!1,message:"User ID required"};return{success:!0,data:{count:await serviceFor(request).markAllAsSeen(userId)}}},{detail:{tags:["Notifications"],summary:"Mark every notification as seen"}}),routes.post("/send",async({body,request,set})=>{if(!requireUser(request,set))return{success:!1,message:"Authentication required"};if(!await canSend(request))return set.status=403,{success:!1,message:"Sending notifications requires godmin or an allowed role"};let recipients=body.userIds??(body.userId?[body.userId]:[]);if(recipients.length===0)return set.status=400,{success:!1,message:"userId or userIds is required"};let channels=body.channels??[config.defaultChannel??"portal"],service=serviceFor(request),failed=(await Promise.allSettled(recipients.map((user_id)=>service.send({user_id,title:body.title,body:body.body,entity_name:body.entityName,entity_id:body.entityId,type:body.type??"custom",source:body.source,channels})))).map((result,index)=>({result,userId:recipients[index]})).filter((entry)=>entry.result.status==="rejected").map((entry)=>entry.userId);return{success:failed.length===0,message:failed.length===0?`Sent to ${recipients.length} recipient(s)`:`Sent to ${recipients.length-failed.length}, failed for ${failed.length}`,data:{sent:recipients.length-failed.length,failed}}},{body:t14.Object({userId:t14.Optional(t14.String()),userIds:t14.Optional(t14.Array(t14.String())),title:t14.String(),body:t14.Optional(t14.String()),entityName:t14.Optional(t14.String()),entityId:t14.Optional(t14.String()),type:t14.Optional(t14.Union([t14.Literal("verification"),t14.Literal("system"),t14.Literal("custom")])),source:t14.Optional(t14.String()),channels:t14.Optional(t14.Array(t14.Union(CHANNELS.map((c)=>t14.Literal(c)))))}),detail:{tags:["Notifications"],summary:"Send a notification to one or more users",description:"Privileged. Delivers over the requested channels (portal, email, telegram, webhook). Email uses the configured provider \u2014 credentials resolve through the secrets store, so a rotation applies immediately."}}),routes.post("/email",async({body,request,set})=>{if(!requireUser(request,set))return{success:!1,message:"Authentication required"};if(!await canSend(request))return set.status=403,{success:!1,message:"Sending email requires godmin or an allowed role"};let emailService=getEmailService?.()??null;if(!emailService?.isAvailable())return set.status=503,{success:!1,message:"No email provider is configured or available"};let result=await emailService.sendEmail({to:body.to,subject:body.subject,html:body.html,text:body.text,replyTo:body.replyTo});if(!result.success)return set.status=502,{success:!1,message:result.error??"Email delivery failed"};return logger2.info("[Notification] Transactional email sent",{recipients:Array.isArray(body.to)?body.to.length:1,subject:body.subject}),{success:!0,message:"Email sent",data:null}},{body:t14.Object({to:t14.Union([t14.String(),t14.Array(t14.String())]),subject:t14.String(),html:t14.Optional(t14.String()),text:t14.Optional(t14.String()),replyTo:t14.Optional(t14.String())}),detail:{tags:["Notifications"],summary:"Send a transactional email to explicit recipients",description:"Backend-to-backend send through the configured provider \u2014 an app never needs an email SDK or the provider credentials of its own. Privileged, same gate as /send."}}),{routes,notificationService:defaultService}}init_ack_manager();import{timingSafeEqual as timingSafeEqual3}from"crypto";import Elysia17 from"elysia";init_ack_manager();var clients=new Map,presenceBroadcastDebounce=new Map;function createClientManager(config){let{redis,logger:logger2}=config,ackTtl=config.ack.ttlSeconds,ackEnabled=config.ack.enabled,maxRetries=config.ack.maxRetries,presenceEnabled=config.presence.enabled,presenceDebounceMs=config.presence.debounceMs,maxClientsPerUser=config.maxClientsPerUser,maxTopicsPerClient=config.maxTopicsPerClient??64,MAX_TOPIC_LENGTH=256;function generateClientId(){return`client_${Date.now()}_${Math.random().toString(36).substring(2,9)}`}function capTopics(topics){let capped=[],seen=new Set;for(let t15 of topics){if(typeof t15!=="string")continue;let trimmed=t15.length>256?t15.slice(0,256):t15;if(seen.has(trimmed))continue;if(seen.add(trimmed),capped.push(trimmed),capped.length>=maxTopicsPerClient)break}return capped}function registerClient(clientId,ws,userId,topics){let existingClients=getClientsByUser(userId);if(existingClients.length>=maxClientsPerUser){let oldestClientId=existingClients[0];if(oldestClientId)logger2.info("[PubSub] Max clients reached, closing oldest",{userId,oldestClientId}),unregisterClient(oldestClientId)}clients.set(clientId,{ws,userId,subscribedTopics:new Set(capTopics(topics)),connectedAt:Date.now(),pendingAcks:new Map}),logger2.info("[PubSub] Client registered",{clientId,userId,topics,totalClients:clients.size})}function unregisterClient(clientId){let client=clients.get(clientId);if(!client)return;let userId=client.userId;if(clients.delete(clientId),logger2.info("[PubSub] Client unregistered",{clientId,userId,totalClients:clients.size}),presenceEnabled&&userId){if(getClientsByUser(userId).length===0)broadcastPresenceToOthers(userId,"offline")}}function updateClientTopics(clientId,topics){let client=clients.get(clientId);if(client)client.subscribedTopics=new Set(capTopics(topics))}function getClientsByUser(userId){let result=[];for(let[clientId,client]of clients)if(client.userId===userId)result.push(clientId);return result}function getConnectedUserIds(){let userIds=new Set;for(let[,client]of clients)if(client.userId)userIds.add(client.userId);return userIds}function getClientCount(){return clients.size}function sendToClient(clientId,message){let client=clients.get(clientId);if(!client)return!1;try{return client.ws.send(JSON.stringify(message)),!0}catch{return clients.delete(clientId),!1}}function broadcastEvent(topic,event){let messageId=generateMessageId(),timestamp=Date.now(),payload=JSON.stringify({type:"event",messageId:ackEnabled?messageId:void 0,topic,data:event,timestamp}),sentCount=0;for(let[clientId,client]of clients)if(client.subscribedTopics.has("*")||client.subscribedTopics.has(topic))try{if(client.ws.send(payload),sentCount++,ackEnabled){if(client.pendingAcks.set(messageId,{sentAt:timestamp,retryCount:0}),recordSent(),client.userId)storePendingMessage(redis,{messageId,topic,clientId,userId:client.userId,data:event,sentAt:timestamp,retryCount:0,maxRetries},ackTtl).catch(()=>{})}}catch{clients.delete(clientId)}logger2.info("[PubSub] Broadcasted event",{topic,messageId,sentCount})}function broadcastToUser(userId,topic,event){let messageId=generateMessageId(),timestamp=Date.now(),payload=JSON.stringify({type:"event",messageId:ackEnabled?messageId:void 0,topic,data:event,timestamp}),sentCount=0,sentToAnyClient=!1;for(let[clientId,client]of clients){if(client.userId!==userId)continue;if(!client.subscribedTopics.has("*")&&!client.subscribedTopics.has(topic))continue;try{if(client.ws.send(payload),sentCount++,sentToAnyClient=!0,ackEnabled)client.pendingAcks.set(messageId,{sentAt:timestamp,retryCount:0}),recordSent()}catch{clients.delete(clientId)}}if(ackEnabled)storePendingMessage(redis,{messageId,topic,clientId:sentToAnyClient?"delivered":"pending",userId,data:event,sentAt:timestamp,retryCount:0,maxRetries},ackTtl).catch(()=>{});logger2.info("[PubSub] Broadcasted to user",{userId,topic,messageId,sentCount,storedForOffline:!sentToAnyClient})}function broadcastToUserNoAck(userId,topic,event){let timestamp=Date.now(),payload=JSON.stringify({type:"event",topic,data:event,timestamp});for(let[clientId,client]of clients){if(client.userId!==userId)continue;if(!client.subscribedTopics.has("*")&&!client.subscribedTopics.has(topic))continue;try{client.ws.send(payload)}catch{clients.delete(clientId)}}}function broadcastPresenceToOthers(userId,status){let debounceKey=`${userId}:${status}`,now=Date.now(),lastBroadcast=presenceBroadcastDebounce.get(debounceKey);if(lastBroadcast&&now-lastBroadcast<presenceDebounceMs)return;if(presenceBroadcastDebounce.set(debounceKey,now),presenceBroadcastDebounce.size>1000){let cutoff=now-presenceDebounceMs*2;for(let[key2,timestamp]of presenceBroadcastDebounce)if(timestamp<cutoff)presenceBroadcastDebounce.delete(key2)}let connectedUserIds=getConnectedUserIds();for(let targetUserId of connectedUserIds)if(targetUserId!==userId)broadcastToUserNoAck(targetUserId,"user-presence",{type:"user-presence",data:{userId,status}})}async function handleClientAck(clientId,messageId){if(!ackEnabled)return!0;let client=clients.get(clientId);if(!client)return!1;if(client.pendingAcks.get(messageId))client.pendingAcks.delete(messageId);if(client.userId)return acknowledgeMessage(redis,client.userId,messageId,ackTtl);return!0}async function deliverPendingMessages(userId,clientId){if(!ackEnabled)return 0;let client=clients.get(clientId);if(!client||client.userId!==userId)return 0;let pendingMessages=await getPendingMessagesForUser(redis,userId);if(pendingMessages.length===0)return 0;logger2.info("[PubSub] Delivering pending messages",{userId,count:pendingMessages.length});let deliveredCount=0;for(let message of pendingMessages){if(!client.subscribedTopics.has("*")&&!client.subscribedTopics.has(message.topic))continue;let payload=JSON.stringify({type:"event",messageId:message.messageId,topic:message.topic,data:message.data,timestamp:message.sentAt,isRedelivery:!0});try{client.ws.send(payload),client.pendingAcks.set(message.messageId,{sentAt:Date.now(),retryCount:message.retryCount+1}),await incrementRetryCount(redis,userId,message.messageId,ackTtl,maxRetries),deliveredCount++}catch{break}}return deliveredCount}return{generateClientId,registerClient,unregisterClient,updateClientTopics,getClientsByUser,getConnectedUserIds,getClientCount,sendToClient,broadcastEvent,broadcastToUser,broadcastToUserNoAck,broadcastPresenceToOthers,handleClientAck,deliverPendingMessages,getPendingMessageCount:(userId)=>getPendingMessageCount(redis,userId)}}var OPAQUE_RUN=/[A-Za-z0-9_-]{24,}(?:\.[A-Za-z0-9_-]{8,}){0,2}/g;function previewOf2(frame){return frame.slice(0,120).replace(OPAQUE_RUN,(match)=>`[redacted ${match.length} chars]`)}function classifyClientFrame(message){if(typeof message==="string"){if(message.trim()==="")return{kind:"ignore"};let parsed;try{parsed=JSON.parse(message)}catch{return{kind:"malformed",preview:previewOf2(message)}}return asMessage(parsed,message.length)}if(message&&typeof message==="object")return asMessage(message,approximateSize(message));return{kind:"ignore"}}function approximateSize(value){if(ArrayBuffer.isView(value))return value.byteLength;if(value instanceof ArrayBuffer)return value.byteLength;try{return JSON.stringify(value)?.length??0}catch{return 0}}function asMessage(value,size){if(!value||typeof value!=="object"||Array.isArray(value))return{kind:"ignore"};let record=value,type=record.type;if(typeof type!=="string"||type==="")return{kind:"ignore"};return{kind:"message",parsed:record,type,size}}function tokensMatch(a,b){let ba=Buffer.from(a),bb=Buffer.from(b);if(ba.length!==bb.length)return!1;return timingSafeEqual3(ba,bb)}var HEARTBEAT_WS_TYPES=new Set(["ping","pong","ack"]);function buildHandshakeHeaders(rawHeaders,queryToken){let headers=new Headers;if(rawHeaders&&typeof rawHeaders==="object"){for(let[key2,value]of Object.entries(rawHeaders))if(typeof value==="string")headers.set(key2,value)}if(queryToken)headers.set("authorization",`Bearer ${queryToken}`),headers.delete("cookie");return headers}function createPubSubRoutes(config){let{logger:logger2,getLiveMonitoringService}=config,clientManager=createClientManager(config);if(config.ack.enabled)initAckCleanup();let cleanupTimer=null,daprApiToken=config.daprApiToken||process.env.APP_API_TOKEN||process.env.DAPR_API_TOKEN,warnedNoDaprToken=!1,plugin=new Elysia17;return plugin.onStart(()=>{if(config.cleanupIntervalMs>0)cleanupTimer=setInterval(()=>{logger2.info("[PubSub] Periodic cleanup running",{totalClients:clientManager.getClientCount()})},config.cleanupIntervalMs);logger2.info("[PubSub] Routes initialized",{basePath:config.basePath,wsPath:config.wsPath,ackEnabled:config.ack.enabled,presenceEnabled:config.presence.enabled})}),plugin.onStop(()=>{if(cleanupTimer)clearInterval(cleanupTimer),cleanupTimer=null}),plugin.post(`${config.basePath}/:topic`,async({params,body,request,set})=>{let topic=params.topic;if(daprApiToken){let presented=request.headers.get("dapr-api-token")??"";if(!tokensMatch(presented,daprApiToken))return logger2.warn("[PubSub] Rejected Dapr event: missing/invalid dapr-api-token",{topic}),set.status=403,{status:"DROP"}}else if(!warnedNoDaprToken)warnedNoDaprToken=!0,logger2.warn("[PubSub] Dapr subscription endpoint is UNAUTHENTICATED \u2014 set config.pubsub.daprApiToken or the APP_API_TOKEN/DAPR_API_TOKEN env so only the Dapr sidecar can inject events");let eventData;try{if(!body){let text2=await request.text();eventData=JSON.parse(text2)}else eventData=body}catch{return set.status=200,{status:"DROP"}}logger2.info("[PubSub] Dapr event received",{topic,eventId:eventData.id,source:eventData.source});let userId=eventData.data?.user_id;if(userId)clientManager.broadcastToUser(userId,topic,eventData);else clientManager.broadcastEvent(topic,eventData);return getLiveMonitoringService?.()?.recordDaprEvent("pubsub_subscribe",{topic,success:!0,metadata:{eventId:eventData.id,source:eventData.source,userId:userId||null}}),set.status=200,{status:"SUCCESS"}}),plugin.ws(config.wsPath,{idleTimeout:config.wsIdleTimeout,open(ws){let data=ws.data||{},query=data.query||{},userId;if(config.authenticate){let handshakeHeaders=buildHandshakeHeaders(data.headers,query.token),authResult=config.authenticate(handshakeHeaders);if(!authResult){ws.send(JSON.stringify({type:"error",error:"Unauthorized: a valid session is required for this connection",timestamp:Date.now()})),ws.close(4001,"Unauthorized"),getLiveMonitoringService?.()?.recordWsEvent("error",{success:!1,error:"Unauthorized WebSocket handshake"});return}userId=authResult.userId}else userId=query.userId;if(!userId){ws.send(JSON.stringify({type:"error",error:"userId is required for WebSocket connection",timestamp:Date.now()})),ws.close(4001,"userId is required"),getLiveMonitoringService?.()?.recordWsEvent("error",{success:!1,error:"userId is required"});return}let clientId=clientManager.generateClientId(),topics=query.topics?.split(",").map((t15)=>t15.trim())||["*"];if(ws.data.clientId=clientId,clientManager.registerClient(clientId,ws,userId,topics),ws.send(JSON.stringify({type:"connected",clientId,subscribedTopics:topics,timestamp:Date.now()})),getLiveMonitoringService?.()?.recordWsEvent("connection",{clientId,userId,topic:topics.join(","),success:!0}),config.presence.enabled)clientManager.broadcastPresenceToOthers(userId,"online");let connectedUserId=userId;if(config.ack.enabled&&connectedUserId)clientManager.getPendingMessageCount(connectedUserId).then((count2)=>{if(count2>0)logger2.info("[PubSub] Delivering pending messages",{userId:connectedUserId,count:count2}),clientManager.deliverPendingMessages(connectedUserId,clientId).catch(()=>{})}).catch(()=>{})},message(ws,message){let clientId=ws.data.clientId,frame=classifyClientFrame(message);if(frame.kind==="ignore")return;if(frame.kind==="malformed"){logger2.debug("[PubSub] Failed to parse client message",{clientId,frame:frame.preview});return}let{parsed}=frame;try{if(!HEARTBEAT_WS_TYPES.has(frame.type))getLiveMonitoringService?.()?.recordWsEvent("message",{clientId,messageType:frame.type,success:!0,dataSize:frame.size});switch(frame.type){case"subscribe":if(Array.isArray(parsed.topics))clientManager.updateClientTopics(clientId,parsed.topics),clientManager.sendToClient(clientId,{type:"subscribed",topics:parsed.topics,timestamp:Date.now()});break;case"unsubscribe":logger2.info("[PubSub] Unsubscribe request",{clientId,topics:parsed.topics});break;case"ping":clientManager.sendToClient(clientId,{type:"pong",timestamp:Date.now()});break;case"ack":if(parsed.messageId)clientManager.handleClientAck(clientId,parsed.messageId).catch(()=>{});break}}catch(error){logger2.error("[PubSub] Client message handler failed",error,{clientId,messageType:frame.type})}},close(ws,code,reason){let clientId=ws.data.clientId;if(clientId)clientManager.unregisterClient(clientId);getLiveMonitoringService?.()?.recordWsEvent("close",{clientId,success:!0,metadata:{code,reason:reason||""}}),logger2.info("[PubSub] Client disconnected",{clientId,code,reason})}}),{plugin,clientManager}}import Elysia18,{t as t15}from"elysia";init_Secrets();var timed=async(fn)=>{let started=performance.now();return{result:await fn(),durationMs:Math.round(performance.now()-started)}},postForm=async(url,body)=>{let response=await fetch(url,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded",Accept:"application/json"},body:new URLSearchParams(body).toString(),signal:AbortSignal.timeout(12000)}),text2=await response.text(),json={};try{json=JSON.parse(text2)}catch{json=Object.fromEntries(new URLSearchParams(text2))}return{status:response.status,json,text:text2}},describeError=(error)=>{if(error instanceof Error){if(error.name==="TimeoutError")return"Provider did not respond within 12s";return error.message}return String(error)},MICROSOFT_TOKEN_URL=(tenant)=>`https://login.microsoftonline.com/${tenant}/oauth2/v2.0/token`,DEFAULT_TOKEN_URLS={google:"https://oauth2.googleapis.com/token",github:"https://github.com/login/oauth/access_token"},describeRedirectUri=(value)=>{let trimmed=value?.trim();if(!trimmed)return"Y\xF6nlendirme adresi (Redirect URI) bo\u015F \u2014 giri\u015F tamamlanamaz";if(/^[A-Z][A-Z0-9_]{2,}$/.test(trimmed))return`Y\xF6nlendirme adresi bir ortam de\u011Fi\u015Fkeni ad\u0131 olarak duruyor ("${trimmed}") ve o de\u011Fi\u015Fken tan\u0131ml\u0131 de\u011Fil`;let parsed;try{parsed=new URL(trimmed)}catch{return`Y\xF6nlendirme adresi ge\xE7erli bir URL de\u011Fil: "${trimmed}"`}if(parsed.protocol!=="https:"&&parsed.hostname!=="localhost")return`Y\xF6nlendirme adresi https olmal\u0131 (\u015Fu an "${parsed.protocol}//")`;return null};async function testOAuthProvider(provider,config){if(!config.clientId||!config.clientSecret)return{ok:!1,status:"failed",message:"Client ID ve Client Secret dolu olmal\u0131",durationMs:0};let redirectProblem=describeRedirectUri(config.redirectUri);if(redirectProblem)return{ok:!1,status:"failed",message:redirectProblem,durationMs:0};try{if(provider==="microsoft"){let tenant=config.tenantId||"common";if(tenant==="common"||tenant==="organizations"||tenant==="consumers")return await probeWithBogusCode(MICROSOFT_TOKEN_URL(tenant),config);let{result,durationMs}=await timed(()=>postForm(MICROSOFT_TOKEN_URL(tenant),{grant_type:"client_credentials",client_id:config.clientId,client_secret:config.clientSecret,scope:"https://graph.microsoft.com/.default"}));if(result.status===200&&result.json.access_token)return{ok:!0,status:"ok",message:`Entra kimlik bilgileri do\u011Fruland\u0131 (tenant ${tenant})`,durationMs};let code=String(result.json.error??result.status);return{ok:!1,status:"failed",message:String(result.json.error_description??result.text).slice(0,400),code,durationMs}}let tokenUrl=config.tokenUrl||DEFAULT_TOKEN_URLS[provider];if(!tokenUrl)return{ok:!1,status:"unknown",message:`"${provider}" i\xE7in token adresi tan\u0131ml\u0131 de\u011Fil \u2014 tokenUrl girin`,durationMs:0};return await probeWithBogusCode(tokenUrl,config)}catch(error){return{ok:!1,status:"failed",message:describeError(error),durationMs:0}}}async function probeWithBogusCode(tokenUrl,config){let{result,durationMs}=await timed(()=>postForm(tokenUrl,{grant_type:"authorization_code",code:"nucleus-credential-probe",client_id:config.clientId,client_secret:config.clientSecret,redirect_uri:config.redirectUri||"https://localhost/callback"})),code=String(result.json.error??""),description=String(result.json.error_description??result.text).slice(0,400);if(code==="invalid_grant"||code==="bad_verification_code")return{ok:!0,status:"ok",message:"Kimlik bilgileri sa\u011Flay\u0131c\u0131 taraf\u0131ndan kabul edildi",code,durationMs};if(code==="invalid_client"||code==="unauthorized_client"||result.status===401)return{ok:!1,status:"failed",message:description||"Sa\u011Flay\u0131c\u0131 Client ID/Secret \xE7iftini reddetti",code:code||"invalid_client",durationMs};if(description.includes("AADSTS7000215")||description.includes("AADSTS700016"))return{ok:!1,status:"failed",message:description,code,durationMs};return{ok:!1,status:"unknown",message:description||"Sa\u011Flay\u0131c\u0131 beklenmeyen bir yan\u0131t d\xF6nd\xFC",code:code||String(result.status),durationMs}}async function testStorageProvider(provider){if(!provider)return{ok:!1,status:"failed",message:"Depolama sa\u011Flay\u0131c\u0131 yap\u0131land\u0131r\u0131lmam\u0131\u015F",durationMs:0};try{let{result,durationMs}=await timed(()=>provider.isAvailable());return result?{ok:!0,status:"ok",message:`Ba\u011Flant\u0131 do\u011Fruland\u0131: ${provider.describe}`,durationMs}:{ok:!1,status:"failed",message:`Eri\u015Filemedi: ${provider.describe} \u2014 sunucu, payla\u015F\u0131m ad\u0131 ve kimlik bilgilerini kontrol edin`,durationMs}}catch(error){return{ok:!1,status:"failed",message:describeError(error),durationMs:0}}}async function testEmailProvider(service,recipient){if(!service)return{ok:!1,status:"failed",message:"E-posta sa\u011Flay\u0131c\u0131 yap\u0131land\u0131r\u0131lmam\u0131\u015F",durationMs:0};if(!service.isAvailable())return{ok:!1,status:"failed",message:"Sa\u011Flay\u0131c\u0131 kimlik bilgileriyle ba\u015Flat\u0131lamad\u0131",durationMs:0};if(!recipient)return{ok:!0,status:"ok",message:"Sa\u011Flay\u0131c\u0131 ba\u015Flat\u0131ld\u0131 \u2014 ger\xE7ek g\xF6nderim i\xE7in bir al\u0131c\u0131 adresi girin",durationMs:0};try{let{result,durationMs}=await timed(()=>service.sendEmail({to:recipient,subject:"Nucleus ba\u011Flant\u0131 testi",html:"<p>Bu e-posta, y\xF6netim panelinden yap\u0131lan ba\u011Flant\u0131 testiyle g\xF6nderildi.</p>"}));return result.success?{ok:!0,status:"ok",message:`Test e-postas\u0131 ${recipient} adresine g\xF6nderildi`,durationMs}:{ok:!1,status:"failed",message:result.error??"G\xF6nderim ba\u015Far\u0131s\u0131z",durationMs}}catch(error){return{ok:!1,status:"failed",message:describeError(error),durationMs:0}}}init_godminGuard();var SECRET_KINDS=["text","password","json","connection_string","pem","boolean","list"];var SCOPE_PATTERN=/^[A-Za-z0-9_.-]{1,200}$/,KEY_PATTERN=/^[A-Za-z0-9_-]{1,120}$/,fail5=(set,status,message)=>{return set.status=status,{isSuccess:!1,message,data:null}};function createSecretsRoutes(routeConfig){let{logger:logger2,basePath,db,schemaTables,getService,resolvedOptions,getEmailService,getStorageProvider:getStorageProvider2}=routeConfig,plugin=new Elysia18({prefix:basePath});plugin.onBeforeHandle(createGodminGuard2({logger:logger2,db,schemaTables,area:"secrets management",allowedRoles:routeConfig.adminRoles}));let requireService=(set)=>{let service=getService();if(!service)return set.status=503,null;return service},actorOf=(request)=>request.headers.get("x-user-id")??void 0;return plugin.get("/slots",async({set})=>{let service=requireService(set);if(!service)return{isSuccess:!1,message:"Secrets management is disabled \u2014 set secrets.enabled and provide an encryption key",data:null};let slots=await service.describe(resolvedOptions),groups=[...new Set(slots.map((s)=>s.group))].sort();return{isSuccess:!0,message:"Credential slots",data:{slots,groups,counts:{total:slots.length,fromDb:slots.filter((s)=>s.source==="db").length,fromEnv:slots.filter((s)=>s.source==="env").length,missing:slots.filter((s)=>s.source==="missing").length,missingRequired:slots.filter((s)=>s.source==="missing"&&s.required).length}}}},{detail:{tags:["Secrets"],summary:"List credential slots discovered from the running config",description:"Slots are derived by walking the config tree, so a new integration appears without a code change. Values are never returned \u2014 only a masked preview and the resolution source."}}),plugin.get("/",async({set})=>{let service=requireService(set);if(!service)return{isSuccess:!1,message:"Secrets management is disabled",data:null};return{isSuccess:!0,message:"Stored credentials",data:{secrets:await service.list()}}},{detail:{tags:["Secrets"],summary:"List stored credentials",description:"Metadata only \u2014 the encrypted value is never returned."}}),plugin.put("/:scope/:key",async({params,body,set,request})=>{let service=requireService(set);if(!service)return{isSuccess:!1,message:"Secrets management is disabled",data:null};let{scope,key:key2}=params;if(!SCOPE_PATTERN.test(scope))return fail5(set,400,"Invalid scope");if(!KEY_PATTERN.test(key2))return fail5(set,400,"Invalid key");let value=body.value;if(typeof value!=="string"||value.length===0)return fail5(set,400,"value is required");if(value.length>65536)return fail5(set,400,"value exceeds 64KB");if(body.kind==="json")try{JSON.parse(value)}catch{return fail5(set,400,"value is not valid JSON")}let saved=await service.set({scope,key:key2,value,kind:body.kind,description:body.description,actorId:actorOf(request)});if(!saved)return fail5(set,500,"Could not store the credential");return{isSuccess:!0,message:"Credential stored",data:{secret:saved}}},{params:t15.Object({scope:t15.String(),key:t15.String()}),body:t15.Object({value:t15.String(),kind:t15.Optional(t15.Union(SECRET_KINDS.map((kind)=>t15.Literal(kind)))),description:t15.Optional(t15.String())}),detail:{tags:["Secrets"],summary:"Set or rotate a credential",description:"Stores the value encrypted (AES-256-GCM). Rotating retains the previous value for a one-step rollback. Takes effect within seconds on every pod \u2014 no restart."}}),plugin.post("/:scope/:key/rollback",async({params,set,request})=>{let service=requireService(set);if(!service)return{isSuccess:!1,message:"Secrets management is disabled",data:null};let restored=await service.rollback(params.scope,params.key,actorOf(request));if(!restored)return fail5(set,404,"No previous value to roll back to");return{isSuccess:!0,message:"Previous credential restored",data:{secret:restored}}},{params:t15.Object({scope:t15.String(),key:t15.String()}),detail:{tags:["Secrets"],summary:"Roll back to the value replaced by the last rotation"}}),plugin.delete("/:scope/:key",async({params,set,request})=>{let service=requireService(set);if(!service)return{isSuccess:!1,message:"Secrets management is disabled",data:null};if(!await service.remove(params.scope,params.key,actorOf(request)))return fail5(set,404,"Credential not found");return{isSuccess:!0,message:"Credential removed \u2014 the config falls back to env or literal",data:null}},{params:t15.Object({scope:t15.String(),key:t15.String()}),detail:{tags:["Secrets"],summary:"Delete a stored credential",description:"Resolution falls back to the env var or literal declared in config."}}),plugin.post("/test",async({body,set})=>{let service=requireService(set);if(!service)return{isSuccess:!1,message:"Secrets management is disabled",data:null};let{target:target2}=body,result;if(target2==="email")result=await testEmailProvider(getEmailService?.()??null,body.recipient);else if(target2==="oauth"){let provider=body.provider;if(!provider)return fail5(set,400,"provider is required for an oauth test");let scope=`authentication.oauth.providers.${provider}`,providerConfig=(resolvedOptions.authentication?.oauth?.providers??{})[provider]??{},declaredString=(key2)=>{let raw=providerConfig[key2];return typeof raw==="string"?raw:void 0};result=await testOAuthProvider(provider,{clientId:service.value(scope,"clientId",declaredString("clientId")),clientSecret:service.value(scope,"clientSecret",declaredString("clientSecret")),tenantId:service.value(scope,"tenantId",declaredString("tenantId")),tokenUrl:declaredString("tokenUrl"),redirectUri:service.value(scope,"redirectUri",declaredString("redirectUri"))})}else if(target2==="storage")result=await testStorageProvider(getStorageProvider2?.()??null);else return fail5(set,400,`Unsupported test target "${target2}"`);return logger2.info("[Secrets] Connection test",{target:target2,provider:body.provider,status:result.status,durationMs:result.durationMs}),{isSuccess:result.ok,message:result.message,data:{result}}},{body:t15.Object({target:t15.Union([t15.Literal("oauth"),t15.Literal("email"),t15.Literal("storage")]),provider:t15.Optional(t15.String()),recipient:t15.Optional(t15.String())}),detail:{tags:["Secrets"],summary:"Test a credential against the real provider",description:"Backend-to-backend only. OAuth uses client_credentials where the provider supports it and a client-authentication probe otherwise; email optionally sends a real test message."}}),plugin.post("/reencrypt",async({body,set})=>{let service=requireService(set);if(!service)return{isSuccess:!1,message:"Secrets management is disabled",data:null};if(!body.newMasterKey||body.newMasterKey.length<16)return fail5(set,400,"newMasterKey must be at least 16 characters");let result=await service.reencryptAll(body.newMasterKey);return{isSuccess:result.failed.length===0,message:result.failed.length===0?`Re-encrypted ${result.migrated} credentials \u2014 deploy the new key before the next restart`:`Re-encrypted ${result.migrated}, failed ${result.failed.length}`,data:result}},{body:t15.Object({newMasterKey:t15.String()}),detail:{tags:["Secrets"],summary:"Re-encrypt every credential under a new master key",description:"Rotates the key protecting the store. The new key must be deployed to the environment before the next restart, or nothing will decrypt."}}),plugin.get("/discover",()=>({isSuccess:!0,message:"Slots discovered from the running config",data:{slots:discoverSlots(resolvedOptions).map(({configValue:_configValue,...slot})=>slot)}}),{detail:{tags:["Secrets"],summary:"Show which credential slots the config declares",description:"Diagnostics \u2014 resolution state is not consulted and no value is read."}}),plugin.post("/storage/migrate",async(ctx)=>{let body=ctx.body,build=routeConfig.buildStorageProvider;if(!build)return fail5(ctx.set,503,"Depolama yap\u0131land\u0131r\u0131lmam\u0131\u015F");let destination=build(body.to),source=build(body.to==="smb"?"local":"smb");if(!source||!destination)return fail5(ctx.set,503,"Depolama yap\u0131land\u0131r\u0131lmam\u0131\u015F");if(!await destination.isAvailable())return fail5(ctx.set,422,`Hedef depo eri\u015Filebilir de\u011Fil (${destination.describe}) \u2014 \xF6nce ba\u011Flant\u0131y\u0131 test edin`);if(body.dryRun){let preview=await migrateStorage({from:source,to:Object.assign(Object.create(Object.getPrototypeOf(destination)),destination,{exists:async()=>!1,write:async()=>{},ensureDir:async()=>{}}),maxFiles:1e5},{logger:logger2});return{isSuccess:!0,message:`${preview.copied} dosya ta\u015F\u0131nacak`,data:{preview}}}let report=await migrateStorage({from:source,to:destination},{logger:logger2}),clean=report.failed===0&&!report.truncated;return logger2.warn("[Storage] Migration run from the admin panel",{to:body.to,copied:report.copied,skipped:report.skipped,failed:report.failed,truncated:report.truncated}),{isSuccess:clean,message:clean?`${report.copied} dosya ta\u015F\u0131nd\u0131, ${report.skipped} zaten mevcuttu`:`${report.copied} ta\u015F\u0131nd\u0131, ${report.failed} ba\u015Far\u0131s\u0131z${report.truncated?", liste kesildi":""}`,data:{report}}},{body:t15.Object({to:t15.Union([t15.Literal("local"),t15.Literal("smb")]),dryRun:t15.Optional(t15.Boolean())}),detail:{tags:["Secrets"],summary:"Copy every stored file to the other backend",description:"Copy-only: the source is never deleted, and a file already on the target is skipped so a re-run resumes. Run BEFORE switching storage.provider."}}),plugin}var snakeToCamel4=(s)=>s.replace(/_([a-z])/g,(_,l)=>l.toUpperCase());function warnOnEntityBasePathCollision(feature,basePath,entities,logger2){let segment=basePath.replace(/^\/+|\/+$/g,"");if(!segment||segment.includes("/"))return!1;let clash=(entities??[]).find((entity)=>snakeToCamel4(entity.table_name)===segment);if(!clash)return!1;return logger2.error(`[${feature}] basePath "${basePath}" is also the generated entity route for "${clash.table_name}". Both are registered and one will shadow the other. Move the feature (e.g. "/nucleus${basePath}") or rename the entity.`),!0}var ipMatches=(ip,entry)=>entry.includes("/")?isIpInCidr(ip,entry):ip===entry;function resolveClientIp(socketIp,forwardedFor,trustedProxies=[]){let peer=socketIp?.trim()||"",chain=(forwardedFor||"").split(",").map((s)=>s.trim()).filter(Boolean);if(!peer)return chain[0]||"unknown";if(trustedProxies.length===0)return peer;let trusted=(ip)=>trustedProxies.some((p)=>ipMatches(ip,p));if(!trusted(peer))return peer;for(let i=chain.length-1;i>=0;i--){let hop=chain[i];if(hop&&!trusted(hop))return hop}return chain[0]||peer}var DEFAULTS={cookieName:"csrf_token",headerName:"x-csrf-token"},resolveCsrfConfig=(raw)=>{if(raw===!0)return{enabled:!0,...DEFAULTS};if(!raw)return{enabled:!1,...DEFAULTS};return{enabled:raw.enabled!==!1,cookieName:raw.cookieName||DEFAULTS.cookieName,headerName:(raw.headerName||DEFAULTS.headerName).toLowerCase()}},parseCookies=(cookieHeader)=>{let out={};if(!cookieHeader)return out;for(let part of cookieHeader.split(";")){let trimmed=part.trim(),eq32=trimmed.indexOf("=");if(eq32>0)out[trimmed.slice(0,eq32)]=trimmed.slice(eq32+1)}return out},SAFE_METHODS=new Set(["GET","HEAD","OPTIONS"]),isStateChanging=(method)=>!SAFE_METHODS.has(method.toUpperCase()),requiresCsrf=(params)=>{if(!isStateChanging(params.method))return!1;if(params.hasAuthorizationHeader)return!1;return params.authCookieNames.some((n)=>!!params.cookies[n])},csrfTokenMatches=(csrfCookie,csrfHeader)=>{if(!csrfCookie||!csrfHeader)return!1;return csrfCookie===csrfHeader};var SENSITIVE_HEADER_NAMES=new Set(["authorization","proxy-authorization","cookie","set-cookie","x-access-token","x-refresh-token","x-session-id","x-user-id","x-user-roles","x-user-claims","x-user-email","x-api-key","x-api-key-id","x-api-key-owner-type","x-auth-type"]);function redactSensitiveHeaders(headers){let out={};return headers.forEach((value,key2)=>{out[key2]=SENSITIVE_HEADER_NAMES.has(key2.toLowerCase())?"[REDACTED]":value}),out}var exceedsBodyLimit=(contentLengthHeader,maxBytes)=>{if(!maxBytes||maxBytes<=0)return!1;if(!contentLengthHeader)return!1;let len=Number(contentLengthHeader);if(!Number.isFinite(len)||len<0)return!1;return len>maxBytes};init_sensitiveColumns();var TENANT_CLAIM="tenant",verifyTenantBinding=(tokenTenant,resolvedSchema,mode="lenient")=>{if(mode==="off")return{ok:!0};if(!resolvedSchema)return{ok:!0};let claim=typeof tokenTenant==="string"&&tokenTenant.length>0?tokenTenant:void 0;if(!claim)return mode==="strict"?{ok:!1,reason:"token is not bound to a tenant"}:{ok:!0};return claim===resolvedSchema?{ok:!0}:{ok:!1,reason:"token tenant does not match the requested tenant"}};init_storage2();import{eq as eq32}from"drizzle-orm";import{Elysia as Elysia19,t as t16}from"elysia";var RESERVED_SUBDOMAINS=["www","api","app","admin","dashboard","mail","ftp","cdn","static","assets","docs","help","support","status","blog","dev","staging","test","demo","localhost"],DEFAULT_SELF_SIGNUP_LIMITS={maxSignupsPerIpPerWindow:3,ipWindowMs:3600000,maxTenantsPerEmail:1};var col9=(table,name2)=>table[name2];function createCheckSubdomainRoute(config){let checkRoute=new Elysia19;return checkRoute.get("/tenants/check-subdomain/:subdomain",async(ctx)=>{let{subdomain}=ctx.params,normalized=subdomain.toLowerCase().trim();if(!/^[a-z][a-z0-9-]*$/.test(normalized)||normalized.length<2||normalized.length>63)return ctx.set.status=400,{isSuccess:!1,message:"Invalid subdomain format. Must start with a letter, contain only lowercase letters, numbers, and hyphens, and be 2-63 characters.",data:{available:!1,subdomain:normalized}};if(RESERVED_SUBDOMAINS.includes(normalized))return{isSuccess:!0,message:"Subdomain is reserved",data:{available:!1,subdomain:normalized}};let tenantRegistry=config.getTenantRegistry(),db=config.getDb();if(tenantRegistry){if(tenantRegistry.getActiveTenants().find((t17)=>t17.subdomain===normalized))return{isSuccess:!0,message:"Subdomain is already taken",data:{available:!1,subdomain:normalized}}}if(db&&tenantRegistry){let tenantsTable=tenantRegistry.getMainContext().schemaTables.tenants;if(tenantsTable)try{if((await db.select().from(tenantsTable).where(eq32(col9(tenantsTable,"subdomain"),normalized)).limit(1)).length>0)return{isSuccess:!0,message:"Subdomain is already taken",data:{available:!1,subdomain:normalized}}}catch{}}return{isSuccess:!0,message:"Subdomain is available",data:{available:!0,subdomain:normalized}}},{params:t16.Object({subdomain:t16.String({minLength:2,maxLength:63})}),detail:{tags:["Tenants"],summary:"Check subdomain availability",description:"Public endpoint to check if a subdomain is available for registration. No authentication required."}}),checkRoute}init_Logger2();import{eq as eq33}from"drizzle-orm";import{Elysia as Elysia20,t as t17}from"elysia";var col10=(table,name2)=>table[name2];function createManageRoutes(config){let log4=config.logger.scoped(TENANT_SUSPEND),manageRoutes=new Elysia20;return manageRoutes.get("/tenants",async(ctx)=>{let db=config.getDb(),tenantRegistry=config.getTenantRegistry();if(!db||!tenantRegistry)return ctx.set.status=503,{success:!1,message:"Tenant management not available",data:null};let requestingUserId=ctx.request.headers.get("x-user-id");if(!requestingUserId)return ctx.set.status=401,{success:!1,message:"Authentication required",data:null};if(!await verifyGodmin(db,tenantRegistry,requestingUserId))return ctx.set.status=403,{success:!1,message:"Godmin privileges required",data:null};let allTenants=[...tenantRegistry.getActiveTenants(),...Array.from(getAllTenants(tenantRegistry)).filter((t18)=>t18.status!=="active")];return{success:!0,message:`Found ${allTenants.length} tenants`,data:{items:allTenants.map((t18)=>({id:t18.id,subdomain:t18.subdomain,schemaName:t18.schemaName,companyId:t18.companyId,companyName:t18.companyName,godAdminEmail:t18.godAdminEmail,status:t18.status,plan:t18.plan,domain:t18.domain,maxUsers:t18.maxUsers,provisionedAt:t18.provisionedAt,suspendedAt:t18.suspendedAt})),totalCount:allTenants.length}}},{detail:{tags:["Tenants"],summary:"List tenants",description:"List all tenants in the platform. Requires godmin privileges."}}),manageRoutes.get("/tenants/:id",async(ctx)=>{let db=config.getDb(),tenantRegistry=config.getTenantRegistry();if(!db||!tenantRegistry)return ctx.set.status=503,{success:!1,message:"Tenant management not available",data:null};let requestingUserId=ctx.request.headers.get("x-user-id");if(!requestingUserId)return ctx.set.status=401,{success:!1,message:"Authentication required",data:null};if(!await verifyGodmin(db,tenantRegistry,requestingUserId))return ctx.set.status=403,{success:!1,message:"Godmin privileges required",data:null};let{id}=ctx.params,tenant=tenantRegistry.getTenantById(id);if(!tenant)return ctx.set.status=404,{success:!1,message:"Tenant not found",data:null};let features=tenantRegistry.getTenantFeatures(id);return{success:!0,message:"Tenant found",data:{...tenant,features:features.map((f)=>({featureName:f.featureName,enabled:f.enabled}))}}},{detail:{tags:["Tenants"],summary:"Get tenant details",description:"Get detailed information about a specific tenant. Requires godmin privileges."}}),manageRoutes.post("/tenants/:id/suspend",async(ctx)=>{let db=config.getDb(),tenantRegistry=config.getTenantRegistry();if(!db||!tenantRegistry)return ctx.set.status=503,{success:!1,message:"Tenant management not available"};let requestingUserId=ctx.request.headers.get("x-user-id");if(!requestingUserId)return ctx.set.status=401,{success:!1,message:"Authentication required"};if(!await verifyGodmin(db,tenantRegistry,requestingUserId))return ctx.set.status=403,{success:!1,message:"Godmin privileges required"};let{id}=ctx.params,body=ctx.body,tenant=tenantRegistry.getTenantById(id);if(!tenant)return ctx.set.status=404,{success:!1,message:"Tenant not found"};if(tenant.status==="suspended")return ctx.set.status=400,{success:!1,message:"Tenant is already suspended"};let mainContext=tenantRegistry.getMainContext(),tenantsTable=mainContext.schemaTables.tenants;if(!tenantsTable)return ctx.set.status=503,{success:!1,message:"Tenants table not available"};let now=new Date;await db.update(tenantsTable).set({status:"suspended",suspendedAt:now,suspendedReason:body.reason||"Suspended by godmin",updatedAt:now}).where(eq33(col10(tenantsTable,"id"),id));let tenantEventsTable=mainContext.schemaTables.tenantEvents;if(tenantEventsTable)try{await db.insert(tenantEventsTable).values({id:crypto.randomUUID(),tenantId:id,eventType:"suspended",eventData:JSON.stringify({reason:body.reason||"Suspended by godmin"}),performedBy:requestingUserId,ipAddress:ctx.request.headers.get("x-forwarded-for")?.split(",")[0]?.trim()||"unknown",createdAt:now,updatedAt:now})}catch{log4.warn("Failed to record suspend event")}return await tenantRegistry.refreshTenant(id),log4.info("Tenant suspended",{tenantId:id,reason:body.reason}),{success:!0,message:`Tenant "${tenant.subdomain}" suspended`}},{body:t17.Object({reason:t17.Optional(t17.String())}),detail:{tags:["Tenants"],summary:"Suspend tenant",description:"Suspend a tenant, preventing all access. Requires godmin privileges."}}),manageRoutes.post("/tenants/:id/reactivate",async(ctx)=>{let db=config.getDb(),tenantRegistry=config.getTenantRegistry();if(!db||!tenantRegistry)return ctx.set.status=503,{success:!1,message:"Tenant management not available"};let requestingUserId=ctx.request.headers.get("x-user-id");if(!requestingUserId)return ctx.set.status=401,{success:!1,message:"Authentication required"};if(!await verifyGodmin(db,tenantRegistry,requestingUserId))return ctx.set.status=403,{success:!1,message:"Godmin privileges required"};let{id}=ctx.params,tenant=tenantRegistry.getTenantById(id);if(!tenant)return ctx.set.status=404,{success:!1,message:"Tenant not found"};if(tenant.status!=="suspended")return ctx.set.status=400,{success:!1,message:`Tenant is not suspended (current: ${tenant.status})`};let mainContext=tenantRegistry.getMainContext(),tenantsTable=mainContext.schemaTables.tenants;if(!tenantsTable)return ctx.set.status=503,{success:!1,message:"Tenants table not available"};let now=new Date;await db.update(tenantsTable).set({status:"active",suspendedAt:null,suspendedReason:null,updatedAt:now}).where(eq33(col10(tenantsTable,"id"),id));let tenantEventsTable=mainContext.schemaTables.tenantEvents;if(tenantEventsTable)try{await db.insert(tenantEventsTable).values({id:crypto.randomUUID(),tenantId:id,eventType:"reactivated",eventData:JSON.stringify({previousReason:tenant.suspendedReason}),performedBy:requestingUserId,ipAddress:ctx.request.headers.get("x-forwarded-for")?.split(",")[0]?.trim()||"unknown",createdAt:now,updatedAt:now})}catch{log4.warn("Failed to record reactivate event")}return await tenantRegistry.refreshTenant(id),log4.info("Tenant reactivated",{tenantId:id}),{success:!0,message:`Tenant "${tenant.subdomain}" reactivated`}},{detail:{tags:["Tenants"],summary:"Reactivate tenant",description:"Reactivate a suspended tenant. Requires godmin privileges."}}),manageRoutes}var verifyGodmin=async(db,tenantRegistry,userId)=>{let usersTable=tenantRegistry.getMainContext().schemaTables.users;if(!usersTable)return!1;return(await db.select().from(usersTable).where(eq33(col10(usersTable,"id"),userId)).limit(1))[0]?.isGod===!0},getAllTenants=(registry2)=>{let schemaNames=registry2.getAllSchemaNames(),tenants=[];for(let name2 of schemaNames){let ctx=registry2.getSchemaContext(name2);if(ctx?.tenant)tenants.push(ctx.tenant)}return tenants};init_Logger2();init_utils6();import{eq as eq34}from"drizzle-orm";import{Elysia as Elysia21,t as t18}from"elysia";var col11=(table,name2)=>table[name2],ProvisionBodySchema=t18.Object({subdomain:t18.String({minLength:2,maxLength:63,pattern:"^[a-z][a-z0-9-]*$"}),companyId:t18.String({minLength:1}),companyName:t18.Optional(t18.String()),godAdminEmail:t18.String({format:"email"}),plan:t18.Optional(t18.String()),domain:t18.Optional(t18.String())});function createProvisionRoute(config){let log4=config.logger.scoped(TENANT_PROVISION),provisionRoutes=new Elysia21;return provisionRoutes.post("/tenants/provision",async(ctx)=>{let db=config.getDb(),tenantRegistry=config.getTenantRegistry();if(!db||!tenantRegistry)return ctx.set.status=503,{success:!1,message:"Tenant provisioning not available"};let requestingUserId=ctx.request.headers.get("x-user-id");if(!requestingUserId)return ctx.set.status=401,{success:!1,message:"Authentication required"};let mainContext=tenantRegistry.getMainContext(),usersTable=mainContext.schemaTables.users;if(!usersTable)return ctx.set.status=503,{success:!1,message:"Users table not available"};let requestingUser=(await db.select().from(usersTable).where(eq34(col11(usersTable,"id"),requestingUserId)).limit(1))[0];if(!requestingUser||!requestingUser.isGod)return ctx.set.status=403,{success:!1,message:"Godmin privileges required"};let body=ctx.body,tenantSchemaName=`tenant_${body.subdomain.replace(/-/g,"_")}`;if(tenantRegistry.getActiveTenants().find((t19)=>t19.subdomain===body.subdomain))return ctx.set.status=409,{success:!1,message:`Subdomain "${body.subdomain}" is already taken`};let tenantsTable=mainContext.schemaTables.tenants;if(!tenantsTable)return ctx.set.status=503,{success:!1,message:"Tenants table not available in main schema"};let tenantId=crypto.randomUUID(),now=new Date;try{await db.insert(tenantsTable).values({id:tenantId,subdomain:body.subdomain,schemaName:tenantSchemaName,companyId:body.companyId,companyName:body.companyName||null,godAdminEmail:body.godAdminEmail,status:"provisioning",plan:body.plan||null,domain:body.domain||null,createdAt:now,updatedAt:now}),log4.info("Tenant record created",{tenantId,subdomain:body.subdomain,schemaName:tenantSchemaName})}catch(err){let msg=err instanceof Error?err.message:String(err);return log4.error("Failed to insert tenant record",{error:msg}),ctx.set.status=500,{success:!1,message:`Failed to create tenant record: ${msg}`}}try{let tenantRecord={id:tenantId,subdomain:body.subdomain,schemaName:tenantSchemaName,companyId:body.companyId,companyName:body.companyName||null,godAdminEmail:body.godAdminEmail,status:"provisioning",plan:body.plan||null,domain:body.domain||null,settings:{},trustedSources:[],maxUsers:null,provisionedAt:null,suspendedAt:null,suspendedReason:null},tenantContext=await tenantRegistry.provisionTenant(tenantRecord);log4.info("Schema provisioned",{tenantId,schemaName:tenantSchemaName,tableCount:Object.keys(tenantContext.schemaTables).length});let tenantUsersTable=tenantContext.schemaTables.users;if(tenantUsersTable){let godminId=crypto.randomUUID(),tempPassword=crypto.randomUUID().slice(0,16),hashedPassword=await hashPassword(tempPassword);await db.insert(tenantUsersTable).values({id:godminId,email:body.godAdminEmail,password:hashedPassword,isGod:!0,isActive:!0,createdAt:now,updatedAt:now}),log4.info("Godmin user seeded",{tenantId,godminEmail:body.godAdminEmail,godminId})}await db.update(tenantsTable).set({status:"active",provisionedAt:now,updatedAt:now}).where(eq34(col11(tenantsTable,"id"),tenantId));let tenantEventsTable=mainContext.schemaTables.tenantEvents;if(tenantEventsTable)try{await db.insert(tenantEventsTable).values({id:crypto.randomUUID(),tenantId,eventType:"provisioned",eventData:JSON.stringify({schemaName:tenantSchemaName,godAdminEmail:body.godAdminEmail,plan:body.plan||null}),performedBy:requestingUserId,ipAddress:ctx.request.headers.get("x-forwarded-for")?.split(",")[0]?.trim()||"unknown",createdAt:now,updatedAt:now})}catch{log4.warn("Failed to record tenant_event, continuing")}return await tenantRegistry.refreshTenant(tenantId),log4.info("Provisioning complete",{tenantId,subdomain:body.subdomain,schemaName:tenantSchemaName}),await config.logger.audit({entityName:"tenants",entityId:tenantId,operation:"PROVISION",userId:requestingUserId,summary:`Tenant "${body.subdomain}" provisioned by godmin`,ipAddress:ctx.request.headers.get("x-forwarded-for")?.split(",")[0]?.trim()||"unknown",userAgent:ctx.request.headers.get("user-agent")||"unknown",path:new URL(ctx.request.url).pathname,query:""}),{success:!0,message:"Tenant provisioned successfully",data:{tenantId,schemaName:tenantSchemaName,subdomain:body.subdomain,godAdminEmail:body.godAdminEmail,status:"active"}}}catch(err){let msg=err instanceof Error?err.message:String(err);log4.error("Provisioning failed",{error:msg,tenantId});try{await db.update(tenantsTable).set({status:"provisioning",updatedAt:now}).where(eq34(col11(tenantsTable,"id"),tenantId))}catch{}return ctx.set.status=500,{success:!1,message:`Provisioning failed: ${msg}`}}},{body:ProvisionBodySchema,detail:{tags:["Tenants"],summary:"Provision new tenant",description:"Create a new tenant with its own schema, tables, and godmin user. Requires godmin privileges."}}),provisionRoutes}init_Authorization();init_Logger2();init_utils6();import{eq as eq35}from"drizzle-orm";import{Elysia as Elysia22,t as t19}from"elysia";var col12=(table,name2)=>table[name2],ipRateMap=new Map,lastCleanup=Date.now();function cleanupRateMap(windowMs){let now=Date.now();if(now-lastCleanup<600000)return;lastCleanup=now;for(let[key2,entry]of ipRateMap.entries())if(now-entry.windowStart>windowMs)ipRateMap.delete(key2)}function isIpRateLimited(ip,maxPerWindow,windowMs){let now=Date.now(),entry=ipRateMap.get(ip);if(!entry||now-entry.windowStart>windowMs)return ipRateMap.set(ip,{count:1,windowStart:now}),!1;return entry.count++,entry.count>maxPerWindow}var SelfSignupBodySchema=t19.Object({email:t19.String({format:"email"}),password:t19.String({minLength:8}),subdomain:t19.String({minLength:2,maxLength:63,pattern:"^[a-z][a-z0-9-]*$"}),plan:t19.Optional(t19.String()),companyName:t19.Optional(t19.String())});function createSelfSignupRoute(config){let log4=config.logger.scoped(TENANT_SELF_SIGNUP),limits={...DEFAULT_SELF_SIGNUP_LIMITS,...config.selfSignupLimits},selfSignupRoutes=new Elysia22;return selfSignupRoutes.post("/tenants/self-signup",async(ctx)=>{cleanupRateMap(limits.ipWindowMs);let db=config.getDb(),tenantRegistry=config.getTenantRegistry();if(!db||!tenantRegistry)return ctx.set.status=503,{success:!1,message:"Tenant provisioning not available"};let ip=ctx.request.headers.get("x-forwarded-for")?.split(",")[0]?.trim()||ctx.request.headers.get("x-real-ip")?.trim()||"unknown";if(isIpRateLimited(ip,limits.maxSignupsPerIpPerWindow,limits.ipWindowMs))return log4.warn("Self-signup rate limited",{ip}),ctx.set.status=429,{success:!1,message:"Too many signup attempts. Please try again later."};let body=ctx.body,email=body.email.toLowerCase().trim(),subdomain=body.subdomain.toLowerCase().trim();if(RESERVED_SUBDOMAINS.includes(subdomain))return ctx.set.status=400,{success:!1,message:"This subdomain is reserved."};let mainContext=tenantRegistry.getMainContext(),usersTable=mainContext.schemaTables.users,tenantsTable=mainContext.schemaTables.tenants;if(!usersTable||!tenantsTable)return ctx.set.status=503,{success:!1,message:"Required tables not available."};if(tenantRegistry.getActiveTenants().find((t20)=>t20.subdomain===subdomain))return ctx.set.status=409,{success:!1,message:"This subdomain is already taken."};try{if((await db.select().from(tenantsTable).where(eq35(col12(tenantsTable,"subdomain"),subdomain)).limit(1)).length>0)return ctx.set.status=409,{success:!1,message:"This subdomain is already taken."}}catch{}try{if((await db.select().from(tenantsTable).where(eq35(col12(tenantsTable,"godAdminEmail"),email))).length>=limits.maxTenantsPerEmail)return ctx.set.status=409,{success:!1,message:`Tenant limit reached. Maximum ${limits.maxTenantsPerEmail} tenant(s) per account.`}}catch{}let userId,hashedPassword=await hashPassword(body.password),now=new Date,existingUsers=await db.select().from(usersTable).where(eq35(col12(usersTable,"email"),email)).limit(1);if(existingUsers.length>0)userId=existingUsers[0].id,log4.info("Self-signup: existing user resolved",{userId,email});else{userId=crypto.randomUUID();try{await db.insert(usersTable).values({id:userId,email,password:hashedPassword,isActive:!0,createdAt:now,updatedAt:now}),log4.info("Self-signup: user created",{userId,email})}catch(err){let msg=err instanceof Error?err.message:String(err);return log4.error("Self-signup: user creation failed",{error:msg}),ctx.set.status=500,{success:!1,message:"Failed to create account."}}}let tenantId=crypto.randomUUID(),tenantSchemaName=`tenant_${subdomain.replace(/-/g,"_")}`;try{await db.insert(tenantsTable).values({id:tenantId,subdomain,schemaName:tenantSchemaName,companyId:userId,companyName:body.companyName||subdomain,godAdminEmail:email,status:"provisioning",plan:body.plan||null,createdAt:now,updatedAt:now}),log4.info("Tenant record created",{tenantId,subdomain})}catch(err){let msg=err instanceof Error?err.message:String(err);return log4.error("Tenant record creation failed",{error:msg}),ctx.set.status=500,{success:!1,message:"Failed to create tenant."}}try{let tenantRecord={id:tenantId,subdomain,schemaName:tenantSchemaName,companyId:userId,companyName:body.companyName||subdomain,godAdminEmail:email,status:"provisioning",plan:body.plan||null,domain:null,settings:{},trustedSources:[],maxUsers:null,provisionedAt:null,suspendedAt:null,suspendedReason:null},tenantContext=await tenantRegistry.provisionTenant(tenantRecord);log4.info("Schema provisioned",{tenantId,schemaName:tenantSchemaName,tableCount:Object.keys(tenantContext.schemaTables).length});let tenantUsersTable=tenantContext.schemaTables.users;if(tenantUsersTable)await db.insert(tenantUsersTable).values({id:userId,email,password:hashedPassword,isGod:!0,isActive:!0,createdAt:now,updatedAt:now}),log4.info("Godmin seeded in tenant schema",{tenantId,email,userId});let tenantRolesTable=tenantContext.schemaTables.roles,tenantUserRolesTable=tenantContext.schemaTables.userRoles;if(tenantRolesTable&&tenantUserRolesTable)try{let godminRoles=await db.select().from(tenantRolesTable).where(eq35(tenantRolesTable.name,GODMIN_ROLE_NAME)).limit(1),godminRoleId;if(godminRoles.length>0)godminRoleId=godminRoles[0].id;else{let[newRole]=await db.insert(tenantRolesTable).values({name:GODMIN_ROLE_NAME,description:"God mode administrator - bypasses all authorization checks"}).returning();godminRoleId=newRole.id,log4.info("Created godmin role in tenant schema",{tenantId,roleId:godminRoleId})}if(godminRoleId)await db.insert(tenantUserRolesTable).values({userId,roleId:godminRoleId}),log4.info("Assigned godmin role to signup user",{tenantId,userId,roleId:godminRoleId})}catch(roleErr){log4.warn("Failed to assign godmin role to signup user",{tenantId,userId,error:roleErr instanceof Error?roleErr.message:String(roleErr)})}await db.update(tenantsTable).set({status:"active",provisionedAt:now,updatedAt:now}).where(eq35(col12(tenantsTable,"id"),tenantId));let tenantEventsTable=mainContext.schemaTables.tenantEvents;if(tenantEventsTable)try{await db.insert(tenantEventsTable).values({id:crypto.randomUUID(),tenantId,eventType:"self_signup",eventData:JSON.stringify({email,subdomain,plan:body.plan||null}),performedBy:userId,ipAddress:ip,createdAt:now,updatedAt:now})}catch{}return await tenantRegistry.refreshTenant(tenantId),log4.info("Self-signup complete",{tenantId,subdomain,email}),await config.logger.audit({entityName:"tenants",entityId:tenantId,operation:"SELF_SIGNUP",userId,summary:`Self-signup: tenant "${subdomain}" provisioned by ${email}`,ipAddress:ip,userAgent:ctx.request.headers.get("user-agent")||"unknown",path:new URL(ctx.request.url).pathname,query:""}),{success:!0,message:"Tenant created successfully",data:{tenantId,subdomain,schemaName:tenantSchemaName,userId,email,status:"active"}}}catch(err){let msg=err instanceof Error?err.message:String(err);log4.error("Self-signup provisioning failed",{error:msg,tenantId});try{await db.update(tenantsTable).set({status:"provisioning",updatedAt:now}).where(eq35(col12(tenantsTable,"id"),tenantId))}catch{}return ctx.set.status=500,{success:!1,message:"Provisioning failed. Please try again."}}},{body:SelfSignupBodySchema,detail:{tags:["Tenants"],summary:"Self-service tenant signup",description:"Public endpoint for self-service signup. Creates user account, provisions tenant schema, and seeds godmin. Rate-limited by IP with configurable max tenants per email."}}),selfSignupRoutes}function createTenantRoutes(app,config){return app.use(createCheckSubdomainRoute(config)),app.use(createProvisionRoute(config)),app.use(createSelfSignupRoute(config)),app.use(createManageRoutes(config)),app}init_Notification();init_Verification();init_adminGuard();import{Elysia as Elysia23,t as t20}from"elysia";function createVerificationRoutes(routeConfig){let{db,schemaTables,config,logger:logger2,tenantRegistry}=routeConfig,defaultVerificationService=new VerificationService({db,schemaTables,config,logger:logger2}),defaultNotificationService=new NotificationService({db,schemaTables,config:routeConfig.notificationConfig||{enabled:!1},logger:logger2,getEmailService:routeConfig.getEmailService}),wireNotificationHandler=(verSvc,notifSvc)=>{verSvc.setNotificationHandler(async(params)=>{if(!routeConfig.notificationConfig?.enabled)return;await notifSvc.triggerNotifications({trigger:params.trigger,flow_id:params.flow_id,entity_name:params.entity_name,entity_id:params.entity_id,node_id:params.node_id,verifier_id:params.verifier_id,decision:params.decision,context:params.context})})};wireNotificationHandler(defaultVerificationService,defaultNotificationService);let getServicesForRequest=(request)=>{if(!tenantRegistry)return{verificationService:defaultVerificationService,notificationService:defaultNotificationService};let schemaName=request.headers.get("x-tenant-schema");if(!schemaName)return{verificationService:defaultVerificationService,notificationService:defaultNotificationService};let ctx=tenantRegistry.getSchemaContext(schemaName);if(!ctx)return{verificationService:defaultVerificationService,notificationService:defaultNotificationService};let reqVerSvc=new VerificationService({db,schemaTables:ctx.schemaTables,config,logger:logger2}),reqNotifSvc=new NotificationService({db,schemaTables:ctx.schemaTables,config:routeConfig.notificationConfig||{enabled:!1},logger:logger2,getEmailService:routeConfig.getEmailService});return wireNotificationHandler(reqVerSvc,reqNotifSvc),{verificationService:reqVerSvc,notificationService:reqNotifSvc}},basePath=config.endpoints?.basePath||"/verifications",flowBasePath=config.flowEndpoints?.basePath||"/verification-flows",routes=new Elysia23,verificationRoutes=new Elysia23({prefix:basePath});if(verificationRoutes.onBeforeHandle(({request,set})=>{if(!request.headers.get("x-user-id"))return set.status=401,{success:!1,message:"Authentication required"}}),verificationRoutes.get("/status/:entity_name/:entity_id",async({params,request,set})=>{let{verificationService}=getServicesForRequest(request),status=await verificationService.getStatus(params.entity_name,params.entity_id),startedBy=status.instance?.started_by;if(!hasGodminRole(request)&&startedBy!=null&&String(startedBy)!==String(request.headers.get("x-user-id")))return set.status=403,{success:!1,message:"Forbidden"};return{success:!0,data:status}},{params:t20.Object({entity_name:t20.String(),entity_id:t20.String()})}),verificationRoutes.post("/:entity_name/:entity_id/decide",async({params,body,request})=>{let{verificationService}=getServicesForRequest(request),userId=request.headers.get("x-user-id");if(!userId)return{success:!1,message:"User ID required",status:401};return await verificationService.decide({entity_name:params.entity_name,entity_id:params.entity_id,user_id:userId,decision:body.decision,reason:body.reason,signature_id:body.signature_id,diff:body.diff})},{params:t20.Object({entity_name:t20.String(),entity_id:t20.String()}),body:t20.Object({decision:t20.Union([t20.Literal("approved"),t20.Literal("rejected")]),reason:t20.Optional(t20.String()),signature_id:t20.Optional(t20.String()),diff:t20.Optional(t20.Record(t20.String(),t20.Unknown()))})}),verificationRoutes.get("/pending",async({request})=>{let{verificationService}=getServicesForRequest(request),userId=request.headers.get("x-user-id");if(!userId)return{success:!1,message:"User ID required",status:401};return{success:!0,data:await verificationService.getPending(userId)}}),verificationRoutes.get("/history/:entity_name/:entity_id",async({params,request,set})=>{let{verificationService}=getServicesForRequest(request),status=await verificationService.getStatus(params.entity_name,params.entity_id),startedBy=status.instance?.started_by;if(!hasGodminRole(request)&&startedBy!=null&&String(startedBy)!==String(request.headers.get("x-user-id")))return set.status=403,{success:!1,message:"Forbidden"};return{success:!0,data:{verifications:status.verifications,current_step:status.current_step,total_steps:status.total_steps,is_completed:status.is_completed,is_rejected:status.is_rejected}}},{params:t20.Object({entity_name:t20.String(),entity_id:t20.String()})}),verificationRoutes.post("/start",async({body,request})=>{let{verificationService}=getServicesForRequest(request),userId=request.headers.get("x-user-id");return await verificationService.startFlow({flow_id:body.flow_id,entity_name:body.entity_name,entity_id:body.entity_id,started_by:userId||void 0})},{body:t20.Object({flow_id:t20.String(),entity_name:t20.String(),entity_id:t20.String()})}),verificationRoutes.post("/start-for-entity",async({body,request})=>{let{verificationService}=getServicesForRequest(request),userId=request.headers.get("x-user-id");return await verificationService.startFlowForEntity({entity_name:body.entity_name,entity_id:body.entity_id,started_by:userId||void 0})},{body:t20.Object({entity_name:t20.String(),entity_id:t20.String()})}),verificationRoutes.get("/statuses/:entity_name",async({params,query,request,set})=>{if(!hasGodminRole(request))return set.status=403,{success:!1,message:"Forbidden: operator privileges required"};let{verificationService}=getServicesForRequest(request);return{success:!0,data:await verificationService.listEntityStatuses({entity_name:params.entity_name,status:query.status||void 0,page:query.page?Number(query.page):void 0,limit:query.limit?Number(query.limit):void 0})}},{params:t20.Object({entity_name:t20.String()}),query:t20.Object({status:t20.Optional(t20.String()),page:t20.Optional(t20.String()),limit:t20.Optional(t20.String())})}),routes.use(verificationRoutes),logger2.info(`[Verification] Routes registered at ${basePath}`),config.flowEndpoints?.enabled!==!1){let flowRoutes=new Elysia23({prefix:flowBasePath});flowRoutes.onBeforeHandle(createGodminGuard({db,schemaTables,logger:logger2},"verification flow management")),flowRoutes.get("/",async({query,request})=>{let{verificationService:vs}=getServicesForRequest(request);return{success:!0,data:await vs.listFlows(query.entity_name||void 0)}},{query:t20.Object({entity_name:t20.Optional(t20.String())})}),flowRoutes.get("/:flow_id",async({params,request})=>{let{verificationService:vs}=getServicesForRequest(request),result=await vs.getFlow(params.flow_id);if(!result)return{success:!1,message:"Flow not found"};return{success:!0,data:result}},{params:t20.Object({flow_id:t20.String()})}),flowRoutes.post("/",async({body,request})=>{let{verificationService:vs}=getServicesForRequest(request);return await vs.saveFlow(body)},{body:t20.Object({flow_id:t20.String(),entity_name:t20.String(),name:t20.String(),description:t20.Optional(t20.String()),trigger_on:t20.Union([t20.Literal("create"),t20.Literal("update"),t20.Literal("delete"),t20.Literal("manual")]),trigger_fields:t20.Optional(t20.Array(t20.String())),is_draft:t20.Boolean(),viewport:t20.Optional(t20.Object({x:t20.Number(),y:t20.Number(),zoom:t20.Number()})),graph:t20.Object({steps:t20.Array(t20.Any()),edges:t20.Array(t20.Any()),verifier_configs:t20.Array(t20.Any()),notification_rules:t20.Array(t20.Any()),notification_recipients:t20.Array(t20.Any()),notification_channels:t20.Array(t20.Any())})})}),flowRoutes.post("/:flow_id/publish",async({params,request})=>{let{verificationService:vs}=getServicesForRequest(request);return await vs.publishFlow(params.flow_id)},{params:t20.Object({flow_id:t20.String()})}),flowRoutes.delete("/:flow_id",async({params,request})=>{let{verificationService:vs}=getServicesForRequest(request);return await vs.deleteFlow(params.flow_id)},{params:t20.Object({flow_id:t20.String()})}),routes.use(flowRoutes),logger2.info(`[Verification] Flow routes registered at ${flowBasePath}`)}return{routes,verificationService:defaultVerificationService,notificationService:defaultNotificationService}}function createNucleusRuntime(deps){return{sendEmail:async(payload)=>{let mailer=deps.getEmailService();if(!mailer?.isAvailable())return{success:!1,error:"No email provider is configured or available"};return mailer.sendEmail(payload)},emailProvider:()=>deps.activeEmailProvider(),isEmailAvailable:()=>!!deps.getEmailService()?.isAvailable()}}import{Elysia as Elysia24}from"elysia";var a=`/* basic theme */
|
|
532
|
+
`)};function createLiveMonitoringRoutes(config){let{getService,logger:logger2,basePath,streamInterval,db,schemaTables}=config,plugin=new Elysia15({prefix:basePath});plugin.onBeforeHandle(createGodminGuard({db:db??null,schemaTables:schemaTables??{},logger:logger2},"live monitoring"));let requireService=()=>{let svc=getService();if(!svc)throw Error("Live monitoring service not initialized");return svc};return plugin.get("/health",()=>{let svc=getService();return{status:svc?"ok":"initializing",timestamp:Date.now(),monitoring:svc?.isEnabled()??!1}},{detail:{tags:["Live Monitoring"],summary:"Health check for live monitoring"}}),plugin.get("/settings",()=>{return requireService().getSettings()},{detail:{tags:["Live Monitoring"],summary:"Get live monitoring settings"}}),plugin.patch("/settings",({body})=>{return requireService().changeSettings(body)},{body:t13.Partial(t13.Object({logMemory:t13.Boolean(),logCpu:t13.Boolean(),logDapr:t13.Boolean(),logWebSocket:t13.Boolean(),memoryLogInterval:t13.Number(),cpuLogInterval:t13.Number(),memoryLogLimit:t13.Number(),cpuLogLimit:t13.Number(),daprLogLimit:t13.Number(),wsLogLimit:t13.Number(),requestLogLimit:t13.Number()})),detail:{tags:["Live Monitoring"],summary:"Change live monitoring settings"}}),plugin.get("/logs",()=>{return requireService().getLogs()},{detail:{tags:["Live Monitoring"],summary:"Get all live monitoring logs"}}),plugin.get("/logs/stream",({request})=>{let abortSignal=request.signal,cleanup,svc=requireService(),snapshot=svc.getSnapshot(),lastTimestamps={memory:snapshot.memory.length?snapshot.memory[snapshot.memory.length-1]?.timestamp??0:0,cpu:snapshot.cpu.length?snapshot.cpu[snapshot.cpu.length-1]?.timestamp??0:0,request:snapshot.requests.length?snapshot.requests[snapshot.requests.length-1]?.timestamp??0:0,dapr:snapshot.dapr.length?snapshot.dapr[snapshot.dapr.length-1]?.timestamp??0:0,ws:snapshot.ws.length?snapshot.ws[snapshot.ws.length-1]?.timestamp??0:0},stream=new ReadableStream({start(controller){let closed=!1;controller.enqueue(encodeEvent("snapshot",snapshot));let interval=setInterval(()=>{if(closed)return;let update=svc.getUpdatesSince(lastTimestamps);if(!update){controller.enqueue(encodeEvent("heartbeat",{timestamp:Date.now()}));return}if(update.memory.length)lastTimestamps.memory=update.memory[update.memory.length-1]?.timestamp??lastTimestamps.memory;if(update.cpu.length)lastTimestamps.cpu=update.cpu[update.cpu.length-1]?.timestamp??lastTimestamps.cpu;if(update.requests.length)lastTimestamps.request=update.requests[update.requests.length-1]?.timestamp??lastTimestamps.request;if(update.dapr.length)lastTimestamps.dapr=update.dapr[update.dapr.length-1]?.timestamp??lastTimestamps.dapr;if(update.ws.length)lastTimestamps.ws=update.ws[update.ws.length-1]?.timestamp??lastTimestamps.ws;controller.enqueue(encodeEvent("update",update))},streamInterval),cleanupHandler=()=>{if(closed)return;closed=!0,clearInterval(interval),abortSignal?.removeEventListener("abort",cleanupHandler);try{controller.close()}catch{}};cleanup=cleanupHandler,abortSignal?.addEventListener("abort",cleanupHandler)},cancel(){cleanup?.()}});return new Response(stream,{headers:STREAM_HEADERS})},{detail:{tags:["Live Monitoring"],summary:"Stream real-time live monitoring data via SSE"}}),logger2.info(`[LiveMonitoring] Routes enabled at ${basePath} (stream interval: ${streamInterval}ms)`),plugin}init_Notification();init_adminGuard();import{Elysia as Elysia16,t as t14}from"elysia";var CHANNELS=["portal","email","telegram","webhook"];function createNotificationRoutes(routeConfig){let{db,schemaTables,config,logger:logger2,tenantRegistry,getEmailService}=routeConfig,basePath=routeConfig.basePath||config.endpoints?.basePath||"/notifications",buildService=(tables)=>new NotificationService({db,schemaTables:tables,config,logger:logger2,getEmailService}),defaultService=buildService(schemaTables),serviceFor=(request)=>{if(!tenantRegistry)return defaultService;let schemaName=request.headers.get("x-tenant-schema");if(!schemaName)return defaultService;let ctx=tenantRegistry.getSchemaContext(schemaName);return ctx?buildService(ctx.schemaTables):defaultService},allowedSendRoles=new Set((config.endpoints?.sendRoles??[]).map((role)=>role.toLowerCase())),canSend=async(request)=>{if(allowedSendRoles.size>0){if(decodeHeaderList(request.headers.get("x-user-roles")).some((role)=>allowedSendRoles.has(role.toLowerCase())))return!0}return isGodminRequest(request,{db,schemaTables,logger:logger2})},routes=new Elysia16({prefix:basePath}),requireUser=(request,set)=>{let userId=request.headers.get("x-user-id");if(!userId)return set.status=401,null;return userId};return routes.get("/",async({request,query,set})=>{let userId=requireUser(request,set);if(!userId)return{success:!1,message:"User ID required"};return{success:!0,data:await serviceFor(request).getNotifications(userId,{limit:query.limit?Number(query.limit):void 0,offset:query.offset?Number(query.offset):void 0,type:query.type||void 0})}},{query:t14.Object({limit:t14.Optional(t14.String()),offset:t14.Optional(t14.String()),type:t14.Optional(t14.String())}),detail:{tags:["Notifications"],summary:"List the caller\u2019s notifications"}}),routes.get("/unseen-count",async({request,set})=>{let userId=requireUser(request,set);if(!userId)return{success:!1,message:"User ID required"};return{success:!0,data:{count:await serviceFor(request).getUnseenCount(userId)}}},{detail:{tags:["Notifications"],summary:"Unseen notification count"}}),routes.post("/:notification_id/seen",async({params,request,set})=>{let userId=requireUser(request,set);if(!userId)return{success:!1,message:"User ID required"};let marked=await serviceFor(request).markAsSeen(params.notification_id,userId);return{success:marked,message:marked?"Marked as seen":"Failed"}},{params:t14.Object({notification_id:t14.String()}),detail:{tags:["Notifications"],summary:"Mark one notification as seen"}}),routes.post("/seen-all",async({request,set})=>{let userId=requireUser(request,set);if(!userId)return{success:!1,message:"User ID required"};return{success:!0,data:{count:await serviceFor(request).markAllAsSeen(userId)}}},{detail:{tags:["Notifications"],summary:"Mark every notification as seen"}}),routes.post("/send",async({body,request,set})=>{if(!requireUser(request,set))return{success:!1,message:"Authentication required"};if(!await canSend(request))return set.status=403,{success:!1,message:"Sending notifications requires godmin or an allowed role"};let recipients=body.userIds??(body.userId?[body.userId]:[]);if(recipients.length===0)return set.status=400,{success:!1,message:"userId or userIds is required"};let channels=body.channels??[config.defaultChannel??"portal"],service=serviceFor(request),failed=(await Promise.allSettled(recipients.map((user_id)=>service.send({user_id,title:body.title,body:body.body,entity_name:body.entityName,entity_id:body.entityId,type:body.type??"custom",source:body.source,channels})))).map((result,index)=>({result,userId:recipients[index]})).filter((entry)=>entry.result.status==="rejected").map((entry)=>entry.userId);return{success:failed.length===0,message:failed.length===0?`Sent to ${recipients.length} recipient(s)`:`Sent to ${recipients.length-failed.length}, failed for ${failed.length}`,data:{sent:recipients.length-failed.length,failed}}},{body:t14.Object({userId:t14.Optional(t14.String()),userIds:t14.Optional(t14.Array(t14.String())),title:t14.String(),body:t14.Optional(t14.String()),entityName:t14.Optional(t14.String()),entityId:t14.Optional(t14.String()),type:t14.Optional(t14.Union([t14.Literal("verification"),t14.Literal("system"),t14.Literal("custom")])),source:t14.Optional(t14.String()),channels:t14.Optional(t14.Array(t14.Union(CHANNELS.map((c)=>t14.Literal(c)))))}),detail:{tags:["Notifications"],summary:"Send a notification to one or more users",description:"Privileged. Delivers over the requested channels (portal, email, telegram, webhook). Email uses the configured provider \u2014 credentials resolve through the secrets store, so a rotation applies immediately."}}),routes.post("/email",async({body,request,set})=>{if(!requireUser(request,set))return{success:!1,message:"Authentication required"};if(!await canSend(request))return set.status=403,{success:!1,message:"Sending email requires godmin or an allowed role"};let emailService=getEmailService?.()??null;if(!emailService?.isAvailable())return set.status=503,{success:!1,message:"No email provider is configured or available"};let result=await emailService.sendEmail({to:body.to,subject:body.subject,html:body.html,text:body.text,replyTo:body.replyTo});if(!result.success)return set.status=502,{success:!1,message:result.error??"Email delivery failed"};return logger2.info("[Notification] Transactional email sent",{recipients:Array.isArray(body.to)?body.to.length:1,subject:body.subject}),{success:!0,message:"Email sent",data:null}},{body:t14.Object({to:t14.Union([t14.String(),t14.Array(t14.String())]),subject:t14.String(),html:t14.Optional(t14.String()),text:t14.Optional(t14.String()),replyTo:t14.Optional(t14.String())}),detail:{tags:["Notifications"],summary:"Send a transactional email to explicit recipients",description:"Backend-to-backend send through the configured provider \u2014 an app never needs an email SDK or the provider credentials of its own. Privileged, same gate as /send."}}),{routes,notificationService:defaultService}}init_ack_manager();import{timingSafeEqual as timingSafeEqual3}from"crypto";import Elysia17 from"elysia";init_ack_manager();var clients=new Map,presenceBroadcastDebounce=new Map;function createClientManager(config){let{redis,logger:logger2}=config,ackTtl=config.ack.ttlSeconds,ackEnabled=config.ack.enabled,maxRetries=config.ack.maxRetries,presenceEnabled=config.presence.enabled,presenceDebounceMs=config.presence.debounceMs,maxClientsPerUser=config.maxClientsPerUser,maxTopicsPerClient=config.maxTopicsPerClient??64,MAX_TOPIC_LENGTH=256;function generateClientId(){return`client_${Date.now()}_${Math.random().toString(36).substring(2,9)}`}function capTopics(topics){let capped=[],seen=new Set;for(let t15 of topics){if(typeof t15!=="string")continue;let trimmed=t15.length>256?t15.slice(0,256):t15;if(seen.has(trimmed))continue;if(seen.add(trimmed),capped.push(trimmed),capped.length>=maxTopicsPerClient)break}return capped}function registerClient(clientId,ws,userId,topics){let existingClients=getClientsByUser(userId);if(existingClients.length>=maxClientsPerUser){let oldestClientId=existingClients[0];if(oldestClientId)logger2.info("[PubSub] Max clients reached, closing oldest",{userId,oldestClientId}),unregisterClient(oldestClientId)}clients.set(clientId,{ws,userId,subscribedTopics:new Set(capTopics(topics)),connectedAt:Date.now(),pendingAcks:new Map}),logger2.info("[PubSub] Client registered",{clientId,userId,topics,totalClients:clients.size})}function unregisterClient(clientId){let client=clients.get(clientId);if(!client)return;let userId=client.userId;if(clients.delete(clientId),logger2.info("[PubSub] Client unregistered",{clientId,userId,totalClients:clients.size}),presenceEnabled&&userId){if(getClientsByUser(userId).length===0)broadcastPresenceToOthers(userId,"offline")}}function updateClientTopics(clientId,topics){let client=clients.get(clientId);if(client)client.subscribedTopics=new Set(capTopics(topics))}function getClientsByUser(userId){let result=[];for(let[clientId,client]of clients)if(client.userId===userId)result.push(clientId);return result}function getConnectedUserIds(){let userIds=new Set;for(let[,client]of clients)if(client.userId)userIds.add(client.userId);return userIds}function getClientCount(){return clients.size}function sendToClient(clientId,message){let client=clients.get(clientId);if(!client)return!1;try{return client.ws.send(JSON.stringify(message)),!0}catch{return clients.delete(clientId),!1}}function broadcastEvent(topic,event){let messageId=generateMessageId(),timestamp=Date.now(),payload=JSON.stringify({type:"event",messageId:ackEnabled?messageId:void 0,topic,data:event,timestamp}),sentCount=0;for(let[clientId,client]of clients)if(client.subscribedTopics.has("*")||client.subscribedTopics.has(topic))try{if(client.ws.send(payload),sentCount++,ackEnabled){if(client.pendingAcks.set(messageId,{sentAt:timestamp,retryCount:0}),recordSent(),client.userId)storePendingMessage(redis,{messageId,topic,clientId,userId:client.userId,data:event,sentAt:timestamp,retryCount:0,maxRetries},ackTtl).catch(()=>{})}}catch{clients.delete(clientId)}logger2.info("[PubSub] Broadcasted event",{topic,messageId,sentCount})}function broadcastToUser(userId,topic,event){let messageId=generateMessageId(),timestamp=Date.now(),payload=JSON.stringify({type:"event",messageId:ackEnabled?messageId:void 0,topic,data:event,timestamp}),sentCount=0,sentToAnyClient=!1;for(let[clientId,client]of clients){if(client.userId!==userId)continue;if(!client.subscribedTopics.has("*")&&!client.subscribedTopics.has(topic))continue;try{if(client.ws.send(payload),sentCount++,sentToAnyClient=!0,ackEnabled)client.pendingAcks.set(messageId,{sentAt:timestamp,retryCount:0}),recordSent()}catch{clients.delete(clientId)}}if(ackEnabled)storePendingMessage(redis,{messageId,topic,clientId:sentToAnyClient?"delivered":"pending",userId,data:event,sentAt:timestamp,retryCount:0,maxRetries},ackTtl).catch(()=>{});logger2.info("[PubSub] Broadcasted to user",{userId,topic,messageId,sentCount,storedForOffline:!sentToAnyClient})}function broadcastToUserNoAck(userId,topic,event){let timestamp=Date.now(),payload=JSON.stringify({type:"event",topic,data:event,timestamp});for(let[clientId,client]of clients){if(client.userId!==userId)continue;if(!client.subscribedTopics.has("*")&&!client.subscribedTopics.has(topic))continue;try{client.ws.send(payload)}catch{clients.delete(clientId)}}}function broadcastPresenceToOthers(userId,status){let debounceKey=`${userId}:${status}`,now=Date.now(),lastBroadcast=presenceBroadcastDebounce.get(debounceKey);if(lastBroadcast&&now-lastBroadcast<presenceDebounceMs)return;if(presenceBroadcastDebounce.set(debounceKey,now),presenceBroadcastDebounce.size>1000){let cutoff=now-presenceDebounceMs*2;for(let[key2,timestamp]of presenceBroadcastDebounce)if(timestamp<cutoff)presenceBroadcastDebounce.delete(key2)}let connectedUserIds=getConnectedUserIds();for(let targetUserId of connectedUserIds)if(targetUserId!==userId)broadcastToUserNoAck(targetUserId,"user-presence",{type:"user-presence",data:{userId,status}})}async function handleClientAck(clientId,messageId){if(!ackEnabled)return!0;let client=clients.get(clientId);if(!client)return!1;if(client.pendingAcks.get(messageId))client.pendingAcks.delete(messageId);if(client.userId)return acknowledgeMessage(redis,client.userId,messageId,ackTtl);return!0}async function deliverPendingMessages(userId,clientId){if(!ackEnabled)return 0;let client=clients.get(clientId);if(!client||client.userId!==userId)return 0;let pendingMessages=await getPendingMessagesForUser(redis,userId);if(pendingMessages.length===0)return 0;logger2.info("[PubSub] Delivering pending messages",{userId,count:pendingMessages.length});let deliveredCount=0;for(let message of pendingMessages){if(!client.subscribedTopics.has("*")&&!client.subscribedTopics.has(message.topic))continue;let payload=JSON.stringify({type:"event",messageId:message.messageId,topic:message.topic,data:message.data,timestamp:message.sentAt,isRedelivery:!0});try{client.ws.send(payload),client.pendingAcks.set(message.messageId,{sentAt:Date.now(),retryCount:message.retryCount+1}),await incrementRetryCount(redis,userId,message.messageId,ackTtl,maxRetries),deliveredCount++}catch{break}}return deliveredCount}return{generateClientId,registerClient,unregisterClient,updateClientTopics,getClientsByUser,getConnectedUserIds,getClientCount,sendToClient,broadcastEvent,broadcastToUser,broadcastToUserNoAck,broadcastPresenceToOthers,handleClientAck,deliverPendingMessages,getPendingMessageCount:(userId)=>getPendingMessageCount(redis,userId)}}var OPAQUE_RUN=/[A-Za-z0-9_-]{24,}(?:\.[A-Za-z0-9_-]{8,}){0,2}/g;function previewOf2(frame){return frame.slice(0,120).replace(OPAQUE_RUN,(match)=>`[redacted ${match.length} chars]`)}function classifyClientFrame(message){if(typeof message==="string"){if(message.trim()==="")return{kind:"ignore"};let parsed;try{parsed=JSON.parse(message)}catch{return{kind:"malformed",preview:previewOf2(message)}}return asMessage(parsed,message.length)}if(message&&typeof message==="object")return asMessage(message,approximateSize(message));return{kind:"ignore"}}function approximateSize(value){if(ArrayBuffer.isView(value))return value.byteLength;if(value instanceof ArrayBuffer)return value.byteLength;try{return JSON.stringify(value)?.length??0}catch{return 0}}function asMessage(value,size){if(!value||typeof value!=="object"||Array.isArray(value))return{kind:"ignore"};let record=value,type=record.type;if(typeof type!=="string"||type==="")return{kind:"ignore"};return{kind:"message",parsed:record,type,size}}function tokensMatch(a,b){let ba=Buffer.from(a),bb=Buffer.from(b);if(ba.length!==bb.length)return!1;return timingSafeEqual3(ba,bb)}var HEARTBEAT_WS_TYPES=new Set(["ping","pong","ack"]);function buildHandshakeHeaders(rawHeaders,queryToken){let headers=new Headers;if(rawHeaders&&typeof rawHeaders==="object"){for(let[key2,value]of Object.entries(rawHeaders))if(typeof value==="string")headers.set(key2,value)}if(queryToken)headers.set("authorization",`Bearer ${queryToken}`),headers.delete("cookie");return headers}function createPubSubRoutes(config){let{logger:logger2,getLiveMonitoringService}=config,clientManager=createClientManager(config);if(config.ack.enabled)initAckCleanup();let cleanupTimer=null,daprApiToken=config.daprApiToken||process.env.APP_API_TOKEN||process.env.DAPR_API_TOKEN,warnedNoDaprToken=!1,plugin=new Elysia17;return plugin.onStart(()=>{if(config.cleanupIntervalMs>0)cleanupTimer=setInterval(()=>{logger2.info("[PubSub] Periodic cleanup running",{totalClients:clientManager.getClientCount()})},config.cleanupIntervalMs);logger2.info("[PubSub] Routes initialized",{basePath:config.basePath,wsPath:config.wsPath,ackEnabled:config.ack.enabled,presenceEnabled:config.presence.enabled})}),plugin.onStop(()=>{if(cleanupTimer)clearInterval(cleanupTimer),cleanupTimer=null}),plugin.post(`${config.basePath}/:topic`,async({params,body,request,set})=>{let topic=params.topic;if(daprApiToken){let presented=request.headers.get("dapr-api-token")??"";if(!tokensMatch(presented,daprApiToken))return logger2.warn("[PubSub] Rejected Dapr event: missing/invalid dapr-api-token",{topic}),set.status=403,{status:"DROP"}}else if(!warnedNoDaprToken)warnedNoDaprToken=!0,logger2.warn("[PubSub] Dapr subscription endpoint is UNAUTHENTICATED \u2014 set config.pubsub.daprApiToken or the APP_API_TOKEN/DAPR_API_TOKEN env so only the Dapr sidecar can inject events");let eventData;try{if(!body){let text2=await request.text();eventData=JSON.parse(text2)}else eventData=body}catch{return set.status=200,{status:"DROP"}}logger2.info("[PubSub] Dapr event received",{topic,eventId:eventData.id,source:eventData.source});let userId=eventData.data?.user_id;if(userId)clientManager.broadcastToUser(userId,topic,eventData);else clientManager.broadcastEvent(topic,eventData);return getLiveMonitoringService?.()?.recordDaprEvent("pubsub_subscribe",{topic,success:!0,metadata:{eventId:eventData.id,source:eventData.source,userId:userId||null}}),set.status=200,{status:"SUCCESS"}}),plugin.ws(config.wsPath,{idleTimeout:config.wsIdleTimeout,open(ws){let data=ws.data||{},query=data.query||{},userId;if(config.authenticate){let handshakeHeaders=buildHandshakeHeaders(data.headers,query.token),authResult=config.authenticate(handshakeHeaders);if(!authResult){ws.send(JSON.stringify({type:"error",error:"Unauthorized: a valid session is required for this connection",timestamp:Date.now()})),ws.close(4001,"Unauthorized"),getLiveMonitoringService?.()?.recordWsEvent("error",{success:!1,error:"Unauthorized WebSocket handshake"});return}userId=authResult.userId}else userId=query.userId;if(!userId){ws.send(JSON.stringify({type:"error",error:"userId is required for WebSocket connection",timestamp:Date.now()})),ws.close(4001,"userId is required"),getLiveMonitoringService?.()?.recordWsEvent("error",{success:!1,error:"userId is required"});return}let clientId=clientManager.generateClientId(),topics=query.topics?.split(",").map((t15)=>t15.trim())||["*"];if(ws.data.clientId=clientId,clientManager.registerClient(clientId,ws,userId,topics),ws.send(JSON.stringify({type:"connected",clientId,subscribedTopics:topics,timestamp:Date.now()})),getLiveMonitoringService?.()?.recordWsEvent("connection",{clientId,userId,topic:topics.join(","),success:!0}),config.presence.enabled)clientManager.broadcastPresenceToOthers(userId,"online");let connectedUserId=userId;if(config.ack.enabled&&connectedUserId)clientManager.getPendingMessageCount(connectedUserId).then((count2)=>{if(count2>0)logger2.info("[PubSub] Delivering pending messages",{userId:connectedUserId,count:count2}),clientManager.deliverPendingMessages(connectedUserId,clientId).catch(()=>{})}).catch(()=>{})},message(ws,message){let clientId=ws.data.clientId,frame=classifyClientFrame(message);if(frame.kind==="ignore")return;if(frame.kind==="malformed"){logger2.debug("[PubSub] Failed to parse client message",{clientId,frame:frame.preview});return}let{parsed}=frame;try{if(!HEARTBEAT_WS_TYPES.has(frame.type))getLiveMonitoringService?.()?.recordWsEvent("message",{clientId,messageType:frame.type,success:!0,dataSize:frame.size});switch(frame.type){case"subscribe":if(Array.isArray(parsed.topics))clientManager.updateClientTopics(clientId,parsed.topics),clientManager.sendToClient(clientId,{type:"subscribed",topics:parsed.topics,timestamp:Date.now()});break;case"unsubscribe":logger2.info("[PubSub] Unsubscribe request",{clientId,topics:parsed.topics});break;case"ping":clientManager.sendToClient(clientId,{type:"pong",timestamp:Date.now()});break;case"ack":if(parsed.messageId)clientManager.handleClientAck(clientId,parsed.messageId).catch(()=>{});break}}catch(error){logger2.error("[PubSub] Client message handler failed",error,{clientId,messageType:frame.type})}},close(ws,code,reason){let clientId=ws.data.clientId;if(clientId)clientManager.unregisterClient(clientId);getLiveMonitoringService?.()?.recordWsEvent("close",{clientId,success:!0,metadata:{code,reason:reason||""}}),logger2.info("[PubSub] Client disconnected",{clientId,code,reason})}}),{plugin,clientManager}}import Elysia18,{t as t15}from"elysia";init_Secrets();var timed=async(fn)=>{let started=performance.now();return{result:await fn(),durationMs:Math.round(performance.now()-started)}},postForm=async(url,body)=>{let response=await fetch(url,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded",Accept:"application/json"},body:new URLSearchParams(body).toString(),signal:AbortSignal.timeout(12000)}),text2=await response.text(),json={};try{json=JSON.parse(text2)}catch{json=Object.fromEntries(new URLSearchParams(text2))}return{status:response.status,json,text:text2}},describeError=(error)=>{if(error instanceof Error){if(error.name==="TimeoutError")return"Provider did not respond within 12s";return error.message}return String(error)},MICROSOFT_TOKEN_URL=(tenant)=>`https://login.microsoftonline.com/${tenant}/oauth2/v2.0/token`,DEFAULT_TOKEN_URLS={google:"https://oauth2.googleapis.com/token",github:"https://github.com/login/oauth/access_token"},describeRedirectUri=(value)=>{let trimmed=value?.trim();if(!trimmed)return"Y\xF6nlendirme adresi (Redirect URI) bo\u015F \u2014 giri\u015F tamamlanamaz";if(/^[A-Z][A-Z0-9_]{2,}$/.test(trimmed))return`Y\xF6nlendirme adresi bir ortam de\u011Fi\u015Fkeni ad\u0131 olarak duruyor ("${trimmed}") ve o de\u011Fi\u015Fken tan\u0131ml\u0131 de\u011Fil`;let parsed;try{parsed=new URL(trimmed)}catch{return`Y\xF6nlendirme adresi ge\xE7erli bir URL de\u011Fil: "${trimmed}"`}if(parsed.protocol!=="https:"&&parsed.hostname!=="localhost")return`Y\xF6nlendirme adresi https olmal\u0131 (\u015Fu an "${parsed.protocol}//")`;return null};async function testOAuthProvider(provider,config){if(!config.clientId||!config.clientSecret)return{ok:!1,status:"failed",message:"Client ID ve Client Secret dolu olmal\u0131",durationMs:0};let redirectProblem=describeRedirectUri(config.redirectUri);if(redirectProblem)return{ok:!1,status:"failed",message:redirectProblem,durationMs:0};try{if(provider==="microsoft"){let tenant=config.tenantId||"common";if(tenant==="common"||tenant==="organizations"||tenant==="consumers")return await probeWithBogusCode(MICROSOFT_TOKEN_URL(tenant),config);let{result,durationMs}=await timed(()=>postForm(MICROSOFT_TOKEN_URL(tenant),{grant_type:"client_credentials",client_id:config.clientId,client_secret:config.clientSecret,scope:"https://graph.microsoft.com/.default"}));if(result.status===200&&result.json.access_token)return{ok:!0,status:"ok",message:`Entra kimlik bilgileri do\u011Fruland\u0131 (tenant ${tenant})`,durationMs};let code=String(result.json.error??result.status);return{ok:!1,status:"failed",message:String(result.json.error_description??result.text).slice(0,400),code,durationMs}}let tokenUrl=config.tokenUrl||DEFAULT_TOKEN_URLS[provider];if(!tokenUrl)return{ok:!1,status:"unknown",message:`"${provider}" i\xE7in token adresi tan\u0131ml\u0131 de\u011Fil \u2014 tokenUrl girin`,durationMs:0};return await probeWithBogusCode(tokenUrl,config)}catch(error){return{ok:!1,status:"failed",message:describeError(error),durationMs:0}}}async function probeWithBogusCode(tokenUrl,config){let{result,durationMs}=await timed(()=>postForm(tokenUrl,{grant_type:"authorization_code",code:"nucleus-credential-probe",client_id:config.clientId,client_secret:config.clientSecret,redirect_uri:config.redirectUri||"https://localhost/callback"})),code=String(result.json.error??""),description=String(result.json.error_description??result.text).slice(0,400);if(code==="invalid_grant"||code==="bad_verification_code")return{ok:!0,status:"ok",message:"Kimlik bilgileri sa\u011Flay\u0131c\u0131 taraf\u0131ndan kabul edildi",code,durationMs};if(code==="invalid_client"||code==="unauthorized_client"||result.status===401)return{ok:!1,status:"failed",message:description||"Sa\u011Flay\u0131c\u0131 Client ID/Secret \xE7iftini reddetti",code:code||"invalid_client",durationMs};if(description.includes("AADSTS7000215")||description.includes("AADSTS700016"))return{ok:!1,status:"failed",message:description,code,durationMs};return{ok:!1,status:"unknown",message:description||"Sa\u011Flay\u0131c\u0131 beklenmeyen bir yan\u0131t d\xF6nd\xFC",code:code||String(result.status),durationMs}}async function testStorageProvider(provider){if(!provider)return{ok:!1,status:"failed",message:"Depolama sa\u011Flay\u0131c\u0131 yap\u0131land\u0131r\u0131lmam\u0131\u015F",durationMs:0};try{let{result,durationMs}=await timed(()=>provider.isAvailable());return result?{ok:!0,status:"ok",message:`Ba\u011Flant\u0131 do\u011Fruland\u0131: ${provider.describe}`,durationMs}:{ok:!1,status:"failed",message:`Eri\u015Filemedi: ${provider.describe} \u2014 sunucu, payla\u015F\u0131m ad\u0131 ve kimlik bilgilerini kontrol edin`,durationMs}}catch(error){return{ok:!1,status:"failed",message:describeError(error),durationMs:0}}}async function testEmailProvider(service,recipient){if(!service)return{ok:!1,status:"failed",message:"E-posta sa\u011Flay\u0131c\u0131 yap\u0131land\u0131r\u0131lmam\u0131\u015F",durationMs:0};if(!service.isAvailable())return{ok:!1,status:"failed",message:"Sa\u011Flay\u0131c\u0131 kimlik bilgileriyle ba\u015Flat\u0131lamad\u0131",durationMs:0};if(!recipient)return{ok:!0,status:"ok",message:"Sa\u011Flay\u0131c\u0131 ba\u015Flat\u0131ld\u0131 \u2014 ger\xE7ek g\xF6nderim i\xE7in bir al\u0131c\u0131 adresi girin",durationMs:0};try{let{result,durationMs}=await timed(()=>service.sendEmail({to:recipient,subject:"Nucleus ba\u011Flant\u0131 testi",html:"<p>Bu e-posta, y\xF6netim panelinden yap\u0131lan ba\u011Flant\u0131 testiyle g\xF6nderildi.</p>"}));return result.success?{ok:!0,status:"ok",message:`Test e-postas\u0131 ${recipient} adresine g\xF6nderildi`,durationMs}:{ok:!1,status:"failed",message:result.error??"G\xF6nderim ba\u015Far\u0131s\u0131z",durationMs}}catch(error){return{ok:!1,status:"failed",message:describeError(error),durationMs:0}}}init_godminGuard();var SECRET_KINDS=["text","password","json","connection_string","pem","boolean","list"];var SCOPE_PATTERN=/^[A-Za-z0-9_.-]{1,200}$/,KEY_PATTERN=/^[A-Za-z0-9_-]{1,120}$/,fail5=(set,status,message)=>{return set.status=status,{isSuccess:!1,message,data:null}};function createSecretsRoutes(routeConfig){let{logger:logger2,basePath,db,schemaTables,getService,resolvedOptions,getEmailService,getStorageProvider:getStorageProvider2}=routeConfig,plugin=new Elysia18({prefix:basePath});plugin.onBeforeHandle(createGodminGuard2({logger:logger2,db,schemaTables,area:"secrets management",allowedRoles:routeConfig.adminRoles}));let requireService=(set)=>{let service=getService();if(!service)return set.status=503,null;return service},actorOf=(request)=>request.headers.get("x-user-id")??void 0;return plugin.get("/slots",async({set})=>{let service=requireService(set);if(!service)return{isSuccess:!1,message:"Secrets management is disabled \u2014 set secrets.enabled and provide an encryption key",data:null};let slots=await service.describe(resolvedOptions),groups=[...new Set(slots.map((s)=>s.group))].sort();return{isSuccess:!0,message:"Credential slots",data:{slots,groups,counts:{total:slots.length,fromDb:slots.filter((s)=>s.source==="db").length,fromEnv:slots.filter((s)=>s.source==="env").length,missing:slots.filter((s)=>s.source==="missing").length,missingRequired:slots.filter((s)=>s.source==="missing"&&s.required).length}}}},{detail:{tags:["Secrets"],summary:"List credential slots discovered from the running config",description:"Slots are derived by walking the config tree, so a new integration appears without a code change. Values are never returned \u2014 only a masked preview and the resolution source."}}),plugin.get("/",async({set})=>{let service=requireService(set);if(!service)return{isSuccess:!1,message:"Secrets management is disabled",data:null};return{isSuccess:!0,message:"Stored credentials",data:{secrets:await service.list()}}},{detail:{tags:["Secrets"],summary:"List stored credentials",description:"Metadata only \u2014 the encrypted value is never returned."}}),plugin.put("/:scope/:key",async({params,body,set,request})=>{let service=requireService(set);if(!service)return{isSuccess:!1,message:"Secrets management is disabled",data:null};let{scope,key:key2}=params;if(!SCOPE_PATTERN.test(scope))return fail5(set,400,"Invalid scope");if(!KEY_PATTERN.test(key2))return fail5(set,400,"Invalid key");let value=body.value;if(typeof value!=="string"||value.length===0)return fail5(set,400,"value is required");if(value.length>65536)return fail5(set,400,"value exceeds 64KB");if(body.kind==="json")try{JSON.parse(value)}catch{return fail5(set,400,"value is not valid JSON")}let saved=await service.set({scope,key:key2,value,kind:body.kind,description:body.description,actorId:actorOf(request)});if(!saved)return fail5(set,500,"Could not store the credential");return{isSuccess:!0,message:"Credential stored",data:{secret:saved}}},{params:t15.Object({scope:t15.String(),key:t15.String()}),body:t15.Object({value:t15.String(),kind:t15.Optional(t15.Union(SECRET_KINDS.map((kind)=>t15.Literal(kind)))),description:t15.Optional(t15.String())}),detail:{tags:["Secrets"],summary:"Set or rotate a credential",description:"Stores the value encrypted (AES-256-GCM). Rotating retains the previous value for a one-step rollback. Takes effect within seconds on every pod \u2014 no restart."}}),plugin.post("/:scope/:key/rollback",async({params,set,request})=>{let service=requireService(set);if(!service)return{isSuccess:!1,message:"Secrets management is disabled",data:null};let restored=await service.rollback(params.scope,params.key,actorOf(request));if(!restored)return fail5(set,404,"No previous value to roll back to");return{isSuccess:!0,message:"Previous credential restored",data:{secret:restored}}},{params:t15.Object({scope:t15.String(),key:t15.String()}),detail:{tags:["Secrets"],summary:"Roll back to the value replaced by the last rotation"}}),plugin.delete("/:scope/:key",async({params,set,request})=>{let service=requireService(set);if(!service)return{isSuccess:!1,message:"Secrets management is disabled",data:null};if(!await service.remove(params.scope,params.key,actorOf(request)))return fail5(set,404,"Credential not found");return{isSuccess:!0,message:"Credential removed \u2014 the config falls back to env or literal",data:null}},{params:t15.Object({scope:t15.String(),key:t15.String()}),detail:{tags:["Secrets"],summary:"Delete a stored credential",description:"Resolution falls back to the env var or literal declared in config."}}),plugin.post("/test",async({body,set})=>{let service=requireService(set);if(!service)return{isSuccess:!1,message:"Secrets management is disabled",data:null};let{target:target2}=body,result;if(target2==="email")result=await testEmailProvider(getEmailService?.()??null,body.recipient);else if(target2==="oauth"){let provider=body.provider;if(!provider)return fail5(set,400,"provider is required for an oauth test");let scope=`authentication.oauth.providers.${provider}`,providerConfig=(resolvedOptions.authentication?.oauth?.providers??{})[provider]??{},declaredString=(key2)=>{let raw=providerConfig[key2];return typeof raw==="string"?raw:void 0};result=await testOAuthProvider(provider,{clientId:service.value(scope,"clientId",declaredString("clientId")),clientSecret:service.value(scope,"clientSecret",declaredString("clientSecret")),tenantId:service.value(scope,"tenantId",declaredString("tenantId")),tokenUrl:declaredString("tokenUrl"),redirectUri:service.value(scope,"redirectUri",declaredString("redirectUri"))})}else if(target2==="storage")result=await testStorageProvider(getStorageProvider2?.()??null);else return fail5(set,400,`Unsupported test target "${target2}"`);return logger2.info("[Secrets] Connection test",{target:target2,provider:body.provider,status:result.status,durationMs:result.durationMs}),{isSuccess:result.ok,message:result.message,data:{result}}},{body:t15.Object({target:t15.Union([t15.Literal("oauth"),t15.Literal("email"),t15.Literal("storage")]),provider:t15.Optional(t15.String()),recipient:t15.Optional(t15.String())}),detail:{tags:["Secrets"],summary:"Test a credential against the real provider",description:"Backend-to-backend only. OAuth uses client_credentials where the provider supports it and a client-authentication probe otherwise; email optionally sends a real test message."}}),plugin.post("/reencrypt",async({body,set})=>{let service=requireService(set);if(!service)return{isSuccess:!1,message:"Secrets management is disabled",data:null};if(!body.newMasterKey||body.newMasterKey.length<16)return fail5(set,400,"newMasterKey must be at least 16 characters");let result=await service.reencryptAll(body.newMasterKey),uncovered="Credentials stored outside this store \u2014 an integration connection\u2019s token, client secret and service password \u2014 are NOT re-encrypted by this. Re-enter them from the integrations panel after the new key is deployed.";return{isSuccess:result.failed.length===0,message:result.failed.length===0?`Re-encrypted ${result.migrated} credentials \u2014 deploy the new key before the next restart. ${uncovered}`:`Nothing was re-encrypted: ${result.failed.length} credential(s) could not be read with the current key, so none were rewritten.`,data:{...result,uncovered}}},{body:t15.Object({newMasterKey:t15.String()}),detail:{tags:["Secrets"],summary:"Re-encrypt every credential under a new master key",description:"Rotates the key protecting the store. The new key must be deployed to the environment before the next restart, or nothing will decrypt."}}),plugin.get("/discover",()=>({isSuccess:!0,message:"Slots discovered from the running config",data:{slots:discoverSlots(resolvedOptions).map(({configValue:_configValue,...slot})=>slot)}}),{detail:{tags:["Secrets"],summary:"Show which credential slots the config declares",description:"Diagnostics \u2014 resolution state is not consulted and no value is read."}}),plugin.post("/storage/migrate",async(ctx)=>{let body=ctx.body,build=routeConfig.buildStorageProvider;if(!build)return fail5(ctx.set,503,"Depolama yap\u0131land\u0131r\u0131lmam\u0131\u015F");let destination=build(body.to),source=build(body.to==="smb"?"local":"smb");if(!source||!destination)return fail5(ctx.set,503,"Depolama yap\u0131land\u0131r\u0131lmam\u0131\u015F");if(!await destination.isAvailable())return fail5(ctx.set,422,`Hedef depo eri\u015Filebilir de\u011Fil (${destination.describe}) \u2014 \xF6nce ba\u011Flant\u0131y\u0131 test edin`);if(body.dryRun){let preview=await migrateStorage({from:source,to:Object.assign(Object.create(Object.getPrototypeOf(destination)),destination,{exists:async()=>!1,write:async()=>{},ensureDir:async()=>{}}),maxFiles:1e5},{logger:logger2});return{isSuccess:!0,message:`${preview.copied} dosya ta\u015F\u0131nacak`,data:{preview}}}let report=await migrateStorage({from:source,to:destination},{logger:logger2}),clean=report.failed===0&&!report.truncated;return logger2.warn("[Storage] Migration run from the admin panel",{to:body.to,copied:report.copied,skipped:report.skipped,failed:report.failed,truncated:report.truncated}),{isSuccess:clean,message:clean?`${report.copied} dosya ta\u015F\u0131nd\u0131, ${report.skipped} zaten mevcuttu`:`${report.copied} ta\u015F\u0131nd\u0131, ${report.failed} ba\u015Far\u0131s\u0131z${report.truncated?", liste kesildi":""}`,data:{report}}},{body:t15.Object({to:t15.Union([t15.Literal("local"),t15.Literal("smb")]),dryRun:t15.Optional(t15.Boolean())}),detail:{tags:["Secrets"],summary:"Copy every stored file to the other backend",description:"Copy-only: the source is never deleted, and a file already on the target is skipped so a re-run resumes. Run BEFORE switching storage.provider."}}),plugin}var snakeToCamel4=(s)=>s.replace(/_([a-z])/g,(_,l)=>l.toUpperCase());function warnOnEntityBasePathCollision(feature,basePath,entities,logger2){let segment=basePath.replace(/^\/+|\/+$/g,"");if(!segment||segment.includes("/"))return!1;let clash=(entities??[]).find((entity)=>snakeToCamel4(entity.table_name)===segment);if(!clash)return!1;return logger2.error(`[${feature}] basePath "${basePath}" is also the generated entity route for "${clash.table_name}". Both are registered and one will shadow the other. Move the feature (e.g. "/nucleus${basePath}") or rename the entity.`),!0}var ipMatches=(ip,entry)=>entry.includes("/")?isIpInCidr(ip,entry):ip===entry;function resolveClientIp(socketIp,forwardedFor,trustedProxies=[]){let peer=socketIp?.trim()||"",chain=(forwardedFor||"").split(",").map((s)=>s.trim()).filter(Boolean);if(!peer)return chain[0]||"unknown";if(trustedProxies.length===0)return peer;let trusted=(ip)=>trustedProxies.some((p)=>ipMatches(ip,p));if(!trusted(peer))return peer;for(let i=chain.length-1;i>=0;i--){let hop=chain[i];if(hop&&!trusted(hop))return hop}return chain[0]||peer}var DEFAULTS={cookieName:"csrf_token",headerName:"x-csrf-token"},resolveCsrfConfig=(raw)=>{if(raw===!0)return{enabled:!0,...DEFAULTS};if(!raw)return{enabled:!1,...DEFAULTS};return{enabled:raw.enabled!==!1,cookieName:raw.cookieName||DEFAULTS.cookieName,headerName:(raw.headerName||DEFAULTS.headerName).toLowerCase()}},parseCookies=(cookieHeader)=>{let out={};if(!cookieHeader)return out;for(let part of cookieHeader.split(";")){let trimmed=part.trim(),eq32=trimmed.indexOf("=");if(eq32>0)out[trimmed.slice(0,eq32)]=trimmed.slice(eq32+1)}return out},SAFE_METHODS=new Set(["GET","HEAD","OPTIONS"]),isStateChanging=(method)=>!SAFE_METHODS.has(method.toUpperCase()),requiresCsrf=(params)=>{if(!isStateChanging(params.method))return!1;if(params.hasAuthorizationHeader)return!1;return params.authCookieNames.some((n)=>!!params.cookies[n])},csrfTokenMatches=(csrfCookie,csrfHeader)=>{if(!csrfCookie||!csrfHeader)return!1;return csrfCookie===csrfHeader};var SENSITIVE_HEADER_NAMES=new Set(["authorization","proxy-authorization","cookie","set-cookie","x-access-token","x-refresh-token","x-session-id","x-user-id","x-user-roles","x-user-claims","x-user-email","x-api-key","x-api-key-id","x-api-key-owner-type","x-auth-type"]);function redactSensitiveHeaders(headers){let out={};return headers.forEach((value,key2)=>{out[key2]=SENSITIVE_HEADER_NAMES.has(key2.toLowerCase())?"[REDACTED]":value}),out}var exceedsBodyLimit=(contentLengthHeader,maxBytes)=>{if(!maxBytes||maxBytes<=0)return!1;if(!contentLengthHeader)return!1;let len=Number(contentLengthHeader);if(!Number.isFinite(len)||len<0)return!1;return len>maxBytes};init_sensitiveColumns();var TENANT_CLAIM="tenant",verifyTenantBinding=(tokenTenant,resolvedSchema,mode="lenient")=>{if(mode==="off")return{ok:!0};if(!resolvedSchema)return{ok:!0};let claim=typeof tokenTenant==="string"&&tokenTenant.length>0?tokenTenant:void 0;if(!claim)return mode==="strict"?{ok:!1,reason:"token is not bound to a tenant"}:{ok:!0};return claim===resolvedSchema?{ok:!0}:{ok:!1,reason:"token tenant does not match the requested tenant"}};init_storage2();import{eq as eq32}from"drizzle-orm";import{Elysia as Elysia19,t as t16}from"elysia";var RESERVED_SUBDOMAINS=["www","api","app","admin","dashboard","mail","ftp","cdn","static","assets","docs","help","support","status","blog","dev","staging","test","demo","localhost"],DEFAULT_SELF_SIGNUP_LIMITS={maxSignupsPerIpPerWindow:3,ipWindowMs:3600000,maxTenantsPerEmail:1};var col9=(table,name2)=>table[name2];function createCheckSubdomainRoute(config){let checkRoute=new Elysia19;return checkRoute.get("/tenants/check-subdomain/:subdomain",async(ctx)=>{let{subdomain}=ctx.params,normalized=subdomain.toLowerCase().trim();if(!/^[a-z][a-z0-9-]*$/.test(normalized)||normalized.length<2||normalized.length>63)return ctx.set.status=400,{isSuccess:!1,message:"Invalid subdomain format. Must start with a letter, contain only lowercase letters, numbers, and hyphens, and be 2-63 characters.",data:{available:!1,subdomain:normalized}};if(RESERVED_SUBDOMAINS.includes(normalized))return{isSuccess:!0,message:"Subdomain is reserved",data:{available:!1,subdomain:normalized}};let tenantRegistry=config.getTenantRegistry(),db=config.getDb();if(tenantRegistry){if(tenantRegistry.getActiveTenants().find((t17)=>t17.subdomain===normalized))return{isSuccess:!0,message:"Subdomain is already taken",data:{available:!1,subdomain:normalized}}}if(db&&tenantRegistry){let tenantsTable=tenantRegistry.getMainContext().schemaTables.tenants;if(tenantsTable)try{if((await db.select().from(tenantsTable).where(eq32(col9(tenantsTable,"subdomain"),normalized)).limit(1)).length>0)return{isSuccess:!0,message:"Subdomain is already taken",data:{available:!1,subdomain:normalized}}}catch{}}return{isSuccess:!0,message:"Subdomain is available",data:{available:!0,subdomain:normalized}}},{params:t16.Object({subdomain:t16.String({minLength:2,maxLength:63})}),detail:{tags:["Tenants"],summary:"Check subdomain availability",description:"Public endpoint to check if a subdomain is available for registration. No authentication required."}}),checkRoute}init_Logger2();import{eq as eq33}from"drizzle-orm";import{Elysia as Elysia20,t as t17}from"elysia";var col10=(table,name2)=>table[name2];function createManageRoutes(config){let log4=config.logger.scoped(TENANT_SUSPEND),manageRoutes=new Elysia20;return manageRoutes.get("/tenants",async(ctx)=>{let db=config.getDb(),tenantRegistry=config.getTenantRegistry();if(!db||!tenantRegistry)return ctx.set.status=503,{success:!1,message:"Tenant management not available",data:null};let requestingUserId=ctx.request.headers.get("x-user-id");if(!requestingUserId)return ctx.set.status=401,{success:!1,message:"Authentication required",data:null};if(!await verifyGodmin(db,tenantRegistry,requestingUserId))return ctx.set.status=403,{success:!1,message:"Godmin privileges required",data:null};let allTenants=[...tenantRegistry.getActiveTenants(),...Array.from(getAllTenants(tenantRegistry)).filter((t18)=>t18.status!=="active")];return{success:!0,message:`Found ${allTenants.length} tenants`,data:{items:allTenants.map((t18)=>({id:t18.id,subdomain:t18.subdomain,schemaName:t18.schemaName,companyId:t18.companyId,companyName:t18.companyName,godAdminEmail:t18.godAdminEmail,status:t18.status,plan:t18.plan,domain:t18.domain,maxUsers:t18.maxUsers,provisionedAt:t18.provisionedAt,suspendedAt:t18.suspendedAt})),totalCount:allTenants.length}}},{detail:{tags:["Tenants"],summary:"List tenants",description:"List all tenants in the platform. Requires godmin privileges."}}),manageRoutes.get("/tenants/:id",async(ctx)=>{let db=config.getDb(),tenantRegistry=config.getTenantRegistry();if(!db||!tenantRegistry)return ctx.set.status=503,{success:!1,message:"Tenant management not available",data:null};let requestingUserId=ctx.request.headers.get("x-user-id");if(!requestingUserId)return ctx.set.status=401,{success:!1,message:"Authentication required",data:null};if(!await verifyGodmin(db,tenantRegistry,requestingUserId))return ctx.set.status=403,{success:!1,message:"Godmin privileges required",data:null};let{id}=ctx.params,tenant=tenantRegistry.getTenantById(id);if(!tenant)return ctx.set.status=404,{success:!1,message:"Tenant not found",data:null};let features=tenantRegistry.getTenantFeatures(id);return{success:!0,message:"Tenant found",data:{...tenant,features:features.map((f)=>({featureName:f.featureName,enabled:f.enabled}))}}},{detail:{tags:["Tenants"],summary:"Get tenant details",description:"Get detailed information about a specific tenant. Requires godmin privileges."}}),manageRoutes.post("/tenants/:id/suspend",async(ctx)=>{let db=config.getDb(),tenantRegistry=config.getTenantRegistry();if(!db||!tenantRegistry)return ctx.set.status=503,{success:!1,message:"Tenant management not available"};let requestingUserId=ctx.request.headers.get("x-user-id");if(!requestingUserId)return ctx.set.status=401,{success:!1,message:"Authentication required"};if(!await verifyGodmin(db,tenantRegistry,requestingUserId))return ctx.set.status=403,{success:!1,message:"Godmin privileges required"};let{id}=ctx.params,body=ctx.body,tenant=tenantRegistry.getTenantById(id);if(!tenant)return ctx.set.status=404,{success:!1,message:"Tenant not found"};if(tenant.status==="suspended")return ctx.set.status=400,{success:!1,message:"Tenant is already suspended"};let mainContext=tenantRegistry.getMainContext(),tenantsTable=mainContext.schemaTables.tenants;if(!tenantsTable)return ctx.set.status=503,{success:!1,message:"Tenants table not available"};let now=new Date;await db.update(tenantsTable).set({status:"suspended",suspendedAt:now,suspendedReason:body.reason||"Suspended by godmin",updatedAt:now}).where(eq33(col10(tenantsTable,"id"),id));let tenantEventsTable=mainContext.schemaTables.tenantEvents;if(tenantEventsTable)try{await db.insert(tenantEventsTable).values({id:crypto.randomUUID(),tenantId:id,eventType:"suspended",eventData:JSON.stringify({reason:body.reason||"Suspended by godmin"}),performedBy:requestingUserId,ipAddress:ctx.request.headers.get("x-forwarded-for")?.split(",")[0]?.trim()||"unknown",createdAt:now,updatedAt:now})}catch{log4.warn("Failed to record suspend event")}return await tenantRegistry.refreshTenant(id),log4.info("Tenant suspended",{tenantId:id,reason:body.reason}),{success:!0,message:`Tenant "${tenant.subdomain}" suspended`}},{body:t17.Object({reason:t17.Optional(t17.String())}),detail:{tags:["Tenants"],summary:"Suspend tenant",description:"Suspend a tenant, preventing all access. Requires godmin privileges."}}),manageRoutes.post("/tenants/:id/reactivate",async(ctx)=>{let db=config.getDb(),tenantRegistry=config.getTenantRegistry();if(!db||!tenantRegistry)return ctx.set.status=503,{success:!1,message:"Tenant management not available"};let requestingUserId=ctx.request.headers.get("x-user-id");if(!requestingUserId)return ctx.set.status=401,{success:!1,message:"Authentication required"};if(!await verifyGodmin(db,tenantRegistry,requestingUserId))return ctx.set.status=403,{success:!1,message:"Godmin privileges required"};let{id}=ctx.params,tenant=tenantRegistry.getTenantById(id);if(!tenant)return ctx.set.status=404,{success:!1,message:"Tenant not found"};if(tenant.status!=="suspended")return ctx.set.status=400,{success:!1,message:`Tenant is not suspended (current: ${tenant.status})`};let mainContext=tenantRegistry.getMainContext(),tenantsTable=mainContext.schemaTables.tenants;if(!tenantsTable)return ctx.set.status=503,{success:!1,message:"Tenants table not available"};let now=new Date;await db.update(tenantsTable).set({status:"active",suspendedAt:null,suspendedReason:null,updatedAt:now}).where(eq33(col10(tenantsTable,"id"),id));let tenantEventsTable=mainContext.schemaTables.tenantEvents;if(tenantEventsTable)try{await db.insert(tenantEventsTable).values({id:crypto.randomUUID(),tenantId:id,eventType:"reactivated",eventData:JSON.stringify({previousReason:tenant.suspendedReason}),performedBy:requestingUserId,ipAddress:ctx.request.headers.get("x-forwarded-for")?.split(",")[0]?.trim()||"unknown",createdAt:now,updatedAt:now})}catch{log4.warn("Failed to record reactivate event")}return await tenantRegistry.refreshTenant(id),log4.info("Tenant reactivated",{tenantId:id}),{success:!0,message:`Tenant "${tenant.subdomain}" reactivated`}},{detail:{tags:["Tenants"],summary:"Reactivate tenant",description:"Reactivate a suspended tenant. Requires godmin privileges."}}),manageRoutes}var verifyGodmin=async(db,tenantRegistry,userId)=>{let usersTable=tenantRegistry.getMainContext().schemaTables.users;if(!usersTable)return!1;return(await db.select().from(usersTable).where(eq33(col10(usersTable,"id"),userId)).limit(1))[0]?.isGod===!0},getAllTenants=(registry2)=>{let schemaNames=registry2.getAllSchemaNames(),tenants=[];for(let name2 of schemaNames){let ctx=registry2.getSchemaContext(name2);if(ctx?.tenant)tenants.push(ctx.tenant)}return tenants};init_Logger2();init_utils6();import{eq as eq34}from"drizzle-orm";import{Elysia as Elysia21,t as t18}from"elysia";var col11=(table,name2)=>table[name2],ProvisionBodySchema=t18.Object({subdomain:t18.String({minLength:2,maxLength:63,pattern:"^[a-z][a-z0-9-]*$"}),companyId:t18.String({minLength:1}),companyName:t18.Optional(t18.String()),godAdminEmail:t18.String({format:"email"}),plan:t18.Optional(t18.String()),domain:t18.Optional(t18.String())});function createProvisionRoute(config){let log4=config.logger.scoped(TENANT_PROVISION),provisionRoutes=new Elysia21;return provisionRoutes.post("/tenants/provision",async(ctx)=>{let db=config.getDb(),tenantRegistry=config.getTenantRegistry();if(!db||!tenantRegistry)return ctx.set.status=503,{success:!1,message:"Tenant provisioning not available"};let requestingUserId=ctx.request.headers.get("x-user-id");if(!requestingUserId)return ctx.set.status=401,{success:!1,message:"Authentication required"};let mainContext=tenantRegistry.getMainContext(),usersTable=mainContext.schemaTables.users;if(!usersTable)return ctx.set.status=503,{success:!1,message:"Users table not available"};let requestingUser=(await db.select().from(usersTable).where(eq34(col11(usersTable,"id"),requestingUserId)).limit(1))[0];if(!requestingUser||!requestingUser.isGod)return ctx.set.status=403,{success:!1,message:"Godmin privileges required"};let body=ctx.body,tenantSchemaName=`tenant_${body.subdomain.replace(/-/g,"_")}`;if(tenantRegistry.getActiveTenants().find((t19)=>t19.subdomain===body.subdomain))return ctx.set.status=409,{success:!1,message:`Subdomain "${body.subdomain}" is already taken`};let tenantsTable=mainContext.schemaTables.tenants;if(!tenantsTable)return ctx.set.status=503,{success:!1,message:"Tenants table not available in main schema"};let tenantId=crypto.randomUUID(),now=new Date;try{await db.insert(tenantsTable).values({id:tenantId,subdomain:body.subdomain,schemaName:tenantSchemaName,companyId:body.companyId,companyName:body.companyName||null,godAdminEmail:body.godAdminEmail,status:"provisioning",plan:body.plan||null,domain:body.domain||null,createdAt:now,updatedAt:now}),log4.info("Tenant record created",{tenantId,subdomain:body.subdomain,schemaName:tenantSchemaName})}catch(err){let msg=err instanceof Error?err.message:String(err);return log4.error("Failed to insert tenant record",{error:msg}),ctx.set.status=500,{success:!1,message:`Failed to create tenant record: ${msg}`}}try{let tenantRecord={id:tenantId,subdomain:body.subdomain,schemaName:tenantSchemaName,companyId:body.companyId,companyName:body.companyName||null,godAdminEmail:body.godAdminEmail,status:"provisioning",plan:body.plan||null,domain:body.domain||null,settings:{},trustedSources:[],maxUsers:null,provisionedAt:null,suspendedAt:null,suspendedReason:null},tenantContext=await tenantRegistry.provisionTenant(tenantRecord);log4.info("Schema provisioned",{tenantId,schemaName:tenantSchemaName,tableCount:Object.keys(tenantContext.schemaTables).length});let tenantUsersTable=tenantContext.schemaTables.users;if(tenantUsersTable){let godminId=crypto.randomUUID(),tempPassword=crypto.randomUUID().slice(0,16),hashedPassword=await hashPassword(tempPassword);await db.insert(tenantUsersTable).values({id:godminId,email:body.godAdminEmail,password:hashedPassword,isGod:!0,isActive:!0,createdAt:now,updatedAt:now}),log4.info("Godmin user seeded",{tenantId,godminEmail:body.godAdminEmail,godminId})}await db.update(tenantsTable).set({status:"active",provisionedAt:now,updatedAt:now}).where(eq34(col11(tenantsTable,"id"),tenantId));let tenantEventsTable=mainContext.schemaTables.tenantEvents;if(tenantEventsTable)try{await db.insert(tenantEventsTable).values({id:crypto.randomUUID(),tenantId,eventType:"provisioned",eventData:JSON.stringify({schemaName:tenantSchemaName,godAdminEmail:body.godAdminEmail,plan:body.plan||null}),performedBy:requestingUserId,ipAddress:ctx.request.headers.get("x-forwarded-for")?.split(",")[0]?.trim()||"unknown",createdAt:now,updatedAt:now})}catch{log4.warn("Failed to record tenant_event, continuing")}return await tenantRegistry.refreshTenant(tenantId),log4.info("Provisioning complete",{tenantId,subdomain:body.subdomain,schemaName:tenantSchemaName}),await config.logger.audit({entityName:"tenants",entityId:tenantId,operation:"PROVISION",userId:requestingUserId,summary:`Tenant "${body.subdomain}" provisioned by godmin`,ipAddress:ctx.request.headers.get("x-forwarded-for")?.split(",")[0]?.trim()||"unknown",userAgent:ctx.request.headers.get("user-agent")||"unknown",path:new URL(ctx.request.url).pathname,query:""}),{success:!0,message:"Tenant provisioned successfully",data:{tenantId,schemaName:tenantSchemaName,subdomain:body.subdomain,godAdminEmail:body.godAdminEmail,status:"active"}}}catch(err){let msg=err instanceof Error?err.message:String(err);log4.error("Provisioning failed",{error:msg,tenantId});try{await db.update(tenantsTable).set({status:"provisioning",updatedAt:now}).where(eq34(col11(tenantsTable,"id"),tenantId))}catch{}return ctx.set.status=500,{success:!1,message:`Provisioning failed: ${msg}`}}},{body:ProvisionBodySchema,detail:{tags:["Tenants"],summary:"Provision new tenant",description:"Create a new tenant with its own schema, tables, and godmin user. Requires godmin privileges."}}),provisionRoutes}init_Authorization();init_Logger2();init_utils6();import{eq as eq35}from"drizzle-orm";import{Elysia as Elysia22,t as t19}from"elysia";var col12=(table,name2)=>table[name2],ipRateMap=new Map,lastCleanup=Date.now();function cleanupRateMap(windowMs){let now=Date.now();if(now-lastCleanup<600000)return;lastCleanup=now;for(let[key2,entry]of ipRateMap.entries())if(now-entry.windowStart>windowMs)ipRateMap.delete(key2)}function isIpRateLimited(ip,maxPerWindow,windowMs){let now=Date.now(),entry=ipRateMap.get(ip);if(!entry||now-entry.windowStart>windowMs)return ipRateMap.set(ip,{count:1,windowStart:now}),!1;return entry.count++,entry.count>maxPerWindow}var SelfSignupBodySchema=t19.Object({email:t19.String({format:"email"}),password:t19.String({minLength:8}),subdomain:t19.String({minLength:2,maxLength:63,pattern:"^[a-z][a-z0-9-]*$"}),plan:t19.Optional(t19.String()),companyName:t19.Optional(t19.String())});function createSelfSignupRoute(config){let log4=config.logger.scoped(TENANT_SELF_SIGNUP),limits={...DEFAULT_SELF_SIGNUP_LIMITS,...config.selfSignupLimits},selfSignupRoutes=new Elysia22;return selfSignupRoutes.post("/tenants/self-signup",async(ctx)=>{cleanupRateMap(limits.ipWindowMs);let db=config.getDb(),tenantRegistry=config.getTenantRegistry();if(!db||!tenantRegistry)return ctx.set.status=503,{success:!1,message:"Tenant provisioning not available"};let ip=ctx.request.headers.get("x-forwarded-for")?.split(",")[0]?.trim()||ctx.request.headers.get("x-real-ip")?.trim()||"unknown";if(isIpRateLimited(ip,limits.maxSignupsPerIpPerWindow,limits.ipWindowMs))return log4.warn("Self-signup rate limited",{ip}),ctx.set.status=429,{success:!1,message:"Too many signup attempts. Please try again later."};let body=ctx.body,email=body.email.toLowerCase().trim(),subdomain=body.subdomain.toLowerCase().trim();if(RESERVED_SUBDOMAINS.includes(subdomain))return ctx.set.status=400,{success:!1,message:"This subdomain is reserved."};let mainContext=tenantRegistry.getMainContext(),usersTable=mainContext.schemaTables.users,tenantsTable=mainContext.schemaTables.tenants;if(!usersTable||!tenantsTable)return ctx.set.status=503,{success:!1,message:"Required tables not available."};if(tenantRegistry.getActiveTenants().find((t20)=>t20.subdomain===subdomain))return ctx.set.status=409,{success:!1,message:"This subdomain is already taken."};try{if((await db.select().from(tenantsTable).where(eq35(col12(tenantsTable,"subdomain"),subdomain)).limit(1)).length>0)return ctx.set.status=409,{success:!1,message:"This subdomain is already taken."}}catch{}try{if((await db.select().from(tenantsTable).where(eq35(col12(tenantsTable,"godAdminEmail"),email))).length>=limits.maxTenantsPerEmail)return ctx.set.status=409,{success:!1,message:`Tenant limit reached. Maximum ${limits.maxTenantsPerEmail} tenant(s) per account.`}}catch{}let userId,hashedPassword=await hashPassword(body.password),now=new Date,existingUsers=await db.select().from(usersTable).where(eq35(col12(usersTable,"email"),email)).limit(1);if(existingUsers.length>0)userId=existingUsers[0].id,log4.info("Self-signup: existing user resolved",{userId,email});else{userId=crypto.randomUUID();try{await db.insert(usersTable).values({id:userId,email,password:hashedPassword,isActive:!0,createdAt:now,updatedAt:now}),log4.info("Self-signup: user created",{userId,email})}catch(err){let msg=err instanceof Error?err.message:String(err);return log4.error("Self-signup: user creation failed",{error:msg}),ctx.set.status=500,{success:!1,message:"Failed to create account."}}}let tenantId=crypto.randomUUID(),tenantSchemaName=`tenant_${subdomain.replace(/-/g,"_")}`;try{await db.insert(tenantsTable).values({id:tenantId,subdomain,schemaName:tenantSchemaName,companyId:userId,companyName:body.companyName||subdomain,godAdminEmail:email,status:"provisioning",plan:body.plan||null,createdAt:now,updatedAt:now}),log4.info("Tenant record created",{tenantId,subdomain})}catch(err){let msg=err instanceof Error?err.message:String(err);return log4.error("Tenant record creation failed",{error:msg}),ctx.set.status=500,{success:!1,message:"Failed to create tenant."}}try{let tenantRecord={id:tenantId,subdomain,schemaName:tenantSchemaName,companyId:userId,companyName:body.companyName||subdomain,godAdminEmail:email,status:"provisioning",plan:body.plan||null,domain:null,settings:{},trustedSources:[],maxUsers:null,provisionedAt:null,suspendedAt:null,suspendedReason:null},tenantContext=await tenantRegistry.provisionTenant(tenantRecord);log4.info("Schema provisioned",{tenantId,schemaName:tenantSchemaName,tableCount:Object.keys(tenantContext.schemaTables).length});let tenantUsersTable=tenantContext.schemaTables.users;if(tenantUsersTable)await db.insert(tenantUsersTable).values({id:userId,email,password:hashedPassword,isGod:!0,isActive:!0,createdAt:now,updatedAt:now}),log4.info("Godmin seeded in tenant schema",{tenantId,email,userId});let tenantRolesTable=tenantContext.schemaTables.roles,tenantUserRolesTable=tenantContext.schemaTables.userRoles;if(tenantRolesTable&&tenantUserRolesTable)try{let godminRoles=await db.select().from(tenantRolesTable).where(eq35(tenantRolesTable.name,GODMIN_ROLE_NAME)).limit(1),godminRoleId;if(godminRoles.length>0)godminRoleId=godminRoles[0].id;else{let[newRole]=await db.insert(tenantRolesTable).values({name:GODMIN_ROLE_NAME,description:"God mode administrator - bypasses all authorization checks"}).returning();godminRoleId=newRole.id,log4.info("Created godmin role in tenant schema",{tenantId,roleId:godminRoleId})}if(godminRoleId)await db.insert(tenantUserRolesTable).values({userId,roleId:godminRoleId}),log4.info("Assigned godmin role to signup user",{tenantId,userId,roleId:godminRoleId})}catch(roleErr){log4.warn("Failed to assign godmin role to signup user",{tenantId,userId,error:roleErr instanceof Error?roleErr.message:String(roleErr)})}await db.update(tenantsTable).set({status:"active",provisionedAt:now,updatedAt:now}).where(eq35(col12(tenantsTable,"id"),tenantId));let tenantEventsTable=mainContext.schemaTables.tenantEvents;if(tenantEventsTable)try{await db.insert(tenantEventsTable).values({id:crypto.randomUUID(),tenantId,eventType:"self_signup",eventData:JSON.stringify({email,subdomain,plan:body.plan||null}),performedBy:userId,ipAddress:ip,createdAt:now,updatedAt:now})}catch{}return await tenantRegistry.refreshTenant(tenantId),log4.info("Self-signup complete",{tenantId,subdomain,email}),await config.logger.audit({entityName:"tenants",entityId:tenantId,operation:"SELF_SIGNUP",userId,summary:`Self-signup: tenant "${subdomain}" provisioned by ${email}`,ipAddress:ip,userAgent:ctx.request.headers.get("user-agent")||"unknown",path:new URL(ctx.request.url).pathname,query:""}),{success:!0,message:"Tenant created successfully",data:{tenantId,subdomain,schemaName:tenantSchemaName,userId,email,status:"active"}}}catch(err){let msg=err instanceof Error?err.message:String(err);log4.error("Self-signup provisioning failed",{error:msg,tenantId});try{await db.update(tenantsTable).set({status:"provisioning",updatedAt:now}).where(eq35(col12(tenantsTable,"id"),tenantId))}catch{}return ctx.set.status=500,{success:!1,message:"Provisioning failed. Please try again."}}},{body:SelfSignupBodySchema,detail:{tags:["Tenants"],summary:"Self-service tenant signup",description:"Public endpoint for self-service signup. Creates user account, provisions tenant schema, and seeds godmin. Rate-limited by IP with configurable max tenants per email."}}),selfSignupRoutes}function createTenantRoutes(app,config){return app.use(createCheckSubdomainRoute(config)),app.use(createProvisionRoute(config)),app.use(createSelfSignupRoute(config)),app.use(createManageRoutes(config)),app}init_Notification();init_Verification();init_adminGuard();import{Elysia as Elysia23,t as t20}from"elysia";function createVerificationRoutes(routeConfig){let{db,schemaTables,config,logger:logger2,tenantRegistry}=routeConfig,defaultVerificationService=new VerificationService({db,schemaTables,config,logger:logger2}),defaultNotificationService=new NotificationService({db,schemaTables,config:routeConfig.notificationConfig||{enabled:!1},logger:logger2,getEmailService:routeConfig.getEmailService}),wireNotificationHandler=(verSvc,notifSvc)=>{verSvc.setNotificationHandler(async(params)=>{if(!routeConfig.notificationConfig?.enabled)return;await notifSvc.triggerNotifications({trigger:params.trigger,flow_id:params.flow_id,entity_name:params.entity_name,entity_id:params.entity_id,node_id:params.node_id,verifier_id:params.verifier_id,decision:params.decision,context:params.context})})};wireNotificationHandler(defaultVerificationService,defaultNotificationService);let getServicesForRequest=(request)=>{if(!tenantRegistry)return{verificationService:defaultVerificationService,notificationService:defaultNotificationService};let schemaName=request.headers.get("x-tenant-schema");if(!schemaName)return{verificationService:defaultVerificationService,notificationService:defaultNotificationService};let ctx=tenantRegistry.getSchemaContext(schemaName);if(!ctx)return{verificationService:defaultVerificationService,notificationService:defaultNotificationService};let reqVerSvc=new VerificationService({db,schemaTables:ctx.schemaTables,config,logger:logger2}),reqNotifSvc=new NotificationService({db,schemaTables:ctx.schemaTables,config:routeConfig.notificationConfig||{enabled:!1},logger:logger2,getEmailService:routeConfig.getEmailService});return wireNotificationHandler(reqVerSvc,reqNotifSvc),{verificationService:reqVerSvc,notificationService:reqNotifSvc}},basePath=config.endpoints?.basePath||"/verifications",flowBasePath=config.flowEndpoints?.basePath||"/verification-flows",routes=new Elysia23,verificationRoutes=new Elysia23({prefix:basePath});if(verificationRoutes.onBeforeHandle(({request,set})=>{if(!request.headers.get("x-user-id"))return set.status=401,{success:!1,message:"Authentication required"}}),verificationRoutes.get("/status/:entity_name/:entity_id",async({params,request,set})=>{let{verificationService}=getServicesForRequest(request),status=await verificationService.getStatus(params.entity_name,params.entity_id),startedBy=status.instance?.started_by;if(!hasGodminRole(request)&&startedBy!=null&&String(startedBy)!==String(request.headers.get("x-user-id")))return set.status=403,{success:!1,message:"Forbidden"};return{success:!0,data:status}},{params:t20.Object({entity_name:t20.String(),entity_id:t20.String()})}),verificationRoutes.post("/:entity_name/:entity_id/decide",async({params,body,request})=>{let{verificationService}=getServicesForRequest(request),userId=request.headers.get("x-user-id");if(!userId)return{success:!1,message:"User ID required",status:401};return await verificationService.decide({entity_name:params.entity_name,entity_id:params.entity_id,user_id:userId,decision:body.decision,reason:body.reason,signature_id:body.signature_id,diff:body.diff})},{params:t20.Object({entity_name:t20.String(),entity_id:t20.String()}),body:t20.Object({decision:t20.Union([t20.Literal("approved"),t20.Literal("rejected")]),reason:t20.Optional(t20.String()),signature_id:t20.Optional(t20.String()),diff:t20.Optional(t20.Record(t20.String(),t20.Unknown()))})}),verificationRoutes.get("/pending",async({request})=>{let{verificationService}=getServicesForRequest(request),userId=request.headers.get("x-user-id");if(!userId)return{success:!1,message:"User ID required",status:401};return{success:!0,data:await verificationService.getPending(userId)}}),verificationRoutes.get("/history/:entity_name/:entity_id",async({params,request,set})=>{let{verificationService}=getServicesForRequest(request),status=await verificationService.getStatus(params.entity_name,params.entity_id),startedBy=status.instance?.started_by;if(!hasGodminRole(request)&&startedBy!=null&&String(startedBy)!==String(request.headers.get("x-user-id")))return set.status=403,{success:!1,message:"Forbidden"};return{success:!0,data:{verifications:status.verifications,current_step:status.current_step,total_steps:status.total_steps,is_completed:status.is_completed,is_rejected:status.is_rejected}}},{params:t20.Object({entity_name:t20.String(),entity_id:t20.String()})}),verificationRoutes.post("/start",async({body,request})=>{let{verificationService}=getServicesForRequest(request),userId=request.headers.get("x-user-id");return await verificationService.startFlow({flow_id:body.flow_id,entity_name:body.entity_name,entity_id:body.entity_id,started_by:userId||void 0})},{body:t20.Object({flow_id:t20.String(),entity_name:t20.String(),entity_id:t20.String()})}),verificationRoutes.post("/start-for-entity",async({body,request})=>{let{verificationService}=getServicesForRequest(request),userId=request.headers.get("x-user-id");return await verificationService.startFlowForEntity({entity_name:body.entity_name,entity_id:body.entity_id,started_by:userId||void 0})},{body:t20.Object({entity_name:t20.String(),entity_id:t20.String()})}),verificationRoutes.get("/statuses/:entity_name",async({params,query,request,set})=>{if(!hasGodminRole(request))return set.status=403,{success:!1,message:"Forbidden: operator privileges required"};let{verificationService}=getServicesForRequest(request);return{success:!0,data:await verificationService.listEntityStatuses({entity_name:params.entity_name,status:query.status||void 0,page:query.page?Number(query.page):void 0,limit:query.limit?Number(query.limit):void 0})}},{params:t20.Object({entity_name:t20.String()}),query:t20.Object({status:t20.Optional(t20.String()),page:t20.Optional(t20.String()),limit:t20.Optional(t20.String())})}),routes.use(verificationRoutes),logger2.info(`[Verification] Routes registered at ${basePath}`),config.flowEndpoints?.enabled!==!1){let flowRoutes=new Elysia23({prefix:flowBasePath});flowRoutes.onBeforeHandle(createGodminGuard({db,schemaTables,logger:logger2},"verification flow management")),flowRoutes.get("/",async({query,request})=>{let{verificationService:vs}=getServicesForRequest(request);return{success:!0,data:await vs.listFlows(query.entity_name||void 0)}},{query:t20.Object({entity_name:t20.Optional(t20.String())})}),flowRoutes.get("/:flow_id",async({params,request})=>{let{verificationService:vs}=getServicesForRequest(request),result=await vs.getFlow(params.flow_id);if(!result)return{success:!1,message:"Flow not found"};return{success:!0,data:result}},{params:t20.Object({flow_id:t20.String()})}),flowRoutes.post("/",async({body,request})=>{let{verificationService:vs}=getServicesForRequest(request);return await vs.saveFlow(body)},{body:t20.Object({flow_id:t20.String(),entity_name:t20.String(),name:t20.String(),description:t20.Optional(t20.String()),trigger_on:t20.Union([t20.Literal("create"),t20.Literal("update"),t20.Literal("delete"),t20.Literal("manual")]),trigger_fields:t20.Optional(t20.Array(t20.String())),is_draft:t20.Boolean(),viewport:t20.Optional(t20.Object({x:t20.Number(),y:t20.Number(),zoom:t20.Number()})),graph:t20.Object({steps:t20.Array(t20.Any()),edges:t20.Array(t20.Any()),verifier_configs:t20.Array(t20.Any()),notification_rules:t20.Array(t20.Any()),notification_recipients:t20.Array(t20.Any()),notification_channels:t20.Array(t20.Any())})})}),flowRoutes.post("/:flow_id/publish",async({params,request})=>{let{verificationService:vs}=getServicesForRequest(request);return await vs.publishFlow(params.flow_id)},{params:t20.Object({flow_id:t20.String()})}),flowRoutes.delete("/:flow_id",async({params,request})=>{let{verificationService:vs}=getServicesForRequest(request);return await vs.deleteFlow(params.flow_id)},{params:t20.Object({flow_id:t20.String()})}),routes.use(flowRoutes),logger2.info(`[Verification] Flow routes registered at ${flowBasePath}`)}return{routes,verificationService:defaultVerificationService,notificationService:defaultNotificationService}}function createNucleusRuntime(deps){return{sendEmail:async(payload)=>{let mailer=deps.getEmailService();if(!mailer?.isAvailable())return{success:!1,error:"No email provider is configured or available"};return mailer.sendEmail(payload)},emailProvider:()=>deps.activeEmailProvider(),isEmailAvailable:()=>!!deps.getEmailService()?.isAvailable()}}import{Elysia as Elysia24}from"elysia";var a=`/* basic theme */
|
|
533
533
|
:root {
|
|
534
534
|
--scalar-text-decoration: underline;
|
|
535
535
|
--scalar-text-decoration-hover: underline;
|
|
@@ -1972,7 +1972,7 @@ data: ${payload}
|
|
|
1972
1972
|
</body>
|
|
1973
1973
|
</html>`;var Kind=Symbol.for("TypeBox.Kind"),toOpenAPIPath=(path7)=>path7.split("/").map((x)=>{if(x.startsWith(":")){if(x=x.slice(1,x.length),x.endsWith("?"))x=x.slice(0,-1);x=`{${x}}`}return x}).join("/"),mapProperties=(name2,schema,models)=>{if(schema===void 0)return[];if(typeof schema==="string")if(schema in models)schema=models[schema];else throw Error(`Can't find model ${schema}`);return Object.entries(schema?.properties??[]).map(([key2,value])=>{let{type:valueType=void 0,description,examples,...schemaKeywords}=value;return{description,examples,schema:{type:valueType,...schemaKeywords},in:name2,name:key2,required:schema.required?.includes(key2)??!1}})},mapTypesResponse=(types18,schema)=>{if(typeof schema==="object"&&["void","undefined","null"].includes(schema.type))return;let responses={};for(let type of types18)responses[type]={schema:typeof schema==="string"?{$ref:`#/components/schemas/${schema}`}:("$ref"in schema)&&(Kind in schema)&&schema[Kind]==="Ref"?{...schema,$ref:`#/components/schemas/${schema.$ref}`}:replaceSchemaType({...schema},{from:t21.Ref(""),to:({$ref,...options})=>{if(!$ref.startsWith("#/components/schemas/"))return t21.Ref(`#/components/schemas/${$ref}`,options);return t21.Ref($ref,options)}})};return responses},capitalize=(word)=>word.charAt(0).toUpperCase()+word.slice(1),generateOperationId=(method,paths)=>{let operationId=method.toLowerCase();if(paths==="/")return operationId+"Index";for(let path7 of paths.split("/"))if(path7.charCodeAt(0)===123)operationId+="By"+capitalize(path7.slice(1,-1));else operationId+=capitalize(path7);return operationId},cloneHook=(hook)=>{if(!hook)return;if(typeof hook==="string")return hook;if(Array.isArray(hook))return[...hook];return{...hook}},registerSchemaPath=({schema,path:path7,method,hook,models})=>{if(hook=cloneHook(hook),hook.parse&&!Array.isArray(hook.parse))hook.parse=[hook.parse];let contentType=hook.parse?.map((x)=>{switch(typeof x){case"string":return x;case"object":if(x&&typeof x?.fn!=="string")return;switch(x?.fn){case"json":case"application/json":return"application/json";case"text":case"text/plain":return"text/plain";case"urlencoded":case"application/x-www-form-urlencoded":return"application/x-www-form-urlencoded";case"arrayBuffer":case"application/octet-stream":return"application/octet-stream";case"formdata":case"multipart/form-data":return"multipart/form-data"}}}).filter((x)=>x!==void 0);if(!contentType||contentType.length===0)contentType=["application/json","multipart/form-data","text/plain"];path7=toOpenAPIPath(path7);let contentTypes=typeof contentType==="string"?[contentType]:contentType??["application/json"],bodySchema=cloneHook(hook?.body),paramsSchema=cloneHook(hook?.params),headerSchema=cloneHook(hook?.headers),querySchema=cloneHook(hook?.query),responseSchema=cloneHook(hook?.response);if(typeof responseSchema==="object")if(Kind in responseSchema){let{type,properties,required,additionalProperties,patternProperties,$ref,...rest}=responseSchema;responseSchema={"200":{...rest,description:rest.description,content:mapTypesResponse(contentTypes,type==="object"||type==="array"?{type,properties,patternProperties,items:responseSchema.items,required}:responseSchema)}}}else Object.entries(responseSchema).forEach(([key2,value])=>{if(typeof value==="string"){if(!models[value])return;let{type,properties,required,additionalProperties:_1,patternProperties:_2,...rest}=models[value];responseSchema[key2]={...rest,description:rest.description,content:mapTypesResponse(contentTypes,value)}}else{let{type,properties,required,additionalProperties,patternProperties,...rest}=value;responseSchema[key2]={...rest,description:rest.description,content:mapTypesResponse(contentTypes,type==="object"||type==="array"?{type,properties,patternProperties,items:value.items,required}:value)}}});else if(typeof responseSchema==="string"){if(!(responseSchema in models))return;let{type,properties,required,$ref,additionalProperties:_1,patternProperties:_2,...rest}=models[responseSchema];responseSchema={"200":{...rest,content:mapTypesResponse(contentTypes,responseSchema)}}}let parameters2=[...mapProperties("header",headerSchema,models),...mapProperties("path",paramsSchema,models),...mapProperties("query",querySchema,models)];schema[path7]={...schema[path7]?schema[path7]:{},[method.toLowerCase()]:{...headerSchema||paramsSchema||querySchema||bodySchema?{parameters:parameters2}:{},...responseSchema?{responses:responseSchema}:{},operationId:hook?.detail?.operationId??generateOperationId(method,path7),...hook?.detail,...bodySchema?{requestBody:{required:!0,content:mapTypesResponse(contentTypes,typeof bodySchema==="string"?{$ref:`#/components/schemas/${bodySchema}`}:bodySchema)}}:null}}},filterPaths=(paths,{excludeStaticFile=!0,exclude=[]})=>{let newPaths={};for(let[key2,value]of Object.entries(paths))if(!exclude.some((x)=>{if(typeof x==="string")return key2===x;return x.test(key2)})&&!key2.includes("*")&&(excludeStaticFile?!key2.includes("."):!0))Object.keys(value).forEach((method)=>{let schema=value[method];if(key2.includes("{")){if(!schema.parameters)schema.parameters=[];schema.parameters=[...key2.split("/").filter((x)=>x.startsWith("{")&&!schema.parameters.find((params)=>params.in==="path"&¶ms.name===x.slice(1,x.length-1))).map((x)=>({schema:{type:"string"},in:"path",name:x.slice(1,x.length-1),required:!0})),...schema.parameters]}if(!schema.responses)schema.responses={200:{}}}),newPaths[key2]=value;return newPaths},swagger=({provider="scalar",scalarVersion="latest",scalarCDN="",scalarConfig={},documentation={},version="5.9.0",excludeStaticFile=!0,path:path7="/swagger",specPath=`${path7}/json`,exclude=[],swaggerOptions={},theme=`https://unpkg.com/swagger-ui-dist@${version}/swagger-ui.css`,autoDarkMode=!0,excludeMethods=["OPTIONS"],excludeTags=[]}={})=>{let schema={},totalRoutes=0;if(!version)version=`https://unpkg.com/swagger-ui-dist@${version}/swagger-ui.css`;let info={title:"Elysia Documentation",description:"Development documentation",version:"0.0.0",...documentation.info},relativePath=specPath.startsWith("/")?specPath.slice(1):specPath,app=new Elysia24({name:"@elysiajs/swagger"}),page=new Response(provider==="swagger-ui"?SwaggerUIRender(info,version,theme,JSON.stringify({url:relativePath,dom_id:"#swagger-ui",...swaggerOptions},(_,value)=>typeof value==="function"?void 0:value),autoDarkMode):ScalarRender(info,scalarVersion,{spec:{url:relativePath,...scalarConfig.spec},...scalarConfig,_integration:"elysiajs"},scalarCDN),{headers:{"content-type":"text/html; charset=utf8"}});return app.get(path7,page,{detail:{hide:!0}}).get(specPath,function(){let routes=app.getGlobalRoutes();if(routes.length!==totalRoutes){let ALLOWED_METHODS=["GET","PUT","POST","DELETE","OPTIONS","HEAD","PATCH","TRACE"];totalRoutes=routes.length,routes.forEach((route)=>{if(route.hooks?.detail?.hide===!0)return;if(excludeMethods.includes(route.method))return;if(ALLOWED_METHODS.includes(route.method)===!1&&route.method!=="ALL")return;if(route.method==="ALL")ALLOWED_METHODS.forEach((method)=>{registerSchemaPath({schema,hook:route.hooks,method,path:route.path,models:app.getGlobalDefinitions?.().type,contentType:route.hooks.type})});else registerSchemaPath({schema,hook:route.hooks,method:route.method,path:route.path,models:app.getGlobalDefinitions?.().type,contentType:route.hooks.type})})}return{openapi:"3.0.3",...{...documentation,tags:documentation.tags?.filter((tag)=>!excludeTags?.includes(tag?.name)),info:{title:"Elysia Documentation",description:"Development documentation",version:"0.0.0",...documentation.info}},paths:{...filterPaths(schema,{excludeStaticFile,exclude:Array.isArray(exclude)?exclude:[exclude]}),...documentation.paths},components:{...documentation.components,schemas:{...app.getGlobalDefinitions?.().type,...documentation.components?.schemas}}}},{detail:{hide:!0}}),app};function createSwaggerPlugin(config){if(config?.enabled===!1)return null;let swaggerConfig={path:config?.path??"/swagger",provider:config?.provider??"scalar",excludeStaticFile:config?.excludeStaticFile??!0,exclude:config?.exclude??[],documentation:{info:{title:config?.documentation?.info?.title??"Nucleus API",description:config?.documentation?.info?.description??"Auto-generated API documentation",version:config?.documentation?.info?.version??"1.0.0",contact:config?.documentation?.info?.contact,license:config?.documentation?.info?.license},tags:config?.documentation?.tags??[],servers:config?.documentation?.servers},scalarConfig:config?.scalarConfig};return swagger(swaggerConfig)}init_utils5();function asText(value){return typeof value==="string"&&value.trim()?value.trim():void 0}function fieldOf(path7){let text2=asText(path7);if(!text2)return;return text2.replace(/^\//,"").replace(/\//g,".")||void 0}function fromValidator(error){let candidate=error;if(typeof candidate?.validator?.Errors!=="function")return;try{let fields=[],reason;for(let item of candidate.validator.Errors(candidate.value)){let field=fieldOf(item?.path);if(field&&!fields.includes(field))fields.push(field);if(reason??=asText(item?.message),fields.length>=4)break}return fields.length||reason?{fields,reason}:void 0}catch{return}}function compose(where,reason){if(where&&reason)return`Invalid request: ${where} \u2014 ${reason}`;if(where)return`Invalid request: ${where}`;if(reason)return`Invalid request: ${reason}`;return"Invalid request"}function fromMessage(raw){let text2=asText(raw);if(!text2)return"Invalid request";let payload;try{payload=JSON.parse(text2)}catch{return}if(!payload||typeof payload!=="object"||payload.type!=="validation")return;let on=asText(payload.on),property=fieldOf(payload.property),reason=asText(payload.summary)??asText(payload.message),where=property&&property!=="root"?`${on?`${on}.`:""}${property}`:on?`the request ${on}`:void 0;return compose(where,reason)}function describeValidationError(error){if(typeof error!=="string"&&error){let detail=fromValidator(error);if(detail){let on=asText(error.type),where=detail.fields.length?detail.fields.map((field)=>on?`${on}.${field}`:field).join(", "):on?`the request ${on}`:void 0;return compose(where,detail.reason)}return fromMessage(error.message)}return fromMessage(error)}function statusOfError(code,error){if(typeof code==="number")return code;let carried=error?.status;if(typeof carried==="number"&&carried>=100&&carried<=599)return carried;return 500}init_auth();init_backup();init_payment();init_marketplace();init_storage2();var mergeEntitiesByName=(entities)=>{let entityMap=new Map;for(let entity of entities){let existing=entityMap.get(entity.table_name),mergedColumns=entity.columns??existing?.columns;entityMap.set(entity.table_name,{...existing||{},...entity,columns:mergedColumns})}return Array.from(entityMap.values())},effectiveConfigEntities=(configEntities)=>{if(!configEntities.some((e)=>e.extends))return configEntities;let{entities:resolved}=resolveEntities(SYSTEM_TABLES,configEntities),byName=new Map(resolved.map((t40)=>[t40.table_name,t40]));return configEntities.map((e)=>e.extends?byName.get(e.table_name)??e:e)},normalizeSystemTable=(table)=>({table_name:table.table_name,excluded_methods:table.excluded_methods?[...table.excluded_methods]:void 0,columns:table.columns?table.columns.map((column)=>({name:column.name,type:column.type})):void 0}),extractSchemaTableEntities=(schemaTables)=>{let entities=[];for(let[_key,tableValue]of Object.entries(schemaTables)){if(!tableValue||typeof tableValue!=="object")continue;let tableObj=tableValue,underscoreMeta=tableObj._;if(underscoreMeta?.name){entities.push({table_name:underscoreMeta.name});continue}let symbols3=Object.getOwnPropertySymbols(tableObj);for(let sym of symbols3){let symValue=tableObj[sym];if(symValue&&typeof symValue==="object"){let symMeta=symValue;if(symMeta.name&&typeof symMeta.name==="string"){entities.push({table_name:symMeta.name});break}}}}return entities};async function NucleusElysiaPlugin(config){let plugin=new Elysia49;if(plugin.get("/health",()=>({status:"ok",timestamp:Date.now()})),config.staticAssets!==!1){let path7=__require("path"),fs4=__require("fs"),assetsPath;if(typeof config.staticAssets==="string")assetsPath=config.staticAssets;else{let localPath=path7.join(process.cwd(),"public"),resolvedPkgPath="";for(let pkgName of["nucleus-core-ts","nucleus-core"])try{let pkgJson=__require.resolve(`${pkgName}/package.json`),candidate=path7.join(path7.dirname(pkgJson),"public");if(fs4.existsSync(candidate)){resolvedPkgPath=candidate;break}}catch{}if(resolvedPkgPath)assetsPath=resolvedPkgPath;else if(fs4.existsSync(localPath))assetsPath=localPath;else assetsPath=localPath}try{plugin.use(await staticPlugin({prefix:"/nucleus-core",assets:assetsPath}))}catch{}}let publicRoutes=[],resolvedOptions,configDir=process.cwd(),configFilePath=null;if(typeof config.options==="string"){let fs4=__require("fs"),path7=__require("path"),configPath=path7.isAbsolute(config.options)?config.options:path7.resolve(process.cwd(),config.options);configDir=path7.dirname(configPath),configFilePath=configPath;let configContent=fs4.readFileSync(configPath,"utf-8");resolvedOptions=JSON.parse(configContent)}else resolvedOptions=config.options;if(resolvedOptions.email?.gmail?.json_file_path){let path7=__require("path"),gmailPath=resolvedOptions.email.gmail.json_file_path;if(!path7.isAbsolute(gmailPath))resolvedOptions.email.gmail.json_file_path=path7.resolve(configDir,gmailPath)}let{authentication,audit,entities,database}=resolvedOptions,isDev=resolvedOptions.mode==="development",loggingConfig=resolvedOptions.logging,logger2=new Logger({service:resolvedOptions.appId||"nucleus",level:loggingConfig?.level||(isDev?"debug":"info"),prettyPrint:loggingConfig?.prettyPrint??isDev,colorize:loggingConfig?.colorize??isDev,includeCallerInfo:loggingConfig?.includeCallerInfo??isDev,redactKeys:loggingConfig?.redactKeys||[],auditEnabled:audit?.enabled??!1,...audit?.suppressReasons!==void 0?{auditSuppressReasons:audit.suppressReasons}:{},...audit?.minSeverity!==void 0?{auditMinSeverity:audit.minSeverity}:{},enabledScopes:loggingConfig?.scopes||["*"]});Logger.getInstance().configure({service:resolvedOptions.appId||"nucleus",level:loggingConfig?.level||(isDev?"debug":"info"),prettyPrint:loggingConfig?.prettyPrint??isDev,colorize:loggingConfig?.colorize??isDev,includeCallerInfo:loggingConfig?.includeCallerInfo??isDev,redactKeys:loggingConfig?.redactKeys||[],enabledScopes:loggingConfig?.scopes||["*"]});{let{entities:resolvedForBoot,errors:extendErrors,warnings:extendWarnings}=resolveEntities(SYSTEM_TABLES,entities??[],{consumerMode:authentication?.mode==="consumer"});for(let warning of extendWarnings)logger2.warn(warning);let syncErrors=[],syncMappings=resolvedOptions.authentication?.oauth?.profileSync?.mappings??[];if(syncMappings.length>0){let columnsFor=(name2)=>{return(resolvedForBoot.find((t40)=>t40.table_name===name2)?.columns??[]).map((c)=>c.name)};syncErrors.push(...validateProfileSyncTargets(syncMappings,{users:columnsFor("users"),profiles:columnsFor("profiles")}))}if(extendErrors.length>0||syncErrors.length>0){let detail=[...extendErrors.map((e)=>` ${e.code}: ${e.message}`),...syncErrors.map((m2)=>` PROFILE_SYNC_TARGET: ${m2}`)].join(`
|
|
1974
1974
|
`);throw Error(`Invalid Nucleus config:
|
|
1975
|
-
${detail}`)}let sensitiveNames=resolvedForBoot.flatMap((e)=>e.columns??[]).filter((c)=>c.sensitive===!0).map((c)=>c.name);{registerSensitiveColumns(sensitiveNames);let redactUnion=[...loggingConfig?.redactKeys||[],...sensitiveColumnNames()];if(logger2.configure({redactKeys:redactUnion}),Logger.getInstance().configure({redactKeys:redactUnion}),sensitiveNames.length>0)logger2.info("[Schema] Sensitive columns registered",{columns:sensitiveNames})}}let requestLogConfig={enabled:loggingConfig?.requests?.enabled!==!1,logArrival:loggingConfig?.requests?.logArrival===!0,includeQuery:loggingConfig?.requests?.includeQuery!==!1,slowThresholdMs:loggingConfig?.requests?.slowThresholdMs??3000,excludePaths:loggingConfig?.requests?.excludePaths??["/health"]},isRequestLogExcluded=(pathname)=>requestLogConfig.excludePaths.some((p)=>p.endsWith("*")?pathname.startsWith(p.slice(0,-1)):pathname===p),envValidation=validateEnvVariables(resolvedOptions);if(!envValidation.valid){for(let error3 of envValidation.errors)logger2.error(`[CONFIG] ${error3.message}`,{field:error3.field,envName:error3.envName});throw Error("Nucleus configuration error: Missing required environment variables. Check logs for details.")}let{resolved:envResolved}=envValidation;{let secretEntries=[["accessToken",envResolved.accessTokenSecret],["refreshToken",envResolved.refreshTokenSecret],["sessionToken",envResolved.sessionTokenSecret]];for(let[name2,value2]of secretEntries)if(value2&&value2.length<32)logger2.warn(`[Security] authentication.${name2}.secret is only ${value2.length} chars \u2014 use at least ${"32"} random bytes.`);let present=secretEntries.map(([,v])=>v).filter((v)=>!!v);if(present.length>1&&new Set(present).size<present.length)logger2.warn("[Security] Two or more of the access/refresh/session token secrets are identical \u2014 use a distinct secret for each.")}let tokenNames={access_token:authentication?.accessToken?.name||"access_token",refresh_token:authentication?.refreshToken?.name||"refresh_token",session_token:authentication?.sessionToken?.name||"session_token"},csrfConfig=resolveCsrfConfig(authentication?.csrf),csrfAuthCookieNames=[tokenNames.session_token,tokenNames.access_token],targetSchemaName=database?.sharedSchema||database?.schemas?.[0]||"main",targetSchema=pgSchema2(targetSchemaName);if(envResolved.databaseUrl)await ensureDatabaseExists(envResolved.databaseUrl,logger2,envResolved.databaseAuthMode);let db=null,dbPool=null,dbAuthMode=envResolved.databaseAuthMode||"password",backgroundIntervals=[],trackInterval=(timer)=>{timer.unref?.(),backgroundIntervals.push(timer)};if(envResolved.databaseUrl){let{Pool:Pool2}=await import("pg"),poolOptions=resolveDbPoolConfig(database?.pool);if(dbAuthMode==="password")dbPool=new Pool2({connectionString:envResolved.databaseUrl,...poolOptions});else{let{getPostgresToken:getPostgresToken2}=await Promise.resolve().then(() => (init_Azure(),exports_Azure));await getPostgresToken2(),dbPool=new Pool2({connectionString:envResolved.databaseUrl,password:getPostgresToken2,ssl:{rejectUnauthorized:!0},...poolOptions}),logger2.info(`[Database] Using Entra ID auth mode: ${dbAuthMode}`)}db=drizzle2(dbPool),dbPool.on("error",(err)=>{logger2.warn("[Database] idle pool client error",{error:err instanceof Error?err.message:String(err)})})}let isMultiTenant=database?.isMultiTenant===!0,tenantRegistry=null,schemaTables={},schemaRelations={},claimsCache=null;if(config.schema){let schemasPath=__require("path").resolve(process.cwd(),config.schema),schemas=__require(schemasPath);schemaTables=schemas.createAllTablesForSchema?schemas.createAllTablesForSchema(targetSchema):{}}if(config.relations){let relationsPath=__require("path").resolve(process.cwd(),config.relations);schemaRelations=__require(relationsPath)}let secretsService=null;if(resolvedOptions.secrets?.enabled){let masterKey=resolveMasterKey(resolvedOptions.secrets.encryptionKey);if(!db)logger2.warn("[Secrets] secrets.enabled=true but no database is configured \u2014 disabled");else if(!masterKey)logger2.error("[Secrets] secrets.enabled=true but no encryption key resolved \u2014 set secrets.encryptionKey or NUCLEUS_SECRETS_KEY. Credential storage is disabled; env and literal values still work.");else if(!schemaTables[SECRETS_TABLE])logger2.error(`[Secrets] secrets.enabled=true but the "${SECRETS_TABLE}" table is missing from the generated schema \u2014 re-run schema generation. Credential storage is disabled.`);else{secretsService=new SecretsService({store:new SecretsStore({db,resolveTable:(tableName)=>schemaTables[tableName],masterKey}),logger:logger2,refreshIntervalMs:resolvedOptions.secrets.refreshIntervalMs,getRedis:()=>getRedisManager()}),logger2.info("[Secrets] Credential store enabled");try{if(await secretsService.refresh(),secretsService.isReady())logger2.info("[Secrets] Credentials preloaded for boot-time resolution",{storedCredentials:secretsService.size()})}catch(error3){logger2.warn("[Secrets] Preload failed \u2014 env and literal values still resolve",{error:error3 instanceof Error?error3.message:String(error3)})}}}let resolveCredential=(scope,key2,configValue)=>{if(secretsService)return secretsService.value(scope,key2,configValue);if(!configValue)return;let fromEnv=process.env[configValue];if(fromEnv)return fromEnv;return/^[A-Z][A-Z0-9_]{2,}$/.test(configValue)?void 0:configValue},resolveRedirectUrl=(value2)=>{if(!value2)return;let fromEnv=process.env[value2];if(fromEnv)return fromEnv;return/^[A-Z][A-Z0-9_]{2,}$/.test(value2)?void 0:value2},withResolvedRedirects=(node,keys)=>{if(!node)return node;let resolved={...node};for(let key2 of keys)if(typeof node[key2]==="string")resolved[key2]=resolveRedirectUrl(node[key2]);return resolved},trustedAppOrigins=()=>{let configured=normalizeTrustedOrigins(resolvedOptions.authentication?.trustedAppOrigins);if(!secretsService)return configured;let resolved=secretsService.listValue("authentication","trustedAppOrigins",configured);return resolved.length>0?resolved:configured},liveOAuthProviders=(resolvedProviders)=>{if(!secretsService)return resolvedProviders;let declared=resolvedOptions.authentication?.oauth?.providers??{},live={};for(let[providerName,providerConfig]of Object.entries(resolvedProviders)){let declaredConfig=declared[providerName]??{},entry={...providerConfig};for(let key2 of["clientId","clientSecret","tenantId","redirectUri"]){let declaredValue=declaredConfig[key2],bootValue=providerConfig[key2];Object.defineProperty(entry,key2,{get:()=>{let resolved=secretsService?.value(`authentication.oauth.providers.${providerName}`,key2,typeof declaredValue==="string"?declaredValue:void 0);if(resolved!==void 0)return resolved;return looksLikeEnvName(typeof bootValue==="string"?bootValue:void 0)?void 0:bootValue},enumerable:!0,configurable:!0})}live[providerName]=entry}return live},storageProvider=null;if(resolvedOptions.storage?.enabled){let storageBase=resolvedOptions.storage.basePath||"./uploads";storageProvider=createStorageProvider({provider:resolvedOptions.storage.provider,basePath:storageBase,smb:resolvedOptions.storage.smb,resolveCredential},{logger:logger2}),setStorageProvider(storageProvider)}let buildStorageProvider=(kind)=>{if(!resolvedOptions.storage?.enabled)return null;return createStorageProvider({provider:kind,basePath:resolvedOptions.storage.basePath||"./uploads",smb:resolvedOptions.storage.smb,resolveCredential:(scope,key2,configValue)=>scope==="storage"&&key2==="provider"?kind:resolveCredential(scope,key2,configValue)},{logger:logger2})},swaggerPlugin=createSwaggerPlugin(config.swagger);if(swaggerPlugin)plugin.use(swaggerPlugin);let systemTables2=config.systemTables||[];publicRoutes=buildPublicRoutes(resolvedOptions,systemTables2,"",targetSchemaName),logger2.info(`[AUTH] Built ${publicRoutes.length} public routes`);let rateLimiter=null,monitoringService=null,liveMonitoringService=null,activeEmailProvider=()=>{let declared=resolveCredential("email","provider",resolvedOptions.email?.provider);if(declared==="azure"||declared==="gmail")return emailProviderOn(declared)||resolvedOptions.email?.provider===declared?declared:null;if(emailProviderOn("azure"))return"azure";if(emailProviderOn("gmail"))return"gmail";return null},emailProviderOn=(provider)=>{let configured=resolvedOptions.email?.[provider]?.enabled===!0;return secretsService?secretsService.flag(`email.${provider}`,"enabled",configured):configured},azureEmailCredentials=()=>{let azureConfig=resolvedOptions.email?.azure;return{enabled:!0,connectionString:resolveCredential("email.azure","connection_string",azureConfig?.connection_string)??"",senderAddress:resolveCredential("email.azure","sender_address",azureConfig?.sender_address)??"",fromName:azureConfig?.from_name}},gmailCredentials=()=>{let gmailConfig=resolvedOptions.email?.gmail;return{enabled:!0,jsonFilePath:gmailConfig?.json_file_path,serviceAccountJson:resolveCredential("email.gmail","service_account_json",gmailConfig?.service_account_json),fromEmail:resolveCredential("email.gmail","from_email",gmailConfig?.from_email)??"",fromName:gmailConfig?.from_name}},azureService=null,gmailService=null,getEmailService=()=>{let provider=activeEmailProvider();if(!provider)return null;if(provider==="azure"){if(!azureService)azureService=new AzureEmailService(azureEmailCredentials(),logger2),logger2.info("[AzureEmailService] Initialized",{available:azureService.isAvailable()});else azureService.reconfigure(azureEmailCredentials());return azureService}if(!gmailService)gmailService=new GmailService(gmailCredentials(),logger2),logger2.info("[GmailService] Initialized",{available:gmailService.isAvailable()});else gmailService.reconfigure(gmailCredentials());return gmailService};if(plugin.decorate("nucleus",createNucleusRuntime({getEmailService,activeEmailProvider})),resolvedOptions.liveMonitoring?.enabled){let liveBasePath=resolvedOptions.liveMonitoring.basePath||"/monitoring",liveStreamInterval=resolvedOptions.liveMonitoring.streamInterval||150;plugin.use(createLiveMonitoringRoutes({getService:()=>liveMonitoringService,logger:logger2,basePath:liveBasePath,streamInterval:liveStreamInterval,db,schemaTables}))}let bootStep=async(name2,run)=>{try{return await run()}catch(error3){logger2.error(`[Boot] Step "${name2}" failed \u2014 continuing in a degraded state rather than crashing`,{error:error3 instanceof Error?error3.message:String(error3)});return}};plugin.onStart(async()=>{await bootStep("redis",()=>initiateRedisManager(resolvedOptions));let redis=getRedisManager();if(redis&&resolvedOptions.configManagement?.enabled)try{let{loadOverridesFromRedis:loadOverridesFromRedis2}=await Promise.resolve().then(() => (init_helpers3(),exports_helpers)),applied=await loadOverridesFromRedis2({read:async(key2)=>{let r2=await redis.read(key2);return{success:r2.success,data:r2.success?r2.data:null}}},resolvedOptions.appId||"nucleus",resolvedOptions);if(applied.length>0)logger2.info(`[ConfigManagement] Loaded ${applied.length} override(s) from Redis`,{sections:applied})}catch(err){logger2.warn("[ConfigManagement] Failed to load overrides from Redis",{error:err instanceof Error?err.message:String(err)})}if(redis&&resolvedOptions.rateLimit?.enabled!==!1)rateLimiter=new RateLimiter({redis,logger:logger2,config:resolvedOptions.rateLimit||{}}),logger2.info(`[RateLimit] Enabled with strategy: ${resolvedOptions.rateLimit?.strategy||"sliding-window"}`);{let channels=resolvedOptions.notification?.channels;if(channels?.telegram?.enabled&&(!channels.telegram.botToken||!channels.telegram.chatId))logger2.warn("[Notification] telegram channel is enabled but botToken/chatId is missing \u2014 telegram deliveries will be skipped");if(channels?.webhook?.enabled&&!channels.webhook.url)logger2.warn("[Notification] webhook channel is enabled but url is missing \u2014 webhook deliveries will be skipped")}if(redis&&resolvedOptions.monitoring?.enabled){let monitoringDb=db,monitoringMetricsTable=schemaTables.monitoringMetrics,monitoringPersistenceEnabled=resolvedOptions.monitoring.persistence?.enabled!==!1,monitoringRetentionDays=resolvedOptions.monitoring.persistence?.retentionDays??30,lastMetricsCleanupAt=0,monitoringDbQuery=monitoringDb?async(sqlText)=>{return(await monitoringDb.execute(sql12.raw(sqlText))).rows}:void 0;if(monitoringPersistenceEnabled&&monitoringDb&&!monitoringMetricsTable)logger2.warn("[Monitoring] monitoring.persistence is enabled but the monitoring_metrics table is missing from the generated schema \u2014 re-run nucleus-generate to add it");let monitoringFlushToDb=monitoringDb&&monitoringPersistenceEnabled&&monitoringMetricsTable?async(metrics)=>{if(metrics.length===0)return;let metricsTable=monitoringMetricsTable;await monitoringDb.insert(metricsTable).values(metrics.map((m2)=>({metricType:m2.metricType,metricName:m2.metricName,value:m2.value,tags:m2.tags??null,recordedAt:new Date(m2.timestamp)})));let nowMs=Date.now();if(nowMs-lastMetricsCleanupAt>86400000){lastMetricsCleanupAt=nowMs;let cutoff=new Date(nowMs-monitoringRetentionDays*24*60*60*1000);await monitoringDb.delete(metricsTable).where(lt3(metricsTable.recordedAt,cutoff))}}:void 0;if(monitoringService=new MonitoringService({redis,logger:logger2,getEmailService,config:resolvedOptions.monitoring,appId:resolvedOptions.appId,dbQuery:monitoringDbQuery,flushToDb:monitoringFlushToDb}),monitoringService.start(),logger2.info("[Monitoring] Service started"),resolvedOptions.monitoring.endpoints?.enabled){let monitoringEndpoints={enabled:!0,basePath:resolvedOptions.monitoring.endpoints.basePath||"/monitoring",stream:{enabled:resolvedOptions.monitoring.endpoints.stream?.enabled!==!1,path:resolvedOptions.monitoring.endpoints.stream?.path||"/stream",interval:resolvedOptions.monitoring.endpoints.stream?.interval||"5s"},snapshot:{enabled:resolvedOptions.monitoring.endpoints.snapshot?.enabled!==!1,path:resolvedOptions.monitoring.endpoints.snapshot?.path||"/snapshot"},history:{enabled:resolvedOptions.monitoring.endpoints.history?.enabled!==!1,path:resolvedOptions.monitoring.endpoints.history?.path||"/history",maxMinutes:resolvedOptions.monitoring.endpoints.history?.maxMinutes||60},alerts:{enabled:resolvedOptions.monitoring.endpoints.alerts?.enabled!==!1,path:resolvedOptions.monitoring.endpoints.alerts?.path||"/alerts"}};plugin.use(createMonitoringRoutes({monitoringService,logger:logger2,endpoints:monitoringEndpoints,db,schemaTables}))}}if(resolvedOptions.liveMonitoring?.enabled)liveMonitoringService=new LiveMonitoringService(resolvedOptions.liveMonitoring),liveMonitoringService.start(),logger2.info("[LiveMonitoring] Service started");let isConsumerModeOnStart=authentication?.mode==="consumer",consumerAllowedTableKeys=isConsumerModeOnStart&&entities?new Set(entities.map((e)=>e.table_name.replace(/_([a-z])/g,(_,c)=>c.toUpperCase()))):null;if(consumerAllowedTableKeys){let opts=resolvedOptions,verificationEnabled=opts.verification?.enabled===!0,notificationEnabled=opts.notification?.enabled===!0,auditEnabled=opts.audit?.enabled===!0,chatEnabled=opts.chat?.enabled===!0,storageEnabled=opts.storage?.enabled===!0,paymentEnabled=opts.payment?.enabled===!0,backupEnabled=opts.backup?.enabled===!0,monitoringPersistenceOn=resolvedOptions.monitoring?.enabled===!0&&resolvedOptions.monitoring?.persistence?.enabled!==!1,featureEnabled={verification:verificationEnabled,notification:notificationEnabled,audit:auditEnabled,chat:chatEnabled,storage:storageEnabled,payment:paymentEnabled,backup:backupEnabled,monitoring:monitoringPersistenceOn,secrets:resolvedOptions.secrets?.enabled===!0,domains:resolvedOptions.domains?.enabled===!0,"multi-tenant":isMultiTenant};for(let sysTable of SYSTEM_TABLES)if(sysTable.feature_set.some((f)=>{if(f==="authentication"||f==="authorization")return!1;if(!(f in featureEnabled))return logger2.warn(`[Schema] Consumer mode has no rule for feature "${f}" (table "${sysTable.table_name}") \u2014 `+"its table will NOT be synced. Add it to featureEnabled in ElysiaPlugin/index.ts."),!1;return featureEnabled[f]===!0})){let camelKey=sysTable.table_name.replace(/_([a-z])/g,(_,c)=>c.toUpperCase());consumerAllowedTableKeys.add(camelKey)}}if(db&&config.schema){let schemas=await import(__require("path").resolve(process.cwd(),config.schema)),auditLogsTable=schemaTables.auditLogs||schemas.auditLogs;if(audit?.enabled&&auditLogsTable)logger2.addAuditTransport(new DatabaseAuditTransport({db,table:auditLogsTable,enabled:!0,dedup:audit.dedup}));let{ensureSchemaExists:ensureSchemaExists2,applySchemaPush:applySchemaPush2}=await Promise.resolve().then(() => (init_schema(),exports_schema));try{logger2.info(`Syncing schema to database (target: ${targetSchemaName})...`),await ensureSchemaExists2(db,targetSchemaName);try{let filteredTables=Object.fromEntries(Object.entries(schemaTables).filter(([key2,v])=>{if(v===void 0||v===null)return!1;if(consumerAllowedTableKeys&&!consumerAllowedTableKeys.has(key2))return!1;if(typeof v==="object"&&v!==null)return Object.getOwnPropertySymbols(v).length>0||v._!==void 0;return!1})),tableNames=Object.keys(filteredTables);if(logger2.info("[Schema] Tables to sync:",{tables:tableNames,count:tableNames.length,mode:isConsumerModeOnStart?"consumer":"full"}),!isConsumerModeOnStart){let usersTableDef=filteredTables.users;if(usersTableDef){let columnSymbols=Object.getOwnPropertyNames(usersTableDef).filter((k)=>!k.startsWith("_"));logger2.info("[Schema] Users table columns:",{columns:columnSymbols})}}let realExit=process.exit,push;try{process.exit=(code)=>{throw Error(`drizzle-kit called process.exit(${code??0}) during pushSchema \u2014 `+"suppressed so the app can keep booting")};let timeoutMs=database?.schemaPushTimeoutMs??120000;push=await withDeadline(pushSchema({schema:targetSchema,...filteredTables},db,[targetSchemaName]),timeoutMs,`pushSchema did not finish within ${timeoutMs}ms. drizzle-kit most likely hit its `+"interactive rename prompt, which cannot be answered without a TTY \u2014 it appears "+"when a push adds a new table while another table exists in the database but not in the schema. Drop the stale table, or split the change across two deploys.")}finally{process.exit=realExit}if(await applySchemaPush2(push,{schemaName:targetSchemaName,allowDataLoss:database?.allowDataLoss===!0,logger:logger2,execute:(statement)=>db.execute(sql12.raw(statement))}))logger2.info("[Schema] pushSchema completed successfully")}catch(pushError){let msg=pushError instanceof Error?pushError.message:String(pushError);logger2.warn(`[Schema] pushSchema warning: ${msg}`)}logger2.info("[Schema] Schema sync completed",{schema:targetSchemaName})}catch(error3){logger2.error("[Schema] Schema sync failed",error3,{schema:targetSchemaName})}if(secretsService)try{await secretsService.start(),logger2.info("[Secrets] Credential store ready",{storedCredentials:secretsService.size()})}catch(error3){logger2.error("[Secrets] Credential store failed to start \u2014 env and literal values still resolve",{error:error3 instanceof Error?error3.message:String(error3)})}if(logger2.info("[Database] Connection established"),isMultiTenant&&db&&config.schema){let schemasForTenant={};try{let schemaPath=__require("path").resolve(process.cwd(),config.schema);logger2.info("[MultiTenant] Loading schema for tenant registry",{schemaPath}),schemasForTenant=await import(schemaPath),logger2.info("[MultiTenant] Schema loaded",{keys:Object.keys(schemasForTenant).slice(0,10),hasCreateAll:!!schemasForTenant.createAllTablesForSchema})}catch(err){let msg=err instanceof Error?err.message:String(err);logger2.error("[MultiTenant] Failed to load schema for tenant registry",{error:msg})}let createAllFn=schemasForTenant.createAllTablesForSchema;if(createAllFn){let idpUrl=isConsumerModeOnStart?authentication?.idpUrl?String(process.env[authentication.idpUrl]||authentication.idpUrl):void 0:void 0;if(tenantRegistry=new TenantRegistry({db,logger:logger2,mainSchemaName:targetSchemaName,mainSchemaTables:schemaTables,mainSchemaRelations:schemaRelations,createAllTablesForSchema:createAllFn,createAllRelationsForSchema:schemasForTenant.createAllRelationsForSchema,appId:resolvedOptions.appId,authMode:authentication?.mode,tenantResolution:database?.tenantResolution||"both",tenantHeader:database?.tenantHeader||"x-tenant-id",redisCacheTtlSeconds:300,defaultTrustedSources:database?.defaultTrustedSources,idpUrl,allowDataLoss:database?.allowDataLoss===!0,onTenantProvisioned:resolvedOptions.authorization?.enabled&&!isConsumerModeOnStart?async(context)=>{let authConfig={...DEFAULT_AUTHORIZATION_CONFIG,...resolvedOptions.authorization};if(authConfig.autoSeedClaims&&db){let claimEntities=mergeEntitiesByName([...extractSchemaTableEntities(context.schemaTables),...SYSTEM_TABLES.map((table)=>normalizeSystemTable(table)),...effectiveConfigEntities(resolvedOptions.entities||[]),...config.systemTables||[],...resolvedOptions.authorization?.externalEntities||[]]);await seedClaims(db,context.schemaTables,context.schemaRelations,claimEntities,authConfig,logger2)}let seedConfig=resolvedOptions.authorization?.seed;if(seedConfig&&db){let{runSeed:runSeed2}=await Promise.resolve().then(() => (init_SeedRunner(),exports_SeedRunner));await runSeed2(db,context.schemaTables,seedConfig,logger2)}logger2.info(`[Authorization] New tenant schema seeded: ${context.schemaName}`)}:void 0}),isConsumerModeOnStart&&idpUrl){await tenantRegistry.initializeFromIdp(),logger2.info("[MultiTenant] Consumer mode: tenants fetched from IDP");let tenantSyncTimer=setInterval(()=>{tenantRegistry?.syncFromIdp().then((result)=>{if(result.added.length>0||result.removed.length>0)logger2.info(`[MultiTenant] Tenant sync: +${result.added.length} / -${result.removed.length} (total ${result.total})`)}).catch((err)=>{let msg=err instanceof Error?err.message:String(err);logger2.warn(`[MultiTenant] Tenant sync failed: ${msg}`)})},60000);trackInterval(tenantSyncTimer)}else await tenantRegistry.initialize();for(let schemaName of tenantRegistry.getAllSchemaNames()){if(schemaName===targetSchemaName)continue;let ctx=tenantRegistry.getSchemaContext(schemaName);if(ctx){await ensureSchemaExists2(db,schemaName);try{let tenantFilteredTables=Object.fromEntries(Object.entries(ctx.schemaTables).filter(([key2,v])=>{if(v===void 0||v===null)return!1;if(consumerAllowedTableKeys&&!consumerAllowedTableKeys.has(key2))return!1;if(typeof v==="object"&&v!==null)return Object.getOwnPropertySymbols(v).length>0||v._!==void 0;return!1})),tenantSchema=pgSchema2(schemaName),tenantPush=await pushSchema({schema:tenantSchema,...tenantFilteredTables},db,[schemaName]);if(await applySchemaPush2(tenantPush,{schemaName,allowDataLoss:database?.allowDataLoss===!0,logger:logger2,execute:(statement)=>db.execute(sql12.raw(statement))}))logger2.info(`[Schema] Tenant schema synced: ${schemaName}`)}catch(tenantPushError){let msg=tenantPushError instanceof Error?tenantPushError.message:String(tenantPushError);logger2.warn(`[Schema] Tenant schema sync warning for ${schemaName}: ${msg}`)}}}logger2.info(`[MultiTenant] Registry initialized with ${tenantRegistry.getAllSchemaNames().length} schemas`),logger2.info("[MultiTenant] Tenant registry ready, routes were pre-registered")}}if(resolvedOptions.authorization?.enabled&&!isConsumerModeOnStart){let authConfig={...DEFAULT_AUTHORIZATION_CONFIG,...resolvedOptions.authorization,godminEmail:resolveConfigCredential(resolvedOptions.authorization?.godminEmail),godminPassword:resolveConfigCredential(resolvedOptions.authorization?.godminPassword)};if(authConfig.autoSeedClaims){let schemaEntities=extractSchemaTableEntities(schemaTables),systemEntities=SYSTEM_TABLES.map((table)=>normalizeSystemTable(table)),configEntities=effectiveConfigEntities(resolvedOptions.entities||[]),externalEntities=resolvedOptions.authorization?.externalEntities||[],claimEntities=mergeEntitiesByName([...schemaEntities,...configEntities,...systemEntities,...config.systemTables||[],...externalEntities]);logger2.info("[Authorization] Seeding claims...",{schemaEntities:schemaEntities.length,systemEntities:systemEntities.length,configEntities:configEntities.length,externalEntities:externalEntities.length,totalEntities:claimEntities.length}),await seedClaims(db,schemaTables,schemaRelations,claimEntities,authConfig,logger2)}let discoveryConfig=resolvedOptions.authorization?.endpointDiscovery;if(discoveryConfig?.enabled&&(discoveryConfig.runOnBoot??!0)&&db)try{let{runEndpointDiscovery:runEndpointDiscovery2}=await Promise.resolve().then(() => (init_seed(),exports_seed)),discoveryResult=await runEndpointDiscovery2(db,schemaTables,discoveryConfig,logger2);logger2.info("[Authorization] Endpoint discovery completed",{services:discoveryResult.services})}catch(discoveryErr){logger2.error("[Authorization] Endpoint discovery failed",{error:discoveryErr instanceof Error?discoveryErr.message:String(discoveryErr)})}if(authConfig.godminEmail&&authConfig.godminPassword)logger2.info("[Authorization] Setting up godmin..."),await setupGodmin(db,schemaTables,authConfig,logger2);let seedConfig=resolvedOptions.authorization?.seed;if(seedConfig){let{runSeed:runSeed2}=await Promise.resolve().then(() => (init_SeedRunner(),exports_SeedRunner));logger2.info("[Authorization] Running custom seed...");let seedResult=await bootStep("authorization.seed",()=>runSeed2(db,schemaTables,seedConfig,logger2));if(seedResult)logger2.info("[Authorization] Custom seed completed",{rolesCreated:seedResult.rolesCreated,rolesExisting:seedResult.rolesExisting,claimsCreated:seedResult.claimsCreated,claimsExisting:seedResult.claimsExisting,assignmentsCreated:seedResult.assignmentsCreated,assignmentsExisting:seedResult.assignmentsExisting,assignmentsUpdated:seedResult.assignmentsUpdated})}let claimGuardsCfg=resolvedOptions.authorization?.claimGuards;if(claimGuardsCfg?.length){let{seedClaimGuards:seedClaimGuards2}=await Promise.resolve().then(() => (init_ClaimGuard(),exports_ClaimGuard));await bootStep("authorization.claimGuards",()=>seedClaimGuards2(db,schemaTables,claimGuardsCfg,logger2))}let jwtClaimsMode=resolvedOptions.authorization?.jwtClaimsMode||"embed",claimsCacheRedis=getRedisManager();if(jwtClaimsMode==="resolve"&&db&&claimsCacheRedis){let{ClaimsCache:ClaimsCache3}=await Promise.resolve().then(() => (init_ClaimsCache(),exports_ClaimsCache));claimsCache=new ClaimsCache3({prefix:resolvedOptions.authorization?.claimsCachePrefix||"nucleus:claims",redis:{get:async(key2)=>{let r2=await claimsCacheRedis.read(key2);return r2.success?r2.data:null},set:async(key2,value2)=>{await claimsCacheRedis.create(key2,value2)},delete:async(key2)=>{await claimsCacheRedis.remove(key2)}},db,schemaTables,logger:logger2});let cacheInstance=claimsCache,cacheResult=await bootStep("authorization.claimsCache",()=>cacheInstance.buildCache());if(cacheResult)logger2.info("[Authorization] Claims cache built (resolve mode)",{version:cacheResult.version,roleCount:cacheResult.roleCount,totalMappings:cacheResult.totalMappings})}else if(jwtClaimsMode==="resolve"&&!claimsCacheRedis)logger2.warn("[Authorization] jwtClaimsMode=resolve requires Redis. Falling back to embed mode.");if(logger2.info("[Authorization] Enabled"),isMultiTenant&&tenantRegistry){let tenantSchemas=tenantRegistry.getAllSchemaNames().filter((name2)=>name2!==targetSchemaName);for(let tenantSchemaName of tenantSchemas){let tenantCtx=tenantRegistry.getSchemaContext(tenantSchemaName);if(!tenantCtx)continue;try{if(authConfig.autoSeedClaims){let tenantSchemaEntities=extractSchemaTableEntities(tenantCtx.schemaTables),tenantClaimEntities=mergeEntitiesByName([...tenantSchemaEntities,...SYSTEM_TABLES.map((table)=>normalizeSystemTable(table)),...effectiveConfigEntities(resolvedOptions.entities||[]),...config.systemTables||[],...resolvedOptions.authorization?.externalEntities||[]]);await seedClaims(db,tenantCtx.schemaTables,tenantCtx.schemaRelations,tenantClaimEntities,authConfig,logger2)}if(tenantCtx.tenant?.godAdminEmail&&authConfig.godminPassword)await setupGodmin(db,tenantCtx.schemaTables,{...authConfig,godminEmail:tenantCtx.tenant.godAdminEmail},logger2);if(seedConfig){let{runSeed:runSeed2}=await Promise.resolve().then(() => (init_SeedRunner(),exports_SeedRunner));await runSeed2(db,tenantCtx.schemaTables,seedConfig,logger2)}logger2.info(`[Authorization] Tenant schema seeded: ${tenantSchemaName}`)}catch(err){let msg=err instanceof Error?err.message:String(err);logger2.warn(`[Authorization] Failed to seed tenant ${tenantSchemaName}: ${msg}`)}}logger2.info(`[Authorization] Multi-tenant seeding complete for ${tenantSchemas.length} schemas`)}}let sessionsTableRef=schemaTables.userSessions;if(!isConsumerModeOnStart&&sessionsTableRef&&resolvedOptions.authentication?.sessions?.enabled){let{lt:lt4}=await import("drizzle-orm"),expiredCount=await bootStep("auth.expiredSessionCleanup",()=>db.update(sessionsTableRef).set({isActive:!1,revokedAt:new Date,revokedReason:"expired"}).where(and23(eq61(sessionsTableRef.isActive,!0),lt4(sessionsTableRef.expiresAt,new Date))));if(expiredCount!==void 0)logger2.info("[AUTH] Expired sessions cleanup completed",{expiredCount});let sessionCleanupInterval=setInterval(async()=>{try{await db.update(sessionsTableRef).set({isActive:!1,revokedAt:new Date,revokedReason:"expired"}).where(and23(eq61(sessionsTableRef.isActive,!0),lt4(sessionsTableRef.expiresAt,new Date)));let approvalTtlMs=86400000,approvalCutoff=new Date(Date.now()-approvalTtlMs);await db.update(sessionsTableRef).set({isActive:!1,revokedAt:new Date,revokedReason:"approval_token_expired",approvalStatus:"rejected",approvalToken:null}).where(and23(eq61(sessionsTableRef.approvalStatus,"pending"),lt4(sessionsTableRef.approvalRequestedAt,approvalCutoff)))}catch(err){logger2.warn("[AUTH] Session cleanup failed",{error:err})}},3600000);trackInterval(sessionCleanupInterval)}if(isMultiTenant&&tenantRegistry&&resolvedOptions.authentication?.sessions?.enabled){let{lt:lt4}=await import("drizzle-orm"),tenantSchemaNames=tenantRegistry.getAllSchemaNames().filter((name2)=>name2!==targetSchemaName);for(let tenantSchemaName of tenantSchemaNames){let tenantCtx=tenantRegistry.getSchemaContext(tenantSchemaName);if(!tenantCtx)continue;let tenantSessionsTable=tenantCtx.schemaTables.userSessions||tenantCtx.schemaTables.user_sessions||tenantCtx.schemaTables.sessions;if(!tenantSessionsTable)continue;try{await db.update(tenantSessionsTable).set({isActive:!1,revokedAt:new Date,revokedReason:"expired"}).where(and23(eq61(tenantSessionsTable.isActive,!0),lt4(tenantSessionsTable.expiresAt,new Date))),logger2.info(`[AUTH] Tenant session cleanup completed: ${tenantSchemaName}`)}catch(err){let msg=err instanceof Error?err.message:String(err);logger2.warn(`[AUTH] Tenant session cleanup failed for ${tenantSchemaName}: ${msg}`)}}}}}).onRequest(async({request,set:set2,server})=>{if(request.headers.delete("x-user-id"),request.headers.delete("x-request-id"),request.headers.delete("x-auth-type"),request.headers.delete("x-api-key-id"),request.headers.delete("x-api-key-owner-type"),request.headers.delete("x-user-roles"),request.headers.delete("x-user-claims"),request.headers.delete("x-user-claim-scopes"),request.headers.delete("x-session-id"),request.headers.delete("x-access-token"),request.headers.delete("x-refresh-token"),request.headers.delete("x-tenant-schema"),exceedsBodyLimit(request.headers.get("content-length"),resolvedOptions.security?.maxRequestBodyBytes))return set2.status=413,Response.json({isSuccess:!1,message:"Request body too large",status:413,errors:[{message:"Request body too large"}],data:null});let requestStartTime=Date.now(),requestSchemaTables=schemaTables;if(tenantRegistry){let tenantVettedClientIp=resolveClientIp(server?.requestIP(request)?.address??null,request.headers.get("x-forwarded-for")??request.headers.get("x-real-ip"),resolvedOptions.rateLimit?.trustedProxies??[]),tenantResult=tenantRegistry.resolveFromRequest(request,tenantVettedClientIp);if(tenantResult.resolved)requestSchemaTables=tenantResult.context.schemaTables,request.headers.set("x-tenant-schema",tenantResult.context.schemaName);else if(new URL(request.url).pathname!=="/health")return set2.status=tenantResult.statusCode,Response.json({isSuccess:!1,message:tenantResult.error,status:tenantResult.statusCode,errors:[{message:tenantResult.error}],data:null})}request.headers.set("x-request-start-time",String(requestStartTime));let requestId=randomUUID8();if(request.headers.set("x-request-id",requestId),set2.headers["x-request-id"]=requestId,resolvedOptions.security?.disableDefaultHeaders!==!0){set2.headers["X-Content-Type-Options"]="nosniff",set2.headers["X-Frame-Options"]="SAMEORIGIN",set2.headers["Referrer-Policy"]="strict-origin-when-cross-origin";let hstsMaxAge=resolvedOptions.security?.hstsMaxAge??15552000;if(hstsMaxAge>0)set2.headers["Strict-Transport-Security"]=`max-age=${hstsMaxAge}; includeSubDomains`}let url=new URL(request.url),pathname=url.pathname,method=request.method,query=url.search;if(csrfConfig.enabled){let csrfSecure=request.headers.get("x-forwarded-proto")==="https"||url.protocol==="https:"?"; Secure":"",issueCsrfCookie=()=>`${csrfConfig.cookieName}=${randomUUID8()}; Path=/; SameSite=Lax${csrfSecure}`,csrfCookies=parseCookies(request.headers.get("cookie"));if(requiresCsrf({method,cookies:csrfCookies,hasAuthorizationHeader:!!request.headers.get("authorization"),authCookieNames:csrfAuthCookieNames})&&!csrfTokenMatches(csrfCookies[csrfConfig.cookieName],request.headers.get(csrfConfig.headerName)))return set2.headers["Set-Cookie"]=issueCsrfCookie(),set2.status=403,Response.json({isSuccess:!1,message:"CSRF token missing or invalid",status:403,errors:[{message:"CSRF token missing or invalid"}],data:null});else if(!isStateChanging(method)&&!csrfCookies[csrfConfig.cookieName])set2.headers["Set-Cookie"]=issueCsrfCookie()}let socketIp=server?.requestIP(request)?.address??null,clientIp=resolveClientIp(socketIp,request.headers.get("x-forwarded-for")??request.headers.get("x-real-ip"),resolvedOptions.rateLimit?.trustedProxies??[]);request.headers.set("x-client-ip",clientIp);let userAgent=request.headers.get("user-agent")||"unknown";if(requestLogConfig.enabled&&requestLogConfig.logArrival&&!isRequestLogExcluded(pathname))logger2.log("debug",`\u2192 ${method} ${pathname}`,{requestId,method,path:pathname,query:requestLogConfig.includeQuery&&query?query:void 0,ip:clientIp,tenant:request.headers.get("x-tenant-schema")||void 0},void 0,void 0,"middleware.request");let tokens,parsedBody={};if(request.method!=="GET"&&request.method!=="HEAD")try{let text2=await request.clone().text();parsedBody=text2?JSON.parse(text2):{}}catch{parsedBody={}}let auditPayload=audit?.enabled?{id:randomUUID8(),user_id:"unknown",entity_name:pathname.split("/").filter(Boolean)[0]||"root",entity_id:null,operation_type:method,summary:"",old_values:{},new_values:parsedBody,ip_address:clientIp,user_agent:userAgent,timestamp:new Date().toISOString(),path:pathname,query}:null,isPublic=isPublicRoute(publicRoutes,pathname,method);if(rateLimiter){let routeCategory=isPublic?"public":"private",authType=resolveAuthType(pathname,resolvedOptions.authentication),category=authType?"auth":routeCategory,rateLimitResult=await rateLimiter.check({ip:clientIp,endpoint:pathname,category,authType}),headers=rateLimiter.getHeaders(rateLimitResult);for(let[key2,value2]of Object.entries(headers))set2.headers[key2]=value2;if(!rateLimitResult.allowed){if(set2.status=429,rateLimitResult.retryAfter)set2.headers["Retry-After"]=String(rateLimitResult.retryAfter);if(logger2.warn(`[RateLimit] Blocked request from ${clientIp} to ${pathname}`),monitoringService)monitoringService.recordRateLimitBlock();return new Response(JSON.stringify({error:"Too Many Requests",retryAfter:rateLimitResult.retryAfter}),{status:429,headers:{"Content-Type":"application/json"}})}}if(pathname==="/health")return;if(authentication?.enabled&&!isPublic){let apiKeyRaw=extractApiKeyFromHeader(request.headers),apiKeysTableRef=requestSchemaTables.apiKeys;if(apiKeyRaw&&authentication.apiKeys?.enabled&&apiKeysTableRef&&db){let keyHash=hashApiKey(apiKeyRaw),apiKeyRecord=(await db.select().from(apiKeysTableRef).where(eq61(apiKeysTableRef.keyHash,keyHash)).limit(1))[0];if(!apiKeyRecord)return set2.status=401,logger2.traceSync({message:"Invalid API key",level:"warn",context:{path:pathname,method},audit:toAudit(auditPayload,"Invalid API key")}),Error("Invalid API key");let validation=validateApiKeyRecord(apiKeyRecord);if(!validation.valid)return set2.status=401,logger2.traceSync({message:`API key rejected: ${validation.reason}`,level:"warn",context:{path:pathname,method,keyId:apiKeyRecord.id},audit:toAudit(auditPayload,`API key rejected: ${validation.reason}`)}),Error(validation.reason);let apiKeyUserId=apiKeyRecord.userId,apiKeyUserData;{let ksTable=requestSchemaTables.users;if(ksTable&&db){apiKeyUserData=(await db.select().from(ksTable).where(eq61(ksTable.id,apiKeyUserId)).limit(1))[0];let{evaluateAccountState:evaluateAccountState2}=await Promise.resolve().then(() => exports_accountState),ksState=apiKeyUserData?evaluateAccountState2(apiKeyUserData):{allowed:!1,reason:"inactive",message:"Account is not active"};if(!ksState.allowed)return set2.status=401,logger2.traceSync({message:`API key rejected: account ${ksState.reason}`,level:"warn",context:{path:pathname,method,keyId:apiKeyRecord.id},audit:toAudit(auditPayload,`API key rejected: account ${ksState.reason}`,{userId:apiKeyUserId})}),Error(ksState.message)}}let keyAllowedRoles=apiKeyRecord.allowedRoles||[],keyAllowedClaims=apiKeyRecord.allowedClaims||[],effectiveRoles=keyAllowedRoles,effectiveClaims=keyAllowedClaims,apiKeyClaimScopes={},userRolesTable=requestSchemaTables.userRoles,rolesTable=requestSchemaTables.roles,roleClaimsTable=requestSchemaTables.roleClaims,claimsTable=requestSchemaTables.claims;if(userRolesTable&&rolesTable){let currentUserRoles=(await db.select({name:rolesTable.name}).from(userRolesTable).innerJoin(rolesTable,eq61(rolesTable.id,userRolesTable.roleId)).where(eq61(userRolesTable.userId,apiKeyUserId))).map((r2)=>r2.name).filter((n2)=>n2!==void 0);effectiveRoles=intersectPermissions(currentUserRoles,keyAllowedRoles)}if(userRolesTable&&roleClaimsTable&&claimsTable){let userClaimRows=await db.select({action:claimsTable.action,scope:roleClaimsTable.scope}).from(userRolesTable).innerJoin(roleClaimsTable,eq61(roleClaimsTable.roleId,userRolesTable.roleId)).innerJoin(claimsTable,eq61(claimsTable.id,roleClaimsTable.claimId)).where(eq61(userRolesTable.userId,apiKeyUserId)),currentUserClaims=[...new Set(userClaimRows.map((r2)=>r2.action).filter((a12)=>a12!==void 0))];effectiveClaims=intersectPermissions(currentUserClaims,keyAllowedClaims);let effectiveClaimSet=new Set(effectiveClaims),apiScopedRows=userClaimRows.filter((r2)=>typeof r2.action==="string"&&effectiveClaimSet.has(r2.action)).map((r2)=>({action:r2.action,scope:r2.scope??null}));if(apiScopedRows.some((r2)=>!!r2.scope)){let{claimScopes,dropped}=resolveClaimScopes(apiScopedRows,apiKeyUserData,logger2);if(apiKeyClaimScopes=claimScopes,dropped.length>0){let droppedSet=new Set(dropped);effectiveClaims=effectiveClaims.filter((a12)=>!droppedSet.has(a12))}}}if(db.update(apiKeysTableRef).set({lastUsedAt:new Date,lastUsedIp:clientIp,usageCount:apiKeyRecord.usageCount+1}).where(eq61(apiKeysTableRef.id,apiKeyRecord.id)).catch(()=>{}),effectiveRoles=effectiveRoles.filter((r2)=>r2!==GODMIN_ROLE_NAME),request.headers.set("x-user-id",apiKeyUserId),request.headers.set("x-auth-type","api_key"),request.headers.set("x-api-key-id",apiKeyRecord.id),request.headers.set("x-api-key-owner-type",apiKeyRecord.ownerType||"personal"),effectiveRoles.length>0)request.headers.set("x-user-roles",encodeHeaderList(effectiveRoles));if(effectiveClaims.length>0)request.headers.set("x-user-claims",encodeHeaderList(effectiveClaims));{let apiEncodedScopes=encodeClaimScopesHeader(apiKeyClaimScopes);if(apiEncodedScopes)request.headers.set("x-user-claim-scopes",apiEncodedScopes)}logger2.info("[AUTH] API key authenticated",{userId:apiKeyUserId,keyId:apiKeyRecord.id,ownerType:apiKeyRecord.ownerType,path:pathname,method,effectiveRoles:effectiveRoles.length,effectiveClaims:effectiveClaims.length});return}if(!authentication.accessToken?.secret)return set2.status=500,logger2.traceSync({message:"Authentication secrets not defined",level:"error",context:{path:pathname,method},audit:toAudit(auditPayload,"Authentication secrets not defined")}),Error("One or more authentication secrets are not defined");if(authentication.mode==="consumer"){tokens=parseTokenValuesFromHeaders(request.headers,tokenNames);let jwtResult=verifyJWT(tokens.access_token||"",envResolved.accessTokenSecret||"",{issuer:authentication.accessToken?.issuer,audience:authentication.accessToken?.audience});if(!jwtResult.valid)return set2.status=401,logger2.traceSync({message:"Invalid or missing access token",level:"warn",context:{path:pathname,method},audit:toAudit(auditPayload,"Invalid or missing access token",{userId:decodeUnverifiedSubject(tokens.access_token)})}),Error("Unauthenticated");let consumerBinding=verifyTenantBinding(jwtResult.payload[TENANT_CLAIM],request.headers.get("x-tenant-schema"),resolvedOptions.authentication?.tenantBinding??"lenient");if(!consumerBinding.ok)return set2.status=401,logger2.traceSync({message:"Access token tenant binding failed",level:"warn",context:{path:pathname,method,reason:consumerBinding.reason},audit:toAudit(auditPayload,"Access token tenant binding failed",{userId:decodeUnverifiedSubject(tokens.access_token)})}),Error("Unauthenticated");let userId=jwtResult.payload.sub,roles=jwtResult.payload.roles,claimsFromToken=jwtResult.payload.claims;if(request.headers.set("x-access-token",tokens.access_token||""),request.headers.set("x-user-id",userId||""),roles&&roles.length>0)request.headers.set("x-user-roles",encodeHeaderList(roles));if(claimsFromToken&&claimsFromToken.length>0)request.headers.set("x-user-claims",encodeHeaderList(claimsFromToken));{let encodedScopes=encodeClaimScopesHeader(jwtResult.payload.claimScopes);if(encodedScopes)request.headers.set("x-user-claim-scopes",encodedScopes)}}else{if(!authentication.refreshToken?.secret||!authentication.sessionToken?.secret)return set2.status=500,logger2.traceSync({message:"Authentication secrets not defined",level:"error",context:{path:pathname,method},audit:toAudit(auditPayload,"Authentication secrets not defined")}),Error("One or more authentication secrets are not defined");if(tokens=parseTokenValuesFromHeaders(request.headers,tokenNames),!tokens.session_token)return set2.status=401,logger2.traceSync({message:"No session token",level:"debug",context:{path:pathname,method},audit:toAudit(auditPayload,"No session token")}),Error("Unauthenticated");let sessionData=await readSession({sessionId:tokens.session_token});if(!sessionData)return set2.status=401,logger2.traceSync({message:"Invalid session",level:"debug",context:{path:pathname,method,sessionId:tokens.session_token},audit:toAudit(auditPayload,"Invalid session")}),Error("Unauthenticated");let sessionsTableCheck=requestSchemaTables.userSessions;if(sessionsTableCheck&&db){let session=(await db.select().from(sessionsTableCheck).where(eq61(sessionsTableCheck.id,tokens.session_token)).limit(1))[0],revokedAtVal=session?.revokedAt,isRevoked=revokedAtVal!=null&&!(typeof revokedAtVal==="object"&&!(revokedAtVal instanceof Date)&&Object.keys(revokedAtVal).length===0);if(!session||session.isActive===!1||isRevoked)return set2.status=401,logger2.traceSync({message:"Session revoked or inactive",level:"warn",context:{path:pathname,method,sessionId:tokens.session_token,isActive:session?.isActive,revokedAt:session?.revokedAt},audit:toAudit(auditPayload,"Session revoked",{userId:sessionData.userId??null})}),Error("Session has been revoked");if(session.expiresAt&&new Date(session.expiresAt)<new Date)return set2.status=401,logger2.traceSync({message:"Session expired",level:"debug",context:{path:pathname,method,sessionId:tokens.session_token,expiresAt:session.expiresAt},audit:toAudit(auditPayload,"Session expired",{userId:sessionData.userId??null})}),Error("Session has expired")}if(sessionData.lastActiveAt&&authentication.sessions?.inactivityTimeout){let lastActive=new Date(sessionData.lastActiveAt).getTime(),inactivityMs=parseTimeToSeconds2(authentication.sessions.inactivityTimeout)*1000;if(Date.now()-lastActive>inactivityMs)return set2.status=401,logger2.traceSync({message:"Session inactive timeout",level:"debug",context:{path:pathname,method,sessionId:tokens.session_token,lastActiveAt:sessionData.lastActiveAt},audit:toAudit(auditPayload,"Session inactive timeout",{userId:sessionData.userId??null})}),Error("Session expired due to inactivity")}updateLastActiveAt(tokens.session_token).catch(()=>{});let sessionsTableRef=requestSchemaTables.userSessions;if(sessionsTableRef&&db)db.update(sessionsTableRef).set({lastActivityAt:new Date}).where(eq61(sessionsTableRef.id,tokens.session_token)).catch(()=>{});let jwtResult=verifyJWT(tokens.access_token||"",envResolved.accessTokenSecret||"",{issuer:authentication.accessToken?.issuer,audience:authentication.accessToken?.audience}),isAccessTokenValid=tokens.access_token?jwtResult.valid:!1,isRefreshTokenValid=tokens.refresh_token?verifyJWT(tokens.refresh_token,envResolved.refreshTokenSecret||"",{issuer:authentication.refreshToken?.issuer,audience:authentication.refreshToken?.audience}).valid:!1;if(!isAccessTokenValid&&isRefreshTokenValid&&tokens.refresh_token&&sessionData.rememberMe===!0){let killSwitchUsersTable=requestSchemaTables.users;if(db&&killSwitchUsersTable){let ksUser=(await db.select().from(killSwitchUsersTable).where(eq61(killSwitchUsersTable.id,sessionData.userId)).limit(1))[0],{evaluateAccountState:evaluateAccountState2}=await Promise.resolve().then(() => exports_accountState),ksState=ksUser?evaluateAccountState2(ksUser):{allowed:!1,reason:"inactive",message:"Account is not active"};if(!ksState.allowed)return set2.status=401,logger2.traceSync({message:`Silent refresh blocked - account ${ksState.reason}`,level:"warn",context:{path:pathname,method},audit:toAudit(auditPayload,`Silent refresh blocked - account ${ksState.reason}`,{userId:sessionData.userId??null})}),Error(ksState.message)}let refreshRoles=[],refreshClaims=[],refreshClaimScopes={},refreshUserRolesTable=requestSchemaTables.userRoles,refreshRolesTable=requestSchemaTables.roles,refreshRoleClaimsTable=requestSchemaTables.roleClaims,refreshClaimsTable=requestSchemaTables.claims;if(db&&refreshUserRolesTable&&refreshRolesTable)try{let{fetchUserRolesAndClaims:fetchUserRolesAndClaims2}=await Promise.resolve().then(() => (init_fetchUserRolesAndClaims(),exports_fetchUserRolesAndClaims)),rc=await fetchUserRolesAndClaims2(db,sessionData.userId,{usersTable:killSwitchUsersTable??null,sessionsTable:null,userRolesTable:refreshUserRolesTable,rolesTable:refreshRolesTable,roleClaimsTable:refreshRoleClaimsTable,claimsTable:refreshClaimsTable,oauthAccountsTable:void 0,apiKeysTable:void 0,schemaTables:requestSchemaTables});refreshRoles=rc.roles,refreshClaims=rc.claims,refreshClaimScopes=rc.claimScopes}catch{}let refreshResult=await refreshAccessTokenWithLock(sessionData.userId,sessionData.id,()=>signNewAccessToken({refreshTokenId:tokens.refresh_token,options:resolvedOptions,sessionData,roles:refreshRoles.length>0?refreshRoles:void 0,claims:refreshClaims.length>0?refreshClaims:void 0,claimScopes:refreshClaimScopes,tenant:request.headers.get("x-tenant-schema")??void 0,resolveMode:resolvedOptions.authorization?.jwtClaimsMode==="resolve"&&!!claimsCache}));if(refreshResult.success&&refreshResult.accessToken){tokens.access_token=refreshResult.accessToken;let rawDomain=authentication.cookieDomain,resolvedDomainRaw=rawDomain?process.env[rawDomain]??rawDomain:void 0,resolvedDomain=resolvedDomainRaw==="localhost"||resolvedDomainRaw===".localhost"?void 0:resolvedDomainRaw,domainPart=resolvedDomain?`; Domain=${resolvedDomain}`:"",bufferSeconds=authentication.cookieMaxAgeBufferSeconds??0,maxAge=Math.max(0,parseTimeToSeconds2(authentication.accessToken.expiresIn??"15m")-bufferSeconds),securePart=!resolvedDomain?"":"; Secure",cookieValue=`${tokenNames.access_token}=${refreshResult.accessToken}; Path=/; HttpOnly; SameSite=Lax${securePart}; Max-Age=${maxAge}${domainPart}`;set2.headers["Set-Cookie"]=cookieValue}}if(jwtResult.valid){let fullBinding=verifyTenantBinding(jwtResult.payload[TENANT_CLAIM],request.headers.get("x-tenant-schema"),resolvedOptions.authentication?.tenantBinding??"lenient");if(!fullBinding.ok)return set2.status=401,logger2.traceSync({message:"Access token tenant binding failed",level:"warn",context:{path:pathname,method,reason:fullBinding.reason},audit:toAudit(auditPayload,"Access token tenant binding failed",{userId:jwtResult.payload.sub??null})}),Error("Unauthenticated")}if(jwtResult.valid&&jwtResult.payload.sub&&String(jwtResult.payload.sub)!==String(sessionData.userId))return set2.status=401,logger2.traceSync({message:"Access token subject does not match session",level:"warn",context:{path:pathname,method,sessionUserId:sessionData.userId,tokenSub:jwtResult.payload.sub},audit:toAudit(auditPayload,"Access token/session subject mismatch",{userId:sessionData.userId??null})}),Error("Unauthenticated");let userId=jwtResult.valid?jwtResult.payload.sub:sessionData.userId,roles=jwtResult.valid?jwtResult.payload.roles:void 0,claimsFromToken=jwtResult.valid?jwtResult.payload.claims:void 0;if(!claimsFromToken?.length&&claimsCache&&roles&&roles.length>0)try{let resolvedClaims=await claimsCache.resolveClaimsForRoles(roles);if(resolvedClaims.length>0)claimsFromToken=resolvedClaims}catch{}if(userId&&db&&authentication.cohorts?.enabled){let mwUsersTable=requestSchemaTables.users;if(mwUsersTable)try{let mwCohortId=(await db.select().from(mwUsersTable).where(eq61(mwUsersTable.id,userId)).limit(1))[0]?.cohortId;if(mwCohortId){let mwCohortsTable=requestSchemaTables.userCohorts??requestSchemaTables.user_cohorts;if(mwCohortsTable){let mwExpiresAt=(await db.select().from(mwCohortsTable).where(eq61(mwCohortsTable.id,mwCohortId)).limit(1))[0]?.expiresAt;if(mwExpiresAt&&new Date(mwExpiresAt)<new Date)return set2.status=403,logger2.traceSync({message:"Cohort expired - access denied",level:"warn",context:{path:pathname,method,userId,cohortId:mwCohortId},audit:toAudit(auditPayload,"Cohort expired",{userId:userId??null})}),Error("Your access has expired. Please contact your administrator.")}}}catch{}}if(request.headers.set("x-access-token",tokens.access_token||""),request.headers.set("x-refresh-token",tokens.refresh_token||""),request.headers.set("x-session-id",tokens.session_token||""),request.headers.set("x-user-id",userId||""),roles&&roles.length>0)request.headers.set("x-user-roles",encodeHeaderList(roles));if(claimsFromToken&&claimsFromToken.length>0)request.headers.set("x-user-claims",encodeHeaderList(claimsFromToken));{let encodedScopes=encodeClaimScopesHeader(jwtResult.valid?jwtResult.payload.claimScopes:void 0);if(encodedScopes)request.headers.set("x-user-claim-scopes",encodedScopes)}}}}).onAfterHandle(({request,set:set2})=>{let afterUrl=new URL(request.url),afterStatus=typeof set2.status==="number"?set2.status:200,afterStartStr=request.headers.get("x-request-start-time"),afterDuration=afterStartStr?Date.now()-parseInt(afterStartStr,10):0;if(requestLogConfig.enabled&&!isRequestLogExcluded(afterUrl.pathname)){let isSlow=afterDuration>=requestLogConfig.slowThresholdMs,level=afterStatus>=500?"error":afterStatus>=400||isSlow?"warn":"info";logger2.log(level,`\u2190 ${request.method} ${afterUrl.pathname} ${afterStatus} (${afterDuration}ms)`,{requestId:request.headers.get("x-request-id")||void 0,method:request.method,path:afterUrl.pathname,query:requestLogConfig.includeQuery&&afterUrl.search?afterUrl.search:void 0,statusCode:afterStatus,durationMs:afterDuration,slow:isSlow||void 0,userId:request.headers.get("x-user-id")||void 0,authType:request.headers.get("x-auth-type")||void 0,tenant:request.headers.get("x-tenant-schema")||void 0,ip:request.headers.get("x-forwarded-for")?.split(",")[0]?.trim()||request.headers.get("x-real-ip")||void 0},void 0,void 0,"middleware.request")}if(monitoringService){let startTimeStr=request.headers.get("x-request-start-time"),startTime=startTimeStr?parseInt(startTimeStr,10):Date.now(),responseTimeMs=Date.now()-startTime,url=new URL(request.url),status=typeof set2.status==="number"?set2.status:200;monitoringService.recordRequest({endpoint:url.pathname,method:request.method,status,responseTimeMs,isError:status>=400,errorType:status>=500?"server_error":status>=400?"client_error":void 0})}if(liveMonitoringService){let url=new URL(request.url),headersObj=redactSensitiveHeaders(request.headers);liveMonitoringService.recordRequest({path:url.pathname,method:request.method,timestamp:Date.now(),headers:headersObj})}}).onError((ctx)=>{let{set:set2,code,error:error3,request}=ctx,status=statusOfError(code,error3),message="Internal Server Error",pgCode,clientSafe=!1;if(error3 instanceof Error){let cause=error3.cause;if(pgCode=cause?.code,pgCode==="23505")message="A record with this value already exists",clientSafe=!0;else if(pgCode==="23503")message="Referenced record does not exist",clientSafe=!0;else if(pgCode==="23502")message=`Missing required field: ${cause?.column||"a required field is empty"}`,clientSafe=!0;else if(pgCode==="22P02")message=cause?.routine==="string_to_uuid"?"Invalid ID format":"Invalid data format",clientSafe=!0;else if(pgCode)message=`Database error (${pgCode}): ${cause?.detail||cause?.message||error3.message}`;else if(code==="VALIDATION")message=describeValidationError(error3)??error3.message,clientSafe=!0;else message=error3.message,clientSafe=status<500}try{let errUrl=new URL(request.url),errStartStr=request.headers.get("x-request-start-time");logger2.log(status>=500?"error":"warn",`\u2716 ${request.method} ${errUrl.pathname} ${status}: ${message}`,{requestId:request.headers.get("x-request-id")||void 0,method:request.method,path:errUrl.pathname,statusCode:status,elysiaCode:typeof code==="string"?code:void 0,pgCode,durationMs:errStartStr?Date.now()-parseInt(errStartStr,10):void 0,userId:request.headers.get("x-user-id")||void 0,tenant:request.headers.get("x-tenant-schema")||void 0},status>=500?error3:void 0)}catch(logErr){logger2.error("Failed to log request error",logErr)}set2.status=status;let clientMessage=clientSafe?message:"Internal Server Error";return Response.json({isSuccess:!1,message:clientMessage,status,errors:[{message:clientMessage}],data:null})});let featureAdminRoles={};for(let[feature,section]of Object.entries(resolvedOptions)){if(!section||typeof section!=="object")continue;let roles=section.adminRoles;if(!Array.isArray(roles))continue;let named=roles.filter((role)=>typeof role==="string"&&role.length>0);if(named.length>0)featureAdminRoles[feature]=named}logger2.info("Creating routes for entities"),createEntityRoutes(plugin,{db,schemaTables,schemaRelations,entities,logger:logger2,databaseUrl:envResolved.databaseUrl,dbPool,storage:resolvedOptions.storage,cdnMedia:{transform:mergeTransformConfig(resolvedOptions.storage?.cdn?.transform),video:mergeVideoConfig(resolvedOptions.storage?.cdn?.video)},authorization:resolvedOptions.authorization,featureAdminRoles,authMode:authentication?.mode,idpUrl:authentication?.idpUrl?process.env[authentication.idpUrl]||authentication.idpUrl:void 0,isEmailServiceAvailable:()=>!!getEmailService()?.isAvailable(),tenantRegistry,getTenantRegistry:()=>tenantRegistry,claimsCache});let isConsumerMode=authentication?.mode==="consumer";if(isMultiTenant&&!isConsumerMode)createTenantRoutes(plugin,{getDb:()=>db,logger:logger2,getTenantRegistry:()=>tenantRegistry,schemaName:targetSchemaName}),logger2.info("[MultiTenant] Tenant routes pre-registered (handlers check runtime readiness)");else if(isMultiTenant&&isConsumerMode)plugin.post("/tenants/refresh",async(ctx)=>{if(!tenantRegistry||!tenantRegistry.isConsumerMode())return ctx.set.status=503,{success:!1,message:"Tenant registry not ready"};try{return{success:!0,data:await tenantRegistry.syncFromIdp()}}catch(err){let msg=err instanceof Error?err.message:String(err);return ctx.set.status=500,{success:!1,message:`Tenant sync failed: ${msg}`}}}),logger2.info("[MultiTenant] Consumer tenant refresh route registered (/tenants/refresh)");let domainServices=null;if(resolvedOptions.domains?.enabled){if(domainServices=createDomainServices({options:resolvedOptions,logger:logger2,getDb:()=>db,getTenantRegistry:()=>tenantRegistry}),domainServices)createDomainRoutes(plugin,{getDomainService:()=>domainServices?.domainService??null,getRegistrationService:()=>domainServices?.registrationService??null,logger:logger2,basePath:resolvedOptions.domains.basePath||"/domains",resolveTenantIdForSchema:(schema3)=>schema3&&tenantRegistry?tenantRegistry.getTenantBySchemaName(schema3)?.id??null:null}),logger2.info("[Domains] Custom domain routes registered",{provider:domainServices.domainService.config.provider,basePath:resolvedOptions.domains.basePath||"/domains"})}if(authentication?.enabled&&!isConsumerMode&&db){let resolveTableForTenant=(tableName,reqSchemaName)=>{if(reqSchemaName&&tenantRegistry){let ctx=tenantRegistry.getSchemaContext(reqSchemaName);if(ctx?.schemaTables[tableName])return ctx.schemaTables[tableName]}return schemaTables[tableName]},usersTable=schemaTables.users,sessionsTable=schemaTables.userSessions||schemaTables.user_sessions||schemaTables.sessions;if(!sessionsTable&&authentication.sessions?.enabled)logger2.warn("[AUTH] sessions is enabled but user_sessions table not found in schema. Disabling sessions.");if(usersTable){await initiateRedisManager(resolvedOptions);let{createAuthRoutes:createAuthRoutes2}=(init_auth(),__toCommonJS(exports_auth)),{signJWT:signJWT2,verifyJWT:verifyJWT3}=(init_JWT(),__toCommonJS(exports_JWT)),{generateSession:generateSession2,deleteSession:deleteSession2}=(init_SessionStore(),__toCommonJS(exports_SessionStore));createAuthRoutes2(plugin,{authConfig:{db,logger:logger2,usersTable,sessionsTable,userRolesTable:schemaTables.userRoles,rolesTable:schemaTables.roles,roleClaimsTable:schemaTables.roleClaims,claimsTable:schemaTables.claims,authentication:{enabled:authentication.enabled,defaultRole:resolvedOptions.authentication?.defaultRole||process.env.AUTH_DEFAULT_ROLE,cookieDomain:resolvedOptions.authentication?.cookieDomain,get trustedAppOrigins(){return trustedAppOrigins()},emailExemptDomains:authentication?.emailExemptDomains,accessToken:authentication.accessToken,refreshToken:authentication.refreshToken,sessionToken:authentication.sessionToken,deviceTrust:authentication.sessions?.deviceTrust}},features:{login:authentication.login,register:authentication.register,logout:authentication.logout,refresh:authentication.refresh,passwordReset:withResolvedRedirects(authentication.passwordReset,["redirectUrl"]),passwordChange:authentication.passwordChange,passwordSet:authentication.passwordSet,sessions:withResolvedRedirects(authentication.sessions,["approvalRedirectUrl"]),magicLink:withResolvedRedirects(authentication.magicLink,["redirectUrl"]),me:authentication.me||{enabled:!0,route:"/auth/me"},invite:withResolvedRedirects(authentication.invite,["redirectUrl"]),captcha:authentication.captcha,oauth:authentication.oauth?.enabled&&envResolved.oauthProviders?{...withResolvedRedirects(authentication.oauth,["successRedirectUrl","errorRedirectUrl"]),providers:liveOAuthProviders(envResolved.oauthProviders)}:void 0,apiKeys:authentication.apiKeys?.enabled?{enabled:!0,route:authentication.apiKeys.route,keyPrefix:authentication.apiKeys.keyPrefix,maxKeysPerUser:authentication.apiKeys.maxKeysPerUser,defaultExpiresIn:authentication.apiKeys.defaultExpiresIn,allowApplicationKeys:authentication.apiKeys.allowApplicationKeys,preventApiKeyManagement:authentication.apiKeys.preventApiKeyManagement}:void 0,webauthn:authentication.webauthn},sessionsTable,oauthAccountsTable:schemaTables.oauthAccounts,oauthStateStore:(()=>{let oauthRedis=getRedisManager();if(!oauthRedis)return;let{createRedisOAuthStateStore:createRedisOAuthStateStore2}=__toCommonJS(exports_stateStore);return createRedisOAuthStateStore2(oauthRedis)})(),apiKeysTable:schemaTables.apiKeys,schemaTables,schemaRelations,tenantRegistry,getTenantRegistry:()=>tenantRegistry,databaseUrl:envResolved.databaseUrl,dbPool,admin:(()=>{let adminCfg=resolvedOptions.authentication?.admin;return{impersonate:{enabled:!0},changeUserId:{enabled:!0},createUser:adminCfg?.createUser??{enabled:!0}}})(),schemaName:targetSchemaName,getEmailService,appName:resolvedOptions.appId,webauthnService:(()=>{if(!authentication.webauthn?.enabled||!db)return null;let{WebAuthnService:WebAuthnService2}=(init_WebAuthn(),__toCommonJS(exports_WebAuthn)),{createDbWebAuthnStorage:createDbWebAuthnStorage2}=(init_dbStorage(),__toCommonJS(exports_dbStorage)),rpName=authentication.webauthn.rpName||resolvedOptions.appId||"Nucleus",rpID=authentication.webauthn.rpID||"localhost",expectedOrigins=authentication.webauthn.expectedOrigins||[`http://${rpID}`,`https://${rpID}`],challengeTtlMs=authentication.webauthn.challengeTtl?parseTimeToSeconds2(authentication.webauthn.challengeTtl)*1000:300000,storage=createDbWebAuthnStorage2({db,resolveTable:resolveTableForTenant});return new WebAuthnService2({rp:{rpName,rpID,expectedOrigins},challengeTtlMs,storage,userVerification:authentication.webauthn?.userVerification})})(),captchaService:(()=>{let redisManager=getRedisManager();if(!authentication.captcha?.enabled||!redisManager)return null;return new CaptchaService({redis:{get:async(key2)=>{let result=await redisManager.read(key2);return result.success?result.data:null},set:async(key2,value2,options)=>{await redisManager.create(key2,value2,options?.ex)},del:async(key2)=>{await redisManager.remove(key2)},incrementCounter:(key2,delta,ttlSeconds)=>redisManager.incrementCounter(key2,delta,ttlSeconds)},logger:logger2,config:{enabled:!0,type:authentication.captcha.type||"math",difficulty:authentication.captcha.difficulty||"medium",expiresIn:authentication.captcha.expiresIn||"5m",maxAttempts:authentication.captcha.maxAttempts||3,caseSensitive:authentication.captcha.caseSensitive??!1}})})(),tokenResponseConfig:{accessToken:{setHeadersEnabled:authentication.accessToken?.setHeadersEnabled??!0,returnJson:authentication.accessToken?.returnJson??!0},refreshToken:{setHeadersEnabled:authentication.refreshToken?.setHeadersEnabled??!0,returnJson:authentication.refreshToken?.returnJson??!0},sessionToken:{setHeadersEnabled:authentication.sessionToken?.setHeadersEnabled??!0,returnJson:authentication.sessionToken?.returnJson??!0}},helpers:{signAccessToken:(userId,roles,claims,tenant,claimScopes)=>{let resolveMode=resolvedOptions.authorization?.jwtClaimsMode==="resolve"&&claimsCache,hasClaimScopes=!resolveMode&&!!claimScopes&&Object.keys(claimScopes).length>0,token=signJWT2({subject:userId,expiresInSeconds:parseTimeToSeconds2(authentication.accessToken?.expiresIn||"15m"),issuer:authentication.accessToken?.issuer,audience:authentication.accessToken?.audience,customClaims:{...roles&&roles.length>0?{roles}:{},...!resolveMode&&claims&&claims.length>0?{claims}:{},...hasClaimScopes?{claimScopes}:{},...tenant?{tenant}:{}}},envResolved.accessTokenSecret||"",authentication.accessToken?.algorithm||"HS256");return warnIfAccessTokenTooLargeForCookie(token,resolveMode?"resolve":resolvedOptions.authorization?.jwtClaimsMode),token},signRefreshToken:(userId)=>signJWT2({subject:userId,expiresInSeconds:parseTimeToSeconds2(authentication.refreshToken?.expiresIn||"7d"),issuer:authentication.refreshToken?.issuer,audience:authentication.refreshToken?.audience},envResolved.refreshTokenSecret||"",authentication.refreshToken?.algorithm||"HS256"),verifyRefreshToken:(token)=>verifyJWT3(token,envResolved.refreshTokenSecret||"",{issuer:authentication.refreshToken?.issuer,audience:authentication.refreshToken?.audience}),createSession:async(params)=>{let sessionTtlSeconds=parseTimeToSeconds2(authentication.sessionToken?.expiresIn||"30d"),result=await generateSession2({userId:params.userId,deviceInfo:params.deviceInfo,rememberMe:params.rememberMe,loginMethod:params.loginMethod,expiresInSeconds:sessionTtlSeconds});if(!result.success)throw logger2.error("[createSession] failed to create session",{userId:params.userId,error:result.error}),Error(`Session storage unavailable: ${result.error||"unknown error"}`);return result.session.id},destroySession:async(sessionId)=>deleteSession2({sessionId}),saveSessionToDb:async(sessionId,params,reqSchemaName)=>{let resolvedSessionsTable=resolveTableForTenant("userSessions",reqSchemaName)||resolveTableForTenant("user_sessions",reqSchemaName)||resolveTableForTenant("sessions",reqSchemaName)||sessionsTable;if(!resolvedSessionsTable||!db)return;let sessionsConfig=authentication.sessions,deviceInfo=ensureDeviceInfo(params.deviceInfo||{ipAddress:""}),resolvedUsersTableForExempt=resolveTableForTenant("users",reqSchemaName),sessionUserEmail=null;if(resolvedUsersTableForExempt)sessionUserEmail=(await db.select().from(resolvedUsersTableForExempt).where(eq61(resolvedUsersTableForExempt.id,params.userId)).limit(1))[0]?.email??null;let userIsEmailExempt=sessionUserEmail?isEmailExempt(sessionUserEmail,authentication?.emailExemptDomains):!1,deviceFingerprint=deviceInfo.deviceHint?`${deviceInfo.browserName||""}-${deviceInfo.osName||""}-${deviceInfo.deviceType||""}-${deviceInfo.deviceHint}`:`${deviceInfo.browserName||""}-${deviceInfo.osName||""}-${deviceInfo.deviceType||""}`,existingSessions=await db.select().from(resolvedSessionsTable).where(and23(eq61(resolvedSessionsTable.userId,params.userId),eq61(resolvedSessionsTable.isActive,!0))),hasValidFingerprint=deviceFingerprint&&!deviceFingerprint.includes("--unknown")&&!deviceFingerprint.includes("Bot/Crawler")&&!deviceFingerprint.includes("Headless")&&deviceFingerprint!=="--"&&deviceFingerprint!=="--unknown",allUserSessions=await db.select().from(resolvedSessionsTable).where(eq61(resolvedSessionsTable.userId,params.userId)),isNewDevice=hasValidFingerprint?!existingSessions.some((s)=>s.deviceFingerprint===deviceFingerprint):!1,wasPreviouslyApproved=hasValidFingerprint?allUserSessions.some((s)=>{let sess=s;return sess.deviceFingerprint===deviceFingerprint&&sess.approvalStatus==="approved"}):!1,hasAnyApprovedSession=existingSessions.some((s)=>s.approvalStatus==="approved"),isImpersonationLogin=params.loginMethod==="impersonation"||params.loginMethod==="impersonation_stop",isOAuthLogin=params.loginMethod?.startsWith("oauth:"),requiresApproval=!isImpersonationLogin&&!userIsEmailExempt&&sessionsConfig?.trustNewDevices===!1&&isNewDevice&&!wasPreviouslyApproved&&hasValidFingerprint&&hasAnyApprovedSession,deviceTrustCfg=sessionsConfig?.deviceTrust,dtTable=deviceTrustCfg?.enabled?resolveTableForTenant("trustedDevices",reqSchemaName)||resolveTableForTenant("trusted_devices",reqSchemaName):void 0,deviceTrustMint=null,deviceTokenToSet=null;if(deviceTrustCfg?.enabled&&dtTable){let DT=await Promise.resolve().then(() => (init_DeviceTrust(),exports_DeviceTrust)),DTStore=await Promise.resolve().then(() => (init_store2(),exports_store)),dtNow=new Date,dtRows=params.deviceToken?await DTStore.findDeviceRowsByRawToken(db,dtTable,params.deviceToken):[],knownRow=DT.selectUsableDeviceRow(dtRows,params.userId,dtNow),pendingRow=dtRows.find((r2)=>(r2.userId??r2.user_id)===params.userId&&r2.status==="pending"),isFirstEver=allUserSessions.length===0&&await DTStore.userHasNoTrustedDevices(db,dtTable,params.userId),decision=DT.decideDeviceApproval({knownDevice:!!knownRow,trustNewDevices:sessionsConfig?.trustNewDevices??!0,hasValidFingerprint:!!hasValidFingerprint,isFirstEverDevice:isFirstEver,loginMethod:params.loginMethod,approvalMethods:deviceTrustCfg.approvalMethods??["password","magic_link","sso","webauthn","oauth:*","register"],onUnidentifiable:deviceTrustCfg.onUnidentifiable??"require_approval",isImpersonation:isImpersonationLogin,isEmailExempt:userIsEmailExempt});if(knownRow)await DTStore.touchDevice(db,dtTable,knownRow.id,deviceInfo.ipAddress).catch(()=>{});if(decision.deny)return logger2.warn("[AUTH] Device-trust denied unidentifiable device",{userId:params.userId}),{requiresApproval:!1,denied:!0};let reuseSessionId=pendingRow?.originSessionId??pendingRow?.origin_session_id;if(decision.requiresApproval&&reuseSessionId)return{requiresApproval:!0,sessionId:reuseSessionId};requiresApproval=decision.requiresApproval,deviceTrustMint=decision.mintToken?decision.trustImmediately?"trusted":"pending":null}logger2.info("[AUTH] Device fingerprint analysis",{userId:params.userId,deviceFingerprint,hasValidFingerprint,isNewDevice,wasPreviouslyApproved,loginMethod:params.loginMethod,isImpersonationLogin,isOAuthLogin,existingSessionCount:existingSessions.length,hasAnyApprovedSession,requiresApproval});let approvalToken=null,approvalStatus="approved";if(requiresApproval){let existingPending=deviceTrustCfg?.enabled?void 0:allUserSessions.find((s)=>{let sess=s;return sess.deviceFingerprint===deviceFingerprint&&(sess.approvalStatus==="pending"||sess.approval_status==="pending")&&sess.approvalToken});if(existingPending){let pendingSess=existingPending,pendingRequestedAt=pendingSess.approvalRequestedAt||pendingSess.approval_requested_at;if(pendingRequestedAt?Date.now()-new Date(pendingRequestedAt).getTime()<86400000:!0)return logger2.info("[AUTH] Reusing existing pending session for same device",{userId:params.userId,deviceFingerprint,existingSessionId:pendingSess.id}),{requiresApproval:!0,sessionId:pendingSess.id}}let{randomBytes:randomBytes7}=await import("crypto");approvalToken=randomBytes7(32).toString("hex"),approvalStatus="pending",logger2.info("[AUTH] New device requires approval",{userId:params.userId,deviceFingerprint,ipAddress:deviceInfo.ipAddress})}let staleBotSessions=existingSessions.filter((s)=>{let sess=s,fp=(sess.deviceFingerprint||"").toLowerCase(),ip=sess.ipAddress||"",ua=(sess.userAgent||"").toLowerCase(),isBotFingerprint=!fp||fp==="--"||fp==="--unknown"||fp.includes("bot/crawler")||fp.includes("headless")||fp.includes("unknown-unknown"),isServerAction=ua.includes("nucleusserveraction")||ua.includes("serveraction")||ua.includes("node-fetch")||ua.includes("undici");return isBotFingerprint&&(ip==="127.0.0.1"||ip==="::1"||ip==="localhost"||!ip)||isServerAction});if(staleBotSessions.length>0){for(let botSession of staleBotSessions)await db.update(resolvedSessionsTable).set({isActive:!1,revokedAt:new Date,revokedReason:"bot_session_cleanup"}).where(eq61(resolvedSessionsTable.id,botSession.id));logger2.info("[AUTH] Cleaned up stale bot/crawler sessions",{userId:params.userId,cleanedCount:staleBotSessions.length})}if(hasValidFingerprint&&!requiresApproval){let sameDeviceOldSessions=existingSessions.filter((s)=>s.deviceFingerprint===deviceFingerprint);for(let oldSession of sameDeviceOldSessions)await db.update(resolvedSessionsTable).set({isActive:!1,revokedAt:new Date,revokedReason:"same_device_relogin"}).where(eq61(resolvedSessionsTable.id,oldSession.id));if(sameDeviceOldSessions.length>0)logger2.info("[AUTH] Revoked old same-device sessions",{userId:params.userId,deviceFingerprint,revokedCount:sameDeviceOldSessions.length})}if(!sessionsConfig?.allowMultipleDevices&&existingSessions.length>0){if((hasValidFingerprint?existingSessions.filter((s)=>s.deviceFingerprint===deviceFingerprint):[]).length===0)for(let oldSession of existingSessions)await db.update(resolvedSessionsTable).set({isActive:!1,revokedAt:new Date,revokedReason:"new_device_login"}).where(eq61(resolvedSessionsTable.id,oldSession.id))}if(sessionsConfig?.maxActiveSessions){let{count:count3}=await import("drizzle-orm"),currentCount=(await db.select({count:count3()}).from(resolvedSessionsTable).where(and23(eq61(resolvedSessionsTable.userId,params.userId),eq61(resolvedSessionsTable.isActive,!0))))[0]?.count||0;if(currentCount>=sessionsConfig.maxActiveSessions){let{asc:asc2}=await import("drizzle-orm"),oldestSessions=await db.select().from(resolvedSessionsTable).where(and23(eq61(resolvedSessionsTable.userId,params.userId),eq61(resolvedSessionsTable.isActive,!0))).orderBy(asc2(resolvedSessionsTable.createdAt)).limit(currentCount-sessionsConfig.maxActiveSessions+1);for(let oldSession of oldestSessions)await db.update(resolvedSessionsTable).set({isActive:!1,revokedAt:new Date,revokedReason:"max_sessions_exceeded"}).where(eq61(resolvedSessionsTable.id,oldSession.id))}}let trustScore=100;if(deviceInfo.isHeadless)trustScore-=50;if(deviceInfo.isBot)trustScore-=40;if(deviceInfo.isSuspicious)logger2.warn("[AUTH] Suspicious login detected",{userId:params.userId,suspiciousPatterns:deviceInfo.suspiciousPatterns,userAgent:deviceInfo.userAgent,ipAddress:deviceInfo.ipAddress});if(isNewDevice)trustScore-=25;if(!deviceInfo.ipAddress||deviceInfo.ipAddress==="unknown")trustScore-=20;if(!deviceInfo.browserName)trustScore-=15;if(!deviceInfo.osName)trustScore-=15;if(!deviceInfo.deviceType||deviceInfo.deviceType==="unknown")trustScore-=10;if(!deviceInfo.deviceName||deviceInfo.deviceName==="Unknown Device")trustScore-=5;let validFingerprint=deviceFingerprint&&!deviceFingerprint.includes("--unknown")&&deviceFingerprint!=="--",validIp=deviceInfo.ipAddress&&deviceInfo.ipAddress!=="unknown";if(validFingerprint){if(existingSessions.filter((s)=>s.deviceFingerprint===deviceFingerprint).length>0)trustScore+=20}if(validIp){if(existingSessions.filter((s)=>s.ipAddress===deviceInfo.ipAddress).length>0)trustScore+=15}trustScore=Math.max(0,Math.min(100,trustScore));let LOW_TRUST_THRESHOLD=50;if(await db.insert(resolvedSessionsTable).values({id:sessionId,userId:params.userId,tokenHash:sessionId,deviceFingerprint,deviceName:deviceInfo.deviceName,deviceType:deviceInfo.deviceType,browserName:deviceInfo.browserName,browserVersion:deviceInfo.browserVersion,osName:deviceInfo.osName,osVersion:deviceInfo.osVersion,ipAddress:deviceInfo.ipAddress,locationCountry:deviceInfo.locationCountry,locationCity:deviceInfo.locationCity,loginMethod:params.loginMethod||"password",rememberMe:params.rememberMe??!1,trustScore,lastActivityAt:new Date,createdAt:new Date,expiresAt:new Date(Date.now()+parseTimeToSeconds2(authentication.sessionToken?.expiresIn||"30d")*1000),isActive:approvalStatus==="approved",approvalStatus,approvalToken,approvalRequestedAt:requiresApproval?new Date:null}),!isImpersonationLogin&&getEmailService()&&(sessionsConfig?.notifyOnNewDevice&&isNewDevice||trustScore<LOW_TRUST_THRESHOLD||requiresApproval)){let resolvedUsersTable=resolveTableForTenant("users",reqSchemaName);if(resolvedUsersTable){let user=(await db.select().from(resolvedUsersTable).where(eq61(resolvedUsersTable.id,params.userId)).limit(1))[0];if(user?.email&&!isEmailExempt(user.email,authentication?.emailExemptDomains)){let isLowTrust=trustScore<LOW_TRUST_THRESHOLD,sessionsRoute=authentication.sessions?.route||"/auth/sessions",configuredUrl=authentication.sessions?.approvalRedirectUrl||"",isLegacyFrontendUrl=!configuredUrl||configuredUrl.endsWith("/devices"),approvalBase;if(!isLegacyFrontendUrl)approvalBase=configuredUrl;else{let origin=pickTrustedOrigin(params.requestOrigin,configuredUrl,trustedAppOrigins());if(params.requestOrigin&&origin!==params.requestOrigin)logger2.warn("[AUTH] Device-approval link origin refused \u2014 not in trustedAppOrigins",{requested:params.requestOrigin,used:origin||"(none)"});approvalBase=`${origin||"http://localhost:9000"}${sessionsRoute}`}let approveUrl=approvalToken?`${approvalBase}/approve-page?token=${approvalToken}`:"",rejectUrl=approvalToken?`${approvalBase}/reject-page?token=${approvalToken}`:"",subject,emailHtml,brandName=resolvedOptions.appId||"Nucleus",loginTime=new Date().toLocaleString("en-US",{dateStyle:"medium",timeStyle:"short"}),deviceSummary=`${deviceInfo.browserName||"Unknown"} ${deviceInfo.browserVersion||""} on ${deviceInfo.osName||"Unknown"} ${deviceInfo.osVersion||""}`,emailWrapper=(content)=>`
|
|
1975
|
+
${detail}`)}let sensitiveNames=resolvedForBoot.flatMap((e)=>e.columns??[]).filter((c)=>c.sensitive===!0).map((c)=>c.name);{registerSensitiveColumns(sensitiveNames);let redactUnion=[...loggingConfig?.redactKeys||[],...sensitiveColumnNames()];if(logger2.configure({redactKeys:redactUnion}),Logger.getInstance().configure({redactKeys:redactUnion}),sensitiveNames.length>0)logger2.info("[Schema] Sensitive columns registered",{columns:sensitiveNames})}}let requestLogConfig={enabled:loggingConfig?.requests?.enabled!==!1,logArrival:loggingConfig?.requests?.logArrival===!0,includeQuery:loggingConfig?.requests?.includeQuery!==!1,slowThresholdMs:loggingConfig?.requests?.slowThresholdMs??3000,excludePaths:loggingConfig?.requests?.excludePaths??["/health"]},isRequestLogExcluded=(pathname)=>requestLogConfig.excludePaths.some((p)=>p.endsWith("*")?pathname.startsWith(p.slice(0,-1)):pathname===p),envValidation=validateEnvVariables(resolvedOptions);if(!envValidation.valid){for(let error3 of envValidation.errors)logger2.error(`[CONFIG] ${error3.message}`,{field:error3.field,envName:error3.envName});throw Error("Nucleus configuration error: Missing required environment variables. Check logs for details.")}let{resolved:envResolved}=envValidation;{let secretEntries=[["accessToken",envResolved.accessTokenSecret],["refreshToken",envResolved.refreshTokenSecret],["sessionToken",envResolved.sessionTokenSecret]];for(let[name2,value2]of secretEntries)if(value2&&value2.length<32)logger2.warn(`[Security] authentication.${name2}.secret is only ${value2.length} chars \u2014 use at least ${"32"} random bytes.`);let present=secretEntries.map(([,v])=>v).filter((v)=>!!v);if(present.length>1&&new Set(present).size<present.length)logger2.warn("[Security] Two or more of the access/refresh/session token secrets are identical \u2014 use a distinct secret for each.")}let tokenNames={access_token:authentication?.accessToken?.name||"access_token",refresh_token:authentication?.refreshToken?.name||"refresh_token",session_token:authentication?.sessionToken?.name||"session_token"},csrfConfig=resolveCsrfConfig(authentication?.csrf),csrfAuthCookieNames=[tokenNames.session_token,tokenNames.access_token],targetSchemaName=database?.sharedSchema||database?.schemas?.[0]||"main",targetSchema=pgSchema2(targetSchemaName);if(envResolved.databaseUrl)await ensureDatabaseExists(envResolved.databaseUrl,logger2,envResolved.databaseAuthMode);let db=null,dbPool=null,dbAuthMode=envResolved.databaseAuthMode||"password",backgroundIntervals=[],trackInterval=(timer)=>{timer.unref?.(),backgroundIntervals.push(timer)};if(envResolved.databaseUrl){let{Pool:Pool2}=await import("pg"),poolOptions=resolveDbPoolConfig(database?.pool);if(dbAuthMode==="password")dbPool=new Pool2({connectionString:envResolved.databaseUrl,...poolOptions});else{let{getPostgresToken:getPostgresToken2}=await Promise.resolve().then(() => (init_Azure(),exports_Azure));await getPostgresToken2(),dbPool=new Pool2({connectionString:envResolved.databaseUrl,password:getPostgresToken2,ssl:{rejectUnauthorized:!0},...poolOptions}),logger2.info(`[Database] Using Entra ID auth mode: ${dbAuthMode}`)}db=drizzle2(dbPool),dbPool.on("error",(err)=>{logger2.warn("[Database] idle pool client error",{error:err instanceof Error?err.message:String(err)})})}let isMultiTenant=database?.isMultiTenant===!0,tenantRegistry=null,schemaTables={},schemaRelations={},claimsCache=null;if(config.schema){let schemasPath=__require("path").resolve(process.cwd(),config.schema),schemas=__require(schemasPath);schemaTables=schemas.createAllTablesForSchema?schemas.createAllTablesForSchema(targetSchema):{}}if(config.relations){let relationsPath=__require("path").resolve(process.cwd(),config.relations);schemaRelations=__require(relationsPath)}let secretsService=null;if(resolvedOptions.secrets?.enabled){let masterKey=resolveMasterKey(resolvedOptions.secrets.encryptionKey);if(!db)logger2.warn("[Secrets] secrets.enabled=true but no database is configured \u2014 disabled");else if(!masterKey)logger2.error("[Secrets] secrets.enabled=true but no encryption key resolved \u2014 set secrets.encryptionKey or NUCLEUS_SECRETS_KEY. Credential storage is disabled; env and literal values still work.");else if(!schemaTables[SECRETS_TABLE])logger2.error(`[Secrets] secrets.enabled=true but the "${SECRETS_TABLE}" table is missing from the generated schema \u2014 re-run schema generation. Credential storage is disabled.`);else{secretsService=new SecretsService({store:new SecretsStore({db,resolveTable:(tableName)=>schemaTables[tableName],masterKey}),logger:logger2,refreshIntervalMs:resolvedOptions.secrets.refreshIntervalMs,getRedis:()=>getRedisManager()}),logger2.info("[Secrets] Credential store enabled");try{if(await secretsService.refresh(),secretsService.isReady())logger2.info("[Secrets] Credentials preloaded for boot-time resolution",{storedCredentials:secretsService.size()})}catch(error3){logger2.warn("[Secrets] Preload failed \u2014 env and literal values still resolve",{error:error3 instanceof Error?error3.message:String(error3)})}}}let resolveCredential=(scope,key2,configValue)=>{if(secretsService)return secretsService.value(scope,key2,configValue);if(!configValue)return;let fromEnv=process.env[configValue];if(fromEnv)return fromEnv;return/^[A-Z][A-Z0-9_]{2,}$/.test(configValue)?void 0:configValue},resolveRedirectUrl=(value2)=>{if(!value2)return;let fromEnv=process.env[value2];if(fromEnv)return fromEnv;return/^[A-Z][A-Z0-9_]{2,}$/.test(value2)?void 0:value2},withResolvedRedirects=(node,keys)=>{if(!node)return node;let resolved={...node};for(let key2 of keys)if(typeof node[key2]==="string")resolved[key2]=resolveRedirectUrl(node[key2]);return resolved},trustedAppOrigins=()=>{let configured=normalizeTrustedOrigins(resolvedOptions.authentication?.trustedAppOrigins);if(!secretsService)return configured;let resolved=secretsService.listValue("authentication","trustedAppOrigins",configured);return resolved.length>0?resolved:configured},liveOAuthProviders=(resolvedProviders)=>{if(!secretsService)return resolvedProviders;let declared=resolvedOptions.authentication?.oauth?.providers??{},live={};for(let[providerName,providerConfig]of Object.entries(resolvedProviders)){let declaredConfig=declared[providerName]??{},entry={...providerConfig};for(let key2 of["clientId","clientSecret","tenantId","redirectUri"]){let declaredValue=declaredConfig[key2],bootValue=providerConfig[key2];Object.defineProperty(entry,key2,{get:()=>{let resolved=secretsService?.value(`authentication.oauth.providers.${providerName}`,key2,typeof declaredValue==="string"?declaredValue:void 0);if(resolved!==void 0)return resolved;return looksLikeEnvName(typeof bootValue==="string"?bootValue:void 0)?void 0:bootValue},enumerable:!0,configurable:!0})}live[providerName]=entry}return live},storageProvider=null;if(resolvedOptions.storage?.enabled){let storageBase=resolvedOptions.storage.basePath||"./uploads";storageProvider=createStorageProvider({provider:resolvedOptions.storage.provider,basePath:storageBase,smb:resolvedOptions.storage.smb,resolveCredential},{logger:logger2}),setStorageProvider(storageProvider)}let buildStorageProvider=(kind)=>{if(!resolvedOptions.storage?.enabled)return null;return createStorageProvider({provider:kind,basePath:resolvedOptions.storage.basePath||"./uploads",smb:resolvedOptions.storage.smb,resolveCredential:(scope,key2,configValue)=>scope==="storage"&&key2==="provider"?kind:resolveCredential(scope,key2,configValue)},{logger:logger2})},swaggerPlugin=createSwaggerPlugin(config.swagger);if(swaggerPlugin)plugin.use(swaggerPlugin);let systemTables2=config.systemTables||[];publicRoutes=buildPublicRoutes(resolvedOptions,systemTables2,"",targetSchemaName),logger2.info(`[AUTH] Built ${publicRoutes.length} public routes`);let rateLimiter=null,monitoringService=null,liveMonitoringService=null,activeEmailProvider=()=>{let declared=resolveCredential("email","provider",resolvedOptions.email?.provider);if(declared==="azure"||declared==="gmail")return emailProviderOn(declared)||resolvedOptions.email?.provider===declared?declared:null;if(emailProviderOn("azure"))return"azure";if(emailProviderOn("gmail"))return"gmail";return null},emailProviderOn=(provider)=>{let configured=resolvedOptions.email?.[provider]?.enabled===!0;return secretsService?secretsService.flag(`email.${provider}`,"enabled",configured):configured},azureEmailCredentials=()=>{let azureConfig=resolvedOptions.email?.azure;return{enabled:!0,connectionString:resolveCredential("email.azure","connection_string",azureConfig?.connection_string)??"",senderAddress:resolveCredential("email.azure","sender_address",azureConfig?.sender_address)??"",fromName:azureConfig?.from_name}},gmailCredentials=()=>{let gmailConfig=resolvedOptions.email?.gmail;return{enabled:!0,jsonFilePath:gmailConfig?.json_file_path,serviceAccountJson:resolveCredential("email.gmail","service_account_json",gmailConfig?.service_account_json),fromEmail:resolveCredential("email.gmail","from_email",gmailConfig?.from_email)??"",fromName:gmailConfig?.from_name}},azureService=null,gmailService=null,getEmailService=()=>{let provider=activeEmailProvider();if(!provider)return null;if(provider==="azure"){if(!azureService)azureService=new AzureEmailService(azureEmailCredentials(),logger2),logger2.info("[AzureEmailService] Initialized",{available:azureService.isAvailable()});else azureService.reconfigure(azureEmailCredentials());return azureService}if(!gmailService)gmailService=new GmailService(gmailCredentials(),logger2),logger2.info("[GmailService] Initialized",{available:gmailService.isAvailable()});else gmailService.reconfigure(gmailCredentials());return gmailService};if(plugin.decorate("nucleus",createNucleusRuntime({getEmailService,activeEmailProvider})),resolvedOptions.liveMonitoring?.enabled){let liveBasePath=resolvedOptions.liveMonitoring.basePath||"/monitoring",liveStreamInterval=resolvedOptions.liveMonitoring.streamInterval||150;plugin.use(createLiveMonitoringRoutes({getService:()=>liveMonitoringService,logger:logger2,basePath:liveBasePath,streamInterval:liveStreamInterval,db,schemaTables}))}let bootStep=async(name2,run)=>{try{return await run()}catch(error3){logger2.error(`[Boot] Step "${name2}" failed \u2014 continuing in a degraded state rather than crashing`,{error:error3 instanceof Error?error3.message:String(error3)});return}};plugin.onStart(async()=>{await bootStep("redis",()=>initiateRedisManager(resolvedOptions));let redis=getRedisManager();if(redis&&resolvedOptions.configManagement?.enabled)try{let{loadOverridesFromRedis:loadOverridesFromRedis2}=await Promise.resolve().then(() => (init_helpers3(),exports_helpers)),applied=await loadOverridesFromRedis2({read:async(key2)=>{let r2=await redis.read(key2);return{success:r2.success,data:r2.success?r2.data:null}}},resolvedOptions.appId||"nucleus",resolvedOptions);if(applied.length>0)logger2.info(`[ConfigManagement] Loaded ${applied.length} override(s) from Redis`,{sections:applied})}catch(err){logger2.warn("[ConfigManagement] Failed to load overrides from Redis",{error:err instanceof Error?err.message:String(err)})}if(redis&&resolvedOptions.rateLimit?.enabled!==!1)rateLimiter=new RateLimiter({redis,logger:logger2,config:resolvedOptions.rateLimit||{}}),logger2.info(`[RateLimit] Enabled with strategy: ${resolvedOptions.rateLimit?.strategy||"sliding-window"}`);{let channels=resolvedOptions.notification?.channels;if(channels?.telegram?.enabled&&(!channels.telegram.botToken||!channels.telegram.chatId))logger2.warn("[Notification] telegram channel is enabled but botToken/chatId is missing \u2014 telegram deliveries will be skipped");if(channels?.webhook?.enabled&&!channels.webhook.url)logger2.warn("[Notification] webhook channel is enabled but url is missing \u2014 webhook deliveries will be skipped")}if(redis&&resolvedOptions.monitoring?.enabled){let monitoringDb=db,monitoringMetricsTable=schemaTables.monitoringMetrics,monitoringPersistenceEnabled=resolvedOptions.monitoring.persistence?.enabled!==!1,monitoringRetentionDays=resolvedOptions.monitoring.persistence?.retentionDays??30,lastMetricsCleanupAt=0,monitoringDbQuery=monitoringDb?async(sqlText)=>{return(await monitoringDb.execute(sql12.raw(sqlText))).rows}:void 0;if(monitoringPersistenceEnabled&&monitoringDb&&!monitoringMetricsTable)logger2.warn("[Monitoring] monitoring.persistence is enabled but the monitoring_metrics table is missing from the generated schema \u2014 re-run nucleus-generate to add it");let monitoringFlushToDb=monitoringDb&&monitoringPersistenceEnabled&&monitoringMetricsTable?async(metrics)=>{if(metrics.length===0)return;let metricsTable=monitoringMetricsTable;await monitoringDb.insert(metricsTable).values(metrics.map((m2)=>({metricType:m2.metricType,metricName:m2.metricName,value:m2.value,tags:m2.tags??null,recordedAt:new Date(m2.timestamp)})));let nowMs=Date.now();if(nowMs-lastMetricsCleanupAt>86400000){lastMetricsCleanupAt=nowMs;let cutoff=new Date(nowMs-monitoringRetentionDays*24*60*60*1000);await monitoringDb.delete(metricsTable).where(lt3(metricsTable.recordedAt,cutoff))}}:void 0;if(monitoringService=new MonitoringService({redis,logger:logger2,getEmailService,config:resolvedOptions.monitoring,appId:resolvedOptions.appId,dbQuery:monitoringDbQuery,flushToDb:monitoringFlushToDb}),monitoringService.start(),logger2.info("[Monitoring] Service started"),resolvedOptions.monitoring.endpoints?.enabled){let monitoringEndpoints={enabled:!0,basePath:resolvedOptions.monitoring.endpoints.basePath||"/monitoring",stream:{enabled:resolvedOptions.monitoring.endpoints.stream?.enabled!==!1,path:resolvedOptions.monitoring.endpoints.stream?.path||"/stream",interval:resolvedOptions.monitoring.endpoints.stream?.interval||"5s"},snapshot:{enabled:resolvedOptions.monitoring.endpoints.snapshot?.enabled!==!1,path:resolvedOptions.monitoring.endpoints.snapshot?.path||"/snapshot"},history:{enabled:resolvedOptions.monitoring.endpoints.history?.enabled!==!1,path:resolvedOptions.monitoring.endpoints.history?.path||"/history",maxMinutes:resolvedOptions.monitoring.endpoints.history?.maxMinutes||60},alerts:{enabled:resolvedOptions.monitoring.endpoints.alerts?.enabled!==!1,path:resolvedOptions.monitoring.endpoints.alerts?.path||"/alerts"}};plugin.use(createMonitoringRoutes({monitoringService,logger:logger2,endpoints:monitoringEndpoints,db,schemaTables}))}}if(resolvedOptions.liveMonitoring?.enabled)liveMonitoringService=new LiveMonitoringService(resolvedOptions.liveMonitoring),liveMonitoringService.start(),logger2.info("[LiveMonitoring] Service started");let isConsumerModeOnStart=authentication?.mode==="consumer",consumerAllowedTableKeys=isConsumerModeOnStart&&entities?new Set(entities.map((e)=>e.table_name.replace(/_([a-z])/g,(_,c)=>c.toUpperCase()))):null;if(consumerAllowedTableKeys){let opts=resolvedOptions,verificationEnabled=opts.verification?.enabled===!0,notificationEnabled=opts.notification?.enabled===!0,auditEnabled=opts.audit?.enabled===!0,chatEnabled=opts.chat?.enabled===!0,storageEnabled=opts.storage?.enabled===!0,paymentEnabled=opts.payment?.enabled===!0,backupEnabled=opts.backup?.enabled===!0,monitoringPersistenceOn=resolvedOptions.monitoring?.enabled===!0&&resolvedOptions.monitoring?.persistence?.enabled!==!1,featureEnabled={verification:verificationEnabled,notification:notificationEnabled,audit:auditEnabled,chat:chatEnabled,storage:storageEnabled,payment:paymentEnabled,backup:backupEnabled,monitoring:monitoringPersistenceOn,secrets:resolvedOptions.secrets?.enabled===!0,domains:resolvedOptions.domains?.enabled===!0,"multi-tenant":isMultiTenant};for(let sysTable of SYSTEM_TABLES)if(sysTable.feature_set.some((f)=>{if(f==="authentication"||f==="authorization")return!1;if(!(f in featureEnabled))return logger2.warn(`[Schema] Consumer mode has no rule for feature "${f}" (table "${sysTable.table_name}") \u2014 `+"its table will NOT be synced. Add it to featureEnabled in ElysiaPlugin/index.ts."),!1;return featureEnabled[f]===!0})){let camelKey=sysTable.table_name.replace(/_([a-z])/g,(_,c)=>c.toUpperCase());consumerAllowedTableKeys.add(camelKey)}}if(db&&config.schema){let schemas=await import(__require("path").resolve(process.cwd(),config.schema)),auditLogsTable=schemaTables.auditLogs||schemas.auditLogs;if(audit?.enabled&&auditLogsTable)logger2.addAuditTransport(new DatabaseAuditTransport({db,table:auditLogsTable,enabled:!0,dedup:audit.dedup}));let{ensureSchemaExists:ensureSchemaExists2,applySchemaPush:applySchemaPush2}=await Promise.resolve().then(() => (init_schema(),exports_schema));try{logger2.info(`Syncing schema to database (target: ${targetSchemaName})...`),await ensureSchemaExists2(db,targetSchemaName);try{let filteredTables=Object.fromEntries(Object.entries(schemaTables).filter(([key2,v])=>{if(v===void 0||v===null)return!1;if(consumerAllowedTableKeys&&!consumerAllowedTableKeys.has(key2))return!1;if(typeof v==="object"&&v!==null)return Object.getOwnPropertySymbols(v).length>0||v._!==void 0;return!1})),tableNames=Object.keys(filteredTables);if(logger2.info("[Schema] Tables to sync:",{tables:tableNames,count:tableNames.length,mode:isConsumerModeOnStart?"consumer":"full"}),!isConsumerModeOnStart){let usersTableDef=filteredTables.users;if(usersTableDef){let columnSymbols=Object.getOwnPropertyNames(usersTableDef).filter((k)=>!k.startsWith("_"));logger2.info("[Schema] Users table columns:",{columns:columnSymbols})}}let realExit=process.exit,push;try{process.exit=(code)=>{throw Error(`drizzle-kit called process.exit(${code??0}) during pushSchema \u2014 `+"suppressed so the app can keep booting")};let timeoutMs=database?.schemaPushTimeoutMs??120000;push=await withDeadline(pushSchema({schema:targetSchema,...filteredTables},db,[targetSchemaName]),timeoutMs,`pushSchema did not finish within ${timeoutMs}ms. drizzle-kit most likely hit its `+"interactive rename prompt, which cannot be answered without a TTY \u2014 it appears "+"when a push adds a new table while another table exists in the database but not in the schema. Drop the stale table, or split the change across two deploys.")}finally{process.exit=realExit}if(await applySchemaPush2(push,{schemaName:targetSchemaName,allowDataLoss:database?.allowDataLoss===!0,logger:logger2,execute:(statement)=>db.execute(sql12.raw(statement))}))logger2.info("[Schema] pushSchema completed successfully")}catch(pushError){let msg=pushError instanceof Error?pushError.message:String(pushError);logger2.warn(`[Schema] pushSchema warning: ${msg}`)}logger2.info("[Schema] Schema sync completed",{schema:targetSchemaName})}catch(error3){logger2.error("[Schema] Schema sync failed",error3,{schema:targetSchemaName})}if(secretsService)try{await secretsService.start(),logger2.info("[Secrets] Credential store ready",{storedCredentials:secretsService.size()})}catch(error3){logger2.error("[Secrets] Credential store failed to start \u2014 env and literal values still resolve",{error:error3 instanceof Error?error3.message:String(error3)})}if(logger2.info("[Database] Connection established"),await bootStep("multi-tenant schemas",async()=>{if(isMultiTenant&&db&&config.schema){let schemasForTenant={};try{let schemaPath=__require("path").resolve(process.cwd(),config.schema);logger2.info("[MultiTenant] Loading schema for tenant registry",{schemaPath}),schemasForTenant=await import(schemaPath),logger2.info("[MultiTenant] Schema loaded",{keys:Object.keys(schemasForTenant).slice(0,10),hasCreateAll:!!schemasForTenant.createAllTablesForSchema})}catch(err){let msg=err instanceof Error?err.message:String(err);logger2.error("[MultiTenant] Failed to load schema for tenant registry",{error:msg})}let createAllFn=schemasForTenant.createAllTablesForSchema;if(createAllFn){let idpUrl=isConsumerModeOnStart?authentication?.idpUrl?String(process.env[authentication.idpUrl]||authentication.idpUrl):void 0:void 0;if(tenantRegistry=new TenantRegistry({db,logger:logger2,mainSchemaName:targetSchemaName,mainSchemaTables:schemaTables,mainSchemaRelations:schemaRelations,createAllTablesForSchema:createAllFn,createAllRelationsForSchema:schemasForTenant.createAllRelationsForSchema,appId:resolvedOptions.appId,authMode:authentication?.mode,tenantResolution:database?.tenantResolution||"both",tenantHeader:database?.tenantHeader||"x-tenant-id",redisCacheTtlSeconds:300,defaultTrustedSources:database?.defaultTrustedSources,idpUrl,allowDataLoss:database?.allowDataLoss===!0,onTenantProvisioned:resolvedOptions.authorization?.enabled&&!isConsumerModeOnStart?async(context)=>{let authConfig={...DEFAULT_AUTHORIZATION_CONFIG,...resolvedOptions.authorization};if(authConfig.autoSeedClaims&&db){let claimEntities=mergeEntitiesByName([...extractSchemaTableEntities(context.schemaTables),...SYSTEM_TABLES.map((table)=>normalizeSystemTable(table)),...effectiveConfigEntities(resolvedOptions.entities||[]),...config.systemTables||[],...resolvedOptions.authorization?.externalEntities||[]]);await seedClaims(db,context.schemaTables,context.schemaRelations,claimEntities,authConfig,logger2)}let seedConfig=resolvedOptions.authorization?.seed;if(seedConfig&&db){let{runSeed:runSeed2}=await Promise.resolve().then(() => (init_SeedRunner(),exports_SeedRunner));await runSeed2(db,context.schemaTables,seedConfig,logger2)}logger2.info(`[Authorization] New tenant schema seeded: ${context.schemaName}`)}:void 0}),isConsumerModeOnStart&&idpUrl){await tenantRegistry.initializeFromIdp(),logger2.info("[MultiTenant] Consumer mode: tenants fetched from IDP");let tenantSyncTimer=setInterval(()=>{tenantRegistry?.syncFromIdp().then((result)=>{if(result.added.length>0||result.removed.length>0)logger2.info(`[MultiTenant] Tenant sync: +${result.added.length} / -${result.removed.length} (total ${result.total})`)}).catch((err)=>{let msg=err instanceof Error?err.message:String(err);logger2.warn(`[MultiTenant] Tenant sync failed: ${msg}`)})},60000);trackInterval(tenantSyncTimer)}else await tenantRegistry.initialize();for(let schemaName of tenantRegistry.getAllSchemaNames()){if(schemaName===targetSchemaName)continue;let ctx=tenantRegistry.getSchemaContext(schemaName);if(ctx){await ensureSchemaExists2(db,schemaName);try{let tenantFilteredTables=Object.fromEntries(Object.entries(ctx.schemaTables).filter(([key2,v])=>{if(v===void 0||v===null)return!1;if(consumerAllowedTableKeys&&!consumerAllowedTableKeys.has(key2))return!1;if(typeof v==="object"&&v!==null)return Object.getOwnPropertySymbols(v).length>0||v._!==void 0;return!1})),tenantSchema=pgSchema2(schemaName),tenantPush=await pushSchema({schema:tenantSchema,...tenantFilteredTables},db,[schemaName]);if(await applySchemaPush2(tenantPush,{schemaName,allowDataLoss:database?.allowDataLoss===!0,logger:logger2,execute:(statement)=>db.execute(sql12.raw(statement))}))logger2.info(`[Schema] Tenant schema synced: ${schemaName}`)}catch(tenantPushError){let msg=tenantPushError instanceof Error?tenantPushError.message:String(tenantPushError);logger2.warn(`[Schema] Tenant schema sync warning for ${schemaName}: ${msg}`)}}}logger2.info(`[MultiTenant] Registry initialized with ${tenantRegistry.getAllSchemaNames().length} schemas`),logger2.info("[MultiTenant] Tenant registry ready, routes were pre-registered")}}}),resolvedOptions.authorization?.enabled&&!isConsumerModeOnStart){let authConfig={...DEFAULT_AUTHORIZATION_CONFIG,...resolvedOptions.authorization,godminEmail:resolveConfigCredential(resolvedOptions.authorization?.godminEmail),godminPassword:resolveConfigCredential(resolvedOptions.authorization?.godminPassword)};if(authConfig.autoSeedClaims){let schemaEntities=extractSchemaTableEntities(schemaTables),systemEntities=SYSTEM_TABLES.map((table)=>normalizeSystemTable(table)),configEntities=effectiveConfigEntities(resolvedOptions.entities||[]),externalEntities=resolvedOptions.authorization?.externalEntities||[],claimEntities=mergeEntitiesByName([...schemaEntities,...configEntities,...systemEntities,...config.systemTables||[],...externalEntities]);logger2.info("[Authorization] Seeding claims...",{schemaEntities:schemaEntities.length,systemEntities:systemEntities.length,configEntities:configEntities.length,externalEntities:externalEntities.length,totalEntities:claimEntities.length}),await seedClaims(db,schemaTables,schemaRelations,claimEntities,authConfig,logger2)}let discoveryConfig=resolvedOptions.authorization?.endpointDiscovery;if(discoveryConfig?.enabled&&(discoveryConfig.runOnBoot??!0)&&db)try{let{runEndpointDiscovery:runEndpointDiscovery2}=await Promise.resolve().then(() => (init_seed(),exports_seed)),discoveryResult=await runEndpointDiscovery2(db,schemaTables,discoveryConfig,logger2);logger2.info("[Authorization] Endpoint discovery completed",{services:discoveryResult.services})}catch(discoveryErr){logger2.error("[Authorization] Endpoint discovery failed",{error:discoveryErr instanceof Error?discoveryErr.message:String(discoveryErr)})}if(authConfig.godminEmail&&authConfig.godminPassword)logger2.info("[Authorization] Setting up godmin..."),await setupGodmin(db,schemaTables,authConfig,logger2);let seedConfig=resolvedOptions.authorization?.seed;if(seedConfig){let{runSeed:runSeed2}=await Promise.resolve().then(() => (init_SeedRunner(),exports_SeedRunner));logger2.info("[Authorization] Running custom seed...");let seedResult=await bootStep("authorization.seed",()=>runSeed2(db,schemaTables,seedConfig,logger2));if(seedResult)logger2.info("[Authorization] Custom seed completed",{rolesCreated:seedResult.rolesCreated,rolesExisting:seedResult.rolesExisting,claimsCreated:seedResult.claimsCreated,claimsExisting:seedResult.claimsExisting,assignmentsCreated:seedResult.assignmentsCreated,assignmentsExisting:seedResult.assignmentsExisting,assignmentsUpdated:seedResult.assignmentsUpdated})}let claimGuardsCfg=resolvedOptions.authorization?.claimGuards;if(claimGuardsCfg?.length){let{seedClaimGuards:seedClaimGuards2}=await Promise.resolve().then(() => (init_ClaimGuard(),exports_ClaimGuard));await bootStep("authorization.claimGuards",()=>seedClaimGuards2(db,schemaTables,claimGuardsCfg,logger2))}let jwtClaimsMode=resolvedOptions.authorization?.jwtClaimsMode||"embed",claimsCacheRedis=getRedisManager();if(jwtClaimsMode==="resolve"&&db&&claimsCacheRedis){let{ClaimsCache:ClaimsCache3}=await Promise.resolve().then(() => (init_ClaimsCache(),exports_ClaimsCache));claimsCache=new ClaimsCache3({prefix:resolvedOptions.authorization?.claimsCachePrefix||"nucleus:claims",redis:{get:async(key2)=>{let r2=await claimsCacheRedis.read(key2);return r2.success?r2.data:null},set:async(key2,value2)=>{await claimsCacheRedis.create(key2,value2)},delete:async(key2)=>{await claimsCacheRedis.remove(key2)}},db,schemaTables,logger:logger2});let cacheInstance=claimsCache,cacheResult=await bootStep("authorization.claimsCache",()=>cacheInstance.buildCache());if(cacheResult)logger2.info("[Authorization] Claims cache built (resolve mode)",{version:cacheResult.version,roleCount:cacheResult.roleCount,totalMappings:cacheResult.totalMappings})}else if(jwtClaimsMode==="resolve"&&!claimsCacheRedis)logger2.warn("[Authorization] jwtClaimsMode=resolve requires Redis. Falling back to embed mode.");if(logger2.info("[Authorization] Enabled"),isMultiTenant&&tenantRegistry){let tenantSchemas=tenantRegistry.getAllSchemaNames().filter((name2)=>name2!==targetSchemaName);for(let tenantSchemaName of tenantSchemas){let tenantCtx=tenantRegistry.getSchemaContext(tenantSchemaName);if(!tenantCtx)continue;try{if(authConfig.autoSeedClaims){let tenantSchemaEntities=extractSchemaTableEntities(tenantCtx.schemaTables),tenantClaimEntities=mergeEntitiesByName([...tenantSchemaEntities,...SYSTEM_TABLES.map((table)=>normalizeSystemTable(table)),...effectiveConfigEntities(resolvedOptions.entities||[]),...config.systemTables||[],...resolvedOptions.authorization?.externalEntities||[]]);await seedClaims(db,tenantCtx.schemaTables,tenantCtx.schemaRelations,tenantClaimEntities,authConfig,logger2)}if(tenantCtx.tenant?.godAdminEmail&&authConfig.godminPassword)await setupGodmin(db,tenantCtx.schemaTables,{...authConfig,godminEmail:tenantCtx.tenant.godAdminEmail},logger2);if(seedConfig){let{runSeed:runSeed2}=await Promise.resolve().then(() => (init_SeedRunner(),exports_SeedRunner));await runSeed2(db,tenantCtx.schemaTables,seedConfig,logger2)}logger2.info(`[Authorization] Tenant schema seeded: ${tenantSchemaName}`)}catch(err){let msg=err instanceof Error?err.message:String(err);logger2.warn(`[Authorization] Failed to seed tenant ${tenantSchemaName}: ${msg}`)}}logger2.info(`[Authorization] Multi-tenant seeding complete for ${tenantSchemas.length} schemas`)}}let sessionsTableRef=schemaTables.userSessions;if(!isConsumerModeOnStart&&sessionsTableRef&&resolvedOptions.authentication?.sessions?.enabled){let{lt:lt4}=await import("drizzle-orm"),expiredCount=await bootStep("auth.expiredSessionCleanup",()=>db.update(sessionsTableRef).set({isActive:!1,revokedAt:new Date,revokedReason:"expired"}).where(and23(eq61(sessionsTableRef.isActive,!0),lt4(sessionsTableRef.expiresAt,new Date))));if(expiredCount!==void 0)logger2.info("[AUTH] Expired sessions cleanup completed",{expiredCount});let sessionCleanupInterval=setInterval(async()=>{try{await db.update(sessionsTableRef).set({isActive:!1,revokedAt:new Date,revokedReason:"expired"}).where(and23(eq61(sessionsTableRef.isActive,!0),lt4(sessionsTableRef.expiresAt,new Date)));let approvalTtlMs=86400000,approvalCutoff=new Date(Date.now()-approvalTtlMs);await db.update(sessionsTableRef).set({isActive:!1,revokedAt:new Date,revokedReason:"approval_token_expired",approvalStatus:"rejected",approvalToken:null}).where(and23(eq61(sessionsTableRef.approvalStatus,"pending"),lt4(sessionsTableRef.approvalRequestedAt,approvalCutoff)))}catch(err){logger2.warn("[AUTH] Session cleanup failed",{error:err})}},3600000);trackInterval(sessionCleanupInterval)}if(isMultiTenant&&tenantRegistry&&resolvedOptions.authentication?.sessions?.enabled){let{lt:lt4}=await import("drizzle-orm"),tenantSchemaNames=tenantRegistry.getAllSchemaNames().filter((name2)=>name2!==targetSchemaName);for(let tenantSchemaName of tenantSchemaNames){let tenantCtx=tenantRegistry.getSchemaContext(tenantSchemaName);if(!tenantCtx)continue;let tenantSessionsTable=tenantCtx.schemaTables.userSessions||tenantCtx.schemaTables.user_sessions||tenantCtx.schemaTables.sessions;if(!tenantSessionsTable)continue;try{await db.update(tenantSessionsTable).set({isActive:!1,revokedAt:new Date,revokedReason:"expired"}).where(and23(eq61(tenantSessionsTable.isActive,!0),lt4(tenantSessionsTable.expiresAt,new Date))),logger2.info(`[AUTH] Tenant session cleanup completed: ${tenantSchemaName}`)}catch(err){let msg=err instanceof Error?err.message:String(err);logger2.warn(`[AUTH] Tenant session cleanup failed for ${tenantSchemaName}: ${msg}`)}}}}}).onRequest(async({request,set:set2,server})=>{if(request.headers.delete("x-user-id"),request.headers.delete("x-request-id"),request.headers.delete("x-auth-type"),request.headers.delete("x-api-key-id"),request.headers.delete("x-api-key-owner-type"),request.headers.delete("x-user-roles"),request.headers.delete("x-user-claims"),request.headers.delete("x-user-claim-scopes"),request.headers.delete("x-session-id"),request.headers.delete("x-access-token"),request.headers.delete("x-refresh-token"),request.headers.delete("x-tenant-schema"),exceedsBodyLimit(request.headers.get("content-length"),resolvedOptions.security?.maxRequestBodyBytes))return set2.status=413,Response.json({isSuccess:!1,message:"Request body too large",status:413,errors:[{message:"Request body too large"}],data:null});let requestStartTime=Date.now(),requestSchemaTables=schemaTables;if(tenantRegistry){let tenantVettedClientIp=resolveClientIp(server?.requestIP(request)?.address??null,request.headers.get("x-forwarded-for")??request.headers.get("x-real-ip"),resolvedOptions.rateLimit?.trustedProxies??[]),tenantResult=tenantRegistry.resolveFromRequest(request,tenantVettedClientIp);if(tenantResult.resolved)requestSchemaTables=tenantResult.context.schemaTables,request.headers.set("x-tenant-schema",tenantResult.context.schemaName);else if(new URL(request.url).pathname!=="/health")return set2.status=tenantResult.statusCode,Response.json({isSuccess:!1,message:tenantResult.error,status:tenantResult.statusCode,errors:[{message:tenantResult.error}],data:null})}request.headers.set("x-request-start-time",String(requestStartTime));let requestId=randomUUID8();if(request.headers.set("x-request-id",requestId),set2.headers["x-request-id"]=requestId,resolvedOptions.security?.disableDefaultHeaders!==!0){set2.headers["X-Content-Type-Options"]="nosniff",set2.headers["X-Frame-Options"]="SAMEORIGIN",set2.headers["Referrer-Policy"]="strict-origin-when-cross-origin";let hstsMaxAge=resolvedOptions.security?.hstsMaxAge??15552000;if(hstsMaxAge>0)set2.headers["Strict-Transport-Security"]=`max-age=${hstsMaxAge}; includeSubDomains`}let url=new URL(request.url),pathname=url.pathname,method=request.method,query=url.search;if(csrfConfig.enabled){let csrfSecure=request.headers.get("x-forwarded-proto")==="https"||url.protocol==="https:"?"; Secure":"",issueCsrfCookie=()=>`${csrfConfig.cookieName}=${randomUUID8()}; Path=/; SameSite=Lax${csrfSecure}`,csrfCookies=parseCookies(request.headers.get("cookie"));if(requiresCsrf({method,cookies:csrfCookies,hasAuthorizationHeader:!!request.headers.get("authorization"),authCookieNames:csrfAuthCookieNames})&&!csrfTokenMatches(csrfCookies[csrfConfig.cookieName],request.headers.get(csrfConfig.headerName)))return set2.headers["Set-Cookie"]=issueCsrfCookie(),set2.status=403,Response.json({isSuccess:!1,message:"CSRF token missing or invalid",status:403,errors:[{message:"CSRF token missing or invalid"}],data:null});else if(!isStateChanging(method)&&!csrfCookies[csrfConfig.cookieName])set2.headers["Set-Cookie"]=issueCsrfCookie()}let socketIp=server?.requestIP(request)?.address??null,clientIp=resolveClientIp(socketIp,request.headers.get("x-forwarded-for")??request.headers.get("x-real-ip"),resolvedOptions.rateLimit?.trustedProxies??[]);request.headers.set("x-client-ip",clientIp);let userAgent=request.headers.get("user-agent")||"unknown";if(requestLogConfig.enabled&&requestLogConfig.logArrival&&!isRequestLogExcluded(pathname))logger2.log("debug",`\u2192 ${method} ${pathname}`,{requestId,method,path:pathname,query:requestLogConfig.includeQuery&&query?query:void 0,ip:clientIp,tenant:request.headers.get("x-tenant-schema")||void 0},void 0,void 0,"middleware.request");let tokens,parsedBody={};if(request.method!=="GET"&&request.method!=="HEAD")try{let text2=await request.clone().text();parsedBody=text2?JSON.parse(text2):{}}catch{parsedBody={}}let auditPayload=audit?.enabled?{id:randomUUID8(),user_id:"unknown",entity_name:pathname.split("/").filter(Boolean)[0]||"root",entity_id:null,operation_type:method,summary:"",old_values:{},new_values:parsedBody,ip_address:clientIp,user_agent:userAgent,timestamp:new Date().toISOString(),path:pathname,query}:null,isPublic=isPublicRoute(publicRoutes,pathname,method);if(rateLimiter){let routeCategory=isPublic?"public":"private",authType=resolveAuthType(pathname,resolvedOptions.authentication),category=authType?"auth":routeCategory,rateLimitResult=await rateLimiter.check({ip:clientIp,endpoint:pathname,category,authType}),headers=rateLimiter.getHeaders(rateLimitResult);for(let[key2,value2]of Object.entries(headers))set2.headers[key2]=value2;if(!rateLimitResult.allowed){if(set2.status=429,rateLimitResult.retryAfter)set2.headers["Retry-After"]=String(rateLimitResult.retryAfter);if(logger2.warn(`[RateLimit] Blocked request from ${clientIp} to ${pathname}`),monitoringService)monitoringService.recordRateLimitBlock();return new Response(JSON.stringify({error:"Too Many Requests",retryAfter:rateLimitResult.retryAfter}),{status:429,headers:{"Content-Type":"application/json"}})}}if(pathname==="/health")return;if(authentication?.enabled&&!isPublic){let apiKeyRaw=extractApiKeyFromHeader(request.headers),apiKeysTableRef=requestSchemaTables.apiKeys;if(apiKeyRaw&&authentication.apiKeys?.enabled&&apiKeysTableRef&&db){let keyHash=hashApiKey(apiKeyRaw),apiKeyRecord=(await db.select().from(apiKeysTableRef).where(eq61(apiKeysTableRef.keyHash,keyHash)).limit(1))[0];if(!apiKeyRecord)return set2.status=401,logger2.traceSync({message:"Invalid API key",level:"warn",context:{path:pathname,method},audit:toAudit(auditPayload,"Invalid API key")}),Error("Invalid API key");let validation=validateApiKeyRecord(apiKeyRecord);if(!validation.valid)return set2.status=401,logger2.traceSync({message:`API key rejected: ${validation.reason}`,level:"warn",context:{path:pathname,method,keyId:apiKeyRecord.id},audit:toAudit(auditPayload,`API key rejected: ${validation.reason}`)}),Error(validation.reason);let apiKeyUserId=apiKeyRecord.userId,apiKeyUserData;{let ksTable=requestSchemaTables.users;if(ksTable&&db){apiKeyUserData=(await db.select().from(ksTable).where(eq61(ksTable.id,apiKeyUserId)).limit(1))[0];let{evaluateAccountState:evaluateAccountState2}=await Promise.resolve().then(() => exports_accountState),ksState=apiKeyUserData?evaluateAccountState2(apiKeyUserData):{allowed:!1,reason:"inactive",message:"Account is not active"};if(!ksState.allowed)return set2.status=401,logger2.traceSync({message:`API key rejected: account ${ksState.reason}`,level:"warn",context:{path:pathname,method,keyId:apiKeyRecord.id},audit:toAudit(auditPayload,`API key rejected: account ${ksState.reason}`,{userId:apiKeyUserId})}),Error(ksState.message)}}let keyAllowedRoles=apiKeyRecord.allowedRoles||[],keyAllowedClaims=apiKeyRecord.allowedClaims||[],effectiveRoles=keyAllowedRoles,effectiveClaims=keyAllowedClaims,apiKeyClaimScopes={},userRolesTable=requestSchemaTables.userRoles,rolesTable=requestSchemaTables.roles,roleClaimsTable=requestSchemaTables.roleClaims,claimsTable=requestSchemaTables.claims;if(userRolesTable&&rolesTable){let currentUserRoles=(await db.select({name:rolesTable.name}).from(userRolesTable).innerJoin(rolesTable,eq61(rolesTable.id,userRolesTable.roleId)).where(eq61(userRolesTable.userId,apiKeyUserId))).map((r2)=>r2.name).filter((n2)=>n2!==void 0);effectiveRoles=intersectPermissions(currentUserRoles,keyAllowedRoles)}if(userRolesTable&&roleClaimsTable&&claimsTable){let userClaimRows=await db.select({action:claimsTable.action,scope:roleClaimsTable.scope}).from(userRolesTable).innerJoin(roleClaimsTable,eq61(roleClaimsTable.roleId,userRolesTable.roleId)).innerJoin(claimsTable,eq61(claimsTable.id,roleClaimsTable.claimId)).where(eq61(userRolesTable.userId,apiKeyUserId)),currentUserClaims=[...new Set(userClaimRows.map((r2)=>r2.action).filter((a12)=>a12!==void 0))];effectiveClaims=intersectPermissions(currentUserClaims,keyAllowedClaims);let effectiveClaimSet=new Set(effectiveClaims),apiScopedRows=userClaimRows.filter((r2)=>typeof r2.action==="string"&&effectiveClaimSet.has(r2.action)).map((r2)=>({action:r2.action,scope:r2.scope??null}));if(apiScopedRows.some((r2)=>!!r2.scope)){let{claimScopes,dropped}=resolveClaimScopes(apiScopedRows,apiKeyUserData,logger2);if(apiKeyClaimScopes=claimScopes,dropped.length>0){let droppedSet=new Set(dropped);effectiveClaims=effectiveClaims.filter((a12)=>!droppedSet.has(a12))}}}if(db.update(apiKeysTableRef).set({lastUsedAt:new Date,lastUsedIp:clientIp,usageCount:apiKeyRecord.usageCount+1}).where(eq61(apiKeysTableRef.id,apiKeyRecord.id)).catch(()=>{}),effectiveRoles=effectiveRoles.filter((r2)=>r2!==GODMIN_ROLE_NAME),request.headers.set("x-user-id",apiKeyUserId),request.headers.set("x-auth-type","api_key"),request.headers.set("x-api-key-id",apiKeyRecord.id),request.headers.set("x-api-key-owner-type",apiKeyRecord.ownerType||"personal"),effectiveRoles.length>0)request.headers.set("x-user-roles",encodeHeaderList(effectiveRoles));if(effectiveClaims.length>0)request.headers.set("x-user-claims",encodeHeaderList(effectiveClaims));{let apiEncodedScopes=encodeClaimScopesHeader(apiKeyClaimScopes);if(apiEncodedScopes)request.headers.set("x-user-claim-scopes",apiEncodedScopes)}logger2.info("[AUTH] API key authenticated",{userId:apiKeyUserId,keyId:apiKeyRecord.id,ownerType:apiKeyRecord.ownerType,path:pathname,method,effectiveRoles:effectiveRoles.length,effectiveClaims:effectiveClaims.length});return}if(!authentication.accessToken?.secret)return set2.status=500,logger2.traceSync({message:"Authentication secrets not defined",level:"error",context:{path:pathname,method},audit:toAudit(auditPayload,"Authentication secrets not defined")}),Error("One or more authentication secrets are not defined");if(authentication.mode==="consumer"){tokens=parseTokenValuesFromHeaders(request.headers,tokenNames);let jwtResult=verifyJWT(tokens.access_token||"",envResolved.accessTokenSecret||"",{issuer:authentication.accessToken?.issuer,audience:authentication.accessToken?.audience});if(!jwtResult.valid)return set2.status=401,logger2.traceSync({message:"Invalid or missing access token",level:"warn",context:{path:pathname,method},audit:toAudit(auditPayload,"Invalid or missing access token",{userId:decodeUnverifiedSubject(tokens.access_token)})}),Error("Unauthenticated");let consumerBinding=verifyTenantBinding(jwtResult.payload[TENANT_CLAIM],request.headers.get("x-tenant-schema"),resolvedOptions.authentication?.tenantBinding??"lenient");if(!consumerBinding.ok)return set2.status=401,logger2.traceSync({message:"Access token tenant binding failed",level:"warn",context:{path:pathname,method,reason:consumerBinding.reason},audit:toAudit(auditPayload,"Access token tenant binding failed",{userId:decodeUnverifiedSubject(tokens.access_token)})}),Error("Unauthenticated");let userId=jwtResult.payload.sub,roles=jwtResult.payload.roles,claimsFromToken=jwtResult.payload.claims;if(request.headers.set("x-access-token",tokens.access_token||""),request.headers.set("x-user-id",userId||""),roles&&roles.length>0)request.headers.set("x-user-roles",encodeHeaderList(roles));if(claimsFromToken&&claimsFromToken.length>0)request.headers.set("x-user-claims",encodeHeaderList(claimsFromToken));{let encodedScopes=encodeClaimScopesHeader(jwtResult.payload.claimScopes);if(encodedScopes)request.headers.set("x-user-claim-scopes",encodedScopes)}}else{if(!authentication.refreshToken?.secret||!authentication.sessionToken?.secret)return set2.status=500,logger2.traceSync({message:"Authentication secrets not defined",level:"error",context:{path:pathname,method},audit:toAudit(auditPayload,"Authentication secrets not defined")}),Error("One or more authentication secrets are not defined");if(tokens=parseTokenValuesFromHeaders(request.headers,tokenNames),!tokens.session_token)return set2.status=401,logger2.traceSync({message:"No session token",level:"debug",context:{path:pathname,method},audit:toAudit(auditPayload,"No session token")}),Error("Unauthenticated");let sessionData=await readSession({sessionId:tokens.session_token});if(!sessionData)return set2.status=401,logger2.traceSync({message:"Invalid session",level:"debug",context:{path:pathname,method,sessionId:tokens.session_token},audit:toAudit(auditPayload,"Invalid session")}),Error("Unauthenticated");let sessionsTableCheck=requestSchemaTables.userSessions;if(sessionsTableCheck&&db){let session=(await db.select().from(sessionsTableCheck).where(eq61(sessionsTableCheck.id,tokens.session_token)).limit(1))[0],revokedAtVal=session?.revokedAt,isRevoked=revokedAtVal!=null&&!(typeof revokedAtVal==="object"&&!(revokedAtVal instanceof Date)&&Object.keys(revokedAtVal).length===0);if(!session||session.isActive===!1||isRevoked)return set2.status=401,logger2.traceSync({message:"Session revoked or inactive",level:"warn",context:{path:pathname,method,sessionId:tokens.session_token,isActive:session?.isActive,revokedAt:session?.revokedAt},audit:toAudit(auditPayload,"Session revoked",{userId:sessionData.userId??null})}),Error("Session has been revoked");if(session.expiresAt&&new Date(session.expiresAt)<new Date)return set2.status=401,logger2.traceSync({message:"Session expired",level:"debug",context:{path:pathname,method,sessionId:tokens.session_token,expiresAt:session.expiresAt},audit:toAudit(auditPayload,"Session expired",{userId:sessionData.userId??null})}),Error("Session has expired")}if(sessionData.lastActiveAt&&authentication.sessions?.inactivityTimeout){let lastActive=new Date(sessionData.lastActiveAt).getTime(),inactivityMs=parseTimeToSeconds2(authentication.sessions.inactivityTimeout)*1000;if(Date.now()-lastActive>inactivityMs)return set2.status=401,logger2.traceSync({message:"Session inactive timeout",level:"debug",context:{path:pathname,method,sessionId:tokens.session_token,lastActiveAt:sessionData.lastActiveAt},audit:toAudit(auditPayload,"Session inactive timeout",{userId:sessionData.userId??null})}),Error("Session expired due to inactivity")}updateLastActiveAt(tokens.session_token).catch(()=>{});let sessionsTableRef=requestSchemaTables.userSessions;if(sessionsTableRef&&db)db.update(sessionsTableRef).set({lastActivityAt:new Date}).where(eq61(sessionsTableRef.id,tokens.session_token)).catch(()=>{});let jwtResult=verifyJWT(tokens.access_token||"",envResolved.accessTokenSecret||"",{issuer:authentication.accessToken?.issuer,audience:authentication.accessToken?.audience}),isAccessTokenValid=tokens.access_token?jwtResult.valid:!1,isRefreshTokenValid=tokens.refresh_token?verifyJWT(tokens.refresh_token,envResolved.refreshTokenSecret||"",{issuer:authentication.refreshToken?.issuer,audience:authentication.refreshToken?.audience}).valid:!1;if(!isAccessTokenValid&&isRefreshTokenValid&&tokens.refresh_token&&sessionData.rememberMe===!0){let killSwitchUsersTable=requestSchemaTables.users;if(db&&killSwitchUsersTable){let ksUser=(await db.select().from(killSwitchUsersTable).where(eq61(killSwitchUsersTable.id,sessionData.userId)).limit(1))[0],{evaluateAccountState:evaluateAccountState2}=await Promise.resolve().then(() => exports_accountState),ksState=ksUser?evaluateAccountState2(ksUser):{allowed:!1,reason:"inactive",message:"Account is not active"};if(!ksState.allowed)return set2.status=401,logger2.traceSync({message:`Silent refresh blocked - account ${ksState.reason}`,level:"warn",context:{path:pathname,method},audit:toAudit(auditPayload,`Silent refresh blocked - account ${ksState.reason}`,{userId:sessionData.userId??null})}),Error(ksState.message)}let refreshRoles=[],refreshClaims=[],refreshClaimScopes={},refreshUserRolesTable=requestSchemaTables.userRoles,refreshRolesTable=requestSchemaTables.roles,refreshRoleClaimsTable=requestSchemaTables.roleClaims,refreshClaimsTable=requestSchemaTables.claims;if(db&&refreshUserRolesTable&&refreshRolesTable)try{let{fetchUserRolesAndClaims:fetchUserRolesAndClaims2}=await Promise.resolve().then(() => (init_fetchUserRolesAndClaims(),exports_fetchUserRolesAndClaims)),rc=await fetchUserRolesAndClaims2(db,sessionData.userId,{usersTable:killSwitchUsersTable??null,sessionsTable:null,userRolesTable:refreshUserRolesTable,rolesTable:refreshRolesTable,roleClaimsTable:refreshRoleClaimsTable,claimsTable:refreshClaimsTable,oauthAccountsTable:void 0,apiKeysTable:void 0,schemaTables:requestSchemaTables});refreshRoles=rc.roles,refreshClaims=rc.claims,refreshClaimScopes=rc.claimScopes}catch{}let refreshResult=await refreshAccessTokenWithLock(sessionData.userId,sessionData.id,()=>signNewAccessToken({refreshTokenId:tokens.refresh_token,options:resolvedOptions,sessionData,roles:refreshRoles.length>0?refreshRoles:void 0,claims:refreshClaims.length>0?refreshClaims:void 0,claimScopes:refreshClaimScopes,tenant:request.headers.get("x-tenant-schema")??void 0,resolveMode:resolvedOptions.authorization?.jwtClaimsMode==="resolve"&&!!claimsCache}));if(refreshResult.success&&refreshResult.accessToken){tokens.access_token=refreshResult.accessToken;let rawDomain=authentication.cookieDomain,resolvedDomainRaw=rawDomain?process.env[rawDomain]??rawDomain:void 0,resolvedDomain=resolvedDomainRaw==="localhost"||resolvedDomainRaw===".localhost"?void 0:resolvedDomainRaw,domainPart=resolvedDomain?`; Domain=${resolvedDomain}`:"",bufferSeconds=authentication.cookieMaxAgeBufferSeconds??0,maxAge=Math.max(0,parseTimeToSeconds2(authentication.accessToken.expiresIn??"15m")-bufferSeconds),securePart=!resolvedDomain?"":"; Secure",cookieValue=`${tokenNames.access_token}=${refreshResult.accessToken}; Path=/; HttpOnly; SameSite=Lax${securePart}; Max-Age=${maxAge}${domainPart}`;set2.headers["Set-Cookie"]=cookieValue}}if(jwtResult.valid){let fullBinding=verifyTenantBinding(jwtResult.payload[TENANT_CLAIM],request.headers.get("x-tenant-schema"),resolvedOptions.authentication?.tenantBinding??"lenient");if(!fullBinding.ok)return set2.status=401,logger2.traceSync({message:"Access token tenant binding failed",level:"warn",context:{path:pathname,method,reason:fullBinding.reason},audit:toAudit(auditPayload,"Access token tenant binding failed",{userId:jwtResult.payload.sub??null})}),Error("Unauthenticated")}if(jwtResult.valid&&jwtResult.payload.sub&&String(jwtResult.payload.sub)!==String(sessionData.userId))return set2.status=401,logger2.traceSync({message:"Access token subject does not match session",level:"warn",context:{path:pathname,method,sessionUserId:sessionData.userId,tokenSub:jwtResult.payload.sub},audit:toAudit(auditPayload,"Access token/session subject mismatch",{userId:sessionData.userId??null})}),Error("Unauthenticated");let userId=jwtResult.valid?jwtResult.payload.sub:sessionData.userId,roles=jwtResult.valid?jwtResult.payload.roles:void 0,claimsFromToken=jwtResult.valid?jwtResult.payload.claims:void 0;if(!claimsFromToken?.length&&claimsCache&&roles&&roles.length>0)try{let resolvedClaims=await claimsCache.resolveClaimsForRoles(roles);if(resolvedClaims.length>0)claimsFromToken=resolvedClaims}catch{}if(userId&&db&&authentication.cohorts?.enabled){let mwUsersTable=requestSchemaTables.users;if(mwUsersTable)try{let mwCohortId=(await db.select().from(mwUsersTable).where(eq61(mwUsersTable.id,userId)).limit(1))[0]?.cohortId;if(mwCohortId){let mwCohortsTable=requestSchemaTables.userCohorts??requestSchemaTables.user_cohorts;if(mwCohortsTable){let mwExpiresAt=(await db.select().from(mwCohortsTable).where(eq61(mwCohortsTable.id,mwCohortId)).limit(1))[0]?.expiresAt;if(mwExpiresAt&&new Date(mwExpiresAt)<new Date)return set2.status=403,logger2.traceSync({message:"Cohort expired - access denied",level:"warn",context:{path:pathname,method,userId,cohortId:mwCohortId},audit:toAudit(auditPayload,"Cohort expired",{userId:userId??null})}),Error("Your access has expired. Please contact your administrator.")}}}catch{}}if(request.headers.set("x-access-token",tokens.access_token||""),request.headers.set("x-refresh-token",tokens.refresh_token||""),request.headers.set("x-session-id",tokens.session_token||""),request.headers.set("x-user-id",userId||""),roles&&roles.length>0)request.headers.set("x-user-roles",encodeHeaderList(roles));if(claimsFromToken&&claimsFromToken.length>0)request.headers.set("x-user-claims",encodeHeaderList(claimsFromToken));{let encodedScopes=encodeClaimScopesHeader(jwtResult.valid?jwtResult.payload.claimScopes:void 0);if(encodedScopes)request.headers.set("x-user-claim-scopes",encodedScopes)}}}}).onAfterHandle(({request,set:set2})=>{let afterUrl=new URL(request.url),afterStatus=typeof set2.status==="number"?set2.status:200,afterStartStr=request.headers.get("x-request-start-time"),afterDuration=afterStartStr?Date.now()-parseInt(afterStartStr,10):0;if(requestLogConfig.enabled&&!isRequestLogExcluded(afterUrl.pathname)){let isSlow=afterDuration>=requestLogConfig.slowThresholdMs,level=afterStatus>=500?"error":afterStatus>=400||isSlow?"warn":"info";logger2.log(level,`\u2190 ${request.method} ${afterUrl.pathname} ${afterStatus} (${afterDuration}ms)`,{requestId:request.headers.get("x-request-id")||void 0,method:request.method,path:afterUrl.pathname,query:requestLogConfig.includeQuery&&afterUrl.search?afterUrl.search:void 0,statusCode:afterStatus,durationMs:afterDuration,slow:isSlow||void 0,userId:request.headers.get("x-user-id")||void 0,authType:request.headers.get("x-auth-type")||void 0,tenant:request.headers.get("x-tenant-schema")||void 0,ip:request.headers.get("x-forwarded-for")?.split(",")[0]?.trim()||request.headers.get("x-real-ip")||void 0},void 0,void 0,"middleware.request")}if(monitoringService){let startTimeStr=request.headers.get("x-request-start-time"),startTime=startTimeStr?parseInt(startTimeStr,10):Date.now(),responseTimeMs=Date.now()-startTime,url=new URL(request.url),status=typeof set2.status==="number"?set2.status:200;monitoringService.recordRequest({endpoint:url.pathname,method:request.method,status,responseTimeMs,isError:status>=400,errorType:status>=500?"server_error":status>=400?"client_error":void 0})}if(liveMonitoringService){let url=new URL(request.url),headersObj=redactSensitiveHeaders(request.headers);liveMonitoringService.recordRequest({path:url.pathname,method:request.method,timestamp:Date.now(),headers:headersObj})}}).onError((ctx)=>{let{set:set2,code,error:error3,request}=ctx,status=statusOfError(code,error3),message="Internal Server Error",pgCode,clientSafe=!1;if(error3 instanceof Error){let cause=error3.cause;if(pgCode=cause?.code,pgCode==="23505")message="A record with this value already exists",clientSafe=!0;else if(pgCode==="23503")message="Referenced record does not exist",clientSafe=!0;else if(pgCode==="23502")message=`Missing required field: ${cause?.column||"a required field is empty"}`,clientSafe=!0;else if(pgCode==="22P02")message=cause?.routine==="string_to_uuid"?"Invalid ID format":"Invalid data format",clientSafe=!0;else if(pgCode)message=`Database error (${pgCode}): ${cause?.detail||cause?.message||error3.message}`;else if(code==="VALIDATION")message=describeValidationError(error3)??error3.message,clientSafe=!0;else message=error3.message,clientSafe=status<500}try{let errUrl=new URL(request.url),errStartStr=request.headers.get("x-request-start-time");logger2.log(status>=500?"error":"warn",`\u2716 ${request.method} ${errUrl.pathname} ${status}: ${message}`,{requestId:request.headers.get("x-request-id")||void 0,method:request.method,path:errUrl.pathname,statusCode:status,elysiaCode:typeof code==="string"?code:void 0,pgCode,durationMs:errStartStr?Date.now()-parseInt(errStartStr,10):void 0,userId:request.headers.get("x-user-id")||void 0,tenant:request.headers.get("x-tenant-schema")||void 0},status>=500?error3:void 0)}catch(logErr){logger2.error("Failed to log request error",logErr)}set2.status=status;let clientMessage=clientSafe?message:"Internal Server Error";return Response.json({isSuccess:!1,message:clientMessage,status,errors:[{message:clientMessage}],data:null})});let featureAdminRoles={};for(let[feature,section]of Object.entries(resolvedOptions)){if(!section||typeof section!=="object")continue;let roles=section.adminRoles;if(!Array.isArray(roles))continue;let named=roles.filter((role)=>typeof role==="string"&&role.length>0);if(named.length>0)featureAdminRoles[feature]=named}logger2.info("Creating routes for entities"),createEntityRoutes(plugin,{db,schemaTables,schemaRelations,entities,logger:logger2,databaseUrl:envResolved.databaseUrl,dbPool,storage:resolvedOptions.storage,cdnMedia:{transform:mergeTransformConfig(resolvedOptions.storage?.cdn?.transform),video:mergeVideoConfig(resolvedOptions.storage?.cdn?.video)},authorization:resolvedOptions.authorization,featureAdminRoles,authMode:authentication?.mode,idpUrl:authentication?.idpUrl?process.env[authentication.idpUrl]||authentication.idpUrl:void 0,isEmailServiceAvailable:()=>!!getEmailService()?.isAvailable(),tenantRegistry,getTenantRegistry:()=>tenantRegistry,claimsCache});let isConsumerMode=authentication?.mode==="consumer";if(isMultiTenant&&!isConsumerMode)createTenantRoutes(plugin,{getDb:()=>db,logger:logger2,getTenantRegistry:()=>tenantRegistry,schemaName:targetSchemaName}),logger2.info("[MultiTenant] Tenant routes pre-registered (handlers check runtime readiness)");else if(isMultiTenant&&isConsumerMode)plugin.post("/tenants/refresh",async(ctx)=>{if(!tenantRegistry||!tenantRegistry.isConsumerMode())return ctx.set.status=503,{success:!1,message:"Tenant registry not ready"};try{return{success:!0,data:await tenantRegistry.syncFromIdp()}}catch(err){let msg=err instanceof Error?err.message:String(err);return ctx.set.status=500,{success:!1,message:`Tenant sync failed: ${msg}`}}}),logger2.info("[MultiTenant] Consumer tenant refresh route registered (/tenants/refresh)");let domainServices=null;if(resolvedOptions.domains?.enabled){if(domainServices=createDomainServices({options:resolvedOptions,logger:logger2,getDb:()=>db,getTenantRegistry:()=>tenantRegistry}),domainServices)createDomainRoutes(plugin,{getDomainService:()=>domainServices?.domainService??null,getRegistrationService:()=>domainServices?.registrationService??null,logger:logger2,basePath:resolvedOptions.domains.basePath||"/domains",resolveTenantIdForSchema:(schema3)=>schema3&&tenantRegistry?tenantRegistry.getTenantBySchemaName(schema3)?.id??null:null}),logger2.info("[Domains] Custom domain routes registered",{provider:domainServices.domainService.config.provider,basePath:resolvedOptions.domains.basePath||"/domains"})}if(authentication?.enabled&&!isConsumerMode&&db){let resolveTableForTenant=(tableName,reqSchemaName)=>{if(reqSchemaName&&tenantRegistry){let ctx=tenantRegistry.getSchemaContext(reqSchemaName);if(ctx?.schemaTables[tableName])return ctx.schemaTables[tableName]}return schemaTables[tableName]},usersTable=schemaTables.users,sessionsTable=schemaTables.userSessions||schemaTables.user_sessions||schemaTables.sessions;if(!sessionsTable&&authentication.sessions?.enabled)logger2.warn("[AUTH] sessions is enabled but user_sessions table not found in schema. Disabling sessions.");if(usersTable){await initiateRedisManager(resolvedOptions);let{createAuthRoutes:createAuthRoutes2}=(init_auth(),__toCommonJS(exports_auth)),{signJWT:signJWT2,verifyJWT:verifyJWT3}=(init_JWT(),__toCommonJS(exports_JWT)),{generateSession:generateSession2,deleteSession:deleteSession2}=(init_SessionStore(),__toCommonJS(exports_SessionStore));createAuthRoutes2(plugin,{authConfig:{db,logger:logger2,usersTable,sessionsTable,userRolesTable:schemaTables.userRoles,rolesTable:schemaTables.roles,roleClaimsTable:schemaTables.roleClaims,claimsTable:schemaTables.claims,authentication:{enabled:authentication.enabled,defaultRole:resolvedOptions.authentication?.defaultRole||process.env.AUTH_DEFAULT_ROLE,cookieDomain:resolvedOptions.authentication?.cookieDomain,get trustedAppOrigins(){return trustedAppOrigins()},emailExemptDomains:authentication?.emailExemptDomains,accessToken:authentication.accessToken,refreshToken:authentication.refreshToken,sessionToken:authentication.sessionToken,deviceTrust:authentication.sessions?.deviceTrust}},features:{login:authentication.login,register:authentication.register,logout:authentication.logout,refresh:authentication.refresh,passwordReset:withResolvedRedirects(authentication.passwordReset,["redirectUrl"]),passwordChange:authentication.passwordChange,passwordSet:authentication.passwordSet,sessions:withResolvedRedirects(authentication.sessions,["approvalRedirectUrl"]),magicLink:withResolvedRedirects(authentication.magicLink,["redirectUrl"]),me:authentication.me||{enabled:!0,route:"/auth/me"},invite:withResolvedRedirects(authentication.invite,["redirectUrl"]),captcha:authentication.captcha,oauth:authentication.oauth?.enabled&&envResolved.oauthProviders?{...withResolvedRedirects(authentication.oauth,["successRedirectUrl","errorRedirectUrl"]),providers:liveOAuthProviders(envResolved.oauthProviders)}:void 0,apiKeys:authentication.apiKeys?.enabled?{enabled:!0,route:authentication.apiKeys.route,keyPrefix:authentication.apiKeys.keyPrefix,maxKeysPerUser:authentication.apiKeys.maxKeysPerUser,defaultExpiresIn:authentication.apiKeys.defaultExpiresIn,allowApplicationKeys:authentication.apiKeys.allowApplicationKeys,preventApiKeyManagement:authentication.apiKeys.preventApiKeyManagement}:void 0,webauthn:authentication.webauthn},sessionsTable,oauthAccountsTable:schemaTables.oauthAccounts,oauthStateStore:(()=>{let oauthRedis=getRedisManager();if(!oauthRedis)return;let{createRedisOAuthStateStore:createRedisOAuthStateStore2}=__toCommonJS(exports_stateStore);return createRedisOAuthStateStore2(oauthRedis)})(),apiKeysTable:schemaTables.apiKeys,schemaTables,schemaRelations,tenantRegistry,getTenantRegistry:()=>tenantRegistry,databaseUrl:envResolved.databaseUrl,dbPool,admin:(()=>{let adminCfg=resolvedOptions.authentication?.admin;return{impersonate:{enabled:!0},changeUserId:{enabled:!0},createUser:adminCfg?.createUser??{enabled:!0}}})(),schemaName:targetSchemaName,getEmailService,appName:resolvedOptions.appId,webauthnService:(()=>{if(!authentication.webauthn?.enabled||!db)return null;let{WebAuthnService:WebAuthnService2}=(init_WebAuthn(),__toCommonJS(exports_WebAuthn)),{createDbWebAuthnStorage:createDbWebAuthnStorage2}=(init_dbStorage(),__toCommonJS(exports_dbStorage)),rpName=authentication.webauthn.rpName||resolvedOptions.appId||"Nucleus",rpID=authentication.webauthn.rpID||"localhost",expectedOrigins=authentication.webauthn.expectedOrigins||[`http://${rpID}`,`https://${rpID}`],challengeTtlMs=authentication.webauthn.challengeTtl?parseTimeToSeconds2(authentication.webauthn.challengeTtl)*1000:300000,storage=createDbWebAuthnStorage2({db,resolveTable:resolveTableForTenant});return new WebAuthnService2({rp:{rpName,rpID,expectedOrigins},challengeTtlMs,storage,userVerification:authentication.webauthn?.userVerification})})(),captchaService:(()=>{let redisManager=getRedisManager();if(!authentication.captcha?.enabled||!redisManager)return null;return new CaptchaService({redis:{get:async(key2)=>{let result=await redisManager.read(key2);return result.success?result.data:null},set:async(key2,value2,options)=>{await redisManager.create(key2,value2,options?.ex)},del:async(key2)=>{await redisManager.remove(key2)},incrementCounter:(key2,delta,ttlSeconds)=>redisManager.incrementCounter(key2,delta,ttlSeconds)},logger:logger2,config:{enabled:!0,type:authentication.captcha.type||"math",difficulty:authentication.captcha.difficulty||"medium",expiresIn:authentication.captcha.expiresIn||"5m",maxAttempts:authentication.captcha.maxAttempts||3,caseSensitive:authentication.captcha.caseSensitive??!1}})})(),tokenResponseConfig:{accessToken:{setHeadersEnabled:authentication.accessToken?.setHeadersEnabled??!0,returnJson:authentication.accessToken?.returnJson??!0},refreshToken:{setHeadersEnabled:authentication.refreshToken?.setHeadersEnabled??!0,returnJson:authentication.refreshToken?.returnJson??!0},sessionToken:{setHeadersEnabled:authentication.sessionToken?.setHeadersEnabled??!0,returnJson:authentication.sessionToken?.returnJson??!0}},helpers:{signAccessToken:(userId,roles,claims,tenant,claimScopes)=>{let resolveMode=resolvedOptions.authorization?.jwtClaimsMode==="resolve"&&claimsCache,hasClaimScopes=!resolveMode&&!!claimScopes&&Object.keys(claimScopes).length>0,token=signJWT2({subject:userId,expiresInSeconds:parseTimeToSeconds2(authentication.accessToken?.expiresIn||"15m"),issuer:authentication.accessToken?.issuer,audience:authentication.accessToken?.audience,customClaims:{...roles&&roles.length>0?{roles}:{},...!resolveMode&&claims&&claims.length>0?{claims}:{},...hasClaimScopes?{claimScopes}:{},...tenant?{tenant}:{}}},envResolved.accessTokenSecret||"",authentication.accessToken?.algorithm||"HS256");return warnIfAccessTokenTooLargeForCookie(token,resolveMode?"resolve":resolvedOptions.authorization?.jwtClaimsMode),token},signRefreshToken:(userId)=>signJWT2({subject:userId,expiresInSeconds:parseTimeToSeconds2(authentication.refreshToken?.expiresIn||"7d"),issuer:authentication.refreshToken?.issuer,audience:authentication.refreshToken?.audience},envResolved.refreshTokenSecret||"",authentication.refreshToken?.algorithm||"HS256"),verifyRefreshToken:(token)=>verifyJWT3(token,envResolved.refreshTokenSecret||"",{issuer:authentication.refreshToken?.issuer,audience:authentication.refreshToken?.audience}),createSession:async(params)=>{let sessionTtlSeconds=parseTimeToSeconds2(authentication.sessionToken?.expiresIn||"30d"),result=await generateSession2({userId:params.userId,deviceInfo:params.deviceInfo,rememberMe:params.rememberMe,loginMethod:params.loginMethod,expiresInSeconds:sessionTtlSeconds});if(!result.success)throw logger2.error("[createSession] failed to create session",{userId:params.userId,error:result.error}),Error(`Session storage unavailable: ${result.error||"unknown error"}`);return result.session.id},destroySession:async(sessionId)=>deleteSession2({sessionId}),saveSessionToDb:async(sessionId,params,reqSchemaName)=>{let resolvedSessionsTable=resolveTableForTenant("userSessions",reqSchemaName)||resolveTableForTenant("user_sessions",reqSchemaName)||resolveTableForTenant("sessions",reqSchemaName)||sessionsTable;if(!resolvedSessionsTable||!db)return;let sessionsConfig=authentication.sessions,deviceInfo=ensureDeviceInfo(params.deviceInfo||{ipAddress:""}),resolvedUsersTableForExempt=resolveTableForTenant("users",reqSchemaName),sessionUserEmail=null;if(resolvedUsersTableForExempt)sessionUserEmail=(await db.select().from(resolvedUsersTableForExempt).where(eq61(resolvedUsersTableForExempt.id,params.userId)).limit(1))[0]?.email??null;let userIsEmailExempt=sessionUserEmail?isEmailExempt(sessionUserEmail,authentication?.emailExemptDomains):!1,deviceFingerprint=deviceInfo.deviceHint?`${deviceInfo.browserName||""}-${deviceInfo.osName||""}-${deviceInfo.deviceType||""}-${deviceInfo.deviceHint}`:`${deviceInfo.browserName||""}-${deviceInfo.osName||""}-${deviceInfo.deviceType||""}`,existingSessions=await db.select().from(resolvedSessionsTable).where(and23(eq61(resolvedSessionsTable.userId,params.userId),eq61(resolvedSessionsTable.isActive,!0))),hasValidFingerprint=deviceFingerprint&&!deviceFingerprint.includes("--unknown")&&!deviceFingerprint.includes("Bot/Crawler")&&!deviceFingerprint.includes("Headless")&&deviceFingerprint!=="--"&&deviceFingerprint!=="--unknown",allUserSessions=await db.select().from(resolvedSessionsTable).where(eq61(resolvedSessionsTable.userId,params.userId)),isNewDevice=hasValidFingerprint?!existingSessions.some((s)=>s.deviceFingerprint===deviceFingerprint):!1,wasPreviouslyApproved=hasValidFingerprint?allUserSessions.some((s)=>{let sess=s;return sess.deviceFingerprint===deviceFingerprint&&sess.approvalStatus==="approved"}):!1,hasAnyApprovedSession=existingSessions.some((s)=>s.approvalStatus==="approved"),isImpersonationLogin=params.loginMethod==="impersonation"||params.loginMethod==="impersonation_stop",isOAuthLogin=params.loginMethod?.startsWith("oauth:"),requiresApproval=!isImpersonationLogin&&!userIsEmailExempt&&sessionsConfig?.trustNewDevices===!1&&isNewDevice&&!wasPreviouslyApproved&&hasValidFingerprint&&hasAnyApprovedSession,deviceTrustCfg=sessionsConfig?.deviceTrust,dtTable=deviceTrustCfg?.enabled?resolveTableForTenant("trustedDevices",reqSchemaName)||resolveTableForTenant("trusted_devices",reqSchemaName):void 0,deviceTrustMint=null,deviceTokenToSet=null;if(deviceTrustCfg?.enabled&&dtTable){let DT=await Promise.resolve().then(() => (init_DeviceTrust(),exports_DeviceTrust)),DTStore=await Promise.resolve().then(() => (init_store2(),exports_store)),dtNow=new Date,dtRows=params.deviceToken?await DTStore.findDeviceRowsByRawToken(db,dtTable,params.deviceToken):[],knownRow=DT.selectUsableDeviceRow(dtRows,params.userId,dtNow),pendingRow=dtRows.find((r2)=>(r2.userId??r2.user_id)===params.userId&&r2.status==="pending"),isFirstEver=allUserSessions.length===0&&await DTStore.userHasNoTrustedDevices(db,dtTable,params.userId),decision=DT.decideDeviceApproval({knownDevice:!!knownRow,trustNewDevices:sessionsConfig?.trustNewDevices??!0,hasValidFingerprint:!!hasValidFingerprint,isFirstEverDevice:isFirstEver,loginMethod:params.loginMethod,approvalMethods:deviceTrustCfg.approvalMethods??["password","magic_link","sso","webauthn","oauth:*","register"],onUnidentifiable:deviceTrustCfg.onUnidentifiable??"require_approval",isImpersonation:isImpersonationLogin,isEmailExempt:userIsEmailExempt});if(knownRow)await DTStore.touchDevice(db,dtTable,knownRow.id,deviceInfo.ipAddress).catch(()=>{});if(decision.deny)return logger2.warn("[AUTH] Device-trust denied unidentifiable device",{userId:params.userId}),{requiresApproval:!1,denied:!0};let reuseSessionId=pendingRow?.originSessionId??pendingRow?.origin_session_id;if(decision.requiresApproval&&reuseSessionId)return{requiresApproval:!0,sessionId:reuseSessionId};requiresApproval=decision.requiresApproval,deviceTrustMint=decision.mintToken?decision.trustImmediately?"trusted":"pending":null}logger2.info("[AUTH] Device fingerprint analysis",{userId:params.userId,deviceFingerprint,hasValidFingerprint,isNewDevice,wasPreviouslyApproved,loginMethod:params.loginMethod,isImpersonationLogin,isOAuthLogin,existingSessionCount:existingSessions.length,hasAnyApprovedSession,requiresApproval});let approvalToken=null,approvalStatus="approved";if(requiresApproval){let existingPending=deviceTrustCfg?.enabled?void 0:allUserSessions.find((s)=>{let sess=s;return sess.deviceFingerprint===deviceFingerprint&&(sess.approvalStatus==="pending"||sess.approval_status==="pending")&&sess.approvalToken});if(existingPending){let pendingSess=existingPending,pendingRequestedAt=pendingSess.approvalRequestedAt||pendingSess.approval_requested_at;if(pendingRequestedAt?Date.now()-new Date(pendingRequestedAt).getTime()<86400000:!0)return logger2.info("[AUTH] Reusing existing pending session for same device",{userId:params.userId,deviceFingerprint,existingSessionId:pendingSess.id}),{requiresApproval:!0,sessionId:pendingSess.id}}let{randomBytes:randomBytes7}=await import("crypto");approvalToken=randomBytes7(32).toString("hex"),approvalStatus="pending",logger2.info("[AUTH] New device requires approval",{userId:params.userId,deviceFingerprint,ipAddress:deviceInfo.ipAddress})}let staleBotSessions=existingSessions.filter((s)=>{let sess=s,fp=(sess.deviceFingerprint||"").toLowerCase(),ip=sess.ipAddress||"",ua=(sess.userAgent||"").toLowerCase(),isBotFingerprint=!fp||fp==="--"||fp==="--unknown"||fp.includes("bot/crawler")||fp.includes("headless")||fp.includes("unknown-unknown"),isServerAction=ua.includes("nucleusserveraction")||ua.includes("serveraction")||ua.includes("node-fetch")||ua.includes("undici");return isBotFingerprint&&(ip==="127.0.0.1"||ip==="::1"||ip==="localhost"||!ip)||isServerAction});if(staleBotSessions.length>0){for(let botSession of staleBotSessions)await db.update(resolvedSessionsTable).set({isActive:!1,revokedAt:new Date,revokedReason:"bot_session_cleanup"}).where(eq61(resolvedSessionsTable.id,botSession.id));logger2.info("[AUTH] Cleaned up stale bot/crawler sessions",{userId:params.userId,cleanedCount:staleBotSessions.length})}if(hasValidFingerprint&&!requiresApproval){let sameDeviceOldSessions=existingSessions.filter((s)=>s.deviceFingerprint===deviceFingerprint);for(let oldSession of sameDeviceOldSessions)await db.update(resolvedSessionsTable).set({isActive:!1,revokedAt:new Date,revokedReason:"same_device_relogin"}).where(eq61(resolvedSessionsTable.id,oldSession.id));if(sameDeviceOldSessions.length>0)logger2.info("[AUTH] Revoked old same-device sessions",{userId:params.userId,deviceFingerprint,revokedCount:sameDeviceOldSessions.length})}if(!sessionsConfig?.allowMultipleDevices&&existingSessions.length>0){if((hasValidFingerprint?existingSessions.filter((s)=>s.deviceFingerprint===deviceFingerprint):[]).length===0)for(let oldSession of existingSessions)await db.update(resolvedSessionsTable).set({isActive:!1,revokedAt:new Date,revokedReason:"new_device_login"}).where(eq61(resolvedSessionsTable.id,oldSession.id))}if(sessionsConfig?.maxActiveSessions){let{count:count3}=await import("drizzle-orm"),currentCount=(await db.select({count:count3()}).from(resolvedSessionsTable).where(and23(eq61(resolvedSessionsTable.userId,params.userId),eq61(resolvedSessionsTable.isActive,!0))))[0]?.count||0;if(currentCount>=sessionsConfig.maxActiveSessions){let{asc:asc2}=await import("drizzle-orm"),oldestSessions=await db.select().from(resolvedSessionsTable).where(and23(eq61(resolvedSessionsTable.userId,params.userId),eq61(resolvedSessionsTable.isActive,!0))).orderBy(asc2(resolvedSessionsTable.createdAt)).limit(currentCount-sessionsConfig.maxActiveSessions+1);for(let oldSession of oldestSessions)await db.update(resolvedSessionsTable).set({isActive:!1,revokedAt:new Date,revokedReason:"max_sessions_exceeded"}).where(eq61(resolvedSessionsTable.id,oldSession.id))}}let trustScore=100;if(deviceInfo.isHeadless)trustScore-=50;if(deviceInfo.isBot)trustScore-=40;if(deviceInfo.isSuspicious)logger2.warn("[AUTH] Suspicious login detected",{userId:params.userId,suspiciousPatterns:deviceInfo.suspiciousPatterns,userAgent:deviceInfo.userAgent,ipAddress:deviceInfo.ipAddress});if(isNewDevice)trustScore-=25;if(!deviceInfo.ipAddress||deviceInfo.ipAddress==="unknown")trustScore-=20;if(!deviceInfo.browserName)trustScore-=15;if(!deviceInfo.osName)trustScore-=15;if(!deviceInfo.deviceType||deviceInfo.deviceType==="unknown")trustScore-=10;if(!deviceInfo.deviceName||deviceInfo.deviceName==="Unknown Device")trustScore-=5;let validFingerprint=deviceFingerprint&&!deviceFingerprint.includes("--unknown")&&deviceFingerprint!=="--",validIp=deviceInfo.ipAddress&&deviceInfo.ipAddress!=="unknown";if(validFingerprint){if(existingSessions.filter((s)=>s.deviceFingerprint===deviceFingerprint).length>0)trustScore+=20}if(validIp){if(existingSessions.filter((s)=>s.ipAddress===deviceInfo.ipAddress).length>0)trustScore+=15}trustScore=Math.max(0,Math.min(100,trustScore));let LOW_TRUST_THRESHOLD=50;if(await db.insert(resolvedSessionsTable).values({id:sessionId,userId:params.userId,tokenHash:sessionId,deviceFingerprint,deviceName:deviceInfo.deviceName,deviceType:deviceInfo.deviceType,browserName:deviceInfo.browserName,browserVersion:deviceInfo.browserVersion,osName:deviceInfo.osName,osVersion:deviceInfo.osVersion,ipAddress:deviceInfo.ipAddress,locationCountry:deviceInfo.locationCountry,locationCity:deviceInfo.locationCity,loginMethod:params.loginMethod||"password",rememberMe:params.rememberMe??!1,trustScore,lastActivityAt:new Date,createdAt:new Date,expiresAt:new Date(Date.now()+parseTimeToSeconds2(authentication.sessionToken?.expiresIn||"30d")*1000),isActive:approvalStatus==="approved",approvalStatus,approvalToken,approvalRequestedAt:requiresApproval?new Date:null}),!isImpersonationLogin&&getEmailService()&&(sessionsConfig?.notifyOnNewDevice&&isNewDevice||trustScore<LOW_TRUST_THRESHOLD||requiresApproval)){let resolvedUsersTable=resolveTableForTenant("users",reqSchemaName);if(resolvedUsersTable){let user=(await db.select().from(resolvedUsersTable).where(eq61(resolvedUsersTable.id,params.userId)).limit(1))[0];if(user?.email&&!isEmailExempt(user.email,authentication?.emailExemptDomains)){let isLowTrust=trustScore<LOW_TRUST_THRESHOLD,sessionsRoute=authentication.sessions?.route||"/auth/sessions",configuredUrl=authentication.sessions?.approvalRedirectUrl||"",isLegacyFrontendUrl=!configuredUrl||configuredUrl.endsWith("/devices"),approvalBase;if(!isLegacyFrontendUrl)approvalBase=configuredUrl;else{let origin=pickTrustedOrigin(params.requestOrigin,configuredUrl,trustedAppOrigins());if(params.requestOrigin&&origin!==params.requestOrigin)logger2.warn("[AUTH] Device-approval link origin refused \u2014 not in trustedAppOrigins",{requested:params.requestOrigin,used:origin||"(none)"});approvalBase=`${origin||"http://localhost:9000"}${sessionsRoute}`}let approveUrl=approvalToken?`${approvalBase}/approve-page?token=${approvalToken}`:"",rejectUrl=approvalToken?`${approvalBase}/reject-page?token=${approvalToken}`:"",subject,emailHtml,brandName=resolvedOptions.appId||"Nucleus",loginTime=new Date().toLocaleString("en-US",{dateStyle:"medium",timeStyle:"short"}),deviceSummary=`${deviceInfo.browserName||"Unknown"} ${deviceInfo.browserVersion||""} on ${deviceInfo.osName||"Unknown"} ${deviceInfo.osVersion||""}`,emailWrapper=(content)=>`
|
|
1976
1976
|
<!DOCTYPE html>
|
|
1977
1977
|
<html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1.0"></head>
|
|
1978
1978
|
<body style="margin:0;padding:0;background-color:#f4f4f5;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;">
|