@scalemule/nextjs 0.0.39 → 0.0.41

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.
@@ -1,5 +1,6 @@
1
1
  'use strict';
2
2
 
3
+ var money = require('@scalemule/money');
3
4
  var headers = require('next/headers');
4
5
  var server = require('next/server');
5
6
  var crypto$1 = require('crypto');
@@ -2667,6 +2668,14 @@ var ScaleMuleServer = class {
2667
2668
  this.apiKey = config.apiKey;
2668
2669
  this.gatewayUrl = resolveGatewayUrl(config);
2669
2670
  this.debug = config.debug || false;
2671
+ this.money = money.createMoneyClient({
2672
+ apiKey: this.apiKey,
2673
+ gatewayUrl: this.gatewayUrl,
2674
+ fetch: globalThis.fetch.bind(globalThis)
2675
+ });
2676
+ }
2677
+ moneyWithSession(sessionToken) {
2678
+ return this.money.withAccessToken(sessionToken);
2670
2679
  }
2671
2680
  /**
2672
2681
  * Make a request to the ScaleMule API
@@ -2745,6 +2754,7 @@ function createServerClient(config) {
2745
2754
  }
2746
2755
  var SESSION_COOKIE_NAME = "sm_session";
2747
2756
  var USER_ID_COOKIE_NAME = "sm_user_id";
2757
+ var KNOWN_ACCOUNTS_COOKIE_NAME = "sm_known_accounts";
2748
2758
  ({
2749
2759
  secure: process.env.NODE_ENV === "production"});
2750
2760
  function createCookieHeader(name, value, options = {}) {
@@ -2845,6 +2855,163 @@ function getSessionFromRequest(request) {
2845
2855
  expiresAt: /* @__PURE__ */ new Date()
2846
2856
  };
2847
2857
  }
