nucleus-core-ts 0.9.981 → 0.9.982

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/.build-ok CHANGED
@@ -1 +1 @@
1
- 0.9.981
1
+ 0.9.982
package/dist/index.js CHANGED
@@ -2030,4 +2030,4 @@ ${content}
2030
2030
  ${warningBanner}
2031
2031
  ${deviceTable}
2032
2032
  <p style="margin:16px 0 0;color:#6b7280;font-size:13px;">If this wasn't you, please secure your account immediately.</p>
2033
- `)}deliver(getEmailService(),{to:user.email,subject,html:emailHtml},"[AUTH] login notification").then((report)=>{if(report.level==="warn")logger2.warn(report.message,{userId:params.userId,trustScore,requiresApproval});else logger2.info(report.message,{userId:params.userId})})}}}if(logger2.info("[AUTH] Session saved to DB",{sessionId,userId:params.userId,isNewDevice,requiresApproval,deviceFingerprint,ipAddress:deviceInfo.ipAddress}),deviceTrustMint&&dtTable&&deviceTrustCfg?.enabled)try{let DT2=await Promise.resolve().then(() => (init_DeviceTrust(),exports_DeviceTrust)),DTStore2=await Promise.resolve().then(() => (init_store3(),exports_store)),{randomUUID:randomUUID11}=await import("crypto"),{raw,hash}=DT2.mintDeviceToken(),ttlSec=parseTimeToSeconds2(deviceTrustCfg.tokenExpiresIn??"30d");await DTStore2.insertDeviceRow(db,dtTable,{id:randomUUID11(),userId:params.userId,tokenHash:hash,status:deviceTrustMint,originSessionId:sessionId,label:deviceInfo.deviceName||`${deviceInfo.browserName||"Unknown"} on ${deviceInfo.osName||"Unknown"}`,deviceFingerprint,firstSeenIp:deviceInfo.ipAddress,expiresAt:new Date(Date.now()+ttlSec*1000)});let rawDomainDT=authentication.cookieDomain,resolvedDomainDT=rawDomainDT?process.env[rawDomainDT]??rawDomainDT:void 0,domainDT=resolvedDomainDT==="localhost"||resolvedDomainDT===".localhost"?void 0:resolvedDomainDT;deviceTokenToSet=DT2.buildDeviceTokenCookie(raw,{cookieName:deviceTrustCfg.cookieName,cookiePrefix:deviceTrustCfg.cookiePrefix,sameSite:deviceTrustCfg.sameSite,maxAgeSeconds:ttlSec,domain:domainDT,secure:!!domainDT})}catch(dtErr){logger2.warn("[AUTH] Device-trust token mint failed \u2014 continuing",{userId:params.userId,error:dtErr instanceof Error?dtErr.message:String(dtErr)})}return{requiresApproval,sessionId,deviceTokenCookie:deviceTokenToSet??void 0}},storeResetToken:async(userId,token,expiresAt,reqSchemaName)=>{let resetTokensTable=resolveTableForTenant("passwordResetTokens",reqSchemaName);if(!resetTokensTable||!db)return;await db.insert(resetTokensTable).values({userId,tokenHash:createHash4("sha256").update(token).digest("hex"),expiresAt})},getResetToken:async(token,reqSchemaName)=>{let{eq:eq66}=__require("drizzle-orm"),resetTokensTable=resolveTableForTenant("passwordResetTokens",reqSchemaName);if(!resetTokensTable||!db)return null;let tokenHash=createHash4("sha256").update(token).digest("hex"),row=(await db.select().from(resetTokensTable).where(eq66(resetTokensTable.tokenHash,tokenHash)).limit(1))[0];if(!row||row.usedAt)return null;return{userId:row.userId,expiresAt:row.expiresAt}},deleteResetToken:async(token,reqSchemaName)=>{let{eq:eq66}=__require("drizzle-orm"),resetTokensTable=resolveTableForTenant("passwordResetTokens",reqSchemaName);if(!resetTokensTable||!db)return;let tokenHash=createHash4("sha256").update(token).digest("hex");await db.delete(resetTokensTable).where(eq66(resetTokensTable.tokenHash,tokenHash))},revokeSessionInDb:async(sessionId,reason,reqSchemaName)=>{let revokeTable=resolveTableForTenant("userSessions",reqSchemaName)||resolveTableForTenant("user_sessions",reqSchemaName)||resolveTableForTenant("sessions",reqSchemaName)||sessionsTable;if(!revokeTable||!db)return;await db.update(revokeTable).set({isActive:!1,revokedAt:new Date,revokedReason:reason}).where(eq65(revokeTable.id,sessionId)),logger2.info("[AUTH] Session revoked in DB",{sessionId,reason})},sendResetEmail:async(email,token,request)=>{if(isEmailExempt(email,authentication?.emailExemptDomains))return logger2.info("[AUTH] Skipping reset email \u2014 domain exempt",{email}),{sent:!1,reason:"exempt"};let mailer=getEmailService();if(!mailer?.isAvailable())return logger2.warn("[AUTH] Cannot send reset email \u2014 no email provider configured"),{sent:!1,reason:"no_provider"};let configuredResetUrl=authentication.passwordReset?.redirectUrl||"http://localhost:3000/reset-password",resetUrl=request?buildEmailActionLink({request,configuredUrl:configuredResetUrl,path:extractConfiguredPath(configuredResetUrl,"/reset-password"),query:{token},allowedOrigins:trustedAppOrigins()}):`${configuredResetUrl}?token=${token}`,result=await mailer.sendEmail({to:email,subject:"Password Reset Request",html:`<p>Click the link to reset your password:</p><a href="${resetUrl}">${resetUrl}</a>`});if(result?.success===!1){let refused=result.rejected;return{sent:!1,reason:Array.isArray(refused)&&refused.length>0?"rejected":"error",detail:result.error}}return{sent:!0}},storeMagicToken:async(params,reqSchemaName)=>{let magicTokensTable=resolveTableForTenant("magicLinkTokens",reqSchemaName);if(!magicTokensTable||!db)return;await db.insert(magicTokensTable).values({userId:params.userId,email:params.email,tokenHash:params.tokenHash,expiresAt:params.expiresAt})},getMagicToken:async(tokenHash,reqSchemaName)=>{let{eq:eq66}=__require("drizzle-orm"),magicTokensTable=resolveTableForTenant("magicLinkTokens",reqSchemaName);if(!magicTokensTable||!db)return null;let row=(await db.select().from(magicTokensTable).where(eq66(magicTokensTable.tokenHash,tokenHash)).limit(1))[0];if(!row||row.usedAt)return null;return{userId:row.userId,email:row.email,tokenHash:row.tokenHash,expiresAt:row.expiresAt}},deleteMagicToken:async(tokenHash,reqSchemaName)=>{let{eq:eq66}=__require("drizzle-orm"),magicTokensTable=resolveTableForTenant("magicLinkTokens",reqSchemaName);if(!magicTokensTable||!db)return;await db.delete(magicTokensTable).where(eq66(magicTokensTable.tokenHash,tokenHash))}}}),logger2.info("[AUTH] Routes registered")}}if(resolvedOptions.storage?.enabled&&resolvedOptions.storage?.cdn?.enabled){let{createCdnRoutes:createCdnRoutes2,mergeCdnConfig:mergeCdnConfig2,mergeStorageConfig:mergeStorageConfig2}=(init_storage2(),__toCommonJS(exports_storage)),cdnConfig=mergeCdnConfig2(resolvedOptions.storage.cdn),storageConfig=mergeStorageConfig2(resolvedOptions.storage),filesTable=schemaTables.files;if(plugin.use(createCdnRoutes2({cdn:cdnConfig,storagePath:storageConfig.basePath,logger:logger2,getStorageProvider:()=>storageProvider,buildStorageProvider,getFileRecord:filesTable&&db?async(id,reqSchemaName)=>{let tbl=filesTable;if(reqSchemaName&&tenantRegistry){let ctx=tenantRegistry.getSchemaContext(reqSchemaName);if(ctx?.schemaTables.files)tbl=ctx.schemaTables.files}let t44=tbl,result=await db.select().from(t44).where(eq65(t44.id,id)).limit(1);if(result.length===0)return null;let record3=result[0];return{id:record3.id,name:record3.name,path:record3.path,mime_type:record3.mimeType||record3.mime_type,original_name:record3.originalName||record3.original_name}}:void 0})),logger2.info(`[Storage] CDN routes enabled at ${cdnConfig.basePath}`),filesTable&&db){let{createResumableRoutes:createResumableRoutes2}=(init_resumable(),__toCommonJS(exports_resumable)),resumable=createResumableRoutes2({basePath:storageConfig.basePath,storage:storageConfig,logger:logger2,getUserId:(request)=>request.headers.get("x-user-id"),canUpload:(request)=>{if(resolvedOptions.authorization?.enabled===!1)return!0;return checkAuthorizationFromJWT({userClaims:decodeHeaderList(request.headers.get("x-user-claims")),userRoles:decodeHeaderList(request.headers.get("x-user-roles")),claimScopes:decodeClaimScopesHeader(request.headers.get("x-user-claim-scopes")),method:"POST",entity:"files",logger:logger2,requireClaimSpecificity:resolvedOptions.authorization?.requireClaimSpecificity}).authorized},register:async(input)=>{let nodePath=__require("path"),{rename:rename6}=__require("fs/promises"),{randomUUID:randomUUID11}=__require("crypto"),id=randomUUID11(),extension2=nodePath.extname(input.originalName),storedName=`${id}${extension2}`,destination=nodePath.join(storageConfig.basePath,storedName);try{await rename6(input.partPath,destination)}catch(error3){return logger2.error("[Storage] A finished upload could not be moved into place",{error:error3}),null}let uploaded={id,name:storedName,originalName:input.originalName,path:storageConfig.basePath,mimeType:input.mimeType,size:input.size,createdAt:new Date},{buildFileRecordPayload:buildFileRecordPayload2,scheduleUploadMediaProcessing:scheduleUploadMediaProcessing2}=(init_storage2(),__toCommonJS(exports_storage)),t44=filesTable,payload={...buildFileRecordPayload2(uploaded,input.userId),type:input.type},row=(await db.insert(t44).values(payload).returning())[0];if(!row?.id)return null;return scheduleUploadMediaProcessing2([uploaded],{storagePath:storageConfig.basePath,media:{transform:mergeTransformConfig(resolvedOptions.storage?.cdn?.transform),video:mergeVideoConfig(resolvedOptions.storage?.cdn?.video),pdf:mergePdfConfig(resolvedOptions.storage?.cdn?.pdf)},logger:logger2}),{id:String(row.id)}}});plugin.use(resumable.plugin),setInterval(()=>{resumable.sweep(Date.now()).then((removed)=>{if(removed>0)logger2.info(`[Storage] Reclaimed ${removed} abandoned upload(s)`)}).catch(()=>{})},3600000).unref?.(),logger2.info("[Storage] Resumable uploads enabled at /uploads")}}if(resolvedOptions.notification?.enabled&&db){let notificationConfig=resolvedOptions.notification;if(notificationConfig.endpoints?.enabled!==!1){warnOnEntityBasePathCollision("Notification",notificationConfig.endpoints?.basePath||"/notifications",resolvedOptions.entities,logger2);let{routes:notificationRoutes}=createNotificationRoutes({db,schemaTables,config:notificationConfig,logger:logger2,getEmailService,tenantRegistry});plugin.use(notificationRoutes),logger2.info(`[Notification] Routes registered at ${notificationConfig.endpoints?.basePath||"/notifications"}`)}}if(resolvedOptions.verification?.enabled&&db){let{routes:verificationRoutes}=createVerificationRoutes({db,schemaTables,config:resolvedOptions.verification,notificationConfig:resolvedOptions.notification,logger:logger2,getEmailService,tenantRegistry});plugin.use(verificationRoutes)}if(resolvedOptions.backup?.enabled&&db){let{createBackupRoutes:createBackupRoutes2}=(init_backup(),__toCommonJS(exports_backup)),{routes:backupRoutes}=createBackupRoutes2({db,logger:logger2,config:{enabled:!0,basePath:resolvedOptions.backup.basePath||"/admin/backup",storagePath:resolvedOptions.backup.storagePath||"./backups",format:resolvedOptions.backup.format||"json",maxBackups:resolvedOptions.backup.maxBackups||50,allowRestore:resolvedOptions.backup.allowRestore??!0,excludeTables:resolvedOptions.backup.excludeTables||["audit_logs","backup_logs"],encryptionKey:resolvedOptions.backup.encryptionKey?process.env[resolvedOptions.backup.encryptionKey]||resolvedOptions.backup.encryptionKey:void 0,schedule:{enabled:resolvedOptions.backup.schedule?.enabled??!1,cron:resolvedOptions.backup.schedule?.cron||"0 2 * * *",retentionDays:resolvedOptions.backup.schedule?.retentionDays||30,timeZone:resolvedOptions.backup.schedule?.timeZone}},schemaTables,schemaName:targetSchemaName,tenantRegistry,lock:getRedisManager()});plugin.use(backupRoutes),logger2.info("[Backup] Routes registered",{basePath:resolvedOptions.backup.basePath||"/admin/backup",scheduleEnabled:resolvedOptions.backup.schedule?.enabled??!1})}if(resolvedOptions.authorization?.endpointDiscovery?.enabled&&db&&resolvedOptions.authentication?.mode!=="consumer"){let{createAuthorizationDiscoveryRoutes:createAuthorizationDiscoveryRoutes2}=(init_authorization(),__toCommonJS(exports_authorization));plugin.use(createAuthorizationDiscoveryRoutes2({db,schemaTables,logger:logger2,discovery:resolvedOptions.authorization.endpointDiscovery,readState:async(key2)=>{let rm3=getRedisManager();if(!rm3)return null;let res=await rm3.read(key2);return res?.success?res.data:null}})),logger2.info("[Authorization] Endpoint-discovery routes registered",{discover:"/authorization/discover",manifest:"/authorization/route-manifest"})}let pubsubClientManager=null;if(resolvedOptions.pubsub?.enabled){let redis=getRedisManager();if(redis){let pubsubConfig=resolvedOptions.pubsub,{plugin:pubsubPlugin,clientManager}=createPubSubRoutes({redis,logger:logger2,basePath:pubsubConfig.basePath||"/subs",wsPath:pubsubConfig.wsPath||"/api/events/subscribe",pubsubName:pubsubConfig.pubsubName||"pubsub-redis",maxClientsPerUser:pubsubConfig.maxClientsPerUser??10,maxTopicsPerClient:pubsubConfig.maxTopicsPerClient??64,wsIdleTimeout:pubsubConfig.wsIdleTimeout??120,ack:{enabled:pubsubConfig.ack?.enabled??!0,ttlSeconds:pubsubConfig.ack?.ttlSeconds??300,maxRetries:pubsubConfig.ack?.maxRetries??3,retryIntervalMs:pubsubConfig.ack?.retryIntervalMs??5000},presence:{enabled:pubsubConfig.presence?.enabled??!0,debounceMs:pubsubConfig.presence?.debounceMs??5000},cleanupIntervalMs:pubsubConfig.cleanupIntervalMs??60000,daprApiToken:pubsubConfig.daprApiToken,getLiveMonitoringService:()=>liveMonitoringService,authenticate:envResolved.accessTokenSecret?(headers)=>{let wsTokens=parseTokenValuesFromHeaders(headers,tokenNames);if(!wsTokens.access_token)return logger2.debug("[PubSub] WS handshake rejected: no access token presented"),{reason:"no-token"};let jwtResult=verifyJWT(wsTokens.access_token,envResolved.accessTokenSecret||"",{issuer:authentication?.accessToken?.issuer,audience:authentication?.accessToken?.audience});if(!jwtResult.valid){let reason=classifyRefusal(jwtResult.error);return logger2.warn("[PubSub] WS handshake rejected: JWT verification failed",{reason:jwtResult.error,classified:reason}),{reason}}let sub=jwtResult.payload?.sub;return typeof sub==="string"&&sub.length>0?{userId:sub}:{reason:"token-without-subject"}}:void 0});plugin.use(pubsubPlugin),pubsubClientManager=clientManager,logger2.info("[PubSub] Enabled",{basePath:pubsubConfig.basePath||"/subs",wsPath:pubsubConfig.wsPath||"/api/events/subscribe"})}else logger2.warn("[PubSub] pubsub is enabled but Redis is not configured. Disabling PubSub.")}if(resolvedOptions.chat?.enabled&&db){let chatConfig=mergeChatConfig(resolvedOptions.chat),chatStorageConfig=mergeStorageConfig(resolvedOptions.storage),attachmentsAvailable=resolvedOptions.storage?.enabled===!0&&resolvedOptions.storage?.cdn?.enabled===!0&&chatConfig.attachments.enabled,cdnBasePath=resolvedOptions.storage?.cdn?.basePath||"/cdn",cdnMedia={transform:mergeTransformConfig(resolvedOptions.storage?.cdn?.transform),video:mergeVideoConfig(resolvedOptions.storage?.cdn?.video),pdf:mergePdfConfig(resolvedOptions.storage?.cdn?.pdf)},{routes:chatRoutes}=createChatRoutes({db,schemaTables,config:chatConfig,logger:logger2,broadcaster:pubsubClientManager,tenantRegistry,storageConfig:chatStorageConfig,attachmentsAvailable,cdnBasePath,cdnMedia});plugin.use(chatRoutes),logger2.info("[Chat] Enabled",{basePath:chatConfig.basePath,attachmentsAvailable,realtime:pubsubClientManager!==null})}if(resolvedOptions.payment?.enabled&&db){let{createPaymentService:createPaymentService2}=(init_Payment(),__toCommonJS(exports_Payment)),{createPaymentRoutes:createPaymentRoutes2}=(init_payment(),__toCommonJS(exports_payment)),paymentService=createPaymentService2(resolvedOptions);if(paymentService){let paymentConfig=resolvedOptions.payment,marketplaceServices=null;if(paymentConfig?.marketplace?.enabled){let{createMarketplaceServices:createMarketplaceServices2}=(init_Payment(),__toCommonJS(exports_Payment));marketplaceServices=createMarketplaceServices2({options:resolvedOptions,logger:logger2,getDb:()=>db,provider:paymentService.providerInstance,schemaTables})}let paymentRoutes=createPaymentRoutes2({provider:paymentService.providerInstance,webhookSecret:paymentService.webhookSecret,getPayoutService:()=>marketplaceServices?.payoutService??null,basePath:paymentConfig?.basePath||"/payment",defaultCurrency:paymentConfig?.defaultCurrency||"TRY",defaultLocale:paymentConfig?.defaultLocale||"tr",successRedirectUrl:paymentConfig?.successRedirectUrl||"/payment/success",failedRedirectUrl:paymentConfig?.failedRedirectUrl||"/payment/failed",errorRedirectUrl:paymentConfig?.errorRedirectUrl||"/payment/error",callbackUrl:paymentConfig?.callbackUrl,savedMethodsEnabled:paymentConfig?.savedMethodsEnabled??!0,threeDSecureEnabled:paymentConfig?.threeDSecureEnabled??!0,subMerchantsEnabled:paymentConfig?.subMerchantsEnabled??!1,transactionsTable:schemaTables.paymentTransactions??schemaTables.payment_transactions,methodsTable:schemaTables.paymentMethods??schemaTables.payment_methods,webhookLogsTable:schemaTables.paymentWebhookLogs??schemaTables.payment_webhook_logs,subMerchantsTable:schemaTables.paymentSubMerchants??schemaTables.payment_sub_merchants,commissionSplitsTable:schemaTables.paymentCommissionSplits??schemaTables.payment_commission_splits,productsTable:schemaTables.paymentProducts??schemaTables.payment_products,pricesTable:schemaTables.paymentPrices??schemaTables.payment_prices,customersTable:schemaTables.paymentCustomers??schemaTables.payment_customers,subscriptionsTable:schemaTables.paymentSubscriptions??schemaTables.payment_subscriptions,invoicesTable:schemaTables.paymentInvoices??schemaTables.payment_invoices,db,logger:logger2});if(plugin.use(paymentRoutes),logger2.info("[Payment] Routes registered",{basePath:paymentConfig?.basePath||"/payment",provider:paymentService.provider}),marketplaceServices){let{createMarketplaceRoutes:createMarketplaceRoutes2}=(init_marketplace(),__toCommonJS(exports_marketplace)),services=marketplaceServices;createMarketplaceRoutes2(plugin,{getMarketplaceService:()=>services.marketplaceService,getPayoutService:()=>services.payoutService,basePath:paymentConfig?.basePath||"/payment",logger:logger2}),logger2.info("[Payment] Marketplace routes registered",{basePath:`${paymentConfig?.basePath||"/payment"}/marketplace`})}}}let cohortConfig=authentication?.cohorts;if(cohortConfig?.enabled!==!1&&!isConsumerMode&&db){let cohortBasePath=cohortConfig?.basePath||"/auth/admin/cohorts",resolveTable=(key2,fallback)=>schemaTables[key2]??(fallback?schemaTables[fallback]:null)??null,resolvedCohortsTable=resolveTable("userCohorts","user_cohorts");if(!resolvedCohortsTable)logger2.warn("[Cohort] user_cohorts table not found in schema \u2014 cohort routes will be inactive. Re-generate schema with nucleus-core >= 0.9.120");if(plugin.use(createCohortRoutes({db,logger:logger2,cohortsTable:resolvedCohortsTable,usersTable:resolveTable("users"),rolesTable:resolveTable("roles"),userRolesTable:resolveTable("userRoles","user_roles"),profilesTable:resolveTable("profiles"),basePath:cohortBasePath,get defaultRole(){return resolvedOptions.authentication?.defaultRole},get defaultRoles(){return resolvedOptions.authentication?.defaultRoles},emailExemptDomains:authentication?.emailExemptDomains,passwordPolicy:authentication?.passwordPolicy})),resolvedCohortsTable)logger2.info("[Cohort] Routes registered",{basePath:cohortBasePath})}if(resolvedOptions.configManagement?.enabled){let configBasePath=resolvedOptions.configManagement.basePath||"/nucleus/config";plugin.use(createConfigRoutes({logger:logger2,resolvedOptions,configFilePath,basePath:configBasePath,db,schemaTables,getRedis:()=>{let redis=getRedisManager();if(!redis)return null;return{read:async(key2)=>{let r2=await redis.read(key2);return{success:r2.success,data:r2.success?r2.data:null}},create:async(key2,value2)=>{return{success:(await redis.create(key2,value2)).success}}}},onConfigUpdate:(section,_newValue)=>{logger2.info(`[ConfigManagement] Section "${section}" updated in-memory`,{section})}})),logger2.info(`[ConfigManagement] Routes enabled at ${configBasePath}`)}if(resolvedOptions.secrets?.enabled){let secretsBasePath=resolvedOptions.secrets.basePath||"/secrets";warnOnEntityBasePathCollision("Secrets",secretsBasePath,resolvedOptions.entities,logger2),plugin.use(createSecretsRoutes({logger:logger2,basePath:secretsBasePath,db,schemaTables,resolvedOptions,getService:()=>secretsService,getEmailService,getStorageProvider:()=>storageProvider,buildStorageProvider,adminRoles:resolvedOptions.secrets.adminRoles})),logger2.info(`[Secrets] Routes enabled at ${secretsBasePath}`)}if(resolvedOptions.integrations?.enabled){let integrationsBasePath=resolvedOptions.integrations.basePath||"/integrations";warnOnEntityBasePathCollision("Integrations",integrationsBasePath,resolvedOptions.entities,logger2),plugin.use(createIntegrationRoutes({logger:logger2,basePath:integrationsBasePath,db,schemaTables,resolvedOptions,getEncryptionKey:()=>resolveMasterKey(resolvedOptions.secrets?.encryptionKey)??null,getLockStore:()=>getRedisManager(),publish:(topic,payload)=>pubsubClientManager?.broadcastEvent(topic,payload),adminRoles:resolvedOptions.integrations.adminRoles}))}plugin.onStart((app)=>{let requiredBody=requiredBodyCeiling({storageEnabled:resolvedOptions.storage?.enabled,maxFileSizeBytes:resolvedOptions.storage?.maxFileSizeBytes,maxFiles:resolvedOptions.storage?.formData?.maxFiles}),complaint=bodyCeilingComplaint({configured:app.config?.serve?.maxRequestBodySize,required:requiredBody});if(complaint)logger2.error(`[Storage] ${complaint}`);let memoryComplaint=memoryCeilingComplaint({required:requiredBody,cgroupLimit:readCgroupLimitBytes()});if(memoryComplaint)logger2.error(`[Storage] ${memoryComplaint}`);let memoryAdvice=readRuntimeMemoryAdvice();if(memoryAdvice){let mib=(bytes)=>`${Math.round(bytes/1024/1024)} MiB`;logger2.warn(`[Runtime] The JS engine sizes its heap for ${mib(memoryAdvice.hostTotal)} but this container is capped at ${mib(memoryAdvice.cgroupLimit)} \u2014 it feels no memory `+"pressure and may grow past the limit and be OOM-killed. Raising the container memory limit delays this; no runtime option we have measured prevents it.")}let port=Number(process.env.PORT)||3000,appId=resolvedOptions.appId||"nucleus",mode=resolvedOptions.mode||"production";console.log(""),console.log(` \x1B[32m\uD83D\uDE80 ${appId}\x1B[0m \x1B[90mv${Date.now()}\x1B[0m`),console.log(` \x1B[36m\u279C\x1B[0m Local: \x1B[36mhttp://localhost:${port}\x1B[0m`),console.log(` \x1B[36m\u279C\x1B[0m Mode: \x1B[33m${mode}\x1B[0m`),console.log("")});let shuttingDown=!1,drainResources=async(trigger)=>{if(shuttingDown)return;shuttingDown=!0,logger2.info(`[Shutdown] ${trigger} \u2014 draining resources`);try{liveMonitoringService?.stop(),monitoringService?.stop(),secretsService?.stop(),storageProvider?.close()}catch(err){logger2.warn("[Shutdown] failed stopping monitoring",{error:err instanceof Error?err.message:String(err)})}try{let redisClient=getRedisManager()?.getDirectClient?.();if(redisClient)await redisClient.quit()}catch(err){logger2.warn("[Shutdown] failed closing Redis",{error:err instanceof Error?err.message:String(err)})}try{for(let timer of backgroundIntervals)clearInterval(timer);backgroundIntervals.length=0}catch(err){logger2.warn("[Shutdown] failed clearing background intervals",{error:err instanceof Error?err.message:String(err)})}try{let{destroyAckCleanup:destroyAckCleanup2}=await Promise.resolve().then(() => (init_ack_manager(),exports_ack_manager));destroyAckCleanup2()}catch{}try{if(dbPool)await dbPool.end()}catch(err){logger2.warn("[Shutdown] failed draining DB pool",{error:err instanceof Error?err.message:String(err)})}try{await lifecycleRecorder?.recordStop(trigger)}catch{}logger2.info("[Shutdown] complete")};if(plugin.onStop(async()=>{await drainResources("Elysia onStop")}),resolvedOptions.gracefulShutdown!==!1){let onSignal=(signal)=>{drainResources(signal).finally(()=>process.exit(0))};process.once("SIGTERM",()=>onSignal("SIGTERM")),process.once("SIGINT",()=>onSignal("SIGINT"))}return plugin}init_AzureEmailService();init_Gmail();export{useUpload,usePubSubStore,usePubSub,uploadWithProgress,uploadPercent,uploadFraction,serverFetch,secondsRemaining,requiredBodyCeiling,parseCron2 as parseCron,matchesCron,isDue,generateVerificationEndpoints,generateTenantEndpoints,generateSystemTableEndpoints,generateMonitoringEndpoints,generateMarketplaceEndpoints,generateEndpointsFromConfig,generateDomainEndpoints,generateCohortEndpoints,generateChatEndpoints,generateAuthEndpoints,generateAllEndpoints,generateAdminEndpoints,describeCron,decodeHeaderList,createServerFactory,createRateWindow,createApiHook,buildProgress,VERIFICATION_ENDPOINTS,TENANT_ENDPOINTS,ServerFetch,SYSTEM_TABLES,PAYMENT_ENDPOINTS,NucleusElysiaPlugin,MONITORING_ENDPOINTS,MARKETPLACE_ENDPOINTS,GmailService,DOMAIN_ENDPOINTS,CONFIG_ENDPOINTS,COHORT_ENDPOINTS,CHAT_ENDPOINTS,AzureEmailService,AUTH_ENDPOINT_CONFIGS,AUTH_ENDPOINTS};
2033
+ `)}deliver(getEmailService(),{to:user.email,subject,html:emailHtml},"[AUTH] login notification").then((report)=>{if(report.level==="warn")logger2.warn(report.message,{userId:params.userId,trustScore,requiresApproval});else logger2.info(report.message,{userId:params.userId})})}}}if(logger2.info("[AUTH] Session saved to DB",{sessionId,userId:params.userId,isNewDevice,requiresApproval,deviceFingerprint,ipAddress:deviceInfo.ipAddress}),deviceTrustMint&&dtTable&&deviceTrustCfg?.enabled)try{let DT2=await Promise.resolve().then(() => (init_DeviceTrust(),exports_DeviceTrust)),DTStore2=await Promise.resolve().then(() => (init_store3(),exports_store)),{randomUUID:randomUUID11}=await import("crypto"),{raw,hash}=DT2.mintDeviceToken(),ttlSec=parseTimeToSeconds2(deviceTrustCfg.tokenExpiresIn??"30d");await DTStore2.insertDeviceRow(db,dtTable,{id:randomUUID11(),userId:params.userId,tokenHash:hash,status:deviceTrustMint,originSessionId:sessionId,label:deviceInfo.deviceName||`${deviceInfo.browserName||"Unknown"} on ${deviceInfo.osName||"Unknown"}`,deviceFingerprint,firstSeenIp:deviceInfo.ipAddress,expiresAt:new Date(Date.now()+ttlSec*1000)});let rawDomainDT=authentication.cookieDomain,resolvedDomainDT=rawDomainDT?process.env[rawDomainDT]??rawDomainDT:void 0,domainDT=resolvedDomainDT==="localhost"||resolvedDomainDT===".localhost"?void 0:resolvedDomainDT;deviceTokenToSet=DT2.buildDeviceTokenCookie(raw,{cookieName:deviceTrustCfg.cookieName,cookiePrefix:deviceTrustCfg.cookiePrefix,sameSite:deviceTrustCfg.sameSite,maxAgeSeconds:ttlSec,domain:domainDT,secure:!!domainDT})}catch(dtErr){logger2.warn("[AUTH] Device-trust token mint failed \u2014 continuing",{userId:params.userId,error:dtErr instanceof Error?dtErr.message:String(dtErr)})}return{requiresApproval,sessionId,deviceTokenCookie:deviceTokenToSet??void 0}},storeResetToken:async(userId,token,expiresAt,reqSchemaName)=>{let resetTokensTable=resolveTableForTenant("passwordResetTokens",reqSchemaName);if(!resetTokensTable||!db)return;await db.insert(resetTokensTable).values({userId,tokenHash:createHash4("sha256").update(token).digest("hex"),expiresAt})},getResetToken:async(token,reqSchemaName)=>{let{eq:eq66}=__require("drizzle-orm"),resetTokensTable=resolveTableForTenant("passwordResetTokens",reqSchemaName);if(!resetTokensTable||!db)return null;let tokenHash=createHash4("sha256").update(token).digest("hex"),row=(await db.select().from(resetTokensTable).where(eq66(resetTokensTable.tokenHash,tokenHash)).limit(1))[0];if(!row||row.usedAt)return null;return{userId:row.userId,expiresAt:row.expiresAt}},deleteResetToken:async(token,reqSchemaName)=>{let{eq:eq66}=__require("drizzle-orm"),resetTokensTable=resolveTableForTenant("passwordResetTokens",reqSchemaName);if(!resetTokensTable||!db)return;let tokenHash=createHash4("sha256").update(token).digest("hex");await db.delete(resetTokensTable).where(eq66(resetTokensTable.tokenHash,tokenHash))},revokeSessionInDb:async(sessionId,reason,reqSchemaName)=>{let revokeTable=resolveTableForTenant("userSessions",reqSchemaName)||resolveTableForTenant("user_sessions",reqSchemaName)||resolveTableForTenant("sessions",reqSchemaName)||sessionsTable;if(!revokeTable||!db)return;await db.update(revokeTable).set({isActive:!1,revokedAt:new Date,revokedReason:reason}).where(eq65(revokeTable.id,sessionId)),logger2.info("[AUTH] Session revoked in DB",{sessionId,reason})},sendResetEmail:async(email,token,request)=>{if(isEmailExempt(email,authentication?.emailExemptDomains))return logger2.info("[AUTH] Skipping reset email \u2014 domain exempt",{email}),{sent:!1,reason:"exempt"};let mailer=getEmailService();if(!mailer?.isAvailable())return logger2.warn("[AUTH] Cannot send reset email \u2014 no email provider configured"),{sent:!1,reason:"no_provider"};let configuredResetUrl=authentication.passwordReset?.redirectUrl||"http://localhost:3000/reset-password",resetUrl=request?buildEmailActionLink({request,configuredUrl:configuredResetUrl,path:extractConfiguredPath(configuredResetUrl,"/reset-password"),query:{token},allowedOrigins:trustedAppOrigins()}):`${configuredResetUrl}?token=${token}`,result=await mailer.sendEmail({to:email,subject:"Password Reset Request",html:`<p>Click the link to reset your password:</p><a href="${resetUrl}">${resetUrl}</a>`});if(result?.success===!1){let refused=result.rejected;return{sent:!1,reason:Array.isArray(refused)&&refused.length>0?"rejected":"error",detail:result.error}}return{sent:!0}},storeMagicToken:async(params,reqSchemaName)=>{let magicTokensTable=resolveTableForTenant("magicLinkTokens",reqSchemaName);if(!magicTokensTable||!db)return;await db.insert(magicTokensTable).values({userId:params.userId,email:params.email,tokenHash:params.tokenHash,expiresAt:params.expiresAt})},getMagicToken:async(tokenHash,reqSchemaName)=>{let{eq:eq66}=__require("drizzle-orm"),magicTokensTable=resolveTableForTenant("magicLinkTokens",reqSchemaName);if(!magicTokensTable||!db)return null;let row=(await db.select().from(magicTokensTable).where(eq66(magicTokensTable.tokenHash,tokenHash)).limit(1))[0];if(!row||row.usedAt)return null;return{userId:row.userId,email:row.email,tokenHash:row.tokenHash,expiresAt:row.expiresAt}},deleteMagicToken:async(tokenHash,reqSchemaName)=>{let{eq:eq66}=__require("drizzle-orm"),magicTokensTable=resolveTableForTenant("magicLinkTokens",reqSchemaName);if(!magicTokensTable||!db)return;await db.delete(magicTokensTable).where(eq66(magicTokensTable.tokenHash,tokenHash))}}}),logger2.info("[AUTH] Routes registered")}}if(resolvedOptions.storage?.enabled&&resolvedOptions.storage?.cdn?.enabled){let{createCdnRoutes:createCdnRoutes2,mergeCdnConfig:mergeCdnConfig2,mergeStorageConfig:mergeStorageConfig2}=(init_storage2(),__toCommonJS(exports_storage)),cdnConfig=mergeCdnConfig2(resolvedOptions.storage.cdn),storageConfig=mergeStorageConfig2(resolvedOptions.storage),filesTable=schemaTables.files;if(plugin.use(createCdnRoutes2({cdn:cdnConfig,storagePath:storageConfig.basePath,logger:logger2,getStorageProvider:()=>storageProvider,buildStorageProvider,getFileRecord:filesTable&&db?async(id,reqSchemaName)=>{let tbl=filesTable;if(reqSchemaName&&tenantRegistry){let ctx=tenantRegistry.getSchemaContext(reqSchemaName);if(ctx?.schemaTables.files)tbl=ctx.schemaTables.files}let t44=tbl,result=await db.select().from(t44).where(eq65(t44.id,id)).limit(1);if(result.length===0)return null;let record3=result[0];return{id:record3.id,name:record3.name,path:record3.path,mime_type:record3.mimeType||record3.mime_type,original_name:record3.originalName||record3.original_name}}:void 0})),logger2.info(`[Storage] CDN routes enabled at ${cdnConfig.basePath}`),filesTable&&db){let{createResumableRoutes:createResumableRoutes2}=(init_resumable(),__toCommonJS(exports_resumable)),resumable=createResumableRoutes2({basePath:storageConfig.basePath,storage:storageConfig,logger:logger2,getUserId:(request)=>request.headers.get("x-user-id"),canUpload:(request)=>{if(resolvedOptions.authorization?.enabled===!1)return!0;return checkAuthorizationFromJWT({userClaims:decodeHeaderList(request.headers.get("x-user-claims")),userRoles:decodeHeaderList(request.headers.get("x-user-roles")),claimScopes:decodeClaimScopesHeader(request.headers.get("x-user-claim-scopes")),method:"POST",entity:"files",logger:logger2,requireClaimSpecificity:resolvedOptions.authorization?.requireClaimSpecificity}).authorized},register:async(input)=>{let nodePath=__require("path"),{rename:rename6}=__require("fs/promises"),{randomUUID:randomUUID11}=__require("crypto"),id=randomUUID11(),extension2=nodePath.extname(input.originalName),storedName=`${id}${extension2}`,destination=nodePath.join(storageConfig.basePath,storedName);try{await rename6(input.partPath,destination)}catch(error3){return logger2.error("[Storage] A finished upload could not be moved into place",{error:error3}),null}let uploaded={id,name:storedName,originalName:input.originalName,path:storageConfig.basePath,mimeType:input.mimeType,size:input.size,createdAt:new Date},{buildFileRecordPayload:buildFileRecordPayload2,scheduleUploadMediaProcessing:scheduleUploadMediaProcessing2}=(init_storage2(),__toCommonJS(exports_storage)),t44=filesTable,payload={...buildFileRecordPayload2(uploaded,input.userId),type:input.type},row=(await db.insert(t44).values(payload).returning())[0];if(!row?.id)return null;return scheduleUploadMediaProcessing2([uploaded],{storagePath:storageConfig.basePath,media:{transform:mergeTransformConfig(resolvedOptions.storage?.cdn?.transform),video:mergeVideoConfig(resolvedOptions.storage?.cdn?.video),pdf:mergePdfConfig(resolvedOptions.storage?.cdn?.pdf)},logger:logger2}),{id:String(row.id)}}});plugin.use(resumable.plugin),setInterval(()=>{resumable.sweep(Date.now()).then((removed)=>{if(removed>0)logger2.info(`[Storage] Reclaimed ${removed} abandoned upload(s)`)}).catch(()=>{})},3600000).unref?.(),logger2.info("[Storage] Resumable uploads enabled at /uploads")}}if(resolvedOptions.notification?.enabled&&db){let notificationConfig=resolvedOptions.notification;if(notificationConfig.endpoints?.enabled!==!1){warnOnEntityBasePathCollision("Notification",notificationConfig.endpoints?.basePath||"/notifications",resolvedOptions.entities,logger2);let{routes:notificationRoutes}=createNotificationRoutes({db,schemaTables,config:notificationConfig,logger:logger2,getEmailService,tenantRegistry});plugin.use(notificationRoutes),logger2.info(`[Notification] Routes registered at ${notificationConfig.endpoints?.basePath||"/notifications"}`)}}if(resolvedOptions.verification?.enabled&&db){let{routes:verificationRoutes}=createVerificationRoutes({db,schemaTables,config:resolvedOptions.verification,notificationConfig:resolvedOptions.notification,logger:logger2,getEmailService,tenantRegistry});plugin.use(verificationRoutes)}if(resolvedOptions.backup?.enabled&&db){let{createBackupRoutes:createBackupRoutes2}=(init_backup(),__toCommonJS(exports_backup)),{routes:backupRoutes}=createBackupRoutes2({db,logger:logger2,config:{enabled:!0,basePath:resolvedOptions.backup.basePath||"/admin/backup",storagePath:resolvedOptions.backup.storagePath||"./backups",format:resolvedOptions.backup.format||"json",maxBackups:resolvedOptions.backup.maxBackups||50,allowRestore:resolvedOptions.backup.allowRestore??!0,excludeTables:resolvedOptions.backup.excludeTables||["audit_logs","backup_logs"],encryptionKey:resolvedOptions.backup.encryptionKey?process.env[resolvedOptions.backup.encryptionKey]||resolvedOptions.backup.encryptionKey:void 0,schedule:{enabled:resolvedOptions.backup.schedule?.enabled??!1,cron:resolvedOptions.backup.schedule?.cron||"0 2 * * *",retentionDays:resolvedOptions.backup.schedule?.retentionDays||30,timeZone:resolvedOptions.backup.schedule?.timeZone}},schemaTables,schemaName:targetSchemaName,tenantRegistry,lock:getRedisManager()});plugin.use(backupRoutes),logger2.info("[Backup] Routes registered",{basePath:resolvedOptions.backup.basePath||"/admin/backup",scheduleEnabled:resolvedOptions.backup.schedule?.enabled??!1})}if(resolvedOptions.authorization?.endpointDiscovery?.enabled&&db&&resolvedOptions.authentication?.mode!=="consumer"){let{createAuthorizationDiscoveryRoutes:createAuthorizationDiscoveryRoutes2}=(init_authorization(),__toCommonJS(exports_authorization));plugin.use(createAuthorizationDiscoveryRoutes2({db,schemaTables,logger:logger2,discovery:resolvedOptions.authorization.endpointDiscovery,readState:async(key2)=>{let rm3=getRedisManager();if(!rm3)return null;let res=await rm3.read(key2);return res?.success?res.data:null}})),logger2.info("[Authorization] Endpoint-discovery routes registered",{discover:"/authorization/discover",manifest:"/authorization/route-manifest"})}let pubsubClientManager=null;if(resolvedOptions.pubsub?.enabled){let redis=getRedisManager();if(redis){let pubsubConfig=resolvedOptions.pubsub,{plugin:pubsubPlugin,clientManager}=createPubSubRoutes({redis,logger:logger2,basePath:pubsubConfig.basePath||"/subs",wsPath:pubsubConfig.wsPath||"/api/events/subscribe",pubsubName:pubsubConfig.pubsubName||"pubsub-redis",maxClientsPerUser:pubsubConfig.maxClientsPerUser??10,maxTopicsPerClient:pubsubConfig.maxTopicsPerClient??64,wsIdleTimeout:pubsubConfig.wsIdleTimeout??120,ack:{enabled:pubsubConfig.ack?.enabled??!0,ttlSeconds:pubsubConfig.ack?.ttlSeconds??300,maxRetries:pubsubConfig.ack?.maxRetries??3,retryIntervalMs:pubsubConfig.ack?.retryIntervalMs??5000},presence:{enabled:pubsubConfig.presence?.enabled??!0,debounceMs:pubsubConfig.presence?.debounceMs??5000},cleanupIntervalMs:pubsubConfig.cleanupIntervalMs??60000,daprApiToken:pubsubConfig.daprApiToken,getLiveMonitoringService:()=>liveMonitoringService,authenticate:envResolved.accessTokenSecret?(headers)=>{let wsTokens=parseTokenValuesFromHeaders(headers,tokenNames);if(!wsTokens.access_token)return logger2.debug("[PubSub] WS handshake rejected: no access token presented"),{reason:"no-token"};let jwtResult=verifyJWT(wsTokens.access_token,envResolved.accessTokenSecret||"",{issuer:authentication?.accessToken?.issuer,audience:authentication?.accessToken?.audience});if(!jwtResult.valid){let reason=classifyRefusal(jwtResult.error);return logger2.warn("[PubSub] WS handshake rejected: JWT verification failed",{reason:jwtResult.error,classified:reason}),{reason}}let sub=jwtResult.payload?.sub;return typeof sub==="string"&&sub.length>0?{userId:sub}:{reason:"token-without-subject"}}:void 0});plugin.use(pubsubPlugin),pubsubClientManager=clientManager,logger2.info("[PubSub] Enabled",{basePath:pubsubConfig.basePath||"/subs",wsPath:pubsubConfig.wsPath||"/api/events/subscribe"})}else logger2.warn("[PubSub] pubsub is enabled but Redis is not configured. Disabling PubSub.")}if(resolvedOptions.chat?.enabled&&db){let chatConfig=mergeChatConfig(resolvedOptions.chat),chatStorageConfig=mergeStorageConfig(resolvedOptions.storage),attachmentsAvailable=resolvedOptions.storage?.enabled===!0&&resolvedOptions.storage?.cdn?.enabled===!0&&chatConfig.attachments.enabled,cdnBasePath=resolvedOptions.storage?.cdn?.basePath||"/cdn",cdnMedia={transform:mergeTransformConfig(resolvedOptions.storage?.cdn?.transform),video:mergeVideoConfig(resolvedOptions.storage?.cdn?.video),pdf:mergePdfConfig(resolvedOptions.storage?.cdn?.pdf)},{routes:chatRoutes}=createChatRoutes({db,schemaTables,config:chatConfig,logger:logger2,broadcaster:pubsubClientManager,tenantRegistry,storageConfig:chatStorageConfig,attachmentsAvailable,cdnBasePath,cdnMedia});plugin.use(chatRoutes),logger2.info("[Chat] Enabled",{basePath:chatConfig.basePath,attachmentsAvailable,realtime:pubsubClientManager!==null})}if(resolvedOptions.payment?.enabled&&db){let{createPaymentService:createPaymentService2}=(init_Payment(),__toCommonJS(exports_Payment)),{createPaymentRoutes:createPaymentRoutes2}=(init_payment(),__toCommonJS(exports_payment)),paymentService=createPaymentService2(resolvedOptions);if(paymentService){let paymentConfig=resolvedOptions.payment,marketplaceServices=null;if(paymentConfig?.marketplace?.enabled){let{createMarketplaceServices:createMarketplaceServices2}=(init_Payment(),__toCommonJS(exports_Payment));marketplaceServices=createMarketplaceServices2({options:resolvedOptions,logger:logger2,getDb:()=>db,provider:paymentService.providerInstance,schemaTables})}let paymentRoutes=createPaymentRoutes2({provider:paymentService.providerInstance,webhookSecret:paymentService.webhookSecret,getPayoutService:()=>marketplaceServices?.payoutService??null,basePath:paymentConfig?.basePath||"/payment",defaultCurrency:paymentConfig?.defaultCurrency||"TRY",defaultLocale:paymentConfig?.defaultLocale||"tr",successRedirectUrl:paymentConfig?.successRedirectUrl||"/payment/success",failedRedirectUrl:paymentConfig?.failedRedirectUrl||"/payment/failed",errorRedirectUrl:paymentConfig?.errorRedirectUrl||"/payment/error",callbackUrl:paymentConfig?.callbackUrl,savedMethodsEnabled:paymentConfig?.savedMethodsEnabled??!0,threeDSecureEnabled:paymentConfig?.threeDSecureEnabled??!0,subMerchantsEnabled:paymentConfig?.subMerchantsEnabled??!1,transactionsTable:schemaTables.paymentTransactions??schemaTables.payment_transactions,methodsTable:schemaTables.paymentMethods??schemaTables.payment_methods,webhookLogsTable:schemaTables.paymentWebhookLogs??schemaTables.payment_webhook_logs,subMerchantsTable:schemaTables.paymentSubMerchants??schemaTables.payment_sub_merchants,commissionSplitsTable:schemaTables.paymentCommissionSplits??schemaTables.payment_commission_splits,productsTable:schemaTables.paymentProducts??schemaTables.payment_products,pricesTable:schemaTables.paymentPrices??schemaTables.payment_prices,customersTable:schemaTables.paymentCustomers??schemaTables.payment_customers,subscriptionsTable:schemaTables.paymentSubscriptions??schemaTables.payment_subscriptions,invoicesTable:schemaTables.paymentInvoices??schemaTables.payment_invoices,db,logger:logger2});if(plugin.use(paymentRoutes),logger2.info("[Payment] Routes registered",{basePath:paymentConfig?.basePath||"/payment",provider:paymentService.provider}),marketplaceServices){let{createMarketplaceRoutes:createMarketplaceRoutes2}=(init_marketplace(),__toCommonJS(exports_marketplace)),services=marketplaceServices;createMarketplaceRoutes2(plugin,{getMarketplaceService:()=>services.marketplaceService,getPayoutService:()=>services.payoutService,basePath:paymentConfig?.basePath||"/payment",logger:logger2}),logger2.info("[Payment] Marketplace routes registered",{basePath:`${paymentConfig?.basePath||"/payment"}/marketplace`})}}}let cohortConfig=authentication?.cohorts;if(cohortConfig?.enabled!==!1&&!isConsumerMode&&db){let cohortBasePath=cohortConfig?.basePath||"/auth/admin/cohorts",resolveTable=(key2,fallback)=>schemaTables[key2]??(fallback?schemaTables[fallback]:null)??null,resolvedCohortsTable=resolveTable("userCohorts","user_cohorts");if(!resolvedCohortsTable)logger2.warn("[Cohort] user_cohorts table not found in schema \u2014 cohort routes will be inactive. Re-generate schema with nucleus-core >= 0.9.120");if(plugin.use(createCohortRoutes({db,logger:logger2,cohortsTable:resolvedCohortsTable,usersTable:resolveTable("users"),rolesTable:resolveTable("roles"),userRolesTable:resolveTable("userRoles","user_roles"),profilesTable:resolveTable("profiles"),basePath:cohortBasePath,get defaultRole(){return resolvedOptions.authentication?.defaultRole},get defaultRoles(){return resolvedOptions.authentication?.defaultRoles},emailExemptDomains:authentication?.emailExemptDomains,passwordPolicy:authentication?.passwordPolicy})),resolvedCohortsTable)logger2.info("[Cohort] Routes registered",{basePath:cohortBasePath})}if(resolvedOptions.configManagement?.enabled){let configBasePath=resolvedOptions.configManagement.basePath||"/nucleus/config";plugin.use(createConfigRoutes({logger:logger2,resolvedOptions,configFilePath,basePath:configBasePath,db,schemaTables,getRedis:()=>{let redis=getRedisManager();if(!redis)return null;return{read:async(key2)=>{let r2=await redis.read(key2);return{success:r2.success,data:r2.success?r2.data:null}},create:async(key2,value2)=>{return{success:(await redis.create(key2,value2)).success}}}},onConfigUpdate:(section,_newValue)=>{logger2.info(`[ConfigManagement] Section "${section}" updated in-memory`,{section})}})),logger2.info(`[ConfigManagement] Routes enabled at ${configBasePath}`)}if(resolvedOptions.secrets?.enabled){let secretsBasePath=resolvedOptions.secrets.basePath||"/secrets";warnOnEntityBasePathCollision("Secrets",secretsBasePath,resolvedOptions.entities,logger2),plugin.use(createSecretsRoutes({logger:logger2,basePath:secretsBasePath,db,schemaTables,resolvedOptions,getService:()=>secretsService,getEmailService,getStorageProvider:()=>storageProvider,buildStorageProvider,adminRoles:resolvedOptions.secrets.adminRoles})),logger2.info(`[Secrets] Routes enabled at ${secretsBasePath}`)}if(resolvedOptions.integrations?.enabled){let integrationsBasePath=resolvedOptions.integrations.basePath||"/integrations";warnOnEntityBasePathCollision("Integrations",integrationsBasePath,resolvedOptions.entities,logger2),plugin.use(createIntegrationRoutes({logger:logger2,basePath:integrationsBasePath,db,schemaTables,resolvedOptions,getEncryptionKey:()=>resolveMasterKey(resolvedOptions.secrets?.encryptionKey)??null,getLockStore:()=>getRedisManager(),publish:(topic,payload)=>pubsubClientManager?.broadcastEvent(topic,payload),adminRoles:resolvedOptions.integrations.adminRoles}))}plugin.onStart((app)=>{let requiredBody=requiredBodyCeiling({storageEnabled:resolvedOptions.storage?.enabled,maxFileSizeBytes:resolvedOptions.storage?.maxFileSizeBytes,maxFiles:resolvedOptions.storage?.formData?.maxFiles}),complaint=bodyCeilingComplaint({configured:app.config?.serve?.maxRequestBodySize,required:requiredBody});if(complaint)logger2.error(`[Storage] ${complaint}`);let memoryComplaint=memoryCeilingComplaint({required:requiredBody,cgroupLimit:readCgroupLimitBytes()});if(memoryComplaint)logger2.error(`[Storage] ${memoryComplaint}`);let memoryAdvice=readRuntimeMemoryAdvice();if(memoryAdvice){let mib=(bytes)=>`${Math.round(bytes/1024/1024)} MiB`;logger2.warn(`[Runtime] The JS engine sizes its heap for ${mib(memoryAdvice.hostTotal)} but this container is capped at ${mib(memoryAdvice.cgroupLimit)} \u2014 it feels no memory `+"pressure and may grow past the limit and be OOM-killed. Raising the container memory limit delays this; no runtime option we have measured prevents it.")}let port=Number(process.env.PORT)||3000,appId=resolvedOptions.appId||"nucleus",mode=resolvedOptions.mode||"production";console.log(""),console.log(` \x1B[32m\uD83D\uDE80 ${appId}\x1B[0m \x1B[90mv${Date.now()}\x1B[0m`),console.log(` \x1B[36m\u279C\x1B[0m Local: \x1B[36mhttp://localhost:${port}\x1B[0m`),console.log(` \x1B[36m\u279C\x1B[0m Mode: \x1B[33m${mode}\x1B[0m`),console.log("")});let shuttingDown=!1,drainResources=async(trigger)=>{if(shuttingDown)return;shuttingDown=!0,logger2.info(`[Shutdown] ${trigger} \u2014 draining resources`);try{await lifecycleRecorder?.recordStop(trigger)}catch{}try{liveMonitoringService?.stop(),monitoringService?.stop(),secretsService?.stop(),storageProvider?.close()}catch(err){logger2.warn("[Shutdown] failed stopping monitoring",{error:err instanceof Error?err.message:String(err)})}try{let redisClient=getRedisManager()?.getDirectClient?.();if(redisClient)await redisClient.quit()}catch(err){logger2.warn("[Shutdown] failed closing Redis",{error:err instanceof Error?err.message:String(err)})}try{for(let timer of backgroundIntervals)clearInterval(timer);backgroundIntervals.length=0}catch(err){logger2.warn("[Shutdown] failed clearing background intervals",{error:err instanceof Error?err.message:String(err)})}try{let{destroyAckCleanup:destroyAckCleanup2}=await Promise.resolve().then(() => (init_ack_manager(),exports_ack_manager));destroyAckCleanup2()}catch{}try{if(dbPool)await dbPool.end()}catch(err){logger2.warn("[Shutdown] failed draining DB pool",{error:err instanceof Error?err.message:String(err)})}logger2.info("[Shutdown] complete")};if(plugin.onStop(async()=>{await drainResources("Elysia onStop")}),resolvedOptions.gracefulShutdown!==!1){let onSignal=(signal)=>{drainResources(signal).finally(()=>process.exit(0))};process.once("SIGTERM",()=>onSignal("SIGTERM")),process.once("SIGINT",()=>onSignal("SIGINT"))}return plugin}init_AzureEmailService();init_Gmail();export{useUpload,usePubSubStore,usePubSub,uploadWithProgress,uploadPercent,uploadFraction,serverFetch,secondsRemaining,requiredBodyCeiling,parseCron2 as parseCron,matchesCron,isDue,generateVerificationEndpoints,generateTenantEndpoints,generateSystemTableEndpoints,generateMonitoringEndpoints,generateMarketplaceEndpoints,generateEndpointsFromConfig,generateDomainEndpoints,generateCohortEndpoints,generateChatEndpoints,generateAuthEndpoints,generateAllEndpoints,generateAdminEndpoints,describeCron,decodeHeaderList,createServerFactory,createRateWindow,createApiHook,buildProgress,VERIFICATION_ENDPOINTS,TENANT_ENDPOINTS,ServerFetch,SYSTEM_TABLES,PAYMENT_ENDPOINTS,NucleusElysiaPlugin,MONITORING_ENDPOINTS,MARKETPLACE_ENDPOINTS,GmailService,DOMAIN_ENDPOINTS,CONFIG_ENDPOINTS,COHORT_ENDPOINTS,CHAT_ENDPOINTS,AzureEmailService,AUTH_ENDPOINT_CONFIGS,AUTH_ENDPOINTS};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nucleus-core-ts",
3
- "version": "0.9.981",
3
+ "version": "0.9.982",
4
4
  "description": "Production-ready, enterprise-grade TypeScript framework for building multi-tenant APIs",
5
5
  "author": "Hidayet Can Özcan <hidayetcan@gmail.com>",
6
6
  "license": "SEE LICENSE IN LICENSE",