@ik-firewall/core 2.3.7 → 2.4.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
@@ -90,10 +90,10 @@ var Registry = class _Registry {
90
90
  /**
91
91
  * Loads instance configurations with Hook support
92
92
  */
93
- load() {
93
+ async load() {
94
94
  if (this.hooks?.loadState) {
95
95
  try {
96
- const hookData = this.hooks.loadState("ik_registry");
96
+ const hookData = await this.hooks.loadState("ik_registry");
97
97
  if (hookData) return JSON.parse(hookData);
98
98
  } catch (e) {
99
99
  console.warn("[IK_REGISTRY] Registry load via hook failed, falling back...");
@@ -114,10 +114,10 @@ var Registry = class _Registry {
114
114
  }
115
115
  return {};
116
116
  }
117
- save(data) {
117
+ async save(data) {
118
118
  const jsonStr = JSON.stringify(data, null, 2);
119
119
  if (this.hooks?.persistState) {
120
- this.hooks.persistState("ik_registry", jsonStr);
120
+ await this.hooks.persistState("ik_registry", jsonStr);
121
121
  }
122
122
  if (fs && this.registryPath) {
123
123
  try {
@@ -132,10 +132,10 @@ var Registry = class _Registry {
132
132
  }
133
133
  }
134
134
  }
135
- updateInstance(instanceId, config) {
136
- const all = this.load();
135
+ async updateInstance(instanceId, config) {
136
+ const all = await this.load();
137
137
  all[instanceId] = { ...all[instanceId] || {}, ...config, updatedAt: (/* @__PURE__ */ new Date()).toISOString() };
138
- this.save(all);
138
+ await this.save(all);
139
139
  }
140
140
  getUsageFilePath() {
141
141
  return this.usagePath;
@@ -158,13 +158,25 @@ var Registry = class _Registry {
158
158
  } catch (e) {
159
159
  }
160
160
  }
161
- clearUsage() {
161
+ async clearUsage() {
162
162
  if (!fs || !this.usagePath) return;
163
163
  try {
164
164
  if (fs.existsSync(this.usagePath)) fs.unlinkSync(this.usagePath);
165
165
  } catch (e) {
166
166
  }
167
167
  }
168
+ async getLastFlushTime() {
169
+ if (this.hooks?.loadState) {
170
+ const val = await this.hooks.loadState("ik_last_flush");
171
+ if (val) return parseInt(val, 10);
172
+ }
173
+ return null;
174
+ }
175
+ async setLastFlushTime(time) {
176
+ if (this.hooks?.persistState) {
177
+ await this.hooks.persistState("ik_last_flush", time.toString());
178
+ }
179
+ }
168
180
  };
169
181
 
170
182
  // src/lib/hmac.ts
@@ -202,6 +214,7 @@ var ConfigManager = class {
202
214
  config;
203
215
  registry;
204
216
  hooks;
217
+ blockedInstances = /* @__PURE__ */ new Set();
205
218
  constructor(initialConfig, hooks) {
206
219
  this.config = initialConfig;
207
220
  this.hooks = hooks;
@@ -209,7 +222,6 @@ var ConfigManager = class {
209
222
  if (hooks) {
210
223
  this.registry.setHooks(hooks);
211
224
  }
212
- this.loadFromRegistry();
213
225
  }
214
226
  getRegistry() {
215
227
  return this.registry;
@@ -225,16 +237,16 @@ var ConfigManager = class {
225
237
  if (state) {
226
238
  const parsed = JSON.parse(state);
227
239
  const registry = this.registry;
228
- registry.save(parsed);
229
- this.loadFromRegistry();
240
+ await registry.save(parsed);
241
+ await this.loadFromRegistry();
230
242
  }
231
243
  } catch (e) {
232
244
  console.warn("[IK_CONFIG] Hydration from hooks failed:", e);
233
245
  }
234
246
  }
235
247
  }
236
- loadFromRegistry() {
237
- const instanceConfigs = this.registry.load();
248
+ async loadFromRegistry() {
249
+ const instanceConfigs = await this.registry.load();
238
250
  this.config.instanceConfigs = {
239
251
  ...this.config.instanceConfigs || {},
240
252
  ...instanceConfigs
@@ -276,7 +288,7 @@ var ConfigManager = class {
276
288
  return;
277
289
  }
278
290
  }
279
- this.setInstanceConfig(instanceId, {
291
+ await this.setInstanceConfig(instanceId, {
280
292
  billingStatus: data.billingStatus,
281
293
  isVerified: data.isVerified,
282
294
  pricing: data.pricing,
@@ -288,7 +300,7 @@ var ConfigManager = class {
288
300
  }
289
301
  } catch (error) {
290
302
  console.error(`[IK_CONFIG] Remote sync failed (${error.message}). Falling open (Fail-Open mode).`);
291
- this.setInstanceConfig(instanceId, {
303
+ await this.setInstanceConfig(instanceId, {
292
304
  isVerified: true,
293
305
  lastSyncDate: now.toISOString()
294
306
  });
@@ -308,11 +320,27 @@ var ConfigManager = class {
308
320
  if (instanceId && this.config.instanceConfigs?.[instanceId]) {
309
321
  merged = { ...merged, ...this.config.instanceConfigs[instanceId] };
310
322
  }
323
+ if (instanceId && this.blockedInstances.has(instanceId)) {
324
+ merged.billingStatus = "blocked";
325
+ }
311
326
  if (override) {
312
327
  merged = { ...merged, ...override };
313
328
  }
314
329
  return merged;
315
330
  }
331
+ /**
332
+ * Updates the live blocked status for an instance (Kill-Switch).
333
+ * This is used by UsageTracker when it receives a response from the central server.
334
+ */
335
+ async setBlockedStatus(instanceId, blocked) {
336
+ if (blocked) {
337
+ this.blockedInstances.add(instanceId);
338
+ await this.setInstanceConfig(instanceId, { billingStatus: "blocked" });
339
+ } else {
340
+ this.blockedInstances.delete(instanceId);
341
+ await this.setInstanceConfig(instanceId, { billingStatus: "active" });
342
+ }
343
+ }
316
344
  updateConfig(newConfig) {
317
345
  this.config = {
318
346
  ...this.config,
@@ -351,7 +379,7 @@ var ConfigManager = class {
351
379
  return false;
352
380
  }
353
381
  }
354
- this.setInstanceConfig(instanceId, {
382
+ await this.setInstanceConfig(instanceId, {
355
383
  licenseKey: data.licenseKey,
356
384
  billingStatus: data.status.toLowerCase(),
357
385
  isVerified: true,
@@ -367,10 +395,10 @@ var ConfigManager = class {
367
395
  return false;
368
396
  }
369
397
  }
370
- ensureInstanceConfig(instanceId) {
371
- const all = this.registry.load();
398
+ async ensureInstanceConfig(instanceId) {
399
+ const all = await this.registry.load();
372
400
  if (!all[instanceId]) {
373
- this.registry.updateInstance(instanceId, {
401
+ await this.registry.updateInstance(instanceId, {
374
402
  balance: this.config.balance || 0.5,
375
403
  aggressiveness: this.config.aggressiveness || 0.5,
376
404
  isEnabled: true,
@@ -378,15 +406,15 @@ var ConfigManager = class {
378
406
  ownerEmail: this.config.ownerEmail
379
407
  // Inherit from global if not specific
380
408
  });
381
- this.loadFromRegistry();
409
+ await this.loadFromRegistry();
382
410
  }
383
411
  }
384
- getInstanceConfigs() {
412
+ async getInstanceConfigs() {
385
413
  return this.registry.load();
386
414
  }
387
- setInstanceConfig(instanceId, config) {
388
- this.registry.updateInstance(instanceId, config);
389
- this.loadFromRegistry();
415
+ async setInstanceConfig(instanceId, config) {
416
+ await this.registry.updateInstance(instanceId, config);
417
+ await this.loadFromRegistry();
390
418
  }
391
419
  };
392
420
 
@@ -1505,11 +1533,14 @@ var UsageTracker = class {
1505
1533
  }
1506
1534
  async checkFlushConditions(instanceId) {
1507
1535
  const now = Date.now();
1536
+ if (this.lastFlushTime === 0) {
1537
+ const persisted = await this.config.getRegistry().getLastFlushTime();
1538
+ if (persisted) this.lastFlushTime = persisted;
1539
+ else this.lastFlushTime = now;
1540
+ }
1508
1541
  const timeSinceFlush = now - this.lastFlushTime;
1509
1542
  if (this.aggregationMap.size >= this.BATCH_SIZE_THRESHOLD || timeSinceFlush >= this.TIME_THRESHOLD_MS) {
1510
- this.performAsyncFlush(instanceId).catch((err) => {
1511
- console.error("[IK_TRACKER] Background flush failed:", err);
1512
- });
1543
+ await this.performAsyncFlush(instanceId);
1513
1544
  }
1514
1545
  }
1515
1546
  async performAsyncFlush(instanceId) {
@@ -1518,7 +1549,8 @@ var UsageTracker = class {
1518
1549
  const reports = Array.from(this.aggregationMap.values());
1519
1550
  this.aggregationMap.clear();
1520
1551
  this.lastFlushTime = Date.now();
1521
- const licenseKey = this.config.getConfig().instanceConfigs?.[instanceId]?.licenseKey || this.config.get("licenseKey");
1552
+ const instanceConfigs = await this.config.getInstanceConfigs();
1553
+ const licenseKey = instanceConfigs[instanceId]?.licenseKey || this.config.get("licenseKey");
1522
1554
  const payload = {
1523
1555
  licenseKey: licenseKey || "TRIAL-KEY",
1524
1556
  instanceId,
@@ -1551,7 +1583,8 @@ var UsageTracker = class {
1551
1583
  try {
1552
1584
  const crypto = typeof window === "undefined" ? (await import("crypto")).default : null;
1553
1585
  if (crypto && crypto.createHmac) {
1554
- payload.signature = crypto.createHmac("sha256", hmacSecret).update(JSON.stringify(payload)).digest("hex");
1586
+ const { signature: _sig, ...signablePayload } = payload;
1587
+ payload.signature = crypto.createHmac("sha256", hmacSecret).update(JSON.stringify(signablePayload)).digest("hex");
1555
1588
  }
1556
1589
  } catch (e) {
1557
1590
  }
@@ -1567,6 +1600,17 @@ var UsageTracker = class {
1567
1600
  if (!response.ok) {
1568
1601
  throw new Error(`HTTP Error: ${response.status} ${response.statusText}`);
1569
1602
  }
1603
+ try {
1604
+ const data = await response.json();
1605
+ if (data && (data.status === "blocked" || data.billingStatus === "blocked")) {
1606
+ this.config.setBlockedStatus(payload.instanceId, true);
1607
+ console.warn(`[IK_TRACKER] \u{1F6E1}\uFE0F Kill-Switch triggered for ${payload.instanceId}: Subscription inactive/blocked.`);
1608
+ } else if (data && (data.status === "active" || data.billingStatus === "active" || data.status === "trial")) {
1609
+ this.config.setBlockedStatus(payload.instanceId, false);
1610
+ }
1611
+ } catch (e) {
1612
+ }
1613
+ await this.config.getRegistry().setLastFlushTime(this.lastFlushTime);
1570
1614
  this.hooks?.onFlushSuccess?.(payload);
1571
1615
  }
1572
1616
  async handleFailure(payload) {
@@ -1780,11 +1824,11 @@ var IKFirewallCore = class _IKFirewallCore {
1780
1824
  getSessionDNA() {
1781
1825
  return this.sessionDNA;
1782
1826
  }
1783
- getInstanceConfigs() {
1827
+ async getInstanceConfigs() {
1784
1828
  return this.configManager.getInstanceConfigs();
1785
1829
  }
1786
- setInstanceConfig(instanceId, config) {
1787
- this.configManager.setInstanceConfig(instanceId, config);
1830
+ async setInstanceConfig(instanceId, config) {
1831
+ await this.configManager.setInstanceConfig(instanceId, config);
1788
1832
  }
1789
1833
  /**
1790
1834
  * Discovers available providers by checking environment variables and local health.
@@ -1868,17 +1912,12 @@ var IKFirewallCore = class _IKFirewallCore {
1868
1912
  this.hydrated = true;
1869
1913
  }
1870
1914
  if (instanceId) {
1871
- this.configManager.ensureInstanceConfig(instanceId);
1872
- this.configManager.syncRemoteConfig(instanceId).catch((err) => {
1873
- console.warn("[IK_CORE] Heartbeat sync failed:", err);
1874
- });
1915
+ await this.configManager.ensureInstanceConfig(instanceId);
1875
1916
  }
1876
1917
  const mergedConfig = this.configManager.getMergedConfig(instanceId);
1877
- if (instanceId && mergedConfig?.isVerified === false) {
1878
- if (mergedConfig?.billingStatus === "blocked") {
1879
- this.hooks?.onStatus?.("\u26A0\uFE0F [IK_FIREWALL] Subscription inactive. Optimization bypassed (Fail-Safe mode).");
1880
- return this.getEmptyMetrics();
1881
- }
1918
+ if (instanceId && mergedConfig?.billingStatus === "blocked") {
1919
+ this.hooks?.onStatus?.("\u26A0\uFE0F [IK_FIREWALL] Subscription inactive. Optimization bypassed (Fail-Safe mode).");
1920
+ return this.getEmptyMetrics();
1882
1921
  }
1883
1922
  let auditProvider = this.localProvider;
1884
1923
  let overrideProvider = null;
@@ -2008,7 +2047,7 @@ var IKFirewallCore = class _IKFirewallCore {
2008
2047
  }
2009
2048
  async analyzeAIAssisted(input, provider, personaName = "professional", instanceId, configOverride) {
2010
2049
  if (instanceId) {
2011
- this.configManager.ensureInstanceConfig(instanceId);
2050
+ await this.configManager.ensureInstanceConfig(instanceId);
2012
2051
  }
2013
2052
  const activeConfig = this.configManager.getMergedConfig(instanceId, configOverride);
2014
2053
  const locale = activeConfig?.locale || "en";
package/dist/index.d.cts CHANGED
@@ -340,8 +340,8 @@ declare class IKFirewallCore {
340
340
  getConfig(): IKConfig;
341
341
  getPlugins(): IKPluginInfo[];
342
342
  getSessionDNA(): number;
343
- getInstanceConfigs(): Record<string, Partial<IKConfig>>;
344
- setInstanceConfig(instanceId: string, config: Partial<IKConfig>): void;
343
+ getInstanceConfigs(): Promise<Record<string, Partial<IKConfig>>>;
344
+ setInstanceConfig(instanceId: string, config: Partial<IKConfig>): Promise<void>;
345
345
  /**
346
346
  * Discovers available providers by checking environment variables and local health.
347
347
  */
package/dist/index.d.ts CHANGED
@@ -340,8 +340,8 @@ declare class IKFirewallCore {
340
340
  getConfig(): IKConfig;
341
341
  getPlugins(): IKPluginInfo[];
342
342
  getSessionDNA(): number;
343
- getInstanceConfigs(): Record<string, Partial<IKConfig>>;
344
- setInstanceConfig(instanceId: string, config: Partial<IKConfig>): void;
343
+ getInstanceConfigs(): Promise<Record<string, Partial<IKConfig>>>;
344
+ setInstanceConfig(instanceId: string, config: Partial<IKConfig>): Promise<void>;
345
345
  /**
346
346
  * Discovers available providers by checking environment variables and local health.
347
347
  */
package/dist/index.js CHANGED
@@ -48,10 +48,10 @@ var Registry = class _Registry {
48
48
  /**
49
49
  * Loads instance configurations with Hook support
50
50
  */
51
- load() {
51
+ async load() {
52
52
  if (this.hooks?.loadState) {
53
53
  try {
54
- const hookData = this.hooks.loadState("ik_registry");
54
+ const hookData = await this.hooks.loadState("ik_registry");
55
55
  if (hookData) return JSON.parse(hookData);
56
56
  } catch (e) {
57
57
  console.warn("[IK_REGISTRY] Registry load via hook failed, falling back...");
@@ -72,10 +72,10 @@ var Registry = class _Registry {
72
72
  }
73
73
  return {};
74
74
  }
75
- save(data) {
75
+ async save(data) {
76
76
  const jsonStr = JSON.stringify(data, null, 2);
77
77
  if (this.hooks?.persistState) {
78
- this.hooks.persistState("ik_registry", jsonStr);
78
+ await this.hooks.persistState("ik_registry", jsonStr);
79
79
  }
80
80
  if (fs && this.registryPath) {
81
81
  try {
@@ -90,10 +90,10 @@ var Registry = class _Registry {
90
90
  }
91
91
  }
92
92
  }
93
- updateInstance(instanceId, config) {
94
- const all = this.load();
93
+ async updateInstance(instanceId, config) {
94
+ const all = await this.load();
95
95
  all[instanceId] = { ...all[instanceId] || {}, ...config, updatedAt: (/* @__PURE__ */ new Date()).toISOString() };
96
- this.save(all);
96
+ await this.save(all);
97
97
  }
98
98
  getUsageFilePath() {
99
99
  return this.usagePath;
@@ -116,13 +116,25 @@ var Registry = class _Registry {
116
116
  } catch (e) {
117
117
  }
118
118
  }
119
- clearUsage() {
119
+ async clearUsage() {
120
120
  if (!fs || !this.usagePath) return;
121
121
  try {
122
122
  if (fs.existsSync(this.usagePath)) fs.unlinkSync(this.usagePath);
123
123
  } catch (e) {
124
124
  }
125
125
  }
126
+ async getLastFlushTime() {
127
+ if (this.hooks?.loadState) {
128
+ const val = await this.hooks.loadState("ik_last_flush");
129
+ if (val) return parseInt(val, 10);
130
+ }
131
+ return null;
132
+ }
133
+ async setLastFlushTime(time) {
134
+ if (this.hooks?.persistState) {
135
+ await this.hooks.persistState("ik_last_flush", time.toString());
136
+ }
137
+ }
126
138
  };
127
139
 
128
140
  // src/lib/hmac.ts
@@ -160,6 +172,7 @@ var ConfigManager = class {
160
172
  config;
161
173
  registry;
162
174
  hooks;
175
+ blockedInstances = /* @__PURE__ */ new Set();
163
176
  constructor(initialConfig, hooks) {
164
177
  this.config = initialConfig;
165
178
  this.hooks = hooks;
@@ -167,7 +180,6 @@ var ConfigManager = class {
167
180
  if (hooks) {
168
181
  this.registry.setHooks(hooks);
169
182
  }
170
- this.loadFromRegistry();
171
183
  }
172
184
  getRegistry() {
173
185
  return this.registry;
@@ -183,16 +195,16 @@ var ConfigManager = class {
183
195
  if (state) {
184
196
  const parsed = JSON.parse(state);
185
197
  const registry = this.registry;
186
- registry.save(parsed);
187
- this.loadFromRegistry();
198
+ await registry.save(parsed);
199
+ await this.loadFromRegistry();
188
200
  }
189
201
  } catch (e) {
190
202
  console.warn("[IK_CONFIG] Hydration from hooks failed:", e);
191
203
  }
192
204
  }
193
205
  }
194
- loadFromRegistry() {
195
- const instanceConfigs = this.registry.load();
206
+ async loadFromRegistry() {
207
+ const instanceConfigs = await this.registry.load();
196
208
  this.config.instanceConfigs = {
197
209
  ...this.config.instanceConfigs || {},
198
210
  ...instanceConfigs
@@ -234,7 +246,7 @@ var ConfigManager = class {
234
246
  return;
235
247
  }
236
248
  }
237
- this.setInstanceConfig(instanceId, {
249
+ await this.setInstanceConfig(instanceId, {
238
250
  billingStatus: data.billingStatus,
239
251
  isVerified: data.isVerified,
240
252
  pricing: data.pricing,
@@ -246,7 +258,7 @@ var ConfigManager = class {
246
258
  }
247
259
  } catch (error) {
248
260
  console.error(`[IK_CONFIG] Remote sync failed (${error.message}). Falling open (Fail-Open mode).`);
249
- this.setInstanceConfig(instanceId, {
261
+ await this.setInstanceConfig(instanceId, {
250
262
  isVerified: true,
251
263
  lastSyncDate: now.toISOString()
252
264
  });
@@ -266,11 +278,27 @@ var ConfigManager = class {
266
278
  if (instanceId && this.config.instanceConfigs?.[instanceId]) {
267
279
  merged = { ...merged, ...this.config.instanceConfigs[instanceId] };
268
280
  }
281
+ if (instanceId && this.blockedInstances.has(instanceId)) {
282
+ merged.billingStatus = "blocked";
283
+ }
269
284
  if (override) {
270
285
  merged = { ...merged, ...override };
271
286
  }
272
287
  return merged;
273
288
  }
289
+ /**
290
+ * Updates the live blocked status for an instance (Kill-Switch).
291
+ * This is used by UsageTracker when it receives a response from the central server.
292
+ */
293
+ async setBlockedStatus(instanceId, blocked) {
294
+ if (blocked) {
295
+ this.blockedInstances.add(instanceId);
296
+ await this.setInstanceConfig(instanceId, { billingStatus: "blocked" });
297
+ } else {
298
+ this.blockedInstances.delete(instanceId);
299
+ await this.setInstanceConfig(instanceId, { billingStatus: "active" });
300
+ }
301
+ }
274
302
  updateConfig(newConfig) {
275
303
  this.config = {
276
304
  ...this.config,
@@ -309,7 +337,7 @@ var ConfigManager = class {
309
337
  return false;
310
338
  }
311
339
  }
312
- this.setInstanceConfig(instanceId, {
340
+ await this.setInstanceConfig(instanceId, {
313
341
  licenseKey: data.licenseKey,
314
342
  billingStatus: data.status.toLowerCase(),
315
343
  isVerified: true,
@@ -325,10 +353,10 @@ var ConfigManager = class {
325
353
  return false;
326
354
  }
327
355
  }
328
- ensureInstanceConfig(instanceId) {
329
- const all = this.registry.load();
356
+ async ensureInstanceConfig(instanceId) {
357
+ const all = await this.registry.load();
330
358
  if (!all[instanceId]) {
331
- this.registry.updateInstance(instanceId, {
359
+ await this.registry.updateInstance(instanceId, {
332
360
  balance: this.config.balance || 0.5,
333
361
  aggressiveness: this.config.aggressiveness || 0.5,
334
362
  isEnabled: true,
@@ -336,15 +364,15 @@ var ConfigManager = class {
336
364
  ownerEmail: this.config.ownerEmail
337
365
  // Inherit from global if not specific
338
366
  });
339
- this.loadFromRegistry();
367
+ await this.loadFromRegistry();
340
368
  }
341
369
  }
342
- getInstanceConfigs() {
370
+ async getInstanceConfigs() {
343
371
  return this.registry.load();
344
372
  }
345
- setInstanceConfig(instanceId, config) {
346
- this.registry.updateInstance(instanceId, config);
347
- this.loadFromRegistry();
373
+ async setInstanceConfig(instanceId, config) {
374
+ await this.registry.updateInstance(instanceId, config);
375
+ await this.loadFromRegistry();
348
376
  }
349
377
  };
350
378
 
@@ -1463,11 +1491,14 @@ var UsageTracker = class {
1463
1491
  }
1464
1492
  async checkFlushConditions(instanceId) {
1465
1493
  const now = Date.now();
1494
+ if (this.lastFlushTime === 0) {
1495
+ const persisted = await this.config.getRegistry().getLastFlushTime();
1496
+ if (persisted) this.lastFlushTime = persisted;
1497
+ else this.lastFlushTime = now;
1498
+ }
1466
1499
  const timeSinceFlush = now - this.lastFlushTime;
1467
1500
  if (this.aggregationMap.size >= this.BATCH_SIZE_THRESHOLD || timeSinceFlush >= this.TIME_THRESHOLD_MS) {
1468
- this.performAsyncFlush(instanceId).catch((err) => {
1469
- console.error("[IK_TRACKER] Background flush failed:", err);
1470
- });
1501
+ await this.performAsyncFlush(instanceId);
1471
1502
  }
1472
1503
  }
1473
1504
  async performAsyncFlush(instanceId) {
@@ -1476,7 +1507,8 @@ var UsageTracker = class {
1476
1507
  const reports = Array.from(this.aggregationMap.values());
1477
1508
  this.aggregationMap.clear();
1478
1509
  this.lastFlushTime = Date.now();
1479
- const licenseKey = this.config.getConfig().instanceConfigs?.[instanceId]?.licenseKey || this.config.get("licenseKey");
1510
+ const instanceConfigs = await this.config.getInstanceConfigs();
1511
+ const licenseKey = instanceConfigs[instanceId]?.licenseKey || this.config.get("licenseKey");
1480
1512
  const payload = {
1481
1513
  licenseKey: licenseKey || "TRIAL-KEY",
1482
1514
  instanceId,
@@ -1509,7 +1541,8 @@ var UsageTracker = class {
1509
1541
  try {
1510
1542
  const crypto = typeof window === "undefined" ? (await import("crypto")).default : null;
1511
1543
  if (crypto && crypto.createHmac) {
1512
- payload.signature = crypto.createHmac("sha256", hmacSecret).update(JSON.stringify(payload)).digest("hex");
1544
+ const { signature: _sig, ...signablePayload } = payload;
1545
+ payload.signature = crypto.createHmac("sha256", hmacSecret).update(JSON.stringify(signablePayload)).digest("hex");
1513
1546
  }
1514
1547
  } catch (e) {
1515
1548
  }
@@ -1525,6 +1558,17 @@ var UsageTracker = class {
1525
1558
  if (!response.ok) {
1526
1559
  throw new Error(`HTTP Error: ${response.status} ${response.statusText}`);
1527
1560
  }
1561
+ try {
1562
+ const data = await response.json();
1563
+ if (data && (data.status === "blocked" || data.billingStatus === "blocked")) {
1564
+ this.config.setBlockedStatus(payload.instanceId, true);
1565
+ console.warn(`[IK_TRACKER] \u{1F6E1}\uFE0F Kill-Switch triggered for ${payload.instanceId}: Subscription inactive/blocked.`);
1566
+ } else if (data && (data.status === "active" || data.billingStatus === "active" || data.status === "trial")) {
1567
+ this.config.setBlockedStatus(payload.instanceId, false);
1568
+ }
1569
+ } catch (e) {
1570
+ }
1571
+ await this.config.getRegistry().setLastFlushTime(this.lastFlushTime);
1528
1572
  this.hooks?.onFlushSuccess?.(payload);
1529
1573
  }
1530
1574
  async handleFailure(payload) {
@@ -1738,11 +1782,11 @@ var IKFirewallCore = class _IKFirewallCore {
1738
1782
  getSessionDNA() {
1739
1783
  return this.sessionDNA;
1740
1784
  }
1741
- getInstanceConfigs() {
1785
+ async getInstanceConfigs() {
1742
1786
  return this.configManager.getInstanceConfigs();
1743
1787
  }
1744
- setInstanceConfig(instanceId, config) {
1745
- this.configManager.setInstanceConfig(instanceId, config);
1788
+ async setInstanceConfig(instanceId, config) {
1789
+ await this.configManager.setInstanceConfig(instanceId, config);
1746
1790
  }
1747
1791
  /**
1748
1792
  * Discovers available providers by checking environment variables and local health.
@@ -1826,17 +1870,12 @@ var IKFirewallCore = class _IKFirewallCore {
1826
1870
  this.hydrated = true;
1827
1871
  }
1828
1872
  if (instanceId) {
1829
- this.configManager.ensureInstanceConfig(instanceId);
1830
- this.configManager.syncRemoteConfig(instanceId).catch((err) => {
1831
- console.warn("[IK_CORE] Heartbeat sync failed:", err);
1832
- });
1873
+ await this.configManager.ensureInstanceConfig(instanceId);
1833
1874
  }
1834
1875
  const mergedConfig = this.configManager.getMergedConfig(instanceId);
1835
- if (instanceId && mergedConfig?.isVerified === false) {
1836
- if (mergedConfig?.billingStatus === "blocked") {
1837
- this.hooks?.onStatus?.("\u26A0\uFE0F [IK_FIREWALL] Subscription inactive. Optimization bypassed (Fail-Safe mode).");
1838
- return this.getEmptyMetrics();
1839
- }
1876
+ if (instanceId && mergedConfig?.billingStatus === "blocked") {
1877
+ this.hooks?.onStatus?.("\u26A0\uFE0F [IK_FIREWALL] Subscription inactive. Optimization bypassed (Fail-Safe mode).");
1878
+ return this.getEmptyMetrics();
1840
1879
  }
1841
1880
  let auditProvider = this.localProvider;
1842
1881
  let overrideProvider = null;
@@ -1966,7 +2005,7 @@ var IKFirewallCore = class _IKFirewallCore {
1966
2005
  }
1967
2006
  async analyzeAIAssisted(input, provider, personaName = "professional", instanceId, configOverride) {
1968
2007
  if (instanceId) {
1969
- this.configManager.ensureInstanceConfig(instanceId);
2008
+ await this.configManager.ensureInstanceConfig(instanceId);
1970
2009
  }
1971
2010
  const activeConfig = this.configManager.getMergedConfig(instanceId, configOverride);
1972
2011
  const locale = activeConfig?.locale || "en";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ik-firewall/core",
3
- "version": "2.3.7",
3
+ "version": "2.4.1",
4
4
  "type": "module",
5
5
  "description": "The core IK Firewall engine for semantic-driven AI optimization.",
6
6
  "main": "./dist/index.js",