@digilogiclabs/platform-core 1.3.0 → 1.4.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 +76 -4
- package/dist/index.d.ts +76 -4
- package/dist/index.js +700 -155
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +698 -147
- 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 +194 -15
- package/dist/testing.js.map +1 -1
- package/dist/testing.mjs +193 -14
- package/dist/testing.mjs.map +1 -1
- package/package.json +6 -1
package/dist/testing.mjs
CHANGED
|
@@ -346,6 +346,7 @@ var init_IAI = __esm({
|
|
|
346
346
|
});
|
|
347
347
|
|
|
348
348
|
// src/interfaces/IRAG.ts
|
|
349
|
+
import { randomBytes as randomBytes6 } from "crypto";
|
|
349
350
|
var ChunkingPresets, MemoryRAG;
|
|
350
351
|
var init_IRAG = __esm({
|
|
351
352
|
"src/interfaces/IRAG.ts"() {
|
|
@@ -475,7 +476,7 @@ var init_IRAG = __esm({
|
|
|
475
476
|
}
|
|
476
477
|
async ingestOne(collection, document, options) {
|
|
477
478
|
const startTime = Date.now();
|
|
478
|
-
const docId = `doc_${Date.now()}_${
|
|
479
|
+
const docId = `doc_${Date.now()}_${randomBytes6(4).toString("hex")}`;
|
|
479
480
|
const now = /* @__PURE__ */ new Date();
|
|
480
481
|
try {
|
|
481
482
|
const col = await this.getCollection(collection);
|
|
@@ -1356,6 +1357,7 @@ var MemoryEmail = class {
|
|
|
1356
1357
|
};
|
|
1357
1358
|
|
|
1358
1359
|
// src/interfaces/IQueue.ts
|
|
1360
|
+
import { randomBytes } from "crypto";
|
|
1359
1361
|
function calculateBackoff(attempt, options) {
|
|
1360
1362
|
if (options.type === "fixed") {
|
|
1361
1363
|
return options.delay;
|
|
@@ -1366,19 +1368,20 @@ function calculateBackoff(attempt, options) {
|
|
|
1366
1368
|
}
|
|
1367
1369
|
function generateJobId() {
|
|
1368
1370
|
const timestamp = Date.now().toString(36);
|
|
1369
|
-
const random =
|
|
1371
|
+
const random = randomBytes(4).toString("hex");
|
|
1370
1372
|
return `job_${timestamp}_${random}`;
|
|
1371
1373
|
}
|
|
1372
1374
|
|
|
1373
1375
|
// src/context/CorrelationContext.ts
|
|
1374
1376
|
import { AsyncLocalStorage } from "async_hooks";
|
|
1377
|
+
import { randomBytes as randomBytes2 } from "crypto";
|
|
1375
1378
|
var CorrelationContextManager = class {
|
|
1376
1379
|
storage = new AsyncLocalStorage();
|
|
1377
1380
|
idGenerator;
|
|
1378
1381
|
constructor() {
|
|
1379
1382
|
this.idGenerator = () => {
|
|
1380
1383
|
const timestamp = Date.now().toString(36);
|
|
1381
|
-
const random =
|
|
1384
|
+
const random = randomBytes2(4).toString("hex");
|
|
1382
1385
|
return `${timestamp}-${random}`;
|
|
1383
1386
|
};
|
|
1384
1387
|
}
|
|
@@ -1984,10 +1987,11 @@ var MemoryQueue = class {
|
|
|
1984
1987
|
};
|
|
1985
1988
|
|
|
1986
1989
|
// src/adapters/console/ConsoleEmail.ts
|
|
1990
|
+
import { randomBytes as randomBytes3 } from "crypto";
|
|
1987
1991
|
var ConsoleEmail = class {
|
|
1988
1992
|
sentEmails = [];
|
|
1989
1993
|
async send(message) {
|
|
1990
|
-
const id = `console_${Date.now()}_${
|
|
1994
|
+
const id = `console_${Date.now()}_${randomBytes3(4).toString("hex")}`;
|
|
1991
1995
|
console.log("\n" + "=".repeat(60));
|
|
1992
1996
|
console.log("\u{1F4E7} EMAIL SENT (Console Adapter)");
|
|
1993
1997
|
console.log("=".repeat(60));
|
|
@@ -2062,6 +2066,7 @@ var ConsoleEmail = class {
|
|
|
2062
2066
|
};
|
|
2063
2067
|
|
|
2064
2068
|
// src/interfaces/ISecrets.ts
|
|
2069
|
+
import { randomBytes as randomBytes4 } from "crypto";
|
|
2065
2070
|
var EnvSecrets = class {
|
|
2066
2071
|
prefix;
|
|
2067
2072
|
cache = /* @__PURE__ */ new Map();
|
|
@@ -2262,12 +2267,7 @@ var MemorySecrets = class {
|
|
|
2262
2267
|
return true;
|
|
2263
2268
|
}
|
|
2264
2269
|
generateSecureValue(length = 32) {
|
|
2265
|
-
|
|
2266
|
-
let result = "";
|
|
2267
|
-
for (let i = 0; i < length; i++) {
|
|
2268
|
-
result += chars[Math.floor(Math.random() * chars.length)];
|
|
2269
|
-
}
|
|
2270
|
-
return result;
|
|
2270
|
+
return randomBytes4(length).toString("base64url").slice(0, length);
|
|
2271
2271
|
}
|
|
2272
2272
|
/**
|
|
2273
2273
|
* Clear all secrets (for testing)
|
|
@@ -2477,6 +2477,25 @@ var RAGConfigSchema = z.object({
|
|
|
2477
2477
|
message: "Pinecone requires apiKey and indexName; Weaviate requires host"
|
|
2478
2478
|
}
|
|
2479
2479
|
);
|
|
2480
|
+
var CryptoConfigSchema = z.object({
|
|
2481
|
+
enabled: z.boolean().default(false).describe("Enable field-level encryption"),
|
|
2482
|
+
masterKey: z.string().optional().describe("256-bit master key as hex (64 chars). Required when enabled."),
|
|
2483
|
+
hmacKey: z.string().optional().describe("HMAC key for deterministic hashing (derived from master key if not provided)")
|
|
2484
|
+
}).refine(
|
|
2485
|
+
(data) => {
|
|
2486
|
+
if (data.enabled) {
|
|
2487
|
+
return data.masterKey && data.masterKey.length >= 64;
|
|
2488
|
+
}
|
|
2489
|
+
return true;
|
|
2490
|
+
},
|
|
2491
|
+
{
|
|
2492
|
+
message: "Crypto requires a 256-bit master key (64 hex characters) when enabled"
|
|
2493
|
+
}
|
|
2494
|
+
);
|
|
2495
|
+
var SecurityConfigSchema = z.object({
|
|
2496
|
+
enforceTls: z.boolean().default(true).describe("Enforce TLS for production connections"),
|
|
2497
|
+
tlsWarnOnly: z.boolean().default(false).describe("Warn instead of throwing when TLS is missing in production")
|
|
2498
|
+
});
|
|
2480
2499
|
var RetryConfigSchema = z.object({
|
|
2481
2500
|
enabled: z.boolean().default(true).describe("Enable retry for failed operations"),
|
|
2482
2501
|
maxAttempts: z.number().int().min(1).max(10).default(3).describe("Maximum retry attempts"),
|
|
@@ -2566,6 +2585,10 @@ var PlatformConfigSchema = z.object({
|
|
|
2566
2585
|
// AI configurations
|
|
2567
2586
|
ai: AIConfigSchema.default({ enabled: false }),
|
|
2568
2587
|
rag: RAGConfigSchema.default({ enabled: false }),
|
|
2588
|
+
// Crypto configuration
|
|
2589
|
+
crypto: CryptoConfigSchema.default({ enabled: false }),
|
|
2590
|
+
// Security configuration
|
|
2591
|
+
security: SecurityConfigSchema.default({}),
|
|
2569
2592
|
// Resilience configuration
|
|
2570
2593
|
resilience: ResilienceConfigSchema.default({}),
|
|
2571
2594
|
// Observability configuration
|
|
@@ -2643,6 +2666,15 @@ function loadConfig() {
|
|
|
2643
2666
|
embeddingApiKey: process.env.EMBEDDING_API_KEY || process.env.OPENAI_API_KEY,
|
|
2644
2667
|
embeddingModel: process.env.EMBEDDING_MODEL
|
|
2645
2668
|
},
|
|
2669
|
+
crypto: {
|
|
2670
|
+
enabled: process.env.CRYPTO_ENABLED === "true",
|
|
2671
|
+
masterKey: process.env.CRYPTO_MASTER_KEY,
|
|
2672
|
+
hmacKey: process.env.CRYPTO_HMAC_KEY
|
|
2673
|
+
},
|
|
2674
|
+
security: {
|
|
2675
|
+
enforceTls: process.env.SECURITY_ENFORCE_TLS !== "false",
|
|
2676
|
+
tlsWarnOnly: process.env.SECURITY_TLS_WARN_ONLY === "true"
|
|
2677
|
+
},
|
|
2646
2678
|
resilience: {
|
|
2647
2679
|
retry: {
|
|
2648
2680
|
enabled: process.env.RESILIENCE_RETRY_ENABLED !== "false",
|
|
@@ -2693,6 +2725,7 @@ function loadConfig() {
|
|
|
2693
2725
|
}
|
|
2694
2726
|
|
|
2695
2727
|
// src/interfaces/ITracing.ts
|
|
2728
|
+
import { randomBytes as randomBytes5 } from "crypto";
|
|
2696
2729
|
var MemorySpan = class {
|
|
2697
2730
|
name;
|
|
2698
2731
|
context;
|
|
@@ -2712,7 +2745,7 @@ var MemorySpan = class {
|
|
|
2712
2745
|
};
|
|
2713
2746
|
}
|
|
2714
2747
|
generateSpanId() {
|
|
2715
|
-
return
|
|
2748
|
+
return randomBytes5(8).toString("hex");
|
|
2716
2749
|
}
|
|
2717
2750
|
setAttribute(key, value) {
|
|
2718
2751
|
this._attributes[key] = value;
|
|
@@ -2772,7 +2805,7 @@ var MemoryTracing = class {
|
|
|
2772
2805
|
this.traceId = this.generateTraceId();
|
|
2773
2806
|
}
|
|
2774
2807
|
generateTraceId() {
|
|
2775
|
-
return
|
|
2808
|
+
return randomBytes5(16).toString("hex");
|
|
2776
2809
|
}
|
|
2777
2810
|
startSpan(name, options) {
|
|
2778
2811
|
const span = new MemorySpan(
|
|
@@ -3212,6 +3245,147 @@ var NoopMetrics = class {
|
|
|
3212
3245
|
// src/factory.ts
|
|
3213
3246
|
init_IAI();
|
|
3214
3247
|
init_IRAG();
|
|
3248
|
+
|
|
3249
|
+
// src/adapters/memory/MemoryCrypto.ts
|
|
3250
|
+
import { randomBytes as randomBytes7, createCipheriv, createDecipheriv, createHmac } from "crypto";
|
|
3251
|
+
var MemoryCrypto = class {
|
|
3252
|
+
keys = /* @__PURE__ */ new Map();
|
|
3253
|
+
activeKeyId;
|
|
3254
|
+
hmacKey;
|
|
3255
|
+
constructor(options) {
|
|
3256
|
+
const masterKeyBuf = options?.masterKey ? Buffer.from(options.masterKey, "hex") : randomBytes7(32);
|
|
3257
|
+
this.hmacKey = options?.hmacKey ? Buffer.from(options.hmacKey, "hex") : randomBytes7(32);
|
|
3258
|
+
const keyId = this.generateKeyId();
|
|
3259
|
+
this.keys.set(keyId, {
|
|
3260
|
+
id: keyId,
|
|
3261
|
+
key: masterKeyBuf,
|
|
3262
|
+
status: "active",
|
|
3263
|
+
createdAt: /* @__PURE__ */ new Date()
|
|
3264
|
+
});
|
|
3265
|
+
this.activeKeyId = keyId;
|
|
3266
|
+
}
|
|
3267
|
+
async encrypt(plaintext, options) {
|
|
3268
|
+
const keyId = options?.keyId || this.activeKeyId;
|
|
3269
|
+
const stored = this.keys.get(keyId);
|
|
3270
|
+
if (!stored) {
|
|
3271
|
+
throw new Error(`Key not found: ${keyId}`);
|
|
3272
|
+
}
|
|
3273
|
+
if (stored.status === "retired") {
|
|
3274
|
+
throw new Error(`Key is retired: ${keyId}`);
|
|
3275
|
+
}
|
|
3276
|
+
if (stored.status === "decrypt-only" && !options?.keyId) {
|
|
3277
|
+
throw new Error(`Key is decrypt-only: ${keyId}`);
|
|
3278
|
+
}
|
|
3279
|
+
const iv = randomBytes7(12);
|
|
3280
|
+
const cipher = createCipheriv("aes-256-gcm", stored.key, iv);
|
|
3281
|
+
if (options?.aad) {
|
|
3282
|
+
cipher.setAAD(Buffer.from(options.aad, "utf8"));
|
|
3283
|
+
}
|
|
3284
|
+
const encrypted = Buffer.concat([
|
|
3285
|
+
cipher.update(plaintext, "utf8"),
|
|
3286
|
+
cipher.final()
|
|
3287
|
+
]);
|
|
3288
|
+
const tag = cipher.getAuthTag();
|
|
3289
|
+
return {
|
|
3290
|
+
ciphertext: encrypted.toString("base64"),
|
|
3291
|
+
iv: iv.toString("base64"),
|
|
3292
|
+
tag: tag.toString("base64"),
|
|
3293
|
+
keyId,
|
|
3294
|
+
algorithm: "aes-256-gcm",
|
|
3295
|
+
version: 1
|
|
3296
|
+
};
|
|
3297
|
+
}
|
|
3298
|
+
async decrypt(field, options) {
|
|
3299
|
+
const stored = this.keys.get(field.keyId);
|
|
3300
|
+
if (!stored) {
|
|
3301
|
+
throw new Error(`Key not found: ${field.keyId}`);
|
|
3302
|
+
}
|
|
3303
|
+
if (stored.status === "retired") {
|
|
3304
|
+
throw new Error(`Key is retired and cannot decrypt: ${field.keyId}`);
|
|
3305
|
+
}
|
|
3306
|
+
const decipher = createDecipheriv(
|
|
3307
|
+
"aes-256-gcm",
|
|
3308
|
+
stored.key,
|
|
3309
|
+
Buffer.from(field.iv, "base64")
|
|
3310
|
+
);
|
|
3311
|
+
decipher.setAuthTag(Buffer.from(field.tag, "base64"));
|
|
3312
|
+
if (options?.aad) {
|
|
3313
|
+
decipher.setAAD(Buffer.from(options.aad, "utf8"));
|
|
3314
|
+
}
|
|
3315
|
+
const decrypted = Buffer.concat([
|
|
3316
|
+
decipher.update(Buffer.from(field.ciphertext, "base64")),
|
|
3317
|
+
decipher.final()
|
|
3318
|
+
]);
|
|
3319
|
+
return decrypted.toString("utf8");
|
|
3320
|
+
}
|
|
3321
|
+
async encryptDeterministic(plaintext, options) {
|
|
3322
|
+
const hash = await this.computeHash(plaintext);
|
|
3323
|
+
const encrypted = await this.encrypt(plaintext, options);
|
|
3324
|
+
return { hash, encrypted };
|
|
3325
|
+
}
|
|
3326
|
+
async computeHash(plaintext) {
|
|
3327
|
+
return createHmac("sha256", this.hmacKey).update(plaintext, "utf8").digest("hex");
|
|
3328
|
+
}
|
|
3329
|
+
async encryptBatch(fields, options) {
|
|
3330
|
+
const result = {};
|
|
3331
|
+
for (const [key, value] of Object.entries(fields)) {
|
|
3332
|
+
result[key] = await this.encrypt(value, options);
|
|
3333
|
+
}
|
|
3334
|
+
return result;
|
|
3335
|
+
}
|
|
3336
|
+
async decryptBatch(fields, options) {
|
|
3337
|
+
const result = {};
|
|
3338
|
+
for (const [key, value] of Object.entries(fields)) {
|
|
3339
|
+
result[key] = await this.decrypt(value, options);
|
|
3340
|
+
}
|
|
3341
|
+
return result;
|
|
3342
|
+
}
|
|
3343
|
+
async rotateKey() {
|
|
3344
|
+
const previousKeyId = this.activeKeyId;
|
|
3345
|
+
const currentKey = this.keys.get(previousKeyId);
|
|
3346
|
+
if (currentKey) {
|
|
3347
|
+
currentKey.status = "decrypt-only";
|
|
3348
|
+
}
|
|
3349
|
+
const newKeyId = this.generateKeyId();
|
|
3350
|
+
this.keys.set(newKeyId, {
|
|
3351
|
+
id: newKeyId,
|
|
3352
|
+
key: randomBytes7(32),
|
|
3353
|
+
status: "active",
|
|
3354
|
+
createdAt: /* @__PURE__ */ new Date()
|
|
3355
|
+
});
|
|
3356
|
+
this.activeKeyId = newKeyId;
|
|
3357
|
+
return { newKeyId, previousKeyId };
|
|
3358
|
+
}
|
|
3359
|
+
async reEncrypt(field, options) {
|
|
3360
|
+
const plaintext = await this.decrypt(field);
|
|
3361
|
+
return this.encrypt(plaintext, options);
|
|
3362
|
+
}
|
|
3363
|
+
async listKeys() {
|
|
3364
|
+
return Array.from(this.keys.values()).map((k) => ({
|
|
3365
|
+
keyId: k.id,
|
|
3366
|
+
createdAt: k.createdAt,
|
|
3367
|
+
status: k.status
|
|
3368
|
+
}));
|
|
3369
|
+
}
|
|
3370
|
+
async getActiveKeyId() {
|
|
3371
|
+
return this.activeKeyId;
|
|
3372
|
+
}
|
|
3373
|
+
async healthCheck() {
|
|
3374
|
+
try {
|
|
3375
|
+
const testPlain = "health-check-test";
|
|
3376
|
+
const encrypted = await this.encrypt(testPlain);
|
|
3377
|
+
const decrypted = await this.decrypt(encrypted);
|
|
3378
|
+
return decrypted === testPlain;
|
|
3379
|
+
} catch {
|
|
3380
|
+
return false;
|
|
3381
|
+
}
|
|
3382
|
+
}
|
|
3383
|
+
generateKeyId() {
|
|
3384
|
+
return `key_${randomBytes7(8).toString("hex")}`;
|
|
3385
|
+
}
|
|
3386
|
+
};
|
|
3387
|
+
|
|
3388
|
+
// src/factory.ts
|
|
3215
3389
|
function createLogger(config) {
|
|
3216
3390
|
if (!config.observability.logging) {
|
|
3217
3391
|
return new NoopLogger();
|
|
@@ -3246,6 +3420,7 @@ function createPlatform(config) {
|
|
|
3246
3420
|
const tracing = finalConfig.observability.tracing.provider === "memory" ? new MemoryTracing() : new NoopTracing();
|
|
3247
3421
|
const ai = finalConfig.ai.enabled ? new MemoryAI() : null;
|
|
3248
3422
|
const rag = finalConfig.rag.enabled ? new MemoryRAG() : null;
|
|
3423
|
+
const crypto2 = finalConfig.crypto.enabled ? new MemoryCrypto() : null;
|
|
3249
3424
|
return createPlatformFromAdapters(
|
|
3250
3425
|
db,
|
|
3251
3426
|
cache,
|
|
@@ -3256,10 +3431,11 @@ function createPlatform(config) {
|
|
|
3256
3431
|
metrics,
|
|
3257
3432
|
tracing,
|
|
3258
3433
|
ai,
|
|
3259
|
-
rag
|
|
3434
|
+
rag,
|
|
3435
|
+
crypto2
|
|
3260
3436
|
);
|
|
3261
3437
|
}
|
|
3262
|
-
function createPlatformFromAdapters(db, cache, storage, email, queue, logger, metrics, tracing, ai, rag) {
|
|
3438
|
+
function createPlatformFromAdapters(db, cache, storage, email, queue, logger, metrics, tracing, ai, rag, crypto2) {
|
|
3263
3439
|
const platform = {
|
|
3264
3440
|
db,
|
|
3265
3441
|
cache,
|
|
@@ -3313,6 +3489,9 @@ function createPlatformFromAdapters(db, cache, storage, email, queue, logger, me
|
|
|
3313
3489
|
if (rag) {
|
|
3314
3490
|
platform.rag = rag;
|
|
3315
3491
|
}
|
|
3492
|
+
if (crypto2) {
|
|
3493
|
+
platform.crypto = crypto2;
|
|
3494
|
+
}
|
|
3316
3495
|
return platform;
|
|
3317
3496
|
}
|
|
3318
3497
|
function deepMerge(target, source) {
|