@vercel/flags-core 1.8.2-d31aae4-20260916165712 → 1.8.3
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 +10 -2
- package/dist/{chunk-3GJDKSPG.js → chunk-NPKDNJX6.js} +73 -24
- package/dist/chunk-NPKDNJX6.js.map +1 -0
- package/dist/{chunk-2WO37TKH.cjs → chunk-UX43BKE3.cjs} +86 -37
- package/dist/chunk-UX43BKE3.cjs.map +1 -0
- package/dist/{chunk-UNFOBBPJ.cjs → chunk-UYSSHTCJ.cjs} +86 -37
- package/dist/chunk-UYSSHTCJ.cjs.map +1 -0
- package/dist/{chunk-DAWMMLXD.js → chunk-ZUA6TEG3.js} +73 -24
- package/dist/chunk-ZUA6TEG3.js.map +1 -0
- package/dist/index.default.cjs +2 -2
- package/dist/index.default.js +1 -1
- package/dist/index.next-js.cjs +2 -2
- package/dist/index.next-js.js +1 -1
- package/dist/openfeature.default.cjs +2 -2
- package/dist/openfeature.default.js +1 -1
- package/dist/openfeature.next-js.cjs +2 -2
- package/dist/openfeature.next-js.js +1 -1
- package/package.json +4 -4
- package/dist/chunk-2WO37TKH.cjs.map +0 -1
- package/dist/chunk-3GJDKSPG.js.map +0 -1
- package/dist/chunk-DAWMMLXD.js.map +0 -1
- package/dist/chunk-UNFOBBPJ.cjs.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
# @vercel/flags-core
|
|
2
2
|
|
|
3
|
-
## 1.8.
|
|
3
|
+
## 1.8.3
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#507](https://github.com/vercel/flags/pull/507) [`c43b9d9`](https://github.com/vercel/flags/commit/c43b9d9076009a6a70ca2de55020ebcb15b1a4cc) Thanks [@luismeyer](https://github.com/luismeyer)! - Retry transient datafile fetch failures across polling, build loading, and offline fallback reads. Fetches use up to three attempts within a shared ten-second deadline that includes authentication, backoff, and body parsing. Shutdown also cancels retries during polling initialization.
|
|
8
|
+
|
|
9
|
+
- [#533](https://github.com/vercel/flags/pull/533) [`7027cb2`](https://github.com/vercel/flags/commit/7027cb271183566ee224c6a96d36cb12ce7cf2fa) Thanks [@dferber90](https://github.com/dferber90)! - Strip all occurrences of the `g` and `y` flags from regex conditions so cached regular expressions produce consistent results across users and repeated evaluations, including when both flags are present.
|
|
10
|
+
|
|
11
|
+
## 1.8.2
|
|
4
12
|
|
|
5
13
|
### Patch Changes
|
|
6
14
|
|
|
@@ -9,7 +17,7 @@
|
|
|
9
17
|
`client.shutdown()`. The Next.js conditional export uses `after` from
|
|
10
18
|
`next/server` by default.
|
|
11
19
|
|
|
12
|
-
- [#490](https://github.com/vercel/flags/pull/490) [`
|
|
20
|
+
- [#490](https://github.com/vercel/flags/pull/490) [`186ea50`](https://github.com/vercel/flags/commit/186ea5092b22cd3eadf136824ecb2d7293a047fd) Thanks [@AndyBitz](https://github.com/AndyBitz)! - Use the runtime-provided ingest transport when available
|
|
13
21
|
|
|
14
22
|
## 1.8.1
|
|
15
23
|
|
|
@@ -73,7 +73,7 @@ function getSplitBoundaries(outcome) {
|
|
|
73
73
|
function getCompiledRegex(rhs) {
|
|
74
74
|
const cached = compiledRegexCache.get(rhs);
|
|
75
75
|
if (cached) return cached;
|
|
76
|
-
const compiled = new RegExp(rhs.pattern, rhs.flags.replace(/[gy]
|
|
76
|
+
const compiled = new RegExp(rhs.pattern, rhs.flags.replace(/[gy]/g, ""));
|
|
77
77
|
compiledRegexCache.set(rhs, compiled);
|
|
78
78
|
return compiled;
|
|
79
79
|
}
|
|
@@ -576,7 +576,7 @@ function bulkEvaluate(flags, shared) {
|
|
|
576
576
|
}
|
|
577
577
|
|
|
578
578
|
// package.json
|
|
579
|
-
var version = "1.8.
|
|
579
|
+
var version = "1.8.3";
|
|
580
580
|
|
|
581
581
|
// src/lib/report-value.ts
|
|
582
582
|
function internalReportValue(key, value, data) {
|
|
@@ -1526,40 +1526,86 @@ var BundledSource = class {
|
|
|
1526
1526
|
|
|
1527
1527
|
// src/controller/fetch-datafile.ts
|
|
1528
1528
|
var DEFAULT_FETCH_TIMEOUT_MS = 1e4;
|
|
1529
|
+
var DEFAULT_MAX_ATTEMPTS = 3;
|
|
1530
|
+
var DatafileHttpError = class extends Error {
|
|
1531
|
+
constructor(status, statusText) {
|
|
1532
|
+
super(`Failed to fetch data: ${statusText}`);
|
|
1533
|
+
this.status = status;
|
|
1534
|
+
}
|
|
1535
|
+
status;
|
|
1536
|
+
get retryable() {
|
|
1537
|
+
return this.status === 408 || this.status === 429 || this.status >= 500;
|
|
1538
|
+
}
|
|
1539
|
+
};
|
|
1529
1540
|
async function fetchDatafile(options) {
|
|
1530
|
-
|
|
1541
|
+
options.signal?.throwIfAborted();
|
|
1542
|
+
const maxAttempts = options.maxAttempts ?? DEFAULT_MAX_ATTEMPTS;
|
|
1543
|
+
if (!Number.isInteger(maxAttempts) || maxAttempts < 1) {
|
|
1544
|
+
throw new Error("maxAttempts must be a positive integer");
|
|
1545
|
+
}
|
|
1531
1546
|
const controller = new AbortController();
|
|
1547
|
+
const { signal } = controller;
|
|
1548
|
+
let rejectAbort;
|
|
1549
|
+
const aborted = new Promise((_, reject) => {
|
|
1550
|
+
rejectAbort = reject;
|
|
1551
|
+
});
|
|
1552
|
+
const onAbort = () => rejectAbort(signal.reason);
|
|
1553
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
1554
|
+
const onExternalAbort = () => controller.abort(options.signal?.reason);
|
|
1555
|
+
options.signal?.addEventListener("abort", onExternalAbort, { once: true });
|
|
1532
1556
|
const timeoutId = setTimeout(
|
|
1533
|
-
() => controller.abort(
|
|
1557
|
+
() => controller.abort(
|
|
1558
|
+
new Error("@vercel/flags-core: Datafile fetch deadline exceeded")
|
|
1559
|
+
),
|
|
1534
1560
|
DEFAULT_FETCH_TIMEOUT_MS
|
|
1535
1561
|
);
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
throw new Error("Fetch aborted");
|
|
1541
|
-
}
|
|
1542
|
-
options.signal.addEventListener("abort", onExternalAbort, { once: true });
|
|
1543
|
-
}
|
|
1544
|
-
try {
|
|
1562
|
+
let delay;
|
|
1563
|
+
const fetchAttempt = async () => {
|
|
1564
|
+
const token = await options.auth.resolveToken();
|
|
1565
|
+
signal.throwIfAborted();
|
|
1545
1566
|
const res = await options.fetch(`${options.host}/v1/datafile`, {
|
|
1546
1567
|
headers: {
|
|
1547
1568
|
Authorization: `Bearer ${token}`,
|
|
1548
1569
|
"User-Agent": `VercelFlagsCore/${version}`,
|
|
1549
1570
|
...process.env.VERCEL_ENV ? { "X-Vercel-Env": process.env.VERCEL_ENV } : null
|
|
1550
1571
|
},
|
|
1551
|
-
signal
|
|
1572
|
+
signal
|
|
1552
1573
|
});
|
|
1553
|
-
|
|
1554
|
-
options.signal?.removeEventListener("abort", onExternalAbort);
|
|
1574
|
+
signal.throwIfAborted();
|
|
1555
1575
|
if (!res.ok) {
|
|
1556
|
-
|
|
1576
|
+
void res.body?.cancel().catch(() => {
|
|
1577
|
+
});
|
|
1578
|
+
throw new DatafileHttpError(res.status, res.statusText);
|
|
1557
1579
|
}
|
|
1558
|
-
|
|
1559
|
-
|
|
1580
|
+
const data = await res.json();
|
|
1581
|
+
signal.throwIfAborted();
|
|
1582
|
+
return data;
|
|
1583
|
+
};
|
|
1584
|
+
try {
|
|
1585
|
+
for (let attempt = 0; ; attempt++) {
|
|
1586
|
+
if (attempt > 0) {
|
|
1587
|
+
await Promise.race([
|
|
1588
|
+
new Promise((resolve) => {
|
|
1589
|
+
delay = setTimeout(resolve, 100 * 2 ** (attempt - 1));
|
|
1590
|
+
}),
|
|
1591
|
+
aborted
|
|
1592
|
+
]);
|
|
1593
|
+
}
|
|
1594
|
+
signal.throwIfAborted();
|
|
1595
|
+
try {
|
|
1596
|
+
return await Promise.race([fetchAttempt(), aborted]);
|
|
1597
|
+
} catch (error) {
|
|
1598
|
+
signal.throwIfAborted();
|
|
1599
|
+
if (attempt === maxAttempts - 1 || error instanceof DatafileHttpError && !error.retryable) {
|
|
1600
|
+
throw error instanceof Error ? error : new Error("Unknown fetch error");
|
|
1601
|
+
}
|
|
1602
|
+
}
|
|
1603
|
+
}
|
|
1604
|
+
} finally {
|
|
1560
1605
|
clearTimeout(timeoutId);
|
|
1606
|
+
clearTimeout(delay);
|
|
1607
|
+
signal.removeEventListener("abort", onAbort);
|
|
1561
1608
|
options.signal?.removeEventListener("abort", onExternalAbort);
|
|
1562
|
-
throw error instanceof Error ? error : new Error("Unknown fetch error");
|
|
1563
1609
|
}
|
|
1564
1610
|
}
|
|
1565
1611
|
|
|
@@ -1655,13 +1701,16 @@ var PollingSource = class extends TypedEmitter {
|
|
|
1655
1701
|
*/
|
|
1656
1702
|
async poll() {
|
|
1657
1703
|
if (this.abortController?.signal.aborted) return;
|
|
1704
|
+
this.abortController ??= new AbortController();
|
|
1705
|
+
const controller = this.abortController;
|
|
1658
1706
|
try {
|
|
1659
1707
|
const data = await fetchDatafile({
|
|
1660
1708
|
...this.config,
|
|
1661
|
-
signal:
|
|
1709
|
+
signal: controller.signal
|
|
1662
1710
|
});
|
|
1663
1711
|
this.emit("data", data);
|
|
1664
1712
|
} catch (error) {
|
|
1713
|
+
controller.signal.throwIfAborted();
|
|
1665
1714
|
const err = error instanceof Error ? error : new Error("Unknown poll error");
|
|
1666
1715
|
this.emit("error", err);
|
|
1667
1716
|
}
|
|
@@ -1673,9 +1722,9 @@ var PollingSource = class extends TypedEmitter {
|
|
|
1673
1722
|
*/
|
|
1674
1723
|
startInterval() {
|
|
1675
1724
|
if (this.intervalId) return;
|
|
1676
|
-
this.abortController = new AbortController();
|
|
1677
1725
|
this.intervalId = setInterval(
|
|
1678
|
-
() => void this.poll()
|
|
1726
|
+
() => void this.poll().catch(() => {
|
|
1727
|
+
}),
|
|
1679
1728
|
this.config.polling.intervalMs
|
|
1680
1729
|
);
|
|
1681
1730
|
}
|
|
@@ -2750,4 +2799,4 @@ export {
|
|
|
2750
2799
|
resetDefaultFlagsClient,
|
|
2751
2800
|
createClient
|
|
2752
2801
|
};
|
|
2753
|
-
//# sourceMappingURL=chunk-
|
|
2802
|
+
//# sourceMappingURL=chunk-NPKDNJX6.js.map
|