@superatomai/sdk-node 0.0.28-mds → 0.0.29-mds
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +36 -20
- package/dist/index.d.ts +36 -20
- package/dist/index.js +99 -49
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +99 -49
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1340,7 +1340,30 @@ var Thread = class {
|
|
|
1340
1340
|
// src/threads/thread-manager.ts
|
|
1341
1341
|
var ThreadManager = class _ThreadManager {
|
|
1342
1342
|
constructor() {
|
|
1343
|
+
this.cleanupInterval = null;
|
|
1344
|
+
// Threads older than 7 days are cleaned up
|
|
1345
|
+
this.threadTtlMs = 7 * 24 * 60 * 60 * 1e3;
|
|
1343
1346
|
this.threads = /* @__PURE__ */ new Map();
|
|
1347
|
+
this.startCleanup();
|
|
1348
|
+
}
|
|
1349
|
+
/**
|
|
1350
|
+
* Periodically remove threads older than 7 days.
|
|
1351
|
+
* Runs every hour to avoid frequent iteration over the map.
|
|
1352
|
+
*/
|
|
1353
|
+
startCleanup() {
|
|
1354
|
+
this.cleanupInterval = setInterval(() => {
|
|
1355
|
+
const now = Date.now();
|
|
1356
|
+
let removedCount = 0;
|
|
1357
|
+
for (const [id, thread] of this.threads.entries()) {
|
|
1358
|
+
if (now - thread.getCreatedAt().getTime() > this.threadTtlMs) {
|
|
1359
|
+
this.threads.delete(id);
|
|
1360
|
+
removedCount++;
|
|
1361
|
+
}
|
|
1362
|
+
}
|
|
1363
|
+
if (removedCount > 0) {
|
|
1364
|
+
console.log(`[ThreadManager] Cleaned up ${removedCount} threads older than 7 days (${this.threads.size} remaining)`);
|
|
1365
|
+
}
|
|
1366
|
+
}, 24 * 60 * 60 * 1e3);
|
|
1344
1367
|
}
|
|
1345
1368
|
/**
|
|
1346
1369
|
* Get singleton instance of ThreadManager
|
|
@@ -1429,15 +1452,24 @@ var ThreadManager = class _ThreadManager {
|
|
|
1429
1452
|
};
|
|
1430
1453
|
|
|
1431
1454
|
// src/utils/query-cache.ts
|
|
1455
|
+
import crypto from "crypto";
|
|
1432
1456
|
var QueryCache = class {
|
|
1433
1457
|
constructor() {
|
|
1434
1458
|
this.cache = /* @__PURE__ */ new Map();
|
|
1435
|
-
this.queryIdCache = /* @__PURE__ */ new Map();
|
|
1436
1459
|
this.ttlMs = 10 * 60 * 1e3;
|
|
1437
|
-
// Default: 10 minutes
|
|
1460
|
+
// Default: 10 minutes
|
|
1461
|
+
this.maxCacheSize = 500;
|
|
1462
|
+
// Max data cache entries
|
|
1438
1463
|
this.cleanupInterval = null;
|
|
1464
|
+
// Encryption for queryId tokens
|
|
1465
|
+
this.algorithm = "aes-256-gcm";
|
|
1466
|
+
const keySource = process.env.QUERY_TOKEN_SECRET || "superatom-query-cache-default-key-v1";
|
|
1467
|
+
this.encryptionKey = crypto.createHash("sha256").update(keySource).digest();
|
|
1439
1468
|
this.startCleanup();
|
|
1440
1469
|
}
|
|
1470
|
+
// ============================================
|
|
1471
|
+
// Data Cache (TTL-based, max size)
|
|
1472
|
+
// ============================================
|
|
1441
1473
|
/**
|
|
1442
1474
|
* Set the cache TTL (Time To Live)
|
|
1443
1475
|
* @param minutes - TTL in minutes (default: 10)
|
|
@@ -1453,10 +1485,13 @@ var QueryCache = class {
|
|
|
1453
1485
|
return this.ttlMs / 60 / 1e3;
|
|
1454
1486
|
}
|
|
1455
1487
|
/**
|
|
1456
|
-
* Store query result in cache
|
|
1457
|
-
* Key is the exact query string (or JSON for parameterized queries)
|
|
1488
|
+
* Store query result in data cache
|
|
1458
1489
|
*/
|
|
1459
1490
|
set(query, data) {
|
|
1491
|
+
if (this.cache.size >= this.maxCacheSize) {
|
|
1492
|
+
const oldestKey = this.cache.keys().next().value;
|
|
1493
|
+
if (oldestKey) this.cache.delete(oldestKey);
|
|
1494
|
+
}
|
|
1460
1495
|
this.cache.set(query, {
|
|
1461
1496
|
query,
|
|
1462
1497
|
data,
|
|
@@ -1469,12 +1504,9 @@ var QueryCache = class {
|
|
|
1469
1504
|
*/
|
|
1470
1505
|
get(query) {
|
|
1471
1506
|
const entry = this.cache.get(query);
|
|
1472
|
-
if (!entry)
|
|
1473
|
-
return null;
|
|
1474
|
-
}
|
|
1507
|
+
if (!entry) return null;
|
|
1475
1508
|
if (Date.now() - entry.timestamp > this.ttlMs) {
|
|
1476
1509
|
this.cache.delete(query);
|
|
1477
|
-
logger.debug(`[QueryCache] Entry expired for query (${query.substring(0, 50)}...)`);
|
|
1478
1510
|
return null;
|
|
1479
1511
|
}
|
|
1480
1512
|
logger.info(`[QueryCache] Cache HIT for query (${query.substring(0, 50)}...)`);
|
|
@@ -1511,14 +1543,13 @@ var QueryCache = class {
|
|
|
1511
1543
|
}
|
|
1512
1544
|
return {
|
|
1513
1545
|
size: this.cache.size,
|
|
1514
|
-
queryIdCount:
|
|
1546
|
+
queryIdCount: 0,
|
|
1547
|
+
// No longer stored in memory
|
|
1515
1548
|
oldestEntryAge: oldestTimestamp ? Date.now() - oldestTimestamp : null
|
|
1516
1549
|
};
|
|
1517
1550
|
}
|
|
1518
1551
|
/**
|
|
1519
|
-
* Start periodic cleanup of expired entries.
|
|
1520
|
-
* Only cleans the data cache — queryIdCache entries are permanent (server lifetime)
|
|
1521
|
-
* because queryIds are persisted in dashboard widgets.
|
|
1552
|
+
* Start periodic cleanup of expired data cache entries.
|
|
1522
1553
|
*/
|
|
1523
1554
|
startCleanup() {
|
|
1524
1555
|
this.cleanupInterval = setInterval(() => {
|
|
@@ -1530,61 +1561,81 @@ var QueryCache = class {
|
|
|
1530
1561
|
expiredCount++;
|
|
1531
1562
|
}
|
|
1532
1563
|
}
|
|
1533
|
-
for (const entry of this.queryIdCache.values()) {
|
|
1534
|
-
if (entry.data && now - entry.timestamp > this.ttlMs) {
|
|
1535
|
-
entry.data = null;
|
|
1536
|
-
}
|
|
1537
|
-
}
|
|
1538
1564
|
if (expiredCount > 0) {
|
|
1539
|
-
logger.debug(`[QueryCache] Cleaned up ${expiredCount} expired data-cache entries`);
|
|
1565
|
+
logger.debug(`[QueryCache] Cleaned up ${expiredCount} expired data-cache entries (${this.cache.size} remaining)`);
|
|
1540
1566
|
}
|
|
1541
1567
|
}, 2 * 60 * 1e3);
|
|
1542
1568
|
}
|
|
1543
1569
|
// ============================================
|
|
1544
|
-
// Query ID
|
|
1570
|
+
// Encrypted Query ID Tokens (zero memory)
|
|
1545
1571
|
// ============================================
|
|
1546
1572
|
/**
|
|
1547
|
-
*
|
|
1573
|
+
* Encrypt a payload into a self-contained token.
|
|
1548
1574
|
*/
|
|
1549
|
-
|
|
1550
|
-
|
|
1575
|
+
encrypt(payload) {
|
|
1576
|
+
const iv = crypto.randomBytes(12);
|
|
1577
|
+
const cipher = crypto.createCipheriv(this.algorithm, this.encryptionKey, iv);
|
|
1578
|
+
let encrypted = cipher.update(payload, "utf8", "base64");
|
|
1579
|
+
encrypted += cipher.final("base64");
|
|
1580
|
+
const authTag = cipher.getAuthTag();
|
|
1581
|
+
return iv.toString("base64") + "." + authTag.toString("base64") + "." + encrypted;
|
|
1551
1582
|
}
|
|
1552
1583
|
/**
|
|
1553
|
-
*
|
|
1554
|
-
|
|
1584
|
+
* Decrypt a token back to the original payload.
|
|
1585
|
+
*/
|
|
1586
|
+
decrypt(token) {
|
|
1587
|
+
try {
|
|
1588
|
+
const parts = token.split(".");
|
|
1589
|
+
if (parts.length !== 3) return null;
|
|
1590
|
+
const iv = Buffer.from(parts[0], "base64");
|
|
1591
|
+
const authTag = Buffer.from(parts[1], "base64");
|
|
1592
|
+
const encrypted = parts[2];
|
|
1593
|
+
const decipher = crypto.createDecipheriv(this.algorithm, this.encryptionKey, iv);
|
|
1594
|
+
decipher.setAuthTag(authTag);
|
|
1595
|
+
let decrypted = decipher.update(encrypted, "base64", "utf8");
|
|
1596
|
+
decrypted += decipher.final("utf8");
|
|
1597
|
+
return decrypted;
|
|
1598
|
+
} catch (err) {
|
|
1599
|
+
logger.warn(`[QueryCache] Failed to decrypt queryId token: ${err instanceof Error ? err.message : String(err)}`);
|
|
1600
|
+
return null;
|
|
1601
|
+
}
|
|
1602
|
+
}
|
|
1603
|
+
/**
|
|
1604
|
+
* Store a query by generating an encrypted token as queryId.
|
|
1605
|
+
* The SQL is encrypted INTO the token — nothing stored in memory.
|
|
1606
|
+
* If data is provided, it's cached temporarily in the data cache.
|
|
1555
1607
|
*/
|
|
1556
1608
|
storeQuery(query, data) {
|
|
1557
|
-
const
|
|
1558
|
-
this.
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
});
|
|
1564
|
-
const queryPreview = typeof query === "string" ? query.substring(0, 50) : JSON.stringify(query).substring(0, 50);
|
|
1565
|
-
logger.debug(`[QueryCache] Stored query as ${queryId} (${queryPreview}...)`);
|
|
1609
|
+
const payload = typeof query === "string" ? query : JSON.stringify(query);
|
|
1610
|
+
const queryId = this.encrypt(payload);
|
|
1611
|
+
if (data) {
|
|
1612
|
+
this.set(queryId, data);
|
|
1613
|
+
}
|
|
1614
|
+
const queryPreview = payload.substring(0, 50);
|
|
1615
|
+
logger.debug(`[QueryCache] Stored query as encrypted token (${queryPreview}...)`);
|
|
1566
1616
|
return queryId;
|
|
1567
1617
|
}
|
|
1568
1618
|
/**
|
|
1569
|
-
* Get a stored query by its
|
|
1570
|
-
*
|
|
1571
|
-
* Cached data may be null if it was evicted by the cleanup interval.
|
|
1619
|
+
* Get a stored query by decrypting its token.
|
|
1620
|
+
* Returns the SQL + any cached result data.
|
|
1572
1621
|
*/
|
|
1573
1622
|
getQuery(queryId) {
|
|
1574
|
-
const
|
|
1575
|
-
if (!
|
|
1576
|
-
|
|
1577
|
-
|
|
1623
|
+
const decrypted = this.decrypt(queryId);
|
|
1624
|
+
if (!decrypted) return null;
|
|
1625
|
+
let query;
|
|
1626
|
+
try {
|
|
1627
|
+
query = JSON.parse(decrypted);
|
|
1628
|
+
} catch {
|
|
1629
|
+
query = decrypted;
|
|
1630
|
+
}
|
|
1631
|
+
const cachedData = this.get(queryId);
|
|
1632
|
+
return { query, data: cachedData };
|
|
1578
1633
|
}
|
|
1579
1634
|
/**
|
|
1580
|
-
* Update cached data for a queryId
|
|
1635
|
+
* Update cached data for a queryId token
|
|
1581
1636
|
*/
|
|
1582
1637
|
setQueryData(queryId, data) {
|
|
1583
|
-
|
|
1584
|
-
if (entry) {
|
|
1585
|
-
entry.data = data;
|
|
1586
|
-
entry.timestamp = Date.now();
|
|
1587
|
-
}
|
|
1638
|
+
this.set(queryId, data);
|
|
1588
1639
|
}
|
|
1589
1640
|
/**
|
|
1590
1641
|
* Stop cleanup interval (for graceful shutdown)
|
|
@@ -1595,7 +1646,6 @@ var QueryCache = class {
|
|
|
1595
1646
|
this.cleanupInterval = null;
|
|
1596
1647
|
}
|
|
1597
1648
|
this.cache.clear();
|
|
1598
|
-
this.queryIdCache.clear();
|
|
1599
1649
|
}
|
|
1600
1650
|
};
|
|
1601
1651
|
var queryCache = new QueryCache();
|
|
@@ -2198,7 +2248,7 @@ async function handleBundleRequest(data, bundleDir, sendMessage) {
|
|
|
2198
2248
|
}
|
|
2199
2249
|
|
|
2200
2250
|
// src/auth/utils.ts
|
|
2201
|
-
import
|
|
2251
|
+
import crypto2 from "crypto";
|
|
2202
2252
|
function decodeBase64ToJson(base64Data) {
|
|
2203
2253
|
try {
|
|
2204
2254
|
const decodedString = Buffer.from(base64Data, "base64").toString("utf-8");
|
|
@@ -2208,7 +2258,7 @@ function decodeBase64ToJson(base64Data) {
|
|
|
2208
2258
|
}
|
|
2209
2259
|
}
|
|
2210
2260
|
function hashPassword(password) {
|
|
2211
|
-
return
|
|
2261
|
+
return crypto2.createHash("sha1").update(password).digest("hex");
|
|
2212
2262
|
}
|
|
2213
2263
|
|
|
2214
2264
|
// src/auth/user-storage.ts
|