@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/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,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 Math.random().toString(16).substring(2, 18).padStart(16, "0");
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 Math.random().toString(16).substring(2, 34).padStart(32, "0");
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) {