@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,7 +1,8 @@
1
- import { S as ServerConfig } from '../webhook-handler-Cz9jtet2.mjs';
2
- export { a as ScaleMuleServer, V as VideoFailedEvent, b as VideoReadyEvent, c as VideoTranscodedEvent, d as VideoUploadedEvent, W as WebhookEvent, e as WebhookRoutesConfig, f as createServerClient, g as createWebhookHandler, h as createWebhookRoutes, p as parseWebhookEvent, r as registerVideoWebhook, i as resolveGatewayUrl, v as verifyWebhookSignature } from '../webhook-handler-Cz9jtet2.mjs';
3
- import { p as ClientContext, A as ApiError } from '../index-BoENfro3.mjs';
1
+ import { S as ServerConfig } from '../webhook-handler-BqzCYRNJ.mjs';
2
+ export { a as ScaleMuleServer, V as VideoFailedEvent, b as VideoReadyEvent, c as VideoTranscodedEvent, d as VideoUploadedEvent, W as WebhookEvent, e as WebhookRoutesConfig, f as createServerClient, g as createWebhookHandler, h as createWebhookRoutes, p as parseWebhookEvent, r as registerVideoWebhook, i as resolveGatewayUrl, v as verifyWebhookSignature } from '../webhook-handler-BqzCYRNJ.mjs';
3
+ import { p as ClientContext, A as ApiError } from '../index-BIIUrnPr.mjs';
4
4
  import { NextRequest, NextResponse } from 'next/server';
5
+ import '@scalemule/money';
5
6
 
6
7
  /**
7
8
  * Client Context Extraction Utilities (Next.js)
@@ -110,6 +111,12 @@ declare function buildFlagContext(clientContext: Pick<ClientContext, 'ip'> | und
110
111
  */
111
112
  declare const SESSION_COOKIE_NAME = "sm_session";
112
113
  declare const USER_ID_COOKIE_NAME = "sm_user_id";
