@smplkit/sdk 1.6.18 → 1.7.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.d.cts CHANGED
@@ -276,6 +276,12 @@ declare class ConfigClient {
276
276
  /** @internal — get resolved config from cache. Used by LiveConfigProxy. */
277
277
  _getCachedConfig(key: string): Record<string, unknown> | undefined;
278
278
  private _handleConfigChanged;
279
+ private _handleConfigDeleted;
280
+ private _handleConfigsChanged;
281
+ /** Fetch a single config by key. Returns null if not found. @internal */
282
+ private _fetchSingleConfig;
283
+ /** Resolve a config's values for an environment (no parent chain). @internal */
284
+ private _resolveConfigValues;
279
285
  /** @internal */
280
286
  private _diffAndFire;
281
287
  }
@@ -829,7 +835,9 @@ type FlagResource = components["schemas"]["FlagResource"];
829
835
  declare class FlagChangeEvent {
830
836
  readonly id: string;
831
837
  readonly source: string;
832
- constructor(id: string, source: string);
838
+ /** True when the flag was deleted. */
839
+ readonly deleted?: true;
840
+ constructor(id: string, source: string, deleted?: true);
833
841
  }
834
842
  /** Evaluation statistics for the flags runtime. */
835
843
  declare class FlagStats {
@@ -1032,7 +1040,10 @@ declare class FlagsClient {
1032
1040
  _connectInternal(environment: string): Promise<void>;
1033
1041
  private _handleFlagChanged;
1034
1042
  private _handleFlagDeleted;
1043
+ private _handleFlagsChanged;
1035
1044
  private _fetchAllFlags;
1045
+ /** Fetch a single flag by key. Returns undefined if not found. @internal */
1046
+ private _fetchSingleFlag;
1036
1047
  private _fetchFlagsList;
1037
1048
  private _fireChangeListeners;
1038
1049
  private _fireChangeListenersAll;
@@ -1064,6 +1075,8 @@ interface LoggerChangeEvent {
1064
1075
  level: LogLevel | null;
1065
1076
  /** How the change was delivered. */
1066
1077
  source: string;
1078
+ /** True when the logger or group was deleted. */
1079
+ deleted?: true;
1067
1080
  }
1068
1081
 
1069
1082
  /**
@@ -1274,6 +1287,8 @@ declare class LoggingClient {
1274
1287
  private _explicitAdapters;
1275
1288
  private _loggerBuffer;
1276
1289
  private _loggerFlushTimer;
1290
+ private _loggerStore;
1291
+ private _groupStore;
1277
1292
  /** @internal */
1278
1293
  constructor(apiKey: string, ensureWs: () => SharedWebSocket, timeout?: number, baseUrl?: string);
1279
1294
  /**
@@ -1335,7 +1350,14 @@ declare class LoggingClient {
1335
1350
  /** Flush buffered loggers to the bulk-register endpoint. */
1336
1351
  private _flushLoggerBuffer;
1337
1352
  private _handleLoggerChanged;
1353
+ private _handleLoggerDeleted;
1338
1354
  private _handleGroupChanged;
1355
+ private _handleGroupDeleted;
1356
+ private _handleLoggersChanged;
1357
+ /** Fetch a single logger by key. Returns null if not found. @internal */
1358
+ private _fetchSingleLogger;
1359
+ /** Fetch a single log group by key. Returns null if not found. @internal */
1360
+ private _fetchSingleGroup;
1339
1361
  private _loggerToModel;
1340
1362
  private _groupToModel;
1341
1363
  }
package/dist/index.d.ts CHANGED
@@ -276,6 +276,12 @@ declare class ConfigClient {
276
276
  /** @internal — get resolved config from cache. Used by LiveConfigProxy. */
277
277
  _getCachedConfig(key: string): Record<string, unknown> | undefined;
278
278
  private _handleConfigChanged;
279
+ private _handleConfigDeleted;
280
+ private _handleConfigsChanged;
281
+ /** Fetch a single config by key. Returns null if not found. @internal */
282
+ private _fetchSingleConfig;
283
+ /** Resolve a config's values for an environment (no parent chain). @internal */
284
+ private _resolveConfigValues;
279
285
  /** @internal */
280
286
  private _diffAndFire;
281
287
  }
@@ -829,7 +835,9 @@ type FlagResource = components["schemas"]["FlagResource"];
829
835
  declare class FlagChangeEvent {
830
836
  readonly id: string;
831
837
  readonly source: string;
832
- constructor(id: string, source: string);
838
+ /** True when the flag was deleted. */
839
+ readonly deleted?: true;
840
+ constructor(id: string, source: string, deleted?: true);
833
841
  }
834
842
  /** Evaluation statistics for the flags runtime. */
835
843
  declare class FlagStats {
@@ -1032,7 +1040,10 @@ declare class FlagsClient {
1032
1040
  _connectInternal(environment: string): Promise<void>;
1033
1041
  private _handleFlagChanged;
1034
1042
  private _handleFlagDeleted;
1043
+ private _handleFlagsChanged;
1035
1044
  private _fetchAllFlags;
1045
+ /** Fetch a single flag by key. Returns undefined if not found. @internal */
1046
+ private _fetchSingleFlag;
1036
1047
  private _fetchFlagsList;
1037
1048
  private _fireChangeListeners;
1038
1049
  private _fireChangeListenersAll;
@@ -1064,6 +1075,8 @@ interface LoggerChangeEvent {
1064
1075
  level: LogLevel | null;
1065
1076
  /** How the change was delivered. */
1066
1077
  source: string;
1078
+ /** True when the logger or group was deleted. */
1079
+ deleted?: true;
1067
1080
  }
1068
1081
 
1069
1082
  /**
@@ -1274,6 +1287,8 @@ declare class LoggingClient {
1274
1287
  private _explicitAdapters;
1275
1288
  private _loggerBuffer;
1276
1289
  private _loggerFlushTimer;
1290
+ private _loggerStore;
1291
+ private _groupStore;
1277
1292
  /** @internal */
1278
1293
  constructor(apiKey: string, ensureWs: () => SharedWebSocket, timeout?: number, baseUrl?: string);
1279
1294
  /**
@@ -1335,7 +1350,14 @@ declare class LoggingClient {
1335
1350
  /** Flush buffered loggers to the bulk-register endpoint. */
1336
1351
  private _flushLoggerBuffer;
1337
1352
  private _handleLoggerChanged;
1353
+ private _handleLoggerDeleted;
1338
1354
  private _handleGroupChanged;
1355
+ private _handleGroupDeleted;
1356
+ private _handleLoggersChanged;
1357
+ /** Fetch a single logger by key. Returns null if not found. @internal */
1358
+ private _fetchSingleLogger;
1359
+ /** Fetch a single log group by key. Returns null if not found. @internal */
1360
+ private _fetchSingleGroup;
1339
1361
  private _loggerToModel;
1340
1362
  private _groupToModel;
1341
1363
  }
package/dist/index.js CHANGED
@@ -17306,7 +17306,8 @@ var ConfigClient = class {
17306
17306
  if (this._getSharedWs) {
17307
17307
  const ws = this._getSharedWs();
17308
17308
  ws.on("config_changed", this._handleConfigChanged);
17309
- ws.on("config_deleted", this._handleConfigChanged);
17309
+ ws.on("config_deleted", this._handleConfigDeleted);
17310
+ ws.on("configs_changed", this._handleConfigsChanged);
17310
17311
  }
17311
17312
  }
17312
17313
  /** @internal — called by SmplClient for backward compat. */
@@ -17329,13 +17330,75 @@ var ConfigClient = class {
17329
17330
  // Internal: WebSocket handler
17330
17331
  // ------------------------------------------------------------------
17331
17332
  _handleConfigChanged = (data) => {
17332
- debug("websocket", `config event received: ${JSON.stringify(data)}`);
17333
+ debug("websocket", `config_changed event received: ${JSON.stringify(data)}`);
17334
+ const configKey = data.id;
17335
+ if (!configKey) return;
17336
+ void this._fetchSingleConfig(configKey).then((newConfig) => {
17337
+ const environment = this._parent?._environment;
17338
+ if (!environment) return;
17339
+ const oldValues = this._configCache[configKey];
17340
+ let newValues;
17341
+ if (newConfig !== null) {
17342
+ newValues = this._resolveConfigValues(newConfig, environment);
17343
+ } else {
17344
+ newValues = {};
17345
+ }
17346
+ const oldJson = JSON.stringify(oldValues ?? {});
17347
+ const newJson = JSON.stringify(newValues);
17348
+ if (oldJson === newJson) return;
17349
+ const oldCache = { ...this._configCache };
17350
+ if (newConfig !== null) {
17351
+ this._configCache[configKey] = newValues;
17352
+ } else {
17353
+ delete this._configCache[configKey];
17354
+ }
17355
+ this._diffAndFire(oldCache, this._configCache, "websocket");
17356
+ }).catch((err) => {
17357
+ debug(
17358
+ "websocket",
17359
+ `config_changed handler error: ${err instanceof Error ? err.message : String(err)}`
17360
+ );
17361
+ });
17362
+ };
17363
+ _handleConfigDeleted = (data) => {
17364
+ debug("websocket", `config_deleted event received: ${JSON.stringify(data)}`);
17365
+ const configKey = data.id;
17366
+ if (!configKey) return;
17367
+ if (configKey in this._configCache) {
17368
+ const oldCache = { ...this._configCache };
17369
+ delete this._configCache[configKey];
17370
+ this._diffAndFire(oldCache, this._configCache, "websocket");
17371
+ }
17372
+ };
17373
+ _handleConfigsChanged = (_data) => {
17374
+ debug("websocket", `configs_changed event received`);
17333
17375
  void this.refresh().catch(() => {
17334
17376
  });
17335
17377
  };
17336
17378
  // ------------------------------------------------------------------
17337
17379
  // Internal: change detection
17338
17380
  // ------------------------------------------------------------------
17381
+ /** Fetch a single config by key. Returns null if not found. @internal */
17382
+ async _fetchSingleConfig(key) {
17383
+ debug("api", `GET /api/v1/configs/${key}`);
17384
+ try {
17385
+ const result = await this._http.GET("/api/v1/configs/{id}", {
17386
+ params: { path: { id: key } }
17387
+ });
17388
+ if (!result.response.ok) return null;
17389
+ if (!result.data?.data) return null;
17390
+ return resourceToConfig(result.data.data, this);
17391
+ } catch {
17392
+ return null;
17393
+ }
17394
+ }
17395
+ /** Resolve a config's values for an environment (no parent chain). @internal */
17396
+ _resolveConfigValues(config, environment) {
17397
+ const base = config.items ?? {};
17398
+ const envEntry = config.environments?.[environment];
17399
+ if (!envEntry?.values) return { ...base };
17400
+ return { ...base, ...envEntry.values };
17401
+ }
17339
17402
  /** @internal */
17340
17403
  _diffAndFire(oldCache, newCache, source) {
17341
17404
  const allConfigKeys = /* @__PURE__ */ new Set([...Object.keys(oldCache), ...Object.keys(newCache)]);
@@ -17615,9 +17678,12 @@ function evaluateFlag(flagDef, environment, evalDict) {
17615
17678
  var FlagChangeEvent = class {
17616
17679
  id;
17617
17680
  source;
17618
- constructor(id, source) {
17681
+ /** True when the flag was deleted. */
17682
+ deleted;
17683
+ constructor(id, source, deleted) {
17619
17684
  this.id = id;
17620
17685
  this.source = source;
17686
+ if (deleted) this.deleted = deleted;
17621
17687
  }
17622
17688
  };
17623
17689
  var ResolutionCache = class {
@@ -18127,6 +18193,7 @@ var FlagsClient = class {
18127
18193
  this._wsManager = this._ensureWs();
18128
18194
  this._wsManager.on("flag_changed", this._handleFlagChanged);
18129
18195
  this._wsManager.on("flag_deleted", this._handleFlagDeleted);
18196
+ this._wsManager.on("flags_changed", this._handleFlagsChanged);
18130
18197
  this._flagFlushTimer = setInterval(() => {
18131
18198
  void this._flushFlags();
18132
18199
  }, FLAG_REGISTRATION_FLUSH_INTERVAL_MS);
@@ -18136,6 +18203,7 @@ var FlagsClient = class {
18136
18203
  if (this._wsManager !== null) {
18137
18204
  this._wsManager.off("flag_changed", this._handleFlagChanged);
18138
18205
  this._wsManager.off("flag_deleted", this._handleFlagDeleted);
18206
+ this._wsManager.off("flags_changed", this._handleFlagsChanged);
18139
18207
  this._wsManager = null;
18140
18208
  }
18141
18209
  if (this._flagFlushTimer !== null) {
@@ -18300,6 +18368,7 @@ var FlagsClient = class {
18300
18368
  this._wsManager = this._ensureWs();
18301
18369
  this._wsManager.on("flag_changed", this._handleFlagChanged);
18302
18370
  this._wsManager.on("flag_deleted", this._handleFlagDeleted);
18371
+ this._wsManager.on("flags_changed", this._handleFlagsChanged);
18303
18372
  this._flagFlushTimer = setInterval(() => {
18304
18373
  void this._flushFlags();
18305
18374
  }, FLAG_REGISTRATION_FLUSH_INTERVAL_MS);
@@ -18308,19 +18377,84 @@ var FlagsClient = class {
18308
18377
  // Internal: event handlers (called by SharedWebSocket)
18309
18378
  // ------------------------------------------------------------------
18310
18379
  _handleFlagChanged = (data) => {
18311
- debug("websocket", `flag event received: ${JSON.stringify(data)}`);
18312
- const flagId = data.id;
18313
- void this._fetchAllFlags().then(() => {
18380
+ debug("websocket", `flag_changed event received: ${JSON.stringify(data)}`);
18381
+ const flagKey = data.id;
18382
+ if (!flagKey) return;
18383
+ void this._fetchSingleFlag(flagKey).then((newDef) => {
18384
+ const oldDef = this._flagStore[flagKey];
18385
+ const oldJson = oldDef !== void 0 ? JSON.stringify(oldDef) : null;
18386
+ const newJson = newDef !== void 0 ? JSON.stringify(newDef) : null;
18387
+ if (oldJson === newJson) return;
18388
+ if (newDef !== void 0) {
18389
+ this._flagStore[flagKey] = newDef;
18390
+ } else {
18391
+ delete this._flagStore[flagKey];
18392
+ }
18314
18393
  this._cache.clear();
18315
- this._fireChangeListeners(flagId ?? null, "websocket");
18394
+ this._fireChangeListeners(flagKey, "websocket");
18316
18395
  });
18317
18396
  };
18318
18397
  _handleFlagDeleted = (data) => {
18319
- debug("websocket", `flag deleted event received: ${JSON.stringify(data)}`);
18320
- const flagId = data.id;
18398
+ debug("websocket", `flag_deleted event received: ${JSON.stringify(data)}`);
18399
+ const flagKey = data.id;
18400
+ if (!flagKey) return;
18401
+ if (flagKey in this._flagStore) {
18402
+ delete this._flagStore[flagKey];
18403
+ }
18404
+ this._cache.clear();
18405
+ const deletedEvent = new FlagChangeEvent(flagKey, "websocket", true);
18406
+ for (const cb of this._globalListeners) {
18407
+ try {
18408
+ cb(deletedEvent);
18409
+ } catch {
18410
+ }
18411
+ }
18412
+ const keyCallbacks = this._keyListeners.get(flagKey);
18413
+ if (keyCallbacks) {
18414
+ for (const cb of keyCallbacks) {
18415
+ try {
18416
+ cb(deletedEvent);
18417
+ } catch {
18418
+ }
18419
+ }
18420
+ }
18421
+ };
18422
+ _handleFlagsChanged = (_data) => {
18423
+ debug("websocket", `flags_changed event received`);
18424
+ const preStore = { ...this._flagStore };
18321
18425
  void this._fetchAllFlags().then(() => {
18322
18426
  this._cache.clear();
18323
- this._fireChangeListeners(flagId ?? null, "websocket");
18427
+ const postStore = this._flagStore;
18428
+ const changedKeys = /* @__PURE__ */ new Set();
18429
+ const allKeys = /* @__PURE__ */ new Set([...Object.keys(preStore), ...Object.keys(postStore)]);
18430
+ for (const key of allKeys) {
18431
+ const preJson = preStore[key] !== void 0 ? JSON.stringify(preStore[key]) : null;
18432
+ const postJson = postStore[key] !== void 0 ? JSON.stringify(postStore[key]) : null;
18433
+ if (preJson !== postJson) {
18434
+ changedKeys.add(key);
18435
+ }
18436
+ }
18437
+ if (changedKeys.size === 0) return;
18438
+ const [firstKey] = changedKeys;
18439
+ const globalEvent = new FlagChangeEvent(firstKey, "websocket");
18440
+ for (const cb of this._globalListeners) {
18441
+ try {
18442
+ cb(globalEvent);
18443
+ } catch {
18444
+ }
18445
+ }
18446
+ for (const key of changedKeys) {
18447
+ const keyCallbacks = this._keyListeners.get(key);
18448
+ if (keyCallbacks) {
18449
+ const keyEvent = new FlagChangeEvent(key, "websocket");
18450
+ for (const cb of keyCallbacks) {
18451
+ try {
18452
+ cb(keyEvent);
18453
+ } catch {
18454
+ }
18455
+ }
18456
+ }
18457
+ }
18324
18458
  });
18325
18459
  };
18326
18460
  // ------------------------------------------------------------------
@@ -18334,6 +18468,20 @@ var FlagsClient = class {
18334
18468
  }
18335
18469
  this._flagStore = store;
18336
18470
  }
18471
+ /** Fetch a single flag by key. Returns undefined if not found. @internal */
18472
+ async _fetchSingleFlag(key) {
18473
+ debug("api", `GET /api/v1/flags/${key}`);
18474
+ try {
18475
+ const result = await this._http.GET("/api/v1/flags/{id}", {
18476
+ params: { path: { id: key } }
18477
+ });
18478
+ if (!result.response.ok) return void 0;
18479
+ if (!result.data?.data) return void 0;
18480
+ return this._resourceToPlainDict(result.data.data);
18481
+ } catch {
18482
+ return void 0;
18483
+ }
18484
+ }
18337
18485
  async _fetchFlagsList() {
18338
18486
  debug("api", "GET /api/v1/flags");
18339
18487
  let data;
@@ -18713,6 +18861,11 @@ var LoggingClient = class {
18713
18861
  _explicitAdapters = false;
18714
18862
  _loggerBuffer = new LoggerRegistrationBuffer();
18715
18863
  _loggerFlushTimer = null;
18864
+ // Local stores for diff-based listener firing
18865
+ _loggerStore = {};
18866
+ // key -> level
18867
+ _groupStore = {};
18868
+ // key -> level
18716
18869
  /** @internal */
18717
18870
  constructor(apiKey, ensureWs, timeout, baseUrl) {
18718
18871
  this._apiKey = apiKey;
@@ -18833,12 +18986,21 @@ var LoggingClient = class {
18833
18986
  }
18834
18987
  /** @internal */
18835
18988
  async _mgGetGroup(id) {
18836
- const groups = await this.management.listGroups();
18837
- const match = groups.find((g) => g.id === id);
18838
- if (!match) {
18989
+ let data;
18990
+ try {
18991
+ const result = await this._http.GET("/api/v1/log_groups/{id}", {
18992
+ params: { path: { id } }
18993
+ });
18994
+ if (result.error !== void 0)
18995
+ await checkError3(result.response, `LogGroup with id '${id}' not found`);
18996
+ data = result.data;
18997
+ } catch (err) {
18998
+ wrapFetchError3(err);
18999
+ }
19000
+ if (!data || !data.data) {
18839
19001
  throw new SmplNotFoundError(`LogGroup with id '${id}' not found`);
18840
19002
  }
18841
- return match;
19003
+ return this._groupToModel(data.data);
18842
19004
  }
18843
19005
  /** @internal */
18844
19006
  async _mgListGroups() {
@@ -19001,13 +19163,20 @@ var LoggingClient = class {
19001
19163
  `fetched ${serverLoggers.length} logger(s) and ${serverGroups.length} group(s) from server`
19002
19164
  );
19003
19165
  this._applyLevels(serverLoggers);
19166
+ for (const l of serverLoggers) {
19167
+ this._loggerStore[l.id] = l.level;
19168
+ }
19169
+ for (const g of serverGroups) {
19170
+ this._groupStore[g.id] = g.level;
19171
+ }
19004
19172
  } catch {
19005
19173
  }
19006
19174
  this._wsManager = this._ensureWs();
19007
19175
  this._wsManager.on("logger_changed", this._handleLoggerChanged);
19008
- this._wsManager.on("logger_deleted", this._handleLoggerChanged);
19176
+ this._wsManager.on("logger_deleted", this._handleLoggerDeleted);
19009
19177
  this._wsManager.on("group_changed", this._handleGroupChanged);
19010
- this._wsManager.on("group_deleted", this._handleGroupChanged);
19178
+ this._wsManager.on("group_deleted", this._handleGroupDeleted);
19179
+ this._wsManager.on("loggers_changed", this._handleLoggersChanged);
19011
19180
  this._loggerFlushTimer = setInterval(() => {
19012
19181
  void this._flushLoggerBuffer();
19013
19182
  }, 3e4);
@@ -19055,9 +19224,10 @@ var LoggingClient = class {
19055
19224
  }
19056
19225
  if (this._wsManager !== null) {
19057
19226
  this._wsManager.off("logger_changed", this._handleLoggerChanged);
19058
- this._wsManager.off("logger_deleted", this._handleLoggerChanged);
19227
+ this._wsManager.off("logger_deleted", this._handleLoggerDeleted);
19059
19228
  this._wsManager.off("group_changed", this._handleGroupChanged);
19060
- this._wsManager.off("group_deleted", this._handleGroupChanged);
19229
+ this._wsManager.off("group_deleted", this._handleGroupDeleted);
19230
+ this._wsManager.off("loggers_changed", this._handleLoggersChanged);
19061
19231
  this._wsManager = null;
19062
19232
  }
19063
19233
  this._started = false;
@@ -19151,47 +19321,225 @@ var LoggingClient = class {
19151
19321
  // Internal: WebSocket handler
19152
19322
  // ------------------------------------------------------------------
19153
19323
  _handleLoggerChanged = (data) => {
19154
- debug("websocket", `logger event received: ${JSON.stringify(data)}`);
19324
+ debug("websocket", `logger_changed event received: ${JSON.stringify(data)}`);
19155
19325
  const id = data.id;
19156
- if (id) {
19157
- void Promise.all([this.management.list(), this.management.listGroups()]).then(([serverLoggers]) => {
19158
- debug("resolution", `resolution pass (trigger: websocket event for logger ${id})`);
19159
- this._applyLevels(serverLoggers);
19160
- const logger = serverLoggers.find((l) => l.id === id);
19161
- const level = logger?.level ?? null;
19162
- const event = {
19163
- id,
19164
- level,
19165
- source: "websocket"
19166
- };
19167
- for (const cb of this._globalListeners) {
19326
+ if (!id) return;
19327
+ void this._fetchSingleLogger(id).then((logger) => {
19328
+ const oldLevel = this._loggerStore[id] ?? null;
19329
+ const newLevel = logger?.level ?? null;
19330
+ if (oldLevel === newLevel) return;
19331
+ this._loggerStore[id] = newLevel;
19332
+ if (logger) {
19333
+ this._applyLevels([logger]);
19334
+ }
19335
+ const event = {
19336
+ id,
19337
+ level: newLevel,
19338
+ source: "websocket"
19339
+ };
19340
+ for (const cb of this._globalListeners) {
19341
+ try {
19342
+ cb(event);
19343
+ } catch {
19344
+ }
19345
+ }
19346
+ const idCallbacks = this._keyListeners.get(id);
19347
+ if (idCallbacks) {
19348
+ for (const cb of idCallbacks) {
19168
19349
  try {
19169
19350
  cb(event);
19170
19351
  } catch {
19171
19352
  }
19172
19353
  }
19173
- const idCallbacks = this._keyListeners.get(id);
19174
- if (idCallbacks) {
19175
- for (const cb of idCallbacks) {
19176
- try {
19177
- cb(event);
19178
- } catch {
19179
- }
19180
- }
19354
+ }
19355
+ }).catch((err) => {
19356
+ debug(
19357
+ "websocket",
19358
+ `logger_changed handler error: ${err instanceof Error ? err.message : String(err)}`
19359
+ );
19360
+ });
19361
+ };
19362
+ _handleLoggerDeleted = (data) => {
19363
+ debug("websocket", `logger_deleted event received: ${JSON.stringify(data)}`);
19364
+ const id = data.id;
19365
+ if (!id) return;
19366
+ delete this._loggerStore[id];
19367
+ const event = {
19368
+ id,
19369
+ level: null,
19370
+ source: "websocket",
19371
+ deleted: true
19372
+ };
19373
+ for (const cb of this._globalListeners) {
19374
+ try {
19375
+ cb(event);
19376
+ } catch (err) {
19377
+ debug(
19378
+ "websocket",
19379
+ `logger_deleted listener error: ${err instanceof Error ? err.message : String(err)}`
19380
+ );
19381
+ }
19382
+ }
19383
+ const idCallbacks = this._keyListeners.get(id);
19384
+ if (idCallbacks) {
19385
+ for (const cb of idCallbacks) {
19386
+ try {
19387
+ cb(event);
19388
+ } catch (err) {
19389
+ debug(
19390
+ "websocket",
19391
+ `logger_deleted key listener error: ${err instanceof Error ? err.message : String(err)}`
19392
+ );
19181
19393
  }
19394
+ }
19395
+ }
19396
+ };
19397
+ _handleGroupChanged = (data) => {
19398
+ debug("websocket", `group_changed event received: ${JSON.stringify(data)}`);
19399
+ const id = data.id;
19400
+ if (!id) return;
19401
+ void this._fetchSingleGroup(id).then((group) => {
19402
+ const oldLevel = this._groupStore[id] ?? null;
19403
+ const newLevel = group?.level ?? null;
19404
+ if (oldLevel === newLevel) return;
19405
+ this._groupStore[id] = newLevel;
19406
+ void this.management.list().then((loggers) => {
19407
+ this._applyLevels(loggers);
19182
19408
  }).catch(() => {
19183
19409
  });
19410
+ }).catch((err) => {
19411
+ debug(
19412
+ "websocket",
19413
+ `group_changed handler error: ${err instanceof Error ? err.message : String(err)}`
19414
+ );
19415
+ });
19416
+ };
19417
+ _handleGroupDeleted = (data) => {
19418
+ debug("websocket", `group_deleted event received: ${JSON.stringify(data)}`);
19419
+ const id = data.id;
19420
+ if (!id) return;
19421
+ delete this._groupStore[id];
19422
+ const event = {
19423
+ id,
19424
+ level: null,
19425
+ source: "websocket",
19426
+ deleted: true
19427
+ };
19428
+ for (const cb of this._globalListeners) {
19429
+ try {
19430
+ cb(event);
19431
+ } catch (err) {
19432
+ debug(
19433
+ "websocket",
19434
+ `group_deleted listener error: ${err instanceof Error ? err.message : String(err)}`
19435
+ );
19436
+ }
19437
+ }
19438
+ const idCallbacks = this._keyListeners.get(id);
19439
+ if (idCallbacks) {
19440
+ for (const cb of idCallbacks) {
19441
+ try {
19442
+ cb(event);
19443
+ } catch (err) {
19444
+ debug(
19445
+ "websocket",
19446
+ `group_deleted key listener error: ${err instanceof Error ? err.message : String(err)}`
19447
+ );
19448
+ }
19449
+ }
19184
19450
  }
19185
19451
  };
19186
- _handleGroupChanged = (data) => {
19187
- debug("websocket", `group event received: ${JSON.stringify(data)}`);
19188
- void Promise.all([this.management.list(), this.management.listGroups()]).then(([serverLoggers]) => {
19189
- debug("resolution", `resolution pass (trigger: group websocket event)`);
19452
+ _handleLoggersChanged = (_data) => {
19453
+ debug("websocket", `loggers_changed event received`);
19454
+ void Promise.all([this.management.list(), this.management.listGroups()]).then(([serverLoggers, serverGroups]) => {
19455
+ debug("resolution", `resolution pass (trigger: loggers_changed event)`);
19456
+ const changedLoggerIds = /* @__PURE__ */ new Set();
19457
+ const newLoggerKeys = new Set(serverLoggers.map((l) => l.id));
19458
+ for (const logger of serverLoggers) {
19459
+ const key = logger.id;
19460
+ const oldLevel = this._loggerStore[key] ?? null;
19461
+ const newLevel = logger.level ?? null;
19462
+ if (oldLevel !== newLevel || !(key in this._loggerStore)) {
19463
+ changedLoggerIds.add(key);
19464
+ this._loggerStore[key] = newLevel;
19465
+ }
19466
+ }
19467
+ for (const key of Object.keys(this._loggerStore)) {
19468
+ if (!newLoggerKeys.has(key)) {
19469
+ changedLoggerIds.add(key);
19470
+ delete this._loggerStore[key];
19471
+ }
19472
+ }
19473
+ for (const group of serverGroups) {
19474
+ this._groupStore[group.id] = group.level ?? null;
19475
+ }
19190
19476
  this._applyLevels(serverLoggers);
19477
+ if (changedLoggerIds.size === 0) return;
19478
+ const [firstKey] = changedLoggerIds;
19479
+ const firstLogger = serverLoggers.find((l) => l.id === firstKey);
19480
+ const globalEvent = {
19481
+ id: firstKey,
19482
+ level: firstLogger?.level ?? null,
19483
+ source: "websocket"
19484
+ };
19485
+ for (const cb of this._globalListeners) {
19486
+ try {
19487
+ cb(globalEvent);
19488
+ } catch {
19489
+ }
19490
+ }
19491
+ for (const key of changedLoggerIds) {
19492
+ const keyCallbacks = this._keyListeners.get(key);
19493
+ if (keyCallbacks) {
19494
+ const l = serverLoggers.find((x) => x.id === key);
19495
+ const keyEvent = {
19496
+ id: key,
19497
+ level: l?.level ?? null,
19498
+ source: "websocket"
19499
+ };
19500
+ for (const cb of keyCallbacks) {
19501
+ try {
19502
+ cb(keyEvent);
19503
+ } catch {
19504
+ }
19505
+ }
19506
+ }
19507
+ }
19191
19508
  }).catch(() => {
19192
19509
  });
19193
19510
  };
19194
19511
  // ------------------------------------------------------------------
19512
+ // Internal: single-resource fetchers
19513
+ // ------------------------------------------------------------------
19514
+ /** Fetch a single logger by key. Returns null if not found. @internal */
19515
+ async _fetchSingleLogger(key) {
19516
+ debug("api", `GET /api/v1/loggers/${key}`);
19517
+ try {
19518
+ const result = await this._http.GET("/api/v1/loggers/{id}", {
19519
+ params: { path: { id: key } }
19520
+ });
19521
+ if (result.error !== void 0) return null;
19522
+ if (!result.data?.data) return null;
19523
+ return this._loggerToModel(result.data.data);
19524
+ } catch {
19525
+ return null;
19526
+ }
19527
+ }
19528
+ /** Fetch a single log group by key. Returns null if not found. @internal */
19529
+ async _fetchSingleGroup(key) {
19530
+ debug("api", `GET /api/v1/log_groups/${key}`);
19531
+ try {
19532
+ const result = await this._http.GET("/api/v1/log_groups/{id}", {
19533
+ params: { path: { id: key } }
19534
+ });
19535
+ if (result.error !== void 0) return null;
19536
+ if (!result.data?.data) return null;
19537
+ return this._groupToModel(result.data.data);
19538
+ } catch {
19539
+ return null;
19540
+ }
19541
+ }
19542
+ // ------------------------------------------------------------------
19195
19543
  // Internal: model conversion
19196
19544
  // ------------------------------------------------------------------
19197
19545
  _loggerToModel(resource) {