@smplkit/sdk 3.0.2 → 3.0.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.
package/dist/index.cjs CHANGED
@@ -20555,6 +20555,30 @@ var FlagsClient = class {
20555
20555
  this._flagFlushTimer = setInterval(() => {
20556
20556
  void this._flushFlags();
20557
20557
  }, FLAG_REGISTRATION_FLUSH_INTERVAL_MS);
20558
+ if (typeof this._flagFlushTimer === "object" && "unref" in this._flagFlushTimer) {
20559
+ this._flagFlushTimer.unref();
20560
+ }
20561
+ }
20562
+ /**
20563
+ * Synchronous teardown — clears the flag-flush interval and unsubscribes
20564
+ * from WebSocket events. Called by `SmplClient.close()`. Does not flush
20565
+ * pending context observations (use {@link disconnect} for that).
20566
+ * @internal
20567
+ */
20568
+ _close() {
20569
+ if (this._flagFlushTimer !== null) {
20570
+ clearInterval(this._flagFlushTimer);
20571
+ this._flagFlushTimer = null;
20572
+ }
20573
+ if (this._wsManager !== null) {
20574
+ this._wsManager.off("flag_changed", this._handleFlagChanged);
20575
+ this._wsManager.off("flag_deleted", this._handleFlagDeleted);
20576
+ this._wsManager.off("flags_changed", this._handleFlagsChanged);
20577
+ this._wsManager = null;
20578
+ }
20579
+ this._cache.clear();
20580
+ this._initialized = false;
20581
+ this._environment = null;
20558
20582
  }
20559
20583
  /** Disconnect the flags runtime and release resources. */
