@kyro-cms/core 0.12.4 → 0.12.6

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.
Files changed (97) hide show
  1. package/dist/{WebhookService-DJ75IwdZ.d.ts → WebhookService-Bpi6w1-6.d.ts} +1 -1
  2. package/dist/{WebhookService-B15DnDeH.d.cts → WebhookService-D_a3FAU4.d.cts} +1 -1
  3. package/dist/api-handler-graphql.cjs +1 -1
  4. package/dist/api-handler-graphql.js +1 -1
  5. package/dist/api-handler-trpc.cjs +1 -1
  6. package/dist/api-handler-trpc.js +1 -1
  7. package/dist/api-handler.cjs +1 -1
  8. package/dist/api-handler.js +1 -1
  9. package/dist/{base-CXZxchcr.d.cts → base-Cpu841KI.d.cts} +1 -1
  10. package/dist/{base-CjuIfzH2.d.ts → base-PZTb6vi6.d.ts} +1 -1
  11. package/dist/bootstrap-4W4342G2.js +1 -0
  12. package/dist/bootstrap-ZGTRVWYE.cjs +1 -0
  13. package/dist/chunk-5YW2WHXR.cjs +133 -0
  14. package/dist/chunk-6SPPR5JZ.js +3 -0
  15. package/dist/{chunk-UJNSOOYZ.cjs → chunk-AMOXD7EJ.cjs} +1 -1
  16. package/dist/chunk-AZNJI6TP.cjs +86 -0
  17. package/dist/chunk-D5P2IPGX.cjs +3 -0
  18. package/dist/chunk-GDOPX6VS.cjs +21 -0
  19. package/dist/chunk-HHH4XNNS.cjs +1 -0
  20. package/dist/{chunk-ET6NN2V2.cjs → chunk-HOP4D5XZ.cjs} +6 -6
  21. package/dist/{chunk-2W4FK6CJ.js → chunk-IKOXCJYO.js} +6 -6
  22. package/dist/chunk-IZCTG4RG.js +1 -0
  23. package/dist/chunk-J5SP3Y2H.js +133 -0
  24. package/dist/chunk-K7HTTXT2.js +3 -0
  25. package/dist/chunk-KSWT2Q5T.js +1 -0
  26. package/dist/chunk-MRBBP5MU.cjs +2 -0
  27. package/dist/{chunk-FO3HLBC7.js → chunk-MSTTFMCM.js} +1 -1
  28. package/dist/chunk-MXTO6XGD.js +21 -0
  29. package/dist/chunk-O7LK4FCW.js +2 -0
  30. package/dist/chunk-RYIEE2TH.cjs +2 -0
  31. package/dist/chunk-U3N4X3K3.js +86 -0
  32. package/dist/chunk-W6P4N3Z7.js +2 -0
  33. package/dist/chunk-YQLXDL4H.cjs +3 -0
  34. package/dist/chunk-Z7HKM3HT.cjs +1 -0
  35. package/dist/cli/index.cjs +1 -1
  36. package/dist/cli/index.js +1 -1
  37. package/dist/client.d.cts +1 -1
  38. package/dist/client.d.ts +1 -1
  39. package/dist/drizzle/index.cjs +1 -1
  40. package/dist/drizzle/index.d.cts +2 -2
  41. package/dist/drizzle/index.d.ts +2 -2
  42. package/dist/drizzle/index.js +1 -1
  43. package/dist/graphql/index.d.cts +2 -2
  44. package/dist/graphql/index.d.ts +2 -2
  45. package/dist/{index-C7FPi-Fj.d.ts → index-B7FXGWrZ.d.ts} +1 -1
  46. package/dist/{index-BCUSHYBf.d.cts → index-DfF-ofSa.d.cts} +1 -1
  47. package/dist/index.cjs +12 -12
  48. package/dist/index.d.cts +12 -11
  49. package/dist/index.d.ts +12 -11
  50. package/dist/index.js +12 -12
  51. package/dist/{mongo-auth-adapter-YPONSOCY.cjs → mongo-auth-adapter-6726C5KF.cjs} +1 -1
  52. package/dist/mongo-auth-adapter-U6SH4OWA.js +1 -0
  53. package/dist/mongodb/index.cjs +1 -1
  54. package/dist/mongodb/index.d.cts +5 -3
  55. package/dist/mongodb/index.d.ts +5 -3
  56. package/dist/mongodb/index.js +1 -1
  57. package/dist/redis-adapter-CQXIPG7W.cjs +1 -0
  58. package/dist/redis-adapter-L7BF3GQ5.js +1 -0
  59. package/dist/rest/index.cjs +1 -1
  60. package/dist/rest/index.d.cts +3 -3
  61. package/dist/rest/index.d.ts +3 -3
  62. package/dist/rest/index.js +1 -1
  63. package/dist/sqlite-adapter-EXYRYZEV.js +1 -0
  64. package/dist/{sqlite-adapter-Z3IBBI4X.cjs → sqlite-adapter-PLD57WOH.cjs} +1 -1
  65. package/dist/templates/index.cjs +1 -1
  66. package/dist/templates/index.d.cts +13 -4
  67. package/dist/templates/index.d.ts +13 -4
  68. package/dist/templates/index.js +1 -1
  69. package/dist/trpc/index.d.cts +2 -2
  70. package/dist/trpc/index.d.ts +2 -2
  71. package/dist/{types-L-qNugRL.d.ts → types-CbofW-fz.d.ts} +1 -0
  72. package/dist/{types-CqqoM3Dy.d.cts → types-DaWvY4Ho.d.cts} +1 -0
  73. package/package.json +12 -11
  74. package/dist/bootstrap-IVQWSJXZ.js +0 -1
  75. package/dist/bootstrap-OHGQGMRV.cjs +0 -1
  76. package/dist/chunk-3YGGZ2VN.js +0 -133
  77. package/dist/chunk-4RSGPSKQ.js +0 -3
  78. package/dist/chunk-ATLSIYRH.cjs +0 -1
  79. package/dist/chunk-AU6IWTBO.js +0 -2
  80. package/dist/chunk-EHLNY6BK.js +0 -21
  81. package/dist/chunk-EQUQJBPP.cjs +0 -2
  82. package/dist/chunk-GZGP4THY.cjs +0 -1
  83. package/dist/chunk-P7CESLDJ.js +0 -1
  84. package/dist/chunk-QRXDCV6K.js +0 -0
  85. package/dist/chunk-RCV2TLOG.cjs +0 -3
  86. package/dist/chunk-UBHFUFD4.cjs +0 -1
  87. package/dist/chunk-UCCFT5OO.cjs +0 -2
  88. package/dist/chunk-UTFLD5DC.cjs +0 -86
  89. package/dist/chunk-W7OSRADF.cjs +0 -21
  90. package/dist/chunk-XSGRGUHP.js +0 -86
  91. package/dist/chunk-YPDRUVWG.js +0 -2
  92. package/dist/chunk-Z7CNY2UV.cjs +0 -133
  93. package/dist/chunk-ZRSXM4BY.js +0 -1
  94. package/dist/mongo-auth-adapter-LG5O4LIH.js +0 -1
  95. package/dist/redis-adapter-KECGVSVX.cjs +0 -1
  96. package/dist/redis-adapter-VAXP43GR.js +0 -1
  97. package/dist/sqlite-adapter-FP45QCYK.js +0 -1