2858
+ var MAX_KNOWN_ACCOUNTS = 10;
2859
+ function maskEmail(email) {
2860
+ const [local, domain] = email.split("@");
2861
+ if (!domain) return "***@***.***";
2862
+ const tldDot = domain.lastIndexOf(".");
2863
+ const tld = tldDot > 0 ? domain.slice(tldDot) : "";
2864
+ const domainBase = tldDot > 0 ? domain.slice(0, tldDot) : domain;
2865
+ return `${local[0] || "*"}***@${domainBase[0] || "*"}***${tld}`;
2866
+ }
2867
+ function stableColorIndex(userId) {
2868
+ let hash = 0;
2869
+ for (let i = 0; i < userId.length; i++) {
2870
+ hash = (hash << 5) - hash + userId.charCodeAt(i) | 0;
2871
+ }
2872
+ return Math.abs(hash) % 8;
2873
+ }
2874
+ function applyPrivacyToEntry(entry, privacy) {
2875
+ switch (privacy) {
2876
+ case "full":
2877
+ return entry;
2878
+ case "masked":
2879
+ return {
2880
+ userId: entry.userId,
2881
+ email: entry.email ? maskEmail(entry.email) : void 0,
2882
+ fullName: entry.fullName ? `${entry.fullName[0].toUpperCase()}.` : void 0,
2883
+ provider: entry.provider,
2884
+ lastActiveAt: entry.lastActiveAt,
2885
+ colorIndex: stableColorIndex(entry.userId)
2886
+ };
2887
+ case "minimal":
2888
+ return {
2889
+ userId: entry.userId,
2890
+ provider: entry.provider,
2891
+ lastActiveAt: entry.lastActiveAt,
2892
+ displayLabel: "Account",
2893
+ colorIndex: stableColorIndex(entry.userId)
2894
+ };
2895
+ }
2896
+ }
2897
+ function appendKnownAccountCookie(headers2, account, existingCookie, options = {}, privacy) {
2898
+ let accounts = {};
2899
+ if (existingCookie) {
2900
+ try {
2901
+ accounts = JSON.parse(decodeURIComponent(existingCookie));
2902
+ } catch {
2903
+ }
2904
+ }
2905
+ const effectivePrivacy = privacy || "full";
2906
+ for (const [userId, entry] of Object.entries(accounts)) {
2907
+ accounts[userId] = applyPrivacyToEntry(entry, effectivePrivacy);
2908
+ }
2909
+ accounts[account.userId] = applyPrivacyToEntry(account, effectivePrivacy);
2910
+ const entries = Object.entries(accounts);
2911
+ if (entries.length > MAX_KNOWN_ACCOUNTS) {
2912
+ entries.sort((a, b) => new Date(b[1].lastActiveAt).getTime() - new Date(a[1].lastActiveAt).getTime());
2913
+ accounts = Object.fromEntries(entries.slice(0, MAX_KNOWN_ACCOUNTS));
2914
+ }
2915
+ const maxAge = 365 * 24 * 60 * 60;
2916
+ const secure = options.secure ?? process.env.NODE_ENV === "production";
2917
+ const sameSite = options.sameSite ?? "lax";
2918
+ const path = options.path ?? "/";
2919
+ let cookie = `${KNOWN_ACCOUNTS_COOKIE_NAME}=${encodeURIComponent(JSON.stringify(accounts))}; Path=${path}; Max-Age=${maxAge}; SameSite=${sameSite}`;
2920
+ if (secure) {
2921
+ cookie += "; Secure";
2922
+ }
2923
+ if (options.domain) {
2924
+ cookie += `; Domain=${options.domain}`;
2925
+ }
2926
+ headers2.append("Set-Cookie", cookie);
2927
+ }
2928
+ function removeKnownAccountFromCookie(headers2, userId, existingCookie, options = {}) {
2929
+ let accounts = {};
2930
+ if (existingCookie) {
2931
+ try {
2932
+ accounts = JSON.parse(decodeURIComponent(existingCookie));
2933
+ } catch {
2934
+ }
2935
+ }
2936
+ delete accounts[userId];
2937
+ const maxAge = 365 * 24 * 60 * 60;
2938
+ const secure = options.secure ?? process.env.NODE_ENV === "production";
2939
+ const sameSite = options.sameSite ?? "lax";
2940
+ const path = options.path ?? "/";
2941
+ let cookie = `${KNOWN_ACCOUNTS_COOKIE_NAME}=${encodeURIComponent(JSON.stringify(accounts))}; Path=${path}; Max-Age=${maxAge}; SameSite=${sameSite}`;
2942
+ if (secure) {
2943
+ cookie += "; Secure";
2944
+ }
2945
+ if (options.domain) {
2946
+ cookie += `; Domain=${options.domain}`;
2947
+ }
2948
+ headers2.append("Set-Cookie", cookie);
2949
+ }
2950
+ function clearKnownAccountsCookie(headers2, options = {}) {
2951
+ const path = options.path ?? "/";
2952
+ let cookie = `${KNOWN_ACCOUNTS_COOKIE_NAME}=; Path=${path}; Max-Age=0`;
2953
+ if (options.domain) {
2954
+ cookie += `; Domain=${options.domain}`;
2955
+ }
2956
+ headers2.append("Set-Cookie", cookie);
2957
+ }
2958
+ function getKnownAccountsFromRequest(request) {
2959
+ const cookieHeader = request.headers.get("cookie");
2960
+ if (!cookieHeader) return [];
2961
+ const cookies4 = Object.fromEntries(
2962
+ cookieHeader.split(";").map((c) => {
2963
+ const [key, ...rest] = c.trim().split("=");
2964
+ return [key, decodeURIComponent(rest.join("="))];
2965
+ })
2966
+ );
2967
+ const raw = cookies4[KNOWN_ACCOUNTS_COOKIE_NAME];
2968
+ if (!raw) return [];
2969
+ try {
2970
+ const accounts = JSON.parse(raw);
2971
+ return Object.values(accounts);
2972
+ } catch {
2973
+ return [];
2974
+ }
2975
+ }
2976
+ function getKnownAccountsCookieRaw(request) {
2977
+ const cookieHeader = request.headers.get("cookie");
2978
+ if (!cookieHeader) return null;
2979
+ const cookies4 = Object.fromEntries(
2980
+ cookieHeader.split(";").map((c) => {
2981
+ const [key, ...rest] = c.trim().split("=");
2982
+ return [key, decodeURIComponent(rest.join("="))];
2983
+ })
2984
+ );
2985
+ return cookies4[KNOWN_ACCOUNTS_COOKIE_NAME] || null;
2986
+ }
2987
+ function normalizeKnownAccountsCookie(request, privacy, options = {}) {
2988
+ if (!privacy || privacy === "full") return null;
2989
+ const raw = getKnownAccountsCookieRaw(request);
2990
+ if (!raw) return null;
2991
+ let accounts = {};
2992
+ try {
2993
+ accounts = JSON.parse(raw);
2994
+ } catch {
2995
+ return null;
2996
+ }
2997
+ let changed = false;
2998
+ for (const [userId, entry] of Object.entries(accounts)) {
2999
+ const normalized = applyPrivacyToEntry(entry, privacy);
3000
+ if (JSON.stringify(normalized) !== JSON.stringify(entry)) {
3001
+ accounts[userId] = normalized;
3002
+ changed = true;
3003
+ }
3004
+ }
3005
+ if (!changed) return null;
3006
+ const maxAge = 365 * 24 * 60 * 60;
3007
+ const secure = options.secure ?? process.env.NODE_ENV === "production";
3008
+ const sameSite = options.sameSite ?? "lax";
3009
+ const path = options.path ?? "/";
3010
+ let cookie = `${KNOWN_ACCOUNTS_COOKIE_NAME}=${encodeURIComponent(JSON.stringify(accounts))}; Path=${path}; Max-Age=${maxAge}; SameSite=${sameSite}`;
3011
+ if (secure) cookie += "; Secure";
3012
+ if (options.domain) cookie += `; Domain=${options.domain}`;
3013
+ return cookie;
3014
+ }
2848
3015
  async function requireSession() {
2849
3016
  const session = await getSession();
2850
3017
  if (!session) {
@@ -3004,7 +3171,25 @@ function createAuthRoutes(config = {}) {
3004
3171
  } catch {
3005
3172
  return successResponse({ user: registeredUser, message: "Registration successful" }, 201);
3006
3173
  }
3007
- return withSession(loginData, { user: registeredUser, sessionToken: loginData.session_token, userId: registeredUser.id }, cookieOptions);
3174
+ const registerResponse = withSession(loginData, { user: registeredUser, sessionToken: loginData.session_token, userId: registeredUser.id }, cookieOptions);
3175
+ if (config.enableAccountSwitcher) {
3176
+ const existingKnown = getKnownAccountsCookieRaw(request);
3177
+ appendKnownAccountCookie(
3178
+ registerResponse.headers,
3179
+ {
3180
+ userId: registeredUser.id,
3181
+ email: registeredUser.email,
3182
+ fullName: registeredUser.full_name ?? void 0,
3183
+ avatarUrl: registeredUser.avatar_url ?? void 0,
3184
+ provider: "email",
3185
+ lastActiveAt: (/* @__PURE__ */ new Date()).toISOString()
3186
+ },
3187
+ existingKnown,
3188
+ cookieOptions,
3189
+ config.accountSwitcherPrivacy
3190
+ );
3191
+ }
3192
+ return registerResponse;
3008
3193
  }
3009
3194
  // ==================== Login ====================
3010
3195
  case "login": {
@@ -3035,7 +3220,25 @@ function createAuthRoutes(config = {}) {
3035
3220
  email: loginData.user.email
3036
3221
  });
3037
3222
  }
