@smplkit/sdk 1.3.26 → 1.3.27
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 +189 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +50 -1
- package/dist/index.d.ts +50 -1
- package/dist/index.js +189 -4
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -17220,6 +17220,10 @@ var ConfigClient = class {
|
|
|
17220
17220
|
if (values === void 0) {
|
|
17221
17221
|
throw new SmplNotFoundError(`Config with key '${key}' not found in cache`);
|
|
17222
17222
|
}
|
|
17223
|
+
const metrics = this._parent?._metrics;
|
|
17224
|
+
if (metrics) {
|
|
17225
|
+
metrics.record("config.resolutions", 1, "resolutions", { config_id: key });
|
|
17226
|
+
}
|
|
17223
17227
|
if (model) {
|
|
17224
17228
|
return new model(values);
|
|
17225
17229
|
}
|
|
@@ -17354,6 +17358,10 @@ var ConfigClient = class {
|
|
|
17354
17358
|
const oldVal = iKey in oldItems ? oldItems[iKey] : null;
|
|
17355
17359
|
const newVal = iKey in newItems ? newItems[iKey] : null;
|
|
17356
17360
|
if (JSON.stringify(oldVal) !== JSON.stringify(newVal)) {
|
|
17361
|
+
const metrics = this._parent?._metrics;
|
|
17362
|
+
if (metrics) {
|
|
17363
|
+
metrics.record("config.changes", 1, "changes", { config_id: cfgKey });
|
|
17364
|
+
}
|
|
17357
17365
|
const event = {
|
|
17358
17366
|
configKey: cfgKey,
|
|
17359
17367
|
itemKey: iKey,
|
|
@@ -18189,8 +18197,18 @@ var FlagsClient = class {
|
|
|
18189
18197
|
const cacheKey = `${key}:${ctxHash}`;
|
|
18190
18198
|
const [hit, cachedValue] = this._cache.get(cacheKey);
|
|
18191
18199
|
if (hit) {
|
|
18200
|
+
const metrics2 = this._parent?._metrics;
|
|
18201
|
+
if (metrics2) {
|
|
18202
|
+
metrics2.record("flags.cache_hits", 1, "hits");
|
|
18203
|
+
metrics2.record("flags.evaluations", 1, "evaluations", { flag_id: key });
|
|
18204
|
+
}
|
|
18192
18205
|
return cachedValue;
|
|
18193
18206
|
}
|
|
18207
|
+
const metrics = this._parent?._metrics;
|
|
18208
|
+
if (metrics) {
|
|
18209
|
+
metrics.record("flags.cache_misses", 1, "misses");
|
|
18210
|
+
metrics.record("flags.evaluations", 1, "evaluations", { flag_id: key });
|
|
18211
|
+
}
|
|
18194
18212
|
const flagDef = this._flagStore[key];
|
|
18195
18213
|
if (flagDef === void 0) {
|
|
18196
18214
|
this._cache.put(cacheKey, defaultValue);
|
|
@@ -18834,6 +18852,12 @@ var LoggingClient = class {
|
|
|
18834
18852
|
} catch {
|
|
18835
18853
|
}
|
|
18836
18854
|
}
|
|
18855
|
+
if (discovered.length > 0) {
|
|
18856
|
+
const metrics = this._parent?._metrics;
|
|
18857
|
+
if (metrics) {
|
|
18858
|
+
metrics.record("logging.loggers_discovered", discovered.length, "loggers");
|
|
18859
|
+
}
|
|
18860
|
+
}
|
|
18837
18861
|
for (const { name, level } of discovered) {
|
|
18838
18862
|
try {
|
|
18839
18863
|
const logger = this.new(name, { managed: true });
|
|
@@ -18928,6 +18952,10 @@ var LoggingClient = class {
|
|
|
18928
18952
|
effectiveLevel = envOverride.level;
|
|
18929
18953
|
}
|
|
18930
18954
|
}
|
|
18955
|
+
const metrics = this._parent?._metrics;
|
|
18956
|
+
if (metrics) {
|
|
18957
|
+
metrics.record("logging.level_changes", 1, "changes", { logger_id: logger.key });
|
|
18958
|
+
}
|
|
18931
18959
|
for (const adapter of this._adapters) {
|
|
18932
18960
|
try {
|
|
18933
18961
|
adapter.applyLevel(logger.key, effectiveLevel);
|
|
@@ -19011,15 +19039,17 @@ var BACKOFF_MS = [1e3, 2e3, 4e3, 8e3, 16e3, 32e3, 6e4];
|
|
|
19011
19039
|
var SharedWebSocket = class {
|
|
19012
19040
|
_appBaseUrl;
|
|
19013
19041
|
_apiKey;
|
|
19042
|
+
_metrics;
|
|
19014
19043
|
_listeners = /* @__PURE__ */ new Map();
|
|
19015
19044
|
_connectionStatus = "disconnected";
|
|
19016
19045
|
_closed = false;
|
|
19017
19046
|
_ws = null;
|
|
19018
19047
|
_reconnectTimer = null;
|
|
19019
19048
|
_backoffIndex = 0;
|
|
19020
|
-
constructor(appBaseUrl, apiKey) {
|
|
19049
|
+
constructor(appBaseUrl, apiKey, metrics) {
|
|
19021
19050
|
this._appBaseUrl = appBaseUrl;
|
|
19022
19051
|
this._apiKey = apiKey;
|
|
19052
|
+
this._metrics = metrics ?? null;
|
|
19023
19053
|
}
|
|
19024
19054
|
// ------------------------------------------------------------------
|
|
19025
19055
|
// Listener registration
|
|
@@ -19118,6 +19148,9 @@ var SharedWebSocket = class {
|
|
|
19118
19148
|
if (msg.type === "connected") {
|
|
19119
19149
|
this._backoffIndex = 0;
|
|
19120
19150
|
this._connectionStatus = "connected";
|
|
19151
|
+
if (this._metrics) {
|
|
19152
|
+
this._metrics.recordGauge("platform.websocket_connections", 1, "connections");
|
|
19153
|
+
}
|
|
19121
19154
|
return;
|
|
19122
19155
|
}
|
|
19123
19156
|
if (msg.type === "error") {
|
|
@@ -19131,6 +19164,9 @@ var SharedWebSocket = class {
|
|
|
19131
19164
|
}
|
|
19132
19165
|
});
|
|
19133
19166
|
ws.on("close", () => {
|
|
19167
|
+
if (this._metrics) {
|
|
19168
|
+
this._metrics.recordGauge("platform.websocket_connections", 0, "connections");
|
|
19169
|
+
}
|
|
19134
19170
|
if (!this._closed) {
|
|
19135
19171
|
this._connectionStatus = "disconnected";
|
|
19136
19172
|
this._scheduleReconnect();
|
|
@@ -19211,8 +19247,145 @@ function resolveApiKey(explicit, environment) {
|
|
|
19211
19247
|
throw new SmplError(noApiKeyMessage(environment));
|
|
19212
19248
|
}
|
|
19213
19249
|
|
|
19214
|
-
// src/
|
|
19250
|
+
// src/_metrics.ts
|
|
19215
19251
|
var APP_BASE_URL2 = "https://app.smplkit.com";
|
|
19252
|
+
function makeCounter(unit) {
|
|
19253
|
+
return { value: 0, unit, windowStart: (/* @__PURE__ */ new Date()).toISOString() };
|
|
19254
|
+
}
|
|
19255
|
+
function makeMapKey(name, dimensions) {
|
|
19256
|
+
const sorted = Object.keys(dimensions).sort().map((k) => `${k}=${dimensions[k]}`).join("&");
|
|
19257
|
+
return `${name}|${sorted}`;
|
|
19258
|
+
}
|
|
19259
|
+
var MetricsReporter = class {
|
|
19260
|
+
_apiKey;
|
|
19261
|
+
_environment;
|
|
19262
|
+
_service;
|
|
19263
|
+
_flushInterval;
|
|
19264
|
+
_counters = /* @__PURE__ */ new Map();
|
|
19265
|
+
_gauges = /* @__PURE__ */ new Map();
|
|
19266
|
+
_timer = null;
|
|
19267
|
+
_closed = false;
|
|
19268
|
+
constructor(options) {
|
|
19269
|
+
this._apiKey = options.apiKey;
|
|
19270
|
+
this._environment = options.environment;
|
|
19271
|
+
this._service = options.service;
|
|
19272
|
+
this._flushInterval = options.flushInterval ?? 60;
|
|
19273
|
+
}
|
|
19274
|
+
// ------------------------------------------------------------------
|
|
19275
|
+
// Public recording API
|
|
19276
|
+
// ------------------------------------------------------------------
|
|
19277
|
+
record(name, value = 1, unit = null, dimensions) {
|
|
19278
|
+
const merged = this._mergeDimensions(dimensions);
|
|
19279
|
+
const key = makeMapKey(name, merged);
|
|
19280
|
+
let entry = this._counters.get(key);
|
|
19281
|
+
if (!entry) {
|
|
19282
|
+
entry = { name, dimensions: merged, counter: makeCounter(unit) };
|
|
19283
|
+
this._counters.set(key, entry);
|
|
19284
|
+
}
|
|
19285
|
+
entry.counter.value += value;
|
|
19286
|
+
if (entry.counter.unit === null && unit !== null) {
|
|
19287
|
+
entry.counter.unit = unit;
|
|
19288
|
+
}
|
|
19289
|
+
this._maybeStartTimer();
|
|
19290
|
+
}
|
|
19291
|
+
recordGauge(name, value, unit = null, dimensions) {
|
|
19292
|
+
const merged = this._mergeDimensions(dimensions);
|
|
19293
|
+
const key = makeMapKey(name, merged);
|
|
19294
|
+
let entry = this._gauges.get(key);
|
|
19295
|
+
if (!entry) {
|
|
19296
|
+
entry = { name, dimensions: merged, counter: makeCounter(unit) };
|
|
19297
|
+
this._gauges.set(key, entry);
|
|
19298
|
+
}
|
|
19299
|
+
entry.counter.value = value;
|
|
19300
|
+
if (entry.counter.unit === null && unit !== null) {
|
|
19301
|
+
entry.counter.unit = unit;
|
|
19302
|
+
}
|
|
19303
|
+
this._maybeStartTimer();
|
|
19304
|
+
}
|
|
19305
|
+
// ------------------------------------------------------------------
|
|
19306
|
+
// Flush / close
|
|
19307
|
+
// ------------------------------------------------------------------
|
|
19308
|
+
flush() {
|
|
19309
|
+
this._flush();
|
|
19310
|
+
}
|
|
19311
|
+
close() {
|
|
19312
|
+
if (this._closed) return;
|
|
19313
|
+
this._closed = true;
|
|
19314
|
+
if (this._timer !== null) {
|
|
19315
|
+
clearInterval(this._timer);
|
|
19316
|
+
this._timer = null;
|
|
19317
|
+
}
|
|
19318
|
+
this._flush();
|
|
19319
|
+
}
|
|
19320
|
+
// ------------------------------------------------------------------
|
|
19321
|
+
// Internal
|
|
19322
|
+
// ------------------------------------------------------------------
|
|
19323
|
+
_mergeDimensions(dimensions) {
|
|
19324
|
+
const merged = {
|
|
19325
|
+
environment: this._environment,
|
|
19326
|
+
service: this._service
|
|
19327
|
+
};
|
|
19328
|
+
if (dimensions) {
|
|
19329
|
+
Object.assign(merged, dimensions);
|
|
19330
|
+
}
|
|
19331
|
+
return merged;
|
|
19332
|
+
}
|
|
19333
|
+
_maybeStartTimer() {
|
|
19334
|
+
if (this._timer === null && !this._closed) {
|
|
19335
|
+
this._timer = setInterval(() => this._flush(), this._flushInterval * 1e3);
|
|
19336
|
+
if (typeof this._timer === "object" && "unref" in this._timer) {
|
|
19337
|
+
this._timer.unref();
|
|
19338
|
+
}
|
|
19339
|
+
}
|
|
19340
|
+
}
|
|
19341
|
+
_flush() {
|
|
19342
|
+
const counters = this._counters;
|
|
19343
|
+
const gauges = this._gauges;
|
|
19344
|
+
this._counters = /* @__PURE__ */ new Map();
|
|
19345
|
+
this._gauges = /* @__PURE__ */ new Map();
|
|
19346
|
+
if (counters.size === 0 && gauges.size === 0) return;
|
|
19347
|
+
const payload = this._buildPayload(counters, gauges);
|
|
19348
|
+
try {
|
|
19349
|
+
fetch(`${APP_BASE_URL2}/api/v1/metrics/bulk`, {
|
|
19350
|
+
method: "POST",
|
|
19351
|
+
headers: {
|
|
19352
|
+
Authorization: `Bearer ${this._apiKey}`,
|
|
19353
|
+
"Content-Type": "application/vnd.api+json",
|
|
19354
|
+
Accept: "application/json"
|
|
19355
|
+
},
|
|
19356
|
+
body: JSON.stringify(payload)
|
|
19357
|
+
}).catch(() => {
|
|
19358
|
+
});
|
|
19359
|
+
} catch {
|
|
19360
|
+
}
|
|
19361
|
+
}
|
|
19362
|
+
_buildPayload(counters, gauges) {
|
|
19363
|
+
const data = [];
|
|
19364
|
+
for (const [, entry] of counters) {
|
|
19365
|
+
data.push(this._entry(entry.name, entry.counter, entry.dimensions));
|
|
19366
|
+
}
|
|
19367
|
+
for (const [, entry] of gauges) {
|
|
19368
|
+
data.push(this._entry(entry.name, entry.counter, entry.dimensions));
|
|
19369
|
+
}
|
|
19370
|
+
return { data };
|
|
19371
|
+
}
|
|
19372
|
+
_entry(name, counter, dimensions) {
|
|
19373
|
+
return {
|
|
19374
|
+
type: "metric",
|
|
19375
|
+
attributes: {
|
|
19376
|
+
name,
|
|
19377
|
+
value: counter.value,
|
|
19378
|
+
unit: counter.unit,
|
|
19379
|
+
period_seconds: this._flushInterval,
|
|
19380
|
+
dimensions,
|
|
19381
|
+
recorded_at: counter.windowStart
|
|
19382
|
+
}
|
|
19383
|
+
};
|
|
19384
|
+
}
|
|
19385
|
+
};
|
|
19386
|
+
|
|
19387
|
+
// src/client.ts
|
|
19388
|
+
var APP_BASE_URL3 = "https://app.smplkit.com";
|
|
19216
19389
|
var NO_ENVIRONMENT_MESSAGE = "No environment provided. Set one of:\n 1. Pass environment to the constructor\n 2. Set the SMPLKIT_ENVIRONMENT environment variable";
|
|
19217
19390
|
var NO_SERVICE_MESSAGE = "No service provided. Set one of:\n 1. Pass service in options\n 2. Set the SMPLKIT_SERVICE environment variable";
|
|
19218
19391
|
var SmplClient = class {
|
|
@@ -19228,6 +19401,8 @@ var SmplClient = class {
|
|
|
19228
19401
|
_environment;
|
|
19229
19402
|
/** @internal */
|
|
19230
19403
|
_service;
|
|
19404
|
+
/** @internal */
|
|
19405
|
+
_metrics = null;
|
|
19231
19406
|
_timeout;
|
|
19232
19407
|
_appHttp;
|
|
19233
19408
|
constructor(options = {}) {
|
|
@@ -19245,12 +19420,19 @@ var SmplClient = class {
|
|
|
19245
19420
|
this._apiKey = apiKey;
|
|
19246
19421
|
this._timeout = options.timeout ?? 3e4;
|
|
19247
19422
|
this._appHttp = (0, import_openapi_fetch4.default)({
|
|
19248
|
-
baseUrl:
|
|
19423
|
+
baseUrl: APP_BASE_URL3,
|
|
19249
19424
|
headers: {
|
|
19250
19425
|
Authorization: `Bearer ${apiKey}`,
|
|
19251
19426
|
Accept: "application/json"
|
|
19252
19427
|
}
|
|
19253
19428
|
});
|
|
19429
|
+
if (!options.disableTelemetry) {
|
|
19430
|
+
this._metrics = new MetricsReporter({
|
|
19431
|
+
apiKey,
|
|
19432
|
+
environment: this._environment,
|
|
19433
|
+
service: this._service
|
|
19434
|
+
});
|
|
19435
|
+
}
|
|
19254
19436
|
this.config = new ConfigClient(apiKey, this._timeout);
|
|
19255
19437
|
this.flags = new FlagsClient(apiKey, () => this._ensureWs(), this._timeout);
|
|
19256
19438
|
this.logging = new LoggingClient(apiKey, () => this._ensureWs(), this._timeout);
|
|
@@ -19280,13 +19462,16 @@ var SmplClient = class {
|
|
|
19280
19462
|
/** Lazily create and start the shared WebSocket. @internal */
|
|
19281
19463
|
_ensureWs() {
|
|
19282
19464
|
if (this._wsManager === null) {
|
|
19283
|
-
this._wsManager = new SharedWebSocket(
|
|
19465
|
+
this._wsManager = new SharedWebSocket(APP_BASE_URL3, this._apiKey, this._metrics);
|
|
19284
19466
|
this._wsManager.start();
|
|
19285
19467
|
}
|
|
19286
19468
|
return this._wsManager;
|
|
19287
19469
|
}
|
|
19288
19470
|
/** Close the shared WebSocket and release resources. */
|
|
19289
19471
|
close() {
|
|
19472
|
+
if (this._metrics !== null) {
|
|
19473
|
+
this._metrics.close();
|
|
19474
|
+
}
|
|
19290
19475
|
this.logging._close();
|
|
19291
19476
|
if (this._wsManager !== null) {
|
|
19292
19477
|
this._wsManager.stop();
|