@smplkit/sdk 3.0.22 → 3.0.23

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
@@ -19199,6 +19199,15 @@ var FlagRegistrationBuffer = class {
19199
19199
  environment: decl.environment ?? void 0
19200
19200
  });
19201
19201
  }
19202
+ /** Non-destructive snapshot — items remain in the buffer until committed. */
19203
+ peek() {
19204
+ return [...this._pending];
19205
+ }
19206
+ /** Remove successfully-sent items by id. Called after a successful POST. */
19207
+ commit(ids) {
19208
+ this._pending = this._pending.filter((item) => !ids.has(item.id));
19209
+ }
19210
+ /** Destructively clear the buffer. For teardown / test use only. */
19202
19211
  drain() {
19203
19212
  const batch = this._pending;
19204
19213
  this._pending = [];
@@ -19340,10 +19349,13 @@ var ManagementFlagsClient = class {
19340
19349
  }
19341
19350
  /** Send any pending flag declarations to the server. */
19342
19351
  async flush() {
19343
- const batch = this._buffer.drain();
19352
+ const batch = this._buffer.peek();
19344
19353
  if (batch.length === 0) return;
19345
19354
  try {
19346
- await this._http.POST("/api/v1/flags/bulk", { body: { flags: batch } });
19355
+ const result = await this._http.POST("/api/v1/flags/bulk", { body: { flags: batch } });
19356
+ if (result.response.ok) {
19357
+ this._buffer.commit(new Set(batch.map((b) => b.id)));
19358
+ }
19347
19359
  } catch {
19348
19360
  }
19349
19361
  }
@@ -20892,6 +20904,15 @@ var FlagRegistrationBuffer2 = class {
20892
20904
  });
20893
20905
  }
20894
20906
  }
20907
+ /** Non-destructive snapshot — items remain in the buffer until committed. */
20908
+ peek() {
20909
+ return [...this._pending];
20910
+ }
20911
+ /** Remove successfully-sent items by id. Called after a successful POST. */
20912
+ commit(ids) {
20913
+ this._pending = this._pending.filter((item) => !ids.has(item.id));
20914
+ }
20915
+ /** Destructively clear the buffer. For teardown / test use only. */
20895
20916
  drain() {
20896
20917
  const batch = this._pending;
20897
20918
  this._pending = [];
@@ -20920,6 +20941,10 @@ var FlagsClient = class {
20920
20941
  _flagBuffer = new FlagRegistrationBuffer2();
20921
20942
  _flagFlushTimer = null;
20922
20943
  _handles = {};
20944
+ // Backoff-retry state for initialize() / _connectInternal()
20945
+ _initBackoffMs = 1e3;
20946
+ _initRetryTimer = null;
20947
+ _wsSubscribed = false;
20923
20948
  _globalListeners = [];
20924
20949
  _keyListeners = /* @__PURE__ */ new Map();
20925
20950
  // Shared WebSocket (set during initialize)
@@ -20997,7 +21022,14 @@ var FlagsClient = class {
20997
21022
  this._parent?._environment ?? null
20998
21023
  );
20999
21024
  if (this._flagBuffer.pendingCount >= FLAG_REGISTRATION_FLUSH_SIZE2) {
21000
- void this._flushFlags();
21025
+ void this._flushFlags().catch((err) => {
21026
+ const msg = err instanceof Error ? err.message : String(err);
21027
+ console.warn(`[smplkit] Failed to bulk-register flags: ${msg}`);
21028
+ debug(
21029
+ "registration",
21030
+ `flag bulk-register error: ${err instanceof Error ? err.stack ?? msg : msg}`
21031
+ );
21032
+ });
21001
21033
  }
21002
21034
  return handle;
21003
21035
  }
@@ -21023,7 +21055,14 @@ var FlagsClient = class {
21023
21055
  this._parent?._environment ?? null
21024
21056
  );
21025
21057
  if (this._flagBuffer.pendingCount >= FLAG_REGISTRATION_FLUSH_SIZE2) {
21026
- void this._flushFlags();
21058
+ void this._flushFlags().catch((err) => {
21059
+ const msg = err instanceof Error ? err.message : String(err);
21060
+ console.warn(`[smplkit] Failed to bulk-register flags: ${msg}`);
21061
+ debug(
21062
+ "registration",
21063
+ `flag bulk-register error: ${err instanceof Error ? err.stack ?? msg : msg}`
21064
+ );
21065
+ });
21027
21066
  }
21028
21067
  return handle;
21029
21068
  }
