@clerk/chrome-extension
Version:
Clerk SDK for Chrome extensions
379 lines (361 loc) • 12.9 kB
JavaScript
;
var noRhc = require('@clerk/clerk-js/no-rhc');
var browser = require('webextension-polyfill');
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
var browser__default = /*#__PURE__*/_interopDefault(browser);
// src/background/clerk.ts
// ../shared/dist/chunk-K64INQ4C.mjs
var DEV_BROWSER_JWT_KEY = "__clerk_db_jwt";
// ../shared/dist/chunk-TETGTEI2.mjs
var isomorphicAtob = (data) => {
if (typeof atob !== "undefined" && typeof atob === "function") {
return atob(data);
} else if (typeof global !== "undefined" && global.Buffer) {
return new global.Buffer(data, "base64").toString();
}
return data;
};
// ../shared/dist/chunk-G3VP5PJE.mjs
var PUBLISHABLE_KEY_LIVE_PREFIX = "pk_live_";
var PUBLISHABLE_KEY_TEST_PREFIX = "pk_test_";
function parsePublishableKey(key, options = {}) {
key = key || "";
if (!key || !isPublishableKey(key)) {
if (options.fatal && !key) {
throw new Error(
"Publishable key is missing. Ensure that your publishable key is correctly configured. Double-check your environment configuration for your keys, or access them here: https://dashboard.clerk.com/last-active?path=api-keys"
);
}
if (options.fatal && !isPublishableKey(key)) {
throw new Error("Publishable key not valid.");
}
return null;
}
const instanceType = key.startsWith(PUBLISHABLE_KEY_LIVE_PREFIX) ? "production" : "development";
let frontendApi = isomorphicAtob(key.split("_")[2]);
frontendApi = frontendApi.slice(0, -1);
if (options.proxyUrl) {
frontendApi = options.proxyUrl;
} else if (instanceType !== "development" && options.domain) {
frontendApi = `clerk.${options.domain}`;
}
return {
instanceType,
frontendApi
};
}
function isPublishableKey(key = "") {
try {
const hasValidPrefix = key.startsWith(PUBLISHABLE_KEY_LIVE_PREFIX) || key.startsWith(PUBLISHABLE_KEY_TEST_PREFIX);
const hasValidFrontendApiPostfix = isomorphicAtob(key.split("_")[2] || "").endsWith("$");
return hasValidPrefix && hasValidFrontendApiPostfix;
} catch {
return false;
}
}
// src/types.ts
var SCOPE = {
BACKGROUND: "background"
};
// src/internal/constants.ts
var AUTH_HEADER = {
PRODUCTION: "Authorization",
DEVELOPMENT: "Clerk-Db-Jwt"
};
var CLIENT_JWT_KEY = "__client";
var CLIENT_UAT_KEY = "__clerk_uat";
var DEFAULT_LOCAL_HOST_PERMISSION = "http://localhost";
var STORAGE_KEY_CLIENT_JWT = "__clerk_client_jwt";
// ../shared/dist/chunk-3EORDU4Z.mjs
var DefaultMessages = Object.freeze({
InvalidProxyUrlErrorMessage: `The proxyUrl passed to Clerk is invalid. The expected value for proxyUrl is an absolute URL or a relative path with a leading '/'. (key={{url}})`,
InvalidPublishableKeyErrorMessage: `The publishableKey passed to Clerk is invalid. You can get your Publishable key at https://dashboard.clerk.com/last-active?path=api-keys. (key={{key}})`,
MissingPublishableKeyErrorMessage: `Missing publishableKey. You can get your key at https://dashboard.clerk.com/last-active?path=api-keys.`,
MissingSecretKeyErrorMessage: `Missing secretKey. You can get your key at https://dashboard.clerk.com/last-active?path=api-keys.`,
MissingClerkProvider: `{{source}} can only be used within the <ClerkProvider /> component. Learn more: https://clerk.com/docs/components/clerk-provider`
});
function buildErrorThrower({ packageName, customMessages }) {
let pkg = packageName;
const messages = {
...DefaultMessages,
...customMessages
};
function buildMessage(rawMessage, replacements) {
if (!replacements) {
return `${pkg}: ${rawMessage}`;
}
let msg = rawMessage;
const matches = rawMessage.matchAll(/{{([a-zA-Z0-9-_]+)}}/g);
for (const match of matches) {
const replacement = (replacements[match[1]] || "").toString();
msg = msg.replace(`{{${match[1]}}}`, replacement);
}
return `${pkg}: ${msg}`;
}
return {
setPackageName({ packageName: packageName2 }) {
if (typeof packageName2 === "string") {
pkg = packageName2;
}
return this;
},
setMessages({ customMessages: customMessages2 }) {
Object.assign(messages, customMessages2 || {});
return this;
},
throwInvalidPublishableKeyError(params) {
throw new Error(buildMessage(messages.InvalidPublishableKeyErrorMessage, params));
},
throwInvalidProxyUrl(params) {
throw new Error(buildMessage(messages.InvalidProxyUrlErrorMessage, params));
},
throwMissingPublishableKeyError() {
throw new Error(buildMessage(messages.MissingPublishableKeyErrorMessage));
},
throwMissingSecretKeyError() {
throw new Error(buildMessage(messages.MissingSecretKeyErrorMessage));
},
throwMissingClerkProviderError(params) {
throw new Error(buildMessage(messages.MissingClerkProvider, params));
},
throw(message) {
throw new Error(buildMessage(message));
}
};
}
// src/internal/utils/errors.ts
var errorLogger = (err) => console.error(err, err.stack);
var errorThrower = buildErrorThrower({ packageName: "@clerk/chrome-extension" });
var missingManifestKeyError = (key) => `Missing \`${key}\` entry in manifest.json`;
function assertPublishableKey(publishableKey) {
if (!publishableKey) {
errorThrower.throwMissingPublishableKeyError();
}
}
function ensureFormattedUrl(url) {
return url.startsWith("http") ? url : `https://${url}`;
}
async function getClientCookie({ url, name }) {
return await browser__default.default.cookies.get({ name, url: ensureFormattedUrl(url) });
}
function createClientCookieListener({ url, name, callback }) {
const domain = new URL(url).hostname;
const cookieDomain = domain.startsWith("www.") ? domain.slice(4) : domain;
const listener = (changeInfo) => {
if (changeInfo.cookie.domain === cookieDomain && changeInfo.cookie.name === name) {
void callback(changeInfo);
}
};
return {
add: () => browser__default.default.cookies.onChanged.addListener(listener),
has: () => browser__default.default.cookies.onChanged.hasListener(listener),
remove: () => browser__default.default.cookies.onChanged.removeListener(listener)
};
}
// src/internal/utils/jwt-handler.ts
function shouldSync(sync, _params) {
return Boolean(sync);
}
function JWTHandler(store, params) {
const { sync, frontendApi, ...cookieParams } = params;
const CACHE_KEY = store.createKey(frontendApi, STORAGE_KEY_CLIENT_JWT, "v2");
const set = async (value) => {
return await store.set(CACHE_KEY, value).catch(errorLogger);
};
const remove = async () => {
return await store.remove(CACHE_KEY).catch(errorLogger);
};
const get = async () => {
if (shouldSync(sync)) {
const syncedJWT = await getClientCookie(cookieParams).catch(errorLogger);
if (syncedJWT) {
await set(syncedJWT.value);
return syncedJWT.value;
}
}
return await store.get(CACHE_KEY);
};
const listener = () => {
if (!shouldSync(sync)) {
return;
}
const { onListenerCallback, ...restCookieParams } = cookieParams;
return createClientCookieListener({
...restCookieParams,
callback: async (changeInfo) => {
const existingJWT = await get();
if (existingJWT === changeInfo.cookie.value) {
const syncedUAT = await getClientCookie({ ...restCookieParams, name: CLIENT_UAT_KEY }).catch(errorLogger);
if (!syncedUAT || (syncedUAT == null ? void 0 : syncedUAT.value) === "0") {
onListenerCallback == null ? void 0 : onListenerCallback();
}
return;
}
await set(changeInfo.cookie.value);
onListenerCallback == null ? void 0 : onListenerCallback();
}
});
};
return { get, listener, set, remove };
}
// src/internal/utils/manifest.ts
function validateRootManifestKey(manifest, key) {
if (!manifest[key]) {
errorThrower.throw(missingManifestKeyError(key));
}
}
function validateManifestPermission(manifest, key) {
var _a;
if (!((_a = manifest.permissions) == null ? void 0 : _a.includes(key))) {
errorThrower.throw(missingManifestKeyError(`permissions.${key}`));
}
}
function hasAdditionalFeatures(features) {
return Boolean(features) && Object.keys(features).length > 0;
}
function validateManifest(manifest, features) {
validateRootManifestKey(manifest, "permissions");
validateManifestPermission(manifest, "storage");
if (!hasAdditionalFeatures(features)) {
return;
}
{
validateRootManifestKey(manifest, "background");
}
if (features.sync) {
validateManifestPermission(manifest, "cookies");
validateRootManifestKey(manifest, "host_permissions");
}
}
// src/internal/utils/request-handler.ts
function requestHandler(jwtHandler, { isProd }) {
const handler = async (requestInit) => {
requestInit.credentials = "omit";
const currentJWT = await jwtHandler.get();
if (!currentJWT) {
return;
}
if (isProd) {
prodHandler(requestInit, currentJWT);
} else {
devHandler(requestInit, currentJWT);
}
};
return handler;
}
function devHandler(requestInit, jwt) {
var _a;
(_a = requestInit.url) == null ? void 0 : _a.searchParams.append("__clerk_db_jwt", jwt);
}
function prodHandler(requestInit, jwt) {
var _a;
(_a = requestInit.url) == null ? void 0 : _a.searchParams.append("_is_native", "1");
requestInit.headers.set(AUTH_HEADER.PRODUCTION, `Bearer ${jwt}`);
}
// src/internal/utils/response-handler.ts
function responseHandler(jwtHandler, { isProd }) {
const handler = async (_, response) => {
if (isProd) {
await prodHandler2(response, jwtHandler);
} else {
await devHandler2(response, jwtHandler);
}
};
return handler;
}
async function devHandler2(response, jwtHandler) {
const header = response == null ? void 0 : response.headers.get(AUTH_HEADER.DEVELOPMENT);
if (header) {
await jwtHandler.set(header);
} else {
await jwtHandler.remove();
}
}
async function prodHandler2(response, jwtHandler) {
const header = response == null ? void 0 : response.headers.get(AUTH_HEADER.PRODUCTION);
if (header == null ? void 0 : header.startsWith("Bearer")) {
const jwt = header.split(" ")[1] || void 0;
if (jwt) {
await jwtHandler.set(jwt);
} else {
await jwtHandler.remove();
}
} else if (header) {
await jwtHandler.set(header);
}
}
var createKey = (...keys) => keys.filter(Boolean).join("|");
var createBrowserStorageCache = (opts = {}) => {
const __storageArea = opts.storageArea || "local";
return {
createKey,
get: (key) => browser__default.default.storage[__storageArea].get(key).then((result) => result[key] || void 0),
remove: (key) => browser__default.default.storage[__storageArea].remove(key),
set: (key, value) => browser__default.default.storage[__storageArea].set({ [key]: value })
};
};
var BrowserStorageCache = createBrowserStorageCache();
// src/internal/clerk.ts
var clerk;
noRhc.Clerk.sdkMetadata = {
name: "@clerk/chrome-extension",
version: "2.2.23"
};
async function createClerkClient({
__experimental_syncHostListener = false,
publishableKey,
scope,
storageCache = BrowserStorageCache,
syncHost
}) {
{
noRhc.Clerk.mountComponentRenderer = void 0;
}
if (clerk && scope !== SCOPE.BACKGROUND) {
return clerk;
}
const sync = Boolean(syncHost);
const key = parsePublishableKey(publishableKey);
assertPublishableKey(key);
const isProd = key.instanceType === "production";
const manifest = browser__default.default.runtime.getManifest();
validateManifest(manifest, {
background: scope === SCOPE.BACKGROUND,
sync
});
const url = syncHost ? syncHost : DEFAULT_LOCAL_HOST_PERMISSION;
clerk = new noRhc.Clerk(publishableKey);
const jwtOptions = {
frontendApi: key.frontendApi,
name: isProd ? CLIENT_JWT_KEY : DEV_BROWSER_JWT_KEY,
url,
sync
};
if (jwtOptions.sync && __experimental_syncHostListener) {
jwtOptions.onListenerCallback = () => {
if (clerk.user) {
clerk.user.reload();
} else {
window.location.reload();
}
};
}
const jwt = JWTHandler(storageCache, jwtOptions);
if (jwtOptions.sync && __experimental_syncHostListener) {
const listener = jwt.listener();
listener == null ? void 0 : listener.add();
}
clerk.__unstable__onAfterResponse(responseHandler(jwt, { isProd }));
clerk.__unstable__onBeforeRequest(requestHandler(jwt, { isProd }));
return clerk;
}
// src/background/clerk.ts
noRhc.Clerk.mountComponentRenderer = void 0;
async function createClerkClient2(opts) {
const clerk2 = await createClerkClient({ ...opts, scope: SCOPE.BACKGROUND });
await clerk2.load({ standardBrowser: false });
return clerk2;
}
exports.createClerkClient = createClerkClient2;
//# sourceMappingURL=index.js.map
//# sourceMappingURL=index.js.map