@vercel/flags-core 1.8.0 → 1.9.0-af502ab-20260904110845

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 CHANGED
@@ -1,5 +1,25 @@
1
1
  # @vercel/flags-core
2
2
 
3
+ ## 1.9.0-af502ab-20260904110845
4
+
5
+ ### Minor Changes
6
+
7
+ - [#486](https://github.com/vercel/flags/pull/486) [`8505d17`](https://github.com/vercel/flags/commit/8505d179b6d1e43d3401cd7d6a7b89bf5ae92854) Thanks [@dferber90](https://github.com/dferber90)! - Add APIs for reporting flag exposures and override values.
8
+
9
+ - The `experimental_reportExposures` client option for supplying an exposure
10
+ reporter.
11
+ - The `experimental_reportOverride` client method for reporting values set by
12
+ the Flags SDK override cookie.
13
+ - The `experimental_exposureLogging` option on `evaluate()` and
14
+ `bulkEvaluate()` for disabling exposure reporting for an individual call.
15
+ - Experiment assignment metadata on `EvaluationResult.experiment`.
16
+ - The `experimental_EvaluationOptions`,
17
+ `experimental_ExperimentAssignment`, `experimental_Exposure`, and
18
+ `experimental_ReportExposures` types.
19
+
20
+ These APIs are not supported for general use yet. Do not use them unless
21
+ Vercel has explicitly enabled them for you.
22
+
3
23
  ## 1.8.0
4
24
 
5
25
  ### Minor Changes
package/README.md CHANGED
@@ -24,6 +24,8 @@ const result = await client.evaluate<boolean>('show-new-feature', false, {
24
24
  });
25
25
  ```
26
26
 
27
+ ## Evaluation Metrics
28
+
27
29
  To associate evaluation metrics with an environment, pass the
28
30
  `metricEnvironment` option:
29
31
 
@@ -327,7 +327,43 @@ function getVariant(definition, index) {
327
327
  variantId
328
328
  };
329
329
  }
330
- function handleOutcome(params, outcome) {
330
+ function getWeightedVariantIndex(params, assignment, seed) {
331
+ const lhs = access(assignment.base, params);
332
+ if (typeof lhs !== "string") return assignment.defaultVariant;
333
+ const bucket = _jsxxhash.xxHash32.call(void 0, lhs, seed);
334
+ const boundaries = getSplitBoundaries(assignment);
335
+ for (let index = 0; index < boundaries.length; index++) {
336
+ if (bucket < boundaries[index]) return index;
337
+ }
338
+ return assignment.defaultVariant;
339
+ }
340
+ function experimentAssignment(experiment, variantId, assignmentReason) {
341
+ if (variantId === null) return void 0;
342
+ return {
343
+ id: experiment.id,
344
+ variantId,
345
+ base: experiment.base,
346
+ rampId: experiment.rampId,
347
+ rampPercentage: experiment.rampPercentage,
348
+ assignmentReason
349
+ };
350
+ }
351
+ function outcomeAssignmentReason(outcome) {
352
+ if (typeof outcome === "number") return "variant";
353
+ switch (outcome.type) {
354
+ case "experiment":
355
+ return "experiment";
356
+ case "split":
357
+ return "split";
358
+ case "rollout":
359
+ return "rollout";
360
+ default: {
361
+ const { type } = outcome;
362
+ return exhaustivenessCheck(type);
363
+ }
364
+ }
365
+ }
366
+ function resolveOutcome(params, outcome) {
331
367
  if (typeof outcome === "number") {
332
368
  const variant = getVariant(params.definition, outcome);
333
369
  return {
@@ -337,32 +373,48 @@ function handleOutcome(params, outcome) {
337
373
  }
338
374
  switch (outcome.type) {
339
375
  case "split": {
340
- const lhs = access(outcome.base, params);
341
- const defaultOutcome = getVariant(
342
- params.definition,
343
- outcome.defaultVariant
376
+ const index = getWeightedVariantIndex(
377
+ params,
378
+ outcome,
379
+ params.definition.seed
344
380
  );
345
- if (typeof lhs !== "string") {
346
- return {
347
- ...defaultOutcome,
348
- outcomeType: "split" /* SPLIT */
349
- };
350
- }
351
- const bucket = _jsxxhash.xxHash32.call(void 0, 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
- }
361
381
  return {
362
- ...defaultOutcome,
382
+ ...getVariant(params.definition, index),
363
383
  outcomeType: "split" /* SPLIT */
364
384
  };
365
385
  }
386
+ case "experiment": {
387
+ const experiment = params.definition.experiment;
388
+ if (!experiment) {
389
+ throw new Error("@vercel/flags-core: Experiment not found");
390
+ }
391
+ const unitValue = access(experiment.base, params);
392
+ const defaultVariant = getVariant(
393
+ params.definition,
394
+ experiment.defaultVariant
395
+ );
396
+ const assignment = (variant, assignmentReason) => ({
397
+ ...variant,
398
+ outcomeType: "experiment" /* EXPERIMENT */,
399
+ experiment: experimentAssignment(
400
+ experiment,
401
+ variant.variantId,
402
+ assignmentReason
403
+ )
404
+ });
405
+ if (typeof unitValue !== "string") {
406
+ return assignment(defaultVariant, "not-enrolled");
407
+ }
408
+ const rampPercentage = _nullishCoalesce(experiment.rampPercentage, () => ( 100));
409
+ const enrolled = rampPercentage >= 100 || rampPercentage > 0 && _jsxxhash.xxHash32.call(void 0, unitValue, experiment.enrollmentSeed) < boundaryFor(rampPercentage, 100);
410
+ if (!enrolled) return assignment(defaultVariant, "not-enrolled");
411
+ const index = getWeightedVariantIndex(
412
+ params,
413
+ experiment,
414
+ params.definition.seed
415
+ );
416
+ return assignment(getVariant(params.definition, index), "experiment");
417
+ }
366
418
  case "rollout": {
367
419
  const lhs = access(outcome.base, params);
368
420
  const defaultOutcome = getVariant(
@@ -435,6 +487,19 @@ function handleOutcome(params, outcome) {
435
487
  }
436
488
  }
437
489
  }
490
+ function handleOutcome(params, outcome, assignmentReason) {
491
+ const result = resolveOutcome(params, outcome);
492
+ const experiment = params.definition.experiment;
493
+ if (!experiment || result.experiment) return result;
494
+ return {
495
+ ...result,
496
+ experiment: experimentAssignment(
497
+ experiment,
498
+ result.variantId,
499
+ _nullishCoalesce(assignmentReason, () => ( outcomeAssignmentReason(outcome)))
500
+ )
501
+ };
502
+ }
438
503
  function evaluate(params, _visited) {
439
504
  const envConfig = params.definition.environments[params.environment];
440
505
  if (typeof envConfig === "number") {
@@ -474,7 +539,7 @@ function evaluate(params, _visited) {
474
539
  (targetList) => matchTargetList(targetList, params)
475
540
  );
476
541
  if (matchedIndex > -1) {
477
- return Object.assign(handleOutcome(params, matchedIndex), {
542
+ return Object.assign(handleOutcome(params, matchedIndex, "targeted"), {
478
543
  reason: "target_match" /* TARGET_MATCH */
479
544
  });
480
545
  }
@@ -508,7 +573,7 @@ function bulkEvaluate(flags, shared) {
508
573
  }
509
574
 
510
575
  // package.json
511
- var version = "1.8.0";
576
+ var version = "1.9.0-af502ab-20260904110845";
512
577
 
513
578
  // src/lib/report-value.ts
514
579
  function internalReportValue(key, value, data) {
@@ -727,6 +792,8 @@ async function bulkEvaluate2(id, flags, entities) {
727
792
  }
728
793
 
729
794
  // src/create-raw-client.ts
795
+ var _functions = require('@vercel/functions');
796
+ var _lite = require('dequal/lite');
730
797
  var idCount = 0;
731
798
  async function performInitialize(instance, initFn) {
732
799
  try {
@@ -740,7 +807,8 @@ async function performInitialize(instance, initFn) {
740
807
  function createCreateRawClient(fns) {
741
808
  return function createRawClient({
742
809
  controller,
743
- origin
810
+ origin,
811
+ experimental_reportExposures
744
812
  }) {
745
813
  const id = idCount++;
746
814
  controllerInstanceMap.set(id, {
@@ -748,6 +816,35 @@ function createCreateRawClient(fns) {
748
816
  initialized: false,
749
817
  initPromise: null
750
818
  });
819
+ function report(exposures, entity) {
820
+ if (!experimental_reportExposures || exposures.length === 0) return;
821
+ const pending = (async () => {
822
+ try {
823
+ await experimental_reportExposures(exposures, entity);
824
+ } catch (error) {
825
+ console.error(
826
+ "@vercel/flags-core: Failed to report experiment exposures",
827
+ error
828
+ );
829
+ }
830
+ })();
831
+ try {
832
+ _functions.waitUntil.call(void 0, pending);
833
+ } catch (e) {
834
+ }
835
+ }
836
+ function getExposure(flagKey, result) {
837
+ if (!result.experiment) return null;
838
+ return {
839
+ flagKey,
840
+ experimentId: result.experiment.id,
841
+ variantId: result.experiment.variantId,
842
+ base: result.experiment.base,
843
+ ...result.experiment.rampId === void 0 ? {} : { rampId: result.experiment.rampId },
844
+ ...result.experiment.rampPercentage === void 0 ? {} : { rampPercentage: result.experiment.rampPercentage },
845
+ assignmentReason: result.experiment.assignmentReason
846
+ };
847
+ }
751
848
  const api = {
752
849
  origin,
753
850
  initialize: async () => {
@@ -774,7 +871,7 @@ function createCreateRawClient(fns) {
774
871
  if (_optionalChain([instance, 'optionalAccess', _22 => _22.initPromise])) {
775
872
  try {
776
873
  await instance.initPromise;
777
- } catch (e) {
874
+ } catch (e2) {
778
875
  }
779
876
  }
780
877
  return fns.getDatafile(id);
@@ -782,25 +879,92 @@ function createCreateRawClient(fns) {
782
879
  getFallbackDatafile: () => {
783
880
  return fns.getFallbackDatafile(id);
784
881
  },
785
- evaluate: async (flagKey, defaultValue, entities) => {
882
+ evaluate: async (flagKey, defaultValue, entities, options) => {
786
883
  const instance = controllerInstanceMap.get(id);
787
884
  if (!_optionalChain([instance, 'optionalAccess', _23 => _23.initialized])) {
788
885
  try {
789
886
  await api.initialize();
790
- } catch (e2) {
887
+ } catch (e3) {
888
+ }
889
+ }
890
+ const entity = _nullishCoalesce(entities, () => ( {}));
891
+ const result = await fns.evaluate(
892
+ id,
893
+ flagKey,
894
+ defaultValue,
895
+ entity
896
+ );
897
+ if (experimental_reportExposures && _optionalChain([options, 'optionalAccess', _24 => _24.experimental_exposureLogging]) !== false) {
898
+ const exposure = getExposure(flagKey, result);
899
+ if (exposure) {
900
+ report([exposure], entity);
791
901
  }
792
902
  }
793
- return fns.evaluate(id, flagKey, defaultValue, entities);
903
+ return result;
794
904
  },
795
- bulkEvaluate: async (flags, entities) => {
905
+ bulkEvaluate: async (flags, entities, options) => {
796
906
  const instance = controllerInstanceMap.get(id);
797
- if (!_optionalChain([instance, 'optionalAccess', _24 => _24.initialized])) {
907
+ if (!_optionalChain([instance, 'optionalAccess', _25 => _25.initialized])) {
798
908
  try {
799
909
  await api.initialize();
800
- } catch (e3) {
910
+ } catch (e4) {
911
+ }
912
+ }
913
+ const entity = _nullishCoalesce(entities, () => ( {}));
914
+ const results = await fns.bulkEvaluate(id, flags, entity);
915
+ if (experimental_reportExposures && _optionalChain([options, 'optionalAccess', _26 => _26.experimental_exposureLogging]) !== false) {
916
+ const exposures = [];
917
+ const seen = /* @__PURE__ */ new Set();
918
+ for (const flag of flags) {
919
+ if (seen.has(flag.key)) continue;
920
+ seen.add(flag.key);
921
+ const result = results[flag.key];
922
+ if (!result) continue;
923
+ const exposure = getExposure(flag.key, result);
924
+ if (exposure) exposures.push(exposure);
801
925
  }
926
+ report(exposures, entity);
927
+ }
928
+ return results;
929
+ },
930
+ experimental_reportOverride: async ({
931
+ key,
932
+ value,
933
+ entities
934
+ }) => {
935
+ if (!experimental_reportExposures) return;
936
+ try {
937
+ const instance = controllerInstanceMap.get(id);
938
+ if (!_optionalChain([instance, 'optionalAccess', _27 => _27.initialized])) await api.initialize();
939
+ const datafile = await fns.getDatafile(id);
940
+ const definition = datafile.definitions[key];
941
+ const experiment = _optionalChain([definition, 'optionalAccess', _28 => _28.experiment]);
942
+ if (!experiment) return;
943
+ const variantIndex = definition.variants.findIndex(
944
+ (variant) => _lite.dequal.call(void 0, variant, value)
945
+ );
946
+ const variantId = variantIndex < 0 ? null : _nullishCoalesce(_optionalChain([definition, 'access', _29 => _29.variantIds, 'optionalAccess', _30 => _30[variantIndex]]), () => ( null));
947
+ const entity = _nullishCoalesce(entities, () => ( {}));
948
+ report(
949
+ [
950
+ {
951
+ flagKey: key,
952
+ experimentId: experiment.id,
953
+ variantId,
954
+ base: experiment.base,
955
+ rampId: experiment.rampId,
956
+ rampPercentage: experiment.rampPercentage,
957
+ assignmentReason: "override"
958
+ }
959
+ ],
960
+ entity
961
+ );
962
+ } catch (error) {
963
+ console.error(
964
+ "@vercel/flags-core: Failed to report experiment override",
965
+ error
966
+ );
802
967
  }
803
- return fns.bulkEvaluate(id, flags, entities);
804
968
  }
805
969
  };
806
970
  return api;
@@ -886,7 +1050,7 @@ var MAX_RETRIES = 3;
886
1050
  var MAX_EVENTS_PER_REQUEST = 2e3;
887
1051
  var EVALUATING_OIDC_TOKEN_HEADER = "X-Vercel-Flags-OIDC-Token";
888
1052
  var FLUSH_REASON_HEADER = "X-Vercel-Flags-Flush-Reason";
889
- var isDebugMode = _optionalChain([process, 'access', _25 => _25.env, 'access', _26 => _26.DEBUG, 'optionalAccess', _27 => _27.includes, 'call', _28 => _28("@vercel/flags-core")]);
1053
+ var isDebugMode = _optionalChain([process, 'access', _31 => _31.env, 'access', _32 => _32.DEBUG, 'optionalAccess', _33 => _33.includes, 'call', _34 => _34("@vercel/flags-core")]);
890
1054
  var debugLog = (...args) => {
891
1055
  if (!isDebugMode) return;
892
1056
  console.log(...args);
@@ -895,7 +1059,7 @@ async function getEvaluatingOidcToken(auth) {
895
1059
  if (!auth.sdkKey) return void 0;
896
1060
  try {
897
1061
  return await _oidc.getVercelOidcToken.call(void 0, );
898
- } catch (e4) {
1062
+ } catch (e5) {
899
1063
  return void 0;
900
1064
  }
901
1065
  }
@@ -965,7 +1129,7 @@ var SYMBOL_FOR_REQ_CONTEXT = /* @__PURE__ */ Symbol.for("@vercel/request-context
965
1129
  var fromSymbol = globalThis;
966
1130
  function getRequestContext() {
967
1131
  try {
968
- const ctx = _optionalChain([fromSymbol, 'access', _29 => _29[SYMBOL_FOR_REQ_CONTEXT], 'optionalAccess', _30 => _30.get, 'optionalCall', _31 => _31()]);
1132
+ const ctx = _optionalChain([fromSymbol, 'access', _35 => _35[SYMBOL_FOR_REQ_CONTEXT], 'optionalAccess', _36 => _36.get, 'optionalCall', _37 => _37()]);
969
1133
  if (ctx && Object.hasOwn(ctx, "headers")) {
970
1134
  return {
971
1135
  ctx,
@@ -973,13 +1137,13 @@ function getRequestContext() {
973
1137
  };
974
1138
  }
975
1139
  return { ctx, headers: void 0 };
976
- } catch (e5) {
1140
+ } catch (e6) {
977
1141
  return { ctx: void 0, headers: void 0 };
978
1142
  }
979
1143
  }
980
1144
 
981
1145
  // src/utils/scheduler.ts
982
- var _functions = require('@vercel/functions');
1146
+
983
1147
  var IDLE_FLUSH_WAIT_MS = 5e3;
984
1148
  var IDLE_FLUSH_JITTER_RATIO = 0.2;
985
1149
  var MAX_FLUSH_WAIT_MS = 6e4;
@@ -1003,7 +1167,7 @@ var Scheduler = (_class = class {
1003
1167
  })();
1004
1168
  try {
1005
1169
  _functions.waitUntil.call(void 0, this.pending);
1006
- } catch (e6) {
1170
+ } catch (e7) {
1007
1171
  }
1008
1172
  this.maxTimeout = setTimeout(
1009
1173
  () => this.resolveScheduledFlush("max_timeout"),
@@ -1030,7 +1194,7 @@ var Scheduler = (_class = class {
1030
1194
  }
1031
1195
  resolveScheduledFlush(reason) {
1032
1196
  this.clearTimeouts();
1033
- _optionalChain([this, 'access', _32 => _32.resolveWait, 'optionalCall', _33 => _33(reason)]);
1197
+ _optionalChain([this, 'access', _38 => _38.resolveWait, 'optionalCall', _39 => _39(reason)]);
1034
1198
  }
1035
1199
  reset() {
1036
1200
  this.pending = null;
@@ -1278,7 +1442,7 @@ var BundledSource = class {
1278
1442
  */
1279
1443
  async tryLoad() {
1280
1444
  const result = await this.getResult();
1281
- if (_optionalChain([result, 'optionalAccess', _34 => _34.state]) === "ok" && result.definitions) {
1445
+ if (_optionalChain([result, 'optionalAccess', _40 => _40.state]) === "ok" && result.definitions) {
1282
1446
  return result.definitions;
1283
1447
  }
1284
1448
  return void 0;
@@ -1318,14 +1482,14 @@ async function fetchDatafile(options) {
1318
1482
  signal: controller.signal
1319
1483
  });
1320
1484
  clearTimeout(timeoutId);
1321
- _optionalChain([options, 'access', _35 => _35.signal, 'optionalAccess', _36 => _36.removeEventListener, 'call', _37 => _37("abort", onExternalAbort)]);
1485
+ _optionalChain([options, 'access', _41 => _41.signal, 'optionalAccess', _42 => _42.removeEventListener, 'call', _43 => _43("abort", onExternalAbort)]);
1322
1486
  if (!res.ok) {
1323
1487
  throw new Error(`Failed to fetch data: ${res.statusText}`);
1324
1488
  }
1325
1489
  return res.json();
1326
1490
  } catch (error) {
1327
1491
  clearTimeout(timeoutId);
1328
- _optionalChain([options, 'access', _38 => _38.signal, 'optionalAccess', _39 => _39.removeEventListener, 'call', _40 => _40("abort", onExternalAbort)]);
1492
+ _optionalChain([options, 'access', _44 => _44.signal, 'optionalAccess', _45 => _45.removeEventListener, 'call', _46 => _46("abort", onExternalAbort)]);
1329
1493
  throw error instanceof Error ? error : new Error("Unknown fetch error");
1330
1494
  }
1331
1495
  }
@@ -1393,7 +1557,7 @@ var TypedEmitter = (_class5 = class {constructor() { _class5.prototype.__init11.
1393
1557
  set.add(handler);
1394
1558
  }
1395
1559
  off(event, handler) {
1396
- _optionalChain([this, 'access', _41 => _41.handlers, 'access', _42 => _42.get, 'call', _43 => _43(event), 'optionalAccess', _44 => _44.delete, 'call', _45 => _45(handler)]);
1560
+ _optionalChain([this, 'access', _47 => _47.handlers, 'access', _48 => _48.get, 'call', _49 => _49(event), 'optionalAccess', _50 => _50.delete, 'call', _51 => _51(handler)]);
1397
1561
  }
1398
1562
  emit(event, ...args) {
1399
1563
  const set = this.handlers.get(event);
@@ -1419,11 +1583,11 @@ var PollingSource = class extends TypedEmitter {
1419
1583
  * Emits 'data' on success, 'error' on failure.
1420
1584
  */
1421
1585
  async poll() {
1422
- if (_optionalChain([this, 'access', _46 => _46.abortController, 'optionalAccess', _47 => _47.signal, 'access', _48 => _48.aborted])) return;
1586
+ if (_optionalChain([this, 'access', _52 => _52.abortController, 'optionalAccess', _53 => _53.signal, 'access', _54 => _54.aborted])) return;
1423
1587
  try {
1424
1588
  const data = await fetchDatafile({
1425
1589
  ...this.config,
1426
- signal: _optionalChain([this, 'access', _49 => _49.abortController, 'optionalAccess', _50 => _50.signal])
1590
+ signal: _optionalChain([this, 'access', _55 => _55.abortController, 'optionalAccess', _56 => _56.signal])
1427
1591
  });
1428
1592
  this.emit("data", data);
1429
1593
  } catch (error) {
@@ -1452,7 +1616,7 @@ var PollingSource = class extends TypedEmitter {
1452
1616
  clearInterval(this.intervalId);
1453
1617
  this.intervalId = void 0;
1454
1618
  }
1455
- _optionalChain([this, 'access', _51 => _51.abortController, 'optionalAccess', _52 => _52.abort, 'call', _53 => _53()]);
1619
+ _optionalChain([this, 'access', _57 => _57.abortController, 'optionalAccess', _58 => _58.abort, 'call', _59 => _59()]);
1456
1620
  this.abortController = void 0;
1457
1621
  }
1458
1622
  };
@@ -1526,7 +1690,7 @@ async function connectStream(config, callbacks) {
1526
1690
  if (pingTimeoutId !== void 0) clearTimeout(pingTimeoutId);
1527
1691
  if (!initialDataReceived) return;
1528
1692
  pingTimeoutId = setTimeout(() => {
1529
- _optionalChain([responseBody, 'optionalAccess', _54 => _54.cancel, 'call', _55 => _55(), 'access', _56 => _56.catch, 'call', _57 => _57(() => {
1693
+ _optionalChain([responseBody, 'optionalAccess', _60 => _60.cancel, 'call', _61 => _61(), 'access', _62 => _62.catch, 'call', _63 => _63(() => {
1530
1694
  })]);
1531
1695
  connectionAbort.abort();
1532
1696
  }, PING_TIMEOUT_MS);
@@ -1545,7 +1709,7 @@ async function connectStream(config, callbacks) {
1545
1709
  if (vercelEnv) {
1546
1710
  headers["X-Vercel-Env"] = vercelEnv;
1547
1711
  }
1548
- const revision = _optionalChain([config, 'access', _58 => _58.revision, 'optionalCall', _59 => _59()]);
1712
+ const revision = _optionalChain([config, 'access', _64 => _64.revision, 'optionalCall', _65 => _65()]);
1549
1713
  if (revision !== void 0) {
1550
1714
  headers["X-Revision"] = String(revision);
1551
1715
  }
@@ -1591,7 +1755,7 @@ async function connectStream(config, callbacks) {
1591
1755
  let message;
1592
1756
  try {
1593
1757
  message = JSON.parse(line);
1594
- } catch (e7) {
1758
+ } catch (e8) {
1595
1759
  console.warn(
1596
1760
  "@vercel/flags-core: Failed to parse stream message, skipping"
1597
1761
  );
@@ -1607,7 +1771,7 @@ async function connectStream(config, callbacks) {
1607
1771
  resetPingTimeout();
1608
1772
  }
1609
1773
  if (message.type === "primed") {
1610
- _optionalChain([onPrimed, 'optionalCall', _60 => _60(message)]);
1774
+ _optionalChain([onPrimed, 'optionalCall', _66 => _66(message)]);
1611
1775
  retryCount = 0;
1612
1776
  if (!initialDataReceived) {
1613
1777
  initialDataReceived = true;
@@ -1630,7 +1794,7 @@ async function connectStream(config, callbacks) {
1630
1794
  clearTimeout(pingTimeoutId);
1631
1795
  abortController.signal.removeEventListener("abort", onMainAbort);
1632
1796
  if (!abortController.signal.aborted) {
1633
- _optionalChain([onDisconnect, 'optionalCall', _61 => _61()]);
1797
+ _optionalChain([onDisconnect, 'optionalCall', _67 => _67()]);
1634
1798
  retryCount++;
1635
1799
  const elapsed = Date.now() - lastAttemptTime;
1636
1800
  const minGap = Math.max(0, BASE_RETRY_DELAY_MS - elapsed);
@@ -1651,7 +1815,7 @@ async function connectStream(config, callbacks) {
1651
1815
  if (!connectionAbort.signal.aborted) {
1652
1816
  lastError = error;
1653
1817
  }
1654
- _optionalChain([onDisconnect, 'optionalCall', _62 => _62()]);
1818
+ _optionalChain([onDisconnect, 'optionalCall', _68 => _68()]);
1655
1819
  retryCount++;
1656
1820
  const elapsed = Date.now() - lastAttemptTime;
1657
1821
  const minGap = Math.max(0, BASE_RETRY_DELAY_MS - elapsed);
@@ -1730,7 +1894,7 @@ var StreamSource = class extends TypedEmitter {
1730
1894
  * Stop the stream connection.
1731
1895
  */
1732
1896
  stop() {
1733
- _optionalChain([this, 'access', _63 => _63.abortController, 'optionalAccess', _64 => _64.abort, 'call', _65 => _65()]);
1897
+ _optionalChain([this, 'access', _69 => _69.abortController, 'optionalAccess', _70 => _70.abort, 'call', _71 => _71()]);
1734
1898
  this.abortController = void 0;
1735
1899
  this.promise = void 0;
1736
1900
  }
@@ -1789,7 +1953,7 @@ var Controller = (_class6 = class {
1789
1953
  this.options = normalizeOptions(options);
1790
1954
  this.streamSource = new StreamSource(
1791
1955
  this.options,
1792
- () => _optionalChain([this, 'access', _66 => _66.data, 'optionalAccess', _67 => _67.revision])
1956
+ () => _optionalChain([this, 'access', _72 => _72.data, 'optionalAccess', _73 => _73.revision])
1793
1957
  );
1794
1958
  this.pollingSource = new PollingSource(this.options);
1795
1959
  this.bundledSource = new BundledSource({
@@ -1897,7 +2061,7 @@ var Controller = (_class6 = class {
1897
2061
  if (bundled) {
1898
2062
  this.data = tagData(bundled, "bundled");
1899
2063
  }
1900
- } catch (e8) {
2064
+ } catch (e9) {
1901
2065
  }
1902
2066
  }
1903
2067
  if (this.data) {
@@ -1999,7 +2163,7 @@ var Controller = (_class6 = class {
1999
2163
  this.data = tagData(fetched, "fetched");
2000
2164
  result = this.data;
2001
2165
  cacheStatus = "MISS";
2002
- } catch (e9) {
2166
+ } catch (e10) {
2003
2167
  throw new Error(
2004
2168
  "@vercel/flags-core: No flag definitions available. Initialize the client or provide a datafile."
2005
2169
  );
@@ -2118,7 +2282,7 @@ var Controller = (_class6 = class {
2118
2282
  return true;
2119
2283
  }
2120
2284
  return false;
2121
- } catch (e10) {
2285
+ } catch (e11) {
2122
2286
  return false;
2123
2287
  }
2124
2288
  }
@@ -2143,7 +2307,7 @@ var Controller = (_class6 = class {
2143
2307
  return true;
2144
2308
  }
2145
2309
  return false;
2146
- } catch (e11) {
2310
+ } catch (e12) {
2147
2311
  clearTimeout(timeoutId);
2148
2312
  return false;
2149
2313
  }
@@ -2193,7 +2357,7 @@ var Controller = (_class6 = class {
2193
2357
  fetch: this.options.fetch
2194
2358
  });
2195
2359
  return tagData(fetched, "fetched");
2196
- } catch (e12) {
2360
+ } catch (e13) {
2197
2361
  }
2198
2362
  throw new Error(
2199
2363
  "@vercel/flags-core: No flag definitions available during build. Provide a datafile or bundled definitions."
@@ -2227,7 +2391,7 @@ var Controller = (_class6 = class {
2227
2391
  this.data = tagData(fetched, "fetched");
2228
2392
  this.transition("degraded");
2229
2393
  return;
2230
- } catch (e13) {
2394
+ } catch (e14) {
2231
2395
  }
2232
2396
  }
2233
2397
  throw new Error(
@@ -2279,7 +2443,7 @@ var Controller = (_class6 = class {
2279
2443
  this.data = tagData(fetched, "fetched");
2280
2444
  this.transition("degraded");
2281
2445
  return [this.data, "MISS"];
2282
- } catch (e14) {
2446
+ } catch (e15) {
2283
2447
  }
2284
2448
  }
2285
2449
  throw new Error(
@@ -2331,11 +2495,11 @@ var Controller = (_class6 = class {
2331
2495
  duration: Date.now() - startTime,
2332
2496
  mode: mode === "streaming" ? "stream" : mode === "polling" ? "poll" : mode
2333
2497
  };
2334
- const configUpdatedAt = _optionalChain([this, 'access', _68 => _68.data, 'optionalAccess', _69 => _69.configUpdatedAt]);
2498
+ const configUpdatedAt = _optionalChain([this, 'access', _74 => _74.data, 'optionalAccess', _75 => _75.configUpdatedAt]);
2335
2499
  if (typeof configUpdatedAt === "number") {
2336
2500
  trackOptions.configUpdatedAt = configUpdatedAt;
2337
2501
  }
2338
- const revision = _optionalChain([this, 'access', _70 => _70.data, 'optionalAccess', _71 => _71.revision]);
2502
+ const revision = _optionalChain([this, 'access', _76 => _76.data, 'optionalAccess', _77 => _77.revision]);
2339
2503
  if (typeof revision === "number") {
2340
2504
  trackOptions.revision = revision;
2341
2505
  }
@@ -2368,7 +2532,7 @@ function parseSdkKeyFromFlagsConnectionString(text) {
2368
2532
  const params = new URLSearchParams(text.slice(6));
2369
2533
  const sdkKey = params.get("sdkKey");
2370
2534
  if (sdkKey && SDK_KEY_REGEX.test(sdkKey)) return sdkKey;
2371
- } catch (e15) {
2535
+ } catch (e16) {
2372
2536
  }
2373
2537
  return null;
2374
2538
  }
@@ -2377,7 +2541,7 @@ function parseSdkKeyFromFlagsConnectionString(text) {
2377
2541
  async function getOidcToken() {
2378
2542
  try {
2379
2543
  return await _oidc.getVercelOidcToken.call(void 0, );
2380
- } catch (e16) {
2544
+ } catch (e17) {
2381
2545
  throw new Error(
2382
2546
  [
2383
2547
  "@vercel/flags-core: Failed to get OIDC token.",
@@ -2445,11 +2609,13 @@ function make(createRawClient) {
2445
2609
  const optionsOnly = typeof sdkKeyOrConnectionStringOrOptions === "object" && sdkKeyOrConnectionStringOrOptions !== null;
2446
2610
  const sdkKeyOrConnectionString = optionsOnly ? void 0 : sdkKeyOrConnectionStringOrOptions;
2447
2611
  const createClientOptions = optionsOnly ? sdkKeyOrConnectionStringOrOptions : options;
2612
+ const { experimental_reportExposures, ...controllerOptions } = _nullishCoalesce(createClientOptions, () => ( {}));
2448
2613
  const auth = new Authentication(sdkKeyOrConnectionString);
2449
- const controller = new Controller({ auth, ...createClientOptions });
2614
+ const controller = new Controller({ auth, ...controllerOptions });
2450
2615
  return createRawClient({
2451
2616
  controller,
2452
- origin: { provider: "vercel", sdkKey: auth.sdkKey }
2617
+ origin: { provider: "vercel", sdkKey: auth.sdkKey },
2618
+ ...experimental_reportExposures ? { experimental_reportExposures } : {}
2453
2619
  });
2454
2620
  }
2455
2621
  function resetDefaultFlagsClient2() {
@@ -2499,4 +2665,4 @@ var {
2499
2665
 
2500
2666
 
2501
2667
  exports.ResolutionReason = ResolutionReason; exports.evaluate = evaluate; exports.FallbackNotFoundError = FallbackNotFoundError; exports.FallbackEntryNotFoundError = FallbackEntryNotFoundError; exports.Controller = Controller; exports.flagsClient = flagsClient; exports.resetDefaultFlagsClient = resetDefaultFlagsClient; exports.createClient = createClient;
2502
- //# sourceMappingURL=chunk-C3FUDFOP.cjs.map
2668
+ //# sourceMappingURL=chunk-5EM5QUML.cjs.map