@@ -21049,7 +21088,14 @@ var FlagsClient = class {
21049
21088
  this._parent?._environment ?? null
21050
21089
  );
21051
21090
  if (this._flagBuffer.pendingCount >= FLAG_REGISTRATION_FLUSH_SIZE2) {
21052
- void this._flushFlags();
21091
+ void this._flushFlags().catch((err) => {
21092
+ const msg = err instanceof Error ? err.message : String(err);
21093
+ console.warn(`[smplkit] Failed to bulk-register flags: ${msg}`);
21094
+ debug(
21095
+ "registration",
21096
+ `flag bulk-register error: ${err instanceof Error ? err.stack ?? msg : msg}`
21097
+ );
21098
+ });
21053
21099
  }
21054
21100
  return handle;
21055
21101
  }
@@ -21075,7 +21121,14 @@ var FlagsClient = class {
21075
21121
  this._parent?._environment ?? null
21076
21122
  );
21077
21123
  if (this._flagBuffer.pendingCount >= FLAG_REGISTRATION_FLUSH_SIZE2) {
21078
- void this._flushFlags();
21124
+ void this._flushFlags().catch((err) => {
21125
+ const msg = err instanceof Error ? err.message : String(err);
21126
+ console.warn(`[smplkit] Failed to bulk-register flags: ${msg}`);
21127
+ debug(
21128
+ "registration",
21129
+ `flag bulk-register error: ${err instanceof Error ? err.stack ?? msg : msg}`
21130
+ );
21131
+ });
21079
21132
  }
21080
21133
  return handle;
21081
21134
  }
