@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.
@@ -558,7 +558,7 @@ function bulkEvaluate(flags, shared) {
558
558
  }
559
559
 
560
560
  // package.json
561
- var version = "1.8.1";
561
+ var version = "1.9.0-0fd2f41-20260915094243";
562
562
 
563
563
  // src/lib/report-value.ts
564
564
  function internalReportValue(key, value, data) {
@@ -956,6 +956,12 @@ function createCreateRawClient(fns) {
956
956
  };
957
957
  }
958
958
 
959
+ // src/utils/debug.ts
960
+ function debugLog(source, message, details = {}) {
961
+ if (!_optionalChain([process, 'access', _31 => _31.env, 'access', _32 => _32.DEBUG, 'optionalAccess', _33 => _33.includes, 'call', _34 => _34("@vercel/flags-core")])) return;
962
+ console.log(`@vercel/flags-core [${source}] ${message}`, details);
963
+ }
964
+
959
965
  // src/utils/read-bundled-definitions.ts
960
966
  var sdkKeyHashCache = /* @__PURE__ */ new Map();
961
967
  async function computeHash(sdkKey) {
@@ -1035,8 +1041,8 @@ var MAX_RETRIES = 3;
1035
1041
  var MAX_EVENTS_PER_REQUEST = 2e3;
1036
1042
  var EVALUATING_OIDC_TOKEN_HEADER = "X-Vercel-Flags-OIDC-Token";
1037
1043
  var FLUSH_REASON_HEADER = "X-Vercel-Flags-Flush-Reason";
1038
- var isDebugMode = _optionalChain([process, 'access', _31 => _31.env, 'access', _32 => _32.DEBUG, 'optionalAccess', _33 => _33.includes, 'call', _34 => _34("@vercel/flags-core")]);
1039
- var debugLog = (...args) => {
1044
+ var isDebugMode = _optionalChain([process, 'access', _35 => _35.env, 'access', _36 => _36.DEBUG, 'optionalAccess', _37 => _37.includes, 'call', _38 => _38("@vercel/flags-core")]);
1045
+ var debugLog2 = (...args) => {
1040
1046
  if (!isDebugMode) return;
1041
1047
  console.log(...args);
1042
1048
  };
@@ -1082,7 +1088,7 @@ async function sendIngestChunk(options, eventsToSend, flushId, flushReason) {
1082
1088
  headers: await getIngestHeaders(options, flushReason),
1083
1089
  body: JSON.stringify(eventsToSend)
1084
1090
  });
1085
- debugLog(
1091
+ debugLog2(
1086
1092
  `@vercel/flags-core: Ingest response ${response.status} for ${eventsToSend.length} events on ${response.headers.get("x-vercel-id")}`
1087
1093
  );
1088
1094
  if (response.ok) {
@@ -1114,7 +1120,7 @@ var SYMBOL_FOR_REQ_CONTEXT = /* @__PURE__ */ Symbol.for("@vercel/request-context
1114
1120
  var fromSymbol = globalThis;
1115
1121
  function getRequestContext() {
1116
1122
  try {
1117
- const ctx = _optionalChain([fromSymbol, 'access', _35 => _35[SYMBOL_FOR_REQ_CONTEXT], 'optionalAccess', _36 => _36.get, 'optionalCall', _37 => _37()]);
1123
+ const ctx = _optionalChain([fromSymbol, 'access', _39 => _39[SYMBOL_FOR_REQ_CONTEXT], 'optionalAccess', _40 => _40.get, 'optionalCall', _41 => _41()]);
1118
1124
  if (ctx && Object.hasOwn(ctx, "headers")) {
1119
1125
  return {
1120
1126
  ctx,
@@ -1179,7 +1185,7 @@ var Scheduler = (_class = class {
1179
1185
  }
1180
1186
  resolveScheduledFlush(reason) {
1181
1187
  this.clearTimeouts();
1182
- _optionalChain([this, 'access', _38 => _38.resolveWait, 'optionalCall', _39 => _39(reason)]);
1188
+ _optionalChain([this, 'access', _42 => _42.resolveWait, 'optionalCall', _43 => _43(reason)]);
1183
1189
  }
1184
1190
  reset() {
1185
1191
  this.pending = null;
@@ -1427,7 +1433,7 @@ var BundledSource = class {
1427
1433
  */
1428
1434
  async tryLoad() {
1429
1435
  const result = await this.getResult();
1430
- if (_optionalChain([result, 'optionalAccess', _40 => _40.state]) === "ok" && result.definitions) {
1436
+ if (_optionalChain([result, 'optionalAccess', _44 => _44.state]) === "ok" && result.definitions) {
1431
1437
  return result.definitions;
1432
1438
  }
1433
1439
  return void 0;
@@ -1467,18 +1473,190 @@ async function fetchDatafile(options) {
1467
1473
  signal: controller.signal
1468
1474
  });
1469
1475
  clearTimeout(timeoutId);
1470
- _optionalChain([options, 'access', _41 => _41.signal, 'optionalAccess', _42 => _42.removeEventListener, 'call', _43 => _43("abort", onExternalAbort)]);
1476
+ _optionalChain([options, 'access', _45 => _45.signal, 'optionalAccess', _46 => _46.removeEventListener, 'call', _47 => _47("abort", onExternalAbort)]);
1471
1477
  if (!res.ok) {
1472
1478
  throw new Error(`Failed to fetch data: ${res.statusText}`);
1473
1479
  }
1474
1480
  return res.json();
1475
1481
  } catch (error) {
1476
1482
  clearTimeout(timeoutId);
1477
- _optionalChain([options, 'access', _44 => _44.signal, 'optionalAccess', _45 => _45.removeEventListener, 'call', _46 => _46("abort", onExternalAbort)]);
1483
+ _optionalChain([options, 'access', _48 => _48.signal, 'optionalAccess', _49 => _49.removeEventListener, 'call', _50 => _50("abort", onExternalAbort)]);
1478
1484
  throw error instanceof Error ? error : new Error("Unknown fetch error");
1479
1485
  }
1480
1486
  }
1481
1487
 
1488
+ // src/controller/header-source.ts
1489
+
1490
+
1491
+ // src/controller/tagged-data.ts
1492
+ function tagData(data, origin) {
1493
+ return Object.assign(data, { _origin: origin });
1494
+ }
1495
+ function originToMetricsSource(origin) {
1496
+ switch (origin) {
1497
+ case "stream":
1498
+ case "poll":
1499
+ case "provided":
1500
+ return "in-memory";
1501
+ case "fetched":
1502
+ return "remote";
1503
+ case "bundled":
1504
+ return "embedded";
1505
+ }
1506
+ }
1507
+
1508
+ // src/controller/typed-emitter.ts
1509
+ var TypedEmitter = (_class5 = class {constructor() { _class5.prototype.__init11.call(this); }
1510
+ __init11() {this.handlers = /* @__PURE__ */ new Map()}
1511
+ on(event, handler) {
1512
+ let set = this.handlers.get(event);
1513
+ if (!set) {
1514
+ set = /* @__PURE__ */ new Set();
1515
+ this.handlers.set(event, set);
1516
+ }
1517
+ set.add(handler);
1518
+ }
1519
+ off(event, handler) {
1520
+ _optionalChain([this, 'access', _51 => _51.handlers, 'access', _52 => _52.get, 'call', _53 => _53(event), 'optionalAccess', _54 => _54.delete, 'call', _55 => _55(handler)]);
1521
+ }
1522
+ emit(event, ...args) {
1523
+ const set = this.handlers.get(event);
1524
+ if (set) {
1525
+ for (const handler of set) {
1526
+ handler(...args);
1527
+ }
1528
+ }
1529
+ }
1530
+ }, _class5);
1531
+
1532
+ // src/controller/header-source.ts
1533
+ var HeaderSource = class extends TypedEmitter {
1534
+
1535
+
1536
+
1537
+ constructor(options) {
1538
+ super();
1539
+ this.options = options;
1540
+ }
1541
+ fetchDatafile() {
1542
+ if (this.promise) {
1543
+ debugLog("header-source", "Reusing pending refresh");
1544
+ return this.promise;
1545
+ }
1546
+ debugLog("header-source", "Starting refresh");
1547
+ const abortController = new AbortController();
1548
+ this.abortController = abortController;
1549
+ this.promise = fetchDatafile({
1550
+ ...this.options,
1551
+ signal: abortController.signal
1552
+ }).then((data) => {
1553
+ abortController.signal.throwIfAborted();
1554
+ debugLog("header-source", "Refresh completed", {
1555
+ projectId: data.projectId,
1556
+ configUpdatedAt: Number(data.configUpdatedAt),
1557
+ revision: data.revision
1558
+ });
1559
+ this.emit("data", data);
1560
+ return data;
1561
+ }).catch((error) => {
1562
+ debugLog("header-source", "Refresh failed", {
1563
+ aborted: abortController.signal.aborted
1564
+ });
1565
+ throw error;
1566
+ }).finally(() => {
1567
+ if (this.abortController === abortController) {
1568
+ this.promise = void 0;
1569
+ this.abortController = void 0;
1570
+ }
1571
+ });
1572
+ return this.promise;
1573
+ }
1574
+ getUpdatedAtHeader(projectId) {
1575
+ const ctx = getRequestContext();
1576
+ 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";
1577
+ const header = _optionalChain([ctx, 'access', _58 => _58.headers, 'optionalAccess', _59 => _59[headerName]]);
1578
+ if (!header) {
1579
+ debugLog("header-source", "Header unavailable", {
1580
+ projectId,
1581
+ reason: "missing-header"
1582
+ });
1583
+ return;
1584
+ }
1585
+ const prefix = `flags_${projectId}=`;
1586
+ 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)]);
1587
+ const timestamp = Number(value);
1588
+ if (!Number.isFinite(timestamp) || timestamp <= 0) {
1589
+ debugLog("header-source", "Header unavailable", {
1590
+ projectId,
1591
+ headerName,
1592
+ reason: value === void 0 ? "project-not-found" : "invalid-timestamp"
1593
+ });
1594
+ return;
1595
+ }
1596
+ debugLog("header-source", "Header version available", {
1597
+ projectId,
1598
+ headerName,
1599
+ timestamp
1600
+ });
1601
+ return timestamp;
1602
+ }
1603
+ async resolveData(currentData) {
1604
+ if (!currentData.configUpdatedAt) {
1605
+ debugLog("header-source", "Skipping header refresh", {
1606
+ projectId: currentData.projectId,
1607
+ reason: "missing-data-timestamp"
1608
+ });
1609
+ return;
1610
+ }
1611
+ const updatedAtHeader = this.getUpdatedAtHeader(currentData.projectId);
1612
+ if (!updatedAtHeader) {
1613
+ return;
1614
+ }
1615
+ const currentUpdatedAt = Number(currentData.configUpdatedAt);
1616
+ const deltaMs = updatedAtHeader - currentUpdatedAt;
1617
+ debugLog("header-source", "Freshness decision", {
1618
+ projectId: currentData.projectId,
1619
+ currentUpdatedAt,
1620
+ headerUpdatedAt: updatedAtHeader,
1621
+ deltaMs,
1622
+ action: updatedAtHeader <= currentUpdatedAt ? "serve-cached" : updatedAtHeader <= currentUpdatedAt + 1e4 ? "background-refresh" : "blocking-refresh"
1623
+ });
1624
+ if (updatedAtHeader <= currentUpdatedAt) {
1625
+ return [currentData, "HIT"];
1626
+ }
1627
+ if (updatedAtHeader <= currentUpdatedAt + 1e4) {
1628
+ const pending = this.fetchDatafile();
1629
+ const signal = _optionalChain([this, 'access', _68 => _68.abortController, 'optionalAccess', _69 => _69.signal]);
1630
+ const background = pending.catch((error) => {
1631
+ if (!_optionalChain([signal, 'optionalAccess', _70 => _70.aborted])) {
1632
+ console.error("@vercel/flags-core: Header refresh failed:", error);
1633
+ }
1634
+ });
1635
+ _functions.waitUntil.call(void 0, background);
1636
+ return [currentData, "STALE"];
1637
+ }
1638
+ const data = await this.fetchDatafile();
1639
+ return [tagData(data, "fetched"), "MISS"];
1640
+ }
1641
+ read(currentData) {
1642
+ return this.resolveData(currentData);
1643
+ }
1644
+ isAvailable(projectId) {
1645
+ return !!this.getUpdatedAtHeader(projectId);
1646
+ }
1647
+ /**
1648
+ * Abort the current header-driven fetch and discard its pending work.
1649
+ */
1650
+ stop() {
1651
+ debugLog("header-source", "Stopping header refresh", {
1652
+ pending: this.promise !== void 0
1653
+ });
1654
+ _optionalChain([this, 'access', _71 => _71.abortController, 'optionalAccess', _72 => _72.abort, 'call', _73 => _73()]);
1655
+ this.abortController = void 0;
1656
+ this.promise = void 0;
1657
+ }
1658
+ };
1659
+
1482
1660
  // src/controller/normalized-options.ts
1483
1661
  var DEFAULT_STREAM_INIT_TIMEOUT_MS = 3e3;
1484
1662
  var DEFAULT_POLLING_INTERVAL_MS = 3e4;
@@ -1530,30 +1708,6 @@ function normalizeOptions(options) {
1530
1708
  };
1531
1709
  }
1532
1710
 
1533
- // src/controller/typed-emitter.ts
1534
- var TypedEmitter = (_class5 = class {constructor() { _class5.prototype.__init11.call(this); }
1535
- __init11() {this.handlers = /* @__PURE__ */ new Map()}
1536
- on(event, handler) {
1537
- let set = this.handlers.get(event);
1538
- if (!set) {
1539
- set = /* @__PURE__ */ new Set();
1540
- this.handlers.set(event, set);
1541
- }
1542
- set.add(handler);
1543
- }
1544
- off(event, handler) {
1545
- _optionalChain([this, 'access', _47 => _47.handlers, 'access', _48 => _48.get, 'call', _49 => _49(event), 'optionalAccess', _50 => _50.delete, 'call', _51 => _51(handler)]);
1546
- }
1547
- emit(event, ...args) {
1548
- const set = this.handlers.get(event);
1549
- if (set) {
1550
- for (const handler of set) {
1551
- handler(...args);
1552
- }
1553
- }
1554
- }
1555
- }, _class5);
1556
-
1557
1711
  // src/controller/polling-source.ts
1558
1712
  var PollingSource = class extends TypedEmitter {
1559
1713
 
@@ -1568,11 +1722,11 @@ var PollingSource = class extends TypedEmitter {
1568
1722
  * Emits 'data' on success, 'error' on failure.
1569
1723
  */
1570
1724
  async poll() {
1571
- if (_optionalChain([this, 'access', _52 => _52.abortController, 'optionalAccess', _53 => _53.signal, 'access', _54 => _54.aborted])) return;
1725
+ if (_optionalChain([this, 'access', _74 => _74.abortController, 'optionalAccess', _75 => _75.signal, 'access', _76 => _76.aborted])) return;
1572
1726
  try {
1573
1727
  const data = await fetchDatafile({
1574
1728
  ...this.config,
1575
- signal: _optionalChain([this, 'access', _55 => _55.abortController, 'optionalAccess', _56 => _56.signal])
1729
+ signal: _optionalChain([this, 'access', _77 => _77.abortController, 'optionalAccess', _78 => _78.signal])
1576
1730
  });
1577
1731
  this.emit("data", data);
1578
1732
  } catch (error) {
@@ -1601,7 +1755,7 @@ var PollingSource = class extends TypedEmitter {
1601
1755
  clearInterval(this.intervalId);
1602
1756
  this.intervalId = void 0;
1603
1757
  }
1604
- _optionalChain([this, 'access', _57 => _57.abortController, 'optionalAccess', _58 => _58.abort, 'call', _59 => _59()]);
1758
+ _optionalChain([this, 'access', _79 => _79.abortController, 'optionalAccess', _80 => _80.abort, 'call', _81 => _81()]);
1605
1759
  this.abortController = void 0;
1606
1760
  }
1607
1761
  };
@@ -1680,7 +1834,7 @@ async function connectStream(config, callbacks) {
1680
1834
  if (pingTimeoutId !== void 0) clearTimeout(pingTimeoutId);
1681
1835
  if (!initialDataReceived) return;
1682
1836
  pingTimeoutId = setTimeout(() => {
1683
- _optionalChain([responseBody, 'optionalAccess', _60 => _60.cancel, 'call', _61 => _61(), 'access', _62 => _62.catch, 'call', _63 => _63(() => {
1837
+ _optionalChain([responseBody, 'optionalAccess', _82 => _82.cancel, 'call', _83 => _83(), 'access', _84 => _84.catch, 'call', _85 => _85(() => {
1684
1838
  })]);
1685
1839
  connectionAbort.abort();
1686
1840
  }, PING_TIMEOUT_MS);
@@ -1702,7 +1856,7 @@ async function connectStream(config, callbacks) {
1702
1856
  if (vercelEnv) {
1703
1857
  headers["X-Vercel-Env"] = vercelEnv;
1704
1858
  }
1705
- const revision = _optionalChain([config, 'access', _64 => _64.revision, 'optionalCall', _65 => _65()]);
1859
+ const revision = _optionalChain([config, 'access', _86 => _86.revision, 'optionalCall', _87 => _87()]);
1706
1860
  if (revision !== void 0) {
1707
1861
  headers["X-Revision"] = String(revision);
1708
1862
  }
@@ -1764,7 +1918,7 @@ async function connectStream(config, callbacks) {
1764
1918
  resetPingTimeout();
1765
1919
  }
1766
1920
  if (message.type === "primed") {
1767
- _optionalChain([onPrimed, 'optionalCall', _66 => _66(message)]);
1921
+ _optionalChain([onPrimed, 'optionalCall', _88 => _88(message)]);
1768
1922
  retryCount = 0;
1769
1923
  if (!initialDataReceived) {
1770
1924
  initialDataReceived = true;
@@ -1787,7 +1941,7 @@ async function connectStream(config, callbacks) {
1787
1941
  clearTimeout(pingTimeoutId);
1788
1942
  abortController.signal.removeEventListener("abort", onMainAbort);
1789
1943
  if (!abortController.signal.aborted) {
1790
- _optionalChain([onDisconnect, 'optionalCall', _67 => _67()]);
1944
+ _optionalChain([onDisconnect, 'optionalCall', _89 => _89()]);
1791
1945
  retryCount++;
1792
1946
  const elapsed = Date.now() - lastAttemptTime;
1793
1947
  const minGap = Math.max(0, BASE_RETRY_DELAY_MS - elapsed);
@@ -1808,7 +1962,7 @@ async function connectStream(config, callbacks) {
1808
1962
  if (!connectionAbort.signal.aborted) {
1809
1963
  lastError = error;
1810
1964
  }
1811
- _optionalChain([onDisconnect, 'optionalCall', _68 => _68()]);
1965
+ _optionalChain([onDisconnect, 'optionalCall', _90 => _90()]);
1812
1966
  retryCount++;
1813
1967
  const elapsed = Date.now() - lastAttemptTime;
1814
1968
  const minGap = Math.max(0, BASE_RETRY_DELAY_MS - elapsed);
@@ -1839,7 +1993,11 @@ var StreamSource = class extends TypedEmitter {
1839
1993
  * If already started, returns the existing promise.
1840
1994
  */
1841
1995
  start() {
1842
- if (this.promise) return this.promise;
1996
+ if (this.promise) {
1997
+ debugLog("stream-source", "Reusing stream connection");
1998
+ return this.promise;
1999
+ }
2000
+ debugLog("stream-source", "Starting stream connection");
1843
2001
  const abortController = new AbortController();
1844
2002
  this.abortController = abortController;
1845
2003
  abortController.signal.addEventListener(
@@ -1863,21 +2021,41 @@ var StreamSource = class extends TypedEmitter {
1863
2021
  },
1864
2022
  {
1865
2023
  onDatafile: (newData) => {
2024
+ debugLog("stream-source", "Connected with datafile", {
2025
+ projectId: newData.projectId,
2026
+ configUpdatedAt: Number(newData.configUpdatedAt),
2027
+ revision: newData.revision
2028
+ });
1866
2029
  this.emit("data", newData);
1867
2030
  this.emit("connected");
1868
2031
  },
1869
2032
  onPrimed: (message) => {
2033
+ debugLog("stream-source", "Connected with current revision", {
2034
+ projectId: message.projectId,
2035
+ revision: message.revision
2036
+ });
1870
2037
  this.emit("primed", message);
1871
2038
  this.emit("connected");
1872
2039
  },
1873
2040
  onDisconnect: () => {
2041
+ debugLog("stream-source", "Disconnected", {
2042
+ aborted: abortController.signal.aborted
2043
+ });
1874
2044
  this.emit("disconnected");
1875
2045
  }
1876
2046
  }
1877
2047
  );
1878
- this.promise = promise;
1879
- return promise;
2048
+ this.promise = promise.catch((error) => {
2049
+ debugLog("stream-source", "Stream initialization failed", {
2050
+ aborted: abortController.signal.aborted
2051
+ });
2052
+ throw error;
2053
+ });
2054
+ return this.promise;
1880
2055
  } catch (error) {
2056
+ debugLog("stream-source", "Stream initialization failed", {
2057
+ aborted: abortController.signal.aborted
2058
+ });
1881
2059
  this.promise = void 0;
1882
2060
  this.abortController = void 0;
1883
2061
  throw error;
@@ -1887,29 +2065,15 @@ var StreamSource = class extends TypedEmitter {
1887
2065
  * Stop the stream connection.
1888
2066
  */
1889
2067
  stop() {
1890
- _optionalChain([this, 'access', _69 => _69.abortController, 'optionalAccess', _70 => _70.abort, 'call', _71 => _71()]);
2068
+ debugLog("stream-source", "Stopping stream connection", {
2069
+ active: this.abortController !== void 0
2070
+ });
2071
+ _optionalChain([this, 'access', _91 => _91.abortController, 'optionalAccess', _92 => _92.abort, 'call', _93 => _93()]);
1891
2072
  this.abortController = void 0;
1892
2073
  this.promise = void 0;
1893
2074
  }
1894
2075
  };
1895
2076
 
1896
- // src/controller/tagged-data.ts
1897
- function tagData(data, origin) {
1898
- return Object.assign(data, { _origin: origin });
1899
- }
1900
- function originToMetricsSource(origin) {
1901
- switch (origin) {
1902
- case "stream":
1903
- case "poll":
1904
- case "provided":
1905
- return "in-memory";
1906
- case "fetched":
1907
- return "remote";
1908
- case "bundled":
1909
- return "embedded";
1910
- }
1911
- }
1912
-
1913
2077
  // src/controller/index.ts
1914
2078
  function parseConfigUpdatedAt(value) {
1915
2079
  if (typeof value === "number") return value;
@@ -1934,6 +2098,7 @@ var Controller = (_class6 = class {
1934
2098
 
1935
2099
 
1936
2100
 
2101
+
1937
2102
  // Usage tracking
1938
2103
 
1939
2104
  __init15() {this.isFirstGetData = true}
@@ -1942,17 +2107,18 @@ var Controller = (_class6 = class {
1942
2107
  __init17() {this.buildReadTracked = false}
1943
2108
  // Suppresses usage tracking when the SDK key is unauthorized
1944
2109
  __init18() {this.unauthorized = false}
1945
- 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);
2110
+ 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);
1946
2111
  this.options = normalizeOptions(options);
1947
2112
  this.streamSource = new StreamSource(
1948
2113
  this.options,
1949
- () => _optionalChain([this, 'access', _72 => _72.data, 'optionalAccess', _73 => _73.revision])
2114
+ () => _optionalChain([this, 'access', _94 => _94.data, 'optionalAccess', _95 => _95.revision])
1950
2115
  );
1951
2116
  this.pollingSource = new PollingSource(this.options);
1952
2117
  this.bundledSource = new BundledSource({
1953
2118
  auth: this.options.auth,
1954
2119
  readBundledDefinitions
1955
2120
  });
2121
+ this.headerSource = new HeaderSource(this.options);
1956
2122
  this.wireSourceEvents();
1957
2123
  if (this.options.datafile) {
1958
2124
  this.data = tagData(this.options.datafile, "provided");
@@ -1988,6 +2154,11 @@ var Controller = (_class6 = class {
1988
2154
  __init24() {this.onPollError = (error) => {
1989
2155
  console.error("@vercel/flags-core: Poll failed:", error);
1990
2156
  }}
2157
+ __init25() {this.onFetchedData = (data) => {
2158
+ if (this.isNewerData(data)) {
2159
+ this.data = tagData(data, "fetched");
2160
+ }
2161
+ }}
1991
2162
  // ---------------------------------------------------------------------------
1992
2163
  // Source event wiring
1993
2164
  // ---------------------------------------------------------------------------
@@ -1998,6 +2169,7 @@ var Controller = (_class6 = class {
1998
2169
  this.streamSource.on("disconnected", this.onStreamDisconnected);
1999
2170
  this.pollingSource.on("data", this.onPollData);
2000
2171
  this.pollingSource.on("error", this.onPollError);
2172
+ this.headerSource.on("data", this.onFetchedData);
2001
2173
  }
2002
2174
  unwireSourceEvents() {
2003
2175
  this.streamSource.off("data", this.onStreamData);
@@ -2006,11 +2178,18 @@ var Controller = (_class6 = class {
2006
2178
  this.streamSource.off("disconnected", this.onStreamDisconnected);
2007
2179
  this.pollingSource.off("data", this.onPollData);
2008
2180
  this.pollingSource.off("error", this.onPollError);
2181
+ this.headerSource.off("data", this.onFetchedData);
2009
2182
  }
2010
2183
  // ---------------------------------------------------------------------------
2011
2184
  // State machine
2012
2185
  // ---------------------------------------------------------------------------
2013
2186
  transition(to) {
2187
+ debugLog("controller", "State changed", {
2188
+ from: this.state,
2189
+ to,
2190
+ projectId: _optionalChain([this, 'access', _96 => _96.data, 'optionalAccess', _97 => _97.projectId]),
2191
+ origin: _optionalChain([this, 'access', _98 => _98.data, 'optionalAccess', _99 => _99._origin])
2192
+ });
2014
2193
  this.state = to;
2015
2194
  }
2016
2195
  get isConnected() {
@@ -2023,6 +2202,8 @@ var Controller = (_class6 = class {
2023
2202
  return "streaming";
2024
2203
  case "polling":
2025
2204
  return "polling";
2205
+ case "vercel":
2206
+ return "vercel";
2026
2207
  default:
2027
2208
  return "offline";
2028
2209
  }
@@ -2039,6 +2220,14 @@ var Controller = (_class6 = class {
2039
2220
  * Offline mode (neither): datafile → bundled → one-time fetch
2040
2221
  */
2041
2222
  async initialize() {
2223
+ debugLog("controller", "Initializing", {
2224
+ buildStep: this.options.buildStep,
2225
+ streamEnabled: this.options.stream.enabled,
2226
+ pollingEnabled: this.options.polling.enabled,
2227
+ hasData: this.data !== void 0,
2228
+ projectId: _optionalChain([this, 'access', _100 => _100.data, 'optionalAccess', _101 => _101.projectId]),
2229
+ origin: _optionalChain([this, 'access', _102 => _102.data, 'optionalAccess', _103 => _103._origin])
2230
+ });
2042
2231
  if (this.options.buildStep) {
2043
2232
  this.transition("build:loading");
2044
2233
  await this.initializeForBuildStep();
@@ -2058,7 +2247,9 @@ var Controller = (_class6 = class {
2058
2247
  }
2059
2248
  }
2060
2249
  if (this.data) {
2061
- if (this.options.stream.enabled) {
2250
+ if (this.headerSource.isAvailable(this.data.projectId)) {
2251
+ this.transition("vercel");
2252
+ } else if (this.options.stream.enabled) {
2062
2253
  this.transition("initializing:stream");
2063
2254
  await this.tryInitializeStream();
2064
2255
  } else if (this.options.polling.enabled) {
@@ -2069,6 +2260,9 @@ var Controller = (_class6 = class {
2069
2260
  }
2070
2261
  return;
2071
2262
  }
2263
+ debugLog("controller", "Header mode unavailable", {
2264
+ reason: "no-definitions"
2265
+ });
2072
2266
  if (this.options.stream.enabled) {
2073
2267
  this.transition("initializing:stream");
2074
2268
  const streamSuccess = await this.tryInitializeStream();
@@ -2097,6 +2291,15 @@ var Controller = (_class6 = class {
2097
2291
  const [result, cacheStatus] = await this.resolveData();
2098
2292
  const readMs = Date.now() - startTime;
2099
2293
  const source = originToMetricsSource(result._origin);
2294
+ debugLog("controller", "Read resolved", {
2295
+ projectId: result.projectId,
2296
+ mode: this.mode,
2297
+ source,
2298
+ origin: result._origin,
2299
+ cacheStatus,
2300
+ configUpdatedAt: parseConfigUpdatedAt(result.configUpdatedAt),
2301
+ revision: result.revision
2302
+ });
2100
2303
  this.trackRead(startTime, cacheHadDefinitions, isFirstRead, source);
2101
2304
  if (this.dataViewSource !== result) {
2102
2305
  const { _origin, ...rest } = result;
@@ -2121,6 +2324,7 @@ var Controller = (_class6 = class {
2121
2324
  this.unwireSourceEvents();
2122
2325
  this.streamSource.stop();
2123
2326
  this.pollingSource.stop();
2327
+ this.headerSource.stop();
2124
2328
  this.data = this.options.datafile ? tagData(this.options.datafile, "provided") : void 0;
2125
2329
  this.transition("shutdown");
2126
2330
  await this.usageTracker.shutdown();
@@ -2164,6 +2368,15 @@ var Controller = (_class6 = class {
2164
2368
  }
2165
2369
  }
2166
2370
  const source = originToMetricsSource(result._origin);
2371
+ debugLog("controller", "Datafile resolved", {
2372
+ projectId: result.projectId,
2373
+ mode: this.mode,
2374
+ source,
2375
+ origin: result._origin,
2376
+ cacheStatus,
2377
+ configUpdatedAt: parseConfigUpdatedAt(result.configUpdatedAt),
2378
+ revision: result.revision
2379
+ });
2167
2380
  if (this.dataViewSource !== result) {
2168
2381
  const { _origin, ...rest } = result;
2169
2382
  this.dataViewBase = rest;
@@ -2202,6 +2415,12 @@ var Controller = (_class6 = class {
2202
2415
  return this.resolveDataForBuildStep();
2203
2416
  }
2204
2417
  if (this.data) {
2418
+ if (this.mode === "vercel") {
2419
+ const result = await this.headerSource.read(this.data);
2420
+ if (result) {
2421
+ return result;
2422
+ }
2423
+ }
2205
2424
  const cacheStatus = this.isConnected ? "HIT" : "STALE";
2206
2425
  return [this.data, cacheStatus];
2207
2426
  }
@@ -2240,6 +2459,14 @@ var Controller = (_class6 = class {
2240
2459
  ]);
2241
2460
  clearTimeout(timeoutId);
2242
2461
  if (result === "timeout") {
2462
+ debugLog(
2463
+ "controller",
2464
+ "Stream initialization timed out; using fallback",
2465
+ {
2466
+ timeoutMs: this.options.stream.initTimeoutMs,
2467
+ origin: _optionalChain([this, 'access', _104 => _104.data, 'optionalAccess', _105 => _105._origin])
2468
+ }
2469
+ );
2243
2470
  console.warn(
2244
2471
  "@vercel/flags-core: Stream initialization timeout, falling back while continuing to connect in the background"
2245
2472
  );
@@ -2488,11 +2715,11 @@ var Controller = (_class6 = class {
2488
2715
  duration: Date.now() - startTime,
2489
2716
  mode: mode === "streaming" ? "stream" : mode === "polling" ? "poll" : mode
2490
2717
  };
2491
- const configUpdatedAt = _optionalChain([this, 'access', _74 => _74.data, 'optionalAccess', _75 => _75.configUpdatedAt]);
2718
+ const configUpdatedAt = _optionalChain([this, 'access', _106 => _106.data, 'optionalAccess', _107 => _107.configUpdatedAt]);
2492
2719
  if (typeof configUpdatedAt === "number") {
2493
2720
  trackOptions.configUpdatedAt = configUpdatedAt;
2494
2721
  }
2495
- const revision = _optionalChain([this, 'access', _76 => _76.data, 'optionalAccess', _77 => _77.revision]);
2722
+ const revision = _optionalChain([this, 'access', _108 => _108.data, 'optionalAccess', _109 => _109.revision]);
2496
2723
  if (typeof revision === "number") {
2497
2724
  trackOptions.revision = revision;
2498
2725
  }
@@ -2683,4 +2910,4 @@ var { flagsClient, resetDefaultFlagsClient, createClient } = make(
2683
2910
 
2684
2911
 
2685
2912
  exports.ResolutionReason = ResolutionReason; exports.evaluate = evaluate; exports.FallbackNotFoundError = FallbackNotFoundError; exports.FallbackEntryNotFoundError = FallbackEntryNotFoundError; exports.Controller = Controller; exports.flagsClient = flagsClient; exports.resetDefaultFlagsClient = resetDefaultFlagsClient; exports.createClient = createClient;
2686
- //# sourceMappingURL=chunk-CKL562EU.cjs.map
2913
+ //# sourceMappingURL=chunk-ZUO5MVUD.cjs.map