@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/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()}_${Math.random().toString(36).substring(7)}`;
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 = Math.random().toString(36).substring(2, 10);
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 = Math.random().toString(36).substring(2, 10);
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()}_${Math.random().toString(36).slice(2, 9)}`;
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
- const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*";
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 Math.random().toString(16).substring(2, 18).padStart(16, "0");
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 Math.random().toString(16).substring(2, 34).padStart(32, "0");
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) {