@@ -21110,19 +21163,51 @@ var FlagsClient = class {
21110
21163
  if (this._initialized) return;
21111
21164
  debug("lifecycle", "FlagsClient.initialize() called");
21112
21165
  this._environment = this._parent?._environment ?? null;
21113
- await this._flushFlags();
21114
- await this._fetchAllFlags();
21166
+ try {
21167
+ await this._flushFlags();
21168
+ await this._fetchAllFlags();
21169
+ } catch (err) {
21170
+ const msg = err instanceof Error ? err.message : String(err);
21171
+ console.warn(`[smplkit] FlagsClient initialization failed (will retry): ${msg}`);
21172
+ if (this._initRetryTimer !== null) {
21173
+ clearTimeout(this._initRetryTimer);
21174
+ this._initRetryTimer = null;
21175
+ }
21176
+ const delay = this._initBackoffMs;
21177
+ this._initBackoffMs = Math.min(this._initBackoffMs * 2, 6e4);
21178
+ this._initRetryTimer = setTimeout(() => {
21179
+ this._initRetryTimer = null;
21180
+ void this.initialize();
21181
+ }, delay);
21182
+ if (typeof this._initRetryTimer === "object" && "unref" in this._initRetryTimer) {
21183
+ this._initRetryTimer.unref();
21184
+ }
21185
+ return;
21186
+ }
21187
+ this._initBackoffMs = 1e3;
21115
21188
  this._initialized = true;
21116
21189
  this._cache.clear();
21117
- this._wsManager = this._ensureWs();
21118
- this._wsManager.on("flag_changed", this._handleFlagChanged);
21119
- this._wsManager.on("flag_deleted", this._handleFlagDeleted);
21120
- this._wsManager.on("flags_changed", this._handleFlagsChanged);
21121
- this._flagFlushTimer = setInterval(() => {
21122
- void this._flushFlags();
21123
- }, FLAG_REGISTRATION_FLUSH_INTERVAL_MS);
21124
- if (typeof this._flagFlushTimer === "object" && "unref" in this._flagFlushTimer) {
21125
- this._flagFlushTimer.unref();
21190
+ if (!this._wsSubscribed) {
21191
+ this._wsManager = this._ensureWs();
21192
+ this._wsManager.on("flag_changed", this._handleFlagChanged);
21193
+ this._wsManager.on("flag_deleted", this._handleFlagDeleted);
21194
+ this._wsManager.on("flags_changed", this._handleFlagsChanged);
21195
+ this._wsSubscribed = true;
21196
+ }
21197
+ if (this._flagFlushTimer === null) {
21198
+ this._flagFlushTimer = setInterval(() => {
21199
+ void this._flushFlags().catch((err) => {
21200
+ const msg = err instanceof Error ? err.message : String(err);
21201
+ console.warn(`[smplkit] Failed to bulk-register flags: ${msg}`);
21202
+ debug(
21203
+ "registration",
21204
+ `flag bulk-register error: ${err instanceof Error ? err.stack ?? msg : msg}`
21205
+ );
21206
+ });
21207
+ }, FLAG_REGISTRATION_FLUSH_INTERVAL_MS);
21208
+ if (typeof this._flagFlushTimer === "object" && "unref" in this._flagFlushTimer) {
21209
+ this._flagFlushTimer.unref();
21210
+ }
21126
21211
  }
21127
21212
  }
21128
21213
  /**
@@ -21132,6 +21217,10 @@ var FlagsClient = class {
21132
21217
  * @internal
21133
21218
  */
21134
21219
  _close() {
21220
+ if (this._initRetryTimer !== null) {
21221
+ clearTimeout(this._initRetryTimer);
21222
+ this._initRetryTimer = null;
21223
+ }
21135
21224
  if (this._flagFlushTimer !== null) {
21136
21225
  clearInterval(this._flagFlushTimer);
21137
21226
  this._flagFlushTimer = null;
@@ -21144,10 +21233,16 @@ var FlagsClient = class {
21144
21233
  }
21145
21234
  this._cache.clear();
21146
21235
  this._initialized = false;
21236
+ this._wsSubscribed = false;
21237
+ this._initBackoffMs = 1e3;
21147
21238
  this._environment = null;
21148
21239
  }
21149
21240
  /** Disconnect the flags runtime and release resources. */
21150
21241
  async disconnect() {
21242
+ if (this._initRetryTimer !== null) {
21243
+ clearTimeout(this._initRetryTimer);
21244
+ this._initRetryTimer = null;
21245
+ }
21151
21246
  if (this._wsManager !== null) {
21152
21247
  this._wsManager.off("flag_changed", this._handleFlagChanged);
21153
21248
  this._wsManager.off("flag_deleted", this._handleFlagDeleted);
@@ -21162,6 +21257,8 @@ var FlagsClient = class {
21162
21257
  this._flagStore = {};
21163
21258
  this._cache.clear();
21164
21259
  this._initialized = false;
21260
+ this._wsSubscribed = false;
21261
+ this._initBackoffMs = 1e3;
21165
21262
  this._environment = null;
21166
21263
  }
21167
21264
  /** Refresh all flag definitions from the server. */
@@ -21290,19 +21387,51 @@ var FlagsClient = class {
21290
21387
  /** @internal — called by SmplClient constructor / lazy init. */
21291
21388
  async _connectInternal(environment) {
21292
21389
  this._environment = environment;
21293
- await this._flushFlags();
21294
- await this._fetchAllFlags();
21390
+ try {
21391
+ await this._flushFlags();
21392
+ await this._fetchAllFlags();
21393
+ } catch (err) {
21394
+ const msg = err instanceof Error ? err.message : String(err);
21395
+ console.warn(`[smplkit] FlagsClient initialization failed (will retry): ${msg}`);
21396
+ if (this._initRetryTimer !== null) {
21397
+ clearTimeout(this._initRetryTimer);
21398
+ this._initRetryTimer = null;
21399
+ }
21400
+ const delay = this._initBackoffMs;
21401
+ this._initBackoffMs = Math.min(this._initBackoffMs * 2, 6e4);
21402
+ this._initRetryTimer = setTimeout(() => {
21403
+ this._initRetryTimer = null;
21404
+ void this._connectInternal(environment);
21405
+ }, delay);
21406
+ if (typeof this._initRetryTimer === "object" && "unref" in this._initRetryTimer) {
21407
+ this._initRetryTimer.unref();
21408
+ }
21409
+ return;
21410
+ }
21411
+ this._initBackoffMs = 1e3;
21295
21412
  this._initialized = true;
21296
21413
  this._cache.clear();
21297
- this._wsManager = this._ensureWs();
21298
- this._wsManager.on("flag_changed", this._handleFlagChanged);
21299
- this._wsManager.on("flag_deleted", this._handleFlagDeleted);
21300
- this._wsManager.on("flags_changed", this._handleFlagsChanged);
21301
- this._flagFlushTimer = setInterval(() => {
21302
- void this._flushFlags();
21303
- }, FLAG_REGISTRATION_FLUSH_INTERVAL_MS);
21304
- if (typeof this._flagFlushTimer === "object" && "unref" in this._flagFlushTimer) {
21305
- this._flagFlushTimer.unref();
21414
+ if (!this._wsSubscribed) {
21415
+ this._wsManager = this._ensureWs();
21416
+ this._wsManager.on("flag_changed", this._handleFlagChanged);
21417
+ this._wsManager.on("flag_deleted", this._handleFlagDeleted);
21418
+ this._wsManager.on("flags_changed", this._handleFlagsChanged);
21419
+ this._wsSubscribed = true;
21420
+ }
21421
+ if (this._flagFlushTimer === null) {
21422
+ this._flagFlushTimer = setInterval(() => {
21423
+ void this._flushFlags().catch((err) => {
21424
+ const msg = err instanceof Error ? err.message : String(err);
21425
+ console.warn(`[smplkit] Failed to bulk-register flags: ${msg}`);
21426
+ debug(
21427
+ "registration",
21428
+ `flag bulk-register error: ${err instanceof Error ? err.stack ?? msg : msg}`
21429
+ );
21430
+ });
21431
+ }, FLAG_REGISTRATION_FLUSH_INTERVAL_MS);
21432
+ if (typeof this._flagFlushTimer === "object" && "unref" in this._flagFlushTimer) {
21433
+ this._flagFlushTimer.unref();
21434
+ }
21306
21435
  }
21307
21436
  }
21308
21437
  // ------------------------------------------------------------------
@@ -21461,21 +21590,16 @@ var FlagsClient = class {
21461
21590
  // Internal: flag registration flush
21462
21591
  // ------------------------------------------------------------------
21463
21592
  async _flushFlags() {
21464
- const batch = this._flagBuffer.drain();
21593
+ const batch = this._flagBuffer.peek();
21465
21594
  if (batch.length === 0) return;
21466
21595
  debug("registration", `flushing ${batch.length} flag(s) to bulk-register endpoint`);
21467
- try {
21468
- await this._http.POST("/api/v1/flags/bulk", {
21469
- body: { flags: batch }
21470
- });
21471
- } catch (err) {
21472
- const msg = err instanceof Error ? err.message : String(err);
21473
- console.warn(`[smplkit] Failed to bulk-register flags: ${msg}`);
21474
- debug(
21475
- "registration",
21476
- `flag bulk-register error: ${err instanceof Error ? err.stack ?? msg : msg}`
21477
- );
21596
+ const result = await this._http.POST("/api/v1/flags/bulk", {
21597
+ body: { flags: batch }
21598
+ });
21599
+ if (!result.response.ok) {
21600
+ throw new Error(`HTTP ${result.response.status}`);
21478
21601
  }
21602
+ this._flagBuffer.commit(new Set(batch.map((b) => b.id)));
21479
21603
  }
21480
21604
  // ------------------------------------------------------------------
21481
21605
  // Internal: context flush