@vercel/flags-core 1.8.1 → 1.9.0-0fd2f41-20260915094243

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.
@@ -573,7 +573,7 @@ function bulkEvaluate(flags, shared) {
573
573
  }
574
574
 
575
575
  // package.json
576
- var version = "1.8.1";
576
+ var version = "1.9.0-0fd2f41-20260915094243";
577
577
 
578
578
  // src/lib/report-value.ts
579
579
  function internalReportValue(key, value, data) {
@@ -971,6 +971,12 @@ function createCreateRawClient(fns) {
971
971
  };
972
972
  }
973
973
 
974
+ // src/utils/debug.ts
975
+ function debugLog(source, message, details = {}) {
976
+ if (!_optionalChain([process, 'access', _31 => _31.env, 'access', _32 => _32.DEBUG, 'optionalAccess', _33 => _33.includes, 'call', _34 => _34("@vercel/flags-core")])) return;
977
+ console.log(`@vercel/flags-core [${source}] ${message}`, details);
978
+ }
979
+
974
980
  // src/utils/read-bundled-definitions.ts
975
981
  var sdkKeyHashCache = /* @__PURE__ */ new Map();
976
982
  async function computeHash(sdkKey) {
@@ -1050,8 +1056,8 @@ var MAX_RETRIES = 3;
1050
1056
  var MAX_EVENTS_PER_REQUEST = 2e3;
1051
1057
  var EVALUATING_OIDC_TOKEN_HEADER = "X-Vercel-Flags-OIDC-Token";
1052
1058
  var FLUSH_REASON_HEADER = "X-Vercel-Flags-Flush-Reason";
1053
- var isDebugMode = _optionalChain([process, 'access', _31 => _31.env, 'access', _32 => _32.DEBUG, 'optionalAccess', _33 => _33.includes, 'call', _34 => _34("@vercel/flags-core")]);
1054
- var debugLog = (...args) => {
1059
+ var isDebugMode = _optionalChain([process, 'access', _35 => _35.env, 'access', _36 => _36.DEBUG, 'optionalAccess', _37 => _37.includes, 'call', _38 => _38("@vercel/flags-core")]);
1060
+ var debugLog2 = (...args) => {
1055
1061
  if (!isDebugMode) return;
1056
1062
  console.log(...args);
1057
1063
  };
@@ -1097,7 +1103,7 @@ async function sendIngestChunk(options, eventsToSend, flushId, flushReason) {
1097
1103
  headers: await getIngestHeaders(options, flushReason),
1098
1104
  body: JSON.stringify(eventsToSend)
1099
1105
  });
1100
- debugLog(
1106
+ debugLog2(
1101
1107
  `@vercel/flags-core: Ingest response ${response.status} for ${eventsToSend.length} events on ${response.headers.get("x-vercel-id")}`
1102
1108
  );
1103
1109
  if (response.ok) {
@@ -1129,7 +1135,7 @@ var SYMBOL_FOR_REQ_CONTEXT = /* @__PURE__ */ Symbol.for("@vercel/request-context
1129
1135
  var fromSymbol = globalThis;
1130
1136
  function getRequestContext() {
1131
1137
  try {
1132
- const ctx = _optionalChain([fromSymbol, 'access', _35 => _35[SYMBOL_FOR_REQ_CONTEXT], 'optionalAccess', _36 => _36.get, 'optionalCall', _37 => _37()]);
1138
+ const ctx = _optionalChain([fromSymbol, 'access', _39 => _39[SYMBOL_FOR_REQ_CONTEXT], 'optionalAccess', _40 => _40.get, 'optionalCall', _41 => _41()]);
1133
1139
  if (ctx && Object.hasOwn(ctx, "headers")) {
1134
1140
  return {
1135
1141
  ctx,
@@ -1194,7 +1200,7 @@ var Scheduler = (_class = class {
1194
1200
  }
1195
1201
  resolveScheduledFlush(reason) {
1196
1202
  this.clearTimeouts();
1197
- _optionalChain([this, 'access', _38 => _38.resolveWait, 'optionalCall', _39 => _39(reason)]);
1203
+ _optionalChain([this, 'access', _42 => _42.resolveWait, 'optionalCall', _43 => _43(reason)]);
1198
1204
  }
1199
1205
  reset() {
1200
1206
  this.pending = null;
@@ -1442,7 +1448,7 @@ var BundledSource = class {
1442
1448
  */
1443
1449
  async tryLoad() {
1444
1450
  const result = await this.getResult();
1445
- if (_optionalChain([result, 'optionalAccess', _40 => _40.state]) === "ok" && result.definitions) {
1451
+ if (_optionalChain([result, 'optionalAccess', _44 => _44.state]) === "ok" && result.definitions) {
1446
1452
  return result.definitions;
1447
1453
  }
1448
1454
  return void 0;
@@ -1482,18 +1488,190 @@ async function fetchDatafile(options) {
1482
1488
  signal: controller.signal
1483
1489
  });
1484
1490
  clearTimeout(timeoutId);
1485
- _optionalChain([options, 'access', _41 => _41.signal, 'optionalAccess', _42 => _42.removeEventListener, 'call', _43 => _43("abort", onExternalAbort)]);
1491
+ _optionalChain([options, 'access', _45 => _45.signal, 'optionalAccess', _46 => _46.removeEventListener, 'call', _47 => _47("abort", onExternalAbort)]);
1486
1492
  if (!res.ok) {
1487
1493
  throw new Error(`Failed to fetch data: ${res.statusText}`);
1488
1494
  }
1489
1495
  return res.json();
1490
1496
  } catch (error) {
1491
1497
  clearTimeout(timeoutId);
1492
- _optionalChain([options, 'access', _44 => _44.signal, 'optionalAccess', _45 => _45.removeEventListener, 'call', _46 => _46("abort", onExternalAbort)]);
1498
+ _optionalChain([options, 'access', _48 => _48.signal, 'optionalAccess', _49 => _49.removeEventListener, 'call', _50 => _50("abort", onExternalAbort)]);
1493
1499
  throw error instanceof Error ? error : new Error("Unknown fetch error");
1494
1500
  }
1495
1501
  }
1496
1502
 
1503
+ // src/controller/header-source.ts
1504
+
1505
+
1506
+ // src/controller/tagged-data.ts
1507
+ function tagData(data, origin) {
1508
+ return Object.assign(data, { _origin: origin });
1509
+ }
1510
+ function originToMetricsSource(origin) {
1511
+ switch (origin) {
1512
+ case "stream":
1513
+ case "poll":
1514
+ case "provided":
1515
+ return "in-memory";
1516
+ case "fetched":
1517
+ return "remote";
1518
+ case "bundled":
1519
+ return "embedded";
1520
+ }
1521
+ }
1522
+
1523
+ // src/controller/typed-emitter.ts
1524
+ var TypedEmitter = (_class5 = class {constructor() { _class5.prototype.__init11.call(this); }
1525
+ __init11() {this.handlers = /* @__PURE__ */ new Map()}
1526
+ on(event, handler) {
1527
+ let set = this.handlers.get(event);
1528
+ if (!set) {
1529
+ set = /* @__PURE__ */ new Set();
1530
+ this.handlers.set(event, set);
1531
+ }
1532
+ set.add(handler);
1533
+ }
1534
+ off(event, handler) {
1535
+ _optionalChain([this, 'access', _51 => _51.handlers, 'access', _52 => _52.get, 'call', _53 => _53(event), 'optionalAccess', _54 => _54.delete, 'call', _55 => _55(handler)]);
1536
+ }
1537
+ emit(event, ...args) {
1538
+ const set = this.handlers.get(event);
1539
+ if (set) {
1540
+ for (const handler of set) {
1541
+ handler(...args);
1542
+ }
1543
+ }
1544
+ }
1545
+ }, _class5);
1546
+
1547
+ // src/controller/header-source.ts
1548
+ var HeaderSource = class extends TypedEmitter {
1549
+
1550
+
1551
+
1552
+ constructor(options) {
1553
+ super();
1554
+ this.options = options;
1555
+ }
1556
+ fetchDatafile() {
1557
+ if (this.promise) {
1558
+ debugLog("header-source", "Reusing pending refresh");
1559
+ return this.promise;
1560
+ }
1561
+ debugLog("header-source", "Starting refresh");
1562
+ const abortController = new AbortController();
1563
+ this.abortController = abortController;
1564
+ this.promise = fetchDatafile({
1565
+ ...this.options,
1566
+ signal: abortController.signal
1567
+ }).then((data) => {
1568
+ abortController.signal.throwIfAborted();
1569
+ debugLog("header-source", "Refresh completed", {
1570
+ projectId: data.projectId,
1571
+ configUpdatedAt: Number(data.configUpdatedAt),
1572
+ revision: data.revision
1573
+ });
1574
+ this.emit("data", data);
1575
+ return data;
1576
+ }).catch((error) => {
1577
+ debugLog("header-source", "Refresh failed", {
1578
+ aborted: abortController.signal.aborted
1579
+ });
1580
+ throw error;
1581
+ }).finally(() => {
1582
+ if (this.abortController === abortController) {
1583
+ this.promise = void 0;
1584
+ this.abortController = void 0;
1585
+ }
1586
+ });
1587
+ return this.promise;
1588
+ }
1589
+ getUpdatedAtHeader(projectId) {
1590
+ const ctx = getRequestContext();
1591
+ const headerName = _optionalChain([ctx, 'access', _56 => _56.headers, 'optionalAccess', _57 => _57["x-vercel-edge-config-versions"]]) != null ? "x-vercel-edge-config-versions" : "edge-config-versions";
1592
+ const header = _optionalChain([ctx, 'access', _58 => _58.headers, 'optionalAccess', _59 => _59[headerName]]);
1593
+ if (!header) {
1594
+ debugLog("header-source", "Header unavailable", {
1595
+ projectId,
1596
+ reason: "missing-header"
1597
+ });
1598
+ return;
1599
+ }
1600
+ const prefix = `flags_${projectId}=`;
1601
+ const value = _optionalChain([header, 'access', _60 => _60.split, 'call', _61 => _61(";"), 'access', _62 => _62.map, 'call', _63 => _63((part) => part.trim()), 'access', _64 => _64.find, 'call', _65 => _65((part) => part.startsWith(prefix)), 'optionalAccess', _66 => _66.slice, 'call', _67 => _67(prefix.length)]);
1602
+ const timestamp = Number(value);
1603
+ if (!Number.isFinite(timestamp) || timestamp <= 0) {
1604
+ debugLog("header-source", "Header unavailable", {
1605
+ projectId,
1606
+ headerName,
1607
+ reason: value === void 0 ? "project-not-found" : "invalid-timestamp"
1608
+ });
1609
+ return;
1610
+ }
1611
+ debugLog("header-source", "Header version available", {
1612
+ projectId,
1613
+ headerName,
1614
+ timestamp
1615
+ });
1616
+ return timestamp;
1617
+ }
1618
+ async resolveData(currentData) {
1619
+ if (!currentData.configUpdatedAt) {
1620
+ debugLog("header-source", "Skipping header refresh", {
1621
+ projectId: currentData.projectId,
1622
+ reason: "missing-data-timestamp"
1623
+ });
1624
+ return;
1625
+ }
1626
+ const updatedAtHeader = this.getUpdatedAtHeader(currentData.projectId);
1627
+ if (!updatedAtHeader) {
1628
+ return;
1629
+ }
1630
+ const currentUpdatedAt = Number(currentData.configUpdatedAt);
1631
+ const deltaMs = updatedAtHeader - currentUpdatedAt;
1632
+ debugLog("header-source", "Freshness decision", {
1633
+ projectId: currentData.projectId,
1634
+ currentUpdatedAt,
1635
+ headerUpdatedAt: updatedAtHeader,
1636
+ deltaMs,
1637
+ action: updatedAtHeader <= currentUpdatedAt ? "serve-cached" : updatedAtHeader <= currentUpdatedAt + 1e4 ? "background-refresh" : "blocking-refresh"
1638
+ });
1639
+ if (updatedAtHeader <= currentUpdatedAt) {
1640
+ return [currentData, "HIT"];
1641
+ }
1642
+ if (updatedAtHeader <= currentUpdatedAt + 1e4) {
1643
+ const pending = this.fetchDatafile();
1644
+ const signal = _optionalChain([this, 'access', _68 => _68.abortController, 'optionalAccess', _69 => _69.signal]);
1645
+ const background = pending.catch((error) => {
1646
+ if (!_optionalChain([signal, 'optionalAccess', _70 => _70.aborted])) {
1647
+ console.error("@vercel/flags-core: Header refresh failed:", error);
1648
+ }
1649
+ });
1650
+ _functions.waitUntil.call(void 0, background);
1651
+ return [currentData, "STALE"];
1652
+ }
1653
+ const data = await this.fetchDatafile();
1654
+ return [tagData(data, "fetched"), "MISS"];
1655
+ }
1656
+ read(currentData) {
1657
+ return this.resolveData(currentData);
1658
+ }
1659
+ isAvailable(projectId) {
1660
+ return !!this.getUpdatedAtHeader(projectId);
1661
+ }
1662
+ /**
1663
+ * Abort the current header-driven fetch and discard its pending work.
1664
+ */
1665
+ stop() {
1666
+ debugLog("header-source", "Stopping header refresh", {
1667
+ pending: this.promise !== void 0
1668
+ });
1669
+ _optionalChain([this, 'access', _71 => _71.abortController, 'optionalAccess', _72 => _72.abort, 'call', _73 => _73()]);
1670
+ this.abortController = void 0;
1671
+ this.promise = void 0;
1672
+ }
1673
+ };
1674
+
1497
1675
  // src/controller/normalized-options.ts
1498
1676
  var DEFAULT_STREAM_INIT_TIMEOUT_MS = 3e3;
1499
1677
  var DEFAULT_POLLING_INTERVAL_MS = 3e4;
@@ -1545,30 +1723,6 @@ function normalizeOptions(options) {
1545
1723
  };
1546
1724
  }
1547
1725
 
1548
- // src/controller/typed-emitter.ts
1549
- var TypedEmitter = (_class5 = class {constructor() { _class5.prototype.__init11.call(this); }
1550
- __init11() {this.handlers = /* @__PURE__ */ new Map()}
1551
- on(event, handler) {
1552
- let set = this.handlers.get(event);
1553
- if (!set) {
1554
- set = /* @__PURE__ */ new Set();
1555
- this.handlers.set(event, set);
1556
- }
1557
- set.add(handler);
1558
- }
1559
- off(event, handler) {
1560
- _optionalChain([this, 'access', _47 => _47.handlers, 'access', _48 => _48.get, 'call', _49 => _49(event), 'optionalAccess', _50 => _50.delete, 'call', _51 => _51(handler)]);
1561
- }
1562
- emit(event, ...args) {
1563
- const set = this.handlers.get(event);
1564
- if (set) {
1565
- for (const handler of set) {
1566
- handler(...args);
1567
- }
1568
- }
1569
- }
1570
- }, _class5);
1571
-
1572
1726
  // src/controller/polling-source.ts
1573
1727
  var PollingSource = class extends TypedEmitter {
1574
1728
 
@@ -1583,11 +1737,11 @@ var PollingSource = class extends TypedEmitter {
1583
1737
  * Emits 'data' on success, 'error' on failure.
1584
1738
  */
1585
1739
  async poll() {
1586
- if (_optionalChain([this, 'access', _52 => _52.abortController, 'optionalAccess', _53 => _53.signal, 'access', _54 => _54.aborted])) return;
1740
+ if (_optionalChain([this, 'access', _74 => _74.abortController, 'optionalAccess', _75 => _75.signal, 'access', _76 => _76.aborted])) return;
1587
1741
  try {
1588
1742
  const data = await fetchDatafile({
1589
1743
  ...this.config,
1590
- signal: _optionalChain([this, 'access', _55 => _55.abortController, 'optionalAccess', _56 => _56.signal])
1744
+ signal: _optionalChain([this, 'access', _77 => _77.abortController, 'optionalAccess', _78 => _78.signal])
1591
1745
  });
1592
1746
  this.emit("data", data);
1593
1747
  } catch (error) {
@@ -1616,7 +1770,7 @@ var PollingSource = class extends TypedEmitter {
1616
1770
  clearInterval(this.intervalId);
1617
1771
  this.intervalId = void 0;
1618
1772
  }
1619
- _optionalChain([this, 'access', _57 => _57.abortController, 'optionalAccess', _58 => _58.abort, 'call', _59 => _59()]);
1773
+ _optionalChain([this, 'access', _79 => _79.abortController, 'optionalAccess', _80 => _80.abort, 'call', _81 => _81()]);
1620
1774
  this.abortController = void 0;
1621
1775
  }
1622
1776
  };
@@ -1695,7 +1849,7 @@ async function connectStream(config, callbacks) {
1695
1849
  if (pingTimeoutId !== void 0) clearTimeout(pingTimeoutId);
1696
1850
  if (!initialDataReceived) return;
1697
1851
  pingTimeoutId = setTimeout(() => {
1698
- _optionalChain([responseBody, 'optionalAccess', _60 => _60.cancel, 'call', _61 => _61(), 'access', _62 => _62.catch, 'call', _63 => _63(() => {
1852
+ _optionalChain([responseBody, 'optionalAccess', _82 => _82.cancel, 'call', _83 => _83(), 'access', _84 => _84.catch, 'call', _85 => _85(() => {
1699
1853
  })]);
1700
1854
  connectionAbort.abort();
1701
1855
  }, PING_TIMEOUT_MS);
@@ -1717,7 +1871,7 @@ async function connectStream(config, callbacks) {
1717
1871
  if (vercelEnv) {
1718
1872
  headers["X-Vercel-Env"] = vercelEnv;
1719
1873
  }
1720
- const revision = _optionalChain([config, 'access', _64 => _64.revision, 'optionalCall', _65 => _65()]);
1874
+ const revision = _optionalChain([config, 'access', _86 => _86.revision, 'optionalCall', _87 => _87()]);
1721
1875
  if (revision !== void 0) {
1722
1876
  headers["X-Revision"] = String(revision);
1723
1877
  }
@@ -1779,7 +1933,7 @@ async function connectStream(config, callbacks) {
1779
1933
  resetPingTimeout();
1780
1934
  }
1781
1935
  if (message.type === "primed") {
1782
- _optionalChain([onPrimed, 'optionalCall', _66 => _66(message)]);
1936
+ _optionalChain([onPrimed, 'optionalCall', _88 => _88(message)]);
1783
1937
  retryCount = 0;
1784
1938
  if (!initialDataReceived) {
1785
1939
  initialDataReceived = true;
@@ -1802,7 +1956,7 @@ async function connectStream(config, callbacks) {
1802
1956
  clearTimeout(pingTimeoutId);
1803
1957
  abortController.signal.removeEventListener("abort", onMainAbort);
1804
1958
  if (!abortController.signal.aborted) {
1805
- _optionalChain([onDisconnect, 'optionalCall', _67 => _67()]);
1959
+ _optionalChain([onDisconnect, 'optionalCall', _89 => _89()]);
1806
1960
  retryCount++;
1807
1961
  const elapsed = Date.now() - lastAttemptTime;
1808
1962
  const minGap = Math.max(0, BASE_RETRY_DELAY_MS - elapsed);
@@ -1823,7 +1977,7 @@ async function connectStream(config, callbacks) {
1823
1977
  if (!connectionAbort.signal.aborted) {
1824
1978
  lastError = error;
1825
1979
  }
1826
- _optionalChain([onDisconnect, 'optionalCall', _68 => _68()]);
1980
+ _optionalChain([onDisconnect, 'optionalCall', _90 => _90()]);
1827
1981
  retryCount++;
1828
1982
  const elapsed = Date.now() - lastAttemptTime;
1829
1983
  const minGap = Math.max(0, BASE_RETRY_DELAY_MS - elapsed);
@@ -1854,7 +2008,11 @@ var StreamSource = class extends TypedEmitter {
1854
2008
  * If already started, returns the existing promise.
1855
2009
  */
1856
2010
  start() {
1857
- if (this.promise) return this.promise;
2011
+ if (this.promise) {
2012
+ debugLog("stream-source", "Reusing stream connection");
2013
+ return this.promise;
2014
+ }
2015
+ debugLog("stream-source", "Starting stream connection");
1858
2016
  const abortController = new AbortController();
1859
2017
  this.abortController = abortController;
1860
2018
  abortController.signal.addEventListener(
@@ -1878,21 +2036,41 @@ var StreamSource = class extends TypedEmitter {
1878
2036
  },
1879
2037
  {
1880
2038
  onDatafile: (newData) => {
2039
+ debugLog("stream-source", "Connected with datafile", {
2040
+ projectId: newData.projectId,
2041
+ configUpdatedAt: Number(newData.configUpdatedAt),
2042
+ revision: newData.revision
2043
+ });
1881
2044
  this.emit("data", newData);
1882
2045
  this.emit("connected");
1883
2046
  },
1884
2047
  onPrimed: (message) => {
2048
+ debugLog("stream-source", "Connected with current revision", {
2049
+ projectId: message.projectId,
2050
+ revision: message.revision
2051
+ });
1885
2052
  this.emit("primed", message);
1886
2053
  this.emit("connected");
1887
2054
  },
1888
2055
  onDisconnect: () => {
2056
+ debugLog("stream-source", "Disconnected", {
2057
+ aborted: abortController.signal.aborted
2058
+ });
1889
2059
  this.emit("disconnected");
1890
2060
  }
1891
2061
  }
1892
2062
  );
1893
- this.promise = promise;
1894
- return promise;
2063
+ this.promise = promise.catch((error) => {
2064
+ debugLog("stream-source", "Stream initialization failed", {
2065
+ aborted: abortController.signal.aborted
2066
+ });
2067
+ throw error;
2068
+ });
2069
+ return this.promise;
1895
2070
  } catch (error) {
2071
+ debugLog("stream-source", "Stream initialization failed", {
2072
+ aborted: abortController.signal.aborted
2073
+ });
1896
2074
  this.promise = void 0;
1897
2075
  this.abortController = void 0;
1898
2076
  throw error;
@@ -1902,29 +2080,15 @@ var StreamSource = class extends TypedEmitter {
1902
2080
  * Stop the stream connection.
1903
2081
  */
1904
2082
  stop() {
1905
- _optionalChain([this, 'access', _69 => _69.abortController, 'optionalAccess', _70 => _70.abort, 'call', _71 => _71()]);
2083
+ debugLog("stream-source", "Stopping stream connection", {
2084
+ active: this.abortController !== void 0
2085
+ });
2086
+ _optionalChain([this, 'access', _91 => _91.abortController, 'optionalAccess', _92 => _92.abort, 'call', _93 => _93()]);
1906
2087
  this.abortController = void 0;
1907
2088
  this.promise = void 0;
1908
2089
  }
1909
2090
  };
1910
2091
 
1911
- // src/controller/tagged-data.ts
1912
- function tagData(data, origin) {
1913
- return Object.assign(data, { _origin: origin });
1914
- }
1915
- function originToMetricsSource(origin) {
1916
- switch (origin) {
1917
- case "stream":
1918
- case "poll":
1919
- case "provided":
1920
- return "in-memory";
1921
- case "fetched":
1922
- return "remote";
1923
- case "bundled":
1924
- return "embedded";
1925
- }
1926
- }
1927
-
1928
2092
  // src/controller/index.ts
1929
2093
  function parseConfigUpdatedAt(value) {
1930
2094
  if (typeof value === "number") return value;
@@ -1949,6 +2113,7 @@ var Controller = (_class6 = class {
1949
2113
 
1950
2114
 
1951
2115
 
2116
+
1952
2117
  // Usage tracking
1953
2118
 
1954
2119
  __init15() {this.isFirstGetData = true}
@@ -1957,17 +2122,18 @@ var Controller = (_class6 = class {
1957
2122
  __init17() {this.buildReadTracked = false}
1958
2123
  // Suppresses usage tracking when the SDK key is unauthorized
1959
2124
  __init18() {this.unauthorized = false}
1960
- constructor(options) {;_class6.prototype.__init12.call(this);_class6.prototype.__init13.call(this);_class6.prototype.__init14.call(this);_class6.prototype.__init15.call(this);_class6.prototype.__init16.call(this);_class6.prototype.__init17.call(this);_class6.prototype.__init18.call(this);_class6.prototype.__init19.call(this);_class6.prototype.__init20.call(this);_class6.prototype.__init21.call(this);_class6.prototype.__init22.call(this);_class6.prototype.__init23.call(this);_class6.prototype.__init24.call(this);
2125
+ constructor(options) {;_class6.prototype.__init12.call(this);_class6.prototype.__init13.call(this);_class6.prototype.__init14.call(this);_class6.prototype.__init15.call(this);_class6.prototype.__init16.call(this);_class6.prototype.__init17.call(this);_class6.prototype.__init18.call(this);_class6.prototype.__init19.call(this);_class6.prototype.__init20.call(this);_class6.prototype.__init21.call(this);_class6.prototype.__init22.call(this);_class6.prototype.__init23.call(this);_class6.prototype.__init24.call(this);_class6.prototype.__init25.call(this);
1961
2126
  this.options = normalizeOptions(options);
1962
2127
  this.streamSource = new StreamSource(
1963
2128
  this.options,
1964
- () => _optionalChain([this, 'access', _72 => _72.data, 'optionalAccess', _73 => _73.revision])
2129
+ () => _optionalChain([this, 'access', _94 => _94.data, 'optionalAccess', _95 => _95.revision])
1965
2130
  );
1966
2131
  this.pollingSource = new PollingSource(this.options);
1967
2132
  this.bundledSource = new BundledSource({
1968
2133
  auth: this.options.auth,
1969
2134
  readBundledDefinitions
1970
2135
  });
2136
+ this.headerSource = new HeaderSource(this.options);
1971
2137
  this.wireSourceEvents();
1972
2138
  if (this.options.datafile) {
1973
2139
  this.data = tagData(this.options.datafile, "provided");
@@ -2003,6 +2169,11 @@ var Controller = (_class6 = class {
2003
2169
  __init24() {this.onPollError = (error) => {
2004
2170
  console.error("@vercel/flags-core: Poll failed:", error);
2005
2171
  }}
2172
+ __init25() {this.onFetchedData = (data) => {
2173
+ if (this.isNewerData(data)) {
2174
+ this.data = tagData(data, "fetched");
2175
+ }
2176
+ }}
2006
2177
  // ---------------------------------------------------------------------------
2007
2178
  // Source event wiring
2008
2179
  // ---------------------------------------------------------------------------
@@ -2013,6 +2184,7 @@ var Controller = (_class6 = class {
2013
2184
  this.streamSource.on("disconnected", this.onStreamDisconnected);
2014
2185
  this.pollingSource.on("data", this.onPollData);
2015
2186
  this.pollingSource.on("error", this.onPollError);
2187
+ this.headerSource.on("data", this.onFetchedData);
2016
2188
  }
2017
2189
  unwireSourceEvents() {
2018
2190
  this.streamSource.off("data", this.onStreamData);
@@ -2021,11 +2193,18 @@ var Controller = (_class6 = class {
2021
2193
  this.streamSource.off("disconnected", this.onStreamDisconnected);
2022
2194
  this.pollingSource.off("data", this.onPollData);
2023
2195
  this.pollingSource.off("error", this.onPollError);
2196
+ this.headerSource.off("data", this.onFetchedData);
2024
2197
  }
2025
2198
  // ---------------------------------------------------------------------------
2026
2199
  // State machine
2027
2200
  // ---------------------------------------------------------------------------
2028
2201
  transition(to) {
2202
+ debugLog("controller", "State changed", {
2203
+ from: this.state,
2204
+ to,
2205
+ projectId: _optionalChain([this, 'access', _96 => _96.data, 'optionalAccess', _97 => _97.projectId]),
2206
+ origin: _optionalChain([this, 'access', _98 => _98.data, 'optionalAccess', _99 => _99._origin])
2207
+ });
2029
2208
  this.state = to;
2030
2209
  }
2031
2210
  get isConnected() {
@@ -2038,6 +2217,8 @@ var Controller = (_class6 = class {
2038
2217
  return "streaming";
2039
2218
  case "polling":
2040
2219
  return "polling";
2220
+ case "vercel":
2221
+ return "vercel";
2041
2222
  default:
2042
2223
  return "offline";
2043
2224
  }
@@ -2054,6 +2235,14 @@ var Controller = (_class6 = class {
2054
2235
  * Offline mode (neither): datafile → bundled → one-time fetch
2055
2236
  */
2056
2237
  async initialize() {
2238
+ debugLog("controller", "Initializing", {
2239
+ buildStep: this.options.buildStep,
2240
+ streamEnabled: this.options.stream.enabled,
2241
+ pollingEnabled: this.options.polling.enabled,
2242
+ hasData: this.data !== void 0,
2243
+ projectId: _optionalChain([this, 'access', _100 => _100.data, 'optionalAccess', _101 => _101.projectId]),
2244
+ origin: _optionalChain([this, 'access', _102 => _102.data, 'optionalAccess', _103 => _103._origin])
2245
+ });
2057
2246
  if (this.options.buildStep) {
2058
2247
  this.transition("build:loading");
2059
2248
  await this.initializeForBuildStep();
@@ -2073,7 +2262,9 @@ var Controller = (_class6 = class {
2073
2262
  }
2074
2263
  }
2075
2264
  if (this.data) {
2076
- if (this.options.stream.enabled) {
2265
+ if (this.headerSource.isAvailable(this.data.projectId)) {
2266
+ this.transition("vercel");
2267
+ } else if (this.options.stream.enabled) {
2077
2268
  this.transition("initializing:stream");
2078
2269
  await this.tryInitializeStream();
2079
2270
  } else if (this.options.polling.enabled) {
@@ -2084,6 +2275,9 @@ var Controller = (_class6 = class {
2084
2275
  }
2085
2276
  return;
2086
2277
  }
2278
+ debugLog("controller", "Header mode unavailable", {
2279
+ reason: "no-definitions"
2280
+ });
2087
2281
  if (this.options.stream.enabled) {
2088
2282
  this.transition("initializing:stream");
2089
2283
  const streamSuccess = await this.tryInitializeStream();
@@ -2112,6 +2306,15 @@ var Controller = (_class6 = class {
2112
2306
  const [result, cacheStatus] = await this.resolveData();
2113
2307
  const readMs = Date.now() - startTime;
2114
2308
  const source = originToMetricsSource(result._origin);
2309
+ debugLog("controller", "Read resolved", {
2310
+ projectId: result.projectId,
2311
+ mode: this.mode,
2312
+ source,
2313
+ origin: result._origin,
2314
+ cacheStatus,
2315
+ configUpdatedAt: parseConfigUpdatedAt(result.configUpdatedAt),
2316
+ revision: result.revision
2317
+ });
2115
2318
  this.trackRead(startTime, cacheHadDefinitions, isFirstRead, source);
2116
2319
  if (this.dataViewSource !== result) {
2117
2320
  const { _origin, ...rest } = result;
@@ -2136,6 +2339,7 @@ var Controller = (_class6 = class {
2136
2339
  this.unwireSourceEvents();
2137
2340
  this.streamSource.stop();
2138
2341
  this.pollingSource.stop();
2342
+ this.headerSource.stop();
2139
2343
  this.data = this.options.datafile ? tagData(this.options.datafile, "provided") : void 0;
2140
2344
  this.transition("shutdown");
2141
2345
  await this.usageTracker.shutdown();
@@ -2179,6 +2383,15 @@ var Controller = (_class6 = class {
2179
2383
  }
2180
2384
  }
2181
2385
  const source = originToMetricsSource(result._origin);
2386
+ debugLog("controller", "Datafile resolved", {
2387
+ projectId: result.projectId,
2388
+ mode: this.mode,
2389
+ source,
2390
+ origin: result._origin,
2391
+ cacheStatus,
2392
+ configUpdatedAt: parseConfigUpdatedAt(result.configUpdatedAt),
2393
+ revision: result.revision
2394
+ });
2182
2395
  if (this.dataViewSource !== result) {
2183
2396
  const { _origin, ...rest } = result;
2184
2397
  this.dataViewBase = rest;
@@ -2217,6 +2430,12 @@ var Controller = (_class6 = class {
2217
2430
  return this.resolveDataForBuildStep();
2218
2431
  }
2219
2432
  if (this.data) {
2433
+ if (this.mode === "vercel") {
2434
+ const result = await this.headerSource.read(this.data);
2435
+ if (result) {
2436
+ return result;
2437
+ }
2438
+ }
2220
2439
  const cacheStatus = this.isConnected ? "HIT" : "STALE";
2221
2440
  return [this.data, cacheStatus];
2222
2441
  }
@@ -2255,6 +2474,14 @@ var Controller = (_class6 = class {
2255
2474
  ]);
2256
2475
  clearTimeout(timeoutId);
2257
2476
  if (result === "timeout") {
2477
+ debugLog(
2478
+ "controller",
2479
+ "Stream initialization timed out; using fallback",
2480
+ {
2481
+ timeoutMs: this.options.stream.initTimeoutMs,
2482
+ origin: _optionalChain([this, 'access', _104 => _104.data, 'optionalAccess', _105 => _105._origin])
2483
+ }
2484
+ );
2258
2485
  console.warn(
2259
2486
  "@vercel/flags-core: Stream initialization timeout, falling back while continuing to connect in the background"
2260
2487
  );
@@ -2503,11 +2730,11 @@ var Controller = (_class6 = class {
2503
2730
  duration: Date.now() - startTime,
2504
2731
  mode: mode === "streaming" ? "stream" : mode === "polling" ? "poll" : mode
2505
2732
  };
2506
- const configUpdatedAt = _optionalChain([this, 'access', _74 => _74.data, 'optionalAccess', _75 => _75.configUpdatedAt]);
2733
+ const configUpdatedAt = _optionalChain([this, 'access', _106 => _106.data, 'optionalAccess', _107 => _107.configUpdatedAt]);
2507
2734
  if (typeof configUpdatedAt === "number") {
2508
2735
  trackOptions.configUpdatedAt = configUpdatedAt;
2509
2736
  }
2510
- const revision = _optionalChain([this, 'access', _76 => _76.data, 'optionalAccess', _77 => _77.revision]);
2737
+ const revision = _optionalChain([this, 'access', _108 => _108.data, 'optionalAccess', _109 => _109.revision]);
2511
2738
  if (typeof revision === "number") {
2512
2739
  trackOptions.revision = revision;
2513
2740
  }
@@ -2673,4 +2900,4 @@ var {
2673
2900
 
2674
2901
 
2675
2902
  exports.ResolutionReason = ResolutionReason; exports.evaluate = evaluate; exports.FallbackNotFoundError = FallbackNotFoundError; exports.FallbackEntryNotFoundError = FallbackEntryNotFoundError; exports.Controller = Controller; exports.flagsClient = flagsClient; exports.resetDefaultFlagsClient = resetDefaultFlagsClient; exports.createClient = createClient;
2676
- //# sourceMappingURL=chunk-CVDAHZHK.cjs.map
2903
+ //# sourceMappingURL=chunk-OXUU7M2A.cjs.map