114
+ /**
115
+ * Known accounts cookie — stores display metadata (email, name, avatar) for
116
+ * accounts that have logged in on this device. NOT httpOnly so client JS can
117
+ * read it to render the account switcher UI. Contains NO tokens or secrets.
118
+ */
119
+ declare const KNOWN_ACCOUNTS_COOKIE_NAME = "sm_known_accounts";
113
120
  interface SessionCookieOptions {
114
121
  /** Cookie max age in seconds (default: 7 days) */
115
122
  maxAge?: number;
@@ -181,6 +188,51 @@ declare function getSession(): Promise<SessionData | null>;
181
188
  * Use this when you need to read cookies from a Request directly.
182
189
  */
183
190
  declare function getSessionFromRequest(request: Request): SessionData | null;
191
+ /**
192
+ * Known account entry stored in cookie.
193
+ * Contains display metadata ONLY — no tokens, no secrets.
194
+ */
195
+ interface KnownAccountEntry {
196
+ userId: string;
197
+ email?: string;
198
+ fullName?: string;
199
+ avatarUrl?: string;
200
+ provider?: string;
201
+ lastActiveAt: string;
202
+ displayLabel?: string;
203
+ colorIndex?: number;
204
+ }
205
+ type AccountSwitcherPrivacy = 'full' | 'masked' | 'minimal';
206
+ /**
207
+ * Add an account to the known accounts cookie.
208
+ * Called after successful login. The cookie is NOT httpOnly so client JS
209
+ * can read it to render the account switcher UI.
210
+ *
211
+ * Appends Set-Cookie headers to an existing Headers object.
212
+ */
213
+ declare function appendKnownAccountCookie(headers: Headers, account: KnownAccountEntry, existingCookie: string | null, options?: SessionCookieOptions, privacy?: AccountSwitcherPrivacy): void;
214
+ /**
215
+ * Remove a specific account from the known accounts cookie.
216
+ */
217
+ declare function removeKnownAccountFromCookie(headers: Headers, userId: string, existingCookie: string | null, options?: SessionCookieOptions): void;
218
+ /**
219
+ * Clear the known accounts cookie entirely.
220
+ */
221
+ declare function clearKnownAccountsCookie(headers: Headers, options?: SessionCookieOptions): void;
222
+ /**
223
+ * Read known accounts from a Request's cookies.
224
+ */
225
+ declare function getKnownAccountsFromRequest(request: Request): KnownAccountEntry[];
226
+ /**
227
+ * Read the raw known accounts cookie value from a Request.
228
+ */
229
+ declare function getKnownAccountsCookieRaw(request: Request): string | null;
230
+ /**
231
+ * Normalize all entries in the known accounts cookie to the given privacy level.
232
+ * Returns a Set-Cookie header string if any entries changed, or null if nothing changed.
233
+ * Used on /me requests to migrate legacy full-PII cookies to the configured privacy level.
234
+ */
235
+ declare function normalizeKnownAccountsCookie(request: Request, privacy: AccountSwitcherPrivacy | undefined, options?: SessionCookieOptions): string | null;
184
236
  /**
185
237
  * Require authentication - throws Response if not authenticated
186
238
  *
@@ -220,6 +272,19 @@ interface AuthRoutesConfig {
220
272
  cookies?: SessionCookieOptions;
221
273
  /** Enable CSRF validation on state-changing requests (POST/DELETE/PATCH) */
222
274
  csrf?: boolean;
275
+ /**
276
+ * Enable the account switcher — remembers which accounts have logged in on
277
+ * this device (metadata only, no tokens). Switching requires re-authentication.
278
+ * Adds routes: switch-account, forget-account, forget-all-accounts, known-accounts.
279
+ */
280
+ enableAccountSwitcher?: boolean;
281
+ /**
282
+ * Privacy level for account switcher display metadata.
283
+ * - 'full': Store email, name, avatar as-is (default)
284
+ * - 'masked': Mask email, truncate name to initial
285
+ * - 'minimal': No PII — just a colored "Account" label
286
+ */
287
+ accountSwitcherPrivacy?: 'full' | 'masked' | 'minimal';
223
288
  /** Callbacks */
224
289
  onLogin?: (user: {
225
290
  id: string;
@@ -1011,4 +1076,187 @@ declare function invalidateBundleCache(key?: string): void;
1011
1076
  */
1012
1077
  declare function prefetchBundles(keys: string[]): Promise<void>;
1013
1078
 
1014
- export { type AnalyticsRoutesConfig, type AnalyticsTrackingGateConfig, type AuthMiddlewareConfig, type AuthRoutesConfig, CSRF_COOKIE_NAME, CSRF_HEADER_NAME, type HandlerContext, type HandlerOptions, type MySqlBundle, type NotificationRoutesConfig, OAUTH_STATE_COOKIE_NAME, type OAuthBundle, type PostgresBundle, type PushRoutesConfig, type RedisBundle, type S3Bundle, SESSION_COOKIE_NAME, ScaleMuleError, ServerConfig, type SessionCookieOptions, type SessionData, type SmtpBundle, USER_ID_COOKIE_NAME, apiHandler, buildClientContextHeaders, buildFlagContext, clearOAuthState, clearSession, configureBundles, configureSecrets, createAnalyticsRoutes, createAuthMiddleware, createAuthRoutes, createNotificationRoutes, createPushRoutes, errorCodeToStatus, extractClientContext, extractClientContextFromReq, generateCSRFToken, getAppSecret, getAppSecretOrDefault, getBootstrapFlags, getBundle, getCSRFToken, getMySqlBundle, getOAuthBundle, getPostgresBundle, getRedisBundle, getS3Bundle, getSession, getSessionFromRequest, getSmtpBundle, invalidateBundleCache, invalidateSecretCache, prefetchBundles, prefetchSecrets, requireAppSecret, requireBundle, requireSession, setOAuthState, unwrap, validateCSRFToken, validateCSRFTokenAsync, validateOAuthState, validateOAuthStateAsync, withAuth, withCSRFProtection, withCSRFToken, withSession };
1079
+ /**
1080
+ * Safe-redirect validation for authentication callback URLs.
1081
+ *
1082
+ * Prevents open-redirect attacks on `returnTo` / `callbackUrl` / `next`
1083
+ * params after login / registration / password-reset flows. An attacker
1084
+ * who can inject a `?returnTo=https://evil.example` into your login
1085
+ * form would otherwise redirect the freshly-authenticated user away
1086
+ * from your origin — a classic phishing + credential-harvesting setup.
1087
+ *
1088
+ * Safe by default — unknown input returns the configured default
1089
+ * path. Hosts opt in to external origins explicitly via
1090
+ * `allowedOrigins`.
1091
+ *
1092
+ * Framework-agnostic: no imports from `next/*`. Safe in any
1093
+ * Edge / Node / middleware runtime.
1094
+ */
1095
+ interface SafeRedirectOptions {
1096
+ /**
1097
+ * Origins (schema + host + optional port) the redirect is allowed
1098
+ * to land on. Default `[]` — only same-origin relative paths are
1099
+ * allowed. Items are compared case-insensitively after normalizing
1100
+ * the scheme and host.
1101
+ *
1102
+ * Good practice: list only origins that your organization controls
1103
+ * and that are reachable over HTTPS.
1104
+ *
1105
+ * @example
1106
+ * ['https://app.example.com', 'https://admin.example.com']
1107
+ */
1108
+ allowedOrigins?: string[];
1109
+ /**
1110
+ * Value returned when the input is missing, invalid, or points
1111
+ * outside the allowlist. Default `'/'`.
1112
+ */
1113
+ defaultPath?: string;
1114
+ /**
1115
+ * Strip the scheme + host from same-origin absolute URLs and
1116
+ * return only the path + query + fragment. Default `true` — keeps
1117
+ * redirect targets as short relative URLs that route through
1118
+ * client-side routing cleanly.
1119
+ */
1120
+ stripSameOriginHost?: boolean;
1121
+ }
1122
+ /**
1123
+ * Returns a safe-to-use redirect path, falling back to
1124
+ * `opts.defaultPath` (default `'/'`) when the input fails validation.
1125
+ *
1126
+ * Accepts:
1127
+ * - empty / nullish → default
1128
+ * - relative paths like `/foo/bar?x=1#frag` (leading `/` required)
1129
+ * - absolute URLs whose origin is in `allowedOrigins`
1130
+ *
1131
+ * Rejects everything else, including:
1132
+ * - schema-relative URLs (`//evil.example`)
1133
+ * - backslash-prefixed paths
1134
+ * - `javascript:`, `data:`, `mailto:`, `vbscript:` etc.
1135
+ * - bare hostnames (`example.com/path`)
1136
+ * - malformed URLs
1137
+ */
1138
+ declare function validateSafeRedirect(input: string | null | undefined, opts?: SafeRedirectOptions): string;
1139
+ /**
1140
+ * Boolean predicate form. Returns `true` when `input` would pass
1141
+ * `validateSafeRedirect` with the same options.
1142
+ */
1143
+ declare function isSafeRedirect(input: string | null | undefined, opts?: SafeRedirectOptions): boolean;
1144
+
1145
+ /**
1146
+ * Security-headers helper for Next.js hosts.
1147
+ *
1148
+ * Returns a shape that drops directly into the `headers()` entry in
1149
+ * `next.config.ts` (or the `headers` field of a Route Handler
1150
+ * `NextResponse`). Reasonable defaults for the top-of-OWASP headers
1151
+ * — HSTS, X-Frame-Options, X-Content-Type-Options, Referrer-Policy,
1152
+ * X-XSS-Protection, Permissions-Policy — with knobs for the fields
1153
+ * that typically differ by app (HSTS duration, frame ancestors,
1154
+ * camera/microphone policies).
1155
+ *
1156
+ * Framework-agnostic: no imports from `next/*` so the function works
1157
+ * in Edge / Node / middleware and is trivially unit-testable.
1158
+ */
1159
+ interface SecurityHeaderEntry {
1160
+ key: string;
1161
+ value: string;
1162
+ }
1163
+ interface BuildSecurityHeadersOptions {
1164
+ /**
1165
+ * HSTS max-age in seconds. Default `31536000` (1 year) — the value
1166
+ * required for inclusion on the HSTS preload list. Set to `0` (or
1167
+ * pass `includeHsts: false`) to opt out entirely.
1168
+ */
1169
+ hstsMaxAgeSeconds?: number;
1170
+ /** Adds the `includeSubDomains` directive to HSTS. Default `true`. */
1171
+ hstsIncludeSubDomains?: boolean;
1172
+ /**
1173
+ * Adds the `preload` directive to HSTS. Default `false` — only set
1174
+ * to `true` after you've read https://hstspreload.org and are ready
1175
+ * to commit; reversing it requires months of calendar time.
1176
+ */
1177
+ hstsPreload?: boolean;
1178
+ /** Emit the HSTS header at all. Default `true`. */
1179
+ includeHsts?: boolean;
1180
+ /**
1181
+ * Value for `X-Frame-Options`. Default `'DENY'`. Pass `'SAMEORIGIN'`
1182
+ * if your app is framed by its own subdomain. Set to `null` to
1183
+ * suppress (e.g. when you're already using `frame-ancestors` in
1184
+ * CSP). `SAMEORIGIN` accepts no host parameter; use CSP's
1185
+ * `frame-ancestors` for finer-grained framing policy.
1186
+ */
1187
+ frameOptions?: 'DENY' | 'SAMEORIGIN' | null;
1188
+ /**
1189
+ * Value for `Referrer-Policy`. Default `'strict-origin-when-cross-origin'`
1190
+ * — same as Next.js's own default, balances analytics with privacy.
1191
+ */
1192
+ referrerPolicy?: 'no-referrer' | 'no-referrer-when-downgrade' | 'origin' | 'origin-when-cross-origin' | 'same-origin' | 'strict-origin' | 'strict-origin-when-cross-origin' | 'unsafe-url';
1193
+ /**
1194
+ * Permissions-Policy directives. Pass a map of `{ feature: allowlist }`
1195
+ * where the allowlist is either an array of origins (string[]) or
1196
+ * one of the well-known tokens `'self'` / `'*'` / `'()'` (deny).
1197
+ *
1198
+ * Default: camera + microphone allowed for `'self'` only (useful
1199
+ * for the conference track); geolocation + payment denied; every
1200
+ * other common feature left unset (browsers apply their own
1201
+ * conservative defaults).
1202
+ *
1203
+ * Pass `{}` to emit an empty `Permissions-Policy: ` header (rarely
1204
+ * useful). Pass `null` to suppress the header entirely.
1205
+ */
1206
+ permissionsPolicy?: PermissionsPolicyMap | null;
1207
+ /**
1208
+ * Value for `X-Content-Type-Options`. Default `'nosniff'` — do not
1209
+ * override without a specific reason.
1210
+ */
1211
+ contentTypeOptions?: string | null;
1212
+ /**
1213
+ * Legacy `X-XSS-Protection`. Default `'0'` (disables the
1214
+ * deprecated IE/Edge filter which had known bypass issues —
1215
+ * recommended by OWASP + Next.js). Set to `'1; mode=block'` only
1216
+ * if you have a specific compliance reason.
1217
+ */
1218
+ xssProtection?: string | null;
1219
+ /**
1220
+ * Extra headers to merge into the result. Takes precedence over
1221
+ * the computed ones — useful for adding Content-Security-Policy or
1222
+ * Cross-Origin-* headers without forcing a new option for each.
1223
+ */
1224
+ extraHeaders?: SecurityHeaderEntry[];
1225
+ }
1226
+ type PermissionsPolicyValue = readonly string[] | 'self' | '*' | '()';
1227
+ type PermissionsPolicyMap = Readonly<Record<string, PermissionsPolicyValue>>;
1228
+ declare const DEFAULT_PERMISSIONS_POLICY: PermissionsPolicyMap;
1229
+ /**
1230
+ * Build a reasonable-default set of security response headers in the
1231
+ * exact shape Next.js `headers()` expects.
1232
+ *
1233
+ * @example next.config.ts
1234
+ * ```ts
1235
+ * import { buildSecurityHeaders } from '@scalemule/nextjs/server'
1236
+ *
1237
+ * export default {
1238
+ * async headers() {
1239
+ * return [
1240
+ * { source: '/:path*', headers: buildSecurityHeaders() },
1241
+ * ]
1242
+ * },
1243
+ * }
1244
+ * ```
1245
+ *
1246
+ * @example custom overrides
1247
+ * ```ts
1248
+ * buildSecurityHeaders({
1249
+ * frameOptions: 'SAMEORIGIN',
1250
+ * permissionsPolicy: {
1251
+ * camera: ['https://trusted.example.com'],
1252
+ * microphone: ['https://trusted.example.com'],
1253
+ * },
1254
+ * extraHeaders: [
1255
+ * { key: 'Content-Security-Policy', value: "default-src 'self'" },
1256
+ * ],
1257
+ * })
1258
+ * ```
1259
+ */
1260
+ declare function buildSecurityHeaders(opts?: BuildSecurityHeadersOptions): SecurityHeaderEntry[];
1261
+
1262
+ export { type AnalyticsRoutesConfig, type AnalyticsTrackingGateConfig, type AuthMiddlewareConfig, type AuthRoutesConfig, type BuildSecurityHeadersOptions, CSRF_COOKIE_NAME, CSRF_HEADER_NAME, DEFAULT_PERMISSIONS_POLICY, type HandlerContext, type HandlerOptions, KNOWN_ACCOUNTS_COOKIE_NAME, type KnownAccountEntry, type MySqlBundle, type NotificationRoutesConfig, OAUTH_STATE_COOKIE_NAME, type OAuthBundle, type PermissionsPolicyMap, type PermissionsPolicyValue, type PostgresBundle, type PushRoutesConfig, type RedisBundle, type S3Bundle, SESSION_COOKIE_NAME, type SafeRedirectOptions, ScaleMuleError, type SecurityHeaderEntry, ServerConfig, type SessionCookieOptions, type SessionData, type SmtpBundle, USER_ID_COOKIE_NAME, apiHandler, appendKnownAccountCookie, buildClientContextHeaders, buildFlagContext, buildSecurityHeaders, clearKnownAccountsCookie, clearOAuthState, clearSession, configureBundles, configureSecrets, createAnalyticsRoutes, createAuthMiddleware, createAuthRoutes, createNotificationRoutes, createPushRoutes, errorCodeToStatus, extractClientContext, extractClientContextFromReq, generateCSRFToken, getAppSecret, getAppSecretOrDefault, getBootstrapFlags, getBundle, getCSRFToken, getKnownAccountsCookieRaw, getKnownAccountsFromRequest, getMySqlBundle, getOAuthBundle, getPostgresBundle, getRedisBundle, getS3Bundle, getSession, getSessionFromRequest, getSmtpBundle, invalidateBundleCache, invalidateSecretCache, isSafeRedirect, normalizeKnownAccountsCookie, prefetchBundles, prefetchSecrets, removeKnownAccountFromCookie, requireAppSecret, requireBundle, requireSession, setOAuthState, unwrap, validateCSRFToken, validateCSRFTokenAsync, validateOAuthState, validateOAuthStateAsync, validateSafeRedirect, withAuth, withCSRFProtection, withCSRFToken, withSession };
@@ -1,7 +1,8 @@
1
- import { S as ServerConfig } from '../webhook-handler-CjSSCdvI.js';
2
- export { a as ScaleMuleServer, V as VideoFailedEvent, b as VideoReadyEvent, c as VideoTranscodedEvent, d as VideoUploadedEvent, W as WebhookEvent, e as WebhookRoutesConfig, f as createServerClient, g as createWebhookHandler, h as createWebhookRoutes, p as parseWebhookEvent, r as registerVideoWebhook, i as resolveGatewayUrl, v as verifyWebhookSignature } from '../webhook-handler-CjSSCdvI.js';
3
- import { p as ClientContext, A as ApiError } from '../index-BoENfro3.js';
1
+ import { S as ServerConfig } from '../webhook-handler-BjFbqZuq.js';
2
+ export { a as ScaleMuleServer, V as VideoFailedEvent, b as VideoReadyEvent, c as VideoTranscodedEvent, d as VideoUploadedEvent, W as WebhookEvent, e as WebhookRoutesConfig, f as createServerClient, g as createWebhookHandler, h as createWebhookRoutes, p as parseWebhookEvent, r as registerVideoWebhook, i as resolveGatewayUrl, v as verifyWebhookSignature } from '../webhook-handler-BjFbqZuq.js';
3
+ import { p as ClientContext, A as ApiError } from '../index-BIIUrnPr.js';
4
4
  import { NextRequest, NextResponse } from 'next/server';
5
+ import '@scalemule/money';
5
6
 
6
7
  /**
7
8
  * Client Context Extraction Utilities (Next.js)
@@ -110,6 +111,12 @@ declare function buildFlagContext(clientContext: Pick<ClientContext, 'ip'> | und
110
111
  */
111
112
  declare const SESSION_COOKIE_NAME = "sm_session";
112
113
  declare const USER_ID_COOKIE_NAME = "sm_user_id";
114
+ /**
115
+ * Known accounts cookie — stores display metadata (email, name, avatar) for
116
+ * accounts that have logged in on this device. NOT httpOnly so client JS can
117
+ * read it to render the account switcher UI. Contains NO tokens or secrets.
118
+ */
119
+ declare const KNOWN_ACCOUNTS_COOKIE_NAME = "sm_known_accounts";
113
120
  interface SessionCookieOptions {
114
121
  /** Cookie max age in seconds (default: 7 days) */
115
122
  maxAge?: number;
@@ -181,6 +188,51 @@ declare function getSession(): Promise<SessionData | null>;
181
188
  * Use this when you need to read cookies from a Request directly.
182
189
  */
183
190
  declare function getSessionFromRequest(request: Request): SessionData | null;
191
+ /**
192
+ * Known account entry stored in cookie.
193
+ * Contains display metadata ONLY — no tokens, no secrets.
194
+ */
195
+ interface KnownAccountEntry {
196
+ userId: string;
197
+ email?: string;
198
+ fullName?: string;
199
+ avatarUrl?: string;
200
+ provider?: string;
201
+ lastActiveAt: string;
202
+ displayLabel?: string;
203
+ colorIndex?: number;
204
+ }
205
+ type AccountSwitcherPrivacy = 'full' | 'masked' | 'minimal';
206
+ /**
207
+ * Add an account to the known accounts cookie.
208
+ * Called after successful login. The cookie is NOT httpOnly so client JS
209
+ * can read it to render the account switcher UI.
210
+ *
211
+ * Appends Set-Cookie headers to an existing Headers object.
212
+ */
213
+ declare function appendKnownAccountCookie(headers: Headers, account: KnownAccountEntry, existingCookie: string | null, options?: SessionCookieOptions, privacy?: AccountSwitcherPrivacy): void;
214
+ /**
215
+ * Remove a specific account from the known accounts cookie.
216
+ */
217
+ declare function removeKnownAccountFromCookie(headers: Headers, userId: string, existingCookie: string | null, options?: SessionCookieOptions): void;
218
+ /**
219
+ * Clear the known accounts cookie entirely.
220
+ */
221
+ declare function clearKnownAccountsCookie(headers: Headers, options?: SessionCookieOptions): void;
222
+ /**
223
+ * Read known accounts from a Request's cookies.
224
+ */
225
+ declare function getKnownAccountsFromRequest(request: Request): KnownAccountEntry[];
226
+ /**
227
+ * Read the raw known accounts cookie value from a Request.
228
+ */
229
+ declare function getKnownAccountsCookieRaw(request: Request): string | null;
230
+ /**
231
+ * Normalize all entries in the known accounts cookie to the given privacy level.
232
+ * Returns a Set-Cookie header string if any entries changed, or null if nothing changed.
233
+ * Used on /me requests to migrate legacy full-PII cookies to the configured privacy level.
234
+ */
235
+ declare function normalizeKnownAccountsCookie(request: Request, privacy: AccountSwitcherPrivacy | undefined, options?: SessionCookieOptions): string | null;
184
236
  /**
185
237
  * Require authentication - throws Response if not authenticated
186
238
  *
@@ -220,6 +272,19 @@ interface AuthRoutesConfig {
220
272
  cookies?: SessionCookieOptions;
221
273
  /** Enable CSRF validation on state-changing requests (POST/DELETE/PATCH) */
222
274
  csrf?: boolean;
275
+ /**
276
+ * Enable the account switcher — remembers which accounts have logged in on
277
+ * this device (metadata only, no tokens). Switching requires re-authentication.
278
+ * Adds routes: switch-account, forget-account, forget-all-accounts, known-accounts.
279
+ */
280
+ enableAccountSwitcher?: boolean;
281
+ /**
282
+ * Privacy level for account switcher display metadata.
283
+ * - 'full': Store email, name, avatar as-is (default)
284
+ * - 'masked': Mask email, truncate name to initial
285
+ * - 'minimal': No PII — just a colored "Account" label
286
+ */
287
+ accountSwitcherPrivacy?: 'full' | 'masked' | 'minimal';
223
288
  /** Callbacks */
224
289
  onLogin?: (user: {
225
290
  id: string;
@@ -1011,4 +1076,187 @@ declare function invalidateBundleCache(key?: string): void;
1011
1076
  */
1012
1077
  declare function prefetchBundles(keys: string[]): Promise<void>;
1013
1078
 
1014
- export { type AnalyticsRoutesConfig, type AnalyticsTrackingGateConfig, type AuthMiddlewareConfig, type AuthRoutesConfig, CSRF_COOKIE_NAME, CSRF_HEADER_NAME, type HandlerContext, type HandlerOptions, type MySqlBundle, type NotificationRoutesConfig, OAUTH_STATE_COOKIE_NAME, type OAuthBundle, type PostgresBundle, type PushRoutesConfig, type RedisBundle, type S3Bundle, SESSION_COOKIE_NAME, ScaleMuleError, ServerConfig, type SessionCookieOptions, type SessionData, type SmtpBundle, USER_ID_COOKIE_NAME, apiHandler, buildClientContextHeaders, buildFlagContext, clearOAuthState, clearSession, configureBundles, configureSecrets, createAnalyticsRoutes, createAuthMiddleware, createAuthRoutes, createNotificationRoutes, createPushRoutes, errorCodeToStatus, extractClientContext, extractClientContextFromReq, generateCSRFToken, getAppSecret, getAppSecretOrDefault, getBootstrapFlags, getBundle, getCSRFToken, getMySqlBundle, getOAuthBundle, getPostgresBundle, getRedisBundle, getS3Bundle, getSession, getSessionFromRequest, getSmtpBundle, invalidateBundleCache, invalidateSecretCache, prefetchBundles, prefetchSecrets, requireAppSecret, requireBundle, requireSession, setOAuthState, unwrap, validateCSRFToken, validateCSRFTokenAsync, validateOAuthState, validateOAuthStateAsync, withAuth, withCSRFProtection, withCSRFToken, withSession };
1079
+ /**
1080
+ * Safe-redirect validation for authentication callback URLs.
1081
+ *
1082
+ * Prevents open-redirect attacks on `returnTo` / `callbackUrl` / `next`
1083
+ * params after login / registration / password-reset flows. An attacker
1084
+ * who can inject a `?returnTo=https://evil.example` into your login
1085
+ * form would otherwise redirect the freshly-authenticated user away
1086
+ * from your origin — a classic phishing + credential-harvesting setup.
1087
+ *
1088
+ * Safe by default — unknown input returns the configured default
1089
+ * path. Hosts opt in to external origins explicitly via
1090
+ * `allowedOrigins`.
1091
+ *
1092
+ * Framework-agnostic: no imports from `next/*`. Safe in any
1093
+ * Edge / Node / middleware runtime.
1094
+ */
1095
+ interface SafeRedirectOptions {
1096
+ /**
1097
+ * Origins (schema + host + optional port) the redirect is allowed
1098
+ * to land on. Default `[]` — only same-origin relative paths are
1099
+ * allowed. Items are compared case-insensitively after normalizing
1100
+ * the scheme and host.
1101
+ *
1102
+ * Good practice: list only origins that your organization controls
1103
+ * and that are reachable over HTTPS.
1104
+ *
1105
+ * @example
1106
+ * ['https://app.example.com', 'https://admin.example.com']
1107
+ */
1108
+ allowedOrigins?: string[];
1109
+ /**
1110
+ * Value returned when the input is missing, invalid, or points
1111
+ * outside the allowlist. Default `'/'`.
1112
+ */
1113
+ defaultPath?: string;
1114
+ /**
1115
+ * Strip the scheme + host from same-origin absolute URLs and
1116
+ * return only the path + query + fragment. Default `true` — keeps
1117
+ * redirect targets as short relative URLs that route through
1118
+ * client-side routing cleanly.
1119
+ */
1120
+ stripSameOriginHost?: boolean;
1121
+ }
1122
+ /**
1123
+ * Returns a safe-to-use redirect path, falling back to
1124
+ * `opts.defaultPath` (default `'/'`) when the input fails validation.
1125
+ *
1126
+ * Accepts:
1127
+ * - empty / nullish → default
1128
+ * - relative paths like `/foo/bar?x=1#frag` (leading `/` required)
1129
+ * - absolute URLs whose origin is in `allowedOrigins`
1130
+ *
1131
+ * Rejects everything else, including:
1132
+ * - schema-relative URLs (`//evil.example`)
1133
+ * - backslash-prefixed paths
1134
+ * - `javascript:`, `data:`, `mailto:`, `vbscript:` etc.
1135
+ * - bare hostnames (`example.com/path`)
1136
+ * - malformed URLs
1137
+ */
1138
+ declare function validateSafeRedirect(input: string | null | undefined, opts?: SafeRedirectOptions): string;
1139
+ /**
1140
+ * Boolean predicate form. Returns `true` when `input` would pass
1141
+ * `validateSafeRedirect` with the same options.
1142
+ */
1143
+ declare function isSafeRedirect(input: string | null | undefined, opts?: SafeRedirectOptions): boolean;
1144
+
1145
+ /**
1146
+ * Security-headers helper for Next.js hosts.
1147
+ *
1148
+ * Returns a shape that drops directly into the `headers()` entry in
1149
+ * `next.config.ts` (or the `headers` field of a Route Handler
1150
+ * `NextResponse`). Reasonable defaults for the top-of-OWASP headers
1151
+ * — HSTS, X-Frame-Options, X-Content-Type-Options, Referrer-Policy,
1152
+ * X-XSS-Protection, Permissions-Policy — with knobs for the fields
1153
+ * that typically differ by app (HSTS duration, frame ancestors,
1154
+ * camera/microphone policies).
1155
+ *
1156
+ * Framework-agnostic: no imports from `next/*` so the function works
1157
+ * in Edge / Node / middleware and is trivially unit-testable.
1158
+ */
1159
+ interface SecurityHeaderEntry {
1160
+ key: string;
1161
+ value: string;
1162
+ }
1163
+ interface BuildSecurityHeadersOptions {
1164
+ /**
1165
+ * HSTS max-age in seconds. Default `31536000` (1 year) — the value
1166
+ * required for inclusion on the HSTS preload list. Set to `0` (or
1167
+ * pass `includeHsts: false`) to opt out entirely.
1168
+ */
1169
+ hstsMaxAgeSeconds?: number;
1170
+ /** Adds the `includeSubDomains` directive to HSTS. Default `true`. */
1171
+ hstsIncludeSubDomains?: boolean;
1172
+ /**
1173
+ * Adds the `preload` directive to HSTS. Default `false` — only set
1174
+ * to `true` after you've read https://hstspreload.org and are ready
1175
+ * to commit; reversing it requires months of calendar time.
1176
+ */
1177
+ hstsPreload?: boolean;
1178
+ /** Emit the HSTS header at all. Default `true`. */
1179
+ includeHsts?: boolean;
1180
+ /**
1181
+ * Value for `X-Frame-Options`. Default `'DENY'`. Pass `'SAMEORIGIN'`
1182
+ * if your app is framed by its own subdomain. Set to `null` to
1183
+ * suppress (e.g. when you're already using `frame-ancestors` in
1184
+ * CSP). `SAMEORIGIN` accepts no host parameter; use CSP's
1185
+ * `frame-ancestors` for finer-grained framing policy.
1186
+ */
1187
+ frameOptions?: 'DENY' | 'SAMEORIGIN' | null;
1188
+ /**
1189
+ * Value for `Referrer-Policy`. Default `'strict-origin-when-cross-origin'`
1190
+ * — same as Next.js's own default, balances analytics with privacy.
1191
+ */
1192
+ referrerPolicy?: 'no-referrer' | 'no-referrer-when-downgrade' | 'origin' | 'origin-when-cross-origin' | 'same-origin' | 'strict-origin' | 'strict-origin-when-cross-origin' | 'unsafe-url';
1193
+ /**
1194
+ * Permissions-Policy directives. Pass a map of `{ feature: allowlist }`
1195
+ * where the allowlist is either an array of origins (string[]) or
1196
+ * one of the well-known tokens `'self'` / `'*'` / `'()'` (deny).
1197
+ *
1198
+ * Default: camera + microphone allowed for `'self'` only (useful
1199
+ * for the conference track); geolocation + payment denied; every
1200
+ * other common feature left unset (browsers apply their own
1201
+ * conservative defaults).
1202
+ *
1203
+ * Pass `{}` to emit an empty `Permissions-Policy: ` header (rarely
1204
+ * useful). Pass `null` to suppress the header entirely.
1205
+ */
1206
+ permissionsPolicy?: PermissionsPolicyMap | null;
1207
+ /**
1208
+ * Value for `X-Content-Type-Options`. Default `'nosniff'` — do not
1209
+ * override without a specific reason.
1210
+ */
1211
+ contentTypeOptions?: string | null;
1212
+ /**
1213
+ * Legacy `X-XSS-Protection`. Default `'0'` (disables the
1214
+ * deprecated IE/Edge filter which had known bypass issues —
1215
+ * recommended by OWASP + Next.js). Set to `'1; mode=block'` only
1216
+ * if you have a specific compliance reason.
1217
+ */
1218
+ xssProtection?: string | null;
1219
+ /**
1220
+ * Extra headers to merge into the result. Takes precedence over
1221
+ * the computed ones — useful for adding Content-Security-Policy or
1222
+ * Cross-Origin-* headers without forcing a new option for each.
1223
+ */
1224
+ extraHeaders?: SecurityHeaderEntry[];
1225
+ }
1226
+ type PermissionsPolicyValue = readonly string[] | 'self' | '*' | '()';
1227
+ type PermissionsPolicyMap = Readonly<Record<string, PermissionsPolicyValue>>;
1228
+ declare const DEFAULT_PERMISSIONS_POLICY: PermissionsPolicyMap;
1229
+ /**
1230
+ * Build a reasonable-default set of security response headers in the
1231
+ * exact shape Next.js `headers()` expects.
1232
+ *
1233
+ * @example next.config.ts
1234
+ * ```ts
1235
+ * import { buildSecurityHeaders } from '@scalemule/nextjs/server'
1236
+ *
1237
+ * export default {
1238
+ * async headers() {
1239
+ * return [
1240
+ * { source: '/:path*', headers: buildSecurityHeaders() },
1241
+ * ]
1242
+ * },
1243
+ * }
1244
+ * ```
1245
+ *
1246
+ * @example custom overrides
1247
+ * ```ts
1248
+ * buildSecurityHeaders({
1249
+ * frameOptions: 'SAMEORIGIN',
1250
+ * permissionsPolicy: {
1251
+ * camera: ['https://trusted.example.com'],
1252
+ * microphone: ['https://trusted.example.com'],
1253
+ * },
1254
+ * extraHeaders: [
1255
+ * { key: 'Content-Security-Policy', value: "default-src 'self'" },
1256
+ * ],
1257
+ * })
1258
+ * ```
1259
+ */
1260
+ declare function buildSecurityHeaders(opts?: BuildSecurityHeadersOptions): SecurityHeaderEntry[];
1261
+
1262
+ export { type AnalyticsRoutesConfig, type AnalyticsTrackingGateConfig, type AuthMiddlewareConfig, type AuthRoutesConfig, type BuildSecurityHeadersOptions, CSRF_COOKIE_NAME, CSRF_HEADER_NAME, DEFAULT_PERMISSIONS_POLICY, type HandlerContext, type HandlerOptions, KNOWN_ACCOUNTS_COOKIE_NAME, type KnownAccountEntry, type MySqlBundle, type NotificationRoutesConfig, OAUTH_STATE_COOKIE_NAME, type OAuthBundle, type PermissionsPolicyMap, type PermissionsPolicyValue, type PostgresBundle, type PushRoutesConfig, type RedisBundle, type S3Bundle, SESSION_COOKIE_NAME, type SafeRedirectOptions, ScaleMuleError, type SecurityHeaderEntry, ServerConfig, type SessionCookieOptions, type SessionData, type SmtpBundle, USER_ID_COOKIE_NAME, apiHandler, appendKnownAccountCookie, buildClientContextHeaders, buildFlagContext, buildSecurityHeaders, clearKnownAccountsCookie, clearOAuthState, clearSession, configureBundles, configureSecrets, createAnalyticsRoutes, createAuthMiddleware, createAuthRoutes, createNotificationRoutes, createPushRoutes, errorCodeToStatus, extractClientContext, extractClientContextFromReq, generateCSRFToken, getAppSecret, getAppSecretOrDefault, getBootstrapFlags, getBundle, getCSRFToken, getKnownAccountsCookieRaw, getKnownAccountsFromRequest, getMySqlBundle, getOAuthBundle, getPostgresBundle, getRedisBundle, getS3Bundle, getSession, getSessionFromRequest, getSmtpBundle, invalidateBundleCache, invalidateSecretCache, isSafeRedirect, normalizeKnownAccountsCookie, prefetchBundles, prefetchSecrets, removeKnownAccountFromCookie, requireAppSecret, requireBundle, requireSession, setOAuthState, unwrap, validateCSRFToken, validateCSRFTokenAsync, validateOAuthState, validateOAuthStateAsync, validateSafeRedirect, withAuth, withCSRFProtection, withCSRFToken, withSession };