3038
- return withSession(loginData, { user: loginData.user, sessionToken: loginData.session_token, userId: loginData.user.id }, cookieOptions);
3223
+ const loginResponse = withSession(loginData, { user: loginData.user, sessionToken: loginData.session_token, userId: loginData.user.id }, cookieOptions);
3224
+ if (config.enableAccountSwitcher) {
3225
+ const existingKnown = getKnownAccountsCookieRaw(request);
3226
+ appendKnownAccountCookie(
3227
+ loginResponse.headers,
3228
+ {
3229
+ userId: loginData.user.id,
3230
+ email: loginData.user.email,
3231
+ fullName: loginData.user.full_name ?? void 0,
3232
+ avatarUrl: loginData.user.avatar_url ?? void 0,
3233
+ provider: "email",
3234
+ lastActiveAt: (/* @__PURE__ */ new Date()).toISOString()
3235
+ },
3236
+ existingKnown,
3237
+ cookieOptions,
3238
+ config.accountSwitcherPrivacy
3239
+ );
3240
+ }
3241
+ return loginResponse;
3039
3242
  }
3040
3243
  // ==================== Logout ====================
3041
3244
  case "logout": {
@@ -3182,6 +3385,59 @@ function createAuthRoutes(config = {}) {
3182
3385
  }
3183
3386
  return successResponse({ message: "Password changed successfully" });
3184
3387
  }
