@panguard-ai/panguard-auth 0.1.0

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 (101) hide show
  1. package/dist/auth.d.ts +32 -0
  2. package/dist/auth.d.ts.map +1 -0
  3. package/dist/auth.js +68 -0
  4. package/dist/auth.js.map +1 -0
  5. package/dist/crypto.d.ts +21 -0
  6. package/dist/crypto.d.ts.map +1 -0
  7. package/dist/crypto.js +60 -0
  8. package/dist/crypto.js.map +1 -0
  9. package/dist/database.d.ts +266 -0
  10. package/dist/database.d.ts.map +1 -0
  11. package/dist/database.js +936 -0
  12. package/dist/database.js.map +1 -0
  13. package/dist/email-verify.d.ts +31 -0
  14. package/dist/email-verify.d.ts.map +1 -0
  15. package/dist/email-verify.js +506 -0
  16. package/dist/email-verify.js.map +1 -0
  17. package/dist/error-tracker.d.ts +24 -0
  18. package/dist/error-tracker.d.ts.map +1 -0
  19. package/dist/error-tracker.js +80 -0
  20. package/dist/error-tracker.js.map +1 -0
  21. package/dist/google-oauth.d.ts +40 -0
  22. package/dist/google-oauth.d.ts.map +1 -0
  23. package/dist/google-oauth.js +77 -0
  24. package/dist/google-oauth.js.map +1 -0
  25. package/dist/google-sheets.d.ts +35 -0
  26. package/dist/google-sheets.d.ts.map +1 -0
  27. package/dist/google-sheets.js +128 -0
  28. package/dist/google-sheets.js.map +1 -0
  29. package/dist/index.d.ts +27 -0
  30. package/dist/index.d.ts.map +1 -0
  31. package/dist/index.js +18 -0
  32. package/dist/index.js.map +1 -0
  33. package/dist/lemonsqueezy.d.ts +61 -0
  34. package/dist/lemonsqueezy.d.ts.map +1 -0
  35. package/dist/lemonsqueezy.js +254 -0
  36. package/dist/lemonsqueezy.js.map +1 -0
  37. package/dist/middleware.d.ts +22 -0
  38. package/dist/middleware.d.ts.map +1 -0
  39. package/dist/middleware.js +40 -0
  40. package/dist/middleware.js.map +1 -0
  41. package/dist/openapi.d.ts +17 -0
  42. package/dist/openapi.d.ts.map +1 -0
  43. package/dist/openapi.js +683 -0
  44. package/dist/openapi.js.map +1 -0
  45. package/dist/rate-limiter.d.ts +46 -0
  46. package/dist/rate-limiter.d.ts.map +1 -0
  47. package/dist/rate-limiter.js +64 -0
  48. package/dist/rate-limiter.js.map +1 -0
  49. package/dist/routes/admin.d.ts +30 -0
  50. package/dist/routes/admin.d.ts.map +1 -0
  51. package/dist/routes/admin.js +490 -0
  52. package/dist/routes/admin.js.map +1 -0
  53. package/dist/routes/auth.d.ts +18 -0
  54. package/dist/routes/auth.d.ts.map +1 -0
  55. package/dist/routes/auth.js +426 -0
  56. package/dist/routes/auth.js.map +1 -0
  57. package/dist/routes/billing.d.ts +14 -0
  58. package/dist/routes/billing.d.ts.map +1 -0
  59. package/dist/routes/billing.js +176 -0
  60. package/dist/routes/billing.js.map +1 -0
  61. package/dist/routes/index.d.ts +60 -0
  62. package/dist/routes/index.d.ts.map +1 -0
  63. package/dist/routes/index.js +133 -0
  64. package/dist/routes/index.js.map +1 -0
  65. package/dist/routes/oauth.d.ts +15 -0
  66. package/dist/routes/oauth.d.ts.map +1 -0
  67. package/dist/routes/oauth.js +215 -0
  68. package/dist/routes/oauth.js.map +1 -0
  69. package/dist/routes/shared.d.ts +71 -0
  70. package/dist/routes/shared.d.ts.map +1 -0
  71. package/dist/routes/shared.js +100 -0
  72. package/dist/routes/shared.js.map +1 -0
  73. package/dist/routes/totp.d.ts +14 -0
  74. package/dist/routes/totp.d.ts.map +1 -0
  75. package/dist/routes/totp.js +166 -0
  76. package/dist/routes/totp.js.map +1 -0
  77. package/dist/routes/usage.d.ts +14 -0
  78. package/dist/routes/usage.d.ts.map +1 -0
  79. package/dist/routes/usage.js +127 -0
  80. package/dist/routes/usage.js.map +1 -0
  81. package/dist/routes/waitlist.d.ts +16 -0
  82. package/dist/routes/waitlist.d.ts.map +1 -0
  83. package/dist/routes/waitlist.js +171 -0
  84. package/dist/routes/waitlist.js.map +1 -0
  85. package/dist/routes.d.ts +72 -0
  86. package/dist/routes.d.ts.map +1 -0
  87. package/dist/routes.js +1806 -0
  88. package/dist/routes.js.map +1 -0
  89. package/dist/totp.d.ts +41 -0
  90. package/dist/totp.d.ts.map +1 -0
  91. package/dist/totp.js +129 -0
  92. package/dist/totp.js.map +1 -0
  93. package/dist/types.d.ts +155 -0
  94. package/dist/types.d.ts.map +1 -0
  95. package/dist/types.js +6 -0
  96. package/dist/types.js.map +1 -0
  97. package/dist/usage-meter.d.ts +49 -0
  98. package/dist/usage-meter.d.ts.map +1 -0
  99. package/dist/usage-meter.js +123 -0
  100. package/dist/usage-meter.js.map +1 -0
  101. package/package.json +33 -0
