@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.d.cts CHANGED
@@ -1772,6 +1772,9 @@ declare class FlagsClient {
1772
1772
  private _flagBuffer;
1773
1773
  private _flagFlushTimer;
1774
1774
  private _handles;
1775
+ private _initBackoffMs;
1776
+ private _initRetryTimer;
1777
+ private _wsSubscribed;
1775
1778
  private _globalListeners;
1776
1779
  private _keyListeners;
1777
1780
  private _wsManager;
@@ -2090,6 +2093,11 @@ declare class FlagRegistrationBuffer {
2090
2093
  private _seen;
2091
2094
  private _pending;
2092
2095
  add(decl: FlagDeclaration): void;
2096
+ /** Non-destructive snapshot — items remain in the buffer until committed. */
2097
+ peek(): Array<components["schemas"]["FlagBulkItem"]>;
2098
+ /** Remove successfully-sent items by id. Called after a successful POST. */
2099
+ commit(ids: Set<string>): void;
2100
+ /** Destructively clear the buffer. For teardown / test use only. */
2093
2101
  drain(): Array<components["schemas"]["FlagBulkItem"]>;
2094
2102
  get pendingCount(): number;
2095
2103
  }
package/dist/index.d.ts CHANGED
@@ -1772,6 +1772,9 @@ declare class FlagsClient {
1772
1772
  private _flagBuffer;
1773
1773
  private _flagFlushTimer;
1774
1774
  private _handles;
1775
+ private _initBackoffMs;
1776
+ private _initRetryTimer;
1777
+ private _wsSubscribed;
1775
1778
  private _globalListeners;
1776
1779
  private _keyListeners;
1777
1780
  private _wsManager;
@@ -2090,6 +2093,11 @@ declare class FlagRegistrationBuffer {
2090
2093
  private _seen;
2091
2094
  private _pending;
2092
2095
  add(decl: FlagDeclaration): void;
2096
+ /** Non-destructive snapshot — items remain in the buffer until committed. */
2097
+ peek(): Array<components["schemas"]["FlagBulkItem"]>;
2098
+ /** Remove successfully-sent items by id. Called after a successful POST. */
2099
+ commit(ids: Set<string>): void;
2100
+ /** Destructively clear the buffer. For teardown / test use only. */
2093
2101
  drain(): Array<components["schemas"]["FlagBulkItem"]>;
2094
2102
  get pendingCount(): number;
2095
2103
  }
package/dist/index.js CHANGED
@@ -19133,6 +19133,15 @@ var FlagRegistrationBuffer = class {
19133
19133
  environment: decl.environment ?? void 0
19134
19134
  });
19135
19135
  }
19136
+ /** Non-destructive snapshot — items remain in the buffer until committed. */
19137
+ peek() {
19138
+ return [...this._pending];
19139
+ }
19140
+ /** Remove successfully-sent items by id. Called after a successful POST. */
19141
+ commit(ids) {
19142
+ this._pending = this._pending.filter((item) => !ids.has(item.id));
19143
+ }
19144
+ /** Destructively clear the buffer. For teardown / test use only. */
19136
19145
  drain() {
19137
19146
  const batch = this._pending;
19138
19147
  this._pending = [];
@@ -19274,10 +19283,13 @@ var ManagementFlagsClient = class {
19274
19283
  }
19275
19284
  /** Send any pending flag declarations to the server. */
19276
19285
  async flush() {
19277
- const batch = this._buffer.drain();
19286
+ const batch = this._buffer.peek();
19278
19287
  if (batch.length === 0) return;
19279
19288
  try {
19280
- await this._http.POST("/api/v1/flags/bulk", { body: { flags: batch } });
19289
+ const result = await this._http.POST("/api/v1/flags/bulk", { body: { flags: batch } });
19290
+ if (result.response.ok) {
19291
+ this._buffer.commit(new Set(batch.map((b) => b.id)));
19292
+ }
19281
19293
  } catch {
19282
19294
  }
19283
19295
  }
@@ -20826,6 +20838,15 @@ var FlagRegistrationBuffer2 = class {
20826
20838
  });
20827
20839
  }
20828
20840
  }
