@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/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,27 @@ 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(
|
|
2484
|
+
"HMAC key for deterministic hashing (derived from master key if not provided)"
|
|
2485
|
+
)
|
|
2486
|
+
}).refine(
|
|
2487
|
+
(data) => {
|
|
2488
|
+
if (data.enabled) {
|
|
2489
|
+
return data.masterKey && data.masterKey.length >= 64;
|
|
2490
|
+
}
|
|
2491
|
+
return true;
|
|
2492
|
+
},
|
|
2493
|
+
{
|
|
2494
|
+
message: "Crypto requires a 256-bit master key (64 hex characters) when enabled"
|
|
2495
|
+
}
|
|
2496
|
+
);
|
|
2497
|
+
var SecurityConfigSchema = z.object({
|
|
2498
|
+
enforceTls: z.boolean().default(true).describe("Enforce TLS for production connections"),
|
|
2499
|
+
tlsWarnOnly: z.boolean().default(false).describe("Warn instead of throwing when TLS is missing in production")
|
|
2500
|
+
});
|
|
2480
2501
|
var RetryConfigSchema = z.object({
|
|
2481
2502
|
enabled: z.boolean().default(true).describe("Enable retry for failed operations"),
|
|
2482
2503
|
maxAttempts: z.number().int().min(1).max(10).default(3).describe("Maximum retry attempts"),
|
|
@@ -2566,6 +2587,10 @@ var PlatformConfigSchema = z.object({
|
|
|
2566
2587
|
// AI configurations
|
|
2567
2588
|
ai: AIConfigSchema.default({ enabled: false }),
|
|
2568
2589
|
rag: RAGConfigSchema.default({ enabled: false }),
|
|
2590
|
+
// Crypto configuration
|
|
2591
|
+
crypto: CryptoConfigSchema.default({ enabled: false }),
|
|
2592
|
+
// Security configuration
|
|
2593
|
+
security: SecurityConfigSchema.default({}),
|
|
2569
2594
|
// Resilience configuration
|
|
2570
2595
|
resilience: ResilienceConfigSchema.default({}),
|
|
2571
2596
|
// Observability configuration
|
|
@@ -2643,6 +2668,15 @@ function loadConfig() {
|
|
|
2643
2668
|
embeddingApiKey: process.env.EMBEDDING_API_KEY || process.env.OPENAI_API_KEY,
|
|
2644
2669
|
embeddingModel: process.env.EMBEDDING_MODEL
|
|
2645
2670
|
},
|
|
2671
|
+
crypto: {
|
|
2672
|
+
enabled: process.env.CRYPTO_ENABLED === "true",
|
|
2673
|
+
masterKey: process.env.CRYPTO_MASTER_KEY,
|
|
2674
|
+
hmacKey: process.env.CRYPTO_HMAC_KEY
|
|
2675
|
+
},
|
|
2676
|
+
security: {
|
|
2677
|
+
enforceTls: process.env.SECURITY_ENFORCE_TLS !== "false",
|
|
2678
|
+
tlsWarnOnly: process.env.SECURITY_TLS_WARN_ONLY === "true"
|
|
2679
|
+
},
|
|
2646
2680
|
resilience: {
|
|
2647
2681
|
retry: {
|
|
2648
2682
|
enabled: process.env.RESILIENCE_RETRY_ENABLED !== "false",
|
|
@@ -2693,6 +2727,7 @@ function loadConfig() {
|
|
|
2693
2727
|
}
|
|
2694
2728
|
|
|
2695
2729
|
// src/interfaces/ITracing.ts
|
|
2730
|
+
import { randomBytes as randomBytes5 } from "crypto";
|
|
2696
2731
|
var MemorySpan = class {
|
|
2697
2732
|
name;
|
|
2698
2733
|
context;
|
|
@@ -2712,7 +2747,7 @@ var MemorySpan = class {
|
|
|
2712
2747
|
};
|
|
2713
2748
|
}
|
|
2714
2749
|
generateSpanId() {
|
|
2715
|
-
return
|
|
2750
|
+
return randomBytes5(8).toString("hex");
|
|
2716
2751
|
}
|
|
2717
2752
|
setAttribute(key, value) {
|
|
2718
2753
|
this._attributes[key] = value;
|
|
@@ -2772,7 +2807,7 @@ var MemoryTracing = class {
|
|
|
2772
2807
|
this.traceId = this.generateTraceId();
|
|
2773
2808
|
}
|
|
2774
2809
|
generateTraceId() {
|
|
2775
|
-
return
|
|
2810
|
+
return randomBytes5(16).toString("hex");
|
|
2776
2811
|
}
|
|
2777
2812
|
startSpan(name, options) {
|
|
2778
2813
|
const span = new MemorySpan(
|
|
@@ -3212,6 +3247,152 @@ var NoopMetrics = class {
|
|
|
3212
3247
|
// src/factory.ts
|
|
3213
3248
|
init_IAI();
|
|
3214
3249
|
init_IRAG();
|
|
3250
|
+
|
|
3251
|
+
// src/adapters/memory/MemoryCrypto.ts
|
|
3252
|
+
import {
|
|
3253
|
+
randomBytes as randomBytes7,
|
|
3254
|
+
createCipheriv,
|
|
3255
|
+
createDecipheriv,
|
|
3256
|
+
createHmac
|
|
3257
|
+
} from "crypto";
|
|
3258
|
+
var MemoryCrypto = class {
|
|
3259
|
+
keys = /* @__PURE__ */ new Map();
|
|
3260
|
+
activeKeyId;
|
|
3261
|
+
hmacKey;
|
|
3262
|
+
constructor(options) {
|
|
3263
|
+
const masterKeyBuf = options?.masterKey ? Buffer.from(options.masterKey, "hex") : randomBytes7(32);
|
|
3264
|
+
this.hmacKey = options?.hmacKey ? Buffer.from(options.hmacKey, "hex") : randomBytes7(32);
|
|
3265
|
+
const keyId = this.generateKeyId();
|
|
3266
|
+
this.keys.set(keyId, {
|
|
3267
|
+
id: keyId,
|
|
3268
|
+
key: masterKeyBuf,
|
|
3269
|
+
status: "active",
|
|
3270
|
+
createdAt: /* @__PURE__ */ new Date()
|
|
3271
|
+
});
|
|
3272
|
+
this.activeKeyId = keyId;
|
|
3273
|
+
}
|
|
3274
|
+
async encrypt(plaintext, options) {
|
|
3275
|
+
const keyId = options?.keyId || this.activeKeyId;
|
|
3276
|
+
const stored = this.keys.get(keyId);
|
|
3277
|
+
if (!stored) {
|
|
3278
|
+
throw new Error(`Key not found: ${keyId}`);
|
|
3279
|
+
}
|
|
3280
|
+
if (stored.status === "retired") {
|
|
3281
|
+
throw new Error(`Key is retired: ${keyId}`);
|
|
3282
|
+
}
|
|
3283
|
+
if (stored.status === "decrypt-only" && !options?.keyId) {
|
|
3284
|
+
throw new Error(`Key is decrypt-only: ${keyId}`);
|
|
3285
|
+
}
|
|
3286
|
+
const iv = randomBytes7(12);
|
|
3287
|
+
const cipher = createCipheriv("aes-256-gcm", stored.key, iv);
|
|
3288
|
+
if (options?.aad) {
|
|
3289
|
+
cipher.setAAD(Buffer.from(options.aad, "utf8"));
|
|
3290
|
+
}
|
|
3291
|
+
const encrypted = Buffer.concat([
|
|
3292
|
+
cipher.update(plaintext, "utf8"),
|
|
3293
|
+
cipher.final()
|
|
3294
|
+
]);
|
|
3295
|
+
const tag = cipher.getAuthTag();
|
|
3296
|
+
return {
|
|
3297
|
+
ciphertext: encrypted.toString("base64"),
|
|
3298
|
+
iv: iv.toString("base64"),
|
|
3299
|
+
tag: tag.toString("base64"),
|
|
3300
|
+
keyId,
|
|
3301
|
+
algorithm: "aes-256-gcm",
|
|
3302
|
+
version: 1
|
|
3303
|
+
};
|
|
3304
|
+
}
|
|
3305
|
+
async decrypt(field, options) {
|
|
3306
|
+
const stored = this.keys.get(field.keyId);
|
|
3307
|
+
if (!stored) {
|
|
3308
|
+
throw new Error(`Key not found: ${field.keyId}`);
|
|
3309
|
+
}
|
|
3310
|
+
if (stored.status === "retired") {
|
|
3311
|
+
throw new Error(`Key is retired and cannot decrypt: ${field.keyId}`);
|
|
3312
|
+
}
|
|
3313
|
+
const decipher = createDecipheriv(
|
|
3314
|
+
"aes-256-gcm",
|
|
3315
|
+
stored.key,
|
|
3316
|
+
Buffer.from(field.iv, "base64")
|
|
3317
|
+
);
|
|
3318
|
+
decipher.setAuthTag(Buffer.from(field.tag, "base64"));
|
|
3319
|
+
if (options?.aad) {
|
|
3320
|
+
decipher.setAAD(Buffer.from(options.aad, "utf8"));
|
|
3321
|
+
}
|
|
3322
|
+
const decrypted = Buffer.concat([
|
|
3323
|
+
decipher.update(Buffer.from(field.ciphertext, "base64")),
|
|
3324
|
+
decipher.final()
|
|
3325
|
+
]);
|
|
3326
|
+
return decrypted.toString("utf8");
|
|
3327
|
+
}
|
|
3328
|
+
async encryptDeterministic(plaintext, options) {
|
|
3329
|
+
const hash = await this.computeHash(plaintext);
|
|
3330
|
+
const encrypted = await this.encrypt(plaintext, options);
|
|
3331
|
+
return { hash, encrypted };
|
|
3332
|
+
}
|
|
3333
|
+
async computeHash(plaintext) {
|
|
3334
|
+
return createHmac("sha256", this.hmacKey).update(plaintext, "utf8").digest("hex");
|
|
3335
|
+
}
|
|
3336
|
+
async encryptBatch(fields, options) {
|
|
3337
|
+
const result = {};
|
|
3338
|
+
for (const [key, value] of Object.entries(fields)) {
|
|
3339
|
+
result[key] = await this.encrypt(value, options);
|
|
3340
|
+
}
|
|
3341
|
+
return result;
|
|
3342
|
+
}
|
|
3343
|
+
async decryptBatch(fields, options) {
|
|
3344
|
+
const result = {};
|
|
3345
|
+
for (const [key, value] of Object.entries(fields)) {
|
|
3346
|
+
result[key] = await this.decrypt(value, options);
|
|
3347
|
+
}
|
|
3348
|
+
return result;
|
|
3349
|
+
}
|
|
3350
|
+
async rotateKey() {
|
|
3351
|
+
const previousKeyId = this.activeKeyId;
|
|
3352
|
+
const currentKey = this.keys.get(previousKeyId);
|
|
3353
|
+
if (currentKey) {
|
|
3354
|
+
currentKey.status = "decrypt-only";
|
|
3355
|
+
}
|
|
3356
|
+
const newKeyId = this.generateKeyId();
|
|
3357
|
+
this.keys.set(newKeyId, {
|
|
3358
|
+
id: newKeyId,
|
|
3359
|
+
key: randomBytes7(32),
|
|
3360
|
+
status: "active",
|
|
3361
|
+
createdAt: /* @__PURE__ */ new Date()
|
|
3362
|
+
});
|
|
3363
|
+
this.activeKeyId = newKeyId;
|
|
3364
|
+
return { newKeyId, previousKeyId };
|
|
3365
|
+
}
|
|
3366
|
+
async reEncrypt(field, options) {
|
|
3367
|
+
const plaintext = await this.decrypt(field);
|
|
3368
|
+
return this.encrypt(plaintext, options);
|
|
3369
|
+
}
|
|
3370
|
+
async listKeys() {
|
|
3371
|
+
return Array.from(this.keys.values()).map((k) => ({
|
|
3372
|
+
keyId: k.id,
|
|
3373
|
+
createdAt: k.createdAt,
|
|
3374
|
+
status: k.status
|
|
3375
|
+
}));
|
|
3376
|
+
}
|
|
3377
|
+
async getActiveKeyId() {
|
|
3378
|
+
return this.activeKeyId;
|
|
3379
|
+
}
|
|
3380
|
+
async healthCheck() {
|
|
3381
|
+
try {
|
|
3382
|
+
const testPlain = "health-check-test";
|
|
3383
|
+
const encrypted = await this.encrypt(testPlain);
|
|
3384
|
+
const decrypted = await this.decrypt(encrypted);
|
|
3385
|
+
return decrypted === testPlain;
|
|
3386
|
+
} catch {
|
|
3387
|
+
return false;
|
|
3388
|
+
}
|
|
3389
|
+
}
|
|
3390
|
+
generateKeyId() {
|
|
3391
|
+
return `key_${randomBytes7(8).toString("hex")}`;
|
|
3392
|
+
}
|
|
3393
|
+
};
|
|
3394
|
+
|
|
3395
|
+
// src/factory.ts
|
|
3215
3396
|
function createLogger(config) {
|
|
3216
3397
|
if (!config.observability.logging) {
|
|
3217
3398
|
return new NoopLogger();
|
|
@@ -3246,6 +3427,7 @@ function createPlatform(config) {
|
|
|
3246
3427
|
const tracing = finalConfig.observability.tracing.provider === "memory" ? new MemoryTracing() : new NoopTracing();
|
|
3247
3428
|
const ai = finalConfig.ai.enabled ? new MemoryAI() : null;
|
|
3248
3429
|
const rag = finalConfig.rag.enabled ? new MemoryRAG() : null;
|
|
3430
|
+
const crypto2 = finalConfig.crypto.enabled ? new MemoryCrypto() : null;
|
|
3249
3431
|
return createPlatformFromAdapters(
|
|
3250
3432
|
db,
|
|
3251
3433
|
cache,
|
|
@@ -3256,10 +3438,11 @@ function createPlatform(config) {
|
|
|
3256
3438
|
metrics,
|
|
3257
3439
|
tracing,
|
|
3258
3440
|
ai,
|
|
3259
|
-
rag
|
|
3441
|
+
rag,
|
|
3442
|
+
crypto2
|
|
3260
3443
|
);
|
|
3261
3444
|
}
|
|
3262
|
-
function createPlatformFromAdapters(db, cache, storage, email, queue, logger, metrics, tracing, ai, rag) {
|
|
3445
|
+
function createPlatformFromAdapters(db, cache, storage, email, queue, logger, metrics, tracing, ai, rag, crypto2) {
|
|
3263
3446
|
const platform = {
|
|
3264
3447
|
db,
|
|
3265
3448
|
cache,
|
|
@@ -3313,6 +3496,9 @@ function createPlatformFromAdapters(db, cache, storage, email, queue, logger, me
|
|
|
3313
3496
|
if (rag) {
|
|
3314
3497
|
platform.rag = rag;
|
|
3315
3498
|
}
|
|
3499
|
+
if (crypto2) {
|
|
3500
|
+
platform.crypto = crypto2;
|
|
3501
|
+
}
|
|
3316
3502
|
return platform;
|
|
3317
3503
|
}
|
|
3318
3504
|
function deepMerge(target, source) {
|