@ik-firewall/core 2.2.0 → 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 = {
@@ -176,32 +255,60 @@ var ConfigManager = class {
176
255
  }
177
256
  }
178
257
  try {
179
- const endpoint = this.config.centralReportEndpoint || "https://ik-firewall-backend.vercel.app/api/v1/sync";
180
- const data = {
181
- billingStatus: "trial",
182
- isVerified: true,
183
- pricing: {
184
- "gpt-4o": { input: 5e-3, output: 0.015 },
185
- "gpt-4o-mini": { input: 15e-5, output: 6e-4 }
186
- },
187
- latestVersion: "2.2.0"
188
- };
189
- this.setInstanceConfig(instanceId, {
190
- billingStatus: data.billingStatus,
191
- isVerified: data.isVerified,
192
- pricing: data.pricing,
193
- lastSyncDate: now.toISOString()
194
- });
195
- if (!instanceConfig?.firstUseDate) {
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) {
196
292
  this.setInstanceConfig(instanceId, { firstUseDate: now.toISOString() });
197
293
  }
198
294
  } catch (error) {
199
- console.error("[IK_CONFIG] Remote sync failed. Falling open (Fail-Open mode).");
295
+ console.error(`[IK_CONFIG] Remote sync failed (${error.message}). Falling open (Fail-Open mode).`);
200
296
  this.setInstanceConfig(instanceId, {
201
297
  isVerified: true,
202
298
  lastSyncDate: now.toISOString()
203
299
  });
204
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
+ }
205
312
  }
206
313
  getConfig() {
207
314
  return { ...this.config };
@@ -242,6 +349,40 @@ var ConfigManager = class {
242
349
  }
243
350
  this.updateConfig({ plugins });
244
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
+ }
245
386
  ensureInstanceConfig(instanceId) {
246
387
  const all = this.registry.load();
247
388
  if (!all[instanceId]) {
@@ -249,7 +390,9 @@ var ConfigManager = class {
249
390
  balance: this.config.balance || 0.5,
250
391
  aggressiveness: this.config.aggressiveness || 0.5,
251
392
  isEnabled: true,
252
- contextMode: "FIRST_MESSAGE"
393
+ contextMode: "FIRST_MESSAGE",
394
+ ownerEmail: this.config.ownerEmail
395
+ // Inherit from global if not specific
253
396
  });
254
397
  this.loadFromRegistry();
255
398
  }
@@ -1328,12 +1471,6 @@ var UsageTracker = class {
1328
1471
  // Immediate reporting for Edge/Stateless environments
1329
1472
  hooks;
1330
1473
  config;
1331
- // Static pricing benchmarks (cost per 1k tokens in USD)
1332
- static PRICING = {
1333
- "gpt-4o": { input: 5e-3, output: 0.015 },
1334
- "gpt-4o-mini": { input: 15e-5, output: 6e-4 },
1335
- "local": { input: 0, output: 0 }
1336
- };
1337
1474
  constructor(config, hooks) {
1338
1475
  this.config = config;
1339
1476
  this.hooks = hooks;
@@ -1366,42 +1503,71 @@ var UsageTracker = class {
1366
1503
  };
1367
1504
  this.buffer.push(data);
1368
1505
  this.hooks?.onUsageReported?.(data);
1369
- if (this.buffer.length >= this.MAX_BUFFER_SIZE) {
1370
- 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);
1371
1523
  }
1372
1524
  }
1373
1525
  /**
1374
1526
  * Send buffered usage data to the central IK billing service
1375
1527
  */
1376
- async flush() {
1377
- if (this.buffer.length === 0) return;
1378
- const endpoint = this.config.get("centralReportEndpoint");
1379
- if (!endpoint) {
1380
- this.buffer = [];
1381
- return;
1382
- }
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");
1383
1533
  try {
1384
- for (const report of this.buffer) {
1385
- 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, {
1386
1559
  method: "POST",
1387
1560
  headers: { "Content-Type": "application/json" },
1388
- body: JSON.stringify({
1389
- instanceId: report.instanceId,
1390
- model: report.model_used,
1391
- inputTokens: report.input_tokens,
1392
- outputTokens: report.output_tokens,
1393
- optimizedTokens: report.optimized_tokens,
1394
- tokensSaved: report.tokens_saved,
1395
- costSaved: report.cost_saved,
1396
- commissionDue: report.commission_due,
1397
- cqScore: report.cq_score,
1398
- routingPath: report.routingPath,
1399
- clientOrigin: report.clientOrigin,
1400
- timestamp: report.timestamp
1401
- })
1561
+ body: JSON.stringify(payload)
1402
1562
  });
1563
+ if (!response.ok) {
1564
+ console.error(`[IK_TRACKER] Failed to send aggregate for ${instanceId}: ${response.statusText}`);
1565
+ }
1403
1566
  }
1404
1567
  this.buffer = [];
1568
+ if (aggregatedData) {
1569
+ this.config.getRegistry().clearUsage();
1570
+ }
1405
1571
  } catch (error) {
1406
1572
  console.error("[IK_TRACKER] Failed to flush usage data:", error);
1407
1573
  }
@@ -1411,6 +1577,49 @@ var UsageTracker = class {
1411
1577
  }
1412
1578
  };
1413
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
+
1414
1623
  // src/core.ts
1415
1624
  var IKFirewallCore = class _IKFirewallCore {
1416
1625
  static instance;
@@ -1465,55 +1674,75 @@ var IKFirewallCore = class _IKFirewallCore {
1465
1674
  FLUID_THRESHOLD: 4
1466
1675
  }
1467
1676
  };
1468
- gatekeeper = new HeuristicGatekeeper();
1677
+ gatekeeper;
1469
1678
  configManager;
1470
1679
  sessionDNA = 0;
1471
- hooks;
1472
1680
  cloudProvider;
1473
1681
  localProvider;
1474
1682
  orchestrator;
1475
1683
  usageTracker;