20841
+ /** Non-destructive snapshot — items remain in the buffer until committed. */
20842
+ peek() {
20843
+ return [...this._pending];
20844
+ }
20845
+ /** Remove successfully-sent items by id. Called after a successful POST. */
20846
+ commit(ids) {
20847
+ this._pending = this._pending.filter((item) => !ids.has(item.id));
20848
+ }
20849
+ /** Destructively clear the buffer. For teardown / test use only. */
20829
20850
  drain() {
20830
20851
  const batch = this._pending;
20831
20852
  this._pending = [];
@@ -20854,6 +20875,10 @@ var FlagsClient = class {
20854
20875
  _flagBuffer = new FlagRegistrationBuffer2();
20855
20876
  _flagFlushTimer = null;
20856
20877
  _handles = {};
20878
+ // Backoff-retry state for initialize() / _connectInternal()
20879
+ _initBackoffMs = 1e3;
20880
+ _initRetryTimer = null;
20881
+ _wsSubscribed = false;
20857
20882
  _globalListeners = [];
20858
20883
  _keyListeners = /* @__PURE__ */ new Map();
20859
20884
  // Shared WebSocket (set during initialize)
@@ -20931,7 +20956,14 @@ var FlagsClient = class {
20931
20956
  this._parent?._environment ?? null
20932
20957
  );
20933
20958
  if (this._flagBuffer.pendingCount >= FLAG_REGISTRATION_FLUSH_SIZE2) {
20934
- void this._flushFlags();
20959
+ void this._flushFlags().catch((err) => {
20960
+ const msg = err instanceof Error ? err.message : String(err);
20961
+ console.warn(`[smplkit] Failed to bulk-register flags: ${msg}`);
20962
+ debug(
20963
+ "registration",
20964
+ `flag bulk-register error: ${err instanceof Error ? err.stack ?? msg : msg}`
20965
+ );
20966
+ });
20935
20967
  }
20936
20968
  return handle;
20937
20969
  }
@@ -20957,7 +20989,14 @@ var FlagsClient = class {
20957
20989
  this._parent?._environment ?? null
20958
20990
  );
20959
20991
  if (this._flagBuffer.pendingCount >= FLAG_REGISTRATION_FLUSH_SIZE2) {
20960
- void this._flushFlags();
20992
+ void this._flushFlags().catch((err) => {
20993
+ const msg = err instanceof Error ? err.message : String(err);
20994
+ console.warn(`[smplkit] Failed to bulk-register flags: ${msg}`);
20995
+ debug(
20996
+ "registration",
20997
+ `flag bulk-register error: ${err instanceof Error ? err.stack ?? msg : msg}`
20998
+ );
20999
+ });
20961
21000
  }
20962
21001
  return handle;
20963
21002
  }
@@ -20983,7 +21022,14 @@ var FlagsClient = class {
20983
21022
  this._parent?._environment ?? null
20984
21023
  );
20985
21024
  if (this._flagBuffer.pendingCount >= FLAG_REGISTRATION_FLUSH_SIZE2) {
20986
- 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
+ });
20987
21033
  }
20988
21034
  return handle;
20989
21035
  }
@@ -21009,7 +21055,14 @@ var FlagsClient = class {
21009
21055
  this._parent?._environment ?? null
21010
21056
  );
21011
21057
  if (this._flagBuffer.pendingCount >= FLAG_REGISTRATION_FLUSH_SIZE2) {
21012
- 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
+ });
21013
21066
  }
21014
21067
  return handle;
21015
21068
  }
