@aiqa/sdk 1.5.0-develop.3 → 1.5.0-develop.4

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.
@@ -257,7 +257,7 @@ declare abstract class IAiqaSdk {
257
257
  abstract connect(): void;
258
258
  abstract disconnect(): void;
259
259
  abstract on(eventName: string, callback: (...args: any[]) => any): void;
260
- abstract off(eventName: string): void;
260
+ abstract off(eventName: string, callback?: (...args: any[]) => any): void;
261
261
  abstract getApplication(): Promise<Application>;
262
262
  abstract addFact(fact: ApplicationFactInput): Promise<AddFactResult>;
263
263
  abstract flagFact(factId: string): Promise<FlagFactResult>;
@@ -274,6 +274,7 @@ declare class AiQaSdk implements IAiqaSdk {
274
274
  cachedApplication?: Application;
275
275
  internalListeners: Map<SdkEvent, Set<(...args: any[]) => void>>;
276
276
  internalEvents: Set<SdkEvent>;
277
+ private wrappersByEvent;
277
278
  constructor(applicationId: string, applicationSecret: string, url?: string);
278
279
  on(name: SdkEvent, callback: (...args: any[]) => any): void;
279
280
  off(name: SdkEvent, callback?: (...args: any[]) => any): void;
@@ -3396,7 +3396,7 @@ var compareVersions = (left, right) => {
3396
3396
  // package.json
3397
3397
  var package_default = {
3398
3398
  name: "@aiqa/sdk",
3399
- version: "1.5.0-develop.2",
3399
+ version: "1.5.0-develop.3",
3400
3400
  main: "dist/node/node.js",
3401
3401
  module: "dist/node/node.js",
3402
3402
  types: "dist/node/node.d.ts",
@@ -3480,9 +3480,41 @@ var DEFAULT_URL = "ws://localhost:3025/ws";
3480
3480
  var DEFAULT_TIMEOUT_MS = 6e4;
3481
3481
  var RUNTIME = typeof window !== "undefined" && typeof window.document !== "undefined" ? "browser" : "node";
3482
3482
  var USER_AGENT = RUNTIME === "browser" ? typeof navigator !== "undefined" ? navigator.userAgent : "browser/unknown" : typeof process !== "undefined" ? `node ${process.version} ${process.platform}` : "node/unknown";
3483
+ function isThenable(value2) {
3484
+ return value2 !== null && typeof value2 === "object" && typeof value2.then === "function";
3485
+ }
3486
+ function wrapAckHandler(callback) {
3487
+ return (...args) => {
3488
+ const last = args[args.length - 1];
3489
+ const hasAck = typeof last === "function";
3490
+ const payload = hasAck ? args.slice(0, -1) : args;
3491
+ try {
3492
+ const handlerResult = callback(...payload);
3493
+ if (isThenable(handlerResult)) {
3494
+ handlerResult.then(void 0, (err) => {
3495
+ console.error("[AiQaSdk] async event handler rejected:", err);
3496
+ });
3497
+ }
3498
+ } catch (err) {
3499
+ console.error("[AiQaSdk] event handler threw:", err);
3500
+ } finally {
3501
+ if (hasAck) {
3502
+ try {
3503
+ last();
3504
+ } catch {
3505
+ }
3506
+ }
3507
+ }
3508
+ };
3509
+ }
3483
3510
  var AiQaSdk = class {
3484
3511
  constructor(applicationId, applicationSecret, url2) {
3485
3512
  this.socket = null;
3513
+ // event → originalCallback → Set<wrappedCallback> registered on
3514
+ // socket.io. A Set per (event, callback) so that subscribing the
3515
+ // same fn twice registers two wrappers and two off() calls clear
3516
+ // both.
3517
+ this.wrappersByEvent = /* @__PURE__ */ new Map();
3486
3518
  this.url = url2 ?? DEFAULT_URL;
3487
3519
  this.internalListeners = /* @__PURE__ */ new Map();
3488
3520
  this.internalEvents = /* @__PURE__ */ new Set(["authenticated"]);
@@ -3507,7 +3539,19 @@ var AiQaSdk = class {
3507
3539
  if (this.isManagerEvent(name)) {
3508
3540
  this.socket.io.on(name, callback);
3509
3541
  } else {
3510
- this.socket.on(name, callback);
3542
+ const wrapped = wrapAckHandler(callback);
3543
+ let wrappersByCallback = this.wrappersByEvent.get(name);
3544
+ if (!wrappersByCallback) {
3545
+ wrappersByCallback = /* @__PURE__ */ new Map();
3546
+ this.wrappersByEvent.set(name, wrappersByCallback);
3547
+ }
3548
+ let wrappers = wrappersByCallback.get(callback);
3549
+ if (!wrappers) {
3550
+ wrappers = /* @__PURE__ */ new Set();
3551
+ wrappersByCallback.set(callback, wrappers);
3552
+ }
3553
+ wrappers.add(wrapped);
3554
+ this.socket.on(name, wrapped);
3511
3555
  }
3512
3556
  }
3513
3557
  off(name, callback) {
@@ -3530,6 +3574,25 @@ var AiQaSdk = class {
3530
3574
  }
3531
3575
  if (this.isManagerEvent(name)) {
3532
3576
  this.socket.io.off(name, callback);
3577
+ return;
3578
+ }
3579
+ if (!callback) {
3580
+ this.socket.off(name);
3581
+ this.wrappersByEvent.delete(name);
3582
+ return;
3583
+ }
3584
+ const wrappersByCallback = this.wrappersByEvent.get(name);
3585
+ const wrappers = wrappersByCallback?.get(callback);
3586
+ if (wrappers && wrappers.size > 0) {
3587
+ const wrapped = wrappers.values().next().value;
3588
+ wrappers.delete(wrapped);
3589
+ this.socket.off(name, wrapped);
3590
+ if (wrappers.size === 0) {
3591
+ wrappersByCallback.delete(callback);
3592
+ if (wrappersByCallback.size === 0) {
3593
+ this.wrappersByEvent.delete(name);
3594
+ }
3595
+ }
3533
3596
  } else {
3534
3597
  this.socket.off(name, callback);
3535
3598
  }
@@ -3547,34 +3610,38 @@ var AiQaSdk = class {
3547
3610
  this.socket.on("connect", () => {
3548
3611
  this.authenticate();
3549
3612
  });
3550
- this.socket.on("app_version", (payload) => {
3551
- let versionRange = payload;
3552
- if (typeof payload === "string") {
3553
- try {
3554
- versionRange = JSON.parse(payload);
3555
- } catch (error) {
3556
- versionRange = payload;
3613
+ this.socket.on(
3614
+ "app_version",
3615
+ wrapAckHandler((payload) => {
3616
+ let versionRange = payload;
3617
+ if (typeof payload === "string") {
3618
+ try {
3619
+ versionRange = JSON.parse(payload);
3620
+ } catch (error) {
3621
+ versionRange = payload;
3622
+ }
3557
3623
  }
3558
- }
3559
- const minVersion = versionRange?.min;
3560
- const maxVersion = versionRange?.max;
3561
- if (minVersion || maxVersion) {
3562
- const tooLow = minVersion ? compareVersions(SDK_VERSION, minVersion) < 0 : false;
3563
- const tooHigh = maxVersion ? compareVersions(SDK_VERSION, maxVersion) > 0 : false;
3564
- if (tooLow || tooHigh) {
3565
- const error = new Error(
3566
- `SDK version ${SDK_VERSION} is not supported. Supported range: ${minVersion || "-"} to ${maxVersion || "-"}.`
3567
- );
3568
- this.socket.disconnect();
3569
- this.socket.emit("error", error);
3624
+ const minVersion = versionRange?.min;
3625
+ const maxVersion = versionRange?.max;
3626
+ if (minVersion || maxVersion) {
3627
+ const tooLow = minVersion ? compareVersions(SDK_VERSION, minVersion) < 0 : false;
3628
+ const tooHigh = maxVersion ? compareVersions(SDK_VERSION, maxVersion) > 0 : false;
3629
+ if (tooLow || tooHigh) {
3630
+ const error = new Error(
3631
+ `SDK version ${SDK_VERSION} is not supported. Supported range: ${minVersion || "-"} to ${maxVersion || "-"}.`
3632
+ );
3633
+ this.socket.disconnect();
3634
+ this.socket.emit("error", error);
3635
+ }
3570
3636
  }
3571
- }
3572
- });
3637
+ })
3638
+ );
3573
3639
  }
3574
3640
  disconnect() {
3575
3641
  if (this.socket) {
3576
3642
  this.socket.disconnect();
3577
3643
  }
3644
+ this.wrappersByEvent.clear();
3578
3645
  }
3579
3646
  sendMessage(method, data) {
3580
3647
  return new Promise((resolve, reject) => {