1684
+ _hooks;
1685
+ defaultConfig;
1476
1686
  constructor(config, hooks, cloudProvider) {
1477
- const defaultConfig = {
1687
+ this.defaultConfig = {
1478
1688
  aggressiveness: 0.15,
1479
1689
  forcedEfficiency: false,
1480
1690
  precisionBias: _IKFirewallCore.CONSTANTS.PRECISION.BIAS_DEFAULT,
1481
1691
  balance: _IKFirewallCore.CONSTANTS.TONE.STABLE_VAL,
1482
1692
  gatekeeperEnabled: true,
1483
1693
  locale: "en",
1484
- providerMode: "hybrid",
1694
+ providerMode: process.env.IK_FIREWALL_MODE || "hybrid",
1485
1695
  runtimeStrategy: "internal",
1486
- localAuditEndpoint: "http://127.0.0.1:8085/v1/chat/completions",
1487
- 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,
1488
1701
  modelConfig: {
1489
1702
  modelType: "1b"
1490
1703
  },
1491
1704
  plugins: []
1492
1705
  };
1493
- this.configManager = new ConfigManager({ ...defaultConfig, ...config });
1494
- 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;
1495
1710
  const activeConfig = this.configManager.getConfig();
1496
1711
  this.localProvider = new LocalProvider(activeConfig.localAuditEndpoint);
1497
1712
  if (cloudProvider) {
1498
- if (cloudProvider instanceof BaseProvider) {
1499
- this.cloudProvider = cloudProvider;
1500
- } else {
1501
- const mode = activeConfig.providerMode;
1502
- if (mode === "anthropic") {
1503
- this.cloudProvider = new AnthropicProvider(cloudProvider);
1504
- } else if (mode === "deepseek") {
1505
- this.cloudProvider = new DeepSeekProvider(cloudProvider);
1506
- } else if (mode === "gemini") {
1507
- this.cloudProvider = new GeminiProvider(cloudProvider);
1508
- } else if (mode === "perplexity") {
1509
- this.cloudProvider = new PerplexityProvider(cloudProvider);
1510
- } else {
1511
- this.cloudProvider = new OpenAIProvider(cloudProvider);
1512
- }
1513
- }
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
+ });
1514
1735
  }
1515
1736
  this.orchestrator = new Orchestrator(this.configManager);
1516
- 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;
1517
1746
  }
