flagmint-js-sdk 2.2.2 → 2.2.3-rc.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.
@@ -38623,6 +38623,12 @@ var __publicField = (obj, key, value) => {
38623
38623
  } catch {
38624
38624
  }
38625
38625
  }
38626
+ function clearCachedFlags(apiKey) {
38627
+ try {
38628
+ storage$1.removeItem?.(getFlagsKey$1(apiKey));
38629
+ } catch {
38630
+ }
38631
+ }
38626
38632
  function loadCachedContext$1(apiKey) {
38627
38633
  try {
38628
38634
  const raw = storage$1.getItem(getContextKey$1(apiKey));
@@ -38661,6 +38667,7 @@ var __publicField = (obj, key, value) => {
38661
38667
  }
38662
38668
  const cacheHelper = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
38663
38669
  __proto__: null,
38670
+ clearCachedFlags,
38664
38671
  clearCachedRulesSnapshot: clearCachedRulesSnapshot$1,
38665
38672
  loadCachedContext: loadCachedContext$1,
38666
38673
  loadCachedFlags: loadCachedFlags$1,
@@ -39095,7 +39102,7 @@ var __publicField = (obj, key, value) => {
39095
39102
  this.connectPromise = new Promise((resolve, reject) => {
39096
39103
  this.connectResolve = resolve;
39097
39104
  this.connectReject = reject;
39098
- const sdkVersion = "2.2.2";
39105
+ const sdkVersion = "2.2.3-rc.0";
39099
39106
  const platform2 = typeof window !== "undefined" ? "browser" : "nodejs";
39100
39107
  const wrapperName = this.configOptions?.wrapper?.name || "native-js";
39101
39108
  const wrapperVersion = this.configOptions?.wrapper?.version || "none";
@@ -41907,22 +41914,80 @@ var __publicField = (obj, key, value) => {
41907
41914
  return false;
41908
41915
  return payload.piiSalt !== void 0 || payload.piiAttributes !== void 0 || payload.piiValueEncoding !== void 0;
41909
41916
  }
41917
+ function piiAttributeKeysFromPayload(payload) {
41918
+ if (!payload || !Array.isArray(payload.piiAttributes))
41919
+ return [];
41920
+ return payload.piiAttributes.filter((k) => typeof k === "string" && k.length > 0);
41921
+ }
41922
+ function hasMalformedPiiAttributes(payload) {
41923
+ if (!payload || payload.piiAttributes === void 0)
41924
+ return false;
41925
+ if (!Array.isArray(payload.piiAttributes))
41926
+ return true;
41927
+ return payload.piiAttributes.some(
41928
+ (entry) => typeof entry !== "string" || entry.length === 0
41929
+ );
41930
+ }
41931
+ function hasExplicitInvalidPiiEncoding(payload) {
41932
+ if (!payload || payload.piiValueEncoding === void 0)
41933
+ return false;
41934
+ return payload.piiValueEncoding !== PII_VALUE_ENCODING;
41935
+ }
41936
+ function payloadRequiresUsablePiiWire(payload) {
41937
+ if (!payload)
41938
+ return false;
41939
+ if (hasExplicitInvalidPiiEncoding(payload))
41940
+ return true;
41941
+ if (hasMalformedPiiAttributes(payload))
41942
+ return true;
41943
+ if (piiAttributeKeysFromPayload(payload).length > 0)
41944
+ return true;
41945
+ return false;
41946
+ }
41947
+ function isExplicitPiiRequirementCleared(payload) {
41948
+ if (!payload || payload.piiAttributes === void 0)
41949
+ return false;
41950
+ if (!Array.isArray(payload.piiAttributes))
41951
+ return false;
41952
+ if (payload.piiAttributes.length !== 0)
41953
+ return false;
41954
+ if (hasExplicitInvalidPiiEncoding(payload))
41955
+ return false;
41956
+ return true;
41957
+ }
41910
41958
  function piiWireOptionsFromPayload(payload) {
41911
41959
  if (!payload)
41912
41960
  return null;
41961
+ if (hasExplicitInvalidPiiEncoding(payload))
41962
+ return null;
41963
+ if (hasMalformedPiiAttributes(payload))
41964
+ return null;
41913
41965
  const salt = typeof payload.piiSalt === "string" ? payload.piiSalt : "";
41914
41966
  if (!salt)
41915
41967
  return null;
41916
- const encoding = typeof payload.piiValueEncoding === "string" ? payload.piiValueEncoding : PII_VALUE_ENCODING;
41917
- if (encoding !== PII_VALUE_ENCODING)
41918
- return null;
41919
- const attrs = Array.isArray(payload.piiAttributes) ? payload.piiAttributes.filter((k) => typeof k === "string") : [];
41968
+ const attrs = piiAttributeKeysFromPayload(payload);
41920
41969
  return {
41921
41970
  piiAttributes: attrs,
41922
41971
  piiSalt: salt,
41923
41972
  piiValueEncoding: PII_VALUE_ENCODING
41924
41973
  };
41925
41974
  }
41975
+ function isPiiWireBroken(payload, resolved, previousPriorHadPiiAttrs = false) {
41976
+ if (hasExplicitInvalidPiiEncoding(payload) || hasMalformedPiiAttributes(payload)) {
41977
+ return true;
41978
+ }
41979
+ if (resolved) {
41980
+ return false;
41981
+ }
41982
+ if (isExplicitPiiRequirementCleared(payload))
41983
+ return false;
41984
+ if (payloadRequiresUsablePiiWire(payload))
41985
+ return true;
41986
+ if (previousPriorHadPiiAttrs && payloadHasExplicitPiiFields(payload)) {
41987
+ return true;
41988
+ }
41989
+ return false;
41990
+ }
41926
41991
  function resolvePiiWireForDelta(previous, action) {
41927
41992
  if (!payloadHasExplicitPiiFields(action)) {
41928
41993
  return previous;
@@ -41975,7 +42040,8 @@ var __publicField = (obj, key, value) => {
41975
42040
  segments: /* @__PURE__ */ new Map(),
41976
42041
  ready: false,
41977
42042
  needsFullConfig: true,
41978
- piiWire: null
42043
+ piiWire: null,
42044
+ piiWireBroken: false
41979
42045
  };
41980
42046
  }
41981
42047
  function cloneState(state) {
@@ -41990,7 +42056,8 @@ var __publicField = (obj, key, value) => {
41990
42056
  piiAttributes: [...state.piiWire.piiAttributes],
41991
42057
  piiSalt: state.piiWire.piiSalt,
41992
42058
  piiValueEncoding: state.piiWire.piiValueEncoding
41993
- } : null
42059
+ } : null,
42060
+ piiWireBroken: state.piiWireBroken
41994
42061
  };
41995
42062
  }
41996
42063
  function segmentsFromRecord(record) {
@@ -42017,14 +42084,18 @@ var __publicField = (obj, key, value) => {
42017
42084
  if (flag?.key)
42018
42085
  flags.set(flag.key, flag);
42019
42086
  }
42087
+ const piiWire = piiWireOptionsFromPayload(action);
42088
+ const piiWireBroken = isPiiWireBroken(action, piiWire, false);
42020
42089
  return {
42021
42090
  version: action.version,
42022
42091
  expiresAt: action.expiresAt,
42023
42092
  flags,
42024
42093
  segments: segmentsFromRecord(action.segments),
42025
- ready: true,
42026
- needsFullConfig: false,
42027
- piiWire: piiWireOptionsFromPayload(action)
42094
+ // Usable rules, but PII metadata must be valid when hashing is required.
42095
+ ready: !piiWireBroken,
42096
+ needsFullConfig: piiWireBroken,
42097
+ piiWire,
42098
+ piiWireBroken
42028
42099
  };
42029
42100
  }
42030
42101
  function applyPatch(state, action) {
@@ -42037,14 +42108,19 @@ var __publicField = (obj, key, value) => {
42037
42108
  flags.set(flag.key, flag);
42038
42109
  }
42039
42110
  const nextPii = resolvePiiWireForDelta(state.piiWire, action);
42111
+ const priorHadPiiAttrs = (state.piiWire?.piiAttributes.length ?? 0) > 0 || state.piiWireBroken;
42112
+ const computedBroken = isPiiWireBroken(action, nextPii, priorHadPiiAttrs);
42113
+ const recoveredWithRequiredAttrs = !!nextPii && nextPii.piiAttributes.length > 0;
42114
+ const piiWireBroken = isExplicitPiiRequirementCleared(action) ? false : recoveredWithRequiredAttrs ? false : computedBroken || state.piiWireBroken;
42040
42115
  return {
42041
42116
  version: action.toVersion,
42042
42117
  expiresAt: typeof action.expiresAt === "number" ? action.expiresAt : state.expiresAt,
42043
42118
  flags,
42044
42119
  segments: applySegmentUpserts(state.segments, action.segments),
42045
- ready: true,
42046
- needsFullConfig: false,
42047
- piiWire: nextPii
42120
+ ready: !piiWireBroken,
42121
+ needsFullConfig: piiWireBroken,
42122
+ piiWire: nextPii,
42123
+ piiWireBroken
42048
42124
  };
42049
42125
  }
42050
42126
  function reduceRules(state, action, now = Date.now()) {
@@ -42064,8 +42140,8 @@ var __publicField = (obj, key, value) => {
42064
42140
  ...cloneState(state),
42065
42141
  version: state.version,
42066
42142
  expiresAt: action.expiresAt,
42067
- ready: true,
42068
- needsFullConfig: state.flags.size === 0 || versionMismatch ? true : state.needsFullConfig
42143
+ ready: !state.piiWireBroken,
42144
+ needsFullConfig: state.piiWireBroken || state.flags.size === 0 || versionMismatch ? true : state.needsFullConfig
42069
42145
  }
42070
42146
  };
42071
42147
  }
@@ -42121,8 +42197,8 @@ var __publicField = (obj, key, value) => {
42121
42197
  ...current,
42122
42198
  version: action.toVersion,
42123
42199
  expiresAt: typeof action.expiresAt === "number" ? action.expiresAt : current.expiresAt,
42124
- ready: true,
42125
- needsFullConfig: false
42200
+ ready: !current.piiWireBroken,
42201
+ needsFullConfig: current.piiWireBroken
42126
42202
  }
42127
42203
  };
42128
42204
  }
@@ -42145,9 +42221,12 @@ var __publicField = (obj, key, value) => {
42145
42221
  return this.state;
42146
42222
  }
42147
42223
  /**
42148
- * Fail-closed readiness: lease not expired and store marked ready.
42224
+ * Fail-closed readiness: lease not expired, store marked ready, and PII
42225
+ * wire metadata usable when hashing is required.
42149
42226
  */
42150
42227
  isReady(now = Date.now()) {
42228
+ if (this.state.piiWireBroken)
42229
+ return false;
42151
42230
  if (!this.state.ready)
42152
42231
  return false;
42153
42232
  if (!this.state.expiresAt)
@@ -42231,7 +42310,9 @@ var __publicField = (obj, key, value) => {
42231
42310
  piiAttributes: [...pii.piiAttributes],
42232
42311
  piiSalt: pii.piiSalt,
42233
42312
  piiValueEncoding: pii.piiValueEncoding
42234
- } : {}
42313
+ } : {},
42314
+ // Persist fail-closed even when piiWire is null (unusable salt/encoding).
42315
+ ...this.state.piiWireBroken ? { piiWireBroken: true } : {}
42235
42316
  };
