@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
|
@@ -558,7 +558,7 @@ function bulkEvaluate(flags, shared) {
|
|
|
558
558
|
}
|
|
559
559
|
|
|
560
560
|
// package.json
|
|
561
|
-
var version = "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',
|
|
1039
|
-
var
|
|
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
|
-
|
|
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',
|
|
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',
|
|
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',
|
|
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',
|
|
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',
|
|
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',
|
|
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',
|
|
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',
|
|
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',
|
|
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',
|
|
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',
|
|
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',
|
|
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',
|
|
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)
|
|
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
|
-
|
|
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
|
-
|
|
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',
|
|
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.
|
|
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',
|
|
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',
|
|
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-
|
|
2913
|
+
//# sourceMappingURL=chunk-ZUO5MVUD.cjs.map
|