@ik-firewall/core 2.2.0 → 2.3.1

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,61 @@ 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 baseUrl = this.config.centralReportEndpoint || "https://ik-firewall.vercel.app";
259
+ const endpoint = `${baseUrl.replace(/\/$/, "")}/api/v1/sync`;
260
+ const instanceConfig2 = this.config.instanceConfigs?.[instanceId];
261
+ const registrationEmail = instanceConfig2?.ownerEmail || this.config.ownerEmail;
262
+ if ((!instanceConfig2?.licenseKey || instanceConfig2.licenseKey.startsWith("TRIAL-")) && registrationEmail) {
263
+ const success = await this.registerInstance(instanceId, registrationEmail);
264
+ if (success) {
265
+ this.hooks?.onStatus?.("\u2728 IK_SYNC: Zero-Config registration successful. License issued.");
266
+ return;
267
+ } else {
268
+ this.hooks?.onStatus?.("\u26A0\uFE0F IK_SYNC: Auto-registration failed. Continuing with local trial.");
269
+ }
270
+ }
271
+ this.hooks?.onStatus?.(`\u{1F4E1} IK_SYNC: Heartbeat to ${endpoint}...`);
272
+ const response = await fetch(`${endpoint}?licenseKey=${instanceConfig2?.licenseKey || ""}&instanceId=${instanceId}&version=2.2.0`);
273
+ if (response.ok) {
274
+ const data = await response.json();
275
+ if (this.config.hmacSecret) {
276
+ const verifier = new IKHmac(this.config.hmacSecret);
277
+ if (!verifier.verify(data)) {
278
+ console.error("[IK_SYNC] \u{1F6A8} Signature verification failed! Remote config rejected.");
279
+ return;
280
+ }
281
+ }
282
+ this.setInstanceConfig(instanceId, {
283
+ billingStatus: data.billingStatus,
284
+ isVerified: data.isVerified,
285
+ pricing: data.pricing,
286
+ lastSyncDate: now.toISOString()
287
+ });
288
+ this.hooks?.onStatus?.("\u2705 IK_SYNC: Remote configuration updated and verified.");
289
+ } else {
290
+ throw new Error(`Server responded with ${response.status}`);
291
+ }
292
+ if (!instanceConfig2?.firstUseDate) {
196
293
  this.setInstanceConfig(instanceId, { firstUseDate: now.toISOString() });
197
294
  }
198
295
  } catch (error) {
199
- console.error("[IK_CONFIG] Remote sync failed. Falling open (Fail-Open mode).");
296
+ console.error(`[IK_CONFIG] Remote sync failed (${error.message}). Falling open (Fail-Open mode).`);
200
297
  this.setInstanceConfig(instanceId, {
201
298
  isVerified: true,
202
299
  lastSyncDate: now.toISOString()
203
300
  });
204
301
  }
302
+ try {
303
+ const registry = this.registry;
304
+ if (registry.exists(registry.getUsageFilePath())) {
305
+ const aggregatedUsage = registry.loadUsage();
306
+ if (aggregatedUsage.length > 0) {
307
+ this.hooks?.onStatus?.(`\u{1F4CA} IK_SYNC: Found ${aggregatedUsage.length} pending usage reports. Preparation for Daily Flush...`);
308
+ this._pendingUsage = aggregatedUsage;
309
+ }
310
+ }
311
+ } catch (e) {
312
+ }
205
313
  }
206
314
  getConfig() {
207
315
  return { ...this.config };
@@ -242,6 +350,40 @@ var ConfigManager = class {
242
350
  }
243
351
  this.updateConfig({ plugins });
244
352
  }
353
+ async registerInstance(instanceId, email) {
354
+ try {
355
+ const endpoint = (this.config.centralReportEndpoint || "https://ik-firewall.vercel.app/api/v1").replace(/\/sync$/, "") + "/register";
356
+ this.hooks?.onStatus?.(`\u{1F680} IK_REGISTRY: Registering new instance for ${email}...`);
357
+ const response = await fetch(endpoint, {
358
+ method: "POST",
359
+ headers: { "Content-Type": "application/json" },
360
+ body: JSON.stringify({ email, instanceId })
361
+ });
362
+ if (response.ok) {
363
+ const data = await response.json();
364
+ if (this.config.hmacSecret) {
365
+ const verifier = new IKHmac(this.config.hmacSecret);
366
+ if (!verifier.verify(data)) {
367
+ console.error("[IK_REGISTRY] \u{1F6A8} Registration signature mismatch. Data rejected!");
368
+ return false;
369
+ }
370
+ }
371
+ this.setInstanceConfig(instanceId, {
372
+ licenseKey: data.licenseKey,
373
+ billingStatus: data.status.toLowerCase(),
374
+ isVerified: true,
375
+ firstUseDate: (/* @__PURE__ */ new Date()).toISOString(),
376
+ pricing: data.pricing
377
+ });
378
+ this.hooks?.onStatus?.("\u2728 IK_REGISTRY: Instance registered successfully and license issued.");
379
+ return true;
380
+ }
381
+ return false;
382
+ } catch (error) {
383
+ console.error("[IK_REGISTRY] Registration failed:", error);
384
+ return false;
385
+ }
386
+ }
245
387
  ensureInstanceConfig(instanceId) {
246
388
  const all = this.registry.load();
247
389
  if (!all[instanceId]) {
@@ -249,7 +391,9 @@ var ConfigManager = class {
249
391
  balance: this.config.balance || 0.5,
250
392
  aggressiveness: this.config.aggressiveness || 0.5,
251
393
  isEnabled: true,
252
- contextMode: "FIRST_MESSAGE"
394
+ contextMode: "FIRST_MESSAGE",
395
+ ownerEmail: this.config.ownerEmail
396
+ // Inherit from global if not specific
253
397
  });
254
398
  this.loadFromRegistry();
255
399
  }
