kontext-sdk 0.5.0 → 0.5.2

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/index.js CHANGED
@@ -1,8 +1,8 @@
1
1
  'use strict';
2
2
 
3
3
  var crypto$1 = require('crypto');
4
- var fs3 = require('fs');
5
- var path3 = require('path');
4
+ var fs4 = require('fs');
5
+ var path4 = require('path');
6
6
 
7
7
  function _interopNamespace(e) {
8
8
  if (e && e.__esModule) return e;
@@ -22,8 +22,15 @@ function _interopNamespace(e) {
22
22
  return Object.freeze(n);
23
23
  }
24
24
 
25
- var fs3__namespace = /*#__PURE__*/_interopNamespace(fs3);
26
- var path3__namespace = /*#__PURE__*/_interopNamespace(path3);
25
+ var fs4__namespace = /*#__PURE__*/_interopNamespace(fs4);
26
+ var path4__namespace = /*#__PURE__*/_interopNamespace(path4);
27
+
28
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
29
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
30
+ }) : x)(function(x) {
31
+ if (typeof require !== "undefined") return require.apply(this, arguments);
32
+ throw Error('Dynamic require of "' + x + '" is not supported');
33
+ });
27
34
 
28
35
  // src/utils.ts
29
36
  function generateId() {
@@ -142,7 +149,7 @@ var TrustScorer = class {
142
149
  const flagged = riskScore >= RISK_FLAG_THRESHOLD;
143
150
  const recommendation = riskScore >= RISK_BLOCK_THRESHOLD ? "block" : riskScore >= RISK_REVIEW_THRESHOLD ? "review" : "approve";
144
151
  return {
145
- txHash: tx.txHash,
152
+ ...tx.txHash ? { txHash: tx.txHash } : {},
146
153
  riskScore,
147
154
  riskLevel,
148
155
  factors,
@@ -412,7 +419,7 @@ var TrustScorer = class {
412
419
  return {
413
420
  name: "amount_risk",
414
421
  score,
415
- description: `Transaction amount ${tx.amount} ${tx.token}`
422
+ description: `Transaction amount ${tx.amount} ${tx.token ?? tx.currency ?? ""}`
416
423
  };
417
424
  }
418
425
  computeNewDestinationRisk(tx) {
@@ -520,6 +527,9 @@ var TrustScorer = class {
520
527
  };
521
528
 
522
529
  // src/types.ts
530
+ function isCryptoTransaction(input) {
531
+ return !!input.txHash && !!input.chain && !!input.token;
532
+ }
523
533
  var KontextErrorCode = /* @__PURE__ */ ((KontextErrorCode2) => {
524
534
  KontextErrorCode2["INITIALIZATION_ERROR"] = "INITIALIZATION_ERROR";
525
535
  KontextErrorCode2["VALIDATION_ERROR"] = "VALIDATION_ERROR";
@@ -725,10 +735,10 @@ var AnomalyDetector = class {
725
735
  return this.createAnomaly(
726
736
  "unusualAmount",
727
737
  amount > threshold * 5 ? "critical" : amount > threshold * 2 ? "high" : "medium",
728
- `Transaction amount ${tx.amount} ${tx.token} exceeds threshold of ${this.thresholds.maxAmount}`,
738
+ `Transaction amount ${tx.amount} ${tx.token ?? tx.currency ?? ""} exceeds threshold of ${this.thresholds.maxAmount}`,
729
739
  tx.agentId,
730
740
  tx.id,
731
- { amount: tx.amount, threshold: this.thresholds.maxAmount, token: tx.token }
741
+ { amount: tx.amount, threshold: this.thresholds.maxAmount, token: tx.token ?? tx.currency }
732
742
  );
733
743
  }
734
744
  const history = this.store.getTransactionsByAgent(tx.agentId);
@@ -1160,6 +1170,18 @@ var DigestChain = class {
1160
1170
  getTerminalDigest() {
1161
1171
  return this.currentDigest;
1162
1172
  }
1173
+ /**
1174
+ * Restore the terminal digest from persisted state.
1175
+ * Called after loading actions from storage so that new actions
1176
+ * chain correctly from the last stored digest instead of genesis.
1177
+ *
1178
+ * Does NOT reconstruct the links array — in-memory verification
1179
+ * via verify() will not work after restore. Use the stored action
1180
+ * digest/priorDigest fields for cross-process chain verification.
1181
+ */
1182
+ restoreTerminalDigest(digest) {
1183
+ this.currentDigest = digest;
1184
+ }
1163
1185
  /**
1164
1186
  * Get the number of links in the chain.
1165
1187
  */
@@ -1427,6 +1449,7 @@ var ActionLogger = class {
1427
1449
  async logTransaction(input) {
1428
1450
  this.validateTransactionInput(input);
1429
1451
  const correlationId = input.correlationId ?? generateId();
1452
+ const description = input.token && input.chain ? `${input.token} transfer of ${input.amount} on ${input.chain}` : `${input.currency ?? "USD"} payment of ${input.amount}${input.paymentMethod ? ` via ${input.paymentMethod}` : ""}`;
1430
1453
  const record = {
1431
1454
  id: generateId(),
1432
1455
  timestamp: now(),
@@ -1435,16 +1458,19 @@ var ActionLogger = class {
1435
1458
  ...input.sessionId ? { sessionId: input.sessionId } : {},
1436
1459
  correlationId,
1437
1460
  type: "transaction",
1438
- description: `${input.token} transfer of ${input.amount} on ${input.chain}`,
1461
+ description,
1439
1462
  metadata: {
1440
1463
  ...input.metadata
1441
1464
  },
1442
- txHash: input.txHash,
1443
- chain: input.chain,
1444
1465
  amount: input.amount,
1445
- token: input.token,
1446
1466
  from: input.from,
1447
- to: input.to
1467
+ to: input.to,
1468
+ ...input.txHash ? { txHash: input.txHash } : {},
1469
+ ...input.chain ? { chain: input.chain } : {},
1470
+ ...input.token ? { token: input.token } : {},
1471
+ ...input.currency ? { currency: input.currency } : {},
1472
+ ...input.paymentMethod ? { paymentMethod: input.paymentMethod } : {},
1473
+ ...input.paymentReference ? { paymentReference: input.paymentReference } : {}
1448
1474
  };
1449
1475
  const link = this.digestChain.append(record);
1450
1476
  record.digest = link.digest;
@@ -1505,6 +1531,13 @@ var ActionLogger = class {
1505
1531
  verifyChain(actions) {
1506
1532
  return this.digestChain.verify(actions);
1507
1533
  }
1534
+ /**
1535
+ * Restore chain state from persisted actions so that new actions
1536
+ * chain correctly across process boundaries.
1537
+ */
1538
+ restoreChainState(terminalDigest) {
1539
+ this.digestChain.restoreTerminalDigest(terminalDigest);
1540
+ }
1508
1541
  // --------------------------------------------------------------------------
1509
1542
  // Private helpers
1510
1543
  // --------------------------------------------------------------------------
@@ -1517,53 +1550,56 @@ var ActionLogger = class {
1517
1550
  { field: "amount", value: input.amount }
1518
1551
  );
1519
1552
  }
1520
- if (!input.txHash || input.txHash.trim() === "") {
1521
- throw new KontextError(
1522
- "VALIDATION_ERROR" /* VALIDATION_ERROR */,
1523
- "Transaction hash is required",
1524
- { field: "txHash" }
1525
- );
1526
- }
1527
1553
  if (!input.from || input.from.trim() === "") {
1528
1554
  throw new KontextError(
1529
1555
  "VALIDATION_ERROR" /* VALIDATION_ERROR */,
1530
- "Sender address (from) is required",
1556
+ "Sender (from) is required",
1531
1557
  { field: "from" }
1532
1558
  );
1533
1559
  }
1534
1560
  if (!input.to || input.to.trim() === "") {
1535
1561
  throw new KontextError(
1536
1562
  "VALIDATION_ERROR" /* VALIDATION_ERROR */,
1537
- "Recipient address (to) is required",
1563
+ "Recipient (to) is required",
1538
1564
  { field: "to" }
1539
1565
  );
1540
1566
  }
1541
- const validChains = ["ethereum", "base", "polygon", "arbitrum", "optimism", "arc", "avalanche", "solana"];
1542
- if (!validChains.includes(input.chain)) {
1543
- throw new KontextError(
1544
- "VALIDATION_ERROR" /* VALIDATION_ERROR */,
1545
- `Invalid chain: ${input.chain}. Must be one of: ${validChains.join(", ")}`,
1546
- { field: "chain", value: input.chain }
1547
- );
1548
- }
1549
- const validTokens = ["USDC", "USDT", "DAI", "EURC"];
1550
- if (!validTokens.includes(input.token)) {
1551
- throw new KontextError(
1552
- "VALIDATION_ERROR" /* VALIDATION_ERROR */,
1553
- `Invalid token: ${input.token}. Must be one of: ${validTokens.join(", ")}`,
1554
- { field: "token", value: input.token }
1555
- );
1567
+ const hasCryptoFields = input.txHash !== void 0 || input.chain !== void 0 || input.token !== void 0;
1568
+ if (hasCryptoFields) {
1569
+ if (!input.txHash || input.txHash.trim() === "") {
1570
+ throw new KontextError(
1571
+ "VALIDATION_ERROR" /* VALIDATION_ERROR */,
1572
+ "Transaction hash is required for crypto transactions",
1573
+ { field: "txHash" }
1574
+ );
1575
+ }
1576
+ const validChains = ["ethereum", "base", "polygon", "arbitrum", "optimism", "arc", "avalanche", "solana"];
1577
+ if (!input.chain || !validChains.includes(input.chain)) {
1578
+ throw new KontextError(
1579
+ "VALIDATION_ERROR" /* VALIDATION_ERROR */,
1580
+ `Invalid chain: ${input.chain}. Must be one of: ${validChains.join(", ")}`,
1581
+ { field: "chain", value: input.chain }
1582
+ );
1583
+ }
1584
+ const validTokens = ["USDC", "USDT", "DAI", "EURC", "USDP", "USDG"];
1585
+ if (!input.token || !validTokens.includes(input.token)) {
1586
+ throw new KontextError(
1587
+ "VALIDATION_ERROR" /* VALIDATION_ERROR */,
1588
+ `Invalid token: ${input.token}. Must be one of: ${validTokens.join(", ")}`,
1589
+ { field: "token", value: input.token }
1590
+ );
1591
+ }
1556
1592
  }
1557
1593
  }
1558
1594
  flushToFile(actions) {
1559
1595
  const outputDir = this.config.localOutputDir ?? ".kontext";
1560
- const logDir = path3__namespace.join(outputDir, "logs");
1596
+ const logDir = path4__namespace.join(outputDir, "logs");
1561
1597
  try {
1562
- fs3__namespace.mkdirSync(logDir, { recursive: true });
1598
+ fs4__namespace.mkdirSync(logDir, { recursive: true });
1563
1599
  const filename = `actions-${(/* @__PURE__ */ new Date()).toISOString().split("T")[0]}.jsonl`;
1564
- const filePath = path3__namespace.join(logDir, filename);
1600
+ const filePath = path4__namespace.join(logDir, filename);
1565
1601
  const lines = actions.map((a) => JSON.stringify(a)).join("\n") + "\n";
1566
- fs3__namespace.appendFileSync(filePath, lines, "utf-8");
1602
+ fs4__namespace.appendFileSync(filePath, lines, "utf-8");
1567
1603
  } catch (error) {
1568
1604
  this.emitLog("warn", "Failed to write log file", { error });
1569
1605
  }
@@ -2012,7 +2048,7 @@ var AuditExporter = class {
2012
2048
  if (options.agentIds && !options.agentIds.includes(tx.agentId)) {
2013
2049
  return false;
2014
2050
  }
2015
- if (options.chains && !options.chains.includes(tx.chain)) {
2051
+ if (options.chains && (!tx.chain || !options.chains.includes(tx.chain))) {
2016
2052
  return false;
2017
2053
  }
2018
2054
  return true;
@@ -2103,8 +2139,6 @@ var AuditExporter = class {
2103
2139
  return sections.join("\n\n");
2104
2140
  }
2105
2141
  };
2106
-
2107
- // src/integrations/usdc.ts
2108
2142
  var USDC_CONTRACTS = {
2109
2143
  ethereum: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
2110
2144
  base: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
@@ -2165,6 +2199,22 @@ var SANCTIONED_ADDRESSES = [
2165
2199
  var SANCTIONED_SET = new Set(
2166
2200
  SANCTIONED_ADDRESSES.map((addr) => addr.toLowerCase())
2167
2201
  );
2202
+ function loadCachedSDN() {
2203
+ try {
2204
+ const dataDir = process.env["KONTEXT_DATA_DIR"] || ".kontext";
2205
+ const cachePath = path4__namespace.join(dataDir, "ofac-sdn-cache.json");
2206
+ if (fs4__namespace.existsSync(cachePath)) {
2207
+ const cache = JSON.parse(fs4__namespace.readFileSync(cachePath, "utf-8"));
2208
+ if (Array.isArray(cache.addresses)) {
2209
+ for (const addr of cache.addresses) {
2210
+ SANCTIONED_SET.add(String(addr).toLowerCase());
2211
+ }
2212
+ }
2213
+ }
2214
+ } catch {
2215
+ }
2216
+ }
2217
+ loadCachedSDN();
2168
2218
  var ENHANCED_DUE_DILIGENCE_THRESHOLD = 3e3;
2169
2219
  var REPORTING_THRESHOLD = 1e4;
2170
2220
  var LARGE_TRANSACTION_THRESHOLD = 5e4;
@@ -2464,6 +2514,183 @@ var UsdcCompliance = class _UsdcCompliance {
2464
2514
  }
2465
2515
  };
2466
2516
 
2517
+ // src/integrations/payment-compliance.ts
2518
+ var ENHANCED_DUE_DILIGENCE_THRESHOLD2 = 3e3;
2519
+ var REPORTING_THRESHOLD2 = 1e4;
2520
+ var LARGE_TRANSACTION_THRESHOLD2 = 5e4;
2521
+ var NAME_MATCH_THRESHOLD = 0.85;
2522
+ var _screener = null;
2523
+ var _screenerLoaded = false;
2524
+ function getScreener() {
2525
+ if (!_screenerLoaded) {
2526
+ _screenerLoaded = true;
2527
+ try {
2528
+ const mod = __require("./ofac-sanctions.js");
2529
+ if (mod.OFACSanctionsScreener) {
2530
+ _screener = new mod.OFACSanctionsScreener();
2531
+ }
2532
+ } catch {
2533
+ }
2534
+ }
2535
+ return _screener;
2536
+ }
2537
+ var PaymentCompliance = class _PaymentCompliance {
2538
+ /**
2539
+ * Run compliance checks on a general payment.
2540
+ *
2541
+ * @param input - Payment to evaluate
2542
+ * @returns UsdcComplianceCheck with pass/fail results and recommendations
2543
+ */
2544
+ static checkPayment(input) {
2545
+ const checks = [];
2546
+ checks.push(_PaymentCompliance.checkAmountValid(input.amount));
2547
+ checks.push(_PaymentCompliance.checkEntityScreening(input.from, "sender"));
2548
+ checks.push(_PaymentCompliance.checkEntityScreening(input.to, "recipient"));
2549
+ checks.push(_PaymentCompliance.checkEnhancedDueDiligence(input.amount));
2550
+ checks.push(_PaymentCompliance.checkReportingThreshold(input.amount));
2551
+ const failedChecks = checks.filter((c) => !c.passed);
2552
+ const compliant = failedChecks.every((c) => c.severity === "low");
2553
+ const highestSeverity = failedChecks.reduce(
2554
+ (max, c) => {
2555
+ const order = ["low", "medium", "high", "critical"];
2556
+ return order.indexOf(c.severity) > order.indexOf(max) ? c.severity : max;
2557
+ },
2558
+ "low"
2559
+ );
2560
+ const recommendations = _PaymentCompliance.generateRecommendations(checks, input);
2561
+ return {
2562
+ compliant,
2563
+ checks,
2564
+ riskLevel: highestSeverity,
2565
+ recommendations
2566
+ };
2567
+ }
2568
+ // --------------------------------------------------------------------------
2569
+ // Individual checks
2570
+ // --------------------------------------------------------------------------
2571
+ static checkAmountValid(amount) {
2572
+ const parsed = parseAmount(amount);
2573
+ const isValid = !isNaN(parsed) && parsed > 0;
2574
+ return {
2575
+ name: "amount_valid",
2576
+ passed: isValid,
2577
+ description: isValid ? `Payment amount ${amount} is valid` : `Payment amount ${amount} is invalid`,
2578
+ severity: isValid ? "low" : "critical"
2579
+ };
2580
+ }
2581
+ static checkEntityScreening(entity, label) {
2582
+ if (/^0x[a-fA-F0-9]{40}$/.test(entity)) {
2583
+ const sanctioned = UsdcCompliance.isSanctioned(entity);
2584
+ return {
2585
+ name: `entity_screening_${label}`,
2586
+ passed: !sanctioned,
2587
+ description: sanctioned ? `${label} address ${entity} matches OFAC SDN sanctioned address` : `${label} address passed sanctions screening`,
2588
+ severity: sanctioned ? "critical" : "low"
2589
+ };
2590
+ }
2591
+ const screener = getScreener();
2592
+ if (!screener) {
2593
+ return {
2594
+ name: `entity_screening_${label}`,
2595
+ passed: true,
2596
+ description: `${label} "${entity}" \u2014 name-based OFAC screening not available (address screening active)`,
2597
+ severity: "low"
2598
+ };
2599
+ }
2600
+ const rawMatches = screener.searchEntityName(entity, NAME_MATCH_THRESHOLD);
2601
+ const matches = rawMatches.filter(
2602
+ (m) => m.similarity >= NAME_MATCH_THRESHOLD && m.matchedOn.length >= 4
2603
+ );
2604
+ if (matches.length > 0) {
2605
+ const topMatch = matches[0];
2606
+ const isActive = topMatch.entity.list !== "DELISTED";
2607
+ if (isActive) {
2608
+ return {
2609
+ name: `entity_screening_${label}`,
2610
+ passed: false,
2611
+ description: `${label} "${entity}" matches OFAC SDN entity "${topMatch.matchedOn}" (${Math.round(topMatch.similarity * 100)}% match)`,
2612
+ severity: "critical"
2613
+ };
2614
+ }
2615
+ return {
2616
+ name: `entity_screening_${label}`,
2617
+ passed: true,
2618
+ description: `${label} "${entity}" matches delisted entity "${topMatch.matchedOn}" \u2014 enhanced due diligence recommended`,
2619
+ severity: "medium"
2620
+ };
2621
+ }
2622
+ return {
2623
+ name: `entity_screening_${label}`,
2624
+ passed: true,
2625
+ description: `${label} "${entity}" passed OFAC entity screening`,
2626
+ severity: "low"
2627
+ };
2628
+ }
2629
+ static checkEnhancedDueDiligence(amount) {
2630
+ const parsed = parseAmount(amount);
2631
+ const requiresEdd = !isNaN(parsed) && parsed >= ENHANCED_DUE_DILIGENCE_THRESHOLD2;
2632
+ return {
2633
+ name: "enhanced_due_diligence",
2634
+ passed: true,
2635
+ description: requiresEdd ? `Amount ${amount} requires enhanced due diligence (threshold: ${ENHANCED_DUE_DILIGENCE_THRESHOLD2})` : `Amount ${amount} is below enhanced due diligence threshold`,
2636
+ severity: requiresEdd ? "medium" : "low"
2637
+ };
2638
+ }
2639
+ static checkReportingThreshold(amount) {
2640
+ const parsed = parseAmount(amount);
2641
+ const requiresReporting = !isNaN(parsed) && parsed >= REPORTING_THRESHOLD2;
2642
+ const isLarge = !isNaN(parsed) && parsed >= LARGE_TRANSACTION_THRESHOLD2;
2643
+ let description;
2644
+ let severity;
2645
+ if (isLarge) {
2646
+ description = `Amount ${amount} is a large payment (>= ${LARGE_TRANSACTION_THRESHOLD2}) \u2014 requires enhanced monitoring`;
2647
+ severity = "high";
2648
+ } else if (requiresReporting) {
2649
+ description = `Amount ${amount} meets reporting threshold (>= ${REPORTING_THRESHOLD2})`;
2650
+ severity = "medium";
2651
+ } else {
2652
+ description = `Amount ${amount} is below reporting threshold`;
2653
+ severity = "low";
2654
+ }
2655
+ return {
2656
+ name: "reporting_threshold",
2657
+ passed: true,
2658
+ description,
2659
+ severity
2660
+ };
2661
+ }
2662
+ // --------------------------------------------------------------------------
2663
+ // Recommendations
2664
+ // --------------------------------------------------------------------------
2665
+ static generateRecommendations(checks, input) {
2666
+ const recommendations = [];
2667
+ const amount = parseAmount(input.amount);
2668
+ for (const check of checks) {
2669
+ if (!check.passed && check.name.startsWith("entity_screening_")) {
2670
+ recommendations.push(
2671
+ `BLOCK: ${check.description}. Payment is prohibited under OFAC regulations.`
2672
+ );
2673
+ }
2674
+ }
2675
+ if (!isNaN(amount) && amount >= LARGE_TRANSACTION_THRESHOLD2) {
2676
+ recommendations.push(
2677
+ `Enhanced monitoring required for payment of ${input.amount} ${input.currency ?? "USD"} (above ${LARGE_TRANSACTION_THRESHOLD2} threshold).`
2678
+ );
2679
+ }
2680
+ if (!isNaN(amount) && amount >= REPORTING_THRESHOLD2) {
2681
+ recommendations.push(
2682
+ `CTR reporting may be required for payment of ${input.amount} ${input.currency ?? "USD"} (meets ${REPORTING_THRESHOLD2} reporting threshold).`
2683
+ );
2684
+ }
2685
+ if (!isNaN(amount) && amount >= ENHANCED_DUE_DILIGENCE_THRESHOLD2) {
2686
+ recommendations.push(
2687
+ `Enhanced due diligence recommended for payment of ${input.amount} ${input.currency ?? "USD"} (Travel Rule threshold: ${ENHANCED_DUE_DILIGENCE_THRESHOLD2}).`
2688
+ );
2689
+ }
2690
+ return recommendations;
2691
+ }
2692
+ };
2693
+
2467
2694
  // src/plans.ts
2468
2695
  var PLAN_LIMITS = {
2469
2696
  free: 2e4,
@@ -2816,7 +3043,7 @@ var JsonFileExporter = class {
2816
3043
  buffer = [];
2817
3044
  bufferSize;
2818
3045
  constructor(options) {
2819
- this.outputDir = path3__namespace.resolve(options?.outputDir ?? ".kontext/exports");
3046
+ this.outputDir = path4__namespace.resolve(options?.outputDir ?? ".kontext/exports");
2820
3047
  this.bufferSize = options?.bufferSize ?? 1;
2821
3048
  }
2822
3049
  async export(events) {
@@ -2831,11 +3058,11 @@ var JsonFileExporter = class {
2831
3058
  const toWrite = [...this.buffer];
2832
3059
  this.buffer = [];
2833
3060
  try {
2834
- fs3__namespace.mkdirSync(this.outputDir, { recursive: true });
3061
+ fs4__namespace.mkdirSync(this.outputDir, { recursive: true });
2835
3062
  const date = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
2836
- const filePath = path3__namespace.join(this.outputDir, `events-${date}.jsonl`);
3063
+ const filePath = path4__namespace.join(this.outputDir, `events-${date}.jsonl`);
2837
3064
  const lines = toWrite.map((e) => JSON.stringify(e)).join("\n") + "\n";
2838
- fs3__namespace.appendFileSync(filePath, lines, "utf-8");
3065
+ fs4__namespace.appendFileSync(filePath, lines, "utf-8");
2839
3066
  } catch (error) {
2840
3067
  console.warn("[Kontext JsonFileExporter] Failed to write events:", error);
2841
3068
  }
@@ -3174,7 +3401,7 @@ var Kontext = class _Kontext {
3174
3401
  * @returns The created transaction record
3175
3402
  */
3176
3403
  async logTransaction(input) {
3177
- if (input.chain !== "base") {
3404
+ if (input.chain && input.chain !== "base") {
3178
3405
  requirePlan("multi-chain", this.planManager.getTier());
3179
3406
  }
3180
3407
  this.validateMetadata(input.metadata);
@@ -3211,10 +3438,22 @@ var Kontext = class _Kontext {
3211
3438
  /**
3212
3439
  * Restore state from the attached storage adapter.
3213
3440
  * Loads previously persisted actions, transactions, tasks, and anomalies.
3441
+ * Also restores the digest chain's terminal digest so that new actions
3442
+ * chain correctly across process boundaries.
3214
3443
  * No-op if no storage adapter is configured.
3215
3444
  */
3216
3445
  async restore() {
3217
3446
  await this.store.restore();
3447
+ const actions = this.store.getActions();
3448
+ if (actions.length > 0) {
3449
+ const sorted = [...actions].sort(
3450
+ (a, b) => new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime()
3451
+ );
3452
+ const lastAction = sorted[sorted.length - 1];
3453
+ if (lastAction.digest) {
3454
+ this.logger.restoreChainState(lastAction.digest);
3455
+ }
3456
+ }
3218
3457
  }
3219
3458
  // --------------------------------------------------------------------------
3220
3459
  // Task Confirmation
@@ -3517,7 +3756,7 @@ var Kontext = class _Kontext {
3517
3756
  */
3518
3757
  async verify(input) {
3519
3758
  const transaction = await this.logTransaction(input);
3520
- const compliance = UsdcCompliance.checkTransaction(input);
3759
+ const compliance = isCryptoTransaction(input) ? UsdcCompliance.checkTransaction(input) : PaymentCompliance.checkPayment(input);
3521
3760
  let reasoningId;
3522
3761
  if (input.reasoning) {
3523
3762
  const entry = await this.logReasoning({
@@ -3546,18 +3785,22 @@ var Kontext = class _Kontext {
3546
3785
  const threshold = parseAmount(this.config.approvalThreshold);
3547
3786
  if (amount > threshold) {
3548
3787
  requiresApproval = true;
3788
+ const label = input.token ? `${input.token} ${input.amount} transfer` : `${input.currency ?? "USD"} ${input.amount} payment`;
3549
3789
  task = await this.createTask({
3550
- description: `Approve ${input.token} ${input.amount} transfer from ${input.from} to ${input.to}`,
3790
+ description: `Approve ${label} from ${input.from} to ${input.to}`,
3551
3791
  agentId: input.agentId,
3552
- requiredEvidence: ["txHash"],
3792
+ requiredEvidence: input.txHash ? ["txHash"] : ["paymentReference"],
3553
3793
  metadata: {
3554
- txHash: input.txHash,
3555
- chain: input.chain,
3556
3794
  amount: input.amount,
3557
- token: input.token,
3558
3795
  from: input.from,
3559
3796
  to: input.to,
3560
- approvalThreshold: this.config.approvalThreshold
3797
+ approvalThreshold: this.config.approvalThreshold,
3798
+ ...input.txHash ? { txHash: input.txHash } : {},
3799
+ ...input.chain ? { chain: input.chain } : {},
3800
+ ...input.token ? { token: input.token } : {},
3801
+ ...input.currency ? { currency: input.currency } : {},
3802
+ ...input.paymentMethod ? { paymentMethod: input.paymentMethod } : {},
3803
+ ...input.paymentReference ? { paymentReference: input.paymentReference } : {}
3561
3804
  }
3562
3805
  });
3563
3806
  }
@@ -3656,7 +3899,7 @@ var Kontext = class _Kontext {
3656
3899
  * and cryptographically verifies the digest chain integrity.
3657
3900
  *
3658
3901
  * The certificate includes: action/transaction/reasoning counts, digest chain
3659
- * verification status (Patent US 12,463,819 B1), the agent's current trust
3902
+ * verification status (patented), the agent's current trust
3660
3903
  * score, and an overall compliance status. A SHA-256 content hash of the
3661
3904
  * certificate itself is included for tamper-evidence.
3662
3905
  *
@@ -3894,20 +4137,20 @@ var MemoryStorage = class {
3894
4137
  var FileStorage = class {
3895
4138
  baseDir;
3896
4139
  constructor(baseDir) {
3897
- this.baseDir = path3__namespace.resolve(baseDir);
4140
+ this.baseDir = path4__namespace.resolve(baseDir);
3898
4141
  }
3899
4142
  async save(key, data) {
3900
- fs3__namespace.mkdirSync(this.baseDir, { recursive: true });
4143
+ fs4__namespace.mkdirSync(this.baseDir, { recursive: true });
3901
4144
  const filePath = this.keyToPath(key);
3902
- const dir = path3__namespace.dirname(filePath);
3903
- fs3__namespace.mkdirSync(dir, { recursive: true });
3904
- fs3__namespace.writeFileSync(filePath, JSON.stringify(data, null, 2), "utf-8");
4145
+ const dir = path4__namespace.dirname(filePath);
4146
+ fs4__namespace.mkdirSync(dir, { recursive: true });
4147
+ fs4__namespace.writeFileSync(filePath, JSON.stringify(data, null, 2), "utf-8");
3905
4148
  }
3906
4149
  async load(key) {
3907
4150
  const filePath = this.keyToPath(key);
3908
- if (!fs3__namespace.existsSync(filePath)) return null;
4151
+ if (!fs4__namespace.existsSync(filePath)) return null;
3909
4152
  try {
3910
- const raw = fs3__namespace.readFileSync(filePath, "utf-8");
4153
+ const raw = fs4__namespace.readFileSync(filePath, "utf-8");
3911
4154
  return JSON.parse(raw);
3912
4155
  } catch {
3913
4156
  return null;
@@ -3915,12 +4158,12 @@ var FileStorage = class {
3915
4158
  }
3916
4159
  async delete(key) {
3917
4160
  const filePath = this.keyToPath(key);
3918
- if (fs3__namespace.existsSync(filePath)) {
3919
- fs3__namespace.unlinkSync(filePath);
4161
+ if (fs4__namespace.existsSync(filePath)) {
4162
+ fs4__namespace.unlinkSync(filePath);
3920
4163
  }
3921
4164
  }
3922
4165
  async list(prefix) {
3923
- if (!fs3__namespace.existsSync(this.baseDir)) return [];
4166
+ if (!fs4__namespace.existsSync(this.baseDir)) return [];
3924
4167
  return this.listRecursive(this.baseDir, prefix);
3925
4168
  }
3926
4169
  /** Get the base directory path. */
@@ -3932,18 +4175,18 @@ var FileStorage = class {
3932
4175
  // --------------------------------------------------------------------------
3933
4176
  keyToPath(key) {
3934
4177
  const safeName = key.replace(/[<>"|?*]/g, "_");
3935
- return path3__namespace.join(this.baseDir, `${safeName}.json`);
4178
+ return path4__namespace.join(this.baseDir, `${safeName}.json`);
3936
4179
  }
3937
4180
  pathToKey(filePath) {
3938
- const relative2 = path3__namespace.relative(this.baseDir, filePath);
4181
+ const relative2 = path4__namespace.relative(this.baseDir, filePath);
3939
4182
  return relative2.replace(/\.json$/, "");
3940
4183
  }
3941
4184
  listRecursive(dir, prefix) {
3942
4185
  const keys = [];
3943
- if (!fs3__namespace.existsSync(dir)) return keys;
3944
- const entries = fs3__namespace.readdirSync(dir, { withFileTypes: true });
4186
+ if (!fs4__namespace.existsSync(dir)) return keys;
4187
+ const entries = fs4__namespace.readdirSync(dir, { withFileTypes: true });
3945
4188
  for (const entry of entries) {
3946
- const fullPath = path3__namespace.join(dir, entry.name);
4189
+ const fullPath = path4__namespace.join(dir, entry.name);
3947
4190
  if (entry.isDirectory()) {
3948
4191
  keys.push(...this.listRecursive(fullPath, prefix));
3949
4192
  } else if (entry.isFile() && entry.name.endsWith(".json")) {
@@ -3957,393 +4200,11 @@ var FileStorage = class {
3957
4200
  }
3958
4201
  };
3959
4202
 
3960
- // src/storage-firestore.ts
3961
- var FirestoreStorageAdapter = class {
3962
- config;
3963
- /** In-memory cache for load() — avoids re-fetching on every store.restore() */
3964
- cache = /* @__PURE__ */ new Map();
3965
- /** Token cache: avoid metadata server round-trips on every write */
3966
- cachedToken = null;
3967
- tokenExpiresAt = 0;
3968
- constructor(config) {
3969
- this.config = {
3970
- gcpProjectId: config.gcpProjectId,
3971
- userId: config.userId,
3972
- accessToken: config.accessToken,
3973
- databaseId: config.databaseId ?? "(default)",
3974
- firestoreBaseUrl: config.firestoreBaseUrl ?? "https://firestore.googleapis.com",
3975
- writeDocumentsIndividually: config.writeDocumentsIndividually ?? true
3976
- };
3977
- }
3978
- // --------------------------------------------------------------------------
3979
- // StorageAdapter interface
3980
- // --------------------------------------------------------------------------
3981
- /**
3982
- * Save data under a Kontext storage key.
3983
- *
3984
- * The flat key space (kontext:actions, kontext:transactions, etc.) is mapped
3985
- * to structured Firestore paths. List data (actions, transactions) is written
3986
- * as individual documents under sub-collections for queryability.
3987
- */
3988
- async save(key, data) {
3989
- this.cache.set(key, data);
3990
- if (key === "kontext:actions" && Array.isArray(data)) {
3991
- await this.saveActionList(data);
3992
- } else if (key === "kontext:transactions" && Array.isArray(data)) {
3993
- await this.saveTransactionList(data);
3994
- } else if (key === "kontext:tasks" && Array.isArray(data)) {
3995
- await this.saveTaskList(data);
3996
- } else if (key === "kontext:anomalies" && Array.isArray(data)) {
3997
- await this.saveAnomalyList(data);
3998
- } else {
3999
- await this.saveDocument(this.keyToPath(key), data);
4000
- }
4001
- }
4002
- /**
4003
- * Load data for a Kontext storage key.
4004
- * Returns cached data if available (populated by save()).
4005
- * Falls back to Firestore fetch for cold starts.
4006
- */
4007
- async load(key) {
4008
- if (this.cache.has(key)) {
4009
- return this.cache.get(key) ?? null;
4010
- }
4011
- if (key === "kontext:actions") {
4012
- const actions = await this.loadActionList();
4013
- this.cache.set(key, actions);
4014
- return actions;
4015
- } else if (key === "kontext:transactions") {
4016
- const txs = await this.loadTransactionList();
4017
- this.cache.set(key, txs);
4018
- return txs;
4019
- } else if (key === "kontext:tasks") {
4020
- const tasks = await this.loadTaskList();
4021
- this.cache.set(key, tasks);
4022
- return tasks;
4023
- } else if (key === "kontext:anomalies") {
4024
- const anomalies = await this.loadAnomalyList();
4025
- this.cache.set(key, anomalies);
4026
- return anomalies;
4027
- } else {
4028
- return this.loadDocument(this.keyToPath(key));
4029
- }
4030
- }
4031
- async delete(key) {
4032
- this.cache.delete(key);
4033
- await this.deleteDocument(this.keyToPath(key));
4034
- }
4035
- async list(prefix) {
4036
- const all = Array.from(this.cache.keys());
4037
- if (!prefix) return all;
4038
- return all.filter((k) => k.startsWith(prefix));
4039
- }
4040
- // --------------------------------------------------------------------------
4041
- // Structured write methods (per-record documents)
4042
- // --------------------------------------------------------------------------
4043
- /**
4044
- * Write a single action log to its canonical Firestore path.
4045
- * Called by the SDK when `writeDocumentsIndividually` is true.
4046
- *
4047
- * Path: users/{userId}/projects/{projectId}/agents/{agentId}/sessions/{sessionId}/actions/{actionId}
4048
- */
4049
- async writeAction(action) {
4050
- if (!this.config.writeDocumentsIndividually) return;
4051
- const path4 = this.actionPath(action);
4052
- await this.saveDocument(path4, action);
4053
- }
4054
- /**
4055
- * Write a single transaction record to its canonical Firestore path.
4056
- *
4057
- * Path: users/{userId}/projects/{projectId}/agents/{agentId}/sessions/{sessionId}/transactions/{txId}
4058
- */
4059
- async writeTransaction(tx) {
4060
- if (!this.config.writeDocumentsIndividually) return;
4061
- const path4 = this.transactionPath(tx);
4062
- await this.saveDocument(path4, tx);
4063
- }
4064
- /**
4065
- * Write a single task to its canonical Firestore path.
4066
- *
4067
- * Path: users/{userId}/projects/{projectId}/tasks/{taskId}
4068
- */
4069
- async writeTask(task) {
4070
- if (!this.config.writeDocumentsIndividually) return;
4071
- const path4 = this.taskPath(task.id);
4072
- await this.saveDocument(path4, task);
4073
- }
4074
- // --------------------------------------------------------------------------
4075
- // Path builders
4076
- // --------------------------------------------------------------------------
4077
- get basePath() {
4078
- return `users/${this.config.userId}/projects`;
4079
- }
4080
- actionPath(action) {
4081
- const sessionId = action.sessionId ?? "_default";
4082
- return `${this.basePath}/${action.projectId}/agents/${sanitize(action.agentId)}/sessions/${sanitize(sessionId)}/actions/${action.id}`;
4083
- }
4084
- transactionPath(tx) {
4085
- const sessionId = tx.sessionId ?? "_default";
4086
- return `${this.basePath}/${tx.projectId}/agents/${sanitize(tx.agentId)}/sessions/${sanitize(sessionId)}/transactions/${tx.id}`;
4087
- }
4088
- taskPath(taskId) {
4089
- return `${this.basePath}/_tasks/${taskId}`;
4090
- }
4091
- anomalyPath(anomalyId, agentId) {
4092
- return `${this.basePath}/_anomalies/agents/${sanitize(agentId)}/${anomalyId}`;
4093
- }
4094
- keyToPath(key) {
4095
- const safe = key.replace(/:/g, "/").replace(/[^a-zA-Z0-9/_-]/g, "_");
4096
- return `${this.basePath}/_meta/${safe}`;
4097
- }
4098
- // --------------------------------------------------------------------------
4099
- // Bulk save/load (called by KontextStore.flush / restore)
4100
- // --------------------------------------------------------------------------
4101
- async saveActionList(actions) {
4102
- if (!this.config.writeDocumentsIndividually) {
4103
- await this.saveDocument(`${this.basePath}/_snapshots/actions`, actions);
4104
- return;
4105
- }
4106
- await Promise.allSettled(actions.map((a) => this.saveDocument(this.actionPath(a), a)));
4107
- }
4108
- async saveTransactionList(txs) {
4109
- if (!this.config.writeDocumentsIndividually) {
4110
- await this.saveDocument(`${this.basePath}/_snapshots/transactions`, txs);
4111
- return;
4112
- }
4113
- await Promise.allSettled(txs.map((tx) => this.saveDocument(this.transactionPath(tx), tx)));
4114
- }
4115
- async saveTaskList(entries) {
4116
- await Promise.allSettled(
4117
- entries.map(([_id, task]) => this.saveDocument(this.taskPath(task.id), task))
4118
- );
4119
- }
4120
- async saveAnomalyList(anomalies) {
4121
- if (!this.config.writeDocumentsIndividually) {
4122
- await this.saveDocument(`${this.basePath}/_snapshots/anomalies`, anomalies);
4123
- return;
4124
- }
4125
- await Promise.allSettled(
4126
- anomalies.map((a) => this.saveDocument(this.anomalyPath(a.id, a.agentId), a))
4127
- );
4128
- }
4129
- async loadActionList() {
4130
- if (!this.config.writeDocumentsIndividually) {
4131
- const snap = await this.loadDocument(`${this.basePath}/_snapshots/actions`);
4132
- return Array.isArray(snap) ? snap : [];
4133
- }
4134
- return this.queryCollectionGroup("actions");
4135
- }
4136
- async loadTransactionList() {
4137
- if (!this.config.writeDocumentsIndividually) {
4138
- const snap = await this.loadDocument(`${this.basePath}/_snapshots/transactions`);
4139
- return Array.isArray(snap) ? snap : [];
4140
- }
4141
- return this.queryCollectionGroup("transactions");
4142
- }
4143
- async loadTaskList() {
4144
- const tasks = await this.queryCollection(`${this.basePath}/_tasks`);
4145
- return tasks.map((t) => [t.id, t]);
4146
- }
4147
- async loadAnomalyList() {
4148
- if (!this.config.writeDocumentsIndividually) {
4149
- const snap = await this.loadDocument(`${this.basePath}/_snapshots/anomalies`);
4150
- return Array.isArray(snap) ? snap : [];
4151
- }
4152
- return this.queryCollectionGroup("anomalies");
4153
- }
4154
- // --------------------------------------------------------------------------
4155
- // Firestore REST API helpers
4156
- // --------------------------------------------------------------------------
4157
- firestoreBase() {
4158
- return `${this.config.firestoreBaseUrl}/v1/projects/${this.config.gcpProjectId}/databases/${this.config.databaseId}/documents`;
4159
- }
4160
- /** Save an arbitrary JS object as a Firestore document at the given path. */
4161
- async saveDocument(fsPath, data) {
4162
- const url = `${this.firestoreBase()}/${fsPath}`;
4163
- const token = await this.getToken();
4164
- const body = JSON.stringify({ fields: toFirestoreFields(data) });
4165
- const res = await fetch(url, {
4166
- method: "PATCH",
4167
- headers: {
4168
- "Content-Type": "application/json",
4169
- Authorization: `Bearer ${token}`
4170
- },
4171
- body
4172
- });
4173
- if (!res.ok) {
4174
- const text = await res.text().catch(() => "");
4175
- throw new Error(`Firestore write failed [${res.status}] ${fsPath}: ${text}`);
4176
- }
4177
- }
4178
- /** Load a document at the given Firestore path. Returns null if not found. */
4179
- async loadDocument(fsPath) {
4180
- const url = `${this.firestoreBase()}/${fsPath}`;
4181
- const token = await this.getToken();
4182
- const res = await fetch(url, {
4183
- headers: { Authorization: `Bearer ${token}` }
4184
- });
4185
- if (res.status === 404) return null;
4186
- if (!res.ok) return null;
4187
- const doc = await res.json();
4188
- return fromFirestoreFields(doc.fields);
4189
- }
4190
- /** Delete a document at the given Firestore path. */
4191
- async deleteDocument(fsPath) {
4192
- const url = `${this.firestoreBase()}/${fsPath}`;
4193
- const token = await this.getToken();
4194
- await fetch(url, {
4195
- method: "DELETE",
4196
- headers: { Authorization: `Bearer ${token}` }
4197
- });
4198
- }
4199
- /**
4200
- * List all documents in a collection and deserialize them.
4201
- * Used for tasks (simple flat collection).
4202
- */
4203
- async queryCollection(collectionPath) {
4204
- const url = `${this.firestoreBase()}/${collectionPath}`;
4205
- const token = await this.getToken();
4206
- const res = await fetch(url, {
4207
- headers: { Authorization: `Bearer ${token}` }
4208
- });
4209
- if (!res.ok) return [];
4210
- const body = await res.json();
4211
- if (!body.documents) return [];
4212
- return body.documents.map((doc) => fromFirestoreFields(doc.fields));
4213
- }
4214
- /**
4215
- * Run a Firestore collection group query to fetch documents across all
4216
- * nested sub-collections with the given name (e.g., 'actions' across all
4217
- * agents and sessions).
4218
- *
4219
- * Scoped to the user's project root to prevent cross-tenant reads.
4220
- */
4221
- async queryCollectionGroup(collectionId) {
4222
- const parent = `projects/${this.config.gcpProjectId}/databases/${this.config.databaseId}/documents`;
4223
- `${this.config.firestoreBaseUrl}/v1/${parent}:runQuery`;
4224
- const token = await this.getToken();
4225
- const scopedUrl = `${this.config.firestoreBaseUrl}/v1/projects/${this.config.gcpProjectId}/databases/${this.config.databaseId}/documents/users/${this.config.userId}:runQuery`;
4226
- const body = {
4227
- structuredQuery: {
4228
- from: [{ collectionId, allDescendants: true }],
4229
- orderBy: [{ field: { fieldPath: "timestamp" }, direction: "ASCENDING" }]
4230
- }
4231
- };
4232
- const res = await fetch(scopedUrl, {
4233
- method: "POST",
4234
- headers: {
4235
- "Content-Type": "application/json",
4236
- Authorization: `Bearer ${token}`
4237
- },
4238
- body: JSON.stringify(body)
4239
- });
4240
- if (!res.ok) return [];
4241
- const results = await res.json();
4242
- return results.filter((r) => r.document?.fields).map((r) => fromFirestoreFields(r.document.fields));
4243
- }
4244
- // --------------------------------------------------------------------------
4245
- // Auth: GCP metadata server + token caching
4246
- // --------------------------------------------------------------------------
4247
- async getToken() {
4248
- if (this.config.accessToken) {
4249
- return this.config.accessToken;
4250
- }
4251
- const now2 = Date.now();
4252
- if (this.cachedToken && now2 < this.tokenExpiresAt - 3e5) {
4253
- return this.cachedToken;
4254
- }
4255
- const metadataUrl = "http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token";
4256
- const res = await fetch(metadataUrl, {
4257
- headers: { "Metadata-Flavor": "Google" }
4258
- });
4259
- if (!res.ok) {
4260
- throw new Error(
4261
- "FirestoreStorageAdapter: Could not fetch GCP access token. On GCP, ensure the service account has Firestore write access. For local dev, pass accessToken in FirestoreStorageConfig."
4262
- );
4263
- }
4264
- const data = await res.json();
4265
- this.cachedToken = data.access_token;
4266
- this.tokenExpiresAt = now2 + data.expires_in * 1e3;
4267
- return this.cachedToken;
4268
- }
4269
- };
4270
- function toFirestoreValue(value) {
4271
- if (value === null || value === void 0) {
4272
- return { nullValue: null };
4273
- }
4274
- if (typeof value === "boolean") {
4275
- return { booleanValue: value };
4276
- }
4277
- if (typeof value === "number") {
4278
- if (Number.isInteger(value)) {
4279
- return { integerValue: String(value) };
4280
- }
4281
- return { doubleValue: value };
4282
- }
4283
- if (typeof value === "string") {
4284
- if (/^\d{4}-\d{2}-\d{2}T/.test(value)) {
4285
- return { timestampValue: value };
4286
- }
4287
- return { stringValue: value };
4288
- }
4289
- if (Array.isArray(value)) {
4290
- return {
4291
- arrayValue: {
4292
- values: value.map(toFirestoreValue)
4293
- }
4294
- };
4295
- }
4296
- if (typeof value === "object") {
4297
- return {
4298
- mapValue: {
4299
- fields: toFirestoreFields(value)
4300
- }
4301
- };
4302
- }
4303
- return { stringValue: String(value) };
4304
- }
4305
- function toFirestoreFields(obj) {
4306
- if (!obj || typeof obj !== "object" || Array.isArray(obj)) {
4307
- return {};
4308
- }
4309
- const result = {};
4310
- for (const [k, v] of Object.entries(obj)) {
4311
- result[k] = toFirestoreValue(v);
4312
- }
4313
- return result;
4314
- }
4315
- function fromFirestoreValue(value) {
4316
- if ("nullValue" in value) return null;
4317
- if ("booleanValue" in value) return value.booleanValue;
4318
- if ("integerValue" in value) return parseInt(value.integerValue, 10);
4319
- if ("doubleValue" in value) return value.doubleValue;
4320
- if ("stringValue" in value) return value.stringValue;
4321
- if ("timestampValue" in value) return value.timestampValue;
4322
- if ("arrayValue" in value) {
4323
- return (value.arrayValue.values ?? []).map(fromFirestoreValue);
4324
- }
4325
- if ("mapValue" in value) {
4326
- return fromFirestoreFields(value.mapValue.fields);
4327
- }
4328
- return null;
4329
- }
4330
- function fromFirestoreFields(fields) {
4331
- const result = {};
4332
- for (const [k, v] of Object.entries(fields)) {
4333
- result[k] = fromFirestoreValue(v);
4334
- }
4335
- return result;
4336
- }
4337
- function sanitize(id) {
4338
- return id.replace(/[/.]/g, "_").slice(0, 1500);
4339
- }
4340
-
4341
4203
  exports.AnomalyDetector = AnomalyDetector;
4342
4204
  exports.ConsoleExporter = ConsoleExporter;
4343
4205
  exports.DigestChain = DigestChain;
4344
4206
  exports.FeatureFlagManager = FeatureFlagManager;
4345
4207
  exports.FileStorage = FileStorage;
4346
- exports.FirestoreStorageAdapter = FirestoreStorageAdapter;
4347
4208
  exports.JsonFileExporter = JsonFileExporter;
4348
4209
  exports.Kontext = Kontext;
4349
4210
  exports.KontextError = KontextError;
@@ -4351,9 +4212,11 @@ exports.KontextErrorCode = KontextErrorCode;
4351
4212
  exports.MemoryStorage = MemoryStorage;
4352
4213
  exports.NoopExporter = NoopExporter;
4353
4214
  exports.PLAN_LIMITS = PLAN_LIMITS;
4215
+ exports.PaymentCompliance = PaymentCompliance;
4354
4216
  exports.PlanManager = PlanManager;
4355
4217
  exports.TrustScorer = TrustScorer;
4356
4218
  exports.UsdcCompliance = UsdcCompliance;
4219
+ exports.isCryptoTransaction = isCryptoTransaction;
4357
4220
  exports.isFeatureAvailable = isFeatureAvailable;
4358
4221
  exports.requirePlan = requirePlan;
4359
4222
  exports.verifyExportedChain = verifyExportedChain;