1518
1747
  static getInstance(config, hooks) {
1519
1748
  if (!_IKFirewallCore.instance) {
@@ -1625,7 +1854,14 @@ var IKFirewallCore = class _IKFirewallCore {
1625
1854
  async analyze(input, provider, personaName = "professional", locale, instanceId) {
1626
1855
  if (instanceId) {
1627
1856
  this.configManager.ensureInstanceConfig(instanceId);
1628
- await this.configManager.syncRemoteConfig(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;
1629
1865
  }
1630
1866
  const mergedConfig = this.configManager.getMergedConfig(instanceId);
1631
1867
  if (instanceId && mergedConfig?.isVerified === false) {
@@ -1695,10 +1931,17 @@ var IKFirewallCore = class _IKFirewallCore {
1695
1931
  throw e;
1696
1932
  }
1697
1933
  }
1698
- 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);
1699
1937
  this.hooks?.onAuditComplete?.(metrics);
1700
1938
  return metrics;
1701
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
+ }
1702
1945
  getEmptyMetrics() {
1703
1946
  return {
1704
1947
  dm: 0,
@@ -1750,28 +1993,6 @@ var IKFirewallCore = class _IKFirewallCore {
1750
1993
  inputLength: input.length
1751
1994
  };
1752
1995
  }
1753
- sniffDNA(input, metrics, locale = "en") {
1754
- const archetype = metrics.semanticInsights?.archetype || "DYNAMIC";
1755
- const domain = metrics.semanticInsights?.detectedDomain || "GENERAL";
1756
- const meta = Dictionaries.meta[locale] || Dictionaries.meta.en;
1757
- const patterns = (meta.system_prompt_patterns || "").split(",").map((p) => p.trim()).filter((p) => p.length > 0);
1758
- const isSystemPrompt = patterns.some((kw) => input.toLowerCase().includes(kw));
1759
- let dnaShift = 0;
1760
- if (archetype === "CRYSTAL") {
1761
- dnaShift += _IKFirewallCore.CONSTANTS.DNA.HARDENING_MODERATE;
1762
- } else if (archetype === "FLUID") {
1763
- dnaShift -= _IKFirewallCore.CONSTANTS.DNA.SOFTENING_STEP;
1764
- } else if (archetype === "NEURAL") {
1765
- dnaShift -= _IKFirewallCore.CONSTANTS.DNA.SOFTENING_STEP / 2;
1766
- }
1767
- if (["LEGAL", "MEDICAL", "FINANCE", "CONSTRUCTION", "ENGINEERING"].includes(domain)) {
1768
- dnaShift += _IKFirewallCore.CONSTANTS.DNA.HARDENING_DOMAIN;
1769
- }
1770
- if (isSystemPrompt) {
1771
- dnaShift += _IKFirewallCore.CONSTANTS.DNA.HARDENING_MODERATE;
1772
- }
1773
- this.setSessionDNA(this.sessionDNA + dnaShift);
1774
- }
1775
1996
  async analyzeAIAssisted(input, provider, personaName = "professional", instanceId, configOverride) {
1776
1997
  if (instanceId) {
1777
1998
  this.configManager.ensureInstanceConfig(instanceId);
@@ -2022,11 +2243,13 @@ Any action outside this scope MUST be rejected and flagged as a boundary violati
2022
2243
  this.hooks?.onStatus?.(`\u{1F6E1}\uFE0F IK_CRYSTALLIZE: Precision domain detected (${domain}). Relaxing noise reduction...`);
2023
2244
  archetypeModifier = -0.3;
2024
2245
  }
2246
+ const cqScore = CognitiveEngine.sniffDNA(input);
2247
+ const cognitiveThreshold = CognitiveEngine.calculateThreshold(cqScore);
2025
2248
  const threshold = Math.min(
2026
2249
  _IKFirewallCore.CONSTANTS.AI.THRESHOLD_MAX,
2027
2250
  Math.max(
2028
2251
  _IKFirewallCore.CONSTANTS.AI.THRESHOLD_MIN,
2029
- dm / _IKFirewallCore.CONSTANTS.AI.DM_THRESHOLD_DIVISOR + basePreference - aggModifier + archetypeModifier - tolerance * 0.1
2252
+ cognitiveThreshold + archetypeModifier - tolerance * 0.1
2030
2253
  )
2031
2254
  );
2032
2255
  const lengthRatio = blueprint ? blueprint.length / input.length : 1;
package/dist/index.d.cts CHANGED
@@ -48,6 +48,8 @@ interface IKConfig {
48
48
  isVerified?: boolean;
49
49
  firstUseDate?: string;
50
50
  lastSyncDate?: string;
51
+ ownerEmail?: string;
52
+ hmacSecret?: string;
51
53
  pricing?: Record<string, {
52
54
  input: number;
53
55
  output: number;
@@ -304,12 +306,15 @@ declare class IKFirewallCore {
304
306
  private gatekeeper;
305
307
  private configManager;
306
308
  private sessionDNA;
307
- hooks?: IKHooks;
308
309
  private cloudProvider?;
309
310
  private localProvider;
310
311
  private orchestrator;
311
312
  private usageTracker;
313
+ private _hooks?;
314
+ private defaultConfig;
312
315
  constructor(config?: Partial<IKConfig>, hooks?: IKHooks, cloudProvider?: AIProvider | BaseProvider);
316
+ get hooks(): IKHooks | undefined;
317
+ set hooks(newHooks: IKHooks | undefined);
313
318
  static getInstance(config?: Partial<IKConfig>, hooks?: IKHooks): IKFirewallCore;
314
319
  setConfig(newConfig: Partial<IKConfig>): void;
315
320
  getConfig(): IKConfig;
@@ -355,9 +360,9 @@ declare class IKFirewallCore {
355
360
  * Primary Analysis Entry Point
356
361
  */
357
362
  analyze(input: string, provider?: AIProvider | BaseProvider, personaName?: string, locale?: string, instanceId?: string): Promise<IKMetrics>;
363
+ private applyHardening;
358
364
  private getEmptyMetrics;
359
365
  private createHeuristicMetrics;
360
- private sniffDNA;
361
366
  analyzeAIAssisted(input: string, provider?: AIProvider | BaseProvider, personaName?: string, instanceId?: string, configOverride?: Partial<IKConfig>): Promise<IKMetrics>;
362
367
  private calculateDNARank;
363
368
  private constructAuditPrompt;
package/dist/index.d.ts CHANGED
@@ -48,6 +48,8 @@ interface IKConfig {
48
48
  isVerified?: boolean;
49
49
  firstUseDate?: string;
50
50
  lastSyncDate?: string;
51
+ ownerEmail?: string;
52
+ hmacSecret?: string;
51
53
  pricing?: Record<string, {
52
54
  input: number;
53
55
  output: number;
@@ -304,12 +306,15 @@ declare class IKFirewallCore {
304
306
  private gatekeeper;
305
307
  private configManager;
306
308
  private sessionDNA;
307
- hooks?: IKHooks;
308
309
  private cloudProvider?;
309
310
  private localProvider;
310
311
  private orchestrator;
311
312
  private usageTracker;
313
+ private _hooks?;
314
+ private defaultConfig;
312
315
  constructor(config?: Partial<IKConfig>, hooks?: IKHooks, cloudProvider?: AIProvider | BaseProvider);
316
+ get hooks(): IKHooks | undefined;
317
+ set hooks(newHooks: IKHooks | undefined);
313
318
  static getInstance(config?: Partial<IKConfig>, hooks?: IKHooks): IKFirewallCore;
314
319
  setConfig(newConfig: Partial<IKConfig>): void;
315
320
  getConfig(): IKConfig;
@@ -355,9 +360,9 @@ declare class IKFirewallCore {
355
360
  * Primary Analysis Entry Point
356
361
  */
357
362
  analyze(input: string, provider?: AIProvider | BaseProvider, personaName?: string, locale?: string, instanceId?: string): Promise<IKMetrics>;
363
+ private applyHardening;
358
364
  private getEmptyMetrics;
359
365
  private createHeuristicMetrics;
360
- private sniffDNA;
361
366
  analyzeAIAssisted(input: string, provider?: AIProvider | BaseProvider, personaName?: string, instanceId?: string, configOverride?: Partial<IKConfig>): Promise<IKMetrics>;
362
367
  private calculateDNARank;
363
368
  private constructAuditPrompt;
package/dist/index.js CHANGED
@@ -16,15 +16,18 @@ if (typeof window === "undefined") {
16
16
  var Registry = class _Registry {
17
17
  static instance;
18
18
  registryPath;
19
+ usagePath;
19
20
  hasWarnedNoFs = false;
20
21
  hasWarnedSaveError = false;
21
22
  constructor() {
22
23
  this.registryPath = "";
24
+ this.usagePath = "";
23
25
  if (typeof process !== "undefined" && process.versions && process.versions.node) {
24
26
  try {
25
27
  fs = __require("fs");
26
28
  path = __require("path");
27
29
  this.registryPath = path.join(process.cwd(), ".ik-adapter", "registry.json");
30
+ this.usagePath = path.join(process.cwd(), ".ik-adapter", "usage.json");
28
31
  this.ensureDirectory();
29
32
  } catch (e) {
30
33
  if (!this.hasWarnedNoFs) {
@@ -59,8 +62,13 @@ var Registry = class _Registry {
59
62
  if (!fs || !this.registryPath) return {};
60
63
  try {
61
64
  if (fs.existsSync(this.registryPath)) {
62
- const data = fs.readFileSync(this.registryPath, "utf8");
63
- return JSON.parse(data);
65
+ const rawData = fs.readFileSync(this.registryPath, "utf8");
66
+ try {
67
+ const decoded = Buffer.from(rawData, "base64").toString("utf8");
68
+ return JSON.parse(decoded);
69
+ } catch (e) {
70
+ return JSON.parse(rawData);
71
+ }
64
72
  }
65
73
  } catch (error) {
66
74
  console.error("[IK_REGISTRY] Load error:", error);
@@ -80,7 +88,9 @@ var Registry = class _Registry {
80
88
  }
81
89
  try {
82
90
  this.ensureDirectory();
83
- fs.writeFileSync(this.registryPath, JSON.stringify(data, null, 2), "utf8");
91
+ const jsonStr = JSON.stringify(data, null, 2);
92
+ const obfuscated = Buffer.from(jsonStr).toString("base64");
93
+ fs.writeFileSync(this.registryPath, obfuscated, "utf8");
84
94
  } catch (error) {
85
95
  if (!this.hasWarnedSaveError) {
86
96
  console.error("\n[IK_REGISTRY] \u{1F6A8} ERROR saving registry.json. Your environment likely has a read-only filesystem (e.g. Vercel Serverless).");
@@ -111,17 +121,76 @@ var Registry = class _Registry {
111
121
  delete all[instanceId];
112
122
  this.save(all);
113
123
  }
124
+ getUsageFilePath() {
125
+ return this.usagePath;
126
+ }
127
+ exists(filePath) {
128
+ return fs && fs.existsSync(filePath);
129
+ }
130
+ loadUsage() {
131
+ if (!fs || !this.usagePath || !fs.existsSync(this.usagePath)) return [];
132
+ try {
133
+ const raw = fs.readFileSync(this.usagePath, "utf8");
134
+ return JSON.parse(raw);
135
+ } catch (e) {
136
+ return [];
137
+ }
138
+ }
139
+ saveUsage(data) {
140
+ if (!fs || !this.usagePath) return;
141
+ try {
142
+ fs.writeFileSync(this.usagePath, JSON.stringify(data, null, 2), "utf8");
143
+ } catch (e) {
144
+ console.error("[IK_REGISTRY] Failed to save usage:", e);
145
+ }
146
+ }
147
+ clearUsage() {
148
+ if (!fs || !this.usagePath) return;
149
+ try {
150
+ if (fs.existsSync(this.usagePath)) {
151
+ fs.unlinkSync(this.usagePath);
152
+ }
153
+ } catch (e) {
154
+ }
155
+ }
156
+ };
157
+
158
+ // src/lib/hmac.ts
159
+ import crypto from "crypto";
160
+ var IKHmac = class {
161
+ secret;
162
+ constructor(secret) {
163
+ this.secret = secret;
164
+ }
165
+ /**
166
+ * Verifies that a response from the IK-Firewall server is authentic.
167
+ */
168
+ verify(data) {
169
+ if (!data || !data.signature) return false;
170
+ const { signature, ...rest } = data;
171
+ const payload = JSON.stringify(rest);
172
+ const expectedSignature = crypto.createHmac("sha256", this.secret).update(payload).digest("hex");
173
+ return signature === expectedSignature;
174
+ }
114
175
  };
115
176
 
116
177
  // src/ConfigManager.ts
117
178
  var ConfigManager = class {
118
179
  config;
119
180
  registry;
120
- constructor(initialConfig) {
181
+ hooks;
182
+ constructor(initialConfig, hooks) {
121
183
  this.config = initialConfig;
184
+ this.hooks = hooks;
122
185
  this.registry = Registry.getInstance();
123
186
  this.loadFromRegistry();
124
187
  }
188
+ getRegistry() {
189
+ return this.registry;
190
+ }
191
+ setHooks(hooks) {
192
+ this.hooks = hooks;
193
+ }
125
194
  loadFromRegistry() {
126
195
  const instanceConfigs = this.registry.load();
127
196
  this.config.instanceConfigs = {
@@ -144,32 +213,60 @@ var ConfigManager = class {
144
213
  }
145
214
  }
146
215
  try {
147
- const endpoint = this.config.centralReportEndpoint || "https://ik-firewall-backend.vercel.app/api/v1/sync";
148
- const data = {
149
- billingStatus: "trial",
150
- isVerified: true,
151
- pricing: {
152
- "gpt-4o": { input: 5e-3, output: 0.015 },
153
- "gpt-4o-mini": { input: 15e-5, output: 6e-4 }
154
- },
155
- latestVersion: "2.2.0"
156
- };
157
- this.setInstanceConfig(instanceId, {
158
- billingStatus: data.billingStatus,
159
- isVerified: data.isVerified,
160
- pricing: data.pricing,
161
- lastSyncDate: now.toISOString()
162
- });
163
- if (!instanceConfig?.firstUseDate) {
216
+ const endpoint = this.config.centralReportEndpoint || "https://ik-firewall.vercel.app/api/v1/sync";
217
+ const instanceConfig2 = this.config.instanceConfigs?.[instanceId];
218
+ const registrationEmail = instanceConfig2?.ownerEmail || this.config.ownerEmail;
219
+ if ((!instanceConfig2?.licenseKey || instanceConfig2.licenseKey.startsWith("TRIAL-")) && registrationEmail) {
220
+ const success = await this.registerInstance(instanceId, registrationEmail);
221
+ if (success) {
222
+ this.hooks?.onStatus?.("\u2728 IK_SYNC: Zero-Config registration successful. License issued.");
223
+ return;
224
+ } else {
225
+ this.hooks?.onStatus?.("\u26A0\uFE0F IK_SYNC: Auto-registration failed. Continuing with local trial.");
226
+ }
227
+ }
228
+ this.hooks?.onStatus?.(`\u{1F4E1} IK_SYNC: Heartbeat to ${endpoint}...`);
229
+ const response = await fetch(`${endpoint}?licenseKey=${instanceConfig2?.licenseKey || ""}&instanceId=${instanceId}&version=2.2.0`);
230
+ if (response.ok) {
231
+ const data = await response.json();
232
+ if (this.config.hmacSecret) {
233
+ const verifier = new IKHmac(this.config.hmacSecret);
234
+ if (!verifier.verify(data)) {
235
+ console.error("[IK_SYNC] \u{1F6A8} Signature verification failed! Remote config rejected.");
236
+ return;
237
+ }
238
+ }
239
+ this.setInstanceConfig(instanceId, {
240
+ billingStatus: data.billingStatus,
241
+ isVerified: data.isVerified,
242
+ pricing: data.pricing,
243
+ lastSyncDate: now.toISOString()
244
+ });
245
+ this.hooks?.onStatus?.("\u2705 IK_SYNC: Remote configuration updated and verified.");
246
+ } else {
247
+ throw new Error(`Server responded with ${response.status}`);
248
+ }
249
+ if (!instanceConfig2?.firstUseDate) {
164
250
  this.setInstanceConfig(instanceId, { firstUseDate: now.toISOString() });
165
251
  }
166
252
  } catch (error) {
167
- console.error("[IK_CONFIG] Remote sync failed. Falling open (Fail-Open mode).");
253
+ console.error(`[IK_CONFIG] Remote sync failed (${error.message}). Falling open (Fail-Open mode).`);
168
254
  this.setInstanceConfig(instanceId, {
169
255
  isVerified: true,
170
256
  lastSyncDate: now.toISOString()
171
257
  });
172
258
  }
259
+ try {
260
+ const registry = this.registry;
261
+ if (registry.exists(registry.getUsageFilePath())) {
262
+ const aggregatedUsage = registry.loadUsage();
263
+ if (aggregatedUsage.length > 0) {
264
+ this.hooks?.onStatus?.(`\u{1F4CA} IK_SYNC: Found ${aggregatedUsage.length} pending usage reports. Preparation for Daily Flush...`);
265
+ this._pendingUsage = aggregatedUsage;
266
+ }
267
+ }
268
+ } catch (e) {
269
+ }
173
270
  }
174
271
  getConfig() {
175
272
  return { ...this.config };
@@ -210,6 +307,40 @@ var ConfigManager = class {
210
307
  }
211
308
  this.updateConfig({ plugins });
212
309
  }
310
+ async registerInstance(instanceId, email) {
311
+ try {
312
+ const endpoint = (this.config.centralReportEndpoint || "https://ik-firewall.vercel.app/api/v1").replace(/\/sync$/, "") + "/register";
313
+ this.hooks?.onStatus?.(`\u{1F680} IK_REGISTRY: Registering new instance for ${email}...`);
314
+ const response = await fetch(endpoint, {
315
+ method: "POST",
316
+ headers: { "Content-Type": "application/json" },
317
+ body: JSON.stringify({ email, instanceId })
318
+ });
319
+ if (response.ok) {
320
+ const data = await response.json();
321
+ if (this.config.hmacSecret) {
322
+ const verifier = new IKHmac(this.config.hmacSecret);
323
+ if (!verifier.verify(data)) {
324
+ console.error("[IK_REGISTRY] \u{1F6A8} Registration signature mismatch. Data rejected!");
325
+ return false;
326
+ }
327
+ }
328
+ this.setInstanceConfig(instanceId, {
329
+ licenseKey: data.licenseKey,
330
+ billingStatus: data.status.toLowerCase(),
331
+ isVerified: true,
332
+ firstUseDate: (/* @__PURE__ */ new Date()).toISOString(),
333
+ pricing: data.pricing
334
+ });
335
+ this.hooks?.onStatus?.("\u2728 IK_REGISTRY: Instance registered successfully and license issued.");
336
+ return true;
337
+ }
338
+ return false;
339
+ } catch (error) {
340
+ console.error("[IK_REGISTRY] Registration failed:", error);
341
+ return false;
342
+ }
343
+ }
213
344
  ensureInstanceConfig(instanceId) {
214
345
  const all = this.registry.load();
215
346
  if (!all[instanceId]) {
@@ -217,7 +348,9 @@ var ConfigManager = class {
217
348
  balance: this.config.balance || 0.5,
218
349
  aggressiveness: this.config.aggressiveness || 0.5,
219
350
  isEnabled: true,
220
- contextMode: "FIRST_MESSAGE"
351
+ contextMode: "FIRST_MESSAGE",
352
+ ownerEmail: this.config.ownerEmail
353
+ // Inherit from global if not specific
221
354
  });
222
355
  this.loadFromRegistry();
223
356
  }
@@ -1296,12 +1429,6 @@ var UsageTracker = class {
1296
1429
  // Immediate reporting for Edge/Stateless environments
1297
1430
  hooks;
1298
1431
  config;
1299
- // Static pricing benchmarks (cost per 1k tokens in USD)
1300
- static PRICING = {
1301
- "gpt-4o": { input: 5e-3, output: 0.015 },
1302
- "gpt-4o-mini": { input: 15e-5, output: 6e-4 },
1303
- "local": { input: 0, output: 0 }
1304
- };
1305
1432
  constructor(config, hooks) {
1306
1433
  this.config = config;
1307
1434
  this.hooks = hooks;
@@ -1334,42 +1461,71 @@ var UsageTracker = class {
1334
1461
  };
1335
1462
  this.buffer.push(data);
1336
1463
  this.hooks?.onUsageReported?.(data);
1337
- if (this.buffer.length >= this.MAX_BUFFER_SIZE) {
1338
- await this.flush();
1464
+ await this.persistToLocalBuffer(data);
1465
+ }
1466
+ /**
1467
+ * Appends usage data to the local .ik-adapter/usage.json file
1468
+ */
1469
+ async persistToLocalBuffer(data) {
1470
+ try {
1471
+ const registry = this.config.getRegistry();
1472
+ const usageFile = registry.getUsageFilePath();
1473
+ let existingUsage = [];
1474
+ if (registry.exists(usageFile)) {
1475
+ existingUsage = registry.loadUsage();
1476
+ }
1477
+ existingUsage.push(data);
1478
+ registry.saveUsage(existingUsage);
1479
+ } catch (e) {
1480
+ console.error("[IK_TRACKER] Failed to persist usage to local buffer:", e);
1339
1481
  }
1340
1482
  }
1341
1483
  /**
1342
1484
  * Send buffered usage data to the central IK billing service
1343
1485
  */
1344
- async flush() {
1345
- if (this.buffer.length === 0) return;
1346
- const endpoint = this.config.get("centralReportEndpoint");
1347
- if (!endpoint) {
1348
- this.buffer = [];
1349
- return;
1350
- }
1486
+ async flush(aggregatedData) {
1487
+ const usageToFlush = aggregatedData || this.buffer;
1488
+ if (usageToFlush.length === 0) return;
1489
+ const endpoint = this.config.get("centralReportEndpoint") || "https://ik-firewall.vercel.app/api/v1/report";
1490
+ const hmacSecret = this.config.get("hmacSecret");
1351
1491
  try {
1352
- for (const report of this.buffer) {
1353
- await fetch(endpoint, {
1492
+ this.hooks?.onStatus?.(`\u{1F4E4} IK_TRACKER: Flushing ${usageToFlush.length} interactions to ${endpoint}...`);
1493
+ const reportsByInstance = {};
1494
+ for (const report of usageToFlush) {
1495
+ if (!reportsByInstance[report.instanceId]) reportsByInstance[report.instanceId] = [];
1496
+ reportsByInstance[report.instanceId].push(report);
1497
+ }
1498
+ for (const [instanceId, reports] of Object.entries(reportsByInstance)) {
1499
+ const instanceConfig = this.config.getConfig().instanceConfigs?.[instanceId];
1500
+ const payload = {
1501
+ licenseKey: instanceConfig?.licenseKey || "",
1502
+ instanceId,
1503
+ reports: reports.map((r) => ({
1504
+ modelName: r.model_used,
1505
+ tokensIn: r.input_tokens,
1506
+ tokensOut: r.output_tokens,
1507
+ tokensSaved: r.tokens_saved,
1508
+ date: r.timestamp
1509
+ }))
1510
+ };
1511
+ if (hmacSecret) {
1512
+ const jsonStr = JSON.stringify(payload);
1513
+ const crypto2 = await import("crypto");
1514
+ payload.signature = crypto2.createHmac("sha256", hmacSecret).update(jsonStr).digest("hex");
1515
+ }
1516
+ const response = await fetch(endpoint, {
1354
1517
  method: "POST",
1355
1518
  headers: { "Content-Type": "application/json" },
1356
- body: JSON.stringify({
1357
- instanceId: report.instanceId,
1358
- model: report.model_used,
1359
- inputTokens: report.input_tokens,
1360
- outputTokens: report.output_tokens,
1361
- optimizedTokens: report.optimized_tokens,
1362
- tokensSaved: report.tokens_saved,
1363
- costSaved: report.cost_saved,
1364
- commissionDue: report.commission_due,
1365
- cqScore: report.cq_score,
1366
- routingPath: report.routingPath,
1367
- clientOrigin: report.clientOrigin,
1368
- timestamp: report.timestamp
1369
- })
1519
+ body: JSON.stringify(payload)
1370
1520
  });
1521
+ if (!response.ok) {
1522
+ console.error(`[IK_TRACKER] Failed to send aggregate for ${instanceId}: ${response.statusText}`);
1523
+ }
1371
1524
  }
1372
1525
  this.buffer = [];
1526
+ if (aggregatedData) {
1527
+ this.config.getRegistry().clearUsage();
1528
+ }
1373
1529
  } catch (error) {
1374
1530
  console.error("[IK_TRACKER] Failed to flush usage data:", error);
1375
1531
  }
@@ -1379,6 +1535,49 @@ var UsageTracker = class {
1379
1535
  }
1380
1536
  };
1381
1537
 
1538
+ // src/CognitiveEngine.ts
1539
+ var CognitiveEngine = class {
1540
+ /**
1541
+ * Sniff Cognitive DNA (CQ Score: 0-100)
1542
+ * Higher score = higher quality, human-like, structured content.
1543
+ */
1544
+ static sniffDNA(input) {
1545
+ if (!input || input.trim().length === 0) return 0;
1546
+ const length = input.length;
1547
+ const words = input.split(/\s+/).filter((w) => w.length > 0);
1548
+ const wordCount = words.length;
1549
+ const sentences = input.split(/[.!?]+/).filter((s) => s.trim().length > 0);
1550
+ const avgSentenceLength = sentences.length > 0 ? wordCount / sentences.length : 0;
1551
+ const sentenceVariety = sentences.length > 1 ? 10 : 0;
1552
+ const uniqueWords = new Set(words.map((w) => w.toLowerCase())).size;
1553
+ const lexicalBreadth = wordCount > 0 ? uniqueWords / wordCount * 40 : 0;
1554
+ const markers = (input.match(/[,;:"'()\[\]]/g) || []).length;
1555
+ const structuralHealth = Math.min(markers / wordCount * 100, 20);
1556
+ const repetitivePenalty = this.calculateRepetitivePenalty(input);
1557
+ let score = lexicalBreadth + structuralHealth + sentenceVariety + (avgSentenceLength > 5 ? 20 : 0);
1558
+ score -= repetitivePenalty;
1559
+ return Math.max(0, Math.min(100, score));
1560
+ }
1561
+ /**
1562
+ * Calculate Crystallization Threshold
1563
+ * Logic:
1564
+ * Low CQ (Noise) -> Aggressive optimization (Lower threshold, e.g. 0.6)
1565
+ * High CQ (Quality) -> Conservative optimization (Higher threshold, e.g. 0.9)
1566
+ */
1567
+ static calculateThreshold(cqScore) {
1568
+ if (cqScore < 30) return 0.65;
1569
+ if (cqScore < 60) return 0.78;
1570
+ if (cqScore < 85) return 0.88;
1571
+ return 0.95;
1572
+ }
1573
+ static calculateRepetitivePenalty(input) {
1574
+ const chunks = input.match(/.{1,10}/g) || [];
1575
+ const uniqueChunks = new Set(chunks).size;
1576
+ const ratio = chunks.length > 10 ? uniqueChunks / chunks.length : 1;
1577
+ return ratio < 0.5 ? (1 - ratio) * 50 : 0;
1578
+ }
1579
+ };
1580
+
1382
1581
  // src/core.ts
1383
1582
  var IKFirewallCore = class _IKFirewallCore {
1384
1583
  static instance;
@@ -1433,55 +1632,75 @@ var IKFirewallCore = class _IKFirewallCore {
1433
1632
  FLUID_THRESHOLD: 4
1434
1633
  }
1435
1634
  };
1436
- gatekeeper = new HeuristicGatekeeper();
1635
+ gatekeeper;
1437
1636
  configManager;
1438
1637
  sessionDNA = 0;
1439
- hooks;
1440
1638
  cloudProvider;
1441
1639
  localProvider;
1442
1640
  orchestrator;
1443
1641
  usageTracker;
1642
+ _hooks;
1643
+ defaultConfig;
1444
1644
  constructor(config, hooks, cloudProvider) {
1445
- const defaultConfig = {
1645
+ this.defaultConfig = {
1446
1646
  aggressiveness: 0.15,
1447
1647
  forcedEfficiency: false,
1448
1648
  precisionBias: _IKFirewallCore.CONSTANTS.PRECISION.BIAS_DEFAULT,
1449
1649
  balance: _IKFirewallCore.CONSTANTS.TONE.STABLE_VAL,
1450
1650
  gatekeeperEnabled: true,
1451
1651
  locale: "en",
1452
- providerMode: "hybrid",
1652
+ providerMode: process.env.IK_FIREWALL_MODE || "hybrid",
1453
1653
  runtimeStrategy: "internal",
1454
- localAuditEndpoint: "http://127.0.0.1:8085/v1/chat/completions",
1455
- fallbackToCloudAudit: false,
1654
+ localAuditEndpoint: process.env.IK_FIREWALL_LOCAL_ENDPOINT || "http://127.0.0.1:8085/v1/chat/completions",
1655
+ centralReportEndpoint: process.env.IK_FIREWALL_CENTRAL_ENDPOINT || "https://ik-firewall.vercel.app/api/v1/sync",
1656
+ ownerEmail: process.env.IK_FIREWALL_EMAIL,
1657
+ hmacSecret: process.env.IK_FIREWALL_SECRET,
1658
+ fallbackToCloudAudit: process.env.IK_FIREWALL_FALLBACK === "true" || false,
1456
1659
  modelConfig: {
1457
1660
  modelType: "1b"
1458
1661
  },
1459
1662
  plugins: []
1460
1663
  };
1461
- this.configManager = new ConfigManager({ ...defaultConfig, ...config });
1462
- if (hooks) this.hooks = hooks;
1664
+ this._hooks = hooks;
1665
+ this.configManager = new ConfigManager({ ...this.defaultConfig, ...config }, hooks);
1666
+ this.gatekeeper = new HeuristicGatekeeper();
1667
+ this.sessionDNA = _IKFirewallCore.CONSTANTS.DNA.MIN;
1463
1668
  const activeConfig = this.configManager.getConfig();
1464
1669
  this.localProvider = new LocalProvider(activeConfig.localAuditEndpoint);
1465
1670
  if (cloudProvider) {
1466
- if (cloudProvider instanceof BaseProvider) {
1467
- this.cloudProvider = cloudProvider;
1468
- } else {
1469
- const mode = activeConfig.providerMode;
1470
- if (mode === "anthropic") {
1471
- this.cloudProvider = new AnthropicProvider(cloudProvider);
1472
- } else if (mode === "deepseek") {
1473
- this.cloudProvider = new DeepSeekProvider(cloudProvider);
1474
- } else if (mode === "gemini") {
1475
- this.cloudProvider = new GeminiProvider(cloudProvider);
1476
- } else if (mode === "perplexity") {
1477
- this.cloudProvider = new PerplexityProvider(cloudProvider);
1478
- } else {
1479
- this.cloudProvider = new OpenAIProvider(cloudProvider);
1480
- }
1481
- }
1671
+ this.cloudProvider = cloudProvider instanceof BaseProvider ? cloudProvider : new OpenAIProvider(cloudProvider);
1672
+ } else if (process.env.OPENAI_API_KEY) {
1673
+ this.cloudProvider = new OpenAIProvider(async (prompt, role) => {
1674
+ const response = await fetch("https://api.openai.com/v1/chat/completions", {
1675
+ method: "POST",
1676
+ headers: {
1677
+ "Authorization": `Bearer ${process.env.OPENAI_API_KEY}`,
1678
+ "Content-Type": "application/json"
1679
+ },
1680
+ body: JSON.stringify({
1681
+ model: role === "audit_layer" ? "gpt-4o-mini" : "gpt-4o",
1682
+ messages: [{ role: "user", content: prompt }],
1683
+ temperature: 0.1
1684
+ })
1685
+ });
1686
+ if (!response.ok) throw new Error(`OpenAI API Error: ${response.statusText}`);
1687
+ const data = await response.json();
1688
+ return {
1689
+ content: data.choices[0].message.content,
1690
+ usage: data.usage
1691
+ };
1692
+ });
1482
1693
  }
1483
1694
  this.orchestrator = new Orchestrator(this.configManager);
1484
- this.usageTracker = new UsageTracker(this.configManager, this.hooks);
1695
+ this.usageTracker = new UsageTracker(this.configManager, this._hooks);
1696
+ }
1697
+ get hooks() {
1698
+ return this._hooks;
1699
+ }
1700
+ set hooks(newHooks) {
1701
+ this._hooks = newHooks;
1702
+ this.configManager.setHooks(newHooks);
1703
+ this.usageTracker.hooks = newHooks;
1485
1704
  }
1486
1705
  static getInstance(config, hooks) {
1487
1706
  if (!_IKFirewallCore.instance) {
@@ -1593,7 +1812,14 @@ var IKFirewallCore = class _IKFirewallCore {
1593
1812
  async analyze(input, provider, personaName = "professional", locale, instanceId) {
1594
1813
  if (instanceId) {
1595
1814
  this.configManager.ensureInstanceConfig(instanceId);
1596
- await this.configManager.syncRemoteConfig(instanceId);
1815
+ const syncPromise = this.configManager.syncRemoteConfig(instanceId).then(async () => {
1816
+ const pendingUsage = this.configManager._pendingUsage;
1817
+ if (pendingUsage && pendingUsage.length > 0) {
1818
+ await this.usageTracker.flush(pendingUsage);
1819
+ this.configManager._pendingUsage = null;
1820
+ }
1821
+ });
1822
+ await syncPromise;
1597
1823
  }
1598
1824
  const mergedConfig = this.configManager.getMergedConfig(instanceId);
1599
1825
  if (instanceId && mergedConfig?.isVerified === false) {
@@ -1663,10 +1889,17 @@ var IKFirewallCore = class _IKFirewallCore {
1663
1889
  throw e;
1664
1890
  }
1665
1891
  }
1666
- this.sniffDNA(input, metrics, activeLocale);
1892
+ const cqScore = CognitiveEngine.sniffDNA(input);
1893
+ metrics.dm = Math.max(metrics.dm, cqScore / 10);
1894
+ this.applyHardening(input, metrics, activeLocale);
1667
1895
  this.hooks?.onAuditComplete?.(metrics);
1668
1896
  return metrics;
1669
1897
  }
1898
+ applyHardening(input, metrics, locale = "en") {
1899
+ const archetype = metrics.semanticInsights?.archetype || "DYNAMIC";
1900
+ const domain = metrics.semanticInsights?.detectedDomain || "GENERAL";
1901
+ this.setSessionDNA(this.sessionDNA + 5);
1902
+ }
1670
1903
  getEmptyMetrics() {
1671
1904
  return {
1672
1905
  dm: 0,
@@ -1718,28 +1951,6 @@ var IKFirewallCore = class _IKFirewallCore {
1718
1951
  inputLength: input.length
1719
1952
  };
1720
1953
  }
1721
- sniffDNA(input, metrics, locale = "en") {
1722
- const archetype = metrics.semanticInsights?.archetype || "DYNAMIC";
1723
- const domain = metrics.semanticInsights?.detectedDomain || "GENERAL";
1724
- const meta = Dictionaries.meta[locale] || Dictionaries.meta.en;
1725
- const patterns = (meta.system_prompt_patterns || "").split(",").map((p) => p.trim()).filter((p) => p.length > 0);
1726
- const isSystemPrompt = patterns.some((kw) => input.toLowerCase().includes(kw));
1727
- let dnaShift = 0;
1728
- if (archetype === "CRYSTAL") {
1729
- dnaShift += _IKFirewallCore.CONSTANTS.DNA.HARDENING_MODERATE;
1730
- } else if (archetype === "FLUID") {
1731
- dnaShift -= _IKFirewallCore.CONSTANTS.DNA.SOFTENING_STEP;
1732
- } else if (archetype === "NEURAL") {
1733
- dnaShift -= _IKFirewallCore.CONSTANTS.DNA.SOFTENING_STEP / 2;
1734
- }
1735
- if (["LEGAL", "MEDICAL", "FINANCE", "CONSTRUCTION", "ENGINEERING"].includes(domain)) {
1736
- dnaShift += _IKFirewallCore.CONSTANTS.DNA.HARDENING_DOMAIN;
1737
- }
1738
- if (isSystemPrompt) {
1739
- dnaShift += _IKFirewallCore.CONSTANTS.DNA.HARDENING_MODERATE;
1740
- }
1741
- this.setSessionDNA(this.sessionDNA + dnaShift);
1742
- }
1743
1954
  async analyzeAIAssisted(input, provider, personaName = "professional", instanceId, configOverride) {
1744
1955
  if (instanceId) {
1745
1956
  this.configManager.ensureInstanceConfig(instanceId);
@@ -1990,11 +2201,13 @@ Any action outside this scope MUST be rejected and flagged as a boundary violati
1990
2201
  this.hooks?.onStatus?.(`\u{1F6E1}\uFE0F IK_CRYSTALLIZE: Precision domain detected (${domain}). Relaxing noise reduction...`);
1991
2202
  archetypeModifier = -0.3;
1992
2203
  }
2204
+ const cqScore = CognitiveEngine.sniffDNA(input);
2205
+ const cognitiveThreshold = CognitiveEngine.calculateThreshold(cqScore);
1993
2206
  const threshold = Math.min(
1994
2207
  _IKFirewallCore.CONSTANTS.AI.THRESHOLD_MAX,
1995
2208
  Math.max(
1996
2209
  _IKFirewallCore.CONSTANTS.AI.THRESHOLD_MIN,
1997
- dm / _IKFirewallCore.CONSTANTS.AI.DM_THRESHOLD_DIVISOR + basePreference - aggModifier + archetypeModifier - tolerance * 0.1
2210
+ cognitiveThreshold + archetypeModifier - tolerance * 0.1
1998
2211
  )
1999
2212
  );
2000
2213
  const lengthRatio = blueprint ? blueprint.length / input.length : 1;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ik-firewall/core",
3
- "version": "2.2.0",
3
+ "version": "2.3.0",
4
4
  "type": "module",
5
5
  "description": "The core IK Firewall engine for semantic-driven AI optimization.",
6
6
  "main": "./dist/index.js",
@@ -17,7 +17,7 @@
17
17
  "dist",
18
18
  "scripts"
19
19
  ],
20
- "api_endpoint": "https://ik-firewall-backend.vercel.app/api/v1",
20
+ "api_endpoint": "https://ik-firewall.vercel.app/api/v1",
21
21
  "scripts": {
22
22
  "prepare": "npm run build",
23
23
  "build": "tsup src/index.ts --format cjs,esm --dts --clean",
@@ -61,7 +61,9 @@ async function setup() {
61
61
  "isEnabled": true
62
62
  }
63
63
  };
64
- fs.writeFileSync(REGISTRY_FILE, JSON.stringify(initialRegistry, null, 2));
64
+ const jsonStr = JSON.stringify(initialRegistry, null, 2);
65
+ const obfuscated = Buffer.from(jsonStr).toString('base64');
66
+ fs.writeFileSync(REGISTRY_FILE, obfuscated, 'utf8');
65
67
  console.log(`✨ Trial activated for: ${email}`);
66
68
  }
67
69