@@ -1328,12 +1472,6 @@ var UsageTracker = class {
1328
1472
  // Immediate reporting for Edge/Stateless environments
1329
1473
  hooks;
1330
1474
  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
1475
  constructor(config, hooks) {
1338
1476
  this.config = config;
1339
1477
  this.hooks = hooks;
@@ -1366,42 +1504,72 @@ var UsageTracker = class {
1366
1504
  };
1367
1505
  this.buffer.push(data);
1368
1506
  this.hooks?.onUsageReported?.(data);
1369
- if (this.buffer.length >= this.MAX_BUFFER_SIZE) {
1370
- await this.flush();
1507
+ await this.persistToLocalBuffer(data);
1508
+ }
1509
+ /**
1510
+ * Appends usage data to the local .ik-adapter/usage.json file
1511
+ */
1512
+ async persistToLocalBuffer(data) {
1513
+ try {
1514
+ const registry = this.config.getRegistry();
1515
+ const usageFile = registry.getUsageFilePath();
1516
+ let existingUsage = [];
1517
+ if (registry.exists(usageFile)) {
1518
+ existingUsage = registry.loadUsage();
1519
+ }
1520
+ existingUsage.push(data);
1521
+ registry.saveUsage(existingUsage);
1522
+ } catch (e) {
1523
+ console.error("[IK_TRACKER] Failed to persist usage to local buffer:", e);
1371
1524
  }
1372
1525
  }
1373
1526
  /**
1374
1527
  * Send buffered usage data to the central IK billing service
1375
1528
  */
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
- }
1529
+ async flush(aggregatedData) {
1530
+ const usageToFlush = aggregatedData || this.buffer;
1531
+ if (usageToFlush.length === 0) return;
1532
+ const baseUrl = this.config.get("centralReportEndpoint") || "https://ik-firewall.vercel.app";
1533
+ const endpoint = `${baseUrl.replace(/\/$/, "")}/api/v1/report`;
1534
+ const hmacSecret = this.config.get("hmacSecret");
1383
1535
  try {
1384
- for (const report of this.buffer) {
1385
- await fetch(endpoint, {
1536
+ this.hooks?.onStatus?.(`\u{1F4E4} IK_TRACKER: Flushing ${usageToFlush.length} interactions to ${endpoint}...`);
1537
+ const reportsByInstance = {};
1538
+ for (const report of usageToFlush) {
1539
+ if (!reportsByInstance[report.instanceId]) reportsByInstance[report.instanceId] = [];
1540
+ reportsByInstance[report.instanceId].push(report);
1541
+ }
1542
+ for (const [instanceId, reports] of Object.entries(reportsByInstance)) {
1543
+ const instanceConfig = this.config.getConfig().instanceConfigs?.[instanceId];
1544
+ const payload = {
1545
+ licenseKey: instanceConfig?.licenseKey || "",
1546
+ instanceId,
1547
+ reports: reports.map((r) => ({
1548
+ modelName: r.model_used,
1549
+ tokensIn: r.input_tokens,
1550
+ tokensOut: r.output_tokens,
1551
+ tokensSaved: r.tokens_saved,
1552
+ date: r.timestamp
1553
+ }))
1554
+ };
1555
+ if (hmacSecret) {
1556
+ const jsonStr = JSON.stringify(payload);
1557
+ const crypto2 = await import("crypto");
1558
+ payload.signature = crypto2.createHmac("sha256", hmacSecret).update(jsonStr).digest("hex");
1559
+ }
1560
+ const response = await fetch(endpoint, {
1386
1561
  method: "POST",
1387
1562
  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
- })
1563
+ body: JSON.stringify(payload)
1402
1564
  });
1565
+ if (!response.ok) {
1566
+ console.error(`[IK_TRACKER] Failed to send aggregate for ${instanceId}: ${response.statusText}`);
1567
+ }
1403
1568
  }
1404
1569
  this.buffer = [];
1570
+ if (aggregatedData) {
1571
+ this.config.getRegistry().clearUsage();
1572
+ }
1405
1573
  } catch (error) {
1406
1574
  console.error("[IK_TRACKER] Failed to flush usage data:", error);
1407
1575
  }
@@ -1411,6 +1579,49 @@ var UsageTracker = class {
1411
1579
  }
1412
1580
  };
1413
1581
 
1582
+ // src/CognitiveEngine.ts
1583
+ var CognitiveEngine = class {
1584
+ /**
1585
+ * Sniff Cognitive DNA (CQ Score: 0-100)
1586
+ * Higher score = higher quality, human-like, structured content.
1587
+ */
1588
+ static sniffDNA(input) {
1589
+ if (!input || input.trim().length === 0) return 0;
1590
+ const length = input.length;
1591
+ const words = input.split(/\s+/).filter((w) => w.length > 0);
1592
+ const wordCount = words.length;
1593
+ const sentences = input.split(/[.!?]+/).filter((s) => s.trim().length > 0);
1594
+ const avgSentenceLength = sentences.length > 0 ? wordCount / sentences.length : 0;
1595
+ const sentenceVariety = sentences.length > 1 ? 10 : 0;
1596
+ const uniqueWords = new Set(words.map((w) => w.toLowerCase())).size;
1597
+ const lexicalBreadth = wordCount > 0 ? uniqueWords / wordCount * 40 : 0;
1598
+ const markers = (input.match(/[,;:"'()\[\]]/g) || []).length;
1599
+ const structuralHealth = Math.min(markers / wordCount * 100, 20);
1600
+ const repetitivePenalty = this.calculateRepetitivePenalty(input);
1601
+ let score = lexicalBreadth + structuralHealth + sentenceVariety + (avgSentenceLength > 5 ? 20 : 0);
1602
+ score -= repetitivePenalty;
1603
+ return Math.max(0, Math.min(100, score));
1604
+ }
1605
+ /**
1606
+ * Calculate Crystallization Threshold
1607
+ * Logic:
1608
+ * Low CQ (Noise) -> Aggressive optimization (Lower threshold, e.g. 0.6)
1609
+ * High CQ (Quality) -> Conservative optimization (Higher threshold, e.g. 0.9)
1610
+ */
1611
+ static calculateThreshold(cqScore) {
1612
+ if (cqScore < 30) return 0.65;
1613
+ if (cqScore < 60) return 0.78;
1614
+ if (cqScore < 85) return 0.88;
1615
+ return 0.95;
1616
+ }
1617
+ static calculateRepetitivePenalty(input) {
1618
+ const chunks = input.match(/.{1,10}/g) || [];
1619
+ const uniqueChunks = new Set(chunks).size;
1620
+ const ratio = chunks.length > 10 ? uniqueChunks / chunks.length : 1;
1621
+ return ratio < 0.5 ? (1 - ratio) * 50 : 0;
1622
+ }
1623
+ };
1624
+
1414
1625
  // src/core.ts
1415
1626
  var IKFirewallCore = class _IKFirewallCore {
1416
1627
  static instance;
@@ -1465,55 +1676,75 @@ var IKFirewallCore = class _IKFirewallCore {
1465
1676
  FLUID_THRESHOLD: 4
1466
1677
  }
1467
1678
  };
1468
- gatekeeper = new HeuristicGatekeeper();
1679
+ gatekeeper;
1469
1680
  configManager;
1470
1681
  sessionDNA = 0;
1471
- hooks;
1472
1682
  cloudProvider;
1473
1683
  localProvider;
1474
1684
  orchestrator;
1475
1685
  usageTracker;
1686
+ _hooks;
1687
+ defaultConfig;
1476
1688
  constructor(config, hooks, cloudProvider) {
1477
- const defaultConfig = {
1689
+ this.defaultConfig = {
1478
1690
  aggressiveness: 0.15,
1479
1691
  forcedEfficiency: false,
1480
1692
  precisionBias: _IKFirewallCore.CONSTANTS.PRECISION.BIAS_DEFAULT,
1481
1693
  balance: _IKFirewallCore.CONSTANTS.TONE.STABLE_VAL,
1482
1694
  gatekeeperEnabled: true,
1483
1695
  locale: "en",
1484
- providerMode: "hybrid",
1696
+ providerMode: process.env.IK_FIREWALL_MODE || "hybrid",
1485
1697
  runtimeStrategy: "internal",
1486
- localAuditEndpoint: "http://127.0.0.1:8085/v1/chat/completions",
1487
- fallbackToCloudAudit: false,
1698
+ localAuditEndpoint: process.env.IK_FIREWALL_LOCAL_ENDPOINT || "http://127.0.0.1:8085/v1/chat/completions",
1699
+ centralReportEndpoint: (process.env.IK_FIREWALL_CENTRAL_ENDPOINT || "https://ik-firewall.vercel.app").replace(/\/$/, ""),
1700
+ ownerEmail: process.env.IK_FIREWALL_EMAIL,
1701
+ hmacSecret: process.env.IK_FIREWALL_SECRET,
1702
+ fallbackToCloudAudit: process.env.IK_FIREWALL_FALLBACK === "true" || false,
1488
1703
  modelConfig: {
1489
1704
  modelType: "1b"
1490
1705
  },
1491
1706
  plugins: []
1492
1707
  };
1493
- this.configManager = new ConfigManager({ ...defaultConfig, ...config });
1494
- if (hooks) this.hooks = hooks;
1708
+ this._hooks = hooks;
1709
+ this.configManager = new ConfigManager({ ...this.defaultConfig, ...config }, hooks);
1710
+ this.gatekeeper = new HeuristicGatekeeper();
1711
+ this.sessionDNA = _IKFirewallCore.CONSTANTS.DNA.MIN;
1495
1712
  const activeConfig = this.configManager.getConfig();
1496
1713
  this.localProvider = new LocalProvider(activeConfig.localAuditEndpoint);
1497
1714
  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
- }
1715
+ this.cloudProvider = cloudProvider instanceof BaseProvider ? cloudProvider : new OpenAIProvider(cloudProvider);
1716
+ } else if (process.env.OPENAI_API_KEY) {
1717
+ this.cloudProvider = new OpenAIProvider(async (prompt, role) => {
1718
+ const response = await fetch("https://api.openai.com/v1/chat/completions", {
1719
+ method: "POST",
1720
+ headers: {
1721
+ "Authorization": `Bearer ${process.env.OPENAI_API_KEY}`,
1722
+ "Content-Type": "application/json"
1723
+ },
1724
+ body: JSON.stringify({
1725
+ model: role === "audit_layer" ? "gpt-4o-mini" : "gpt-4o",
1726
+ messages: [{ role: "user", content: prompt }],
1727
+ temperature: 0.1
1728
+ })
1729
+ });
1730
+ if (!response.ok) throw new Error(`OpenAI API Error: ${response.statusText}`);
1731
+ const data = await response.json();
1732
+ return {
1733
+ content: data.choices[0].message.content,
1734
+ usage: data.usage
1735
+ };
1736
+ });
1514
1737
  }
1515
1738
  this.orchestrator = new Orchestrator(this.configManager);
1516
- this.usageTracker = new UsageTracker(this.configManager, this.hooks);
1739
+ this.usageTracker = new UsageTracker(this.configManager, this._hooks);
1740
+ }
1741
+ get hooks() {
1742
+ return this._hooks;
1743
+ }
1744
+ set hooks(newHooks) {
1745
+ this._hooks = newHooks;
1746
+ this.configManager.setHooks(newHooks);
1747
+ this.usageTracker.hooks = newHooks;
1517
1748
  }
1518
1749
  static getInstance(config, hooks) {
1519
1750
  if (!_IKFirewallCore.instance) {
@@ -1625,7 +1856,14 @@ var IKFirewallCore = class _IKFirewallCore {
1625
1856
  async analyze(input, provider, personaName = "professional", locale, instanceId) {
1626
1857
  if (instanceId) {
1627
1858
  this.configManager.ensureInstanceConfig(instanceId);
1628
- await this.configManager.syncRemoteConfig(instanceId);
1859
+ const syncPromise = this.configManager.syncRemoteConfig(instanceId).then(async () => {
1860
+ const pendingUsage = this.configManager._pendingUsage;
1861
+ if (pendingUsage && pendingUsage.length > 0) {
1862
+ await this.usageTracker.flush(pendingUsage);
1863
+ this.configManager._pendingUsage = null;
1864
+ }
1865
+ });
1866
+ await syncPromise;
1629
1867
  }
1630
1868
  const mergedConfig = this.configManager.getMergedConfig(instanceId);
1631
1869
  if (instanceId && mergedConfig?.isVerified === false) {
@@ -1695,10 +1933,17 @@ var IKFirewallCore = class _IKFirewallCore {
1695
1933
  throw e;
1696
1934
  }
1697
1935
  }
1698
- this.sniffDNA(input, metrics, activeLocale);
1936
+ const cqScore = CognitiveEngine.sniffDNA(input);
1937
+ metrics.dm = Math.max(metrics.dm, cqScore / 10);
1938
+ this.applyHardening(input, metrics, activeLocale);
1699
1939
  this.hooks?.onAuditComplete?.(metrics);
1700
1940
  return metrics;
1701
1941
  }
1942
+ applyHardening(input, metrics, locale = "en") {
1943
+ const archetype = metrics.semanticInsights?.archetype || "DYNAMIC";
1944
+ const domain = metrics.semanticInsights?.detectedDomain || "GENERAL";
1945
+ this.setSessionDNA(this.sessionDNA + 5);
1946
+ }
1702
1947
  getEmptyMetrics() {
1703
1948
  return {
1704
1949
  dm: 0,
@@ -1750,28 +1995,6 @@ var IKFirewallCore = class _IKFirewallCore {
1750
1995
  inputLength: input.length
1751
1996
  };
1752
1997
  }
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
1998
  async analyzeAIAssisted(input, provider, personaName = "professional", instanceId, configOverride) {
1776
1999
  if (instanceId) {
1777
2000
  this.configManager.ensureInstanceConfig(instanceId);
@@ -2022,11 +2245,13 @@ Any action outside this scope MUST be rejected and flagged as a boundary violati
2022
2245
  this.hooks?.onStatus?.(`\u{1F6E1}\uFE0F IK_CRYSTALLIZE: Precision domain detected (${domain}). Relaxing noise reduction...`);
2023
2246
  archetypeModifier = -0.3;
2024
2247
  }
2248
+ const cqScore = CognitiveEngine.sniffDNA(input);
2249
+ const cognitiveThreshold = CognitiveEngine.calculateThreshold(cqScore);
2025
2250
  const threshold = Math.min(
2026
2251
  _IKFirewallCore.CONSTANTS.AI.THRESHOLD_MAX,
2027
2252
  Math.max(
2028
2253
  _IKFirewallCore.CONSTANTS.AI.THRESHOLD_MIN,
2029
- dm / _IKFirewallCore.CONSTANTS.AI.DM_THRESHOLD_DIVISOR + basePreference - aggModifier + archetypeModifier - tolerance * 0.1
2254
+ cognitiveThreshold + archetypeModifier - tolerance * 0.1
2030
2255
  )
2031
2256
  );
2032
2257
  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,61 @@ 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 baseUrl = this.config.centralReportEndpoint || "https://ik-firewall.vercel.app";
217
+ const endpoint = `${baseUrl.replace(/\/$/, "")}/api/v1/sync`;
218
+ const instanceConfig2 = this.config.instanceConfigs?.[instanceId];
219
+ const registrationEmail = instanceConfig2?.ownerEmail || this.config.ownerEmail;
220
+ if ((!instanceConfig2?.licenseKey || instanceConfig2.licenseKey.startsWith("TRIAL-")) && registrationEmail) {
221
+ const success = await this.registerInstance(instanceId, registrationEmail);
222
+ if (success) {
223
+ this.hooks?.onStatus?.("\u2728 IK_SYNC: Zero-Config registration successful. License issued.");
224
+ return;
225
+ } else {
226
+ this.hooks?.onStatus?.("\u26A0\uFE0F IK_SYNC: Auto-registration failed. Continuing with local trial.");
227
+ }
228
+ }
229
+ this.hooks?.onStatus?.(`\u{1F4E1} IK_SYNC: Heartbeat to ${endpoint}...`);
230
+ const response = await fetch(`${endpoint}?licenseKey=${instanceConfig2?.licenseKey || ""}&instanceId=${instanceId}&version=2.2.0`);
231
+ if (response.ok) {
232
+ const data = await response.json();
233
+ if (this.config.hmacSecret) {
234
+ const verifier = new IKHmac(this.config.hmacSecret);
235
+ if (!verifier.verify(data)) {
236
+ console.error("[IK_SYNC] \u{1F6A8} Signature verification failed! Remote config rejected.");
237
+ return;
238
+ }
239
+ }
240
+ this.setInstanceConfig(instanceId, {
241
+ billingStatus: data.billingStatus,
242
+ isVerified: data.isVerified,
243
+ pricing: data.pricing,
244
+ lastSyncDate: now.toISOString()
245
+ });
246
+ this.hooks?.onStatus?.("\u2705 IK_SYNC: Remote configuration updated and verified.");
247
+ } else {
248
+ throw new Error(`Server responded with ${response.status}`);
249
+ }
250
+ if (!instanceConfig2?.firstUseDate) {
164
251
  this.setInstanceConfig(instanceId, { firstUseDate: now.toISOString() });
165
252
  }
166
253
  } catch (error) {
167
- console.error("[IK_CONFIG] Remote sync failed. Falling open (Fail-Open mode).");
254
+ console.error(`[IK_CONFIG] Remote sync failed (${error.message}). Falling open (Fail-Open mode).`);
168
255
  this.setInstanceConfig(instanceId, {
169
256
  isVerified: true,
170
257
  lastSyncDate: now.toISOString()
171
258
  });
172
259
  }
260
+ try {
261
+ const registry = this.registry;
262
+ if (registry.exists(registry.getUsageFilePath())) {
263
+ const aggregatedUsage = registry.loadUsage();
264
+ if (aggregatedUsage.length > 0) {
265
+ this.hooks?.onStatus?.(`\u{1F4CA} IK_SYNC: Found ${aggregatedUsage.length} pending usage reports. Preparation for Daily Flush...`);
266
+ this._pendingUsage = aggregatedUsage;
267
+ }
268
+ }
269
+ } catch (e) {
270
+ }
173
271
  }
174
272
  getConfig() {
175
273
  return { ...this.config };
@@ -210,6 +308,40 @@ var ConfigManager = class {
210
308
  }
211
309
  this.updateConfig({ plugins });
212
310
  }
311
+ async registerInstance(instanceId, email) {
312
+ try {
313
+ const endpoint = (this.config.centralReportEndpoint || "https://ik-firewall.vercel.app/api/v1").replace(/\/sync$/, "") + "/register";
314
+ this.hooks?.onStatus?.(`\u{1F680} IK_REGISTRY: Registering new instance for ${email}...`);
315
+ const response = await fetch(endpoint, {
316
+ method: "POST",
317
+ headers: { "Content-Type": "application/json" },
318
+ body: JSON.stringify({ email, instanceId })
319
+ });
320
+ if (response.ok) {
321
+ const data = await response.json();
322
+ if (this.config.hmacSecret) {
323
+ const verifier = new IKHmac(this.config.hmacSecret);
324
+ if (!verifier.verify(data)) {
325
+ console.error("[IK_REGISTRY] \u{1F6A8} Registration signature mismatch. Data rejected!");
326
+ return false;
327
+ }
328
+ }
329
+ this.setInstanceConfig(instanceId, {
330
+ licenseKey: data.licenseKey,
331
+ billingStatus: data.status.toLowerCase(),
332
+ isVerified: true,
333
+ firstUseDate: (/* @__PURE__ */ new Date()).toISOString(),
334
+ pricing: data.pricing
335
+ });
336
+ this.hooks?.onStatus?.("\u2728 IK_REGISTRY: Instance registered successfully and license issued.");
337
+ return true;
338
+ }
339
+ return false;
340
+ } catch (error) {
341
+ console.error("[IK_REGISTRY] Registration failed:", error);
342
+ return false;
343
+ }
344
+ }
213
345
  ensureInstanceConfig(instanceId) {
214
346
  const all = this.registry.load();
215
347
  if (!all[instanceId]) {
@@ -217,7 +349,9 @@ var ConfigManager = class {
217
349
  balance: this.config.balance || 0.5,
218
350
  aggressiveness: this.config.aggressiveness || 0.5,
219
351
  isEnabled: true,
220
- contextMode: "FIRST_MESSAGE"
352
+ contextMode: "FIRST_MESSAGE",
353
+ ownerEmail: this.config.ownerEmail
354
+ // Inherit from global if not specific
221
355
  });
222
356
  this.loadFromRegistry();
223
357
  }
@@ -1296,12 +1430,6 @@ var UsageTracker = class {
1296
1430
  // Immediate reporting for Edge/Stateless environments
1297
1431
  hooks;
1298
1432
  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
1433
  constructor(config, hooks) {
1306
1434
  this.config = config;
1307
1435
  this.hooks = hooks;
@@ -1334,42 +1462,72 @@ var UsageTracker = class {
1334
1462
  };
1335
1463
  this.buffer.push(data);
1336
1464
  this.hooks?.onUsageReported?.(data);
1337
- if (this.buffer.length >= this.MAX_BUFFER_SIZE) {
1338
- await this.flush();
1465
+ await this.persistToLocalBuffer(data);
1466
+ }
1467
+ /**
1468
+ * Appends usage data to the local .ik-adapter/usage.json file
1469
+ */
1470
+ async persistToLocalBuffer(data) {
1471
+ try {
1472
+ const registry = this.config.getRegistry();
1473
+ const usageFile = registry.getUsageFilePath();
1474
+ let existingUsage = [];
1475
+ if (registry.exists(usageFile)) {
1476
+ existingUsage = registry.loadUsage();
1477
+ }
1478
+ existingUsage.push(data);
1479
+ registry.saveUsage(existingUsage);
1480
+ } catch (e) {
1481
+ console.error("[IK_TRACKER] Failed to persist usage to local buffer:", e);
1339
1482
  }
1340
1483
  }
1341
1484
  /**
1342
1485
  * Send buffered usage data to the central IK billing service
1343
1486
  */
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
- }
1487
+ async flush(aggregatedData) {
1488
+ const usageToFlush = aggregatedData || this.buffer;
1489
+ if (usageToFlush.length === 0) return;
1490
+ const baseUrl = this.config.get("centralReportEndpoint") || "https://ik-firewall.vercel.app";
1491
+ const endpoint = `${baseUrl.replace(/\/$/, "")}/api/v1/report`;
1492
+ const hmacSecret = this.config.get("hmacSecret");
1351
1493
  try {
1352
- for (const report of this.buffer) {
1353
- await fetch(endpoint, {
1494
+ this.hooks?.onStatus?.(`\u{1F4E4} IK_TRACKER: Flushing ${usageToFlush.length} interactions to ${endpoint}...`);
1495
+ const reportsByInstance = {};
1496
+ for (const report of usageToFlush) {
1497
+ if (!reportsByInstance[report.instanceId]) reportsByInstance[report.instanceId] = [];
1498
+ reportsByInstance[report.instanceId].push(report);
1499
+ }
1500
+ for (const [instanceId, reports] of Object.entries(reportsByInstance)) {
1501
+ const instanceConfig = this.config.getConfig().instanceConfigs?.[instanceId];
1502
+ const payload = {
1503
+ licenseKey: instanceConfig?.licenseKey || "",
1504
+ instanceId,
1505
+ reports: reports.map((r) => ({
1506
+ modelName: r.model_used,
1507
+ tokensIn: r.input_tokens,
1508
+ tokensOut: r.output_tokens,
1509
+ tokensSaved: r.tokens_saved,
1510
+ date: r.timestamp
1511
+ }))
1512
+ };
1513
+ if (hmacSecret) {
1514
+ const jsonStr = JSON.stringify(payload);
1515
+ const crypto2 = await import("crypto");
1516
+ payload.signature = crypto2.createHmac("sha256", hmacSecret).update(jsonStr).digest("hex");
1517
+ }
1518
+ const response = await fetch(endpoint, {
1354
1519
  method: "POST",
1355
1520
  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
- })
1521
+ body: JSON.stringify(payload)
1370
1522
  });
1523
+ if (!response.ok) {
1524
+ console.error(`[IK_TRACKER] Failed to send aggregate for ${instanceId}: ${response.statusText}`);
1525
+ }
1371
1526
  }
1372
1527
  this.buffer = [];
1528
+ if (aggregatedData) {
1529
+ this.config.getRegistry().clearUsage();
1530
+ }
1373
1531
  } catch (error) {
1374
1532
  console.error("[IK_TRACKER] Failed to flush usage data:", error);
1375
1533
  }
@@ -1379,6 +1537,49 @@ var UsageTracker = class {
1379
1537
  }
1380
1538
  };
1381
1539
 
1540
+ // src/CognitiveEngine.ts
1541
+ var CognitiveEngine = class {
1542
+ /**
1543
+ * Sniff Cognitive DNA (CQ Score: 0-100)
1544
+ * Higher score = higher quality, human-like, structured content.
1545
+ */
1546
+ static sniffDNA(input) {
1547
+ if (!input || input.trim().length === 0) return 0;
1548
+ const length = input.length;
1549
+ const words = input.split(/\s+/).filter((w) => w.length > 0);
1550
+ const wordCount = words.length;
1551
+ const sentences = input.split(/[.!?]+/).filter((s) => s.trim().length > 0);
1552
+ const avgSentenceLength = sentences.length > 0 ? wordCount / sentences.length : 0;
1553
+ const sentenceVariety = sentences.length > 1 ? 10 : 0;
1554
+ const uniqueWords = new Set(words.map((w) => w.toLowerCase())).size;
1555
+ const lexicalBreadth = wordCount > 0 ? uniqueWords / wordCount * 40 : 0;
1556
+ const markers = (input.match(/[,;:"'()\[\]]/g) || []).length;
1557
+ const structuralHealth = Math.min(markers / wordCount * 100, 20);
1558
+ const repetitivePenalty = this.calculateRepetitivePenalty(input);
1559
+ let score = lexicalBreadth + structuralHealth + sentenceVariety + (avgSentenceLength > 5 ? 20 : 0);
1560
+ score -= repetitivePenalty;
1561
+ return Math.max(0, Math.min(100, score));
1562
+ }
1563
+ /**
1564
+ * Calculate Crystallization Threshold
1565
+ * Logic:
1566
+ * Low CQ (Noise) -> Aggressive optimization (Lower threshold, e.g. 0.6)
1567
+ * High CQ (Quality) -> Conservative optimization (Higher threshold, e.g. 0.9)
1568
+ */
1569
+ static calculateThreshold(cqScore) {
1570
+ if (cqScore < 30) return 0.65;
1571
+ if (cqScore < 60) return 0.78;
1572
+ if (cqScore < 85) return 0.88;
1573
+ return 0.95;
1574
+ }
1575
+ static calculateRepetitivePenalty(input) {
1576
+ const chunks = input.match(/.{1,10}/g) || [];
1577
+ const uniqueChunks = new Set(chunks).size;
1578
+ const ratio = chunks.length > 10 ? uniqueChunks / chunks.length : 1;
1579
+ return ratio < 0.5 ? (1 - ratio) * 50 : 0;
1580
+ }
1581
+ };
1582
+
1382
1583
  // src/core.ts
1383
1584
  var IKFirewallCore = class _IKFirewallCore {
1384
1585
  static instance;
@@ -1433,55 +1634,75 @@ var IKFirewallCore = class _IKFirewallCore {
1433
1634
  FLUID_THRESHOLD: 4
1434
1635
  }
1435
1636
  };
1436
- gatekeeper = new HeuristicGatekeeper();
1637
+ gatekeeper;
1437
1638
  configManager;
1438
1639
  sessionDNA = 0;
1439
- hooks;
1440
1640
  cloudProvider;
1441
1641
  localProvider;
1442
1642
  orchestrator;
1443
1643
  usageTracker;
1644
+ _hooks;
1645
+ defaultConfig;
1444
1646
  constructor(config, hooks, cloudProvider) {
1445
- const defaultConfig = {
1647
+ this.defaultConfig = {
1446
1648
  aggressiveness: 0.15,
1447
1649
  forcedEfficiency: false,
1448
1650
  precisionBias: _IKFirewallCore.CONSTANTS.PRECISION.BIAS_DEFAULT,
1449
1651
  balance: _IKFirewallCore.CONSTANTS.TONE.STABLE_VAL,
1450
1652
  gatekeeperEnabled: true,
1451
1653
  locale: "en",
1452
- providerMode: "hybrid",
1654
+ providerMode: process.env.IK_FIREWALL_MODE || "hybrid",
1453
1655
  runtimeStrategy: "internal",
1454
- localAuditEndpoint: "http://127.0.0.1:8085/v1/chat/completions",
1455
- fallbackToCloudAudit: false,
1656
+ localAuditEndpoint: process.env.IK_FIREWALL_LOCAL_ENDPOINT || "http://127.0.0.1:8085/v1/chat/completions",
1657
+ centralReportEndpoint: (process.env.IK_FIREWALL_CENTRAL_ENDPOINT || "https://ik-firewall.vercel.app").replace(/\/$/, ""),
1658
+ ownerEmail: process.env.IK_FIREWALL_EMAIL,
1659
+ hmacSecret: process.env.IK_FIREWALL_SECRET,
1660
+ fallbackToCloudAudit: process.env.IK_FIREWALL_FALLBACK === "true" || false,
1456
1661
  modelConfig: {
1457
1662
  modelType: "1b"
1458
1663
  },
1459
1664
  plugins: []
1460
1665
  };
1461
- this.configManager = new ConfigManager({ ...defaultConfig, ...config });
1462
- if (hooks) this.hooks = hooks;
1666
+ this._hooks = hooks;
1667
+ this.configManager = new ConfigManager({ ...this.defaultConfig, ...config }, hooks);
1668
+ this.gatekeeper = new HeuristicGatekeeper();
1669
+ this.sessionDNA = _IKFirewallCore.CONSTANTS.DNA.MIN;
1463
1670
  const activeConfig = this.configManager.getConfig();
1464
1671
  this.localProvider = new LocalProvider(activeConfig.localAuditEndpoint);
1465
1672
  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
- }
1673
+ this.cloudProvider = cloudProvider instanceof BaseProvider ? cloudProvider : new OpenAIProvider(cloudProvider);
1674
+ } else if (process.env.OPENAI_API_KEY) {
1675
+ this.cloudProvider = new OpenAIProvider(async (prompt, role) => {
1676
+ const response = await fetch("https://api.openai.com/v1/chat/completions", {
1677
+ method: "POST",
1678
+ headers: {
1679
+ "Authorization": `Bearer ${process.env.OPENAI_API_KEY}`,
1680
+ "Content-Type": "application/json"
1681
+ },
1682
+ body: JSON.stringify({
1683
+ model: role === "audit_layer" ? "gpt-4o-mini" : "gpt-4o",
1684
+ messages: [{ role: "user", content: prompt }],
1685
+ temperature: 0.1
1686
+ })
1687
+ });
1688
+ if (!response.ok) throw new Error(`OpenAI API Error: ${response.statusText}`);
1689
+ const data = await response.json();
1690
+ return {
1691
+ content: data.choices[0].message.content,
1692
+ usage: data.usage
1693
+ };
1694
+ });
1482
1695
  }
1483
1696
  this.orchestrator = new Orchestrator(this.configManager);
1484
- this.usageTracker = new UsageTracker(this.configManager, this.hooks);
1697
+ this.usageTracker = new UsageTracker(this.configManager, this._hooks);
1698
+ }
1699
+ get hooks() {
1700
+ return this._hooks;
1701
+ }
1702
+ set hooks(newHooks) {
1703
+ this._hooks = newHooks;
1704
+ this.configManager.setHooks(newHooks);
1705
+ this.usageTracker.hooks = newHooks;
1485
1706
  }
1486
1707
  static getInstance(config, hooks) {
1487
1708
  if (!_IKFirewallCore.instance) {
@@ -1593,7 +1814,14 @@ var IKFirewallCore = class _IKFirewallCore {
1593
1814
  async analyze(input, provider, personaName = "professional", locale, instanceId) {
1594
1815
  if (instanceId) {
1595
1816
  this.configManager.ensureInstanceConfig(instanceId);
1596
- await this.configManager.syncRemoteConfig(instanceId);
1817
+ const syncPromise = this.configManager.syncRemoteConfig(instanceId).then(async () => {
1818
+ const pendingUsage = this.configManager._pendingUsage;
1819
+ if (pendingUsage && pendingUsage.length > 0) {
1820
+ await this.usageTracker.flush(pendingUsage);
1821
+ this.configManager._pendingUsage = null;
1822
+ }
1823
+ });
1824
+ await syncPromise;
1597
1825
  }
1598
1826
  const mergedConfig = this.configManager.getMergedConfig(instanceId);
1599
1827
  if (instanceId && mergedConfig?.isVerified === false) {
@@ -1663,10 +1891,17 @@ var IKFirewallCore = class _IKFirewallCore {
1663
1891
  throw e;
1664
1892
  }
1665
1893
  }
1666
- this.sniffDNA(input, metrics, activeLocale);
1894
+ const cqScore = CognitiveEngine.sniffDNA(input);
1895
+ metrics.dm = Math.max(metrics.dm, cqScore / 10);
1896
+ this.applyHardening(input, metrics, activeLocale);
1667
1897
  this.hooks?.onAuditComplete?.(metrics);
1668
1898
  return metrics;
1669
1899
  }
1900
+ applyHardening(input, metrics, locale = "en") {
1901
+ const archetype = metrics.semanticInsights?.archetype || "DYNAMIC";
1902
+ const domain = metrics.semanticInsights?.detectedDomain || "GENERAL";
1903
+ this.setSessionDNA(this.sessionDNA + 5);
1904
+ }
1670
1905
  getEmptyMetrics() {
1671
1906
  return {
1672
1907
  dm: 0,
@@ -1718,28 +1953,6 @@ var IKFirewallCore = class _IKFirewallCore {
1718
1953
  inputLength: input.length
1719
1954
  };
1720
1955
  }
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
1956
  async analyzeAIAssisted(input, provider, personaName = "professional", instanceId, configOverride) {
1744
1957
  if (instanceId) {
1745
1958
  this.configManager.ensureInstanceConfig(instanceId);
@@ -1990,11 +2203,13 @@ Any action outside this scope MUST be rejected and flagged as a boundary violati
1990
2203
  this.hooks?.onStatus?.(`\u{1F6E1}\uFE0F IK_CRYSTALLIZE: Precision domain detected (${domain}). Relaxing noise reduction...`);
1991
2204
  archetypeModifier = -0.3;
1992
2205
  }
2206
+ const cqScore = CognitiveEngine.sniffDNA(input);
2207
+ const cognitiveThreshold = CognitiveEngine.calculateThreshold(cqScore);
1993
2208
  const threshold = Math.min(
1994
2209
  _IKFirewallCore.CONSTANTS.AI.THRESHOLD_MAX,
1995
2210
  Math.max(
1996
2211
  _IKFirewallCore.CONSTANTS.AI.THRESHOLD_MIN,
1997
- dm / _IKFirewallCore.CONSTANTS.AI.DM_THRESHOLD_DIVISOR + basePreference - aggModifier + archetypeModifier - tolerance * 0.1
2212
+ cognitiveThreshold + archetypeModifier - tolerance * 0.1
1998
2213
  )
1999
2214
  );
2000
2215
  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.1",
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