flagmint-js-sdk 2.2.2 → 2.2.3-rc.1
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 +125 -25
- package/dist/flagmint.cjs.js.map +1 -1
- package/dist/flagmint.es.js +125 -25
- package/dist/flagmint.es.js.map +1 -1
- package/dist/flagmint.umd.js +125 -25
- package/dist/flagmint.umd.js.map +1 -1
- package/dist/sdk/core/config-sync/index.d.ts +1 -1
- package/dist/sdk/core/config-sync/piiHash.d.ts +46 -0
- package/dist/sdk/core/config-sync/rulesStore.d.ts +7 -1
- package/dist/sdk/core/config-sync/types.d.ts +5 -0
- package/dist/sdk/core/helpers/cacheHelper.d.ts +7 -0
- package/package.json +1 -1
package/dist/flagmint.es.js
CHANGED
|
@@ -38590,12 +38590,27 @@ function parseRulesSnapshot$1(raw) {
|
|
|
38590
38590
|
if (!parsed || typeof parsed.version !== "number" || typeof parsed.expiresAt !== "number" || !Array.isArray(parsed.flags) || typeof parsed.segments !== "object" || parsed.segments === null) {
|
|
38591
38591
|
return null;
|
|
38592
38592
|
}
|
|
38593
|
-
|
|
38593
|
+
const snapshot = {
|
|
38594
38594
|
version: parsed.version,
|
|
38595
38595
|
expiresAt: parsed.expiresAt,
|
|
38596
38596
|
flags: parsed.flags,
|
|
38597
38597
|
segments: parsed.segments || {}
|
|
38598
38598
|
};
|
|
38599
|
+
if (Array.isArray(parsed.piiAttributes)) {
|
|
38600
|
+
snapshot.piiAttributes = parsed.piiAttributes.filter(
|
|
38601
|
+
(attr) => typeof attr === "string"
|
|
38602
|
+
);
|
|
38603
|
+
}
|
|
38604
|
+
if (typeof parsed.piiSalt === "string") {
|
|
38605
|
+
snapshot.piiSalt = parsed.piiSalt;
|
|
38606
|
+
}
|
|
38607
|
+
if (typeof parsed.piiValueEncoding === "string") {
|
|
38608
|
+
snapshot.piiValueEncoding = parsed.piiValueEncoding;
|
|
38609
|
+
}
|
|
38610
|
+
if (parsed.piiWireBroken === true) {
|
|
38611
|
+
snapshot.piiWireBroken = true;
|
|
38612
|
+
}
|
|
38613
|
+
return snapshot;
|
|
38599
38614
|
} catch {
|
|
38600
38615
|
return null;
|
|
38601
38616
|
}
|
|
@@ -38619,6 +38634,12 @@ function saveCachedFlags$1(apiKey, data) {
|
|
|
38619
38634
|
} catch {
|
|
38620
38635
|
}
|
|
38621
38636
|
}
|
|
38637
|
+
function clearCachedFlags(apiKey) {
|
|
38638
|
+
try {
|
|
38639
|
+
storage$1.removeItem?.(getFlagsKey$1(apiKey));
|
|
38640
|
+
} catch {
|
|
38641
|
+
}
|
|
38642
|
+
}
|
|
38622
38643
|
function loadCachedContext$1(apiKey) {
|
|
38623
38644
|
try {
|
|
38624
38645
|
const raw = storage$1.getItem(getContextKey$1(apiKey));
|
|
@@ -38657,6 +38678,7 @@ function clearCachedRulesSnapshot$1(apiKey) {
|
|
|
38657
38678
|
}
|
|
38658
38679
|
const cacheHelper = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
38659
38680
|
__proto__: null,
|
|
38681
|
+
clearCachedFlags,
|
|
38660
38682
|
clearCachedRulesSnapshot: clearCachedRulesSnapshot$1,
|
|
38661
38683
|
loadCachedContext: loadCachedContext$1,
|
|
38662
38684
|
loadCachedFlags: loadCachedFlags$1,
|
|
@@ -39091,7 +39113,7 @@ class SseTransport {
|
|
|
39091
39113
|
this.connectPromise = new Promise((resolve, reject) => {
|
|
39092
39114
|
this.connectResolve = resolve;
|
|
39093
39115
|
this.connectReject = reject;
|
|
39094
|
-
const sdkVersion = "2.2.
|
|
39116
|
+
const sdkVersion = "2.2.3-rc.1";
|
|
39095
39117
|
const platform2 = typeof window !== "undefined" ? "browser" : "nodejs";
|
|
39096
39118
|
const wrapperName = this.configOptions?.wrapper?.name || "native-js";
|
|
39097
39119
|
const wrapperVersion = this.configOptions?.wrapper?.version || "none";
|
|
@@ -41903,22 +41925,80 @@ function payloadHasExplicitPiiFields(payload) {
|
|
|
41903
41925
|
return false;
|
|
41904
41926
|
return payload.piiSalt !== void 0 || payload.piiAttributes !== void 0 || payload.piiValueEncoding !== void 0;
|
|
41905
41927
|
}
|
|
41928
|
+
function piiAttributeKeysFromPayload(payload) {
|
|
41929
|
+
if (!payload || !Array.isArray(payload.piiAttributes))
|
|
41930
|
+
return [];
|
|
41931
|
+
return payload.piiAttributes.filter((k) => typeof k === "string" && k.length > 0);
|
|
41932
|
+
}
|
|
41933
|
+
function hasMalformedPiiAttributes(payload) {
|
|
41934
|
+
if (!payload || payload.piiAttributes === void 0)
|
|
41935
|
+
return false;
|
|
41936
|
+
if (!Array.isArray(payload.piiAttributes))
|
|
41937
|
+
return true;
|
|
41938
|
+
return payload.piiAttributes.some(
|
|
41939
|
+
(entry) => typeof entry !== "string" || entry.length === 0
|
|
41940
|
+
);
|
|
41941
|
+
}
|
|
41942
|
+
function hasExplicitInvalidPiiEncoding(payload) {
|
|
41943
|
+
if (!payload || payload.piiValueEncoding === void 0)
|
|
41944
|
+
return false;
|
|
41945
|
+
return payload.piiValueEncoding !== PII_VALUE_ENCODING;
|
|
41946
|
+
}
|
|
41947
|
+
function payloadRequiresUsablePiiWire(payload) {
|
|
41948
|
+
if (!payload)
|
|
41949
|
+
return false;
|
|
41950
|
+
if (hasExplicitInvalidPiiEncoding(payload))
|
|
41951
|
+
return true;
|
|
41952
|
+
if (hasMalformedPiiAttributes(payload))
|
|
41953
|
+
return true;
|
|
41954
|
+
if (piiAttributeKeysFromPayload(payload).length > 0)
|
|
41955
|
+
return true;
|
|
41956
|
+
return false;
|
|
41957
|
+
}
|
|
41958
|
+
function isExplicitPiiRequirementCleared(payload) {
|
|
41959
|
+
if (!payload || payload.piiAttributes === void 0)
|
|
41960
|
+
return false;
|
|
41961
|
+
if (!Array.isArray(payload.piiAttributes))
|
|
41962
|
+
return false;
|
|
41963
|
+
if (payload.piiAttributes.length !== 0)
|
|
41964
|
+
return false;
|
|
41965
|
+
if (hasExplicitInvalidPiiEncoding(payload))
|
|
41966
|
+
return false;
|
|
41967
|
+
return true;
|
|
41968
|
+
}
|
|
41906
41969
|
function piiWireOptionsFromPayload(payload) {
|
|
41907
41970
|
if (!payload)
|
|
41908
41971
|
return null;
|
|
41972
|
+
if (hasExplicitInvalidPiiEncoding(payload))
|
|
41973
|
+
return null;
|
|
41974
|
+
if (hasMalformedPiiAttributes(payload))
|
|
41975
|
+
return null;
|
|
41909
41976
|
const salt = typeof payload.piiSalt === "string" ? payload.piiSalt : "";
|
|
41910
41977
|
if (!salt)
|
|
41911
41978
|
return null;
|
|
41912
|
-
const
|
|
41913
|
-
if (encoding !== PII_VALUE_ENCODING)
|
|
41914
|
-
return null;
|
|
41915
|
-
const attrs = Array.isArray(payload.piiAttributes) ? payload.piiAttributes.filter((k) => typeof k === "string") : [];
|
|
41979
|
+
const attrs = piiAttributeKeysFromPayload(payload);
|
|
41916
41980
|
return {
|
|
41917
41981
|
piiAttributes: attrs,
|
|
41918
41982
|
piiSalt: salt,
|
|
41919
41983
|
piiValueEncoding: PII_VALUE_ENCODING
|
|
41920
41984
|
};
|
|
41921
41985
|
}
|
|
41986
|
+
function isPiiWireBroken(payload, resolved, previousPriorHadPiiAttrs = false) {
|
|
41987
|
+
if (hasExplicitInvalidPiiEncoding(payload) || hasMalformedPiiAttributes(payload)) {
|
|
41988
|
+
return true;
|
|
41989
|
+
}
|
|
41990
|
+
if (resolved) {
|
|
41991
|
+
return false;
|
|
41992
|
+
}
|
|
41993
|
+
if (isExplicitPiiRequirementCleared(payload))
|
|
41994
|
+
return false;
|
|
41995
|
+
if (payloadRequiresUsablePiiWire(payload))
|
|
41996
|
+
return true;
|
|
41997
|
+
if (previousPriorHadPiiAttrs && payloadHasExplicitPiiFields(payload)) {
|
|
41998
|
+
return true;
|
|
41999
|
+
}
|
|
42000
|
+
return false;
|
|
42001
|
+
}
|
|
41922
42002
|
function resolvePiiWireForDelta(previous, action) {
|
|
41923
42003
|
if (!payloadHasExplicitPiiFields(action)) {
|
|
41924
42004
|
return previous;
|
|
@@ -41971,7 +42051,8 @@ function createEmptyRulesState() {
|
|
|
41971
42051
|
segments: /* @__PURE__ */ new Map(),
|
|
41972
42052
|
ready: false,
|
|
41973
42053
|
needsFullConfig: true,
|
|
41974
|
-
piiWire: null
|
|
42054
|
+
piiWire: null,
|
|
42055
|
+
piiWireBroken: false
|
|
41975
42056
|
};
|
|
41976
42057
|
}
|
|
41977
42058
|
function cloneState(state) {
|
|
@@ -41986,7 +42067,8 @@ function cloneState(state) {
|
|
|
41986
42067
|
piiAttributes: [...state.piiWire.piiAttributes],
|
|
41987
42068
|
piiSalt: state.piiWire.piiSalt,
|
|
41988
42069
|
piiValueEncoding: state.piiWire.piiValueEncoding
|
|
41989
|
-
} : null
|
|
42070
|
+
} : null,
|
|
42071
|
+
piiWireBroken: state.piiWireBroken
|
|
41990
42072
|
};
|
|
41991
42073
|
}
|
|
41992
42074
|
function segmentsFromRecord(record) {
|
|
@@ -42013,14 +42095,18 @@ function hydrateFromFull(action) {
|
|
|
42013
42095
|
if (flag?.key)
|
|
42014
42096
|
flags.set(flag.key, flag);
|
|
42015
42097
|
}
|
|
42098
|
+
const piiWire = piiWireOptionsFromPayload(action);
|
|
42099
|
+
const piiWireBroken = isPiiWireBroken(action, piiWire, false);
|
|
42016
42100
|
return {
|
|
42017
42101
|
version: action.version,
|
|
42018
42102
|
expiresAt: action.expiresAt,
|
|
42019
42103
|
flags,
|
|
42020
42104
|
segments: segmentsFromRecord(action.segments),
|
|
42021
|
-
|
|
42022
|
-
|
|
42023
|
-
|
|
42105
|
+
// Usable rules, but PII metadata must be valid when hashing is required.
|
|
42106
|
+
ready: !piiWireBroken,
|
|
42107
|
+
needsFullConfig: piiWireBroken,
|
|
42108
|
+
piiWire,
|
|
42109
|
+
piiWireBroken
|
|
42024
42110
|
};
|
|
42025
42111
|
}
|
|
42026
42112
|
function applyPatch(state, action) {
|
|
@@ -42033,14 +42119,19 @@ function applyPatch(state, action) {
|
|
|
42033
42119
|
flags.set(flag.key, flag);
|
|
42034
42120
|
}
|
|
42035
42121
|
const nextPii = resolvePiiWireForDelta(state.piiWire, action);
|
|
42122
|
+
const priorHadPiiAttrs = (state.piiWire?.piiAttributes.length ?? 0) > 0 || state.piiWireBroken;
|
|
42123
|
+
const computedBroken = isPiiWireBroken(action, nextPii, priorHadPiiAttrs);
|
|
42124
|
+
const recoveredWithRequiredAttrs = !!nextPii && nextPii.piiAttributes.length > 0;
|
|
42125
|
+
const piiWireBroken = isExplicitPiiRequirementCleared(action) ? false : recoveredWithRequiredAttrs ? false : computedBroken || state.piiWireBroken;
|
|
42036
42126
|
return {
|
|
42037
42127
|
version: action.toVersion,
|
|
42038
42128
|
expiresAt: typeof action.expiresAt === "number" ? action.expiresAt : state.expiresAt,
|
|
42039
42129
|
flags,
|
|
42040
42130
|
segments: applySegmentUpserts(state.segments, action.segments),
|
|
42041
|
-
ready:
|
|
42042
|
-
needsFullConfig:
|
|
42043
|
-
piiWire: nextPii
|
|
42131
|
+
ready: !piiWireBroken,
|
|
42132
|
+
needsFullConfig: piiWireBroken,
|
|
42133
|
+
piiWire: nextPii,
|
|
42134
|
+
piiWireBroken
|
|
42044
42135
|
};
|
|
42045
42136
|
}
|
|
42046
42137
|
function reduceRules(state, action, now = Date.now()) {
|
|
@@ -42060,8 +42151,8 @@ function reduceRules(state, action, now = Date.now()) {
|
|
|
42060
42151
|
...cloneState(state),
|
|
42061
42152
|
version: state.version,
|
|
42062
42153
|
expiresAt: action.expiresAt,
|
|
42063
|
-
ready:
|
|
42064
|
-
needsFullConfig: state.flags.size === 0 || versionMismatch ? true : state.needsFullConfig
|
|
42154
|
+
ready: !state.piiWireBroken,
|
|
42155
|
+
needsFullConfig: state.piiWireBroken || state.flags.size === 0 || versionMismatch ? true : state.needsFullConfig
|
|
42065
42156
|
}
|
|
42066
42157
|
};
|
|
42067
42158
|
}
|
|
@@ -42117,8 +42208,8 @@ function reduceRules(state, action, now = Date.now()) {
|
|
|
42117
42208
|
...current,
|
|
42118
42209
|
version: action.toVersion,
|
|
42119
42210
|
expiresAt: typeof action.expiresAt === "number" ? action.expiresAt : current.expiresAt,
|
|
42120
|
-
ready:
|
|
42121
|
-
needsFullConfig:
|
|
42211
|
+
ready: !current.piiWireBroken,
|
|
42212
|
+
needsFullConfig: current.piiWireBroken
|
|
42122
42213
|
}
|
|
42123
42214
|
};
|
|
42124
42215
|
}
|
|
@@ -42141,9 +42232,12 @@ class RulesStore {
|
|
|
42141
42232
|
return this.state;
|
|
42142
42233
|
}
|
|
42143
42234
|
/**
|
|
42144
|
-
* Fail-closed readiness: lease not expired
|
|
42235
|
+
* Fail-closed readiness: lease not expired, store marked ready, and PII
|
|
42236
|
+
* wire metadata usable when hashing is required.
|
|
42145
42237
|
*/
|
|
42146
42238
|
isReady(now = Date.now()) {
|
|
42239
|
+
if (this.state.piiWireBroken)
|
|
42240
|
+
return false;
|
|
42147
42241
|
if (!this.state.ready)
|
|
42148
42242
|
return false;
|
|
42149
42243
|
if (!this.state.expiresAt)
|
|
@@ -42227,7 +42321,9 @@ class RulesStore {
|
|
|
42227
42321
|
piiAttributes: [...pii.piiAttributes],
|
|
42228
42322
|
piiSalt: pii.piiSalt,
|
|
42229
42323
|
piiValueEncoding: pii.piiValueEncoding
|
|
42230
|
-
} : {}
|
|
42324
|
+
} : {},
|
|
42325
|
+
// Persist fail-closed even when piiWire is null (unusable salt/encoding).
|
|
42326
|
+
...this.state.piiWireBroken ? { piiWireBroken: true } : {}
|
|
42231
42327
|
};
|
|
42232
42328
|
}
|
|
42233
42329
|
hydrateFromSnapshot(snapshot, now = Date.now()) {
|
|
@@ -42237,14 +42333,17 @@ class RulesStore {
|
|
|
42237
42333
|
flags.set(flag.key, flag);
|
|
42238
42334
|
}
|
|
42239
42335
|
const expired = isConfigPayloadExpired(snapshot.expiresAt, now);
|
|
42336
|
+
const piiWire = piiWireOptionsFromPayload(snapshot);
|
|
42337
|
+
const piiWireBroken = snapshot.piiWireBroken === true || isPiiWireBroken(snapshot, piiWire, false);
|
|
42240
42338
|
this.state = {
|
|
42241
42339
|
version: snapshot.version,
|
|
42242
42340
|
expiresAt: snapshot.expiresAt,
|
|
42243
42341
|
flags,
|
|
42244
42342
|
segments: segmentsFromRecord(snapshot.segments),
|
|
42245
|
-
ready: !expired && flags.size > 0,
|
|
42246
|
-
needsFullConfig: expired || flags.size === 0,
|
|
42247
|
-
piiWire
|
|
42343
|
+
ready: !expired && flags.size > 0 && !piiWireBroken,
|
|
42344
|
+
needsFullConfig: expired || flags.size === 0 || piiWireBroken,
|
|
42345
|
+
piiWire,
|
|
42346
|
+
piiWireBroken
|
|
42248
42347
|
};
|
|
42249
42348
|
}
|
|
42250
42349
|
}
|
|
@@ -43215,9 +43314,10 @@ class FlagClient {
|
|
|
43215
43314
|
}
|
|
43216
43315
|
let hydratedRules = false;
|
|
43217
43316
|
if (this.configSync && this.rulesStore && this.enableOfflineCache) {
|
|
43317
|
+
clearCachedFlags(this.apiKey);
|
|
43218
43318
|
hydratedRules = await this.hydrateRulesFromCache();
|
|
43219
43319
|
}
|
|
43220
|
-
if (this.enableOfflineCache && !hydratedRules) {
|
|
43320
|
+
if (this.enableOfflineCache && !this.configSync && !hydratedRules) {
|
|
43221
43321
|
const cached = await Promise.resolve(
|
|
43222
43322
|
this.cacheAdapter.loadFlags(this.apiKey, this.cacheTTL)
|
|
43223
43323
|
);
|
|
@@ -43459,7 +43559,7 @@ class FlagClient {
|
|
|
43459
43559
|
*/
|
|
43460
43560
|
updateFlags(newFlags, fromShare = false) {
|
|
43461
43561
|
this.flags = newFlags;
|
|
43462
|
-
if (this.enableOfflineCache) {
|
|
43562
|
+
if (this.enableOfflineCache && !this.configSync) {
|
|
43463
43563
|
void Promise.resolve(
|
|
43464
43564
|
this.cacheAdapter.saveFlags(this.apiKey, newFlags)
|
|
43465
43565
|
);
|