@ik-firewall/core 2.3.6 → 2.4.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
@@ -202,6 +202,7 @@ var ConfigManager = class {
202
202
  config;
203
203
  registry;
204
204
  hooks;
205
+ blockedInstances = /* @__PURE__ */ new Set();
205
206
  constructor(initialConfig, hooks) {
206
207
  this.config = initialConfig;
207
208
  this.hooks = hooks;
@@ -308,11 +309,27 @@ var ConfigManager = class {
308
309
  if (instanceId && this.config.instanceConfigs?.[instanceId]) {
309
310
  merged = { ...merged, ...this.config.instanceConfigs[instanceId] };
310
311
  }
312
+ if (instanceId && this.blockedInstances.has(instanceId)) {
313
+ merged.billingStatus = "blocked";
314
+ }
311
315
  if (override) {
312
316
  merged = { ...merged, ...override };
313
317
  }
314
318
  return merged;
315
319
  }
320
+ /**
321
+ * Updates the live blocked status for an instance (Kill-Switch).
322
+ * This is used by UsageTracker when it receives a response from the central server.
323
+ */
324
+ setBlockedStatus(instanceId, blocked) {
325
+ if (blocked) {
326
+ this.blockedInstances.add(instanceId);
327
+ this.setInstanceConfig(instanceId, { billingStatus: "blocked" });
328
+ } else {
329
+ this.blockedInstances.delete(instanceId);
330
+ this.setInstanceConfig(instanceId, { billingStatus: "active" });
331
+ }
332
+ }
316
333
  updateConfig(newConfig) {
317
334
  this.config = {
318
335
  ...this.config,
@@ -1528,8 +1545,14 @@ var UsageTracker = class {
1528
1545
  try {
1529
1546
  await this.sendBatch(payload);
1530
1547
  } catch (error) {
1531
- console.error("[IK_TRACKER] Batch send failed, queuing for retry:", error);
1532
- this.handleFailure(payload);
1548
+ console.error("[IK_TRACKER] Batch send failed:", error.message);
1549
+ const isAuthError = error.message?.includes("401");
1550
+ if (!isAuthError) {
1551
+ console.log("[IK_TRACKER] Queuing for retry...");
1552
+ this.handleFailure(payload);
1553
+ } else {
1554
+ console.warn("[IK_TRACKER] Unauthorized: Please check your IK_FIREWALL_SECRET and License Key. Discarding batch.");
1555
+ }
1533
1556
  } finally {
1534
1557
  this.flushInProgress = false;
1535
1558
  }
@@ -1538,6 +1561,9 @@ var UsageTracker = class {
1538
1561
  const baseUrl = this.config.get("centralReportEndpoint") || "https://ik-firewall.vercel.app";
1539
1562
  const endpoint = `${baseUrl.replace(/\/$/, "")}/api/v1/report`;
1540
1563
  const hmacSecret = this.config.get("hmacSecret") || process.env.IK_FIREWALL_SECRET;
1564
+ if (process.env.IK_FIREWALL_DISABLED === "true" || process.env.NEXT_PUBLIC_IK_FIREWALL_DISABLED === "true") {
1565
+ return;
1566
+ }
1541
1567
  if (hmacSecret) {
1542
1568
  try {
1543
1569
  const crypto = typeof window === "undefined" ? (await import("crypto")).default : null;
@@ -1558,6 +1584,16 @@ var UsageTracker = class {
1558
1584
  if (!response.ok) {
1559
1585
  throw new Error(`HTTP Error: ${response.status} ${response.statusText}`);
1560
1586
  }
1587
+ try {
1588
+ const data = await response.json();
1589
+ if (data && (data.status === "blocked" || data.billingStatus === "blocked")) {
1590
+ this.config.setBlockedStatus(payload.instanceId, true);
1591
+ console.warn(`[IK_TRACKER] \u{1F6E1}\uFE0F Kill-Switch triggered for ${payload.instanceId}: Subscription inactive/blocked.`);
1592
+ } else if (data && (data.status === "active" || data.billingStatus === "active" || data.status === "trial")) {
1593
+ this.config.setBlockedStatus(payload.instanceId, false);
1594
+ }
1595
+ } catch (e) {
1596
+ }
1561
1597
  this.hooks?.onFlushSuccess?.(payload);
1562
1598
  }
1563
1599
  async handleFailure(payload) {
@@ -1860,16 +1896,11 @@ var IKFirewallCore = class _IKFirewallCore {
1860
1896
  }
1861
1897
  if (instanceId) {
1862
1898
  this.configManager.ensureInstanceConfig(instanceId);
1863
- this.configManager.syncRemoteConfig(instanceId).catch((err) => {
1864
- console.warn("[IK_CORE] Heartbeat sync failed:", err);
1865
- });
1866
1899
  }
1867
1900
  const mergedConfig = this.configManager.getMergedConfig(instanceId);
1868
- if (instanceId && mergedConfig?.isVerified === false) {
1869
- if (mergedConfig?.billingStatus === "blocked") {
1870
- this.hooks?.onStatus?.("\u26A0\uFE0F [IK_FIREWALL] Subscription inactive. Optimization bypassed (Fail-Safe mode).");
1871
- return this.getEmptyMetrics();
1872
- }
1901
+ if (instanceId && mergedConfig?.billingStatus === "blocked") {
1902
+ this.hooks?.onStatus?.("\u26A0\uFE0F [IK_FIREWALL] Subscription inactive. Optimization bypassed (Fail-Safe mode).");
1903
+ return this.getEmptyMetrics();
1873
1904
  }
1874
1905
  let auditProvider = this.localProvider;
1875
1906
  let overrideProvider = null;
package/dist/index.js CHANGED
@@ -160,6 +160,7 @@ var ConfigManager = class {
160
160
  config;
161
161
  registry;
162
162
  hooks;
163
+ blockedInstances = /* @__PURE__ */ new Set();
163
164
  constructor(initialConfig, hooks) {
164
165
  this.config = initialConfig;
165
166
  this.hooks = hooks;
@@ -266,11 +267,27 @@ var ConfigManager = class {
266
267
  if (instanceId && this.config.instanceConfigs?.[instanceId]) {
267
268
  merged = { ...merged, ...this.config.instanceConfigs[instanceId] };
268
269
  }
270
+ if (instanceId && this.blockedInstances.has(instanceId)) {
271
+ merged.billingStatus = "blocked";
272
+ }
269
273
  if (override) {
270
274
  merged = { ...merged, ...override };
271
275
  }
272
276
  return merged;
273
277
  }
278
+ /**
279
+ * Updates the live blocked status for an instance (Kill-Switch).
280
+ * This is used by UsageTracker when it receives a response from the central server.
281
+ */
282
+ setBlockedStatus(instanceId, blocked) {
283
+ if (blocked) {
284
+ this.blockedInstances.add(instanceId);
285
+ this.setInstanceConfig(instanceId, { billingStatus: "blocked" });
286
+ } else {
287
+ this.blockedInstances.delete(instanceId);
288
+ this.setInstanceConfig(instanceId, { billingStatus: "active" });
289
+ }
290
+ }
274
291
  updateConfig(newConfig) {
275
292
  this.config = {
276
293
  ...this.config,
@@ -1486,8 +1503,14 @@ var UsageTracker = class {
1486
1503
  try {
1487
1504
  await this.sendBatch(payload);
1488
1505
  } catch (error) {
1489
- console.error("[IK_TRACKER] Batch send failed, queuing for retry:", error);
1490
- this.handleFailure(payload);
1506
+ console.error("[IK_TRACKER] Batch send failed:", error.message);
1507
+ const isAuthError = error.message?.includes("401");
1508
+ if (!isAuthError) {
1509
+ console.log("[IK_TRACKER] Queuing for retry...");
1510
+ this.handleFailure(payload);
1511
+ } else {
1512
+ console.warn("[IK_TRACKER] Unauthorized: Please check your IK_FIREWALL_SECRET and License Key. Discarding batch.");
1513
+ }
1491
1514
  } finally {
1492
1515
  this.flushInProgress = false;
1493
1516
  }
@@ -1496,6 +1519,9 @@ var UsageTracker = class {
1496
1519
  const baseUrl = this.config.get("centralReportEndpoint") || "https://ik-firewall.vercel.app";
1497
1520
  const endpoint = `${baseUrl.replace(/\/$/, "")}/api/v1/report`;
1498
1521
  const hmacSecret = this.config.get("hmacSecret") || process.env.IK_FIREWALL_SECRET;
1522
+ if (process.env.IK_FIREWALL_DISABLED === "true" || process.env.NEXT_PUBLIC_IK_FIREWALL_DISABLED === "true") {
1523
+ return;
1524
+ }
1499
1525
  if (hmacSecret) {
1500
1526
  try {
1501
1527
  const crypto = typeof window === "undefined" ? (await import("crypto")).default : null;
@@ -1516,6 +1542,16 @@ var UsageTracker = class {
1516
1542
  if (!response.ok) {
1517
1543
  throw new Error(`HTTP Error: ${response.status} ${response.statusText}`);
1518
1544
  }
1545
+ try {
1546
+ const data = await response.json();
1547
+ if (data && (data.status === "blocked" || data.billingStatus === "blocked")) {
1548
+ this.config.setBlockedStatus(payload.instanceId, true);
1549
+ console.warn(`[IK_TRACKER] \u{1F6E1}\uFE0F Kill-Switch triggered for ${payload.instanceId}: Subscription inactive/blocked.`);
1550
+ } else if (data && (data.status === "active" || data.billingStatus === "active" || data.status === "trial")) {
1551
+ this.config.setBlockedStatus(payload.instanceId, false);
1552
+ }
1553
+ } catch (e) {
1554
+ }
1519
1555
  this.hooks?.onFlushSuccess?.(payload);
1520
1556
  }
1521
1557
  async handleFailure(payload) {
@@ -1818,16 +1854,11 @@ var IKFirewallCore = class _IKFirewallCore {
1818
1854
  }
1819
1855
  if (instanceId) {
1820
1856
  this.configManager.ensureInstanceConfig(instanceId);
1821
- this.configManager.syncRemoteConfig(instanceId).catch((err) => {
1822
- console.warn("[IK_CORE] Heartbeat sync failed:", err);
1823
- });
1824
1857
  }
1825
1858
  const mergedConfig = this.configManager.getMergedConfig(instanceId);
1826
- if (instanceId && mergedConfig?.isVerified === false) {
1827
- if (mergedConfig?.billingStatus === "blocked") {
1828
- this.hooks?.onStatus?.("\u26A0\uFE0F [IK_FIREWALL] Subscription inactive. Optimization bypassed (Fail-Safe mode).");
1829
- return this.getEmptyMetrics();
1830
- }
1859
+ if (instanceId && mergedConfig?.billingStatus === "blocked") {
1860
+ this.hooks?.onStatus?.("\u26A0\uFE0F [IK_FIREWALL] Subscription inactive. Optimization bypassed (Fail-Safe mode).");
1861
+ return this.getEmptyMetrics();
1831
1862
  }
1832
1863
  let auditProvider = this.localProvider;
1833
1864
  let overrideProvider = null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ik-firewall/core",
3
- "version": "2.3.6",
3
+ "version": "2.4.0",
4
4
  "type": "module",
5
5
  "description": "The core IK Firewall engine for semantic-driven AI optimization.",
6
6
  "main": "./dist/index.js",