@@ -21044,19 +21097,51 @@ var FlagsClient = class {
21044
21097
  if (this._initialized) return;
21045
21098
  debug("lifecycle", "FlagsClient.initialize() called");
21046
21099
  this._environment = this._parent?._environment ?? null;
21047
- await this._flushFlags();
21048
- await this._fetchAllFlags();
21100
+ try {
21101
+ await this._flushFlags();
21102
+ await this._fetchAllFlags();
21103
+ } catch (err) {
21104
+ const msg = err instanceof Error ? err.message : String(err);
21105
+ console.warn(`[smplkit] FlagsClient initialization failed (will retry): ${msg}`);
21106
+ if (this._initRetryTimer !== null) {
21107
+ clearTimeout(this._initRetryTimer);
21108
+ this._initRetryTimer = null;
21109
+ }
21110
+ const delay = this._initBackoffMs;
21111
+ this._initBackoffMs = Math.min(this._initBackoffMs * 2, 6e4);
21112
+ this._initRetryTimer = setTimeout(() => {
21113
+ this._initRetryTimer = null;
21114
+ void this.initialize();
21115
+ }, delay);
21116
+ if (typeof this._initRetryTimer === "object" && "unref" in this._initRetryTimer) {
21117
+ this._initRetryTimer.unref();
21118
+ }
21119
+ return;
21120
+ }
21121
+ this._initBackoffMs = 1e3;
21049
21122
  this._initialized = true;
21050
21123
  this._cache.clear();
21051
- this._wsManager = this._ensureWs();
21052
- this._wsManager.on("flag_changed", this._handleFlagChanged);
21053
- this._wsManager.on("flag_deleted", this._handleFlagDeleted);
21054
- this._wsManager.on("flags_changed", this._handleFlagsChanged);
21055
- this._flagFlushTimer = setInterval(() => {
21056
- void this._flushFlags();
21057
- }, FLAG_REGISTRATION_FLUSH_INTERVAL_MS);
21058
- if (typeof this._flagFlushTimer === "object" && "unref" in this._flagFlushTimer) {
21059
- this._flagFlushTimer.unref();
21124
+ if (!this._wsSubscribed) {
21125
+ this._wsManager = this._ensureWs();
21126
+ this._wsManager.on("flag_changed", this._handleFlagChanged);
21127
+ this._wsManager.on("flag_deleted", this._handleFlagDeleted);
21128
+ this._wsManager.on("flags_changed", this._handleFlagsChanged);
21129
+ this._wsSubscribed = true;
21130
+ }
21131
+ if (this._flagFlushTimer === null) {
21132
+ this._flagFlushTimer = setInterval(() => {
21133
+ void this._flushFlags().catch((err) => {
21134
+ const msg = err instanceof Error ? err.message : String(err);
21135
+ console.warn(`[smplkit] Failed to bulk-register flags: ${msg}`);
21136
+ debug(
21137
+ "registration",
21138
+ `flag bulk-register error: ${err instanceof Error ? err.stack ?? msg : msg}`
21139
+ );
21140
+ });
21141
+ }, FLAG_REGISTRATION_FLUSH_INTERVAL_MS);
21142
+ if (typeof this._flagFlushTimer === "object" && "unref" in this._flagFlushTimer) {
21143
+ this._flagFlushTimer.unref();
21144
+ }
21060
21145
  }
21061
21146
  }
21062
21147
  /**
@@ -21066,6 +21151,10 @@ var FlagsClient = class {
21066
21151
  * @internal
21067
21152
  */
21068
21153
  _close() {
21154
+ if (this._initRetryTimer !== null) {
21155
+ clearTimeout(this._initRetryTimer);
21156
+ this._initRetryTimer = null;
21157
+ }
21069
21158
  if (this._flagFlushTimer !== null) {
21070
21159
  clearInterval(this._flagFlushTimer);
21071
21160
  this._flagFlushTimer = null;
@@ -21078,10 +21167,16 @@ var FlagsClient = class {
21078
21167
  }
21079
21168
  this._cache.clear();
21080
21169
  this._initialized = false;
21170
+ this._wsSubscribed = false;
21171
+ this._initBackoffMs = 1e3;
21081
21172
  this._environment = null;
21082
21173
  }
21083
21174
  /** Disconnect the flags runtime and release resources. */
21084
21175
  async disconnect() {
21176
+ if (this._initRetryTimer !== null) {
21177
+ clearTimeout(this._initRetryTimer);
21178
+ this._initRetryTimer = null;
21179
+ }
21085
21180
  if (this._wsManager !== null) {
21086
21181
  this._wsManager.off("flag_changed", this._handleFlagChanged);
21087
21182
  this._wsManager.off("flag_deleted", this._handleFlagDeleted);
@@ -21096,6 +21191,8 @@ var FlagsClient = class {
21096
21191
  this._flagStore = {};
21097
21192
  this._cache.clear();
21098
21193
  this._initialized = false;
21194
+ this._wsSubscribed = false;
21195
+ this._initBackoffMs = 1e3;
21099
21196
  this._environment = null;
21100
21197
  }
21101
21198
  /** Refresh all flag definitions from the server. */
@@ -21224,19 +21321,51 @@ var FlagsClient = class {
21224
21321
  /** @internal — called by SmplClient constructor / lazy init. */
21225
21322
  async _connectInternal(environment) {
21226
21323
  this._environment = environment;
21227
- await this._flushFlags();
21228
- await this._fetchAllFlags();
21324
+ try {
21325
+ await this._flushFlags();
21326
+ await this._fetchAllFlags();
21327
+ } catch (err) {
21328
+ const msg = err instanceof Error ? err.message : String(err);
21329
+ console.warn(`[smplkit] FlagsClient initialization failed (will retry): ${msg}`);
21330
+ if (this._initRetryTimer !== null) {
21331
+ clearTimeout(this._initRetryTimer);
21332
+ this._initRetryTimer = null;
21333
+ }
21334
+ const delay = this._initBackoffMs;
21335
+ this._initBackoffMs = Math.min(this._initBackoffMs * 2, 6e4);
21336
+ this._initRetryTimer = setTimeout(() => {
21337
+ this._initRetryTimer = null;
21338
+ void this._connectInternal(environment);
21339
+ }, delay);
21340
+ if (typeof this._initRetryTimer === "object" && "unref" in this._initRetryTimer) {
21341
+ this._initRetryTimer.unref();
21342
+ }
21343
+ return;
21344
+ }
21345
+ this._initBackoffMs = 1e3;
21229
21346
  this._initialized = true;
21230
21347
  this._cache.clear();
21231
- this._wsManager = this._ensureWs();
21232
- this._wsManager.on("flag_changed", this._handleFlagChanged);
21233
- this._wsManager.on("flag_deleted", this._handleFlagDeleted);
21234
- this._wsManager.on("flags_changed", this._handleFlagsChanged);
21235
- this._flagFlushTimer = setInterval(() => {
21236
- void this._flushFlags();
21237
- }, FLAG_REGISTRATION_FLUSH_INTERVAL_MS);
21238
- if (typeof this._flagFlushTimer === "object" && "unref" in this._flagFlushTimer) {
21239
- this._flagFlushTimer.unref();
21348
+ if (!this._wsSubscribed) {
21349
+ this._wsManager = this._ensureWs();
21350
+ this._wsManager.on("flag_changed", this._handleFlagChanged);
21351
+ this._wsManager.on("flag_deleted", this._handleFlagDeleted);
21352
+ this._wsManager.on("flags_changed", this._handleFlagsChanged);
21353
+ this._wsSubscribed = true;
21354
+ }
21355
+ if (this._flagFlushTimer === null) {
21356
+ this._flagFlushTimer = setInterval(() => {
21357
+ void this._flushFlags().catch((err) => {
21358
+ const msg = err instanceof Error ? err.message : String(err);
21359
+ console.warn(`[smplkit] Failed to bulk-register flags: ${msg}`);
21360
+ debug(
21361
+ "registration",
21362
+ `flag bulk-register error: ${err instanceof Error ? err.stack ?? msg : msg}`
21363
+ );
21364
+ });
21365
+ }, FLAG_REGISTRATION_FLUSH_INTERVAL_MS);
21366
+ if (typeof this._flagFlushTimer === "object" && "unref" in this._flagFlushTimer) {
21367
+ this._flagFlushTimer.unref();
21368
+ }
21240
21369
  }
21241
21370
  }
21242
21371
  // ------------------------------------------------------------------
@@ -21395,21 +21524,16 @@ var FlagsClient = class {
21395
21524
  // Internal: flag registration flush
21396
21525
  // ------------------------------------------------------------------
21397
21526
  async _flushFlags() {
21398
- const batch = this._flagBuffer.drain();
21527
+ const batch = this._flagBuffer.peek();
21399
21528
  if (batch.length === 0) return;
21400
21529
  debug("registration", `flushing ${batch.length} flag(s) to bulk-register endpoint`);
21401
- try {
21402
- await this._http.POST("/api/v1/flags/bulk", {
21403
- body: { flags: batch }
21404
- });
21405
- } catch (err) {
21406
- const msg = err instanceof Error ? err.message : String(err);
21407
- console.warn(`[smplkit] Failed to bulk-register flags: ${msg}`);
21408
- debug(
21409
- "registration",
21410
- `flag bulk-register error: ${err instanceof Error ? err.stack ?? msg : msg}`
21411
- );
21530
+ const result = await this._http.POST("/api/v1/flags/bulk", {
21531
+ body: { flags: batch }
21532
+ });
21533
+ if (!result.response.ok) {
21534
+ throw new Error(`HTTP ${result.response.status}`);
21412
21535
  }
21536
+ this._flagBuffer.commit(new Set(batch.map((b) => b.id)));
21413
21537
  }
21414
21538
  // ------------------------------------------------------------------
21415
21539
  // Internal: context flush