@@ -0,0 +1 @@
1
+ 'use strict';var h=require('bcryptjs'),crypto=require('crypto');function _interopDefault(e){return e&&e.__esModule?e:{default:e}}var h__default=/*#__PURE__*/_interopDefault(h);var w=class{db;prefix;sessionTTL;refreshTokenTTL;indexesEnsured=false;constructor(e){this.db=e.db,this.prefix=e.collectionPrefix||"",this.sessionTTL=e.sessionTTL||86400,this.refreshTokenTTL=e.refreshTokenTTL||604800;}getDatabase(){if(typeof this.db=="function"){let e=this.db();if(!e)throw new Error("MongoDB database not initialized");return e}if(!this.db)throw new Error("MongoDB database not initialized");return this.db}col(e){return this.getDatabase().collection(`${this.prefix}${e}`)}async connect(){this.indexesEnsured||await this.ensureIndexes();}async disconnect(){}async ensureIndexes(){await this.col("users").createIndex({email:1},{unique:true}),await this.col("users").createIndex({tenantId:1}),await this.col("users").createIndex({role:1}),await this.col("sessions").createIndex({token:1},{unique:true}),await this.col("sessions").createIndex({refreshToken:1}),await this.col("sessions").createIndex({userId:1}),await this.col("sessions").createIndex({expiresAt:1},{expireAfterSeconds:0}),await this.col("audit_logs").createIndex({timestamp:-1}),await this.col("audit_logs").createIndex({userId:1}),await this.col("audit_logs").createIndex({action:1}),await this.col("audit_logs").createIndex({resource:1}),await this.col("password_history").createIndex({userId:1,createdAt:-1}),await this.col("lockouts").createIndex({userId:1},{unique:true}),await this.col("lockouts").createIndex({lockedUntil:1}),this.indexesEnsured=true;}async createUser(e){let s=crypto.randomUUID(),t=new Date,i=await this.hashPassword(e.password),n={_id:s,name:e.name||null,email:e.email.toLowerCase(),passwordHash:i,role:e.role||"customer",avatar:e.avatar||null,tenantId:e.tenantId||null,emailVerified:false,locked:false,lastLogin:null,failedLoginAttempts:0,createdAt:t,updatedAt:t};return await this.col("users").insertOne(n),this.docToAuthUser(n)}async findUserByEmail(e){let s=await this.col("users").findOne({email:e.toLowerCase()});return s?this.docToAuthUser(s):null}async findUserById(e){let s=await this.col("users").findOne({_id:e});return s?this.docToAuthUser(s):null}async updateUser(e,s){let t={updatedAt:new Date};s.name!==void 0&&(t.name=s.name),s.email!==void 0&&(t.email=s.email),s.passwordHash!==void 0&&(t.passwordHash=s.passwordHash),s.role!==void 0&&(t.role=s.role),s.avatar!==void 0&&(t.avatar=s.avatar),s.tenantId!==void 0&&(t.tenantId=s.tenantId),s.emailVerified!==void 0&&(t.emailVerified=s.emailVerified),s.locked!==void 0&&(t.locked=s.locked),s.lastLogin!==void 0&&(t.lastLogin=s.lastLogin?new Date(s.lastLogin):null),s.failedLoginAttempts!==void 0&&(t.failedLoginAttempts=s.failedLoginAttempts);let i=await this.col("users").findOneAndUpdate({_id:e},{$set:t},{returnDocument:"after"});return i?this.docToAuthUser(i):null}async deleteUser(e){return (await this.col("users").deleteOne({_id:e})).deletedCount>0}async verifyPassword(e,s){let t=await this.findUserByEmail(e);if(!t)return null;let i=await this.col("users").findOne({email:e.toLowerCase()},{projection:{passwordHash:1}});return i?.passwordHash&&await h__default.default.compare(s,i.passwordHash)?t:null}async hashPassword(e){return h__default.default.hash(e,12)}async createSession(e,s){let t=crypto.randomUUID(),i=crypto.randomBytes(32).toString("base64url"),n=crypto.randomBytes(32).toString("base64url"),a=new Date,u=new Date(a.getTime()+this.sessionTTL*1e3),d={_id:t,userId:e,token:i,refreshToken:n,ipAddress:s?.ipAddress||null,userAgent:s?.userAgent||null,expiresAt:u,createdAt:a};return await this.col("sessions").insertOne(d),this.docToSession(d)}async findSessionByToken(e){let s=await this.col("sessions").findOne({token:e,expiresAt:{$gt:new Date}});return s?this.docToSession(s):null}async findSessionByRefreshToken(e){let s=await this.col("sessions").findOne({refreshToken:e,expiresAt:{$gt:new Date}});return s?this.docToSession(s):null}async deleteSession(e){return (await this.col("sessions").deleteOne({_id:e})).deletedCount>0}async deleteUserSessions(e){return (await this.col("sessions").deleteMany({userId:e})).deletedCount}async hasAnyUsers(){return await this.col("users").countDocuments()>0}async addPasswordToHistory(e,s){await this.col("password_history").insertOne({userId:e,passwordHash:s,createdAt:new Date});}async getPasswordHistory(e,s=5){return (await this.col("password_history").find({userId:e}).sort({createdAt:-1}).limit(s).toArray()).map(i=>i.passwordHash)}async isPasswordInHistory(e,s,t=5){let i=await this.getPasswordHistory(s,t);for(let n of i)if(await h__default.default.compare(e,n))return true;return false}async findAuditLogs(e){let{limit:s=50,offset:t=0,userId:i,action:n,resource:a,resourceId:u,success:d,startDate:c,endDate:f}=e,o={};i&&(o.userId=i),n&&(Array.isArray(n)?o.action={$in:n}:o.action=n),a&&(o.resource=a),u&&(o.resourceId=u),d!==void 0&&(o.success=d),(c||f)&&(o.timestamp={},c&&(o.timestamp.$gte=c),f&&(o.timestamp.$lte=f));let g=await this.col("audit_logs").countDocuments(o);return {logs:(await this.col("audit_logs").find(o).sort({timestamp:-1}).skip(t).limit(s).toArray()).map(r=>({id:r._id,timestamp:r.timestamp,action:r.action,userId:r.userId||void 0,userEmail:r.userEmail||void 0,role:r.role||void 0,resource:r.resource,resourceId:r.resourceId||void 0,changes:r.changes||void 0,ipAddress:r.ipAddress||void 0,userAgent:r.userAgent||void 0,success:r.success,error:r.error||void 0,metadata:r.metadata||void 0})),total:g}}async createAuditLog(e){let s=crypto.randomUUID(),t=new Date;return await this.col("audit_logs").insertOne({_id:s,action:e.action,userId:e.userId||null,userEmail:e.userEmail||null,role:e.role||null,resource:e.resource,resourceId:e.resourceId||null,changes:e.changes||null,ipAddress:e.ipAddress||null,userAgent:e.userAgent||null,success:e.success,error:e.error||null,metadata:e.metadata||null,timestamp:t}),{...e,id:s,timestamp:t}}docToAuthUser(e){return {id:e._id,name:e.name||void 0,email:e.email,passwordHash:e.passwordHash||void 0,role:e.role,tenantId:e.tenantId||void 0,avatar:e.avatar||void 0,emailVerified:e.emailVerified||false,locked:e.locked||false,lastLogin:e.lastLogin?.toISOString?.()||e.lastLogin||void 0,failedLoginAttempts:e.failedLoginAttempts||0,createdAt:e.createdAt?.toISOString?.()||e.createdAt,updatedAt:e.updatedAt?.toISOString?.()||e.updatedAt}}docToSession(e){return {id:e._id,userId:e.userId,token:e.token,refreshToken:e.refreshToken||void 0,expiresAt:e.expiresAt?.toISOString?.()||e.expiresAt,createdAt:e.createdAt?.toISOString?.()||e.createdAt,ipAddress:e.ipAddress||void 0,userAgent:e.userAgent||void 0}}async createEmailVerificationToken(e){let s=crypto.randomBytes(32).toString("hex"),t=new Date(Date.now()+1440*60*1e3);return await this.db.collection("email_verifications").insertOne({userId:new(await import('mongodb')).ObjectId(e),token:s,expiresAt:t,createdAt:new Date}),{token:s,expiresAt:t}}async verifyEmailToken(e){let s=await this.db.collection("email_verifications").findOne({token:e});return s?s.expiresAt<new Date?{success:false,error:"Verification token has expired"}:(await this.db.collection("users").updateOne({_id:s.userId},{$set:{emailVerified:true}}),await this.db.collection("email_verifications").deleteOne({_id:s._id}),{success:true,userId:s.userId.toString()}):{success:false,error:"Invalid verification token"}}async createPasswordResetToken(e){let s=await this.findUserByEmail(e);if(!s)return {token:"",expiresAt:new Date,error:"User not found"};let t=crypto.randomBytes(32).toString("hex"),i=new Date(Date.now()+3600*1e3);return await this.db.collection("password_resets").insertOne({userId:new(await import('mongodb')).ObjectId(s.id),token:t,expiresAt:i,createdAt:new Date}),{token:t,expiresAt:i}}async resetPasswordWithToken(e,s){let t=await this.db.collection("password_resets").findOne({token:e});if(!t)return {success:false,error:"Invalid reset token"};if(t.expiresAt<new Date)return {success:false,error:"Reset token has expired"};if(t.usedAt)return {success:false,error:"Reset token has already been used"};let i=await this.hashPassword(s);return await this.db.collection("users").updateOne({_id:t.userId},{$set:{passwordHash:i,updatedAt:new Date}}),await this.db.collection("password_resets").updateOne({_id:t._id},{$set:{usedAt:new Date}}),await this.db.collection("sessions").deleteMany({userId:t.userId}),{success:true}}};exports.a=w;
@@ -1,4 +1,4 @@
1
- 'use strict';var c=require('bcryptjs'),crypto=require('crypto'),fs=require('fs'),path=require('path'),module$1=require('module');var _documentCurrentScript=typeof document!=='undefined'?document.currentScript:null;function _interopDefault(e){return e&&e.__esModule?e:{default:e}}var c__default=/*#__PURE__*/_interopDefault(c);var m=module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('chunk-ET6NN2V2.cjs', document.baseURI).href))),h="node:sqlite",{DatabaseSync:_}=m(h),g=5e3,S=1e3,k=-64e3,A=268435456,E=class{db=null;path;saltRounds;externalDb;busyTimeout;walAutoCheckpoint;cacheSize;mmapSize;preparedStatements=new Map;constructor(e={}){this.path=e.path||"./data/auth.db",this.saltRounds=e.saltRounds||12,this.externalDb=!!e.db,this.busyTimeout=e.busyTimeout??g,this.walAutoCheckpoint=e.walAutoCheckpoint??S,this.cacheSize=e.cacheSize??k,this.mmapSize=e.mmapSize??A,e.db&&(this.db=e.db);}async connect(){if(this.db)return;let e=path.dirname(this.path);e&&e!=="."&&fs.mkdirSync(e,{recursive:true}),this.db=new _(this.path),this.db.exec(`PRAGMA busy_timeout = ${this.busyTimeout}`),this.db.exec("PRAGMA journal_mode = WAL"),this.db.exec("PRAGMA synchronous = NORMAL"),this.db.exec("PRAGMA cache_size = "+this.cacheSize),this.db.exec("PRAGMA mmap_size = "+this.mmapSize),this.db.exec("PRAGMA wal_autocheckpoint = "+this.walAutoCheckpoint),this.db.exec("PRAGMA foreign_keys = ON"),this.db.exec("PRAGMA temp_store = MEMORY"),this.ensureTables(),this.prepareStatements();}async disconnect(){this.db&&!this.externalDb&&(this.db.exec("PRAGMA wal_checkpoint(TRUNCATE)"),this.db.close(),this.db=null,this.preparedStatements.clear());}async ensureConnected(){if(this.db||await this.connect(),!this.db)throw new Error("Failed to connect to SQLite database");return this.db}ensureTables(){if(this.db){this.db.exec(`
1
+ 'use strict';var c=require('bcryptjs'),crypto=require('crypto'),fs=require('fs'),path=require('path'),module$1=require('module');var _documentCurrentScript=typeof document!=='undefined'?document.currentScript:null;function _interopDefault(e){return e&&e.__esModule?e:{default:e}}var c__default=/*#__PURE__*/_interopDefault(c);var h=module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('chunk-HOP4D5XZ.cjs', document.baseURI).href))),m="node:sqlite",{DatabaseSync:_}=h(m),g=5e3,S=1e3,k=-64e3,A=268435456,E=class{db=null;path;saltRounds;externalDb;busyTimeout;walAutoCheckpoint;cacheSize;mmapSize;preparedStatements=new Map;constructor(e={}){this.path=e.path||"./data/auth.db",this.saltRounds=e.saltRounds||12,this.externalDb=!!e.db,this.busyTimeout=e.busyTimeout??g,this.walAutoCheckpoint=e.walAutoCheckpoint??S,this.cacheSize=e.cacheSize??k,this.mmapSize=e.mmapSize??A,e.db&&(this.db=e.db);}async connect(){if(this.db)return;let e=path.dirname(this.path);e&&e!=="."&&fs.mkdirSync(e,{recursive:true}),this.db=new _(this.path),this.db.exec(`PRAGMA busy_timeout = ${this.busyTimeout}`),this.db.exec("PRAGMA journal_mode = WAL"),this.db.exec("PRAGMA synchronous = NORMAL"),this.db.exec("PRAGMA cache_size = "+this.cacheSize),this.db.exec("PRAGMA mmap_size = "+this.mmapSize),this.db.exec("PRAGMA wal_autocheckpoint = "+this.walAutoCheckpoint),this.db.exec("PRAGMA foreign_keys = ON"),this.db.exec("PRAGMA temp_store = MEMORY"),this.ensureTables(),this.prepareStatements();}async disconnect(){this.db&&!this.externalDb&&(this.db.exec("PRAGMA wal_checkpoint(TRUNCATE)"),this.db.close(),this.db=null,this.preparedStatements.clear());}async ensureConnected(){if(this.db||await this.connect(),!this.db)throw new Error("Failed to connect to SQLite database");return this.db}ensureTables(){if(this.db){this.db.exec(`
2
2
  CREATE TABLE IF NOT EXISTS kyro_users (
3
3
  id TEXT PRIMARY KEY,
4
4
  name TEXT,
@@ -104,7 +104,7 @@
104
104
 
105
105
  CREATE INDEX IF NOT EXISTS idx_kyro_email_verifications_token ON kyro_email_verifications(token);
106
106
  CREATE INDEX IF NOT EXISTS idx_kyro_password_resets_token ON kyro_password_resets(token);
107
- `);try{this.db.exec("ALTER TABLE kyro_users ADD COLUMN name TEXT");}catch{}}}prepareStatements(){this.db&&(this.preparedStatements.set("findUserByEmail",this.db.prepare("SELECT * FROM kyro_users WHERE email = ?")),this.preparedStatements.set("findUserById",this.db.prepare("SELECT * FROM kyro_users WHERE id = ?")),this.preparedStatements.set("findSessionByToken",this.db.prepare("SELECT * FROM kyro_sessions WHERE token = ?")),this.preparedStatements.set("findSessionByRefreshToken",this.db.prepare("SELECT * FROM kyro_sessions WHERE refresh_token = ?")),this.preparedStatements.set("deleteSession",this.db.prepare("DELETE FROM kyro_sessions WHERE id = ? OR token = ?")),this.preparedStatements.set("deleteUserSessions",this.db.prepare("DELETE FROM kyro_sessions WHERE user_id = ?")),this.preparedStatements.set("countUsers",this.db.prepare("SELECT COUNT(*) as count FROM kyro_users")),this.preparedStatements.set("deleteUser",this.db.prepare("DELETE FROM kyro_users WHERE id = ?")),this.preparedStatements.set("findUsersPaginated",this.db.prepare("SELECT * FROM kyro_users ORDER BY created_at DESC LIMIT ? OFFSET ?")),this.preparedStatements.set("findUsersWithSearch",this.db.prepare("SELECT * FROM kyro_users WHERE email LIKE ? ORDER BY created_at DESC LIMIT ? OFFSET ?")),this.preparedStatements.set("countUsersWithSearch",this.db.prepare("SELECT COUNT(*) as count FROM kyro_users WHERE email LIKE ?")),this.preparedStatements.set("getPasswordHistory",this.db.prepare("SELECT password_hash FROM kyro_password_history WHERE user_id = ? ORDER BY created_at DESC LIMIT ?")),this.preparedStatements.set("addPasswordHistory",this.db.prepare("INSERT INTO kyro_password_history (user_id, password_hash, created_at) VALUES (?, ?, ?)")),this.preparedStatements.set("trimPasswordHistory",this.db.prepare(`DELETE FROM kyro_password_history WHERE id IN (
107
+ `);try{this.db.exec("ALTER TABLE kyro_users ADD COLUMN name TEXT");}catch{}try{this.db.exec("ALTER TABLE kyro_users ADD COLUMN avatar TEXT");}catch{}}}prepareStatements(){this.db&&(this.preparedStatements.set("findUserByEmail",this.db.prepare("SELECT * FROM kyro_users WHERE email = ?")),this.preparedStatements.set("findUserById",this.db.prepare("SELECT * FROM kyro_users WHERE id = ?")),this.preparedStatements.set("findSessionByToken",this.db.prepare("SELECT * FROM kyro_sessions WHERE token = ?")),this.preparedStatements.set("findSessionByRefreshToken",this.db.prepare("SELECT * FROM kyro_sessions WHERE refresh_token = ?")),this.preparedStatements.set("deleteSession",this.db.prepare("DELETE FROM kyro_sessions WHERE id = ? OR token = ?")),this.preparedStatements.set("deleteUserSessions",this.db.prepare("DELETE FROM kyro_sessions WHERE user_id = ?")),this.preparedStatements.set("countUsers",this.db.prepare("SELECT COUNT(*) as count FROM kyro_users")),this.preparedStatements.set("deleteUser",this.db.prepare("DELETE FROM kyro_users WHERE id = ?")),this.preparedStatements.set("findUsersPaginated",this.db.prepare("SELECT * FROM kyro_users ORDER BY created_at DESC LIMIT ? OFFSET ?")),this.preparedStatements.set("findUsersWithSearch",this.db.prepare("SELECT * FROM kyro_users WHERE email LIKE ? ORDER BY created_at DESC LIMIT ? OFFSET ?")),this.preparedStatements.set("countUsersWithSearch",this.db.prepare("SELECT COUNT(*) as count FROM kyro_users WHERE email LIKE ?")),this.preparedStatements.set("getPasswordHistory",this.db.prepare("SELECT password_hash FROM kyro_password_history WHERE user_id = ? ORDER BY created_at DESC LIMIT ?")),this.preparedStatements.set("addPasswordHistory",this.db.prepare("INSERT INTO kyro_password_history (user_id, password_hash, created_at) VALUES (?, ?, ?)")),this.preparedStatements.set("trimPasswordHistory",this.db.prepare(`DELETE FROM kyro_password_history WHERE id IN (
108
108
  SELECT id FROM kyro_password_history WHERE user_id = ? ORDER BY created_at DESC LIMIT -1 OFFSET 5
109
109
  )`)),this.preparedStatements.set("deleteExpiredSessions",this.db.prepare("DELETE FROM kyro_sessions WHERE expires_at < ?")),this.preparedStatements.set("cleanupOldAuditLogs",this.db.prepare("DELETE FROM kyro_audit_logs WHERE timestamp < ?")),this.preparedStatements.set("cleanupExpiredLockouts",this.db.prepare("UPDATE kyro_lockouts SET attempts = 0, locked_at = NULL, locked_until = NULL WHERE locked_until < ?")),this.preparedStatements.set("getLockout",this.db.prepare("SELECT * FROM kyro_lockouts WHERE user_id = ?")),this.preparedStatements.set("upsertLockout",this.db.prepare(`
110
110
  INSERT INTO kyro_lockouts (user_id, attempts, last_attempt, locked_at, locked_until)
@@ -114,9 +114,9 @@
114
114
  last_attempt = excluded.last_attempt,
115
115
  locked_at = excluded.locked_at,
116
116
  locked_until = excluded.locked_until
117
- `)),this.preparedStatements.set("resetLockout",this.db.prepare("UPDATE kyro_lockouts SET attempts = 0, locked_at = NULL, locked_until = NULL WHERE user_id = ?")));}stmt(e){let s=this.preparedStatements.get(e);if(!s)throw new Error(`Prepared statement not found: ${e}`);return s}async cleanupExpiredSessions(){return await this.ensureConnected(),this.stmt("deleteExpiredSessions").run(new Date().toISOString()).changes}async cleanupOldAuditLogs(e=30){await this.ensureConnected();let s=new Date(Date.now()-e*24*60*60*1e3).toISOString();return this.stmt("cleanupOldAuditLogs").run(s).changes}async getStats(){await this.ensureConnected();let e=this.stmt("countUsers").get().count,s=this.db.prepare("SELECT COUNT(*) as count FROM kyro_sessions WHERE expires_at > ?").get(new Date().toISOString()).count,t=this.db.prepare("SELECT COUNT(*) as count FROM kyro_audit_logs").get().count;return {userCount:e,activeSessionCount:s,auditLogCount:t}}async createUser(e){await this.ensureConnected();let s=crypto.randomBytes(16).toString("hex"),t=new Date().toISOString(),r=await this.hashPassword(e.password),n={id:s,name:e.name,email:e.email.toLowerCase(),passwordHash:r,role:e.role||"customer",avatar:e.avatar,tenantId:e.tenantId,createdAt:t,updatedAt:t};return this.db.prepare(`INSERT INTO kyro_users (id, name, email, password_hash, role, avatar, tenant_id, created_at, updated_at)
118
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(s,n.name||null,n.email,n.passwordHash,n.role,n.avatar||null,n.tenantId||null,t,t),n}async findUserByEmail(e){await this.ensureConnected();let s=this.stmt("findUserByEmail").get(e.toLowerCase());return s?this.rowToUser(s):null}async findUserById(e){await this.ensureConnected();let s=this.stmt("findUserById").get(e);return s?this.rowToUser(s):null}async updateUser(e,s){if(await this.ensureConnected(),!await this.findUserById(e))return null;let r=[],n=[];return s.email!==void 0&&(r.push("email = ?"),n.push(s.email.toLowerCase())),s.name!==void 0&&(r.push("name = ?"),n.push(s.name)),s.passwordHash!==void 0&&(r.push("password_hash = ?"),n.push(s.passwordHash)),s.role!==void 0&&(r.push("role = ?"),n.push(s.role)),s.avatar!==void 0&&(r.push("avatar = ?"),n.push(s.avatar)),s.tenantId!==void 0&&(r.push("tenant_id = ?"),n.push(s.tenantId)),s.emailVerified!==void 0&&(r.push("email_verified = ?"),n.push(s.emailVerified?1:0)),s.locked!==void 0&&(r.push("locked = ?"),n.push(s.locked?1:0)),s.lastLogin!==void 0&&(r.push("last_login = ?"),n.push(s.lastLogin)),s.failedLoginAttempts!==void 0&&(r.push("failed_login_attempts = ?"),n.push(s.failedLoginAttempts)),r.push("updated_at = ?"),n.push(new Date().toISOString()),n.push(e),this.db.prepare(`UPDATE kyro_users SET ${r.join(", ")} WHERE id = ?`).run(...n),this.findUserById(e)}async deleteUser(e){return await this.ensureConnected(),this.stmt("deleteUser").run(e).changes>0}async hashPassword(e){return c__default.default.hash(e,this.saltRounds)}async verifyPassword(e,s){await this.ensureConnected();let t=await this.findUserByEmail(e);if(!t)return null;let r=this.db.prepare("SELECT password_hash FROM kyro_users WHERE id = ?").get(t.id);return r?.password_hash&&await c__default.default.compare(s,r.password_hash)?t:null}async createSession(e,s={}){await this.ensureConnected();let t=crypto.randomBytes(32).toString("hex"),r=crypto.randomBytes(32).toString("base64url"),n=crypto.randomBytes(32).toString("base64url"),d=new Date,u=new Date(d.getTime()+864e5).toISOString(),i={id:t,userId:e,token:r,refreshToken:n,expiresAt:u,createdAt:d.toISOString(),ipAddress:s.ipAddress,userAgent:s.userAgent};return this.db.prepare(`INSERT INTO kyro_sessions (id, user_id, token, refresh_token, expires_at, created_at, ip_address, user_agent)
119
- VALUES (?, ?, ?, ?, ?, ?, ?, ?)`).run(i.id,i.userId,i.token,i.refreshToken??null,i.expiresAt,i.createdAt,i.ipAddress??null,i.userAgent??null),i}async findSessionByToken(e){await this.ensureConnected();let s=this.stmt("findSessionByToken").get(e);return s?this.rowToSession(s):null}async findSessionByRefreshToken(e){await this.ensureConnected();let s=this.stmt("findSessionByRefreshToken").get(e);return s?this.rowToSession(s):null}async deleteSession(e){return await this.ensureConnected(),this.stmt("deleteSession").run(e,e).changes>0}async deleteUserSessions(e){return await this.ensureConnected(),this.stmt("deleteUserSessions").run(e).changes}async hasAnyUsers(){return await this.ensureConnected(),this.stmt("countUsers").get().count>0}async findUsers(e={}){await this.ensureConnected();let s=e.page??1,t=e.limit??10,r=(s-1)*t,n=e.search,d,u;if(n){let i=`%${n}%`;d=this.stmt("countUsersWithSearch").get(i).count,u=this.stmt("findUsersWithSearch").all(i,t,r);}else d=this.stmt("countUsers").get().count,u=this.stmt("findUsersPaginated").all(t,r);return {users:u.map(i=>this.rowToUser(i)),total:d}}async addPasswordToHistory(e,s){await this.ensureConnected(),this.stmt("addPasswordHistory").run(e,s,new Date().toISOString()),this.stmt("trimPasswordHistory").run(e);}async getPasswordHistory(e,s=5){return await this.ensureConnected(),this.stmt("getPasswordHistory").all(e,s).map(r=>r.password_hash)}async isPasswordInHistory(e,s,t=5){let r=await this.getPasswordHistory(s,t);for(let n of r)if(await c__default.default.compare(e,n))return true;return false}async recordFailedAttempt(e){await this.ensureConnected();let s=Date.now(),t=this.stmt("getLockout").get(e),r=(t?.attempts||0)+1,n=r>=5?s+900*1e3:t?.locked_until||null;this.stmt("upsertLockout").run(e,r,s,n!==null?s:null,n);}async resetAttempts(e){await this.ensureConnected(),this.stmt("resetLockout").run(e);}async checkLockout(e){await this.ensureConnected(),this.stmt("cleanupExpiredLockouts").run(Date.now());let s=this.stmt("getLockout").get(e);return s?s.locked_until!==null&&s.locked_until>Date.now()?{locked:true,attemptsRemaining:0,lockedUntil:new Date(s.locked_until),totalAttempts:s.attempts}:{locked:false,attemptsRemaining:Math.max(0,5-s.attempts),totalAttempts:s.attempts}:{locked:false,attemptsRemaining:5,totalAttempts:0}}async logAudit(e){await this.ensureConnected();let s=crypto.randomBytes(16).toString("hex"),t=new Date().toISOString();return this.db.prepare(`INSERT INTO kyro_audit_logs (
117
+ `)),this.preparedStatements.set("resetLockout",this.db.prepare("UPDATE kyro_lockouts SET attempts = 0, locked_at = NULL, locked_until = NULL WHERE user_id = ?")));}stmt(e){let s=this.preparedStatements.get(e);if(!s)throw new Error(`Prepared statement not found: ${e}`);return s}async cleanupExpiredSessions(){return await this.ensureConnected(),this.stmt("deleteExpiredSessions").run(new Date().toISOString()).changes}async cleanupOldAuditLogs(e=30){await this.ensureConnected();let s=new Date(Date.now()-e*24*60*60*1e3).toISOString();return this.stmt("cleanupOldAuditLogs").run(s).changes}async getStats(){await this.ensureConnected();let e=this.stmt("countUsers").get().count,s=this.db.prepare("SELECT COUNT(*) as count FROM kyro_sessions WHERE expires_at > ?").get(new Date().toISOString()).count,t=this.db.prepare("SELECT COUNT(*) as count FROM kyro_audit_logs").get().count;return {userCount:e,activeSessionCount:s,auditLogCount:t}}async createUser(e){await this.ensureConnected();let s=crypto.randomBytes(16).toString("hex"),t=new Date().toISOString(),r=await this.hashPassword(e.password),i={id:s,name:e.name,email:e.email.toLowerCase(),passwordHash:r,role:e.role||"customer",avatar:e.avatar,tenantId:e.tenantId,createdAt:t,updatedAt:t};return this.db.prepare(`INSERT INTO kyro_users (id, name, email, password_hash, role, avatar, tenant_id, created_at, updated_at)
118
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(s,i.name||null,i.email,i.passwordHash,i.role,i.avatar||null,i.tenantId||null,t,t),i}async findUserByEmail(e){await this.ensureConnected();let s=this.stmt("findUserByEmail").get(e.toLowerCase());return s?this.rowToUser(s):null}async findUserById(e){await this.ensureConnected();let s=this.stmt("findUserById").get(e);return s?this.rowToUser(s):null}async updateUser(e,s){if(await this.ensureConnected(),!await this.findUserById(e))return null;let r=[],i=[];return s.email!==void 0&&(r.push("email = ?"),i.push(s.email.toLowerCase())),s.name!==void 0&&(r.push("name = ?"),i.push(s.name)),s.passwordHash!==void 0&&(r.push("password_hash = ?"),i.push(s.passwordHash)),s.role!==void 0&&(r.push("role = ?"),i.push(s.role)),s.avatar!==void 0&&(r.push("avatar = ?"),i.push(s.avatar)),s.tenantId!==void 0&&(r.push("tenant_id = ?"),i.push(s.tenantId)),s.emailVerified!==void 0&&(r.push("email_verified = ?"),i.push(s.emailVerified?1:0)),s.locked!==void 0&&(r.push("locked = ?"),i.push(s.locked?1:0)),s.lastLogin!==void 0&&(r.push("last_login = ?"),i.push(s.lastLogin)),s.failedLoginAttempts!==void 0&&(r.push("failed_login_attempts = ?"),i.push(s.failedLoginAttempts)),r.push("updated_at = ?"),i.push(new Date().toISOString()),i.push(e),this.db.prepare(`UPDATE kyro_users SET ${r.join(", ")} WHERE id = ?`).run(...i),this.findUserById(e)}async deleteUser(e){return await this.ensureConnected(),this.stmt("deleteUser").run(e).changes>0}async hashPassword(e){return c__default.default.hash(e,this.saltRounds)}async verifyPassword(e,s){await this.ensureConnected();let t=await this.findUserByEmail(e);if(!t)return null;let r=this.db.prepare("SELECT password_hash FROM kyro_users WHERE id = ?").get(t.id);return r?.password_hash&&await c__default.default.compare(s,r.password_hash)?t:null}async createSession(e,s={}){await this.ensureConnected();let t=crypto.randomBytes(32).toString("hex"),r=crypto.randomBytes(32).toString("base64url"),i=crypto.randomBytes(32).toString("base64url"),d=new Date,u=new Date(d.getTime()+864e5).toISOString(),n={id:t,userId:e,token:r,refreshToken:i,expiresAt:u,createdAt:d.toISOString(),ipAddress:s.ipAddress,userAgent:s.userAgent};return this.db.prepare(`INSERT INTO kyro_sessions (id, user_id, token, refresh_token, expires_at, created_at, ip_address, user_agent)
119
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)`).run(n.id,n.userId,n.token,n.refreshToken??null,n.expiresAt,n.createdAt,n.ipAddress??null,n.userAgent??null),n}async findSessionByToken(e){await this.ensureConnected();let s=this.stmt("findSessionByToken").get(e);return s?this.rowToSession(s):null}async findSessionByRefreshToken(e){await this.ensureConnected();let s=this.stmt("findSessionByRefreshToken").get(e);return s?this.rowToSession(s):null}async deleteSession(e){return await this.ensureConnected(),this.stmt("deleteSession").run(e,e).changes>0}async deleteUserSessions(e){return await this.ensureConnected(),this.stmt("deleteUserSessions").run(e).changes}async hasAnyUsers(){return await this.ensureConnected(),this.stmt("countUsers").get().count>0}async findUsers(e={}){await this.ensureConnected();let s=e.page??1,t=e.limit??10,r=(s-1)*t,i=e.search,d,u;if(i){let n=`%${i}%`;d=this.stmt("countUsersWithSearch").get(n).count,u=this.stmt("findUsersWithSearch").all(n,t,r);}else d=this.stmt("countUsers").get().count,u=this.stmt("findUsersPaginated").all(t,r);return {users:u.map(n=>this.rowToUser(n)),total:d}}async addPasswordToHistory(e,s){await this.ensureConnected(),this.stmt("addPasswordHistory").run(e,s,new Date().toISOString()),this.stmt("trimPasswordHistory").run(e);}async getPasswordHistory(e,s=5){return await this.ensureConnected(),this.stmt("getPasswordHistory").all(e,s).map(r=>r.password_hash)}async isPasswordInHistory(e,s,t=5){let r=await this.getPasswordHistory(s,t);for(let i of r)if(await c__default.default.compare(e,i))return true;return false}async recordFailedAttempt(e){await this.ensureConnected();let s=Date.now(),t=this.stmt("getLockout").get(e),r=(t?.attempts||0)+1,i=r>=5?s+900*1e3:t?.locked_until||null;this.stmt("upsertLockout").run(e,r,s,i!==null?s:null,i);}async resetAttempts(e){await this.ensureConnected(),this.stmt("resetLockout").run(e);}async checkLockout(e){await this.ensureConnected(),this.stmt("cleanupExpiredLockouts").run(Date.now());let s=this.stmt("getLockout").get(e);return s?s.locked_until!==null&&s.locked_until>Date.now()?{locked:true,attemptsRemaining:0,lockedUntil:new Date(s.locked_until),totalAttempts:s.attempts}:{locked:false,attemptsRemaining:Math.max(0,5-s.attempts),totalAttempts:s.attempts}:{locked:false,attemptsRemaining:5,totalAttempts:0}}async logAudit(e){await this.ensureConnected();let s=crypto.randomBytes(16).toString("hex"),t=new Date().toISOString();return this.db.prepare(`INSERT INTO kyro_audit_logs (
120
120
  id, timestamp, action, user_id, user_email, role, resource, resource_id,
121
121
  ip_address, user_agent, success, error, metadata, created_at
122
- ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(s,t,e.action,e.userId||null,e.userEmail||null,e.role||null,e.resource,e.resourceId||null,e.ipAddress||null,e.userAgent||null,e.success?1:0,e.error||null,e.metadata?JSON.stringify(e.metadata):null,new Date().toISOString()),s}async queryAuditLogs(e={}){await this.ensureConnected();let s=[],t=[];e.action&&(s.push("action = ?"),t.push(e.action)),e.userId&&(s.push("user_id = ?"),t.push(e.userId)),e.resource&&(s.push("resource = ?"),t.push(e.resource)),e.success!==void 0&&(s.push("success = ?"),t.push(e.success?1:0)),e.startDate&&(s.push("timestamp >= ?"),t.push(e.startDate.toISOString())),e.endDate&&(s.push("timestamp <= ?"),t.push(e.endDate.toISOString()));let r=s.length>0?"WHERE "+s.join(" AND "):"",n=e.limit||50,d=e.offset||0,u=this.db.prepare(`SELECT COUNT(*) as count FROM kyro_audit_logs ${r}`).get(...t),i=this.db.prepare(`SELECT * FROM kyro_audit_logs ${r} ORDER BY timestamp DESC LIMIT ? OFFSET ?`).all(...t,n,d);return {total:u.count,logs:i.map(a=>({id:a.id,timestamp:new Date(a.timestamp),action:a.action,userId:a.user_id||void 0,userEmail:a.user_email||void 0,resource:a.resource,resourceId:a.resource_id||void 0,ipAddress:a.ip_address||void 0,userAgent:a.user_agent||void 0,success:a.success===1,error:a.error||void 0,metadata:a.metadata?JSON.parse(a.metadata):void 0}))}}rowToUser(e){return {id:e.id,name:e.name||void 0,email:e.email,passwordHash:e.password_hash,role:e.role,tenantId:e.tenant_id,avatar:e.avatar,emailVerified:e.email_verified===1,locked:e.locked===1,lastLogin:e.last_login,failedLoginAttempts:e.failed_login_attempts||0,createdAt:e.created_at,updatedAt:e.updated_at}}rowToSession(e){return {id:e.id,userId:e.user_id,token:e.token,refreshToken:e.refresh_token,expiresAt:e.expires_at,createdAt:e.created_at,ipAddress:e.ip_address,userAgent:e.user_agent}}async findAuditLogs(e){let s=await this.queryAuditLogs({action:e.action,userId:e.userId,resource:e.resource,success:e.success,startDate:e.startDate,endDate:e.endDate,limit:e.limit,offset:e.offset});return {logs:s.logs.map(t=>({...t,action:t.action})),total:s.total}}async createAuditLog(e){let s=await this.logAudit({action:e.action,userId:e.userId,userEmail:e.userEmail,role:e.role,resource:e.resource,resourceId:e.resourceId,ipAddress:e.ipAddress,userAgent:e.userAgent,success:e.success,error:e.error,metadata:e.metadata}),t=this.db?.prepare("SELECT * FROM kyro_audit_logs WHERE id = ?").get(s);return {...e,id:s,timestamp:t?new Date(t.timestamp):new Date}}async createEmailVerificationToken(e){await this.ensureConnected();let s=crypto.randomBytes(16).toString("hex"),t=crypto.randomBytes(32).toString("hex"),r=new Date(Date.now()+1440*60*1e3);return this.db.prepare("INSERT INTO kyro_email_verifications (id, user_id, token, expires_at, created_at) VALUES (?, ?, ?, ?, ?)").run(s,e,t,r.toISOString(),new Date().toISOString()),{token:t,expiresAt:r}}async verifyEmailToken(e){await this.ensureConnected();let s=this.db.prepare("SELECT * FROM kyro_email_verifications WHERE token = ?").get(e);return s?new Date(s.expires_at)<new Date?{success:false,error:"Verification token has expired"}:(this.db.prepare("UPDATE kyro_users SET email_verified = 1 WHERE id = ?").run(s.user_id),this.db.prepare("DELETE FROM kyro_email_verifications WHERE id = ?").run(s.id),{success:true,userId:s.user_id}):{success:false,error:"Invalid verification token"}}async createPasswordResetToken(e){await this.ensureConnected();let s=await this.findUserByEmail(e);if(!s)return {token:"",expiresAt:new Date,error:"User not found"};let t=crypto.randomBytes(16).toString("hex"),r=crypto.randomBytes(32).toString("hex"),n=new Date(Date.now()+3600*1e3);return this.db.prepare("INSERT INTO kyro_password_resets (id, user_id, token, expires_at, created_at) VALUES (?, ?, ?, ?, ?)").run(t,s.id,r,n.toISOString(),new Date().toISOString()),{token:r,expiresAt:n}}async resetPasswordWithToken(e,s){await this.ensureConnected();let t=this.db.prepare("SELECT * FROM kyro_password_resets WHERE token = ?").get(e);if(!t)return {success:false,error:"Invalid reset token"};if(new Date(t.expires_at)<new Date)return {success:false,error:"Reset token has expired"};if(t.used_at)return {success:false,error:"Reset token has already been used"};let r=await this.hashPassword(s);return this.db.prepare("UPDATE kyro_users SET password_hash = ?, updated_at = ? WHERE id = ?").run(r,new Date().toISOString(),t.user_id),this.db.prepare("UPDATE kyro_password_resets SET used_at = ? WHERE id = ?").run(new Date().toISOString(),t.id),this.db.prepare("DELETE FROM kyro_sessions WHERE user_id = ?").run(t.user_id),{success:true}}};exports.a=E;
122
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(s,t,e.action,e.userId||null,e.userEmail||null,e.role||null,e.resource,e.resourceId||null,e.ipAddress||null,e.userAgent||null,e.success?1:0,e.error||null,e.metadata?JSON.stringify(e.metadata):null,new Date().toISOString()),s}async queryAuditLogs(e={}){await this.ensureConnected();let s=[],t=[];e.action&&(s.push("action = ?"),t.push(e.action)),e.userId&&(s.push("user_id = ?"),t.push(e.userId)),e.resource&&(s.push("resource = ?"),t.push(e.resource)),e.success!==void 0&&(s.push("success = ?"),t.push(e.success?1:0)),e.startDate&&(s.push("timestamp >= ?"),t.push(e.startDate.toISOString())),e.endDate&&(s.push("timestamp <= ?"),t.push(e.endDate.toISOString()));let r=s.length>0?"WHERE "+s.join(" AND "):"",i=e.limit||50,d=e.offset||0,u=this.db.prepare(`SELECT COUNT(*) as count FROM kyro_audit_logs ${r}`).get(...t),n=this.db.prepare(`SELECT * FROM kyro_audit_logs ${r} ORDER BY timestamp DESC LIMIT ? OFFSET ?`).all(...t,i,d);return {total:u.count,logs:n.map(a=>({id:a.id,timestamp:new Date(a.timestamp),action:a.action,userId:a.user_id||void 0,userEmail:a.user_email||void 0,resource:a.resource,resourceId:a.resource_id||void 0,ipAddress:a.ip_address||void 0,userAgent:a.user_agent||void 0,success:a.success===1,error:a.error||void 0,metadata:a.metadata?JSON.parse(a.metadata):void 0}))}}rowToUser(e){return {id:e.id,name:e.name||void 0,email:e.email,passwordHash:e.password_hash,role:e.role,tenantId:e.tenant_id,avatar:e.avatar,emailVerified:e.email_verified===1,locked:e.locked===1,lastLogin:e.last_login,failedLoginAttempts:e.failed_login_attempts||0,createdAt:e.created_at,updatedAt:e.updated_at}}rowToSession(e){return {id:e.id,userId:e.user_id,token:e.token,refreshToken:e.refresh_token,expiresAt:e.expires_at,createdAt:e.created_at,ipAddress:e.ip_address,userAgent:e.user_agent}}async findAuditLogs(e){let s=await this.queryAuditLogs({action:e.action,userId:e.userId,resource:e.resource,success:e.success,startDate:e.startDate,endDate:e.endDate,limit:e.limit,offset:e.offset});return {logs:s.logs.map(t=>({...t,action:t.action})),total:s.total}}async createAuditLog(e){let s=await this.logAudit({action:e.action,userId:e.userId,userEmail:e.userEmail,role:e.role,resource:e.resource,resourceId:e.resourceId,ipAddress:e.ipAddress,userAgent:e.userAgent,success:e.success,error:e.error,metadata:e.metadata}),t=this.db?.prepare("SELECT * FROM kyro_audit_logs WHERE id = ?").get(s);return {...e,id:s,timestamp:t?new Date(t.timestamp):new Date}}async createEmailVerificationToken(e){await this.ensureConnected();let s=crypto.randomBytes(16).toString("hex"),t=crypto.randomBytes(32).toString("hex"),r=new Date(Date.now()+1440*60*1e3);return this.db.prepare("INSERT INTO kyro_email_verifications (id, user_id, token, expires_at, created_at) VALUES (?, ?, ?, ?, ?)").run(s,e,t,r.toISOString(),new Date().toISOString()),{token:t,expiresAt:r}}async verifyEmailToken(e){await this.ensureConnected();let s=this.db.prepare("SELECT * FROM kyro_email_verifications WHERE token = ?").get(e);return s?new Date(s.expires_at)<new Date?{success:false,error:"Verification token has expired"}:(this.db.prepare("UPDATE kyro_users SET email_verified = 1 WHERE id = ?").run(s.user_id),this.db.prepare("DELETE FROM kyro_email_verifications WHERE id = ?").run(s.id),{success:true,userId:s.user_id}):{success:false,error:"Invalid verification token"}}async createPasswordResetToken(e){await this.ensureConnected();let s=await this.findUserByEmail(e);if(!s)return {token:"",expiresAt:new Date,error:"User not found"};let t=crypto.randomBytes(16).toString("hex"),r=crypto.randomBytes(32).toString("hex"),i=new Date(Date.now()+3600*1e3);return this.db.prepare("INSERT INTO kyro_password_resets (id, user_id, token, expires_at, created_at) VALUES (?, ?, ?, ?, ?)").run(t,s.id,r,i.toISOString(),new Date().toISOString()),{token:r,expiresAt:i}}async resetPasswordWithToken(e,s){await this.ensureConnected();let t=this.db.prepare("SELECT * FROM kyro_password_resets WHERE token = ?").get(e);if(!t)return {success:false,error:"Invalid reset token"};if(new Date(t.expires_at)<new Date)return {success:false,error:"Reset token has expired"};if(t.used_at)return {success:false,error:"Reset token has already been used"};let r=await this.hashPassword(s);return this.db.prepare("UPDATE kyro_users SET password_hash = ?, updated_at = ? WHERE id = ?").run(r,new Date().toISOString(),t.user_id),this.db.prepare("UPDATE kyro_password_resets SET used_at = ? WHERE id = ?").run(new Date().toISOString(),t.id),this.db.prepare("DELETE FROM kyro_sessions WHERE user_id = ?").run(t.user_id),{success:true}}};exports.a=E;
@@ -1,4 +1,4 @@
1
- import c from'bcryptjs';import {randomBytes}from'crypto';import {mkdirSync}from'fs';import {dirname}from'path';import {createRequire}from'module';var m=createRequire(import.meta.url),h="node:sqlite",{DatabaseSync:_}=m(h),g=5e3,S=1e3,k=-64e3,A=268435456,E=class{db=null;path;saltRounds;externalDb;busyTimeout;walAutoCheckpoint;cacheSize;mmapSize;preparedStatements=new Map;constructor(e={}){this.path=e.path||"./data/auth.db",this.saltRounds=e.saltRounds||12,this.externalDb=!!e.db,this.busyTimeout=e.busyTimeout??g,this.walAutoCheckpoint=e.walAutoCheckpoint??S,this.cacheSize=e.cacheSize??k,this.mmapSize=e.mmapSize??A,e.db&&(this.db=e.db);}async connect(){if(this.db)return;let e=dirname(this.path);e&&e!=="."&&mkdirSync(e,{recursive:true}),this.db=new _(this.path),this.db.exec(`PRAGMA busy_timeout = ${this.busyTimeout}`),this.db.exec("PRAGMA journal_mode = WAL"),this.db.exec("PRAGMA synchronous = NORMAL"),this.db.exec("PRAGMA cache_size = "+this.cacheSize),this.db.exec("PRAGMA mmap_size = "+this.mmapSize),this.db.exec("PRAGMA wal_autocheckpoint = "+this.walAutoCheckpoint),this.db.exec("PRAGMA foreign_keys = ON"),this.db.exec("PRAGMA temp_store = MEMORY"),this.ensureTables(),this.prepareStatements();}async disconnect(){this.db&&!this.externalDb&&(this.db.exec("PRAGMA wal_checkpoint(TRUNCATE)"),this.db.close(),this.db=null,this.preparedStatements.clear());}async ensureConnected(){if(this.db||await this.connect(),!this.db)throw new Error("Failed to connect to SQLite database");return this.db}ensureTables(){if(this.db){this.db.exec(`
1
+ import c from'bcryptjs';import {randomBytes}from'crypto';import {mkdirSync}from'fs';import {dirname}from'path';import {createRequire}from'module';var h=createRequire(import.meta.url),m="node:sqlite",{DatabaseSync:_}=h(m),g=5e3,S=1e3,k=-64e3,A=268435456,E=class{db=null;path;saltRounds;externalDb;busyTimeout;walAutoCheckpoint;cacheSize;mmapSize;preparedStatements=new Map;constructor(e={}){this.path=e.path||"./data/auth.db",this.saltRounds=e.saltRounds||12,this.externalDb=!!e.db,this.busyTimeout=e.busyTimeout??g,this.walAutoCheckpoint=e.walAutoCheckpoint??S,this.cacheSize=e.cacheSize??k,this.mmapSize=e.mmapSize??A,e.db&&(this.db=e.db);}async connect(){if(this.db)return;let e=dirname(this.path);e&&e!=="."&&mkdirSync(e,{recursive:true}),this.db=new _(this.path),this.db.exec(`PRAGMA busy_timeout = ${this.busyTimeout}`),this.db.exec("PRAGMA journal_mode = WAL"),this.db.exec("PRAGMA synchronous = NORMAL"),this.db.exec("PRAGMA cache_size = "+this.cacheSize),this.db.exec("PRAGMA mmap_size = "+this.mmapSize),this.db.exec("PRAGMA wal_autocheckpoint = "+this.walAutoCheckpoint),this.db.exec("PRAGMA foreign_keys = ON"),this.db.exec("PRAGMA temp_store = MEMORY"),this.ensureTables(),this.prepareStatements();}async disconnect(){this.db&&!this.externalDb&&(this.db.exec("PRAGMA wal_checkpoint(TRUNCATE)"),this.db.close(),this.db=null,this.preparedStatements.clear());}async ensureConnected(){if(this.db||await this.connect(),!this.db)throw new Error("Failed to connect to SQLite database");return this.db}ensureTables(){if(this.db){this.db.exec(`
2
2
  CREATE TABLE IF NOT EXISTS kyro_users (
3
3
  id TEXT PRIMARY KEY,
4
4
  name TEXT,
@@ -104,7 +104,7 @@ import c from'bcryptjs';import {randomBytes}from'crypto';import {mkdirSync}from'
104
104
 
105
105
  CREATE INDEX IF NOT EXISTS idx_kyro_email_verifications_token ON kyro_email_verifications(token);
106
106
  CREATE INDEX IF NOT EXISTS idx_kyro_password_resets_token ON kyro_password_resets(token);
107
- `);try{this.db.exec("ALTER TABLE kyro_users ADD COLUMN name TEXT");}catch{}}}prepareStatements(){this.db&&(this.preparedStatements.set("findUserByEmail",this.db.prepare("SELECT * FROM kyro_users WHERE email = ?")),this.preparedStatements.set("findUserById",this.db.prepare("SELECT * FROM kyro_users WHERE id = ?")),this.preparedStatements.set("findSessionByToken",this.db.prepare("SELECT * FROM kyro_sessions WHERE token = ?")),this.preparedStatements.set("findSessionByRefreshToken",this.db.prepare("SELECT * FROM kyro_sessions WHERE refresh_token = ?")),this.preparedStatements.set("deleteSession",this.db.prepare("DELETE FROM kyro_sessions WHERE id = ? OR token = ?")),this.preparedStatements.set("deleteUserSessions",this.db.prepare("DELETE FROM kyro_sessions WHERE user_id = ?")),this.preparedStatements.set("countUsers",this.db.prepare("SELECT COUNT(*) as count FROM kyro_users")),this.preparedStatements.set("deleteUser",this.db.prepare("DELETE FROM kyro_users WHERE id = ?")),this.preparedStatements.set("findUsersPaginated",this.db.prepare("SELECT * FROM kyro_users ORDER BY created_at DESC LIMIT ? OFFSET ?")),this.preparedStatements.set("findUsersWithSearch",this.db.prepare("SELECT * FROM kyro_users WHERE email LIKE ? ORDER BY created_at DESC LIMIT ? OFFSET ?")),this.preparedStatements.set("countUsersWithSearch",this.db.prepare("SELECT COUNT(*) as count FROM kyro_users WHERE email LIKE ?")),this.preparedStatements.set("getPasswordHistory",this.db.prepare("SELECT password_hash FROM kyro_password_history WHERE user_id = ? ORDER BY created_at DESC LIMIT ?")),this.preparedStatements.set("addPasswordHistory",this.db.prepare("INSERT INTO kyro_password_history (user_id, password_hash, created_at) VALUES (?, ?, ?)")),this.preparedStatements.set("trimPasswordHistory",this.db.prepare(`DELETE FROM kyro_password_history WHERE id IN (
107
+ `);try{this.db.exec("ALTER TABLE kyro_users ADD COLUMN name TEXT");}catch{}try{this.db.exec("ALTER TABLE kyro_users ADD COLUMN avatar TEXT");}catch{}}}prepareStatements(){this.db&&(this.preparedStatements.set("findUserByEmail",this.db.prepare("SELECT * FROM kyro_users WHERE email = ?")),this.preparedStatements.set("findUserById",this.db.prepare("SELECT * FROM kyro_users WHERE id = ?")),this.preparedStatements.set("findSessionByToken",this.db.prepare("SELECT * FROM kyro_sessions WHERE token = ?")),this.preparedStatements.set("findSessionByRefreshToken",this.db.prepare("SELECT * FROM kyro_sessions WHERE refresh_token = ?")),this.preparedStatements.set("deleteSession",this.db.prepare("DELETE FROM kyro_sessions WHERE id = ? OR token = ?")),this.preparedStatements.set("deleteUserSessions",this.db.prepare("DELETE FROM kyro_sessions WHERE user_id = ?")),this.preparedStatements.set("countUsers",this.db.prepare("SELECT COUNT(*) as count FROM kyro_users")),this.preparedStatements.set("deleteUser",this.db.prepare("DELETE FROM kyro_users WHERE id = ?")),this.preparedStatements.set("findUsersPaginated",this.db.prepare("SELECT * FROM kyro_users ORDER BY created_at DESC LIMIT ? OFFSET ?")),this.preparedStatements.set("findUsersWithSearch",this.db.prepare("SELECT * FROM kyro_users WHERE email LIKE ? ORDER BY created_at DESC LIMIT ? OFFSET ?")),this.preparedStatements.set("countUsersWithSearch",this.db.prepare("SELECT COUNT(*) as count FROM kyro_users WHERE email LIKE ?")),this.preparedStatements.set("getPasswordHistory",this.db.prepare("SELECT password_hash FROM kyro_password_history WHERE user_id = ? ORDER BY created_at DESC LIMIT ?")),this.preparedStatements.set("addPasswordHistory",this.db.prepare("INSERT INTO kyro_password_history (user_id, password_hash, created_at) VALUES (?, ?, ?)")),this.preparedStatements.set("trimPasswordHistory",this.db.prepare(`DELETE FROM kyro_password_history WHERE id IN (
108
108
  SELECT id FROM kyro_password_history WHERE user_id = ? ORDER BY created_at DESC LIMIT -1 OFFSET 5
109
109
  )`)),this.preparedStatements.set("deleteExpiredSessions",this.db.prepare("DELETE FROM kyro_sessions WHERE expires_at < ?")),this.preparedStatements.set("cleanupOldAuditLogs",this.db.prepare("DELETE FROM kyro_audit_logs WHERE timestamp < ?")),this.preparedStatements.set("cleanupExpiredLockouts",this.db.prepare("UPDATE kyro_lockouts SET attempts = 0, locked_at = NULL, locked_until = NULL WHERE locked_until < ?")),this.preparedStatements.set("getLockout",this.db.prepare("SELECT * FROM kyro_lockouts WHERE user_id = ?")),this.preparedStatements.set("upsertLockout",this.db.prepare(`
110
110
  INSERT INTO kyro_lockouts (user_id, attempts, last_attempt, locked_at, locked_until)
@@ -114,9 +114,9 @@ import c from'bcryptjs';import {randomBytes}from'crypto';import {mkdirSync}from'
114
114
  last_attempt = excluded.last_attempt,
115
115
  locked_at = excluded.locked_at,
116
116
  locked_until = excluded.locked_until
117
- `)),this.preparedStatements.set("resetLockout",this.db.prepare("UPDATE kyro_lockouts SET attempts = 0, locked_at = NULL, locked_until = NULL WHERE user_id = ?")));}stmt(e){let s=this.preparedStatements.get(e);if(!s)throw new Error(`Prepared statement not found: ${e}`);return s}async cleanupExpiredSessions(){return await this.ensureConnected(),this.stmt("deleteExpiredSessions").run(new Date().toISOString()).changes}async cleanupOldAuditLogs(e=30){await this.ensureConnected();let s=new Date(Date.now()-e*24*60*60*1e3).toISOString();return this.stmt("cleanupOldAuditLogs").run(s).changes}async getStats(){await this.ensureConnected();let e=this.stmt("countUsers").get().count,s=this.db.prepare("SELECT COUNT(*) as count FROM kyro_sessions WHERE expires_at > ?").get(new Date().toISOString()).count,t=this.db.prepare("SELECT COUNT(*) as count FROM kyro_audit_logs").get().count;return {userCount:e,activeSessionCount:s,auditLogCount:t}}async createUser(e){await this.ensureConnected();let s=randomBytes(16).toString("hex"),t=new Date().toISOString(),r=await this.hashPassword(e.password),n={id:s,name:e.name,email:e.email.toLowerCase(),passwordHash:r,role:e.role||"customer",avatar:e.avatar,tenantId:e.tenantId,createdAt:t,updatedAt:t};return this.db.prepare(`INSERT INTO kyro_users (id, name, email, password_hash, role, avatar, tenant_id, created_at, updated_at)
118
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(s,n.name||null,n.email,n.passwordHash,n.role,n.avatar||null,n.tenantId||null,t,t),n}async findUserByEmail(e){await this.ensureConnected();let s=this.stmt("findUserByEmail").get(e.toLowerCase());return s?this.rowToUser(s):null}async findUserById(e){await this.ensureConnected();let s=this.stmt("findUserById").get(e);return s?this.rowToUser(s):null}async updateUser(e,s){if(await this.ensureConnected(),!await this.findUserById(e))return null;let r=[],n=[];return s.email!==void 0&&(r.push("email = ?"),n.push(s.email.toLowerCase())),s.name!==void 0&&(r.push("name = ?"),n.push(s.name)),s.passwordHash!==void 0&&(r.push("password_hash = ?"),n.push(s.passwordHash)),s.role!==void 0&&(r.push("role = ?"),n.push(s.role)),s.avatar!==void 0&&(r.push("avatar = ?"),n.push(s.avatar)),s.tenantId!==void 0&&(r.push("tenant_id = ?"),n.push(s.tenantId)),s.emailVerified!==void 0&&(r.push("email_verified = ?"),n.push(s.emailVerified?1:0)),s.locked!==void 0&&(r.push("locked = ?"),n.push(s.locked?1:0)),s.lastLogin!==void 0&&(r.push("last_login = ?"),n.push(s.lastLogin)),s.failedLoginAttempts!==void 0&&(r.push("failed_login_attempts = ?"),n.push(s.failedLoginAttempts)),r.push("updated_at = ?"),n.push(new Date().toISOString()),n.push(e),this.db.prepare(`UPDATE kyro_users SET ${r.join(", ")} WHERE id = ?`).run(...n),this.findUserById(e)}async deleteUser(e){return await this.ensureConnected(),this.stmt("deleteUser").run(e).changes>0}async hashPassword(e){return c.hash(e,this.saltRounds)}async verifyPassword(e,s){await this.ensureConnected();let t=await this.findUserByEmail(e);if(!t)return null;let r=this.db.prepare("SELECT password_hash FROM kyro_users WHERE id = ?").get(t.id);return r?.password_hash&&await c.compare(s,r.password_hash)?t:null}async createSession(e,s={}){await this.ensureConnected();let t=randomBytes(32).toString("hex"),r=randomBytes(32).toString("base64url"),n=randomBytes(32).toString("base64url"),d=new Date,u=new Date(d.getTime()+864e5).toISOString(),i={id:t,userId:e,token:r,refreshToken:n,expiresAt:u,createdAt:d.toISOString(),ipAddress:s.ipAddress,userAgent:s.userAgent};return this.db.prepare(`INSERT INTO kyro_sessions (id, user_id, token, refresh_token, expires_at, created_at, ip_address, user_agent)
119
- VALUES (?, ?, ?, ?, ?, ?, ?, ?)`).run(i.id,i.userId,i.token,i.refreshToken??null,i.expiresAt,i.createdAt,i.ipAddress??null,i.userAgent??null),i}async findSessionByToken(e){await this.ensureConnected();let s=this.stmt("findSessionByToken").get(e);return s?this.rowToSession(s):null}async findSessionByRefreshToken(e){await this.ensureConnected();let s=this.stmt("findSessionByRefreshToken").get(e);return s?this.rowToSession(s):null}async deleteSession(e){return await this.ensureConnected(),this.stmt("deleteSession").run(e,e).changes>0}async deleteUserSessions(e){return await this.ensureConnected(),this.stmt("deleteUserSessions").run(e).changes}async hasAnyUsers(){return await this.ensureConnected(),this.stmt("countUsers").get().count>0}async findUsers(e={}){await this.ensureConnected();let s=e.page??1,t=e.limit??10,r=(s-1)*t,n=e.search,d,u;if(n){let i=`%${n}%`;d=this.stmt("countUsersWithSearch").get(i).count,u=this.stmt("findUsersWithSearch").all(i,t,r);}else d=this.stmt("countUsers").get().count,u=this.stmt("findUsersPaginated").all(t,r);return {users:u.map(i=>this.rowToUser(i)),total:d}}async addPasswordToHistory(e,s){await this.ensureConnected(),this.stmt("addPasswordHistory").run(e,s,new Date().toISOString()),this.stmt("trimPasswordHistory").run(e);}async getPasswordHistory(e,s=5){return await this.ensureConnected(),this.stmt("getPasswordHistory").all(e,s).map(r=>r.password_hash)}async isPasswordInHistory(e,s,t=5){let r=await this.getPasswordHistory(s,t);for(let n of r)if(await c.compare(e,n))return true;return false}async recordFailedAttempt(e){await this.ensureConnected();let s=Date.now(),t=this.stmt("getLockout").get(e),r=(t?.attempts||0)+1,n=r>=5?s+900*1e3:t?.locked_until||null;this.stmt("upsertLockout").run(e,r,s,n!==null?s:null,n);}async resetAttempts(e){await this.ensureConnected(),this.stmt("resetLockout").run(e);}async checkLockout(e){await this.ensureConnected(),this.stmt("cleanupExpiredLockouts").run(Date.now());let s=this.stmt("getLockout").get(e);return s?s.locked_until!==null&&s.locked_until>Date.now()?{locked:true,attemptsRemaining:0,lockedUntil:new Date(s.locked_until),totalAttempts:s.attempts}:{locked:false,attemptsRemaining:Math.max(0,5-s.attempts),totalAttempts:s.attempts}:{locked:false,attemptsRemaining:5,totalAttempts:0}}async logAudit(e){await this.ensureConnected();let s=randomBytes(16).toString("hex"),t=new Date().toISOString();return this.db.prepare(`INSERT INTO kyro_audit_logs (
117
+ `)),this.preparedStatements.set("resetLockout",this.db.prepare("UPDATE kyro_lockouts SET attempts = 0, locked_at = NULL, locked_until = NULL WHERE user_id = ?")));}stmt(e){let s=this.preparedStatements.get(e);if(!s)throw new Error(`Prepared statement not found: ${e}`);return s}async cleanupExpiredSessions(){return await this.ensureConnected(),this.stmt("deleteExpiredSessions").run(new Date().toISOString()).changes}async cleanupOldAuditLogs(e=30){await this.ensureConnected();let s=new Date(Date.now()-e*24*60*60*1e3).toISOString();return this.stmt("cleanupOldAuditLogs").run(s).changes}async getStats(){await this.ensureConnected();let e=this.stmt("countUsers").get().count,s=this.db.prepare("SELECT COUNT(*) as count FROM kyro_sessions WHERE expires_at > ?").get(new Date().toISOString()).count,t=this.db.prepare("SELECT COUNT(*) as count FROM kyro_audit_logs").get().count;return {userCount:e,activeSessionCount:s,auditLogCount:t}}async createUser(e){await this.ensureConnected();let s=randomBytes(16).toString("hex"),t=new Date().toISOString(),r=await this.hashPassword(e.password),i={id:s,name:e.name,email:e.email.toLowerCase(),passwordHash:r,role:e.role||"customer",avatar:e.avatar,tenantId:e.tenantId,createdAt:t,updatedAt:t};return this.db.prepare(`INSERT INTO kyro_users (id, name, email, password_hash, role, avatar, tenant_id, created_at, updated_at)
118
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(s,i.name||null,i.email,i.passwordHash,i.role,i.avatar||null,i.tenantId||null,t,t),i}async findUserByEmail(e){await this.ensureConnected();let s=this.stmt("findUserByEmail").get(e.toLowerCase());return s?this.rowToUser(s):null}async findUserById(e){await this.ensureConnected();let s=this.stmt("findUserById").get(e);return s?this.rowToUser(s):null}async updateUser(e,s){if(await this.ensureConnected(),!await this.findUserById(e))return null;let r=[],i=[];return s.email!==void 0&&(r.push("email = ?"),i.push(s.email.toLowerCase())),s.name!==void 0&&(r.push("name = ?"),i.push(s.name)),s.passwordHash!==void 0&&(r.push("password_hash = ?"),i.push(s.passwordHash)),s.role!==void 0&&(r.push("role = ?"),i.push(s.role)),s.avatar!==void 0&&(r.push("avatar = ?"),i.push(s.avatar)),s.tenantId!==void 0&&(r.push("tenant_id = ?"),i.push(s.tenantId)),s.emailVerified!==void 0&&(r.push("email_verified = ?"),i.push(s.emailVerified?1:0)),s.locked!==void 0&&(r.push("locked = ?"),i.push(s.locked?1:0)),s.lastLogin!==void 0&&(r.push("last_login = ?"),i.push(s.lastLogin)),s.failedLoginAttempts!==void 0&&(r.push("failed_login_attempts = ?"),i.push(s.failedLoginAttempts)),r.push("updated_at = ?"),i.push(new Date().toISOString()),i.push(e),this.db.prepare(`UPDATE kyro_users SET ${r.join(", ")} WHERE id = ?`).run(...i),this.findUserById(e)}async deleteUser(e){return await this.ensureConnected(),this.stmt("deleteUser").run(e).changes>0}async hashPassword(e){return c.hash(e,this.saltRounds)}async verifyPassword(e,s){await this.ensureConnected();let t=await this.findUserByEmail(e);if(!t)return null;let r=this.db.prepare("SELECT password_hash FROM kyro_users WHERE id = ?").get(t.id);return r?.password_hash&&await c.compare(s,r.password_hash)?t:null}async createSession(e,s={}){await this.ensureConnected();let t=randomBytes(32).toString("hex"),r=randomBytes(32).toString("base64url"),i=randomBytes(32).toString("base64url"),d=new Date,u=new Date(d.getTime()+864e5).toISOString(),n={id:t,userId:e,token:r,refreshToken:i,expiresAt:u,createdAt:d.toISOString(),ipAddress:s.ipAddress,userAgent:s.userAgent};return this.db.prepare(`INSERT INTO kyro_sessions (id, user_id, token, refresh_token, expires_at, created_at, ip_address, user_agent)
119
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)`).run(n.id,n.userId,n.token,n.refreshToken??null,n.expiresAt,n.createdAt,n.ipAddress??null,n.userAgent??null),n}async findSessionByToken(e){await this.ensureConnected();let s=this.stmt("findSessionByToken").get(e);return s?this.rowToSession(s):null}async findSessionByRefreshToken(e){await this.ensureConnected();let s=this.stmt("findSessionByRefreshToken").get(e);return s?this.rowToSession(s):null}async deleteSession(e){return await this.ensureConnected(),this.stmt("deleteSession").run(e,e).changes>0}async deleteUserSessions(e){return await this.ensureConnected(),this.stmt("deleteUserSessions").run(e).changes}async hasAnyUsers(){return await this.ensureConnected(),this.stmt("countUsers").get().count>0}async findUsers(e={}){await this.ensureConnected();let s=e.page??1,t=e.limit??10,r=(s-1)*t,i=e.search,d,u;if(i){let n=`%${i}%`;d=this.stmt("countUsersWithSearch").get(n).count,u=this.stmt("findUsersWithSearch").all(n,t,r);}else d=this.stmt("countUsers").get().count,u=this.stmt("findUsersPaginated").all(t,r);return {users:u.map(n=>this.rowToUser(n)),total:d}}async addPasswordToHistory(e,s){await this.ensureConnected(),this.stmt("addPasswordHistory").run(e,s,new Date().toISOString()),this.stmt("trimPasswordHistory").run(e);}async getPasswordHistory(e,s=5){return await this.ensureConnected(),this.stmt("getPasswordHistory").all(e,s).map(r=>r.password_hash)}async isPasswordInHistory(e,s,t=5){let r=await this.getPasswordHistory(s,t);for(let i of r)if(await c.compare(e,i))return true;return false}async recordFailedAttempt(e){await this.ensureConnected();let s=Date.now(),t=this.stmt("getLockout").get(e),r=(t?.attempts||0)+1,i=r>=5?s+900*1e3:t?.locked_until||null;this.stmt("upsertLockout").run(e,r,s,i!==null?s:null,i);}async resetAttempts(e){await this.ensureConnected(),this.stmt("resetLockout").run(e);}async checkLockout(e){await this.ensureConnected(),this.stmt("cleanupExpiredLockouts").run(Date.now());let s=this.stmt("getLockout").get(e);return s?s.locked_until!==null&&s.locked_until>Date.now()?{locked:true,attemptsRemaining:0,lockedUntil:new Date(s.locked_until),totalAttempts:s.attempts}:{locked:false,attemptsRemaining:Math.max(0,5-s.attempts),totalAttempts:s.attempts}:{locked:false,attemptsRemaining:5,totalAttempts:0}}async logAudit(e){await this.ensureConnected();let s=randomBytes(16).toString("hex"),t=new Date().toISOString();return this.db.prepare(`INSERT INTO kyro_audit_logs (
120
120
  id, timestamp, action, user_id, user_email, role, resource, resource_id,
121
121
  ip_address, user_agent, success, error, metadata, created_at
122
- ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(s,t,e.action,e.userId||null,e.userEmail||null,e.role||null,e.resource,e.resourceId||null,e.ipAddress||null,e.userAgent||null,e.success?1:0,e.error||null,e.metadata?JSON.stringify(e.metadata):null,new Date().toISOString()),s}async queryAuditLogs(e={}){await this.ensureConnected();let s=[],t=[];e.action&&(s.push("action = ?"),t.push(e.action)),e.userId&&(s.push("user_id = ?"),t.push(e.userId)),e.resource&&(s.push("resource = ?"),t.push(e.resource)),e.success!==void 0&&(s.push("success = ?"),t.push(e.success?1:0)),e.startDate&&(s.push("timestamp >= ?"),t.push(e.startDate.toISOString())),e.endDate&&(s.push("timestamp <= ?"),t.push(e.endDate.toISOString()));let r=s.length>0?"WHERE "+s.join(" AND "):"",n=e.limit||50,d=e.offset||0,u=this.db.prepare(`SELECT COUNT(*) as count FROM kyro_audit_logs ${r}`).get(...t),i=this.db.prepare(`SELECT * FROM kyro_audit_logs ${r} ORDER BY timestamp DESC LIMIT ? OFFSET ?`).all(...t,n,d);return {total:u.count,logs:i.map(a=>({id:a.id,timestamp:new Date(a.timestamp),action:a.action,userId:a.user_id||void 0,userEmail:a.user_email||void 0,resource:a.resource,resourceId:a.resource_id||void 0,ipAddress:a.ip_address||void 0,userAgent:a.user_agent||void 0,success:a.success===1,error:a.error||void 0,metadata:a.metadata?JSON.parse(a.metadata):void 0}))}}rowToUser(e){return {id:e.id,name:e.name||void 0,email:e.email,passwordHash:e.password_hash,role:e.role,tenantId:e.tenant_id,avatar:e.avatar,emailVerified:e.email_verified===1,locked:e.locked===1,lastLogin:e.last_login,failedLoginAttempts:e.failed_login_attempts||0,createdAt:e.created_at,updatedAt:e.updated_at}}rowToSession(e){return {id:e.id,userId:e.user_id,token:e.token,refreshToken:e.refresh_token,expiresAt:e.expires_at,createdAt:e.created_at,ipAddress:e.ip_address,userAgent:e.user_agent}}async findAuditLogs(e){let s=await this.queryAuditLogs({action:e.action,userId:e.userId,resource:e.resource,success:e.success,startDate:e.startDate,endDate:e.endDate,limit:e.limit,offset:e.offset});return {logs:s.logs.map(t=>({...t,action:t.action})),total:s.total}}async createAuditLog(e){let s=await this.logAudit({action:e.action,userId:e.userId,userEmail:e.userEmail,role:e.role,resource:e.resource,resourceId:e.resourceId,ipAddress:e.ipAddress,userAgent:e.userAgent,success:e.success,error:e.error,metadata:e.metadata}),t=this.db?.prepare("SELECT * FROM kyro_audit_logs WHERE id = ?").get(s);return {...e,id:s,timestamp:t?new Date(t.timestamp):new Date}}async createEmailVerificationToken(e){await this.ensureConnected();let s=randomBytes(16).toString("hex"),t=randomBytes(32).toString("hex"),r=new Date(Date.now()+1440*60*1e3);return this.db.prepare("INSERT INTO kyro_email_verifications (id, user_id, token, expires_at, created_at) VALUES (?, ?, ?, ?, ?)").run(s,e,t,r.toISOString(),new Date().toISOString()),{token:t,expiresAt:r}}async verifyEmailToken(e){await this.ensureConnected();let s=this.db.prepare("SELECT * FROM kyro_email_verifications WHERE token = ?").get(e);return s?new Date(s.expires_at)<new Date?{success:false,error:"Verification token has expired"}:(this.db.prepare("UPDATE kyro_users SET email_verified = 1 WHERE id = ?").run(s.user_id),this.db.prepare("DELETE FROM kyro_email_verifications WHERE id = ?").run(s.id),{success:true,userId:s.user_id}):{success:false,error:"Invalid verification token"}}async createPasswordResetToken(e){await this.ensureConnected();let s=await this.findUserByEmail(e);if(!s)return {token:"",expiresAt:new Date,error:"User not found"};let t=randomBytes(16).toString("hex"),r=randomBytes(32).toString("hex"),n=new Date(Date.now()+3600*1e3);return this.db.prepare("INSERT INTO kyro_password_resets (id, user_id, token, expires_at, created_at) VALUES (?, ?, ?, ?, ?)").run(t,s.id,r,n.toISOString(),new Date().toISOString()),{token:r,expiresAt:n}}async resetPasswordWithToken(e,s){await this.ensureConnected();let t=this.db.prepare("SELECT * FROM kyro_password_resets WHERE token = ?").get(e);if(!t)return {success:false,error:"Invalid reset token"};if(new Date(t.expires_at)<new Date)return {success:false,error:"Reset token has expired"};if(t.used_at)return {success:false,error:"Reset token has already been used"};let r=await this.hashPassword(s);return this.db.prepare("UPDATE kyro_users SET password_hash = ?, updated_at = ? WHERE id = ?").run(r,new Date().toISOString(),t.user_id),this.db.prepare("UPDATE kyro_password_resets SET used_at = ? WHERE id = ?").run(new Date().toISOString(),t.id),this.db.prepare("DELETE FROM kyro_sessions WHERE user_id = ?").run(t.user_id),{success:true}}};export{E as a};
122
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(s,t,e.action,e.userId||null,e.userEmail||null,e.role||null,e.resource,e.resourceId||null,e.ipAddress||null,e.userAgent||null,e.success?1:0,e.error||null,e.metadata?JSON.stringify(e.metadata):null,new Date().toISOString()),s}async queryAuditLogs(e={}){await this.ensureConnected();let s=[],t=[];e.action&&(s.push("action = ?"),t.push(e.action)),e.userId&&(s.push("user_id = ?"),t.push(e.userId)),e.resource&&(s.push("resource = ?"),t.push(e.resource)),e.success!==void 0&&(s.push("success = ?"),t.push(e.success?1:0)),e.startDate&&(s.push("timestamp >= ?"),t.push(e.startDate.toISOString())),e.endDate&&(s.push("timestamp <= ?"),t.push(e.endDate.toISOString()));let r=s.length>0?"WHERE "+s.join(" AND "):"",i=e.limit||50,d=e.offset||0,u=this.db.prepare(`SELECT COUNT(*) as count FROM kyro_audit_logs ${r}`).get(...t),n=this.db.prepare(`SELECT * FROM kyro_audit_logs ${r} ORDER BY timestamp DESC LIMIT ? OFFSET ?`).all(...t,i,d);return {total:u.count,logs:n.map(a=>({id:a.id,timestamp:new Date(a.timestamp),action:a.action,userId:a.user_id||void 0,userEmail:a.user_email||void 0,resource:a.resource,resourceId:a.resource_id||void 0,ipAddress:a.ip_address||void 0,userAgent:a.user_agent||void 0,success:a.success===1,error:a.error||void 0,metadata:a.metadata?JSON.parse(a.metadata):void 0}))}}rowToUser(e){return {id:e.id,name:e.name||void 0,email:e.email,passwordHash:e.password_hash,role:e.role,tenantId:e.tenant_id,avatar:e.avatar,emailVerified:e.email_verified===1,locked:e.locked===1,lastLogin:e.last_login,failedLoginAttempts:e.failed_login_attempts||0,createdAt:e.created_at,updatedAt:e.updated_at}}rowToSession(e){return {id:e.id,userId:e.user_id,token:e.token,refreshToken:e.refresh_token,expiresAt:e.expires_at,createdAt:e.created_at,ipAddress:e.ip_address,userAgent:e.user_agent}}async findAuditLogs(e){let s=await this.queryAuditLogs({action:e.action,userId:e.userId,resource:e.resource,success:e.success,startDate:e.startDate,endDate:e.endDate,limit:e.limit,offset:e.offset});return {logs:s.logs.map(t=>({...t,action:t.action})),total:s.total}}async createAuditLog(e){let s=await this.logAudit({action:e.action,userId:e.userId,userEmail:e.userEmail,role:e.role,resource:e.resource,resourceId:e.resourceId,ipAddress:e.ipAddress,userAgent:e.userAgent,success:e.success,error:e.error,metadata:e.metadata}),t=this.db?.prepare("SELECT * FROM kyro_audit_logs WHERE id = ?").get(s);return {...e,id:s,timestamp:t?new Date(t.timestamp):new Date}}async createEmailVerificationToken(e){await this.ensureConnected();let s=randomBytes(16).toString("hex"),t=randomBytes(32).toString("hex"),r=new Date(Date.now()+1440*60*1e3);return this.db.prepare("INSERT INTO kyro_email_verifications (id, user_id, token, expires_at, created_at) VALUES (?, ?, ?, ?, ?)").run(s,e,t,r.toISOString(),new Date().toISOString()),{token:t,expiresAt:r}}async verifyEmailToken(e){await this.ensureConnected();let s=this.db.prepare("SELECT * FROM kyro_email_verifications WHERE token = ?").get(e);return s?new Date(s.expires_at)<new Date?{success:false,error:"Verification token has expired"}:(this.db.prepare("UPDATE kyro_users SET email_verified = 1 WHERE id = ?").run(s.user_id),this.db.prepare("DELETE FROM kyro_email_verifications WHERE id = ?").run(s.id),{success:true,userId:s.user_id}):{success:false,error:"Invalid verification token"}}async createPasswordResetToken(e){await this.ensureConnected();let s=await this.findUserByEmail(e);if(!s)return {token:"",expiresAt:new Date,error:"User not found"};let t=randomBytes(16).toString("hex"),r=randomBytes(32).toString("hex"),i=new Date(Date.now()+3600*1e3);return this.db.prepare("INSERT INTO kyro_password_resets (id, user_id, token, expires_at, created_at) VALUES (?, ?, ?, ?, ?)").run(t,s.id,r,i.toISOString(),new Date().toISOString()),{token:r,expiresAt:i}}async resetPasswordWithToken(e,s){await this.ensureConnected();let t=this.db.prepare("SELECT * FROM kyro_password_resets WHERE token = ?").get(e);if(!t)return {success:false,error:"Invalid reset token"};if(new Date(t.expires_at)<new Date)return {success:false,error:"Reset token has expired"};if(t.used_at)return {success:false,error:"Reset token has already been used"};let r=await this.hashPassword(s);return this.db.prepare("UPDATE kyro_users SET password_hash = ?, updated_at = ? WHERE id = ?").run(r,new Date().toISOString(),t.user_id),this.db.prepare("UPDATE kyro_password_resets SET used_at = ? WHERE id = ?").run(new Date().toISOString(),t.id),this.db.prepare("DELETE FROM kyro_sessions WHERE user_id = ?").run(t.user_id),{success:true}}};export{E as a};
@@ -0,0 +1 @@
1
+ import h from'bcryptjs';import {randomUUID,randomBytes}from'crypto';var w=class{db;prefix;sessionTTL;refreshTokenTTL;indexesEnsured=false;constructor(e){this.db=e.db,this.prefix=e.collectionPrefix||"",this.sessionTTL=e.sessionTTL||86400,this.refreshTokenTTL=e.refreshTokenTTL||604800;}getDatabase(){if(typeof this.db=="function"){let e=this.db();if(!e)throw new Error("MongoDB database not initialized");return e}if(!this.db)throw new Error("MongoDB database not initialized");return this.db}col(e){return this.getDatabase().collection(`${this.prefix}${e}`)}async connect(){this.indexesEnsured||await this.ensureIndexes();}async disconnect(){}async ensureIndexes(){await this.col("users").createIndex({email:1},{unique:true}),await this.col("users").createIndex({tenantId:1}),await this.col("users").createIndex({role:1}),await this.col("sessions").createIndex({token:1},{unique:true}),await this.col("sessions").createIndex({refreshToken:1}),await this.col("sessions").createIndex({userId:1}),await this.col("sessions").createIndex({expiresAt:1},{expireAfterSeconds:0}),await this.col("audit_logs").createIndex({timestamp:-1}),await this.col("audit_logs").createIndex({userId:1}),await this.col("audit_logs").createIndex({action:1}),await this.col("audit_logs").createIndex({resource:1}),await this.col("password_history").createIndex({userId:1,createdAt:-1}),await this.col("lockouts").createIndex({userId:1},{unique:true}),await this.col("lockouts").createIndex({lockedUntil:1}),this.indexesEnsured=true;}async createUser(e){let s=randomUUID(),t=new Date,i=await this.hashPassword(e.password),n={_id:s,name:e.name||null,email:e.email.toLowerCase(),passwordHash:i,role:e.role||"customer",avatar:e.avatar||null,tenantId:e.tenantId||null,emailVerified:false,locked:false,lastLogin:null,failedLoginAttempts:0,createdAt:t,updatedAt:t};return await this.col("users").insertOne(n),this.docToAuthUser(n)}async findUserByEmail(e){let s=await this.col("users").findOne({email:e.toLowerCase()});return s?this.docToAuthUser(s):null}async findUserById(e){let s=await this.col("users").findOne({_id:e});return s?this.docToAuthUser(s):null}async updateUser(e,s){let t={updatedAt:new Date};s.name!==void 0&&(t.name=s.name),s.email!==void 0&&(t.email=s.email),s.passwordHash!==void 0&&(t.passwordHash=s.passwordHash),s.role!==void 0&&(t.role=s.role),s.avatar!==void 0&&(t.avatar=s.avatar),s.tenantId!==void 0&&(t.tenantId=s.tenantId),s.emailVerified!==void 0&&(t.emailVerified=s.emailVerified),s.locked!==void 0&&(t.locked=s.locked),s.lastLogin!==void 0&&(t.lastLogin=s.lastLogin?new Date(s.lastLogin):null),s.failedLoginAttempts!==void 0&&(t.failedLoginAttempts=s.failedLoginAttempts);let i=await this.col("users").findOneAndUpdate({_id:e},{$set:t},{returnDocument:"after"});return i?this.docToAuthUser(i):null}async deleteUser(e){return (await this.col("users").deleteOne({_id:e})).deletedCount>0}async verifyPassword(e,s){let t=await this.findUserByEmail(e);if(!t)return null;let i=await this.col("users").findOne({email:e.toLowerCase()},{projection:{passwordHash:1}});return i?.passwordHash&&await h.compare(s,i.passwordHash)?t:null}async hashPassword(e){return h.hash(e,12)}async createSession(e,s){let t=randomUUID(),i=randomBytes(32).toString("base64url"),n=randomBytes(32).toString("base64url"),a=new Date,u=new Date(a.getTime()+this.sessionTTL*1e3),d={_id:t,userId:e,token:i,refreshToken:n,ipAddress:s?.ipAddress||null,userAgent:s?.userAgent||null,expiresAt:u,createdAt:a};return await this.col("sessions").insertOne(d),this.docToSession(d)}async findSessionByToken(e){let s=await this.col("sessions").findOne({token:e,expiresAt:{$gt:new Date}});return s?this.docToSession(s):null}async findSessionByRefreshToken(e){let s=await this.col("sessions").findOne({refreshToken:e,expiresAt:{$gt:new Date}});return s?this.docToSession(s):null}async deleteSession(e){return (await this.col("sessions").deleteOne({_id:e})).deletedCount>0}async deleteUserSessions(e){return (await this.col("sessions").deleteMany({userId:e})).deletedCount}async hasAnyUsers(){return await this.col("users").countDocuments()>0}async addPasswordToHistory(e,s){await this.col("password_history").insertOne({userId:e,passwordHash:s,createdAt:new Date});}async getPasswordHistory(e,s=5){return (await this.col("password_history").find({userId:e}).sort({createdAt:-1}).limit(s).toArray()).map(i=>i.passwordHash)}async isPasswordInHistory(e,s,t=5){let i=await this.getPasswordHistory(s,t);for(let n of i)if(await h.compare(e,n))return true;return false}async findAuditLogs(e){let{limit:s=50,offset:t=0,userId:i,action:n,resource:a,resourceId:u,success:d,startDate:c,endDate:f}=e,o={};i&&(o.userId=i),n&&(Array.isArray(n)?o.action={$in:n}:o.action=n),a&&(o.resource=a),u&&(o.resourceId=u),d!==void 0&&(o.success=d),(c||f)&&(o.timestamp={},c&&(o.timestamp.$gte=c),f&&(o.timestamp.$lte=f));let g=await this.col("audit_logs").countDocuments(o);return {logs:(await this.col("audit_logs").find(o).sort({timestamp:-1}).skip(t).limit(s).toArray()).map(r=>({id:r._id,timestamp:r.timestamp,action:r.action,userId:r.userId||void 0,userEmail:r.userEmail||void 0,role:r.role||void 0,resource:r.resource,resourceId:r.resourceId||void 0,changes:r.changes||void 0,ipAddress:r.ipAddress||void 0,userAgent:r.userAgent||void 0,success:r.success,error:r.error||void 0,metadata:r.metadata||void 0})),total:g}}async createAuditLog(e){let s=randomUUID(),t=new Date;return await this.col("audit_logs").insertOne({_id:s,action:e.action,userId:e.userId||null,userEmail:e.userEmail||null,role:e.role||null,resource:e.resource,resourceId:e.resourceId||null,changes:e.changes||null,ipAddress:e.ipAddress||null,userAgent:e.userAgent||null,success:e.success,error:e.error||null,metadata:e.metadata||null,timestamp:t}),{...e,id:s,timestamp:t}}docToAuthUser(e){return {id:e._id,name:e.name||void 0,email:e.email,passwordHash:e.passwordHash||void 0,role:e.role,tenantId:e.tenantId||void 0,avatar:e.avatar||void 0,emailVerified:e.emailVerified||false,locked:e.locked||false,lastLogin:e.lastLogin?.toISOString?.()||e.lastLogin||void 0,failedLoginAttempts:e.failedLoginAttempts||0,createdAt:e.createdAt?.toISOString?.()||e.createdAt,updatedAt:e.updatedAt?.toISOString?.()||e.updatedAt}}docToSession(e){return {id:e._id,userId:e.userId,token:e.token,refreshToken:e.refreshToken||void 0,expiresAt:e.expiresAt?.toISOString?.()||e.expiresAt,createdAt:e.createdAt?.toISOString?.()||e.createdAt,ipAddress:e.ipAddress||void 0,userAgent:e.userAgent||void 0}}async createEmailVerificationToken(e){let s=randomBytes(32).toString("hex"),t=new Date(Date.now()+1440*60*1e3);return await this.db.collection("email_verifications").insertOne({userId:new(await import('mongodb')).ObjectId(e),token:s,expiresAt:t,createdAt:new Date}),{token:s,expiresAt:t}}async verifyEmailToken(e){let s=await this.db.collection("email_verifications").findOne({token:e});return s?s.expiresAt<new Date?{success:false,error:"Verification token has expired"}:(await this.db.collection("users").updateOne({_id:s.userId},{$set:{emailVerified:true}}),await this.db.collection("email_verifications").deleteOne({_id:s._id}),{success:true,userId:s.userId.toString()}):{success:false,error:"Invalid verification token"}}async createPasswordResetToken(e){let s=await this.findUserByEmail(e);if(!s)return {token:"",expiresAt:new Date,error:"User not found"};let t=randomBytes(32).toString("hex"),i=new Date(Date.now()+3600*1e3);return await this.db.collection("password_resets").insertOne({userId:new(await import('mongodb')).ObjectId(s.id),token:t,expiresAt:i,createdAt:new Date}),{token:t,expiresAt:i}}async resetPasswordWithToken(e,s){let t=await this.db.collection("password_resets").findOne({token:e});if(!t)return {success:false,error:"Invalid reset token"};if(t.expiresAt<new Date)return {success:false,error:"Reset token has expired"};if(t.usedAt)return {success:false,error:"Reset token has already been used"};let i=await this.hashPassword(s);return await this.db.collection("users").updateOne({_id:t.userId},{$set:{passwordHash:i,updatedAt:new Date}}),await this.db.collection("password_resets").updateOne({_id:t._id},{$set:{usedAt:new Date}}),await this.db.collection("sessions").deleteMany({userId:t.userId}),{success:true}}};export{w as a};
@@ -0,0 +1,133 @@
1
+ import {a,c,b,d}from'./chunk-TQNM4C7H.js';import {a as a$1}from'./chunk-6SPPR5JZ.js';import {sql,eq,desc,and,or,ne,inArray,like,gt,gte,lt,lte}from'drizzle-orm';import {text,uuid,jsonb,timestamp,boolean,decimal,integer as integer$1,varchar,pgTable}from'drizzle-orm/pg-core';import {text as text$1,integer,numeric,sqliteTable}from'drizzle-orm/sqlite-core';import {drizzle}from'drizzle-orm/postgres-js';import le from'postgres';import {randomBytes}from'crypto';import {mkdir}from'fs/promises';import {resolve,dirname}from'path';import {createRequire}from'module';var j=false;function _(f){if(typeof f!="string")return f;let t=f.replace(/-/g,"").toLowerCase();return t.length===32?`${t.slice(0,8)}-${t.slice(8,12)}-${t.slice(12,16)}-${t.slice(16,20)}-${t.slice(20)}`:f}function L(f,t="postgres"){switch(f.type){case "text":case "email":case "password":case "color":case "icon":return t==="sqlite"?"text":"varchar";case "textarea":case "code":case "markdown":case "secret":return "text";case "number":return f.integer?"integer":"decimal";case "checkbox":return "boolean";case "date":return "timestamp";case "select":case "radio":return t==="sqlite"?"text":"varchar";case "richtext":case "json":case "array":case "group":case "blocks":case "row":case "collapsible":case "tabs":return "jsonb";case "relationship":return t==="sqlite"?"text":"varchar";case "upload":return "jsonb";default:return "jsonb"}}function we(f,t="postgres"){let i=f.slug.replace(/-/g,"_"),e=[];e.push(`export const ${i} = pgTable('${i}', {`),e.push(" id: uuid('id').primaryKey().defaultRandom(),");for(let s of f.fields){if(s.name==="id")continue;let a=L(s,t),r=s.required,n=` ${s.name}: pg.${a}('${s.name}')`;s.unique&&(n+=".unique()"),r||(n+=".nullable()"),s.defaultValue!==void 0&&(typeof s.defaultValue=="string"?n+=`.default('${s.defaultValue}')`:typeof s.defaultValue=="boolean"?n+=`.default(${s.defaultValue})`:n+=`.default(sql\`${JSON.stringify(s.defaultValue)}\`)`),n+=",",e.push(n);}return f.timestamps&&(e.push(" createdAt: pg.timestamp('created_at').defaultNow(),"),e.push(" updatedAt: pg.timestamp('updated_at').defaultNow(),")),e.push(` status: ${t==="sqlite"?"sqlite":"pg"}.varchar('status').default('draft'),`),e.push(` hasDraft: ${t==="sqlite"?"sqlite":"pg"}.boolean('hasDraft').default(false),`),e.push("});"),e.join(`
2
+ `)}function B(f,t){return Array.isArray(f)?f.map(i=>{if(!i||typeof i!="object")return i;let e=i.data?{...i.data}:void 0;if(!e)return i;let s=t.find(a=>a.slug===i.type||a.slug===i.slug);if(!s||!Array.isArray(s.fields))return i;for(let a of s.fields){if(a.name&&(a.type==="upload"||a.type==="image")&&e[a.name]){let r=e[a.name];Array.isArray(r)?e[a.name]=r.map(n=>typeof n=="string"?{id:n}:n):typeof r=="string"&&(e[a.name]={id:r});}if(a.type==="blocks"&&a.name&&e[a.name]){let r=a.blocks||[];e[a.name]=B(e[a.name],r);}}return {...i,data:e}}):f}var v=class extends a{client;schema;dialect;connectionString;versionsTableReady=false;constructor(t){if(super(),this.schema=t.schema||{},t.connectionString){this.connectionString=t.connectionString;let i=t.connectionString.toLowerCase();i.startsWith("postgres://")||i.startsWith("postgresql://")?this.dialect="postgres":i.includes(".db")||i.includes("sqlite")||i.includes("file:")?this.dialect="sqlite":this.dialect=t.type||"postgres";}else this.client=t.client,this.dialect=t.type||"sqlite";}prepareData(t,i){let e=super.prepareData(t,i);e.createdAt&&typeof e.createdAt=="string"&&(e.createdAt=new Date(e.createdAt)),e.updatedAt&&typeof e.updatedAt=="string"&&(e.updatedAt=new Date(e.updatedAt));for(let s of i.fields)if(s.type==="date"&&s.name){let a=e[s.name];a&&typeof a=="string"&&(e[s.name]=new Date(a));}for(let s of i.fields){let r=L(s,this.dialect)==="jsonb";if(s.type==="tabs"&&"tabs"in s&&s.name){let n=t[s.name];if(n&&typeof n=="object"){let o={};for(let[c,d]of Object.entries(n)){let u=s.tabs.flatMap(g=>g.fields).find(g=>g.name===c);(u?.type==="upload"||u?.type==="image"||u?.type==="list"||u?.type==="relationship-block")&&d?o[c]=Array.isArray(d)||typeof d=="object"?JSON.stringify(d):d:o[c]=d;}e[s.name]=this.dialect==="sqlite"||!r?JSON.stringify(o):o;}}else if(r&&s.name&&t[s.name]!==void 0&&t[s.name]!==null)e[s.name]=this.dialect==="sqlite"?JSON.stringify(t[s.name]):t[s.name];else if((s.type==="upload"||s.type==="image"||s.type==="list"||s.type==="relationship-block")&&s.name){let n=t[s.name];n!=null&&(e[s.name]=this.dialect==="sqlite"||!r?typeof n=="string"?n:JSON.stringify(n):n);}}for(let s of i.fields)if(s.name&&e[s.name]===""){let a=L(s,this.dialect);(a==="timestamp"||a==="jsonb"||a==="decimal"||a==="integer"||a==="numeric"||a==="boolean")&&(e[s.name]=null);}return e}async connect(){if(this.connectionString&&!this.client){if(this.dialect==="postgres"){let t,i;try{t=(await import('postgres')).default,i=(await import('drizzle-orm/postgres-js')).drizzle;}catch{a$1(["postgres","drizzle-orm"]),t=(await import('postgres')).default,i=(await import('drizzle-orm/postgres-js')).drizzle;}let e=t(this.connectionString,{onnotice:()=>{}});this.client=i(e,{schema:this.schema});}else if(this.dialect==="sqlite"){let t,i;try{t=(await import('better-sqlite3')).default,i=(await import('drizzle-orm/better-sqlite3')).drizzle;}catch{a$1(["better-sqlite3","drizzle-orm"]),t=(await import('better-sqlite3')).default,i=(await import('drizzle-orm/better-sqlite3')).drizzle;}let e=new t(this.connectionString.replace("file:",""));this.client=i(e,{schema:this.schema});}}this.connected=true;}async init(t,i=[]){if(await super.init(t,i),this.connectionString&&!this.client&&await this.connect(),this.client&&!j){for(let s of t){let a=this.getTableName(s.slug);this.schema[a]||(this.schema[a]=this.createTableFromConfig(s));}await this.ensureCollectionTables(t);let e=i.map(s=>({slug:`_globals_${s.slug}`,fields:s.fields,label:s.label}));for(let s of e){let a=this.getTableName(s.slug);this.schema[a]||(this.schema[a]=this.createTableFromConfig(s,true)),this.collections.has(s.slug)||this.collections.set(s.slug,s);}await this.ensureCollectionTables(e),j=true;}}createTableFromConfig(t,i=false){let e=this.getTableName(t.slug),s={id:i?text("id").primaryKey():uuid("id").primaryKey().defaultRandom()};for(let a of t.fields){if(!a.name||a.name==="id")continue;let r=L(a,this.dialect),n=a.name.replace(/-/g,"_"),o=n.replace(/([A-Z])/g,"_$1").toLowerCase(),c;if(this.dialect==="sqlite")switch(r){case "varchar":case "text":c=text$1(o);break;case "integer":c=integer(o);break;case "decimal":case "numeric":c=numeric(o);break;case "boolean":c=integer(o,{mode:"boolean"});break;case "timestamp":c=text$1(o);break;case "jsonb":c=text$1(o);break;default:c=text$1(o);}else switch(r){case "varchar":c=varchar(o,{length:255});break;case "integer":c=integer$1(o);break;case "decimal":c=decimal(o);break;case "boolean":c=boolean(o);break;case "timestamp":c=timestamp(o);break;case "jsonb":c=jsonb(o);break;default:c=text(o);}a.required||(c=c.default(null)),s[n]=c;}return s.createdAt||(s.createdAt=this.dialect==="sqlite"?text$1("created_at").default(new Date().toISOString()):timestamp("created_at").defaultNow()),s.updatedAt||(s.updatedAt=this.dialect==="sqlite"?text$1("updated_at").default(new Date().toISOString()):timestamp("updated_at").defaultNow()),e!=="users"&&e!=="audit_logs"&&(s.status||(s.status=this.dialect==="sqlite"?text$1("status").default("draft"):varchar("status",{length:20}).default("draft")),s.hasDraft||(s.hasDraft=this.dialect==="sqlite"?integer("hasDraft",{mode:"boolean"}).default(false):boolean("hasDraft").default(false))),this.dialect==="sqlite"?sqliteTable(e,s):pgTable(e,s)}async ensureCollectionTables(t){let i=[];for(let e of t){let s=e.slug.startsWith("_globals_"),a=this.getTableName(e.slug),r=this.generateCreateColumns(e),n=e.fields.some(u=>u.name==="createdAt"),o=e.fields.some(u=>u.name==="updatedAt"),c=e.fields.some(u=>u.name==="status"),d=e.fields.some(u=>u.name==="hasDraft");if(this.dialect==="postgres"){let u=s?'"id" TEXT PRIMARY KEY':'"id" UUID PRIMARY KEY DEFAULT gen_random_uuid()';i.push(`
3
+ CREATE TABLE IF NOT EXISTS "${a}" (
4
+ ${u},
5
+ ${r}
6
+ ${n?"":'"created_at" TIMESTAMP NOT NULL DEFAULT NOW(),'}
7
+ ${o?"":'"updated_at" TIMESTAMP NOT NULL DEFAULT NOW(),'}
8
+ ${c?"":`"status" VARCHAR(20) DEFAULT 'draft',`}
9
+ ${d?"":'"hasDraft" BOOLEAN DEFAULT false'}
10
+ )
11
+ `);}else i.push(`
12
+ CREATE TABLE IF NOT EXISTS "${a}" (
13
+ "id" TEXT PRIMARY KEY,
14
+ ${r}
15
+ ${n?"":`"created_at" TEXT NOT NULL DEFAULT (datetime('now')),`}
16
+ ${o?"":`"updated_at" TEXT NOT NULL DEFAULT (datetime('now')),`}
17
+ ${c?"":`"status" TEXT DEFAULT 'draft',`}
18
+ ${d?"":'"hasDraft" INTEGER DEFAULT 0'}
19
+ )
20
+ `);}if(i.length>0)if(this.dialect==="postgres")await this.client.execute(sql.raw(i.join(`;
21
+ `)));else for(let e of i)await this.client.execute(sql.raw(e));for(let e of t){let s=this.getTableName(e.slug);s==="users"||s==="audit_logs"||await this.syncTableColumns(e,s);}}getColumnSqlDefinition(t,i){let e=L(t,i),s=t.name.replace(/-/g,"_").replace(/([A-Z])/g,"_$1").toLowerCase(),a=this.columnSqlType(e,i);return `"${s}" ${a} DEFAULT NULL`}columnSqlType(t,i){if(i==="sqlite")switch(t){case "varchar":return "TEXT";case "text":return "TEXT";case "integer":return "INTEGER";case "decimal":case "numeric":return "NUMERIC";case "boolean":return "INTEGER";case "timestamp":return "TEXT";case "jsonb":return "TEXT";default:return "TEXT"}switch(t){case "varchar":return "VARCHAR(255)";case "text":return "TEXT";case "integer":return "INTEGER";case "decimal":case "numeric":return "DECIMAL";case "boolean":return "BOOLEAN";case "timestamp":return "TIMESTAMP";case "jsonb":return "JSONB";default:return "TEXT"}}getExpectedColumnDefs(t,i){let e={},s=t.slug.startsWith("_globals_"),a=t.fields.some(c=>c.name==="createdAt"),r=t.fields.some(c=>c.name==="updatedAt"),n=t.fields.some(c=>c.name==="status"),o=t.fields.some(c=>c.name==="hasDraft");this.dialect==="postgres"?(e.id=s?'"id" TEXT PRIMARY KEY':'"id" UUID PRIMARY KEY DEFAULT gen_random_uuid()',a||(e.created_at='"created_at" TIMESTAMP DEFAULT NULL'),r||(e.updated_at='"updated_at" TIMESTAMP DEFAULT NULL'),n||(e.status='"status" VARCHAR(20) DEFAULT NULL'),o||(e.hasDraft='"hasDraft" BOOLEAN DEFAULT NULL')):(e.id='"id" TEXT PRIMARY KEY',a||(e.created_at='"created_at" TEXT DEFAULT NULL'),r||(e.updated_at='"updated_at" TEXT DEFAULT NULL'),n||(e.status='"status" TEXT DEFAULT NULL'),o||(e.hasDraft='"hasDraft" INTEGER DEFAULT NULL'));for(let c of t.fields){if(!c.name||c.name==="id")continue;let d=this.getColumnSqlDefinition(c,this.dialect),u=c.name.replace(/-/g,"_").replace(/([A-Z])/g,"_$1").toLowerCase();e[u]=d;}return e}async syncTableColumns(t,i){let e;try{if(this.dialect==="postgres"){let r=await this.client.execute(sql`SELECT column_name, data_type, character_maximum_length FROM information_schema.columns WHERE table_name = ${i}`);e=new Map(r.map(n=>[n.column_name,{type:n.data_type,maxLen:n.character_maximum_length}]));}else {let r=await this.client.execute(sql`PRAGMA table_info("${sql.raw(i)}")`);e=new Map(r.map(n=>[n.name,{type:n.type,maxLen:null}]));}}catch{return}let s=this.getExpectedColumnDefs(t,i),a=Object.keys(s).filter(r=>!e.has(r));if(a.length>0){let r=a.map(n=>`ALTER TABLE "${i}" ADD COLUMN ${s[n]}`);await this.executeRaw(sql.raw(r.join(`;
22
+ `)));}if(this.dialect==="postgres")for(let r of t.fields){if(!r.name||r.name==="id")continue;let n=L(r,this.dialect),o=r.name.replace(/-/g,"_").replace(/([A-Z])/g,"_$1").toLowerCase(),c=e.get(o);!c||c.type!=="character varying"||(n==="text"?await this.executeRaw(sql.raw(`ALTER TABLE "${i}" ALTER COLUMN "${o}" TYPE TEXT`)):n==="jsonb"&&(await this.executeRaw(sql.raw(`ALTER TABLE "${i}" ALTER COLUMN "${o}" DROP DEFAULT`)),await this.executeRaw(sql.raw(`ALTER TABLE "${i}" ALTER COLUMN "${o}" TYPE JSONB USING (CASE WHEN "${o}" IS NULL THEN NULL WHEN "${o}"::text ~ '^\\s*\\{' THEN "${o}"::jsonb ELSE jsonb_build_object('id', "${o}"::text) END)`))));}}generateCreateColumns(t){let i=[];for(let e of t.fields){if(!e.name||e.name==="id")continue;let s=L(e,this.dialect),a=e.name.replace(/-/g,"_").replace(/([A-Z])/g,"_$1").toLowerCase(),r=e.required?"NOT NULL":"DEFAULT NULL",n;if(this.dialect==="sqlite")switch(s){case "varchar":case "text":n=`TEXT ${r}`;break;case "integer":n=`INTEGER ${r}`;break;case "decimal":case "numeric":n=`NUMERIC ${r}`;break;case "boolean":n=`INTEGER ${r}`;break;case "timestamp":n=`TEXT ${r}`;break;case "jsonb":n=`TEXT ${r}`;break;default:n=`TEXT ${r}`;}else switch(s){case "varchar":n=`VARCHAR(255) ${r}`;break;case "integer":n=`INTEGER ${r}`;break;case "decimal":n=`DECIMAL ${r}`;break;case "boolean":n=`BOOLEAN ${r}`;break;case "timestamp":n=`TIMESTAMP ${r}`;break;case "jsonb":n=`JSONB ${r}`;break;default:n=`TEXT ${r}`;}i.push(`"${a}" ${n}`);}return i.join(`,
23
+ `)+(i.length>0?",":"")}async disconnect(){this.connected=false;}async find(t){let{collection:i,where:e={},sort:s,limit:a=10,page:r=1,tenantId:n,select:o,draft:c$1}=t,d$1=this.getCollection(i),u=this.getTable(i),h={...e};this.tenantContext&&d$1.tenantScoped&&(h=c({where:h},i,this.tenantContext,b).where||{});let g=this.buildWhereClause(h,d$1,u,n),y=d$1.fields.find(m=>m.name==="status"),p=y?.type==="select"&&Array.isArray(y.options)&&y.options.some(m=>m.value==="published");!c$1&&u.status&&p&&g.push(eq(u.status,"published"));let A=this.parseSort(s),w=!c$1&&u.status&&p?{...h,status:"published"}:h,W=await this.count({collection:i,where:w,tenantId:n}),V=(r-1)*a,O=[];try{let m=u[A.field]||u.createdAt||u.id,R=A.direction==="asc"?m:desc(m),E=this.client.select().from(u);g.length>0&&(E=E.where(and(...g))),O=await E.orderBy(R).limit(a).offset(V);}catch(m){console.error("[DrizzleAdapter] Query error:",m);}let N=O.map(m=>this.processResult(m,d$1));return this.tenantContext&&!this.tenantContext.isSuperAdmin&&(N=N.filter(m=>d(m,i,this.tenantContext,b))),c$1&&(N=await Promise.all(N.map(async m=>{let R=await this.executeRaw(sql`
24
+ SELECT * FROM kyro_versions
25
+ WHERE collection_slug = ${i}
26
+ AND document_id = ${m.id}
27
+ ORDER BY created_at DESC
28
+ LIMIT 1
29
+ `);if(R.length>0){let E=R[0],z=typeof E.data=="string"?JSON.parse(E.data):E.data;return {...m,...z,status:m.status}}return m}))),{docs:N,...this.calculatePagination(r,a,W)}}async findByID(t){let{collection:i,id:e,tenantId:s,draft:a}=t,r=this.getCollection(i),n=this.getTable(i),o=this.dialect==="postgres"&&typeof e=="string"?_(e):e;if(this.tenantContext&&r.tenantScoped){let p={id:o,tenantId:this.tenantContext.tenantId};if(!d(p,i,this.tenantContext,b))return null}let c=[eq(n.id,o)];s&&n.tenantId&&c.push(eq(n.tenantId,s));let d$1=r.fields.find(p=>p.name==="status"),u=d$1?.type==="select"&&Array.isArray(d$1.options)&&d$1.options.some(p=>p.value==="published");!a&&n.status&&u&&c.push(eq(n.status,"published"));let h=c.length>1?and(...c):c[0],g=await this.client.select().from(n).where(h);if(g.length===0)return null;let y=this.processResult(g[0],r);if(a){let p=await this.executeRaw(sql`
30
+ SELECT * FROM kyro_versions
31
+ WHERE collection_slug = ${i}
32
+ AND document_id = ${y.id}
33
+ ORDER BY created_at DESC
34
+ LIMIT 1
35
+ `);if(p.length>0){let A=p[0],w=typeof A.data=="string"?JSON.parse(A.data):A.data;y={...y,...w,status:y.status};}}return y}async create(t){let{collection:i,data:e,tenantId:s}=t,a=this.getCollection(i),r=this.getTable(i),n=this.prepareData(e,a);s&&a.tenantScoped&&(n.tenantId=s);let o=await this.client.insert(r).values(n).returning();return this.processResult(o[0],a)}async update(t){let{collection:i,id:e,data:s,tenantId:a}=t,r=this.getCollection(i),n=this.getTable(i),o=this.prepareData(s,r),c=this.dialect==="postgres"&&typeof e=="string"?_(e):e,d=[eq(n.id,c)];a&&n.tenantId&&d.push(eq(n.tenantId,a));let u=await this.client.update(n).set(o).where(and(...d)).returning();if(u.length===0)throw new Error(`Document not found: ${i}/${e}`);return this.processResult(u[0],r)}async delete(t){let{collection:i,id:e,tenantId:s}=t,a=this.getCollection(i),r=this.getTable(i),n=this.dialect==="postgres"&&typeof e=="string"?_(e):e,o=[eq(r.id,n)];s&&r.tenantId&&o.push(eq(r.tenantId,s));let c=await this.client.delete(r).where(and(...o)).returning();if(c.length===0)throw new Error(`Document not found: ${i}/${e}`);return this.processResult(c[0],a)}async count(t){let{collection:i,where:e={},tenantId:s}=t,a=this.getCollection(i),r=this.getTable(i),n=this.buildWhereClause(e,a,r,s);try{let o=this.client.select({count:sql`count(*)`}).from(r);n.length>0&&(o=o.where(and(...n)));let c=await o;return Number(c[0]?.count||0)}catch{return 0}}async findOne(t){let{collection:i,where:e={},tenantId:s,draft:a}=t;if(i.startsWith("_globals_")){let n=i.replace("_globals_",""),o=this.globals.get(n);if(!o)throw new Error(`Global "${n}" not found`);let c=this.getTable(i),d=this.client.select().from(c),u=o.fields.find(p=>p.name==="status"),h=u?.type==="select"&&Array.isArray(u.options)&&u.options.some(p=>p.value==="published");!a&&c.status&&h&&(d=d.where(eq(c.status,"published")));let g=await d.limit(1);if(g.length===0)return null;let y=this.processResult(g[0],o);if(a){let p=await this.executeRaw(sql`
36
+ SELECT * FROM kyro_versions
37
+ WHERE collection_slug = ${i}
38
+ AND document_id = ${n}
39
+ ORDER BY created_at DESC
40
+ LIMIT 1
41
+ `);if(p.length>0){let A=p[0],w=typeof A.data=="string"?JSON.parse(A.data):A.data;y={...y,...w,status:y.status};}}return y}return (await this.find({...t,limit:1})).docs[0]||null}async findVersions(t){await this.ensureVersionsTable();let{collection:i,documentId:e,limit:s=10,page:a=1,tenantId:r}=t,n=(a-1)*s,o=this.getCollection(i),c=await this.executeRaw(sql`
42
+ SELECT count(*) as count
43
+ FROM kyro_versions
44
+ WHERE collection_slug = ${i}
45
+ AND document_id = ${e}
46
+ AND autosave = 0
47
+ ${r&&o.tenantScoped?sql`AND tenant_id = ${r}`:sql``}
48
+ `),d=parseInt(c[0]?.count||"0");return {docs:(await this.executeRaw(sql`
49
+ SELECT *
50
+ FROM kyro_versions
51
+ WHERE collection_slug = ${i}
52
+ AND document_id = ${e}
53
+ AND autosave = 0
54
+ ${r&&o.tenantScoped?sql`AND tenant_id = ${r}`:sql``}
55
+ ORDER BY created_at DESC
56
+ LIMIT ${s}
57
+ OFFSET ${n}
58
+ `)).map(h=>({...h,data:typeof h.data=="string"?JSON.parse(h.data):h.data})),...this.calculatePagination(a,s,d)}}async findVersionByID(t){await this.ensureVersionsTable();let i=this.getCollection(t.collection),e=await this.executeRaw(sql`
59
+ SELECT * FROM kyro_versions
60
+ WHERE id = ${t.versionId}
61
+ AND collection_slug = ${t.collection}
62
+ ${t.tenantId&&i.tenantScoped?sql`AND tenant_id = ${t.tenantId}`:sql``}
63
+ LIMIT 1
64
+ `);if(e.length===0)return null;let s=e[0];return {...s,data:typeof s.data=="string"?JSON.parse(s.data):s.data}}async createVersion(t){await this.ensureVersionsTable();let i=this.getCollection(t.collection),e=new Date().toISOString();if(t.autosave){let a=await this.executeRaw(sql`
65
+ SELECT * FROM kyro_versions
66
+ WHERE collection_slug = ${t.collection}
67
+ AND document_id = ${t.documentId}
68
+ AND autosave = 1
69
+ ${t.tenantId&&i.tenantScoped?sql`AND tenant_id = ${t.tenantId}`:sql``}
70
+ LIMIT 1
71
+ `);if(a.length>0)return await this.executeRaw(sql`
72
+ UPDATE kyro_versions
73
+ SET data = ${JSON.stringify(t.data)},
74
+ status = ${t.status},
75
+ updated_at = ${e}
76
+ WHERE id = ${a[0].id}
77
+ `),this.findVersionByID({collection:t.collection,versionId:a[0].id,tenantId:t.tenantId})}let s=Math.random().toString(36).substring(2,15);if(await this.executeRaw(sql`
78
+ INSERT INTO kyro_versions (
79
+ id, collection_slug, document_id, tenant_id, data, status, autosave, created_by, change_description, created_at, updated_at
80
+ ) VALUES (
81
+ ${s}, ${t.collection}, ${t.documentId}, ${t.tenantId&&i.tenantScoped?t.tenantId:null},
82
+ ${JSON.stringify(t.data)}, ${t.status}, ${t.autosave?1:0}, ${t.createdBy||null},
83
+ ${t.changeDescription||null}, ${e}, ${e}
84
+ )
85
+ `),!t.autosave){let a=this.getCollection(t.collection);a.versions?.maxPerDoc&&await this.deleteVersions({collection:t.collection,documentId:t.documentId,keepLatest:a.versions.maxPerDoc,tenantId:t.tenantId});}return this.findVersionByID({collection:t.collection,versionId:s,tenantId:t.tenantId})}async updateLatestVersion(t){return this.createVersion({...t,autosave:true})}async deleteVersions(t){await this.ensureVersionsTable();let i=this.getCollection(t.collection);if(t.keepLatest){let s=(await this.executeRaw(sql`
86
+ SELECT id FROM kyro_versions
87
+ WHERE collection_slug = ${t.collection}
88
+ AND document_id = ${t.documentId}
89
+ AND autosave = 0
90
+ ${t.tenantId&&i.tenantScoped?sql`AND tenant_id = ${t.tenantId}`:sql``}
91
+ ORDER BY created_at DESC
92
+ LIMIT ${t.keepLatest}
93
+ `)).map(a=>a.id);s.length>0&&await this.executeRaw(sql`
94
+ DELETE FROM kyro_versions
95
+ WHERE collection_slug = ${t.collection}
96
+ AND document_id = ${t.documentId}
97
+ AND autosave = 0
98
+ AND id NOT IN (${sql.join(s.map(a=>sql`${a}`),sql`, `)})
99
+ `);}else await this.executeRaw(sql`
100
+ DELETE FROM kyro_versions
101
+ WHERE collection_slug = ${t.collection}
102
+ AND document_id = ${t.documentId}
103
+ ${t.tenantId&&i.tenantScoped?sql`AND tenant_id = ${t.tenantId}`:sql``}
104
+ `);}getTable(t){let i=this.getTableName(t),e=this.schema[i];if(!e)throw new Error(`Table "${i}" not found in schema`);return e}buildWhereClause(t,i,e,s){let a=[];s&&i.tenantScoped&&e.tenantId&&a.push(eq(e.tenantId,s));for(let[r,n]of Object.entries(t))if(r==="id"&&this.dialect==="postgres"&&(typeof n=="string"?n=_(n):n&&typeof n=="object"&&(n.equals!==void 0&&typeof n.equals=="string"&&(n={...n,equals:_(n.equals)}),n.in&&Array.isArray(n.in)&&(n={...n,in:n.in.map(o=>typeof o=="string"?_(o):o)}))),r==="AND"&&Array.isArray(n)){let o=n.map(c=>this.buildWhereClause(c,i,e)).flat().filter(Boolean);o.length>0&&a.push(and(...o));}else if(r==="OR"&&Array.isArray(n)){let o=n.map(c=>this.buildWhereClause(c,i,e)).flat().filter(Boolean);o.length>0&&a.push(or(...o));}else if(typeof n=="object"&&n!==null&&!Array.isArray(n)){let o=e[r];if(!o)continue;n.equals!==void 0&&a.push(eq(o,n.equals)),n.not_equals!==void 0&&a.push(ne(o,n.not_equals)),n.in&&Array.isArray(n.in)&&a.push(inArray(o,n.in)),n.like!==void 0&&a.push(like(o,n.like)),n.contains!==void 0&&a.push(like(o,`%${n.contains}%`)),n.greater_than!==void 0&&a.push(gt(o,n.greater_than)),n.greater_than_equal!==void 0&&a.push(gte(o,n.greater_than_equal)),n.less_than!==void 0&&a.push(lt(o,n.less_than)),n.less_than_equal!==void 0&&a.push(lte(o,n.less_than_equal));}else {let o=e[r];o&&a.push(eq(o,n));}return a}processResult(t,i){if(!t)return null;let e={...t};t.id&&(e.id=String(t.id));for(let s of i.fields){if(!s.name)continue;let a=s.name.replace(/-/g,"_").replace(/([A-Z])/g,"_$1").toLowerCase();a!==s.name&&e[a]!==void 0&&e[s.name]===void 0&&(e[s.name]=e[a],delete e[a]);}for(let s of i.fields){if(["json","richtext","array","group","blocks","upload","image","list","relationship-block"].includes(s.type)){let a=s;if(e[a.name]&&typeof e[a.name]=="string")try{let r=JSON.parse(e[a.name]);e[a.name]=r;}catch{}if(s.type==="blocks"&&e[a.name]&&Array.isArray(e[a.name])){let r=a.blocks||[];e[a.name]=B(e[a.name],r);}}if(s.type==="tabs"&&"tabs"in s&&s.name){if(typeof e[s.name]=="object"&&e[s.name]!==null&&!Array.isArray(e[s.name])){for(let r of s.tabs)for(let n of r.fields)if((n.type==="upload"||n.type==="image")&&n.name){let o=e[s.name][n.name];if(typeof o=="string")try{let c=JSON.parse(o);e[s.name][n.name]=Array.isArray(c)?c.map(d=>d&&typeof d=="object"&&typeof d.id=="string"?d.id:String(d||"")):typeof c.id=="string"?c.id:String(c.id||"");}catch{}else o&&typeof o=="object"&&(e[s.name][n.name]=Array.isArray(o)?o.map(c=>c&&typeof c=="object"&&typeof c.id=="string"?c.id:String(c||"")):typeof o.id=="string"?o.id:String(o.id||""));}continue}if(typeof e[s.name]=="string")try{let r=JSON.parse(e[s.name]);if(typeof r=="object"&&r!==null){e[s.name]=r;continue}}catch{}let a={};for(let r of s.tabs)for(let n of r.fields)if(n.name&&e[n.name]!==void 0){let o=e[n.name];if(["json","richtext","array","group","blocks","upload","image","list","relationship-block"].includes(n.type)){if(o&&typeof o=="string")try{o=JSON.parse(o);}catch{}(n.type==="upload"||n.type==="image")&&o&&typeof o=="object"&&(o=Array.isArray(o)?o.map(c=>c&&typeof c=="object"&&typeof c.id=="string"?c.id:String(c||"")):typeof o.id=="string"?o.id:String(o.id||""));}a[n.name]=o,delete e[n.name];}e[s.name]=a;}}return e.createdAt&&(e.createdAt=new Date(e.createdAt).toISOString()),e.updatedAt&&(e.updatedAt=new Date(e.updatedAt).toISOString()),e}async ensureVersionsTable(){if(this.versionsTableReady)return;let t;this.dialect==="sqlite"?t=`
105
+ CREATE TABLE IF NOT EXISTS kyro_versions (
106
+ id text PRIMARY KEY,
107
+ collection_slug text NOT NULL,
108
+ document_id text NOT NULL,
109
+ tenant_id text,
110
+ data text NOT NULL,
111
+ status text NOT NULL DEFAULT 'draft',
112
+ autosave integer NOT NULL DEFAULT 0,
113
+ created_by text,
114
+ change_description text,
115
+ created_at text DEFAULT (datetime('now')),
116
+ updated_at text DEFAULT (datetime('now'))
117
+ )
118
+ `:t=`
119
+ CREATE TABLE IF NOT EXISTS kyro_versions (
120
+ id text PRIMARY KEY,
121
+ collection_slug text NOT NULL,
122
+ document_id text NOT NULL,
123
+ tenant_id text,
124
+ data text NOT NULL,
125
+ status text NOT NULL,
126
+ autosave integer NOT NULL DEFAULT 0,
127
+ created_by text,
128
+ change_description text,
129
+ created_at text NOT NULL,
130
+ updated_at text NOT NULL
131
+ )
132
+ `,await this.executeRaw(sql.raw(t));try{this.dialect==="postgres"?await this.executeRaw(sql.raw("ALTER TABLE kyro_versions ADD COLUMN IF NOT EXISTS autosave integer NOT NULL DEFAULT 0")):await this.executeRaw(sql.raw("ALTER TABLE kyro_versions ADD COLUMN autosave integer NOT NULL DEFAULT 0"));}catch{}this.versionsTableReady=true;}async executeRaw(t){let i=await this.client.execute(t);return Array.isArray(i)?i:Array.isArray(i?.rows)?i.rows:Array.isArray(i?.[0])?i[0]:[]}};function Ne(f){return new v(f)}var he=createRequire(import.meta.url),ye="node:sqlite",{DatabaseSync:ge}=he(ye);function Te(){return process.env.DB_TYPE==="postgres"?"postgres":"sqlite"}function X(){return randomBytes(16).toString("hex")}async function Oe(){let f=Te();if(f==="sqlite"){let r=resolve(process.cwd(),"data","kyro.db");await mkdir(dirname(r),{recursive:true});let n=new ge(r);return n.exec("PRAGMA journal_mode = WAL"),{db:n,dialect:f,genId:X}}let t=process.env.DATABASE_URL||"postgresql://postgres:postgres@localhost:5432/kyro_cms",i=parseInt(process.env.DB_POOL_MAX||"10",10),e=process.env.DB_SSL==="true",s=le(t,{max:i,ssl:e?"require":false,onnotice:()=>{}});return {db:drizzle(s),dialect:f,genId:X}}async function Ue(f,t){}async function qe(f){let{roles:t}=await import('./schema-KFYUM674.js');await f.insert(t).values({name:"super_admin",level:100,inherits:[],description:"Full system access across all tenants",isSystem:true}).onConflictDoNothing();}
133
+ export{L as a,we as b,v as c,Ne as d,X as e,Oe as f,Ue as g,qe as h};