@smplkit/sdk 3.0.1 → 3.0.3
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 +203 -97
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +48 -6
- package/dist/index.d.ts +48 -6
- package/dist/index.js +203 -97
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -1429,9 +1429,9 @@ declare class Config {
|
|
|
1429
1429
|
*/
|
|
1430
1430
|
_buildChain(configs?: Config[]): Promise<Array<{
|
|
1431
1431
|
id: string | null;
|
|
1432
|
-
items: Record<string,
|
|
1432
|
+
items: Record<string, unknown>;
|
|
1433
1433
|
environments: Record<string, {
|
|
1434
|
-
values: Record<string,
|
|
1434
|
+
values: Record<string, unknown>;
|
|
1435
1435
|
}>;
|
|
1436
1436
|
}>>;
|
|
1437
1437
|
toString(): string;
|
|
@@ -1549,6 +1549,13 @@ declare class FlagsClient {
|
|
|
1549
1549
|
* before using `.get()` on flag handles.
|
|
1550
1550
|
*/
|
|
1551
1551
|
initialize(): Promise<void>;
|
|
1552
|
+
/**
|
|
1553
|
+
* Synchronous teardown — clears the flag-flush interval and unsubscribes
|
|
1554
|
+
* from WebSocket events. Called by `SmplClient.close()`. Does not flush
|
|
1555
|
+
* pending context observations (use {@link disconnect} for that).
|
|
1556
|
+
* @internal
|
|
1557
|
+
*/
|
|
1558
|
+
_close(): void;
|
|
1552
1559
|
/** Disconnect the flags runtime and release resources. */
|
|
1553
1560
|
disconnect(): Promise<void>;
|
|
1554
1561
|
/** Refresh all flag definitions from the server. */
|
|
@@ -2409,6 +2416,11 @@ declare class ConfigClient {
|
|
|
2409
2416
|
/** @internal — resolves the management config sub-client used by lazy-init/refresh. */
|
|
2410
2417
|
_resolveManagement?: () => SmplManagementClient;
|
|
2411
2418
|
private _configCache;
|
|
2419
|
+
/** Raw Config objects keyed by id, kept around so a single-config
|
|
2420
|
+
* change (WS event) can refetch one config and rebuild the resolved
|
|
2421
|
+
* cache for everyone (including descendants that inherit from it)
|
|
2422
|
+
* without a full re-list. Mirrors Python's `_raw_config_cache`. */
|
|
2423
|
+
private _configStore;
|
|
2412
2424
|
private _initialized;
|
|
2413
2425
|
private _listeners;
|
|
2414
2426
|
/** @internal */
|
|
@@ -2464,12 +2476,10 @@ declare class ConfigClient {
|
|
|
2464
2476
|
/** @internal — get resolved config from cache. Used by LiveConfigProxy. */
|
|
2465
2477
|
_getCachedConfig(key: string): Record<string, unknown> | undefined;
|
|
2466
2478
|
private _handleConfigChanged;
|
|
2467
|
-
private _handleConfigDeleted;
|
|
2468
|
-
private _handleConfigsChanged;
|
|
2469
2479
|
/** Fetch a single config by key. Returns null if not found. @internal */
|
|
2470
2480
|
private _fetchSingleConfig;
|
|
2471
|
-
|
|
2472
|
-
private
|
|
2481
|
+
private _handleConfigDeleted;
|
|
2482
|
+
private _handleConfigsChanged;
|
|
2473
2483
|
/** @internal */
|
|
2474
2484
|
private _diffAndFire;
|
|
2475
2485
|
}
|
|
@@ -2565,8 +2575,32 @@ declare class LoggingClient {
|
|
|
2565
2575
|
* `install()`.
|
|
2566
2576
|
*
|
|
2567
2577
|
* Mirrors Python's `client.logging.install()`. There is no `stop()`.
|
|
2578
|
+
*
|
|
2579
|
+
* Adapter coverage:
|
|
2580
|
+
* - **winston**: pre-existing named loggers (`winston.loggers.*`) and the
|
|
2581
|
+
* default logger are auto-discovered.
|
|
2582
|
+
* - **pino**: pino has no global registry, so only loggers created
|
|
2583
|
+
* through `pino()` / `logger.child()` *after* `install()` runs are
|
|
2584
|
+
* tracked. To bring pre-existing pino loggers under management, recreate
|
|
2585
|
+
* them after install or register them explicitly via
|
|
2586
|
+
* `client.manage.loggers.register([...])`.
|
|
2587
|
+
*
|
|
2588
|
+
* After the initial pass, call {@link refresh} to re-fetch managed levels
|
|
2589
|
+
* from the server and re-apply them onto the native loggers (e.g. after
|
|
2590
|
+
* suspecting drift, or to force a manual sync outside the WebSocket).
|
|
2568
2591
|
*/
|
|
2569
2592
|
install(): Promise<void>;
|
|
2593
|
+
/**
|
|
2594
|
+
* Re-fetch logger and group levels from the server and re-apply them
|
|
2595
|
+
* onto the registered adapters.
|
|
2596
|
+
*
|
|
2597
|
+
* Diff-based: change listeners only fire for loggers whose level
|
|
2598
|
+
* actually changed (added, removed, or different level), with
|
|
2599
|
+
* `source: "manual"`. Mirrors Python's `client.logging.refresh()`.
|
|
2600
|
+
*
|
|
2601
|
+
* @throws SmplError if `install()` has not been called.
|
|
2602
|
+
*/
|
|
2603
|
+
refresh(): Promise<void>;
|
|
2570
2604
|
/**
|
|
2571
2605
|
* @deprecated Use {@link LoggingClient.install}. Retained as a backwards-
|
|
2572
2606
|
* compatible alias.
|
|
@@ -2596,6 +2630,14 @@ declare class LoggingClient {
|
|
|
2596
2630
|
private _handleGroupChanged;
|
|
2597
2631
|
private _handleGroupDeleted;
|
|
2598
2632
|
private _handleLoggersChanged;
|
|
2633
|
+
/**
|
|
2634
|
+
* Full refetch of loggers + log_groups, apply resolved levels to
|
|
2635
|
+
* adapters, diff against local stores and fire change listeners
|
|
2636
|
+
* (global once, per-key for each changed id). Shared between the
|
|
2637
|
+
* `loggers_changed` WS handler and the public `refresh()` method.
|
|
2638
|
+
* @internal
|
|
2639
|
+
*/
|
|
2640
|
+
private _resolveAndFire;
|
|
2599
2641
|
/** Fetch a single logger by key. Returns null if not found. @internal */
|
|
2600
2642
|
private _fetchSingleLogger;
|
|
2601
2643
|
/** Fetch a single log group by key. Returns null if not found. @internal */
|
package/dist/index.d.ts
CHANGED
|
@@ -1429,9 +1429,9 @@ declare class Config {
|
|
|
1429
1429
|
*/
|
|
1430
1430
|
_buildChain(configs?: Config[]): Promise<Array<{
|
|
1431
1431
|
id: string | null;
|
|
1432
|
-
items: Record<string,
|
|
1432
|
+
items: Record<string, unknown>;
|
|
1433
1433
|
environments: Record<string, {
|
|
1434
|
-
values: Record<string,
|
|
1434
|
+
values: Record<string, unknown>;
|
|
1435
1435
|
}>;
|
|
1436
1436
|
}>>;
|
|
1437
1437
|
toString(): string;
|
|
@@ -1549,6 +1549,13 @@ declare class FlagsClient {
|
|
|
1549
1549
|
* before using `.get()` on flag handles.
|
|
1550
1550
|
*/
|
|
1551
1551
|
initialize(): Promise<void>;
|
|
1552
|
+
/**
|
|
1553
|
+
* Synchronous teardown — clears the flag-flush interval and unsubscribes
|
|
1554
|
+
* from WebSocket events. Called by `SmplClient.close()`. Does not flush
|
|
1555
|
+
* pending context observations (use {@link disconnect} for that).
|
|
1556
|
+
* @internal
|
|
1557
|
+
*/
|
|
1558
|
+
_close(): void;
|
|
1552
1559
|
/** Disconnect the flags runtime and release resources. */
|
|
1553
1560
|
disconnect(): Promise<void>;
|
|
1554
1561
|
/** Refresh all flag definitions from the server. */
|
|
@@ -2409,6 +2416,11 @@ declare class ConfigClient {
|
|
|
2409
2416
|
/** @internal — resolves the management config sub-client used by lazy-init/refresh. */
|
|
2410
2417
|
_resolveManagement?: () => SmplManagementClient;
|
|
2411
2418
|
private _configCache;
|
|
2419
|
+
/** Raw Config objects keyed by id, kept around so a single-config
|
|
2420
|
+
* change (WS event) can refetch one config and rebuild the resolved
|
|
2421
|
+
* cache for everyone (including descendants that inherit from it)
|
|
2422
|
+
* without a full re-list. Mirrors Python's `_raw_config_cache`. */
|
|
2423
|
+
private _configStore;
|
|
2412
2424
|
private _initialized;
|
|
2413
2425
|
private _listeners;
|
|
2414
2426
|
/** @internal */
|
|
@@ -2464,12 +2476,10 @@ declare class ConfigClient {
|
|
|
2464
2476
|
/** @internal — get resolved config from cache. Used by LiveConfigProxy. */
|
|
2465
2477
|
_getCachedConfig(key: string): Record<string, unknown> | undefined;
|
|
2466
2478
|
private _handleConfigChanged;
|
|
2467
|
-
private _handleConfigDeleted;
|
|
2468
|
-
private _handleConfigsChanged;
|
|
2469
2479
|
/** Fetch a single config by key. Returns null if not found. @internal */
|
|
2470
2480
|
private _fetchSingleConfig;
|
|
2471
|
-
|
|
2472
|
-
private
|
|
2481
|
+
private _handleConfigDeleted;
|
|
2482
|
+
private _handleConfigsChanged;
|
|
2473
2483
|
/** @internal */
|
|
2474
2484
|
private _diffAndFire;
|
|
2475
2485
|
}
|
|
@@ -2565,8 +2575,32 @@ declare class LoggingClient {
|
|
|
2565
2575
|
* `install()`.
|
|
2566
2576
|
*
|
|
2567
2577
|
* Mirrors Python's `client.logging.install()`. There is no `stop()`.
|
|
2578
|
+
*
|
|
2579
|
+
* Adapter coverage:
|
|
2580
|
+
* - **winston**: pre-existing named loggers (`winston.loggers.*`) and the
|
|
2581
|
+
* default logger are auto-discovered.
|
|
2582
|
+
* - **pino**: pino has no global registry, so only loggers created
|
|
2583
|
+
* through `pino()` / `logger.child()` *after* `install()` runs are
|
|
2584
|
+
* tracked. To bring pre-existing pino loggers under management, recreate
|
|
2585
|
+
* them after install or register them explicitly via
|
|
2586
|
+
* `client.manage.loggers.register([...])`.
|
|
2587
|
+
*
|
|
2588
|
+
* After the initial pass, call {@link refresh} to re-fetch managed levels
|
|
2589
|
+
* from the server and re-apply them onto the native loggers (e.g. after
|
|
2590
|
+
* suspecting drift, or to force a manual sync outside the WebSocket).
|
|
2568
2591
|
*/
|
|
2569
2592
|
install(): Promise<void>;
|
|
2593
|
+
/**
|
|
2594
|
+
* Re-fetch logger and group levels from the server and re-apply them
|
|
2595
|
+
* onto the registered adapters.
|
|
2596
|
+
*
|
|
2597
|
+
* Diff-based: change listeners only fire for loggers whose level
|
|
2598
|
+
* actually changed (added, removed, or different level), with
|
|
2599
|
+
* `source: "manual"`. Mirrors Python's `client.logging.refresh()`.
|
|
2600
|
+
*
|
|
2601
|
+
* @throws SmplError if `install()` has not been called.
|
|
2602
|
+
*/
|
|
2603
|
+
refresh(): Promise<void>;
|
|
2570
2604
|
/**
|
|
2571
2605
|
* @deprecated Use {@link LoggingClient.install}. Retained as a backwards-
|
|
2572
2606
|
* compatible alias.
|
|
@@ -2596,6 +2630,14 @@ declare class LoggingClient {
|
|
|
2596
2630
|
private _handleGroupChanged;
|
|
2597
2631
|
private _handleGroupDeleted;
|
|
2598
2632
|
private _handleLoggersChanged;
|
|
2633
|
+
/**
|
|
2634
|
+
* Full refetch of loggers + log_groups, apply resolved levels to
|
|
2635
|
+
* adapters, diff against local stores and fire change listeners
|
|
2636
|
+
* (global once, per-key for each changed id). Shared between the
|
|
2637
|
+
* `loggers_changed` WS handler and the public `refresh()` method.
|
|
2638
|
+
* @internal
|
|
2639
|
+
*/
|
|
2640
|
+
private _resolveAndFire;
|
|
2599
2641
|
/** Fetch a single logger by key. Returns null if not found. @internal */
|
|
2600
2642
|
private _fetchSingleLogger;
|
|
2601
2643
|
/** Fetch a single log group by key. Returns null if not found. @internal */
|
package/dist/index.js
CHANGED
|
@@ -16838,6 +16838,13 @@ function environmentsToWire(environments) {
|
|
|
16838
16838
|
}
|
|
16839
16839
|
return out;
|
|
16840
16840
|
}
|
|
16841
|
+
function environmentsForResolver(environments) {
|
|
16842
|
+
const out = {};
|
|
16843
|
+
for (const [envId, env] of Object.entries(environments)) {
|
|
16844
|
+
out[envId] = { values: env.values };
|
|
16845
|
+
}
|
|
16846
|
+
return out;
|
|
16847
|
+
}
|
|
16841
16848
|
var Config = class {
|
|
16842
16849
|
id;
|
|
16843
16850
|
name;
|
|
@@ -17027,8 +17034,8 @@ var Config = class {
|
|
|
17027
17034
|
const chain = [
|
|
17028
17035
|
{
|
|
17029
17036
|
id: this.id,
|
|
17030
|
-
items: this.
|
|
17031
|
-
environments:
|
|
17037
|
+
items: this.items,
|
|
17038
|
+
environments: environmentsForResolver(this._environments)
|
|
17032
17039
|
}
|
|
17033
17040
|
];
|
|
17034
17041
|
let current = this;
|
|
@@ -17050,8 +17057,8 @@ var Config = class {
|
|
|
17050
17057
|
}
|
|
17051
17058
|
chain.push({
|
|
17052
17059
|
id: parentConfig.id,
|
|
17053
|
-
items: parentConfig.
|
|
17054
|
-
environments:
|
|
17060
|
+
items: parentConfig.items,
|
|
17061
|
+
environments: environmentsForResolver(parentConfig._environments)
|
|
17055
17062
|
});
|
|
17056
17063
|
current = parentConfig;
|
|
17057
17064
|
}
|
|
@@ -17063,6 +17070,22 @@ var Config = class {
|
|
|
17063
17070
|
};
|
|
17064
17071
|
|
|
17065
17072
|
// src/config/proxy.ts
|
|
17073
|
+
function _unflattenDotNotation(flat) {
|
|
17074
|
+
const nested = {};
|
|
17075
|
+
for (const [key, value] of Object.entries(flat)) {
|
|
17076
|
+
const parts = key.split(".");
|
|
17077
|
+
let current = nested;
|
|
17078
|
+
for (let i = 0; i < parts.length - 1; i++) {
|
|
17079
|
+
const part = parts[i];
|
|
17080
|
+
if (current[part] === void 0 || typeof current[part] !== "object" || current[part] === null) {
|
|
17081
|
+
current[part] = {};
|
|
17082
|
+
}
|
|
17083
|
+
current = current[part];
|
|
17084
|
+
}
|
|
17085
|
+
current[parts[parts.length - 1]] = value;
|
|
17086
|
+
}
|
|
17087
|
+
return nested;
|
|
17088
|
+
}
|
|
17066
17089
|
var LiveConfigProxy = class {
|
|
17067
17090
|
/** @internal */
|
|
17068
17091
|
_client;
|
|
@@ -17085,7 +17108,8 @@ var LiveConfigProxy = class {
|
|
|
17085
17108
|
}
|
|
17086
17109
|
const values = target._currentValues();
|
|
17087
17110
|
if (target._model) {
|
|
17088
|
-
const
|
|
17111
|
+
const nested = _unflattenDotNotation(values);
|
|
17112
|
+
const instance = new target._model(nested);
|
|
17089
17113
|
return instance[prop];
|
|
17090
17114
|
}
|
|
17091
17115
|
return values[prop];
|
|
@@ -17247,6 +17271,11 @@ var ConfigClient = class {
|
|
|
17247
17271
|
/** @internal — resolves the management config sub-client used by lazy-init/refresh. */
|
|
17248
17272
|
_resolveManagement;
|
|
17249
17273
|
_configCache = {};
|
|
17274
|
+
/** Raw Config objects keyed by id, kept around so a single-config
|
|
17275
|
+
* change (WS event) can refetch one config and rebuild the resolved
|
|
17276
|
+
* cache for everyone (including descendants that inherit from it)
|
|
17277
|
+
* without a full re-list. Mirrors Python's `_raw_config_cache`. */
|
|
17278
|
+
_configStore = {};
|
|
17250
17279
|
_initialized = false;
|
|
17251
17280
|
_listeners = [];
|
|
17252
17281
|
/** @internal */
|
|
@@ -17355,12 +17384,15 @@ var ConfigClient = class {
|
|
|
17355
17384
|
}
|
|
17356
17385
|
const configs = await this._listConfigs();
|
|
17357
17386
|
const newCache = {};
|
|
17387
|
+
const newStore = {};
|
|
17358
17388
|
for (const cfg of configs) {
|
|
17359
17389
|
const chain = await cfg._buildChain(configs);
|
|
17360
17390
|
newCache[cfg.id] = resolveChain(chain, environment);
|
|
17391
|
+
newStore[cfg.id] = cfg;
|
|
17361
17392
|
}
|
|
17362
17393
|
const oldCache = this._configCache;
|
|
17363
17394
|
this._configCache = newCache;
|
|
17395
|
+
this._configStore = newStore;
|
|
17364
17396
|
this._diffAndFire(oldCache, newCache, "manual");
|
|
17365
17397
|
}
|
|
17366
17398
|
/**
|
|
@@ -17402,11 +17434,14 @@ var ConfigClient = class {
|
|
|
17402
17434
|
}
|
|
17403
17435
|
const configs = await this._listConfigs();
|
|
17404
17436
|
const cache = {};
|
|
17437
|
+
const store = {};
|
|
17405
17438
|
for (const cfg of configs) {
|
|
17406
17439
|
const chain = await cfg._buildChain(configs);
|
|
17407
17440
|
cache[cfg.id] = resolveChain(chain, environment);
|
|
17441
|
+
store[cfg.id] = cfg;
|
|
17408
17442
|
}
|
|
17409
17443
|
this._configCache = cache;
|
|
17444
|
+
this._configStore = store;
|
|
17410
17445
|
this._initialized = true;
|
|
17411
17446
|
if (this._getSharedWs) {
|
|
17412
17447
|
const ws = this._getSharedWs();
|
|
@@ -17420,11 +17455,14 @@ var ConfigClient = class {
|
|
|
17420
17455
|
if (this._initialized) return;
|
|
17421
17456
|
const configs = await this._listConfigs();
|
|
17422
17457
|
const cache = {};
|
|
17458
|
+
const store = {};
|
|
17423
17459
|
for (const cfg of configs) {
|
|
17424
17460
|
const chain = await cfg._buildChain(configs);
|
|
17425
17461
|
cache[cfg.id] = resolveChain(chain, environment);
|
|
17462
|
+
store[cfg.id] = cfg;
|
|
17426
17463
|
}
|
|
17427
17464
|
this._configCache = cache;
|
|
17465
|
+
this._configStore = store;
|
|
17428
17466
|
this._initialized = true;
|
|
17429
17467
|
}
|
|
17430
17468
|
/** @internal — get resolved config from cache. Used by LiveConfigProxy. */
|
|
@@ -17438,26 +17476,29 @@ var ConfigClient = class {
|
|
|
17438
17476
|
debug("websocket", `config_changed event received: ${JSON.stringify(data)}`);
|
|
17439
17477
|
const configKey = data.id;
|
|
17440
17478
|
if (!configKey) return;
|
|
17479
|
+
const environment = this._parent?._environment;
|
|
17480
|
+
if (!environment) return;
|
|
17441
17481
|
void this._fetchSingleConfig(configKey).then((newConfig) => {
|
|
17442
|
-
const
|
|
17443
|
-
if (
|
|
17444
|
-
|
|
17445
|
-
let newValues;
|
|
17446
|
-
if (newConfig !== null) {
|
|
17447
|
-
newValues = this._resolveConfigValues(newConfig, environment);
|
|
17448
|
-
} else {
|
|
17449
|
-
newValues = {};
|
|
17450
|
-
}
|
|
17451
|
-
const oldJson = JSON.stringify(oldValues ?? {});
|
|
17452
|
-
const newJson = JSON.stringify(newValues);
|
|
17453
|
-
if (oldJson === newJson) return;
|
|
17454
|
-
const oldCache = { ...this._configCache };
|
|
17455
|
-
if (newConfig !== null) {
|
|
17456
|
-
this._configCache[configKey] = newValues;
|
|
17482
|
+
const newStore = { ...this._configStore };
|
|
17483
|
+
if (newConfig === null) {
|
|
17484
|
+
delete newStore[configKey];
|
|
17457
17485
|
} else {
|
|
17458
|
-
|
|
17459
|
-
}
|
|
17460
|
-
|
|
17486
|
+
newStore[configKey] = newConfig;
|
|
17487
|
+
}
|
|
17488
|
+
const allConfigs = Object.values(newStore);
|
|
17489
|
+
return Promise.all(
|
|
17490
|
+
allConfigs.map(async (cfg) => {
|
|
17491
|
+
const chain = await cfg._buildChain(allConfigs);
|
|
17492
|
+
return [cfg.id, resolveChain(chain, environment)];
|
|
17493
|
+
})
|
|
17494
|
+
).then((entries) => ({ entries, newStore }));
|
|
17495
|
+
}).then(({ entries, newStore }) => {
|
|
17496
|
+
const newCache = {};
|
|
17497
|
+
for (const [id, values] of entries) newCache[id] = values;
|
|
17498
|
+
const oldCache = this._configCache;
|
|
17499
|
+
this._configCache = newCache;
|
|
17500
|
+
this._configStore = newStore;
|
|
17501
|
+
this._diffAndFire(oldCache, newCache, "websocket");
|
|
17461
17502
|
}).catch((err) => {
|
|
17462
17503
|
debug(
|
|
17463
17504
|
"websocket",
|
|
@@ -17465,6 +17506,20 @@ var ConfigClient = class {
|
|
|
17465
17506
|
);
|
|
17466
17507
|
});
|
|
17467
17508
|
};
|
|
17509
|
+
/** Fetch a single config by key. Returns null if not found. @internal */
|
|
17510
|
+
async _fetchSingleConfig(key) {
|
|
17511
|
+
debug("api", `GET /api/v1/configs/${key}`);
|
|
17512
|
+
try {
|
|
17513
|
+
const result = await this._http.GET("/api/v1/configs/{id}", {
|
|
17514
|
+
params: { path: { id: key } }
|
|
17515
|
+
});
|
|
17516
|
+
if (!result.response.ok) return null;
|
|
17517
|
+
if (!result.data?.data) return null;
|
|
17518
|
+
return resourceToConfig(result.data.data);
|
|
17519
|
+
} catch {
|
|
17520
|
+
return null;
|
|
17521
|
+
}
|
|
17522
|
+
}
|
|
17468
17523
|
_handleConfigDeleted = (data) => {
|
|
17469
17524
|
debug("websocket", `config_deleted event received: ${JSON.stringify(data)}`);
|
|
17470
17525
|
const configKey = data.id;
|
|
@@ -17483,27 +17538,6 @@ var ConfigClient = class {
|
|
|
17483
17538
|
// ------------------------------------------------------------------
|
|
17484
17539
|
// Internal: change detection
|
|
17485
17540
|
// ------------------------------------------------------------------
|
|
17486
|
-
/** Fetch a single config by key. Returns null if not found. @internal */
|
|
17487
|
-
async _fetchSingleConfig(key) {
|
|
17488
|
-
debug("api", `GET /api/v1/configs/${key}`);
|
|
17489
|
-
try {
|
|
17490
|
-
const result = await this._http.GET("/api/v1/configs/{id}", {
|
|
17491
|
-
params: { path: { id: key } }
|
|
17492
|
-
});
|
|
17493
|
-
if (!result.response.ok) return null;
|
|
17494
|
-
if (!result.data?.data) return null;
|
|
17495
|
-
return resourceToConfig(result.data.data);
|
|
17496
|
-
} catch {
|
|
17497
|
-
return null;
|
|
17498
|
-
}
|
|
17499
|
-
}
|
|
17500
|
-
/** Resolve a config's values for an environment (no parent chain). @internal */
|
|
17501
|
-
_resolveConfigValues(config, environment) {
|
|
17502
|
-
const base = config.items ?? {};
|
|
17503
|
-
const envEntry = config.environments?.[environment];
|
|
17504
|
-
if (!envEntry?.values) return { ...base };
|
|
17505
|
-
return { ...base, ...envEntry.values };
|
|
17506
|
-
}
|
|
17507
17541
|
/** @internal */
|
|
17508
17542
|
_diffAndFire(oldCache, newCache, source) {
|
|
17509
17543
|
const allConfigKeys = /* @__PURE__ */ new Set([...Object.keys(oldCache), ...Object.keys(newCache)]);
|
|
@@ -20456,6 +20490,30 @@ var FlagsClient = class {
|
|
|
20456
20490
|
this._flagFlushTimer = setInterval(() => {
|
|
20457
20491
|
void this._flushFlags();
|
|
20458
20492
|
}, FLAG_REGISTRATION_FLUSH_INTERVAL_MS);
|
|
20493
|
+
if (typeof this._flagFlushTimer === "object" && "unref" in this._flagFlushTimer) {
|
|
20494
|
+
this._flagFlushTimer.unref();
|
|
20495
|
+
}
|
|
20496
|
+
}
|
|
20497
|
+
/**
|
|
20498
|
+
* Synchronous teardown — clears the flag-flush interval and unsubscribes
|
|
20499
|
+
* from WebSocket events. Called by `SmplClient.close()`. Does not flush
|
|
20500
|
+
* pending context observations (use {@link disconnect} for that).
|
|
20501
|
+
* @internal
|
|
20502
|
+
*/
|
|
20503
|
+
_close() {
|
|
20504
|
+
if (this._flagFlushTimer !== null) {
|
|
20505
|
+
clearInterval(this._flagFlushTimer);
|
|
20506
|
+
this._flagFlushTimer = null;
|
|
20507
|
+
}
|
|
20508
|
+
if (this._wsManager !== null) {
|
|
20509
|
+
this._wsManager.off("flag_changed", this._handleFlagChanged);
|
|
20510
|
+
this._wsManager.off("flag_deleted", this._handleFlagDeleted);
|
|
20511
|
+
this._wsManager.off("flags_changed", this._handleFlagsChanged);
|
|
20512
|
+
this._wsManager = null;
|
|
20513
|
+
}
|
|
20514
|
+
this._cache.clear();
|
|
20515
|
+
this._initialized = false;
|
|
20516
|
+
this._environment = null;
|
|
20459
20517
|
}
|
|
20460
20518
|
/** Disconnect the flags runtime and release resources. */
|
|
20461
20519
|
async disconnect() {
|
|
@@ -20612,6 +20670,9 @@ var FlagsClient = class {
|
|
|
20612
20670
|
this._flagFlushTimer = setInterval(() => {
|
|
20613
20671
|
void this._flushFlags();
|
|
20614
20672
|
}, FLAG_REGISTRATION_FLUSH_INTERVAL_MS);
|
|
20673
|
+
if (typeof this._flagFlushTimer === "object" && "unref" in this._flagFlushTimer) {
|
|
20674
|
+
this._flagFlushTimer.unref();
|
|
20675
|
+
}
|
|
20615
20676
|
}
|
|
20616
20677
|
// ------------------------------------------------------------------
|
|
20617
20678
|
// Internal: event handlers (called by SharedWebSocket)
|
|
@@ -20959,10 +21020,39 @@ var LoggingClient = class {
|
|
|
20959
21020
|
* `install()`.
|
|
20960
21021
|
*
|
|
20961
21022
|
* Mirrors Python's `client.logging.install()`. There is no `stop()`.
|
|
21023
|
+
*
|
|
21024
|
+
* Adapter coverage:
|
|
21025
|
+
* - **winston**: pre-existing named loggers (`winston.loggers.*`) and the
|
|
21026
|
+
* default logger are auto-discovered.
|
|
21027
|
+
* - **pino**: pino has no global registry, so only loggers created
|
|
21028
|
+
* through `pino()` / `logger.child()` *after* `install()` runs are
|
|
21029
|
+
* tracked. To bring pre-existing pino loggers under management, recreate
|
|
21030
|
+
* them after install or register them explicitly via
|
|
21031
|
+
* `client.manage.loggers.register([...])`.
|
|
21032
|
+
*
|
|
21033
|
+
* After the initial pass, call {@link refresh} to re-fetch managed levels
|
|
21034
|
+
* from the server and re-apply them onto the native loggers (e.g. after
|
|
21035
|
+
* suspecting drift, or to force a manual sync outside the WebSocket).
|
|
20962
21036
|
*/
|
|
20963
21037
|
async install() {
|
|
20964
21038
|
return this._installInternal();
|
|
20965
21039
|
}
|
|
21040
|
+
/**
|
|
21041
|
+
* Re-fetch logger and group levels from the server and re-apply them
|
|
21042
|
+
* onto the registered adapters.
|
|
21043
|
+
*
|
|
21044
|
+
* Diff-based: change listeners only fire for loggers whose level
|
|
21045
|
+
* actually changed (added, removed, or different level), with
|
|
21046
|
+
* `source: "manual"`. Mirrors Python's `client.logging.refresh()`.
|
|
21047
|
+
*
|
|
21048
|
+
* @throws SmplError if `install()` has not been called.
|
|
21049
|
+
*/
|
|
21050
|
+
async refresh() {
|
|
21051
|
+
if (!this._started) {
|
|
21052
|
+
throw new SmplError("Logging not installed. Call install() first.");
|
|
21053
|
+
}
|
|
21054
|
+
await this._resolveAndFire("manual");
|
|
21055
|
+
}
|
|
20966
21056
|
/**
|
|
20967
21057
|
* @deprecated Use {@link LoggingClient.install}. Retained as a backwards-
|
|
20968
21058
|
* compatible alias.
|
|
@@ -21035,6 +21125,9 @@ var LoggingClient = class {
|
|
|
21035
21125
|
this._loggerFlushTimer = setInterval(() => {
|
|
21036
21126
|
void this._flushLoggerBuffer();
|
|
21037
21127
|
}, 3e4);
|
|
21128
|
+
if (typeof this._loggerFlushTimer === "object" && "unref" in this._loggerFlushTimer) {
|
|
21129
|
+
this._loggerFlushTimer.unref();
|
|
21130
|
+
}
|
|
21038
21131
|
this._started = true;
|
|
21039
21132
|
}
|
|
21040
21133
|
// ------------------------------------------------------------------
|
|
@@ -21306,63 +21399,75 @@ var LoggingClient = class {
|
|
|
21306
21399
|
};
|
|
21307
21400
|
_handleLoggersChanged = (_data) => {
|
|
21308
21401
|
debug("websocket", `loggers_changed event received`);
|
|
21309
|
-
void
|
|
21310
|
-
|
|
21311
|
-
|
|
21312
|
-
|
|
21313
|
-
|
|
21314
|
-
|
|
21315
|
-
|
|
21316
|
-
|
|
21317
|
-
|
|
21318
|
-
|
|
21319
|
-
|
|
21320
|
-
|
|
21321
|
-
|
|
21322
|
-
|
|
21323
|
-
|
|
21324
|
-
|
|
21325
|
-
|
|
21326
|
-
|
|
21327
|
-
|
|
21328
|
-
|
|
21329
|
-
|
|
21330
|
-
|
|
21331
|
-
this.
|
|
21332
|
-
|
|
21333
|
-
|
|
21334
|
-
|
|
21335
|
-
|
|
21336
|
-
|
|
21337
|
-
|
|
21338
|
-
|
|
21339
|
-
|
|
21340
|
-
|
|
21341
|
-
|
|
21342
|
-
|
|
21343
|
-
|
|
21344
|
-
|
|
21402
|
+
void this._resolveAndFire("websocket").catch(() => {
|
|
21403
|
+
});
|
|
21404
|
+
};
|
|
21405
|
+
/**
|
|
21406
|
+
* Full refetch of loggers + log_groups, apply resolved levels to
|
|
21407
|
+
* adapters, diff against local stores and fire change listeners
|
|
21408
|
+
* (global once, per-key for each changed id). Shared between the
|
|
21409
|
+
* `loggers_changed` WS handler and the public `refresh()` method.
|
|
21410
|
+
* @internal
|
|
21411
|
+
*/
|
|
21412
|
+
async _resolveAndFire(source) {
|
|
21413
|
+
const [serverLoggers, serverGroups] = await Promise.all([
|
|
21414
|
+
this._listLoggers(),
|
|
21415
|
+
this._listLogGroups()
|
|
21416
|
+
]);
|
|
21417
|
+
debug("resolution", `resolution pass (trigger: ${source})`);
|
|
21418
|
+
const changedLoggerIds = /* @__PURE__ */ new Set();
|
|
21419
|
+
const newLoggerKeys = new Set(serverLoggers.map((l) => l.id));
|
|
21420
|
+
for (const logger of serverLoggers) {
|
|
21421
|
+
const key = logger.id;
|
|
21422
|
+
const oldLevel = this._loggerStore[key] ?? null;
|
|
21423
|
+
const newLevel = logger.level ?? null;
|
|
21424
|
+
if (oldLevel !== newLevel || !(key in this._loggerStore)) {
|
|
21425
|
+
changedLoggerIds.add(key);
|
|
21426
|
+
this._loggerStore[key] = newLevel;
|
|
21427
|
+
}
|
|
21428
|
+
}
|
|
21429
|
+
for (const key of Object.keys(this._loggerStore)) {
|
|
21430
|
+
if (!newLoggerKeys.has(key)) {
|
|
21431
|
+
changedLoggerIds.add(key);
|
|
21432
|
+
delete this._loggerStore[key];
|
|
21433
|
+
}
|
|
21434
|
+
}
|
|
21435
|
+
for (const group of serverGroups) {
|
|
21436
|
+
this._groupStore[group.id] = group.level ?? null;
|
|
21437
|
+
}
|
|
21438
|
+
this._applyLevels(serverLoggers);
|
|
21439
|
+
if (changedLoggerIds.size === 0) return;
|
|
21440
|
+
const [firstKey] = changedLoggerIds;
|
|
21441
|
+
const firstLogger = serverLoggers.find((l) => l.id === firstKey);
|
|
21442
|
+
const globalEvent = new LoggerChangeEvent({
|
|
21443
|
+
id: firstKey,
|
|
21444
|
+
level: firstLogger?.level ?? null,
|
|
21445
|
+
source
|
|
21446
|
+
});
|
|
21447
|
+
for (const cb of this._globalListeners) {
|
|
21448
|
+
try {
|
|
21449
|
+
cb(globalEvent);
|
|
21450
|
+
} catch {
|
|
21345
21451
|
}
|
|
21346
|
-
|
|
21347
|
-
|
|
21348
|
-
|
|
21349
|
-
|
|
21350
|
-
|
|
21351
|
-
|
|
21352
|
-
|
|
21353
|
-
|
|
21354
|
-
|
|
21355
|
-
|
|
21356
|
-
|
|
21357
|
-
|
|
21358
|
-
|
|
21359
|
-
|
|
21452
|
+
}
|
|
21453
|
+
for (const key of changedLoggerIds) {
|
|
21454
|
+
const keyCallbacks = this._keyListeners.get(key);
|
|
21455
|
+
if (keyCallbacks) {
|
|
21456
|
+
const l = serverLoggers.find((x) => x.id === key);
|
|
21457
|
+
const keyEvent = new LoggerChangeEvent({
|
|
21458
|
+
id: key,
|
|
21459
|
+
level: l?.level ?? null,
|
|
21460
|
+
source
|
|
21461
|
+
});
|
|
21462
|
+
for (const cb of keyCallbacks) {
|
|
21463
|
+
try {
|
|
21464
|
+
cb(keyEvent);
|
|
21465
|
+
} catch {
|
|
21360
21466
|
}
|
|
21361
21467
|
}
|
|
21362
21468
|
}
|
|
21363
|
-
}
|
|
21364
|
-
|
|
21365
|
-
};
|
|
21469
|
+
}
|
|
21470
|
+
}
|
|
21366
21471
|
// ------------------------------------------------------------------
|
|
21367
21472
|
// Internal: single-resource fetchers
|
|
21368
21473
|
// ------------------------------------------------------------------
|
|
@@ -21905,6 +22010,7 @@ var SmplClient = class {
|
|
|
21905
22010
|
if (this._metrics !== null) {
|
|
21906
22011
|
this._metrics.close();
|
|
21907
22012
|
}
|
|
22013
|
+
this.flags._close();
|
|
21908
22014
|
this.logging._close();
|
|
21909
22015
|
if (this._wsManager !== null) {
|
|
21910
22016
|
this._wsManager.stop();
|