package/dist/auth.d.ts ADDED
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Authentication utilities: password hashing and token generation.
3
+ * Uses only node:crypto — zero external dependencies.
4
+ * @module @panguard-ai/panguard-auth/auth
5
+ */
6
+ /**
7
+ * Hash a password using scrypt with a random salt.
8
+ * Returns `salt:hash` in hex.
9
+ */
10
+ export declare function hashPassword(password: string): Promise<string>;
11
+ /**
12
+ * Verify a password against a stored `salt:hash` string.
13
+ */
14
+ export declare function verifyPassword(password: string, stored: string): Promise<boolean>;
15
+ /**
16
+ * Generate a cryptographically secure session token (64 hex chars).
17
+ */
18
+ export declare function generateSessionToken(): string;
19
+ /**
20
+ * Generate a verification token (UUID v4).
21
+ */
22
+ export declare function generateVerifyToken(): string;
23
+ /**
24
+ * Hash a session token with SHA-256 for secure storage.
25
+ * The plaintext token is sent to the client; only the hash is stored in DB.
26
+ */
27
+ export declare function hashToken(token: string): string;
28
+ /**
29
+ * Calculate session expiry (24 hours from now).
30
+ */
31
+ export declare function sessionExpiry(hours?: number): string;
32
+ //# sourceMappingURL=auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AASH;;;GAGG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAc9D;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAiBjF;AAED;;GAEG;AACH,wBAAgB,oBAAoB,IAAI,MAAM,CAE7C;AAED;;GAEG;AACH,wBAAgB,mBAAmB,IAAI,MAAM,CAE5C;AAED;;;GAGG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAE/C;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,KAAK,SAAK,GAAG,MAAM,CAIhD"}
package/dist/auth.js ADDED
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Authentication utilities: password hashing and token generation.
3
+ * Uses only node:crypto — zero external dependencies.
4
+ * @module @panguard-ai/panguard-auth/auth
5
+ */
6
+ import { scrypt, randomBytes, randomUUID, timingSafeEqual, createHash } from 'node:crypto';
7
+ const SCRYPT_KEYLEN = 64;
8
+ const SCRYPT_COST = 16384; // N
9
+ const SCRYPT_BLOCK = 8; // r
10
+ const SCRYPT_PARALLEL = 1; // p
11
+ /**
12
+ * Hash a password using scrypt with a random salt.
13
+ * Returns `salt:hash` in hex.
14
+ */
15
+ export function hashPassword(password) {
16
+ return new Promise((resolve, reject) => {
17
+ const salt = randomBytes(16).toString('hex');
18
+ scrypt(password, salt, SCRYPT_KEYLEN, { N: SCRYPT_COST, r: SCRYPT_BLOCK, p: SCRYPT_PARALLEL }, (err, derived) => {
19
+ if (err)
20
+ return reject(err);
21
+ resolve(`${salt}:${derived.toString('hex')}`);
22
+ });
23
+ });
24
+ }
25
+ /**
26
+ * Verify a password against a stored `salt:hash` string.
27
+ */
28
+ export function verifyPassword(password, stored) {
29
+ return new Promise((resolve, reject) => {
30
+ const [salt, hash] = stored.split(':');
31
+ if (!salt || !hash)
32
+ return resolve(false);
33
+ scrypt(password, salt, SCRYPT_KEYLEN, { N: SCRYPT_COST, r: SCRYPT_BLOCK, p: SCRYPT_PARALLEL }, (err, derived) => {
34
+ if (err)
35
+ return reject(err);
36
+ const storedBuf = Buffer.from(hash, 'hex');
37
+ resolve(timingSafeEqual(derived, storedBuf));
38
+ });
39
+ });
40
+ }
41
+ /**
42
+ * Generate a cryptographically secure session token (64 hex chars).
43
+ */
44
+ export function generateSessionToken() {
45
+ return randomBytes(32).toString('hex');
46
+ }
47
+ /**
48
+ * Generate a verification token (UUID v4).
49
+ */
50
+ export function generateVerifyToken() {
51
+ return randomUUID();
52
+ }
53
+ /**
54
+ * Hash a session token with SHA-256 for secure storage.
55
+ * The plaintext token is sent to the client; only the hash is stored in DB.
56
+ */
57
+ export function hashToken(token) {
58
+ return createHash('sha256').update(token).digest('hex');
59
+ }
60
+ /**
61
+ * Calculate session expiry (24 hours from now).
62
+ */
63
+ export function sessionExpiry(hours = 24) {
64
+ const d = new Date();
65
+ d.setHours(d.getHours() + hours);
66
+ return d.toISOString().replace('T', ' ').slice(0, 19);
67
+ }
68
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,UAAU,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE3F,MAAM,aAAa,GAAG,EAAE,CAAC;AACzB,MAAM,WAAW,GAAG,KAAK,CAAC,CAAC,IAAI;AAC/B,MAAM,YAAY,GAAG,CAAC,CAAC,CAAC,IAAI;AAC5B,MAAM,eAAe,GAAG,CAAC,CAAC,CAAC,IAAI;AAE/B;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,QAAgB;IAC3C,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,MAAM,IAAI,GAAG,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;QAC7C,MAAM,CACJ,QAAQ,EACR,IAAI,EACJ,aAAa,EACb,EAAE,CAAC,EAAE,WAAW,EAAE,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,eAAe,EAAE,EACvD,CAAC,GAAG,EAAE,OAAO,EAAE,EAAE;YACf,IAAI,GAAG;gBAAE,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC;YAC5B,OAAO,CAAC,GAAG,IAAI,IAAI,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QAChD,CAAC,CACF,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,cAAc,CAAC,QAAgB,EAAE,MAAc;IAC7D,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACvC,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI;YAAE,OAAO,OAAO,CAAC,KAAK,CAAC,CAAC;QAE1C,MAAM,CACJ,QAAQ,EACR,IAAI,EACJ,aAAa,EACb,EAAE,CAAC,EAAE,WAAW,EAAE,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,eAAe,EAAE,EACvD,CAAC,GAAG,EAAE,OAAO,EAAE,EAAE;YACf,IAAI,GAAG;gBAAE,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC;YAC5B,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;YAC3C,OAAO,CAAC,eAAe,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC,CAAC;QAC/C,CAAC,CACF,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,oBAAoB;IAClC,OAAO,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AACzC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,mBAAmB;IACjC,OAAO,UAAU,EAAE,CAAC;AACtB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,SAAS,CAAC,KAAa;IACrC,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAC1D,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,aAAa,CAAC,KAAK,GAAG,EAAE;IACtC,MAAM,CAAC,GAAG,IAAI,IAAI,EAAE,CAAC;IACrB,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,EAAE,GAAG,KAAK,CAAC,CAAC;IACjC,OAAO,CAAC,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AACxD,CAAC"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Encryption utilities for sensitive data at rest.
3
+ * Uses AES-256-GCM with random IV for each encryption.
4
+ *
5
+ * @module @panguard-ai/panguard-auth/crypto
6
+ */
7
+ /**
8
+ * Encrypt a plaintext string using AES-256-GCM.
9
+ * Returns format: iv:authTag:ciphertext (all hex-encoded).
10
+ */
11
+ export declare function encryptSecret(plaintext: string): string;
12
+ /**
13
+ * Decrypt a ciphertext string produced by encryptSecret.
14
+ * Input format: iv:authTag:ciphertext (all hex-encoded).
15
+ */
16
+ export declare function decryptSecret(ciphertext: string): string;
17
+ /**
18
+ * Check if a value looks like an encrypted secret (iv:tag:cipher format).
19
+ */
20
+ export declare function isEncrypted(value: string): boolean;
21
+ //# sourceMappingURL=crypto.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"crypto.d.ts","sourceRoot":"","sources":["../src/crypto.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAuBH;;;GAGG;AACH,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CASvD;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAgBxD;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAGlD"}
package/dist/crypto.js ADDED
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Encryption utilities for sensitive data at rest.
3
+ * Uses AES-256-GCM with random IV for each encryption.
4
+ *
5
+ * @module @panguard-ai/panguard-auth/crypto
6
+ */
7
+ import { createCipheriv, createDecipheriv, randomBytes } from 'node:crypto';
8
+ const ALGORITHM = 'aes-256-gcm';
9
+ const IV_LENGTH = 12; // 96 bits, recommended for GCM
10
+ const AUTH_TAG_LENGTH = 16; // 128 bits
11
+ /**
12
+ * Get the encryption key from environment.
13
+ * Must be a 64-character hex string (32 bytes).
14
+ */
15
+ function getEncryptionKey() {
16
+ const keyHex = process.env['TOTP_ENCRYPTION_KEY'];
17
+ if (!keyHex || keyHex.length !== 64) {
18
+ throw new Error('TOTP_ENCRYPTION_KEY must be set as a 64-character hex string (32 bytes). ' +
19
+ "Generate one with: node -e \"console.log(require('crypto').randomBytes(32).toString('hex'))\"");
20
+ }
21
+ return Buffer.from(keyHex, 'hex');
22
+ }
23
+ /**
24
+ * Encrypt a plaintext string using AES-256-GCM.
25
+ * Returns format: iv:authTag:ciphertext (all hex-encoded).
26
+ */
27
+ export function encryptSecret(plaintext) {
28
+ const key = getEncryptionKey();
29
+ const iv = randomBytes(IV_LENGTH);
30
+ const cipher = createCipheriv(ALGORITHM, key, iv, { authTagLength: AUTH_TAG_LENGTH });
31
+ const encrypted = Buffer.concat([cipher.update(plaintext, 'utf8'), cipher.final()]);
32
+ const authTag = cipher.getAuthTag();
33
+ return `${iv.toString('hex')}:${authTag.toString('hex')}:${encrypted.toString('hex')}`;
34
+ }
35
+ /**
36
+ * Decrypt a ciphertext string produced by encryptSecret.
37
+ * Input format: iv:authTag:ciphertext (all hex-encoded).
38
+ */
39
+ export function decryptSecret(ciphertext) {
40
+ const parts = ciphertext.split(':');
41
+ if (parts.length !== 3) {
42
+ throw new Error('Invalid encrypted secret format');
43
+ }
44
+ const key = getEncryptionKey();
45
+ const iv = Buffer.from(parts[0], 'hex');
46
+ const authTag = Buffer.from(parts[1], 'hex');
47
+ const encrypted = Buffer.from(parts[2], 'hex');
48
+ const decipher = createDecipheriv(ALGORITHM, key, iv, { authTagLength: AUTH_TAG_LENGTH });
49
+ decipher.setAuthTag(authTag);
50
+ const decrypted = Buffer.concat([decipher.update(encrypted), decipher.final()]);
51
+ return decrypted.toString('utf8');
52
+ }
53
+ /**
54
+ * Check if a value looks like an encrypted secret (iv:tag:cipher format).
55
+ */
56
+ export function isEncrypted(value) {
57
+ const parts = value.split(':');
58
+ return parts.length === 3 && parts.every((p) => /^[0-9a-f]+$/.test(p));
59
+ }
60
+ //# sourceMappingURL=crypto.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"crypto.js","sourceRoot":"","sources":["../src/crypto.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,266 @@
1
+ /**
2
+ * SQLite database layer for Panguard Auth
3
+ * @module @panguard-ai/panguard-auth/database
4
+ */
5
+ import type { WaitlistEntry, WaitlistInput, WaitlistStats, User, RegisterInput, Session, UserAdmin, SessionAdmin, ActivityItem, AuditLogFilter } from './types.js';
6
+ export declare class AuthDB {
7
+ private readonly db;
8
+ constructor(dbPath: string);
9
+ private initialize;
10
+ addToWaitlist(input: WaitlistInput, verifyToken: string): WaitlistEntry;
11
+ getWaitlistByEmail(email: string): WaitlistEntry | undefined;
12
+ getWaitlistById(id: number): WaitlistEntry | undefined;
13
+ verifyWaitlistToken(token: string): WaitlistEntry | undefined;
14
+ getWaitlistStats(): WaitlistStats;
15
+ getAllWaitlist(): WaitlistEntry[];
16
+ createUser(input: RegisterInput, passwordHash: string): User;
17
+ getUserByEmail(email: string): User | undefined;
18
+ getUserById(id: number): User | undefined;
19
+ updateLastLogin(userId: number): void;
20
+ createSession(userId: number, token: string, expiresAt: string): Session;
21
+ getSession(token: string): (Session & {
22
+ user: User;
23
+ }) | undefined;
24
+ deleteSession(token: string): void;
25
+ cleanExpiredSessions(): number;
26
+ createReportPurchase(userId: number, addonId: string, pricingModel: string, expiresAt?: string): ReportPurchase;
27
+ getReportPurchaseById(id: number): ReportPurchase | undefined;
28
+ getUserReportPurchases(userId: number): ReportPurchase[];
29
+ hasActiveReportPurchase(userId: number, addonId: string): boolean;
30
+ getAllUsersAdmin(): UserAdmin[];
31
+ searchUsers(query: string): UserAdmin[];
32
+ getActiveSessions(): SessionAdmin[];
33
+ deleteSessionById(sessionId: number): boolean;
34
+ getRecentActivity(limit?: number): ActivityItem[];
35
+ getAdminDashboardStats(): {
36
+ users: {
37
+ total: number;
38
+ byTier: Record<string, number>;
39
+ byRole: Record<string, number>;
40
+ recentSignups: number;
41
+ verifiedCount: number;
42
+ signupsByDay: Array<{
43
+ date: string;
44
+ count: number;
45
+ }>;
46
+ };
47
+ waitlist: WaitlistStats & {
48
+ signupsByDay: Array<{
49
+ date: string;
50
+ count: number;
51
+ }>;
52
+ };
53
+ sessions: {
54
+ active: number;
55
+ total: number;
56
+ };
57
+ reportPurchases: {
58
+ total: number;
59
+ active: number;
60
+ };
61
+ };
62
+ getAllUsers(): User[];
63
+ updateUserTier(userId: number, tier: string, planExpiresAt?: string): void;
64
+ updateUserRole(userId: number, role: string): void;
65
+ getUserStats(): {
66
+ total: number;
67
+ byTier: Record<string, number>;
68
+ byRole: Record<string, number>;
69
+ recentSignups: number;
70
+ };
71
+ approveWaitlistEntry(id: number): void;
72
+ rejectWaitlistEntry(id: number): void;
73
+ addAuditLog(action: string, actorId: number | null, targetId: number | null, details?: string): void;
74
+ getAuditLog(limit?: number): AuditLogEntry[];
75
+ upsertSubscription(data: {
76
+ userId: number;
77
+ lsSubscriptionId: string;
78
+ lsCustomerId: string;
79
+ lsVariantId: string;
80
+ tier: string;
81
+ status: string;
82
+ renewsAt: string | null;
83
+ endsAt: string | null;
84
+ }): void;
85
+ getSubscriptionByLsId(lsSubscriptionId: string): Subscription | undefined;
86
+ getActiveSubscription(userId: number): Subscription | undefined;
87
+ updateSubscriptionStatus(lsSubscriptionId: string, status: string, endsAt: string | null): void;
88
+ /**
89
+ * Downgrade all users whose plan_expires_at has passed to free tier.
90
+ * Returns the list of downgraded user emails (for notification).
91
+ */
92
+ checkExpiredPlans(): Array<{
93
+ id: number;
94
+ email: string;
95
+ tier: string;
96
+ }>;
97
+ /**
98
+ * Get users whose plans expire within the given number of days.
99
+ * Used for sending expiration warning emails.
100
+ */
101
+ getExpiringPlans(withinDays: number): Array<{
102
+ id: number;
103
+ email: string;
104
+ name: string;
105
+ tier: string;
106
+ planExpiresAt: string;
107
+ }>;
108
+ /**
109
+ * Store a hashed reset token for a user. Invalidates any previous tokens.
110
+ * Returns the token expiry time.
111
+ */
112
+ createResetToken(userId: number, tokenHash: string): string;
113
+ /**
114
+ * Validate a reset token hash. Returns the user_id if valid, undefined otherwise.
115
+ * Marks the token as used atomically.
116
+ */
117
+ validateResetToken(tokenHash: string): number | undefined;
118
+ /**
119
+ * Update a user's password hash.
120
+ */
121
+ updateUserPassword(userId: number, passwordHash: string): void;
122
+ deleteSessionsByUserId(userId: number): number;
123
+ /**
124
+ * Delete a user and ALL associated data (GDPR right to erasure).
125
+ * Uses a transaction to ensure atomicity.
126
+ */
127
+ deleteUser(userId: number): {
128
+ deleted: boolean;
129
+ tablesAffected: string[];
130
+ };
131
+ /**
132
+ * Export all user data (GDPR right to data portability).
133
+ * Returns a structured object with all data belonging to the user.
134
+ */
135
+ exportUserData(userId: number): Record<string, unknown> | null;
136
+ /**
137
+ * Store TOTP secret and backup codes for a user.
138
+ */
139
+ saveTotpSecret(userId: number, secret: string, backupCodes: string): void;
140
+ /**
141
+ * Enable TOTP for a user (after they verify it works).
142
+ */
143
+ enableTotp(userId: number): void;
144
+ /**
145
+ * Update the last used TOTP time step (for replay protection).
146
+ */
147
+ updateLastUsedStep(userId: number, step: number): void;
148
+ /**
149
+ * Disable and remove TOTP for a user.
150
+ */
151
+ disableTotp(userId: number): void;
152
+ /**
153
+ * Get TOTP secret for a user.
154
+ */
155
+ getTotpSecret(userId: number): TotpSecret | undefined;
156
+ /**
157
+ * Consume a backup code. Returns true if the code was valid and consumed.
158
+ */
159
+ consumeBackupCode(userId: number, code: string): boolean;
160
+ /**
161
+ * Get usage count for a resource in a given period.
162
+ */
163
+ getUsage(userId: number, resource: string, period: string): number;
164
+ /**
165
+ * Increment usage counter for a resource.
166
+ */
167
+ incrementUsage(userId: number, resource: string, period: string, amount?: number): void;
168
+ /**
169
+ * Set absolute usage value for a resource (for count-based resources).
170
+ */
171
+ setUsage(userId: number, resource: string, period: string, count: number): void;
172
+ /**
173
+ * Get all usage meters for a user.
174
+ */
175
+ getUserUsage(userId: number): Array<{
176
+ resource: string;
177
+ period: string;
178
+ count: number;
179
+ }>;
180
+ /**
181
+ * Delete old usage meters (periods older than given cutoff).
182
+ * Used for cleanup of historical data.
183
+ */
184
+ cleanupOldUsage(cutoffPeriod: string): number;
185
+ suspendUser(userId: number): void;
186
+ unsuspendUser(userId: number): void;
187
+ getAuditLogFiltered(filter: AuditLogFilter): {
188
+ items: AuditLogEntry[];
189
+ total: number;
190
+ };
191
+ getDistinctAuditActions(): string[];
192
+ getUserDetailById(userId: number): {
193
+ user: UserAdmin;
194
+ subscription: {
195
+ status: string;
196
+ tier: string;
197
+ renewsAt: string | null;
198
+ endsAt: string | null;
199
+ } | null;
200
+ usage: Array<{
201
+ resource: string;
202
+ period: string;
203
+ count: number;
204
+ }>;
205
+ sessions: Array<{
206
+ id: number;
207
+ expiresAt: string;
208
+ createdAt: string;
209
+ }>;
210
+ recentAudit: AuditLogEntry[];
211
+ totpEnabled: boolean;
212
+ } | null;
213
+ getAdminUsageAggregate(): Array<{
214
+ userId: number;
215
+ email: string;
216
+ name: string;
217
+ tier: string;
218
+ resource: string;
219
+ period: string;
220
+ count: number;
221
+ }>;
222
+ /** Lightweight DB connectivity probe for health checks. */
223
+ healthCheck(): void;
224
+ close(): void;
225
+ }
226
+ export interface ReportPurchase {
227
+ id: number;
228
+ userId: number;
229
+ addonId: string;
230
+ pricingModel: string;
231
+ status: string;
232
+ purchasedAt: string;
233
+ expiresAt: string | null;
234
+ }
235
+ export interface Subscription {
236
+ id: number;
237
+ userId: number;
238
+ lsSubscriptionId: string;
239
+ lsCustomerId: string;
240
+ lsVariantId: string;
241
+ tier: string;
242
+ status: string;
243
+ renewsAt: string | null;
244
+ endsAt: string | null;
245
+ createdAt: string;
246
+ updatedAt: string;
247
+ }
248
+ export interface TotpSecret {
249
+ id: number;
250
+ userId: number;
251
+ encryptedSecret: string;
252
+ backupCodes: string;
253
+ enabled: number;
254
+ lastUsedStep: number;
255
+ createdAt: string;
256
+ updatedAt: string;
257
+ }
258
+ export interface AuditLogEntry {
259
+ id: number;
260
+ action: string;
261
+ actorId: number | null;
262
+ targetId: number | null;
263
+ details: string | null;
264
+ createdAt: string;
265
+ }
266
+ //# sourceMappingURL=database.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../src/database.ts"],"names":[],"mappings":"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"}