@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.
- package/CHANGELOG.md +8 -0
- package/README.md +50 -5
- package/dist/{chunk-5BWCBI7I.js → chunk-FEALIMCH.js} +276 -49
- package/dist/chunk-FEALIMCH.js.map +1 -0
- package/dist/{chunk-CVDAHZHK.cjs → chunk-OXUU7M2A.cjs} +295 -68
- package/dist/chunk-OXUU7M2A.cjs.map +1 -0
- package/dist/{chunk-DYSF37WV.js → chunk-XFCAUSUZ.js} +276 -49
- package/dist/chunk-XFCAUSUZ.js.map +1 -0
- package/dist/{chunk-CKL562EU.cjs → chunk-ZUO5MVUD.cjs} +295 -68
- package/dist/chunk-ZUO5MVUD.cjs.map +1 -0
- package/dist/index.default.cjs +2 -2
- package/dist/index.default.d.cts +9 -2
- package/dist/index.default.d.ts +9 -2
- package/dist/index.default.js +1 -1
- package/dist/index.next-js.cjs +2 -2
- package/dist/index.next-js.d.cts +9 -2
- package/dist/index.next-js.d.ts +9 -2
- package/dist/index.next-js.js +1 -1
- package/dist/openfeature.default.cjs +2 -2
- package/dist/openfeature.default.d.cts +1 -1
- package/dist/openfeature.default.d.ts +1 -1
- package/dist/openfeature.default.js +1 -1
- package/dist/openfeature.next-js.cjs +2 -2
- package/dist/openfeature.next-js.d.cts +1 -1
- package/dist/openfeature.next-js.d.ts +1 -1
- package/dist/openfeature.next-js.js +1 -1
- package/dist/{types-CIONStRG.d.cts → types-w8u8i22D.d.cts} +15 -5
- package/dist/{types-CIONStRG.d.ts → types-w8u8i22D.d.ts} +15 -5
- package/package.json +1 -1
- package/dist/chunk-5BWCBI7I.js.map +0 -1
- package/dist/chunk-CKL562EU.cjs.map +0 -1
- package/dist/chunk-CVDAHZHK.cjs.map +0 -1
- package/dist/chunk-DYSF37WV.js.map +0 -1
|
@@ -573,7 +573,7 @@ function bulkEvaluate(flags, shared) {
|
|
|
573
573
|
}
|
|
574
574
|
|
|
575
575
|
// package.json
|
|
576
|
-
var version = "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',
|
|
1054
|
-
var
|
|
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
|
-
|
|
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',
|
|
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',
|
|
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',
|
|
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',
|
|
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',
|
|
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',
|
|
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',
|
|
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',
|
|
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',
|
|
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',
|
|
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',
|
|
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',
|
|
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',
|
|
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)
|
|
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
|
-
|
|
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
|
-
|
|
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',
|
|
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.
|
|
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',
|
|
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',
|
|
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-
|
|
2903
|
+
//# sourceMappingURL=chunk-OXUU7M2A.cjs.map
|