nucleus-core-ts 0.8.89 → 0.8.91
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 +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1523,7 +1523,7 @@ data: ${t}
|
|
|
1523
1523
|
</script>
|
|
1524
1524
|
<script src="${o?o:`https://cdn.jsdelivr.net/npm/@scalar/api-reference@${r}/dist/browser/standalone.min.js`}" crossorigin></script>
|
|
1525
1525
|
</body>
|
|
1526
|
-
</html>`;var El=Symbol.for("TypeBox.Kind"),cA=(n)=>n.split("/").map((r)=>{if(r.startsWith(":")){if(r=r.slice(1,r.length),r.endsWith("?"))r=r.slice(0,-1);r=`{${r}}`}return r}).join("/"),kl=(n,r,t)=>{if(r===void 0)return[];if(typeof r==="string")if(r in t)r=t[r];else throw Error(`Can't find model ${r}`);return Object.entries(r?.properties??[]).map(([o,a])=>{let{type:c=void 0,description:e,examples:i,...s}=a;return{description:e,examples:i,schema:{type:c,...s},in:n,name:o,required:r.required?.includes(o)??!1}})},Wc=(n,r)=>{if(typeof r==="object"&&["void","undefined","null"].includes(r.type))return;let t={};for(let o of n)t[o]={schema:typeof r==="string"?{$ref:`#/components/schemas/${r}`}:("$ref"in r)&&(El in r)&&r[El]==="Ref"?{...r,$ref:`#/components/schemas/${r.$ref}`}:aA({...r},{from:Rl.Ref(""),to:({$ref:a,...c})=>{if(!a.startsWith("#/components/schemas/"))return Rl.Ref(`#/components/schemas/${a}`,c);return Rl.Ref(a,c)}})};return t},t_=(n)=>n.charAt(0).toUpperCase()+n.slice(1),eA=(n,r)=>{let t=n.toLowerCase();if(r==="/")return t+"Index";for(let o of r.split("/"))if(o.charCodeAt(0)===123)t+="By"+t_(o.slice(1,-1));else t+=t_(o);return t},Ya=(n)=>{if(!n)return;if(typeof n==="string")return n;if(Array.isArray(n))return[...n];return{...n}},o_=({schema:n,path:r,method:t,hook:o,models:a})=>{if(o=Ya(o),o.parse&&!Array.isArray(o.parse))o.parse=[o.parse];let c=o.parse?.map((w)=>{switch(typeof w){case"string":return w;case"object":if(w&&typeof w?.fn!=="string")return;switch(w?.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((w)=>w!==void 0);if(!c||c.length===0)c=["application/json","multipart/form-data","text/plain"];r=cA(r);let e=typeof c==="string"?[c]:c??["application/json"],i=Ya(o?.body),s=Ya(o?.params),f=Ya(o?.headers),l=Ya(o?.query),d=Ya(o?.response);if(typeof d==="object")if(El in d){let{type:w,properties:h,required:_,additionalProperties:g,patternProperties:R,$ref:k,...M}=d;d={"200":{...M,description:M.description,content:Wc(e,w==="object"||w==="array"?{type:w,properties:h,patternProperties:R,items:d.items,required:_}:d)}}}else Object.entries(d).forEach(([w,h])=>{if(typeof h==="string"){if(!a[h])return;let{type:_,properties:g,required:R,additionalProperties:k,patternProperties:M,...C}=a[h];d[w]={...C,description:C.description,content:Wc(e,h)}}else{let{type:_,properties:g,required:R,additionalProperties:k,patternProperties:M,...C}=h;d[w]={...C,description:C.description,content:Wc(e,_==="object"||_==="array"?{type:_,properties:g,patternProperties:M,items:h.items,required:R}:h)}}});else if(typeof d==="string"){if(!(d in a))return;let{type:w,properties:h,required:_,$ref:g,additionalProperties:R,patternProperties:k,...M}=a[d];d={"200":{...M,content:Wc(e,d)}}}let b=[...kl("header",f,a),...kl("path",s,a),...kl("query",l,a)];n[r]={...n[r]?n[r]:{},[t.toLowerCase()]:{...f||s||l||i?{parameters:b}:{},...d?{responses:d}:{},operationId:o?.detail?.operationId??eA(t,r),...o?.detail,...i?{requestBody:{required:!0,content:Wc(e,typeof i==="string"?{$ref:`#/components/schemas/${i}`}:i)}}:null}}},iA=(n,{excludeStaticFile:r=!0,exclude:t=[]})=>{let o={};for(let[a,c]of Object.entries(n))if(!t.some((e)=>{if(typeof e==="string")return a===e;return e.test(a)})&&!a.includes("*")&&(r?!a.includes("."):!0))Object.keys(c).forEach((e)=>{let i=c[e];if(a.includes("{")){if(!i.parameters)i.parameters=[];i.parameters=[...a.split("/").filter((s)=>s.startsWith("{")&&!i.parameters.find((f)=>f.in==="path"&&f.name===s.slice(1,s.length-1))).map((s)=>({schema:{type:"string"},in:"path",name:s.slice(1,s.length-1),required:!0})),...i.parameters]}if(!i.responses)i.responses={200:{}}}),o[a]=c;return o},c_=({provider:n="scalar",scalarVersion:r="latest",scalarCDN:t="",scalarConfig:o={},documentation:a={},version:c="5.9.0",excludeStaticFile:e=!0,path:i="/swagger",specPath:s=`${i}/json`,exclude:f=[],swaggerOptions:l={},theme:d=`https://unpkg.com/swagger-ui-dist@${c}/swagger-ui.css`,autoDarkMode:b=!0,excludeMethods:w=["OPTIONS"],excludeTags:h=[]}={})=>{let _={},g=0;if(!c)c=`https://unpkg.com/swagger-ui-dist@${c}/swagger-ui.css`;let R={title:"Elysia Documentation",description:"Development documentation",version:"0.0.0",...a.info},k=s.startsWith("/")?s.slice(1):s,M=new nA({name:"@elysiajs/swagger"}),C=new Response(n==="swagger-ui"?tA(R,c,d,JSON.stringify({url:k,dom_id:"#swagger-ui",...l},(N,m)=>typeof m==="function"?void 0:m),b):oA(R,r,{spec:{url:k,...o.spec},...o,_integration:"elysiajs"},t),{headers:{"content-type":"text/html; charset=utf8"}});return M.get(i,C,{detail:{hide:!0}}).get(s,function(){let m=M.getGlobalRoutes();if(m.length!==g){let A=["GET","PUT","POST","DELETE","OPTIONS","HEAD","PATCH","TRACE"];g=m.length,m.forEach((H)=>{if(H.hooks?.detail?.hide===!0)return;if(w.includes(H.method))return;if(A.includes(H.method)===!1&&H.method!=="ALL")return;if(H.method==="ALL")A.forEach((D)=>{o_({schema:_,hook:H.hooks,method:D,path:H.path,models:M.getGlobalDefinitions?.().type,contentType:H.hooks.type})});else o_({schema:_,hook:H.hooks,method:H.method,path:H.path,models:M.getGlobalDefinitions?.().type,contentType:H.hooks.type})})}return{openapi:"3.0.3",...{...a,tags:a.tags?.filter((A)=>!h?.includes(A?.name)),info:{title:"Elysia Documentation",description:"Development documentation",version:"0.0.0",...a.info}},paths:{...iA(_,{excludeStaticFile:e,exclude:Array.isArray(f)?f:[f]}),...a.paths},components:{...a.components,schemas:{...M.getGlobalDefinitions?.().type,...a.components?.schemas}}}},{detail:{hide:!0}}),M};function Sl(n){if(n?.enabled===!1)return null;let r={path:n?.path??"/swagger",provider:n?.provider??"scalar",excludeStaticFile:n?.excludeStaticFile??!0,exclude:n?.exclude??[],documentation:{info:{title:n?.documentation?.info?.title??"Nucleus API",description:n?.documentation?.info?.description??"Auto-generated API documentation",version:n?.documentation?.info?.version??"1.0.0",contact:n?.documentation?.info?.contact,license:n?.documentation?.info?.license},tags:n?.documentation?.tags??[],servers:n?.documentation?.servers},scalarConfig:n?.scalarConfig};return c_(r)}Ie();Qd();ni();var HE=(n)=>{let r=new Map;for(let t of n){let o=r.get(t.table_name),a=t.columns??o?.columns;r.set(t.table_name,{...o||{},...t,columns:a})}return Array.from(r.values())},zE=(n)=>({table_name:n.table_name,excluded_methods:n.excluded_methods?[...n.excluded_methods]:void 0,columns:n.columns?n.columns.map((r)=>({name:r.name,type:r.type})):void 0}),UE=(n)=>{let r=[];for(let[t,o]of Object.entries(n)){if(!o||typeof o!=="object")continue;let a=o,c=a._;if(c?.name){r.push({table_name:c.name});continue}let e=Object.getOwnPropertySymbols(a);for(let i of e){let s=a[i];if(s&&typeof s==="object"){let f=s;if(f.name&&typeof f.name==="string"){r.push({table_name:f.name});break}}}}return r};async function BE(n){let r=new DE;if(r.get("/health",()=>({status:"ok",timestamp:Date.now()})),n.staticAssets!==!1){let E=Sn("path"),S=Sn("fs"),z;if(typeof n.staticAssets==="string")z=n.staticAssets;else{let U=E.join(process.cwd(),"public"),P="";for(let p of["nucleus-core-ts","nucleus-core"])try{let K=Sn.resolve(`${p}/package.json`),B=E.join(E.dirname(K),"public");if(S.existsSync(B)){P=B;break}}catch{}if(P)z=P;else if(S.existsSync(U))z=U;else z=U}try{r.use(await au({prefix:"/nucleus-core",assets:z}))}catch{}}let t=[],o,a=process.cwd();if(typeof n.options==="string"){let E=Sn("fs"),S=Sn("path"),z=S.isAbsolute(n.options)?n.options:S.resolve(process.cwd(),n.options);a=S.dirname(z);let U=E.readFileSync(z,"utf-8");o=JSON.parse(U)}else o=n.options;if(o.email?.gmail?.json_file_path){let E=Sn("path"),S=o.email.gmail.json_file_path;if(!E.isAbsolute(S))o.email.gmail.json_file_path=E.resolve(a,S)}let{authentication:c,audit:e,entities:i,database:s}=o,f=o.mode==="development",l=new Cr({service:o.appId||"nucleus",prettyPrint:f,colorize:f,auditEnabled:e?.enabled??!1}),d=ug(o);if(!d.valid){for(let E of d.errors)l.error(`[CONFIG] ${E.message}`,{field:E.field,envName:E.envName});throw Error("Nucleus configuration error: Missing required environment variables. Check logs for details.")}let{resolved:b}=d,w={access_token:c?.accessToken?.name||"access_token",refresh_token:c?.refreshToken?.name||"refresh_token",session_token:c?.sessionToken?.name||"session_token"},h=s?.schemas?.[0]||"main",_=ME(h);if(b.databaseUrl)await bg(b.databaseUrl,l);let g=b.databaseUrl?SE(b.databaseUrl):null,R={},k={};if(n.schema){let S=Sn("path").resolve(process.cwd(),n.schema),z=Sn(S);R=z.createAllTablesForSchema?z.createAllTablesForSchema(_):{}}if(n.relations){let S=Sn("path").resolve(process.cwd(),n.relations);k=Sn(S)}let M=Sl(n.swagger);if(M)r.use(M);let C=n.systemTables||[];t=Nf(o,C,"",h),l.info(`[AUTH] Built ${t.length} public routes`);let N=null,m=null,A=null,H=null;if(o.email?.gmail?.enabled&&o.email.gmail.json_file_path)l.info("[GmailService] Initializing...",{jsonFilePath:o.email.gmail.json_file_path,fromEmail:o.email.gmail.from_email}),H=new Jf({enabled:!0,jsonFilePath:o.email.gmail.json_file_path,fromEmail:o.email.gmail.from_email||"",fromName:o.email.gmail.from_name},l),l.info("[GmailService] isAvailable:",{available:H.isAvailable()});if(o.liveMonitoring?.enabled){let E=o.liveMonitoring.basePath||"/monitoring",S=o.liveMonitoring.streamInterval||150;r.use(Ag({getService:()=>A,logger:l,basePath:E,streamInterval:S}))}r.onStart(async()=>{tl(o);let E=Te();if(E&&o.rateLimit?.enabled!==!1)N=new Qf({redis:E,logger:l,config:o.rateLimit||{}}),l.info(`[RateLimit] Enabled with strategy: ${o.rateLimit?.strategy||"sliding-window"}`);if(E&&o.monitoring?.enabled){if(m=new Vf({redis:E,logger:l,gmail:H||void 0,config:o.monitoring,appId:o.appId}),m.start(),l.info("[Monitoring] Service started"),o.monitoring.endpoints?.enabled){let z={enabled:!0,basePath:o.monitoring.endpoints.basePath||"/monitoring",stream:{enabled:o.monitoring.endpoints.stream?.enabled!==!1,path:o.monitoring.endpoints.stream?.path||"/stream",interval:o.monitoring.endpoints.stream?.interval||"5s"},snapshot:{enabled:o.monitoring.endpoints.snapshot?.enabled!==!1,path:o.monitoring.endpoints.snapshot?.path||"/snapshot"},history:{enabled:o.monitoring.endpoints.history?.enabled!==!1,path:o.monitoring.endpoints.history?.path||"/history",maxMinutes:o.monitoring.endpoints.history?.maxMinutes||60},alerts:{enabled:o.monitoring.endpoints.alerts?.enabled!==!1,path:o.monitoring.endpoints.alerts?.path||"/alerts"}};r.use(ll({monitoringService:m,logger:l,endpoints:z}))}}if(o.liveMonitoring?.enabled)A=new Ce(o.liveMonitoring),A.start(),l.info("[LiveMonitoring] Service started");let S=c?.mode==="consumer";if(g&&n.schema&&!S){let P=await import(Sn("path").resolve(process.cwd(),n.schema)),p=R.auditLogs||P.auditLogs;if(e?.enabled&&p)l.addAuditTransport(new de({db:g,table:p,enabled:!0}));try{l.info(`Syncing schema to database (target: ${h})...`);let{sql:B}=await import("drizzle-orm");await g.execute(B.raw(`CREATE SCHEMA IF NOT EXISTS "${h}"`));try{let L=Object.fromEntries(Object.entries(R).filter(([q,F])=>{if(F===void 0||F===null)return!1;if(typeof F==="object"&&F!==null)return Object.getOwnPropertySymbols(F).length>0||F._!==void 0;return!1})),Y=Object.keys(L);l.info("[Schema] Tables to sync:",{tables:Y,count:Y.length});let Q=L.users;if(Q){let q=Object.getOwnPropertyNames(Q).filter((F)=>!F.startsWith("_"));l.info("[Schema] Users table columns:",{columns:q})}await(await EE({schema:_,...L},g,[h])).apply(),l.info("[Schema] pushSchema completed successfully")}catch(L){let Y=L instanceof Error?L.message:String(L);l.warn(`[Schema] pushSchema warning: ${Y}`)}console.log("Schema sync completed")}catch(B){let L=B instanceof Error?B.message:String(B);console.error("Schema sync failed:",L)}if(console.log("Database connection established"),o.authorization?.enabled){let B={...ib,...o.authorization};if(B.autoSeedClaims){let L=UE(R),Y=qe.map((q)=>zE(q)),Q=o.entities||[],V=HE([...L,...Q,...Y,...n.systemTables||[]]);l.info("[Authorization] Seeding claims...",{schemaEntities:L.length,systemEntities:Y.length,configEntities:Q.length,totalEntities:V.length}),await yu(g,R,k,V,B,l)}if(B.godminEmail&&B.godminPassword)l.info("[Authorization] Setting up godmin..."),await rb(g,R,B,l);l.info("[Authorization] Enabled")}let K=R.userSessions;if(K&&o.authentication?.sessions?.enabled){let{lt:B}=await import("drizzle-orm"),L=await g.update(K).set({isActive:!1,revokedAt:new Date,revokedReason:"expired"}).where(ie($r(K.isActive,!0),B(K.expiresAt,new Date)));l.info("[AUTH] Expired sessions cleanup completed",{expiredCount:L}),setInterval(async()=>{try{await g.update(K).set({isActive:!1,revokedAt:new Date,revokedReason:"expired"}).where(ie($r(K.isActive,!0),B(K.expiresAt,new Date)))}catch(Y){l.warn("[AUTH] Session cleanup failed",{error:Y})}},3600000)}}}).onRequest(async({request:E,set:S})=>{let z=Date.now();E.headers.set("x-request-start-time",String(z));let U=new URL(E.url),P=U.pathname,p=E.method,K=U.search,B=E.headers.get("x-forwarded-for")?.split(",")[0]?.trim()||E.headers.get("x-real-ip")?.trim()||"unknown",L=E.headers.get("user-agent")||"unknown",Y,Q={};if(E.method!=="GET"&&E.method!=="HEAD")try{let v=await E.clone().text();Q=v?JSON.parse(v):{}}catch{Q={}}let V=e?.enabled?{id:kE(),user_id:"unknown",entity_name:P.split("/").filter(Boolean)[0]||"root",entity_id:null,operation_type:p,summary:"",old_values:{},new_values:Q,ip_address:B,user_agent:L,timestamp:new Date().toISOString(),path:P,query:K}:null,q=xf(t,P,p);if(N){let F=q?"public":"private",v;if(P.includes("/auth/login"))v="login";else if(P.includes("/auth/register"))v="register";else if(P.includes("/auth/password-reset"))v="passwordReset";else if(P.includes("/auth/magic-link"))v="magicLink";let dn=v?"auth":F,on=await N.check({ip:B,endpoint:P,category:dn,authType:v}),un=N.getHeaders(on);for(let[en,Yn]of Object.entries(un))S.headers[en]=Yn;if(!on.allowed){if(S.status=429,on.retryAfter)S.headers["Retry-After"]=String(on.retryAfter);if(l.warn(`[RateLimit] Blocked request from ${B} to ${P}`),m)m.recordRateLimitBlock();return new Response(JSON.stringify({error:"Too Many Requests",retryAfter:on.retryAfter}),{status:429,headers:{"Content-Type":"application/json"}})}}if(P==="/health")return;if(c?.enabled&&!q){if(!c.accessToken?.secret)return S.status=500,l.traceSync({message:"Authentication secrets not defined",level:"error",context:{path:P,method:p},audit:xt(V,"Authentication secrets not defined")}),Error("One or more authentication secrets are not defined");if(c.mode==="consumer"){Y=rl(E.headers,w);let v=so(Y.access_token||"",b.accessTokenSecret||"");if(!v.valid)return S.status=401,l.traceSync({message:"Invalid or missing access token",level:"warn",context:{path:P,method:p},audit:xt(V,"Invalid or missing access token")}),Error("Unauthenticated");let dn=v.payload.sub,on=v.payload.roles,un=v.payload.claims;if(E.headers.set("x-access-token",Y.access_token||""),E.headers.set("x-user-id",dn||""),on&&on.length>0)E.headers.set("x-user-roles",on.join(","));if(un&&un.length>0)E.headers.set("x-user-claims",un.join(","))}else{if(!c.refreshToken?.secret||!c.sessionToken?.secret)return S.status=500,l.traceSync({message:"Authentication secrets not defined",level:"error",context:{path:P,method:p},audit:xt(V,"Authentication secrets not defined")}),Error("One or more authentication secrets are not defined");if(Y=rl(E.headers,w),!Y.session_token)return S.status=401,l.traceSync({message:"No session token",level:"warn",context:{path:P,method:p},audit:xt(V,"No session token")}),Error("Unauthenticated");let v=await Qo({sessionId:Y.session_token});if(!v)return S.status=401,l.traceSync({message:"Invalid session",level:"warn",context:{path:P,method:p,sessionId:Y.session_token},audit:xt(V,"Invalid session")}),Error("Unauthenticated");let dn=R.userSessions;if(dn&&g){let T=(await g.select().from(dn).where($r(dn.id,Y.session_token)).limit(1))[0],Jn=T?.revokedAt!==null&&T?.revokedAt!==void 0&&!(typeof T?.revokedAt==="object"&&Object.keys(T.revokedAt).length===0);if(!T||T.isActive===!1||Jn)return S.status=401,l.traceSync({message:"Session revoked or inactive",level:"warn",context:{path:P,method:p,sessionId:Y.session_token,isActive:T?.isActive,revokedAt:T?.revokedAt},audit:xt(V,"Session revoked")}),Error("Session has been revoked");if(T.expiresAt&&new Date(T.expiresAt)<new Date)return S.status=401,l.traceSync({message:"Session expired",level:"warn",context:{path:P,method:p,sessionId:Y.session_token,expiresAt:T.expiresAt},audit:xt(V,"Session expired")}),Error("Session has expired")}if(v.lastActiveAt&&c.sessions?.inactivityTimeout){let _n=new Date(v.lastActiveAt).getTime(),T=st(c.sessions.inactivityTimeout)*1000;if(Date.now()-_n>T)return S.status=401,l.traceSync({message:"Session inactive timeout",level:"warn",context:{path:P,method:p,sessionId:Y.session_token,lastActiveAt:v.lastActiveAt},audit:xt(V,"Session inactive timeout")}),Error("Session expired due to inactivity")}Af(Y.session_token).catch(()=>{});let on=R.userSessions;if(on&&g)g.update(on).set({lastActivityAt:new Date}).where($r(on.id,Y.session_token)).catch(()=>{});let un=so(Y.access_token||"",b.accessTokenSecret||""),en=Y.access_token?un.valid:!1,Yn=Y.refresh_token?so(Y.refresh_token,b.refreshTokenSecret||"").valid:!1;if(!en&&Yn&&Y.refresh_token&&v.rememberMe===!0){let _n=await dg(v.userId,v.id,()=>fg({refreshTokenId:Y.refresh_token,options:o,sessionData:v}));if(_n.success&&_n.accessToken){Y.access_token=_n.accessToken;let T=`${w.access_token}=${_n.accessToken}; Path=/; HttpOnly; SameSite=Strict;Secure; Max-Age=${st(c.accessToken.expiresIn??"15m")}`;S.headers["Set-Cookie"]=T}}let nr=un.valid?un.payload.sub:v.userId,gn=un.valid?un.payload.roles:void 0,et=un.valid?un.payload.claims:void 0;if(E.headers.set("x-access-token",Y.access_token||""),E.headers.set("x-refresh-token",Y.refresh_token||""),E.headers.set("x-session-id",Y.session_token||""),E.headers.set("x-user-id",nr||""),gn&&gn.length>0)E.headers.set("x-user-roles",gn.join(","));if(et&&et.length>0)E.headers.set("x-user-claims",et.join(","))}}}).onAfterHandle(({request:E,set:S})=>{if(m){let z=E.headers.get("x-request-start-time"),U=z?parseInt(z,10):Date.now(),P=Date.now()-U,p=new URL(E.url),K=typeof S.status==="number"?S.status:200;m.recordRequest({endpoint:p.pathname,method:E.method,status:K,responseTimeMs:P,isError:K>=400,errorType:K>=500?"server_error":K>=400?"client_error":void 0})}if(A){let z=new URL(E.url),U={};E.headers.forEach((P,p)=>{U[p]=P}),A.recordRequest({path:z.pathname,method:E.method,timestamp:Date.now(),headers:U})}}).onError((E)=>{let{set:S,code:z,error:U}=E,P=typeof z==="number"?z:500,p=U instanceof Error?U.message:"Internal Server Error";return S.status=P,Response.json({isSuccess:!1,message:p,status:P,errors:[U],data:null})}),l.info("Creating routes for entities"),fl(r,{db:g,schemaTables:R,schemaRelations:k,entities:i,logger:l,databaseUrl:b.databaseUrl,storage:o.storage,authorization:o.authorization,emailServiceAvailable:!!(o.email?.gmail?.enabled&&o.email.gmail.json_file_path)});let D=c?.mode==="consumer";if(c?.enabled&&!D&&g){let E=R.users,S=R.userSessions||R.user_sessions||R.sessions;if(!S&&c.sessions?.enabled)l.warn("[AUTH] sessions is enabled but user_sessions table not found in schema. Disabling sessions.");if(E){tl(o);let{createAuthRoutes:z}=(Qd(),se(M2)),{signJWT:U,verifyJWT:P}=(Vo(),se(wu)),{generateSession:p,deleteSession:K}=(Rf(),se(Iu));z(r,{authConfig:{db:g,logger:l,usersTable:E,sessionsTable:S,userRolesTable:R.userRoles,rolesTable:R.roles,roleClaimsTable:R.roleClaims,claimsTable:R.claims,authentication:{enabled:c.enabled,accessToken:c.accessToken,refreshToken:c.refreshToken,sessionToken:c.sessionToken}},features:{login:c.login,register:c.register,logout:c.logout,refresh:c.refresh,passwordReset:(()=>{let B=!!(o.email?.gmail?.enabled&&o.email.gmail.json_file_path);if(c.passwordReset?.enabled&&!B)return l.warn("[AUTH] passwordReset is enabled but no email provider is configured. Disabling passwordReset."),{...c.passwordReset,enabled:!1};return c.passwordReset})(),passwordChange:c.passwordChange,passwordSet:c.passwordSet,sessions:c.sessions,magicLink:(()=>{let B=!!(o.email?.gmail?.enabled&&o.email.gmail.json_file_path);if(c.magicLink?.enabled&&!B)return l.warn("[AUTH] magicLink is enabled but no email provider is configured. Disabling magicLink."),{...c.magicLink,enabled:!1};return c.magicLink})(),me:c.me||{enabled:!0,route:"/auth/me"},invite:(()=>{let B=!!(o.email?.gmail?.enabled&&o.email.gmail.json_file_path);if(c.invite?.enabled&&!B)return l.warn("[AUTH] invite is enabled but no email provider is configured. Disabling invite."),{...c.invite,enabled:!1};return c.invite})(),captcha:c.captcha,oauth:c.oauth?.enabled&&b.oauthProviders?{...c.oauth,providers:b.oauthProviders}:void 0},sessionsTable:S,oauthAccountsTable:R.oauthAccounts,schemaTables:R,schemaRelations:k,databaseUrl:b.databaseUrl,admin:{impersonate:{enabled:!0},changeUserId:{enabled:!0}},emailService:H,appName:o.appId,captchaService:(()=>{let B=Te();if(!c.captcha?.enabled||!B)return null;return new Wf({redis:{get:async(Y)=>{let Q=await B.read(Y);return Q.success?Q.data:null},set:async(Y,Q,V)=>{await B.create(Y,Q,V?.ex)},del:async(Y)=>{await B.remove(Y)}},logger:l,config:{enabled:!0,type:c.captcha.type||"math",difficulty:c.captcha.difficulty||"medium",expiresIn:c.captcha.expiresIn||"5m",maxAttempts:c.captcha.maxAttempts||3,caseSensitive:c.captcha.caseSensitive??!1}})})(),tokenResponseConfig:{accessToken:{setHeadersEnabled:c.accessToken?.setHeadersEnabled??!0,returnJson:c.accessToken?.returnJson??!0},refreshToken:{setHeadersEnabled:c.refreshToken?.setHeadersEnabled??!0,returnJson:c.refreshToken?.returnJson??!0},sessionToken:{setHeadersEnabled:c.sessionToken?.setHeadersEnabled??!0,returnJson:c.sessionToken?.returnJson??!0}},helpers:{signAccessToken:(B,L,Y)=>U({subject:B,expiresInSeconds:st(c.accessToken?.expiresIn||"15m"),issuer:c.accessToken?.issuer,audience:c.accessToken?.audience,customClaims:{...L&&L.length>0?{roles:L}:{},...Y&&Y.length>0?{claims:Y}:{}}},b.accessTokenSecret||"",c.accessToken?.algorithm||"HS256"),signRefreshToken:(B)=>U({subject:B,expiresInSeconds:st(c.refreshToken?.expiresIn||"7d"),issuer:c.refreshToken?.issuer,audience:c.refreshToken?.audience},b.refreshTokenSecret||"",c.refreshToken?.algorithm||"HS256"),verifyRefreshToken:(B)=>P(B,b.refreshTokenSecret||""),createSession:async(B)=>{let L=await p({userId:B.userId,deviceInfo:B.deviceInfo});return L.success?L.session.id:""},destroySession:async(B)=>K({sessionId:B}),saveSessionToDb:async(B,L)=>{if(!S||!g)return;let Y=c.sessions,Q=L.deviceInfo||{},V=`${Q.browserName||""}-${Q.osName||""}-${Q.deviceType||""}`,q=await g.select().from(S).where(ie($r(S.userId,L.userId),$r(S.isActive,!0))),F=V&&!V.includes("--unknown")&&!V.includes("Bot/Crawler")&&!V.includes("Headless")&&V!=="--"&&V!=="--unknown",v=F?!q.some((Gn)=>Gn.deviceFingerprint===V):!1,dn=q.some((Gn)=>Gn.approvalStatus==="approved"),on=L.loginMethod==="impersonation"||L.loginMethod==="impersonation_stop",un=!on&&Y?.trustNewDevices===!1&&v&&F&&dn;l.info("[AUTH] Device fingerprint analysis",{userId:L.userId,deviceFingerprint:V,hasValidFingerprint:F,isNewDevice:v,existingSessionCount:q.length,hasAnyApprovedSession:dn,requiresApproval:un});let en=null,Yn="approved";if(un){let{randomBytes:Gn}=await import("crypto");en=Gn(32).toString("hex"),Yn="pending",l.info("[AUTH] New device requires approval",{userId:L.userId,deviceFingerprint:V,ipAddress:Q.ipAddress})}let nr=q.filter((Gn)=>{let qn=Gn,gr=qn.deviceFingerprint||"",Ar=qn.ipAddress||"";return(!gr||gr==="--"||gr==="--unknown"||gr.includes("Bot/Crawler")||gr.includes("Headless")||gr.includes("unknown-unknown"))&&(Ar==="127.0.0.1"||Ar==="::1"||Ar==="localhost"||!Ar)});if(nr.length>0){for(let Gn of nr)await g.update(S).set({isActive:!1,revokedAt:new Date,revokedReason:"bot_session_cleanup"}).where($r(S.id,Gn.id));l.info("[AUTH] Cleaned up stale bot/crawler sessions",{userId:L.userId,cleanedCount:nr.length})}if(F&&!v&&!on){let Gn=q.filter((qn)=>qn.deviceFingerprint===V);for(let qn of Gn)await g.update(S).set({isActive:!1,revokedAt:new Date,revokedReason:"relogin_same_device"}).where($r(S.id,qn.id));l.info("[AUTH] Revoked old sessions from same device",{userId:L.userId,deviceFingerprint:V,revokedCount:Gn.length})}if(!Y?.allowMultipleDevices&&q.length>0){if(q.filter((qn)=>qn.deviceFingerprint===V).length===0&&v)for(let qn of q)await g.update(S).set({isActive:!1,revokedAt:new Date,revokedReason:"new_device_login"}).where($r(S.id,qn.id))}if(Y?.maxActiveSessions){let{count:Gn}=await import("drizzle-orm"),gr=(await g.select({count:Gn()}).from(S).where(ie($r(S.userId,L.userId),$r(S.isActive,!0))))[0]?.count||0;if(gr>=Y.maxActiveSessions){let{asc:Ar}=await import("drizzle-orm"),Mt=await g.select().from(S).where(ie($r(S.userId,L.userId),$r(S.isActive,!0))).orderBy(Ar(S.createdAt)).limit(gr-Y.maxActiveSessions+1);for(let ir of Mt)await g.update(S).set({isActive:!1,revokedAt:new Date,revokedReason:"max_sessions_exceeded"}).where($r(S.id,ir.id))}}let gn=100;if(Q.isHeadless)gn-=50;if(Q.isBot)gn-=40;if(Q.isSuspicious)l.warn("[AUTH] Suspicious login detected",{userId:L.userId,suspiciousPatterns:Q.suspiciousPatterns,userAgent:Q.userAgent,ipAddress:Q.ipAddress});if(v)gn-=25;if(!Q.ipAddress||Q.ipAddress==="unknown")gn-=20;if(!Q.browserName)gn-=15;if(!Q.osName)gn-=15;if(!Q.deviceType||Q.deviceType==="unknown")gn-=10;if(!Q.deviceName||Q.deviceName==="Unknown Device")gn-=5;let et=V&&!V.includes("--unknown")&&V!=="--",_n=Q.ipAddress&&Q.ipAddress!=="unknown";if(et){if(q.filter((qn)=>qn.deviceFingerprint===V).length>0)gn+=20}if(_n){if(q.filter((qn)=>qn.ipAddress===Q.ipAddress).length>0)gn+=15}gn=Math.max(0,Math.min(100,gn));let T=50;if(await g.insert(S).values({id:B,userId:L.userId,tokenHash:B,deviceFingerprint:V,deviceName:Q.deviceName,deviceType:Q.deviceType,browserName:Q.browserName,browserVersion:Q.browserVersion,osName:Q.osName,osVersion:Q.osVersion,ipAddress:Q.ipAddress,locationCountry:Q.locationCountry,locationCity:Q.locationCity,loginMethod:L.loginMethod||"password",rememberMe:L.rememberMe??!1,trustScore:gn,lastActivityAt:new Date,createdAt:new Date,expiresAt:new Date(Date.now()+st(c.sessionToken?.expiresIn||"30d")*1000),isActive:Yn==="approved",approvalStatus:Yn,approvalToken:en,approvalRequestedAt:un?new Date:null}),H&&(Y?.notifyOnNewDevice&&v||gn<T||un)){let Gn=R.users;if(Gn){let gr=(await g.select().from(Gn).where($r(Gn.id,L.userId)).limit(1))[0];if(gr?.email){let Ar=gn<T,Mt=c.sessions?.approvalRedirectUrl||"http://localhost:3000/devices",ir=en?`${Mt}?action=approve&token=${en}`:"",lr=en?`${Mt}?action=reject&token=${en}`:"",Rs,ks;if(un)Rs="\uD83D\uDD10 New Device Login Requires Approval",ks=`
|
|
1526
|
+
</html>`;var El=Symbol.for("TypeBox.Kind"),cA=(n)=>n.split("/").map((r)=>{if(r.startsWith(":")){if(r=r.slice(1,r.length),r.endsWith("?"))r=r.slice(0,-1);r=`{${r}}`}return r}).join("/"),kl=(n,r,t)=>{if(r===void 0)return[];if(typeof r==="string")if(r in t)r=t[r];else throw Error(`Can't find model ${r}`);return Object.entries(r?.properties??[]).map(([o,a])=>{let{type:c=void 0,description:e,examples:i,...s}=a;return{description:e,examples:i,schema:{type:c,...s},in:n,name:o,required:r.required?.includes(o)??!1}})},Wc=(n,r)=>{if(typeof r==="object"&&["void","undefined","null"].includes(r.type))return;let t={};for(let o of n)t[o]={schema:typeof r==="string"?{$ref:`#/components/schemas/${r}`}:("$ref"in r)&&(El in r)&&r[El]==="Ref"?{...r,$ref:`#/components/schemas/${r.$ref}`}:aA({...r},{from:Rl.Ref(""),to:({$ref:a,...c})=>{if(!a.startsWith("#/components/schemas/"))return Rl.Ref(`#/components/schemas/${a}`,c);return Rl.Ref(a,c)}})};return t},t_=(n)=>n.charAt(0).toUpperCase()+n.slice(1),eA=(n,r)=>{let t=n.toLowerCase();if(r==="/")return t+"Index";for(let o of r.split("/"))if(o.charCodeAt(0)===123)t+="By"+t_(o.slice(1,-1));else t+=t_(o);return t},Ya=(n)=>{if(!n)return;if(typeof n==="string")return n;if(Array.isArray(n))return[...n];return{...n}},o_=({schema:n,path:r,method:t,hook:o,models:a})=>{if(o=Ya(o),o.parse&&!Array.isArray(o.parse))o.parse=[o.parse];let c=o.parse?.map((w)=>{switch(typeof w){case"string":return w;case"object":if(w&&typeof w?.fn!=="string")return;switch(w?.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((w)=>w!==void 0);if(!c||c.length===0)c=["application/json","multipart/form-data","text/plain"];r=cA(r);let e=typeof c==="string"?[c]:c??["application/json"],i=Ya(o?.body),s=Ya(o?.params),f=Ya(o?.headers),l=Ya(o?.query),d=Ya(o?.response);if(typeof d==="object")if(El in d){let{type:w,properties:h,required:_,additionalProperties:g,patternProperties:R,$ref:k,...M}=d;d={"200":{...M,description:M.description,content:Wc(e,w==="object"||w==="array"?{type:w,properties:h,patternProperties:R,items:d.items,required:_}:d)}}}else Object.entries(d).forEach(([w,h])=>{if(typeof h==="string"){if(!a[h])return;let{type:_,properties:g,required:R,additionalProperties:k,patternProperties:M,...C}=a[h];d[w]={...C,description:C.description,content:Wc(e,h)}}else{let{type:_,properties:g,required:R,additionalProperties:k,patternProperties:M,...C}=h;d[w]={...C,description:C.description,content:Wc(e,_==="object"||_==="array"?{type:_,properties:g,patternProperties:M,items:h.items,required:R}:h)}}});else if(typeof d==="string"){if(!(d in a))return;let{type:w,properties:h,required:_,$ref:g,additionalProperties:R,patternProperties:k,...M}=a[d];d={"200":{...M,content:Wc(e,d)}}}let b=[...kl("header",f,a),...kl("path",s,a),...kl("query",l,a)];n[r]={...n[r]?n[r]:{},[t.toLowerCase()]:{...f||s||l||i?{parameters:b}:{},...d?{responses:d}:{},operationId:o?.detail?.operationId??eA(t,r),...o?.detail,...i?{requestBody:{required:!0,content:Wc(e,typeof i==="string"?{$ref:`#/components/schemas/${i}`}:i)}}:null}}},iA=(n,{excludeStaticFile:r=!0,exclude:t=[]})=>{let o={};for(let[a,c]of Object.entries(n))if(!t.some((e)=>{if(typeof e==="string")return a===e;return e.test(a)})&&!a.includes("*")&&(r?!a.includes("."):!0))Object.keys(c).forEach((e)=>{let i=c[e];if(a.includes("{")){if(!i.parameters)i.parameters=[];i.parameters=[...a.split("/").filter((s)=>s.startsWith("{")&&!i.parameters.find((f)=>f.in==="path"&&f.name===s.slice(1,s.length-1))).map((s)=>({schema:{type:"string"},in:"path",name:s.slice(1,s.length-1),required:!0})),...i.parameters]}if(!i.responses)i.responses={200:{}}}),o[a]=c;return o},c_=({provider:n="scalar",scalarVersion:r="latest",scalarCDN:t="",scalarConfig:o={},documentation:a={},version:c="5.9.0",excludeStaticFile:e=!0,path:i="/swagger",specPath:s=`${i}/json`,exclude:f=[],swaggerOptions:l={},theme:d=`https://unpkg.com/swagger-ui-dist@${c}/swagger-ui.css`,autoDarkMode:b=!0,excludeMethods:w=["OPTIONS"],excludeTags:h=[]}={})=>{let _={},g=0;if(!c)c=`https://unpkg.com/swagger-ui-dist@${c}/swagger-ui.css`;let R={title:"Elysia Documentation",description:"Development documentation",version:"0.0.0",...a.info},k=s.startsWith("/")?s.slice(1):s,M=new nA({name:"@elysiajs/swagger"}),C=new Response(n==="swagger-ui"?tA(R,c,d,JSON.stringify({url:k,dom_id:"#swagger-ui",...l},(N,m)=>typeof m==="function"?void 0:m),b):oA(R,r,{spec:{url:k,...o.spec},...o,_integration:"elysiajs"},t),{headers:{"content-type":"text/html; charset=utf8"}});return M.get(i,C,{detail:{hide:!0}}).get(s,function(){let m=M.getGlobalRoutes();if(m.length!==g){let A=["GET","PUT","POST","DELETE","OPTIONS","HEAD","PATCH","TRACE"];g=m.length,m.forEach((H)=>{if(H.hooks?.detail?.hide===!0)return;if(w.includes(H.method))return;if(A.includes(H.method)===!1&&H.method!=="ALL")return;if(H.method==="ALL")A.forEach((D)=>{o_({schema:_,hook:H.hooks,method:D,path:H.path,models:M.getGlobalDefinitions?.().type,contentType:H.hooks.type})});else o_({schema:_,hook:H.hooks,method:H.method,path:H.path,models:M.getGlobalDefinitions?.().type,contentType:H.hooks.type})})}return{openapi:"3.0.3",...{...a,tags:a.tags?.filter((A)=>!h?.includes(A?.name)),info:{title:"Elysia Documentation",description:"Development documentation",version:"0.0.0",...a.info}},paths:{...iA(_,{excludeStaticFile:e,exclude:Array.isArray(f)?f:[f]}),...a.paths},components:{...a.components,schemas:{...M.getGlobalDefinitions?.().type,...a.components?.schemas}}}},{detail:{hide:!0}}),M};function Sl(n){if(n?.enabled===!1)return null;let r={path:n?.path??"/swagger",provider:n?.provider??"scalar",excludeStaticFile:n?.excludeStaticFile??!0,exclude:n?.exclude??[],documentation:{info:{title:n?.documentation?.info?.title??"Nucleus API",description:n?.documentation?.info?.description??"Auto-generated API documentation",version:n?.documentation?.info?.version??"1.0.0",contact:n?.documentation?.info?.contact,license:n?.documentation?.info?.license},tags:n?.documentation?.tags??[],servers:n?.documentation?.servers},scalarConfig:n?.scalarConfig};return c_(r)}Ie();Qd();ni();var HE=(n)=>{let r=new Map;for(let t of n){let o=r.get(t.table_name),a=t.columns??o?.columns;r.set(t.table_name,{...o||{},...t,columns:a})}return Array.from(r.values())},zE=(n)=>({table_name:n.table_name,excluded_methods:n.excluded_methods?[...n.excluded_methods]:void 0,columns:n.columns?n.columns.map((r)=>({name:r.name,type:r.type})):void 0}),UE=(n)=>{let r=[];for(let[t,o]of Object.entries(n)){if(!o||typeof o!=="object")continue;let a=o,c=a._;if(c?.name){r.push({table_name:c.name});continue}let e=Object.getOwnPropertySymbols(a);for(let i of e){let s=a[i];if(s&&typeof s==="object"){let f=s;if(f.name&&typeof f.name==="string"){r.push({table_name:f.name});break}}}}return r};async function BE(n){let r=new DE;if(r.get("/health",()=>({status:"ok",timestamp:Date.now()})),n.staticAssets!==!1){let E=Sn("path"),S=Sn("fs"),z;if(typeof n.staticAssets==="string")z=n.staticAssets;else{let U=E.join(process.cwd(),"public"),P="";for(let p of["nucleus-core-ts","nucleus-core"])try{let K=Sn.resolve(`${p}/package.json`),B=E.join(E.dirname(K),"public");if(S.existsSync(B)){P=B;break}}catch{}if(P)z=P;else if(S.existsSync(U))z=U;else z=U}try{r.use(await au({prefix:"/nucleus-core",assets:z}))}catch{}}let t=[],o,a=process.cwd();if(typeof n.options==="string"){let E=Sn("fs"),S=Sn("path"),z=S.isAbsolute(n.options)?n.options:S.resolve(process.cwd(),n.options);a=S.dirname(z);let U=E.readFileSync(z,"utf-8");o=JSON.parse(U)}else o=n.options;if(o.email?.gmail?.json_file_path){let E=Sn("path"),S=o.email.gmail.json_file_path;if(!E.isAbsolute(S))o.email.gmail.json_file_path=E.resolve(a,S)}let{authentication:c,audit:e,entities:i,database:s}=o,f=o.mode==="development",l=new Cr({service:o.appId||"nucleus",prettyPrint:f,colorize:f,auditEnabled:e?.enabled??!1}),d=ug(o);if(!d.valid){for(let E of d.errors)l.error(`[CONFIG] ${E.message}`,{field:E.field,envName:E.envName});throw Error("Nucleus configuration error: Missing required environment variables. Check logs for details.")}let{resolved:b}=d,w={access_token:c?.accessToken?.name||"access_token",refresh_token:c?.refreshToken?.name||"refresh_token",session_token:c?.sessionToken?.name||"session_token"},h=s?.schemas?.[0]||"main",_=ME(h);if(b.databaseUrl)await bg(b.databaseUrl,l);let g=b.databaseUrl?SE(b.databaseUrl):null,R={},k={};if(n.schema){let S=Sn("path").resolve(process.cwd(),n.schema),z=Sn(S);R=z.createAllTablesForSchema?z.createAllTablesForSchema(_):{}}if(n.relations){let S=Sn("path").resolve(process.cwd(),n.relations);k=Sn(S)}let M=Sl(n.swagger);if(M)r.use(M);let C=n.systemTables||[];t=Nf(o,C,"",h),l.info(`[AUTH] Built ${t.length} public routes`);let N=null,m=null,A=null,H=null;if(o.email?.gmail?.enabled&&o.email.gmail.json_file_path)l.info("[GmailService] Initializing...",{jsonFilePath:o.email.gmail.json_file_path,fromEmail:o.email.gmail.from_email}),H=new Jf({enabled:!0,jsonFilePath:o.email.gmail.json_file_path,fromEmail:o.email.gmail.from_email||"",fromName:o.email.gmail.from_name},l),l.info("[GmailService] isAvailable:",{available:H.isAvailable()});if(o.liveMonitoring?.enabled){let E=o.liveMonitoring.basePath||"/monitoring",S=o.liveMonitoring.streamInterval||150;r.use(Ag({getService:()=>A,logger:l,basePath:E,streamInterval:S}))}r.onStart(async()=>{tl(o);let E=Te();if(E&&o.rateLimit?.enabled!==!1)N=new Qf({redis:E,logger:l,config:o.rateLimit||{}}),l.info(`[RateLimit] Enabled with strategy: ${o.rateLimit?.strategy||"sliding-window"}`);if(E&&o.monitoring?.enabled){if(m=new Vf({redis:E,logger:l,gmail:H||void 0,config:o.monitoring,appId:o.appId}),m.start(),l.info("[Monitoring] Service started"),o.monitoring.endpoints?.enabled){let z={enabled:!0,basePath:o.monitoring.endpoints.basePath||"/monitoring",stream:{enabled:o.monitoring.endpoints.stream?.enabled!==!1,path:o.monitoring.endpoints.stream?.path||"/stream",interval:o.monitoring.endpoints.stream?.interval||"5s"},snapshot:{enabled:o.monitoring.endpoints.snapshot?.enabled!==!1,path:o.monitoring.endpoints.snapshot?.path||"/snapshot"},history:{enabled:o.monitoring.endpoints.history?.enabled!==!1,path:o.monitoring.endpoints.history?.path||"/history",maxMinutes:o.monitoring.endpoints.history?.maxMinutes||60},alerts:{enabled:o.monitoring.endpoints.alerts?.enabled!==!1,path:o.monitoring.endpoints.alerts?.path||"/alerts"}};r.use(ll({monitoringService:m,logger:l,endpoints:z}))}}if(o.liveMonitoring?.enabled)A=new Ce(o.liveMonitoring),A.start(),l.info("[LiveMonitoring] Service started");let S=c?.mode==="consumer";if(g&&n.schema&&!S){let P=await import(Sn("path").resolve(process.cwd(),n.schema)),p=R.auditLogs||P.auditLogs;if(e?.enabled&&p)l.addAuditTransport(new de({db:g,table:p,enabled:!0}));try{l.info(`Syncing schema to database (target: ${h})...`);let{sql:B}=await import("drizzle-orm");await g.execute(B.raw(`CREATE SCHEMA IF NOT EXISTS "${h}"`));try{let L=Object.fromEntries(Object.entries(R).filter(([q,F])=>{if(F===void 0||F===null)return!1;if(typeof F==="object"&&F!==null)return Object.getOwnPropertySymbols(F).length>0||F._!==void 0;return!1})),Y=Object.keys(L);l.info("[Schema] Tables to sync:",{tables:Y,count:Y.length});let Q=L.users;if(Q){let q=Object.getOwnPropertyNames(Q).filter((F)=>!F.startsWith("_"));l.info("[Schema] Users table columns:",{columns:q})}await(await EE({schema:_,...L},g,[h])).apply(),l.info("[Schema] pushSchema completed successfully")}catch(L){let Y=L instanceof Error?L.message:String(L);l.warn(`[Schema] pushSchema warning: ${Y}`)}console.log("Schema sync completed")}catch(B){let L=B instanceof Error?B.message:String(B);console.error("Schema sync failed:",L)}if(console.log("Database connection established"),o.authorization?.enabled){let B={...ib,...o.authorization};if(B.autoSeedClaims){let L=UE(R),Y=qe.map((q)=>zE(q)),Q=o.entities||[],V=HE([...L,...Q,...Y,...n.systemTables||[]]);l.info("[Authorization] Seeding claims...",{schemaEntities:L.length,systemEntities:Y.length,configEntities:Q.length,totalEntities:V.length}),await yu(g,R,k,V,B,l)}if(B.godminEmail&&B.godminPassword)l.info("[Authorization] Setting up godmin..."),await rb(g,R,B,l);l.info("[Authorization] Enabled")}let K=R.userSessions;if(K&&o.authentication?.sessions?.enabled){let{lt:B}=await import("drizzle-orm"),L=await g.update(K).set({isActive:!1,revokedAt:new Date,revokedReason:"expired"}).where(ie($r(K.isActive,!0),B(K.expiresAt,new Date)));l.info("[AUTH] Expired sessions cleanup completed",{expiredCount:L}),setInterval(async()=>{try{await g.update(K).set({isActive:!1,revokedAt:new Date,revokedReason:"expired"}).where(ie($r(K.isActive,!0),B(K.expiresAt,new Date)))}catch(Y){l.warn("[AUTH] Session cleanup failed",{error:Y})}},3600000)}}}).onRequest(async({request:E,set:S})=>{let z=Date.now();E.headers.set("x-request-start-time",String(z));let U=new URL(E.url),P=U.pathname,p=E.method,K=U.search,B=E.headers.get("x-forwarded-for")?.split(",")[0]?.trim()||E.headers.get("x-real-ip")?.trim()||"unknown",L=E.headers.get("user-agent")||"unknown",Y,Q={};if(E.method!=="GET"&&E.method!=="HEAD")try{let v=await E.clone().text();Q=v?JSON.parse(v):{}}catch{Q={}}let V=e?.enabled?{id:kE(),user_id:"unknown",entity_name:P.split("/").filter(Boolean)[0]||"root",entity_id:null,operation_type:p,summary:"",old_values:{},new_values:Q,ip_address:B,user_agent:L,timestamp:new Date().toISOString(),path:P,query:K}:null,q=xf(t,P,p);if(N){let F=q?"public":"private",v;if(P.includes("/auth/login"))v="login";else if(P.includes("/auth/register"))v="register";else if(P.includes("/auth/password-reset"))v="passwordReset";else if(P.includes("/auth/magic-link"))v="magicLink";let dn=v?"auth":F,on=await N.check({ip:B,endpoint:P,category:dn,authType:v}),un=N.getHeaders(on);for(let[en,Yn]of Object.entries(un))S.headers[en]=Yn;if(!on.allowed){if(S.status=429,on.retryAfter)S.headers["Retry-After"]=String(on.retryAfter);if(l.warn(`[RateLimit] Blocked request from ${B} to ${P}`),m)m.recordRateLimitBlock();return new Response(JSON.stringify({error:"Too Many Requests",retryAfter:on.retryAfter}),{status:429,headers:{"Content-Type":"application/json"}})}}if(P==="/health")return;if(c?.enabled&&!q){if(!c.accessToken?.secret)return S.status=500,l.traceSync({message:"Authentication secrets not defined",level:"error",context:{path:P,method:p},audit:xt(V,"Authentication secrets not defined")}),Error("One or more authentication secrets are not defined");if(c.mode==="consumer"){Y=rl(E.headers,w);let v=so(Y.access_token||"",b.accessTokenSecret||"");if(!v.valid)return S.status=401,l.traceSync({message:"Invalid or missing access token",level:"warn",context:{path:P,method:p},audit:xt(V,"Invalid or missing access token")}),Error("Unauthenticated");let dn=v.payload.sub,on=v.payload.roles,un=v.payload.claims;if(E.headers.set("x-access-token",Y.access_token||""),E.headers.set("x-user-id",dn||""),on&&on.length>0)E.headers.set("x-user-roles",on.join(","));if(un&&un.length>0)E.headers.set("x-user-claims",un.join(","))}else{if(!c.refreshToken?.secret||!c.sessionToken?.secret)return S.status=500,l.traceSync({message:"Authentication secrets not defined",level:"error",context:{path:P,method:p},audit:xt(V,"Authentication secrets not defined")}),Error("One or more authentication secrets are not defined");if(Y=rl(E.headers,w),!Y.session_token)return S.status=401,l.traceSync({message:"No session token",level:"warn",context:{path:P,method:p},audit:xt(V,"No session token")}),Error("Unauthenticated");let v=await Qo({sessionId:Y.session_token});if(!v)return S.status=401,l.traceSync({message:"Invalid session",level:"warn",context:{path:P,method:p,sessionId:Y.session_token},audit:xt(V,"Invalid session")}),Error("Unauthenticated");let dn=R.userSessions;if(dn&&g){let T=(await g.select().from(dn).where($r(dn.id,Y.session_token)).limit(1))[0],Jn=T?.revokedAt!==null&&T?.revokedAt!==void 0&&!(typeof T?.revokedAt==="object"&&Object.keys(T.revokedAt).length===0);if(!T||T.isActive===!1||Jn)return S.status=401,l.traceSync({message:"Session revoked or inactive",level:"warn",context:{path:P,method:p,sessionId:Y.session_token,isActive:T?.isActive,revokedAt:T?.revokedAt},audit:xt(V,"Session revoked")}),Error("Session has been revoked");if(T.expiresAt&&new Date(T.expiresAt)<new Date)return S.status=401,l.traceSync({message:"Session expired",level:"warn",context:{path:P,method:p,sessionId:Y.session_token,expiresAt:T.expiresAt},audit:xt(V,"Session expired")}),Error("Session has expired")}if(v.lastActiveAt&&c.sessions?.inactivityTimeout){let _n=new Date(v.lastActiveAt).getTime(),T=st(c.sessions.inactivityTimeout)*1000;if(Date.now()-_n>T)return S.status=401,l.traceSync({message:"Session inactive timeout",level:"warn",context:{path:P,method:p,sessionId:Y.session_token,lastActiveAt:v.lastActiveAt},audit:xt(V,"Session inactive timeout")}),Error("Session expired due to inactivity")}Af(Y.session_token).catch(()=>{});let on=R.userSessions;if(on&&g)g.update(on).set({lastActivityAt:new Date}).where($r(on.id,Y.session_token)).catch(()=>{});let un=so(Y.access_token||"",b.accessTokenSecret||""),en=Y.access_token?un.valid:!1,Yn=Y.refresh_token?so(Y.refresh_token,b.refreshTokenSecret||"").valid:!1;if(!en&&Yn&&Y.refresh_token&&v.rememberMe===!0){let _n=await dg(v.userId,v.id,()=>fg({refreshTokenId:Y.refresh_token,options:o,sessionData:v}));if(_n.success&&_n.accessToken){Y.access_token=_n.accessToken;let T=`${w.access_token}=${_n.accessToken}; Path=/; HttpOnly; SameSite=Strict;Secure; Max-Age=${st(c.accessToken.expiresIn??"15m")}`;S.headers["Set-Cookie"]=T}}let nr=un.valid?un.payload.sub:v.userId,gn=un.valid?un.payload.roles:void 0,et=un.valid?un.payload.claims:void 0;if(E.headers.set("x-access-token",Y.access_token||""),E.headers.set("x-refresh-token",Y.refresh_token||""),E.headers.set("x-session-id",Y.session_token||""),E.headers.set("x-user-id",nr||""),gn&&gn.length>0)E.headers.set("x-user-roles",gn.join(","));if(et&&et.length>0)E.headers.set("x-user-claims",et.join(","))}}}).onAfterHandle(({request:E,set:S})=>{if(m){let z=E.headers.get("x-request-start-time"),U=z?parseInt(z,10):Date.now(),P=Date.now()-U,p=new URL(E.url),K=typeof S.status==="number"?S.status:200;m.recordRequest({endpoint:p.pathname,method:E.method,status:K,responseTimeMs:P,isError:K>=400,errorType:K>=500?"server_error":K>=400?"client_error":void 0})}if(A){let z=new URL(E.url),U={};E.headers.forEach((P,p)=>{U[p]=P}),A.recordRequest({path:z.pathname,method:E.method,timestamp:Date.now(),headers:U})}}).onError((E)=>{let{set:S,code:z,error:U}=E,P=typeof z==="number"?z:500,p=U instanceof Error?U.message:"Internal Server Error";return S.status=P,Response.json({isSuccess:!1,message:p,status:P,errors:[U],data:null})}),l.info("Creating routes for entities"),fl(r,{db:g,schemaTables:R,schemaRelations:k,entities:i,logger:l,databaseUrl:b.databaseUrl,storage:o.storage,authorization:o.authorization,emailServiceAvailable:!!(o.email?.gmail?.enabled&&o.email.gmail.json_file_path)});let D=c?.mode==="consumer";if(c?.enabled&&!D&&g){let E=R.users,S=R.userSessions||R.user_sessions||R.sessions;if(!S&&c.sessions?.enabled)l.warn("[AUTH] sessions is enabled but user_sessions table not found in schema. Disabling sessions.");if(E){tl(o);let{createAuthRoutes:z}=(Qd(),se(M2)),{signJWT:U,verifyJWT:P}=(Vo(),se(wu)),{generateSession:p,deleteSession:K}=(Rf(),se(Iu));z(r,{authConfig:{db:g,logger:l,usersTable:E,sessionsTable:S,userRolesTable:R.userRoles,rolesTable:R.roles,roleClaimsTable:R.roleClaims,claimsTable:R.claims,authentication:{enabled:c.enabled,accessToken:c.accessToken,refreshToken:c.refreshToken,sessionToken:c.sessionToken}},features:{login:c.login,register:c.register,logout:c.logout,refresh:c.refresh,passwordReset:(()=>{let B=!!(o.email?.gmail?.enabled&&o.email.gmail.json_file_path);if(c.passwordReset?.enabled&&!B)return l.warn("[AUTH] passwordReset is enabled but no email provider is configured. Disabling passwordReset."),{...c.passwordReset,enabled:!1};return c.passwordReset})(),passwordChange:c.passwordChange,passwordSet:c.passwordSet,sessions:c.sessions,magicLink:(()=>{let B=!!(o.email?.gmail?.enabled&&o.email.gmail.json_file_path);if(c.magicLink?.enabled&&!B)return l.warn("[AUTH] magicLink is enabled but no email provider is configured. Disabling magicLink."),{...c.magicLink,enabled:!1};return c.magicLink})(),me:c.me||{enabled:!0,route:"/auth/me"},invite:(()=>{let B=!!(o.email?.gmail?.enabled&&o.email.gmail.json_file_path);if(c.invite?.enabled&&!B)return l.warn("[AUTH] invite is enabled but no email provider is configured. Disabling invite."),{...c.invite,enabled:!1};return c.invite})(),captcha:c.captcha,oauth:c.oauth?.enabled&&b.oauthProviders?{...c.oauth,providers:b.oauthProviders}:void 0},sessionsTable:S,oauthAccountsTable:R.oauthAccounts,schemaTables:R,schemaRelations:k,databaseUrl:b.databaseUrl,admin:{impersonate:{enabled:!0},changeUserId:{enabled:!0}},emailService:H,appName:o.appId,captchaService:(()=>{let B=Te();if(!c.captcha?.enabled||!B)return null;return new Wf({redis:{get:async(Y)=>{let Q=await B.read(Y);return Q.success?Q.data:null},set:async(Y,Q,V)=>{await B.create(Y,Q,V?.ex)},del:async(Y)=>{await B.remove(Y)}},logger:l,config:{enabled:!0,type:c.captcha.type||"math",difficulty:c.captcha.difficulty||"medium",expiresIn:c.captcha.expiresIn||"5m",maxAttempts:c.captcha.maxAttempts||3,caseSensitive:c.captcha.caseSensitive??!1}})})(),tokenResponseConfig:{accessToken:{setHeadersEnabled:c.accessToken?.setHeadersEnabled??!0,returnJson:c.accessToken?.returnJson??!0},refreshToken:{setHeadersEnabled:c.refreshToken?.setHeadersEnabled??!0,returnJson:c.refreshToken?.returnJson??!0},sessionToken:{setHeadersEnabled:c.sessionToken?.setHeadersEnabled??!0,returnJson:c.sessionToken?.returnJson??!0}},helpers:{signAccessToken:(B,L,Y)=>U({subject:B,expiresInSeconds:st(c.accessToken?.expiresIn||"15m"),issuer:c.accessToken?.issuer,audience:c.accessToken?.audience,customClaims:{...L&&L.length>0?{roles:L}:{},...Y&&Y.length>0?{claims:Y}:{}}},b.accessTokenSecret||"",c.accessToken?.algorithm||"HS256"),signRefreshToken:(B)=>U({subject:B,expiresInSeconds:st(c.refreshToken?.expiresIn||"7d"),issuer:c.refreshToken?.issuer,audience:c.refreshToken?.audience},b.refreshTokenSecret||"",c.refreshToken?.algorithm||"HS256"),verifyRefreshToken:(B)=>P(B,b.refreshTokenSecret||""),createSession:async(B)=>{let L=await p({userId:B.userId,deviceInfo:B.deviceInfo});return L.success?L.session.id:""},destroySession:async(B)=>K({sessionId:B}),saveSessionToDb:async(B,L)=>{if(!S||!g)return;let Y=c.sessions,Q=L.deviceInfo||{},V=`${Q.browserName||""}-${Q.osName||""}-${Q.deviceType||""}`,q=await g.select().from(S).where(ie($r(S.userId,L.userId),$r(S.isActive,!0))),F=V&&!V.includes("--unknown")&&!V.includes("Bot/Crawler")&&!V.includes("Headless")&&V!=="--"&&V!=="--unknown",v=F?!q.some((Gn)=>Gn.deviceFingerprint===V):!1,dn=q.some((Gn)=>Gn.approvalStatus==="approved"),on=L.loginMethod==="impersonation"||L.loginMethod==="impersonation_stop",un=!on&&Y?.trustNewDevices===!1&&v&&F&&dn;l.info("[AUTH] Device fingerprint analysis",{userId:L.userId,deviceFingerprint:V,hasValidFingerprint:F,isNewDevice:v,loginMethod:L.loginMethod,isImpersonationLogin:on,existingSessionCount:q.length,hasAnyApprovedSession:dn,requiresApproval:un});let en=null,Yn="approved";if(un){let{randomBytes:Gn}=await import("crypto");en=Gn(32).toString("hex"),Yn="pending",l.info("[AUTH] New device requires approval",{userId:L.userId,deviceFingerprint:V,ipAddress:Q.ipAddress})}let nr=q.filter((Gn)=>{let qn=Gn,gr=qn.deviceFingerprint||"",Ar=qn.ipAddress||"";return(!gr||gr==="--"||gr==="--unknown"||gr.includes("Bot/Crawler")||gr.includes("Headless")||gr.includes("unknown-unknown"))&&(Ar==="127.0.0.1"||Ar==="::1"||Ar==="localhost"||!Ar)});if(nr.length>0){for(let Gn of nr)await g.update(S).set({isActive:!1,revokedAt:new Date,revokedReason:"bot_session_cleanup"}).where($r(S.id,Gn.id));l.info("[AUTH] Cleaned up stale bot/crawler sessions",{userId:L.userId,cleanedCount:nr.length})}if(F&&!v&&!on){let Gn=q.filter((qn)=>qn.deviceFingerprint===V);for(let qn of Gn)await g.update(S).set({isActive:!1,revokedAt:new Date,revokedReason:"relogin_same_device"}).where($r(S.id,qn.id));l.info("[AUTH] Revoked old sessions from same device",{userId:L.userId,deviceFingerprint:V,revokedCount:Gn.length})}if(!Y?.allowMultipleDevices&&q.length>0){if(q.filter((qn)=>qn.deviceFingerprint===V).length===0&&v)for(let qn of q)await g.update(S).set({isActive:!1,revokedAt:new Date,revokedReason:"new_device_login"}).where($r(S.id,qn.id))}if(Y?.maxActiveSessions){let{count:Gn}=await import("drizzle-orm"),gr=(await g.select({count:Gn()}).from(S).where(ie($r(S.userId,L.userId),$r(S.isActive,!0))))[0]?.count||0;if(gr>=Y.maxActiveSessions){let{asc:Ar}=await import("drizzle-orm"),Mt=await g.select().from(S).where(ie($r(S.userId,L.userId),$r(S.isActive,!0))).orderBy(Ar(S.createdAt)).limit(gr-Y.maxActiveSessions+1);for(let ir of Mt)await g.update(S).set({isActive:!1,revokedAt:new Date,revokedReason:"max_sessions_exceeded"}).where($r(S.id,ir.id))}}let gn=100;if(Q.isHeadless)gn-=50;if(Q.isBot)gn-=40;if(Q.isSuspicious)l.warn("[AUTH] Suspicious login detected",{userId:L.userId,suspiciousPatterns:Q.suspiciousPatterns,userAgent:Q.userAgent,ipAddress:Q.ipAddress});if(v)gn-=25;if(!Q.ipAddress||Q.ipAddress==="unknown")gn-=20;if(!Q.browserName)gn-=15;if(!Q.osName)gn-=15;if(!Q.deviceType||Q.deviceType==="unknown")gn-=10;if(!Q.deviceName||Q.deviceName==="Unknown Device")gn-=5;let et=V&&!V.includes("--unknown")&&V!=="--",_n=Q.ipAddress&&Q.ipAddress!=="unknown";if(et){if(q.filter((qn)=>qn.deviceFingerprint===V).length>0)gn+=20}if(_n){if(q.filter((qn)=>qn.ipAddress===Q.ipAddress).length>0)gn+=15}gn=Math.max(0,Math.min(100,gn));let T=50;if(await g.insert(S).values({id:B,userId:L.userId,tokenHash:B,deviceFingerprint:V,deviceName:Q.deviceName,deviceType:Q.deviceType,browserName:Q.browserName,browserVersion:Q.browserVersion,osName:Q.osName,osVersion:Q.osVersion,ipAddress:Q.ipAddress,locationCountry:Q.locationCountry,locationCity:Q.locationCity,loginMethod:L.loginMethod||"password",rememberMe:L.rememberMe??!1,trustScore:gn,lastActivityAt:new Date,createdAt:new Date,expiresAt:new Date(Date.now()+st(c.sessionToken?.expiresIn||"30d")*1000),isActive:Yn==="approved",approvalStatus:Yn,approvalToken:en,approvalRequestedAt:un?new Date:null}),H&&(Y?.notifyOnNewDevice&&v||gn<T||un)){let Gn=R.users;if(Gn){let gr=(await g.select().from(Gn).where($r(Gn.id,L.userId)).limit(1))[0];if(gr?.email){let Ar=gn<T,Mt=c.sessions?.approvalRedirectUrl||"http://localhost:3000/devices",ir=en?`${Mt}?action=approve&token=${en}`:"",lr=en?`${Mt}?action=reject&token=${en}`:"",Rs,ks;if(un)Rs="\uD83D\uDD10 New Device Login Requires Approval",ks=`
|
|
1527
1527
|
<h2>\uD83D\uDD10 New Device Login Requires Your Approval</h2>
|
|
1528
1528
|
<p>Someone is trying to log into your account from a new device:</p>
|
|
1529
1529
|
<ul>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nucleus-core-ts",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.91",
|
|
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",
|