@web-widget/flags-kit
Version:
Flags SDK by Vercel - The feature flags toolkit for Next.js, SvelteKit, and Web Router - Enhanced fork with improved Web Router support
353 lines (316 loc) • 13.2 kB
JavaScript
;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(); } } async function _asyncNullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return await 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 _chunkQLJ65HXQcjs = require('./chunk-QLJ65HXQ.cjs');
var _chunkROBQSGBHcjs = require('./chunk-ROBQSGBH.cjs');
var _chunkMEG7RDX7cjs = require('./chunk-MEG7RDX7.cjs');
// src/sveltekit/index.ts
var _kit = require('@sveltejs/kit');
var _async_hooks = require('async_hooks');
var _cookies = require('@edge-runtime/cookies');
// src/sveltekit/precompute.ts
async function evaluate(flags, request) {
return Promise.all(flags.map((flag2) => flag2(request)));
}
async function precompute(flags, request, secret) {
const values = await evaluate(flags, request);
return serialize2(flags, values, secret);
}
function combine(flags, values) {
return Object.fromEntries(flags.map((flag2, i) => [flag2.key, values[i]]));
}
async function serialize2(flags, values, secret) {
return _chunkQLJ65HXQcjs.serialize.call(void 0, combine(flags, values), flags, secret);
}
async function deserialize2(flags, code, secret) {
return _chunkQLJ65HXQcjs.deserialize.call(void 0, code, flags, secret);
}
async function getPrecomputed(flagKey, precomputeFlags, code, secret) {
const flagSet = await deserialize2(precomputeFlags, code, secret);
return flagSet[flagKey];
}
function* cartesianIterator(items) {
const remainder = items.length > 1 ? cartesianIterator(items.slice(1)) : [[]];
for (let r of remainder)
for (let h of items.at(0))
yield [h, ...r];
}
async function generatePermutations(flags, filter = null, secret) {
const options = flags.map((flag2) => {
if (!flag2.options)
return [false, true];
return flag2.options.map((option) => option.value);
});
const list = [];
for (const permutation of cartesianIterator(options)) {
const permObject = permutation.reduce(
(acc, value, index) => {
acc[flags[index].key] = value;
return acc;
},
{}
);
if (!filter || filter(permObject))
list.push(permObject);
}
return Promise.all(list.map((values) => _chunkQLJ65HXQcjs.serialize.call(void 0, values, flags, secret)));
}
// src/sveltekit/env.ts
var default_secret = process.env.FLAGS_SECRET;
async function tryGetSecret(secret) {
if (!default_secret) {
try {
const env = await Promise.resolve().then(() => _interopRequireWildcard(require("$env/static/private")));
default_secret = env.FLAGS_SECRET;
} catch (e) {
}
}
secret = secret || default_secret;
if (!secret) {
throw new Error(
"flags: No secret provided. Set an environment variable FLAGS_SECRET or provide a secret to the function."
);
}
return secret;
}
// src/sveltekit/index.ts
function hasOwnProperty(obj, prop) {
return obj.hasOwnProperty(prop);
}
var headersMap = /* @__PURE__ */ new WeakMap();
var cookiesMap = /* @__PURE__ */ new WeakMap();
function sealHeaders(headers) {
const cached = headersMap.get(headers);
if (cached !== void 0)
return cached;
const sealed = _chunkROBQSGBHcjs.HeadersAdapter.seal(
headers,
"Headers cannot be modified in SvelteKit. Headers are read-only during request processing."
);
headersMap.set(headers, sealed);
return sealed;
}
function sealCookies(headers) {
const cached = cookiesMap.get(headers);
if (cached !== void 0)
return cached;
const sealed = _chunkROBQSGBHcjs.RequestCookiesAdapter.seal(
new (0, _cookies.RequestCookies)(headers),
"Cookies cannot be modified in SvelteKit. Use the cookies API from @sveltejs/kit to set cookies. Read more: https://kit.svelte.dev/docs/load#cookies"
);
cookiesMap.set(headers, sealed);
return sealed;
}
async function resolveObjectPromises(obj) {
const entries = Object.entries(obj);
const resolvedEntries = await Promise.all(
entries.map(async ([key, promise]) => {
const value = await promise;
return [key, value];
})
);
return Object.fromEntries(resolvedEntries);
}
function getDecide(definition) {
return function decide(params) {
if (typeof definition.decide === "function") {
return definition.decide(params);
}
if (typeof _optionalChain([definition, 'access', _ => _.adapter, 'optionalAccess', _2 => _2.decide]) === "function") {
return definition.adapter.decide({ key: definition.key, ...params });
}
throw new Error(`flags: No decide function provided for ${definition.key}`);
};
}
function getIdentify(definition) {
if (typeof definition.identify === "function") {
return definition.identify;
}
if (typeof _optionalChain([definition, 'access', _3 => _3.adapter, 'optionalAccess', _4 => _4.identify]) === "function") {
return definition.adapter.identify;
}
}
var requestMap = /* @__PURE__ */ new WeakMap();
function flag(definition) {
const decide = getDecide(definition);
const identify = getIdentify(definition);
const flagImpl = async function flagImpl2(requestOrCode, flagsArrayOrSecret) {
let store = flagStorage.getStore();
if (!store) {
if (requestOrCode instanceof Request) {
store = requestMap.get(requestOrCode);
if (!store) {
store = createContext(
requestOrCode,
await _asyncNullishCoalesce(flagsArrayOrSecret, async () => ( await tryGetSecret()))
);
requestMap.set(requestOrCode, store);
}
} else {
throw new Error("flags: Neither context found nor Request provided");
}
}
if (typeof requestOrCode === "string" && Array.isArray(flagsArrayOrSecret)) {
return getPrecomputed(
definition.key,
flagsArrayOrSecret,
requestOrCode,
store.secret
);
}
if (hasOwnProperty(store.usedFlags, definition.key)) {
const valuePromise2 = store.usedFlags[definition.key];
if (typeof valuePromise2 !== "undefined") {
return valuePromise2;
}
}
const headers = sealHeaders(store.request.headers);
const cookies = sealCookies(store.request.headers);
const overridesCookie = _optionalChain([cookies, 'access', _5 => _5.get, 'call', _6 => _6("vercel-flag-overrides"), 'optionalAccess', _7 => _7.value]);
const overrides = overridesCookie ? await _chunkROBQSGBHcjs.decryptOverrides.call(void 0, overridesCookie, store.secret) : void 0;
if (overrides && hasOwnProperty(overrides, definition.key)) {
const value2 = overrides[definition.key];
if (typeof value2 !== "undefined") {
_chunkROBQSGBHcjs.reportValue.call(void 0, definition.key, value2);
store.usedFlags[definition.key] = Promise.resolve(value2);
return value2;
}
}
let entities;
if (identify) {
if (!store.identifiers.has(identify)) {
const entities2 = identify({
headers,
cookies
});
store.identifiers.set(identify, entities2);
}
entities = await store.identifiers.get(identify);
}
const valuePromise = decide({
headers,
cookies,
entities
});
store.usedFlags[definition.key] = valuePromise;
const value = await valuePromise;
_chunkROBQSGBHcjs.reportValue.call(void 0, definition.key, value);
return value;
};
flagImpl.key = definition.key;
flagImpl.defaultValue = definition.defaultValue;
flagImpl.origin = definition.origin;
flagImpl.description = definition.description;
flagImpl.options = _chunkQLJ65HXQcjs.normalizeOptions.call(void 0, definition.options);
flagImpl.decide = decide;
flagImpl.identify = identify;
return flagImpl;
}
function getProviderData(flags) {
const definitions = Object.values(flags).reduce(
(acc, d) => {
acc[d.key] = {
options: _chunkQLJ65HXQcjs.normalizeOptions.call(void 0, d.options),
origin: d.origin,
description: d.description
};
return acc;
},
{}
);
return { definitions, hints: [] };
}
function createContext(request, secret, params) {
return {
request,
secret,
params: _nullishCoalesce(params, () => ( {})),
usedFlags: {},
identifiers: /* @__PURE__ */ new Map()
};
}
var flagStorage = new (0, _async_hooks.AsyncLocalStorage)();
function createHandle({
secret,
flags
}) {
return async function handle({ event, resolve }) {
await _asyncNullishCoalesce(secret, async () => ( (secret = await tryGetSecret(secret))));
if (flags && // avoid creating the URL object for every request by checking with includes() first
event.request.url.includes("/.well-known/") && new URL(event.request.url).pathname === "/.well-known/vercel/flags") {
return handleWellKnownFlagsRoute(event, secret, flags);
}
const flagContext = createContext(
event.request,
secret,
event.params
);
return flagStorage.run(
flagContext,
() => resolve(event, {
transformPageChunk: async ({ html }) => {
const store = flagStorage.getStore();
if (!store || Object.keys(store.usedFlags).length === 0)
return html;
const encryptedFlagValues = await _chunkROBQSGBHcjs.encryptFlagValues.call(void 0,
await resolveObjectPromises(store.usedFlags),
secret
);
return html.replace(
"</body>",
`<script type="application/json" data-flag-values>${_chunkMEG7RDX7cjs.safeJsonStringify.call(void 0, encryptedFlagValues)}</script></body>`
);
}
})
);
};
}
async function handleWellKnownFlagsRoute(event, secret, flags) {
const access = await _chunkROBQSGBHcjs.verifyAccess.call(void 0,
event.request.headers.get("Authorization"),
secret
);
if (!access)
return new Response(null, { status: 401 });
const providerData = getProviderData(flags);
return Response.json(providerData, {
headers: { "x-flags-sdk-version": _chunkROBQSGBHcjs.version }
});
}
async function encryptFlagValues2(value, secret) {
return _chunkROBQSGBHcjs.encryptFlagValues.call(void 0, value, await tryGetSecret(secret));
}
async function decryptFlagValues2(encryptedData, secret) {
return _chunkROBQSGBHcjs.decryptFlagValues.call(void 0, encryptedData, await tryGetSecret(secret));
}
async function encryptOverrides2(overrides, secret) {
return _chunkROBQSGBHcjs.encryptOverrides.call(void 0, overrides, await tryGetSecret(secret));
}
async function decryptOverrides2(encryptedData, secret) {
return _chunkROBQSGBHcjs.decryptOverrides.call(void 0, encryptedData, await tryGetSecret(secret));
}
async function encryptFlagDefinitions2(value, secret) {
return _chunkROBQSGBHcjs.encryptFlagDefinitions.call(void 0, value, await tryGetSecret(secret));
}
async function decryptFlagDefinitions2(encryptedData, secret) {
return _chunkROBQSGBHcjs.decryptFlagDefinitions.call(void 0, encryptedData, await tryGetSecret(secret));
}
async function precompute2(flags, request, secret) {
return precompute(flags, request, await tryGetSecret(secret));
}
async function generatePermutations2(flags, filter = null, secret) {
return generatePermutations(flags, filter, await tryGetSecret(secret));
}
function createFlagsDiscoveryEndpoint(getApiData, options) {
const requestHandler = async (event) => {
const access = await _chunkROBQSGBHcjs.verifyAccess.call(void 0,
event.request.headers.get("Authorization"),
_optionalChain([options, 'optionalAccess', _8 => _8.secret])
);
if (!access)
_kit.error.call(void 0, 401);
const apiData = await getApiData(event);
return _kit.json.call(void 0, apiData, { headers: { "x-flags-sdk-version": _chunkROBQSGBHcjs.version } });
};
return requestHandler;
}
exports.createFlagsDiscoveryEndpoint = createFlagsDiscoveryEndpoint; exports.createHandle = createHandle; exports.decryptFlagDefinitions = decryptFlagDefinitions2; exports.decryptFlagValues = decryptFlagValues2; exports.decryptOverrides = decryptOverrides2; exports.encryptFlagDefinitions = encryptFlagDefinitions2; exports.encryptFlagValues = encryptFlagValues2; exports.encryptOverrides = encryptOverrides2; exports.flag = flag; exports.generatePermutations = generatePermutations2; exports.getProviderData = getProviderData; exports.precompute = precompute2;
//# sourceMappingURL=sveltekit.cjs.map