nucleus-core-ts 0.9.704 → 0.9.705

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.
@@ -1742,6 +1742,71 @@ export namespace MARKETPLACE_ENDPOINTS {
1742
1742
  export { _error_93 as _error };
1743
1743
  }
1744
1744
  }
1745
+ export class GmailService {
1746
+ constructor(config: any, logger2: any);
1747
+ gmail: null;
1748
+ fromEmail: any;
1749
+ fromName: any;
1750
+ logger: any;
1751
+ initialized: boolean;
1752
+ encodeHeaderValue(value: any): any;
1753
+ isAvailable(): boolean;
1754
+ initialize(jsonFilePath: any): void;
1755
+ createEmailMessage(payload: any): string;
1756
+ sendEmail(payload: any): Promise<{
1757
+ success: boolean;
1758
+ error: string;
1759
+ } | {
1760
+ success: boolean;
1761
+ error?: undefined;
1762
+ }>;
1763
+ emailWrapper(content: any, appName: any): string;
1764
+ emailButton(href: any, label: any): string;
1765
+ emailDivider(): string;
1766
+ emailLinkFallback(link: any, notice: any): string;
1767
+ sendWelcomeEmail(email: any, name: any, appName?: string): Promise<{
1768
+ success: boolean;
1769
+ error: string;
1770
+ } | {
1771
+ success: boolean;
1772
+ error?: undefined;
1773
+ }>;
1774
+ sendVerificationEmail(email: any, name: any, verificationLink: any, appName?: string): Promise<{
1775
+ success: boolean;
1776
+ error: string;
1777
+ } | {
1778
+ success: boolean;
1779
+ error?: undefined;
1780
+ }>;
1781
+ sendPasswordResetEmail(email: any, name: any, resetLink: any, appName?: string): Promise<{
1782
+ success: boolean;
1783
+ error: string;
1784
+ } | {
1785
+ success: boolean;
1786
+ error?: undefined;
1787
+ }>;
1788
+ sendMagicLinkEmail(email: any, magicLink: any, appName?: string): Promise<{
1789
+ success: boolean;
1790
+ error: string;
1791
+ } | {
1792
+ success: boolean;
1793
+ error?: undefined;
1794
+ }>;
1795
+ sendAlertEmail(to: any, subject: any, html: any): Promise<{
1796
+ success: boolean;
1797
+ error: string;
1798
+ } | {
1799
+ success: boolean;
1800
+ error?: undefined;
1801
+ }>;
1802
+ sendInvitationEmail(email: any, inviteLink: any, appName?: string): Promise<{
1803
+ success: boolean;
1804
+ error: string;
1805
+ } | {
1806
+ success: boolean;
1807
+ error?: undefined;
1808
+ }>;
1809
+ }
1745
1810
  export namespace DOMAIN_ENDPOINTS {
1746
1811
  namespace DOMAIN_RESOLVE {
1747
1812
  let method_94: string;
package/dist/index.d.ts CHANGED
@@ -6,4 +6,6 @@ export type { AuthorizationCheckResult, AuthorizationConfig, Claim, Role, RoleCl
6
6
  export type { AzureEmailServiceConfig } from './src/Services/Email/AzureEmailService';
7
7
  export { AzureEmailService } from './src/Services/Email/AzureEmailService';
8
8
  export type { EmailAttachment, EmailPayload, EmailSendResult, EmailService, } from './src/Services/Email/types';
9
+ export { GmailService } from './src/Services/Gmail';
10
+ export type { GmailServiceConfig } from './src/Services/Gmail';
9
11
  export type * from './src/types';
package/dist/index.js CHANGED
@@ -2007,4 +2007,4 @@ ${content}
2007
2007
  ${warningBanner}
2008
2008
  ${deviceTable}
2009
2009
  <p style="margin:16px 0 0;color:#6b7280;font-size:13px;">If this wasn't you, please secure your account immediately.</p>
2010
- `)}emailService?.sendEmail({to:user.email,subject,html:emailHtml}).catch((err)=>{logger2.warn("[AUTH] Failed to send login notification email",{error:err,userId:params.userId,trustScore,requiresApproval})})}}}return logger2.info("[AUTH] Session saved to DB",{sessionId,userId:params.userId,isNewDevice,requiresApproval,deviceFingerprint,ipAddress:deviceInfo.ipAddress}),{requiresApproval,sessionId}},storeResetToken:async(userId,token,expiresAt,reqSchemaName)=>{let resetTokensTable=resolveTableForTenant("passwordResetTokens",reqSchemaName);if(!resetTokensTable||!db)return;await db.insert(resetTokensTable).values({userId,tokenHash:createHash2("sha256").update(token).digest("hex"),expiresAt})},getResetToken:async(token,reqSchemaName)=>{let{eq:eq54}=__require("drizzle-orm"),resetTokensTable=resolveTableForTenant("passwordResetTokens",reqSchemaName);if(!resetTokensTable||!db)return null;let tokenHash=createHash2("sha256").update(token).digest("hex"),row=(await db.select().from(resetTokensTable).where(eq54(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:eq54}=__require("drizzle-orm"),resetTokensTable=resolveTableForTenant("passwordResetTokens",reqSchemaName);if(!resetTokensTable||!db)return;let tokenHash=createHash2("sha256").update(token).digest("hex");await db.delete(resetTokensTable).where(eq54(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(eq53(revokeTable.id,sessionId)),logger2.info("[AUTH] Session revoked in DB",{sessionId,reason})},sendResetEmail:async(email,token,request)=>{if(isEmailExempt(email,authentication?.emailExemptDomains)){logger2.info("[AUTH] Skipping reset email \u2014 domain exempt",{email});return}if(!emailService?.isAvailable()){logger2.warn("[AUTH] Cannot send reset email - gmail service not available");return}let configuredResetUrl=authentication.passwordReset?.redirectUrl||"http://localhost:3000/reset-password",resetUrl=request?buildEmailActionLink({request,configuredUrl:configuredResetUrl,path:extractConfiguredPath(configuredResetUrl,"/reset-password"),query:{token},allowedOrigins:authentication.trustedAppOrigins}):`${configuredResetUrl}?token=${token}`;await emailService.sendEmail({to:email,subject:"Password Reset Request",html:`<p>Click the link to reset your password:</p><a href="${resetUrl}">${resetUrl}</a>`})},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:eq54}=__require("drizzle-orm"),magicTokensTable=resolveTableForTenant("magicLinkTokens",reqSchemaName);if(!magicTokensTable||!db)return null;let row=(await db.select().from(magicTokensTable).where(eq54(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:eq54}=__require("drizzle-orm"),magicTokensTable=resolveTableForTenant("magicLinkTokens",reqSchemaName);if(!magicTokensTable||!db)return;await db.delete(magicTokensTable).where(eq54(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;plugin.use(createCdnRoutes2({cdn:cdnConfig,storagePath:storageConfig.basePath,logger:logger2,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 t36=tbl,result=await db.select().from(t36).where(eq53(t36.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}}:void 0})),logger2.info(`[Storage] CDN routes enabled at ${cdnConfig.basePath}`)}if(resolvedOptions.verification?.enabled&&db){let{routes:verificationRoutes}=createVerificationRoutes({db,schemaTables,config:resolvedOptions.verification,notificationConfig:resolvedOptions.notification,logger:logger2,emailService:emailService||void 0,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}},schemaTables,schemaName:targetSchemaName,tenantRegistry});plugin.use(backupRoutes),logger2.info("[Backup] Routes registered",{basePath:resolvedOptions.backup.basePath||"/admin/backup",scheduleEnabled:resolvedOptions.backup.schedule?.enabled??!1})}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,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,getLiveMonitoringService:()=>liveMonitoringService,authenticate:envResolved.accessTokenSecret?(headers)=>{let wsTokens=parseTokenValuesFromHeaders(headers,tokenNames);if(!wsTokens.access_token)return null;let jwtResult=verifyJWT(wsTokens.access_token,envResolved.accessTokenSecret||"",{issuer:authentication?.accessToken?.issuer,audience:authentication?.accessToken?.audience});if(!jwtResult.valid)return null;let sub=jwtResult.payload?.sub;return typeof sub==="string"&&sub.length>0?{userId:sub}:null}: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",{routes:chatRoutes}=createChatRoutes({db,schemaTables,config:chatConfig,logger:logger2,broadcaster:pubsubClientManager,tenantRegistry,storageConfig:chatStorageConfig,attachmentsAvailable,cdnBasePath});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,defaultRole:authentication?.defaultRole,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}`)}plugin.onStart(()=>{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()}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}export{usePubSubStore,usePubSub,serverFetch,generateVerificationEndpoints,generateTenantEndpoints,generateSystemTableEndpoints,generateMonitoringEndpoints,generateMarketplaceEndpoints,generateEndpointsFromConfig,generateDomainEndpoints,generateCohortEndpoints,generateChatEndpoints,generateAuthEndpoints,generateAllEndpoints,generateAdminEndpoints,createServerFactory,createApiHook,VERIFICATION_ENDPOINTS,TENANT_ENDPOINTS,ServerFetch,PAYMENT_ENDPOINTS,NucleusElysiaPlugin,MONITORING_ENDPOINTS,MARKETPLACE_ENDPOINTS,DOMAIN_ENDPOINTS,CONFIG_ENDPOINTS,COHORT_ENDPOINTS,CHAT_ENDPOINTS,AzureEmailService,AUTH_ENDPOINT_CONFIGS,AUTH_ENDPOINTS};
2010
+ `)}emailService?.sendEmail({to:user.email,subject,html:emailHtml}).catch((err)=>{logger2.warn("[AUTH] Failed to send login notification email",{error:err,userId:params.userId,trustScore,requiresApproval})})}}}return logger2.info("[AUTH] Session saved to DB",{sessionId,userId:params.userId,isNewDevice,requiresApproval,deviceFingerprint,ipAddress:deviceInfo.ipAddress}),{requiresApproval,sessionId}},storeResetToken:async(userId,token,expiresAt,reqSchemaName)=>{let resetTokensTable=resolveTableForTenant("passwordResetTokens",reqSchemaName);if(!resetTokensTable||!db)return;await db.insert(resetTokensTable).values({userId,tokenHash:createHash2("sha256").update(token).digest("hex"),expiresAt})},getResetToken:async(token,reqSchemaName)=>{let{eq:eq54}=__require("drizzle-orm"),resetTokensTable=resolveTableForTenant("passwordResetTokens",reqSchemaName);if(!resetTokensTable||!db)return null;let tokenHash=createHash2("sha256").update(token).digest("hex"),row=(await db.select().from(resetTokensTable).where(eq54(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:eq54}=__require("drizzle-orm"),resetTokensTable=resolveTableForTenant("passwordResetTokens",reqSchemaName);if(!resetTokensTable||!db)return;let tokenHash=createHash2("sha256").update(token).digest("hex");await db.delete(resetTokensTable).where(eq54(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(eq53(revokeTable.id,sessionId)),logger2.info("[AUTH] Session revoked in DB",{sessionId,reason})},sendResetEmail:async(email,token,request)=>{if(isEmailExempt(email,authentication?.emailExemptDomains)){logger2.info("[AUTH] Skipping reset email \u2014 domain exempt",{email});return}if(!emailService?.isAvailable()){logger2.warn("[AUTH] Cannot send reset email - gmail service not available");return}let configuredResetUrl=authentication.passwordReset?.redirectUrl||"http://localhost:3000/reset-password",resetUrl=request?buildEmailActionLink({request,configuredUrl:configuredResetUrl,path:extractConfiguredPath(configuredResetUrl,"/reset-password"),query:{token},allowedOrigins:authentication.trustedAppOrigins}):`${configuredResetUrl}?token=${token}`;await emailService.sendEmail({to:email,subject:"Password Reset Request",html:`<p>Click the link to reset your password:</p><a href="${resetUrl}">${resetUrl}</a>`})},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:eq54}=__require("drizzle-orm"),magicTokensTable=resolveTableForTenant("magicLinkTokens",reqSchemaName);if(!magicTokensTable||!db)return null;let row=(await db.select().from(magicTokensTable).where(eq54(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:eq54}=__require("drizzle-orm"),magicTokensTable=resolveTableForTenant("magicLinkTokens",reqSchemaName);if(!magicTokensTable||!db)return;await db.delete(magicTokensTable).where(eq54(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;plugin.use(createCdnRoutes2({cdn:cdnConfig,storagePath:storageConfig.basePath,logger:logger2,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 t36=tbl,result=await db.select().from(t36).where(eq53(t36.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}}:void 0})),logger2.info(`[Storage] CDN routes enabled at ${cdnConfig.basePath}`)}if(resolvedOptions.verification?.enabled&&db){let{routes:verificationRoutes}=createVerificationRoutes({db,schemaTables,config:resolvedOptions.verification,notificationConfig:resolvedOptions.notification,logger:logger2,emailService:emailService||void 0,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}},schemaTables,schemaName:targetSchemaName,tenantRegistry});plugin.use(backupRoutes),logger2.info("[Backup] Routes registered",{basePath:resolvedOptions.backup.basePath||"/admin/backup",scheduleEnabled:resolvedOptions.backup.schedule?.enabled??!1})}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,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,getLiveMonitoringService:()=>liveMonitoringService,authenticate:envResolved.accessTokenSecret?(headers)=>{let wsTokens=parseTokenValuesFromHeaders(headers,tokenNames);if(!wsTokens.access_token)return null;let jwtResult=verifyJWT(wsTokens.access_token,envResolved.accessTokenSecret||"",{issuer:authentication?.accessToken?.issuer,audience:authentication?.accessToken?.audience});if(!jwtResult.valid)return null;let sub=jwtResult.payload?.sub;return typeof sub==="string"&&sub.length>0?{userId:sub}:null}: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",{routes:chatRoutes}=createChatRoutes({db,schemaTables,config:chatConfig,logger:logger2,broadcaster:pubsubClientManager,tenantRegistry,storageConfig:chatStorageConfig,attachmentsAvailable,cdnBasePath});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,defaultRole:authentication?.defaultRole,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}`)}plugin.onStart(()=>{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()}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_Gmail();export{usePubSubStore,usePubSub,serverFetch,generateVerificationEndpoints,generateTenantEndpoints,generateSystemTableEndpoints,generateMonitoringEndpoints,generateMarketplaceEndpoints,generateEndpointsFromConfig,generateDomainEndpoints,generateCohortEndpoints,generateChatEndpoints,generateAuthEndpoints,generateAllEndpoints,generateAdminEndpoints,createServerFactory,createApiHook,VERIFICATION_ENDPOINTS,TENANT_ENDPOINTS,ServerFetch,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.704",
3
+ "version": "0.9.705",
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",