@digilogiclabs/platform-core 1.3.0 → 1.5.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.
- package/README.md +79 -3
- package/dist/{ConsoleEmail-hUDFsKoA.d.mts → ConsoleEmail-ubSVWgTa.d.mts} +187 -1
- package/dist/{ConsoleEmail-hUDFsKoA.d.ts → ConsoleEmail-ubSVWgTa.d.ts} +187 -1
- package/dist/index.d.mts +1583 -130
- package/dist/index.d.ts +1583 -130
- package/dist/index.js +1978 -169
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1922 -162
- package/dist/index.mjs.map +1 -1
- package/dist/migrate.js +3 -2
- package/dist/migrate.js.map +1 -1
- package/dist/security-headers.d.mts +75 -0
- package/dist/security-headers.d.ts +75 -0
- package/dist/security-headers.js +137 -0
- package/dist/security-headers.js.map +1 -0
- package/dist/security-headers.mjs +111 -0
- package/dist/security-headers.mjs.map +1 -0
- package/dist/testing.d.mts +2 -2
- package/dist/testing.d.ts +2 -2
- package/dist/testing.js +196 -15
- package/dist/testing.js.map +1 -1
- package/dist/testing.mjs +200 -14
- package/dist/testing.mjs.map +1 -1
- package/package.json +16 -11
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
var __defProp = Object.defineProperty;
|
|
2
2
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
3
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
4
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
5
|
+
}) : x)(function(x) {
|
|
6
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
7
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
8
|
+
});
|
|
3
9
|
var __esm = (fn, res) => function __init() {
|
|
4
10
|
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
5
11
|
};
|
|
@@ -387,6 +393,7 @@ var init_IAI = __esm({
|
|
|
387
393
|
});
|
|
388
394
|
|
|
389
395
|
// src/interfaces/IRAG.ts
|
|
396
|
+
import { randomBytes as randomBytes13 } from "crypto";
|
|
390
397
|
var ChunkingPresets, MemoryRAG;
|
|
391
398
|
var init_IRAG = __esm({
|
|
392
399
|
"src/interfaces/IRAG.ts"() {
|
|
@@ -516,7 +523,7 @@ var init_IRAG = __esm({
|
|
|
516
523
|
}
|
|
517
524
|
async ingestOne(collection, document, options) {
|
|
518
525
|
const startTime = Date.now();
|
|
519
|
-
const docId = `doc_${Date.now()}_${
|
|
526
|
+
const docId = `doc_${Date.now()}_${randomBytes13(4).toString("hex")}`;
|
|
520
527
|
const now = /* @__PURE__ */ new Date();
|
|
521
528
|
try {
|
|
522
529
|
const col = await this.getCollection(collection);
|
|
@@ -1059,6 +1066,7 @@ var PostgresDatabase_exports = {};
|
|
|
1059
1066
|
__export(PostgresDatabase_exports, {
|
|
1060
1067
|
PostgresDatabase: () => PostgresDatabase
|
|
1061
1068
|
});
|
|
1069
|
+
import { randomBytes as randomBytes22 } from "crypto";
|
|
1062
1070
|
function toPoolConfig(config) {
|
|
1063
1071
|
const poolConfig = {};
|
|
1064
1072
|
if (config.connectionString) {
|
|
@@ -1209,7 +1217,7 @@ var init_PostgresDatabase = __esm({
|
|
|
1209
1217
|
}
|
|
1210
1218
|
}
|
|
1211
1219
|
async transaction(fn) {
|
|
1212
|
-
const savepointName = `sp_${Date.now()}_${
|
|
1220
|
+
const savepointName = `sp_${Date.now()}_${randomBytes22(4).toString("hex")}`;
|
|
1213
1221
|
try {
|
|
1214
1222
|
await this.client.query(`SAVEPOINT ${savepointName}`);
|
|
1215
1223
|
const result = await fn(this);
|
|
@@ -1737,7 +1745,7 @@ var init_RedisCache = __esm({
|
|
|
1737
1745
|
* Create a RedisCache from configuration
|
|
1738
1746
|
*/
|
|
1739
1747
|
static async create(config) {
|
|
1740
|
-
const { default:
|
|
1748
|
+
const { default: Redis2 } = await import("ioredis");
|
|
1741
1749
|
let client;
|
|
1742
1750
|
if (config.cluster) {
|
|
1743
1751
|
const { Cluster } = await import("ioredis");
|
|
@@ -1750,7 +1758,7 @@ var init_RedisCache = __esm({
|
|
|
1750
1758
|
}
|
|
1751
1759
|
});
|
|
1752
1760
|
} else if (config.sentinel) {
|
|
1753
|
-
client = new
|
|
1761
|
+
client = new Redis2({
|
|
1754
1762
|
sentinels: config.sentinel.sentinels,
|
|
1755
1763
|
name: config.sentinel.name,
|
|
1756
1764
|
password: config.password,
|
|
@@ -1759,7 +1767,7 @@ var init_RedisCache = __esm({
|
|
|
1759
1767
|
});
|
|
1760
1768
|
} else {
|
|
1761
1769
|
const options = toIORedisOptions(config);
|
|
1762
|
-
client = typeof options === "string" ? new
|
|
1770
|
+
client = typeof options === "string" ? new Redis2(options) : new Redis2(options);
|
|
1763
1771
|
}
|
|
1764
1772
|
if (!config.lazyConnect) {
|
|
1765
1773
|
await new Promise((resolve, reject) => {
|
|
@@ -1893,9 +1901,9 @@ var init_RedisCache = __esm({
|
|
|
1893
1901
|
}
|
|
1894
1902
|
async subscribe(channel, callback) {
|
|
1895
1903
|
if (!this.subscriberClient) {
|
|
1896
|
-
const { default:
|
|
1904
|
+
const { default: Redis2 } = await import("ioredis");
|
|
1897
1905
|
const options = toIORedisOptions(this.config);
|
|
1898
|
-
this.subscriberClient = typeof options === "string" ? new
|
|
1906
|
+
this.subscriberClient = typeof options === "string" ? new Redis2(options) : new Redis2(options);
|
|
1899
1907
|
this.subscriberClient.on("message", (ch, message) => {
|
|
1900
1908
|
const callbacks = this.subscriptions.get(ch);
|
|
1901
1909
|
if (callbacks) {
|
|
@@ -5445,6 +5453,7 @@ __export(PineconeRAG_exports, {
|
|
|
5445
5453
|
PineconeRAG: () => PineconeRAG,
|
|
5446
5454
|
createPineconeRAG: () => createPineconeRAG
|
|
5447
5455
|
});
|
|
5456
|
+
import { randomBytes as randomBytes23 } from "crypto";
|
|
5448
5457
|
function createPineconeRAG(config) {
|
|
5449
5458
|
return new PineconeRAG(config);
|
|
5450
5459
|
}
|
|
@@ -5602,7 +5611,7 @@ var init_PineconeRAG = __esm({
|
|
|
5602
5611
|
throw new Error(`Collection ${collection} not found`);
|
|
5603
5612
|
}
|
|
5604
5613
|
const now = /* @__PURE__ */ new Date();
|
|
5605
|
-
const documentId = `doc_${Date.now()}_${
|
|
5614
|
+
const documentId = `doc_${Date.now()}_${randomBytes23(4).toString("hex")}`;
|
|
5606
5615
|
const doc = {
|
|
5607
5616
|
id: documentId,
|
|
5608
5617
|
source: document.source,
|
|
@@ -6166,6 +6175,7 @@ __export(WeaviateRAG_exports, {
|
|
|
6166
6175
|
WeaviateRAG: () => WeaviateRAG,
|
|
6167
6176
|
createWeaviateRAG: () => createWeaviateRAG
|
|
6168
6177
|
});
|
|
6178
|
+
import { randomBytes as randomBytes24 } from "crypto";
|
|
6169
6179
|
function createWeaviateRAG(config) {
|
|
6170
6180
|
return new WeaviateRAG(config);
|
|
6171
6181
|
}
|
|
@@ -6360,7 +6370,7 @@ var init_WeaviateRAG = __esm({
|
|
|
6360
6370
|
const client = await this.getClient();
|
|
6361
6371
|
const className = this.getClassName(collection);
|
|
6362
6372
|
const now = /* @__PURE__ */ new Date();
|
|
6363
|
-
const documentId = `doc_${Date.now()}_${
|
|
6373
|
+
const documentId = `doc_${Date.now()}_${randomBytes24(4).toString("hex")}`;
|
|
6364
6374
|
const doc = {
|
|
6365
6375
|
id: documentId,
|
|
6366
6376
|
source: document.source,
|
|
@@ -6935,7 +6945,183 @@ var init_WeaviateRAG = __esm({
|
|
|
6935
6945
|
}
|
|
6936
6946
|
});
|
|
6937
6947
|
|
|
6948
|
+
// src/adapters/node-crypto/NodeCrypto.ts
|
|
6949
|
+
var NodeCrypto_exports = {};
|
|
6950
|
+
__export(NodeCrypto_exports, {
|
|
6951
|
+
NodeCrypto: () => NodeCrypto
|
|
6952
|
+
});
|
|
6953
|
+
import {
|
|
6954
|
+
randomBytes as randomBytes25,
|
|
6955
|
+
createCipheriv as createCipheriv2,
|
|
6956
|
+
createDecipheriv as createDecipheriv2,
|
|
6957
|
+
createHmac as createHmac2,
|
|
6958
|
+
hkdfSync
|
|
6959
|
+
} from "crypto";
|
|
6960
|
+
var NodeCrypto;
|
|
6961
|
+
var init_NodeCrypto = __esm({
|
|
6962
|
+
"src/adapters/node-crypto/NodeCrypto.ts"() {
|
|
6963
|
+
"use strict";
|
|
6964
|
+
NodeCrypto = class {
|
|
6965
|
+
masterKey;
|
|
6966
|
+
hmacKey;
|
|
6967
|
+
keys = /* @__PURE__ */ new Map();
|
|
6968
|
+
activeKeyId;
|
|
6969
|
+
keyCounter = 0;
|
|
6970
|
+
constructor(config) {
|
|
6971
|
+
if (!config.masterKey || config.masterKey.length < 64) {
|
|
6972
|
+
throw new Error(
|
|
6973
|
+
"NodeCrypto requires a 256-bit master key (64 hex characters)"
|
|
6974
|
+
);
|
|
6975
|
+
}
|
|
6976
|
+
this.masterKey = Buffer.from(config.masterKey, "hex");
|
|
6977
|
+
this.hmacKey = config.hmacKey ? Buffer.from(config.hmacKey, "hex") : Buffer.from(hkdfSync("sha256", this.masterKey, "", "hmac-key", 32));
|
|
6978
|
+
const keyId = this.generateKeyId();
|
|
6979
|
+
const dek = this.deriveDEK(keyId);
|
|
6980
|
+
this.keys.set(keyId, {
|
|
6981
|
+
id: keyId,
|
|
6982
|
+
dek,
|
|
6983
|
+
status: "active",
|
|
6984
|
+
createdAt: /* @__PURE__ */ new Date()
|
|
6985
|
+
});
|
|
6986
|
+
this.activeKeyId = keyId;
|
|
6987
|
+
}
|
|
6988
|
+
async encrypt(plaintext, options) {
|
|
6989
|
+
const keyId = options?.keyId || this.activeKeyId;
|
|
6990
|
+
const stored = this.keys.get(keyId);
|
|
6991
|
+
if (!stored) {
|
|
6992
|
+
throw new Error(`Key not found: ${keyId}`);
|
|
6993
|
+
}
|
|
6994
|
+
if (stored.status === "retired") {
|
|
6995
|
+
throw new Error(`Key is retired and cannot encrypt: ${keyId}`);
|
|
6996
|
+
}
|
|
6997
|
+
if (stored.status === "decrypt-only" && !options?.keyId) {
|
|
6998
|
+
throw new Error(`Key is decrypt-only: ${keyId}`);
|
|
6999
|
+
}
|
|
7000
|
+
const iv = randomBytes25(12);
|
|
7001
|
+
const cipher = createCipheriv2("aes-256-gcm", stored.dek, iv);
|
|
7002
|
+
if (options?.aad) {
|
|
7003
|
+
cipher.setAAD(Buffer.from(options.aad, "utf8"));
|
|
7004
|
+
}
|
|
7005
|
+
const encrypted = Buffer.concat([
|
|
7006
|
+
cipher.update(plaintext, "utf8"),
|
|
7007
|
+
cipher.final()
|
|
7008
|
+
]);
|
|
7009
|
+
const tag = cipher.getAuthTag();
|
|
7010
|
+
return {
|
|
7011
|
+
ciphertext: encrypted.toString("base64"),
|
|
7012
|
+
iv: iv.toString("base64"),
|
|
7013
|
+
tag: tag.toString("base64"),
|
|
7014
|
+
keyId,
|
|
7015
|
+
algorithm: "aes-256-gcm",
|
|
7016
|
+
version: 1
|
|
7017
|
+
};
|
|
7018
|
+
}
|
|
7019
|
+
async decrypt(field, options) {
|
|
7020
|
+
const stored = this.keys.get(field.keyId);
|
|
7021
|
+
if (!stored) {
|
|
7022
|
+
throw new Error(`Key not found: ${field.keyId}`);
|
|
7023
|
+
}
|
|
7024
|
+
if (stored.status === "retired") {
|
|
7025
|
+
throw new Error(`Key is retired and cannot decrypt: ${field.keyId}`);
|
|
7026
|
+
}
|
|
7027
|
+
const decipher = createDecipheriv2(
|
|
7028
|
+
"aes-256-gcm",
|
|
7029
|
+
stored.dek,
|
|
7030
|
+
Buffer.from(field.iv, "base64")
|
|
7031
|
+
);
|
|
7032
|
+
decipher.setAuthTag(Buffer.from(field.tag, "base64"));
|
|
7033
|
+
if (options?.aad) {
|
|
7034
|
+
decipher.setAAD(Buffer.from(options.aad, "utf8"));
|
|
7035
|
+
}
|
|
7036
|
+
const decrypted = Buffer.concat([
|
|
7037
|
+
decipher.update(Buffer.from(field.ciphertext, "base64")),
|
|
7038
|
+
decipher.final()
|
|
7039
|
+
]);
|
|
7040
|
+
return decrypted.toString("utf8");
|
|
7041
|
+
}
|
|
7042
|
+
async encryptDeterministic(plaintext, options) {
|
|
7043
|
+
const hash = await this.computeHash(plaintext);
|
|
7044
|
+
const encrypted = await this.encrypt(plaintext, options);
|
|
7045
|
+
return { hash, encrypted };
|
|
7046
|
+
}
|
|
7047
|
+
async computeHash(plaintext) {
|
|
7048
|
+
return createHmac2("sha256", this.hmacKey).update(plaintext, "utf8").digest("hex");
|
|
7049
|
+
}
|
|
7050
|
+
async encryptBatch(fields, options) {
|
|
7051
|
+
const result = {};
|
|
7052
|
+
for (const [key, value] of Object.entries(fields)) {
|
|
7053
|
+
result[key] = await this.encrypt(value, options);
|
|
7054
|
+
}
|
|
7055
|
+
return result;
|
|
7056
|
+
}
|
|
7057
|
+
async decryptBatch(fields, options) {
|
|
7058
|
+
const result = {};
|
|
7059
|
+
for (const [key, value] of Object.entries(fields)) {
|
|
7060
|
+
result[key] = await this.decrypt(value, options);
|
|
7061
|
+
}
|
|
7062
|
+
return result;
|
|
7063
|
+
}
|
|
7064
|
+
async rotateKey() {
|
|
7065
|
+
const previousKeyId = this.activeKeyId;
|
|
7066
|
+
const currentKey = this.keys.get(previousKeyId);
|
|
7067
|
+
if (currentKey) {
|
|
7068
|
+
currentKey.status = "decrypt-only";
|
|
7069
|
+
}
|
|
7070
|
+
const newKeyId = this.generateKeyId();
|
|
7071
|
+
const dek = this.deriveDEK(newKeyId);
|
|
7072
|
+
this.keys.set(newKeyId, {
|
|
7073
|
+
id: newKeyId,
|
|
7074
|
+
dek,
|
|
7075
|
+
status: "active",
|
|
7076
|
+
createdAt: /* @__PURE__ */ new Date()
|
|
7077
|
+
});
|
|
7078
|
+
this.activeKeyId = newKeyId;
|
|
7079
|
+
return { newKeyId, previousKeyId };
|
|
7080
|
+
}
|
|
7081
|
+
async reEncrypt(field, options) {
|
|
7082
|
+
const plaintext = await this.decrypt(field);
|
|
7083
|
+
return this.encrypt(plaintext, options);
|
|
7084
|
+
}
|
|
7085
|
+
async listKeys() {
|
|
7086
|
+
return Array.from(this.keys.values()).map((k) => ({
|
|
7087
|
+
keyId: k.id,
|
|
7088
|
+
createdAt: k.createdAt,
|
|
7089
|
+
status: k.status
|
|
7090
|
+
}));
|
|
7091
|
+
}
|
|
7092
|
+
async getActiveKeyId() {
|
|
7093
|
+
return this.activeKeyId;
|
|
7094
|
+
}
|
|
7095
|
+
async healthCheck() {
|
|
7096
|
+
try {
|
|
7097
|
+
const testPlain = "health-check-" + randomBytes25(4).toString("hex");
|
|
7098
|
+
const encrypted = await this.encrypt(testPlain);
|
|
7099
|
+
const decrypted = await this.decrypt(encrypted);
|
|
7100
|
+
return decrypted === testPlain;
|
|
7101
|
+
} catch {
|
|
7102
|
+
return false;
|
|
7103
|
+
}
|
|
7104
|
+
}
|
|
7105
|
+
/**
|
|
7106
|
+
* Derive a Data Encryption Key from the master key using HKDF.
|
|
7107
|
+
*/
|
|
7108
|
+
deriveDEK(keyId) {
|
|
7109
|
+
return Buffer.from(
|
|
7110
|
+
hkdfSync("sha256", this.masterKey, keyId, "dek-derivation", 32)
|
|
7111
|
+
);
|
|
7112
|
+
}
|
|
7113
|
+
generateKeyId() {
|
|
7114
|
+
this.keyCounter++;
|
|
7115
|
+
const timestamp = Date.now().toString(36);
|
|
7116
|
+
const random = randomBytes25(4).toString("hex");
|
|
7117
|
+
return `dek_${timestamp}_${random}_${this.keyCounter}`;
|
|
7118
|
+
}
|
|
7119
|
+
};
|
|
7120
|
+
}
|
|
7121
|
+
});
|
|
7122
|
+
|
|
6938
7123
|
// src/interfaces/IQueue.ts
|
|
7124
|
+
import { randomBytes } from "crypto";
|
|
6939
7125
|
function calculateBackoff(attempt, options) {
|
|
6940
7126
|
if (options.type === "fixed") {
|
|
6941
7127
|
return options.delay;
|
|
@@ -6946,7 +7132,7 @@ function calculateBackoff(attempt, options) {
|
|
|
6946
7132
|
}
|
|
6947
7133
|
function generateJobId() {
|
|
6948
7134
|
const timestamp = Date.now().toString(36);
|
|
6949
|
-
const random =
|
|
7135
|
+
const random = randomBytes(4).toString("hex");
|
|
6950
7136
|
return `job_${timestamp}_${random}`;
|
|
6951
7137
|
}
|
|
6952
7138
|
|
|
@@ -7297,6 +7483,7 @@ function createScopedMetrics(metrics, prefix, defaultTags = {}) {
|
|
|
7297
7483
|
}
|
|
7298
7484
|
|
|
7299
7485
|
// src/interfaces/ISecrets.ts
|
|
7486
|
+
import { randomBytes as randomBytes2 } from "crypto";
|
|
7300
7487
|
var EnvSecrets = class {
|
|
7301
7488
|
prefix;
|
|
7302
7489
|
cache = /* @__PURE__ */ new Map();
|
|
@@ -7497,12 +7684,7 @@ var MemorySecrets = class {
|
|
|
7497
7684
|
return true;
|
|
7498
7685
|
}
|
|
7499
7686
|
generateSecureValue(length = 32) {
|
|
7500
|
-
|
|
7501
|
-
let result = "";
|
|
7502
|
-
for (let i = 0; i < length; i++) {
|
|
7503
|
-
result += chars[Math.floor(Math.random() * chars.length)];
|
|
7504
|
-
}
|
|
7505
|
-
return result;
|
|
7687
|
+
return randomBytes2(length).toString("base64url").slice(0, length);
|
|
7506
7688
|
}
|
|
7507
7689
|
/**
|
|
7508
7690
|
* Clear all secrets (for testing)
|
|
@@ -7520,6 +7702,7 @@ var MemorySecrets = class {
|
|
|
7520
7702
|
};
|
|
7521
7703
|
|
|
7522
7704
|
// src/interfaces/ITracing.ts
|
|
7705
|
+
import { randomBytes as randomBytes3 } from "crypto";
|
|
7523
7706
|
var MemorySpan = class {
|
|
7524
7707
|
name;
|
|
7525
7708
|
context;
|
|
@@ -7539,7 +7722,7 @@ var MemorySpan = class {
|
|
|
7539
7722
|
};
|
|
7540
7723
|
}
|
|
7541
7724
|
generateSpanId() {
|
|
7542
|
-
return
|
|
7725
|
+
return randomBytes3(8).toString("hex");
|
|
7543
7726
|
}
|
|
7544
7727
|
setAttribute(key, value) {
|
|
7545
7728
|
this._attributes[key] = value;
|
|
@@ -7599,7 +7782,7 @@ var MemoryTracing = class {
|
|
|
7599
7782
|
this.traceId = this.generateTraceId();
|
|
7600
7783
|
}
|
|
7601
7784
|
generateTraceId() {
|
|
7602
|
-
return
|
|
7785
|
+
return randomBytes3(16).toString("hex");
|
|
7603
7786
|
}
|
|
7604
7787
|
startSpan(name, options) {
|
|
7605
7788
|
const span = new MemorySpan(
|
|
@@ -7752,9 +7935,10 @@ var NoopTracing = class {
|
|
|
7752
7935
|
};
|
|
7753
7936
|
|
|
7754
7937
|
// src/interfaces/IErrorReporter.ts
|
|
7938
|
+
import { randomBytes as randomBytes4 } from "crypto";
|
|
7755
7939
|
function generateErrorId() {
|
|
7756
7940
|
const timestamp = Date.now().toString(36);
|
|
7757
|
-
const random =
|
|
7941
|
+
const random = randomBytes4(4).toString("hex");
|
|
7758
7942
|
return `err_${timestamp}_${random}`;
|
|
7759
7943
|
}
|
|
7760
7944
|
function generateFingerprint(error) {
|
|
@@ -7798,9 +7982,10 @@ function createErrorReport(error, context, options) {
|
|
|
7798
7982
|
}
|
|
7799
7983
|
|
|
7800
7984
|
// src/interfaces/IAuditLog.ts
|
|
7985
|
+
import { randomBytes as randomBytes5 } from "crypto";
|
|
7801
7986
|
function generateAuditId() {
|
|
7802
7987
|
const timestamp = Date.now().toString(36);
|
|
7803
|
-
const random =
|
|
7988
|
+
const random = randomBytes5(4).toString("hex");
|
|
7804
7989
|
return `aud_${timestamp}${random}`;
|
|
7805
7990
|
}
|
|
7806
7991
|
function generateChecksum(event) {
|
|
@@ -7966,9 +8151,10 @@ var AuditEvents = {
|
|
|
7966
8151
|
};
|
|
7967
8152
|
|
|
7968
8153
|
// src/interfaces/IScheduler.ts
|
|
8154
|
+
import { randomBytes as randomBytes6 } from "crypto";
|
|
7969
8155
|
function generateScheduleId() {
|
|
7970
8156
|
const timestamp = Date.now().toString(36);
|
|
7971
|
-
const random =
|
|
8157
|
+
const random = randomBytes6(4).toString("hex");
|
|
7972
8158
|
return `sch_${timestamp}${random}`;
|
|
7973
8159
|
}
|
|
7974
8160
|
function getNextCronRun(cron, after = /* @__PURE__ */ new Date(), timezone) {
|
|
@@ -8027,28 +8213,24 @@ function describeCron(cron) {
|
|
|
8027
8213
|
}
|
|
8028
8214
|
|
|
8029
8215
|
// src/interfaces/IWebhook.ts
|
|
8216
|
+
import { randomBytes as randomBytes7 } from "crypto";
|
|
8030
8217
|
function generateWebhookId() {
|
|
8031
8218
|
const timestamp = Date.now().toString(36);
|
|
8032
|
-
const random =
|
|
8219
|
+
const random = randomBytes7(6).toString("hex");
|
|
8033
8220
|
return `wh_${timestamp}${random}`;
|
|
8034
8221
|
}
|
|
8035
8222
|
function generateDeliveryId() {
|
|
8036
8223
|
const timestamp = Date.now().toString(36);
|
|
8037
|
-
const random =
|
|
8224
|
+
const random = randomBytes7(6).toString("hex");
|
|
8038
8225
|
return `del_${timestamp}${random}`;
|
|
8039
8226
|
}
|
|
8040
8227
|
function generateEventId() {
|
|
8041
8228
|
const timestamp = Date.now().toString(36);
|
|
8042
|
-
const random =
|
|
8229
|
+
const random = randomBytes7(6).toString("hex");
|
|
8043
8230
|
return `evt_${timestamp}${random}`;
|
|
8044
8231
|
}
|
|
8045
8232
|
function generateWebhookSecret(length = 32) {
|
|
8046
|
-
|
|
8047
|
-
let secret = "whsec_";
|
|
8048
|
-
for (let i = 0; i < length; i++) {
|
|
8049
|
-
secret += chars.charAt(Math.floor(Math.random() * chars.length));
|
|
8050
|
-
}
|
|
8051
|
-
return secret;
|
|
8233
|
+
return `whsec_${randomBytes7(length).toString("base64url").slice(0, length)}`;
|
|
8052
8234
|
}
|
|
8053
8235
|
function matchEventType(eventType, pattern) {
|
|
8054
8236
|
if (eventType === pattern || pattern === "*" || pattern === "**") {
|
|
@@ -8125,9 +8307,10 @@ var WebhookEventTypes = {
|
|
|
8125
8307
|
};
|
|
8126
8308
|
|
|
8127
8309
|
// src/interfaces/INotification.ts
|
|
8310
|
+
import { randomBytes as randomBytes8 } from "crypto";
|
|
8128
8311
|
function generateNotificationId() {
|
|
8129
8312
|
const timestamp = Date.now().toString(36);
|
|
8130
|
-
const random =
|
|
8313
|
+
const random = randomBytes8(4).toString("hex");
|
|
8131
8314
|
return `notif_${timestamp}${random}`;
|
|
8132
8315
|
}
|
|
8133
8316
|
function isInQuietHours(preferences) {
|
|
@@ -8617,6 +8800,7 @@ var MemoryAuth = class {
|
|
|
8617
8800
|
};
|
|
8618
8801
|
|
|
8619
8802
|
// src/interfaces/IPayment.ts
|
|
8803
|
+
import { randomBytes as randomBytes9 } from "crypto";
|
|
8620
8804
|
function createPaymentError(code, message, originalError) {
|
|
8621
8805
|
return { code, message, originalError };
|
|
8622
8806
|
}
|
|
@@ -8648,7 +8832,7 @@ function formatAmount(amount, currency, locale = "en-US") {
|
|
|
8648
8832
|
}
|
|
8649
8833
|
function generatePaymentId(prefix = "pi") {
|
|
8650
8834
|
const timestamp = Date.now().toString(36);
|
|
8651
|
-
const random =
|
|
8835
|
+
const random = randomBytes9(8).toString("hex");
|
|
8652
8836
|
return `${prefix}_${timestamp}${random}`;
|
|
8653
8837
|
}
|
|
8654
8838
|
var MemoryPayment = class {
|
|
@@ -8706,7 +8890,7 @@ var MemoryPayment = class {
|
|
|
8706
8890
|
amount: options.amount,
|
|
8707
8891
|
currency: options.currency,
|
|
8708
8892
|
status: options.paymentMethodId ? "requires_confirmation" : "requires_payment_method",
|
|
8709
|
-
clientSecret: `${id}_secret_${
|
|
8893
|
+
clientSecret: `${id}_secret_${randomBytes9(16).toString("base64url")}`,
|
|
8710
8894
|
metadata: options.metadata,
|
|
8711
8895
|
description: options.description,
|
|
8712
8896
|
receiptEmail: options.receiptEmail,
|
|
@@ -9021,6 +9205,7 @@ var MemoryPayment = class {
|
|
|
9021
9205
|
};
|
|
9022
9206
|
|
|
9023
9207
|
// src/interfaces/IAuthSSO.ts
|
|
9208
|
+
import { randomBytes as randomBytes10 } from "crypto";
|
|
9024
9209
|
var MemoryAuthSSO = class {
|
|
9025
9210
|
samlConfigs = /* @__PURE__ */ new Map();
|
|
9026
9211
|
oidcConfigs = /* @__PURE__ */ new Map();
|
|
@@ -9052,7 +9237,7 @@ var MemoryAuthSSO = class {
|
|
|
9052
9237
|
if (!config) {
|
|
9053
9238
|
throw new Error("SAML not configured for tenant");
|
|
9054
9239
|
}
|
|
9055
|
-
const id = `_${
|
|
9240
|
+
const id = `_${randomBytes10(8).toString("hex")}`;
|
|
9056
9241
|
return {
|
|
9057
9242
|
id,
|
|
9058
9243
|
redirectUrl: `${config.ssoUrl}?SAMLRequest=mock_request&RelayState=${options.relayState ?? ""}`,
|
|
@@ -9064,7 +9249,7 @@ var MemoryAuthSSO = class {
|
|
|
9064
9249
|
}
|
|
9065
9250
|
async processSamlResponse(_samlResponse, _relayState) {
|
|
9066
9251
|
const user = {
|
|
9067
|
-
id: `saml_${
|
|
9252
|
+
id: `saml_${randomBytes10(8).toString("hex")}`,
|
|
9068
9253
|
email: "saml.user@example.com",
|
|
9069
9254
|
emailVerified: true,
|
|
9070
9255
|
metadata: { ssoProvider: "saml" },
|
|
@@ -9074,7 +9259,7 @@ var MemoryAuthSSO = class {
|
|
|
9074
9259
|
success: true,
|
|
9075
9260
|
user,
|
|
9076
9261
|
session: {
|
|
9077
|
-
accessToken: `saml_token_${
|
|
9262
|
+
accessToken: `saml_token_${randomBytes10(8).toString("hex")}`,
|
|
9078
9263
|
expiresAt: new Date(Date.now() + 36e5),
|
|
9079
9264
|
user
|
|
9080
9265
|
},
|
|
@@ -9111,8 +9296,8 @@ var MemoryAuthSSO = class {
|
|
|
9111
9296
|
}
|
|
9112
9297
|
// OIDC Authentication
|
|
9113
9298
|
async initiateOidcLogin(options) {
|
|
9114
|
-
const state = options.state ??
|
|
9115
|
-
const nonce =
|
|
9299
|
+
const state = options.state ?? randomBytes10(8).toString("hex");
|
|
9300
|
+
const nonce = randomBytes10(8).toString("hex");
|
|
9116
9301
|
return {
|
|
9117
9302
|
state,
|
|
9118
9303
|
redirectUrl: `https://idp.example.com/authorize?client_id=mock&redirect_uri=${encodeURIComponent(options.redirectUri)}&state=${state}`,
|
|
@@ -9123,7 +9308,7 @@ var MemoryAuthSSO = class {
|
|
|
9123
9308
|
}
|
|
9124
9309
|
async processOidcCallback(_code, _state, _codeVerifier) {
|
|
9125
9310
|
const user = {
|
|
9126
|
-
id: `oidc_${
|
|
9311
|
+
id: `oidc_${randomBytes10(8).toString("hex")}`,
|
|
9127
9312
|
email: "oidc.user@example.com",
|
|
9128
9313
|
emailVerified: true,
|
|
9129
9314
|
metadata: { ssoProvider: "oidc" },
|
|
@@ -9133,7 +9318,7 @@ var MemoryAuthSSO = class {
|
|
|
9133
9318
|
success: true,
|
|
9134
9319
|
user,
|
|
9135
9320
|
session: {
|
|
9136
|
-
accessToken: `oidc_token_${
|
|
9321
|
+
accessToken: `oidc_token_${randomBytes10(8).toString("hex")}`,
|
|
9137
9322
|
expiresAt: new Date(Date.now() + 36e5),
|
|
9138
9323
|
user
|
|
9139
9324
|
},
|
|
@@ -9142,7 +9327,7 @@ var MemoryAuthSSO = class {
|
|
|
9142
9327
|
}
|
|
9143
9328
|
async refreshOidcTokens(_refreshToken, _tenantId) {
|
|
9144
9329
|
return {
|
|
9145
|
-
accessToken: `refreshed_token_${
|
|
9330
|
+
accessToken: `refreshed_token_${randomBytes10(8).toString("hex")}`,
|
|
9146
9331
|
expiresIn: 3600
|
|
9147
9332
|
};
|
|
9148
9333
|
}
|
|
@@ -9172,7 +9357,7 @@ var MemoryAuthSSO = class {
|
|
|
9172
9357
|
}
|
|
9173
9358
|
// SCIM
|
|
9174
9359
|
async configureScim(config) {
|
|
9175
|
-
const token = `scim_token_${
|
|
9360
|
+
const token = `scim_token_${randomBytes10(8).toString("hex")}`;
|
|
9176
9361
|
this.scimConfigs.set(config.tenantId, { ...config, bearerToken: token });
|
|
9177
9362
|
return { bearerToken: token };
|
|
9178
9363
|
}
|
|
@@ -9185,7 +9370,7 @@ var MemoryAuthSSO = class {
|
|
|
9185
9370
|
async regenerateScimToken(tenantId) {
|
|
9186
9371
|
const config = this.scimConfigs.get(tenantId);
|
|
9187
9372
|
if (!config) throw new Error("SCIM not configured");
|
|
9188
|
-
const token = `scim_token_${
|
|
9373
|
+
const token = `scim_token_${randomBytes10(8).toString("hex")}`;
|
|
9189
9374
|
config.bearerToken = token;
|
|
9190
9375
|
return { bearerToken: token };
|
|
9191
9376
|
}
|
|
@@ -9194,7 +9379,7 @@ var MemoryAuthSSO = class {
|
|
|
9194
9379
|
}
|
|
9195
9380
|
// Domain Verification
|
|
9196
9381
|
async initiateDomainVerification(tenantId, domain) {
|
|
9197
|
-
const token = `dll-verify-${
|
|
9382
|
+
const token = `dll-verify-${randomBytes10(8).toString("hex")}`;
|
|
9198
9383
|
this.pendingVerifications.set(`${tenantId}:${domain}`, { domain, token });
|
|
9199
9384
|
return {
|
|
9200
9385
|
verificationMethod: "dns_txt",
|
|
@@ -9260,6 +9445,7 @@ var MemoryAuthSSO = class {
|
|
|
9260
9445
|
};
|
|
9261
9446
|
|
|
9262
9447
|
// src/interfaces/ITenant.ts
|
|
9448
|
+
import { randomBytes as randomBytes11 } from "crypto";
|
|
9263
9449
|
var tenantContextStorage = /* @__PURE__ */ new Map();
|
|
9264
9450
|
var contextIdCounter = 0;
|
|
9265
9451
|
var currentContextId = null;
|
|
@@ -9327,7 +9513,7 @@ var MemoryTenant = class {
|
|
|
9327
9513
|
// Tenant CRUD
|
|
9328
9514
|
async createTenant(options) {
|
|
9329
9515
|
const tenant = {
|
|
9330
|
-
id: `tenant_${
|
|
9516
|
+
id: `tenant_${randomBytes11(8).toString("hex")}`,
|
|
9331
9517
|
slug: options.slug,
|
|
9332
9518
|
name: options.name,
|
|
9333
9519
|
status: "active",
|
|
@@ -9448,7 +9634,7 @@ var MemoryTenant = class {
|
|
|
9448
9634
|
}
|
|
9449
9635
|
async addMember(tenantId, userId, role) {
|
|
9450
9636
|
const member = {
|
|
9451
|
-
id: `member_${
|
|
9637
|
+
id: `member_${randomBytes11(8).toString("hex")}`,
|
|
9452
9638
|
tenantId,
|
|
9453
9639
|
userId,
|
|
9454
9640
|
role,
|
|
@@ -9489,12 +9675,12 @@ var MemoryTenant = class {
|
|
|
9489
9675
|
}
|
|
9490
9676
|
async inviteMember(tenantId, options) {
|
|
9491
9677
|
const invitation = {
|
|
9492
|
-
id: `inv_${
|
|
9678
|
+
id: `inv_${randomBytes11(8).toString("hex")}`,
|
|
9493
9679
|
tenantId,
|
|
9494
9680
|
email: options.email,
|
|
9495
9681
|
role: options.role,
|
|
9496
9682
|
invitedBy: "system",
|
|
9497
|
-
token:
|
|
9683
|
+
token: randomBytes11(16).toString("base64url"),
|
|
9498
9684
|
status: "pending",
|
|
9499
9685
|
createdAt: /* @__PURE__ */ new Date(),
|
|
9500
9686
|
expiresAt: new Date(
|
|
@@ -9655,6 +9841,7 @@ var MemoryTenant = class {
|
|
|
9655
9841
|
init_IAI();
|
|
9656
9842
|
|
|
9657
9843
|
// src/interfaces/IPromptStore.ts
|
|
9844
|
+
import { randomBytes as randomBytes12 } from "crypto";
|
|
9658
9845
|
var MemoryPromptStore = class {
|
|
9659
9846
|
// userId -> variantId
|
|
9660
9847
|
constructor(config = {}) {
|
|
@@ -9670,7 +9857,7 @@ var MemoryPromptStore = class {
|
|
|
9670
9857
|
// Prompt CRUD
|
|
9671
9858
|
// ─────────────────────────────────────────────────────────────
|
|
9672
9859
|
async create(prompt) {
|
|
9673
|
-
const id = `prompt_${Date.now()}_${
|
|
9860
|
+
const id = `prompt_${Date.now()}_${randomBytes12(4).toString("hex")}`;
|
|
9674
9861
|
const now = /* @__PURE__ */ new Date();
|
|
9675
9862
|
const newPrompt = {
|
|
9676
9863
|
...prompt,
|
|
@@ -9685,7 +9872,7 @@ var MemoryPromptStore = class {
|
|
|
9685
9872
|
this.prompts.set(id, newPrompt);
|
|
9686
9873
|
this.prompts.set(prompt.slug, newPrompt);
|
|
9687
9874
|
const version = {
|
|
9688
|
-
id: `pv_${Date.now()}_${
|
|
9875
|
+
id: `pv_${Date.now()}_${randomBytes12(4).toString("hex")}`,
|
|
9689
9876
|
promptId: id,
|
|
9690
9877
|
version: 1,
|
|
9691
9878
|
content: prompt.content,
|
|
@@ -9720,7 +9907,7 @@ var MemoryPromptStore = class {
|
|
|
9720
9907
|
latestVersion.isLatest = false;
|
|
9721
9908
|
}
|
|
9722
9909
|
const newVersion = {
|
|
9723
|
-
id: `pv_${Date.now()}_${
|
|
9910
|
+
id: `pv_${Date.now()}_${randomBytes12(4).toString("hex")}`,
|
|
9724
9911
|
promptId: prompt.id,
|
|
9725
9912
|
version: versions.length + 1,
|
|
9726
9913
|
content: updates.content,
|
|
@@ -9965,7 +10152,7 @@ ${v2.content}`;
|
|
|
9965
10152
|
// A/B Testing
|
|
9966
10153
|
// ─────────────────────────────────────────────────────────────
|
|
9967
10154
|
async createExperiment(experiment) {
|
|
9968
|
-
const id = `exp_${Date.now()}_${
|
|
10155
|
+
const id = `exp_${Date.now()}_${randomBytes12(4).toString("hex")}`;
|
|
9969
10156
|
const now = /* @__PURE__ */ new Date();
|
|
9970
10157
|
const newExperiment = {
|
|
9971
10158
|
...experiment,
|
|
@@ -10042,7 +10229,7 @@ ${v2.content}`;
|
|
|
10042
10229
|
// Prompt Chains
|
|
10043
10230
|
// ─────────────────────────────────────────────────────────────
|
|
10044
10231
|
async createChain(chain) {
|
|
10045
|
-
const id = `chain_${Date.now()}_${
|
|
10232
|
+
const id = `chain_${Date.now()}_${randomBytes12(4).toString("hex")}`;
|
|
10046
10233
|
const now = /* @__PURE__ */ new Date();
|
|
10047
10234
|
const newChain = {
|
|
10048
10235
|
...chain,
|
|
@@ -10133,7 +10320,7 @@ ${v2.content}`;
|
|
|
10133
10320
|
async recordUsage(record) {
|
|
10134
10321
|
const usageRecord = {
|
|
10135
10322
|
...record,
|
|
10136
|
-
id: `usage_${Date.now()}_${
|
|
10323
|
+
id: `usage_${Date.now()}_${randomBytes12(4).toString("hex")}`,
|
|
10137
10324
|
createdAt: /* @__PURE__ */ new Date()
|
|
10138
10325
|
};
|
|
10139
10326
|
if (this.config.trackUsage !== false) {
|
|
@@ -10237,6 +10424,7 @@ ${v2.content}`;
|
|
|
10237
10424
|
init_IRAG();
|
|
10238
10425
|
|
|
10239
10426
|
// src/interfaces/IAIUsage.ts
|
|
10427
|
+
import { randomBytes as randomBytes14 } from "crypto";
|
|
10240
10428
|
var MemoryAIUsage = class {
|
|
10241
10429
|
constructor(config = {}) {
|
|
10242
10430
|
this.config = config;
|
|
@@ -10270,7 +10458,7 @@ var MemoryAIUsage = class {
|
|
|
10270
10458
|
async record(record) {
|
|
10271
10459
|
const newRecord = {
|
|
10272
10460
|
...record,
|
|
10273
|
-
id: `usage_${Date.now()}_${
|
|
10461
|
+
id: `usage_${Date.now()}_${randomBytes14(4).toString("hex")}`,
|
|
10274
10462
|
createdAt: /* @__PURE__ */ new Date()
|
|
10275
10463
|
};
|
|
10276
10464
|
this.records.push(newRecord);
|
|
@@ -10351,7 +10539,7 @@ var MemoryAIUsage = class {
|
|
|
10351
10539
|
const period = this.getPeriodBounds(quota.period, /* @__PURE__ */ new Date());
|
|
10352
10540
|
const newQuota = {
|
|
10353
10541
|
...quota,
|
|
10354
|
-
id: existingQuota?.id || `quota_${Date.now()}_${
|
|
10542
|
+
id: existingQuota?.id || `quota_${Date.now()}_${randomBytes14(4).toString("hex")}`,
|
|
10355
10543
|
used: existingQuota?.used || 0,
|
|
10356
10544
|
periodStart: period.start,
|
|
10357
10545
|
periodEnd: period.end
|
|
@@ -10445,7 +10633,7 @@ var MemoryAIUsage = class {
|
|
|
10445
10633
|
const period = this.getPeriodBounds(budget.period, /* @__PURE__ */ new Date());
|
|
10446
10634
|
const newBudget = {
|
|
10447
10635
|
...budget,
|
|
10448
|
-
id: existingBudget?.id || `budget_${Date.now()}_${
|
|
10636
|
+
id: existingBudget?.id || `budget_${Date.now()}_${randomBytes14(4).toString("hex")}`,
|
|
10449
10637
|
spent: existingBudget?.spent || 0,
|
|
10450
10638
|
periodStart: period.start,
|
|
10451
10639
|
periodEnd: period.end
|
|
@@ -10709,7 +10897,7 @@ var MemoryAIUsage = class {
|
|
|
10709
10897
|
const items = Array.from(itemsMap.values());
|
|
10710
10898
|
const subtotal = items.reduce((sum, item) => sum + item.costUsd, 0);
|
|
10711
10899
|
const invoice = {
|
|
10712
|
-
id: `inv_${Date.now()}_${
|
|
10900
|
+
id: `inv_${Date.now()}_${randomBytes14(4).toString("hex")}`,
|
|
10713
10901
|
tenantId,
|
|
10714
10902
|
periodStart,
|
|
10715
10903
|
periodEnd,
|
|
@@ -10922,7 +11110,7 @@ var MemoryAIUsage = class {
|
|
|
10922
11110
|
);
|
|
10923
11111
|
if (existingAlert) return;
|
|
10924
11112
|
this.alerts.push({
|
|
10925
|
-
id: `alert_${Date.now()}_${
|
|
11113
|
+
id: `alert_${Date.now()}_${randomBytes14(4).toString("hex")}`,
|
|
10926
11114
|
tenantId,
|
|
10927
11115
|
type,
|
|
10928
11116
|
severity,
|
|
@@ -11051,6 +11239,7 @@ var MemoryAIUsage = class {
|
|
|
11051
11239
|
};
|
|
11052
11240
|
|
|
11053
11241
|
// src/interfaces/IDevice.ts
|
|
11242
|
+
import { randomBytes as randomBytes15 } from "crypto";
|
|
11054
11243
|
var MemoryDevice = class {
|
|
11055
11244
|
constructor(config = {}) {
|
|
11056
11245
|
this.config = config;
|
|
@@ -11075,7 +11264,7 @@ var MemoryDevice = class {
|
|
|
11075
11264
|
const now = /* @__PURE__ */ new Date();
|
|
11076
11265
|
const newDevice = {
|
|
11077
11266
|
...device,
|
|
11078
|
-
id: `dev_${Date.now()}_${
|
|
11267
|
+
id: `dev_${Date.now()}_${randomBytes15(4).toString("hex")}`,
|
|
11079
11268
|
status: "active",
|
|
11080
11269
|
connectionState: "disconnected",
|
|
11081
11270
|
tags: device.tags || [],
|
|
@@ -11198,7 +11387,7 @@ var MemoryDevice = class {
|
|
|
11198
11387
|
// Provisioning
|
|
11199
11388
|
// ─────────────────────────────────────────────────────────────
|
|
11200
11389
|
async provision(request) {
|
|
11201
|
-
const id = `prov_${Date.now()}_${
|
|
11390
|
+
const id = `prov_${Date.now()}_${randomBytes15(4).toString("hex")}`;
|
|
11202
11391
|
const newRequest = {
|
|
11203
11392
|
...request,
|
|
11204
11393
|
id,
|
|
@@ -11210,7 +11399,7 @@ var MemoryDevice = class {
|
|
|
11210
11399
|
const result = {
|
|
11211
11400
|
credentials: {
|
|
11212
11401
|
type: request.config.authMethod || "token",
|
|
11213
|
-
token: `tok_${Date.now()}_${
|
|
11402
|
+
token: `tok_${Date.now()}_${randomBytes15(16).toString("hex")}`
|
|
11214
11403
|
},
|
|
11215
11404
|
endpoint: "mqtt://localhost:1883",
|
|
11216
11405
|
mqttBroker: "mqtt://localhost:1883"
|
|
@@ -11253,7 +11442,7 @@ var MemoryDevice = class {
|
|
|
11253
11442
|
}
|
|
11254
11443
|
}
|
|
11255
11444
|
async generateRegistrationCode(deviceType, tenantId, expiresInHours = 24) {
|
|
11256
|
-
const code = `REG_${
|
|
11445
|
+
const code = `REG_${randomBytes15(4).toString("hex").toUpperCase()}`;
|
|
11257
11446
|
this.registrationCodes.set(code, {
|
|
11258
11447
|
deviceType,
|
|
11259
11448
|
tenantId,
|
|
@@ -11353,7 +11542,7 @@ var MemoryDevice = class {
|
|
|
11353
11542
|
async ingestTelemetry(message) {
|
|
11354
11543
|
const newMessage = {
|
|
11355
11544
|
...message,
|
|
11356
|
-
id: `tel_${Date.now()}_${
|
|
11545
|
+
id: `tel_${Date.now()}_${randomBytes15(4).toString("hex")}`,
|
|
11357
11546
|
receivedAt: /* @__PURE__ */ new Date()
|
|
11358
11547
|
};
|
|
11359
11548
|
if (this.config.storeTelemetry !== false) {
|
|
@@ -11433,7 +11622,7 @@ var MemoryDevice = class {
|
|
|
11433
11622
|
// ─────────────────────────────────────────────────────────────
|
|
11434
11623
|
async sendCommand(deviceId, name, payload, options) {
|
|
11435
11624
|
const command = {
|
|
11436
|
-
id: `cmd_${Date.now()}_${
|
|
11625
|
+
id: `cmd_${Date.now()}_${randomBytes15(4).toString("hex")}`,
|
|
11437
11626
|
deviceId,
|
|
11438
11627
|
name,
|
|
11439
11628
|
payload,
|
|
@@ -11496,7 +11685,7 @@ var MemoryDevice = class {
|
|
|
11496
11685
|
async createFirmware(firmware) {
|
|
11497
11686
|
const newFirmware = {
|
|
11498
11687
|
...firmware,
|
|
11499
|
-
id: `fw_${Date.now()}_${
|
|
11688
|
+
id: `fw_${Date.now()}_${randomBytes15(4).toString("hex")}`,
|
|
11500
11689
|
status: "draft",
|
|
11501
11690
|
createdAt: /* @__PURE__ */ new Date()
|
|
11502
11691
|
};
|
|
@@ -11548,7 +11737,7 @@ var MemoryDevice = class {
|
|
|
11548
11737
|
throw new Error(`Firmware not found: ${firmwareVersionId}`);
|
|
11549
11738
|
}
|
|
11550
11739
|
const update = {
|
|
11551
|
-
id: `upd_${Date.now()}_${
|
|
11740
|
+
id: `upd_${Date.now()}_${randomBytes15(4).toString("hex")}`,
|
|
11552
11741
|
deviceId,
|
|
11553
11742
|
firmwareVersionId,
|
|
11554
11743
|
targetVersion: firmware.version,
|
|
@@ -11602,7 +11791,7 @@ var MemoryDevice = class {
|
|
|
11602
11791
|
const now = /* @__PURE__ */ new Date();
|
|
11603
11792
|
const newGroup = {
|
|
11604
11793
|
...group,
|
|
11605
|
-
id: `grp_${Date.now()}_${
|
|
11794
|
+
id: `grp_${Date.now()}_${randomBytes15(4).toString("hex")}`,
|
|
11606
11795
|
deviceCount: 0,
|
|
11607
11796
|
tags: group.tags || [],
|
|
11608
11797
|
attributes: group.attributes || {},
|
|
@@ -11722,6 +11911,7 @@ var MemoryDevice = class {
|
|
|
11722
11911
|
};
|
|
11723
11912
|
|
|
11724
11913
|
// src/interfaces/IBilling.ts
|
|
11914
|
+
import { randomBytes as randomBytes16 } from "crypto";
|
|
11725
11915
|
var MemoryBilling = class {
|
|
11726
11916
|
constructor(config = {}) {
|
|
11727
11917
|
this.config = config;
|
|
@@ -11742,7 +11932,7 @@ var MemoryBilling = class {
|
|
|
11742
11932
|
async createProduct(product) {
|
|
11743
11933
|
const newProduct = {
|
|
11744
11934
|
...product,
|
|
11745
|
-
id: `prod_${Date.now()}_${
|
|
11935
|
+
id: `prod_${Date.now()}_${randomBytes16(4).toString("hex")}`,
|
|
11746
11936
|
features: product.features || [],
|
|
11747
11937
|
metadata: product.metadata || {},
|
|
11748
11938
|
createdAt: /* @__PURE__ */ new Date(),
|
|
@@ -11770,7 +11960,7 @@ var MemoryBilling = class {
|
|
|
11770
11960
|
async createPrice(price) {
|
|
11771
11961
|
const newPrice = {
|
|
11772
11962
|
...price,
|
|
11773
|
-
id: `price_${Date.now()}_${
|
|
11963
|
+
id: `price_${Date.now()}_${randomBytes16(4).toString("hex")}`,
|
|
11774
11964
|
metadata: price.metadata || {},
|
|
11775
11965
|
createdAt: /* @__PURE__ */ new Date(),
|
|
11776
11966
|
updatedAt: /* @__PURE__ */ new Date()
|
|
@@ -11801,7 +11991,7 @@ var MemoryBilling = class {
|
|
|
11801
11991
|
async createMeter(meter) {
|
|
11802
11992
|
const newMeter = {
|
|
11803
11993
|
...meter,
|
|
11804
|
-
id: `meter_${Date.now()}_${
|
|
11994
|
+
id: `meter_${Date.now()}_${randomBytes16(4).toString("hex")}`,
|
|
11805
11995
|
createdAt: /* @__PURE__ */ new Date(),
|
|
11806
11996
|
updatedAt: /* @__PURE__ */ new Date()
|
|
11807
11997
|
};
|
|
@@ -11835,13 +12025,13 @@ var MemoryBilling = class {
|
|
|
11835
12025
|
const trialDays = options.trialDays ?? price.trialDays ?? 0;
|
|
11836
12026
|
const periodEnd = this.addPeriod(now, price.billingPeriod);
|
|
11837
12027
|
const subscription = {
|
|
11838
|
-
id: `sub_${Date.now()}_${
|
|
12028
|
+
id: `sub_${Date.now()}_${randomBytes16(4).toString("hex")}`,
|
|
11839
12029
|
customerId: options.customerId,
|
|
11840
12030
|
tenantId: options.tenantId,
|
|
11841
12031
|
status: trialDays > 0 ? "trialing" : "active",
|
|
11842
12032
|
items: [
|
|
11843
12033
|
{
|
|
11844
|
-
id: `si_${Date.now()}_${
|
|
12034
|
+
id: `si_${Date.now()}_${randomBytes16(4).toString("hex")}`,
|
|
11845
12035
|
priceId: options.priceId,
|
|
11846
12036
|
quantity: options.quantity || 1
|
|
11847
12037
|
}
|
|
@@ -11932,7 +12122,7 @@ var MemoryBilling = class {
|
|
|
11932
12122
|
const sub = await this.getSubscription(subscriptionId);
|
|
11933
12123
|
if (!sub) throw new Error(`Subscription not found: ${subscriptionId}`);
|
|
11934
12124
|
sub.items.push({
|
|
11935
|
-
id: `si_${Date.now()}_${
|
|
12125
|
+
id: `si_${Date.now()}_${randomBytes16(4).toString("hex")}`,
|
|
11936
12126
|
priceId,
|
|
11937
12127
|
quantity: quantity || 1
|
|
11938
12128
|
});
|
|
@@ -11984,7 +12174,7 @@ var MemoryBilling = class {
|
|
|
11984
12174
|
if (existing) return existing;
|
|
11985
12175
|
}
|
|
11986
12176
|
const event = {
|
|
11987
|
-
id: `ue_${Date.now()}_${
|
|
12177
|
+
id: `ue_${Date.now()}_${randomBytes16(4).toString("hex")}`,
|
|
11988
12178
|
subscriptionId,
|
|
11989
12179
|
customerId: sub.customerId,
|
|
11990
12180
|
meterId: meter.id,
|
|
@@ -12055,7 +12245,7 @@ var MemoryBilling = class {
|
|
|
12055
12245
|
if (price) {
|
|
12056
12246
|
const unitAmount = price.unitAmount || 0;
|
|
12057
12247
|
lineItems.push({
|
|
12058
|
-
id: `ii_${Date.now()}_${
|
|
12248
|
+
id: `ii_${Date.now()}_${randomBytes16(4).toString("hex")}`,
|
|
12059
12249
|
priceId: item.priceId,
|
|
12060
12250
|
description: price.name,
|
|
12061
12251
|
quantity: item.quantity,
|
|
@@ -12070,7 +12260,7 @@ var MemoryBilling = class {
|
|
|
12070
12260
|
const usageSummary = await this.getUsageSummary(subscriptionId);
|
|
12071
12261
|
for (const usage of usageSummary) {
|
|
12072
12262
|
lineItems.push({
|
|
12073
|
-
id: `ii_${Date.now()}_${
|
|
12263
|
+
id: `ii_${Date.now()}_${randomBytes16(4).toString("hex")}`,
|
|
12074
12264
|
description: `${usage.meterName}: ${usage.total} ${usage.unit}`,
|
|
12075
12265
|
quantity: usage.total,
|
|
12076
12266
|
unitAmount: usage.cost / usage.total,
|
|
@@ -12093,7 +12283,7 @@ var MemoryBilling = class {
|
|
|
12093
12283
|
const tax = (subtotal - discount) * (taxRate / 100);
|
|
12094
12284
|
const total = subtotal - discount + tax;
|
|
12095
12285
|
const invoice = {
|
|
12096
|
-
id: `inv_${Date.now()}_${
|
|
12286
|
+
id: `inv_${Date.now()}_${randomBytes16(4).toString("hex")}`,
|
|
12097
12287
|
customerId: sub.customerId,
|
|
12098
12288
|
subscriptionId,
|
|
12099
12289
|
tenantId: sub.tenantId,
|
|
@@ -12124,14 +12314,14 @@ var MemoryBilling = class {
|
|
|
12124
12314
|
async createInvoice(options) {
|
|
12125
12315
|
const lineItems = options.lineItems.map((item) => ({
|
|
12126
12316
|
...item,
|
|
12127
|
-
id: `ii_${Date.now()}_${
|
|
12317
|
+
id: `ii_${Date.now()}_${randomBytes16(4).toString("hex")}`
|
|
12128
12318
|
}));
|
|
12129
12319
|
const subtotal = lineItems.reduce((sum, item) => sum + item.amount, 0);
|
|
12130
12320
|
const taxRate = this.config.defaultTaxRate || 0;
|
|
12131
12321
|
const tax = subtotal * (taxRate / 100);
|
|
12132
12322
|
const total = subtotal + tax;
|
|
12133
12323
|
const invoice = {
|
|
12134
|
-
id: `inv_${Date.now()}_${
|
|
12324
|
+
id: `inv_${Date.now()}_${randomBytes16(4).toString("hex")}`,
|
|
12135
12325
|
customerId: options.customerId,
|
|
12136
12326
|
tenantId: options.tenantId,
|
|
12137
12327
|
number: `${this.config.invoiceNumberPrefix || "INV-"}${++this.invoiceCounter}`,
|
|
@@ -12220,7 +12410,7 @@ var MemoryBilling = class {
|
|
|
12220
12410
|
async createDunningConfig(config) {
|
|
12221
12411
|
const newConfig = {
|
|
12222
12412
|
...config,
|
|
12223
|
-
id: `dun_${Date.now()}_${
|
|
12413
|
+
id: `dun_${Date.now()}_${randomBytes16(4).toString("hex")}`,
|
|
12224
12414
|
createdAt: /* @__PURE__ */ new Date(),
|
|
12225
12415
|
updatedAt: /* @__PURE__ */ new Date()
|
|
12226
12416
|
};
|
|
@@ -12246,7 +12436,7 @@ var MemoryBilling = class {
|
|
|
12246
12436
|
const invoice = await this.getInvoice(invoiceId);
|
|
12247
12437
|
if (!invoice) throw new Error(`Invoice not found: ${invoiceId}`);
|
|
12248
12438
|
const attempt = {
|
|
12249
|
-
id: `da_${Date.now()}_${
|
|
12439
|
+
id: `da_${Date.now()}_${randomBytes16(4).toString("hex")}`,
|
|
12250
12440
|
invoiceId,
|
|
12251
12441
|
attemptNumber: invoice.attemptCount + 1,
|
|
12252
12442
|
action: "retry_payment",
|
|
@@ -12278,7 +12468,7 @@ var MemoryBilling = class {
|
|
|
12278
12468
|
balance.updatedAt = /* @__PURE__ */ new Date();
|
|
12279
12469
|
this.creditBalances.set(customerId, balance);
|
|
12280
12470
|
const transaction = {
|
|
12281
|
-
id: `ct_${Date.now()}_${
|
|
12471
|
+
id: `ct_${Date.now()}_${randomBytes16(4).toString("hex")}`,
|
|
12282
12472
|
customerId,
|
|
12283
12473
|
type: options?.type || "manual",
|
|
12284
12474
|
amount,
|
|
@@ -12303,7 +12493,7 @@ var MemoryBilling = class {
|
|
|
12303
12493
|
balance.updatedAt = /* @__PURE__ */ new Date();
|
|
12304
12494
|
this.creditBalances.set(customerId, balance);
|
|
12305
12495
|
const transaction = {
|
|
12306
|
-
id: `ct_${Date.now()}_${
|
|
12496
|
+
id: `ct_${Date.now()}_${randomBytes16(4).toString("hex")}`,
|
|
12307
12497
|
customerId,
|
|
12308
12498
|
type: "manual",
|
|
12309
12499
|
amount: -amount,
|
|
@@ -12327,7 +12517,7 @@ var MemoryBilling = class {
|
|
|
12327
12517
|
async createCoupon(coupon) {
|
|
12328
12518
|
const newCoupon = {
|
|
12329
12519
|
...coupon,
|
|
12330
|
-
id: `coup_${Date.now()}_${
|
|
12520
|
+
id: `coup_${Date.now()}_${randomBytes16(4).toString("hex")}`,
|
|
12331
12521
|
timesRedeemed: 0,
|
|
12332
12522
|
createdAt: /* @__PURE__ */ new Date(),
|
|
12333
12523
|
updatedAt: /* @__PURE__ */ new Date()
|
|
@@ -12563,6 +12753,7 @@ var MemoryBilling = class {
|
|
|
12563
12753
|
};
|
|
12564
12754
|
|
|
12565
12755
|
// src/interfaces/IDevPortal.ts
|
|
12756
|
+
import { randomBytes as randomBytes17 } from "crypto";
|
|
12566
12757
|
var MemoryDevPortal = class {
|
|
12567
12758
|
constructor(config = {}) {
|
|
12568
12759
|
this.config = config;
|
|
@@ -12575,8 +12766,9 @@ var MemoryDevPortal = class {
|
|
|
12575
12766
|
usageRecords = [];
|
|
12576
12767
|
// API Key Management
|
|
12577
12768
|
async createApiKey(options, userId) {
|
|
12578
|
-
const
|
|
12579
|
-
const
|
|
12769
|
+
const { randomBytes: randomBytes37, createHash: createHash2 } = await import("crypto");
|
|
12770
|
+
const id = `key_${Date.now()}_${randomBytes37(8).toString("hex")}`;
|
|
12771
|
+
const secret = `sk_${options.type}_${randomBytes37(24).toString("base64url")}`;
|
|
12580
12772
|
const prefix = secret.substring(0, 12);
|
|
12581
12773
|
const key = {
|
|
12582
12774
|
id,
|
|
@@ -12663,7 +12855,7 @@ var MemoryDevPortal = class {
|
|
|
12663
12855
|
// API Documentation
|
|
12664
12856
|
async generateDocumentation(endpoints, config) {
|
|
12665
12857
|
const doc = {
|
|
12666
|
-
id: `doc_${Date.now()}_${
|
|
12858
|
+
id: `doc_${Date.now()}_${randomBytes17(4).toString("hex")}`,
|
|
12667
12859
|
title: config.title,
|
|
12668
12860
|
version: config.version,
|
|
12669
12861
|
baseUrl: config.baseUrl,
|
|
@@ -12719,7 +12911,7 @@ var MemoryDevPortal = class {
|
|
|
12719
12911
|
if (!doc) throw new Error(`Documentation not found: ${docId}`);
|
|
12720
12912
|
const newEndpoint = {
|
|
12721
12913
|
...endpoint,
|
|
12722
|
-
id: `ep_${Date.now()}_${
|
|
12914
|
+
id: `ep_${Date.now()}_${randomBytes17(4).toString("hex")}`
|
|
12723
12915
|
};
|
|
12724
12916
|
doc.endpoints.push(newEndpoint);
|
|
12725
12917
|
return newEndpoint;
|
|
@@ -12815,7 +13007,7 @@ SDK for ${documentation.title}`,
|
|
|
12815
13007
|
});
|
|
12816
13008
|
}
|
|
12817
13009
|
const sdk = {
|
|
12818
|
-
id: `sdk_${Date.now()}_${
|
|
13010
|
+
id: `sdk_${Date.now()}_${randomBytes17(4).toString("hex")}`,
|
|
12819
13011
|
language: config.language,
|
|
12820
13012
|
packageName: config.packageName,
|
|
12821
13013
|
version: config.version,
|
|
@@ -12842,7 +13034,7 @@ SDK for ${documentation.title}`,
|
|
|
12842
13034
|
}
|
|
12843
13035
|
// Sandbox / Playground
|
|
12844
13036
|
async createSandbox(options, userId) {
|
|
12845
|
-
const id = `sandbox_${Date.now()}_${
|
|
13037
|
+
const id = `sandbox_${Date.now()}_${randomBytes17(4).toString("hex")}`;
|
|
12846
13038
|
const lifetimeHours = options.lifetimeHours || this.config.sandboxDefaultLifetimeHours || 24;
|
|
12847
13039
|
const sandbox = {
|
|
12848
13040
|
id,
|
|
@@ -12851,7 +13043,7 @@ SDK for ${documentation.title}`,
|
|
|
12851
13043
|
tenantId: options.tenantId,
|
|
12852
13044
|
status: "active",
|
|
12853
13045
|
baseUrl: `https://sandbox-${id}.example.com`,
|
|
12854
|
-
apiKey: `sandbox_${
|
|
13046
|
+
apiKey: `sandbox_${randomBytes17(8).toString("hex")}`,
|
|
12855
13047
|
seedDataLoaded: options.seedData || [],
|
|
12856
13048
|
config: options.config || {},
|
|
12857
13049
|
limits: {
|
|
@@ -12988,7 +13180,7 @@ SDK for ${documentation.title}`,
|
|
|
12988
13180
|
}
|
|
12989
13181
|
// Webhook Testing
|
|
12990
13182
|
async createWebhookTestEndpoint(userId, maxEvents = 100) {
|
|
12991
|
-
const id = `wh_test_${Date.now()}_${
|
|
13183
|
+
const id = `wh_test_${Date.now()}_${randomBytes17(4).toString("hex")}`;
|
|
12992
13184
|
const endpoint = {
|
|
12993
13185
|
id,
|
|
12994
13186
|
url: `https://webhook-test.example.com/${id}`,
|
|
@@ -13025,18 +13217,13 @@ SDK for ${documentation.title}`,
|
|
|
13025
13217
|
statusCode: 200,
|
|
13026
13218
|
headers: { "content-type": "application/json" },
|
|
13027
13219
|
body: { received: true },
|
|
13028
|
-
latencyMs:
|
|
13220
|
+
latencyMs: 0
|
|
13029
13221
|
};
|
|
13030
13222
|
}
|
|
13031
13223
|
// Private helpers
|
|
13032
13224
|
hashKey(key) {
|
|
13033
|
-
|
|
13034
|
-
|
|
13035
|
-
const char = key.charCodeAt(i);
|
|
13036
|
-
hash = (hash << 5) - hash + char;
|
|
13037
|
-
hash = hash & hash;
|
|
13038
|
-
}
|
|
13039
|
-
return `hashed_${Math.abs(hash).toString(36)}`;
|
|
13225
|
+
const { createHash: createHash2 } = __require("crypto");
|
|
13226
|
+
return createHash2("sha256").update(key).digest("hex");
|
|
13040
13227
|
}
|
|
13041
13228
|
endpointsToOpenApiPaths(endpoints) {
|
|
13042
13229
|
const paths = {};
|
|
@@ -13128,6 +13315,7 @@ class ApiClient:
|
|
|
13128
13315
|
};
|
|
13129
13316
|
|
|
13130
13317
|
// src/interfaces/ICompliance.ts
|
|
13318
|
+
import { randomBytes as randomBytes18 } from "crypto";
|
|
13131
13319
|
var MemoryCompliance = class {
|
|
13132
13320
|
constructor(config = {}) {
|
|
13133
13321
|
this.config = config;
|
|
@@ -13144,13 +13332,13 @@ var MemoryCompliance = class {
|
|
|
13144
13332
|
breaches = /* @__PURE__ */ new Map();
|
|
13145
13333
|
// DSAR Management
|
|
13146
13334
|
async createDsar(options) {
|
|
13147
|
-
const id = `dsar_${Date.now()}_${
|
|
13335
|
+
const id = `dsar_${Date.now()}_${randomBytes18(4).toString("hex")}`;
|
|
13148
13336
|
const dsar = {
|
|
13149
13337
|
id,
|
|
13150
13338
|
type: options.type,
|
|
13151
13339
|
subjectId: options.subjectId || options.subjectEmail,
|
|
13152
13340
|
subjectEmail: options.subjectEmail,
|
|
13153
|
-
verificationToken: `verify_${
|
|
13341
|
+
verificationToken: `verify_${randomBytes18(8).toString("hex")}`,
|
|
13154
13342
|
verified: false,
|
|
13155
13343
|
status: "pending_verification",
|
|
13156
13344
|
tenantId: options.tenantId,
|
|
@@ -13201,7 +13389,7 @@ var MemoryCompliance = class {
|
|
|
13201
13389
|
dsar.updatedAt = /* @__PURE__ */ new Date();
|
|
13202
13390
|
if (notes) {
|
|
13203
13391
|
dsar.notes.push({
|
|
13204
|
-
id: `note_${Date.now()}_${
|
|
13392
|
+
id: `note_${Date.now()}_${randomBytes18(4).toString("hex")}`,
|
|
13205
13393
|
content: notes,
|
|
13206
13394
|
authorId: "system",
|
|
13207
13395
|
createdAt: /* @__PURE__ */ new Date()
|
|
@@ -13213,7 +13401,7 @@ var MemoryCompliance = class {
|
|
|
13213
13401
|
const dsar = await this.getDsar(dsarId);
|
|
13214
13402
|
if (!dsar) throw new Error(`DSAR not found: ${dsarId}`);
|
|
13215
13403
|
const note = {
|
|
13216
|
-
id: `note_${Date.now()}_${
|
|
13404
|
+
id: `note_${Date.now()}_${randomBytes18(4).toString("hex")}`,
|
|
13217
13405
|
content,
|
|
13218
13406
|
authorId,
|
|
13219
13407
|
createdAt: /* @__PURE__ */ new Date()
|
|
@@ -13227,7 +13415,7 @@ var MemoryCompliance = class {
|
|
|
13227
13415
|
if (!dsar) throw new Error(`DSAR not found: ${dsarId}`);
|
|
13228
13416
|
const att = {
|
|
13229
13417
|
...attachment,
|
|
13230
|
-
id: `att_${Date.now()}_${
|
|
13418
|
+
id: `att_${Date.now()}_${randomBytes18(4).toString("hex")}`,
|
|
13231
13419
|
createdAt: /* @__PURE__ */ new Date()
|
|
13232
13420
|
};
|
|
13233
13421
|
dsar.attachments.push(att);
|
|
@@ -13268,7 +13456,7 @@ var MemoryCompliance = class {
|
|
|
13268
13456
|
}
|
|
13269
13457
|
// Consent Management
|
|
13270
13458
|
async recordConsent(options) {
|
|
13271
|
-
const id = `consent_${Date.now()}_${
|
|
13459
|
+
const id = `consent_${Date.now()}_${randomBytes18(4).toString("hex")}`;
|
|
13272
13460
|
const consent = {
|
|
13273
13461
|
id,
|
|
13274
13462
|
subjectId: options.subjectId,
|
|
@@ -13343,7 +13531,7 @@ var MemoryCompliance = class {
|
|
|
13343
13531
|
}
|
|
13344
13532
|
// Retention Policies
|
|
13345
13533
|
async createRetentionPolicy(policy) {
|
|
13346
|
-
const id = `rp_${Date.now()}_${
|
|
13534
|
+
const id = `rp_${Date.now()}_${randomBytes18(4).toString("hex")}`;
|
|
13347
13535
|
const newPolicy = {
|
|
13348
13536
|
...policy,
|
|
13349
13537
|
id,
|
|
@@ -13376,7 +13564,7 @@ var MemoryCompliance = class {
|
|
|
13376
13564
|
if (!policy) throw new Error(`Policy not found: ${policyId}`);
|
|
13377
13565
|
const startedAt = /* @__PURE__ */ new Date();
|
|
13378
13566
|
const execution = {
|
|
13379
|
-
id: `re_${Date.now()}_${
|
|
13567
|
+
id: `re_${Date.now()}_${randomBytes18(4).toString("hex")}`,
|
|
13380
13568
|
policyId,
|
|
13381
13569
|
recordsProcessed: 100,
|
|
13382
13570
|
recordsAffected: 15,
|
|
@@ -13395,7 +13583,7 @@ var MemoryCompliance = class {
|
|
|
13395
13583
|
}
|
|
13396
13584
|
// Data Inventory
|
|
13397
13585
|
async addDataInventoryItem(item) {
|
|
13398
|
-
const id = `di_${Date.now()}_${
|
|
13586
|
+
const id = `di_${Date.now()}_${randomBytes18(4).toString("hex")}`;
|
|
13399
13587
|
const newItem = {
|
|
13400
13588
|
...item,
|
|
13401
13589
|
id,
|
|
@@ -13456,7 +13644,7 @@ var MemoryCompliance = class {
|
|
|
13456
13644
|
}
|
|
13457
13645
|
// Audit Evidence
|
|
13458
13646
|
async addEvidence(evidence) {
|
|
13459
|
-
const id = `ev_${Date.now()}_${
|
|
13647
|
+
const id = `ev_${Date.now()}_${randomBytes18(4).toString("hex")}`;
|
|
13460
13648
|
const newEvidence = {
|
|
13461
13649
|
...evidence,
|
|
13462
13650
|
id,
|
|
@@ -13532,7 +13720,7 @@ var MemoryCompliance = class {
|
|
|
13532
13720
|
}
|
|
13533
13721
|
// PIAs
|
|
13534
13722
|
async createPia(pia) {
|
|
13535
|
-
const id = `pia_${Date.now()}_${
|
|
13723
|
+
const id = `pia_${Date.now()}_${randomBytes18(4).toString("hex")}`;
|
|
13536
13724
|
const newPia = {
|
|
13537
13725
|
...pia,
|
|
13538
13726
|
id,
|
|
@@ -13564,7 +13752,7 @@ var MemoryCompliance = class {
|
|
|
13564
13752
|
if (!pia) throw new Error(`PIA not found: ${piaId}`);
|
|
13565
13753
|
const newRisk = {
|
|
13566
13754
|
...risk,
|
|
13567
|
-
id: `risk_${Date.now()}_${
|
|
13755
|
+
id: `risk_${Date.now()}_${randomBytes18(4).toString("hex")}`
|
|
13568
13756
|
};
|
|
13569
13757
|
pia.risks.push(newRisk);
|
|
13570
13758
|
pia.updatedAt = /* @__PURE__ */ new Date();
|
|
@@ -13575,7 +13763,7 @@ var MemoryCompliance = class {
|
|
|
13575
13763
|
if (!pia) throw new Error(`PIA not found: ${piaId}`);
|
|
13576
13764
|
const newMitigation = {
|
|
13577
13765
|
...mitigation,
|
|
13578
|
-
id: `mit_${Date.now()}_${
|
|
13766
|
+
id: `mit_${Date.now()}_${randomBytes18(4).toString("hex")}`
|
|
13579
13767
|
};
|
|
13580
13768
|
pia.mitigations.push(newMitigation);
|
|
13581
13769
|
pia.updatedAt = /* @__PURE__ */ new Date();
|
|
@@ -13612,7 +13800,7 @@ var MemoryCompliance = class {
|
|
|
13612
13800
|
(c) => c.status === "non_compliant"
|
|
13613
13801
|
).length;
|
|
13614
13802
|
const report = {
|
|
13615
|
-
id: `report_${Date.now()}_${
|
|
13803
|
+
id: `report_${Date.now()}_${randomBytes18(4).toString("hex")}`,
|
|
13616
13804
|
title: `${framework.toUpperCase()} Compliance Report`,
|
|
13617
13805
|
framework,
|
|
13618
13806
|
period,
|
|
@@ -13663,7 +13851,7 @@ var MemoryCompliance = class {
|
|
|
13663
13851
|
}
|
|
13664
13852
|
// Breach Management
|
|
13665
13853
|
async recordBreach(breach) {
|
|
13666
|
-
const id = `breach_${Date.now()}_${
|
|
13854
|
+
const id = `breach_${Date.now()}_${randomBytes18(4).toString("hex")}`;
|
|
13667
13855
|
const newBreach = {
|
|
13668
13856
|
...breach,
|
|
13669
13857
|
id,
|
|
@@ -13902,6 +14090,27 @@ var RAGConfigSchema = z.object({
|
|
|
13902
14090
|
message: "Pinecone requires apiKey and indexName; Weaviate requires host"
|
|
13903
14091
|
}
|
|
13904
14092
|
);
|
|
14093
|
+
var CryptoConfigSchema = z.object({
|
|
14094
|
+
enabled: z.boolean().default(false).describe("Enable field-level encryption"),
|
|
14095
|
+
masterKey: z.string().optional().describe("256-bit master key as hex (64 chars). Required when enabled."),
|
|
14096
|
+
hmacKey: z.string().optional().describe(
|
|
14097
|
+
"HMAC key for deterministic hashing (derived from master key if not provided)"
|
|
14098
|
+
)
|
|
14099
|
+
}).refine(
|
|
14100
|
+
(data) => {
|
|
14101
|
+
if (data.enabled) {
|
|
14102
|
+
return data.masterKey && data.masterKey.length >= 64;
|
|
14103
|
+
}
|
|
14104
|
+
return true;
|
|
14105
|
+
},
|
|
14106
|
+
{
|
|
14107
|
+
message: "Crypto requires a 256-bit master key (64 hex characters) when enabled"
|
|
14108
|
+
}
|
|
14109
|
+
);
|
|
14110
|
+
var SecurityConfigSchema = z.object({
|
|
14111
|
+
enforceTls: z.boolean().default(true).describe("Enforce TLS for production connections"),
|
|
14112
|
+
tlsWarnOnly: z.boolean().default(false).describe("Warn instead of throwing when TLS is missing in production")
|
|
14113
|
+
});
|
|
13905
14114
|
var RetryConfigSchema = z.object({
|
|
13906
14115
|
enabled: z.boolean().default(true).describe("Enable retry for failed operations"),
|
|
13907
14116
|
maxAttempts: z.number().int().min(1).max(10).default(3).describe("Maximum retry attempts"),
|
|
@@ -13991,6 +14200,10 @@ var PlatformConfigSchema = z.object({
|
|
|
13991
14200
|
// AI configurations
|
|
13992
14201
|
ai: AIConfigSchema.default({ enabled: false }),
|
|
13993
14202
|
rag: RAGConfigSchema.default({ enabled: false }),
|
|
14203
|
+
// Crypto configuration
|
|
14204
|
+
crypto: CryptoConfigSchema.default({ enabled: false }),
|
|
14205
|
+
// Security configuration
|
|
14206
|
+
security: SecurityConfigSchema.default({}),
|
|
13994
14207
|
// Resilience configuration
|
|
13995
14208
|
resilience: ResilienceConfigSchema.default({}),
|
|
13996
14209
|
// Observability configuration
|
|
@@ -14068,6 +14281,15 @@ function loadConfig() {
|
|
|
14068
14281
|
embeddingApiKey: process.env.EMBEDDING_API_KEY || process.env.OPENAI_API_KEY,
|
|
14069
14282
|
embeddingModel: process.env.EMBEDDING_MODEL
|
|
14070
14283
|
},
|
|
14284
|
+
crypto: {
|
|
14285
|
+
enabled: process.env.CRYPTO_ENABLED === "true",
|
|
14286
|
+
masterKey: process.env.CRYPTO_MASTER_KEY,
|
|
14287
|
+
hmacKey: process.env.CRYPTO_HMAC_KEY
|
|
14288
|
+
},
|
|
14289
|
+
security: {
|
|
14290
|
+
enforceTls: process.env.SECURITY_ENFORCE_TLS !== "false",
|
|
14291
|
+
tlsWarnOnly: process.env.SECURITY_TLS_WARN_ONLY === "true"
|
|
14292
|
+
},
|
|
14071
14293
|
resilience: {
|
|
14072
14294
|
retry: {
|
|
14073
14295
|
enabled: process.env.RESILIENCE_RETRY_ENABLED !== "false",
|
|
@@ -14474,13 +14696,14 @@ var MemoryEmail = class {
|
|
|
14474
14696
|
|
|
14475
14697
|
// src/context/CorrelationContext.ts
|
|
14476
14698
|
import { AsyncLocalStorage } from "async_hooks";
|
|
14699
|
+
import { randomBytes as randomBytes19 } from "crypto";
|
|
14477
14700
|
var CorrelationContextManager = class {
|
|
14478
14701
|
storage = new AsyncLocalStorage();
|
|
14479
14702
|
idGenerator;
|
|
14480
14703
|
constructor() {
|
|
14481
14704
|
this.idGenerator = () => {
|
|
14482
14705
|
const timestamp = Date.now().toString(36);
|
|
14483
|
-
const random =
|
|
14706
|
+
const random = randomBytes19(4).toString("hex");
|
|
14484
14707
|
return `${timestamp}-${random}`;
|
|
14485
14708
|
};
|
|
14486
14709
|
}
|
|
@@ -15110,10 +15333,11 @@ var MemoryQueue = class {
|
|
|
15110
15333
|
};
|
|
15111
15334
|
|
|
15112
15335
|
// src/adapters/console/ConsoleEmail.ts
|
|
15336
|
+
import { randomBytes as randomBytes20 } from "crypto";
|
|
15113
15337
|
var ConsoleEmail = class {
|
|
15114
15338
|
sentEmails = [];
|
|
15115
15339
|
async send(message) {
|
|
15116
|
-
const id = `console_${Date.now()}_${
|
|
15340
|
+
const id = `console_${Date.now()}_${randomBytes20(4).toString("hex")}`;
|
|
15117
15341
|
console.log("\n" + "=".repeat(60));
|
|
15118
15342
|
console.log("\u{1F4E7} EMAIL SENT (Console Adapter)");
|
|
15119
15343
|
console.log("=".repeat(60));
|
|
@@ -15190,6 +15414,152 @@ var ConsoleEmail = class {
|
|
|
15190
15414
|
// src/factory.ts
|
|
15191
15415
|
init_IAI();
|
|
15192
15416
|
init_IRAG();
|
|
15417
|
+
|
|
15418
|
+
// src/adapters/memory/MemoryCrypto.ts
|
|
15419
|
+
import {
|
|
15420
|
+
randomBytes as randomBytes21,
|
|
15421
|
+
createCipheriv,
|
|
15422
|
+
createDecipheriv,
|
|
15423
|
+
createHmac
|
|
15424
|
+
} from "crypto";
|
|
15425
|
+
var MemoryCrypto = class {
|
|
15426
|
+
keys = /* @__PURE__ */ new Map();
|
|
15427
|
+
activeKeyId;
|
|
15428
|
+
hmacKey;
|
|
15429
|
+
constructor(options) {
|
|
15430
|
+
const masterKeyBuf = options?.masterKey ? Buffer.from(options.masterKey, "hex") : randomBytes21(32);
|
|
15431
|
+
this.hmacKey = options?.hmacKey ? Buffer.from(options.hmacKey, "hex") : randomBytes21(32);
|
|
15432
|
+
const keyId = this.generateKeyId();
|
|
15433
|
+
this.keys.set(keyId, {
|
|
15434
|
+
id: keyId,
|
|
15435
|
+
key: masterKeyBuf,
|
|
15436
|
+
status: "active",
|
|
15437
|
+
createdAt: /* @__PURE__ */ new Date()
|
|
15438
|
+
});
|
|
15439
|
+
this.activeKeyId = keyId;
|
|
15440
|
+
}
|
|
15441
|
+
async encrypt(plaintext, options) {
|
|
15442
|
+
const keyId = options?.keyId || this.activeKeyId;
|
|
15443
|
+
const stored = this.keys.get(keyId);
|
|
15444
|
+
if (!stored) {
|
|
15445
|
+
throw new Error(`Key not found: ${keyId}`);
|
|
15446
|
+
}
|
|
15447
|
+
if (stored.status === "retired") {
|
|
15448
|
+
throw new Error(`Key is retired: ${keyId}`);
|
|
15449
|
+
}
|
|
15450
|
+
if (stored.status === "decrypt-only" && !options?.keyId) {
|
|
15451
|
+
throw new Error(`Key is decrypt-only: ${keyId}`);
|
|
15452
|
+
}
|
|
15453
|
+
const iv = randomBytes21(12);
|
|
15454
|
+
const cipher = createCipheriv("aes-256-gcm", stored.key, iv);
|
|
15455
|
+
if (options?.aad) {
|
|
15456
|
+
cipher.setAAD(Buffer.from(options.aad, "utf8"));
|
|
15457
|
+
}
|
|
15458
|
+
const encrypted = Buffer.concat([
|
|
15459
|
+
cipher.update(plaintext, "utf8"),
|
|
15460
|
+
cipher.final()
|
|
15461
|
+
]);
|
|
15462
|
+
const tag = cipher.getAuthTag();
|
|
15463
|
+
return {
|
|
15464
|
+
ciphertext: encrypted.toString("base64"),
|
|
15465
|
+
iv: iv.toString("base64"),
|
|
15466
|
+
tag: tag.toString("base64"),
|
|
15467
|
+
keyId,
|
|
15468
|
+
algorithm: "aes-256-gcm",
|
|
15469
|
+
version: 1
|
|
15470
|
+
};
|
|
15471
|
+
}
|
|
15472
|
+
async decrypt(field, options) {
|
|
15473
|
+
const stored = this.keys.get(field.keyId);
|
|
15474
|
+
if (!stored) {
|
|
15475
|
+
throw new Error(`Key not found: ${field.keyId}`);
|
|
15476
|
+
}
|
|
15477
|
+
if (stored.status === "retired") {
|
|
15478
|
+
throw new Error(`Key is retired and cannot decrypt: ${field.keyId}`);
|
|
15479
|
+
}
|
|
15480
|
+
const decipher = createDecipheriv(
|
|
15481
|
+
"aes-256-gcm",
|
|
15482
|
+
stored.key,
|
|
15483
|
+
Buffer.from(field.iv, "base64")
|
|
15484
|
+
);
|
|
15485
|
+
decipher.setAuthTag(Buffer.from(field.tag, "base64"));
|
|
15486
|
+
if (options?.aad) {
|
|
15487
|
+
decipher.setAAD(Buffer.from(options.aad, "utf8"));
|
|
15488
|
+
}
|
|
15489
|
+
const decrypted = Buffer.concat([
|
|
15490
|
+
decipher.update(Buffer.from(field.ciphertext, "base64")),
|
|
15491
|
+
decipher.final()
|
|
15492
|
+
]);
|
|
15493
|
+
return decrypted.toString("utf8");
|
|
15494
|
+
}
|
|
15495
|
+
async encryptDeterministic(plaintext, options) {
|
|
15496
|
+
const hash = await this.computeHash(plaintext);
|
|
15497
|
+
const encrypted = await this.encrypt(plaintext, options);
|
|
15498
|
+
return { hash, encrypted };
|
|
15499
|
+
}
|
|
15500
|
+
async computeHash(plaintext) {
|
|
15501
|
+
return createHmac("sha256", this.hmacKey).update(plaintext, "utf8").digest("hex");
|
|
15502
|
+
}
|
|
15503
|
+
async encryptBatch(fields, options) {
|
|
15504
|
+
const result = {};
|
|
15505
|
+
for (const [key, value] of Object.entries(fields)) {
|
|
15506
|
+
result[key] = await this.encrypt(value, options);
|
|
15507
|
+
}
|
|
15508
|
+
return result;
|
|
15509
|
+
}
|
|
15510
|
+
async decryptBatch(fields, options) {
|
|
15511
|
+
const result = {};
|
|
15512
|
+
for (const [key, value] of Object.entries(fields)) {
|
|
15513
|
+
result[key] = await this.decrypt(value, options);
|
|
15514
|
+
}
|
|
15515
|
+
return result;
|
|
15516
|
+
}
|
|
15517
|
+
async rotateKey() {
|
|
15518
|
+
const previousKeyId = this.activeKeyId;
|
|
15519
|
+
const currentKey = this.keys.get(previousKeyId);
|
|
15520
|
+
if (currentKey) {
|
|
15521
|
+
currentKey.status = "decrypt-only";
|
|
15522
|
+
}
|
|
15523
|
+
const newKeyId = this.generateKeyId();
|
|
15524
|
+
this.keys.set(newKeyId, {
|
|
15525
|
+
id: newKeyId,
|
|
15526
|
+
key: randomBytes21(32),
|
|
15527
|
+
status: "active",
|
|
15528
|
+
createdAt: /* @__PURE__ */ new Date()
|
|
15529
|
+
});
|
|
15530
|
+
this.activeKeyId = newKeyId;
|
|
15531
|
+
return { newKeyId, previousKeyId };
|
|
15532
|
+
}
|
|
15533
|
+
async reEncrypt(field, options) {
|
|
15534
|
+
const plaintext = await this.decrypt(field);
|
|
15535
|
+
return this.encrypt(plaintext, options);
|
|
15536
|
+
}
|
|
15537
|
+
async listKeys() {
|
|
15538
|
+
return Array.from(this.keys.values()).map((k) => ({
|
|
15539
|
+
keyId: k.id,
|
|
15540
|
+
createdAt: k.createdAt,
|
|
15541
|
+
status: k.status
|
|
15542
|
+
}));
|
|
15543
|
+
}
|
|
15544
|
+
async getActiveKeyId() {
|
|
15545
|
+
return this.activeKeyId;
|
|
15546
|
+
}
|
|
15547
|
+
async healthCheck() {
|
|
15548
|
+
try {
|
|
15549
|
+
const testPlain = "health-check-test";
|
|
15550
|
+
const encrypted = await this.encrypt(testPlain);
|
|
15551
|
+
const decrypted = await this.decrypt(encrypted);
|
|
15552
|
+
return decrypted === testPlain;
|
|
15553
|
+
} catch {
|
|
15554
|
+
return false;
|
|
15555
|
+
}
|
|
15556
|
+
}
|
|
15557
|
+
generateKeyId() {
|
|
15558
|
+
return `key_${randomBytes21(8).toString("hex")}`;
|
|
15559
|
+
}
|
|
15560
|
+
};
|
|
15561
|
+
|
|
15562
|
+
// src/factory.ts
|
|
15193
15563
|
async function createDatabaseAdapter(config) {
|
|
15194
15564
|
switch (config.database.provider) {
|
|
15195
15565
|
case "postgres": {
|
|
@@ -15245,9 +15615,9 @@ async function createCacheAdapter(config) {
|
|
|
15245
15615
|
"Upstash requires UPSTASH_REDIS_REST_URL and UPSTASH_REDIS_REST_TOKEN environment variables"
|
|
15246
15616
|
);
|
|
15247
15617
|
}
|
|
15248
|
-
const { Redis } = await import("@upstash/redis");
|
|
15618
|
+
const { Redis: Redis2 } = await import("@upstash/redis");
|
|
15249
15619
|
const { UpstashCache: UpstashCache2 } = await Promise.resolve().then(() => (init_UpstashCache(), UpstashCache_exports));
|
|
15250
|
-
const client = new
|
|
15620
|
+
const client = new Redis2({
|
|
15251
15621
|
url: config.cache.upstashUrl,
|
|
15252
15622
|
token: config.cache.upstashToken
|
|
15253
15623
|
});
|
|
@@ -15490,16 +15860,73 @@ async function createRAGAdapter(config, ai) {
|
|
|
15490
15860
|
return new MemoryRAG();
|
|
15491
15861
|
}
|
|
15492
15862
|
}
|
|
15863
|
+
async function createCryptoAdapter(config) {
|
|
15864
|
+
if (!config.crypto.enabled) {
|
|
15865
|
+
return null;
|
|
15866
|
+
}
|
|
15867
|
+
if (config.crypto.masterKey && config.crypto.masterKey.length >= 64) {
|
|
15868
|
+
const { NodeCrypto: NodeCrypto2 } = await Promise.resolve().then(() => (init_NodeCrypto(), NodeCrypto_exports));
|
|
15869
|
+
return new NodeCrypto2({
|
|
15870
|
+
masterKey: config.crypto.masterKey,
|
|
15871
|
+
hmacKey: config.crypto.hmacKey
|
|
15872
|
+
});
|
|
15873
|
+
}
|
|
15874
|
+
return new MemoryCrypto();
|
|
15875
|
+
}
|
|
15876
|
+
function validateTlsSecurity(config) {
|
|
15877
|
+
const isProduction = process.env.NODE_ENV === "production";
|
|
15878
|
+
if (!isProduction || !config.security.enforceTls) {
|
|
15879
|
+
return;
|
|
15880
|
+
}
|
|
15881
|
+
const warnings = [];
|
|
15882
|
+
if (config.database.provider === "postgres") {
|
|
15883
|
+
const connStr = config.database.connectionString || config.database.url || "";
|
|
15884
|
+
const hasSSL = config.database.ssl || connStr.includes("sslmode=require") || connStr.includes("sslmode=verify");
|
|
15885
|
+
if (!hasSSL) {
|
|
15886
|
+
warnings.push(
|
|
15887
|
+
"PostgreSQL: TLS/SSL not configured. Set database.ssl=true or add sslmode=require to connection string."
|
|
15888
|
+
);
|
|
15889
|
+
}
|
|
15890
|
+
}
|
|
15891
|
+
if (config.cache.provider === "redis") {
|
|
15892
|
+
const url = config.cache.url || "";
|
|
15893
|
+
if (url && !url.startsWith("rediss://")) {
|
|
15894
|
+
warnings.push(
|
|
15895
|
+
"Redis: Connection URL uses redis:// instead of rediss:// (TLS). Consider enabling TLS."
|
|
15896
|
+
);
|
|
15897
|
+
}
|
|
15898
|
+
}
|
|
15899
|
+
if (config.email.provider === "smtp") {
|
|
15900
|
+
if (!config.email.secure) {
|
|
15901
|
+
warnings.push(
|
|
15902
|
+
"SMTP: secure=false in production. Set email.secure=true for TLS."
|
|
15903
|
+
);
|
|
15904
|
+
}
|
|
15905
|
+
}
|
|
15906
|
+
if (warnings.length > 0) {
|
|
15907
|
+
const message = `[Security] TLS warnings in production:
|
|
15908
|
+
- ${warnings.join("\n - ")}`;
|
|
15909
|
+
if (config.security.tlsWarnOnly) {
|
|
15910
|
+
console.warn(message);
|
|
15911
|
+
} else {
|
|
15912
|
+
throw new Error(message);
|
|
15913
|
+
}
|
|
15914
|
+
}
|
|
15915
|
+
}
|
|
15493
15916
|
async function createPlatformAsync(config) {
|
|
15494
15917
|
const finalConfig = config ? deepMerge(loadConfig(), config) : loadConfig();
|
|
15495
|
-
|
|
15496
|
-
|
|
15497
|
-
|
|
15498
|
-
|
|
15499
|
-
|
|
15500
|
-
|
|
15501
|
-
|
|
15502
|
-
|
|
15918
|
+
validateTlsSecurity(finalConfig);
|
|
15919
|
+
const [db, cache, storage, email, queue, tracing, crypto2] = await Promise.all(
|
|
15920
|
+
[
|
|
15921
|
+
createDatabaseAdapter(finalConfig),
|
|
15922
|
+
createCacheAdapter(finalConfig),
|
|
15923
|
+
createStorageAdapter(finalConfig),
|
|
15924
|
+
createEmailAdapter(finalConfig),
|
|
15925
|
+
createQueueAdapter(finalConfig),
|
|
15926
|
+
createTracingAdapter(finalConfig),
|
|
15927
|
+
createCryptoAdapter(finalConfig)
|
|
15928
|
+
]
|
|
15929
|
+
);
|
|
15503
15930
|
const logger = createLogger(finalConfig);
|
|
15504
15931
|
const metrics = createMetrics(finalConfig);
|
|
15505
15932
|
const ai = await createAIAdapter(finalConfig);
|
|
@@ -15514,7 +15941,8 @@ async function createPlatformAsync(config) {
|
|
|
15514
15941
|
metrics,
|
|
15515
15942
|
tracing,
|
|
15516
15943
|
ai,
|
|
15517
|
-
rag
|
|
15944
|
+
rag,
|
|
15945
|
+
crypto2
|
|
15518
15946
|
);
|
|
15519
15947
|
}
|
|
15520
15948
|
function createPlatform(config) {
|
|
@@ -15535,6 +15963,7 @@ function createPlatform(config) {
|
|
|
15535
15963
|
const tracing = finalConfig.observability.tracing.provider === "memory" ? new MemoryTracing() : new NoopTracing();
|
|
15536
15964
|
const ai = finalConfig.ai.enabled ? new MemoryAI() : null;
|
|
15537
15965
|
const rag = finalConfig.rag.enabled ? new MemoryRAG() : null;
|
|
15966
|
+
const crypto2 = finalConfig.crypto.enabled ? new MemoryCrypto() : null;
|
|
15538
15967
|
return createPlatformFromAdapters(
|
|
15539
15968
|
db,
|
|
15540
15969
|
cache,
|
|
@@ -15545,10 +15974,11 @@ function createPlatform(config) {
|
|
|
15545
15974
|
metrics,
|
|
15546
15975
|
tracing,
|
|
15547
15976
|
ai,
|
|
15548
|
-
rag
|
|
15977
|
+
rag,
|
|
15978
|
+
crypto2
|
|
15549
15979
|
);
|
|
15550
15980
|
}
|
|
15551
|
-
function createPlatformFromAdapters(db, cache, storage, email, queue, logger, metrics, tracing, ai, rag) {
|
|
15981
|
+
function createPlatformFromAdapters(db, cache, storage, email, queue, logger, metrics, tracing, ai, rag, crypto2) {
|
|
15552
15982
|
const platform = {
|
|
15553
15983
|
db,
|
|
15554
15984
|
cache,
|
|
@@ -15602,6 +16032,9 @@ function createPlatformFromAdapters(db, cache, storage, email, queue, logger, me
|
|
|
15602
16032
|
if (rag) {
|
|
15603
16033
|
platform.rag = rag;
|
|
15604
16034
|
}
|
|
16035
|
+
if (crypto2) {
|
|
16036
|
+
platform.crypto = crypto2;
|
|
16037
|
+
}
|
|
15605
16038
|
return platform;
|
|
15606
16039
|
}
|
|
15607
16040
|
function deepMerge(target, source) {
|
|
@@ -17073,6 +17506,7 @@ var FallbackStrategies = {
|
|
|
17073
17506
|
};
|
|
17074
17507
|
|
|
17075
17508
|
// src/security.ts
|
|
17509
|
+
import { timingSafeEqual } from "crypto";
|
|
17076
17510
|
var URL_PROTOCOL_PATTERN = /(https?:\/\/|ftp:\/\/|www\.)\S+/i;
|
|
17077
17511
|
var URL_DOMAIN_PATTERN = /\b[\w.-]+\.(com|net|org|io|co|dev|app|xyz|info|biz|me|us|uk|edu|gov)\b/i;
|
|
17078
17512
|
var HTML_TAG_PATTERN = /<[^>]*>/;
|
|
@@ -17097,6 +17531,144 @@ function defangUrl(str) {
|
|
|
17097
17531
|
function sanitizeForEmail(str) {
|
|
17098
17532
|
return escapeHtml(str);
|
|
17099
17533
|
}
|
|
17534
|
+
function constantTimeEqual(a, b) {
|
|
17535
|
+
try {
|
|
17536
|
+
const aBuf = Buffer.from(a, "utf-8");
|
|
17537
|
+
const bBuf = Buffer.from(b, "utf-8");
|
|
17538
|
+
if (aBuf.length !== bBuf.length) return false;
|
|
17539
|
+
return timingSafeEqual(aBuf, bBuf);
|
|
17540
|
+
} catch {
|
|
17541
|
+
return false;
|
|
17542
|
+
}
|
|
17543
|
+
}
|
|
17544
|
+
function sanitizeApiError(error, statusCode, isDevelopment = false) {
|
|
17545
|
+
if (statusCode >= 400 && statusCode < 500) {
|
|
17546
|
+
const message = error instanceof Error ? error.message : String(error || "Bad request");
|
|
17547
|
+
return { message };
|
|
17548
|
+
}
|
|
17549
|
+
const result = {
|
|
17550
|
+
message: "An internal error occurred. Please try again later.",
|
|
17551
|
+
code: "INTERNAL_ERROR"
|
|
17552
|
+
};
|
|
17553
|
+
if (isDevelopment && error instanceof Error) {
|
|
17554
|
+
result.stack = error.stack;
|
|
17555
|
+
}
|
|
17556
|
+
return result;
|
|
17557
|
+
}
|
|
17558
|
+
function getCorrelationId2(headers) {
|
|
17559
|
+
const get = typeof headers === "function" ? headers : (name) => {
|
|
17560
|
+
const val = headers[name] ?? headers[name.toLowerCase()];
|
|
17561
|
+
return Array.isArray(val) ? val[0] : val;
|
|
17562
|
+
};
|
|
17563
|
+
return get("x-request-id") || get("X-Request-ID") || get("x-correlation-id") || get("X-Correlation-ID") || crypto.randomUUID();
|
|
17564
|
+
}
|
|
17565
|
+
|
|
17566
|
+
// src/security-headers.ts
|
|
17567
|
+
var SecurityHeaderPresets = {
|
|
17568
|
+
/** Minimal: basic headers only, no CSP */
|
|
17569
|
+
minimal: {
|
|
17570
|
+
csp: false,
|
|
17571
|
+
hsts: false
|
|
17572
|
+
},
|
|
17573
|
+
/** Standard: full CSP + HSTS for most apps */
|
|
17574
|
+
standard: {
|
|
17575
|
+
csp: true,
|
|
17576
|
+
hsts: true,
|
|
17577
|
+
frameOptions: "DENY"
|
|
17578
|
+
},
|
|
17579
|
+
/** Strict: deny all permissions, strict CSP, no frame embedding */
|
|
17580
|
+
strict: {
|
|
17581
|
+
csp: true,
|
|
17582
|
+
hsts: true,
|
|
17583
|
+
hstsMaxAge: 63072e3,
|
|
17584
|
+
// 2 years
|
|
17585
|
+
frameOptions: "DENY"
|
|
17586
|
+
}
|
|
17587
|
+
};
|
|
17588
|
+
function generateSecurityHeaders(config = {}) {
|
|
17589
|
+
const isProduction = config.isProduction ?? process.env.NODE_ENV === "production";
|
|
17590
|
+
const frameOptions = config.frameOptions ?? "DENY";
|
|
17591
|
+
const enableCsp = config.csp ?? true;
|
|
17592
|
+
const enableHsts = config.hsts ?? true;
|
|
17593
|
+
const hstsMaxAge = config.hstsMaxAge ?? 31536e3;
|
|
17594
|
+
const baseHeaders = [
|
|
17595
|
+
{ key: "X-Frame-Options", value: frameOptions },
|
|
17596
|
+
{ key: "X-Content-Type-Options", value: "nosniff" },
|
|
17597
|
+
// Modern browsers use CSP, not XSS-Protection. Value '0' disables the
|
|
17598
|
+
// legacy filter which can itself introduce vulnerabilities.
|
|
17599
|
+
{ key: "X-XSS-Protection", value: "0" },
|
|
17600
|
+
{
|
|
17601
|
+
key: "Referrer-Policy",
|
|
17602
|
+
value: "strict-origin-when-cross-origin"
|
|
17603
|
+
},
|
|
17604
|
+
{
|
|
17605
|
+
key: "Permissions-Policy",
|
|
17606
|
+
value: "camera=(), microphone=(), geolocation=()"
|
|
17607
|
+
}
|
|
17608
|
+
];
|
|
17609
|
+
const entries = [
|
|
17610
|
+
{ source: "/:path*", headers: baseHeaders }
|
|
17611
|
+
];
|
|
17612
|
+
if (isProduction) {
|
|
17613
|
+
const prodHeaders = [];
|
|
17614
|
+
if (enableHsts) {
|
|
17615
|
+
prodHeaders.push({
|
|
17616
|
+
key: "Strict-Transport-Security",
|
|
17617
|
+
value: `max-age=${hstsMaxAge}; includeSubDomains`
|
|
17618
|
+
});
|
|
17619
|
+
}
|
|
17620
|
+
if (enableCsp) {
|
|
17621
|
+
const csp = buildCsp(config);
|
|
17622
|
+
prodHeaders.push({ key: "Content-Security-Policy", value: csp });
|
|
17623
|
+
}
|
|
17624
|
+
if (prodHeaders.length > 0) {
|
|
17625
|
+
entries.push({ source: "/:path*", headers: prodHeaders });
|
|
17626
|
+
}
|
|
17627
|
+
}
|
|
17628
|
+
return entries;
|
|
17629
|
+
}
|
|
17630
|
+
function buildCsp(config) {
|
|
17631
|
+
const scriptSrc = [
|
|
17632
|
+
"'self'",
|
|
17633
|
+
"'unsafe-inline'",
|
|
17634
|
+
"'unsafe-eval'",
|
|
17635
|
+
...config.cspScriptSrc ?? []
|
|
17636
|
+
];
|
|
17637
|
+
const styleSrc = [
|
|
17638
|
+
"'self'",
|
|
17639
|
+
"'unsafe-inline'",
|
|
17640
|
+
"https://fonts.googleapis.com",
|
|
17641
|
+
...config.cspStyleSrc ?? []
|
|
17642
|
+
];
|
|
17643
|
+
const imgSrc = [
|
|
17644
|
+
"'self'",
|
|
17645
|
+
"data:",
|
|
17646
|
+
"https:",
|
|
17647
|
+
"blob:",
|
|
17648
|
+
...config.cspImgSrc ?? []
|
|
17649
|
+
];
|
|
17650
|
+
const fontSrc = ["'self'", "data:", "https://fonts.gstatic.com"];
|
|
17651
|
+
const connectSrc = ["'self'", ...config.cspConnectSrc ?? []];
|
|
17652
|
+
const frameSrc = [...config.cspFrameSrc ?? []];
|
|
17653
|
+
const directives = [
|
|
17654
|
+
`default-src 'self'`,
|
|
17655
|
+
`script-src ${scriptSrc.join(" ")}`,
|
|
17656
|
+
`style-src ${styleSrc.join(" ")}`,
|
|
17657
|
+
`img-src ${imgSrc.join(" ")}`,
|
|
17658
|
+
`font-src ${fontSrc.join(" ")}`,
|
|
17659
|
+
`connect-src ${connectSrc.join(" ")}`
|
|
17660
|
+
];
|
|
17661
|
+
if (frameSrc.length > 0) {
|
|
17662
|
+
directives.push(`frame-src ${frameSrc.join(" ")}`);
|
|
17663
|
+
}
|
|
17664
|
+
directives.push(
|
|
17665
|
+
`object-src 'none'`,
|
|
17666
|
+
`base-uri 'self'`,
|
|
17667
|
+
`form-action 'self'`,
|
|
17668
|
+
`frame-ancestors 'none'`
|
|
17669
|
+
);
|
|
17670
|
+
return directives.join("; ");
|
|
17671
|
+
}
|
|
17100
17672
|
|
|
17101
17673
|
// src/api.ts
|
|
17102
17674
|
var ApiErrorCode = {
|
|
@@ -17223,6 +17795,850 @@ function buildPagination(page, limit, total) {
|
|
|
17223
17795
|
};
|
|
17224
17796
|
}
|
|
17225
17797
|
|
|
17798
|
+
// src/auth/keycloak.ts
|
|
17799
|
+
var KEYCLOAK_DEFAULT_ROLES = [
|
|
17800
|
+
"offline_access",
|
|
17801
|
+
"uma_authorization"
|
|
17802
|
+
];
|
|
17803
|
+
function parseKeycloakRoles(accessToken, additionalDefaultRoles = []) {
|
|
17804
|
+
if (!accessToken) return [];
|
|
17805
|
+
try {
|
|
17806
|
+
const parts = accessToken.split(".");
|
|
17807
|
+
if (parts.length !== 3) return [];
|
|
17808
|
+
const payload = parts[1];
|
|
17809
|
+
const decoded = JSON.parse(atob(payload));
|
|
17810
|
+
const realmRoles = decoded.realm_roles ?? decoded.realm_access?.roles;
|
|
17811
|
+
if (!Array.isArray(realmRoles)) return [];
|
|
17812
|
+
const filterSet = /* @__PURE__ */ new Set([
|
|
17813
|
+
...KEYCLOAK_DEFAULT_ROLES,
|
|
17814
|
+
...additionalDefaultRoles
|
|
17815
|
+
]);
|
|
17816
|
+
return realmRoles.filter(
|
|
17817
|
+
(role) => typeof role === "string" && !filterSet.has(role)
|
|
17818
|
+
);
|
|
17819
|
+
} catch {
|
|
17820
|
+
return [];
|
|
17821
|
+
}
|
|
17822
|
+
}
|
|
17823
|
+
function hasRole(roles, role) {
|
|
17824
|
+
return roles?.includes(role) ?? false;
|
|
17825
|
+
}
|
|
17826
|
+
function hasAnyRole(roles, requiredRoles) {
|
|
17827
|
+
if (!roles || roles.length === 0) return false;
|
|
17828
|
+
return requiredRoles.some((role) => roles.includes(role));
|
|
17829
|
+
}
|
|
17830
|
+
function hasAllRoles(roles, requiredRoles) {
|
|
17831
|
+
if (!roles || roles.length === 0) return false;
|
|
17832
|
+
return requiredRoles.every((role) => roles.includes(role));
|
|
17833
|
+
}
|
|
17834
|
+
function isTokenExpired(expiresAt, bufferMs = 6e4) {
|
|
17835
|
+
if (!expiresAt) return true;
|
|
17836
|
+
return Date.now() >= expiresAt - bufferMs;
|
|
17837
|
+
}
|
|
17838
|
+
function buildTokenRefreshParams(config, refreshToken) {
|
|
17839
|
+
return new URLSearchParams({
|
|
17840
|
+
grant_type: "refresh_token",
|
|
17841
|
+
client_id: config.clientId,
|
|
17842
|
+
client_secret: config.clientSecret,
|
|
17843
|
+
refresh_token: refreshToken
|
|
17844
|
+
});
|
|
17845
|
+
}
|
|
17846
|
+
function getTokenEndpoint(issuer) {
|
|
17847
|
+
const base = issuer.endsWith("/") ? issuer.slice(0, -1) : issuer;
|
|
17848
|
+
return `${base}/protocol/openid-connect/token`;
|
|
17849
|
+
}
|
|
17850
|
+
function getEndSessionEndpoint(issuer) {
|
|
17851
|
+
const base = issuer.endsWith("/") ? issuer.slice(0, -1) : issuer;
|
|
17852
|
+
return `${base}/protocol/openid-connect/logout`;
|
|
17853
|
+
}
|
|
17854
|
+
async function refreshKeycloakToken(config, refreshToken, additionalDefaultRoles) {
|
|
17855
|
+
try {
|
|
17856
|
+
const endpoint = getTokenEndpoint(config.issuer);
|
|
17857
|
+
const params = buildTokenRefreshParams(config, refreshToken);
|
|
17858
|
+
const response = await fetch(endpoint, {
|
|
17859
|
+
method: "POST",
|
|
17860
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
17861
|
+
body: params
|
|
17862
|
+
});
|
|
17863
|
+
if (!response.ok) {
|
|
17864
|
+
const body = await response.text().catch(() => "");
|
|
17865
|
+
return {
|
|
17866
|
+
ok: false,
|
|
17867
|
+
error: `Token refresh failed: HTTP ${response.status} - ${body}`
|
|
17868
|
+
};
|
|
17869
|
+
}
|
|
17870
|
+
const data = await response.json();
|
|
17871
|
+
return {
|
|
17872
|
+
ok: true,
|
|
17873
|
+
tokens: {
|
|
17874
|
+
accessToken: data.access_token,
|
|
17875
|
+
refreshToken: data.refresh_token ?? refreshToken,
|
|
17876
|
+
idToken: data.id_token,
|
|
17877
|
+
expiresAt: Date.now() + data.expires_in * 1e3,
|
|
17878
|
+
roles: parseKeycloakRoles(data.access_token, additionalDefaultRoles)
|
|
17879
|
+
}
|
|
17880
|
+
};
|
|
17881
|
+
} catch (error) {
|
|
17882
|
+
return {
|
|
17883
|
+
ok: false,
|
|
17884
|
+
error: error instanceof Error ? error.message : "Token refresh failed"
|
|
17885
|
+
};
|
|
17886
|
+
}
|
|
17887
|
+
}
|
|
17888
|
+
|
|
17889
|
+
// src/auth/nextjs-keycloak.ts
|
|
17890
|
+
function buildAuthCookies(config = {}) {
|
|
17891
|
+
const { domain, sessionToken = true, callbackUrl = true } = config;
|
|
17892
|
+
const isProduction = process.env.NODE_ENV === "production";
|
|
17893
|
+
const cookieDomain = isProduction ? domain : void 0;
|
|
17894
|
+
const baseOptions = {
|
|
17895
|
+
httpOnly: true,
|
|
17896
|
+
sameSite: "lax",
|
|
17897
|
+
path: "/",
|
|
17898
|
+
secure: isProduction,
|
|
17899
|
+
domain: cookieDomain
|
|
17900
|
+
};
|
|
17901
|
+
const cookies = {
|
|
17902
|
+
pkceCodeVerifier: {
|
|
17903
|
+
name: "authjs.pkce.code_verifier",
|
|
17904
|
+
options: { ...baseOptions }
|
|
17905
|
+
},
|
|
17906
|
+
state: {
|
|
17907
|
+
name: "authjs.state",
|
|
17908
|
+
options: { ...baseOptions }
|
|
17909
|
+
}
|
|
17910
|
+
};
|
|
17911
|
+
if (sessionToken) {
|
|
17912
|
+
cookies.sessionToken = {
|
|
17913
|
+
name: isProduction ? "__Secure-authjs.session-token" : "authjs.session-token",
|
|
17914
|
+
options: { ...baseOptions }
|
|
17915
|
+
};
|
|
17916
|
+
}
|
|
17917
|
+
if (callbackUrl) {
|
|
17918
|
+
cookies.callbackUrl = {
|
|
17919
|
+
name: isProduction ? "__Secure-authjs.callback-url" : "authjs.callback-url",
|
|
17920
|
+
options: { ...baseOptions }
|
|
17921
|
+
};
|
|
17922
|
+
}
|
|
17923
|
+
return cookies;
|
|
17924
|
+
}
|
|
17925
|
+
function buildRedirectCallback(config = {}) {
|
|
17926
|
+
const { allowWwwVariant = false } = config;
|
|
17927
|
+
return async ({ url, baseUrl }) => {
|
|
17928
|
+
if (url.startsWith("/")) return `${baseUrl}${url}`;
|
|
17929
|
+
try {
|
|
17930
|
+
if (new URL(url).origin === baseUrl) return url;
|
|
17931
|
+
} catch {
|
|
17932
|
+
return baseUrl;
|
|
17933
|
+
}
|
|
17934
|
+
if (allowWwwVariant) {
|
|
17935
|
+
try {
|
|
17936
|
+
const urlHost = new URL(url).hostname;
|
|
17937
|
+
const baseHost = new URL(baseUrl).hostname;
|
|
17938
|
+
if (urlHost === `www.${baseHost}` || baseHost === `www.${urlHost}`) {
|
|
17939
|
+
return url;
|
|
17940
|
+
}
|
|
17941
|
+
} catch {
|
|
17942
|
+
}
|
|
17943
|
+
}
|
|
17944
|
+
return baseUrl;
|
|
17945
|
+
};
|
|
17946
|
+
}
|
|
17947
|
+
function buildKeycloakCallbacks(config) {
|
|
17948
|
+
const {
|
|
17949
|
+
issuer,
|
|
17950
|
+
clientId,
|
|
17951
|
+
clientSecret,
|
|
17952
|
+
defaultRoles = [],
|
|
17953
|
+
debug = process.env.NODE_ENV === "development"
|
|
17954
|
+
} = config;
|
|
17955
|
+
const kcConfig = { issuer, clientId, clientSecret };
|
|
17956
|
+
function log(message, meta) {
|
|
17957
|
+
if (debug) {
|
|
17958
|
+
console.log(`[Auth] ${message}`, meta ? JSON.stringify(meta) : "");
|
|
17959
|
+
}
|
|
17960
|
+
}
|
|
17961
|
+
return {
|
|
17962
|
+
/**
|
|
17963
|
+
* JWT callback — stores Keycloak tokens and handles refresh.
|
|
17964
|
+
*
|
|
17965
|
+
* Compatible with Auth.js v5 JWT callback signature.
|
|
17966
|
+
*/
|
|
17967
|
+
async jwt({
|
|
17968
|
+
token,
|
|
17969
|
+
user,
|
|
17970
|
+
account
|
|
17971
|
+
}) {
|
|
17972
|
+
if (user) {
|
|
17973
|
+
token.id = token.sub ?? user.id;
|
|
17974
|
+
}
|
|
17975
|
+
if (account?.provider === "keycloak") {
|
|
17976
|
+
token.accessToken = account.access_token;
|
|
17977
|
+
token.refreshToken = account.refresh_token;
|
|
17978
|
+
token.idToken = account.id_token;
|
|
17979
|
+
token.roles = parseKeycloakRoles(
|
|
17980
|
+
account.access_token,
|
|
17981
|
+
defaultRoles
|
|
17982
|
+
);
|
|
17983
|
+
token.accessTokenExpires = account.expires_at ? account.expires_at * 1e3 : Date.now() + 3e5;
|
|
17984
|
+
return token;
|
|
17985
|
+
}
|
|
17986
|
+
if (!isTokenExpired(token.accessTokenExpires)) {
|
|
17987
|
+
return token;
|
|
17988
|
+
}
|
|
17989
|
+
if (token.refreshToken) {
|
|
17990
|
+
log("Token expired, attempting refresh...");
|
|
17991
|
+
const result = await refreshKeycloakToken(
|
|
17992
|
+
kcConfig,
|
|
17993
|
+
token.refreshToken,
|
|
17994
|
+
defaultRoles
|
|
17995
|
+
);
|
|
17996
|
+
if (result.ok) {
|
|
17997
|
+
token.accessToken = result.tokens.accessToken;
|
|
17998
|
+
token.idToken = result.tokens.idToken ?? token.idToken;
|
|
17999
|
+
token.refreshToken = result.tokens.refreshToken ?? token.refreshToken;
|
|
18000
|
+
token.accessTokenExpires = result.tokens.expiresAt;
|
|
18001
|
+
token.roles = result.tokens.roles;
|
|
18002
|
+
delete token.error;
|
|
18003
|
+
log("Token refreshed OK");
|
|
18004
|
+
return token;
|
|
18005
|
+
}
|
|
18006
|
+
log("Token refresh failed", { error: result.error });
|
|
18007
|
+
return { ...token, error: "RefreshTokenError" };
|
|
18008
|
+
}
|
|
18009
|
+
log("Token expired but no refresh token available");
|
|
18010
|
+
return { ...token, error: "RefreshTokenError" };
|
|
18011
|
+
},
|
|
18012
|
+
/**
|
|
18013
|
+
* Session callback — maps JWT fields to the session object.
|
|
18014
|
+
*
|
|
18015
|
+
* Compatible with Auth.js v5 session callback signature.
|
|
18016
|
+
*/
|
|
18017
|
+
async session({
|
|
18018
|
+
session,
|
|
18019
|
+
token
|
|
18020
|
+
}) {
|
|
18021
|
+
const user = session.user;
|
|
18022
|
+
if (user) {
|
|
18023
|
+
user.id = token.id || token.sub;
|
|
18024
|
+
user.roles = token.roles || [];
|
|
18025
|
+
}
|
|
18026
|
+
session.idToken = token.idToken;
|
|
18027
|
+
session.accessToken = token.accessToken;
|
|
18028
|
+
if (token.error) {
|
|
18029
|
+
session.error = token.error;
|
|
18030
|
+
}
|
|
18031
|
+
return session;
|
|
18032
|
+
}
|
|
18033
|
+
};
|
|
18034
|
+
}
|
|
18035
|
+
|
|
18036
|
+
// src/auth/api-security.ts
|
|
18037
|
+
var StandardRateLimitPresets = {
|
|
18038
|
+
/** General API: 100/min, 200/min authenticated */
|
|
18039
|
+
apiGeneral: {
|
|
18040
|
+
limit: 100,
|
|
18041
|
+
windowSeconds: 60,
|
|
18042
|
+
authenticatedLimit: 200
|
|
18043
|
+
},
|
|
18044
|
+
/** Admin operations: 100/min (admins are trusted) */
|
|
18045
|
+
adminAction: {
|
|
18046
|
+
limit: 100,
|
|
18047
|
+
windowSeconds: 60
|
|
18048
|
+
},
|
|
18049
|
+
/** AI/expensive operations: 20/hour, 50/hour authenticated */
|
|
18050
|
+
aiRequest: {
|
|
18051
|
+
limit: 20,
|
|
18052
|
+
windowSeconds: 3600,
|
|
18053
|
+
authenticatedLimit: 50
|
|
18054
|
+
},
|
|
18055
|
+
/** Auth attempts: 5/15min with 15min block */
|
|
18056
|
+
authAttempt: {
|
|
18057
|
+
limit: 5,
|
|
18058
|
+
windowSeconds: 900,
|
|
18059
|
+
blockDurationSeconds: 900
|
|
18060
|
+
},
|
|
18061
|
+
/** Contact/public forms: 10/hour */
|
|
18062
|
+
publicForm: {
|
|
18063
|
+
limit: 10,
|
|
18064
|
+
windowSeconds: 3600,
|
|
18065
|
+
blockDurationSeconds: 1800
|
|
18066
|
+
},
|
|
18067
|
+
/** Checkout/billing: 10/hour with 1hr block */
|
|
18068
|
+
checkout: {
|
|
18069
|
+
limit: 10,
|
|
18070
|
+
windowSeconds: 3600,
|
|
18071
|
+
blockDurationSeconds: 3600
|
|
18072
|
+
}
|
|
18073
|
+
};
|
|
18074
|
+
function resolveRateLimitIdentifier(session, clientIp) {
|
|
18075
|
+
if (session?.user?.id) {
|
|
18076
|
+
return { identifier: `user:${session.user.id}`, isAuthenticated: true };
|
|
18077
|
+
}
|
|
18078
|
+
if (session?.user?.email) {
|
|
18079
|
+
return {
|
|
18080
|
+
identifier: `email:${session.user.email}`,
|
|
18081
|
+
isAuthenticated: true
|
|
18082
|
+
};
|
|
18083
|
+
}
|
|
18084
|
+
return { identifier: `ip:${clientIp}`, isAuthenticated: false };
|
|
18085
|
+
}
|
|
18086
|
+
function extractClientIp(getHeader) {
|
|
18087
|
+
return getHeader("cf-connecting-ip") || getHeader("x-real-ip") || getHeader("x-forwarded-for")?.split(",")[0]?.trim() || "unknown";
|
|
18088
|
+
}
|
|
18089
|
+
function buildRateLimitHeaders(limit, remaining, resetAtMs) {
|
|
18090
|
+
return {
|
|
18091
|
+
"X-RateLimit-Limit": String(limit),
|
|
18092
|
+
"X-RateLimit-Remaining": String(Math.max(0, remaining)),
|
|
18093
|
+
"X-RateLimit-Reset": String(Math.ceil(resetAtMs / 1e3))
|
|
18094
|
+
};
|
|
18095
|
+
}
|
|
18096
|
+
function buildErrorBody(error, extra) {
|
|
18097
|
+
return { error, ...extra };
|
|
18098
|
+
}
|
|
18099
|
+
var WrapperPresets = {
|
|
18100
|
+
/** Public route: no auth, rate limited */
|
|
18101
|
+
public: {
|
|
18102
|
+
requireAuth: false,
|
|
18103
|
+
requireAdmin: false,
|
|
18104
|
+
rateLimit: "apiGeneral"
|
|
18105
|
+
},
|
|
18106
|
+
/** Authenticated route: requires session */
|
|
18107
|
+
authenticated: {
|
|
18108
|
+
requireAuth: true,
|
|
18109
|
+
requireAdmin: false,
|
|
18110
|
+
rateLimit: "apiGeneral"
|
|
18111
|
+
},
|
|
18112
|
+
/** Admin route: requires session with admin role */
|
|
18113
|
+
admin: {
|
|
18114
|
+
requireAuth: true,
|
|
18115
|
+
requireAdmin: true,
|
|
18116
|
+
rateLimit: "adminAction"
|
|
18117
|
+
},
|
|
18118
|
+
/** Legacy admin: accepts session OR bearer token */
|
|
18119
|
+
legacyAdmin: {
|
|
18120
|
+
requireAuth: true,
|
|
18121
|
+
requireAdmin: true,
|
|
18122
|
+
allowBearerToken: true,
|
|
18123
|
+
rateLimit: "adminAction"
|
|
18124
|
+
},
|
|
18125
|
+
/** AI/expensive: requires auth, strict rate limit */
|
|
18126
|
+
ai: {
|
|
18127
|
+
requireAuth: true,
|
|
18128
|
+
requireAdmin: false,
|
|
18129
|
+
rateLimit: "aiRequest"
|
|
18130
|
+
},
|
|
18131
|
+
/** Cron: no rate limit, admin-level access */
|
|
18132
|
+
cron: {
|
|
18133
|
+
requireAuth: true,
|
|
18134
|
+
requireAdmin: false,
|
|
18135
|
+
skipRateLimit: true,
|
|
18136
|
+
skipAudit: false
|
|
18137
|
+
}
|
|
18138
|
+
};
|
|
18139
|
+
|
|
18140
|
+
// src/auth/schemas.ts
|
|
18141
|
+
import { z as z2 } from "zod";
|
|
18142
|
+
var EmailSchema = z2.string().trim().toLowerCase().email("Invalid email address");
|
|
18143
|
+
var PasswordSchema = z2.string().min(8, "Password must be at least 8 characters").max(100, "Password must be less than 100 characters");
|
|
18144
|
+
var SlugSchema = z2.string().min(1, "Slug is required").max(100, "Slug must be less than 100 characters").regex(
|
|
18145
|
+
/^[a-z0-9-]+$/,
|
|
18146
|
+
"Slug can only contain lowercase letters, numbers, and hyphens"
|
|
18147
|
+
);
|
|
18148
|
+
var PhoneSchema = z2.string().regex(/^[\d\s()+.\-]{7,20}$/, "Invalid phone number format");
|
|
18149
|
+
var PersonNameSchema = z2.string().min(2, "Name must be at least 2 characters").max(100, "Name must be less than 100 characters").regex(
|
|
18150
|
+
/^[a-zA-Z\s\-']+$/,
|
|
18151
|
+
"Name can only contain letters, spaces, hyphens and apostrophes"
|
|
18152
|
+
);
|
|
18153
|
+
function createSafeTextSchema(options) {
|
|
18154
|
+
const {
|
|
18155
|
+
min,
|
|
18156
|
+
max,
|
|
18157
|
+
allowHtml = false,
|
|
18158
|
+
allowUrls = false,
|
|
18159
|
+
fieldName = "Text"
|
|
18160
|
+
} = options ?? {};
|
|
18161
|
+
let schema = z2.string();
|
|
18162
|
+
if (min !== void 0)
|
|
18163
|
+
schema = schema.min(min, `${fieldName} must be at least ${min} characters`);
|
|
18164
|
+
if (max !== void 0)
|
|
18165
|
+
schema = schema.max(
|
|
18166
|
+
max,
|
|
18167
|
+
`${fieldName} must be less than ${max} characters`
|
|
18168
|
+
);
|
|
18169
|
+
if (!allowHtml && !allowUrls) {
|
|
18170
|
+
return schema.refine((val) => !HTML_TAG_PATTERN.test(val), "HTML tags are not allowed").refine(
|
|
18171
|
+
(val) => !URL_PROTOCOL_PATTERN.test(val),
|
|
18172
|
+
"Links are not allowed for security reasons"
|
|
18173
|
+
).refine(
|
|
18174
|
+
(val) => !URL_DOMAIN_PATTERN.test(val),
|
|
18175
|
+
"Links are not allowed for security reasons"
|
|
18176
|
+
);
|
|
18177
|
+
}
|
|
18178
|
+
if (!allowHtml) {
|
|
18179
|
+
return schema.refine(
|
|
18180
|
+
(val) => !HTML_TAG_PATTERN.test(val),
|
|
18181
|
+
"HTML tags are not allowed"
|
|
18182
|
+
);
|
|
18183
|
+
}
|
|
18184
|
+
if (!allowUrls) {
|
|
18185
|
+
return schema.refine(
|
|
18186
|
+
(val) => !URL_PROTOCOL_PATTERN.test(val),
|
|
18187
|
+
"Links are not allowed for security reasons"
|
|
18188
|
+
).refine(
|
|
18189
|
+
(val) => !URL_DOMAIN_PATTERN.test(val),
|
|
18190
|
+
"Links are not allowed for security reasons"
|
|
18191
|
+
);
|
|
18192
|
+
}
|
|
18193
|
+
return schema;
|
|
18194
|
+
}
|
|
18195
|
+
var PaginationSchema = z2.object({
|
|
18196
|
+
page: z2.coerce.number().int().positive().default(1),
|
|
18197
|
+
limit: z2.coerce.number().int().positive().max(100).default(20),
|
|
18198
|
+
sortBy: z2.string().optional(),
|
|
18199
|
+
sortOrder: z2.enum(["asc", "desc"]).default("desc")
|
|
18200
|
+
});
|
|
18201
|
+
var DateRangeSchema = z2.object({
|
|
18202
|
+
startDate: z2.string().datetime(),
|
|
18203
|
+
endDate: z2.string().datetime()
|
|
18204
|
+
}).refine((data) => new Date(data.startDate) <= new Date(data.endDate), {
|
|
18205
|
+
message: "Start date must be before end date"
|
|
18206
|
+
});
|
|
18207
|
+
var SearchQuerySchema = z2.object({
|
|
18208
|
+
query: z2.string().min(1).max(200).trim(),
|
|
18209
|
+
page: z2.coerce.number().int().positive().default(1),
|
|
18210
|
+
limit: z2.coerce.number().int().positive().max(50).default(10)
|
|
18211
|
+
});
|
|
18212
|
+
var LoginSchema = z2.object({
|
|
18213
|
+
email: EmailSchema,
|
|
18214
|
+
password: PasswordSchema
|
|
18215
|
+
});
|
|
18216
|
+
var SignupSchema = z2.object({
|
|
18217
|
+
email: EmailSchema,
|
|
18218
|
+
password: PasswordSchema,
|
|
18219
|
+
name: z2.string().min(2).max(100).optional()
|
|
18220
|
+
});
|
|
18221
|
+
|
|
18222
|
+
// src/auth/feature-flags.ts
|
|
18223
|
+
function detectStage() {
|
|
18224
|
+
const stage = process.env.DEPLOYMENT_STAGE;
|
|
18225
|
+
if (stage === "staging" || stage === "preview") return stage;
|
|
18226
|
+
if (process.env.NODE_ENV === "production") return "production";
|
|
18227
|
+
return "development";
|
|
18228
|
+
}
|
|
18229
|
+
function resolveFlagValue(value) {
|
|
18230
|
+
if (typeof value === "boolean") return value;
|
|
18231
|
+
const envValue = process.env[value.envVar];
|
|
18232
|
+
if (envValue === void 0 || envValue === "") {
|
|
18233
|
+
return value.default ?? false;
|
|
18234
|
+
}
|
|
18235
|
+
return envValue === "true" || envValue === "1";
|
|
18236
|
+
}
|
|
18237
|
+
function createFeatureFlags(definitions) {
|
|
18238
|
+
return {
|
|
18239
|
+
/**
|
|
18240
|
+
* Resolve all flags for the current environment.
|
|
18241
|
+
* Call this once at startup or per-request for dynamic flags.
|
|
18242
|
+
*/
|
|
18243
|
+
resolve(stage) {
|
|
18244
|
+
const currentStage = stage ?? detectStage();
|
|
18245
|
+
const resolved = {};
|
|
18246
|
+
for (const [key, def] of Object.entries(definitions)) {
|
|
18247
|
+
const stageKey = currentStage === "preview" ? "staging" : currentStage;
|
|
18248
|
+
resolved[key] = resolveFlagValue(def[stageKey]);
|
|
18249
|
+
}
|
|
18250
|
+
return resolved;
|
|
18251
|
+
},
|
|
18252
|
+
/**
|
|
18253
|
+
* Check if a single flag is enabled.
|
|
18254
|
+
*/
|
|
18255
|
+
isEnabled(flag, stage) {
|
|
18256
|
+
const currentStage = stage ?? detectStage();
|
|
18257
|
+
const def = definitions[flag];
|
|
18258
|
+
const stageKey = currentStage === "preview" ? "staging" : currentStage;
|
|
18259
|
+
return resolveFlagValue(def[stageKey]);
|
|
18260
|
+
},
|
|
18261
|
+
/**
|
|
18262
|
+
* Get the flag definitions (for introspection/admin UI).
|
|
18263
|
+
*/
|
|
18264
|
+
definitions
|
|
18265
|
+
};
|
|
18266
|
+
}
|
|
18267
|
+
function buildAllowlist(config) {
|
|
18268
|
+
const fromEnv = config.envVar ? process.env[config.envVar]?.split(",").map((e) => e.trim().toLowerCase()).filter(Boolean) ?? [] : [];
|
|
18269
|
+
const fallback = config.fallback?.map((e) => e.toLowerCase()) ?? [];
|
|
18270
|
+
return [.../* @__PURE__ */ new Set([...fromEnv, ...fallback])];
|
|
18271
|
+
}
|
|
18272
|
+
function isAllowlisted(email, allowlist) {
|
|
18273
|
+
return allowlist.includes(email.toLowerCase());
|
|
18274
|
+
}
|
|
18275
|
+
|
|
18276
|
+
// src/auth/rate-limiter.ts
|
|
18277
|
+
var CommonRateLimits = {
|
|
18278
|
+
/** General API: 100/min, 200/min authenticated */
|
|
18279
|
+
apiGeneral: {
|
|
18280
|
+
limit: 100,
|
|
18281
|
+
windowSeconds: 60,
|
|
18282
|
+
authenticatedLimit: 200
|
|
18283
|
+
},
|
|
18284
|
+
/** Admin actions: 100/min */
|
|
18285
|
+
adminAction: {
|
|
18286
|
+
limit: 100,
|
|
18287
|
+
windowSeconds: 60
|
|
18288
|
+
},
|
|
18289
|
+
/** Auth attempts: 10/15min with 30min block */
|
|
18290
|
+
authAttempt: {
|
|
18291
|
+
limit: 10,
|
|
18292
|
+
windowSeconds: 900,
|
|
18293
|
+
blockDurationSeconds: 1800
|
|
18294
|
+
},
|
|
18295
|
+
/** AI/expensive requests: 20/hour, 50/hour authenticated */
|
|
18296
|
+
aiRequest: {
|
|
18297
|
+
limit: 20,
|
|
18298
|
+
windowSeconds: 3600,
|
|
18299
|
+
authenticatedLimit: 50
|
|
18300
|
+
},
|
|
18301
|
+
/** Public form submissions: 5/hour with 1hr block */
|
|
18302
|
+
publicForm: {
|
|
18303
|
+
limit: 5,
|
|
18304
|
+
windowSeconds: 3600,
|
|
18305
|
+
blockDurationSeconds: 3600
|
|
18306
|
+
},
|
|
18307
|
+
/** Checkout/billing: 10/hour with 1hr block */
|
|
18308
|
+
checkout: {
|
|
18309
|
+
limit: 10,
|
|
18310
|
+
windowSeconds: 3600,
|
|
18311
|
+
blockDurationSeconds: 3600
|
|
18312
|
+
}
|
|
18313
|
+
};
|
|
18314
|
+
function createMemoryRateLimitStore() {
|
|
18315
|
+
const windows = /* @__PURE__ */ new Map();
|
|
18316
|
+
const blocks = /* @__PURE__ */ new Map();
|
|
18317
|
+
const cleanupInterval = setInterval(() => {
|
|
18318
|
+
const now = Date.now();
|
|
18319
|
+
for (const [key, entry] of windows) {
|
|
18320
|
+
if (entry.expiresAt < now) windows.delete(key);
|
|
18321
|
+
}
|
|
18322
|
+
for (const [key, expiry] of blocks) {
|
|
18323
|
+
if (expiry < now) blocks.delete(key);
|
|
18324
|
+
}
|
|
18325
|
+
}, 60 * 1e3);
|
|
18326
|
+
if (cleanupInterval.unref) {
|
|
18327
|
+
cleanupInterval.unref();
|
|
18328
|
+
}
|
|
18329
|
+
return {
|
|
18330
|
+
async increment(key, windowMs, now) {
|
|
18331
|
+
const windowStart = now - windowMs;
|
|
18332
|
+
let entry = windows.get(key);
|
|
18333
|
+
if (!entry) {
|
|
18334
|
+
entry = { timestamps: [], expiresAt: now + windowMs + 6e4 };
|
|
18335
|
+
windows.set(key, entry);
|
|
18336
|
+
}
|
|
18337
|
+
entry.timestamps = entry.timestamps.filter((t) => t > windowStart);
|
|
18338
|
+
entry.timestamps.push(now);
|
|
18339
|
+
entry.expiresAt = now + windowMs + 6e4;
|
|
18340
|
+
return { count: entry.timestamps.length };
|
|
18341
|
+
},
|
|
18342
|
+
async isBlocked(key) {
|
|
18343
|
+
const expiry = blocks.get(key);
|
|
18344
|
+
if (!expiry || expiry < Date.now()) {
|
|
18345
|
+
blocks.delete(key);
|
|
18346
|
+
return { blocked: false, ttlMs: 0 };
|
|
18347
|
+
}
|
|
18348
|
+
return { blocked: true, ttlMs: expiry - Date.now() };
|
|
18349
|
+
},
|
|
18350
|
+
async setBlock(key, durationSeconds) {
|
|
18351
|
+
blocks.set(key, Date.now() + durationSeconds * 1e3);
|
|
18352
|
+
},
|
|
18353
|
+
async reset(key) {
|
|
18354
|
+
windows.delete(key);
|
|
18355
|
+
blocks.delete(`block:${key}`);
|
|
18356
|
+
blocks.delete(key);
|
|
18357
|
+
}
|
|
18358
|
+
};
|
|
18359
|
+
}
|
|
18360
|
+
var defaultStore;
|
|
18361
|
+
function getDefaultStore() {
|
|
18362
|
+
if (!defaultStore) {
|
|
18363
|
+
defaultStore = createMemoryRateLimitStore();
|
|
18364
|
+
}
|
|
18365
|
+
return defaultStore;
|
|
18366
|
+
}
|
|
18367
|
+
async function checkRateLimit(operation, identifier, rule, options = {}) {
|
|
18368
|
+
const store = options.store ?? getDefaultStore();
|
|
18369
|
+
const limit = options.isAuthenticated && rule.authenticatedLimit ? rule.authenticatedLimit : rule.limit;
|
|
18370
|
+
const now = Date.now();
|
|
18371
|
+
const windowMs = rule.windowSeconds * 1e3;
|
|
18372
|
+
const resetAt = now + windowMs;
|
|
18373
|
+
const key = `ratelimit:${operation}:${identifier}`;
|
|
18374
|
+
const blockKey = `ratelimit:block:${operation}:${identifier}`;
|
|
18375
|
+
try {
|
|
18376
|
+
if (rule.blockDurationSeconds) {
|
|
18377
|
+
const blockStatus = await store.isBlocked(blockKey);
|
|
18378
|
+
if (blockStatus.blocked) {
|
|
18379
|
+
return {
|
|
18380
|
+
allowed: false,
|
|
18381
|
+
remaining: 0,
|
|
18382
|
+
resetAt: now + blockStatus.ttlMs,
|
|
18383
|
+
current: limit + 1,
|
|
18384
|
+
limit,
|
|
18385
|
+
retryAfterSeconds: Math.ceil(blockStatus.ttlMs / 1e3)
|
|
18386
|
+
};
|
|
18387
|
+
}
|
|
18388
|
+
}
|
|
18389
|
+
const { count } = await store.increment(key, windowMs, now);
|
|
18390
|
+
if (count > limit) {
|
|
18391
|
+
options.logger?.warn("Rate limit exceeded", {
|
|
18392
|
+
operation,
|
|
18393
|
+
identifier,
|
|
18394
|
+
current: count,
|
|
18395
|
+
limit
|
|
18396
|
+
});
|
|
18397
|
+
if (rule.blockDurationSeconds) {
|
|
18398
|
+
await store.setBlock(blockKey, rule.blockDurationSeconds);
|
|
18399
|
+
}
|
|
18400
|
+
return {
|
|
18401
|
+
allowed: false,
|
|
18402
|
+
remaining: 0,
|
|
18403
|
+
resetAt,
|
|
18404
|
+
current: count,
|
|
18405
|
+
limit,
|
|
18406
|
+
retryAfterSeconds: Math.ceil(windowMs / 1e3)
|
|
18407
|
+
};
|
|
18408
|
+
}
|
|
18409
|
+
return {
|
|
18410
|
+
allowed: true,
|
|
18411
|
+
remaining: limit - count,
|
|
18412
|
+
resetAt,
|
|
18413
|
+
current: count,
|
|
18414
|
+
limit,
|
|
18415
|
+
retryAfterSeconds: 0
|
|
18416
|
+
};
|
|
18417
|
+
} catch (error) {
|
|
18418
|
+
options.logger?.error("Rate limit check failed, allowing request", {
|
|
18419
|
+
error: error instanceof Error ? error.message : String(error),
|
|
18420
|
+
operation,
|
|
18421
|
+
identifier
|
|
18422
|
+
});
|
|
18423
|
+
return {
|
|
18424
|
+
allowed: true,
|
|
18425
|
+
remaining: limit,
|
|
18426
|
+
resetAt,
|
|
18427
|
+
current: 0,
|
|
18428
|
+
limit,
|
|
18429
|
+
retryAfterSeconds: 0
|
|
18430
|
+
};
|
|
18431
|
+
}
|
|
18432
|
+
}
|
|
18433
|
+
async function getRateLimitStatus(operation, identifier, rule, store) {
|
|
18434
|
+
const s = store ?? getDefaultStore();
|
|
18435
|
+
const key = `ratelimit:${operation}:${identifier}`;
|
|
18436
|
+
const now = Date.now();
|
|
18437
|
+
const windowMs = rule.windowSeconds * 1e3;
|
|
18438
|
+
try {
|
|
18439
|
+
const { count } = await s.increment(key, windowMs, now);
|
|
18440
|
+
return {
|
|
18441
|
+
allowed: count <= rule.limit,
|
|
18442
|
+
remaining: Math.max(0, rule.limit - count),
|
|
18443
|
+
resetAt: now + windowMs,
|
|
18444
|
+
current: count,
|
|
18445
|
+
limit: rule.limit,
|
|
18446
|
+
retryAfterSeconds: count > rule.limit ? Math.ceil(windowMs / 1e3) : 0
|
|
18447
|
+
};
|
|
18448
|
+
} catch {
|
|
18449
|
+
return null;
|
|
18450
|
+
}
|
|
18451
|
+
}
|
|
18452
|
+
async function resetRateLimitForKey(operation, identifier, store) {
|
|
18453
|
+
const s = store ?? getDefaultStore();
|
|
18454
|
+
const key = `ratelimit:${operation}:${identifier}`;
|
|
18455
|
+
const blockKey = `ratelimit:block:${operation}:${identifier}`;
|
|
18456
|
+
await s.reset(key);
|
|
18457
|
+
await s.reset(blockKey);
|
|
18458
|
+
}
|
|
18459
|
+
function buildRateLimitResponseHeaders(result) {
|
|
18460
|
+
const headers = {
|
|
18461
|
+
"X-RateLimit-Limit": String(result.limit),
|
|
18462
|
+
"X-RateLimit-Remaining": String(result.remaining),
|
|
18463
|
+
"X-RateLimit-Reset": String(Math.ceil(result.resetAt / 1e3))
|
|
18464
|
+
};
|
|
18465
|
+
if (!result.allowed) {
|
|
18466
|
+
headers["Retry-After"] = String(result.retryAfterSeconds);
|
|
18467
|
+
}
|
|
18468
|
+
return headers;
|
|
18469
|
+
}
|
|
18470
|
+
function resolveIdentifier(session, clientIp) {
|
|
18471
|
+
if (session?.user?.id) {
|
|
18472
|
+
return { identifier: `user:${session.user.id}`, isAuthenticated: true };
|
|
18473
|
+
}
|
|
18474
|
+
if (session?.user?.email) {
|
|
18475
|
+
return {
|
|
18476
|
+
identifier: `email:${session.user.email}`,
|
|
18477
|
+
isAuthenticated: true
|
|
18478
|
+
};
|
|
18479
|
+
}
|
|
18480
|
+
return { identifier: `ip:${clientIp ?? "unknown"}`, isAuthenticated: false };
|
|
18481
|
+
}
|
|
18482
|
+
|
|
18483
|
+
// src/auth/audit.ts
|
|
18484
|
+
var StandardAuditActions = {
|
|
18485
|
+
// Authentication
|
|
18486
|
+
LOGIN_SUCCESS: "auth.login.success",
|
|
18487
|
+
LOGIN_FAILURE: "auth.login.failure",
|
|
18488
|
+
LOGOUT: "auth.logout",
|
|
18489
|
+
SESSION_REFRESH: "auth.session.refresh",
|
|
18490
|
+
PASSWORD_CHANGE: "auth.password.change",
|
|
18491
|
+
PASSWORD_RESET: "auth.password.reset",
|
|
18492
|
+
// Billing
|
|
18493
|
+
CHECKOUT_START: "billing.checkout.start",
|
|
18494
|
+
CHECKOUT_COMPLETE: "billing.checkout.complete",
|
|
18495
|
+
SUBSCRIPTION_CREATE: "billing.subscription.create",
|
|
18496
|
+
SUBSCRIPTION_CANCEL: "billing.subscription.cancel",
|
|
18497
|
+
SUBSCRIPTION_UPDATE: "billing.subscription.update",
|
|
18498
|
+
PAYMENT_FAILED: "billing.payment.failed",
|
|
18499
|
+
// Admin
|
|
18500
|
+
ADMIN_LOGIN: "admin.login",
|
|
18501
|
+
ADMIN_USER_VIEW: "admin.user.view",
|
|
18502
|
+
ADMIN_USER_UPDATE: "admin.user.update",
|
|
18503
|
+
ADMIN_CONFIG_CHANGE: "admin.config.change",
|
|
18504
|
+
// Security Events
|
|
18505
|
+
RATE_LIMIT_EXCEEDED: "security.rate_limit.exceeded",
|
|
18506
|
+
INVALID_INPUT: "security.input.invalid",
|
|
18507
|
+
UNAUTHORIZED_ACCESS: "security.access.unauthorized",
|
|
18508
|
+
OWNERSHIP_VIOLATION: "security.ownership.violation",
|
|
18509
|
+
WEBHOOK_SIGNATURE_INVALID: "security.webhook.signature_invalid",
|
|
18510
|
+
// Data
|
|
18511
|
+
DATA_EXPORT: "data.export",
|
|
18512
|
+
DATA_DELETE: "data.delete",
|
|
18513
|
+
DATA_UPDATE: "data.update"
|
|
18514
|
+
};
|
|
18515
|
+
function extractAuditIp(request) {
|
|
18516
|
+
if (!request) return void 0;
|
|
18517
|
+
const headers = [
|
|
18518
|
+
"cf-connecting-ip",
|
|
18519
|
+
// Cloudflare
|
|
18520
|
+
"x-real-ip",
|
|
18521
|
+
// Nginx
|
|
18522
|
+
"x-forwarded-for",
|
|
18523
|
+
// Standard proxy
|
|
18524
|
+
"x-client-ip"
|
|
18525
|
+
// Apache
|
|
18526
|
+
];
|
|
18527
|
+
for (const header of headers) {
|
|
18528
|
+
const value = request.headers.get(header);
|
|
18529
|
+
if (value) {
|
|
18530
|
+
return value.split(",")[0]?.trim();
|
|
18531
|
+
}
|
|
18532
|
+
}
|
|
18533
|
+
return void 0;
|
|
18534
|
+
}
|
|
18535
|
+
function extractAuditUserAgent(request) {
|
|
18536
|
+
return request?.headers.get("user-agent") ?? void 0;
|
|
18537
|
+
}
|
|
18538
|
+
function extractAuditRequestId(request) {
|
|
18539
|
+
return request?.headers.get("x-request-id") ?? crypto.randomUUID();
|
|
18540
|
+
}
|
|
18541
|
+
function createAuditActor(session) {
|
|
18542
|
+
if (!session?.user) {
|
|
18543
|
+
return { id: "anonymous", type: "anonymous" };
|
|
18544
|
+
}
|
|
18545
|
+
return {
|
|
18546
|
+
id: session.user.id ?? session.user.email ?? "unknown",
|
|
18547
|
+
email: session.user.email ?? void 0,
|
|
18548
|
+
type: "user"
|
|
18549
|
+
};
|
|
18550
|
+
}
|
|
18551
|
+
var defaultLogger = {
|
|
18552
|
+
info: (msg, meta) => console.log(msg, meta ? JSON.stringify(meta) : ""),
|
|
18553
|
+
warn: (msg, meta) => console.warn(msg, meta ? JSON.stringify(meta) : ""),
|
|
18554
|
+
error: (msg, meta) => console.error(msg, meta ? JSON.stringify(meta) : "")
|
|
18555
|
+
};
|
|
18556
|
+
function createAuditLogger(options = {}) {
|
|
18557
|
+
const { persist, logger = defaultLogger } = options;
|
|
18558
|
+
async function log(event, request) {
|
|
18559
|
+
const record = {
|
|
18560
|
+
id: crypto.randomUUID(),
|
|
18561
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
18562
|
+
ip: extractAuditIp(request),
|
|
18563
|
+
userAgent: extractAuditUserAgent(request),
|
|
18564
|
+
requestId: extractAuditRequestId(request),
|
|
18565
|
+
...event
|
|
18566
|
+
};
|
|
18567
|
+
const logFn = event.outcome === "failure" || event.outcome === "blocked" ? logger.warn : logger.info;
|
|
18568
|
+
logFn(`[AUDIT] ${event.action}`, {
|
|
18569
|
+
auditId: record.id,
|
|
18570
|
+
actor: record.actor,
|
|
18571
|
+
action: record.action,
|
|
18572
|
+
resource: record.resource,
|
|
18573
|
+
outcome: record.outcome,
|
|
18574
|
+
ip: record.ip,
|
|
18575
|
+
metadata: record.metadata,
|
|
18576
|
+
reason: record.reason
|
|
18577
|
+
});
|
|
18578
|
+
if (persist) {
|
|
18579
|
+
try {
|
|
18580
|
+
await persist(record);
|
|
18581
|
+
} catch (error) {
|
|
18582
|
+
logger.error("Failed to persist audit log", {
|
|
18583
|
+
error: error instanceof Error ? error.message : String(error),
|
|
18584
|
+
auditId: record.id
|
|
18585
|
+
});
|
|
18586
|
+
}
|
|
18587
|
+
}
|
|
18588
|
+
return record;
|
|
18589
|
+
}
|
|
18590
|
+
function createTimedAudit(event, request) {
|
|
18591
|
+
const startTime = Date.now();
|
|
18592
|
+
return {
|
|
18593
|
+
success: async (metadata) => {
|
|
18594
|
+
return log(
|
|
18595
|
+
{
|
|
18596
|
+
...event,
|
|
18597
|
+
outcome: "success",
|
|
18598
|
+
metadata: {
|
|
18599
|
+
...event.metadata,
|
|
18600
|
+
...metadata,
|
|
18601
|
+
durationMs: Date.now() - startTime
|
|
18602
|
+
}
|
|
18603
|
+
},
|
|
18604
|
+
request
|
|
18605
|
+
);
|
|
18606
|
+
},
|
|
18607
|
+
failure: async (reason, metadata) => {
|
|
18608
|
+
return log(
|
|
18609
|
+
{
|
|
18610
|
+
...event,
|
|
18611
|
+
outcome: "failure",
|
|
18612
|
+
reason,
|
|
18613
|
+
metadata: {
|
|
18614
|
+
...event.metadata,
|
|
18615
|
+
...metadata,
|
|
18616
|
+
durationMs: Date.now() - startTime
|
|
18617
|
+
}
|
|
18618
|
+
},
|
|
18619
|
+
request
|
|
18620
|
+
);
|
|
18621
|
+
},
|
|
18622
|
+
blocked: async (reason, metadata) => {
|
|
18623
|
+
return log(
|
|
18624
|
+
{
|
|
18625
|
+
...event,
|
|
18626
|
+
outcome: "blocked",
|
|
18627
|
+
reason,
|
|
18628
|
+
metadata: {
|
|
18629
|
+
...event.metadata,
|
|
18630
|
+
...metadata,
|
|
18631
|
+
durationMs: Date.now() - startTime
|
|
18632
|
+
}
|
|
18633
|
+
},
|
|
18634
|
+
request
|
|
18635
|
+
);
|
|
18636
|
+
}
|
|
18637
|
+
};
|
|
18638
|
+
}
|
|
18639
|
+
return { log, createTimedAudit };
|
|
18640
|
+
}
|
|
18641
|
+
|
|
17226
18642
|
// src/http/health.ts
|
|
17227
18643
|
function createHealthEndpoints(platform, options = {}) {
|
|
17228
18644
|
const {
|
|
@@ -18301,7 +19717,7 @@ var MemoryAuditLog = class {
|
|
|
18301
19717
|
};
|
|
18302
19718
|
|
|
18303
19719
|
// src/adapters/memory/MemoryWebhook.ts
|
|
18304
|
-
import { createHmac } from "crypto";
|
|
19720
|
+
import { createHmac as createHmac3, randomBytes as randomBytes26 } from "crypto";
|
|
18305
19721
|
var MemoryWebhook = class {
|
|
18306
19722
|
endpoints = /* @__PURE__ */ new Map();
|
|
18307
19723
|
deliveries = /* @__PURE__ */ new Map();
|
|
@@ -18583,7 +19999,7 @@ var MemoryWebhook = class {
|
|
|
18583
19999
|
config.secret,
|
|
18584
20000
|
algorithm
|
|
18585
20001
|
);
|
|
18586
|
-
const providedSig = signature.replace(/^(sha256=|sha512
|
|
20002
|
+
const providedSig = signature.replace(/^(sha256=|sha512=)/, "");
|
|
18587
20003
|
if (providedSig !== expectedSignature) {
|
|
18588
20004
|
return { valid: false, error: "Invalid signature" };
|
|
18589
20005
|
}
|
|
@@ -18688,7 +20104,7 @@ var MemoryWebhook = class {
|
|
|
18688
20104
|
this.deliveries.set(delivery.id, delivery);
|
|
18689
20105
|
}
|
|
18690
20106
|
async executeDelivery(endpoint, event, attemptNumber) {
|
|
18691
|
-
const attemptId = `att_${Date.now().toString(36)}${
|
|
20107
|
+
const attemptId = `att_${Date.now().toString(36)}${randomBytes26(4).toString("hex")}`;
|
|
18692
20108
|
const startTime = Date.now();
|
|
18693
20109
|
if (this.config.simulatedDelay > 0) {
|
|
18694
20110
|
await new Promise(
|
|
@@ -18742,7 +20158,7 @@ var MemoryWebhook = class {
|
|
|
18742
20158
|
this.endpoints.set(endpoint.id, endpoint);
|
|
18743
20159
|
}
|
|
18744
20160
|
computeSignature(payload, secret, algorithm) {
|
|
18745
|
-
return
|
|
20161
|
+
return createHmac3(algorithm, secret).update(payload).digest("hex");
|
|
18746
20162
|
}
|
|
18747
20163
|
};
|
|
18748
20164
|
|
|
@@ -19093,6 +20509,7 @@ var MemoryNotification = class {
|
|
|
19093
20509
|
};
|
|
19094
20510
|
|
|
19095
20511
|
// src/adapters/memory/MemoryScheduler.ts
|
|
20512
|
+
import { randomBytes as randomBytes27 } from "crypto";
|
|
19096
20513
|
var MemoryScheduler = class {
|
|
19097
20514
|
config;
|
|
19098
20515
|
schedules = /* @__PURE__ */ new Map();
|
|
@@ -19376,7 +20793,7 @@ var MemoryScheduler = class {
|
|
|
19376
20793
|
}
|
|
19377
20794
|
}
|
|
19378
20795
|
async executeSchedule(schedule) {
|
|
19379
|
-
const executionId = `exec_${Date.now().toString(36)}${
|
|
20796
|
+
const executionId = `exec_${Date.now().toString(36)}${randomBytes27(4).toString("hex")}`;
|
|
19380
20797
|
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
19381
20798
|
const execution = {
|
|
19382
20799
|
id: executionId,
|
|
@@ -19856,6 +21273,7 @@ CREATE INDEX IF NOT EXISTS idx_${tableName}_trace_id ON ${tableName}((context->>
|
|
|
19856
21273
|
};
|
|
19857
21274
|
|
|
19858
21275
|
// src/adapters/database/DatabaseErrorReporter.ts
|
|
21276
|
+
import { randomBytes as randomBytes28 } from "crypto";
|
|
19859
21277
|
var DatabaseErrorReporter = class {
|
|
19860
21278
|
db;
|
|
19861
21279
|
errorsTable;
|
|
@@ -20150,7 +21568,7 @@ CREATE INDEX IF NOT EXISTS idx_${breadcrumbsTable}_error ON ${breadcrumbsTable}(
|
|
|
20150
21568
|
if (report.breadcrumbs && report.breadcrumbs.length > 0) {
|
|
20151
21569
|
for (const crumb of report.breadcrumbs) {
|
|
20152
21570
|
await this.db.from(this.breadcrumbsTable).insert({
|
|
20153
|
-
id: `bc_${Date.now().toString(36)}${
|
|
21571
|
+
id: `bc_${Date.now().toString(36)}${randomBytes28(4).toString("hex")}`,
|
|
20154
21572
|
error_id: report.id,
|
|
20155
21573
|
category: crumb.category,
|
|
20156
21574
|
message: crumb.message,
|
|
@@ -20190,6 +21608,7 @@ CREATE INDEX IF NOT EXISTS idx_${breadcrumbsTable}_error ON ${breadcrumbsTable}(
|
|
|
20190
21608
|
};
|
|
20191
21609
|
|
|
20192
21610
|
// src/adapters/database/DatabasePromptStore.ts
|
|
21611
|
+
import { randomBytes as randomBytes29 } from "crypto";
|
|
20193
21612
|
var DatabasePromptStore = class {
|
|
20194
21613
|
db;
|
|
20195
21614
|
cache;
|
|
@@ -20329,7 +21748,7 @@ CREATE INDEX IF NOT EXISTS idx_${tablePrefix}usage_experiment ON ${tablePrefix}p
|
|
|
20329
21748
|
// Prompt CRUD
|
|
20330
21749
|
// ═══════════════════════════════════════════════════════════════
|
|
20331
21750
|
async create(prompt) {
|
|
20332
|
-
const id = `prompt_${Date.now()}_${
|
|
21751
|
+
const id = `prompt_${Date.now()}_${randomBytes29(4).toString("hex")}`;
|
|
20333
21752
|
const now = /* @__PURE__ */ new Date();
|
|
20334
21753
|
const newPrompt = {
|
|
20335
21754
|
...prompt,
|
|
@@ -20357,7 +21776,7 @@ CREATE INDEX IF NOT EXISTS idx_${tablePrefix}usage_experiment ON ${tablePrefix}p
|
|
|
20357
21776
|
created_by: newPrompt.createdBy,
|
|
20358
21777
|
updated_by: newPrompt.updatedBy
|
|
20359
21778
|
}).execute();
|
|
20360
|
-
const versionId = `pv_${Date.now()}_${
|
|
21779
|
+
const versionId = `pv_${Date.now()}_${randomBytes29(4).toString("hex")}`;
|
|
20361
21780
|
await this.db.from(this.versionsTable).insert({
|
|
20362
21781
|
id: versionId,
|
|
20363
21782
|
prompt_id: id,
|
|
@@ -20426,7 +21845,7 @@ CREATE INDEX IF NOT EXISTS idx_${tablePrefix}usage_experiment ON ${tablePrefix}p
|
|
|
20426
21845
|
await this.db.from(this.versionsTable).update({ is_latest: false }).where("prompt_id", "=", prompt.id).execute();
|
|
20427
21846
|
const versionsResult = await this.db.from(this.versionsTable).where("prompt_id", "=", prompt.id).execute();
|
|
20428
21847
|
const newVersionNum = versionsResult.data.length + 1;
|
|
20429
|
-
const versionId = `pv_${Date.now()}_${
|
|
21848
|
+
const versionId = `pv_${Date.now()}_${randomBytes29(4).toString("hex")}`;
|
|
20430
21849
|
await this.db.from(this.versionsTable).insert({
|
|
20431
21850
|
id: versionId,
|
|
20432
21851
|
prompt_id: prompt.id,
|
|
@@ -20681,7 +22100,7 @@ ${v2.content}`;
|
|
|
20681
22100
|
// A/B Testing
|
|
20682
22101
|
// ═══════════════════════════════════════════════════════════════
|
|
20683
22102
|
async createExperiment(experiment) {
|
|
20684
|
-
const id = `exp_${Date.now()}_${
|
|
22103
|
+
const id = `exp_${Date.now()}_${randomBytes29(4).toString("hex")}`;
|
|
20685
22104
|
const now = /* @__PURE__ */ new Date();
|
|
20686
22105
|
const newExperiment = {
|
|
20687
22106
|
...experiment,
|
|
@@ -20795,7 +22214,7 @@ ${v2.content}`;
|
|
|
20795
22214
|
// Prompt Chains
|
|
20796
22215
|
// ═══════════════════════════════════════════════════════════════
|
|
20797
22216
|
async createChain(chain) {
|
|
20798
|
-
const id = `chain_${Date.now()}_${
|
|
22217
|
+
const id = `chain_${Date.now()}_${randomBytes29(4).toString("hex")}`;
|
|
20799
22218
|
const now = /* @__PURE__ */ new Date();
|
|
20800
22219
|
const newChain = {
|
|
20801
22220
|
...chain,
|
|
@@ -20893,7 +22312,7 @@ ${v2.content}`;
|
|
|
20893
22312
|
// Usage & Analytics
|
|
20894
22313
|
// ═══════════════════════════════════════════════════════════════
|
|
20895
22314
|
async recordUsage(record) {
|
|
20896
|
-
const id = `usage_${Date.now()}_${
|
|
22315
|
+
const id = `usage_${Date.now()}_${randomBytes29(4).toString("hex")}`;
|
|
20897
22316
|
const now = /* @__PURE__ */ new Date();
|
|
20898
22317
|
const usageRecord = {
|
|
20899
22318
|
...record,
|
|
@@ -21079,8 +22498,9 @@ ${v2.content}`;
|
|
|
21079
22498
|
};
|
|
21080
22499
|
|
|
21081
22500
|
// src/adapters/database/DatabaseCompliance.ts
|
|
22501
|
+
import { randomBytes as randomBytes30 } from "crypto";
|
|
21082
22502
|
function generateId(prefix) {
|
|
21083
|
-
return `${prefix}_${Date.now()}_${
|
|
22503
|
+
return `${prefix}_${Date.now()}_${randomBytes30(4).toString("hex")}`;
|
|
21084
22504
|
}
|
|
21085
22505
|
function toDate(value) {
|
|
21086
22506
|
return value ? new Date(value) : void 0;
|
|
@@ -21271,7 +22691,7 @@ var DatabaseCompliance = class {
|
|
|
21271
22691
|
async createDsar(options) {
|
|
21272
22692
|
const id = generateId("dsar");
|
|
21273
22693
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
21274
|
-
const verificationToken = `verify_${
|
|
22694
|
+
const verificationToken = `verify_${randomBytes30(16).toString("hex")}`;
|
|
21275
22695
|
const result = await this.db.from("compliance_dsars").insert({
|
|
21276
22696
|
id,
|
|
21277
22697
|
type: options.type,
|
|
@@ -22210,6 +23630,7 @@ var DatabaseCompliance = class {
|
|
|
22210
23630
|
};
|
|
22211
23631
|
|
|
22212
23632
|
// src/adapters/database/DatabaseAIUsage.ts
|
|
23633
|
+
import { randomBytes as randomBytes31 } from "crypto";
|
|
22213
23634
|
var DatabaseAIUsage = class {
|
|
22214
23635
|
db;
|
|
22215
23636
|
config;
|
|
@@ -22223,7 +23644,7 @@ var DatabaseAIUsage = class {
|
|
|
22223
23644
|
// Usage Recording
|
|
22224
23645
|
// ─────────────────────────────────────────────────────────────
|
|
22225
23646
|
async record(record) {
|
|
22226
|
-
const id = `usage_${Date.now()}_${
|
|
23647
|
+
const id = `usage_${Date.now()}_${randomBytes31(4).toString("hex")}`;
|
|
22227
23648
|
const now = /* @__PURE__ */ new Date();
|
|
22228
23649
|
await this.db.from(`${this.prefix}records`).insert({
|
|
22229
23650
|
id,
|
|
@@ -22330,7 +23751,7 @@ var DatabaseAIUsage = class {
|
|
|
22330
23751
|
quota.category
|
|
22331
23752
|
);
|
|
22332
23753
|
const period = this.getPeriodBounds(quota.period, /* @__PURE__ */ new Date());
|
|
22333
|
-
const id = existing?.id || `quota_${Date.now()}_${
|
|
23754
|
+
const id = existing?.id || `quota_${Date.now()}_${randomBytes31(4).toString("hex")}`;
|
|
22334
23755
|
const data = {
|
|
22335
23756
|
id,
|
|
22336
23757
|
tenant_id: quota.tenantId,
|
|
@@ -22467,7 +23888,7 @@ var DatabaseAIUsage = class {
|
|
|
22467
23888
|
existingResult.data[0]
|
|
22468
23889
|
) : null;
|
|
22469
23890
|
const period = this.getPeriodBounds(budget.period, /* @__PURE__ */ new Date());
|
|
22470
|
-
const id = existing?.id || `budget_${Date.now()}_${
|
|
23891
|
+
const id = existing?.id || `budget_${Date.now()}_${randomBytes31(4).toString("hex")}`;
|
|
22471
23892
|
const data = {
|
|
22472
23893
|
id,
|
|
22473
23894
|
tenant_id: budget.tenantId,
|
|
@@ -22766,7 +24187,7 @@ var DatabaseAIUsage = class {
|
|
|
22766
24187
|
}
|
|
22767
24188
|
const items = Array.from(itemsMap.values());
|
|
22768
24189
|
const subtotal = items.reduce((sum, item) => sum + item.costUsd, 0);
|
|
22769
|
-
const id = `inv_${Date.now()}_${
|
|
24190
|
+
const id = `inv_${Date.now()}_${randomBytes31(4).toString("hex")}`;
|
|
22770
24191
|
const now = /* @__PURE__ */ new Date();
|
|
22771
24192
|
await this.db.from(`${this.prefix}invoices`).insert({
|
|
22772
24193
|
id,
|
|
@@ -22988,7 +24409,7 @@ var DatabaseAIUsage = class {
|
|
|
22988
24409
|
}
|
|
22989
24410
|
}
|
|
22990
24411
|
async createAlert(tenantId, type, severity, message, metadata) {
|
|
22991
|
-
const id = `alert_${Date.now()}_${
|
|
24412
|
+
const id = `alert_${Date.now()}_${randomBytes31(4).toString("hex")}`;
|
|
22992
24413
|
await this.db.from(`${this.prefix}alerts`).insert({
|
|
22993
24414
|
id,
|
|
22994
24415
|
tenant_id: tenantId,
|
|
@@ -23194,6 +24615,7 @@ var DatabaseAIUsage = class {
|
|
|
23194
24615
|
};
|
|
23195
24616
|
|
|
23196
24617
|
// src/adapters/database/DatabaseNotification.ts
|
|
24618
|
+
import { randomBytes as randomBytes32 } from "crypto";
|
|
23197
24619
|
var DatabaseNotification = class {
|
|
23198
24620
|
db;
|
|
23199
24621
|
email;
|
|
@@ -23431,7 +24853,7 @@ var DatabaseNotification = class {
|
|
|
23431
24853
|
// PUSH SUBSCRIPTIONS
|
|
23432
24854
|
// ═══════════════════════════════════════════════════════════════
|
|
23433
24855
|
async registerPushSubscription(userId, subscription) {
|
|
23434
|
-
const id = `push_${Date.now()}_${
|
|
24856
|
+
const id = `push_${Date.now()}_${randomBytes32(4).toString("hex")}`;
|
|
23435
24857
|
const existing = await this.db.from(`${this.prefix}push_subscriptions`).where("user_id", "=", userId).where("endpoint", "=", subscription.endpoint).execute();
|
|
23436
24858
|
if (existing.data && existing.data.length > 0) {
|
|
23437
24859
|
await this.db.from(`${this.prefix}push_subscriptions`).where("user_id", "=", userId).where("endpoint", "=", subscription.endpoint).update({
|
|
@@ -23529,7 +24951,7 @@ var DatabaseNotification = class {
|
|
|
23529
24951
|
// TOPICS
|
|
23530
24952
|
// ═══════════════════════════════════════════════════════════════
|
|
23531
24953
|
async subscribeToTopic(userId, topic) {
|
|
23532
|
-
const id = `topic_${Date.now()}_${
|
|
24954
|
+
const id = `topic_${Date.now()}_${randomBytes32(4).toString("hex")}`;
|
|
23533
24955
|
const existing = await this.db.from(`${this.prefix}notification_topic_subs`).where("user_id", "=", userId).where("topic", "=", topic).execute();
|
|
23534
24956
|
if (!existing.data || existing.data.length === 0) {
|
|
23535
24957
|
await this.db.from(`${this.prefix}notification_topic_subs`).insert({
|
|
@@ -23610,7 +25032,7 @@ var DatabaseNotification = class {
|
|
|
23610
25032
|
// PRIVATE HELPERS
|
|
23611
25033
|
// ═══════════════════════════════════════════════════════════════
|
|
23612
25034
|
async logDelivery(notificationId, channel, status, messageId, error) {
|
|
23613
|
-
const id = `del_${Date.now()}_${
|
|
25035
|
+
const id = `del_${Date.now()}_${randomBytes32(4).toString("hex")}`;
|
|
23614
25036
|
try {
|
|
23615
25037
|
await this.db.from(`${this.prefix}notification_delivery_log`).insert({
|
|
23616
25038
|
id,
|
|
@@ -23672,6 +25094,7 @@ var DatabaseNotification = class {
|
|
|
23672
25094
|
};
|
|
23673
25095
|
|
|
23674
25096
|
// src/adapters/database/DatabaseBilling.ts
|
|
25097
|
+
import { randomBytes as randomBytes33 } from "crypto";
|
|
23675
25098
|
var DatabaseBilling = class {
|
|
23676
25099
|
db;
|
|
23677
25100
|
prefix;
|
|
@@ -23694,7 +25117,7 @@ var DatabaseBilling = class {
|
|
|
23694
25117
|
return `${this.prefix}${name}`;
|
|
23695
25118
|
}
|
|
23696
25119
|
generateId(prefix) {
|
|
23697
|
-
return `${prefix}_${Date.now()}_${
|
|
25120
|
+
return `${prefix}_${Date.now()}_${randomBytes33(4).toString("hex")}`;
|
|
23698
25121
|
}
|
|
23699
25122
|
// ─────────────────────────────────────────────────────────────
|
|
23700
25123
|
// Product & Price Management
|
|
@@ -25192,6 +26615,7 @@ var DatabaseBilling = class {
|
|
|
25192
26615
|
};
|
|
25193
26616
|
|
|
25194
26617
|
// src/adapters/scheduler/QueueScheduler.ts
|
|
26618
|
+
import { randomBytes as randomBytes34 } from "crypto";
|
|
25195
26619
|
var QueueScheduler = class {
|
|
25196
26620
|
queue;
|
|
25197
26621
|
db;
|
|
@@ -25607,7 +27031,7 @@ CREATE INDEX IF NOT EXISTS idx_${executionsTable}_started ON ${executionsTable}(
|
|
|
25607
27031
|
}
|
|
25608
27032
|
}
|
|
25609
27033
|
async executeSchedule(schedule) {
|
|
25610
|
-
const executionId = `exec_${Date.now().toString(36)}${
|
|
27034
|
+
const executionId = `exec_${Date.now().toString(36)}${randomBytes34(4).toString("hex")}`;
|
|
25611
27035
|
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
25612
27036
|
const execution = {
|
|
25613
27037
|
id: executionId,
|
|
@@ -25770,7 +27194,7 @@ CREATE INDEX IF NOT EXISTS idx_${executionsTable}_started ON ${executionsTable}(
|
|
|
25770
27194
|
};
|
|
25771
27195
|
|
|
25772
27196
|
// src/adapters/webhook/HttpWebhook.ts
|
|
25773
|
-
import { createHmac as
|
|
27197
|
+
import { createHmac as createHmac4, timingSafeEqual as timingSafeEqual2, randomBytes as randomBytes35 } from "crypto";
|
|
25774
27198
|
var HttpWebhook = class {
|
|
25775
27199
|
db;
|
|
25776
27200
|
queue;
|
|
@@ -26112,14 +27536,14 @@ var HttpWebhook = class {
|
|
|
26112
27536
|
config.secret,
|
|
26113
27537
|
algorithm
|
|
26114
27538
|
);
|
|
26115
|
-
const providedSig = signature.replace(/^(sha256=|sha512
|
|
27539
|
+
const providedSig = signature.replace(/^(sha256=|sha512=)/, "");
|
|
26116
27540
|
try {
|
|
26117
27541
|
const providedBuffer = Buffer.from(providedSig, "hex");
|
|
26118
27542
|
const expectedBuffer = Buffer.from(expectedSignature, "hex");
|
|
26119
27543
|
if (providedBuffer.length !== expectedBuffer.length) {
|
|
26120
27544
|
return { valid: false, error: "Invalid signature" };
|
|
26121
27545
|
}
|
|
26122
|
-
if (!
|
|
27546
|
+
if (!timingSafeEqual2(providedBuffer, expectedBuffer)) {
|
|
26123
27547
|
return { valid: false, error: "Invalid signature" };
|
|
26124
27548
|
}
|
|
26125
27549
|
} catch {
|
|
@@ -26368,7 +27792,7 @@ CREATE INDEX IF NOT EXISTS idx_${attemptsTable}_delivery ON ${attemptsTable}(del
|
|
|
26368
27792
|
await this.saveDelivery(delivery);
|
|
26369
27793
|
}
|
|
26370
27794
|
async executeDelivery(endpoint, event, attemptNumber) {
|
|
26371
|
-
const attemptId = `att_${Date.now().toString(36)}${
|
|
27795
|
+
const attemptId = `att_${Date.now().toString(36)}${randomBytes35(4).toString("hex")}`;
|
|
26372
27796
|
const startTime = Date.now();
|
|
26373
27797
|
const payloadStr = JSON.stringify(event);
|
|
26374
27798
|
const signature = this.computeSignature(
|
|
@@ -26472,7 +27896,7 @@ CREATE INDEX IF NOT EXISTS idx_${attemptsTable}_delivery ON ${attemptsTable}(del
|
|
|
26472
27896
|
await this.saveEndpoint(endpoint);
|
|
26473
27897
|
}
|
|
26474
27898
|
computeSignature(payload, secret, algorithm) {
|
|
26475
|
-
return
|
|
27899
|
+
return createHmac4(algorithm, secret).update(payload).digest("hex");
|
|
26476
27900
|
}
|
|
26477
27901
|
endpointToRow(endpoint) {
|
|
26478
27902
|
return {
|
|
@@ -27794,6 +29218,9 @@ init_PineconeRAG();
|
|
|
27794
29218
|
// src/adapters/weaviate/index.ts
|
|
27795
29219
|
init_WeaviateRAG();
|
|
27796
29220
|
|
|
29221
|
+
// src/index.ts
|
|
29222
|
+
init_NodeCrypto();
|
|
29223
|
+
|
|
27797
29224
|
// src/adapters/oidc/GenericOIDCAuthSSO.ts
|
|
27798
29225
|
function generateRandomString(length) {
|
|
27799
29226
|
const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
|
@@ -28387,6 +29814,7 @@ var GenericOIDCAuthSSO = class {
|
|
|
28387
29814
|
};
|
|
28388
29815
|
|
|
28389
29816
|
// src/adapters/postgres-tenant/PostgresTenant.ts
|
|
29817
|
+
import { randomBytes as randomBytes36 } from "crypto";
|
|
28390
29818
|
var tenantContextMap = /* @__PURE__ */ new Map();
|
|
28391
29819
|
var contextIdCounter2 = 0;
|
|
28392
29820
|
var currentContextId2 = null;
|
|
@@ -29168,7 +30596,273 @@ var PostgresTenant = class {
|
|
|
29168
30596
|
}
|
|
29169
30597
|
};
|
|
29170
30598
|
function generateId2() {
|
|
29171
|
-
return
|
|
30599
|
+
return randomBytes36(8).toString("hex") + Date.now().toString(36);
|
|
30600
|
+
}
|
|
30601
|
+
|
|
30602
|
+
// src/env.ts
|
|
30603
|
+
function getRequiredEnv(key) {
|
|
30604
|
+
const value = process.env[key];
|
|
30605
|
+
if (!value) {
|
|
30606
|
+
throw new Error(`Missing required environment variable: ${key}`);
|
|
30607
|
+
}
|
|
30608
|
+
return value;
|
|
30609
|
+
}
|
|
30610
|
+
function getOptionalEnv(key, defaultValue) {
|
|
30611
|
+
return process.env[key] || defaultValue;
|
|
30612
|
+
}
|
|
30613
|
+
function getBoolEnv(key, defaultValue = false) {
|
|
30614
|
+
const value = process.env[key];
|
|
30615
|
+
if (value === void 0 || value === "") return defaultValue;
|
|
30616
|
+
return value === "true" || value === "1";
|
|
30617
|
+
}
|
|
30618
|
+
function getIntEnv(key, defaultValue) {
|
|
30619
|
+
const value = process.env[key];
|
|
30620
|
+
if (value === void 0 || value === "") return defaultValue;
|
|
30621
|
+
const parsed = parseInt(value, 10);
|
|
30622
|
+
return isNaN(parsed) ? defaultValue : parsed;
|
|
30623
|
+
}
|
|
30624
|
+
function validateEnvVars(config) {
|
|
30625
|
+
const result = checkEnvVars(config);
|
|
30626
|
+
if (!result.valid) {
|
|
30627
|
+
const lines = [];
|
|
30628
|
+
if (result.missing.length > 0) {
|
|
30629
|
+
lines.push(
|
|
30630
|
+
"Missing required environment variables:",
|
|
30631
|
+
...result.missing.map((v) => ` - ${v}`)
|
|
30632
|
+
);
|
|
30633
|
+
}
|
|
30634
|
+
if (result.missingOneOf.length > 0) {
|
|
30635
|
+
for (const group of result.missingOneOf) {
|
|
30636
|
+
lines.push(`Missing one of: ${group.join(" | ")}`);
|
|
30637
|
+
}
|
|
30638
|
+
}
|
|
30639
|
+
if (result.invalid.length > 0) {
|
|
30640
|
+
lines.push(
|
|
30641
|
+
"Invalid environment variables:",
|
|
30642
|
+
...result.invalid.map((v) => ` - ${v.key}: ${v.reason}`)
|
|
30643
|
+
);
|
|
30644
|
+
}
|
|
30645
|
+
throw new Error(lines.join("\n"));
|
|
30646
|
+
}
|
|
30647
|
+
}
|
|
30648
|
+
function checkEnvVars(config) {
|
|
30649
|
+
const missing = [];
|
|
30650
|
+
const invalid = [];
|
|
30651
|
+
const missingOneOf = [];
|
|
30652
|
+
if (config.required) {
|
|
30653
|
+
for (const key of config.required) {
|
|
30654
|
+
if (!process.env[key]) {
|
|
30655
|
+
missing.push(key);
|
|
30656
|
+
}
|
|
30657
|
+
}
|
|
30658
|
+
}
|
|
30659
|
+
if (config.requireOneOf) {
|
|
30660
|
+
for (const group of config.requireOneOf) {
|
|
30661
|
+
const hasAny = group.some((key) => !!process.env[key]);
|
|
30662
|
+
if (!hasAny) {
|
|
30663
|
+
missingOneOf.push(group);
|
|
30664
|
+
}
|
|
30665
|
+
}
|
|
30666
|
+
}
|
|
30667
|
+
if (config.validators) {
|
|
30668
|
+
for (const [key, validator] of Object.entries(config.validators)) {
|
|
30669
|
+
const value = process.env[key];
|
|
30670
|
+
if (value) {
|
|
30671
|
+
const result = validator(value);
|
|
30672
|
+
if (result !== true) {
|
|
30673
|
+
invalid.push({ key, reason: result });
|
|
30674
|
+
}
|
|
30675
|
+
}
|
|
30676
|
+
}
|
|
30677
|
+
}
|
|
30678
|
+
return {
|
|
30679
|
+
valid: missing.length === 0 && invalid.length === 0 && missingOneOf.length === 0,
|
|
30680
|
+
missing,
|
|
30681
|
+
invalid,
|
|
30682
|
+
missingOneOf
|
|
30683
|
+
};
|
|
30684
|
+
}
|
|
30685
|
+
function getEnvSummary(keys) {
|
|
30686
|
+
const summary = {};
|
|
30687
|
+
for (const key of keys) {
|
|
30688
|
+
summary[key] = !!process.env[key];
|
|
30689
|
+
}
|
|
30690
|
+
return summary;
|
|
30691
|
+
}
|
|
30692
|
+
|
|
30693
|
+
// src/app-logger.ts
|
|
30694
|
+
var LEVEL_PRIORITY2 = {
|
|
30695
|
+
debug: 0,
|
|
30696
|
+
info: 1,
|
|
30697
|
+
warn: 2,
|
|
30698
|
+
error: 3
|
|
30699
|
+
};
|
|
30700
|
+
function defaultOutput(level, message, context) {
|
|
30701
|
+
const isProduction = process.env.NODE_ENV === "production";
|
|
30702
|
+
if (isProduction) {
|
|
30703
|
+
const entry = { level, message, ...context };
|
|
30704
|
+
const method = level === "error" ? "error" : level === "warn" ? "warn" : "log";
|
|
30705
|
+
console[method](JSON.stringify(entry));
|
|
30706
|
+
} else {
|
|
30707
|
+
const prefix = `[${level.toUpperCase()}]`;
|
|
30708
|
+
const ctx = Object.keys(context).length > 0 ? " " + JSON.stringify(context) : "";
|
|
30709
|
+
const method = level === "error" ? "error" : level === "warn" ? "warn" : level === "debug" ? "debug" : "log";
|
|
30710
|
+
console[method](`${prefix} ${message}${ctx}`);
|
|
30711
|
+
}
|
|
30712
|
+
}
|
|
30713
|
+
var AppLoggerImpl = class _AppLoggerImpl {
|
|
30714
|
+
baseContext;
|
|
30715
|
+
minLevelPriority;
|
|
30716
|
+
outputFn;
|
|
30717
|
+
onErrorFn;
|
|
30718
|
+
constructor(baseContext, options) {
|
|
30719
|
+
this.baseContext = baseContext;
|
|
30720
|
+
this.minLevelPriority = LEVEL_PRIORITY2[options.minLevel] ?? 0;
|
|
30721
|
+
this.outputFn = options.output;
|
|
30722
|
+
this.onErrorFn = options.onError;
|
|
30723
|
+
}
|
|
30724
|
+
log(level, message, context) {
|
|
30725
|
+
if ((LEVEL_PRIORITY2[level] ?? 0) < this.minLevelPriority) return;
|
|
30726
|
+
const merged = {
|
|
30727
|
+
...this.baseContext,
|
|
30728
|
+
...context,
|
|
30729
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
30730
|
+
};
|
|
30731
|
+
this.outputFn(level, message, merged);
|
|
30732
|
+
}
|
|
30733
|
+
debug(message, context) {
|
|
30734
|
+
this.log("debug", message, context);
|
|
30735
|
+
}
|
|
30736
|
+
info(message, context) {
|
|
30737
|
+
this.log("info", message, context);
|
|
30738
|
+
}
|
|
30739
|
+
warn(message, context) {
|
|
30740
|
+
this.log("warn", message, context);
|
|
30741
|
+
}
|
|
30742
|
+
error(message, context) {
|
|
30743
|
+
this.log("error", message, context);
|
|
30744
|
+
if (this.onErrorFn) {
|
|
30745
|
+
try {
|
|
30746
|
+
this.onErrorFn(message, { ...this.baseContext, ...context });
|
|
30747
|
+
} catch {
|
|
30748
|
+
}
|
|
30749
|
+
}
|
|
30750
|
+
}
|
|
30751
|
+
child(context) {
|
|
30752
|
+
return new _AppLoggerImpl(
|
|
30753
|
+
{ ...this.baseContext, ...context },
|
|
30754
|
+
{
|
|
30755
|
+
minLevel: Object.entries(LEVEL_PRIORITY2).find(
|
|
30756
|
+
([, v]) => v === this.minLevelPriority
|
|
30757
|
+
)?.[0] ?? "debug",
|
|
30758
|
+
output: this.outputFn,
|
|
30759
|
+
onError: this.onErrorFn
|
|
30760
|
+
}
|
|
30761
|
+
);
|
|
30762
|
+
}
|
|
30763
|
+
forRequest(request, operation) {
|
|
30764
|
+
const requestId = request.headers.get("x-request-id") ?? request.headers.get("x-correlation-id") ?? crypto.randomUUID();
|
|
30765
|
+
let path;
|
|
30766
|
+
try {
|
|
30767
|
+
path = new URL(request.url).pathname;
|
|
30768
|
+
} catch {
|
|
30769
|
+
path = request.url;
|
|
30770
|
+
}
|
|
30771
|
+
return this.child({
|
|
30772
|
+
requestId,
|
|
30773
|
+
operation,
|
|
30774
|
+
method: request.method,
|
|
30775
|
+
path
|
|
30776
|
+
});
|
|
30777
|
+
}
|
|
30778
|
+
forJob(jobType, jobId, context) {
|
|
30779
|
+
return this.child({ jobType, jobId, ...context });
|
|
30780
|
+
}
|
|
30781
|
+
async timed(operation, fn, context) {
|
|
30782
|
+
const opLogger = this.child({ operation, ...context });
|
|
30783
|
+
opLogger.debug("Operation started");
|
|
30784
|
+
const start = Date.now();
|
|
30785
|
+
try {
|
|
30786
|
+
const result = await fn();
|
|
30787
|
+
opLogger.info("Operation completed", {
|
|
30788
|
+
durationMs: Date.now() - start
|
|
30789
|
+
});
|
|
30790
|
+
return result;
|
|
30791
|
+
} catch (error) {
|
|
30792
|
+
opLogger.error("Operation failed", {
|
|
30793
|
+
durationMs: Date.now() - start,
|
|
30794
|
+
error: error instanceof Error ? error.message : String(error)
|
|
30795
|
+
});
|
|
30796
|
+
throw error;
|
|
30797
|
+
}
|
|
30798
|
+
}
|
|
30799
|
+
};
|
|
30800
|
+
function createAppLogger(options) {
|
|
30801
|
+
const {
|
|
30802
|
+
service,
|
|
30803
|
+
minLevel = process.env.NODE_ENV === "production" ? "info" : "debug",
|
|
30804
|
+
output = defaultOutput,
|
|
30805
|
+
onError
|
|
30806
|
+
} = options;
|
|
30807
|
+
return new AppLoggerImpl({ service }, { minLevel, output, onError });
|
|
30808
|
+
}
|
|
30809
|
+
|
|
30810
|
+
// src/redis-client.ts
|
|
30811
|
+
import Redis from "ioredis";
|
|
30812
|
+
function createRedisClient(options) {
|
|
30813
|
+
const {
|
|
30814
|
+
url,
|
|
30815
|
+
keyPrefix,
|
|
30816
|
+
maxRetries = 3,
|
|
30817
|
+
lazyConnect = true,
|
|
30818
|
+
silent = false
|
|
30819
|
+
} = options;
|
|
30820
|
+
const logger = options.logger ?? {
|
|
30821
|
+
error: console.error
|
|
30822
|
+
};
|
|
30823
|
+
const client = new Redis(url, {
|
|
30824
|
+
keyPrefix,
|
|
30825
|
+
maxRetriesPerRequest: maxRetries,
|
|
30826
|
+
retryStrategy(times) {
|
|
30827
|
+
if (times > maxRetries) return null;
|
|
30828
|
+
return Math.min(times * 200, 2e3);
|
|
30829
|
+
},
|
|
30830
|
+
lazyConnect
|
|
30831
|
+
});
|
|
30832
|
+
if (!silent) {
|
|
30833
|
+
client.on("error", (err) => {
|
|
30834
|
+
logger.error("[redis] Connection error", { message: err.message });
|
|
30835
|
+
});
|
|
30836
|
+
if (logger.info) {
|
|
30837
|
+
const logInfo = logger.info;
|
|
30838
|
+
client.on("connect", () => {
|
|
30839
|
+
logInfo("[redis] Connected");
|
|
30840
|
+
});
|
|
30841
|
+
}
|
|
30842
|
+
}
|
|
30843
|
+
if (lazyConnect) {
|
|
30844
|
+
client.connect().catch(() => {
|
|
30845
|
+
});
|
|
30846
|
+
}
|
|
30847
|
+
return client;
|
|
30848
|
+
}
|
|
30849
|
+
var sharedClient = null;
|
|
30850
|
+
function getSharedRedis() {
|
|
30851
|
+
if (sharedClient) return sharedClient;
|
|
30852
|
+
const url = process.env.REDIS_URL;
|
|
30853
|
+
if (!url) return null;
|
|
30854
|
+
sharedClient = createRedisClient({
|
|
30855
|
+
url,
|
|
30856
|
+
keyPrefix: process.env.REDIS_KEY_PREFIX,
|
|
30857
|
+
silent: process.env.NODE_ENV === "test"
|
|
30858
|
+
});
|
|
30859
|
+
return sharedClient;
|
|
30860
|
+
}
|
|
30861
|
+
async function closeSharedRedis() {
|
|
30862
|
+
if (sharedClient) {
|
|
30863
|
+
await sharedClient.quit();
|
|
30864
|
+
sharedClient = null;
|
|
30865
|
+
}
|
|
29172
30866
|
}
|
|
29173
30867
|
|
|
29174
30868
|
// src/migrations/Migrator.ts
|
|
@@ -29947,9 +31641,11 @@ export {
|
|
|
29947
31641
|
CircuitBreakerRegistry,
|
|
29948
31642
|
CircuitOpenError,
|
|
29949
31643
|
CommonApiErrors,
|
|
31644
|
+
CommonRateLimits,
|
|
29950
31645
|
ConsoleEmail,
|
|
29951
31646
|
ConsoleLogger,
|
|
29952
31647
|
CronPresets,
|
|
31648
|
+
CryptoConfigSchema,
|
|
29953
31649
|
DEFAULT_BULKHEAD_OPTIONS,
|
|
29954
31650
|
DEFAULT_CIRCUIT_BREAKER_OPTIONS,
|
|
29955
31651
|
DEFAULT_RETRY_OPTIONS,
|
|
@@ -29962,17 +31658,21 @@ export {
|
|
|
29962
31658
|
DatabaseNotification,
|
|
29963
31659
|
DatabasePromptStore,
|
|
29964
31660
|
DatabaseProviderSchema,
|
|
31661
|
+
DateRangeSchema,
|
|
29965
31662
|
DefaultTimeouts,
|
|
29966
31663
|
EmailConfigSchema,
|
|
29967
31664
|
EmailProviderSchema,
|
|
31665
|
+
EmailSchema,
|
|
29968
31666
|
EnvSecrets,
|
|
29969
31667
|
FallbackStrategies,
|
|
29970
31668
|
GenericOIDCAuthSSO,
|
|
29971
31669
|
GoogleAIAdapter,
|
|
29972
31670
|
HTML_TAG_PATTERN,
|
|
29973
31671
|
HttpWebhook,
|
|
31672
|
+
KEYCLOAK_DEFAULT_ROLES,
|
|
29974
31673
|
LogLevelSchema,
|
|
29975
31674
|
LoggingConfigSchema,
|
|
31675
|
+
LoginSchema,
|
|
29976
31676
|
MemoryAI,
|
|
29977
31677
|
MemoryAIUsage,
|
|
29978
31678
|
MemoryAuditLog,
|
|
@@ -29981,6 +31681,7 @@ export {
|
|
|
29981
31681
|
MemoryBilling,
|
|
29982
31682
|
MemoryCache,
|
|
29983
31683
|
MemoryCompliance,
|
|
31684
|
+
MemoryCrypto,
|
|
29984
31685
|
MemoryDatabase,
|
|
29985
31686
|
MemoryDevPortal,
|
|
29986
31687
|
MemoryDevice,
|
|
@@ -30002,6 +31703,7 @@ export {
|
|
|
30002
31703
|
MetricsConfigSchema,
|
|
30003
31704
|
MiddlewareConfigSchema,
|
|
30004
31705
|
Migrator,
|
|
31706
|
+
NodeCrypto,
|
|
30005
31707
|
NoopLogger,
|
|
30006
31708
|
NoopMetrics,
|
|
30007
31709
|
NoopTracing,
|
|
@@ -30009,7 +31711,11 @@ export {
|
|
|
30009
31711
|
ObservabilityConfigSchema,
|
|
30010
31712
|
OpenAIAdapter,
|
|
30011
31713
|
PG_ERROR_MAP,
|
|
31714
|
+
PaginationSchema,
|
|
31715
|
+
PasswordSchema,
|
|
30012
31716
|
PaymentErrorMessages,
|
|
31717
|
+
PersonNameSchema,
|
|
31718
|
+
PhoneSchema,
|
|
30013
31719
|
PineconeRAG,
|
|
30014
31720
|
PlatformConfigSchema,
|
|
30015
31721
|
PostgresDatabase,
|
|
@@ -30029,7 +31735,14 @@ export {
|
|
|
30029
31735
|
RetryPredicates,
|
|
30030
31736
|
S3Storage,
|
|
30031
31737
|
SQL,
|
|
31738
|
+
SearchQuerySchema,
|
|
31739
|
+
SecurityConfigSchema,
|
|
31740
|
+
SecurityHeaderPresets,
|
|
31741
|
+
SignupSchema,
|
|
31742
|
+
SlugSchema,
|
|
30032
31743
|
SmtpEmail,
|
|
31744
|
+
StandardAuditActions,
|
|
31745
|
+
StandardRateLimitPresets,
|
|
30033
31746
|
StorageConfigSchema,
|
|
30034
31747
|
StorageProviderSchema,
|
|
30035
31748
|
StripePayment,
|
|
@@ -30045,16 +31758,32 @@ export {
|
|
|
30045
31758
|
UpstashCache,
|
|
30046
31759
|
WeaviateRAG,
|
|
30047
31760
|
WebhookEventTypes,
|
|
31761
|
+
WrapperPresets,
|
|
31762
|
+
buildAllowlist,
|
|
31763
|
+
buildAuthCookies,
|
|
31764
|
+
buildErrorBody,
|
|
31765
|
+
buildKeycloakCallbacks,
|
|
30048
31766
|
buildPagination,
|
|
31767
|
+
buildRateLimitHeaders,
|
|
31768
|
+
buildRateLimitResponseHeaders,
|
|
31769
|
+
buildRedirectCallback,
|
|
31770
|
+
buildTokenRefreshParams,
|
|
30049
31771
|
calculateBackoff,
|
|
30050
31772
|
calculateRetryDelay,
|
|
31773
|
+
checkEnvVars,
|
|
31774
|
+
checkRateLimit,
|
|
30051
31775
|
classifyError,
|
|
31776
|
+
closeSharedRedis,
|
|
30052
31777
|
composeHookRegistries,
|
|
31778
|
+
constantTimeEqual,
|
|
30053
31779
|
containsHtml,
|
|
30054
31780
|
containsUrls,
|
|
30055
31781
|
correlationContext,
|
|
30056
31782
|
createAIError,
|
|
30057
31783
|
createAnthropicAdapter,
|
|
31784
|
+
createAppLogger,
|
|
31785
|
+
createAuditActor,
|
|
31786
|
+
createAuditLogger,
|
|
30058
31787
|
createAuthError,
|
|
30059
31788
|
createBulkhead,
|
|
30060
31789
|
createCacheMiddleware,
|
|
@@ -30065,6 +31794,7 @@ export {
|
|
|
30065
31794
|
createErrorReport,
|
|
30066
31795
|
createExpressHealthHandlers,
|
|
30067
31796
|
createExpressMetricsHandler,
|
|
31797
|
+
createFeatureFlags,
|
|
30068
31798
|
createGoogleAIAdapter,
|
|
30069
31799
|
createHealthEndpoints,
|
|
30070
31800
|
createHealthServer,
|
|
@@ -30072,6 +31802,7 @@ export {
|
|
|
30072
31802
|
createIpKeyGenerator,
|
|
30073
31803
|
createJobContext,
|
|
30074
31804
|
createLoggingMiddleware,
|
|
31805
|
+
createMemoryRateLimitStore,
|
|
30075
31806
|
createMetricsEndpoint,
|
|
30076
31807
|
createMetricsMiddleware,
|
|
30077
31808
|
createMetricsServer,
|
|
@@ -30085,8 +31816,10 @@ export {
|
|
|
30085
31816
|
createPlatform,
|
|
30086
31817
|
createPlatformAsync,
|
|
30087
31818
|
createRateLimitMiddleware,
|
|
31819
|
+
createRedisClient,
|
|
30088
31820
|
createRequestContext,
|
|
30089
31821
|
createRequestIdMiddleware,
|
|
31822
|
+
createSafeTextSchema,
|
|
30090
31823
|
createScopedMetrics,
|
|
30091
31824
|
createSlowQueryMiddleware,
|
|
30092
31825
|
createSsoOidcConfigsTable,
|
|
@@ -30103,8 +31836,13 @@ export {
|
|
|
30103
31836
|
defangUrl,
|
|
30104
31837
|
defineMigration,
|
|
30105
31838
|
describeCron,
|
|
31839
|
+
detectStage,
|
|
30106
31840
|
enterpriseMigrations,
|
|
30107
31841
|
escapeHtml,
|
|
31842
|
+
extractAuditIp,
|
|
31843
|
+
extractAuditRequestId,
|
|
31844
|
+
extractAuditUserAgent,
|
|
31845
|
+
extractClientIp,
|
|
30108
31846
|
filterChannelsByPreferences,
|
|
30109
31847
|
formatAmount,
|
|
30110
31848
|
generateAuditId,
|
|
@@ -30118,40 +31856,62 @@ export {
|
|
|
30118
31856
|
generatePaymentId,
|
|
30119
31857
|
generateScheduleId,
|
|
30120
31858
|
generateSecureToken,
|
|
31859
|
+
generateSecurityHeaders,
|
|
30121
31860
|
generateVersion,
|
|
30122
31861
|
generateWebhookId,
|
|
30123
31862
|
generateWebhookSecret,
|
|
31863
|
+
getBoolEnv,
|
|
30124
31864
|
getContext,
|
|
30125
|
-
getCorrelationId,
|
|
31865
|
+
getCorrelationId2 as getCorrelationId,
|
|
30126
31866
|
getDefaultConfig,
|
|
31867
|
+
getEndSessionEndpoint,
|
|
30127
31868
|
getEnterpriseMigrations,
|
|
31869
|
+
getEnvSummary,
|
|
31870
|
+
getIntEnv,
|
|
30128
31871
|
getLogMeta,
|
|
30129
31872
|
getNextCronRun,
|
|
31873
|
+
getOptionalEnv,
|
|
31874
|
+
getRateLimitStatus,
|
|
30130
31875
|
getRequestId,
|
|
31876
|
+
getRequiredEnv,
|
|
31877
|
+
getSharedRedis,
|
|
30131
31878
|
getTenantId,
|
|
31879
|
+
getTokenEndpoint,
|
|
30132
31880
|
getTraceId,
|
|
30133
31881
|
getUserId,
|
|
31882
|
+
hasAllRoles,
|
|
31883
|
+
hasAnyRole,
|
|
31884
|
+
hasRole,
|
|
30134
31885
|
isAIError,
|
|
31886
|
+
isAllowlisted,
|
|
30135
31887
|
isApiError,
|
|
30136
31888
|
isAuthError,
|
|
30137
31889
|
isInContext,
|
|
30138
31890
|
isInQuietHours,
|
|
30139
31891
|
isPaymentError,
|
|
31892
|
+
isTokenExpired,
|
|
30140
31893
|
isValidCron,
|
|
30141
31894
|
loadConfig,
|
|
30142
31895
|
matchAction,
|
|
30143
31896
|
matchEventType,
|
|
31897
|
+
parseKeycloakRoles,
|
|
30144
31898
|
raceTimeout,
|
|
31899
|
+
refreshKeycloakToken,
|
|
31900
|
+
resetRateLimitForKey,
|
|
31901
|
+
resolveIdentifier,
|
|
31902
|
+
resolveRateLimitIdentifier,
|
|
30145
31903
|
retryable,
|
|
30146
31904
|
runWithContext,
|
|
30147
31905
|
runWithContextAsync,
|
|
30148
31906
|
safeValidateConfig,
|
|
31907
|
+
sanitizeApiError,
|
|
30149
31908
|
sanitizeForEmail,
|
|
30150
31909
|
sqlMigration,
|
|
30151
31910
|
stripHtml,
|
|
30152
31911
|
timedHealthCheck,
|
|
30153
31912
|
toHealthCheckResult,
|
|
30154
31913
|
validateConfig,
|
|
31914
|
+
validateEnvVars,
|
|
30155
31915
|
withCorrelation,
|
|
30156
31916
|
withCorrelationAsync,
|
|
30157
31917
|
withFallback,
|