@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.
@@ -47,16 +47,25 @@ var Packed;
47
47
 
48
48
  // src/evaluate.ts
49
49
  var MAX_REGEX_INPUT_LENGTH = 1e4;
50
- var UINT32_MAX = 4294967295;
51
- var scaledWeightsCache = /* @__PURE__ */ new WeakMap();
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 getScaledWeights(outcome) {
54
- const cached = scaledWeightsCache.get(outcome);
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 scaled = outcome.weights.map((w) => w / total * UINT32_MAX);
58
- scaledWeightsCache.set(outcome, scaled);
59
- return scaled;
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);
@@ -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 >= maxValue) return true;
297
- const value = hashInput(lhs, params.definition.seed) % maxValue;
298
- return value < outcome.passPromille;
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 value = hashInput(lhs, params.definition.seed);
344
- const scaledWeights = getScaledWeights(outcome);
345
- const variantIndex = findWeightedIndex(scaledWeights, value, UINT32_MAX);
346
- const variant = variantIndex === -1 ? defaultOutcome : getVariant(params.definition, variantIndex);
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
- ...variant,
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 = 1e5;
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 >= 1e5) {
409
+ if (currentPromille >= PROMILLE_SCALE) {
396
410
  return {
397
411
  ...rollToVariant,
398
412
  outcomeType: "rollout" /* ROLLOUT */
399
413
  };
400
414
  }
401
- const value = hashInput(lhs, params.definition.seed);
402
- const threshold = currentPromille / 1e5 * UINT32_MAX;
403
- const variant = value < threshold ? rollToVariant : rollFromVariant;
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
- ...variant,
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.6.0";
511
+ var version = "1.7.0";
498
512
 
499
513
  // src/lib/report-value.ts
500
514
  function internalReportValue(key, value, data) {
@@ -2480,4 +2494,4 @@ export {
2480
2494
  resetDefaultFlagsClient,
2481
2495
  createClient
2482
2496
  };
2483
- //# sourceMappingURL=chunk-FBTDSIHP.js.map
2497
+ //# sourceMappingURL=chunk-7J22AK5Q.js.map