@ik-firewall/core 1.0.2 → 2.3.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/index.cjs CHANGED
@@ -1,7 +1,9 @@
1
1
  "use strict";
2
+ var __create = Object.create;
2
3
  var __defProp = Object.defineProperty;
3
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
5
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
6
8
  var __export = (target, all) => {
7
9
  for (var name in all)
@@ -15,6 +17,14 @@ var __copyProps = (to, from, except, desc) => {
15
17
  }
16
18
  return to;
17
19
  };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
18
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
29
 
20
30
  // src/index.ts
@@ -48,15 +58,18 @@ if (typeof window === "undefined") {
48
58
  var Registry = class _Registry {
49
59
  static instance;
50
60
  registryPath;
61
+ usagePath;
51
62
  hasWarnedNoFs = false;
52
63
  hasWarnedSaveError = false;
53
64
  constructor() {
54
65
  this.registryPath = "";
66
+ this.usagePath = "";
55
67
  if (typeof process !== "undefined" && process.versions && process.versions.node) {
56
68
  try {
57
69
  fs = require("fs");
58
70
  path = require("path");
59
71
  this.registryPath = path.join(process.cwd(), ".ik-adapter", "registry.json");
72
+ this.usagePath = path.join(process.cwd(), ".ik-adapter", "usage.json");
60
73
  this.ensureDirectory();
61
74
  } catch (e) {
62
75
  if (!this.hasWarnedNoFs) {
@@ -91,8 +104,13 @@ var Registry = class _Registry {
91
104
  if (!fs || !this.registryPath) return {};
92
105
  try {
93
106
  if (fs.existsSync(this.registryPath)) {
94
- const data = fs.readFileSync(this.registryPath, "utf8");
95
- return JSON.parse(data);
107
+ const rawData = fs.readFileSync(this.registryPath, "utf8");
108
+ try {
109
+ const decoded = Buffer.from(rawData, "base64").toString("utf8");
110
+ return JSON.parse(decoded);
111
+ } catch (e) {
112
+ return JSON.parse(rawData);
113
+ }
96
114
  }
97
115
  } catch (error) {
98
116
  console.error("[IK_REGISTRY] Load error:", error);
@@ -112,7 +130,9 @@ var Registry = class _Registry {
112
130
  }
113
131
  try {
114
132
  this.ensureDirectory();
115
- fs.writeFileSync(this.registryPath, JSON.stringify(data, null, 2), "utf8");
133
+ const jsonStr = JSON.stringify(data, null, 2);
134
+ const obfuscated = Buffer.from(jsonStr).toString("base64");
135
+ fs.writeFileSync(this.registryPath, obfuscated, "utf8");
116
136
  } catch (error) {
117
137
  if (!this.hasWarnedSaveError) {
118
138
  console.error("\n[IK_REGISTRY] \u{1F6A8} ERROR saving registry.json. Your environment likely has a read-only filesystem (e.g. Vercel Serverless).");
@@ -143,17 +163,76 @@ var Registry = class _Registry {
143
163
  delete all[instanceId];
144
164
  this.save(all);
145
165
  }
166
+ getUsageFilePath() {
167
+ return this.usagePath;
168
+ }
169
+ exists(filePath) {
170
+ return fs && fs.existsSync(filePath);
171
+ }
172
+ loadUsage() {
173
+ if (!fs || !this.usagePath || !fs.existsSync(this.usagePath)) return [];
174
+ try {
175
+ const raw = fs.readFileSync(this.usagePath, "utf8");
176
+ return JSON.parse(raw);
177
+ } catch (e) {
178
+ return [];
179
+ }
180
+ }
181
+ saveUsage(data) {
182
+ if (!fs || !this.usagePath) return;
183
+ try {
184
+ fs.writeFileSync(this.usagePath, JSON.stringify(data, null, 2), "utf8");
185
+ } catch (e) {
186
+ console.error("[IK_REGISTRY] Failed to save usage:", e);
187
+ }
188
+ }
189
+ clearUsage() {
190
+ if (!fs || !this.usagePath) return;
191
+ try {
192
+ if (fs.existsSync(this.usagePath)) {
193
+ fs.unlinkSync(this.usagePath);
194
+ }
195
+ } catch (e) {
196
+ }
197
+ }
198
+ };
199
+
200
+ // src/lib/hmac.ts
201
+ var import_node_crypto = __toESM(require("crypto"), 1);
202
+ var IKHmac = class {
203
+ secret;
204
+ constructor(secret) {
205
+ this.secret = secret;
206
+ }
207
+ /**
208
+ * Verifies that a response from the IK-Firewall server is authentic.
209
+ */
210
+ verify(data) {
211
+ if (!data || !data.signature) return false;
212
+ const { signature, ...rest } = data;
213
+ const payload = JSON.stringify(rest);
214
+ const expectedSignature = import_node_crypto.default.createHmac("sha256", this.secret).update(payload).digest("hex");
215
+ return signature === expectedSignature;
216
+ }
146
217
  };
147
218
 
148
219
  // src/ConfigManager.ts
149
220
  var ConfigManager = class {
150
221
  config;
151
222
  registry;
152
- constructor(initialConfig) {
223
+ hooks;
224
+ constructor(initialConfig, hooks) {
153
225
  this.config = initialConfig;
226
+ this.hooks = hooks;
154
227
  this.registry = Registry.getInstance();
155
228
  this.loadFromRegistry();
156
229
  }
230
+ getRegistry() {
231
+ return this.registry;
232
+ }
233
+ setHooks(hooks) {
234
+ this.hooks = hooks;
235
+ }
157
236
  loadFromRegistry() {
158
237
  const instanceConfigs = this.registry.load();
159
238
  this.config.instanceConfigs = {
@@ -161,6 +240,76 @@ var ConfigManager = class {
161
240
  ...instanceConfigs
162
241
  };
163
242
  }
243
+ /**
244
+ * Syncs remote configuration (pricing, license status) from the Vercel API.
245
+ * Runs once every 24 hours (Heartbeat).
246
+ */
247
+ async syncRemoteConfig(instanceId) {
248
+ const now = /* @__PURE__ */ new Date();
249
+ const instanceConfig = this.config.instanceConfigs?.[instanceId];
250
+ if (instanceConfig?.lastSyncDate) {
251
+ const lastSync = new Date(instanceConfig.lastSyncDate);
252
+ const hoursSinceSync = (now.getTime() - lastSync.getTime()) / (1e3 * 60 * 60);
253
+ if (hoursSinceSync < 24) {
254
+ return;
255
+ }
256
+ }
257
+ try {
258
+ const endpoint = this.config.centralReportEndpoint || "https://ik-firewall.vercel.app/api/v1/sync";
259
+ const instanceConfig2 = this.config.instanceConfigs?.[instanceId];
260
+ const registrationEmail = instanceConfig2?.ownerEmail || this.config.ownerEmail;
261
+ if ((!instanceConfig2?.licenseKey || instanceConfig2.licenseKey.startsWith("TRIAL-")) && registrationEmail) {
262
+ const success = await this.registerInstance(instanceId, registrationEmail);
263
+ if (success) {
264
+ this.hooks?.onStatus?.("\u2728 IK_SYNC: Zero-Config registration successful. License issued.");
265
+ return;
266
+ } else {
267
+ this.hooks?.onStatus?.("\u26A0\uFE0F IK_SYNC: Auto-registration failed. Continuing with local trial.");
268
+ }
269
+ }
270
+ this.hooks?.onStatus?.(`\u{1F4E1} IK_SYNC: Heartbeat to ${endpoint}...`);
271
+ const response = await fetch(`${endpoint}?licenseKey=${instanceConfig2?.licenseKey || ""}&instanceId=${instanceId}&version=2.2.0`);
272
+ if (response.ok) {
273
+ const data = await response.json();
274
+ if (this.config.hmacSecret) {
275
+ const verifier = new IKHmac(this.config.hmacSecret);
276
+ if (!verifier.verify(data)) {
277
+ console.error("[IK_SYNC] \u{1F6A8} Signature verification failed! Remote config rejected.");
278
+ return;
279
+ }
280
+ }
281
+ this.setInstanceConfig(instanceId, {
282
+ billingStatus: data.billingStatus,
283
+ isVerified: data.isVerified,
284
+ pricing: data.pricing,
285
+ lastSyncDate: now.toISOString()
286
+ });
287
+ this.hooks?.onStatus?.("\u2705 IK_SYNC: Remote configuration updated and verified.");
288
+ } else {
289
+ throw new Error(`Server responded with ${response.status}`);
290
+ }
291
+ if (!instanceConfig2?.firstUseDate) {
292
+ this.setInstanceConfig(instanceId, { firstUseDate: now.toISOString() });
293
+ }
294
+ } catch (error) {
295
+ console.error(`[IK_CONFIG] Remote sync failed (${error.message}). Falling open (Fail-Open mode).`);
296
+ this.setInstanceConfig(instanceId, {
297
+ isVerified: true,
298
+ lastSyncDate: now.toISOString()
299
+ });
300
+ }
301
+ try {
302
+ const registry = this.registry;
303
+ if (registry.exists(registry.getUsageFilePath())) {
304
+ const aggregatedUsage = registry.loadUsage();
305
+ if (aggregatedUsage.length > 0) {
306
+ this.hooks?.onStatus?.(`\u{1F4CA} IK_SYNC: Found ${aggregatedUsage.length} pending usage reports. Preparation for Daily Flush...`);
307
+ this._pendingUsage = aggregatedUsage;
308
+ }
309
+ }
310
+ } catch (e) {
311
+ }
312
+ }
164
313
  getConfig() {
165
314
  return { ...this.config };
166
315
  }
@@ -200,6 +349,40 @@ var ConfigManager = class {
200
349
  }
201
350
  this.updateConfig({ plugins });
202
351
  }
352
+ async registerInstance(instanceId, email) {
353
+ try {
354
+ const endpoint = (this.config.centralReportEndpoint || "https://ik-firewall.vercel.app/api/v1").replace(/\/sync$/, "") + "/register";
355
+ this.hooks?.onStatus?.(`\u{1F680} IK_REGISTRY: Registering new instance for ${email}...`);
356
+ const response = await fetch(endpoint, {
357
+ method: "POST",
358
+ headers: { "Content-Type": "application/json" },
359
+ body: JSON.stringify({ email, instanceId })
360
+ });
361
+ if (response.ok) {
362
+ const data = await response.json();
363
+ if (this.config.hmacSecret) {
364
+ const verifier = new IKHmac(this.config.hmacSecret);
365
+ if (!verifier.verify(data)) {
366
+ console.error("[IK_REGISTRY] \u{1F6A8} Registration signature mismatch. Data rejected!");
367
+ return false;
368
+ }
369
+ }
370
+ this.setInstanceConfig(instanceId, {
371
+ licenseKey: data.licenseKey,
372
+ billingStatus: data.status.toLowerCase(),
373
+ isVerified: true,
374
+ firstUseDate: (/* @__PURE__ */ new Date()).toISOString(),
375
+ pricing: data.pricing
376
+ });
377
+ this.hooks?.onStatus?.("\u2728 IK_REGISTRY: Instance registered successfully and license issued.");
378
+ return true;
379
+ }
380
+ return false;
381
+ } catch (error) {
382
+ console.error("[IK_REGISTRY] Registration failed:", error);
383
+ return false;
384
+ }
385
+ }
203
386
  ensureInstanceConfig(instanceId) {
204
387
  const all = this.registry.load();
205
388
  if (!all[instanceId]) {
@@ -207,7 +390,9 @@ var ConfigManager = class {
207
390
  balance: this.config.balance || 0.5,
208
391
  aggressiveness: this.config.aggressiveness || 0.5,
209
392
  isEnabled: true,
210
- contextMode: "FIRST_MESSAGE"
393
+ contextMode: "FIRST_MESSAGE",
394
+ ownerEmail: this.config.ownerEmail
395
+ // Inherit from global if not specific
211
396
  });
212
397
  this.loadFromRegistry();
213
398
  }
@@ -1280,18 +1465,12 @@ var Orchestrator = class {
1280
1465
  };
1281
1466
 
1282
1467
  // src/UsageTracker.ts
1283
- var UsageTracker = class _UsageTracker {
1468
+ var UsageTracker = class {
1284
1469
  buffer = [];
1285
1470
  MAX_BUFFER_SIZE = 1;
1286
1471
  // Immediate reporting for Edge/Stateless environments
1287
1472
  hooks;
1288
1473
  config;
1289
- // Static pricing benchmarks (cost per 1k tokens in USD)
1290
- static PRICING = {
1291
- "gpt-4o": { input: 5e-3, output: 0.015 },
1292
- "gpt-4o-mini": { input: 15e-5, output: 6e-4 },
1293
- "local": { input: 0, output: 0 }
1294
- };
1295
1474
  constructor(config, hooks) {
1296
1475
  this.config = config;
1297
1476
  this.hooks = hooks;
@@ -1302,8 +1481,10 @@ var UsageTracker = class _UsageTracker {
1302
1481
  async logInteraction(params) {
1303
1482
  const { instanceId, model, inputTokens, outputTokens, optimizedTokens = 0, cqScore, routingPath, clientOrigin, trace } = params;
1304
1483
  const tokensSaved = optimizedTokens > 0 ? inputTokens - optimizedTokens : 0;
1305
- const modelPricing = _UsageTracker.PRICING[model] || _UsageTracker.PRICING["gpt-4o-mini"];
1306
- const costSaved = tokensSaved / 1e3 * modelPricing.input;
1484
+ const instanceConfig = this.config.getConfig().instanceConfigs?.[instanceId];
1485
+ const remotePricing = instanceConfig?.pricing?.[model] || { input: 5e-3, output: 0.015 };
1486
+ const costSaved = tokensSaved / 1e3 * remotePricing.input;
1487
+ const commissionDue = costSaved * 0.2;
1307
1488
  const data = {
1308
1489
  instanceId,
1309
1490
  model_used: model,
@@ -1313,6 +1494,7 @@ var UsageTracker = class _UsageTracker {
1313
1494
  optimized_tokens: optimizedTokens,
1314
1495
  tokens_saved: tokensSaved,
1315
1496
  cost_saved: Number(costSaved.toFixed(6)),
1497
+ commission_due: Number(commissionDue.toFixed(6)),
1316
1498
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
1317
1499
  is_local: model === "local",
1318
1500
  cq_score: cqScore,
@@ -1321,40 +1503,71 @@ var UsageTracker = class _UsageTracker {
1321
1503
  };
1322
1504
  this.buffer.push(data);
1323
1505
  this.hooks?.onUsageReported?.(data);
1324
- if (this.buffer.length >= this.MAX_BUFFER_SIZE) {
1325
- await this.flush();
1506
+ await this.persistToLocalBuffer(data);
1507
+ }
1508
+ /**
1509
+ * Appends usage data to the local .ik-adapter/usage.json file
1510
+ */
1511
+ async persistToLocalBuffer(data) {
1512
+ try {
1513
+ const registry = this.config.getRegistry();
1514
+ const usageFile = registry.getUsageFilePath();
1515
+ let existingUsage = [];
1516
+ if (registry.exists(usageFile)) {
1517
+ existingUsage = registry.loadUsage();
1518
+ }
1519
+ existingUsage.push(data);
1520
+ registry.saveUsage(existingUsage);
1521
+ } catch (e) {
1522
+ console.error("[IK_TRACKER] Failed to persist usage to local buffer:", e);
1326
1523
  }
1327
1524
  }
1328
1525
  /**
1329
1526
  * Send buffered usage data to the central IK billing service
1330
1527
  */
1331
- async flush() {
1332
- if (this.buffer.length === 0) return;
1333
- const endpoint = this.config.get("centralReportEndpoint");
1334
- if (!endpoint) {
1335
- console.warn("[IK_TRACKER] No centralReportEndpoint defined. Clearing buffer to prevent memory leak.");
1336
- this.buffer = [];
1337
- return;
1338
- }
1528
+ async flush(aggregatedData) {
1529
+ const usageToFlush = aggregatedData || this.buffer;
1530
+ if (usageToFlush.length === 0) return;
1531
+ const endpoint = this.config.get("centralReportEndpoint") || "https://ik-firewall.vercel.app/api/v1/report";
1532
+ const hmacSecret = this.config.get("hmacSecret");
1339
1533
  try {
1340
- for (const report of this.buffer) {
1341
- await fetch(endpoint, {
1534
+ this.hooks?.onStatus?.(`\u{1F4E4} IK_TRACKER: Flushing ${usageToFlush.length} interactions to ${endpoint}...`);
1535
+ const reportsByInstance = {};
1536
+ for (const report of usageToFlush) {
1537
+ if (!reportsByInstance[report.instanceId]) reportsByInstance[report.instanceId] = [];
1538
+ reportsByInstance[report.instanceId].push(report);
1539
+ }
1540
+ for (const [instanceId, reports] of Object.entries(reportsByInstance)) {
1541
+ const instanceConfig = this.config.getConfig().instanceConfigs?.[instanceId];
1542
+ const payload = {
1543
+ licenseKey: instanceConfig?.licenseKey || "",
1544
+ instanceId,
1545
+ reports: reports.map((r) => ({
1546
+ modelName: r.model_used,
1547
+ tokensIn: r.input_tokens,
1548
+ tokensOut: r.output_tokens,
1549
+ tokensSaved: r.tokens_saved,
1550
+ date: r.timestamp
1551
+ }))
1552
+ };
1553
+ if (hmacSecret) {
1554
+ const jsonStr = JSON.stringify(payload);
1555
+ const crypto2 = await import("crypto");
1556
+ payload.signature = crypto2.createHmac("sha256", hmacSecret).update(jsonStr).digest("hex");
1557
+ }
1558
+ const response = await fetch(endpoint, {
1342
1559
  method: "POST",
1343
1560
  headers: { "Content-Type": "application/json" },
1344
- body: JSON.stringify({
1345
- instanceId: report.instanceId,
1346
- model: report.model_used,
1347
- inputTokens: report.input_tokens,
1348
- outputTokens: report.output_tokens,
1349
- optimizedTokens: report.optimized_tokens,
1350
- cqScore: report.cq_score,
1351
- routingPath: report.routingPath,
1352
- clientOrigin: report.clientOrigin,
1353
- trace: report.trace
1354
- })
1561
+ body: JSON.stringify(payload)
1355
1562
  });
1563
+ if (!response.ok) {
1564
+ console.error(`[IK_TRACKER] Failed to send aggregate for ${instanceId}: ${response.statusText}`);
1565
+ }
1356
1566
  }
1357
1567
  this.buffer = [];
1568
+ if (aggregatedData) {
1569
+ this.config.getRegistry().clearUsage();
1570
+ }
1358
1571
  } catch (error) {
1359
1572
  console.error("[IK_TRACKER] Failed to flush usage data:", error);
1360
1573
  }
@@ -1364,6 +1577,49 @@ var UsageTracker = class _UsageTracker {
1364
1577
  }
1365
1578
  };
1366
1579
 
1580
+ // src/CognitiveEngine.ts
1581
+ var CognitiveEngine = class {
1582
+ /**
1583
+ * Sniff Cognitive DNA (CQ Score: 0-100)
1584
+ * Higher score = higher quality, human-like, structured content.
1585
+ */
1586
+ static sniffDNA(input) {
1587
+ if (!input || input.trim().length === 0) return 0;
1588
+ const length = input.length;
1589
+ const words = input.split(/\s+/).filter((w) => w.length > 0);
1590
+ const wordCount = words.length;
1591
+ const sentences = input.split(/[.!?]+/).filter((s) => s.trim().length > 0);
1592
+ const avgSentenceLength = sentences.length > 0 ? wordCount / sentences.length : 0;
1593
+ const sentenceVariety = sentences.length > 1 ? 10 : 0;
1594
+ const uniqueWords = new Set(words.map((w) => w.toLowerCase())).size;
1595
+ const lexicalBreadth = wordCount > 0 ? uniqueWords / wordCount * 40 : 0;
1596
+ const markers = (input.match(/[,;:"'()\[\]]/g) || []).length;
1597
+ const structuralHealth = Math.min(markers / wordCount * 100, 20);
1598
+ const repetitivePenalty = this.calculateRepetitivePenalty(input);
1599
+ let score = lexicalBreadth + structuralHealth + sentenceVariety + (avgSentenceLength > 5 ? 20 : 0);
1600
+ score -= repetitivePenalty;
1601
+ return Math.max(0, Math.min(100, score));
1602
+ }
1603
+ /**
1604
+ * Calculate Crystallization Threshold
1605
+ * Logic:
1606
+ * Low CQ (Noise) -> Aggressive optimization (Lower threshold, e.g. 0.6)
1607
+ * High CQ (Quality) -> Conservative optimization (Higher threshold, e.g. 0.9)
1608
+ */
1609
+ static calculateThreshold(cqScore) {
1610
+ if (cqScore < 30) return 0.65;
1611
+ if (cqScore < 60) return 0.78;
1612
+ if (cqScore < 85) return 0.88;
1613
+ return 0.95;
1614
+ }
1615
+ static calculateRepetitivePenalty(input) {
1616
+ const chunks = input.match(/.{1,10}/g) || [];
1617
+ const uniqueChunks = new Set(chunks).size;
1618
+ const ratio = chunks.length > 10 ? uniqueChunks / chunks.length : 1;
1619
+ return ratio < 0.5 ? (1 - ratio) * 50 : 0;
1620
+ }
1621
+ };
1622
+
1367
1623
  // src/core.ts
1368
1624
  var IKFirewallCore = class _IKFirewallCore {
1369
1625
  static instance;
@@ -1418,55 +1674,75 @@ var IKFirewallCore = class _IKFirewallCore {
1418
1674
  FLUID_THRESHOLD: 4
1419
1675
  }
1420
1676
  };
1421
- gatekeeper = new HeuristicGatekeeper();
1677
+ gatekeeper;
1422
1678
  configManager;
1423
1679
  sessionDNA = 0;
1424
- hooks;
1425
1680
  cloudProvider;
1426
1681
  localProvider;
1427
1682
  orchestrator;
1428
1683
  usageTracker;
1684
+ _hooks;
1685
+ defaultConfig;
1429
1686
  constructor(config, hooks, cloudProvider) {
1430
- const defaultConfig = {
1687
+ this.defaultConfig = {
1431
1688
  aggressiveness: 0.15,
1432
1689
  forcedEfficiency: false,
1433
1690
  precisionBias: _IKFirewallCore.CONSTANTS.PRECISION.BIAS_DEFAULT,
1434
1691
  balance: _IKFirewallCore.CONSTANTS.TONE.STABLE_VAL,
1435
1692
  gatekeeperEnabled: true,
1436
1693
  locale: "en",
1437
- providerMode: "hybrid",
1694
+ providerMode: process.env.IK_FIREWALL_MODE || "hybrid",
1438
1695
  runtimeStrategy: "internal",
1439
- localAuditEndpoint: "http://127.0.0.1:8085/v1/chat/completions",
1440
- fallbackToCloudAudit: false,
1696
+ localAuditEndpoint: process.env.IK_FIREWALL_LOCAL_ENDPOINT || "http://127.0.0.1:8085/v1/chat/completions",
1697
+ centralReportEndpoint: process.env.IK_FIREWALL_CENTRAL_ENDPOINT || "https://ik-firewall.vercel.app/api/v1/sync",
1698
+ ownerEmail: process.env.IK_FIREWALL_EMAIL,
1699
+ hmacSecret: process.env.IK_FIREWALL_SECRET,
1700
+ fallbackToCloudAudit: process.env.IK_FIREWALL_FALLBACK === "true" || false,
1441
1701
  modelConfig: {
1442
1702
  modelType: "1b"
1443
1703
  },
1444
1704
  plugins: []
1445
1705
  };
1446
- this.configManager = new ConfigManager({ ...defaultConfig, ...config });
1447
- if (hooks) this.hooks = hooks;
1706
+ this._hooks = hooks;
1707
+ this.configManager = new ConfigManager({ ...this.defaultConfig, ...config }, hooks);
1708
+ this.gatekeeper = new HeuristicGatekeeper();
1709
+ this.sessionDNA = _IKFirewallCore.CONSTANTS.DNA.MIN;
1448
1710
  const activeConfig = this.configManager.getConfig();
1449
1711
  this.localProvider = new LocalProvider(activeConfig.localAuditEndpoint);
1450
1712
  if (cloudProvider) {
1451
- if (cloudProvider instanceof BaseProvider) {
1452
- this.cloudProvider = cloudProvider;
1453
- } else {
1454
- const mode = activeConfig.providerMode;
1455
- if (mode === "anthropic") {
1456
- this.cloudProvider = new AnthropicProvider(cloudProvider);
1457
- } else if (mode === "deepseek") {
1458
- this.cloudProvider = new DeepSeekProvider(cloudProvider);
1459
- } else if (mode === "gemini") {
1460
- this.cloudProvider = new GeminiProvider(cloudProvider);
1461
- } else if (mode === "perplexity") {
1462
- this.cloudProvider = new PerplexityProvider(cloudProvider);
1463
- } else {
1464
- this.cloudProvider = new OpenAIProvider(cloudProvider);
1465
- }
1466
- }
1713
+ this.cloudProvider = cloudProvider instanceof BaseProvider ? cloudProvider : new OpenAIProvider(cloudProvider);
1714
+ } else if (process.env.OPENAI_API_KEY) {
1715
+ this.cloudProvider = new OpenAIProvider(async (prompt, role) => {
1716
+ const response = await fetch("https://api.openai.com/v1/chat/completions", {
1717
+ method: "POST",
1718
+ headers: {
1719
+ "Authorization": `Bearer ${process.env.OPENAI_API_KEY}`,
1720
+ "Content-Type": "application/json"
1721
+ },
1722
+ body: JSON.stringify({
1723
+ model: role === "audit_layer" ? "gpt-4o-mini" : "gpt-4o",
1724
+ messages: [{ role: "user", content: prompt }],
1725
+ temperature: 0.1
1726
+ })
1727
+ });
1728
+ if (!response.ok) throw new Error(`OpenAI API Error: ${response.statusText}`);
1729
+ const data = await response.json();
1730
+ return {
1731
+ content: data.choices[0].message.content,
1732
+ usage: data.usage
1733
+ };
1734
+ });
1467
1735
  }
1468
1736
  this.orchestrator = new Orchestrator(this.configManager);
1469
- this.usageTracker = new UsageTracker(this.configManager, this.hooks);
1737
+ this.usageTracker = new UsageTracker(this.configManager, this._hooks);
1738
+ }
1739
+ get hooks() {
1740
+ return this._hooks;
1741
+ }
1742
+ set hooks(newHooks) {
1743
+ this._hooks = newHooks;
1744
+ this.configManager.setHooks(newHooks);
1745
+ this.usageTracker.hooks = newHooks;
1470
1746
  }
1471
1747
  static getInstance(config, hooks) {
1472
1748
  if (!_IKFirewallCore.instance) {
@@ -1578,6 +1854,21 @@ var IKFirewallCore = class _IKFirewallCore {
1578
1854
  async analyze(input, provider, personaName = "professional", locale, instanceId) {
1579
1855
  if (instanceId) {
1580
1856
  this.configManager.ensureInstanceConfig(instanceId);
1857
+ const syncPromise = this.configManager.syncRemoteConfig(instanceId).then(async () => {
1858
+ const pendingUsage = this.configManager._pendingUsage;
1859
+ if (pendingUsage && pendingUsage.length > 0) {
1860
+ await this.usageTracker.flush(pendingUsage);
1861
+ this.configManager._pendingUsage = null;
1862
+ }
1863
+ });
1864
+ await syncPromise;
1865
+ }
1866
+ const mergedConfig = this.configManager.getMergedConfig(instanceId);
1867
+ if (instanceId && mergedConfig?.isVerified === false) {
1868
+ if (mergedConfig?.billingStatus === "blocked") {
1869
+ this.hooks?.onStatus?.("\u26A0\uFE0F [IK_FIREWALL] Subscription inactive. Optimization bypassed (Fail-Safe mode).");
1870
+ return this.getEmptyMetrics();
1871
+ }
1581
1872
  }
1582
1873
  let auditProvider = this.localProvider;
1583
1874
  let overrideProvider = null;
@@ -1612,18 +1903,20 @@ var IKFirewallCore = class _IKFirewallCore {
1612
1903
  const ei = (input.match(/[,;.:-]/g) || []).length / (input.split(" ").length || 1);
1613
1904
  let requiresAuditOverride = false;
1614
1905
  let boundaryMetrics = { boundaryScore: 0, requiresHumanIntervention: false };
1615
- if (this.getConfig().safeMode) {
1616
- boundaryMetrics = this.gatekeeper.evaluateBoundaryCommunication(input, this.getConfig().customBoundaryKeywords);
1617
- if (boundaryMetrics.requiresHumanIntervention) {
1906
+ if (this.getConfig()?.safeMode) {
1907
+ boundaryMetrics = this.gatekeeper.evaluateBoundaryCommunication(input, this.getConfig()?.customBoundaryKeywords);
1908
+ if (boundaryMetrics?.requiresHumanIntervention) {
1618
1909
  requiresAuditOverride = true;
1619
1910
  }
1620
1911
  }
1621
1912
  const skipAudit = !requiresAuditOverride && this.getConfig().gatekeeperEnabled && localInsight.complexityScore < _IKFirewallCore.CONSTANTS.HEURISTICS.COMPLEXITY_SKIP_THRESHOLD;
1622
1913
  if (skipAudit) {
1623
1914
  this.hooks?.onStatus?.("\u26A1 IK_GATEKEEPER: Simple request detected. Skipping Deep Audit.");
1624
- const metrics2 = this.createHeuristicMetrics(input, dm, ei, uniqueWords, localInsight.intentMode);
1625
- metrics2.semanticInsights.boundaryScore = boundaryMetrics.boundaryScore;
1626
- metrics2.semanticInsights.requiresHumanIntervention = boundaryMetrics.requiresHumanIntervention;
1915
+ const metrics2 = this.createHeuristicMetrics(input, dm, ei, uniqueWords, localInsight?.intentMode);
1916
+ if (metrics2.semanticInsights) {
1917
+ metrics2.semanticInsights.boundaryScore = boundaryMetrics.boundaryScore;
1918
+ metrics2.semanticInsights.requiresHumanIntervention = boundaryMetrics.requiresHumanIntervention;
1919
+ }
1627
1920
  this.hooks?.onAuditComplete?.(metrics2);
1628
1921
  return metrics2;
1629
1922
  }
@@ -1638,10 +1931,17 @@ var IKFirewallCore = class _IKFirewallCore {
1638
1931
  throw e;
1639
1932
  }
1640
1933
  }
1641
- this.sniffDNA(input, metrics, activeLocale);
1934
+ const cqScore = CognitiveEngine.sniffDNA(input);
1935
+ metrics.dm = Math.max(metrics.dm, cqScore / 10);
1936
+ this.applyHardening(input, metrics, activeLocale);
1642
1937
  this.hooks?.onAuditComplete?.(metrics);
1643
1938
  return metrics;
1644
1939
  }
1940
+ applyHardening(input, metrics, locale = "en") {
1941
+ const archetype = metrics.semanticInsights?.archetype || "DYNAMIC";
1942
+ const domain = metrics.semanticInsights?.detectedDomain || "GENERAL";
1943
+ this.setSessionDNA(this.sessionDNA + 5);
1944
+ }
1645
1945
  getEmptyMetrics() {
1646
1946
  return {
1647
1947
  dm: 0,
@@ -1693,39 +1993,17 @@ var IKFirewallCore = class _IKFirewallCore {
1693
1993
  inputLength: input.length
1694
1994
  };
1695
1995
  }
1696
- sniffDNA(input, metrics, locale = "en") {
1697
- const archetype = metrics.semanticInsights?.archetype || "DYNAMIC";
1698
- const domain = metrics.semanticInsights?.detectedDomain || "GENERAL";
1699
- const meta = Dictionaries.meta[locale] || Dictionaries.meta.en;
1700
- const patterns = (meta.system_prompt_patterns || "").split(",").map((p) => p.trim()).filter((p) => p.length > 0);
1701
- const isSystemPrompt = patterns.some((kw) => input.toLowerCase().includes(kw));
1702
- let dnaShift = 0;
1703
- if (archetype === "CRYSTAL") {
1704
- dnaShift += _IKFirewallCore.CONSTANTS.DNA.HARDENING_MODERATE;
1705
- } else if (archetype === "FLUID") {
1706
- dnaShift -= _IKFirewallCore.CONSTANTS.DNA.SOFTENING_STEP;
1707
- } else if (archetype === "NEURAL") {
1708
- dnaShift -= _IKFirewallCore.CONSTANTS.DNA.SOFTENING_STEP / 2;
1709
- }
1710
- if (["LEGAL", "MEDICAL", "FINANCE", "CONSTRUCTION", "ENGINEERING"].includes(domain)) {
1711
- dnaShift += _IKFirewallCore.CONSTANTS.DNA.HARDENING_DOMAIN;
1712
- }
1713
- if (isSystemPrompt) {
1714
- dnaShift += _IKFirewallCore.CONSTANTS.DNA.HARDENING_MODERATE;
1715
- }
1716
- this.setSessionDNA(this.sessionDNA + dnaShift);
1717
- }
1718
1996
  async analyzeAIAssisted(input, provider, personaName = "professional", instanceId, configOverride) {
1719
1997
  if (instanceId) {
1720
1998
  this.configManager.ensureInstanceConfig(instanceId);
1721
1999
  }
1722
2000
  const activeConfig = this.configManager.getMergedConfig(instanceId, configOverride);
1723
- const locale = activeConfig.locale || "en";
2001
+ const locale = activeConfig?.locale || "en";
1724
2002
  const cqScore = this.orchestrator.calculateCQ(input);
1725
2003
  let isAuditTask = false;
1726
- if (activeConfig.safeMode) {
1727
- const boundaryResult = this.gatekeeper.evaluateBoundaryCommunication(input, activeConfig.customBoundaryKeywords);
1728
- if (boundaryResult.requiresHumanIntervention) {
2004
+ if (activeConfig?.safeMode) {
2005
+ const boundaryResult = this.gatekeeper.evaluateBoundaryCommunication(input, activeConfig?.customBoundaryKeywords);
2006
+ if (boundaryResult?.requiresHumanIntervention) {
1729
2007
  isAuditTask = true;
1730
2008
  }
1731
2009
  }
@@ -1947,7 +2225,11 @@ Any action outside this scope MUST be rejected and flagged as a boundary violati
1947
2225
  inputLength
1948
2226
  };
1949
2227
  }
1950
- crystallize(input, metrics, locale = "en") {
2228
+ crystallize(input, metrics, locale = "en", instanceId) {
2229
+ const mergedConfig = this.configManager.getMergedConfig(instanceId);
2230
+ if (instanceId && mergedConfig?.isVerified === false) {
2231
+ return input;
2232
+ }
1951
2233
  const archetype = metrics?.semanticInsights?.archetype || "DYNAMIC";
1952
2234
  const tolerance = metrics?.semanticInsights?.ambiguityTolerance || 0.5;
1953
2235
  const blueprint = metrics?.semanticInsights?.conceptualBlueprint;
@@ -1961,11 +2243,13 @@ Any action outside this scope MUST be rejected and flagged as a boundary violati
1961
2243
  this.hooks?.onStatus?.(`\u{1F6E1}\uFE0F IK_CRYSTALLIZE: Precision domain detected (${domain}). Relaxing noise reduction...`);
1962
2244
  archetypeModifier = -0.3;
1963
2245
  }
2246
+ const cqScore = CognitiveEngine.sniffDNA(input);
2247
+ const cognitiveThreshold = CognitiveEngine.calculateThreshold(cqScore);
1964
2248
  const threshold = Math.min(
1965
2249
  _IKFirewallCore.CONSTANTS.AI.THRESHOLD_MAX,
1966
2250
  Math.max(
1967
2251
  _IKFirewallCore.CONSTANTS.AI.THRESHOLD_MIN,
1968
- dm / _IKFirewallCore.CONSTANTS.AI.DM_THRESHOLD_DIVISOR + basePreference - aggModifier + archetypeModifier - tolerance * 0.1
2252
+ cognitiveThreshold + archetypeModifier - tolerance * 0.1
1969
2253
  )
1970
2254
  );
1971
2255
  const lengthRatio = blueprint ? blueprint.length / input.length : 1;