@digilogiclabs/platform-core 1.2.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);
@@ -1126,7 +1127,11 @@ var MemoryQueryBuilder = class {
1126
1127
  const updated = [];
1127
1128
  const newTable = table.map((item) => {
1128
1129
  if (this.matchesWhere(item)) {
1129
- const updatedItem = { ...item, ...this._updateData, updated_at: (/* @__PURE__ */ new Date()).toISOString() };
1130
+ const updatedItem = {
1131
+ ...item,
1132
+ ...this._updateData,
1133
+ updated_at: (/* @__PURE__ */ new Date()).toISOString()
1134
+ };
1130
1135
  updated.push(updatedItem);
1131
1136
  return updatedItem;
1132
1137
  }
@@ -1141,8 +1146,10 @@ var MemoryQueryBuilder = class {
1141
1146
  result.sort((a, b) => {
1142
1147
  const aVal = a[column];
1143
1148
  const bVal = b[column];
1144
- if (aVal === null || aVal === void 0) return direction === "asc" ? 1 : -1;
1145
- if (bVal === null || bVal === void 0) return direction === "asc" ? -1 : 1;
1149
+ if (aVal === null || aVal === void 0)
1150
+ return direction === "asc" ? 1 : -1;
1151
+ if (bVal === null || bVal === void 0)
1152
+ return direction === "asc" ? -1 : 1;
1146
1153
  const cmp = aVal < bVal ? -1 : aVal > bVal ? 1 : 0;
1147
1154
  return direction === "asc" ? cmp : -cmp;
1148
1155
  });
@@ -1223,7 +1230,9 @@ var MemoryCache = class {
1223
1230
  return Promise.all(keys.map((key) => this.get(key)));
1224
1231
  }
1225
1232
  async mset(entries) {
1226
- await Promise.all(entries.map(({ key, value, ttl }) => this.set(key, value, ttl)));
1233
+ await Promise.all(
1234
+ entries.map(({ key, value, ttl }) => this.set(key, value, ttl))
1235
+ );
1227
1236
  }
1228
1237
  async incr(key, by = 1) {
1229
1238
  const current = await this.get(key) || 0;
@@ -1272,7 +1281,10 @@ var MemoryCache = class {
1272
1281
  var MemoryStorage = class {
1273
1282
  files = /* @__PURE__ */ new Map();
1274
1283
  async upload(key, data, options) {
1275
- this.files.set(key, { data: Buffer.from("mock"), contentType: options?.contentType });
1284
+ this.files.set(key, {
1285
+ data: Buffer.from("mock"),
1286
+ contentType: options?.contentType
1287
+ });
1276
1288
  return { url: "memory://" + key };
1277
1289
  }
1278
1290
  async download(key) {
@@ -1345,6 +1357,7 @@ var MemoryEmail = class {
1345
1357
  };
1346
1358
 
1347
1359
  // src/interfaces/IQueue.ts
1360
+ import { randomBytes } from "crypto";
1348
1361
  function calculateBackoff(attempt, options) {
1349
1362
  if (options.type === "fixed") {
1350
1363
  return options.delay;
@@ -1355,19 +1368,20 @@ function calculateBackoff(attempt, options) {
1355
1368
  }
1356
1369
  function generateJobId() {
1357
1370
  const timestamp = Date.now().toString(36);
1358
- const random = Math.random().toString(36).substring(2, 10);
1371
+ const random = randomBytes(4).toString("hex");
1359
1372
  return `job_${timestamp}_${random}`;
1360
1373
  }
1361
1374
 
1362
1375
  // src/context/CorrelationContext.ts
1363
1376
  import { AsyncLocalStorage } from "async_hooks";
1377
+ import { randomBytes as randomBytes2 } from "crypto";
1364
1378
  var CorrelationContextManager = class {
1365
1379
  storage = new AsyncLocalStorage();
1366
1380
  idGenerator;
1367
1381
  constructor() {
1368
1382
  this.idGenerator = () => {
1369
1383
  const timestamp = Date.now().toString(36);
1370
- const random = Math.random().toString(36).substring(2, 10);
1384
+ const random = randomBytes2(4).toString("hex");
1371
1385
  return `${timestamp}-${random}`;
1372
1386
  };
1373
1387
  }
@@ -1973,16 +1987,19 @@ var MemoryQueue = class {
1973
1987
  };
1974
1988
 
1975
1989
  // src/adapters/console/ConsoleEmail.ts
1990
+ import { randomBytes as randomBytes3 } from "crypto";
1976
1991
  var ConsoleEmail = class {
1977
1992
  sentEmails = [];
1978
1993
  async send(message) {
1979
- const id = `console_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`;
1994
+ const id = `console_${Date.now()}_${randomBytes3(4).toString("hex")}`;
1980
1995
  console.log("\n" + "=".repeat(60));
1981
1996
  console.log("\u{1F4E7} EMAIL SENT (Console Adapter)");
1982
1997
  console.log("=".repeat(60));
1983
1998
  console.log(`ID: ${id}`);
1984
1999
  console.log(`To: ${this.formatAddresses(message.to)}`);
1985
- console.log(`From: ${message.from ? this.formatAddress(message.from) : "(default)"}`);
2000
+ console.log(
2001
+ `From: ${message.from ? this.formatAddress(message.from) : "(default)"}`
2002
+ );
1986
2003
  console.log(`Subject: ${message.subject}`);
1987
2004
  if (message.replyTo) {
1988
2005
  console.log(`Reply-To: ${this.formatAddress(message.replyTo)}`);
@@ -1991,15 +2008,21 @@ var ConsoleEmail = class {
1991
2008
  console.log(`Tags: ${message.tags.join(", ")}`);
1992
2009
  }
1993
2010
  if (message.attachments && message.attachments.length > 0) {
1994
- console.log(`Attachments: ${message.attachments.map((a) => a.filename).join(", ")}`);
2011
+ console.log(
2012
+ `Attachments: ${message.attachments.map((a) => a.filename).join(", ")}`
2013
+ );
1995
2014
  }
1996
2015
  console.log("-".repeat(60));
1997
2016
  if (message.text) {
1998
2017
  console.log("TEXT BODY:");
1999
- console.log(message.text.slice(0, 500) + (message.text.length > 500 ? "\n...(truncated)" : ""));
2018
+ console.log(
2019
+ message.text.slice(0, 500) + (message.text.length > 500 ? "\n...(truncated)" : "")
2020
+ );
2000
2021
  }
2001
2022
  if (message.html) {
2002
- console.log("HTML BODY: [HTML content - " + message.html.length + " chars]");
2023
+ console.log(
2024
+ "HTML BODY: [HTML content - " + message.html.length + " chars]"
2025
+ );
2003
2026
  }
2004
2027
  console.log("=".repeat(60) + "\n");
2005
2028
  this.sentEmails.push(message);
@@ -2043,6 +2066,7 @@ var ConsoleEmail = class {
2043
2066
  };
2044
2067
 
2045
2068
  // src/interfaces/ISecrets.ts
2069
+ import { randomBytes as randomBytes4 } from "crypto";
2046
2070
  var EnvSecrets = class {
2047
2071
  prefix;
2048
2072
  cache = /* @__PURE__ */ new Map();
@@ -2243,12 +2267,7 @@ var MemorySecrets = class {
2243
2267
  return true;
2244
2268
  }
2245
2269
  generateSecureValue(length = 32) {
2246
- const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*";
2247
- let result = "";
2248
- for (let i = 0; i < length; i++) {
2249
- result += chars[Math.floor(Math.random() * chars.length)];
2250
- }
2251
- return result;
2270
+ return randomBytes4(length).toString("base64url").slice(0, length);
2252
2271
  }
2253
2272
  /**
2254
2273
  * Clear all secrets (for testing)
@@ -2267,14 +2286,34 @@ var MemorySecrets = class {
2267
2286
 
2268
2287
  // src/config.ts
2269
2288
  import { z } from "zod";
2270
- var DatabaseProviderSchema = z.enum(["memory", "postgres", "supabase"]);
2289
+ var DatabaseProviderSchema = z.enum([
2290
+ "memory",
2291
+ "postgres",
2292
+ "supabase"
2293
+ ]);
2271
2294
  var CacheProviderSchema = z.enum(["memory", "redis", "upstash"]);
2272
- var StorageProviderSchema = z.enum(["memory", "s3", "minio", "r2", "supabase"]);
2273
- var EmailProviderSchema = z.enum(["memory", "console", "smtp", "resend"]);
2295
+ var StorageProviderSchema = z.enum([
2296
+ "memory",
2297
+ "s3",
2298
+ "minio",
2299
+ "r2",
2300
+ "supabase"
2301
+ ]);
2302
+ var EmailProviderSchema = z.enum([
2303
+ "memory",
2304
+ "console",
2305
+ "smtp",
2306
+ "resend"
2307
+ ]);
2274
2308
  var QueueProviderSchema = z.enum(["memory", "bullmq"]);
2275
2309
  var TracingProviderSchema = z.enum(["noop", "memory", "otlp"]);
2276
2310
  var LogLevelSchema = z.enum(["debug", "info", "warn", "error"]);
2277
- var AIProviderSchema = z.enum(["memory", "openai", "anthropic", "google"]);
2311
+ var AIProviderSchema = z.enum([
2312
+ "memory",
2313
+ "openai",
2314
+ "anthropic",
2315
+ "google"
2316
+ ]);
2278
2317
  var RAGProviderSchema = z.enum(["memory", "pinecone", "weaviate"]);
2279
2318
  var DatabaseConfigSchema = z.object({
2280
2319
  provider: DatabaseProviderSchema.default("memory"),
@@ -2285,7 +2324,10 @@ var DatabaseConfigSchema = z.object({
2285
2324
  supabaseServiceRoleKey: z.string().optional().describe("Supabase service role key"),
2286
2325
  poolSize: z.number().int().min(1).max(100).default(10).describe("Connection pool size"),
2287
2326
  connectionTimeout: z.number().int().min(1e3).max(6e4).default(5e3).describe("Connection timeout in ms"),
2288
- ssl: z.union([z.boolean(), z.object({ rejectUnauthorized: z.boolean().optional() })]).optional().describe("SSL configuration")
2327
+ ssl: z.union([
2328
+ z.boolean(),
2329
+ z.object({ rejectUnauthorized: z.boolean().optional() })
2330
+ ]).optional().describe("SSL configuration")
2289
2331
  }).refine(
2290
2332
  (data) => {
2291
2333
  if (data.provider === "supabase") {
@@ -2416,7 +2458,9 @@ var RAGConfigSchema = z.object({
2416
2458
  indexName: z.string().optional().describe("Pinecone index name or Weaviate class"),
2417
2459
  namespace: z.string().optional().describe("Default namespace"),
2418
2460
  host: z.string().url().optional().describe("Weaviate host URL"),
2419
- embeddingProvider: AIProviderSchema.default("memory").describe("Provider for generating embeddings"),
2461
+ embeddingProvider: AIProviderSchema.default("memory").describe(
2462
+ "Provider for generating embeddings"
2463
+ ),
2420
2464
  embeddingApiKey: z.string().optional().describe("API key for embedding provider"),
2421
2465
  embeddingModel: z.string().optional().describe("Model for generating embeddings")
2422
2466
  }).refine(
@@ -2433,6 +2477,25 @@ var RAGConfigSchema = z.object({
2433
2477
  message: "Pinecone requires apiKey and indexName; Weaviate requires host"
2434
2478
  }
2435
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
+ });
2436
2499
  var RetryConfigSchema = z.object({
2437
2500
  enabled: z.boolean().default(true).describe("Enable retry for failed operations"),
2438
2501
  maxAttempts: z.number().int().min(1).max(10).default(3).describe("Maximum retry attempts"),
@@ -2522,6 +2585,10 @@ var PlatformConfigSchema = z.object({
2522
2585
  // AI configurations
2523
2586
  ai: AIConfigSchema.default({ enabled: false }),
2524
2587
  rag: RAGConfigSchema.default({ enabled: false }),
2588
+ // Crypto configuration
2589
+ crypto: CryptoConfigSchema.default({ enabled: false }),
2590
+ // Security configuration
2591
+ security: SecurityConfigSchema.default({}),
2525
2592
  // Resilience configuration
2526
2593
  resilience: ResilienceConfigSchema.default({}),
2527
2594
  // Observability configuration
@@ -2599,6 +2666,15 @@ function loadConfig() {
2599
2666
  embeddingApiKey: process.env.EMBEDDING_API_KEY || process.env.OPENAI_API_KEY,
2600
2667
  embeddingModel: process.env.EMBEDDING_MODEL
2601
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
+ },
2602
2678
  resilience: {
2603
2679
  retry: {
2604
2680
  enabled: process.env.RESILIENCE_RETRY_ENABLED !== "false",
@@ -2649,6 +2725,7 @@ function loadConfig() {
2649
2725
  }
2650
2726
 
2651
2727
  // src/interfaces/ITracing.ts
2728
+ import { randomBytes as randomBytes5 } from "crypto";
2652
2729
  var MemorySpan = class {
2653
2730
  name;
2654
2731
  context;
@@ -2668,7 +2745,7 @@ var MemorySpan = class {
2668
2745
  };
2669
2746
  }
2670
2747
  generateSpanId() {
2671
- return Math.random().toString(16).substring(2, 18).padStart(16, "0");
2748
+ return randomBytes5(8).toString("hex");
2672
2749
  }
2673
2750
  setAttribute(key, value) {
2674
2751
  this._attributes[key] = value;
@@ -2728,7 +2805,7 @@ var MemoryTracing = class {
2728
2805
  this.traceId = this.generateTraceId();
2729
2806
  }
2730
2807
  generateTraceId() {
2731
- return Math.random().toString(16).substring(2, 34).padStart(32, "0");
2808
+ return randomBytes5(16).toString("hex");
2732
2809
  }
2733
2810
  startSpan(name, options) {
2734
2811
  const span = new MemorySpan(
@@ -3168,6 +3245,147 @@ var NoopMetrics = class {
3168
3245
  // src/factory.ts
3169
3246
  init_IAI();
3170
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
3171
3389
  function createLogger(config) {
3172
3390
  if (!config.observability.logging) {
3173
3391
  return new NoopLogger();
@@ -3202,9 +3420,22 @@ function createPlatform(config) {
3202
3420
  const tracing = finalConfig.observability.tracing.provider === "memory" ? new MemoryTracing() : new NoopTracing();
3203
3421
  const ai = finalConfig.ai.enabled ? new MemoryAI() : null;
3204
3422
  const rag = finalConfig.rag.enabled ? new MemoryRAG() : null;
3205
- return createPlatformFromAdapters(db, cache, storage, email, queue, logger, metrics, tracing, ai, rag);
3423
+ const crypto2 = finalConfig.crypto.enabled ? new MemoryCrypto() : null;
3424
+ return createPlatformFromAdapters(
3425
+ db,
3426
+ cache,
3427
+ storage,
3428
+ email,
3429
+ queue,
3430
+ logger,
3431
+ metrics,
3432
+ tracing,
3433
+ ai,
3434
+ rag,
3435
+ crypto2
3436
+ );
3206
3437
  }
3207
- 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) {
3208
3439
  const platform = {
3209
3440
  db,
3210
3441
  cache,
@@ -3215,7 +3446,14 @@ function createPlatformFromAdapters(db, cache, storage, email, queue, logger, me
3215
3446
  metrics,
3216
3447
  tracing,
3217
3448
  async healthCheck() {
3218
- const [dbHealth, cacheHealth, storageHealth, emailHealth, queueHealth, tracingHealth] = await Promise.all([
3449
+ const [
3450
+ dbHealth,
3451
+ cacheHealth,
3452
+ storageHealth,
3453
+ emailHealth,
3454
+ queueHealth,
3455
+ tracingHealth
3456
+ ] = await Promise.all([
3219
3457
  db.healthCheck(),
3220
3458
  cache.healthCheck(),
3221
3459
  storage.healthCheck(),
@@ -3237,7 +3475,12 @@ function createPlatformFromAdapters(db, cache, storage, email, queue, logger, me
3237
3475
  };
3238
3476
  },
3239
3477
  async close() {
3240
- await Promise.all([db.close(), cache.close(), queue.close(), tracing.close()]);
3478
+ await Promise.all([
3479
+ db.close(),
3480
+ cache.close(),
3481
+ queue.close(),
3482
+ tracing.close()
3483
+ ]);
3241
3484
  }
3242
3485
  };
3243
3486
  if (ai) {
@@ -3246,6 +3489,9 @@ function createPlatformFromAdapters(db, cache, storage, email, queue, logger, me
3246
3489
  if (rag) {
3247
3490
  platform.rag = rag;
3248
3491
  }
3492
+ if (crypto2) {
3493
+ platform.crypto = crypto2;
3494
+ }
3249
3495
  return platform;
3250
3496
  }
3251
3497
  function deepMerge(target, source) {
@@ -3304,7 +3550,11 @@ function createTestPlatformWithInternals() {
3304
3550
  };
3305
3551
  },
3306
3552
  async close() {
3307
- await Promise.all([memoryDb.close(), memoryCache.close(), memoryQueue.close()]);
3553
+ await Promise.all([
3554
+ memoryDb.close(),
3555
+ memoryCache.close(),
3556
+ memoryQueue.close()
3557
+ ]);
3308
3558
  }
3309
3559
  };
3310
3560
  return {
@@ -3344,15 +3594,20 @@ function assertEmailSent(memoryEmail, expected) {
3344
3594
  const matchesTo = (emailTo, expectedTo) => {
3345
3595
  if (!emailTo) return false;
3346
3596
  if (Array.isArray(emailTo)) {
3347
- return emailTo.some((addr) => addr === expectedTo || typeof addr === "object" && addr.email === expectedTo);
3597
+ return emailTo.some(
3598
+ (addr) => addr === expectedTo || typeof addr === "object" && addr.email === expectedTo
3599
+ );
3348
3600
  }
3349
3601
  return emailTo === expectedTo || typeof emailTo === "object" && emailTo.email === expectedTo;
3350
3602
  };
3351
3603
  const found = emails.find((email) => {
3352
- if (expected.to && !matchesTo(email.to, expected.to)) return false;
3604
+ if (expected.to && !matchesTo(email.to, expected.to))
3605
+ return false;
3353
3606
  if (expected.subject) {
3354
- if (typeof expected.subject === "string" && email.subject !== expected.subject) return false;
3355
- if (expected.subject instanceof RegExp && !expected.subject.test(email.subject)) return false;
3607
+ if (typeof expected.subject === "string" && email.subject !== expected.subject)
3608
+ return false;
3609
+ if (expected.subject instanceof RegExp && !expected.subject.test(email.subject))
3610
+ return false;
3356
3611
  }
3357
3612
  if (expected.bodyContains) {
3358
3613
  const body = email.html || email.text || "";