@nxuss/lemma 0.5.5 → 0.5.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.
- package/dist/cjs/cloud/BurstRateLimiter.d.ts +26 -0
- package/dist/cjs/cloud/BurstRateLimiter.d.ts.map +1 -0
- package/dist/cjs/cloud/BurstRateLimiter.js +63 -0
- package/dist/cjs/cloud/BurstRateLimiter.js.map +1 -0
- package/dist/cjs/cloud/KeyManager.d.ts +1 -0
- package/dist/cjs/cloud/KeyManager.d.ts.map +1 -1
- package/dist/cjs/cloud/KeyManager.js +28 -1
- package/dist/cjs/cloud/KeyManager.js.map +1 -1
- package/dist/cjs/cloud/PostgresQuotaLimiter.d.ts +60 -0
- package/dist/cjs/cloud/PostgresQuotaLimiter.d.ts.map +1 -0
- package/dist/cjs/cloud/PostgresQuotaLimiter.js +200 -0
- package/dist/cjs/cloud/PostgresQuotaLimiter.js.map +1 -0
- package/dist/cjs/cloud/TenantCache.d.ts +1 -1
- package/dist/cjs/cloud/TenantCache.d.ts.map +1 -1
- package/dist/cjs/cloud/TenantCache.js +21 -3
- package/dist/cjs/cloud/TenantCache.js.map +1 -1
- package/dist/cjs/cloud/server.d.ts +3 -1
- package/dist/cjs/cloud/server.d.ts.map +1 -1
- package/dist/cjs/cloud/server.js +42 -5
- package/dist/cjs/cloud/server.js.map +1 -1
- package/dist/cjs/cloud/types.d.ts +3 -0
- package/dist/cjs/cloud/types.d.ts.map +1 -1
- package/dist/cjs/cloud/types.js +3 -3
- package/dist/cjs/cloud/types.js.map +1 -1
- package/dist/esm/cloud/BurstRateLimiter.d.ts +26 -0
- package/dist/esm/cloud/BurstRateLimiter.d.ts.map +1 -0
- package/dist/esm/cloud/BurstRateLimiter.js +59 -0
- package/dist/esm/cloud/BurstRateLimiter.js.map +1 -0
- package/dist/esm/cloud/KeyManager.d.ts +1 -0
- package/dist/esm/cloud/KeyManager.d.ts.map +1 -1
- package/dist/esm/cloud/KeyManager.js +28 -1
- package/dist/esm/cloud/KeyManager.js.map +1 -1
- package/dist/esm/cloud/PostgresQuotaLimiter.d.ts +60 -0
- package/dist/esm/cloud/PostgresQuotaLimiter.d.ts.map +1 -0
- package/dist/esm/cloud/PostgresQuotaLimiter.js +196 -0
- package/dist/esm/cloud/PostgresQuotaLimiter.js.map +1 -0
- package/dist/esm/cloud/TenantCache.d.ts +1 -1
- package/dist/esm/cloud/TenantCache.d.ts.map +1 -1
- package/dist/esm/cloud/TenantCache.js +21 -3
- package/dist/esm/cloud/TenantCache.js.map +1 -1
- package/dist/esm/cloud/server.d.ts +3 -1
- package/dist/esm/cloud/server.d.ts.map +1 -1
- package/dist/esm/cloud/server.js +41 -5
- package/dist/esm/cloud/server.js.map +1 -1
- package/dist/esm/cloud/types.d.ts +3 -0
- package/dist/esm/cloud/types.d.ts.map +1 -1
- package/dist/esm/cloud/types.js +3 -3
- package/dist/esm/cloud/types.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lemma Cloud — Burst Rate Limiter
|
|
3
|
+
*
|
|
4
|
+
* Highly optimized, in-memory sliding window rate limiter.
|
|
5
|
+
* Caps requests at 10 RPS per API Key.
|
|
6
|
+
* Adds <50 microseconds overhead (0.05ms) to the critical path.
|
|
7
|
+
*/
|
|
8
|
+
export declare class BurstRateLimiter {
|
|
9
|
+
private windows;
|
|
10
|
+
private maxRequestsPerSecond;
|
|
11
|
+
private windowSizeMs;
|
|
12
|
+
constructor(maxRps?: number, windowSizeMs?: number);
|
|
13
|
+
/**
|
|
14
|
+
* Check if a request is allowed under the rate limit
|
|
15
|
+
* @param keyId The unique identifier for the rate limit window (e.g. API key)
|
|
16
|
+
*/
|
|
17
|
+
check(keyId: string): {
|
|
18
|
+
allowed: boolean;
|
|
19
|
+
remaining: number;
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Helper to manually clear a rate limit window (useful for unit tests)
|
|
23
|
+
*/
|
|
24
|
+
clear(keyId: string): void;
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=BurstRateLimiter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BurstRateLimiter.d.ts","sourceRoot":"","sources":["../../../src/cloud/BurstRateLimiter.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,OAAO,CAA+B;IAC9C,OAAO,CAAC,oBAAoB,CAAS;IACrC,OAAO,CAAC,YAAY,CAAS;gBAEjB,MAAM,SAAK,EAAE,YAAY,SAAO;IAoB5C;;;OAGG;IACH,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE;IA0B7D;;OAEG;IACH,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;CAG3B"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Lemma Cloud — Burst Rate Limiter
|
|
4
|
+
*
|
|
5
|
+
* Highly optimized, in-memory sliding window rate limiter.
|
|
6
|
+
* Caps requests at 10 RPS per API Key.
|
|
7
|
+
* Adds <50 microseconds overhead (0.05ms) to the critical path.
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.BurstRateLimiter = void 0;
|
|
11
|
+
class BurstRateLimiter {
|
|
12
|
+
constructor(maxRps = 10, windowSizeMs = 1000) {
|
|
13
|
+
this.windows = new Map();
|
|
14
|
+
this.maxRequestsPerSecond = maxRps;
|
|
15
|
+
this.windowSizeMs = windowSizeMs;
|
|
16
|
+
// Periodic sweep to prevent memory leak (runs every minute)
|
|
17
|
+
setInterval(() => {
|
|
18
|
+
const now = Date.now();
|
|
19
|
+
const expirationTime = now - this.windowSizeMs;
|
|
20
|
+
for (const [key, timestamps] of this.windows.entries()) {
|
|
21
|
+
const active = timestamps.filter(t => t > expirationTime);
|
|
22
|
+
if (active.length === 0) {
|
|
23
|
+
this.windows.delete(key);
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
this.windows.set(key, active);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}, 60000).unref();
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Check if a request is allowed under the rate limit
|
|
33
|
+
* @param keyId The unique identifier for the rate limit window (e.g. API key)
|
|
34
|
+
*/
|
|
35
|
+
check(keyId) {
|
|
36
|
+
const now = Date.now();
|
|
37
|
+
const expirationTime = now - this.windowSizeMs;
|
|
38
|
+
let timestamps = this.windows.get(keyId) || [];
|
|
39
|
+
// Prune expired timestamps (older than 1 second)
|
|
40
|
+
timestamps = timestamps.filter(t => t > expirationTime);
|
|
41
|
+
if (timestamps.length >= this.maxRequestsPerSecond) {
|
|
42
|
+
return {
|
|
43
|
+
allowed: false,
|
|
44
|
+
remaining: 0,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
// Register current request
|
|
48
|
+
timestamps.push(now);
|
|
49
|
+
this.windows.set(keyId, timestamps);
|
|
50
|
+
return {
|
|
51
|
+
allowed: true,
|
|
52
|
+
remaining: this.maxRequestsPerSecond - timestamps.length,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Helper to manually clear a rate limit window (useful for unit tests)
|
|
57
|
+
*/
|
|
58
|
+
clear(keyId) {
|
|
59
|
+
this.windows.delete(keyId);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
exports.BurstRateLimiter = BurstRateLimiter;
|
|
63
|
+
//# sourceMappingURL=BurstRateLimiter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BurstRateLimiter.js","sourceRoot":"","sources":["../../../src/cloud/BurstRateLimiter.ts"],"names":[],"mappings":";AAAA;;;;;;GAMG;;;AAEH,MAAa,gBAAgB;IAK3B,YAAY,MAAM,GAAG,EAAE,EAAE,YAAY,GAAG,IAAI;QAJpC,YAAO,GAAG,IAAI,GAAG,EAAoB,CAAC;QAK5C,IAAI,CAAC,oBAAoB,GAAG,MAAM,CAAC;QACnC,IAAI,CAAC,YAAY,GAAG,YAAY,CAAC;QAEjC,4DAA4D;QAC5D,WAAW,CAAC,GAAG,EAAE;YACf,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YACvB,MAAM,cAAc,GAAG,GAAG,GAAG,IAAI,CAAC,YAAY,CAAC;YAE/C,KAAK,MAAM,CAAC,GAAG,EAAE,UAAU,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC;gBACvD,MAAM,MAAM,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,cAAc,CAAC,CAAC;gBAC1D,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;oBACxB,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;gBAC3B,CAAC;qBAAM,CAAC;oBACN,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;gBAChC,CAAC;YACH,CAAC;QACH,CAAC,EAAE,KAAK,CAAC,CAAC,KAAK,EAAE,CAAC;IACpB,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,KAAa;QACjB,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,MAAM,cAAc,GAAG,GAAG,GAAG,IAAI,CAAC,YAAY,CAAC;QAE/C,IAAI,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;QAE/C,iDAAiD;QACjD,UAAU,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,cAAc,CAAC,CAAC;QAExD,IAAI,UAAU,CAAC,MAAM,IAAI,IAAI,CAAC,oBAAoB,EAAE,CAAC;YACnD,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,SAAS,EAAE,CAAC;aACb,CAAC;QACJ,CAAC;QAED,2BAA2B;QAC3B,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACrB,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC;QAEpC,OAAO;YACL,OAAO,EAAE,IAAI;YACb,SAAS,EAAE,IAAI,CAAC,oBAAoB,GAAG,UAAU,CAAC,MAAM;SACzD,CAAC;IACJ,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,KAAa;QACjB,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAC7B,CAAC;CACF;AA7DD,4CA6DC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"KeyManager.d.ts","sourceRoot":"","sources":["../../../src/cloud/KeyManager.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,OAAO,EAAE,MAAM,EAAe,MAAM,SAAS,CAAC;AAE9C,qBAAa,UAAU;IACrB,OAAO,CAAC,IAAI,CAA6B;IACzC,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,SAAS,CAA+B;gBAEpC,SAAS,SAAqB;IAO1C,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,GAAE,MAAM,CAAC,MAAM,CAAU,GAAG,MAAM;IAkB/E,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG;QAAE,KAAK,EAAE,OAAO,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE;
|
|
1
|
+
{"version":3,"file":"KeyManager.d.ts","sourceRoot":"","sources":["../../../src/cloud/KeyManager.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,OAAO,EAAE,MAAM,EAAe,MAAM,SAAS,CAAC;AAE9C,qBAAa,UAAU;IACrB,OAAO,CAAC,IAAI,CAA6B;IACzC,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,SAAS,CAA+B;gBAEpC,SAAS,SAAqB;IAO1C,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,GAAE,MAAM,CAAC,MAAM,CAAU,GAAG,MAAM;IAkB/E,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG;QAAE,KAAK,EAAE,OAAO,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE;IAsC1E,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAWlC,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,GAAG,OAAO;IAQzD,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO;IAQ9B,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE;IAIvC,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAMtC,OAAO,CAAC,eAAe;IAUvB,OAAO,CAAC,iBAAiB;IAezB,OAAO,CAAC,YAAY;IAQpB,OAAO,CAAC,IAAI;IAWZ,OAAO,CAAC,IAAI;CAiBb"}
|
|
@@ -31,7 +31,7 @@ class KeyManager {
|
|
|
31
31
|
plan,
|
|
32
32
|
createdAt: Date.now(),
|
|
33
33
|
active: true,
|
|
34
|
-
usage: { today: 0, total: 0, lastReset: Date.now() },
|
|
34
|
+
usage: { today: 0, monthly: 0, total: 0, lastReset: Date.now(), lastMonthlyReset: Date.now() },
|
|
35
35
|
};
|
|
36
36
|
this.keys.set(id, key);
|
|
37
37
|
this.scheduleSave();
|
|
@@ -49,6 +49,8 @@ class KeyManager {
|
|
|
49
49
|
}
|
|
50
50
|
// Reset daily counter if needed
|
|
51
51
|
this.maybeResetDaily(key);
|
|
52
|
+
// Reset monthly counter if needed
|
|
53
|
+
this.maybeResetMonthly(key);
|
|
52
54
|
// Check plan limits
|
|
53
55
|
const limits = types_1.PLAN_LIMITS[key.plan];
|
|
54
56
|
if (key.usage.today >= limits.dailyRequests) {
|
|
@@ -59,6 +61,12 @@ class KeyManager {
|
|
|
59
61
|
: 'Daily request limit reached. Contact support to increase limits.',
|
|
60
62
|
};
|
|
61
63
|
}
|
|
64
|
+
if (!process.env.DATABASE_URL && key.usage.monthly >= limits.monthlyRequests) {
|
|
65
|
+
return {
|
|
66
|
+
valid: false,
|
|
67
|
+
reason: 'Monthly Cloud Quota Exceeded. Please upgrade your plan.',
|
|
68
|
+
};
|
|
69
|
+
}
|
|
62
70
|
return { valid: true, key };
|
|
63
71
|
}
|
|
64
72
|
// ─── Usage Tracking ─────────────────────────────────────────────────────────
|
|
@@ -67,6 +75,7 @@ class KeyManager {
|
|
|
67
75
|
if (!key)
|
|
68
76
|
return;
|
|
69
77
|
key.usage.today++;
|
|
78
|
+
key.usage.monthly++;
|
|
70
79
|
key.usage.total++;
|
|
71
80
|
this.scheduleSave();
|
|
72
81
|
}
|
|
@@ -103,6 +112,17 @@ class KeyManager {
|
|
|
103
112
|
key.usage.lastReset = now;
|
|
104
113
|
}
|
|
105
114
|
}
|
|
115
|
+
maybeResetMonthly(key) {
|
|
116
|
+
const now = Date.now();
|
|
117
|
+
const currentDate = new Date(now);
|
|
118
|
+
const lastResetDate = new Date(key.usage.lastMonthlyReset || 0);
|
|
119
|
+
if (currentDate.getUTCMonth() !== lastResetDate.getUTCMonth() ||
|
|
120
|
+
currentDate.getUTCFullYear() !== lastResetDate.getUTCFullYear()) {
|
|
121
|
+
key.usage.monthly = 0;
|
|
122
|
+
key.usage.lastMonthlyReset = now;
|
|
123
|
+
this.scheduleSave();
|
|
124
|
+
}
|
|
125
|
+
}
|
|
106
126
|
scheduleSave() {
|
|
107
127
|
if (this.saveTimer)
|
|
108
128
|
return;
|
|
@@ -129,6 +149,13 @@ class KeyManager {
|
|
|
129
149
|
return;
|
|
130
150
|
const data = JSON.parse(fs_1.default.readFileSync(this.storePath, 'utf-8'));
|
|
131
151
|
for (const [id, key] of data) {
|
|
152
|
+
// Upgrade legacy schema key attributes
|
|
153
|
+
if (key && key.usage) {
|
|
154
|
+
if (key.usage.monthly === undefined)
|
|
155
|
+
key.usage.monthly = 0;
|
|
156
|
+
if (key.usage.lastMonthlyReset === undefined)
|
|
157
|
+
key.usage.lastMonthlyReset = key.usage.lastReset || Date.now();
|
|
158
|
+
}
|
|
132
159
|
this.keys.set(id, key);
|
|
133
160
|
}
|
|
134
161
|
console.log(`[KeyManager] Loaded ${this.keys.size} keys`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"KeyManager.js","sourceRoot":"","sources":["../../../src/cloud/KeyManager.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;;;;AAEH,oDAA4B;AAC5B,4CAAoB;AACpB,gDAAwB;AACxB,mCAA8C;AAE9C,MAAa,UAAU;IAKrB,YAAY,SAAS,GAAG,kBAAkB;QAJlC,SAAI,GAAG,IAAI,GAAG,EAAkB,CAAC;QAEjC,cAAS,GAA0B,IAAI,CAAC;QAG9C,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;QAC3B,IAAI,CAAC,IAAI,EAAE,CAAC;IACd,CAAC;IAED,+EAA+E;IAE/E,QAAQ,CAAC,QAAgB,EAAE,IAAY,EAAE,OAAuB,MAAM;QACpE,MAAM,EAAE,GAAG,MAAM,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,IAAI,gBAAM,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QAC/F,MAAM,GAAG,GAAW;YAClB,EAAE;YACF,QAAQ;YACR,IAAI;YACJ,IAAI;YACJ,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;YACrB,MAAM,EAAE,IAAI;YACZ,KAAK,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE;
|
|
1
|
+
{"version":3,"file":"KeyManager.js","sourceRoot":"","sources":["../../../src/cloud/KeyManager.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;;;;AAEH,oDAA4B;AAC5B,4CAAoB;AACpB,gDAAwB;AACxB,mCAA8C;AAE9C,MAAa,UAAU;IAKrB,YAAY,SAAS,GAAG,kBAAkB;QAJlC,SAAI,GAAG,IAAI,GAAG,EAAkB,CAAC;QAEjC,cAAS,GAA0B,IAAI,CAAC;QAG9C,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;QAC3B,IAAI,CAAC,IAAI,EAAE,CAAC;IACd,CAAC;IAED,+EAA+E;IAE/E,QAAQ,CAAC,QAAgB,EAAE,IAAY,EAAE,OAAuB,MAAM;QACpE,MAAM,EAAE,GAAG,MAAM,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,IAAI,gBAAM,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QAC/F,MAAM,GAAG,GAAW;YAClB,EAAE;YACF,QAAQ;YACR,IAAI;YACJ,IAAI;YACJ,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;YACrB,MAAM,EAAE,IAAI;YACZ,KAAK,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,gBAAgB,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE;SAC/F,CAAC;QACF,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;QACvB,IAAI,CAAC,YAAY,EAAE,CAAC;QACpB,OAAO,GAAG,CAAC;IACb,CAAC;IAED,+EAA+E;IAE/E,QAAQ,CAAC,KAAa;QACpB,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAEjC,IAAI,CAAC,GAAG;YAAY,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,iBAAiB,EAAE,CAAC;QACvE,IAAI,CAAC,GAAG,CAAC,MAAM;YAAK,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,sBAAsB,EAAE,CAAC;QAC5E,IAAI,GAAG,CAAC,SAAS,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,GAAG,CAAC,SAAS,EAAE,CAAC;YAChD,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,qBAAqB,EAAE,CAAC;QACzD,CAAC;QAED,gCAAgC;QAChC,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC;QAC1B,kCAAkC;QAClC,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,CAAC;QAE5B,oBAAoB;QACpB,MAAM,MAAM,GAAG,mBAAW,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACrC,IAAI,GAAG,CAAC,KAAK,CAAC,KAAK,IAAI,MAAM,CAAC,aAAa,EAAE,CAAC;YAC5C,OAAO;gBACL,KAAK,EAAE,KAAK;gBACZ,MAAM,EAAE,GAAG,CAAC,IAAI,KAAK,MAAM;oBACzB,CAAC,CAAC,uEAAuE;oBACzE,CAAC,CAAC,kEAAkE;aACvE,CAAC;QACJ,CAAC;QAED,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,GAAG,CAAC,KAAK,CAAC,OAAO,IAAI,MAAM,CAAC,eAAe,EAAE,CAAC;YAC7E,OAAO;gBACL,KAAK,EAAE,KAAK;gBACZ,MAAM,EAAE,yDAAyD;aAClE,CAAC;QACJ,CAAC;QAGD,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC;IAC9B,CAAC;IAED,+EAA+E;IAE/E,aAAa,CAAC,KAAa;QACzB,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACjC,IAAI,CAAC,GAAG;YAAE,OAAO;QACjB,GAAG,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;QAClB,GAAG,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC;QACpB,GAAG,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;QAClB,IAAI,CAAC,YAAY,EAAE,CAAC;IACtB,CAAC;IAED,+EAA+E;IAE/E,WAAW,CAAC,KAAa,EAAE,IAAoB;QAC7C,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACjC,IAAI,CAAC,GAAG;YAAE,OAAO,KAAK,CAAC;QACvB,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC;QAChB,IAAI,CAAC,YAAY,EAAE,CAAC;QACpB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,CAAC,KAAa;QAClB,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACjC,IAAI,CAAC,GAAG;YAAE,OAAO,KAAK,CAAC;QACvB,GAAG,CAAC,MAAM,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,YAAY,EAAE,CAAC;QACpB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,WAAW,CAAC,QAAgB;QAC1B,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC;IAC7E,CAAC;IAED,GAAG,CAAC,KAAa;QACf,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IAC9B,CAAC;IAED,+EAA+E;IAEvE,eAAe,CAAC,GAAW;QACjC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,MAAM,QAAQ,GAAG,IAAI,IAAI,EAAE,CAAC;QAC5B,QAAQ,CAAC,WAAW,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;QACjC,IAAI,GAAG,CAAC,KAAK,CAAC,SAAS,GAAG,QAAQ,CAAC,OAAO,EAAE,EAAE,CAAC;YAC7C,GAAG,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC;YACpB,GAAG,CAAC,KAAK,CAAC,SAAS,GAAG,GAAG,CAAC;QAC5B,CAAC;IACH,CAAC;IAEO,iBAAiB,CAAC,GAAW;QACnC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,MAAM,WAAW,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC;QAClC,MAAM,aAAa,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,gBAAgB,IAAI,CAAC,CAAC,CAAC;QAEhE,IACE,WAAW,CAAC,WAAW,EAAE,KAAK,aAAa,CAAC,WAAW,EAAE;YACzD,WAAW,CAAC,cAAc,EAAE,KAAK,aAAa,CAAC,cAAc,EAAE,EAC/D,CAAC;YACD,GAAG,CAAC,KAAK,CAAC,OAAO,GAAG,CAAC,CAAC;YACtB,GAAG,CAAC,KAAK,CAAC,gBAAgB,GAAG,GAAG,CAAC;YACjC,IAAI,CAAC,YAAY,EAAE,CAAC;QACtB,CAAC;IACH,CAAC;IAEO,YAAY;QAClB,IAAI,IAAI,CAAC,SAAS;YAAE,OAAO;QAC3B,IAAI,CAAC,SAAS,GAAG,UAAU,CAAC,GAAG,EAAE;YAC/B,IAAI,CAAC,IAAI,EAAE,CAAC;YACZ,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;QACxB,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,kBAAkB;IAC9B,CAAC;IAEO,IAAI;QACV,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,cAAI,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YACzC,IAAI,CAAC,YAAE,CAAC,UAAU,CAAC,GAAG,CAAC;gBAAE,YAAE,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YAChE,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;YACtE,YAAE,CAAC,aAAa,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;QAClD,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,CAAC,KAAK,CAAC,mCAAmC,EAAE,GAAG,CAAC,CAAC;QAC1D,CAAC;IACH,CAAC;IAEO,IAAI;QACV,IAAI,CAAC;YACH,IAAI,CAAC,YAAE,CAAC,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC;gBAAE,OAAO;YAC3C,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,YAAE,CAAC,YAAY,CAAC,IAAI,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC,CAAC;YAClE,KAAK,MAAM,CAAC,EAAE,EAAE,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC;gBAC7B,uCAAuC;gBACvC,IAAI,GAAG,IAAI,GAAG,CAAC,KAAK,EAAE,CAAC;oBACrB,IAAI,GAAG,CAAC,KAAK,CAAC,OAAO,KAAK,SAAS;wBAAE,GAAG,CAAC,KAAK,CAAC,OAAO,GAAG,CAAC,CAAC;oBAC3D,IAAI,GAAG,CAAC,KAAK,CAAC,gBAAgB,KAAK,SAAS;wBAAE,GAAG,CAAC,KAAK,CAAC,gBAAgB,GAAG,GAAG,CAAC,KAAK,CAAC,SAAS,IAAI,IAAI,CAAC,GAAG,EAAE,CAAC;gBAC/G,CAAC;gBACD,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,GAAa,CAAC,CAAC;YACnC,CAAC;YACD,OAAO,CAAC,GAAG,CAAC,uBAAuB,IAAI,CAAC,IAAI,CAAC,IAAI,OAAO,CAAC,CAAC;QAC5D,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,CAAC,KAAK,CAAC,mCAAmC,EAAE,GAAG,CAAC,CAAC;QAC1D,CAAC;IACH,CAAC;CACF;AAtKD,gCAsKC"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { Pool } from 'pg';
|
|
2
|
+
export interface TenantQuota {
|
|
3
|
+
tenantId: string;
|
|
4
|
+
totalRequestsThisMonth: number;
|
|
5
|
+
quotaLimit: number;
|
|
6
|
+
billingCycleResetDate: Date;
|
|
7
|
+
}
|
|
8
|
+
export declare class PostgresQuotaLimiter {
|
|
9
|
+
private pool;
|
|
10
|
+
private inMemoryQuotas;
|
|
11
|
+
private pendingIncrements;
|
|
12
|
+
private flushIntervalMs;
|
|
13
|
+
private flushTimer;
|
|
14
|
+
private isFlushing;
|
|
15
|
+
constructor(pool: Pool, flushIntervalMs?: number);
|
|
16
|
+
/**
|
|
17
|
+
* Start the background flush timer
|
|
18
|
+
*/
|
|
19
|
+
start(): void;
|
|
20
|
+
/**
|
|
21
|
+
* Stop the background flush timer and flush any remaining increments
|
|
22
|
+
*/
|
|
23
|
+
stop(): Promise<void>;
|
|
24
|
+
/**
|
|
25
|
+
* Synchronously validate a tenant's request against in-memory limits.
|
|
26
|
+
* If a cache miss occurs, initializes with default limits and lazily loads from Postgres in the background.
|
|
27
|
+
*/
|
|
28
|
+
checkQuota(tenantId: string, defaultLimit?: number): {
|
|
29
|
+
allowed: boolean;
|
|
30
|
+
reason?: string;
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* Lazily loads tenant quota details from PostgreSQL in the background.
|
|
34
|
+
* Merges loaded DB counts with any in-memory increments that accumulated in the meantime.
|
|
35
|
+
*/
|
|
36
|
+
private lazyLoadTenantQuota;
|
|
37
|
+
/**
|
|
38
|
+
* Queue increments in memory to await bulk batch flush
|
|
39
|
+
*/
|
|
40
|
+
private enqueueIncrement;
|
|
41
|
+
/**
|
|
42
|
+
* Performs an atomic database bulk UPSERT of all pending in-memory increments.
|
|
43
|
+
* If a database error occurs, pending increments are safely rolled back and merged
|
|
44
|
+
* into the in-memory map to try again in the next batch flush cycle.
|
|
45
|
+
*/
|
|
46
|
+
flushPendingIncrements(): Promise<void>;
|
|
47
|
+
/**
|
|
48
|
+
* Helper to calculate the 1st of the next calendar month at midnight UTC
|
|
49
|
+
*/
|
|
50
|
+
private calculateNextResetDate;
|
|
51
|
+
/**
|
|
52
|
+
* For test harness only: directly seed an in-memory quota entry
|
|
53
|
+
*/
|
|
54
|
+
seedQuotaForTest(tenantId: string, quota: TenantQuota): void;
|
|
55
|
+
/**
|
|
56
|
+
* For test harness only: check in-memory status
|
|
57
|
+
*/
|
|
58
|
+
getInMemoryQuota(tenantId: string): TenantQuota | undefined;
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=PostgresQuotaLimiter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PostgresQuotaLimiter.d.ts","sourceRoot":"","sources":["../../../src/cloud/PostgresQuotaLimiter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,IAAI,CAAC;AAE1B,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,sBAAsB,EAAE,MAAM,CAAC;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,qBAAqB,EAAE,IAAI,CAAC;CAC7B;AAED,qBAAa,oBAAoB;IAC/B,OAAO,CAAC,IAAI,CAAO;IACnB,OAAO,CAAC,cAAc,CAAkC;IACxD,OAAO,CAAC,iBAAiB,CAA6B;IACtD,OAAO,CAAC,eAAe,CAAS;IAChC,OAAO,CAAC,UAAU,CAA+B;IACjD,OAAO,CAAC,UAAU,CAAS;gBAEf,IAAI,EAAE,IAAI,EAAE,eAAe,SAAO;IAK9C;;OAEG;IACH,KAAK,IAAI,IAAI;IAUb;;OAEG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAS3B;;;OAGG;IACH,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,YAAY,SAAQ,GAAG;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE;IA6CzF;;;OAGG;YACW,mBAAmB;IA8CjC;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAKxB;;;;OAIG;IACG,sBAAsB,IAAI,OAAO,CAAC,IAAI,CAAC;IAiD7C;;OAEG;IACH,OAAO,CAAC,sBAAsB;IAQ9B;;OAEG;IACH,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,GAAG,IAAI;IAI5D;;OAEG;IACH,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS;CAG5D"}
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PostgresQuotaLimiter = void 0;
|
|
4
|
+
class PostgresQuotaLimiter {
|
|
5
|
+
constructor(pool, flushIntervalMs = 5000) {
|
|
6
|
+
this.inMemoryQuotas = new Map();
|
|
7
|
+
this.pendingIncrements = new Map();
|
|
8
|
+
this.flushTimer = null;
|
|
9
|
+
this.isFlushing = false;
|
|
10
|
+
this.pool = pool;
|
|
11
|
+
this.flushIntervalMs = flushIntervalMs;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Start the background flush timer
|
|
15
|
+
*/
|
|
16
|
+
start() {
|
|
17
|
+
if (this.flushTimer)
|
|
18
|
+
return;
|
|
19
|
+
this.flushTimer = setInterval(() => {
|
|
20
|
+
this.flushPendingIncrements().catch(err => {
|
|
21
|
+
console.error('[PostgresQuotaLimiter] Background flush failed:', err);
|
|
22
|
+
});
|
|
23
|
+
}, this.flushIntervalMs).unref();
|
|
24
|
+
console.log(`[PostgresQuotaLimiter] Asynchronous batch flusher started (interval: ${this.flushIntervalMs}ms)`);
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Stop the background flush timer and flush any remaining increments
|
|
28
|
+
*/
|
|
29
|
+
async stop() {
|
|
30
|
+
if (this.flushTimer) {
|
|
31
|
+
clearInterval(this.flushTimer);
|
|
32
|
+
this.flushTimer = null;
|
|
33
|
+
}
|
|
34
|
+
console.log('[PostgresQuotaLimiter] Stopping flusher, performing final flush...');
|
|
35
|
+
await this.flushPendingIncrements();
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Synchronously validate a tenant's request against in-memory limits.
|
|
39
|
+
* If a cache miss occurs, initializes with default limits and lazily loads from Postgres in the background.
|
|
40
|
+
*/
|
|
41
|
+
checkQuota(tenantId, defaultLimit = 50000) {
|
|
42
|
+
let quota = this.inMemoryQuotas.get(tenantId);
|
|
43
|
+
if (!quota) {
|
|
44
|
+
// 1. First-time seen in this memory session: initialize with sensible default
|
|
45
|
+
const nextReset = this.calculateNextResetDate();
|
|
46
|
+
quota = {
|
|
47
|
+
tenantId,
|
|
48
|
+
totalRequestsThisMonth: 0,
|
|
49
|
+
quotaLimit: defaultLimit,
|
|
50
|
+
billingCycleResetDate: nextReset,
|
|
51
|
+
};
|
|
52
|
+
this.inMemoryQuotas.set(tenantId, quota);
|
|
53
|
+
// 2. Trigger asynchronous, non-blocking load from PostgreSQL
|
|
54
|
+
this.lazyLoadTenantQuota(tenantId, defaultLimit).catch(err => {
|
|
55
|
+
console.error(`[PostgresQuotaLimiter] Failed to lazy load quota for ${tenantId}:`, err);
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
const now = Date.now();
|
|
59
|
+
// 3. Handle calendar reset boundary checking
|
|
60
|
+
if (now >= quota.billingCycleResetDate.getTime()) {
|
|
61
|
+
quota.totalRequestsThisMonth = 0;
|
|
62
|
+
quota.billingCycleResetDate = this.calculateNextResetDate();
|
|
63
|
+
// Record a zero-increment upsert to sync the new reset date to Postgres
|
|
64
|
+
this.enqueueIncrement(tenantId, 0);
|
|
65
|
+
}
|
|
66
|
+
// 4. Validate quota limit
|
|
67
|
+
if (quota.totalRequestsThisMonth >= quota.quotaLimit) {
|
|
68
|
+
return {
|
|
69
|
+
allowed: false,
|
|
70
|
+
reason: 'Monthly Cloud Quota Exceeded. Please upgrade your plan.',
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
// 5. Allow request, increment counter locally, and queue the increment
|
|
74
|
+
quota.totalRequestsThisMonth++;
|
|
75
|
+
this.enqueueIncrement(tenantId, 1);
|
|
76
|
+
return { allowed: true };
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Lazily loads tenant quota details from PostgreSQL in the background.
|
|
80
|
+
* Merges loaded DB counts with any in-memory increments that accumulated in the meantime.
|
|
81
|
+
*/
|
|
82
|
+
async lazyLoadTenantQuota(tenantId, defaultLimit) {
|
|
83
|
+
try {
|
|
84
|
+
const result = await this.pool.query('SELECT total_requests_this_month, quota_limit, billing_cycle_reset_date FROM tenant_quotas WHERE tenant_id = $1', [tenantId]);
|
|
85
|
+
const nextReset = this.calculateNextResetDate();
|
|
86
|
+
if (result.rows.length > 0) {
|
|
87
|
+
const row = result.rows[0];
|
|
88
|
+
const dbQuota = {
|
|
89
|
+
tenantId,
|
|
90
|
+
totalRequestsThisMonth: parseInt(row.total_requests_this_month, 10),
|
|
91
|
+
quotaLimit: parseInt(row.quota_limit, 10),
|
|
92
|
+
billingCycleResetDate: new Date(row.billing_cycle_reset_date),
|
|
93
|
+
};
|
|
94
|
+
const currentQuota = this.inMemoryQuotas.get(tenantId);
|
|
95
|
+
if (currentQuota) {
|
|
96
|
+
// Check if DB stored reset date has expired in the real world
|
|
97
|
+
if (Date.now() >= dbQuota.billingCycleResetDate.getTime()) {
|
|
98
|
+
dbQuota.totalRequestsThisMonth = 0;
|
|
99
|
+
dbQuota.billingCycleResetDate = nextReset;
|
|
100
|
+
}
|
|
101
|
+
// Merge: Add currently accumulated pending increments onto DB count
|
|
102
|
+
const pending = this.pendingIncrements.get(tenantId) || 0;
|
|
103
|
+
currentQuota.totalRequestsThisMonth = dbQuota.totalRequestsThisMonth + pending;
|
|
104
|
+
currentQuota.quotaLimit = dbQuota.quotaLimit;
|
|
105
|
+
currentQuota.billingCycleResetDate = dbQuota.billingCycleResetDate;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
// First-time tenant insertion in Postgres (UPSERT to initialize)
|
|
110
|
+
await this.pool.query(`INSERT INTO tenant_quotas (tenant_id, total_requests_this_month, quota_limit, billing_cycle_reset_date)
|
|
111
|
+
VALUES ($1, 0, $2, $3)
|
|
112
|
+
ON CONFLICT (tenant_id) DO NOTHING`, [tenantId, defaultLimit, nextReset]);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
catch (err) {
|
|
116
|
+
console.error(`[PostgresQuotaLimiter] Database load error for tenant ${tenantId}:`, err);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Queue increments in memory to await bulk batch flush
|
|
121
|
+
*/
|
|
122
|
+
enqueueIncrement(tenantId, amount) {
|
|
123
|
+
const current = this.pendingIncrements.get(tenantId) || 0;
|
|
124
|
+
this.pendingIncrements.set(tenantId, current + amount);
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Performs an atomic database bulk UPSERT of all pending in-memory increments.
|
|
128
|
+
* If a database error occurs, pending increments are safely rolled back and merged
|
|
129
|
+
* into the in-memory map to try again in the next batch flush cycle.
|
|
130
|
+
*/
|
|
131
|
+
async flushPendingIncrements() {
|
|
132
|
+
if (this.isFlushing || this.pendingIncrements.size === 0)
|
|
133
|
+
return;
|
|
134
|
+
this.isFlushing = true;
|
|
135
|
+
// Shallow copy and clear the queue immediately to avoid race conditions
|
|
136
|
+
// with new inbound requests accumulating during database I/O
|
|
137
|
+
const incrementsToFlush = new Map(this.pendingIncrements);
|
|
138
|
+
this.pendingIncrements.clear();
|
|
139
|
+
try {
|
|
140
|
+
const client = await this.pool.connect();
|
|
141
|
+
try {
|
|
142
|
+
await client.query('BEGIN');
|
|
143
|
+
for (const [tenantId, increment] of incrementsToFlush.entries()) {
|
|
144
|
+
const quota = this.inMemoryQuotas.get(tenantId);
|
|
145
|
+
const limit = quota ? quota.quotaLimit : 50000;
|
|
146
|
+
const resetDate = quota ? quota.billingCycleResetDate : this.calculateNextResetDate();
|
|
147
|
+
await client.query(`INSERT INTO tenant_quotas (tenant_id, total_requests_this_month, quota_limit, billing_cycle_reset_date)
|
|
148
|
+
VALUES ($1, $2, $3, $4)
|
|
149
|
+
ON CONFLICT (tenant_id) DO UPDATE
|
|
150
|
+
SET total_requests_this_month = tenant_quotas.total_requests_this_month + EXCLUDED.total_requests_this_month,
|
|
151
|
+
billing_cycle_reset_date = EXCLUDED.billing_cycle_reset_date,
|
|
152
|
+
updated_at = CURRENT_TIMESTAMP`, [tenantId, increment, limit, resetDate]);
|
|
153
|
+
}
|
|
154
|
+
await client.query('COMMIT');
|
|
155
|
+
}
|
|
156
|
+
catch (err) {
|
|
157
|
+
await client.query('ROLLBACK');
|
|
158
|
+
throw err;
|
|
159
|
+
}
|
|
160
|
+
finally {
|
|
161
|
+
client.release();
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
catch (err) {
|
|
165
|
+
console.error('[PostgresQuotaLimiter] Batch flush database error. Restoring increments:', err);
|
|
166
|
+
// Restore increments back to pending list so they are retried on the next run
|
|
167
|
+
for (const [tenantId, increment] of incrementsToFlush.entries()) {
|
|
168
|
+
const current = this.pendingIncrements.get(tenantId) || 0;
|
|
169
|
+
this.pendingIncrements.set(tenantId, current + increment);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
finally {
|
|
173
|
+
this.isFlushing = false;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Helper to calculate the 1st of the next calendar month at midnight UTC
|
|
178
|
+
*/
|
|
179
|
+
calculateNextResetDate() {
|
|
180
|
+
const d = new Date();
|
|
181
|
+
d.setUTCMonth(d.getUTCMonth() + 1);
|
|
182
|
+
d.setUTCDate(1);
|
|
183
|
+
d.setUTCHours(0, 0, 0, 0);
|
|
184
|
+
return d;
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* For test harness only: directly seed an in-memory quota entry
|
|
188
|
+
*/
|
|
189
|
+
seedQuotaForTest(tenantId, quota) {
|
|
190
|
+
this.inMemoryQuotas.set(tenantId, quota);
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* For test harness only: check in-memory status
|
|
194
|
+
*/
|
|
195
|
+
getInMemoryQuota(tenantId) {
|
|
196
|
+
return this.inMemoryQuotas.get(tenantId);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
exports.PostgresQuotaLimiter = PostgresQuotaLimiter;
|
|
200
|
+
//# sourceMappingURL=PostgresQuotaLimiter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PostgresQuotaLimiter.js","sourceRoot":"","sources":["../../../src/cloud/PostgresQuotaLimiter.ts"],"names":[],"mappings":"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"}
|
|
@@ -23,7 +23,7 @@ export declare class TenantCache {
|
|
|
23
23
|
data?: any;
|
|
24
24
|
similarity?: number;
|
|
25
25
|
}>;
|
|
26
|
-
store(key: string, input: string, data: any, ttl: number): Promise<void>;
|
|
26
|
+
store(key: string, input: string, data: any, ttl: number, maxEntries?: number): Promise<void>;
|
|
27
27
|
getStats(): Promise<TenantStats>;
|
|
28
28
|
private embed;
|
|
29
29
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TenantCache.d.ts","sourceRoot":"","sources":["../../../src/cloud/TenantCache.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,WAAW,EAAuD,MAAM,SAAS,CAAC;AAU3F,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,cAAc,CAAS;IAE/B,OAAO,CAAC,YAAY,CAAa;IACjC,OAAO,CAAC,gBAAgB,CAAa;IACrC,OAAO,CAAC,cAAc,CAA+B;IACrD,OAAO,CAAC,SAAS,CAAa;IAE9B,OAAO,CAAC,KAAK,CAA0B;gBAE3B,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM;IAS3E,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAW3B,KAAK,CACT,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC;QAAE,GAAG,EAAE,OAAO,CAAC;QAAC,IAAI,CAAC,EAAE,GAAG,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"TenantCache.d.ts","sourceRoot":"","sources":["../../../src/cloud/TenantCache.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,WAAW,EAAuD,MAAM,SAAS,CAAC;AAU3F,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,cAAc,CAAS;IAE/B,OAAO,CAAC,YAAY,CAAa;IACjC,OAAO,CAAC,gBAAgB,CAAa;IACrC,OAAO,CAAC,cAAc,CAA+B;IACrD,OAAO,CAAC,SAAS,CAAa;IAE9B,OAAO,CAAC,KAAK,CAA0B;gBAE3B,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM;IAS3E,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAW3B,KAAK,CACT,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC;QAAE,GAAG,EAAE,OAAO,CAAC;QAAC,IAAI,CAAC,EAAE,GAAG,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAuDvD,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,UAAU,SAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IA+B5F,QAAQ,IAAI,OAAO,CAAC,WAAW,CAAC;YAyBxB,KAAK;CAyCpB"}
|
|
@@ -85,9 +85,21 @@ class TenantCache {
|
|
|
85
85
|
return { hit: false };
|
|
86
86
|
}
|
|
87
87
|
const meta = results.metadatas[0][0];
|
|
88
|
-
|
|
89
|
-
|
|
88
|
+
const age = Date.now() - meta.createdAt;
|
|
89
|
+
// 1. Enforce strict 7-day TTL cache eviction policy (Pro/SaaS tier)
|
|
90
|
+
const MAX_TTL_MS = 7 * 24 * 60 * 60 * 1000; // 7 days
|
|
91
|
+
if (age > MAX_TTL_MS) {
|
|
90
92
|
this.stats.misses++;
|
|
93
|
+
// Evict expired entry from vector database in background
|
|
94
|
+
const expiredId = results.ids[0][0];
|
|
95
|
+
this.chromaCollection.delete({ ids: [expiredId] }).catch(() => { });
|
|
96
|
+
return { hit: false };
|
|
97
|
+
}
|
|
98
|
+
// 2. Check custom entry TTL
|
|
99
|
+
if (meta.ttl > 0 && age > meta.ttl) {
|
|
100
|
+
this.stats.misses++;
|
|
101
|
+
const expiredId = results.ids[0][0];
|
|
102
|
+
this.chromaCollection.delete({ ids: [expiredId] }).catch(() => { });
|
|
91
103
|
return { hit: false };
|
|
92
104
|
}
|
|
93
105
|
this.stats.hits++;
|
|
@@ -99,10 +111,16 @@ class TenantCache {
|
|
|
99
111
|
}
|
|
100
112
|
}
|
|
101
113
|
// ─── Store ──────────────────────────────────────────────────────────────────
|
|
102
|
-
async store(key, input, data, ttl) {
|
|
114
|
+
async store(key, input, data, ttl, maxEntries = 10000) {
|
|
103
115
|
if (!this.chromaCollection)
|
|
104
116
|
await this.initialize();
|
|
105
117
|
try {
|
|
118
|
+
// Enforce maximum cache entries constraint to prevent storage bloat
|
|
119
|
+
const count = await this.chromaCollection.count();
|
|
120
|
+
if (count >= maxEntries) {
|
|
121
|
+
console.warn(`⚠️ [TenantCache:${this.tenantId}] Vector cache limit reached (${count}/${maxEntries} entries). Skipping store to prevent storage bloat.`);
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
106
124
|
const embedding = await this.embed(input);
|
|
107
125
|
await this.chromaCollection.upsert({
|
|
108
126
|
ids: [key],
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TenantCache.js","sourceRoot":"","sources":["../../../src/cloud/TenantCache.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAGH,mCAA2F;AAU3F,MAAa,WAAW;IActB,YAAY,QAAgB,EAAE,SAAiB,EAAE,SAAiB,EAAE,KAAa;QAPzE,iBAAY,GAAQ,IAAI,CAAC;QACzB,qBAAgB,GAAQ,IAAI,CAAC;QAC7B,mBAAc,GAAG,IAAI,GAAG,EAAoB,CAAC;QAC7C,cAAS,GAAQ,IAAI,CAAC;QAEtB,UAAK,GAAG,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC;QAGrC,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;QAC3B,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;QAC3B,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,iDAAiD;QACjD,IAAI,CAAC,cAAc,GAAG,SAAS,QAAQ,CAAC,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC;IACtF,CAAC;IAED,KAAK,CAAC,UAAU;QACd,MAAM,EAAE,YAAY,EAAE,GAAG,wDAAa,UAAU,GAAC,CAAC;QAClD,IAAI,CAAC,YAAY,GAAG,IAAI,YAAY,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC;QAC/D,IAAI,CAAC,gBAAgB,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,qBAAqB,CAAC;YACpE,IAAI,EAAE,IAAI,CAAC,cAAc;YACzB,QAAQ,EAAE,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,CAAC,QAAQ,EAAE;SAC5D,CAAC,CAAC;IACL,CAAC;IAED,+EAA+E;IAE/E,KAAK,CAAC,KAAK,CACT,KAAa,EACb,SAAiB;QAEjB,IAAI,CAAC,IAAI,CAAC,gBAAgB;YAAE,MAAM,IAAI,CAAC,UAAU,EAAE,CAAC;QAEpD,IAAI,CAAC;YACH,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;YAC1C,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,gBAAgB,CAAC,KAAK,CAAC;gBAChD,eAAe,EAAE,CAAC,SAAS,CAAC;gBAC5B,QAAQ,EAAE,CAAC;gBACX,OAAO,EAAE,CAAC,WAAW,EAAE,WAAW,CAAC;aACpC,CAAC,CAAC;YAEH,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC;gBAC9B,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC;gBACpB,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC;YACxB,CAAC;YAED,MAAM,QAAQ,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YACzC,MAAM,UAAU,GAAG,CAAC,GAAG,QAAQ,CAAC;YAEhC,IAAI,UAAU,GAAG,SAAS,EAAE,CAAC;gBAC3B,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC;gBACpB,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC;YACxB,CAAC;YAED,MAAM,IAAI,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAQ,CAAC;
|
|
1
|
+
{"version":3,"file":"TenantCache.js","sourceRoot":"","sources":["../../../src/cloud/TenantCache.ts"],"names":[],"mappings":"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"}
|
|
@@ -10,8 +10,10 @@
|
|
|
10
10
|
*/
|
|
11
11
|
import { KeyManager } from './KeyManager';
|
|
12
12
|
import { TenantCache } from './TenantCache';
|
|
13
|
+
import { PostgresQuotaLimiter } from './PostgresQuotaLimiter';
|
|
13
14
|
declare const app: import("express-serve-static-core").Express;
|
|
14
15
|
declare const keyManager: KeyManager;
|
|
15
16
|
declare const tenantCaches: Map<string, TenantCache>;
|
|
16
|
-
|
|
17
|
+
declare let postgresQuotaLimiter: PostgresQuotaLimiter | null;
|
|
18
|
+
export { app, keyManager, tenantCaches, postgresQuotaLimiter };
|
|
17
19
|
//# sourceMappingURL=server.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../../src/cloud/server.ts"],"names":[],"mappings":";AACA;;;;;;;;GAQG;AAIH,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../../src/cloud/server.ts"],"names":[],"mappings":";AACA;;;;;;;;GAQG;AAIH,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAI5C,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAG9D,QAAA,MAAM,GAAG,6CAAY,CAAC;AAYtB,QAAA,MAAM,UAAU,YAAmB,CAAC;AACpC,QAAA,MAAM,YAAY,0BAAiC,CAAC;AAIpD,QAAA,IAAI,oBAAoB,EAAE,oBAAoB,GAAG,IAAW,CAAC;AA6U7D,OAAO,EAAE,GAAG,EAAE,UAAU,EAAE,YAAY,EAAE,oBAAoB,EAAE,CAAC"}
|