flagmint-js-sdk 2.2.1 → 2.2.2
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/README.md +1 -1
- package/dist/flagmint.cjs.js +140 -21
- package/dist/flagmint.cjs.js.map +1 -1
- package/dist/flagmint.es.js +140 -21
- package/dist/flagmint.es.js.map +1 -1
- package/dist/flagmint.umd.js +140 -21
- package/dist/flagmint.umd.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/sdk/core/config-sync/evaluateSdkFlag.d.ts +24 -1
- package/dist/sdk/core/config-sync/index.d.ts +4 -2
- package/dist/sdk/core/config-sync/piiHash.d.ts +87 -0
- package/dist/sdk/core/config-sync/rulesStore.d.ts +3 -0
- package/dist/sdk/core/config-sync/types.d.ts +12 -2
- package/package.json +1 -1
package/dist/flagmint.es.js
CHANGED
|
@@ -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.
|
|
39094
|
+
const sdkVersion = "2.2.2";
|
|
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$
|
|
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$
|
|
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,107 @@ 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
|
+
function normalizePiiString(value) {
|
|
41875
|
+
return value.trim().toLowerCase();
|
|
41876
|
+
}
|
|
41877
|
+
function hashPiiValue(value, salt) {
|
|
41878
|
+
const mac = hmac2(
|
|
41879
|
+
sha256,
|
|
41880
|
+
textEncoder.encode(salt),
|
|
41881
|
+
textEncoder.encode(normalizePiiString(value))
|
|
41882
|
+
);
|
|
41883
|
+
return bytesToHex$1(mac);
|
|
41884
|
+
}
|
|
41885
|
+
function isPiiAttribute(attribute, piiAttributes) {
|
|
41886
|
+
if (!attribute || piiAttributes.length === 0)
|
|
41887
|
+
return false;
|
|
41888
|
+
const attr = attribute.trim();
|
|
41889
|
+
if (!attr)
|
|
41890
|
+
return false;
|
|
41891
|
+
for (const key2 of piiAttributes) {
|
|
41892
|
+
if (!key2)
|
|
41893
|
+
continue;
|
|
41894
|
+
if (attr === key2)
|
|
41895
|
+
return true;
|
|
41896
|
+
if (attr.endsWith(`.${key2}`))
|
|
41897
|
+
return true;
|
|
41898
|
+
}
|
|
41899
|
+
return false;
|
|
41900
|
+
}
|
|
41901
|
+
function payloadHasExplicitPiiFields(payload) {
|
|
41902
|
+
if (!payload)
|
|
41903
|
+
return false;
|
|
41904
|
+
return payload.piiSalt !== void 0 || payload.piiAttributes !== void 0 || payload.piiValueEncoding !== void 0;
|
|
41905
|
+
}
|
|
41906
|
+
function piiWireOptionsFromPayload(payload) {
|
|
41907
|
+
if (!payload)
|
|
41908
|
+
return null;
|
|
41909
|
+
const salt = typeof payload.piiSalt === "string" ? payload.piiSalt : "";
|
|
41910
|
+
if (!salt)
|
|
41911
|
+
return null;
|
|
41912
|
+
const encoding = typeof payload.piiValueEncoding === "string" ? payload.piiValueEncoding : PII_VALUE_ENCODING;
|
|
41913
|
+
if (encoding !== PII_VALUE_ENCODING)
|
|
41914
|
+
return null;
|
|
41915
|
+
const attrs = Array.isArray(payload.piiAttributes) ? payload.piiAttributes.filter((k) => typeof k === "string") : [];
|
|
41916
|
+
return {
|
|
41917
|
+
piiAttributes: attrs,
|
|
41918
|
+
piiSalt: salt,
|
|
41919
|
+
piiValueEncoding: PII_VALUE_ENCODING
|
|
41920
|
+
};
|
|
41921
|
+
}
|
|
41922
|
+
function resolvePiiWireForDelta(previous, action) {
|
|
41923
|
+
if (!payloadHasExplicitPiiFields(action)) {
|
|
41924
|
+
return previous;
|
|
41925
|
+
}
|
|
41926
|
+
const merged = {
|
|
41927
|
+
piiSalt: action.piiSalt !== void 0 ? action.piiSalt : previous?.piiSalt,
|
|
41928
|
+
piiAttributes: action.piiAttributes !== void 0 ? action.piiAttributes : previous?.piiAttributes,
|
|
41929
|
+
piiValueEncoding: action.piiValueEncoding !== void 0 ? action.piiValueEncoding : previous?.piiValueEncoding
|
|
41930
|
+
};
|
|
41931
|
+
return piiWireOptionsFromPayload(merged);
|
|
41932
|
+
}
|
|
41933
|
+
function applyPiiHashToFlatContext(context, options, mode) {
|
|
41934
|
+
if (!options || !options.piiSalt || !options.piiAttributes.length || options.piiValueEncoding !== PII_VALUE_ENCODING) {
|
|
41935
|
+
return context;
|
|
41936
|
+
}
|
|
41937
|
+
if (mode?.alreadyHashed) {
|
|
41938
|
+
return context;
|
|
41939
|
+
}
|
|
41940
|
+
let changed = false;
|
|
41941
|
+
const out = { ...context };
|
|
41942
|
+
for (const [key2, value] of Object.entries(context)) {
|
|
41943
|
+
if (!isPiiAttribute(key2, options.piiAttributes))
|
|
41944
|
+
continue;
|
|
41945
|
+
if (typeof value === "string") {
|
|
41946
|
+
out[key2] = hashPiiValue(value, options.piiSalt);
|
|
41947
|
+
changed = true;
|
|
41948
|
+
continue;
|
|
41949
|
+
}
|
|
41950
|
+
if (Array.isArray(value)) {
|
|
41951
|
+
let arrayChanged = false;
|
|
41952
|
+
const next = value.map((entry) => {
|
|
41953
|
+
if (typeof entry !== "string")
|
|
41954
|
+
return entry;
|
|
41955
|
+
arrayChanged = true;
|
|
41956
|
+
return hashPiiValue(entry, options.piiSalt);
|
|
41957
|
+
});
|
|
41958
|
+
if (arrayChanged) {
|
|
41959
|
+
out[key2] = next;
|
|
41960
|
+
changed = true;
|
|
41961
|
+
}
|
|
41962
|
+
}
|
|
41963
|
+
}
|
|
41964
|
+
return changed ? out : context;
|
|
41965
|
+
}
|
|
41872
41966
|
function createEmptyRulesState() {
|
|
41873
41967
|
return {
|
|
41874
41968
|
version: 0,
|
|
@@ -41876,7 +41970,8 @@ function createEmptyRulesState() {
|
|
|
41876
41970
|
flags: /* @__PURE__ */ new Map(),
|
|
41877
41971
|
segments: /* @__PURE__ */ new Map(),
|
|
41878
41972
|
ready: false,
|
|
41879
|
-
needsFullConfig: true
|
|
41973
|
+
needsFullConfig: true,
|
|
41974
|
+
piiWire: null
|
|
41880
41975
|
};
|
|
41881
41976
|
}
|
|
41882
41977
|
function cloneState(state) {
|
|
@@ -41886,7 +41981,12 @@ function cloneState(state) {
|
|
|
41886
41981
|
flags: new Map(state.flags),
|
|
41887
41982
|
segments: new Map(state.segments),
|
|
41888
41983
|
ready: state.ready,
|
|
41889
|
-
needsFullConfig: state.needsFullConfig
|
|
41984
|
+
needsFullConfig: state.needsFullConfig,
|
|
41985
|
+
piiWire: state.piiWire ? {
|
|
41986
|
+
piiAttributes: [...state.piiWire.piiAttributes],
|
|
41987
|
+
piiSalt: state.piiWire.piiSalt,
|
|
41988
|
+
piiValueEncoding: state.piiWire.piiValueEncoding
|
|
41989
|
+
} : null
|
|
41890
41990
|
};
|
|
41891
41991
|
}
|
|
41892
41992
|
function segmentsFromRecord(record) {
|
|
@@ -41919,7 +42019,8 @@ function hydrateFromFull(action) {
|
|
|
41919
42019
|
flags,
|
|
41920
42020
|
segments: segmentsFromRecord(action.segments),
|
|
41921
42021
|
ready: true,
|
|
41922
|
-
needsFullConfig: false
|
|
42022
|
+
needsFullConfig: false,
|
|
42023
|
+
piiWire: piiWireOptionsFromPayload(action)
|
|
41923
42024
|
};
|
|
41924
42025
|
}
|
|
41925
42026
|
function applyPatch(state, action) {
|
|
@@ -41931,13 +42032,15 @@ function applyPatch(state, action) {
|
|
|
41931
42032
|
if (flag?.key)
|
|
41932
42033
|
flags.set(flag.key, flag);
|
|
41933
42034
|
}
|
|
42035
|
+
const nextPii = resolvePiiWireForDelta(state.piiWire, action);
|
|
41934
42036
|
return {
|
|
41935
42037
|
version: action.toVersion,
|
|
41936
42038
|
expiresAt: typeof action.expiresAt === "number" ? action.expiresAt : state.expiresAt,
|
|
41937
42039
|
flags,
|
|
41938
42040
|
segments: applySegmentUpserts(state.segments, action.segments),
|
|
41939
42041
|
ready: true,
|
|
41940
|
-
needsFullConfig: false
|
|
42042
|
+
needsFullConfig: false,
|
|
42043
|
+
piiWire: nextPii
|
|
41941
42044
|
};
|
|
41942
42045
|
}
|
|
41943
42046
|
function reduceRules(state, action, now = Date.now()) {
|
|
@@ -42114,11 +42217,17 @@ class RulesStore {
|
|
|
42114
42217
|
this.state.segments.forEach((segment, id) => {
|
|
42115
42218
|
segments[id] = segment;
|
|
42116
42219
|
});
|
|
42220
|
+
const pii = this.state.piiWire;
|
|
42117
42221
|
return {
|
|
42118
42222
|
version: this.state.version,
|
|
42119
42223
|
expiresAt: this.state.expiresAt,
|
|
42120
42224
|
flags: Array.from(this.state.flags.values()),
|
|
42121
|
-
segments
|
|
42225
|
+
segments,
|
|
42226
|
+
...pii ? {
|
|
42227
|
+
piiAttributes: [...pii.piiAttributes],
|
|
42228
|
+
piiSalt: pii.piiSalt,
|
|
42229
|
+
piiValueEncoding: pii.piiValueEncoding
|
|
42230
|
+
} : {}
|
|
42122
42231
|
};
|
|
42123
42232
|
}
|
|
42124
42233
|
hydrateFromSnapshot(snapshot, now = Date.now()) {
|
|
@@ -42134,7 +42243,8 @@ class RulesStore {
|
|
|
42134
42243
|
flags,
|
|
42135
42244
|
segments: segmentsFromRecord(snapshot.segments),
|
|
42136
42245
|
ready: !expired && flags.size > 0,
|
|
42137
|
-
needsFullConfig: expired || flags.size === 0
|
|
42246
|
+
needsFullConfig: expired || flags.size === 0,
|
|
42247
|
+
piiWire: piiWireOptionsFromPayload(snapshot)
|
|
42138
42248
|
};
|
|
42139
42249
|
}
|
|
42140
42250
|
}
|
|
@@ -42336,7 +42446,7 @@ function flattenEvaluationContext(context) {
|
|
|
42336
42446
|
function toComparableString(value) {
|
|
42337
42447
|
if (value === null || value === void 0)
|
|
42338
42448
|
return "";
|
|
42339
|
-
return String(value);
|
|
42449
|
+
return String(value).trim().toLowerCase();
|
|
42340
42450
|
}
|
|
42341
42451
|
function toComparableArray(value) {
|
|
42342
42452
|
if (Array.isArray(value)) {
|
|
@@ -42898,8 +43008,13 @@ function prepareContextForEvaluator(context) {
|
|
|
42898
43008
|
}
|
|
42899
43009
|
return context;
|
|
42900
43010
|
}
|
|
42901
|
-
function
|
|
42902
|
-
const
|
|
43011
|
+
function prepareContextForLocalEval(context, pii) {
|
|
43012
|
+
const prepared = prepareContextForEvaluator(context);
|
|
43013
|
+
const flat = flattenEvaluationContext(prepared);
|
|
43014
|
+
return applyPiiHashToFlatContext(flat, pii);
|
|
43015
|
+
}
|
|
43016
|
+
function evaluateSdkFlag(flag, context, segments, pii) {
|
|
43017
|
+
const evalContext = prepareContextForLocalEval(context, pii);
|
|
42903
43018
|
const variationsById = {};
|
|
42904
43019
|
for (const v of flag.variations || []) {
|
|
42905
43020
|
if (v?.id)
|
|
@@ -42959,7 +43074,7 @@ function evaluateSdkFlag(flag, context, segments) {
|
|
|
42959
43074
|
}
|
|
42960
43075
|
function evaluateAllSdkFlags(flags, context, segments, options) {
|
|
42961
43076
|
const list = flags instanceof Map ? Array.from(flags.values()) : flags;
|
|
42962
|
-
const prepared =
|
|
43077
|
+
const prepared = prepareContextForLocalEval(context, options?.pii);
|
|
42963
43078
|
const out = {};
|
|
42964
43079
|
for (const flag of list) {
|
|
42965
43080
|
if (!flag?.key)
|
|
@@ -42968,7 +43083,7 @@ function evaluateAllSdkFlags(flags, context, segments, options) {
|
|
|
42968
43083
|
out[flag.key] = coerceType(flag.default_value, flag.type);
|
|
42969
43084
|
continue;
|
|
42970
43085
|
}
|
|
42971
|
-
out[flag.key] = evaluateSdkFlag(flag, prepared, segments);
|
|
43086
|
+
out[flag.key] = evaluateSdkFlag(flag, prepared, segments, null);
|
|
42972
43087
|
}
|
|
42973
43088
|
return out;
|
|
42974
43089
|
}
|
|
@@ -43413,7 +43528,8 @@ class FlagClient {
|
|
|
43413
43528
|
value = evaluateSdkFlag(
|
|
43414
43529
|
flag,
|
|
43415
43530
|
this.context,
|
|
43416
|
-
this.rulesStore.getState().segments
|
|
43531
|
+
this.rulesStore.getState().segments,
|
|
43532
|
+
this.rulesStore.getState().piiWire
|
|
43417
43533
|
) ?? fallback;
|
|
43418
43534
|
}
|
|
43419
43535
|
} else {
|
|
@@ -43893,7 +44009,7 @@ class FlagClient {
|
|
|
43893
44009
|
state.flags,
|
|
43894
44010
|
context ?? this.context,
|
|
43895
44011
|
state.segments,
|
|
43896
|
-
{ failClosedDefaultsOnly: failClosed }
|
|
44012
|
+
{ failClosedDefaultsOnly: failClosed, pii: state.piiWire }
|
|
43897
44013
|
);
|
|
43898
44014
|
}
|
|
43899
44015
|
analyticsMapFromRulesStore() {
|
|
@@ -44023,6 +44139,7 @@ export {
|
|
|
44023
44139
|
LongPollingTransport,
|
|
44024
44140
|
RulesStore,
|
|
44025
44141
|
SseTransport,
|
|
44142
|
+
applyPiiHashToFlatContext,
|
|
44026
44143
|
applyRolloutStrategy,
|
|
44027
44144
|
cacheHelper_async as asyncCache,
|
|
44028
44145
|
canonicalizeForSigning,
|
|
@@ -44040,11 +44157,13 @@ export {
|
|
|
44040
44157
|
flattenEvaluationContext,
|
|
44041
44158
|
generateAslClientKeyPair,
|
|
44042
44159
|
hashPercent,
|
|
44160
|
+
hashPiiValue,
|
|
44043
44161
|
hashToPercentage,
|
|
44044
44162
|
isConfigPayloadExpired,
|
|
44045
44163
|
isInSegment,
|
|
44046
44164
|
performAslHandshake,
|
|
44047
44165
|
pickVariant,
|
|
44166
|
+
prepareContextForLocalEval,
|
|
44048
44167
|
reduceRules,
|
|
44049
44168
|
signConfigPayload,
|
|
44050
44169
|
stringHash,
|