@ik-firewall/core 1.0.2 → 2.2.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
@@ -161,6 +161,48 @@ var ConfigManager = class {
161
161
  ...instanceConfigs
162
162
  };
163
163
  }
164
+ /**
165
+ * Syncs remote configuration (pricing, license status) from the Vercel API.
166
+ * Runs once every 24 hours (Heartbeat).
167
+ */
168
+ async syncRemoteConfig(instanceId) {
169
+ const now = /* @__PURE__ */ new Date();
170
+ const instanceConfig = this.config.instanceConfigs?.[instanceId];
171
+ if (instanceConfig?.lastSyncDate) {
172
+ const lastSync = new Date(instanceConfig.lastSyncDate);
173
+ const hoursSinceSync = (now.getTime() - lastSync.getTime()) / (1e3 * 60 * 60);
174
+ if (hoursSinceSync < 24) {
175
+ return;
176
+ }
177
+ }
178
+ 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) {
196
+ this.setInstanceConfig(instanceId, { firstUseDate: now.toISOString() });
197
+ }
198
+ } catch (error) {
199
+ console.error("[IK_CONFIG] Remote sync failed. Falling open (Fail-Open mode).");
200
+ this.setInstanceConfig(instanceId, {
201
+ isVerified: true,
202
+ lastSyncDate: now.toISOString()
203
+ });
204
+ }
205
+ }
164
206
  getConfig() {
165
207
  return { ...this.config };
166
208
  }
@@ -1280,7 +1322,7 @@ var Orchestrator = class {
1280
1322
  };
1281
1323
 
1282
1324
  // src/UsageTracker.ts
