@vercel/flags-core 1.5.0-dde2adb-20260526050633 → 1.5.0
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-XINPOF5O.cjs → chunk-CSSU7O2G.cjs} +117 -54
- package/dist/chunk-CSSU7O2G.cjs.map +1 -0
- package/dist/{chunk-UICJ4U6H.js → chunk-D3AZORK2.js} +116 -53
- package/dist/chunk-D3AZORK2.js.map +1 -0
- package/dist/{chunk-ZHIY5NVJ.cjs → chunk-K3VOC24J.cjs} +116 -53
- package/dist/chunk-K3VOC24J.cjs.map +1 -0
- package/dist/{chunk-CX2U3ZTN.js → chunk-WTGXBSWR.js} +116 -53
- package/dist/chunk-WTGXBSWR.js.map +1 -0
- package/dist/index.default.cjs +2 -2
- package/dist/index.default.d.cts +19 -6
- package/dist/index.default.d.ts +19 -6
- package/dist/index.default.js +1 -1
- package/dist/index.next-js.cjs +2 -2
- package/dist/index.next-js.d.cts +19 -6
- package/dist/index.next-js.d.ts +19 -6
- 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-C70GeY3G.d.cts → types-DkVz6AOY.d.cts} +3 -2
- package/dist/{types-C70GeY3G.d.ts → types-DkVz6AOY.d.ts} +3 -2
- package/package.json +2 -1
- package/dist/chunk-CX2U3ZTN.js.map +0 -1
- package/dist/chunk-UICJ4U6H.js.map +0 -1
- package/dist/chunk-XINPOF5O.cjs.map +0 -1
- package/dist/chunk-ZHIY5NVJ.cjs.map +0 -1
|
@@ -482,7 +482,7 @@ function findWeightedIndex(weights, value, maxValue) {
|
|
|
482
482
|
}
|
|
483
483
|
|
|
484
484
|
// package.json
|
|
485
|
-
var version = "1.5.0
|
|
485
|
+
var version = "1.5.0";
|
|
486
486
|
|
|
487
487
|
// src/lib/report-value.ts
|
|
488
488
|
function internalReportValue(key, value, data) {
|
|
@@ -759,7 +759,7 @@ function hashSdkKey(sdkKey) {
|
|
|
759
759
|
sdkKeyHashCache.set(sdkKey, promise);
|
|
760
760
|
return promise;
|
|
761
761
|
}
|
|
762
|
-
async function readBundledDefinitions(
|
|
762
|
+
async function readBundledDefinitions(auth) {
|
|
763
763
|
let get;
|
|
764
764
|
try {
|
|
765
765
|
const module = await import(
|
|
@@ -776,10 +776,20 @@ async function readBundledDefinitions(sdkKey) {
|
|
|
776
776
|
if (typeof get !== "function") {
|
|
777
777
|
return { definitions: null, state: "missing-file" };
|
|
778
778
|
}
|
|
779
|
-
|
|
779
|
+
let lookup;
|
|
780
|
+
try {
|
|
781
|
+
lookup = await auth.resolveBundledDefinitionsLookup();
|
|
782
|
+
} catch (error) {
|
|
783
|
+
return { definitions: null, state: "unexpected-error", error };
|
|
784
|
+
}
|
|
785
|
+
if (lookup.type === "project-id") {
|
|
786
|
+
const entry2 = get(lookup.projectId);
|
|
787
|
+
return entry2 ? { definitions: entry2, state: "ok" } : { definitions: null, state: "missing-entry" };
|
|
788
|
+
}
|
|
789
|
+
const entry = get(lookup.sdkKey);
|
|
780
790
|
if (entry) return { definitions: entry, state: "ok" };
|
|
781
791
|
try {
|
|
782
|
-
const hashedKey = await hashSdkKey(sdkKey);
|
|
792
|
+
const hashedKey = await hashSdkKey(lookup.sdkKey);
|
|
783
793
|
const hashedEntry = get(hashedKey);
|
|
784
794
|
if (hashedEntry) return { definitions: hashedEntry, state: "ok" };
|
|
785
795
|
} catch (error) {
|
|
@@ -950,13 +960,14 @@ var UsageTracker = class {
|
|
|
950
960
|
const flushId = ++this.flushCounter;
|
|
951
961
|
for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {
|
|
952
962
|
try {
|
|
963
|
+
const token = await this.options.auth.resolveToken();
|
|
953
964
|
const response = await this.options.fetch(
|
|
954
965
|
`${this.options.host}/v1/ingest`,
|
|
955
966
|
{
|
|
956
967
|
method: "POST",
|
|
957
968
|
headers: {
|
|
958
969
|
"Content-Type": "application/json",
|
|
959
|
-
Authorization: `Bearer ${
|
|
970
|
+
Authorization: `Bearer ${token}`,
|
|
960
971
|
"User-Agent": `VercelFlagsCore/${version}`,
|
|
961
972
|
...process.env.VERCEL_ENV ? { "X-Vercel-Env": process.env.VERCEL_ENV } : null,
|
|
962
973
|
...isDebugMode ? { "x-vercel-debug-ingest": "1" } : null
|
|
@@ -1008,11 +1019,10 @@ var FallbackEntryNotFoundError = class extends Error {
|
|
|
1008
1019
|
|
|
1009
1020
|
// src/controller/bundled-source.ts
|
|
1010
1021
|
var BundledSource = class {
|
|
1011
|
-
promise;
|
|
1012
|
-
options;
|
|
1013
1022
|
constructor(options) {
|
|
1014
1023
|
this.options = options;
|
|
1015
1024
|
}
|
|
1025
|
+
promise;
|
|
1016
1026
|
/**
|
|
1017
1027
|
* Load bundled definitions.
|
|
1018
1028
|
* Throws if bundled definitions are not available.
|
|
@@ -1057,7 +1067,7 @@ var BundledSource = class {
|
|
|
1057
1067
|
}
|
|
1058
1068
|
getResult() {
|
|
1059
1069
|
if (!this.promise) {
|
|
1060
|
-
this.promise = this.options.readBundledDefinitions(this.options.
|
|
1070
|
+
this.promise = this.options.readBundledDefinitions(this.options.auth);
|
|
1061
1071
|
}
|
|
1062
1072
|
return this.promise;
|
|
1063
1073
|
}
|
|
@@ -1066,6 +1076,7 @@ var BundledSource = class {
|
|
|
1066
1076
|
// src/controller/fetch-datafile.ts
|
|
1067
1077
|
var DEFAULT_FETCH_TIMEOUT_MS = 1e4;
|
|
1068
1078
|
async function fetchDatafile(options) {
|
|
1079
|
+
const token = await options.auth.resolveToken();
|
|
1069
1080
|
const controller = new AbortController();
|
|
1070
1081
|
const timeoutId = setTimeout(
|
|
1071
1082
|
() => controller.abort(),
|
|
@@ -1082,7 +1093,7 @@ async function fetchDatafile(options) {
|
|
|
1082
1093
|
try {
|
|
1083
1094
|
const res = await options.fetch(`${options.host}/v1/datafile`, {
|
|
1084
1095
|
headers: {
|
|
1085
|
-
Authorization: `Bearer ${
|
|
1096
|
+
Authorization: `Bearer ${token}`,
|
|
1086
1097
|
"User-Agent": `VercelFlagsCore/${version}`,
|
|
1087
1098
|
...process.env.VERCEL_ENV ? { "X-Vercel-Env": process.env.VERCEL_ENV } : null
|
|
1088
1099
|
},
|
|
@@ -1139,7 +1150,7 @@ function normalizeOptions(options) {
|
|
|
1139
1150
|
};
|
|
1140
1151
|
}
|
|
1141
1152
|
return {
|
|
1142
|
-
|
|
1153
|
+
auth: options.auth,
|
|
1143
1154
|
datafile: options.datafile,
|
|
1144
1155
|
stream,
|
|
1145
1156
|
polling,
|
|
@@ -1249,13 +1260,14 @@ var UnauthorizedError = class extends Error {
|
|
|
1249
1260
|
this.name = "UnauthorizedError";
|
|
1250
1261
|
}
|
|
1251
1262
|
};
|
|
1263
|
+
var TokenResolutionError = class extends Error {
|
|
1264
|
+
constructor(error) {
|
|
1265
|
+
super("stream: token resolution failed", { cause: error });
|
|
1266
|
+
this.name = "TokenResolutionError";
|
|
1267
|
+
}
|
|
1268
|
+
};
|
|
1252
1269
|
async function connectStream(config, callbacks) {
|
|
1253
|
-
const {
|
|
1254
|
-
host,
|
|
1255
|
-
sdkKey,
|
|
1256
|
-
abortController,
|
|
1257
|
-
fetch: fetchFn = globalThis.fetch
|
|
1258
|
-
} = config;
|
|
1270
|
+
const { host, abortController, fetch: fetchFn = globalThis.fetch } = config;
|
|
1259
1271
|
const { onDatafile, onPrimed, onDisconnect } = callbacks;
|
|
1260
1272
|
let retryCount = 0;
|
|
1261
1273
|
let lastAttemptTime = 0;
|
|
@@ -1296,8 +1308,11 @@ async function connectStream(config, callbacks) {
|
|
|
1296
1308
|
};
|
|
1297
1309
|
try {
|
|
1298
1310
|
lastAttemptTime = Date.now();
|
|
1311
|
+
const token = await config.resolveToken().catch((error) => {
|
|
1312
|
+
throw new TokenResolutionError(error);
|
|
1313
|
+
});
|
|
1299
1314
|
const headers = {
|
|
1300
|
-
Authorization: `Bearer ${
|
|
1315
|
+
Authorization: `Bearer ${token}`,
|
|
1301
1316
|
"User-Agent": `VercelFlagsCore/${version}`,
|
|
1302
1317
|
"X-Retry-Attempt": String(retryCount)
|
|
1303
1318
|
};
|
|
@@ -1403,6 +1418,11 @@ async function connectStream(config, callbacks) {
|
|
|
1403
1418
|
if (abortController.signal.aborted) {
|
|
1404
1419
|
break;
|
|
1405
1420
|
}
|
|
1421
|
+
if (error instanceof TokenResolutionError && !initialDataReceived) {
|
|
1422
|
+
rejectInit(error.cause);
|
|
1423
|
+
abortController.abort();
|
|
1424
|
+
break;
|
|
1425
|
+
}
|
|
1406
1426
|
if (!connectionAbort.signal.aborted) {
|
|
1407
1427
|
console.error("@vercel/flags-core: Stream error", error);
|
|
1408
1428
|
}
|
|
@@ -1454,7 +1474,7 @@ var StreamSource = class extends TypedEmitter {
|
|
|
1454
1474
|
const promise = connectStream(
|
|
1455
1475
|
{
|
|
1456
1476
|
host: this.options.host,
|
|
1457
|
-
|
|
1477
|
+
resolveToken: () => this.options.auth.resolveToken(),
|
|
1458
1478
|
abortController,
|
|
1459
1479
|
fetch: this.options.fetch,
|
|
1460
1480
|
revision: this.revision
|
|
@@ -1541,11 +1561,6 @@ var Controller = class {
|
|
|
1541
1561
|
// Suppresses usage tracking when the SDK key is unauthorized
|
|
1542
1562
|
unauthorized = false;
|
|
1543
1563
|
constructor(options) {
|
|
1544
|
-
if (!options.sdkKey || typeof options.sdkKey !== "string" || !options.sdkKey.startsWith("vf_")) {
|
|
1545
|
-
throw new Error(
|
|
1546
|
-
'@vercel/flags-core: SDK key must be a string starting with "vf_"'
|
|
1547
|
-
);
|
|
1548
|
-
}
|
|
1549
1564
|
this.options = normalizeOptions(options);
|
|
1550
1565
|
this.streamSource = new StreamSource(
|
|
1551
1566
|
this.options,
|
|
@@ -1553,7 +1568,7 @@ var Controller = class {
|
|
|
1553
1568
|
);
|
|
1554
1569
|
this.pollingSource = new PollingSource(this.options);
|
|
1555
1570
|
this.bundledSource = new BundledSource({
|
|
1556
|
-
|
|
1571
|
+
auth: this.options.auth,
|
|
1557
1572
|
readBundledDefinitions
|
|
1558
1573
|
});
|
|
1559
1574
|
this.wireSourceEvents();
|
|
@@ -1753,7 +1768,7 @@ var Controller = class {
|
|
|
1753
1768
|
try {
|
|
1754
1769
|
const fetched = await fetchDatafile({
|
|
1755
1770
|
host: this.options.host,
|
|
1756
|
-
|
|
1771
|
+
auth: this.options.auth,
|
|
1757
1772
|
fetch: this.options.fetch
|
|
1758
1773
|
});
|
|
1759
1774
|
this.data = tagData(fetched, "fetched");
|
|
@@ -1949,7 +1964,7 @@ var Controller = class {
|
|
|
1949
1964
|
try {
|
|
1950
1965
|
const fetched = await fetchDatafile({
|
|
1951
1966
|
host: this.options.host,
|
|
1952
|
-
|
|
1967
|
+
auth: this.options.auth,
|
|
1953
1968
|
fetch: this.options.fetch
|
|
1954
1969
|
});
|
|
1955
1970
|
return tagData(fetched, "fetched");
|
|
@@ -1981,7 +1996,7 @@ var Controller = class {
|
|
|
1981
1996
|
try {
|
|
1982
1997
|
const fetched = await fetchDatafile({
|
|
1983
1998
|
host: this.options.host,
|
|
1984
|
-
|
|
1999
|
+
auth: this.options.auth,
|
|
1985
2000
|
fetch: this.options.fetch
|
|
1986
2001
|
});
|
|
1987
2002
|
this.data = tagData(fetched, "fetched");
|
|
@@ -2033,7 +2048,7 @@ var Controller = class {
|
|
|
2033
2048
|
try {
|
|
2034
2049
|
const fetched = await fetchDatafile({
|
|
2035
2050
|
host: this.options.host,
|
|
2036
|
-
|
|
2051
|
+
auth: this.options.auth,
|
|
2037
2052
|
fetch: this.options.fetch
|
|
2038
2053
|
});
|
|
2039
2054
|
this.data = tagData(fetched, "fetched");
|
|
@@ -2106,6 +2121,9 @@ var Controller = class {
|
|
|
2106
2121
|
}
|
|
2107
2122
|
};
|
|
2108
2123
|
|
|
2124
|
+
// src/controller/auth.ts
|
|
2125
|
+
import { getVercelOidcToken } from "@vercel/oidc";
|
|
2126
|
+
|
|
2109
2127
|
// src/utils/sdk-keys.ts
|
|
2110
2128
|
var SDK_KEY_REGEX = /^vf_(?:server|client)_/;
|
|
2111
2129
|
function parseSdkKeyFromFlagsConnectionString(text) {
|
|
@@ -2120,28 +2138,80 @@ function parseSdkKeyFromFlagsConnectionString(text) {
|
|
|
2120
2138
|
return null;
|
|
2121
2139
|
}
|
|
2122
2140
|
|
|
2141
|
+
// src/controller/auth.ts
|
|
2142
|
+
async function getOidcToken() {
|
|
2143
|
+
try {
|
|
2144
|
+
return await getVercelOidcToken();
|
|
2145
|
+
} catch {
|
|
2146
|
+
throw new Error(
|
|
2147
|
+
[
|
|
2148
|
+
"@vercel/flags-core: Failed to get OIDC token.",
|
|
2149
|
+
"Are you running in a Vercel Environment where OIDC tokens are available?",
|
|
2150
|
+
"Did you mean to use an SDK Key instead? Use the environment variable FLAGS or pass it directly to the client."
|
|
2151
|
+
].join(" ")
|
|
2152
|
+
);
|
|
2153
|
+
}
|
|
2154
|
+
}
|
|
2155
|
+
function getProjectIdFromOidcToken(oidcToken) {
|
|
2156
|
+
const tokenParts = oidcToken.split(".");
|
|
2157
|
+
if (tokenParts.length !== 3 || !tokenParts[1]) {
|
|
2158
|
+
throw new Error("@vercel/flags-core: Invalid OIDC token");
|
|
2159
|
+
}
|
|
2160
|
+
const payload = JSON.parse(
|
|
2161
|
+
Buffer.from(tokenParts[1], "base64url").toString("utf8")
|
|
2162
|
+
);
|
|
2163
|
+
if (typeof payload.project_id !== "string" || !payload.project_id) {
|
|
2164
|
+
throw new Error(
|
|
2165
|
+
"@vercel/flags-core: Missing project_id claim in OIDC token"
|
|
2166
|
+
);
|
|
2167
|
+
}
|
|
2168
|
+
return payload.project_id;
|
|
2169
|
+
}
|
|
2170
|
+
var Authentication = class {
|
|
2171
|
+
sdkKey;
|
|
2172
|
+
constructor(sdkKeyOrConnectionString) {
|
|
2173
|
+
if (sdkKeyOrConnectionString !== void 0) {
|
|
2174
|
+
if (typeof sdkKeyOrConnectionString !== "string") {
|
|
2175
|
+
throw new Error(
|
|
2176
|
+
`@vercel/flags-core: Invalid sdkKey. Expected string, got ${typeof sdkKeyOrConnectionString}`
|
|
2177
|
+
);
|
|
2178
|
+
}
|
|
2179
|
+
const parsed = parseSdkKeyFromFlagsConnectionString(
|
|
2180
|
+
sdkKeyOrConnectionString
|
|
2181
|
+
);
|
|
2182
|
+
if (!parsed) {
|
|
2183
|
+
throw new Error("@vercel/flags-core: Missing sdkKey");
|
|
2184
|
+
}
|
|
2185
|
+
this.sdkKey = parsed;
|
|
2186
|
+
}
|
|
2187
|
+
}
|
|
2188
|
+
async resolveToken() {
|
|
2189
|
+
if (this.sdkKey) {
|
|
2190
|
+
return this.sdkKey;
|
|
2191
|
+
}
|
|
2192
|
+
return await getOidcToken();
|
|
2193
|
+
}
|
|
2194
|
+
async resolveBundledDefinitionsLookup() {
|
|
2195
|
+
if (this.sdkKey) {
|
|
2196
|
+
return { type: "sdk-key", sdkKey: this.sdkKey };
|
|
2197
|
+
}
|
|
2198
|
+
const oidcToken = await this.resolveToken();
|
|
2199
|
+
return {
|
|
2200
|
+
type: "project-id",
|
|
2201
|
+
projectId: getProjectIdFromOidcToken(oidcToken)
|
|
2202
|
+
};
|
|
2203
|
+
}
|
|
2204
|
+
};
|
|
2205
|
+
|
|
2123
2206
|
// src/index.make.ts
|
|
2124
2207
|
function make(createRawClient) {
|
|
2125
2208
|
let _defaultFlagsClient = null;
|
|
2126
2209
|
function createClient2(sdkKeyOrConnectionString, options) {
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
if (typeof sdkKeyOrConnectionString !== "string")
|
|
2130
|
-
throw new Error(
|
|
2131
|
-
`@vercel/flags-core: Invalid sdkKey. Expected string, got ${typeof sdkKeyOrConnectionString}`
|
|
2132
|
-
);
|
|
2133
|
-
const sdkKey = parseSdkKeyFromFlagsConnectionString(
|
|
2134
|
-
sdkKeyOrConnectionString
|
|
2135
|
-
);
|
|
2136
|
-
if (!sdkKey) {
|
|
2137
|
-
throw new Error(
|
|
2138
|
-
"@vercel/flags-core: Missing sdkKey in connection string"
|
|
2139
|
-
);
|
|
2140
|
-
}
|
|
2141
|
-
const controller = new Controller({ sdkKey, ...options });
|
|
2210
|
+
const auth = new Authentication(sdkKeyOrConnectionString);
|
|
2211
|
+
const controller = new Controller({ auth, ...options });
|
|
2142
2212
|
return createRawClient({
|
|
2143
2213
|
controller,
|
|
2144
|
-
origin: { provider: "vercel", sdkKey }
|
|
2214
|
+
origin: { provider: "vercel", sdkKey: auth.sdkKey }
|
|
2145
2215
|
});
|
|
2146
2216
|
}
|
|
2147
2217
|
function resetDefaultFlagsClient2() {
|
|
@@ -2150,14 +2220,7 @@ function make(createRawClient) {
|
|
|
2150
2220
|
const flagsClient2 = new Proxy({}, {
|
|
2151
2221
|
get(_, prop) {
|
|
2152
2222
|
if (!_defaultFlagsClient) {
|
|
2153
|
-
|
|
2154
|
-
throw new Error("flags: Missing environment variable FLAGS");
|
|
2155
|
-
}
|
|
2156
|
-
const sdkKey = parseSdkKeyFromFlagsConnectionString(process.env.FLAGS);
|
|
2157
|
-
if (!sdkKey) {
|
|
2158
|
-
throw new Error("@vercel/flags-core: Missing sdkKey");
|
|
2159
|
-
}
|
|
2160
|
-
_defaultFlagsClient = createClient2(sdkKey);
|
|
2223
|
+
_defaultFlagsClient = createClient2(process.env.FLAGS);
|
|
2161
2224
|
}
|
|
2162
2225
|
return _defaultFlagsClient[prop];
|
|
2163
2226
|
}
|
|
@@ -2198,4 +2261,4 @@ export {
|
|
|
2198
2261
|
resetDefaultFlagsClient,
|
|
2199
2262
|
createClient
|
|
2200
2263
|
};
|
|
2201
|
-
//# sourceMappingURL=chunk-
|
|
2264
|
+
//# sourceMappingURL=chunk-WTGXBSWR.js.map
|