@vercel/flags-core 1.9.0-ea4d7de-20260922121332 → 1.9.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 +20 -2
- package/dist/{chunk-L6QJOXJN.cjs → chunk-PGKH4XQ7.cjs} +385 -353
- package/dist/chunk-PGKH4XQ7.cjs.map +1 -0
- package/dist/{chunk-FKI4L3NY.js → chunk-SLNLPFKU.js} +354 -322
- package/dist/chunk-SLNLPFKU.js.map +1 -0
- package/dist/{chunk-C22F472K.js → chunk-TDZBUVBG.js} +354 -322
- package/dist/chunk-TDZBUVBG.js.map +1 -0
- package/dist/{chunk-VQ3WFG4Y.cjs → chunk-W742GGZU.cjs} +386 -354
- package/dist/chunk-W742GGZU.cjs.map +1 -0
- package/dist/index.default.cjs +2 -2
- package/dist/index.default.d.cts +10 -28
- package/dist/index.default.d.ts +10 -28
- package/dist/index.default.js +1 -1
- package/dist/index.next-js.cjs +2 -2
- package/dist/index.next-js.d.cts +10 -28
- package/dist/index.next-js.d.ts +10 -28
- 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-WeTcbSQF.d.cts → types-1OK52NNi.d.cts} +10 -8
- package/dist/{types-WeTcbSQF.d.ts → types-1OK52NNi.d.ts} +10 -8
- package/package.json +4 -4
- package/dist/chunk-C22F472K.js.map +0 -1
- package/dist/chunk-FKI4L3NY.js.map +0 -1
- package/dist/chunk-L6QJOXJN.cjs.map +0 -1
- package/dist/chunk-VQ3WFG4Y.cjs.map +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { newObj[key] = obj[key]; } } } newObj.default = obj; return newObj; } } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } }
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { newObj[key] = obj[key]; } } } newObj.default = obj; return newObj; } } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } var _class; var _class2; var _class3; var _class4; var _class5; var _class6;// src/index.next-js.ts
|
|
2
2
|
var _cache = require('next/cache');
|
|
3
3
|
var _server = require('next/server');
|
|
4
4
|
|
|
@@ -56,7 +56,7 @@ function getSplitBoundaries(outcome) {
|
|
|
56
56
|
function getCompiledRegex(rhs) {
|
|
57
57
|
const cached = compiledRegexCache.get(rhs);
|
|
58
58
|
if (cached) return cached;
|
|
59
|
-
const compiled = new RegExp(rhs.pattern, rhs.flags.replace(/[gy]
|
|
59
|
+
const compiled = new RegExp(rhs.pattern, rhs.flags.replace(/[gy]/g, ""));
|
|
60
60
|
compiledRegexCache.set(rhs, compiled);
|
|
61
61
|
return compiled;
|
|
62
62
|
}
|
|
@@ -433,7 +433,7 @@ function resolveOutcome(params, outcome) {
|
|
|
433
433
|
break;
|
|
434
434
|
}
|
|
435
435
|
}
|
|
436
|
-
if (exhausted) currentPromille = PROMILLE_SCALE;
|
|
436
|
+
if (exhausted) currentPromille = _nullishCoalesce(outcome.finalPromille, () => ( PROMILLE_SCALE));
|
|
437
437
|
if (currentPromille <= 0) {
|
|
438
438
|
return {
|
|
439
439
|
...rollFromVariant,
|
|
@@ -559,7 +559,7 @@ function bulkEvaluate(flags, shared) {
|
|
|
559
559
|
}
|
|
560
560
|
|
|
561
561
|
// package.json
|
|
562
|
-
var version = "1.9.0
|
|
562
|
+
var version = "1.9.0";
|
|
563
563
|
|
|
564
564
|
// src/lib/report-value.ts
|
|
565
565
|
function internalReportValue(key, value, data) {
|
|
@@ -1023,6 +1023,126 @@ async function readBundledDefinitions(auth) {
|
|
|
1023
1023
|
// src/utils/ingest.ts
|
|
1024
1024
|
var _oidc = require('@vercel/oidc');
|
|
1025
1025
|
|
|
1026
|
+
// src/controller/auth.ts
|
|
1027
|
+
|
|
1028
|
+
|
|
1029
|
+
// src/utils/sdk-keys.ts
|
|
1030
|
+
var SDK_KEY_REGEX = /^vf_(?:server|client)_/;
|
|
1031
|
+
function isValidSdkKey(value) {
|
|
1032
|
+
return SDK_KEY_REGEX.test(value);
|
|
1033
|
+
}
|
|
1034
|
+
var PROJECT_ID_REGEX = /^[A-Za-z0-9_]{1,64}$/;
|
|
1035
|
+
function isValidProjectId(value) {
|
|
1036
|
+
return PROJECT_ID_REGEX.test(value);
|
|
1037
|
+
}
|
|
1038
|
+
function parseFlagsConnectionString(text) {
|
|
1039
|
+
if (SDK_KEY_REGEX.test(text)) return { sdkKey: text, projectId: null };
|
|
1040
|
+
if (!text.startsWith("flags:")) return null;
|
|
1041
|
+
try {
|
|
1042
|
+
const params = new URLSearchParams(text.slice(6));
|
|
1043
|
+
return {
|
|
1044
|
+
sdkKey: params.get("sdkKey") || null,
|
|
1045
|
+
projectId: params.get("projectId") || null
|
|
1046
|
+
};
|
|
1047
|
+
} catch (e5) {
|
|
1048
|
+
return null;
|
|
1049
|
+
}
|
|
1050
|
+
}
|
|
1051
|
+
|
|
1052
|
+
// src/controller/auth.ts
|
|
1053
|
+
var SOURCE_PROJECT_HEADER = "X-Vercel-Flags-Project-Id";
|
|
1054
|
+
function authHeaders(token, sourceProjectId) {
|
|
1055
|
+
return {
|
|
1056
|
+
Authorization: `Bearer ${token}`,
|
|
1057
|
+
...sourceProjectId ? { [SOURCE_PROJECT_HEADER]: sourceProjectId } : null
|
|
1058
|
+
};
|
|
1059
|
+
}
|
|
1060
|
+
function unauthorizedMessage(sourceProjectId) {
|
|
1061
|
+
if (!sourceProjectId) return "unauthorized (401)";
|
|
1062
|
+
return `unauthorized (401): this deployment is not allowed to read the flags of project "${sourceProjectId}". Check the connection string and that the project is connected.`;
|
|
1063
|
+
}
|
|
1064
|
+
async function getOidcToken() {
|
|
1065
|
+
try {
|
|
1066
|
+
return await _oidc.getVercelOidcToken.call(void 0, );
|
|
1067
|
+
} catch (e6) {
|
|
1068
|
+
throw new Error(
|
|
1069
|
+
[
|
|
1070
|
+
"@vercel/flags-core: Failed to get OIDC token.",
|
|
1071
|
+
"Are you running in a Vercel Environment where OIDC tokens are available?",
|
|
1072
|
+
"Did you mean to use an SDK Key instead? Use the environment variable FLAGS or pass it directly to the client."
|
|
1073
|
+
].join(" ")
|
|
1074
|
+
);
|
|
1075
|
+
}
|
|
1076
|
+
}
|
|
1077
|
+
function getProjectIdFromOidcToken(oidcToken) {
|
|
1078
|
+
const tokenParts = oidcToken.split(".");
|
|
1079
|
+
if (tokenParts.length !== 3 || !tokenParts[1]) {
|
|
1080
|
+
throw new Error("@vercel/flags-core: Invalid OIDC token");
|
|
1081
|
+
}
|
|
1082
|
+
const payload = JSON.parse(
|
|
1083
|
+
Buffer.from(tokenParts[1], "base64url").toString("utf8")
|
|
1084
|
+
);
|
|
1085
|
+
if (typeof payload.project_id !== "string" || !payload.project_id) {
|
|
1086
|
+
throw new Error(
|
|
1087
|
+
"@vercel/flags-core: Missing project_id claim in OIDC token"
|
|
1088
|
+
);
|
|
1089
|
+
}
|
|
1090
|
+
return payload.project_id;
|
|
1091
|
+
}
|
|
1092
|
+
var Authentication = class {
|
|
1093
|
+
|
|
1094
|
+
|
|
1095
|
+
constructor(sdkKeyOrConnectionString) {
|
|
1096
|
+
if (sdkKeyOrConnectionString !== void 0) {
|
|
1097
|
+
if (typeof sdkKeyOrConnectionString !== "string") {
|
|
1098
|
+
throw new Error(
|
|
1099
|
+
`@vercel/flags-core: Invalid sdkKey. Expected string, got ${typeof sdkKeyOrConnectionString}`
|
|
1100
|
+
);
|
|
1101
|
+
}
|
|
1102
|
+
const parsed = parseFlagsConnectionString(sdkKeyOrConnectionString);
|
|
1103
|
+
if (_optionalChain([parsed, 'optionalAccess', _31 => _31.sdkKey]) && parsed.projectId) {
|
|
1104
|
+
throw new Error(
|
|
1105
|
+
"@vercel/flags-core: A connection string must contain either sdkKey or projectId, not both"
|
|
1106
|
+
);
|
|
1107
|
+
}
|
|
1108
|
+
if (_optionalChain([parsed, 'optionalAccess', _32 => _32.sdkKey])) {
|
|
1109
|
+
if (!isValidSdkKey(parsed.sdkKey)) {
|
|
1110
|
+
throw new Error("@vercel/flags-core: Missing sdkKey");
|
|
1111
|
+
}
|
|
1112
|
+
this.sdkKey = parsed.sdkKey;
|
|
1113
|
+
} else if (_optionalChain([parsed, 'optionalAccess', _33 => _33.projectId])) {
|
|
1114
|
+
if (!isValidProjectId(parsed.projectId)) {
|
|
1115
|
+
throw new Error(
|
|
1116
|
+
"@vercel/flags-core: Invalid projectId in connection string"
|
|
1117
|
+
);
|
|
1118
|
+
}
|
|
1119
|
+
this.sourceProjectId = parsed.projectId;
|
|
1120
|
+
} else {
|
|
1121
|
+
throw new Error("@vercel/flags-core: Missing sdkKey");
|
|
1122
|
+
}
|
|
1123
|
+
}
|
|
1124
|
+
}
|
|
1125
|
+
async resolveToken() {
|
|
1126
|
+
if (this.sdkKey) {
|
|
1127
|
+
return this.sdkKey;
|
|
1128
|
+
}
|
|
1129
|
+
return await getOidcToken();
|
|
1130
|
+
}
|
|
1131
|
+
async resolveBundledDefinitionsLookup() {
|
|
1132
|
+
if (this.sdkKey) {
|
|
1133
|
+
return { type: "sdk-key", sdkKey: this.sdkKey };
|
|
1134
|
+
}
|
|
1135
|
+
if (this.sourceProjectId) {
|
|
1136
|
+
return { type: "project-id", projectId: this.sourceProjectId };
|
|
1137
|
+
}
|
|
1138
|
+
const oidcToken = await this.resolveToken();
|
|
1139
|
+
return {
|
|
1140
|
+
type: "project-id",
|
|
1141
|
+
projectId: getProjectIdFromOidcToken(oidcToken)
|
|
1142
|
+
};
|
|
1143
|
+
}
|
|
1144
|
+
};
|
|
1145
|
+
|
|
1026
1146
|
// src/utils/backoff.ts
|
|
1027
1147
|
var DEFAULT_BASE_MS = 250;
|
|
1028
1148
|
var DEFAULT_CAP_MS = 5e3;
|
|
@@ -1038,12 +1158,26 @@ function getJitteredWaitMs(baseMs, ratio) {
|
|
|
1038
1158
|
return Math.floor(min + Math.random() * span);
|
|
1039
1159
|
}
|
|
1040
1160
|
|
|
1161
|
+
// src/utils/runtime-ingest.ts
|
|
1162
|
+
var FLAGS_CONTEXT_SYMBOL = /* @__PURE__ */ Symbol.for("@vercel/flags-context");
|
|
1163
|
+
function getRuntimeIngestFor(auth) {
|
|
1164
|
+
return auth.sourceProjectId ? void 0 : getRuntimeIngest();
|
|
1165
|
+
}
|
|
1166
|
+
function getRuntimeIngest() {
|
|
1167
|
+
try {
|
|
1168
|
+
const context = globalThis[FLAGS_CONTEXT_SYMBOL];
|
|
1169
|
+
return typeof _optionalChain([context, 'optionalAccess', _34 => _34.ingest]) === "function" ? context.ingest : void 0;
|
|
1170
|
+
} catch (e7) {
|
|
1171
|
+
return void 0;
|
|
1172
|
+
}
|
|
1173
|
+
}
|
|
1174
|
+
|
|
1041
1175
|
// src/utils/ingest.ts
|
|
1042
1176
|
var MAX_RETRIES = 3;
|
|
1043
1177
|
var MAX_EVENTS_PER_REQUEST = 2e3;
|
|
1044
1178
|
var EVALUATING_OIDC_TOKEN_HEADER = "X-Vercel-Flags-OIDC-Token";
|
|
1045
1179
|
var FLUSH_REASON_HEADER = "X-Vercel-Flags-Flush-Reason";
|
|
1046
|
-
var isDebugMode = _optionalChain([process, 'access',
|
|
1180
|
+
var isDebugMode = _optionalChain([process, 'access', _35 => _35.env, 'access', _36 => _36.DEBUG, 'optionalAccess', _37 => _37.includes, 'call', _38 => _38("@vercel/flags-core")]);
|
|
1047
1181
|
var debugLog = (...args) => {
|
|
1048
1182
|
if (!isDebugMode) return;
|
|
1049
1183
|
console.log(...args);
|
|
@@ -1052,7 +1186,7 @@ async function getEvaluatingOidcToken(auth) {
|
|
|
1052
1186
|
if (!auth.sdkKey) return void 0;
|
|
1053
1187
|
try {
|
|
1054
1188
|
return await _oidc.getVercelOidcToken.call(void 0, );
|
|
1055
|
-
} catch (
|
|
1189
|
+
} catch (e8) {
|
|
1056
1190
|
return void 0;
|
|
1057
1191
|
}
|
|
1058
1192
|
}
|
|
@@ -1061,7 +1195,7 @@ async function getIngestHeaders(options, flushReason) {
|
|
|
1061
1195
|
const evaluatingOidcToken = await getEvaluatingOidcToken(options.auth);
|
|
1062
1196
|
return {
|
|
1063
1197
|
"Content-Type": "application/json",
|
|
1064
|
-
|
|
1198
|
+
...authHeaders(token, options.auth.sourceProjectId),
|
|
1065
1199
|
"User-Agent": `VercelFlagsCore/${version}`,
|
|
1066
1200
|
[FLUSH_REASON_HEADER]: flushReason,
|
|
1067
1201
|
..._nullishCoalesce(options.metricEnvironment, () => ( process.env.VERCEL_ENV)) ? {
|
|
@@ -1071,8 +1205,28 @@ async function getIngestHeaders(options, flushReason) {
|
|
|
1071
1205
|
...isDebugMode ? { "x-vercel-debug-ingest": "1" } : null
|
|
1072
1206
|
};
|
|
1073
1207
|
}
|
|
1208
|
+
function getRuntimeIngestHeaders(options, flushReason) {
|
|
1209
|
+
return {
|
|
1210
|
+
"Content-Type": "application/json",
|
|
1211
|
+
...options.auth.sdkKey ? { Authorization: `Bearer ${options.auth.sdkKey}` } : null,
|
|
1212
|
+
"User-Agent": `VercelFlagsCore/${version}`,
|
|
1213
|
+
[FLUSH_REASON_HEADER]: flushReason,
|
|
1214
|
+
..._nullishCoalesce(options.metricEnvironment, () => ( process.env.VERCEL_ENV)) ? {
|
|
1215
|
+
"X-Vercel-Env": _nullishCoalesce(options.metricEnvironment, () => ( process.env.VERCEL_ENV))
|
|
1216
|
+
} : null,
|
|
1217
|
+
...isDebugMode ? { "x-vercel-debug-ingest": "1" } : null
|
|
1218
|
+
};
|
|
1219
|
+
}
|
|
1074
1220
|
async function sendIngestEvents(options, events, flushId, flushReason) {
|
|
1075
|
-
|
|
1221
|
+
let eventsToSend = events.map((event) => event.ingestEvent());
|
|
1222
|
+
const runtimeIngest = getRuntimeIngestFor(options.auth);
|
|
1223
|
+
if (runtimeIngest) {
|
|
1224
|
+
const headers = getRuntimeIngestHeaders(options, flushReason);
|
|
1225
|
+
eventsToSend = eventsToSend.filter(
|
|
1226
|
+
(event) => !runtimeIngest({ headers, body: [event] })
|
|
1227
|
+
);
|
|
1228
|
+
if (eventsToSend.length === 0) return;
|
|
1229
|
+
}
|
|
1076
1230
|
for (let i = 0; i < eventsToSend.length; i += MAX_EVENTS_PER_REQUEST) {
|
|
1077
1231
|
await sendIngestChunk(
|
|
1078
1232
|
options,
|
|
@@ -1122,7 +1276,7 @@ var SYMBOL_FOR_REQ_CONTEXT = /* @__PURE__ */ Symbol.for("@vercel/request-context
|
|
|
1122
1276
|
var fromSymbol = globalThis;
|
|
1123
1277
|
function getRequestContext() {
|
|
1124
1278
|
try {
|
|
1125
|
-
const ctx = _optionalChain([fromSymbol, 'access',
|
|
1279
|
+
const ctx = _optionalChain([fromSymbol, 'access', _39 => _39[SYMBOL_FOR_REQ_CONTEXT], 'optionalAccess', _40 => _40.get, 'optionalCall', _41 => _41()]);
|
|
1126
1280
|
if (ctx && Object.hasOwn(ctx, "headers")) {
|
|
1127
1281
|
return {
|
|
1128
1282
|
ctx,
|
|
@@ -1130,7 +1284,7 @@ function getRequestContext() {
|
|
|
1130
1284
|
};
|
|
1131
1285
|
}
|
|
1132
1286
|
return { ctx, headers: void 0 };
|
|
1133
|
-
} catch (
|
|
1287
|
+
} catch (e9) {
|
|
1134
1288
|
return { ctx: void 0, headers: void 0 };
|
|
1135
1289
|
}
|
|
1136
1290
|
}
|
|
@@ -1162,7 +1316,7 @@ var Scheduler = (_class = class {
|
|
|
1162
1316
|
})();
|
|
1163
1317
|
try {
|
|
1164
1318
|
this.scheduleTask(this.pending);
|
|
1165
|
-
} catch (
|
|
1319
|
+
} catch (e10) {
|
|
1166
1320
|
}
|
|
1167
1321
|
this.maxTimeout = setTimeout(
|
|
1168
1322
|
() => this.resolveScheduledFlush("max_timeout"),
|
|
@@ -1189,7 +1343,7 @@ var Scheduler = (_class = class {
|
|
|
1189
1343
|
}
|
|
1190
1344
|
resolveScheduledFlush(reason) {
|
|
1191
1345
|
this.clearTimeouts();
|
|
1192
|
-
_optionalChain([this, 'access',
|
|
1346
|
+
_optionalChain([this, 'access', _42 => _42.resolveWait, 'optionalCall', _43 => _43(reason)]);
|
|
1193
1347
|
}
|
|
1194
1348
|
reset() {
|
|
1195
1349
|
this.pending = null;
|
|
@@ -1308,11 +1462,14 @@ var UsageTracker = (_class4 = class {
|
|
|
1308
1462
|
__init7() {this.flushCount = 0}
|
|
1309
1463
|
|
|
1310
1464
|
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1465
|
+
|
|
1466
|
+
__init8() {this.inflightFlushes = /* @__PURE__ */ new Set()}
|
|
1467
|
+
__init9() {this.trackedRequests = /* @__PURE__ */ new WeakSet()}
|
|
1468
|
+
__init10() {this.readEvents = []}
|
|
1469
|
+
__init11() {this.evaluationEvents = /* @__PURE__ */ new Map()}
|
|
1470
|
+
constructor(options) {;_class4.prototype.__init7.call(this);_class4.prototype.__init8.call(this);_class4.prototype.__init9.call(this);_class4.prototype.__init10.call(this);_class4.prototype.__init11.call(this);
|
|
1315
1471
|
this.options = options;
|
|
1472
|
+
this.waitUntil = options.waitUntil;
|
|
1316
1473
|
this.scheduler = new Scheduler(
|
|
1317
1474
|
(reason) => this.flushEvents(reason),
|
|
1318
1475
|
options.waitUntil
|
|
@@ -1325,6 +1482,7 @@ var UsageTracker = (_class4 = class {
|
|
|
1325
1482
|
async shutdown() {
|
|
1326
1483
|
await this.scheduler.shutdown();
|
|
1327
1484
|
await this.flushEvents("shutdown");
|
|
1485
|
+
await Promise.all([...this.inflightFlushes]);
|
|
1328
1486
|
}
|
|
1329
1487
|
/**
|
|
1330
1488
|
* Tracks a config read event. Deduplicates by request context.
|
|
@@ -1336,7 +1494,7 @@ var UsageTracker = (_class4 = class {
|
|
|
1336
1494
|
if (this.trackedRequests.has(ctx)) return;
|
|
1337
1495
|
this.trackedRequests.add(ctx);
|
|
1338
1496
|
this.readEvents.push(new FlagsConfigReadEvent(headers, options));
|
|
1339
|
-
this.
|
|
1497
|
+
this.requestFlush();
|
|
1340
1498
|
} catch (error) {
|
|
1341
1499
|
console.error("@vercel/flags-core: Failed to record event:", error);
|
|
1342
1500
|
}
|
|
@@ -1360,7 +1518,7 @@ var UsageTracker = (_class4 = class {
|
|
|
1360
1518
|
new FlagsEvaluationEvent(bucketedOptions)
|
|
1361
1519
|
);
|
|
1362
1520
|
}
|
|
1363
|
-
this.
|
|
1521
|
+
this.requestFlush();
|
|
1364
1522
|
} catch (error) {
|
|
1365
1523
|
console.error(
|
|
1366
1524
|
"@vercel/flags-core: Failed to record evaluation event:",
|
|
@@ -1368,6 +1526,25 @@ var UsageTracker = (_class4 = class {
|
|
|
1368
1526
|
);
|
|
1369
1527
|
}
|
|
1370
1528
|
}
|
|
1529
|
+
/**
|
|
1530
|
+
* Flushes immediately when the runtime provides an ingest transport,
|
|
1531
|
+
* otherwise falls back to the time-based scheduler.
|
|
1532
|
+
*/
|
|
1533
|
+
requestFlush() {
|
|
1534
|
+
if (getRuntimeIngestFor(this.options.auth)) {
|
|
1535
|
+
const flush = this.flushEvents("immediate").catch((error) => {
|
|
1536
|
+
console.error("@vercel/flags-core: Failed to flush events:", error);
|
|
1537
|
+
});
|
|
1538
|
+
this.inflightFlushes.add(flush);
|
|
1539
|
+
void flush.finally(() => this.inflightFlushes.delete(flush));
|
|
1540
|
+
try {
|
|
1541
|
+
_optionalChain([this, 'access', _44 => _44.waitUntil, 'optionalCall', _45 => _45(flush)]);
|
|
1542
|
+
} catch (e11) {
|
|
1543
|
+
}
|
|
1544
|
+
} else {
|
|
1545
|
+
this.scheduler.scheduleFlush();
|
|
1546
|
+
}
|
|
1547
|
+
}
|
|
1371
1548
|
/**
|
|
1372
1549
|
* Send all events to the ingest service
|
|
1373
1550
|
*/
|
|
@@ -1440,7 +1617,7 @@ var BundledSource = class {
|
|
|
1440
1617
|
*/
|
|
1441
1618
|
async tryLoad() {
|
|
1442
1619
|
const result = await this.getResult();
|
|
1443
|
-
if (_optionalChain([result, 'optionalAccess',
|
|
1620
|
+
if (_optionalChain([result, 'optionalAccess', _46 => _46.state]) === "ok" && result.definitions) {
|
|
1444
1621
|
return result.definitions;
|
|
1445
1622
|
}
|
|
1446
1623
|
return void 0;
|
|
@@ -1455,192 +1632,91 @@ var BundledSource = class {
|
|
|
1455
1632
|
|
|
1456
1633
|
// src/controller/fetch-datafile.ts
|
|
1457
1634
|
var DEFAULT_FETCH_TIMEOUT_MS = 1e4;
|
|
1635
|
+
var DEFAULT_MAX_ATTEMPTS = 3;
|
|
1636
|
+
var DatafileHttpError = class extends Error {
|
|
1637
|
+
constructor(status, statusText) {
|
|
1638
|
+
super(`Failed to fetch data: ${statusText}`);
|
|
1639
|
+
this.status = status;
|
|
1640
|
+
}
|
|
1641
|
+
|
|
1642
|
+
get retryable() {
|
|
1643
|
+
return this.status === 408 || this.status === 429 || this.status >= 500;
|
|
1644
|
+
}
|
|
1645
|
+
};
|
|
1458
1646
|
async function fetchDatafile(options) {
|
|
1459
|
-
|
|
1647
|
+
_optionalChain([options, 'access', _47 => _47.signal, 'optionalAccess', _48 => _48.throwIfAborted, 'call', _49 => _49()]);
|
|
1648
|
+
const maxAttempts = _nullishCoalesce(options.maxAttempts, () => ( DEFAULT_MAX_ATTEMPTS));
|
|
1649
|
+
if (!Number.isInteger(maxAttempts) || maxAttempts < 1) {
|
|
1650
|
+
throw new Error("maxAttempts must be a positive integer");
|
|
1651
|
+
}
|
|
1460
1652
|
const controller = new AbortController();
|
|
1653
|
+
const { signal } = controller;
|
|
1654
|
+
let rejectAbort;
|
|
1655
|
+
const aborted = new Promise((_, reject) => {
|
|
1656
|
+
rejectAbort = reject;
|
|
1657
|
+
});
|
|
1658
|
+
const onAbort = () => rejectAbort(signal.reason);
|
|
1659
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
1660
|
+
const onExternalAbort = () => controller.abort(_optionalChain([options, 'access', _50 => _50.signal, 'optionalAccess', _51 => _51.reason]));
|
|
1661
|
+
_optionalChain([options, 'access', _52 => _52.signal, 'optionalAccess', _53 => _53.addEventListener, 'call', _54 => _54("abort", onExternalAbort, { once: true })]);
|
|
1461
1662
|
const timeoutId = setTimeout(
|
|
1462
|
-
() => controller.abort(
|
|
1663
|
+
() => controller.abort(
|
|
1664
|
+
new Error("@vercel/flags-core: Datafile fetch deadline exceeded")
|
|
1665
|
+
),
|
|
1463
1666
|
DEFAULT_FETCH_TIMEOUT_MS
|
|
1464
1667
|
);
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
throw new Error("Fetch aborted");
|
|
1470
|
-
}
|
|
1471
|
-
options.signal.addEventListener("abort", onExternalAbort, { once: true });
|
|
1472
|
-
}
|
|
1473
|
-
try {
|
|
1668
|
+
let delay;
|
|
1669
|
+
const fetchAttempt = async () => {
|
|
1670
|
+
const token = await options.auth.resolveToken();
|
|
1671
|
+
signal.throwIfAborted();
|
|
1474
1672
|
const res = await options.fetch(`${options.host}/v1/datafile`, {
|
|
1475
1673
|
headers: {
|
|
1476
|
-
|
|
1674
|
+
...authHeaders(token, options.auth.sourceProjectId),
|
|
1477
1675
|
"User-Agent": `VercelFlagsCore/${version}`,
|
|
1478
1676
|
...process.env.VERCEL_ENV ? { "X-Vercel-Env": process.env.VERCEL_ENV } : null
|
|
1479
1677
|
},
|
|
1480
|
-
signal
|
|
1678
|
+
signal
|
|
1481
1679
|
});
|
|
1482
|
-
|
|
1483
|
-
_optionalChain([options, 'access', _41 => _41.signal, 'optionalAccess', _42 => _42.removeEventListener, 'call', _43 => _43("abort", onExternalAbort)]);
|
|
1680
|
+
signal.throwIfAborted();
|
|
1484
1681
|
if (!res.ok) {
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
throw error instanceof Error ? error : new Error("Unknown fetch error");
|
|
1492
|
-
}
|
|
1493
|
-
}
|
|
1494
|
-
|
|
1495
|
-
// src/controller/tagged-data.ts
|
|
1496
|
-
function tagData(data, origin) {
|
|
1497
|
-
const tagged = { ...data, _origin: origin };
|
|
1498
|
-
if (origin === "fetched" || origin === "poll" || origin === "stream") {
|
|
1499
|
-
tagged.fetchedAt = Date.now();
|
|
1500
|
-
} else if (typeof data.fetchedAt !== "number" || !Number.isFinite(data.fetchedAt) || data.fetchedAt < 0) {
|
|
1501
|
-
delete tagged.fetchedAt;
|
|
1502
|
-
}
|
|
1503
|
-
return tagged;
|
|
1504
|
-
}
|
|
1505
|
-
function originToMetricsSource(origin) {
|
|
1506
|
-
switch (origin) {
|
|
1507
|
-
case "stream":
|
|
1508
|
-
case "poll":
|
|
1509
|
-
case "provided":
|
|
1510
|
-
return "in-memory";
|
|
1511
|
-
case "fetched":
|
|
1512
|
-
return "remote";
|
|
1513
|
-
case "bundled":
|
|
1514
|
-
return "embedded";
|
|
1515
|
-
}
|
|
1516
|
-
}
|
|
1517
|
-
|
|
1518
|
-
// src/controller/typed-emitter.ts
|
|
1519
|
-
var TypedEmitter = (_class5 = class {constructor() { _class5.prototype.__init11.call(this); }
|
|
1520
|
-
__init11() {this.handlers = /* @__PURE__ */ new Map()}
|
|
1521
|
-
on(event, handler) {
|
|
1522
|
-
let set = this.handlers.get(event);
|
|
1523
|
-
if (!set) {
|
|
1524
|
-
set = /* @__PURE__ */ new Set();
|
|
1525
|
-
this.handlers.set(event, set);
|
|
1526
|
-
}
|
|
1527
|
-
set.add(handler);
|
|
1528
|
-
}
|
|
1529
|
-
off(event, handler) {
|
|
1530
|
-
_optionalChain([this, 'access', _47 => _47.handlers, 'access', _48 => _48.get, 'call', _49 => _49(event), 'optionalAccess', _50 => _50.delete, 'call', _51 => _51(handler)]);
|
|
1531
|
-
}
|
|
1532
|
-
emit(event, ...args) {
|
|
1533
|
-
const set = this.handlers.get(event);
|
|
1534
|
-
if (set) {
|
|
1535
|
-
for (const handler of set) {
|
|
1536
|
-
handler(...args);
|
|
1537
|
-
}
|
|
1682
|
+
void _optionalChain([res, 'access', _55 => _55.body, 'optionalAccess', _56 => _56.cancel, 'call', _57 => _57(), 'access', _58 => _58.catch, 'call', _59 => _59(() => {
|
|
1683
|
+
})]);
|
|
1684
|
+
throw new DatafileHttpError(
|
|
1685
|
+
res.status,
|
|
1686
|
+
res.status === 401 && options.auth.sourceProjectId ? unauthorizedMessage(options.auth.sourceProjectId) : res.statusText
|
|
1687
|
+
);
|
|
1538
1688
|
}
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
}
|
|
1553
|
-
fetchDatafile() {
|
|
1554
|
-
if (this.promise) return this.promise;
|
|
1555
|
-
const abortController = new AbortController();
|
|
1556
|
-
this.abortController = abortController;
|
|
1557
|
-
this.promise = fetchDatafile({
|
|
1558
|
-
...this.options,
|
|
1559
|
-
signal: abortController.signal
|
|
1560
|
-
}).then((data) => {
|
|
1561
|
-
abortController.signal.throwIfAborted();
|
|
1562
|
-
this.emit("data", data);
|
|
1563
|
-
return data;
|
|
1564
|
-
}).finally(() => {
|
|
1565
|
-
if (this.abortController === abortController) {
|
|
1566
|
-
this.promise = void 0;
|
|
1567
|
-
this.abortController = void 0;
|
|
1689
|
+
const data = await res.json();
|
|
1690
|
+
signal.throwIfAborted();
|
|
1691
|
+
return data;
|
|
1692
|
+
};
|
|
1693
|
+
try {
|
|
1694
|
+
for (let attempt = 0; ; attempt++) {
|
|
1695
|
+
if (attempt > 0) {
|
|
1696
|
+
await Promise.race([
|
|
1697
|
+
new Promise((resolve) => {
|
|
1698
|
+
delay = setTimeout(resolve, 100 * 2 ** (attempt - 1));
|
|
1699
|
+
}),
|
|
1700
|
+
aborted
|
|
1701
|
+
]);
|
|
1568
1702
|
}
|
|
1569
|
-
|
|
1570
|
-
return this.promise;
|
|
1571
|
-
}
|
|
1572
|
-
getUpdatedAtHeader(projectId, header) {
|
|
1573
|
-
if (!header) {
|
|
1574
|
-
return;
|
|
1575
|
-
}
|
|
1576
|
-
const prefix = `flags_${projectId}=`;
|
|
1577
|
-
const value = _optionalChain([header, 'access', _52 => _52.split, 'call', _53 => _53(";"), 'access', _54 => _54.map, 'call', _55 => _55((part) => part.trim()), 'access', _56 => _56.find, 'call', _57 => _57((part) => part.startsWith(prefix)), 'optionalAccess', _58 => _58.slice, 'call', _59 => _59(prefix.length)]);
|
|
1578
|
-
const timestamp = Number(value);
|
|
1579
|
-
return Number.isFinite(timestamp) && timestamp > 0 ? timestamp : void 0;
|
|
1580
|
-
}
|
|
1581
|
-
async resolveData(currentData, updatedAtHeader) {
|
|
1582
|
-
if (!currentData.configUpdatedAt) {
|
|
1583
|
-
return;
|
|
1584
|
-
}
|
|
1585
|
-
if (!updatedAtHeader) {
|
|
1586
|
-
return;
|
|
1587
|
-
}
|
|
1588
|
-
const currentUpdatedAt = Number(currentData.configUpdatedAt);
|
|
1589
|
-
if (updatedAtHeader <= currentUpdatedAt) {
|
|
1590
|
-
return [currentData, "HIT"];
|
|
1591
|
-
}
|
|
1592
|
-
const freshAt = Math.max(
|
|
1593
|
-
_nullishCoalesce(currentData.fetchedAt, () => ( -Infinity)),
|
|
1594
|
-
_optionalChain([this, 'access', _60 => _60.lastSeen, 'optionalAccess', _61 => _61.version]) === currentUpdatedAt ? this.lastSeen.at : -Infinity
|
|
1595
|
-
);
|
|
1596
|
-
const { staleWhileRevalidateMs } = this.options;
|
|
1597
|
-
if (staleWhileRevalidateMs > 0 && Date.now() - freshAt <= staleWhileRevalidateMs) {
|
|
1598
|
-
const pending = this.fetchDatafile();
|
|
1599
|
-
const signal = _optionalChain([this, 'access', _62 => _62.abortController, 'optionalAccess', _63 => _63.signal]);
|
|
1600
|
-
const background = pending.catch((error) => {
|
|
1601
|
-
if (!_optionalChain([signal, 'optionalAccess', _64 => _64.aborted])) {
|
|
1602
|
-
console.error("@vercel/flags-core: Header refresh failed:", error);
|
|
1603
|
-
}
|
|
1604
|
-
});
|
|
1703
|
+
signal.throwIfAborted();
|
|
1605
1704
|
try {
|
|
1606
|
-
|
|
1607
|
-
} catch (
|
|
1705
|
+
return await Promise.race([fetchAttempt(), aborted]);
|
|
1706
|
+
} catch (error) {
|
|
1707
|
+
signal.throwIfAborted();
|
|
1708
|
+
if (attempt === maxAttempts - 1 || error instanceof DatafileHttpError && !error.retryable) {
|
|
1709
|
+
throw error instanceof Error ? error : new Error("Unknown fetch error");
|
|
1710
|
+
}
|
|
1608
1711
|
}
|
|
1609
|
-
return [currentData, "STALE"];
|
|
1610
|
-
}
|
|
1611
|
-
const data = await this.fetchDatafile();
|
|
1612
|
-
return [tagData(data, "fetched"), "MISS"];
|
|
1613
|
-
}
|
|
1614
|
-
observe(version2, currentVersion) {
|
|
1615
|
-
this.highestObserved = Math.max(this.highestObserved, version2);
|
|
1616
|
-
if (version2 !== currentVersion || version2 !== this.highestObserved) return;
|
|
1617
|
-
this.lastSeen = { version: version2, at: Date.now() };
|
|
1618
|
-
}
|
|
1619
|
-
async read(currentData) {
|
|
1620
|
-
const { headers } = getRequestContext();
|
|
1621
|
-
const header = _nullishCoalesce(_optionalChain([headers, 'optionalAccess', _65 => _65["x-vercel-flags-config-versions"]]), () => ( _optionalChain([headers, 'optionalAccess', _66 => _66["flags-config-versions"]])));
|
|
1622
|
-
const data = await _asyncNullishCoalesce(currentData, async () => ( tagData(await this.fetchDatafile(), "fetched")));
|
|
1623
|
-
const updatedAtHeader = this.getUpdatedAtHeader(data.projectId, header);
|
|
1624
|
-
if (updatedAtHeader) {
|
|
1625
|
-
this.observe(updatedAtHeader, Number(data.configUpdatedAt));
|
|
1626
1712
|
}
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
}
|
|
1633
|
-
/**
|
|
1634
|
-
* Abort the current header-driven fetch and discard its pending work.
|
|
1635
|
-
*/
|
|
1636
|
-
stop() {
|
|
1637
|
-
_optionalChain([this, 'access', _67 => _67.abortController, 'optionalAccess', _68 => _68.abort, 'call', _69 => _69()]);
|
|
1638
|
-
this.abortController = void 0;
|
|
1639
|
-
this.promise = void 0;
|
|
1640
|
-
this.lastSeen = void 0;
|
|
1641
|
-
this.highestObserved = 0;
|
|
1713
|
+
} finally {
|
|
1714
|
+
clearTimeout(timeoutId);
|
|
1715
|
+
clearTimeout(delay);
|
|
1716
|
+
signal.removeEventListener("abort", onAbort);
|
|
1717
|
+
_optionalChain([options, 'access', _60 => _60.signal, 'optionalAccess', _61 => _61.removeEventListener, 'call', _62 => _62("abort", onExternalAbort)]);
|
|
1642
1718
|
}
|
|
1643
|
-
}
|
|
1719
|
+
}
|
|
1644
1720
|
|
|
1645
1721
|
// src/controller/normalized-options.ts
|
|
1646
1722
|
|
|
@@ -1648,7 +1724,6 @@ var DEFAULT_STREAM_INIT_TIMEOUT_MS = 3e3;
|
|
|
1648
1724
|
var DEFAULT_POLLING_INTERVAL_MS = 3e4;
|
|
1649
1725
|
var MIN_POLLING_INTERVAL_MS = 3e4;
|
|
1650
1726
|
var DEFAULT_POLLING_INIT_TIMEOUT_MS = 3e3;
|
|
1651
|
-
var DEFAULT_STALE_WHILE_REVALIDATE_MS = 1e4;
|
|
1652
1727
|
function normalizeOptions(options) {
|
|
1653
1728
|
const autoDetectedBuildStep = process.env.CI === "1" || process.env.NEXT_PHASE === "phase-production-build";
|
|
1654
1729
|
const buildStep = _nullishCoalesce(options.buildStep, () => ( autoDetectedBuildStep));
|
|
@@ -1681,19 +1756,11 @@ function normalizeOptions(options) {
|
|
|
1681
1756
|
initTimeoutMs: options.polling.initTimeoutMs
|
|
1682
1757
|
};
|
|
1683
1758
|
}
|
|
1684
|
-
const staleWhileRevalidateMs = _nullishCoalesce(options.staleWhileRevalidateMs, () => ( DEFAULT_STALE_WHILE_REVALIDATE_MS));
|
|
1685
|
-
if (!Number.isFinite(staleWhileRevalidateMs) || staleWhileRevalidateMs < 0) {
|
|
1686
|
-
throw new Error(
|
|
1687
|
-
"@vercel/flags-core: staleWhileRevalidateMs must be a finite, non-negative number."
|
|
1688
|
-
);
|
|
1689
|
-
}
|
|
1690
1759
|
return {
|
|
1691
1760
|
auth: options.auth,
|
|
1692
1761
|
datafile: options.datafile,
|
|
1693
1762
|
stream,
|
|
1694
1763
|
polling,
|
|
1695
|
-
vercel: _nullishCoalesce(options.vercel, () => ( process.env.VERCEL === "1")),
|
|
1696
|
-
staleWhileRevalidateMs,
|
|
1697
1764
|
buildStep,
|
|
1698
1765
|
fetch: _nullishCoalesce(options.fetch, () => ( globalThis.fetch)),
|
|
1699
1766
|
waitUntil: _nullishCoalesce(options.waitUntil, () => ( _functions.waitUntil)),
|
|
@@ -1704,6 +1771,35 @@ function normalizeOptions(options) {
|
|
|
1704
1771
|
};
|
|
1705
1772
|
}
|
|
1706
1773
|
|
|
1774
|
+
// src/controller/typed-emitter.ts
|
|
1775
|
+
var TypedEmitter = (_class5 = class {constructor() { _class5.prototype.__init12.call(this); }
|
|
1776
|
+
__init12() {this.handlers = /* @__PURE__ */ new Map()}
|
|
1777
|
+
on(event, handler) {
|
|
1778
|
+
let set = this.handlers.get(event);
|
|
1779
|
+
if (!set) {
|
|
1780
|
+
set = /* @__PURE__ */ new Set();
|
|
1781
|
+
this.handlers.set(event, set);
|
|
1782
|
+
}
|
|
1783
|
+
set.add(handler);
|
|
1784
|
+
}
|
|
1785
|
+
off(event, handler) {
|
|
1786
|
+
const set = this.handlers.get(event);
|
|
1787
|
+
if (!set) return;
|
|
1788
|
+
set.delete(handler);
|
|
1789
|
+
if (set.size === 0) {
|
|
1790
|
+
this.handlers.delete(event);
|
|
1791
|
+
}
|
|
1792
|
+
}
|
|
1793
|
+
emit(event, ...args) {
|
|
1794
|
+
const set = this.handlers.get(event);
|
|
1795
|
+
if (set) {
|
|
1796
|
+
for (const handler of set) {
|
|
1797
|
+
handler(...args);
|
|
1798
|
+
}
|
|
1799
|
+
}
|
|
1800
|
+
}
|
|
1801
|
+
}, _class5);
|
|
1802
|
+
|
|
1707
1803
|
// src/controller/polling-source.ts
|
|
1708
1804
|
var PollingSource = class extends TypedEmitter {
|
|
1709
1805
|
|
|
@@ -1718,14 +1814,17 @@ var PollingSource = class extends TypedEmitter {
|
|
|
1718
1814
|
* Emits 'data' on success, 'error' on failure.
|
|
1719
1815
|
*/
|
|
1720
1816
|
async poll() {
|
|
1721
|
-
if (_optionalChain([this, 'access',
|
|
1817
|
+
if (_optionalChain([this, 'access', _63 => _63.abortController, 'optionalAccess', _64 => _64.signal, 'access', _65 => _65.aborted])) return;
|
|
1818
|
+
this.abortController ??= new AbortController();
|
|
1819
|
+
const controller = this.abortController;
|
|
1722
1820
|
try {
|
|
1723
1821
|
const data = await fetchDatafile({
|
|
1724
1822
|
...this.config,
|
|
1725
|
-
signal:
|
|
1823
|
+
signal: controller.signal
|
|
1726
1824
|
});
|
|
1727
1825
|
this.emit("data", data);
|
|
1728
1826
|
} catch (error) {
|
|
1827
|
+
controller.signal.throwIfAborted();
|
|
1729
1828
|
const err = error instanceof Error ? error : new Error("Unknown poll error");
|
|
1730
1829
|
this.emit("error", err);
|
|
1731
1830
|
}
|
|
@@ -1737,9 +1836,9 @@ var PollingSource = class extends TypedEmitter {
|
|
|
1737
1836
|
*/
|
|
1738
1837
|
startInterval() {
|
|
1739
1838
|
if (this.intervalId) return;
|
|
1740
|
-
this.abortController = new AbortController();
|
|
1741
1839
|
this.intervalId = setInterval(
|
|
1742
|
-
() => void this.poll()
|
|
1840
|
+
() => void this.poll().catch(() => {
|
|
1841
|
+
}),
|
|
1743
1842
|
this.config.polling.intervalMs
|
|
1744
1843
|
);
|
|
1745
1844
|
}
|
|
@@ -1751,7 +1850,7 @@ var PollingSource = class extends TypedEmitter {
|
|
|
1751
1850
|
clearInterval(this.intervalId);
|
|
1752
1851
|
this.intervalId = void 0;
|
|
1753
1852
|
}
|
|
1754
|
-
_optionalChain([this, 'access',
|
|
1853
|
+
_optionalChain([this, 'access', _66 => _66.abortController, 'optionalAccess', _67 => _67.abort, 'call', _68 => _68()]);
|
|
1755
1854
|
this.abortController = void 0;
|
|
1756
1855
|
}
|
|
1757
1856
|
};
|
|
@@ -1780,8 +1879,8 @@ function backoff(retryCount) {
|
|
|
1780
1879
|
return delay + Math.random() * 1e3;
|
|
1781
1880
|
}
|
|
1782
1881
|
var UnauthorizedError = class extends Error {
|
|
1783
|
-
constructor() {
|
|
1784
|
-
super(
|
|
1882
|
+
constructor(sourceProjectId) {
|
|
1883
|
+
super(`stream: ${unauthorizedMessage(sourceProjectId)}`);
|
|
1785
1884
|
this.name = "UnauthorizedError";
|
|
1786
1885
|
}
|
|
1787
1886
|
};
|
|
@@ -1830,7 +1929,7 @@ async function connectStream(config, callbacks) {
|
|
|
1830
1929
|
if (pingTimeoutId !== void 0) clearTimeout(pingTimeoutId);
|
|
1831
1930
|
if (!initialDataReceived) return;
|
|
1832
1931
|
pingTimeoutId = setTimeout(() => {
|
|
1833
|
-
_optionalChain([responseBody, 'optionalAccess',
|
|
1932
|
+
_optionalChain([responseBody, 'optionalAccess', _69 => _69.cancel, 'call', _70 => _70(), 'access', _71 => _71.catch, 'call', _72 => _72(() => {
|
|
1834
1933
|
})]);
|
|
1835
1934
|
connectionAbort.abort();
|
|
1836
1935
|
}, PING_TIMEOUT_MS);
|
|
@@ -1841,7 +1940,7 @@ async function connectStream(config, callbacks) {
|
|
|
1841
1940
|
throw new TokenResolutionError(error);
|
|
1842
1941
|
});
|
|
1843
1942
|
const headers = {
|
|
1844
|
-
|
|
1943
|
+
...authHeaders(token, config.sourceProjectId),
|
|
1845
1944
|
"User-Agent": `VercelFlagsCore/${version}`,
|
|
1846
1945
|
"X-Retry-Attempt": String(retryCount)
|
|
1847
1946
|
};
|
|
@@ -1852,7 +1951,7 @@ async function connectStream(config, callbacks) {
|
|
|
1852
1951
|
if (vercelEnv) {
|
|
1853
1952
|
headers["X-Vercel-Env"] = vercelEnv;
|
|
1854
1953
|
}
|
|
1855
|
-
const revision = _optionalChain([config, 'access',
|
|
1954
|
+
const revision = _optionalChain([config, 'access', _73 => _73.revision, 'optionalCall', _74 => _74()]);
|
|
1856
1955
|
if (revision !== void 0) {
|
|
1857
1956
|
headers["X-Revision"] = String(revision);
|
|
1858
1957
|
}
|
|
@@ -1863,7 +1962,7 @@ async function connectStream(config, callbacks) {
|
|
|
1863
1962
|
if (!response.ok) {
|
|
1864
1963
|
if (response.status === 401) {
|
|
1865
1964
|
if (!initialDataReceived) {
|
|
1866
|
-
rejectInit(new UnauthorizedError());
|
|
1965
|
+
rejectInit(new UnauthorizedError(config.sourceProjectId));
|
|
1867
1966
|
}
|
|
1868
1967
|
abortController.abort();
|
|
1869
1968
|
break;
|
|
@@ -1898,7 +1997,7 @@ async function connectStream(config, callbacks) {
|
|
|
1898
1997
|
let message;
|
|
1899
1998
|
try {
|
|
1900
1999
|
message = JSON.parse(line);
|
|
1901
|
-
} catch (
|
|
2000
|
+
} catch (e12) {
|
|
1902
2001
|
console.warn(
|
|
1903
2002
|
"@vercel/flags-core: Failed to parse stream message, skipping"
|
|
1904
2003
|
);
|
|
@@ -1914,7 +2013,7 @@ async function connectStream(config, callbacks) {
|
|
|
1914
2013
|
resetPingTimeout();
|
|
1915
2014
|
}
|
|
1916
2015
|
if (message.type === "primed") {
|
|
1917
|
-
_optionalChain([onPrimed, 'optionalCall',
|
|
2016
|
+
_optionalChain([onPrimed, 'optionalCall', _75 => _75(message)]);
|
|
1918
2017
|
retryCount = 0;
|
|
1919
2018
|
if (!initialDataReceived) {
|
|
1920
2019
|
initialDataReceived = true;
|
|
@@ -1937,7 +2036,7 @@ async function connectStream(config, callbacks) {
|
|
|
1937
2036
|
clearTimeout(pingTimeoutId);
|
|
1938
2037
|
abortController.signal.removeEventListener("abort", onMainAbort);
|
|
1939
2038
|
if (!abortController.signal.aborted) {
|
|
1940
|
-
_optionalChain([onDisconnect, 'optionalCall',
|
|
2039
|
+
_optionalChain([onDisconnect, 'optionalCall', _76 => _76()]);
|
|
1941
2040
|
retryCount++;
|
|
1942
2041
|
const elapsed = Date.now() - lastAttemptTime;
|
|
1943
2042
|
const minGap = Math.max(0, BASE_RETRY_DELAY_MS - elapsed);
|
|
@@ -1958,7 +2057,7 @@ async function connectStream(config, callbacks) {
|
|
|
1958
2057
|
if (!connectionAbort.signal.aborted) {
|
|
1959
2058
|
lastError = error;
|
|
1960
2059
|
}
|
|
1961
|
-
_optionalChain([onDisconnect, 'optionalCall',
|
|
2060
|
+
_optionalChain([onDisconnect, 'optionalCall', _77 => _77()]);
|
|
1962
2061
|
retryCount++;
|
|
1963
2062
|
const elapsed = Date.now() - lastAttemptTime;
|
|
1964
2063
|
const minGap = Math.max(0, BASE_RETRY_DELAY_MS - elapsed);
|
|
@@ -2007,6 +2106,7 @@ var StreamSource = class extends TypedEmitter {
|
|
|
2007
2106
|
{
|
|
2008
2107
|
host: this.options.host,
|
|
2009
2108
|
resolveToken: () => this.options.auth.resolveToken(),
|
|
2109
|
+
sourceProjectId: this.options.auth.sourceProjectId,
|
|
2010
2110
|
abortController,
|
|
2011
2111
|
fetch: this.options.fetch,
|
|
2012
2112
|
revision: this.revision
|
|
@@ -2037,12 +2137,29 @@ var StreamSource = class extends TypedEmitter {
|
|
|
2037
2137
|
* Stop the stream connection.
|
|
2038
2138
|
*/
|
|
2039
2139
|
stop() {
|
|
2040
|
-
_optionalChain([this, 'access',
|
|
2140
|
+
_optionalChain([this, 'access', _78 => _78.abortController, 'optionalAccess', _79 => _79.abort, 'call', _80 => _80()]);
|
|
2041
2141
|
this.abortController = void 0;
|
|
2042
2142
|
this.promise = void 0;
|
|
2043
2143
|
}
|
|
2044
2144
|
};
|
|
2045
2145
|
|
|
2146
|
+
// src/controller/tagged-data.ts
|
|
2147
|
+
function tagData(data, origin) {
|
|
2148
|
+
return Object.assign(data, { _origin: origin });
|
|
2149
|
+
}
|
|
2150
|
+
function originToMetricsSource(origin) {
|
|
2151
|
+
switch (origin) {
|
|
2152
|
+
case "stream":
|
|
2153
|
+
case "poll":
|
|
2154
|
+
case "provided":
|
|
2155
|
+
return "in-memory";
|
|
2156
|
+
case "fetched":
|
|
2157
|
+
return "remote";
|
|
2158
|
+
case "bundled":
|
|
2159
|
+
return "embedded";
|
|
2160
|
+
}
|
|
2161
|
+
}
|
|
2162
|
+
|
|
2046
2163
|
// src/controller/index.ts
|
|
2047
2164
|
function parseConfigUpdatedAt(value) {
|
|
2048
2165
|
if (typeof value === "number") return value;
|
|
@@ -2052,7 +2169,7 @@ function parseConfigUpdatedAt(value) {
|
|
|
2052
2169
|
}
|
|
2053
2170
|
return void 0;
|
|
2054
2171
|
}
|
|
2055
|
-
var Controller = (
|
|
2172
|
+
var Controller = (_class6 = class {
|
|
2056
2173
|
|
|
2057
2174
|
// State machine
|
|
2058
2175
|
__init13() {this.state = "idle"}
|
|
@@ -2060,34 +2177,33 @@ var Controller = (_class7 = class {
|
|
|
2060
2177
|
|
|
2061
2178
|
// Memoized data spread for read() / getDatafile().
|
|
2062
2179
|
// Rebuilt only when `this.data` reference changes (e.g. on stream/poll update).
|
|
2063
|
-
// Holds the result of stripping
|
|
2180
|
+
// Holds the result of stripping `_origin`; metrics are appended per-call.
|
|
2064
2181
|
__init14() {this.dataViewSource = void 0}
|
|
2065
2182
|
__init15() {this.dataViewBase = void 0}
|
|
2066
2183
|
// Sources (I/O delegates)
|
|
2067
2184
|
|
|
2068
2185
|
|
|
2069
2186
|
|
|
2070
|
-
|
|
2071
2187
|
// Usage tracking
|
|
2072
2188
|
|
|
2073
2189
|
__init16() {this.isFirstGetData = true}
|
|
2074
2190
|
// Build-step deduplication
|
|
2075
2191
|
__init17() {this.buildDataPromise = null}
|
|
2076
2192
|
__init18() {this.buildReadTracked = false}
|
|
2077
|
-
// Suppresses usage tracking
|
|
2193
|
+
// Suppresses usage tracking while the credential is rejected. Set on a 401
|
|
2194
|
+
// from any source, cleared as soon as a source delivers data again.
|
|
2078
2195
|
__init19() {this.unauthorized = false}
|
|
2079
|
-
constructor(options) {;
|
|
2196
|
+
constructor(options) {;_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);
|
|
2080
2197
|
this.options = normalizeOptions(options);
|
|
2081
2198
|
this.streamSource = new StreamSource(
|
|
2082
2199
|
this.options,
|
|
2083
|
-
() => _optionalChain([this, 'access',
|
|
2200
|
+
() => _optionalChain([this, 'access', _81 => _81.data, 'optionalAccess', _82 => _82.revision])
|
|
2084
2201
|
);
|
|
2085
2202
|
this.pollingSource = new PollingSource(this.options);
|
|
2086
2203
|
this.bundledSource = new BundledSource({
|
|
2087
2204
|
auth: this.options.auth,
|
|
2088
2205
|
readBundledDefinitions
|
|
2089
2206
|
});
|
|
2090
|
-
this.headerSource = new HeaderSource(this.options);
|
|
2091
2207
|
this.wireSourceEvents();
|
|
2092
2208
|
if (this.options.datafile) {
|
|
2093
2209
|
this.data = tagData(this.options.datafile, "provided");
|
|
@@ -2096,11 +2212,13 @@ var Controller = (_class7 = class {
|
|
|
2096
2212
|
}
|
|
2097
2213
|
// Source event handlers (stored for cleanup)
|
|
2098
2214
|
__init20() {this.onStreamData = (data) => {
|
|
2215
|
+
this.unauthorized = false;
|
|
2099
2216
|
if (this.isNewerData(data)) {
|
|
2100
2217
|
this.data = tagData(data, "stream");
|
|
2101
2218
|
}
|
|
2102
2219
|
}}
|
|
2103
2220
|
__init21() {this.onStreamPrimed = () => {
|
|
2221
|
+
this.unauthorized = false;
|
|
2104
2222
|
if (this.state === "degraded" || this.state === "initializing:stream") {
|
|
2105
2223
|
this.transition("streaming");
|
|
2106
2224
|
}
|
|
@@ -2116,18 +2234,15 @@ var Controller = (_class7 = class {
|
|
|
2116
2234
|
}
|
|
2117
2235
|
}}
|
|
2118
2236
|
__init24() {this.onPollData = (data) => {
|
|
2237
|
+
this.unauthorized = false;
|
|
2119
2238
|
if (this.isNewerData(data)) {
|
|
2120
2239
|
this.data = tagData(data, "poll");
|
|
2121
2240
|
}
|
|
2122
2241
|
}}
|
|
2123
2242
|
__init25() {this.onPollError = (error) => {
|
|
2243
|
+
this.noteUnauthorized(error);
|
|
2124
2244
|
console.error("@vercel/flags-core: Poll failed:", error);
|
|
2125
2245
|
}}
|
|
2126
|
-
__init26() {this.onFetchedData = (data) => {
|
|
2127
|
-
if (this.isNewerData(data)) {
|
|
2128
|
-
this.data = tagData(data, "fetched");
|
|
2129
|
-
}
|
|
2130
|
-
}}
|
|
2131
2246
|
// ---------------------------------------------------------------------------
|
|
2132
2247
|
// Source event wiring
|
|
2133
2248
|
// ---------------------------------------------------------------------------
|
|
@@ -2138,7 +2253,6 @@ var Controller = (_class7 = class {
|
|
|
2138
2253
|
this.streamSource.on("disconnected", this.onStreamDisconnected);
|
|
2139
2254
|
this.pollingSource.on("data", this.onPollData);
|
|
2140
2255
|
this.pollingSource.on("error", this.onPollError);
|
|
2141
|
-
this.headerSource.on("data", this.onFetchedData);
|
|
2142
2256
|
}
|
|
2143
2257
|
unwireSourceEvents() {
|
|
2144
2258
|
this.streamSource.off("data", this.onStreamData);
|
|
@@ -2147,7 +2261,6 @@ var Controller = (_class7 = class {
|
|
|
2147
2261
|
this.streamSource.off("disconnected", this.onStreamDisconnected);
|
|
2148
2262
|
this.pollingSource.off("data", this.onPollData);
|
|
2149
2263
|
this.pollingSource.off("error", this.onPollError);
|
|
2150
|
-
this.headerSource.off("data", this.onFetchedData);
|
|
2151
2264
|
}
|
|
2152
2265
|
// ---------------------------------------------------------------------------
|
|
2153
2266
|
// State machine
|
|
@@ -2165,8 +2278,6 @@ var Controller = (_class7 = class {
|
|
|
2165
2278
|
return "streaming";
|
|
2166
2279
|
case "polling":
|
|
2167
2280
|
return "polling";
|
|
2168
|
-
case "vercel":
|
|
2169
|
-
return "vercel";
|
|
2170
2281
|
default:
|
|
2171
2282
|
return "offline";
|
|
2172
2283
|
}
|
|
@@ -2180,7 +2291,6 @@ var Controller = (_class7 = class {
|
|
|
2180
2291
|
* Build step: datafile → bundled → one-time fetch
|
|
2181
2292
|
* Streaming mode: stream → datafile → bundled
|
|
2182
2293
|
* Polling mode (no stream): poll → datafile → bundled
|
|
2183
|
-
* Vercel mode: datafile → bundled; fetch only on a read
|
|
2184
2294
|
* Offline mode (neither): datafile → bundled → one-time fetch
|
|
2185
2295
|
*/
|
|
2186
2296
|
async initialize() {
|
|
@@ -2194,20 +2304,13 @@ var Controller = (_class7 = class {
|
|
|
2194
2304
|
this.data = tagData(this.options.datafile, "provided");
|
|
2195
2305
|
}
|
|
2196
2306
|
if (!this.data) {
|
|
2197
|
-
this.transition("initializing:fallback");
|
|
2198
|
-
let bundled;
|
|
2199
2307
|
try {
|
|
2200
|
-
bundled = await this.bundledSource.tryLoad();
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
|
|
2308
|
+
const bundled = await this.bundledSource.tryLoad();
|
|
2309
|
+
if (bundled) {
|
|
2310
|
+
this.data = tagData(bundled, "bundled");
|
|
2311
|
+
}
|
|
2312
|
+
} catch (e13) {
|
|
2205
2313
|
}
|
|
2206
|
-
if (bundled) this.data = tagData(bundled, "bundled");
|
|
2207
|
-
}
|
|
2208
|
-
if (this.headerSource.isAvailable()) {
|
|
2209
|
-
this.transition("vercel");
|
|
2210
|
-
return;
|
|
2211
2314
|
}
|
|
2212
2315
|
if (this.data) {
|
|
2213
2316
|
if (this.options.stream.enabled) {
|
|
@@ -2273,7 +2376,6 @@ var Controller = (_class7 = class {
|
|
|
2273
2376
|
this.unwireSourceEvents();
|
|
2274
2377
|
this.streamSource.stop();
|
|
2275
2378
|
this.pollingSource.stop();
|
|
2276
|
-
this.headerSource.stop();
|
|
2277
2379
|
this.data = this.options.datafile ? tagData(this.options.datafile, "provided") : void 0;
|
|
2278
2380
|
this.transition("shutdown");
|
|
2279
2381
|
await this.usageTracker.shutdown();
|
|
@@ -2309,9 +2411,10 @@ var Controller = (_class7 = class {
|
|
|
2309
2411
|
this.data = tagData(fetched, "fetched");
|
|
2310
2412
|
result = this.data;
|
|
2311
2413
|
cacheStatus = "MISS";
|
|
2312
|
-
} catch (
|
|
2313
|
-
|
|
2314
|
-
|
|
2414
|
+
} catch (error) {
|
|
2415
|
+
this.noteUnauthorized(error);
|
|
2416
|
+
throw this.noDefinitionsError(
|
|
2417
|
+
". Initialize the client or provide a datafile."
|
|
2315
2418
|
);
|
|
2316
2419
|
}
|
|
2317
2420
|
}
|
|
@@ -2354,10 +2457,6 @@ var Controller = (_class7 = class {
|
|
|
2354
2457
|
if (this.options.buildStep) {
|
|
2355
2458
|
return this.resolveDataForBuildStep();
|
|
2356
2459
|
}
|
|
2357
|
-
if (this.state === "vercel") {
|
|
2358
|
-
const result = await this.headerSource.read(this.data);
|
|
2359
|
-
if (result) return result;
|
|
2360
|
-
}
|
|
2361
2460
|
if (this.data) {
|
|
2362
2461
|
const cacheStatus = this.isConnected ? "HIT" : "STALE";
|
|
2363
2462
|
return [this.data, cacheStatus];
|
|
@@ -2377,9 +2476,7 @@ var Controller = (_class7 = class {
|
|
|
2377
2476
|
await this.streamSource.start();
|
|
2378
2477
|
return true;
|
|
2379
2478
|
} catch (error) {
|
|
2380
|
-
|
|
2381
|
-
this.unauthorized = true;
|
|
2382
|
-
}
|
|
2479
|
+
this.noteUnauthorized(error);
|
|
2383
2480
|
return false;
|
|
2384
2481
|
}
|
|
2385
2482
|
}
|
|
@@ -2407,9 +2504,7 @@ var Controller = (_class7 = class {
|
|
|
2407
2504
|
return true;
|
|
2408
2505
|
} catch (error) {
|
|
2409
2506
|
clearTimeout(timeoutId);
|
|
2410
|
-
|
|
2411
|
-
this.unauthorized = true;
|
|
2412
|
-
}
|
|
2507
|
+
this.noteUnauthorized(error);
|
|
2413
2508
|
return false;
|
|
2414
2509
|
}
|
|
2415
2510
|
}
|
|
@@ -2432,7 +2527,7 @@ var Controller = (_class7 = class {
|
|
|
2432
2527
|
return true;
|
|
2433
2528
|
}
|
|
2434
2529
|
return false;
|
|
2435
|
-
} catch (
|
|
2530
|
+
} catch (e14) {
|
|
2436
2531
|
return false;
|
|
2437
2532
|
}
|
|
2438
2533
|
}
|
|
@@ -2457,11 +2552,16 @@ var Controller = (_class7 = class {
|
|
|
2457
2552
|
return true;
|
|
2458
2553
|
}
|
|
2459
2554
|
return false;
|
|
2460
|
-
} catch (
|
|
2555
|
+
} catch (e15) {
|
|
2461
2556
|
clearTimeout(timeoutId);
|
|
2462
2557
|
return false;
|
|
2463
2558
|
}
|
|
2464
2559
|
}
|
|
2560
|
+
noteUnauthorized(error) {
|
|
2561
|
+
if (error instanceof UnauthorizedError || error instanceof Error && error.message.includes("401")) {
|
|
2562
|
+
this.unauthorized = true;
|
|
2563
|
+
}
|
|
2564
|
+
}
|
|
2465
2565
|
// ---------------------------------------------------------------------------
|
|
2466
2566
|
// Build step helpers
|
|
2467
2567
|
// ---------------------------------------------------------------------------
|
|
@@ -2507,10 +2607,11 @@ var Controller = (_class7 = class {
|
|
|
2507
2607
|
fetch: this.options.fetch
|
|
2508
2608
|
});
|
|
2509
2609
|
return tagData(fetched, "fetched");
|
|
2510
|
-
} catch (
|
|
2610
|
+
} catch (error) {
|
|
2611
|
+
this.noteUnauthorized(error);
|
|
2511
2612
|
}
|
|
2512
|
-
throw
|
|
2513
|
-
"
|
|
2613
|
+
throw this.noDefinitionsError(
|
|
2614
|
+
" during build. Provide a datafile or bundled definitions."
|
|
2514
2615
|
);
|
|
2515
2616
|
}
|
|
2516
2617
|
// ---------------------------------------------------------------------------
|
|
@@ -2541,11 +2642,20 @@ var Controller = (_class7 = class {
|
|
|
2541
2642
|
this.data = tagData(fetched, "fetched");
|
|
2542
2643
|
this.transition("degraded");
|
|
2543
2644
|
return;
|
|
2544
|
-
} catch (
|
|
2645
|
+
} catch (e16) {
|
|
2545
2646
|
}
|
|
2546
2647
|
}
|
|
2547
|
-
throw
|
|
2548
|
-
|
|
2648
|
+
throw this.noDefinitionsError(". Bundled definitions not found.");
|
|
2649
|
+
}
|
|
2650
|
+
/**
|
|
2651
|
+
* `detail` continues the sentence "No flag definitions available", so it
|
|
2652
|
+
* starts with either "." or " during build.".
|
|
2653
|
+
*/
|
|
2654
|
+
noDefinitionsError(detail) {
|
|
2655
|
+
const { sourceProjectId } = this.options.auth;
|
|
2656
|
+
const reason = this.unauthorized && sourceProjectId ? ` Request was ${unauthorizedMessage(sourceProjectId)}` : "";
|
|
2657
|
+
return new Error(
|
|
2658
|
+
`@vercel/flags-core: No flag definitions available${detail}${reason}`
|
|
2549
2659
|
);
|
|
2550
2660
|
}
|
|
2551
2661
|
/**
|
|
@@ -2593,11 +2703,11 @@ var Controller = (_class7 = class {
|
|
|
2593
2703
|
this.data = tagData(fetched, "fetched");
|
|
2594
2704
|
this.transition("degraded");
|
|
2595
2705
|
return [this.data, "MISS"];
|
|
2596
|
-
} catch (
|
|
2706
|
+
} catch (e17) {
|
|
2597
2707
|
}
|
|
2598
2708
|
}
|
|
2599
|
-
throw
|
|
2600
|
-
"
|
|
2709
|
+
throw this.noDefinitionsError(
|
|
2710
|
+
". Provide a datafile or bundled definitions."
|
|
2601
2711
|
);
|
|
2602
2712
|
}
|
|
2603
2713
|
// ---------------------------------------------------------------------------
|
|
@@ -2645,11 +2755,11 @@ var Controller = (_class7 = class {
|
|
|
2645
2755
|
duration: Date.now() - startTime,
|
|
2646
2756
|
mode: mode === "streaming" ? "stream" : mode === "polling" ? "poll" : mode
|
|
2647
2757
|
};
|
|
2648
|
-
const configUpdatedAt = _optionalChain([this, 'access',
|
|
2758
|
+
const configUpdatedAt = _optionalChain([this, 'access', _83 => _83.data, 'optionalAccess', _84 => _84.configUpdatedAt]);
|
|
2649
2759
|
if (typeof configUpdatedAt === "number") {
|
|
2650
2760
|
trackOptions.configUpdatedAt = configUpdatedAt;
|
|
2651
2761
|
}
|
|
2652
|
-
const revision = _optionalChain([this, 'access',
|
|
2762
|
+
const revision = _optionalChain([this, 'access', _85 => _85.data, 'optionalAccess', _86 => _86.revision]);
|
|
2653
2763
|
if (typeof revision === "number") {
|
|
2654
2764
|
trackOptions.revision = revision;
|
|
2655
2765
|
}
|
|
@@ -2668,89 +2778,7 @@ var Controller = (_class7 = class {
|
|
|
2668
2778
|
clientName: _nullishCoalesce(options.clientName, () => ( this.options.clientName))
|
|
2669
2779
|
});
|
|
2670
2780
|
}
|
|
2671
|
-
},
|
|
2672
|
-
|
|
2673
|
-
// src/controller/auth.ts
|
|
2674
|
-
|
|
2675
|
-
|
|
2676
|
-
// src/utils/sdk-keys.ts
|
|
2677
|
-
var SDK_KEY_REGEX = /^vf_(?:server|client)_/;
|
|
2678
|
-
function parseSdkKeyFromFlagsConnectionString(text) {
|
|
2679
|
-
if (SDK_KEY_REGEX.test(text)) return text;
|
|
2680
|
-
try {
|
|
2681
|
-
if (!text.startsWith("flags:")) return null;
|
|
2682
|
-
const params = new URLSearchParams(text.slice(6));
|
|
2683
|
-
const sdkKey = params.get("sdkKey");
|
|
2684
|
-
if (sdkKey && SDK_KEY_REGEX.test(sdkKey)) return sdkKey;
|
|
2685
|
-
} catch (e17) {
|
|
2686
|
-
}
|
|
2687
|
-
return null;
|
|
2688
|
-
}
|
|
2689
|
-
|
|
2690
|
-
// src/controller/auth.ts
|
|
2691
|
-
async function getOidcToken() {
|
|
2692
|
-
try {
|
|
2693
|
-
return await _oidc.getVercelOidcToken.call(void 0, );
|
|
2694
|
-
} catch (e18) {
|
|
2695
|
-
throw new Error(
|
|
2696
|
-
[
|
|
2697
|
-
"@vercel/flags-core: Failed to get OIDC token.",
|
|
2698
|
-
"Are you running in a Vercel Environment where OIDC tokens are available?",
|
|
2699
|
-
"Did you mean to use an SDK Key instead? Use the environment variable FLAGS or pass it directly to the client."
|
|
2700
|
-
].join(" ")
|
|
2701
|
-
);
|
|
2702
|
-
}
|
|
2703
|
-
}
|
|
2704
|
-
function getProjectIdFromOidcToken(oidcToken) {
|
|
2705
|
-
const tokenParts = oidcToken.split(".");
|
|
2706
|
-
if (tokenParts.length !== 3 || !tokenParts[1]) {
|
|
2707
|
-
throw new Error("@vercel/flags-core: Invalid OIDC token");
|
|
2708
|
-
}
|
|
2709
|
-
const payload = JSON.parse(
|
|
2710
|
-
Buffer.from(tokenParts[1], "base64url").toString("utf8")
|
|
2711
|
-
);
|
|
2712
|
-
if (typeof payload.project_id !== "string" || !payload.project_id) {
|
|
2713
|
-
throw new Error(
|
|
2714
|
-
"@vercel/flags-core: Missing project_id claim in OIDC token"
|
|
2715
|
-
);
|
|
2716
|
-
}
|
|
2717
|
-
return payload.project_id;
|
|
2718
|
-
}
|
|
2719
|
-
var Authentication = class {
|
|
2720
|
-
|
|
2721
|
-
constructor(sdkKeyOrConnectionString) {
|
|
2722
|
-
if (sdkKeyOrConnectionString !== void 0) {
|
|
2723
|
-
if (typeof sdkKeyOrConnectionString !== "string") {
|
|
2724
|
-
throw new Error(
|
|
2725
|
-
`@vercel/flags-core: Invalid sdkKey. Expected string, got ${typeof sdkKeyOrConnectionString}`
|
|
2726
|
-
);
|
|
2727
|
-
}
|
|
2728
|
-
const parsed = parseSdkKeyFromFlagsConnectionString(
|
|
2729
|
-
sdkKeyOrConnectionString
|
|
2730
|
-
);
|
|
2731
|
-
if (!parsed) {
|
|
2732
|
-
throw new Error("@vercel/flags-core: Missing sdkKey");
|
|
2733
|
-
}
|
|
2734
|
-
this.sdkKey = parsed;
|
|
2735
|
-
}
|
|
2736
|
-
}
|
|
2737
|
-
async resolveToken() {
|
|
2738
|
-
if (this.sdkKey) {
|
|
2739
|
-
return this.sdkKey;
|
|
2740
|
-
}
|
|
2741
|
-
return await getOidcToken();
|
|
2742
|
-
}
|
|
2743
|
-
async resolveBundledDefinitionsLookup() {
|
|
2744
|
-
if (this.sdkKey) {
|
|
2745
|
-
return { type: "sdk-key", sdkKey: this.sdkKey };
|
|
2746
|
-
}
|
|
2747
|
-
const oidcToken = await this.resolveToken();
|
|
2748
|
-
return {
|
|
2749
|
-
type: "project-id",
|
|
2750
|
-
projectId: getProjectIdFromOidcToken(oidcToken)
|
|
2751
|
-
};
|
|
2752
|
-
}
|
|
2753
|
-
};
|
|
2781
|
+
}, _class6);
|
|
2754
2782
|
|
|
2755
2783
|
// src/index.make.ts
|
|
2756
2784
|
function make(createRawClient, defaults) {
|
|
@@ -2769,7 +2797,11 @@ function make(createRawClient, defaults) {
|
|
|
2769
2797
|
});
|
|
2770
2798
|
return createRawClient({
|
|
2771
2799
|
controller,
|
|
2772
|
-
origin: {
|
|
2800
|
+
origin: {
|
|
2801
|
+
provider: "vercel",
|
|
2802
|
+
sdkKey: auth.sdkKey,
|
|
2803
|
+
...auth.sourceProjectId ? { projectId: auth.sourceProjectId } : null
|
|
2804
|
+
},
|
|
2773
2805
|
waitUntil: waitUntil2,
|
|
2774
2806
|
...experimental_reportExposures ? { experimental_reportExposures } : {}
|
|
2775
2807
|
});
|
|
@@ -2797,7 +2829,7 @@ function setCacheLife() {
|
|
|
2797
2829
|
try {
|
|
2798
2830
|
_cache.cacheLife.call(void 0, { revalidate: 0, expire: 0 });
|
|
2799
2831
|
_cache.cacheLife.call(void 0, { stale: 60 });
|
|
2800
|
-
} catch (
|
|
2832
|
+
} catch (e18) {
|
|
2801
2833
|
}
|
|
2802
2834
|
}
|
|
2803
2835
|
var cachedFns = {
|
|
@@ -2847,4 +2879,4 @@ var { flagsClient, resetDefaultFlagsClient, createClient } = make(
|
|
|
2847
2879
|
|
|
2848
2880
|
|
|
2849
2881
|
exports.ResolutionReason = ResolutionReason; exports.evaluate = evaluate; exports.FallbackNotFoundError = FallbackNotFoundError; exports.FallbackEntryNotFoundError = FallbackEntryNotFoundError; exports.Controller = Controller; exports.flagsClient = flagsClient; exports.resetDefaultFlagsClient = resetDefaultFlagsClient; exports.createClient = createClient;
|
|
2850
|
-
//# sourceMappingURL=chunk-
|
|
2882
|
+
//# sourceMappingURL=chunk-W742GGZU.cjs.map
|