1283
- var UsageTracker = class _UsageTracker {
1325
+ var UsageTracker = class {
1284
1326
  buffer = [];
1285
1327
  MAX_BUFFER_SIZE = 1;
1286
1328
  // Immediate reporting for Edge/Stateless environments
@@ -1302,8 +1344,10 @@ var UsageTracker = class _UsageTracker {
1302
1344
  async logInteraction(params) {
1303
1345
  const { instanceId, model, inputTokens, outputTokens, optimizedTokens = 0, cqScore, routingPath, clientOrigin, trace } = params;
1304
1346
  const tokensSaved = optimizedTokens > 0 ? inputTokens - optimizedTokens : 0;
1305
- const modelPricing = _UsageTracker.PRICING[model] || _UsageTracker.PRICING["gpt-4o-mini"];
1306
- const costSaved = tokensSaved / 1e3 * modelPricing.input;
1347
+ const instanceConfig = this.config.getConfig().instanceConfigs?.[instanceId];
1348
+ const remotePricing = instanceConfig?.pricing?.[model] || { input: 5e-3, output: 0.015 };
1349
+ const costSaved = tokensSaved / 1e3 * remotePricing.input;
1350
+ const commissionDue = costSaved * 0.2;
1307
1351
  const data = {
1308
1352
  instanceId,
1309
1353
  model_used: model,
@@ -1313,6 +1357,7 @@ var UsageTracker = class _UsageTracker {
1313
1357
  optimized_tokens: optimizedTokens,
1314
1358
  tokens_saved: tokensSaved,
1315
1359
  cost_saved: Number(costSaved.toFixed(6)),
1360
+ commission_due: Number(commissionDue.toFixed(6)),
1316
1361
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
1317
1362
  is_local: model === "local",
1318
1363
  cq_score: cqScore,
@@ -1332,7 +1377,6 @@ var UsageTracker = class _UsageTracker {
1332
1377
  if (this.buffer.length === 0) return;
1333
1378
  const endpoint = this.config.get("centralReportEndpoint");
1334
1379
  if (!endpoint) {
1335
- console.warn("[IK_TRACKER] No centralReportEndpoint defined. Clearing buffer to prevent memory leak.");
1336
1380
  this.buffer = [];
1337
1381
  return;
1338
1382
  }
@@ -1347,10 +1391,13 @@ var UsageTracker = class _UsageTracker {
1347
1391
  inputTokens: report.input_tokens,
1348
1392
  outputTokens: report.output_tokens,
1349
1393
  optimizedTokens: report.optimized_tokens,
1394
+ tokensSaved: report.tokens_saved,
1395
+ costSaved: report.cost_saved,
1396
+ commissionDue: report.commission_due,
1350
1397
  cqScore: report.cq_score,
1351
1398
  routingPath: report.routingPath,
1352
1399
  clientOrigin: report.clientOrigin,
1353
- trace: report.trace
1400
+ timestamp: report.timestamp
1354
1401
  })
1355
1402
  });
1356
1403
  }
@@ -1578,6 +1625,14 @@ var IKFirewallCore = class _IKFirewallCore {
1578
1625
  async analyze(input, provider, personaName = "professional", locale, instanceId) {
1579
1626
  if (instanceId) {
1580
1627
  this.configManager.ensureInstanceConfig(instanceId);
1628
+ await this.configManager.syncRemoteConfig(instanceId);
1629
+ }
1630
+ const mergedConfig = this.configManager.getMergedConfig(instanceId);
1631
+ if (instanceId && mergedConfig?.isVerified === false) {
1632
+ if (mergedConfig?.billingStatus === "blocked") {
1633
+ this.hooks?.onStatus?.("\u26A0\uFE0F [IK_FIREWALL] Subscription inactive. Optimization bypassed (Fail-Safe mode).");
1634
+ return this.getEmptyMetrics();
1635
+ }
1581
1636
  }
1582
1637
  let auditProvider = this.localProvider;
1583
1638
  let overrideProvider = null;
@@ -1612,18 +1667,20 @@ var IKFirewallCore = class _IKFirewallCore {
1612
1667
  const ei = (input.match(/[,;.:-]/g) || []).length / (input.split(" ").length || 1);
1613
1668
  let requiresAuditOverride = false;
1614
1669
  let boundaryMetrics = { boundaryScore: 0, requiresHumanIntervention: false };
1615
- if (this.getConfig().safeMode) {
1616
- boundaryMetrics = this.gatekeeper.evaluateBoundaryCommunication(input, this.getConfig().customBoundaryKeywords);
1617
- if (boundaryMetrics.requiresHumanIntervention) {
1670
+ if (this.getConfig()?.safeMode) {
1671
+ boundaryMetrics = this.gatekeeper.evaluateBoundaryCommunication(input, this.getConfig()?.customBoundaryKeywords);
1672
+ if (boundaryMetrics?.requiresHumanIntervention) {
1618
1673
  requiresAuditOverride = true;
1619
1674
  }
1620
1675
  }
1621
1676
  const skipAudit = !requiresAuditOverride && this.getConfig().gatekeeperEnabled && localInsight.complexityScore < _IKFirewallCore.CONSTANTS.HEURISTICS.COMPLEXITY_SKIP_THRESHOLD;
1622
1677
  if (skipAudit) {
1623
1678
  this.hooks?.onStatus?.("\u26A1 IK_GATEKEEPER: Simple request detected. Skipping Deep Audit.");
1624
- const metrics2 = this.createHeuristicMetrics(input, dm, ei, uniqueWords, localInsight.intentMode);
1625
- metrics2.semanticInsights.boundaryScore = boundaryMetrics.boundaryScore;
1626
- metrics2.semanticInsights.requiresHumanIntervention = boundaryMetrics.requiresHumanIntervention;
1679
+ const metrics2 = this.createHeuristicMetrics(input, dm, ei, uniqueWords, localInsight?.intentMode);
1680
+ if (metrics2.semanticInsights) {
1681
+ metrics2.semanticInsights.boundaryScore = boundaryMetrics.boundaryScore;
1682
+ metrics2.semanticInsights.requiresHumanIntervention = boundaryMetrics.requiresHumanIntervention;
1683
+ }
1627
1684
  this.hooks?.onAuditComplete?.(metrics2);
1628
1685
  return metrics2;
1629
1686
  }
@@ -1720,12 +1777,12 @@ var IKFirewallCore = class _IKFirewallCore {
1720
1777
  this.configManager.ensureInstanceConfig(instanceId);
1721
1778
  }
1722
1779
  const activeConfig = this.configManager.getMergedConfig(instanceId, configOverride);
1723
- const locale = activeConfig.locale || "en";
1780
+ const locale = activeConfig?.locale || "en";
1724
1781
  const cqScore = this.orchestrator.calculateCQ(input);
1725
1782
  let isAuditTask = false;
1726
- if (activeConfig.safeMode) {
1727
- const boundaryResult = this.gatekeeper.evaluateBoundaryCommunication(input, activeConfig.customBoundaryKeywords);
1728
- if (boundaryResult.requiresHumanIntervention) {
1783
+ if (activeConfig?.safeMode) {
1784
+ const boundaryResult = this.gatekeeper.evaluateBoundaryCommunication(input, activeConfig?.customBoundaryKeywords);
1785
+ if (boundaryResult?.requiresHumanIntervention) {
1729
1786
  isAuditTask = true;
1730
1787
  }
1731
1788
  }
@@ -1947,7 +2004,11 @@ Any action outside this scope MUST be rejected and flagged as a boundary violati
1947
2004
  inputLength
1948
2005
  };
1949
2006
  }
1950
- crystallize(input, metrics, locale = "en") {
2007
+ crystallize(input, metrics, locale = "en", instanceId) {
2008
+ const mergedConfig = this.configManager.getMergedConfig(instanceId);
2009
+ if (instanceId && mergedConfig?.isVerified === false) {
2010
+ return input;
2011
+ }
1951
2012
  const archetype = metrics?.semanticInsights?.archetype || "DYNAMIC";
1952
2013
  const tolerance = metrics?.semanticInsights?.ambiguityTolerance || 0.5;
1953
2014
  const blueprint = metrics?.semanticInsights?.conceptualBlueprint;
package/dist/index.d.cts CHANGED
@@ -43,6 +43,15 @@ interface IKConfig {
43
43
  contextMode?: ContextMode;
44
44
  instanceConfigs?: Record<string, Partial<IKConfig>>;
45
45
  isEnabled?: boolean;
46
+ licenseKey?: string;
47
+ billingStatus?: 'active' | 'blocked' | 'trial';
48
+ isVerified?: boolean;
49
+ firstUseDate?: string;
50
+ lastSyncDate?: string;
51
+ pricing?: Record<string, {
52
+ input: number;
53
+ output: number;
54
+ }>;
46
55
  }
47
56
  interface IKPluginInfo {
48
57
  id: string;
@@ -147,6 +156,7 @@ interface UsageData {
147
156
  optimized_tokens?: number;
148
157
  tokens_saved: number;
149
158
  cost_saved: number;
159
+ commission_due: number;
150
160
  timestamp: string;
151
161
  is_local: boolean;
152
162
  cq_score: number;
@@ -352,7 +362,7 @@ declare class IKFirewallCore {
352
362
  private calculateDNARank;
353
363
  private constructAuditPrompt;
354
364
  private getFallbackMetrics;
355
- crystallize(input: string, metrics?: IKMetrics, locale?: string): string;
365
+ crystallize(input: string, metrics?: IKMetrics, locale?: string, instanceId?: string): string;
356
366
  private miniCrystallize;
357
367
  getAgentDirective(personaName: string, userInsights?: IKMetrics['semanticInsights'], locale?: string): string;
358
368
  private getApproachGuidance;
package/dist/index.d.ts CHANGED
@@ -43,6 +43,15 @@ interface IKConfig {
43
43
  contextMode?: ContextMode;
44
44
  instanceConfigs?: Record<string, Partial<IKConfig>>;
45
45
  isEnabled?: boolean;
46
+ licenseKey?: string;
47
+ billingStatus?: 'active' | 'blocked' | 'trial';
48
+ isVerified?: boolean;
49
+ firstUseDate?: string;
50
+ lastSyncDate?: string;
51
+ pricing?: Record<string, {
52
+ input: number;
53
+ output: number;
54
+ }>;
46
55
  }
47
56
  interface IKPluginInfo {
48
57
  id: string;
@@ -147,6 +156,7 @@ interface UsageData {
147
156
  optimized_tokens?: number;
148
157
  tokens_saved: number;
149
158
  cost_saved: number;
159
+ commission_due: number;
150
160
  timestamp: string;
151
161
  is_local: boolean;
152
162
  cq_score: number;
@@ -352,7 +362,7 @@ declare class IKFirewallCore {
352
362
  private calculateDNARank;
353
363
  private constructAuditPrompt;
354
364
  private getFallbackMetrics;
355
- crystallize(input: string, metrics?: IKMetrics, locale?: string): string;
365
+ crystallize(input: string, metrics?: IKMetrics, locale?: string, instanceId?: string): string;
356
366
  private miniCrystallize;
357
367
  getAgentDirective(personaName: string, userInsights?: IKMetrics['semanticInsights'], locale?: string): string;
358
368
  private getApproachGuidance;
package/dist/index.js CHANGED
@@ -129,6 +129,48 @@ var ConfigManager = class {
129
129
  ...instanceConfigs
130
130
  };
131
131
  }
132
+ /**
133
+ * Syncs remote configuration (pricing, license status) from the Vercel API.
134
+ * Runs once every 24 hours (Heartbeat).
135
+ */
136
+ async syncRemoteConfig(instanceId) {
137
+ const now = /* @__PURE__ */ new Date();
138
+ const instanceConfig = this.config.instanceConfigs?.[instanceId];
139
+ if (instanceConfig?.lastSyncDate) {
140
+ const lastSync = new Date(instanceConfig.lastSyncDate);
141
+ const hoursSinceSync = (now.getTime() - lastSync.getTime()) / (1e3 * 60 * 60);
142
+ if (hoursSinceSync < 24) {
143
+ return;
144
+ }
145
+ }
146
+ 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) {
164
+ this.setInstanceConfig(instanceId, { firstUseDate: now.toISOString() });
165
+ }
166
+ } catch (error) {
167
+ console.error("[IK_CONFIG] Remote sync failed. Falling open (Fail-Open mode).");
168
+ this.setInstanceConfig(instanceId, {
169
+ isVerified: true,
170
+ lastSyncDate: now.toISOString()
171
+ });
172
+ }
173
+ }
132
174
  getConfig() {
133
175
  return { ...this.config };
134
176
  }
@@ -1248,7 +1290,7 @@ var Orchestrator = class {
1248
1290
  };
1249
1291
 
1250
1292
  // src/UsageTracker.ts
1251
- var UsageTracker = class _UsageTracker {
1293
+ var UsageTracker = class {
1252
1294
  buffer = [];
1253
1295
  MAX_BUFFER_SIZE = 1;
1254
1296
  // Immediate reporting for Edge/Stateless environments
@@ -1270,8 +1312,10 @@ var UsageTracker = class _UsageTracker {
1270
1312
  async logInteraction(params) {
1271
1313
  const { instanceId, model, inputTokens, outputTokens, optimizedTokens = 0, cqScore, routingPath, clientOrigin, trace } = params;
1272
1314
  const tokensSaved = optimizedTokens > 0 ? inputTokens - optimizedTokens : 0;
1273
- const modelPricing = _UsageTracker.PRICING[model] || _UsageTracker.PRICING["gpt-4o-mini"];
1274
- const costSaved = tokensSaved / 1e3 * modelPricing.input;
1315
+ const instanceConfig = this.config.getConfig().instanceConfigs?.[instanceId];
1316
+ const remotePricing = instanceConfig?.pricing?.[model] || { input: 5e-3, output: 0.015 };
1317
+ const costSaved = tokensSaved / 1e3 * remotePricing.input;
1318
+ const commissionDue = costSaved * 0.2;
1275
1319
  const data = {
1276
1320
  instanceId,
1277
1321
  model_used: model,
@@ -1281,6 +1325,7 @@ var UsageTracker = class _UsageTracker {
1281
1325
  optimized_tokens: optimizedTokens,
1282
1326
  tokens_saved: tokensSaved,
1283
1327
  cost_saved: Number(costSaved.toFixed(6)),
1328
+ commission_due: Number(commissionDue.toFixed(6)),
1284
1329
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
1285
1330
  is_local: model === "local",
1286
1331
  cq_score: cqScore,
@@ -1300,7 +1345,6 @@ var UsageTracker = class _UsageTracker {
1300
1345
  if (this.buffer.length === 0) return;
1301
1346
  const endpoint = this.config.get("centralReportEndpoint");
1302
1347
  if (!endpoint) {
1303
- console.warn("[IK_TRACKER] No centralReportEndpoint defined. Clearing buffer to prevent memory leak.");
1304
1348
  this.buffer = [];
1305
1349
  return;
1306
1350
  }
@@ -1315,10 +1359,13 @@ var UsageTracker = class _UsageTracker {
1315
1359
  inputTokens: report.input_tokens,
1316
1360
  outputTokens: report.output_tokens,
1317
1361
  optimizedTokens: report.optimized_tokens,
1362
+ tokensSaved: report.tokens_saved,
1363
+ costSaved: report.cost_saved,
1364
+ commissionDue: report.commission_due,
1318
1365
  cqScore: report.cq_score,
1319
1366
  routingPath: report.routingPath,
1320
1367
  clientOrigin: report.clientOrigin,
1321
- trace: report.trace
1368
+ timestamp: report.timestamp
1322
1369
  })
1323
1370
  });
1324
1371
  }
@@ -1546,6 +1593,14 @@ var IKFirewallCore = class _IKFirewallCore {
1546
1593
  async analyze(input, provider, personaName = "professional", locale, instanceId) {
1547
1594
  if (instanceId) {
1548
1595
  this.configManager.ensureInstanceConfig(instanceId);
1596
+ await this.configManager.syncRemoteConfig(instanceId);
1597
+ }
1598
+ const mergedConfig = this.configManager.getMergedConfig(instanceId);
1599
+ if (instanceId && mergedConfig?.isVerified === false) {
1600
+ if (mergedConfig?.billingStatus === "blocked") {
1601
+ this.hooks?.onStatus?.("\u26A0\uFE0F [IK_FIREWALL] Subscription inactive. Optimization bypassed (Fail-Safe mode).");
1602
+ return this.getEmptyMetrics();
1603
+ }
1549
1604
  }
1550
1605
  let auditProvider = this.localProvider;
1551
1606
  let overrideProvider = null;
@@ -1580,18 +1635,20 @@ var IKFirewallCore = class _IKFirewallCore {
1580
1635
  const ei = (input.match(/[,;.:-]/g) || []).length / (input.split(" ").length || 1);
1581
1636
  let requiresAuditOverride = false;
1582
1637
  let boundaryMetrics = { boundaryScore: 0, requiresHumanIntervention: false };
1583
- if (this.getConfig().safeMode) {
1584
- boundaryMetrics = this.gatekeeper.evaluateBoundaryCommunication(input, this.getConfig().customBoundaryKeywords);
1585
- if (boundaryMetrics.requiresHumanIntervention) {
1638
+ if (this.getConfig()?.safeMode) {
1639
+ boundaryMetrics = this.gatekeeper.evaluateBoundaryCommunication(input, this.getConfig()?.customBoundaryKeywords);
1640
+ if (boundaryMetrics?.requiresHumanIntervention) {
1586
1641
  requiresAuditOverride = true;
1587
1642
  }
1588
1643
  }
1589
1644
  const skipAudit = !requiresAuditOverride && this.getConfig().gatekeeperEnabled && localInsight.complexityScore < _IKFirewallCore.CONSTANTS.HEURISTICS.COMPLEXITY_SKIP_THRESHOLD;
1590
1645
  if (skipAudit) {
1591
1646
  this.hooks?.onStatus?.("\u26A1 IK_GATEKEEPER: Simple request detected. Skipping Deep Audit.");
1592
- const metrics2 = this.createHeuristicMetrics(input, dm, ei, uniqueWords, localInsight.intentMode);
1593
- metrics2.semanticInsights.boundaryScore = boundaryMetrics.boundaryScore;
1594
- metrics2.semanticInsights.requiresHumanIntervention = boundaryMetrics.requiresHumanIntervention;
1647
+ const metrics2 = this.createHeuristicMetrics(input, dm, ei, uniqueWords, localInsight?.intentMode);
1648
+ if (metrics2.semanticInsights) {
1649
+ metrics2.semanticInsights.boundaryScore = boundaryMetrics.boundaryScore;
1650
+ metrics2.semanticInsights.requiresHumanIntervention = boundaryMetrics.requiresHumanIntervention;
1651
+ }
1595
1652
  this.hooks?.onAuditComplete?.(metrics2);
1596
1653
  return metrics2;
1597
1654
  }
@@ -1688,12 +1745,12 @@ var IKFirewallCore = class _IKFirewallCore {
1688
1745
  this.configManager.ensureInstanceConfig(instanceId);
1689
1746
  }
1690
1747
  const activeConfig = this.configManager.getMergedConfig(instanceId, configOverride);
1691
- const locale = activeConfig.locale || "en";
1748
+ const locale = activeConfig?.locale || "en";
1692
1749
  const cqScore = this.orchestrator.calculateCQ(input);
1693
1750
  let isAuditTask = false;
1694
- if (activeConfig.safeMode) {
1695
- const boundaryResult = this.gatekeeper.evaluateBoundaryCommunication(input, activeConfig.customBoundaryKeywords);
1696
- if (boundaryResult.requiresHumanIntervention) {
1751
+ if (activeConfig?.safeMode) {
1752
+ const boundaryResult = this.gatekeeper.evaluateBoundaryCommunication(input, activeConfig?.customBoundaryKeywords);
1753
+ if (boundaryResult?.requiresHumanIntervention) {
1697
1754
  isAuditTask = true;
1698
1755
  }
1699
1756
  }
@@ -1915,7 +1972,11 @@ Any action outside this scope MUST be rejected and flagged as a boundary violati
1915
1972
  inputLength
1916
1973
  };
1917
1974
  }
1918
- crystallize(input, metrics, locale = "en") {
1975
+ crystallize(input, metrics, locale = "en", instanceId) {
1976
+ const mergedConfig = this.configManager.getMergedConfig(instanceId);
1977
+ if (instanceId && mergedConfig?.isVerified === false) {
1978
+ return input;
1979
+ }
1919
1980
  const archetype = metrics?.semanticInsights?.archetype || "DYNAMIC";
1920
1981
  const tolerance = metrics?.semanticInsights?.ambiguityTolerance || 0.5;
1921
1982
  const blueprint = metrics?.semanticInsights?.conceptualBlueprint;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ik-firewall/core",
3
- "version": "1.0.2",
3
+ "version": "2.2.0",
4
4
  "type": "module",
5
5
  "description": "The core IK Firewall engine for semantic-driven AI optimization.",
6
6
  "main": "./dist/index.js",
@@ -8,18 +8,20 @@
8
8
  "types": "./dist/index.d.ts",
9
9
  "exports": {
10
10
  ".": {
11
+ "types": "./dist/index.d.ts",
11
12
  "import": "./dist/index.js",
12
- "require": "./dist/index.cjs",
13
- "types": "./dist/index.d.ts"
13
+ "require": "./dist/index.cjs"
14
14
  }
15
15
  },
16
16
  "files": [
17
17
  "dist",
18
18
  "scripts"
19
19
  ],
20
+ "api_endpoint": "https://ik-firewall-backend.vercel.app/api/v1",
20
21
  "scripts": {
21
22
  "prepare": "npm run build",
22
23
  "build": "tsup src/index.ts --format cjs,esm --dts --clean",
24
+ "build:wasm": "cd wasm-core && wasm-pack build --target nodejs",
23
25
  "dev": "tsup src/index.ts --format cjs,esm --watch --dts",
24
26
  "lint": "eslint src/**/*.ts",
25
27
  "test": "jest",
@@ -35,7 +37,7 @@
35
37
  "optimization"
36
38
  ],
37
39
  "author": "Stefan Vasic",
38
- "license": "MIT",
40
+ "license": "BSL-1.1",
39
41
  "devDependencies": {
40
42
  "@types/node": "^25.0.10",
41
43
  "tsup": "^8.0.0",
@@ -1,44 +1,83 @@
1
1
  import fs from 'fs';
2
2
  import path from 'path';
3
3
  import { fileURLToPath } from 'url';
4
+ import readline from 'node:readline';
4
5
 
5
6
  const __filename = fileURLToPath(import.meta.url);
6
7
  const __dirname = path.dirname(__filename);
7
8
 
8
9
  // Constants
9
10
  const BIN_DIR = path.join(__dirname, '..', '.bin');
10
- const RUNTIME_NAME = process.platform === 'win32' ? 'ik-runtime.exe' : 'ik-runtime';
11
- const MODEL_NAME = 'ik-local-1b-v1.gguf';
11
+ const REGISTRY_DIR = path.join(process.cwd(), '.ik-adapter');
12
+ const REGISTRY_FILE = path.join(REGISTRY_DIR, 'registry.json');
13
+
14
+ async function askEmail() {
15
+ if (process.env.IK_EMAIL) return process.env.IK_EMAIL;
16
+
17
+ const rl = readline.createInterface({
18
+ input: process.stdin,
19
+ output: process.stdout
20
+ });
21
+
22
+ const prompt = (query) => new Promise((resolve) => rl.question(query, resolve));
23
+
24
+ let email = "";
25
+ while (!email || !email.includes('@')) {
26
+ email = await prompt('\nšŸ“§ IK_FIREWALL: [MANDATORY] Please enter your email to activate your account: ');
27
+ if (!email || !email.includes('@')) {
28
+ console.log('āš ļø Invalid email. Email is required for license generation.');
29
+ }
30
+ }
31
+ rl.close();
32
+ return email;
33
+ }
12
34
 
13
35
  async function setup() {
14
- if (process.env.CI || process.env.VERCEL) {
15
- console.log('ā­ļø IK_FIREWALL: CI/Vercel environment detected. Skipping local runtime setup.');
36
+ // Vercel / Netlify / AWS Lambda often have read-only file systems
37
+ if (process.env.VERCEL || process.env.RENDER || process.env.AWS_LAMBDA_FUNCTION_NAME) {
38
+ console.log('\nā­ļø IK_FIREWALL: Read-only Serverless environment detected.');
39
+ console.log('šŸ’” NOTE: Registry & Local Binary setup will be bypassed. Ensure you set "centralReportEndpoint" via code config.');
16
40
  return;
17
41
  }
18
- console.log('šŸš€ IK_FIREWALL: Initiating Zero-Config Runtime Setup...');
42
+ console.log('\nšŸš€ IK_FIREWALL: Initiating Zero-Config Runtime Setup...');
19
43
 
20
- // 1. Create .bin directory
21
- if (!fs.existsSync(BIN_DIR)) {
22
- fs.mkdirSync(BIN_DIR, { recursive: true });
23
- console.log(`āœ… Created directory: ${BIN_DIR}`);
44
+ // 1. Create .bin and .ik-adapter directories
45
+ [BIN_DIR, REGISTRY_DIR].forEach(dir => {
46
+ if (!fs.existsSync(dir)) {
47
+ fs.mkdirSync(dir, { recursive: true });
48
+ }
49
+ });
50
+
51
+ // 2. Initialize Trial Registry
52
+ if (!fs.existsSync(REGISTRY_FILE)) {
53
+ const email = await askEmail();
54
+ const initialRegistry = {
55
+ "default": {
56
+ "licenseKey": "TRIAL-" + Math.random().toString(36).substring(7).toUpperCase(),
57
+ "billingStatus": "trial",
58
+ "isVerified": true,
59
+ "firstUseDate": new Date().toISOString(),
60
+ "ownerEmail": email,
61
+ "isEnabled": true
62
+ }
63
+ };
64
+ fs.writeFileSync(REGISTRY_FILE, JSON.stringify(initialRegistry, null, 2));
65
+ console.log(`✨ Trial activated for: ${email}`);
24
66
  }
25
67
 
26
- // 2. Detect OS & Architecture
68
+ // 3. Detect OS & Architecture
27
69
  const platform = process.platform;
28
70
  const arch = process.arch;
29
71
  console.log(`šŸ” Detected environment: ${platform}-${arch}`);
30
72
 
31
- // 3. Inform user about the Emulator (since binary is OS-dependent)
32
- const emulatorPath = path.join(__dirname, 'runtime-emulator.js');
33
- console.log(`\nšŸ’” TIP: For this prototype on Windows, use the Node.js Emulator instead of the .exe:`);
34
- console.log(` node scripts/runtime-emulator.js`);
35
-
36
- // Create a helper dev script in package.json context or similar
37
- console.log('\nšŸ“¦ IK-Runtime environment prepared.');
38
- console.log('✨ IK Adapter is now ready for local escalation testing!');
73
+ // 4. Usage Tips
74
+ console.log(`\nšŸ“¦ IK-Runtime environment prepared.`);
75
+ console.log('šŸ’” TIP: For local optimization (Sidecar), use "npm run start-ai".');
76
+ console.log('šŸ› ļø DEV: If building locally, you can use the Node.js Emulator: node scripts/runtime-emulator.js');
77
+ console.log('✨ IK Adapter is now ready for production-grade AI protection!\n');
39
78
  }
40
79
 
41
80
  setup().catch(err => {
42
81
  console.error('āŒ IK_FIREWALL Setup Failed:', err.message);
43
- process.exit(1);
82
+ process.exit(0); // Don't block install on setup error
44
83
  });