3388
+ // ==================== Switch Account ====================
3389
+ // Clears the active session so the user can re-authenticate as a different account.
3390
+ // The known accounts cookie is preserved — only the session cookie is cleared.
3391
+ case "switch-account": {
3392
+ if (!config.enableAccountSwitcher) {
3393
+ return errorResponse("NOT_FOUND", "Account switcher not enabled", 404);
3394
+ }
3395
+ const session = await getSession();
3396
+ if (session) {
3397
+ try {
3398
+ await sm.auth.logout(session.sessionToken);
3399
+ } catch {
3400
+ }
3401
+ }
3402
+ const switchResponse = clearSession({ message: "Session cleared for account switch" }, cookieOptions);
3403
+ const knownAccounts = getKnownAccountsFromRequest(request);
3404
+ return new Response(
3405
+ JSON.stringify({ success: true, data: { message: "Session cleared for account switch", knownAccounts } }),
3406
+ { status: 200, headers: switchResponse.headers }
3407
+ );
3408
+ }
3409
+ // ==================== Forget Account ====================
3410
+ // Remove a specific account from the known accounts cookie.
3411
+ case "forget-account": {
3412
+ if (!config.enableAccountSwitcher) {
3413
+ return errorResponse("NOT_FOUND", "Account switcher not enabled", 404);
3414
+ }
3415
+ const { user_id } = body;
3416
+ if (!user_id) {
3417
+ return errorResponse("VALIDATION_ERROR", "user_id required", 400);
3418
+ }
3419
+ const headers2 = new Headers();
3420
+ headers2.set("Content-Type", "application/json");
3421
+ const existingKnown = getKnownAccountsCookieRaw(request);
3422
+ removeKnownAccountFromCookie(headers2, user_id, existingKnown, cookieOptions);
3423
+ return new Response(
3424
+ JSON.stringify({ success: true, data: { message: "Account forgotten" } }),
3425
+ { status: 200, headers: headers2 }
3426
+ );
3427
+ }
3428
+ // ==================== Forget All Accounts ====================
3429
+ case "forget-all-accounts": {
3430
+ if (!config.enableAccountSwitcher) {
3431
+ return errorResponse("NOT_FOUND", "Account switcher not enabled", 404);
3432
+ }
3433
+ const headers2 = new Headers();
3434
+ headers2.set("Content-Type", "application/json");
3435
+ clearKnownAccountsCookie(headers2, cookieOptions);
3436
+ return new Response(
3437
+ JSON.stringify({ success: true, data: { message: "All accounts forgotten" } }),
3438
+ { status: 200, headers: headers2 }
3439
+ );
3440
+ }
3185
3441
  default:
3186
3442
  return errorResponse("NOT_FOUND", `Unknown endpoint: ${path}`, 404);
3187
3443
  }
