@vercel/flags-core 1.6.0 → 1.7.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/CHANGELOG.md +16 -0
- package/dist/{chunk-FBTDSIHP.js → chunk-PLRBLION.js} +50 -34
- package/dist/chunk-PLRBLION.js.map +1 -0
- package/dist/{chunk-L653ZWQA.js → chunk-RH2MIZYW.js} +50 -34
- package/dist/chunk-RH2MIZYW.js.map +1 -0
- package/dist/{chunk-HTK4XPSW.cjs → chunk-Y7HU5ZNT.cjs} +50 -34
- package/dist/chunk-Y7HU5ZNT.cjs.map +1 -0
- package/dist/{chunk-VT24U6D2.cjs → chunk-Z7PTTGMK.cjs} +50 -34
- package/dist/chunk-Z7PTTGMK.cjs.map +1 -0
- package/dist/index.default.cjs +2 -2
- package/dist/index.default.js +1 -1
- package/dist/index.next-js.cjs +2 -2
- package/dist/index.next-js.js +1 -1
- package/dist/openfeature.default.cjs +2 -2
- package/dist/openfeature.default.js +1 -1
- package/dist/openfeature.next-js.cjs +2 -2
- package/dist/openfeature.next-js.js +1 -1
- package/package.json +5 -5
- package/dist/chunk-FBTDSIHP.js.map +0 -1
- package/dist/chunk-HTK4XPSW.cjs.map +0 -1
- package/dist/chunk-L653ZWQA.js.map +0 -1
- package/dist/chunk-VT24U6D2.cjs.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# @vercel/flags-core
|
|
2
2
|
|
|
3
|
+
## 1.7.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#450](https://github.com/vercel/flags/pull/450) [`ceb1519`](https://github.com/vercel/flags/commit/ceb15198f73a973ac559648b8d978c23d23ef0c5) Thanks [@dferber90](https://github.com/dferber90)! - Strip the `g` and `y` flags from RegEx conditions to prevent cached `RegExp` instances from retaining `lastIndex` state.
|
|
8
|
+
|
|
9
|
+
## 1.7.0
|
|
10
|
+
|
|
11
|
+
### Minor Changes
|
|
12
|
+
|
|
13
|
+
- [#427](https://github.com/vercel/flags/pull/427) [`50b1aa4`](https://github.com/vercel/flags/commit/50b1aa4f9614b8e78f76cc9e3ae539e58a46fa7e) Thanks [@dferber90](https://github.com/dferber90)! - Align rollout, split, and segment split user assignment onto a single hash bucketing scheme.
|
|
14
|
+
|
|
15
|
+
Previously splits and rollouts bucketed users with opposite conventions, so switching a flag between a split and a rollout (or locking in a rollout as a split) could reassign users even when the effective distribution was unchanged. All three now derive their cut points from one shared boundary function over the full hash space, so a rollout at a given percentage is identical to the equivalent split.
|
|
16
|
+
|
|
17
|
+
Split assignments are effectively unchanged. Rollouts and segment splits are re-bucketed once with this release; after that, converting a flag between outcome types never reassigns anyone.
|
|
18
|
+
|
|
3
19
|
## 1.6.0
|
|
4
20
|
|
|
5
21
|
### Minor Changes
|
|
@@ -47,21 +47,30 @@ var Packed;
|
|
|
47
47
|
|
|
48
48
|
// src/evaluate.ts
|
|
49
49
|
var MAX_REGEX_INPUT_LENGTH = 1e4;
|
|
50
|
-
var
|
|
51
|
-
var
|
|
50
|
+
var HASH_SPACE = 2 ** 32;
|
|
51
|
+
var PROMILLE_SCALE = 1e5;
|
|
52
|
+
function boundaryFor(numerator, denominator) {
|
|
53
|
+
return Math.floor(numerator / denominator * HASH_SPACE);
|
|
54
|
+
}
|
|
55
|
+
var splitBoundariesCache = /* @__PURE__ */ new WeakMap();
|
|
52
56
|
var compiledRegexCache = /* @__PURE__ */ new WeakMap();
|
|
53
|
-
function
|
|
54
|
-
const cached =
|
|
57
|
+
function getSplitBoundaries(outcome) {
|
|
58
|
+
const cached = splitBoundariesCache.get(outcome);
|
|
55
59
|
if (cached) return cached;
|
|
56
60
|
const total = sum(outcome.weights);
|
|
57
|
-
const
|
|
58
|
-
|
|
59
|
-
|
|
61
|
+
const boundaries = [];
|
|
62
|
+
let cumulative = 0;
|
|
63
|
+
for (const weight of outcome.weights) {
|
|
64
|
+
cumulative += weight;
|
|
65
|
+
boundaries.push(boundaryFor(cumulative, total));
|
|
66
|
+
}
|
|
67
|
+
splitBoundariesCache.set(outcome, boundaries);
|
|
68
|
+
return boundaries;
|
|
60
69
|
}
|
|
61
70
|
function getCompiledRegex(rhs) {
|
|
62
71
|
const cached = compiledRegexCache.get(rhs);
|
|
63
72
|
if (cached) return cached;
|
|
64
|
-
const compiled = new RegExp(rhs.pattern, rhs.flags);
|
|
73
|
+
const compiled = new RegExp(rhs.pattern, rhs.flags.replace(/[gy]/, ""));
|
|
65
74
|
compiledRegexCache.set(rhs, compiled);
|
|
66
75
|
return compiled;
|
|
67
76
|
}
|
|
@@ -291,11 +300,10 @@ function handleSegmentOutcome(params, outcome) {
|
|
|
291
300
|
case "split": {
|
|
292
301
|
const lhs = access(outcome.base, params);
|
|
293
302
|
if (typeof lhs !== "string") return false;
|
|
294
|
-
const maxValue = 1e5;
|
|
295
303
|
if (outcome.passPromille <= 0) return false;
|
|
296
|
-
if (outcome.passPromille >=
|
|
297
|
-
const
|
|
298
|
-
return
|
|
304
|
+
if (outcome.passPromille >= PROMILLE_SCALE) return true;
|
|
305
|
+
const bucket = hashInput(lhs, params.definition.seed);
|
|
306
|
+
return bucket < boundaryFor(outcome.passPromille, PROMILLE_SCALE);
|
|
299
307
|
}
|
|
300
308
|
default: {
|
|
301
309
|
const { type } = outcome;
|
|
@@ -340,12 +348,18 @@ function handleOutcome(params, outcome) {
|
|
|
340
348
|
outcomeType: "split" /* SPLIT */
|
|
341
349
|
};
|
|
342
350
|
}
|
|
343
|
-
const
|
|
344
|
-
const
|
|
345
|
-
|
|
346
|
-
|
|
351
|
+
const bucket = hashInput(lhs, params.definition.seed);
|
|
352
|
+
const boundaries = getSplitBoundaries(outcome);
|
|
353
|
+
for (let index = 0; index < boundaries.length; index++) {
|
|
354
|
+
if (bucket < boundaries[index]) {
|
|
355
|
+
return {
|
|
356
|
+
...getVariant(params.definition, index),
|
|
357
|
+
outcomeType: "split" /* SPLIT */
|
|
358
|
+
};
|
|
359
|
+
}
|
|
360
|
+
}
|
|
347
361
|
return {
|
|
348
|
-
...
|
|
362
|
+
...defaultOutcome,
|
|
349
363
|
outcomeType: "split" /* SPLIT */
|
|
350
364
|
};
|
|
351
365
|
}
|
|
@@ -381,7 +395,7 @@ function handleOutcome(params, outcome) {
|
|
|
381
395
|
break;
|
|
382
396
|
}
|
|
383
397
|
}
|
|
384
|
-
if (exhausted) currentPromille =
|
|
398
|
+
if (exhausted) currentPromille = PROMILLE_SCALE;
|
|
385
399
|
if (currentPromille <= 0) {
|
|
386
400
|
return {
|
|
387
401
|
...rollFromVariant,
|
|
@@ -392,17 +406,26 @@ function handleOutcome(params, outcome) {
|
|
|
392
406
|
params.definition,
|
|
393
407
|
outcome.rollToVariant
|
|
394
408
|
);
|
|
395
|
-
if (currentPromille >=
|
|
409
|
+
if (currentPromille >= PROMILLE_SCALE) {
|
|
396
410
|
return {
|
|
397
411
|
...rollToVariant,
|
|
398
412
|
outcomeType: "rollout" /* ROLLOUT */
|
|
399
413
|
};
|
|
400
414
|
}
|
|
401
|
-
const
|
|
402
|
-
|
|
403
|
-
|
|
415
|
+
const bucket = hashInput(lhs, params.definition.seed);
|
|
416
|
+
if (outcome.rollToVariant < outcome.rollFromVariant) {
|
|
417
|
+
const rollToBoundary = boundaryFor(currentPromille, PROMILLE_SCALE);
|
|
418
|
+
return {
|
|
419
|
+
...bucket < rollToBoundary ? rollToVariant : rollFromVariant,
|
|
420
|
+
outcomeType: "rollout" /* ROLLOUT */
|
|
421
|
+
};
|
|
422
|
+
}
|
|
423
|
+
const rollFromBoundary = boundaryFor(
|
|
424
|
+
PROMILLE_SCALE - currentPromille,
|
|
425
|
+
PROMILLE_SCALE
|
|
426
|
+
);
|
|
404
427
|
return {
|
|
405
|
-
...
|
|
428
|
+
...bucket < rollFromBoundary ? rollFromVariant : rollToVariant,
|
|
406
429
|
outcomeType: "rollout" /* ROLLOUT */
|
|
407
430
|
};
|
|
408
431
|
}
|
|
@@ -483,18 +506,9 @@ function bulkEvaluate(flags, shared) {
|
|
|
483
506
|
}
|
|
484
507
|
return results;
|
|
485
508
|
}
|
|
486
|
-
function findWeightedIndex(weights, value, maxValue) {
|
|
487
|
-
if (value < 0 || value >= maxValue) return -1;
|
|
488
|
-
let sum2 = 0;
|
|
489
|
-
for (let i = 0; i < weights.length; i++) {
|
|
490
|
-
sum2 += weights[i];
|
|
491
|
-
if (value < sum2) return i;
|
|
492
|
-
}
|
|
493
|
-
return -1;
|
|
494
|
-
}
|
|
495
509
|
|
|
496
510
|
// package.json
|
|
497
|
-
var version = "1.
|
|
511
|
+
var version = "1.7.1";
|
|
498
512
|
|
|
499
513
|
// src/lib/report-value.ts
|
|
500
514
|
function internalReportValue(key, value, data) {
|
|
@@ -971,6 +985,7 @@ var Scheduler = class {
|
|
|
971
985
|
constructor(onFlush) {
|
|
972
986
|
this.onFlush = onFlush;
|
|
973
987
|
}
|
|
988
|
+
onFlush;
|
|
974
989
|
resolveWait = null;
|
|
975
990
|
pending = null;
|
|
976
991
|
idleTimeout = null;
|
|
@@ -1222,6 +1237,7 @@ var BundledSource = class {
|
|
|
1222
1237
|
constructor(options) {
|
|
1223
1238
|
this.options = options;
|
|
1224
1239
|
}
|
|
1240
|
+
options;
|
|
1225
1241
|
promise;
|
|
1226
1242
|
/**
|
|
1227
1243
|
* Load bundled definitions.
|
|
@@ -2480,4 +2496,4 @@ export {
|
|
|
2480
2496
|
resetDefaultFlagsClient,
|
|
2481
2497
|
createClient
|
|
2482
2498
|
};
|
|
2483
|
-
//# sourceMappingURL=chunk-
|
|
2499
|
+
//# sourceMappingURL=chunk-PLRBLION.js.map
|