@vercel/flags-core 1.6.0 → 1.7.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.
- package/CHANGELOG.md +10 -0
- package/dist/{chunk-L653ZWQA.js → chunk-3QHXSGEW.js} +47 -33
- package/dist/chunk-3QHXSGEW.js.map +1 -0
- package/dist/{chunk-FBTDSIHP.js → chunk-7J22AK5Q.js} +47 -33
- package/dist/chunk-7J22AK5Q.js.map +1 -0
- package/dist/{chunk-HTK4XPSW.cjs → chunk-DQD4QVK6.cjs} +47 -33
- package/dist/chunk-DQD4QVK6.cjs.map +1 -0
- package/dist/{chunk-VT24U6D2.cjs → chunk-SMFV3VH7.cjs} +47 -33
- package/dist/chunk-SMFV3VH7.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 +1 -1
- 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,15 @@
|
|
|
1
1
|
# @vercel/flags-core
|
|
2
2
|
|
|
3
|
+
## 1.7.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#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.
|
|
8
|
+
|
|
9
|
+
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.
|
|
10
|
+
|
|
11
|
+
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.
|
|
12
|
+
|
|
3
13
|
## 1.6.0
|
|
4
14
|
|
|
5
15
|
### Minor Changes
|
|
@@ -32,16 +32,25 @@ var Packed;
|
|
|
32
32
|
|
|
33
33
|
// src/evaluate.ts
|
|
34
34
|
var MAX_REGEX_INPUT_LENGTH = 1e4;
|
|
35
|
-
var
|
|
36
|
-
var
|
|
35
|
+
var HASH_SPACE = 2 ** 32;
|
|
36
|
+
var PROMILLE_SCALE = 1e5;
|
|
37
|
+
function boundaryFor(numerator, denominator) {
|
|
38
|
+
return Math.floor(numerator / denominator * HASH_SPACE);
|
|
39
|
+
}
|
|
40
|
+
var splitBoundariesCache = /* @__PURE__ */ new WeakMap();
|
|
37
41
|
var compiledRegexCache = /* @__PURE__ */ new WeakMap();
|
|
38
|
-
function
|
|
39
|
-
const cached =
|
|
42
|
+
function getSplitBoundaries(outcome) {
|
|
43
|
+
const cached = splitBoundariesCache.get(outcome);
|
|
40
44
|
if (cached) return cached;
|
|
41
45
|
const total = sum(outcome.weights);
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
|
|
46
|
+
const boundaries = [];
|
|
47
|
+
let cumulative = 0;
|
|
48
|
+
for (const weight of outcome.weights) {
|
|
49
|
+
cumulative += weight;
|
|
50
|
+
boundaries.push(boundaryFor(cumulative, total));
|
|
51
|
+
}
|
|
52
|
+
splitBoundariesCache.set(outcome, boundaries);
|
|
53
|
+
return boundaries;
|
|
45
54
|
}
|
|
46
55
|
function getCompiledRegex(rhs) {
|
|
47
56
|
const cached = compiledRegexCache.get(rhs);
|
|
@@ -276,11 +285,10 @@ function handleSegmentOutcome(params, outcome) {
|
|
|
276
285
|
case "split": {
|
|
277
286
|
const lhs = access(outcome.base, params);
|
|
278
287
|
if (typeof lhs !== "string") return false;
|
|
279
|
-
const maxValue = 1e5;
|
|
280
288
|
if (outcome.passPromille <= 0) return false;
|
|
281
|
-
if (outcome.passPromille >=
|
|
282
|
-
const
|
|
283
|
-
return
|
|
289
|
+
if (outcome.passPromille >= PROMILLE_SCALE) return true;
|
|
290
|
+
const bucket = hashInput(lhs, params.definition.seed);
|
|
291
|
+
return bucket < boundaryFor(outcome.passPromille, PROMILLE_SCALE);
|
|
284
292
|
}
|
|
285
293
|
default: {
|
|
286
294
|
const { type } = outcome;
|
|
@@ -325,12 +333,18 @@ function handleOutcome(params, outcome) {
|
|
|
325
333
|
outcomeType: "split" /* SPLIT */
|
|
326
334
|
};
|
|
327
335
|
}
|
|
328
|
-
const
|
|
329
|
-
const
|
|
330
|
-
|
|
331
|
-
|
|
336
|
+
const bucket = hashInput(lhs, params.definition.seed);
|
|
337
|
+
const boundaries = getSplitBoundaries(outcome);
|
|
338
|
+
for (let index = 0; index < boundaries.length; index++) {
|
|
339
|
+
if (bucket < boundaries[index]) {
|
|
340
|
+
return {
|
|
341
|
+
...getVariant(params.definition, index),
|
|
342
|
+
outcomeType: "split" /* SPLIT */
|
|
343
|
+
};
|
|
344
|
+
}
|
|
345
|
+
}
|
|
332
346
|
return {
|
|
333
|
-
...
|
|
347
|
+
...defaultOutcome,
|
|
334
348
|
outcomeType: "split" /* SPLIT */
|
|
335
349
|
};
|
|
336
350
|
}
|
|
@@ -366,7 +380,7 @@ function handleOutcome(params, outcome) {
|
|
|
366
380
|
break;
|
|
367
381
|
}
|
|
368
382
|
}
|
|
369
|
-
if (exhausted) currentPromille =
|
|
383
|
+
if (exhausted) currentPromille = PROMILLE_SCALE;
|
|
370
384
|
if (currentPromille <= 0) {
|
|
371
385
|
return {
|
|
372
386
|
...rollFromVariant,
|
|
@@ -377,17 +391,26 @@ function handleOutcome(params, outcome) {
|
|
|
377
391
|
params.definition,
|
|
378
392
|
outcome.rollToVariant
|
|
379
393
|
);
|
|
380
|
-
if (currentPromille >=
|
|
394
|
+
if (currentPromille >= PROMILLE_SCALE) {
|
|
381
395
|
return {
|
|
382
396
|
...rollToVariant,
|
|
383
397
|
outcomeType: "rollout" /* ROLLOUT */
|
|
384
398
|
};
|
|
385
399
|
}
|
|
386
|
-
const
|
|
387
|
-
|
|
388
|
-
|
|
400
|
+
const bucket = hashInput(lhs, params.definition.seed);
|
|
401
|
+
if (outcome.rollToVariant < outcome.rollFromVariant) {
|
|
402
|
+
const rollToBoundary = boundaryFor(currentPromille, PROMILLE_SCALE);
|
|
403
|
+
return {
|
|
404
|
+
...bucket < rollToBoundary ? rollToVariant : rollFromVariant,
|
|
405
|
+
outcomeType: "rollout" /* ROLLOUT */
|
|
406
|
+
};
|
|
407
|
+
}
|
|
408
|
+
const rollFromBoundary = boundaryFor(
|
|
409
|
+
PROMILLE_SCALE - currentPromille,
|
|
410
|
+
PROMILLE_SCALE
|
|
411
|
+
);
|
|
389
412
|
return {
|
|
390
|
-
...
|
|
413
|
+
...bucket < rollFromBoundary ? rollFromVariant : rollToVariant,
|
|
391
414
|
outcomeType: "rollout" /* ROLLOUT */
|
|
392
415
|
};
|
|
393
416
|
}
|
|
@@ -468,18 +491,9 @@ function bulkEvaluate(flags, shared) {
|
|
|
468
491
|
}
|
|
469
492
|
return results;
|
|
470
493
|
}
|
|
471
|
-
function findWeightedIndex(weights, value, maxValue) {
|
|
472
|
-
if (value < 0 || value >= maxValue) return -1;
|
|
473
|
-
let sum2 = 0;
|
|
474
|
-
for (let i = 0; i < weights.length; i++) {
|
|
475
|
-
sum2 += weights[i];
|
|
476
|
-
if (value < sum2) return i;
|
|
477
|
-
}
|
|
478
|
-
return -1;
|
|
479
|
-
}
|
|
480
494
|
|
|
481
495
|
// package.json
|
|
482
|
-
var version = "1.
|
|
496
|
+
var version = "1.7.0";
|
|
483
497
|
|
|
484
498
|
// src/lib/report-value.ts
|
|
485
499
|
function internalReportValue(key, value, data) {
|
|
@@ -2490,4 +2504,4 @@ export {
|
|
|
2490
2504
|
resetDefaultFlagsClient,
|
|
2491
2505
|
createClient
|
|
2492
2506
|
};
|
|
2493
|
-
//# sourceMappingURL=chunk-
|
|
2507
|
+
//# sourceMappingURL=chunk-3QHXSGEW.js.map
|