@@ -3197,20 +3453,25 @@ function createAuthRoutes(config = {}) {
3197
3453
  switch (path) {
3198
3454
  // ==================== Get Current User ====================
3199
3455
  case "me": {
3456
+ const normCookie = config.enableAccountSwitcher ? normalizeKnownAccountsCookie(request, config.accountSwitcherPrivacy, cookieOptions) : null;
3457
+ const withNorm = (resp) => {
3458
+ if (normCookie) resp.headers.append("Set-Cookie", normCookie);
3459
+ return resp;
3460
+ };
3200
3461
  const session = await getSession();
3201
3462
  if (!session) {
3202
- return errorResponse("UNAUTHORIZED", "Authentication required", 401);
3463
+ return withNorm(errorResponse("UNAUTHORIZED", "Authentication required", 401));
3203
3464
  }
3204
3465
  let userData;
3205
3466
  try {
3206
3467
  userData = await sm.auth.me(session.sessionToken);
3207
3468
  } catch {
3208
- return clearSession(
3469
+ return withNorm(clearSession(
3209
3470
  { error: { code: "SESSION_EXPIRED", message: "Session expired" } },
3210
3471
  cookieOptions
3211
- );
3472
+ ));
3212
3473
  }
3213
- return successResponse({ user: userData, sessionToken: session.sessionToken, userId: session.userId });
3474
+ return withNorm(successResponse({ user: userData, sessionToken: session.sessionToken, userId: session.userId }));
3214
3475
  }
3215
3476
  // ==================== Get Session Status ====================
3216
3477
  case "session": {
@@ -3220,6 +3481,14 @@ function createAuthRoutes(config = {}) {
3220
3481
  userId: session?.userId || null
3221
3482
  });
3222
3483
  }
3484
+ // ==================== Get Known Accounts ====================
3485
+ case "known-accounts": {
3486
+ if (!config.enableAccountSwitcher) {
3487
+ return errorResponse("NOT_FOUND", "Account switcher not enabled", 404);
3488
+ }
3489
+ const knownAccounts = getKnownAccountsFromRequest(request);
3490
+ return successResponse({ knownAccounts });
3491
+ }
3223
3492
  default:
3224
3493
  return errorResponse("NOT_FOUND", `Unknown endpoint: ${path}`, 404);
3225
3494
  }
@@ -4827,16 +5096,138 @@ async function prefetchBundles(keys) {
4827
5096
  await Promise.all(keys.map((key) => getBundle(key)));
4828
5097
  }
4829
5098
 
