@scalemule/nextjs 0.0.1

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.
@@ -0,0 +1,868 @@
1
+ import { S as ServerConfig } from '../webhook-handler-C-5_Ey1T.mjs';
2
+ export { a as ScaleMuleServer, d as VideoFailedEvent, V as VideoReadyEvent, f as VideoTranscodedEvent, e as VideoUploadedEvent, W as WebhookEvent, g as WebhookRoutesConfig, c as createServerClient, h as createWebhookHandler, b as createWebhookRoutes, p as parseWebhookEvent, r as registerVideoWebhook, v as verifyWebhookSignature } from '../webhook-handler-C-5_Ey1T.mjs';
3
+ import { _ as ClientContext, L as LoginResponse, A as ApiError } from '../index-BkacIKdu.mjs';
4
+ import { NextRequest, NextResponse } from 'next/server';
5
+
6
+ /**
7
+ * Client Context Extraction Utilities (Next.js)
8
+ *
9
+ * Next.js-specific helpers for extracting end user context from incoming
10
+ * requests so it can be forwarded to ScaleMule when making server-to-server
11
+ * calls. This ensures ScaleMule captures the actual end user's information
12
+ * (IP, user agent, device fingerprint) instead of the server's information.
13
+ *
14
+ * For non-Next.js servers (Express, Fastify, raw Node.js), use the
15
+ * framework-agnostic `extractClientContext()` and `buildClientContextHeaders()`
16
+ * exported directly from `@scalemule/sdk`.
17
+ */
18
+
19
+ interface NextRequestLike {
20
+ headers: {
21
+ get(name: string): string | null;
22
+ };
23
+ ip?: string;
24
+ }
25
+ interface IncomingMessageLike {
26
+ headers: Record<string, string | string[] | undefined>;
27
+ socket?: {
28
+ remoteAddress?: string;
29
+ };
30
+ }
31
+ /**
32
+ * Extract client context from a Next.js App Router request.
33
+ *
34
+ * Use this in App Router API routes (route handlers) to capture
35
+ * the end user's information for forwarding to ScaleMule.
36
+ *
37
+ * Supports all major cloud providers and CDNs:
38
+ * - Cloudflare (CF-Connecting-IP)
39
+ * - DigitalOcean App Platform (DO-Connecting-IP)
40
+ * - Vercel (X-Vercel-Forwarded-For)
41
+ * - Akamai (True-Client-IP)
42
+ * - AWS/nginx (X-Real-IP, X-Forwarded-For)
43
+ *
44
+ * @example
45
+ * ```typescript
46
+ * // app/api/upload/route.ts
47
+ * import { NextRequest, NextResponse } from 'next/server'
48
+ * import { extractClientContext, createServerClient } from '@scalemule/nextjs/server'
49
+ *
50
+ * export async function POST(request: NextRequest) {
51
+ * const clientContext = extractClientContext(request)
52
+ * const scalemule = createServerClient()
53
+ *
54
+ * const result = await scalemule.storage.upload(userId, file, {
55
+ * clientContext
56
+ * })
57
+ *
58
+ * return NextResponse.json(result)
59
+ * }
60
+ * ```
61
+ */
62
+ declare function extractClientContext(request: NextRequestLike): ClientContext;
63
+ /**
64
+ * Extract client context from a Pages Router API request.
65
+ *
66
+ * Use this in Pages Router API routes to capture the end user's
67
+ * information for forwarding to ScaleMule.
68
+ *
69
+ * @example
70
+ * ```typescript
71
+ * // pages/api/upload.ts
72
+ * import type { NextApiRequest, NextApiResponse } from 'next'
73
+ * import { extractClientContextFromReq, createServerClient } from '@scalemule/nextjs/server'
74
+ *
75
+ * export default async function handler(req: NextApiRequest, res: NextApiResponse) {
76
+ * const clientContext = extractClientContextFromReq(req)
77
+ * const scalemule = createServerClient()
78
+ *
79
+ * const result = await scalemule.storage.upload(userId, file, {
80
+ * clientContext
81
+ * })
82
+ *
83
+ * res.json(result)
84
+ * }
85
+ * ```
86
+ */
87
+ declare function extractClientContextFromReq(req: IncomingMessageLike): ClientContext;
88
+ /**
89
+ * Build headers to forward client context to ScaleMule.
90
+ *
91
+ * This is used internally by the SDK to add authenticated forwarded-IP headers
92
+ * (and legacy compatibility headers) when client context is provided.
93
+ *
94
+ * @internal
95
+ */
96
+ declare function buildClientContextHeaders(context: ClientContext | undefined): Record<string, string>;
97
+
98
+ /**
99
+ * Cookie Utilities for Secure Session Management
100
+ *
101
+ * Handles HTTP-only secure cookies for authentication.
102
+ * Tokens are never exposed to the browser.
103
+ */
104
+
105
+ declare const SESSION_COOKIE_NAME = "sm_session";
106
+ declare const USER_ID_COOKIE_NAME = "sm_user_id";
107
+ interface SessionCookieOptions {
108
+ /** Cookie max age in seconds (default: 7 days) */
109
+ maxAge?: number;
110
+ /** Cookie domain (default: current domain) */
111
+ domain?: string;
112
+ /** Cookie path (default: '/') */
113
+ path?: string;
114
+ /** SameSite attribute (default: 'lax') */
115
+ sameSite?: 'strict' | 'lax' | 'none';
116
+ /** Whether to use secure cookies (default: true in production) */
117
+ secure?: boolean;
118
+ }
119
+ interface SessionData {
120
+ sessionToken: string;
121
+ userId: string;
122
+ expiresAt: Date;
123
+ }
124
+ /**
125
+ * Create a Response with session cookies set
126
+ *
127
+ * Use this after successful login to set HTTP-only cookies and return user data.
128
+ * The session token is stored in cookies, never sent to the browser in JSON.
129
+ *
130
+ * @example
131
+ * ```ts
132
+ * const result = await sm.auth.login({ email, password })
133
+ * if (result.success) {
134
+ * return withSession(result.data, { user: result.data.user })
135
+ * }
136
+ * ```
137
+ */
138
+ declare function withSession<T extends Record<string, unknown>>(loginResponse: LoginResponse, responseBody: T, options?: SessionCookieOptions): Response;
139
+ /**
140
+ * Create a Response that clears session cookies
141
+ *
142
+ * Use this after logout to clear HTTP-only cookies.
143
+ *
144
+ * @example
145
+ * ```ts
146
+ * await sm.auth.logout(sessionToken)
147
+ * return clearSession({ message: 'Logged out' })
148
+ * ```
149
+ */
150
+ declare function clearSession<T extends Record<string, unknown>>(responseBody: T, options?: SessionCookieOptions, status?: number): Response;
151
+ /**
152
+ * Get session data from request cookies
153
+ *
154
+ * Use this in API routes to get the current session.
155
+ * Returns null if no valid session cookie exists.
156
+ *
157
+ * @example
158
+ * ```ts
159
+ * const session = await getSession()
160
+ * if (!session) {
161
+ * return Response.json({ error: 'Not authenticated' }, { status: 401 })
162
+ * }
163
+ * const user = await sm.auth.me(session.sessionToken)
164
+ * ```
165
+ */
166
+ declare function getSession(): Promise<SessionData | null>;
167
+ /**
168
+ * Get session from a Request object (for edge/middleware)
169
+ *
170
+ * Use this when you need to read cookies from a Request directly.
171
+ */
172
+ declare function getSessionFromRequest(request: Request): SessionData | null;
173
+ /**
174
+ * Require authentication - throws Response if not authenticated
175
+ *
176
+ * Use this at the start of protected API routes.
177
+ *
178
+ * @example
179
+ * ```ts
180
+ * export async function GET() {
181
+ * const session = await requireSession()
182
+ * // session is guaranteed to exist here
183
+ * const files = await sm.storage.list(session.userId)
184
+ * }
185
+ * ```
186
+ */
187
+ declare function requireSession(): Promise<SessionData>;
188
+
189
+ /**
190
+ * Ready-Made API Route Handlers
191
+ *
192
+ * Drop-in route handlers for Next.js App Router.
193
+ * Just import and re-export - no custom code needed.
194
+ *
195
+ * @example
196
+ * ```ts
197
+ * // app/api/auth/[...scalemule]/route.ts
198
+ * import { createAuthRoutes } from '@scalemule/nextjs/server'
199
+ *
200
+ * const handlers = createAuthRoutes()
201
+ * export const { GET, POST, DELETE } = handlers
202
+ * ```
203
+ */
204
+
205
+ interface AuthRoutesConfig {
206
+ /** Server client config (optional if using env vars) */
207
+ client?: Partial<ServerConfig>;
208
+ /** Cookie options */
209
+ cookies?: SessionCookieOptions;
210
+ /** Enable CSRF validation on state-changing requests (POST/DELETE/PATCH) */
211
+ csrf?: boolean;
212
+ /** Callbacks */
213
+ onLogin?: (user: {
214
+ id: string;
215
+ email: string;
216
+ }) => void | Promise<void>;
217
+ onLogout?: () => void | Promise<void>;
218
+ onRegister?: (user: {
219
+ id: string;
220
+ email: string;
221
+ }) => void | Promise<void>;
222
+ }
223
+ type RouteHandler = (request: Request, context: {
224
+ params: Promise<{
225
+ scalemule?: string[];
226
+ }>;
227
+ }) => Promise<Response>;
228
+ /**
229
+ * Create authentication API route handlers
230
+ *
231
+ * Creates handlers for all auth operations that can be mounted at a catch-all route.
232
+ *
233
+ * @example
234
+ * ```ts
235
+ * // app/api/auth/[...scalemule]/route.ts
236
+ * import { createAuthRoutes } from '@scalemule/nextjs/server'
237
+ *
238
+ * const handlers = createAuthRoutes({
239
+ * cookies: { domain: '.yourdomain.com' },
240
+ * onLogin: (user) => console.log('User logged in:', user.email),
241
+ * })
242
+ *
243
+ * export const { GET, POST, DELETE } = handlers
244
+ * ```
245
+ *
246
+ * This creates the following endpoints:
247
+ * - POST /api/auth/register - Register new user
248
+ * - POST /api/auth/login - Login
249
+ * - POST /api/auth/logout - Logout
250
+ * - GET /api/auth/me - Get current user
251
+ * - POST /api/auth/forgot-password - Request password reset
252
+ * - POST /api/auth/reset-password - Reset password with token
253
+ * - POST /api/auth/verify-email - Verify email
254
+ */
255
+ declare function createAuthRoutes(config?: AuthRoutesConfig): {
256
+ GET: RouteHandler;
257
+ POST: RouteHandler;
258
+ DELETE: RouteHandler;
259
+ PATCH: RouteHandler;
260
+ };
261
+ interface AnalyticsRoutesConfig {
262
+ /** Server client config (optional if using env vars) */
263
+ client?: Partial<ServerConfig>;
264
+ /** Called after each event is tracked */
265
+ onEvent?: (event: {
266
+ event_name: string;
267
+ session_id?: string;
268
+ }) => void | Promise<void>;
269
+ /**
270
+ * When true, this is a simple proxy endpoint that handles events directly
271
+ * without path routing. Use for endpoints like /api/t/e.
272
+ * Default: false (uses catch-all route pattern)
273
+ */
274
+ simpleProxy?: boolean;
275
+ }
276
+ /**
277
+ * Create analytics API route handlers
278
+ *
279
+ * Creates handlers for analytics tracking that can be mounted at a route.
280
+ * AUTOMATICALLY extracts and forwards the real client IP to ScaleMule.
281
+ *
282
+ * @example
283
+ * ```ts
284
+ * // app/api/analytics/[...path]/route.ts (or /api/t/[...path]/route.ts to avoid ad-blockers)
285
+ * import { createAnalyticsRoutes } from '@scalemule/nextjs/server'
286
+ *
287
+ * const handlers = createAnalyticsRoutes()
288
+ * export const { POST } = handlers
289
+ * ```
290
+ *
291
+ * This creates the following endpoints:
292
+ * - POST /api/analytics/event - Track a single event
293
+ * - POST /api/analytics/events - Track a single event (alias)
294
+ * - POST /api/analytics/batch - Track multiple events
295
+ * - POST /api/analytics/page-view - Track a page view
296
+ *
297
+ * Client-side usage:
298
+ * ```ts
299
+ * // Track event
300
+ * fetch('/api/analytics/event', {
301
+ * method: 'POST',
302
+ * headers: { 'Content-Type': 'application/json' },
303
+ * body: JSON.stringify({
304
+ * event_name: 'button_clicked',
305
+ * properties: { button_id: 'signup' }
306
+ * })
307
+ * })
308
+ * ```
309
+ */
310
+ declare function createAnalyticsRoutes(config?: AnalyticsRoutesConfig): {
311
+ POST: RouteHandler;
312
+ };
313
+
314
+ /**
315
+ * Error utilities for ScaleMule API route handlers.
316
+ *
317
+ * ScaleMuleError is a throwable error with HTTP status code.
318
+ * unwrap() converts SDK { data, error } results into throw-on-error.
319
+ * errorCodeToStatus() maps error codes to HTTP status codes.
320
+ */
321
+
322
+ /**
323
+ * Throwable error with HTTP status code and machine-readable error code.
324
+ *
325
+ * Throw this from apiHandler() callbacks to return a formatted error response.
326
+ *
327
+ * @example
328
+ * ```ts
329
+ * throw new ScaleMuleError('NOT_FOUND', 'Snap not found', 404)
330
+ * throw new ScaleMuleError('FORBIDDEN', 'Not your snap', 403)
331
+ * ```
332
+ */
333
+ declare class ScaleMuleError extends Error {
334
+ readonly code: string;
335
+ readonly status: number;
336
+ readonly details?: Record<string, unknown> | undefined;
337
+ constructor(code: string, message: string, status?: number, details?: Record<string, unknown> | undefined);
338
+ }
339
+ declare function errorCodeToStatus(code: string): number;
340
+ /**
341
+ * Result shape accepted by unwrap().
342
+ * Compatible with both the base SDK's { data, error } and the
343
+ * Next.js SDK's { success, data, error } response contracts.
344
+ */
345
+ type SdkResult<T> = {
346
+ data?: T | null;
347
+ error?: ApiError | null;
348
+ success?: boolean;
349
+ };
350
+ /**
351
+ * Convert an SDK result into throw-on-error.
352
+ *
353
+ * If the result has an error (or success === false), throws a ScaleMuleError
354
+ * with the appropriate HTTP status code. Otherwise returns the data, typed
355
+ * and non-null.
356
+ *
357
+ * @example
358
+ * ```ts
359
+ * const user = unwrap(await sm.auth.me(token))
360
+ * const snaps = unwrap(await sm.data.query('snaps', { ... }))
361
+ * ```
362
+ */
363
+ declare function unwrap<T>(result: SdkResult<T>): T;
364
+
365
+ /**
366
+ * API Route Handler Wrapper
367
+ *
368
+ * Eliminates error handling boilerplate in Next.js API routes.
369
+ * Catches ScaleMuleError, thrown Response objects, and unexpected errors,
370
+ * returning properly formatted JSON responses.
371
+ *
372
+ * @example
373
+ * ```ts
374
+ * import { apiHandler, unwrap, ScaleMuleError } from '@scalemule/nextjs/server'
375
+ *
376
+ * export const POST = apiHandler(async (req, { params, searchParams }) => {
377
+ * const { phone } = await req.json()
378
+ * if (!phone) throw new ScaleMuleError('VALIDATION_ERROR', 'Phone required', 400)
379
+ *
380
+ * const data = unwrap(await sm.auth.sendPhoneOtp({ phone, purpose: 'verify_phone' }))
381
+ * return { message: 'OTP sent', expires_in_seconds: data.expires_in_seconds }
382
+ * }, { csrf: true })
383
+ * ```
384
+ */
385
+
386
+ type HandlerContext = {
387
+ /** Resolved route params (e.g., { id: '123' }) */
388
+ params: Record<string, string>;
389
+ /** URL search params */
390
+ searchParams: URLSearchParams;
391
+ /** Session data (only present when options.auth is true) */
392
+ session?: SessionData;
393
+ };
394
+ type HandlerFn = (request: NextRequest, context: HandlerContext) => Promise<Response | Record<string, unknown> | void>;
395
+ type HandlerOptions = {
396
+ /** Validate CSRF token before calling handler (default: false) */
397
+ csrf?: boolean;
398
+ /** Require authentication before calling handler (default: false) */
399
+ auth?: boolean;
400
+ /** Override default error response formatting */
401
+ onError?: (error: ScaleMuleError) => Response | undefined;
402
+ };
403
+ /**
404
+ * Wrap a Next.js API route handler with automatic error handling.
405
+ *
406
+ * - Catches `ScaleMuleError` (from `unwrap()` or manual throws) → JSON error response
407
+ * - Catches thrown `Response` objects (from `requireSession()`) → passes through
408
+ * - Catches unexpected errors → 500 JSON response
409
+ * - Optionally validates CSRF tokens and requires authentication
410
+ * - Auto-wraps returned objects in `{ success: true, data }` responses
411
+ *
412
+ * @example
413
+ * ```ts
414
+ * // Simple route
415
+ * export const GET = apiHandler(async (req) => {
416
+ * const items = unwrap(await sm.data.query('items'))
417
+ * return { items }
418
+ * })
419
+ *
420
+ * // With CSRF + auth
421
+ * export const DELETE = apiHandler(async (req, { params, session }) => {
422
+ * const snap = unwrap(await sm.data.get('snaps', params.id))
423
+ * if (snap.userId !== session!.userId) throw new ScaleMuleError('FORBIDDEN', 'Not yours', 403)
424
+ * unwrap(await sm.data.delete('snaps', params.id))
425
+ * return { deleted: true }
426
+ * }, { csrf: true, auth: true })
427
+ * ```
428
+ */
429
+ declare function apiHandler(handler: HandlerFn, options?: HandlerOptions): (request: NextRequest, routeContext?: {
430
+ params: Promise<Record<string, string | string[]>>;
431
+ }) => Promise<Response>;
432
+
433
+ /**
434
+ * Next.js Middleware Helpers
435
+ *
436
+ * Use these in middleware.ts to protect routes server-side.
437
+ *
438
+ * @example
439
+ * ```ts
440
+ * // middleware.ts
441
+ * import { createAuthMiddleware } from '@scalemule/nextjs/server'
442
+ *
443
+ * export default createAuthMiddleware({
444
+ * protectedRoutes: ['/dashboard', '/settings', '/api/user'],
445
+ * publicRoutes: ['/login', '/register', '/'],
446
+ * redirectTo: '/login',
447
+ * })
448
+ *
449
+ * export const config = {
450
+ * matcher: ['/((?!_next/static|_next/image|favicon.ico).*)'],
451
+ * }
452
+ * ```
453
+ */
454
+
455
+ interface AuthMiddlewareConfig {
456
+ /** Routes that require authentication (supports glob patterns) */
457
+ protectedRoutes?: string[];
458
+ /** Routes that are always public (supports glob patterns) */
459
+ publicRoutes?: string[];
460
+ /** Where to redirect unauthenticated users (default: '/login') */
461
+ redirectTo?: string;
462
+ /** Where to redirect authenticated users from public-only routes */
463
+ redirectAuthenticated?: string;
464
+ /** Routes where authenticated users should be redirected (e.g., login page) */
465
+ authOnlyPublic?: string[];
466
+ /** Skip validation and just check cookie presence (faster) */
467
+ skipValidation?: boolean;
468
+ /** Custom handler for unauthorized requests */
469
+ onUnauthorized?: (request: NextRequest) => NextResponse;
470
+ }
471
+ /**
472
+ * Create authentication middleware for Next.js
473
+ *
474
+ * @example
475
+ * ```ts
476
+ * // middleware.ts
477
+ * import { createAuthMiddleware } from '@scalemule/nextjs/server'
478
+ *
479
+ * export default createAuthMiddleware({
480
+ * protectedRoutes: ['/dashboard/*', '/api/user/*'],
481
+ * publicRoutes: ['/login', '/register', '/api/auth/*'],
482
+ * redirectTo: '/login',
483
+ * })
484
+ * ```
485
+ */
486
+ declare function createAuthMiddleware(config?: AuthMiddlewareConfig): (request: NextRequest) => Promise<NextResponse>;
487
+ /**
488
+ * Simple authentication check middleware (no validation, just cookie presence)
489
+ *
490
+ * Faster than createAuthMiddleware with full validation.
491
+ * Use when you want quick protection without hitting the backend.
492
+ */
493
+ declare function withAuth(config?: Pick<AuthMiddlewareConfig, 'redirectTo' | 'onUnauthorized'>): (request: NextRequest) => NextResponse;
494
+
495
+ /**
496
+ * CSRF Protection Utilities
497
+ *
498
+ * Implements the double-submit cookie pattern for CSRF protection.
499
+ *
500
+ * Usage:
501
+ * 1. Generate token on page load and set cookie
502
+ * 2. Include token in request header or body
503
+ * 3. Validate token matches cookie on server
504
+ *
505
+ * @example
506
+ * ```typescript
507
+ * // In your API route:
508
+ * import { validateCSRFToken, CSRF_HEADER_NAME } from '@scalemule/nextjs/server'
509
+ *
510
+ * export async function POST(request: NextRequest) {
511
+ * const error = validateCSRFToken(request)
512
+ * if (error) {
513
+ * return NextResponse.json({ error }, { status: 403 })
514
+ * }
515
+ * // ... handle request
516
+ * }
517
+ * ```
518
+ */
519
+
520
+ declare const CSRF_COOKIE_NAME = "sm_csrf";
521
+ declare const CSRF_HEADER_NAME = "x-csrf-token";
522
+ /**
523
+ * Generate a cryptographically secure CSRF token
524
+ */
525
+ declare function generateCSRFToken(): string;
526
+ /**
527
+ * Create a response with CSRF token cookie set.
528
+ * Call this on page loads or when user logs in.
529
+ */
530
+ declare function withCSRFToken(response: NextResponse, token?: string): NextResponse;
531
+ /**
532
+ * Validate CSRF token from request.
533
+ * Returns error message if invalid, undefined if valid.
534
+ *
535
+ * Checks that:
536
+ * 1. CSRF cookie exists
537
+ * 2. CSRF header or body field exists
538
+ * 3. Values match
539
+ */
540
+ declare function validateCSRFToken(request: NextRequest): string | undefined;
541
+ /**
542
+ * Validate CSRF token (async version that can read from body)
543
+ */
544
+ declare function validateCSRFTokenAsync(request: NextRequest, body?: Record<string, unknown>): Promise<string | undefined>;
545
+ /**
546
+ * Middleware helper to validate CSRF on all state-changing requests
547
+ */
548
+ declare function withCSRFProtection(handler: (request: NextRequest) => Promise<NextResponse> | NextResponse): (request: NextRequest) => Promise<NextResponse>;
549
+ /**
550
+ * Get CSRF token for the current request (server component).
551
+ * Use this to pass the token to client components.
552
+ */
553
+ declare function getCSRFToken(): Promise<string>;
554
+
555
+ /**
556
+ * OAuth State Management Utilities
557
+ *
558
+ * Provides secure OAuth state storage using httpOnly cookies instead of sessionStorage.
559
+ * This prevents XSS attacks from stealing OAuth state tokens.
560
+ *
561
+ * Usage:
562
+ * ```typescript
563
+ * // In your OAuth start route:
564
+ * import { setOAuthState } from '@scalemule/nextjs/server'
565
+ *
566
+ * export async function POST(request: NextRequest) {
567
+ * const result = await sm.auth.startOAuth({ provider: 'google', ... })
568
+ * return setOAuthState(NextResponse.json(result), result.state)
569
+ * }
570
+ *
571
+ * // In your OAuth callback route:
572
+ * import { validateOAuthState, clearOAuthState } from '@scalemule/nextjs/server'
573
+ *
574
+ * export async function GET(request: NextRequest) {
575
+ * const state = request.nextUrl.searchParams.get('state')
576
+ * const error = validateOAuthState(request, state)
577
+ * if (error) {
578
+ * return NextResponse.json({ error }, { status: 403 })
579
+ * }
580
+ * // ... complete OAuth flow
581
+ * return clearOAuthState(NextResponse.redirect('/dashboard'))
582
+ * }
583
+ * ```
584
+ */
585
+
586
+ declare const OAUTH_STATE_COOKIE_NAME = "sm_oauth_state";
587
+ /**
588
+ * Set OAuth state in an httpOnly cookie.
589
+ * Call this when starting an OAuth flow.
590
+ */
591
+ declare function setOAuthState(response: NextResponse, state: string): NextResponse;
592
+ /**
593
+ * Validate OAuth state from callback against stored cookie.
594
+ * Returns error message if invalid, undefined if valid.
595
+ */
596
+ declare function validateOAuthState(request: NextRequest, callbackState: string | null): string | undefined;
597
+ /**
598
+ * Validate OAuth state (async version for Server Components).
599
+ */
600
+ declare function validateOAuthStateAsync(callbackState: string | null): Promise<string | undefined>;
601
+ /**
602
+ * Clear OAuth state cookie after successful authentication.
603
+ */
604
+ declare function clearOAuthState(response: NextResponse): NextResponse;
605
+
606
+ /**
607
+ * Application Secrets Management
608
+ *
609
+ * Provides cached access to tenant secrets stored in ScaleMule Vault.
610
+ * Use this instead of environment variables for sensitive configuration.
611
+ *
612
+ * Benefits:
613
+ * - Secrets stored securely with AES-256-GCM + AWS KMS encryption
614
+ * - Centralized management via ScaleMule admin dashboard
615
+ * - Automatic caching to minimize API calls
616
+ * - No need to manage k8s secrets yourself
617
+ *
618
+ * @example
619
+ * ```typescript
620
+ * import { getAppSecret } from '@scalemule/nextjs/server'
621
+ *
622
+ * // In your API route or server component:
623
+ * const salt = await getAppSecret('ANONYMOUS_USER_SALT')
624
+ * // Uses cached value on subsequent calls
625
+ * ```
626
+ */
627
+ /** Configuration options */
628
+ interface SecretsConfig {
629
+ /** Cache TTL in milliseconds (default: 5 minutes) */
630
+ cacheTtlMs?: number;
631
+ /** Disable caching (for testing) */
632
+ noCache?: boolean;
633
+ }
634
+ /**
635
+ * Configure secrets caching behavior
636
+ *
637
+ * @example
638
+ * ```typescript
639
+ * configureSecrets({ cacheTtlMs: 60000 }) // 1 minute cache
640
+ * ```
641
+ */
642
+ declare function configureSecrets(config: SecretsConfig): void;
643
+ /**
644
+ * Get a secret from the ScaleMule tenant vault
645
+ *
646
+ * This function automatically caches secrets to minimize API calls.
647
+ * If the secret doesn't exist, returns undefined.
648
+ *
649
+ * @param key - The secret key (e.g., 'ANONYMOUS_USER_SALT')
650
+ * @returns The secret value, or undefined if not found
651
+ *
652
+ * @example
653
+ * ```typescript
654
+ * import { getAppSecret } from '@scalemule/nextjs/server'
655
+ *
656
+ * export async function POST(request: NextRequest) {
657
+ * const salt = await getAppSecret('ANONYMOUS_USER_SALT')
658
+ * if (!salt) {
659
+ * console.warn('ANONYMOUS_USER_SALT not configured in ScaleMule vault')
660
+ * // Fall back to environment variable or default
661
+ * salt = process.env.ANONYMOUS_USER_SALT || 'default-salt'
662
+ * }
663
+ * // Use the salt...
664
+ * }
665
+ * ```
666
+ */
667
+ declare function getAppSecret(key: string): Promise<string | undefined>;
668
+ /**
669
+ * Get a secret, throwing if not found
670
+ *
671
+ * Use this when the secret is required and the app cannot function without it.
672
+ *
673
+ * @param key - The secret key
674
+ * @returns The secret value
675
+ * @throws Error if the secret is not found
676
+ *
677
+ * @example
678
+ * ```typescript
679
+ * const salt = await requireAppSecret('ANONYMOUS_USER_SALT')
680
+ * // Throws if not configured
681
+ * ```
682
+ */
683
+ declare function requireAppSecret(key: string): Promise<string>;
684
+ /**
685
+ * Get a secret with a fallback value
686
+ *
687
+ * Useful for development or when migrating from environment variables.
688
+ *
689
+ * @param key - The secret key
690
+ * @param fallback - Fallback value if secret not found
691
+ * @returns The secret value or fallback
692
+ *
693
+ * @example
694
+ * ```typescript
695
+ * // Fall back to env var if not in vault yet
696
+ * const salt = await getAppSecretOrDefault(
697
+ * 'ANONYMOUS_USER_SALT',
698
+ * process.env.ANONYMOUS_USER_SALT || 'dev-salt'
699
+ * )
700
+ * ```
701
+ */
702
+ declare function getAppSecretOrDefault(key: string, fallback: string): Promise<string>;
703
+ /**
704
+ * Invalidate cached secret (force refresh on next access)
705
+ *
706
+ * @param key - The secret key to invalidate, or undefined to clear all
707
+ */
708
+ declare function invalidateSecretCache(key?: string): void;
709
+ /**
710
+ * Prefetch secrets into cache
711
+ *
712
+ * Call this during app startup to warm the cache.
713
+ *
714
+ * @param keys - Array of secret keys to prefetch
715
+ *
716
+ * @example
717
+ * ```typescript
718
+ * // In your app initialization:
719
+ * await prefetchSecrets(['ANONYMOUS_USER_SALT', 'WEBHOOK_SECRET'])
720
+ * ```
721
+ */
722
+ declare function prefetchSecrets(keys: string[]): Promise<void>;
723
+
724
+ /**
725
+ * Application Bundles Management
726
+ *
727
+ * Bundles are structured secrets like database credentials, S3 configs, etc.
728
+ * They support inheritance - child bundles can inherit from parent bundles
729
+ * and override specific fields.
730
+ *
731
+ * @example
732
+ * ```typescript
733
+ * import { getBundle, getMySqlBundle } from '@scalemule/nextjs/server'
734
+ *
735
+ * // Get a generic bundle
736
+ * const config = await getBundle<{ apiKey: string }>('external/stripe')
737
+ *
738
+ * // Get a typed MySQL bundle
739
+ * const db = await getMySqlBundle('database/prod')
740
+ * const connection = mysql.createConnection(db.connectionUrl)
741
+ * ```
742
+ */
743
+ interface MySqlBundle {
744
+ host: string;
745
+ port: number;
746
+ username: string;
747
+ password: string;
748
+ database: string;
749
+ ssl_mode?: string;
750
+ }
751
+ interface PostgresBundle {
752
+ host: string;
753
+ port: number;
754
+ username: string;
755
+ password: string;
756
+ database: string;
757
+ ssl_mode?: string;
758
+ }
759
+ interface RedisBundle {
760
+ host: string;
761
+ port: number;
762
+ password?: string;
763
+ database?: number;
764
+ ssl?: boolean;
765
+ }
766
+ interface S3Bundle {
767
+ bucket: string;
768
+ region: string;
769
+ access_key_id: string;
770
+ secret_access_key: string;
771
+ endpoint?: string;
772
+ }
773
+ interface OAuthBundle {
774
+ client_id: string;
775
+ client_secret: string;
776
+ redirect_uri: string;
777
+ scopes?: string[];
778
+ }
779
+ interface SmtpBundle {
780
+ host: string;
781
+ port: number;
782
+ username: string;
783
+ password: string;
784
+ from_email: string;
785
+ from_name?: string;
786
+ encryption?: 'none' | 'tls' | 'starttls';
787
+ }
788
+ /** Configuration options */
789
+ interface BundlesConfig {
790
+ /** Cache TTL in milliseconds (default: 5 minutes) */
791
+ cacheTtlMs?: number;
792
+ /** Disable caching (for testing) */
793
+ noCache?: boolean;
794
+ }
795
+ /**
796
+ * Configure bundles caching behavior
797
+ */
798
+ declare function configureBundles(config: BundlesConfig): void;
799
+ /**
800
+ * Get a bundle from the ScaleMule vault
801
+ *
802
+ * @param key - The bundle key (e.g., 'database/prod')
803
+ * @param resolve - Whether to resolve inheritance (default: true)
804
+ * @returns The bundle data, or undefined if not found
805
+ *
806
+ * @example
807
+ * ```typescript
808
+ * const stripe = await getBundle<{ apiKey: string }>('external/stripe')
809
+ * if (stripe) {
810
+ * const client = new Stripe(stripe.apiKey)
811
+ * }
812
+ * ```
813
+ */
814
+ declare function getBundle<T = Record<string, unknown>>(key: string, resolve?: boolean): Promise<T | undefined>;
815
+ /**
816
+ * Get a bundle, throwing if not found
817
+ */
818
+ declare function requireBundle<T = Record<string, unknown>>(key: string, resolve?: boolean): Promise<T>;
819
+ /**
820
+ * Get a MySQL bundle with connection URL
821
+ *
822
+ * @example
823
+ * ```typescript
824
+ * const db = await getMySqlBundle('database/prod')
825
+ * const connection = mysql.createConnection(db.connectionUrl)
826
+ * ```
827
+ */
828
+ declare function getMySqlBundle(key: string): Promise<(MySqlBundle & {
829
+ connectionUrl: string;
830
+ }) | undefined>;
831
+ /**
832
+ * Get a PostgreSQL bundle with connection URL
833
+ */
834
+ declare function getPostgresBundle(key: string): Promise<(PostgresBundle & {
835
+ connectionUrl: string;
836
+ }) | undefined>;
837
+ /**
838
+ * Get a Redis bundle with connection URL
839
+ */
840
+ declare function getRedisBundle(key: string): Promise<(RedisBundle & {
841
+ connectionUrl: string;
842
+ }) | undefined>;
843
+ /**
844
+ * Get an S3 bundle
845
+ */
846
+ declare function getS3Bundle(key: string): Promise<S3Bundle | undefined>;
847
+ /**
848
+ * Get an OAuth bundle
849
+ */
850
+ declare function getOAuthBundle(key: string): Promise<OAuthBundle | undefined>;
851
+ /**
852
+ * Get an SMTP bundle
853
+ */
854
+ declare function getSmtpBundle(key: string): Promise<SmtpBundle | undefined>;
855
+ /**
856
+ * Invalidate cached bundle (force refresh on next access)
857
+ *
858
+ * @param key - The bundle key to invalidate, or undefined to clear all
859
+ */
860
+ declare function invalidateBundleCache(key?: string): void;
861
+ /**
862
+ * Prefetch bundles into cache
863
+ *
864
+ * @param keys - Array of bundle keys to prefetch
865
+ */
866
+ declare function prefetchBundles(keys: string[]): Promise<void>;
867
+
868
+ export { type AnalyticsRoutesConfig, type AuthMiddlewareConfig, type AuthRoutesConfig, CSRF_COOKIE_NAME, CSRF_HEADER_NAME, type HandlerContext, type HandlerOptions, type MySqlBundle, OAUTH_STATE_COOKIE_NAME, type OAuthBundle, type PostgresBundle, type RedisBundle, type S3Bundle, SESSION_COOKIE_NAME, ScaleMuleError, ServerConfig, type SessionCookieOptions, type SessionData, type SmtpBundle, USER_ID_COOKIE_NAME, apiHandler, buildClientContextHeaders, clearOAuthState, clearSession, configureBundles, configureSecrets, createAnalyticsRoutes, createAuthMiddleware, createAuthRoutes, errorCodeToStatus, extractClientContext, extractClientContextFromReq, generateCSRFToken, getAppSecret, getAppSecretOrDefault, 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 };