modelence 0.6.0-dev.7 → 0.6.0-dev.9

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/server.js CHANGED
@@ -1,18 +1,18 @@
1
- import {a as a$2}from'./chunk-DN5SVAO2.js';import {f,g,e,l,m,n,o,i,h as h$1,d,k,p as p$1,a as a$3,t,s,q as q$1,r,j as j$2}from'./chunk-5TLHWYXF.js';export{e as Module,f as Store,l as dbUsers,g as schema}from'./chunk-5TLHWYXF.js';import {a}from'./chunk-R7MPLJMA.js';import {e as e$1,d as d$1,c,f as f$1,g as g$1,a as a$1,h as h$2,j as j$1,k as k$1}from'./chunk-2QLNYYBR.js';export{a as getConfig}from'./chunk-2QLNYYBR.js';import ct from'dotenv';import Xt from'fs/promises';import Rt from'os';import ee from'path';import ft from'bcrypt';import E,{z as z$1}from'zod';import {randomBytes}from'crypto';import {MongoClient}from'mongodb';export{ObjectId}from'mongodb';import {createServer,defineConfig,loadConfigFromFile,mergeConfig}from'vite';import $t from'@vitejs/plugin-react';import Ut from'fs';import re,{Router}from'express';import oe from'passport';import {Strategy}from'passport-google-oauth20';import qt from'cookie-parser';import Ft from'http';async function Ce(e){let t=e.toLowerCase().trim().split("@");if(t.length!==2)return false;let o=t[1];return !!await m.findOne({domain:o})}var ve={interval:a.days(1),async handler(){let e=await fetch("https://disposable.github.io/disposable-email-domains/domains.txt");if(!e.ok)throw new Error(`HTTP ${e.status}: ${e.statusText}`);let o=(await e.text()).split(`
2
- `).map(n=>n.trim().toLowerCase()).filter(n=>n.length>0),r=new Date,i=500;for(let n=0;n<o.length;n+=i){let s=o.slice(n,n+i);try{await m.insertMany(s.map(a=>({domain:a,addedAt:r})));}catch(a){a.name==="MongoBulkWriteError"&&a.result?.nInserted;}}}};var z=Object.freeze({});function Me(e){z=Object.freeze(Object.assign({},z,e));}function p(){return z}function dt(){return typeof window!="object"}function v(){if(!dt())throw new Error("This function can only be called on the server")}function U(e){return e.replace(/<[^>]*>/g,"").replace(/\s+/g," ").trim()}function Re({name:e,email:t,verificationUrl:o}){return `
3
- <p>Hi${e?` ${e}`:""},</p>
4
- <p>Please verify your email address ${t} by clicking the link below:</p>
1
+ import {a as a$2}from'./chunk-DN5SVAO2.js';import {d as d$1,a as a$3}from'./chunk-C3UESBRX.js';import {a}from'./chunk-R7MPLJMA.js';import {b as b$1,e,d as d$2,c as c$1,f,g,i,a as a$1,h as h$1,j as j$1,k as k$1}from'./chunk-2QLNYYBR.js';export{a as getConfig}from'./chunk-2QLNYYBR.js';import Ot from'dotenv';import Lo from'fs/promises';import Xt from'os';import fe from'path';import {randomBytes}from'crypto';import {ObjectId,MongoClient}from'mongodb';export{ObjectId}from'mongodb';import S,{z}from'zod';import zt from'bcrypt';import {createServer,defineConfig,loadConfigFromFile,mergeConfig}from'vite';import po from'@vitejs/plugin-react';import fo from'fs';import we,{Router}from'express';import ge from'passport';import {Strategy}from'passport-google-oauth20';import To from'cookie-parser';import _o from'http';import {Server}from'socket.io';import {createAdapter}from'@socket.io/mongo-adapter';var Te=new Map,T={authenticated:null,unauthenticated:null};function _e(t,e){T.authenticated=e.authenticated,T.unauthenticated=e.unauthenticated;for(let[o,n]of Object.entries(t))Te.set(o,n);}function F(){return T.unauthenticated?[T.unauthenticated]:[]}function ke(){return T.authenticated?[T.authenticated]:[]}function Ae(t,e){let o=e.find(n=>!_t(t,n));if(o)throw new Error(`Access denied - missing permission: '${o}'`)}function _t(t,e){for(let o of t){let n=Te.get(o);if(n&&n.permissions.includes(e))return true}return false}var y=class{constructor(e,{stores:o=[],queries:n={},mutations:r={},routes:i=[],cronJobs:s={},configSchema:a={},rateLimits:l=[],channels:m=[]}){this.name=e,this.stores=o,this.queries=n,this.mutations=r,this.routes=i,this.cronJobs=s,this.configSchema=a,this.rateLimits=l,this.channels=m;}};var h=class{constructor(e,o){this.name=e,this.schema=o.schema,this.methods=o.methods,this.indexes=o.indexes;}getName(){return this.name}getSchema(){return this.schema}init(e){if(this.collection)throw new Error(`Collection ${this.name} is already initialized`);this.client=e,this.collection=this.client.db().collection(this.name);}async createIndexes(){this.indexes.length>0&&await this.requireCollection().createIndexes(this.indexes);}wrapDocument(e){return this.methods?Object.create(null,Object.getOwnPropertyDescriptors({...e,...this.methods})):e}getSelector(e){return typeof e=="string"?{_id:new ObjectId(e)}:e instanceof ObjectId?{_id:e}:e}requireCollection(){if(!this.collection)throw new Error(`Collection ${this.name} is not provisioned`);return this.collection}requireClient(){if(!this.client)throw new Error("Database is not connected");return this.client}async findOne(e,o){let n=await this.requireCollection().findOne(e,o);return n?this.wrapDocument(n):null}async requireOne(e,o,n){let r=await this.findOne(e,o);if(!r)throw n?n():new Error(`Record not found in ${this.name}`);return r}find(e,o){let n=this.requireCollection().find(e);return o?.sort&&n.sort(o.sort),o?.limit&&n.limit(o.limit),o?.skip&&n.skip(o.skip),n}async findById(e){let o=typeof e=="string"?{_id:new ObjectId(e)}:{_id:e};return await this.findOne(o)}async requireById(e,o){let n=await this.findById(e);if(!n)throw o?o():new Error(`Record with id ${e} not found in ${this.name}`);return n}countDocuments(e){return this.requireCollection().countDocuments(e)}async fetch(e,o){return (await this.find(e,o).toArray()).map(this.wrapDocument.bind(this))}async insertOne(e){return await this.requireCollection().insertOne(e)}async insertMany(e){return await this.requireCollection().insertMany(e)}async updateOne(e,o){return await this.requireCollection().updateOne(this.getSelector(e),o)}async upsertOne(e,o){return await this.requireCollection().updateOne(this.getSelector(e),o,{upsert:true})}async updateMany(e,o,n){return await this.requireCollection().updateMany(e,o,n)}async upsertMany(e,o){return await this.requireCollection().updateMany(e,o,{upsert:true})}async deleteOne(e){return await this.requireCollection().deleteOne(e)}async deleteMany(e){return await this.requireCollection().deleteMany(e)}aggregate(e,o){return this.requireCollection().aggregate(e,o)}bulkWrite(e){return this.requireCollection().bulkWrite(e)}getDatabase(){return this.requireClient().db()}rawCollection(){return this.requireCollection()}async renameFrom(e,o){let n=this.getDatabase();if(!this.collection||!n)throw new Error(`Store ${this.name} is not provisioned`);if((await n.listCollections({name:e}).toArray()).length===0)throw new Error(`Collection ${e} not found`);if((await n.listCollections({name:this.name}).toArray()).length>0)throw new Error(`Collection ${this.name} already exists`);await n.collection(e).rename(this.name,o);}};var kt=z.string.bind(z),At=z.number.bind(z),It=z.date.bind(z),Pt=z.boolean.bind(z),Lt=z.array.bind(z),jt=z.object.bind(z),$t=z.enum.bind(z),c={string:kt,number:At,date:It,boolean:Pt,array:Lt,object:jt,enum:$t,objectId(){return z.instanceof(ObjectId)},userId(){return z.instanceof(ObjectId)},ref(t){return z.instanceof(ObjectId)},union:z.union.bind(z),infer(t){return {}}};var _=new h("_modelenceSessions",{schema:{authToken:c.string(),createdAt:c.date(),expiresAt:c.date(),userId:c.userId().nullable()},indexes:[{key:{authToken:1},unique:true},{key:{expiresAt:1}}]});async function Ie(t){let e=t?await _.findOne({authToken:t}):null;return e?{authToken:String(e.authToken),expiresAt:new Date(e.expiresAt),userId:e.userId??null}:await re()}async function Pe(t,e){await _.updateOne({authToken:t},{$set:{userId:e}});}async function Le(t){await _.updateOne({authToken:t},{$set:{userId:null}});}async function re(t=null){let e=randomBytes(32).toString("base64url"),o=Date.now(),n=new Date(o+a.days(7));return await _.insertOne({authToken:e,createdAt:new Date(o),expiresAt:n,userId:t}),{authToken:e,expiresAt:n,userId:t}}async function Nt(t){let e=Date.now(),o=new Date(e+a.days(7));await _.updateOne({authToken:t.authToken},{$set:{lastActiveDate:new Date(e),expiresAt:o}});}var je=new y("_system.session",{stores:[_],mutations:{init:async function(t,{session:e,user:o}){return {session:e,user:o,configs:b$1()}},heartbeat:async function(t,{session:e}){e&&await Nt(e);}}});var d=new h("_modelenceUsers",{schema:{handle:c.string(),emails:c.array(c.object({address:c.string(),verified:c.boolean()})).optional(),createdAt:c.date(),authMethods:c.object({password:c.object({hash:c.string()}).optional(),google:c.object({id:c.string()}).optional()})},indexes:[{key:{handle:1},unique:true,collation:{locale:"en",strength:2}}]}),L=new h("_modelenceDisposableEmailDomains",{schema:{domain:c.string(),addedAt:c.date()},indexes:[{key:{domain:1},unique:true}]}),k=new h("_modelenceEmailVerificationTokens",{schema:{userId:c.objectId(),email:c.string().optional(),token:c.string(),createdAt:c.date(),expiresAt:c.date()},indexes:[{key:{token:1},unique:true},{key:{expiresAt:1},expireAfterSeconds:0}]}),v=new h("_modelenceResetPasswordTokens",{schema:{userId:c.objectId(),token:c.string(),createdAt:c.date(),expiresAt:c.date()},indexes:[{key:{token:1},unique:true},{key:{expiresAt:1},expireAfterSeconds:0}]});async function $e(t){let e=t.toLowerCase().trim().split("@");if(e.length!==2)return false;let o=e[1];return !!await L.findOne({domain:o})}var Ue={interval:a.days(1),async handler(){let t=await fetch("https://disposable.github.io/disposable-email-domains/domains.txt");if(!t.ok)throw new Error(`HTTP ${t.status}: ${t.statusText}`);let o=(await t.text()).split(`
2
+ `).map(i=>i.trim().toLowerCase()).filter(i=>i.length>0),n=new Date,r=500;for(let i=0;i<o.length;i+=r){let s=o.slice(i,i+r);try{await L.insertMany(s.map(a=>({domain:a,addedAt:n})));}catch(a){a.name==="MongoBulkWriteError"&&a.result?.nInserted;}}}};var ie=Object.freeze({});function Ne(t){ie=Object.freeze(Object.assign({},ie,t));}function w(){return ie}function Wt(){return typeof window!="object"}function R(){if(!Wt())throw new Error("This function can only be called on the server")}function V(t){return t.replace(/<[^>]*>/g,"").replace(/\s+/g," ").trim()}function We({name:t,email:e,verificationUrl:o}){return `
3
+ <p>Hi${t?` ${t}`:""},</p>
4
+ <p>Please verify your email address ${e} by clicking the link below:</p>
5
5
  <p><a href="${o}">${o}</a></p>
6
6
  <p>If you did not request this, please ignore this email.</p>
7
- `}async function xe(e){let t=process.env.MODELENCE_SITE_URL,o=p().emailVerifiedRedirectUrl||t||"/";try{let r=z$1.string().parse(e.query.token),i=await n.findOne({token:r,expiresAt:{$gt:new Date}});if(!i)throw new Error("Invalid or expired verification token");if(!await l.findOne({_id:i.userId}))throw new Error("User not found");let s=i.email;if(!s)throw new Error("Email not found in token");if((await l.updateOne({_id:i.userId,"emails.address":s,"emails.verified":{$ne:!0}},{$set:{"emails.$.verified":!0}})).matchedCount===0)throw await l.findOne({_id:i.userId,"emails.address":s})?new Error("Email is already verified"):new Error("Email address not found for this user");await n.deleteOne({_id:i._id});}catch(r){if(r instanceof Error)return console.error("Error verifying email:",r),{status:301,redirect:`${o}?status=error&message=${encodeURIComponent(r.message)}`}}return {status:301,redirect:`${o}?status=verified`}}async function j({userId:e,email:t,baseUrl:o=process.env.MODELENCE_SITE_URL}){if(p().provider){let r=p().provider,i=randomBytes(32).toString("hex"),n$1=new Date(Date.now()+a.hours(24));await n.insertOne({userId:e,email:t,token:i,createdAt:new Date,expiresAt:n$1});let s=`${o}/api/_internal/auth/verify-email?token=${i}`,c=(p()?.verification?.template||Re)({name:"",email:t,verificationUrl:s}),f=U(c);await r?.sendEmail({to:t,from:p()?.from||"noreply@modelence.com",subject:p()?.verification?.subject||"Verify your email address",text:f,html:c});}}function J(e){return z$1.string().min(8,{message:"Password must contain at least 8 characters"}).parse(e)}function _(e){return z$1.string().email({message:"Invalid email address"}).parse(e)}async function Oe(e,{user:t,session:o,connectionInfo:r}){if(!o)throw new Error("Session is not initialized");let i=r?.ip;i&&await M({bucket:"signin",type:"ip",value:i});let n=_(e.email),s=z$1.string().parse(e.password),a=await l.findOne({"emails.address":n},{collation:{locale:"en",strength:2}}),c=a?.authMethods?.password?.hash;if(!c)throw _e();if(!a.emails?.find(l=>l.address===n)?.verified&&p()?.provider){if(i)try{await M({bucket:"verification",type:"user",value:a._id.toString()});}catch{throw new Error("Your email address hasn't been verified yet. Please use the verification email we've send earlier to your inbox.")}throw await j({userId:a?._id,email:n,baseUrl:r?.baseUrl}),new Error("Your email address hasn't been verified yet. We've sent a new verification email to your inbox.")}if(!await ft.compare(s,c))throw _e();return await h$1(o.authToken,a._id),{user:{id:a._id,handle:a.handle}}}async function De(e,{user:t,session:o}){if(!o)throw new Error("Session is not initialized");await i(o.authToken);}function _e(){return new Error("Incorrect email/password combination")}async function ke(e,{user:t}){if(!t)throw new Error("Not authenticated");let o=await l.requireById(t.id);return {handle:o.handle,emails:o.emails,authMethods:Object.keys(o.authMethods||{})}}var T=new f("_modelenceRateLimits",{schema:{bucket:g.string(),type:g.enum(["ip","user"]),value:g.string(),windowMs:g.number(),windowStart:g.date(),windowCount:g.number(),prevWindowCount:g.number(),expiresAt:g.date()},indexes:[{key:{bucket:1,type:1,value:1,windowMs:1},unique:true},{key:{expiresAt:1},expireAfterSeconds:0}]});var q=[];function Te(e){if(q.length>0)throw new Error("Duplicate call to initRateLimits - already initialized");q=e;}async function M(e){let{bucket:t,type:o,value:r}=e,i=q.filter(n=>n.bucket===t&&n.type===o);for(let n of i)await wt(n,r);}async function wt(e,t,o){let r=()=>new d(`Rate limit exceeded for ${e.bucket}`),i=await T.findOne({bucket:e.bucket,type:e.type,value:t,windowMs:e.window}),n=Date.now(),s=Math.floor(n/e.window)*e.window,{count:a,modifier:c}=i?ht(i,s,n):{count:0,modifier:{$setOnInsert:{windowStart:new Date(s),windowCount:1,prevWindowCount:0,expiresAt:new Date(s+e.window+e.window)}}};if(a>=e.limit)throw r();await T.upsertOne({bucket:e.bucket,type:e.type,value:t,windowMs:e.window},c);}function ht(e,t,o){let r=t-e.windowMs;if(e.windowStart.getTime()===t){let i=e.windowCount,n=e.prevWindowCount,s=1-(o-t)/e.windowMs;return {count:Math.round(i+n*s),modifier:{$inc:{windowCount:1},$setOnInsert:{windowStart:new Date(t),prevWindowCount:0,expiresAt:new Date(t+e.windowMs+e.windowMs)}}}}if(e.windowStart.getTime()===r){let i=1-(o-t)/e.windowMs;return {count:Math.round(e.windowCount*i),modifier:{$set:{windowStart:new Date(t),windowCount:1,prevWindowCount:e.windowCount,expiresAt:new Date(t+e.windowMs+e.windowMs)}}}}return {count:0,modifier:{$set:{windowStart:new Date(t),windowCount:1,prevWindowCount:0,expiresAt:new Date(t+e.windowMs+e.windowMs)}}}}async function Ae(e,{user:t,connectionInfo:o}){let r=_(e.email),i=J(e.password),n=o?.ip;if(n&&await M({bucket:"signupAttempt",type:"ip",value:n}),await Ce(r))throw new Error("Please use a permanent email address");let s=await l.findOne({"emails.address":r},{collation:{locale:"en",strength:2}});if(s){let f=s.emails?.find(g=>g.address===r);throw new Error(`User with email already exists: ${f?.address}`)}n&&await M({bucket:"signup",type:"ip",value:n});let a=await ft.hash(i,10),c=await l.insertOne({handle:r,emails:[{address:r,verified:false}],createdAt:new Date,authMethods:{password:{hash:a}}});return await j({userId:c?.insertedId,email:r,baseUrl:o?.baseUrl}),c.insertedId}function vt(e,t){return t?t.startsWith("http://")||t.startsWith("https://")?t:`${e}${t.startsWith("/")?"":"/"}${t}`:e}function Mt({email:e,resetUrl:t}){return `
7
+ `}async function Je(t){let e=process.env.MODELENCE_SITE_URL,o=w().emailVerifiedRedirectUrl||e||"/";try{let n=z.string().parse(t.query.token),r=await k.findOne({token:n,expiresAt:{$gt:new Date}});if(!r)throw new Error("Invalid or expired verification token");if(!await d.findOne({_id:r.userId}))throw new Error("User not found");let s=r.email;if(!s)throw new Error("Email not found in token");if((await d.updateOne({_id:r.userId,"emails.address":s,"emails.verified":{$ne:!0}},{$set:{"emails.$.verified":!0}})).matchedCount===0)throw await d.findOne({_id:r.userId,"emails.address":s})?new Error("Email is already verified"):new Error("Email address not found for this user");await k.deleteOne({_id:r._id});}catch(n){if(n instanceof Error)return console.error("Error verifying email:",n),{status:301,redirect:`${o}?status=error&message=${encodeURIComponent(n.message)}`}}return {status:301,redirect:`${o}?status=verified`}}async function H({userId:t,email:e,baseUrl:o=process.env.MODELENCE_SITE_URL}){if(w().provider){let n=w().provider,r=randomBytes(32).toString("hex"),i=new Date(Date.now()+a.hours(24));await k.insertOne({userId:t,email:e,token:r,createdAt:new Date,expiresAt:i});let s=`${o}/api/_internal/auth/verify-email?token=${r}`,l=(w()?.verification?.template||We)({name:"",email:e,verificationUrl:s}),m=V(l);await n?.sendEmail({to:e,from:w()?.from||"noreply@modelence.com",subject:w()?.verification?.subject||"Verify your email address",text:m,html:l});}}function K(t){return z.string().min(8,{message:"Password must contain at least 8 characters"}).parse(t)}function A(t){return z.string().email({message:"Invalid email address"}).parse(t)}var se=Object.freeze({});function ze(t){se=Object.freeze(Object.assign({},se,t));}function b(){return se}async function Fe(t,{user:e,session:o,connectionInfo:n}){try{if(!o)throw new Error("Session is not initialized");let r=n?.ip;r&&await D({bucket:"signin",type:"ip",value:r});let i=A(t.email),s=z.string().parse(t.password),a=await d.findOne({"emails.address":i},{collation:{locale:"en",strength:2}}),l=a?.authMethods?.password?.hash;if(!l)throw Be();if(!a.emails?.find(g=>g.address===i)?.verified&&w()?.provider){if(r)try{await D({bucket:"verification",type:"user",value:a._id.toString()});}catch{throw new Error("Your email address hasn't been verified yet. Please use the verification email we've send earlier to your inbox.")}throw await H({userId:a?._id,email:i,baseUrl:n?.baseUrl}),new Error("Your email address hasn't been verified yet. We've sent a new verification email to your inbox.")}if(!await zt.compare(s,l))throw Be();return await Pe(o.authToken,a._id),b().login?.onSuccess?.(a),{user:{id:a._id,handle:a.handle}}}catch(r){throw r instanceof Error&&b().login?.onError?.(r),r}}async function Ve(t,{user:e,session:o}){if(!o)throw new Error("Session is not initialized");await Le(o.authToken);}function Be(){return new Error("Incorrect email/password combination")}async function He(t,{user:e}){if(!e)throw new Error("Not authenticated");let o=await d.requireById(e.id);return {handle:o.handle,emails:o.emails,authMethods:Object.keys(o.authMethods||{})}}var j=new h("_modelenceRateLimits",{schema:{bucket:c.string(),type:c.enum(["ip","user"]),value:c.string(),windowMs:c.number(),windowStart:c.date(),windowCount:c.number(),prevWindowCount:c.number(),expiresAt:c.date()},indexes:[{key:{bucket:1,type:1,value:1,windowMs:1},unique:true},{key:{expiresAt:1},expireAfterSeconds:0}]});var ae=[];function Ke(t){if(ae.length>0)throw new Error("Duplicate call to initRateLimits - already initialized");ae=t;}async function D(t){let{bucket:e,type:o,value:n}=t,r=ae.filter(i=>i.bucket===e&&i.type===o);for(let i of r)await Ft(i,n);}async function Ft(t,e,o){let n=()=>new d$1(`Rate limit exceeded for ${t.bucket}`),r=await j.findOne({bucket:t.bucket,type:t.type,value:e,windowMs:t.window}),i=Date.now(),s=Math.floor(i/t.window)*t.window,{count:a,modifier:l}=r?Vt(r,s,i):{count:0,modifier:{$setOnInsert:{windowStart:new Date(s),windowCount:1,prevWindowCount:0,expiresAt:new Date(s+t.window+t.window)}}};if(a>=t.limit)throw n();await j.upsertOne({bucket:t.bucket,type:t.type,value:e,windowMs:t.window},l);}function Vt(t,e,o){let n=e-t.windowMs;if(t.windowStart.getTime()===e){let r=t.windowCount,i=t.prevWindowCount,s=1-(o-e)/t.windowMs;return {count:Math.round(r+i*s),modifier:{$inc:{windowCount:1},$setOnInsert:{windowStart:new Date(e),prevWindowCount:0,expiresAt:new Date(e+t.windowMs+t.windowMs)}}}}if(t.windowStart.getTime()===n){let r=1-(o-e)/t.windowMs;return {count:Math.round(t.windowCount*r),modifier:{$set:{windowStart:new Date(e),windowCount:1,prevWindowCount:t.windowCount,expiresAt:new Date(e+t.windowMs+t.windowMs)}}}}return {count:0,modifier:{$set:{windowStart:new Date(e),windowCount:1,prevWindowCount:0,expiresAt:new Date(e+t.windowMs+t.windowMs)}}}}async function Ge(t,{user:e,connectionInfo:o}){try{let n=A(t.email),r=K(t.password),i=o?.ip;if(i&&await D({bucket:"signupAttempt",type:"ip",value:i}),await $e(n))throw new Error("Please use a permanent email address");let s=await d.findOne({"emails.address":n},{collation:{locale:"en",strength:2}});if(s){let C=s.emails?.find(g=>g.address===n);throw new Error(`User with email already exists: ${C?.address}`)}i&&await D({bucket:"signup",type:"ip",value:i});let a=await zt.hash(r,10),l=await d.insertOne({handle:n,emails:[{address:n,verified:!1}],createdAt:new Date,authMethods:{password:{hash:a}}}),m=await d.findOne({_id:l.insertedId},{readPreference:"primary"});if(!m)throw new Error("User not found");return await H({userId:l?.insertedId,email:n,baseUrl:o?.baseUrl}),b().signup?.onSuccess?.(m),l.insertedId}catch(n){throw n instanceof Error&&b().signup?.onError?.(n),n}}function Qt(t,e){return e?e.startsWith("http://")||e.startsWith("https://")?e:`${t}${e.startsWith("/")?"":"/"}${e}`:t}function Yt({email:t,resetUrl:e}){return `
8
8
  <p>Hi,</p>
9
- <p>We received a request to reset your password for ${e}.</p>
9
+ <p>We received a request to reset your password for ${t}.</p>
10
10
  <p>Click the link below to reset your password:</p>
11
- <p><a href="${t}">${t}</a></p>
11
+ <p><a href="${e}">${e}</a></p>
12
12
  <p>This link will expire in 1 hour.</p>
13
13
  <p>If you did not request this password reset, please ignore this email.</p>
14
- `}var F={success:true,message:"If an account with that email exists, a password reset link has been sent"};async function Ie(e,{connectionInfo:t}){let o$1=_(e.email),r=await l.findOne({"emails.address":o$1},{collation:{locale:"en",strength:2}});if(!r||!r.authMethods?.password)return F;let i=p().provider;if(!i)throw new Error("Email provider is not configured");let n=randomBytes(32).toString("hex"),s=new Date(Date.now()+a.hours(1));await o.insertOne({userId:r._id,token:n,createdAt:new Date,expiresAt:s});let a$1=process.env.MODELENCE_SITE_URL||t?.baseUrl,f=`${vt(a$1,p().passwordReset?.redirectUrl)}?token=${n}`,l$1=(p()?.passwordReset?.template||Mt)({email:o$1,resetUrl:f,name:""}),x=U(l$1);return await i.sendEmail({to:o$1,from:p()?.from||"noreply@modelence.com",subject:p()?.passwordReset?.subject||"Reset your password",text:x,html:l$1}),F}async function Le(e,{}){let t=z$1.string().parse(e.token),o$1=J(e.password),r=await o.findOne({token:t});if(!r)throw new Error("Invalid or expired reset token");if(r.expiresAt<new Date)throw await o.deleteOne({token:t}),new Error("Reset token has expired");let i=await l.findOne({_id:r.userId});if(!i)throw new Error("User not found");let n=await ft.hash(o$1,10);return await l.updateOne({_id:i._id},{$set:{"authMethods.password.hash":n}}),await o.deleteOne({token:t}),{success:true,message:"Password has been reset successfully"}}var Ne=new e("_system.user",{stores:[l,m,n,o],queries:{getOwnProfile:ke},mutations:{signupWithPassword:Ae,loginWithPassword:Oe,logout:De,sendResetPasswordToken:Ie,resetPassword:Le},cronJobs:{updateDisposableEmailList:ve},rateLimits:[{bucket:"signup",type:"ip",window:a.minutes(15),limit:20},{bucket:"signup",type:"ip",window:a.days(1),limit:200},{bucket:"signupAttempt",type:"ip",window:a.minutes(15),limit:50},{bucket:"signupAttempt",type:"ip",window:a.days(1),limit:500},{bucket:"signin",type:"ip",window:a.minutes(15),limit:50},{bucket:"signin",type:"ip",window:a.days(1),limit:500},{bucket:"verification",type:"user",window:a.minutes(15),limit:3},{bucket:"verification",type:"user",window:a.days(1),limit:10}],configSchema:{"auth.email.enabled":{type:"boolean",isPublic:true,default:true},"auth.email.from":{type:"string",isPublic:false,default:""},"auth.email.verification":{type:"boolean",isPublic:true,default:false},"auth.google.enabled":{type:"boolean",isPublic:true,default:false},"auth.google.clientId":{type:"string",isPublic:false,default:""},"auth.google.clientSecret":{type:"secret",isPublic:false,default:""}},routes:[{path:"/api/_internal/auth/verify-email",handlers:{get:xe}}]});async function Pe({configSchema:e,cronJobsMetadata:t,stores:o}){let r=process.env.MODELENCE_CONTAINER_ID;if(!r)throw new Error("Unable to connect to Modelence Cloud: MODELENCE_CONTAINER_ID is not set");try{let i=Object.values(o).map(s=>({name:s.getName(),schema:s.getSchema(),collections:[s.getName()]})),n=await K("/api/connect","POST",{hostname:Rt.hostname(),containerId:r,dataModels:i,configSchema:e,cronJobsMetadata:t});if(n.status==="error")throw new Error(n.error);return console.log("Successfully connected to Modelence Cloud"),n}catch(i){throw console.error("Unable to connect to Modelence Cloud:",i),i}}async function $e(){return await K("/api/configs","GET")}async function Ue(){return await K("/api/sync","POST",{containerId:process.env.MODELENCE_CONTAINER_ID})}async function K(e,t,o){let{MODELENCE_SERVICE_ENDPOINT:r,MODELENCE_SERVICE_TOKEN:i}=process.env;if(!r)throw new Error("Unable to connect to Modelence Cloud: MODELENCE_SERVICE_ENDPOINT is not set");let n=await fetch(`${r}${e}`,{method:t,headers:{Authorization:`Bearer ${i}`,...o?{"Content-Type":"application/json"}:{}},body:o?JSON.stringify(o):void 0});if(!n.ok){let s=await n.text();try{let a=JSON.parse(s);throw new Error(`Unable to connect to Modelence Cloud: HTTP status: ${n.status}, ${a?.error}`)}catch{throw new Error(`Unable to connect to Modelence Cloud: HTTP status: ${n.status}, ${s}`)}}return await n.json()}var Y=false,xt=a.seconds(10);function je(){setInterval(async()=>{if(!Y){Y=true;try{await Ue();}catch(e){console.error("Error syncing status",e);}try{await St();}catch(e){console.error("Error syncing config",e);}Y=false;}},xt);}async function St(){let{configs:e}=await $e();c(e);}var _t=a.minutes(1),Ot=a.seconds(10),R={},Q,A=new f("_modelenceCronJobs",{schema:{alias:g.string(),lastStartDate:g.date().optional(),lock:g.object({containerId:g.string(),acquireDate:g.date()}).optional()},indexes:[{key:{alias:1},unique:true,background:true}]});function Ve(e,{description:t="",interval:o,timeout:r=_t,handler:i}){if(R[e])throw new Error(`Duplicate cron job declaration: '${e}' already exists`);if(Q)throw new Error(`Unable to add a cron job - cron jobs have already been initialized: [${e}]`);if(o<a.seconds(5))throw new Error(`Cron job interval should not be less than 5 second [${e}]`);if(r>a.days(1))throw new Error(`Cron job timeout should not be longer than 1 day [${e}]`);R[e]={alias:e,params:{description:t,interval:o,timeout:r},handler:i,state:{isRunning:false}};}async function Be(){if(Q)throw new Error("Cron jobs already started");let e=Object.keys(R);if(e.length>0){let t={alias:{$in:e}},o=await A.findOne({...t,"lock.containerId":{$exists:true}});await Promise.all(e.map(n=>A.upsertOne({alias:n},{$set:{lock:{containerId:process.env.MODELENCE_CONTAINER_ID||"unknown",acquireDate:new Date}}}))),o&&await Dt(Ot);let r=await A.fetch(t),i=Date.now();r.forEach(n=>{let s=R[n.alias];s&&(s.state.scheduledRunTs=n.lastStartDate?n.lastStartDate.getTime()+s.params.interval:i);}),Object.values(R).forEach(n=>{n.state.scheduledRunTs||(n.state.scheduledRunTs=i);}),Q=setInterval(kt,a.seconds(1));}}function Dt(e){return new Promise(t=>setTimeout(t,e))}async function kt(){let e=Date.now();Object.values(R).forEach(async t=>{let{params:o,state:r}=t;if(r.isRunning){r.startTs&&r.startTs+o.timeout<e&&(r.isRunning=false);return}r.scheduledRunTs&&r.scheduledRunTs<=e&&await Tt(t);});}async function Tt(e){let{alias:t,params:o,handler:r,state:i}=e;i.isRunning=true,i.startTs=Date.now();let n=j$1("cron",`cron:${t}`);r().then(()=>{Je(i,o),n.end("success");}).catch(s=>{Je(i,o),k$1(s),n.end("error"),console.error(`Error in cron job '${t}':`,s);}),await A.updateOne({alias:t},{$set:{lastStartDate:new Date(i.startTs)}});}function Je(e,t){e.scheduledRunTs=e.startTs?e.startTs+t.interval:Date.now(),e.startTs=void 0,e.isRunning=false;}function He(){return Object.values(R).map(({alias:e,params:t})=>({alias:e,description:t.description,interval:t.interval,timeout:t.timeout}))}var We=new e("_system.cron",{stores:[A]});var h=null;async function Ge(){if(h)return h;let e=I();if(!e)throw new Error("MongoDB URI is not set");h=new MongoClient(e,{maxPoolSize:20});try{return await h.connect(),await h.db("admin").command({ping:1}),console.log("Pinged your deployment. You successfully connected to MongoDB!"),h}catch(t){throw console.error(t),h=null,t}}function I(){let e=a$1("_system.mongodbUri");return e?String(e):void 0}function ze(){return h}var Z={};function X(e,t){return v(),Ye(e),V("query",e,t)}function qe(e,t){return v(),Ye(e),V("mutation",e,t)}function Fe(e,t){return v(),Qe(e),V("query",e,t)}function Ke(e,t){return v(),Qe(e),V("mutation",e,t)}function Ye(e){if(e.toLowerCase().startsWith("_system."))throw new Error(`Method name cannot start with a reserved prefix: '_system.' (${e})`)}function Qe(e){if(!e.toLowerCase().startsWith("_system."))throw new Error(`System method name must start with a prefix: '_system.' (${e})`)}function V(e,t,o){if(v(),Z[t])throw new Error(`Method with name '${t}' is already defined.`);let r=typeof o=="function"?o:o.handler,i=typeof o=="function"?[]:o.permissions??[];Z[t]={type:e,name:t,handler:r,permissions:i};}async function Ze(e,t,o){v();let r$1=Z[e];if(!r$1)throw new Error(`Method with name '${e}' is not defined.`);let{type:i,handler:n}=r$1,s=j$1("method",`method:${e}`,{type:i,args:t}),a;try{r(o.roles,r$1.permissions),a=await n(t,o);}catch(c){throw s.end("error"),c}return s.end(),a}var B=new f("_modelenceMigrations",{schema:{version:g.number(),appliedAt:g.date()},indexes:[{key:{version:1},unique:true}]});async function Xe(e){if(e.length===0)return;let t=e.map(({version:n})=>n),o=await B.fetch({version:{$in:t}}),r=new Set(o.map(({version:n})=>n)),i=e.filter(({version:n})=>!r.has(n));if(i.length!==0){console.log(`Running migrations (${i.length})...`);for(let{version:n,description:s,handler:a}of i)console.log(`Running migration v${n}: ${s}`),await B.insertOne({version:n,appliedAt:new Date}),await a(),console.log(`Migration v${n} complete`);}}var et=new e("_system.migration",{stores:[B]});var tt=new e("_system.rateLimit",{stores:[T]});var te=class{async init(){this.config=await Vt(),this.isDev()&&(console.log("Starting Vite dev server..."),this.viteServer=await createServer(this.config));}middlewares(){if(this.isDev())return this.viteServer?.middlewares??[];let t=[re.static("./.modelence/build/client".replace(/\\/g,"/"))];return this.config?.publicDir&&t.push(re.static(this.config.publicDir)),t}handler(t,o){if(this.isDev())try{o.sendFile("index.html",{root:"./src/client"});}catch(r){console.error("Error serving index.html:",r),o.status(500).send("Internal Server Error");}else o.sendFile("index.html",{root:"./.modelence/build/client".replace(/\\/g,"/")});}isDev(){return process.env.NODE_ENV!=="production"}};async function jt(){let e=process.cwd();try{return (await loadConfigFromFile({command:"serve",mode:"development"},void 0,e))?.config||{}}catch(t){return console.warn("Could not load vite config:",t),{}}}function Jt(e,t){let o=mergeConfig(e,t);if(o.plugins&&Array.isArray(o.plugins)){let r=new Set;o.plugins=o.plugins.filter(i=>{if(!i||typeof i!="object")return true;let n=i.name;return !n||r.has(n)?false:(r.add(n),true)}).reverse(),o.plugins.reverse();}return o}async function Vt(){let e=process.cwd(),t=await jt(),o=[".eslintrc.js",".eslintrc.json",".eslintrc","eslint.config.js",".eslintrc.yml",".eslintrc.yaml"].find(n=>Ut.existsSync(ee.join(e,n))),r=[$t(),Bt()];if(o){let n=(await import('vite-plugin-eslint')).default;r.push(n({failOnError:false,include:["src/**/*.js","src/**/*.jsx","src/**/*.ts","src/**/*.tsx"],cwd:e,overrideConfigFile:ee.resolve(e,o)}));}let i=defineConfig({plugins:r,build:{outDir:".modelence/build/client".replace(/\\/g,"/"),emptyOutDir:true},server:{middlewareMode:true},root:"./src/client",resolve:{alias:{"@":ee.resolve(e,"src").replace(/\\/g,"/")}}});return Jt(i,t)}function Bt(){return {name:"modelence-asset-handler",async transform(e,t){if(/\.(png|jpe?g|gif|svg|mpwebm|ogg|mp3|wav|flac|aac)$/.test(t))return process.env.NODE_ENV==="development",e},async generateBundle(e,t){}}}var rt=new te;async function nt(e,t){let{authToken:o}=await j$2(t);e.cookie("authToken",o,{httpOnly:true,secure:process.env.NODE_ENV==="production",sameSite:"strict"}),e.status(301),e.redirect("/");}async function Gt(e,t){let o=e.user,r=await l.findOne({"authMethods.google.id":o.id});if(r){await nt(t,r._id);return}let i=o.emails[0]&&o.emails[0]?.value;if(i||t.status(400).json({error:"Email address is required for Google authentication."}),await l.findOne({"emails.address":i},{collation:{locale:"en",strength:2}})){t.status(400).json({error:"User with this email already exists. Please log in instead."});return}let s=await l.insertOne({handle:i,emails:[{address:i,verified:true}],createdAt:new Date,authMethods:{google:{id:o.id}}});await nt(t,s.insertedId);}function zt(){let e=Router(),t=!!a$1("_system.user.auth.google.enabled"),o=String(a$1("_system.user.auth.google.clientId")),r=String(a$1("_system.user.auth.google.clientSecret"));return !t||!o||!r||(oe.use(new Strategy({clientID:o,clientSecret:r,callbackURL:"/api/_internal/auth/google/callback",proxy:true},(i,n,s,a)=>a(null,s))),e.get("/api/_internal/auth/google",oe.authenticate("google",{scope:["profile","email"],session:false})),e.get("/api/_internal/auth/google/callback",oe.authenticate("google",{session:false}),Gt)),e}var it=zt;function st(e){return async(t,o)=>{try{let r=await e({query:t.query,body:t.body,params:t.params,headers:t.headers,cookies:t.cookies,req:t});o.status(r.status||200),r.redirect&&o.redirect(r.redirect),r.headers&&Object.entries(r.headers).forEach(([i,n])=>{o.setHeader(i,n);}),o.send(r.data);}catch(r){r instanceof a$3?o.status(r.status).send(r.message):(console.error(`Error in route handler: ${t.path}`),console.error(r),o.status(500).send(String(r)));}}}function Yt(e,t){for(let o of t)for(let r of o.routes){let{path:i,handlers:n}=r;Object.entries(n).forEach(([s,a])=>{e[s](i,st(a));});}}async function at(e,{combinedModules:t$1,websockets:o,rooms:r}){let i=re();i.use(re.json()),i.use(re.urlencoded({extended:true})),i.use(qt()),i.use(oe.initialize()),i.use(it()),i.post("/api/_internal/method/:methodName(*)",async(a,c)=>{let{methodName:f}=a.params,g=await Qt(a);try{let l=await Ze(f,a.body.args,g);c.json({data:l,typeMap:a$2(l)});}catch(l){if(console.error(`Error in method ${f}:`,l),l instanceof a$3)c.status(l.status).send(l.message);else if(l instanceof Error&&l?.constructor?.name==="ZodError"&&"errors"in l){let L=l.flatten(),H=Object.entries(L.fieldErrors).map(([W,G])=>`${W}: ${(G??[]).join(", ")}`).join("; "),N=L.formErrors.join("; "),O=[H,N].filter(Boolean).join("; ");c.status(400).send(O);}else c.status(500).send(l instanceof Error?l.message:String(l));}}),Yt(i,t$1),await e.init(),e.middlewares&&i.use(e.middlewares()),i.all("*",(a,c)=>e.handler(a,c)),process.on("unhandledRejection",(a,c)=>{console.error("Unhandled Promise Rejection:"),console.error(a instanceof Error?a.stack:a),console.error("Promise:",c);}),process.on("uncaughtException",a=>{console.error("Uncaught Exception:"),console.error(a.stack),console.trace("Full application stack:");});let n=Ft.createServer(i);o?.enabled&&t(n,r);let s=process.env.MODELENCE_PORT||process.env.PORT||3e3;n.listen(s,()=>{h$2("Application started",{source:"app"}),console.log(`
15
- Application started on http://localhost:${s}
16
- `);});}async function Qt(e){let t=E.string().nullish().transform(n=>n??null).parse(e.cookies.authToken||e.body.authToken),o=E.object({screenWidth:E.number(),screenHeight:E.number(),windowWidth:E.number(),windowHeight:E.number(),pixelRatio:E.number(),orientation:E.string().nullable()}).parse(e.body.clientInfo),r={ip:Zt(e),userAgent:e.get("user-agent"),acceptLanguage:e.get("accept-language"),referrer:e.get("referrer"),baseUrl:e.protocol+"://"+e.get("host")};if(!!I()){let{session:n,user:s$1,roles:a}=await s(t);return {clientInfo:o,connectionInfo:r,session:n,user:s$1,roles:a}}return {clientInfo:o,connectionInfo:r,session:null,user:null,roles:q$1()}}function Zt(e){let t=e.headers["x-forwarded-for"];if(t)return (Array.isArray(t)?t[0]:t.split(",")[0]).trim();let o=e.ip||e.socket?.remoteAddress;if(o)return o.startsWith("::ffff:")?o.substring(7):o}async function oo({modules:e=[],roles:t={},defaultRoles:o={},server:r=rt,migrations:i=[],email:n={},websockets:s={}}){ct.config(),ct.config({path:".modelence.env"});let a=!!process.env.MODELENCE_SERVICE_ENDPOINT,c$1=process.env.MODELENCE_CRON_ENABLED==="true";go().then(()=>{}).catch(()=>{});let f=[Ne,k,We,et,tt],g=[...f,...e];e$1(),no(f),ro(e),p$1(t,o);let l=co(g);d$1(l);let x=io(g),L=so(g);c$1&&lo(g);let H=ao(g);if(Te(H),a){let{configs:O,environmentId:W,appAlias:G,environmentAlias:lt,telemetry:mt}=await Pe({configSchema:l,cronJobsMetadata:c$1?He():void 0,stores:x});c(O),f$1({environmentId:W,appAlias:G,environmentAlias:lt,telemetry:mt});}else c(fo(l));Me(n);let N=I();if(N&&(await Ge(),mo(x)),c$1&&await Xe(i),N)for(let O of x)O.createIndexes();a&&(await g$1(),je()),c$1&&Be().catch(console.error),await at(r,{combinedModules:g,websockets:s,rooms:L});}function ro(e){for(let t of e){for(let[o,r]of Object.entries(t.queries))X(`${t.name}.${o}`,r);for(let[o,r]of Object.entries(t.mutations))qe(`${t.name}.${o}`,r);}}function no(e){for(let t of e){for(let[o,r]of Object.entries(t.queries))Fe(`${t.name}.${o}`,r);for(let[o,r]of Object.entries(t.mutations))Ke(`${t.name}.${o}`,r);}}function io(e){return e.flatMap(t=>t.stores)}function so(e){return e.flatMap(t=>t.rooms)}function ao(e){return e.flatMap(t=>t.rateLimits)}function co(e){let t={};for(let o of e)for(let[r,i]of Object.entries(o.configSchema)){let n=`${o.name}.${r}`;if(n in t)throw new Error(`Duplicate config schema key: ${n} (${o.name})`);t[n]=i;}return t}function lo(e){for(let t of e)for(let[o,r]of Object.entries(t.cronJobs))Ve(`${t.name}.${o}`,r);}function mo(e){let t=ze();if(!t)throw new Error("Failed to initialize stores: MongoDB client not initialized");for(let o of e)o.init(t);}var uo={MONGODB_URI:"_system.mongodbUri",MODELENCE_AUTH_GOOGLE_ENABLED:"_system.user.auth.google.enabled",MODELENCE_AUTH_GOOGLE_CLIENT_ID:"_system.user.auth.google.clientId",MODELENCE_AUTH_GOOGLE_CLIENT_SECRET:"_system.user.auth.google.clientSecret",MODELENCE_EMAIL_RESEND_API_KEY:"_system.email.resend.apiKey",MODELENCE_EMAIL_AWS_SES_REGION:"_system.email.awsSes.region",MODELENCE_EMAIL_AWS_SES_ACCESS_KEY_ID:"_system.email.awsSes.accessKeyId",MODELENCE_EMAIL_AWS_SES_SECRET_ACCESS_KEY:"_system.email.awsSes.secretAccessKey",MODELENCE_EMAIL_SMTP_HOST:"_system.email.smtp.host",MODELENCE_EMAIL_SMTP_PORT:"_system.email.smtp.port",MODELENCE_EMAIL_SMTP_USER:"_system.email.smtp.user",MODELENCE_EMAIL_SMTP_PASS:"_system.email.smtp.pass",GOOGLE_AUTH_ENABLED:"_system.user.auth.google.enabled",GOOGLE_AUTH_CLIENT_ID:"_system.user.auth.google.clientId",GOOGLE_AUTH_CLIENT_SECRET:"_system.user.auth.google.clientSecret"};function po(e,t){if(t==="number"){let o=Number(e);if(isNaN(o))throw new Error(`Invalid number value for config: ${e}`);return o}if(t==="boolean"){if(e.toLowerCase()==="true")return true;if(e.toLowerCase()==="false")return false;throw new Error(`Invalid boolean value for config: ${e}`)}return e}function fo(e){let t=[];for(let[o,r]of Object.entries(uo)){let i=process.env[o],n=e[r];if(i){let s=n?.type??"string";t.push({key:r,type:s,value:po(i,s)});}}return t}async function go(){if(process.env.MODELENCE_TRACKING_ENABLED!=="false"){let t=process.env.MODELENCE_SERVICE_ENDPOINT??"https://cloud.modelence.com",o=process.env.MODELENCE_ENVIRONMENT_ID,r=await wo(),i=await import('./package-XIRYRLMA.js');await fetch(`${t}/api/track/app-start`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({projectName:r.name,version:i.default.version,localHostname:Rt.hostname(),environmentId:o})});}}async function wo(){try{let e=ee.join(process.cwd(),"package.json"),t=await Xt.readFile(e,"utf-8");return {name:JSON.parse(t).name||"unknown"}}catch{return {name:"unknown"}}}
17
- export{M as consumeRateLimit,X as createQuery,oo as startApp};//# sourceMappingURL=server.js.map
14
+ `}var ce={success:true,message:"If an account with that email exists, a password reset link has been sent"};async function Ze(t,{connectionInfo:e}){let o=A(t.email),n=await d.findOne({"emails.address":o},{collation:{locale:"en",strength:2}});if(!n||!n.authMethods?.password)return ce;let r=w().provider;if(!r)throw new Error("Email provider is not configured");let i=randomBytes(32).toString("hex"),s=new Date(Date.now()+a.hours(1));await v.insertOne({userId:n._id,token:i,createdAt:new Date,expiresAt:s});let a$1=process.env.MODELENCE_SITE_URL||e?.baseUrl,m=`${Qt(a$1,w().passwordReset?.redirectUrl)}?token=${i}`,g=(w()?.passwordReset?.template||Yt)({email:o,resetUrl:m,name:""}),p=V(g);return await r.sendEmail({to:o,from:w()?.from||"noreply@modelence.com",subject:w()?.passwordReset?.subject||"Reset your password",text:p,html:g}),ce}async function Qe(t,{}){let e=z.string().parse(t.token),o=K(t.password),n=await v.findOne({token:e});if(!n)throw new Error("Invalid or expired reset token");if(n.expiresAt<new Date)throw await v.deleteOne({token:e}),new Error("Reset token has expired");let r=await d.findOne({_id:n.userId});if(!r)throw new Error("User not found");let i=await zt.hash(o,10);return await d.updateOne({_id:r._id},{$set:{"authMethods.password.hash":i}}),await v.deleteOne({token:e}),{success:true,message:"Password has been reset successfully"}}var Ye=new y("_system.user",{stores:[d,L,k,v],queries:{getOwnProfile:He},mutations:{signupWithPassword:Ge,loginWithPassword:Fe,logout:Ve,sendResetPasswordToken:Ze,resetPassword:Qe},cronJobs:{updateDisposableEmailList:Ue},rateLimits:[{bucket:"signup",type:"ip",window:a.minutes(15),limit:20},{bucket:"signup",type:"ip",window:a.days(1),limit:200},{bucket:"signupAttempt",type:"ip",window:a.minutes(15),limit:50},{bucket:"signupAttempt",type:"ip",window:a.days(1),limit:500},{bucket:"signin",type:"ip",window:a.minutes(15),limit:50},{bucket:"signin",type:"ip",window:a.days(1),limit:500},{bucket:"verification",type:"user",window:a.minutes(15),limit:3},{bucket:"verification",type:"user",window:a.days(1),limit:10}],configSchema:{"auth.email.enabled":{type:"boolean",isPublic:true,default:true},"auth.email.from":{type:"string",isPublic:false,default:""},"auth.email.verification":{type:"boolean",isPublic:true,default:false},"auth.google.enabled":{type:"boolean",isPublic:true,default:false},"auth.google.clientId":{type:"string",isPublic:false,default:""},"auth.google.clientSecret":{type:"secret",isPublic:false,default:""}},routes:[{path:"/api/_internal/auth/verify-email",handlers:{get:Je}}]});async function Xe({configSchema:t,cronJobsMetadata:e,stores:o}){let n=process.env.MODELENCE_CONTAINER_ID;if(!n)throw new Error("Unable to connect to Modelence Cloud: MODELENCE_CONTAINER_ID is not set");try{let r=Object.values(o).map(s=>({name:s.getName(),schema:s.getSchema(),collections:[s.getName()]})),i=await le("/api/connect","POST",{hostname:Xt.hostname(),containerId:n,dataModels:r,configSchema:t,cronJobsMetadata:e});if(i.status==="error")throw new Error(i.error);return console.log("Successfully connected to Modelence Cloud"),i}catch(r){throw console.error("Unable to connect to Modelence Cloud:",r),r}}async function et(){return await le("/api/configs","GET")}async function tt(){return await le("/api/sync","POST",{containerId:process.env.MODELENCE_CONTAINER_ID})}async function le(t,e,o){let{MODELENCE_SERVICE_ENDPOINT:n,MODELENCE_SERVICE_TOKEN:r}=process.env;if(!n)throw new Error("Unable to connect to Modelence Cloud: MODELENCE_SERVICE_ENDPOINT is not set");let i=await fetch(`${n}${t}`,{method:e,headers:{Authorization:`Bearer ${r}`,...o?{"Content-Type":"application/json"}:{}},body:o?JSON.stringify(o):void 0});if(!i.ok){let s=await i.text();try{let a=JSON.parse(s);throw new Error(`Unable to connect to Modelence Cloud: HTTP status: ${i.status}, ${a?.error}`)}catch{throw new Error(`Unable to connect to Modelence Cloud: HTTP status: ${i.status}, ${s}`)}}return await i.json()}var ue=false,eo=a.seconds(10);function ot(){setInterval(async()=>{if(!ue){ue=true;try{await tt();}catch(t){console.error("Error syncing status",t);}try{await to();}catch(t){console.error("Error syncing config",t);}ue=false;}},eo);}async function to(){let{configs:t}=await et();c$1(t);}var oo=a.minutes(1),no=a.seconds(10),O={},de,$=new h("_modelenceCronJobs",{schema:{alias:c.string(),lastStartDate:c.date().optional(),lock:c.object({containerId:c.string(),acquireDate:c.date()}).optional()},indexes:[{key:{alias:1},unique:true,background:true}]});function rt(t,{description:e="",interval:o,timeout:n=oo,handler:r}){if(O[t])throw new Error(`Duplicate cron job declaration: '${t}' already exists`);if(de)throw new Error(`Unable to add a cron job - cron jobs have already been initialized: [${t}]`);if(o<a.seconds(5))throw new Error(`Cron job interval should not be less than 5 second [${t}]`);if(n>a.days(1))throw new Error(`Cron job timeout should not be longer than 1 day [${t}]`);O[t]={alias:t,params:{description:e,interval:o,timeout:n},handler:r,state:{isRunning:false}};}async function it(){if(de)throw new Error("Cron jobs already started");let t=Object.keys(O);if(t.length>0){let e={alias:{$in:t}},o=await $.findOne({...e,"lock.containerId":{$exists:true}});await Promise.all(t.map(i=>$.upsertOne({alias:i},{$set:{lock:{containerId:process.env.MODELENCE_CONTAINER_ID||"unknown",acquireDate:new Date}}}))),o&&await ro(no);let n=await $.fetch(e),r=Date.now();n.forEach(i=>{let s=O[i.alias];s&&(s.state.scheduledRunTs=i.lastStartDate?i.lastStartDate.getTime()+s.params.interval:r);}),Object.values(O).forEach(i=>{i.state.scheduledRunTs||(i.state.scheduledRunTs=r);}),de=setInterval(io,a.seconds(1));}}function ro(t){return new Promise(e=>setTimeout(e,t))}async function io(){let t=Date.now();Object.values(O).forEach(async e=>{let{params:o,state:n}=e;if(n.isRunning){n.startTs&&n.startTs+o.timeout<t&&(n.isRunning=false);return}n.scheduledRunTs&&n.scheduledRunTs<=t&&await so(e);});}async function so(t){let{alias:e,params:o,handler:n,state:r}=t;r.isRunning=true,r.startTs=Date.now();let i=j$1("cron",`cron:${e}`);n().then(()=>{nt(r,o),i.end("success");}).catch(s=>{nt(r,o),k$1(s),i.end("error"),console.error(`Error in cron job '${e}':`,s);}),await $.updateOne({alias:e},{$set:{lastStartDate:new Date(r.startTs)}});}function nt(t,e){t.scheduledRunTs=t.startTs?t.startTs+e.interval:Date.now(),t.startTs=void 0,t.isRunning=false;}function st(){return Object.values(O).map(({alias:t,params:e})=>({alias:t,description:e.description,interval:e.interval,timeout:e.timeout}))}var at=new y("_system.cron",{stores:[$]});var E=null;async function ct(){if(E)return E;let t=U();if(!t)throw new Error("MongoDB URI is not set");E=new MongoClient(t,{maxPoolSize:20});try{return await E.connect(),await E.db("admin").command({ping:1}),console.log("Pinged your deployment. You successfully connected to MongoDB!"),E}catch(e){throw console.error(e),E=null,e}}function U(){let t=a$1("_system.mongodbUri");return t?String(t):void 0}function G(){return E}var me={};function pe(t,e){return R(),mt(t),Z("query",t,e)}function lt(t,e){return R(),mt(t),Z("mutation",t,e)}function ut(t,e){return R(),pt(t),Z("query",t,e)}function dt(t,e){return R(),pt(t),Z("mutation",t,e)}function mt(t){if(t.toLowerCase().startsWith("_system."))throw new Error(`Method name cannot start with a reserved prefix: '_system.' (${t})`)}function pt(t){if(!t.toLowerCase().startsWith("_system."))throw new Error(`System method name must start with a prefix: '_system.' (${t})`)}function Z(t,e,o){if(R(),me[e])throw new Error(`Method with name '${e}' is already defined.`);let n=typeof o=="function"?o:o.handler,r=typeof o=="function"?[]:o.permissions??[];me[e]={type:t,name:e,handler:n,permissions:r};}async function ft(t,e,o){R();let n=me[t];if(!n)throw new Error(`Method with name '${t}' is not defined.`);let{type:r,handler:i}=n,s=j$1("method",`method:${t}`,{type:r,args:e}),a;try{Ae(o.roles,n.permissions),a=await i(e,o);}catch(l){throw s.end("error"),l}return s.end(),a}var Q=new h("_modelenceMigrations",{schema:{version:c.number(),appliedAt:c.date()},indexes:[{key:{version:1},unique:true}]});async function ht(t){if(t.length===0)return;let e=t.map(({version:i})=>i),o=await Q.fetch({version:{$in:e}}),n=new Set(o.map(({version:i})=>i)),r=t.filter(({version:i})=>!n.has(i));if(r.length!==0){console.log(`Running migrations (${r.length})...`);for(let{version:i,description:s,handler:a}of r)console.log(`Running migration v${i}: ${s}`),await Q.insertOne({version:i,appliedAt:new Date}),await a(),console.log(`Migration v${i} complete`);}}var gt=new y("_system.migration",{stores:[Q]});var wt=new y("_system.rateLimit",{stores:[j]});var he=class{async init(){this.config=await wo(),this.isDev()&&(console.log("Starting Vite dev server..."),this.viteServer=await createServer(this.config));}middlewares(){if(this.isDev())return this.viteServer?.middlewares??[];let e=[we.static("./.modelence/build/client".replace(/\\/g,"/"))];return this.config?.publicDir&&e.push(we.static(this.config.publicDir)),e}handler(e,o){if(this.isDev())try{o.sendFile("index.html",{root:"./src/client"});}catch(n){console.error("Error serving index.html:",n),o.status(500).send("Internal Server Error");}else o.sendFile("index.html",{root:"./.modelence/build/client".replace(/\\/g,"/")});}isDev(){return process.env.NODE_ENV!=="production"}};async function ho(){let t=process.cwd();try{return (await loadConfigFromFile({command:"serve",mode:"development"},void 0,t))?.config||{}}catch(e){return console.warn("Could not load vite config:",e),{}}}function go(t,e){let o=mergeConfig(t,e);if(o.plugins&&Array.isArray(o.plugins)){let n=new Set;o.plugins=o.plugins.filter(r=>{if(!r||typeof r!="object")return true;let i=r.name;return !i||n.has(i)?false:(n.add(i),true)}).reverse(),o.plugins.reverse();}return o}async function wo(){let t=process.cwd(),e=await ho(),o=[".eslintrc.js",".eslintrc.json",".eslintrc","eslint.config.js",".eslintrc.yml",".eslintrc.yaml"].find(i=>fo.existsSync(fe.join(t,i))),n=[po(),yo()];if(o){let i=(await import('vite-plugin-eslint')).default;n.push(i({failOnError:false,include:["src/**/*.js","src/**/*.jsx","src/**/*.ts","src/**/*.tsx"],cwd:t,overrideConfigFile:fe.resolve(t,o)}));}let r=defineConfig({plugins:n,build:{outDir:".modelence/build/client".replace(/\\/g,"/"),emptyOutDir:true},server:{middlewareMode:true},root:"./src/client",resolve:{alias:{"@":fe.resolve(t,"src").replace(/\\/g,"/")}}});return go(r,e)}function yo(){return {name:"modelence-asset-handler",async transform(t,e){if(/\.(png|jpe?g|gif|svg|mpwebm|ogg|mp3|wav|flac|aac)$/.test(e))return process.env.NODE_ENV==="development",t},async generateBundle(t,e){}}}var bt=new he;async function Ct(t,e){let{authToken:o}=await re(e);t.cookie("authToken",o,{httpOnly:true,secure:process.env.NODE_ENV==="production",sameSite:"strict"}),t.status(301),t.redirect("/");}async function Eo(t,e){let o=t.user,n=await d.findOne({"authMethods.google.id":o.id});try{if(n){await Ct(e,n._id),b().login?.onSuccess?.(n);return}}catch(r){throw r instanceof Error&&b().login?.onError?.(r),r}try{let r=o.emails[0]&&o.emails[0]?.value;if(r||e.status(400).json({error:"Email address is required for Google authentication."}),await d.findOne({"emails.address":r},{collation:{locale:"en",strength:2}})){e.status(400).json({error:"User with this email already exists. Please log in instead."});return}let s=await d.insertOne({handle:r,emails:[{address:r,verified:!0}],createdAt:new Date,authMethods:{google:{id:o.id}}});await Ct(e,s.insertedId);let a=await d.findOne({_id:s.insertedId},{readPreference:"primary"});a&&b().signup?.onSuccess?.(a);}catch(r){throw r instanceof Error&&b().signup?.onError?.(r),r}}function So(){let t=Router(),e=!!a$1("_system.user.auth.google.enabled"),o=String(a$1("_system.user.auth.google.clientId")),n=String(a$1("_system.user.auth.google.clientSecret"));return !e||!o||!n||(ge.use(new Strategy({clientID:o,clientSecret:n,callbackURL:"/api/_internal/auth/google/callback",proxy:true},(r,i,s,a)=>a(null,s))),t.get("/api/_internal/auth/google",ge.authenticate("google",{scope:["profile","email"],session:false})),t.get("/api/_internal/auth/google/callback",ge.authenticate("google",{session:false}),Eo)),t}var Et=So;function St(t){return async(e,o)=>{try{let n=await t({query:e.query,body:e.body,params:e.params,headers:e.headers,cookies:e.cookies,req:e});o.status(n.status||200),n.redirect&&o.redirect(n.redirect),n.headers&&Object.entries(n.headers).forEach(([r,i])=>{o.setHeader(r,i);}),o.send(n.data);}catch(n){n instanceof a$3?o.status(n.status).send(n.message):(console.error(`Error in route handler: ${e.path}`),console.error(n),o.status(500).send(String(n)));}}}async function N(t){let e=await Ie(t),o=e.userId?await d.findOne({_id:new ObjectId(e.userId)}):null,n=o?{id:o._id.toString(),handle:o.handle}:null,r=n?ke():F();return {user:n,session:e,roles:r}}var Y=null,Do="_system.socketio";async function Oo({httpServer:t,channels:e}){let o=G();if(!o)throw new Error("");let n=o.db().collection(Do);await n.createIndex({createdAt:1},{expireAfterSeconds:3600,background:true}),Y=new Server(t,{cors:{origin:"*",methods:["GET","POST"]},adapter:createAdapter(n)}),Y.use(async(r,i)=>{let s=r.handshake.auth.token;try{r.data=await N(s);}finally{i();}}),Y.on("connection",r=>{h$1("Socket.IO client connected",{source:"websocket",socketId:r.id}),r.on("disconnect",()=>{h$1("Socket.IO client disconnected",{source:"websocket",socketId:r.id});}),r.on("joinChannel",async i=>{let[s]=i.split(":");for(let a of e)a.category===s&&(!a.canAccessChannel||await a.canAccessChannel(r.data))&&r.join(i);r.join(i),console.log(`User ${r.id} joined channel ${i}`),r.emit("joinedChannel",i);}),r.on("leaveChannel",i=>{r.leave(i),console.log(`User ${r.id} left channel ${i}`),r.emit("leftChannel",i);});}),h$1("Socket.IO server initialized",{source:"websocket"});}function Mo({category:t,id:e,data:o}){Y?.to(`${t}:${e}`).emit(t,o);}var xt={init:Oo,broadcast:Mo};function Ao(t,e){for(let o of e)for(let n of o.routes){let{path:r,handlers:i}=n;Object.entries(i).forEach(([s,a])=>{t[s](r,St(a));});}}async function vt(t,{combinedModules:e,websocket:o,channels:n}){let r=we();r.use(we.json()),r.use(we.urlencoded({extended:true})),r.use(To()),r.use(ge.initialize()),r.use(Et()),r.post("/api/_internal/method/:methodName(*)",async(l,m)=>{let{methodName:C}=l.params,g=await Io(l);try{let p=await ft(C,l.body.args,g);m.json({data:p,typeMap:a$2(p)});}catch(p){if(console.error(`Error in method ${C}:`,p),p instanceof a$3)m.status(p.status).send(p.message);else if(p instanceof Error&&p?.constructor?.name==="ZodError"&&"errors"in p){let J=p.flatten(),X=Object.entries(J.fieldErrors).map(([ee,te])=>`${ee}: ${(te??[]).join(", ")}`).join("; "),q=J.formErrors.join("; "),I=[X,q].filter(Boolean).join("; ");m.status(400).send(I);}else m.status(500).send(p instanceof Error?p.message:String(p));}}),Ao(r,e),await t.init(),t.middlewares&&r.use(t.middlewares()),r.all("*",(l,m)=>t.handler(l,m)),process.on("unhandledRejection",(l,m)=>{console.error("Unhandled Promise Rejection:"),console.error(l instanceof Error?l.stack:l),console.error("Promise:",m);}),process.on("uncaughtException",l=>{console.error("Uncaught Exception:"),console.error(l.stack),console.trace("Full application stack:");});let i=_o.createServer(r);(o?.provider||xt).init({httpServer:i,channels:n});let a=process.env.MODELENCE_PORT||process.env.PORT||3e3;i.listen(a,()=>{h$1("Application started",{source:"app"}),console.log(`
15
+ Application started on http://localhost:${a}
16
+ `);});}async function Io(t){let e=S.string().nullish().transform(i=>i??null).parse(t.cookies.authToken||t.body.authToken),o=S.object({screenWidth:S.number(),screenHeight:S.number(),windowWidth:S.number(),windowHeight:S.number(),pixelRatio:S.number(),orientation:S.string().nullable()}).parse(t.body.clientInfo),n={ip:Po(t),userAgent:t.get("user-agent"),acceptLanguage:t.get("accept-language"),referrer:t.get("referrer"),baseUrl:t.protocol+"://"+t.get("host")};if(!!U()){let{session:i,user:s,roles:a}=await N(e);return {clientInfo:o,connectionInfo:n,session:i,user:s,roles:a}}return {clientInfo:o,connectionInfo:n,session:null,user:null,roles:F()}}function Po(t){let e=t.headers["x-forwarded-for"];if(e)return (Array.isArray(e)?e[0]:e.split(",")[0]).trim();let o=t.ip||t.socket?.remoteAddress;if(o)return o.startsWith("::ffff:")?o.substring(7):o}var ye=Object.freeze({});function Rt(t){ye=Object.freeze(Object.assign({},ye,t));}function Dt(){return ye}async function Uo({modules:t=[],roles:e$1={},defaultRoles:o={},server:n=bt,migrations:r=[],email:i={},auth:s={},websocket:a={}}){Ot.config(),Ot.config({path:".modelence.env"});let l=!!process.env.MODELENCE_SERVICE_ENDPOINT,m=process.env.MODELENCE_CRON_ENABLED==="true";Zo().then(()=>{}).catch(()=>{});let C=[Ye,je,at,gt,wt],g$1=[...C,...t];e(),Wo(C),No(t),_e(e$1,o);let p=Bo(g$1);d$2(p);let W=Jo(g$1),J=qo(g$1);m&&Fo(g$1);let X=zo(g$1);if(Ke(X),l){let{configs:I,environmentId:ee,appAlias:te,environmentAlias:Mt,telemetry:Tt}=await Xe({configSchema:p,cronJobsMetadata:m?st():void 0,stores:W});c$1(I),f({environmentId:ee,appAlias:te,environmentAlias:Mt,telemetry:Tt});}else c$1(Go(p));Ne(i),ze(s),Rt(a);let q=U();if(q&&(await ct(),Vo(W)),m&&await ht(r),q)for(let I of W)I.createIndexes();l&&(await g(),ot()),m&&it().catch(console.error),await vt(n,{combinedModules:g$1,websocket:a,channels:J});}function No(t){for(let e of t){for(let[o,n]of Object.entries(e.queries))pe(`${e.name}.${o}`,n);for(let[o,n]of Object.entries(e.mutations))lt(`${e.name}.${o}`,n);}}function Wo(t){for(let e of t){for(let[o,n]of Object.entries(e.queries))ut(`${e.name}.${o}`,n);for(let[o,n]of Object.entries(e.mutations))dt(`${e.name}.${o}`,n);}}function Jo(t){return t.flatMap(e=>e.stores)}function qo(t){return t.flatMap(e=>e.channels)}function zo(t){return t.flatMap(e=>e.rateLimits)}function Bo(t){let e={};for(let o of t)for(let[n,r]of Object.entries(o.configSchema)){let i=`${o.name}.${n}`;if(i in e)throw new Error(`Duplicate config schema key: ${i} (${o.name})`);e[i]=r;}return e}function Fo(t){for(let e of t)for(let[o,n]of Object.entries(e.cronJobs))rt(`${e.name}.${o}`,n);}function Vo(t){let e=G();if(!e)throw new Error("Failed to initialize stores: MongoDB client not initialized");for(let o of t)o.init(e);}var Ho={MONGODB_URI:"_system.mongodbUri",MODELENCE_AUTH_GOOGLE_ENABLED:"_system.user.auth.google.enabled",MODELENCE_AUTH_GOOGLE_CLIENT_ID:"_system.user.auth.google.clientId",MODELENCE_AUTH_GOOGLE_CLIENT_SECRET:"_system.user.auth.google.clientSecret",MODELENCE_EMAIL_RESEND_API_KEY:"_system.email.resend.apiKey",MODELENCE_EMAIL_AWS_SES_REGION:"_system.email.awsSes.region",MODELENCE_EMAIL_AWS_SES_ACCESS_KEY_ID:"_system.email.awsSes.accessKeyId",MODELENCE_EMAIL_AWS_SES_SECRET_ACCESS_KEY:"_system.email.awsSes.secretAccessKey",MODELENCE_EMAIL_SMTP_HOST:"_system.email.smtp.host",MODELENCE_EMAIL_SMTP_PORT:"_system.email.smtp.port",MODELENCE_EMAIL_SMTP_USER:"_system.email.smtp.user",MODELENCE_EMAIL_SMTP_PASS:"_system.email.smtp.pass",GOOGLE_AUTH_ENABLED:"_system.user.auth.google.enabled",GOOGLE_AUTH_CLIENT_ID:"_system.user.auth.google.clientId",GOOGLE_AUTH_CLIENT_SECRET:"_system.user.auth.google.clientSecret"};function Ko(t,e){if(e==="number"){let o=Number(t);if(isNaN(o))throw new Error(`Invalid number value for config: ${t}`);return o}if(e==="boolean"){if(t.toLowerCase()==="true")return true;if(t.toLowerCase()==="false")return false;throw new Error(`Invalid boolean value for config: ${t}`)}return t}function Go(t){let e=[];for(let[o,n]of Object.entries(Ho)){let r=process.env[o],i=t[n];if(r){let s=i?.type??"string";e.push({key:n,type:s,value:Ko(r,s)});}}return e}async function Zo(){if(process.env.MODELENCE_TRACKING_ENABLED!=="false"){let e=process.env.MODELENCE_SERVICE_ENDPOINT??"https://cloud.modelence.com",o=process.env.MODELENCE_ENVIRONMENT_ID,n=await Qo(),r=await import('./package-ACIQW6FM.js');await fetch(`${e}/api/track/app-start`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({projectName:n.name,version:r.default.version,localHostname:Xt.hostname(),environmentId:o})});}}async function Qo(){try{let t=fe.join(process.cwd(),"package.json"),e=await Lo.readFile(t,"utf-8");return {name:JSON.parse(e).name||"unknown"}}catch{return {name:"unknown"}}}var be=class{constructor(e,o){this.category=e,this.canAccessChannel=o||null;}broadcast(e,o){let n=Dt().provider;if(!n){i("Websockets provider should be added to startApp",{});return}n.broadcast({category:this.category,id:e,data:o});}};
17
+ export{y as Module,be as ServerChannel,h as Store,N as authenticate,D as consumeRateLimit,pe as createQuery,d as dbUsers,c as schema,Uo as startApp};//# sourceMappingURL=server.js.map
18
18
  //# sourceMappingURL=server.js.map