5099
+ // src/server/redirect.ts
5100
+ function normalizeOrigin(origin) {
5101
+ try {
5102
+ const u = new URL(origin);
5103
+ return `${u.protocol}//${u.host}`.toLowerCase();
5104
+ } catch {
5105
+ return null;
5106
+ }
5107
+ }
5108
+ function isSafeSchemeRelative(input) {
5109
+ return !(input.startsWith("//") || input.startsWith("\\"));
5110
+ }
5111
+ function validateSafeRedirect(input, opts = {}) {
5112
+ const defaultPath = opts.defaultPath ?? "/";
5113
+ if (!input || typeof input !== "string") return defaultPath;
5114
+ const trimmed = input.trim();
5115
+ if (!trimmed) return defaultPath;
5116
+ if (!isSafeSchemeRelative(trimmed)) return defaultPath;
5117
+ const colon = trimmed.indexOf(":");
5118
+ if (colon > 0 && colon < 15) {
5119
+ const scheme = trimmed.slice(0, colon).toLowerCase();
5120
+ if (/^[a-z][a-z0-9+.-]*$/.test(scheme) && scheme !== "http" && scheme !== "https") {
5121
+ return defaultPath;
5122
+ }
5123
+ }
5124
+ if (trimmed.startsWith("/")) {
5125
+ if (trimmed.length > 1 && trimmed[1] === "\\") return defaultPath;
5126
+ return trimmed;
5127
+ }
5128
+ const allowed = (opts.allowedOrigins ?? []).map(normalizeOrigin).filter((o) => o !== null);
5129
+ try {
5130
+ const parsed = new URL(trimmed);
5131
+ const origin = `${parsed.protocol}//${parsed.host}`.toLowerCase();
5132
+ if (!allowed.includes(origin)) return defaultPath;
5133
+ if (opts.stripSameOriginHost !== false) {
5134
+ return `${parsed.pathname}${parsed.search}${parsed.hash}` || "/";
5135
+ }
5136
+ return trimmed;
5137
+ } catch {
5138
+ return defaultPath;
5139
+ }
5140
+ }
5141
+ function isSafeRedirect(input, opts = {}) {
5142
+ if (!input || typeof input !== "string") return false;
5143
+ const defaultPath = `__unsafe_sentinel_${Math.random()}`;
5144
+ const resolved = validateSafeRedirect(input, { ...opts, defaultPath });
5145
+ return resolved !== defaultPath;
5146
+ }
5147
+
5148
+ // src/server/security-headers.ts
5149
+ var DEFAULT_PERMISSIONS_POLICY = {
5150
+ // Conference track features — allow self-origin only.
5151
+ camera: "self",
5152
+ microphone: "self",
5153
+ "display-capture": "self",
5154
+ // Deny-by-default for features the SDK never uses.
5155
+ geolocation: "()",
5156
+ payment: "()",
5157
+ "publickey-credentials-get": "self",
5158
+ usb: "()",
5159
+ serial: "()",
5160
+ bluetooth: "()"
5161
+ };
5162
+ function formatPermissionsDirective(feature, value) {
5163
+ if (value === "*") return `${feature}=*`;
5164
+ if (value === "()" || Array.isArray(value) && value.length === 0) {
5165
+ return `${feature}=()`;
5166
+ }
5167
+ if (value === "self") return `${feature}=(self)`;
5168
+ const origins = value;
5169
+ const parts = origins.map((o) => o === "self" ? "self" : `"${o}"`);
5170
+ return `${feature}=(${parts.join(" ")})`;
5171
+ }
5172
+ function buildSecurityHeaders(opts = {}) {
5173
+ const headers2 = [];
5174
+ const includeHsts = opts.includeHsts ?? true;
5175
+ const hstsMaxAge = opts.hstsMaxAgeSeconds ?? 31536e3;
5176
+ if (includeHsts && hstsMaxAge > 0) {
5177
+ const parts = [`max-age=${hstsMaxAge}`];
5178
+ if (opts.hstsIncludeSubDomains ?? true) parts.push("includeSubDomains");
5179
+ if (opts.hstsPreload ?? false) parts.push("preload");
5180
+ headers2.push({
5181
+ key: "Strict-Transport-Security",
5182
+ value: parts.join("; ")
5183
+ });
5184
+ }
5185
+ const frameOptions = opts.frameOptions === void 0 ? "DENY" : opts.frameOptions;
5186
+ if (frameOptions !== null) {
5187
+ headers2.push({ key: "X-Frame-Options", value: frameOptions });
5188
+ }
5189
+ const contentTypeOptions = opts.contentTypeOptions === void 0 ? "nosniff" : opts.contentTypeOptions;
5190
+ if (contentTypeOptions !== null) {
5191
+ headers2.push({ key: "X-Content-Type-Options", value: contentTypeOptions });
5192
+ }
5193
+ headers2.push({
5194
+ key: "Referrer-Policy",
5195
+ value: opts.referrerPolicy ?? "strict-origin-when-cross-origin"
5196
+ });
5197
+ const xss = opts.xssProtection === void 0 ? "0" : opts.xssProtection;
5198
+ if (xss !== null) {
5199
+ headers2.push({ key: "X-XSS-Protection", value: xss });
5200
+ }
5201
+ const permissions = opts.permissionsPolicy === void 0 ? DEFAULT_PERMISSIONS_POLICY : opts.permissionsPolicy;
5202
+ if (permissions !== null) {
5203
+ const directives = Object.entries(permissions).map(([feature, value]) => formatPermissionsDirective(feature, value)).join(", ");
5204
+ headers2.push({ key: "Permissions-Policy", value: directives });
5205
+ }
5206
+ if (opts.extraHeaders?.length) {
5207
+ const byKey = new Map(headers2.map((h) => [h.key.toLowerCase(), h]));
5208
+ for (const extra of opts.extraHeaders) {
5209
+ byKey.set(extra.key.toLowerCase(), extra);
5210
+ }
5211
+ return Array.from(byKey.values());
5212
+ }
5213
+ return headers2;
5214
+ }
5215
+
4830
5216
  exports.CSRF_COOKIE_NAME = CSRF_COOKIE_NAME;
