flagmint-js-sdk 2.2.1 → 2.2.2-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.
@@ -39091,7 +39091,7 @@ class SseTransport {
39091
39091
  this.connectPromise = new Promise((resolve, reject) => {
39092
39092
  this.connectResolve = resolve;
39093
39093
  this.connectReject = reject;
39094
- const sdkVersion = "2.2.1";
39094
+ const sdkVersion = "2.2.2-rc.0";
39095
39095
  const platform2 = typeof window !== "undefined" ? "browser" : "nodejs";
39096
39096
  const wrapperName = this.configOptions?.wrapper?.name || "native-js";
39097
39097
  const wrapperVersion = this.configOptions?.wrapper?.version || "none";
@@ -41777,7 +41777,7 @@ function expand2(hash3, prk, info, length = 32) {
41777
41777
  const hkdf = (hash3, ikm, salt, info, length) => expand2(hash3, extract(hash3, ikm, salt), info, length);
41778
41778
  const ASL_HKDF_INFO = "flagmint-asl-config-sync-mac-v1";
41779
41779
  const ASL_KEY_AGREEMENT = "x25519-hkdf-sha256";
41780
- const textEncoder$1 = new TextEncoder();
41780
+ const textEncoder$2 = new TextEncoder();
41781
41781
  function generateAslClientKeyPair() {
41782
41782
  const privateKey = x25519.utils.randomSecretKey();
41783
41783
  const publicKey = x25519.getPublicKey(privateKey);
@@ -41808,7 +41808,7 @@ function deriveAslMacKey(input) {
41808
41808
  sha256,
41809
41809
  shared,
41810
41810
  salt,
41811
- textEncoder$1.encode(ASL_HKDF_INFO),
41811
+ textEncoder$2.encode(ASL_HKDF_INFO),
41812
41812
  32
41813
41813
  );
41814
41814
  return { configMacKey };
@@ -41818,7 +41818,7 @@ function wipeKeyMaterial(key2) {
41818
41818
  return;
41819
41819
  key2.fill(0);
41820
41820
  }
41821
- const textEncoder = new TextEncoder();
41821
+ const textEncoder$1 = new TextEncoder();
41822
41822
  function canonicalizeForSigning(value) {
41823
41823
  return JSON.stringify(sortValue(value));
41824
41824
  }
@@ -41835,12 +41835,12 @@ function sortValue(value) {
41835
41835
  return sorted;
41836
41836
  }
41837
41837
  function normalizeMacKey(secret2) {
41838
- return typeof secret2 === "string" ? textEncoder.encode(secret2) : secret2;
41838
+ return typeof secret2 === "string" ? textEncoder$1.encode(secret2) : secret2;
41839
41839
  }
41840
41840
  function signConfigPayload(body, secret2) {
41841
41841
  const { signature: _ignored, ...unsigned } = body;
41842
41842
  const canonical = canonicalizeForSigning(unsigned);
41843
- const mac = hmac2(sha256, normalizeMacKey(secret2), textEncoder.encode(canonical));
41843
+ const mac = hmac2(sha256, normalizeMacKey(secret2), textEncoder$1.encode(canonical));
41844
41844
  return bytesToHex$1(mac);
41845
41845
  }
41846
41846
  function timingSafeEqualBytes(a, b) {
@@ -41862,13 +41862,93 @@ function verifyConfigPayloadSignature(body, secret2) {
41862
41862
  } catch {
41863
41863
  return false;
41864
41864
  }
41865
- const a = textEncoder.encode(body.signature);
41866
- const b = textEncoder.encode(expected);
41865
+ const a = textEncoder$1.encode(body.signature);
41866
+ const b = textEncoder$1.encode(expected);
41867
41867
  return timingSafeEqualBytes(a, b);
41868
41868
  }
41869
41869
  function isConfigPayloadExpired(expiresAt, now = Date.now()) {
41870
41870
  return !Number.isFinite(expiresAt) || now >= expiresAt;
41871
41871
  }
41872
+ const PII_VALUE_ENCODING = "hmac-v1";
41873
+ const textEncoder = new TextEncoder();
41874
+ const HASH_HEX_PATTERN = /^[0-9a-f]{64}$/;
41875
+ function normalizePiiString(value) {
41876
+ return value.trim().toLowerCase();
41877
+ }
41878
+ function hashPiiValue(value, salt) {
41879
+ const mac = hmac2(
41880
+ sha256,
41881
+ textEncoder.encode(salt),
41882
+ textEncoder.encode(normalizePiiString(value))
41883
+ );
41884
+ return bytesToHex$1(mac);
41885
+ }
41886
+ function isPiiAttribute(attribute, piiAttributes) {
41887
+ if (!attribute || piiAttributes.length === 0)
41888
+ return false;
41889
+ const attr = attribute.trim();
41890
+ if (!attr)
41891
+ return false;
41892
+ for (const key2 of piiAttributes) {
41893
+ if (!key2)
41894
+ continue;
41895
+ if (attr === key2)
41896
+ return true;
41897
+ if (attr.endsWith(`.${key2}`))
41898
+ return true;
41899
+ }
41900
+ return false;
41901
+ }
41902
+ function piiWireOptionsFromPayload(payload) {
41903
+ if (!payload)
41904
+ return null;
41905
+ const salt = typeof payload.piiSalt === "string" ? payload.piiSalt : "";
41906
+ if (!salt)
41907
+ return null;
41908
+ const encoding = typeof payload.piiValueEncoding === "string" ? payload.piiValueEncoding : PII_VALUE_ENCODING;
41909
+ if (encoding !== PII_VALUE_ENCODING)
41910
+ return null;
41911
+ const attrs = Array.isArray(payload.piiAttributes) ? payload.piiAttributes.filter((k) => typeof k === "string") : [];
41912
+ return {
41913
+ piiAttributes: attrs,
41914
+ piiSalt: salt,
41915
+ piiValueEncoding: PII_VALUE_ENCODING
41916
+ };
41917
+ }
41918
+ function applyPiiHashToFlatContext(context, options) {
41919
+ if (!options || !options.piiSalt || !options.piiAttributes.length || options.piiValueEncoding !== PII_VALUE_ENCODING) {
41920
+ return context;
41921
+ }
41922
+ let changed = false;
41923
+ const out = { ...context };
41924
+ for (const [key2, value] of Object.entries(context)) {
41925
+ if (!isPiiAttribute(key2, options.piiAttributes))
41926
+ continue;
41927
+ if (typeof value === "string") {
41928
+ if (HASH_HEX_PATTERN.test(value))
41929
+ continue;
41930
+ out[key2] = hashPiiValue(value, options.piiSalt);
41931
+ changed = true;
41932
+ continue;
41933
+ }
41934
+ if (Array.isArray(value)) {
41935
+ let arrayChanged = false;
41936
+ const next = value.map((entry) => {
41937
+ if (typeof entry !== "string")
41938
+ return entry;
41939
+ if (HASH_HEX_PATTERN.test(entry))
41940
+ return entry;
41941
+ arrayChanged = true;
41942
+ return hashPiiValue(entry, options.piiSalt);
41943
+ });
41944
+ if (arrayChanged) {
41945
+ out[key2] = next;
41946
+ changed = true;
41947
+ }
41948
+ }
41949
+ }
41950
+ return changed ? out : context;
41951
+ }
41872
41952
  function createEmptyRulesState() {
41873
41953
  return {
41874
41954
  version: 0,
@@ -41876,7 +41956,8 @@ function createEmptyRulesState() {
41876
41956
  flags: /* @__PURE__ */ new Map(),
41877
41957
  segments: /* @__PURE__ */ new Map(),
41878
41958
  ready: false,
41879
- needsFullConfig: true
41959
+ needsFullConfig: true,
41960
+ piiWire: null
41880
41961
  };
41881
41962
  }
41882
41963
  function cloneState(state) {
@@ -41886,7 +41967,12 @@ function cloneState(state) {
41886
41967
  flags: new Map(state.flags),
41887
41968
  segments: new Map(state.segments),
41888
41969
  ready: state.ready,
41889
- needsFullConfig: state.needsFullConfig
41970
+ needsFullConfig: state.needsFullConfig,
41971
+ piiWire: state.piiWire ? {
41972
+ piiAttributes: [...state.piiWire.piiAttributes],
41973
+ piiSalt: state.piiWire.piiSalt,
41974
+ piiValueEncoding: state.piiWire.piiValueEncoding
41975
+ } : null
41890
41976
  };
41891
41977
  }
41892
41978
  function segmentsFromRecord(record) {
@@ -41919,7 +42005,8 @@ function hydrateFromFull(action) {
41919
42005
  flags,
41920
42006
  segments: segmentsFromRecord(action.segments),
41921
42007
  ready: true,
41922
- needsFullConfig: false
42008
+ needsFullConfig: false,
42009
+ piiWire: piiWireOptionsFromPayload(action)
41923
42010
  };
41924
42011
  }
41925
42012
  function applyPatch(state, action) {
@@ -41931,13 +42018,15 @@ function applyPatch(state, action) {
41931
42018
  if (flag?.key)
41932
42019
  flags.set(flag.key, flag);
41933
42020
  }
42021
+ const nextPii = piiWireOptionsFromPayload(action) ?? state.piiWire;
41934
42022
  return {
41935
42023
  version: action.toVersion,
41936
42024
  expiresAt: typeof action.expiresAt === "number" ? action.expiresAt : state.expiresAt,
41937
42025
  flags,
41938
42026
  segments: applySegmentUpserts(state.segments, action.segments),
41939
42027
  ready: true,
41940
- needsFullConfig: false
42028
+ needsFullConfig: false,
42029
+ piiWire: nextPii
41941
42030
  };
41942
42031
  }
41943
42032
  function reduceRules(state, action, now = Date.now()) {
@@ -42114,11 +42203,17 @@ class RulesStore {
42114
42203
  this.state.segments.forEach((segment, id) => {
42115
42204
  segments[id] = segment;
42116
42205
  });
42206
+ const pii = this.state.piiWire;
42117
42207
  return {
42118
42208
  version: this.state.version,
42119
42209
  expiresAt: this.state.expiresAt,
42120
42210
  flags: Array.from(this.state.flags.values()),
42121
- segments
42211
+ segments,
42212
+ ...pii ? {
42213
+ piiAttributes: [...pii.piiAttributes],
42214
+ piiSalt: pii.piiSalt,
42215
+ piiValueEncoding: pii.piiValueEncoding
42216
+ } : {}
42122
42217
  };
42123
42218
  }
42124
42219
  hydrateFromSnapshot(snapshot, now = Date.now()) {
@@ -42134,7 +42229,8 @@ class RulesStore {
42134
42229
  flags,
42135
42230
  segments: segmentsFromRecord(snapshot.segments),
42136
42231
  ready: !expired && flags.size > 0,
42137
- needsFullConfig: expired || flags.size === 0
42232
+ needsFullConfig: expired || flags.size === 0,
42233
+ piiWire: piiWireOptionsFromPayload(snapshot)
42138
42234
  };
42139
42235
  }
42140
42236
  }
@@ -42898,8 +42994,13 @@ function prepareContextForEvaluator(context) {
42898
42994
  }
42899
42995
  return context;
42900
42996
  }
42901
- function evaluateSdkFlag(flag, context, segments) {
42902
- const evalContext = prepareContextForEvaluator(context);
42997
+ function prepareContextForLocalEval(context, pii) {
42998
+ const prepared = prepareContextForEvaluator(context);
42999
+ const flat = flattenEvaluationContext(prepared);
43000
+ return applyPiiHashToFlatContext(flat, pii);
43001
+ }
43002
+ function evaluateSdkFlag(flag, context, segments, pii) {
43003
+ const evalContext = prepareContextForLocalEval(context, pii);
42903
43004
  const variationsById = {};
42904
43005
  for (const v of flag.variations || []) {
42905
43006
  if (v?.id)
@@ -42959,7 +43060,7 @@ function evaluateSdkFlag(flag, context, segments) {
42959
43060
  }
42960
43061
  function evaluateAllSdkFlags(flags, context, segments, options) {
42961
43062
  const list = flags instanceof Map ? Array.from(flags.values()) : flags;
42962
- const prepared = prepareContextForEvaluator(context);
43063
+ const prepared = prepareContextForLocalEval(context, options?.pii);
42963
43064
  const out = {};
42964
43065
  for (const flag of list) {
42965
43066
  if (!flag?.key)
@@ -42968,7 +43069,7 @@ function evaluateAllSdkFlags(flags, context, segments, options) {
42968
43069
  out[flag.key] = coerceType(flag.default_value, flag.type);
42969
43070
  continue;
42970
43071
  }
42971
- out[flag.key] = evaluateSdkFlag(flag, prepared, segments);
43072
+ out[flag.key] = evaluateSdkFlag(flag, prepared, segments, null);
42972
43073
  }
42973
43074
  return out;
42974
43075
  }
@@ -43413,7 +43514,8 @@ class FlagClient {
43413
43514
  value = evaluateSdkFlag(
43414
43515
  flag,
43415
43516
  this.context,
43416
- this.rulesStore.getState().segments
43517
+ this.rulesStore.getState().segments,
43518
+ this.rulesStore.getState().piiWire
43417
43519
  ) ?? fallback;
43418
43520
  }
43419
43521
  } else {
@@ -43893,7 +43995,7 @@ class FlagClient {
43893
43995
  state.flags,
43894
43996
  context ?? this.context,
43895
43997
  state.segments,
43896
- { failClosedDefaultsOnly: failClosed }
43998
+ { failClosedDefaultsOnly: failClosed, pii: state.piiWire }
43897
43999
  );
43898
44000
  }
43899
44001
  analyticsMapFromRulesStore() {
@@ -44023,6 +44125,7 @@ export {
44023
44125
  LongPollingTransport,
44024
44126
  RulesStore,
44025
44127
  SseTransport,
44128
+ applyPiiHashToFlatContext,
44026
44129
  applyRolloutStrategy,
44027
44130
  cacheHelper_async as asyncCache,
44028
44131
  canonicalizeForSigning,
@@ -44040,11 +44143,13 @@ export {
44040
44143
  flattenEvaluationContext,
44041
44144
  generateAslClientKeyPair,
44042
44145
  hashPercent,
44146
+ hashPiiValue,
44043
44147
  hashToPercentage,
44044
44148
  isConfigPayloadExpired,
44045
44149
  isInSegment,
44046
44150
  performAslHandshake,
44047
44151
  pickVariant,
44152
+ prepareContextForLocalEval,
44048
44153
  reduceRules,
44049
44154
  signConfigPayload,
44050
44155
  stringHash,