20560
20584
  async disconnect() {
@@ -20711,6 +20735,9 @@ var FlagsClient = class {
20711
20735
  this._flagFlushTimer = setInterval(() => {
20712
20736
  void this._flushFlags();
20713
20737
  }, FLAG_REGISTRATION_FLUSH_INTERVAL_MS);
20738
+ if (typeof this._flagFlushTimer === "object" && "unref" in this._flagFlushTimer) {
20739
+ this._flagFlushTimer.unref();
20740
+ }
20714
20741
  }
20715
20742
  // ------------------------------------------------------------------
20716
20743
  // Internal: event handlers (called by SharedWebSocket)
@@ -21058,10 +21085,39 @@ var LoggingClient = class {
21058
21085
  * `install()`.
21059
21086
  *
21060
21087
  * Mirrors Python's `client.logging.install()`. There is no `stop()`.
21088
+ *
21089
+ * Adapter coverage:
21090
+ * - **winston**: pre-existing named loggers (`winston.loggers.*`) and the
21091
+ * default logger are auto-discovered.
21092
+ * - **pino**: pino has no global registry, so only loggers created
21093
+ * through `pino()` / `logger.child()` *after* `install()` runs are
21094
+ * tracked. To bring pre-existing pino loggers under management, recreate
21095
+ * them after install or register them explicitly via
21096
+ * `client.manage.loggers.register([...])`.
21097
+ *
21098
+ * After the initial pass, call {@link refresh} to re-fetch managed levels
21099
+ * from the server and re-apply them onto the native loggers (e.g. after
21100
+ * suspecting drift, or to force a manual sync outside the WebSocket).
21061
21101
  */
21062
21102
  async install() {
21063
21103
  return this._installInternal();
21064
21104
  }
21105
+ /**
21106
+ * Re-fetch logger and group levels from the server and re-apply them
21107
+ * onto the registered adapters.
21108
+ *
21109
+ * Diff-based: change listeners only fire for loggers whose level
21110
+ * actually changed (added, removed, or different level), with
21111
+ * `source: "manual"`. Mirrors Python's `client.logging.refresh()`.
21112
+ *
21113
+ * @throws SmplError if `install()` has not been called.
21114
+ */
21115
+ async refresh() {
21116
+ if (!this._started) {
21117
+ throw new SmplError("Logging not installed. Call install() first.");
21118
+ }
21119
+ await this._resolveAndFire("manual");
21120
+ }
21065
21121
  /**
21066
21122
  * @deprecated Use {@link LoggingClient.install}. Retained as a backwards-
21067
21123
  * compatible alias.
@@ -21134,6 +21190,9 @@ var LoggingClient = class {
21134
21190
  this._loggerFlushTimer = setInterval(() => {
21135
21191
  void this._flushLoggerBuffer();
21136
21192
  }, 3e4);
21193
+ if (typeof this._loggerFlushTimer === "object" && "unref" in this._loggerFlushTimer) {
21194
+ this._loggerFlushTimer.unref();
21195
+ }
21137
21196
  this._started = true;
21138
21197
  }
21139
21198
  // ------------------------------------------------------------------
@@ -21405,63 +21464,75 @@ var LoggingClient = class {
21405
21464
  };
21406
21465
  _handleLoggersChanged = (_data) => {
21407
21466
  debug("websocket", `loggers_changed event received`);
21408
- void Promise.all([this._listLoggers(), this._listLogGroups()]).then(([serverLoggers, serverGroups]) => {
21409
- debug("resolution", `resolution pass (trigger: loggers_changed event)`);
21410
- const changedLoggerIds = /* @__PURE__ */ new Set();
21411
- const newLoggerKeys = new Set(serverLoggers.map((l) => l.id));
21412
- for (const logger of serverLoggers) {
21413
- const key = logger.id;
21414
- const oldLevel = this._loggerStore[key] ?? null;
21415
- const newLevel = logger.level ?? null;
21416
- if (oldLevel !== newLevel || !(key in this._loggerStore)) {
21417
- changedLoggerIds.add(key);
21418
- this._loggerStore[key] = newLevel;
21419
- }
21420
- }
21421
- for (const key of Object.keys(this._loggerStore)) {
21422
- if (!newLoggerKeys.has(key)) {
21423
- changedLoggerIds.add(key);
21424
- delete this._loggerStore[key];
21425
- }
21426
- }
21427
- for (const group of serverGroups) {
21428
- this._groupStore[group.id] = group.level ?? null;
21429
- }
21430
- this._applyLevels(serverLoggers);
21431
- if (changedLoggerIds.size === 0) return;
21432
- const [firstKey] = changedLoggerIds;
21433
- const firstLogger = serverLoggers.find((l) => l.id === firstKey);
21434
- const globalEvent = new LoggerChangeEvent({
21435
- id: firstKey,
21436
- level: firstLogger?.level ?? null,
21437
- source: "websocket"
21438
- });
21439
- for (const cb of this._globalListeners) {
21440
- try {
21441
- cb(globalEvent);
21442
- } catch {
21443
- }
21467
+ void this._resolveAndFire("websocket").catch(() => {
21468
+ });
21469
+ };
21470
+ /**
21471
+ * Full refetch of loggers + log_groups, apply resolved levels to
21472
+ * adapters, diff against local stores and fire change listeners
21473
+ * (global once, per-key for each changed id). Shared between the
21474
+ * `loggers_changed` WS handler and the public `refresh()` method.
21475
+ * @internal
21476
+ */
21477
+ async _resolveAndFire(source) {
21478
+ const [serverLoggers, serverGroups] = await Promise.all([
21479
+ this._listLoggers(),
21480
+ this._listLogGroups()
21481
+ ]);
21482
+ debug("resolution", `resolution pass (trigger: ${source})`);
21483
+ const changedLoggerIds = /* @__PURE__ */ new Set();
21484
+ const newLoggerKeys = new Set(serverLoggers.map((l) => l.id));
21485
+ for (const logger of serverLoggers) {
21486
+ const key = logger.id;
21487
+ const oldLevel = this._loggerStore[key] ?? null;
21488
+ const newLevel = logger.level ?? null;
21489
+ if (oldLevel !== newLevel || !(key in this._loggerStore)) {
21490
+ changedLoggerIds.add(key);
21491
+ this._loggerStore[key] = newLevel;
21492
+ }
21493
+ }
21494
+ for (const key of Object.keys(this._loggerStore)) {
21495
+ if (!newLoggerKeys.has(key)) {
21496
+ changedLoggerIds.add(key);
21497
+ delete this._loggerStore[key];
21498
+ }
21499
+ }
21500
+ for (const group of serverGroups) {
21501
+ this._groupStore[group.id] = group.level ?? null;
21502
+ }
21503
+ this._applyLevels(serverLoggers);
21504
+ if (changedLoggerIds.size === 0) return;
21505
+ const [firstKey] = changedLoggerIds;
21506
+ const firstLogger = serverLoggers.find((l) => l.id === firstKey);
21507
+ const globalEvent = new LoggerChangeEvent({
21508
+ id: firstKey,
21509
+ level: firstLogger?.level ?? null,
21510
+ source
21511
+ });
21512
+ for (const cb of this._globalListeners) {
21513
+ try {
21514
+ cb(globalEvent);
21515
+ } catch {
21444
21516
  }
21445
- for (const key of changedLoggerIds) {
21446
- const keyCallbacks = this._keyListeners.get(key);
21447
- if (keyCallbacks) {
21448
- const l = serverLoggers.find((x) => x.id === key);
21449
- const keyEvent = new LoggerChangeEvent({
21450
- id: key,
21451
- level: l?.level ?? null,
21452
- source: "websocket"
21453
- });
21454
- for (const cb of keyCallbacks) {
21455
- try {
21456
- cb(keyEvent);
21457
- } catch {
21458
- }
21517
+ }
21518
+ for (const key of changedLoggerIds) {
21519
+ const keyCallbacks = this._keyListeners.get(key);
21520
+ if (keyCallbacks) {
21521
+ const l = serverLoggers.find((x) => x.id === key);
21522
+ const keyEvent = new LoggerChangeEvent({
21523
+ id: key,
21524
+ level: l?.level ?? null,
21525
+ source
21526
+ });
21527
+ for (const cb of keyCallbacks) {
21528
+ try {
21529
+ cb(keyEvent);
21530
+ } catch {
21459
21531
  }
21460
21532
  }
21461
21533
  }
21462
- }).catch(() => {
21463
- });
21464
- };
21534
+ }
21535
+ }
21465
21536
  // ------------------------------------------------------------------
21466
21537
  // Internal: single-resource fetchers
21467
21538
  // ------------------------------------------------------------------
@@ -22004,6 +22075,7 @@ var SmplClient = class {
22004
22075
  if (this._metrics !== null) {
22005
22076
  this._metrics.close();
22006
22077
  }
22078
+ this.flags._close();
22007
22079
  this.logging._close();
22008
22080
  if (this._wsManager !== null) {
22009
22081
  this._wsManager.stop();