4831
5217
  exports.CSRF_HEADER_NAME = CSRF_HEADER_NAME;
5218
+ exports.DEFAULT_PERMISSIONS_POLICY = DEFAULT_PERMISSIONS_POLICY;
5219
+ exports.KNOWN_ACCOUNTS_COOKIE_NAME = KNOWN_ACCOUNTS_COOKIE_NAME;
4832
5220
  exports.OAUTH_STATE_COOKIE_NAME = OAUTH_STATE_COOKIE_NAME;
4833
5221
  exports.SESSION_COOKIE_NAME = SESSION_COOKIE_NAME;
4834
5222
  exports.ScaleMuleError = ScaleMuleError;
4835
5223
  exports.ScaleMuleServer = ScaleMuleServer;
4836
5224
  exports.USER_ID_COOKIE_NAME = USER_ID_COOKIE_NAME;
4837
5225
  exports.apiHandler = apiHandler;
5226
+ exports.appendKnownAccountCookie = appendKnownAccountCookie;
4838
5227
  exports.buildClientContextHeaders = buildClientContextHeaders;
4839
5228
  exports.buildFlagContext = buildFlagContext;
5229
+ exports.buildSecurityHeaders = buildSecurityHeaders;
5230
+ exports.clearKnownAccountsCookie = clearKnownAccountsCookie;
4840
5231
  exports.clearOAuthState = clearOAuthState;
4841
5232
  exports.clearSession = clearSession;
4842
5233
  exports.configureBundles = configureBundles;
@@ -4858,6 +5249,8 @@ exports.getAppSecretOrDefault = getAppSecretOrDefault;
4858
5249
  exports.getBootstrapFlags = getBootstrapFlags;
4859
5250
  exports.getBundle = getBundle;
4860
5251
  exports.getCSRFToken = getCSRFToken;
5252
+ exports.getKnownAccountsCookieRaw = getKnownAccountsCookieRaw;
5253
+ exports.getKnownAccountsFromRequest = getKnownAccountsFromRequest;
4861
5254
  exports.getMySqlBundle = getMySqlBundle;
4862
5255
  exports.getOAuthBundle = getOAuthBundle;
4863
5256
  exports.getPostgresBundle = getPostgresBundle;
@@ -4868,10 +5261,13 @@ exports.getSessionFromRequest = getSessionFromRequest;
4868
5261
  exports.getSmtpBundle = getSmtpBundle;
4869
5262
  exports.invalidateBundleCache = invalidateBundleCache;
4870
5263
  exports.invalidateSecretCache = invalidateSecretCache;
5264
+ exports.isSafeRedirect = isSafeRedirect;
5265
+ exports.normalizeKnownAccountsCookie = normalizeKnownAccountsCookie;
4871
5266
  exports.parseWebhookEvent = parseWebhookEvent;
4872
5267
  exports.prefetchBundles = prefetchBundles;
4873
5268
  exports.prefetchSecrets = prefetchSecrets;
4874
5269
  exports.registerVideoWebhook = registerVideoWebhook;
5270
+ exports.removeKnownAccountFromCookie = removeKnownAccountFromCookie;
4875
5271
  exports.requireAppSecret = requireAppSecret;
4876
5272
  exports.requireBundle = requireBundle;
4877
5273
  exports.requireSession = requireSession;
@@ -4882,6 +5278,7 @@ exports.validateCSRFToken = validateCSRFToken;
4882
5278
  exports.validateCSRFTokenAsync = validateCSRFTokenAsync;
4883
5279
  exports.validateOAuthState = validateOAuthState;
4884
5280
  exports.validateOAuthStateAsync = validateOAuthStateAsync;
5281
+ exports.validateSafeRedirect = validateSafeRedirect;
4885
5282
  exports.verifyWebhookSignature = verifyWebhookSignature;
4886
5283
  exports.withAuth = withAuth;
4887
5284
  exports.withCSRFProtection = withCSRFProtection;