42236
42317
  }
42237
42318
  hydrateFromSnapshot(snapshot, now = Date.now()) {
@@ -42241,14 +42322,17 @@ var __publicField = (obj, key, value) => {
42241
42322
  flags.set(flag.key, flag);
42242
42323
  }
42243
42324
  const expired = isConfigPayloadExpired(snapshot.expiresAt, now);
42325
+ const piiWire = piiWireOptionsFromPayload(snapshot);
42326
+ const piiWireBroken = snapshot.piiWireBroken === true || isPiiWireBroken(snapshot, piiWire, false);
42244
42327
  this.state = {
42245
42328
  version: snapshot.version,
42246
42329
  expiresAt: snapshot.expiresAt,
42247
42330
  flags,
42248
42331
  segments: segmentsFromRecord(snapshot.segments),
42249
- ready: !expired && flags.size > 0,
42250
- needsFullConfig: expired || flags.size === 0,
42251
- piiWire: piiWireOptionsFromPayload(snapshot)
42332
+ ready: !expired && flags.size > 0 && !piiWireBroken,
42333
+ needsFullConfig: expired || flags.size === 0 || piiWireBroken,
42334
+ piiWire,
42335
+ piiWireBroken
42252
42336
  };
42253
42337
  }
42254
42338
  }
@@ -43219,9 +43303,10 @@ var __publicField = (obj, key, value) => {
43219
43303
  }
43220
43304
  let hydratedRules = false;
43221
43305
  if (this.configSync && this.rulesStore && this.enableOfflineCache) {
43306
+ clearCachedFlags(this.apiKey);
43222
43307
  hydratedRules = await this.hydrateRulesFromCache();
43223
43308
  }
43224
- if (this.enableOfflineCache && !hydratedRules) {
43309
+ if (this.enableOfflineCache && !this.configSync && !hydratedRules) {
43225
43310
  const cached = await Promise.resolve(
43226
43311
  this.cacheAdapter.loadFlags(this.apiKey, this.cacheTTL)
43227
43312
  );
@@ -43463,7 +43548,7 @@ var __publicField = (obj, key, value) => {
43463
43548
  */
43464
43549
  updateFlags(newFlags, fromShare = false) {
43465
43550
  this.flags = newFlags;
43466
- if (this.enableOfflineCache) {
43551
+ if (this.enableOfflineCache && !this.configSync) {
43467
43552
  void Promise.resolve(
43468
43553
  this.cacheAdapter.saveFlags(this.apiKey, newFlags)
43469
43554
  );