@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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 ScaleMule Inc.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,297 @@
1
+ # @scalemule/nextjs
2
+
3
+ ScaleMule SDK for Next.js applications.
4
+
5
+ Server-side authentication with HTTP-only cookies, CSRF protection, webhook handling, secrets management, and client-side hooks.
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ npm install @scalemule/nextjs
11
+ ```
12
+
13
+ ## Auth in 6 Lines
14
+
15
+ ```ts
16
+ // app/api/auth/[...scalemule]/route.ts
17
+ import { createAuthRoutes } from '@scalemule/nextjs/server'
18
+
19
+ export const { GET, POST, DELETE, PATCH } = createAuthRoutes()
20
+ ```
21
+
22
+ This creates all auth endpoints automatically:
23
+ - `POST /api/auth/register` — register + set HTTP-only cookie
24
+ - `POST /api/auth/login` — login + set HTTP-only cookie
25
+ - `POST /api/auth/logout` — logout + clear cookie
26
+ - `GET /api/auth/me` — get current user
27
+ - `POST /api/auth/forgot-password` — request password reset
28
+ - `POST /api/auth/reset-password` — reset password
29
+ - `POST /api/auth/verify-email` — verify email
30
+ - `POST /api/auth/resend-verification` — resend verification (session or email-only)
31
+ - `POST /api/auth/refresh` — refresh session
32
+ - `PATCH /api/auth/me` — update profile
33
+ - `DELETE /api/auth/me` — delete account
34
+
35
+ API keys never reach the browser. Session tokens are HTTP-only cookies.
36
+
37
+ ## Environment Variables
38
+
39
+ ```bash
40
+ # .env.local
41
+ SCALEMULE_API_KEY=sk_prod_xxx # server-only, no NEXT_PUBLIC_ prefix
42
+ SCALEMULE_ENV=prod # 'dev' | 'prod'
43
+ SCALEMULE_COOKIE_DOMAIN=.yourdomain.com # optional, for subdomain sharing
44
+ ```
45
+
46
+ ## Auth Route Options
47
+
48
+ ```ts
49
+ export const { GET, POST, DELETE, PATCH } = createAuthRoutes({
50
+ // CSRF validation (recommended for production)
51
+ csrf: true,
52
+
53
+ // Cookie configuration
54
+ cookies: {
55
+ domain: '.yourdomain.com', // share across subdomains
56
+ maxAge: 30 * 24 * 60 * 60, // 30 days
57
+ },
58
+
59
+ // Lifecycle hooks
60
+ onRegister: async (user) => { /* post-registration logic */ },
61
+ onLogin: async (user) => { /* post-login logic */ },
62
+ onLogout: async () => { /* cleanup */ },
63
+ })
64
+ ```
65
+
66
+ ## Webhooks in 10 Lines
67
+
68
+ ```ts
69
+ // app/api/webhooks/scalemule/route.ts
70
+ import { createWebhookHandler } from '@scalemule/nextjs/server/webhooks'
71
+
72
+ export const POST = createWebhookHandler({
73
+ secret: process.env.SCALEMULE_WEBHOOK_SECRET,
74
+ onEvent: {
75
+ 'storage.file.uploaded': async (event) => {
76
+ console.log('File uploaded:', event.data.file_id)
77
+ },
78
+ 'video.transcoding.completed': async (event) => {
79
+ console.log('Video ready:', event.data.video_id)
80
+ },
81
+ },
82
+ })
83
+ ```
84
+
85
+ HMAC-SHA256 signature verification and 5-minute replay protection included.
86
+
87
+ ## 1-Line Auth Export
88
+
89
+ For zero-config auth (reads from env vars):
90
+
91
+ ```ts
92
+ // app/api/auth/[...scalemule]/route.ts
93
+ export { GET, POST, DELETE, PATCH } from '@scalemule/nextjs/server/auth'
94
+ ```
95
+
96
+ ## Client-Side Provider
97
+
98
+ ```tsx
99
+ // app/layout.tsx
100
+ import { ScaleMuleProvider } from '@scalemule/nextjs'
101
+
102
+ export default function RootLayout({ children }: { children: React.ReactNode }) {
103
+ return (
104
+ <html>
105
+ <body>
106
+ <ScaleMuleProvider
107
+ apiKey={process.env.NEXT_PUBLIC_SCALEMULE_API_KEY!}
108
+ environment={process.env.NEXT_PUBLIC_SCALEMULE_ENV as 'dev' | 'prod'}
109
+ >
110
+ {children}
111
+ </ScaleMuleProvider>
112
+ </body>
113
+ </html>
114
+ )
115
+ }
116
+ ```
117
+
118
+ ## Client-Side Hooks
119
+
120
+ ### `useAuth()`
121
+
122
+ ```tsx
123
+ 'use client'
124
+ import { useAuth } from '@scalemule/nextjs'
125
+
126
+ function LoginPage() {
127
+ const { login, register, logout, user, loading, isAuthenticated, error } = useAuth()
128
+
129
+ const handleLogin = async () => {
130
+ await login({ email, password })
131
+ }
132
+ }
133
+ ```
134
+
135
+ ### `useContent()`
136
+
137
+ ```tsx
138
+ import { useContent } from '@scalemule/nextjs'
139
+
140
+ function Gallery() {
141
+ const { files, upload, loading, uploadProgress, refresh, remove } = useContent({ autoFetch: true })
142
+
143
+ const handleUpload = async (file: File) => {
144
+ await upload(file, {
145
+ onProgress: (pct) => console.log(`${pct}%`),
146
+ })
147
+ }
148
+ }
149
+ ```
150
+
151
+ ### `useUser()`
152
+
153
+ ```tsx
154
+ import { useUser } from '@scalemule/nextjs'
155
+
156
+ function Settings() {
157
+ const { profile, update, changePassword, changeEmail, deleteAccount, exportData } = useUser()
158
+ }
159
+ ```
160
+
161
+ ### `useRealtime()`
162
+
163
+ ```tsx
164
+ import { useRealtime } from '@scalemule/nextjs'
165
+
166
+ function LiveUpdates() {
167
+ const { status, subscribe } = useRealtime({ autoConnect: true })
168
+
169
+ useEffect(() => {
170
+ const unsub = subscribe('notifications', (data) => {
171
+ console.log('New notification:', data)
172
+ })
173
+ return () => unsub()
174
+ }, [subscribe])
175
+ }
176
+ ```
177
+
178
+ ## Server Client
179
+
180
+ For server-side operations beyond auth (API routes, server components, server actions):
181
+
182
+ ```ts
183
+ import { createServerClient } from '@scalemule/nextjs/server'
184
+
185
+ const sm = createServerClient()
186
+
187
+ // Storage
188
+ const { data } = await sm.storage.getViewUrl(fileId)
189
+
190
+ // Auth (with session token)
191
+ const { data: user } = await sm.auth.me(sessionToken)
192
+
193
+ // Secrets
194
+ const secret = await sm.secrets.get('STRIPE_KEY')
195
+
196
+ // Vault bundles
197
+ const db = await sm.bundles.get('database/primary')
198
+ ```
199
+
200
+ ## CSRF Protection
201
+
202
+ ### Middleware Setup
203
+
204
+ ```ts
205
+ // middleware.ts
206
+ import { generateCSRFToken, CSRF_COOKIE_NAME } from '@scalemule/nextjs/server'
207
+ import { NextResponse } from 'next/server'
208
+
209
+ export function middleware(request) {
210
+ const response = NextResponse.next()
211
+
212
+ if (!request.cookies.get(CSRF_COOKIE_NAME)) {
213
+ const token = generateCSRFToken()
214
+ response.cookies.set(CSRF_COOKIE_NAME, token, {
215
+ httpOnly: false, // must be readable by JS
216
+ sameSite: 'strict',
217
+ secure: process.env.NODE_ENV === 'production',
218
+ path: '/',
219
+ })
220
+ }
221
+
222
+ return response
223
+ }
224
+ ```
225
+
226
+ ### Enable in Auth Routes
227
+
228
+ ```ts
229
+ export const { GET, POST, DELETE, PATCH } = createAuthRoutes({
230
+ csrf: true, // validates x-csrf-token header against cookie
231
+ })
232
+ ```
233
+
234
+ ### Client-Side
235
+
236
+ ```ts
237
+ // Read CSRF token from cookie and include in requests
238
+ const csrfToken = document.cookie.match(/csrf_token=([^;]+)/)?.[1]
239
+
240
+ fetch('/api/auth/login', {
241
+ method: 'POST',
242
+ headers: {
243
+ 'Content-Type': 'application/json',
244
+ 'x-csrf-token': csrfToken,
245
+ },
246
+ body: JSON.stringify({ email, password }),
247
+ })
248
+ ```
249
+
250
+ ## Secrets & Vault
251
+
252
+ ```ts
253
+ import {
254
+ getAppSecret,
255
+ requireAppSecret,
256
+ getMySqlBundle,
257
+ getRedisBundle,
258
+ getS3Bundle,
259
+ getOAuthBundle,
260
+ getBundle,
261
+ } from '@scalemule/nextjs/server'
262
+
263
+ // Simple secrets
264
+ const apiKey = await getAppSecret('STRIPE_API_KEY')
265
+ const required = await requireAppSecret('WEBHOOK_SECRET') // throws if missing
266
+
267
+ // Typed bundles
268
+ const db = await getMySqlBundle('database/primary') // { host, port, user, password, database, connectionUrl }
269
+ const redis = await getRedisBundle('cache/main') // { host, port, password, connectionUrl }
270
+ const s3 = await getS3Bundle('storage/uploads') // { bucket, region, access_key_id, secret_access_key }
271
+ const oauth = await getOAuthBundle('google') // { client_id, client_secret, redirect_uri }
272
+
273
+ // Generic bundle
274
+ const stripe = await getBundle<{ api_key: string; webhook_secret: string }>('external/stripe')
275
+ ```
276
+
277
+ Secrets are cached for 5 minutes. Configure with `configureSecrets({ cacheTtlMs, noCache })`.
278
+
279
+ ## Testing
280
+
281
+ ```tsx
282
+ import { MockScaleMuleProvider, createMockUser, createMockFile } from '@scalemule/nextjs/testing'
283
+ import { render, screen } from '@testing-library/react'
284
+
285
+ test('shows user name', () => {
286
+ render(
287
+ <MockScaleMuleProvider user={createMockUser({ full_name: 'Jane' })}>
288
+ <ProfilePage />
289
+ </MockScaleMuleProvider>
290
+ )
291
+ expect(screen.getByText('Jane')).toBeInTheDocument()
292
+ })
293
+ ```
294
+
295
+ ## License
296
+
297
+ MIT - ScaleMule Inc.
@@ -0,0 +1,163 @@
1
+ import { i as StorageAdapter, j as ApiResponse } from './index-BkacIKdu.mjs';
2
+
3
+ /**
4
+ * ScaleMule API Client
5
+ *
6
+ * Core HTTP client that handles:
7
+ * - Automatic x-api-key header injection
8
+ * - Automatic Authorization: Bearer header injection when authenticated
9
+ * - Session token management
10
+ * - Error handling and response parsing
11
+ */
12
+
13
+ type ScaleMuleEnvironment = 'dev' | 'prod';
14
+ interface ClientConfig {
15
+ /** Your ScaleMule API key */
16
+ apiKey: string;
17
+ /** Your ScaleMule Application ID (required for realtime features) */
18
+ applicationId?: string;
19
+ /** Environment: 'dev' or 'prod' - automatically sets gateway URL */
20
+ environment?: ScaleMuleEnvironment;
21
+ /** Custom gateway URL (overrides environment preset) */
22
+ gatewayUrl?: string;
23
+ /** Enable debug logging */
24
+ debug?: boolean;
25
+ /** Custom storage adapter */
26
+ storage?: StorageAdapter;
27
+ /** Enable rate limit queue (automatically queues requests when rate limited) */
28
+ enableRateLimitQueue?: boolean;
29
+ /** Enable offline queue (queues requests when offline, syncs when back online) */
30
+ enableOfflineQueue?: boolean;
31
+ }
32
+ interface RequestOptions extends RequestInit {
33
+ /** Skip adding auth headers (for public endpoints) */
34
+ skipAuth?: boolean;
35
+ /** Custom timeout in milliseconds */
36
+ timeout?: number;
37
+ /** Number of retry attempts for transient failures (default: 2) */
38
+ retries?: number;
39
+ /** Skip retries */
40
+ skipRetry?: boolean;
41
+ }
42
+ /**
43
+ * ScaleMule API Client
44
+ *
45
+ * Handles all HTTP communication with the ScaleMule gateway.
46
+ */
47
+ declare class ScaleMuleClient {
48
+ private apiKey;
49
+ private applicationId;
50
+ private gatewayUrl;
51
+ private debug;
52
+ private storage;
53
+ private sessionToken;
54
+ private userId;
55
+ private rateLimitQueue;
56
+ private offlineQueue;
57
+ private enableRateLimitQueue;
58
+ private enableOfflineQueue;
59
+ constructor(config: ClientConfig);
60
+ /**
61
+ * Sync offline queue when coming back online
62
+ */
63
+ private syncOfflineQueue;
64
+ /**
65
+ * Check if client is online
66
+ */
67
+ isOnline(): boolean;
68
+ /**
69
+ * Get number of pending offline requests
70
+ */
71
+ getOfflineQueueLength(): number;
72
+ /**
73
+ * Get number of pending rate-limited requests
74
+ */
75
+ getRateLimitQueueLength(): number;
76
+ /**
77
+ * Check if currently rate limited
78
+ */
79
+ isRateLimited(): boolean;
80
+ /**
81
+ * Get the gateway URL
82
+ */
83
+ getGatewayUrl(): string;
84
+ /**
85
+ * Get the application ID (required for realtime features)
86
+ */
87
+ getApplicationId(): string | null;
88
+ /**
89
+ * Initialize client by loading persisted session
90
+ */
91
+ initialize(): Promise<void>;
92
+ /**
93
+ * Set session after login
94
+ */
95
+ setSession(token: string, userId: string): Promise<void>;
96
+ /**
97
+ * Clear session on logout
98
+ */
99
+ clearSession(): Promise<void>;
100
+ /**
101
+ * Get current session token
102
+ */
103
+ getSessionToken(): string | null;
104
+ /**
105
+ * Get current user ID
106
+ */
107
+ getUserId(): string | null;
108
+ /**
109
+ * Check if client has an active session
110
+ */
111
+ isAuthenticated(): boolean;
112
+ /**
113
+ * Build headers for a request
114
+ */
115
+ private buildHeaders;
116
+ /**
117
+ * Make an HTTP request to the ScaleMule API
118
+ */
119
+ request<T>(path: string, options?: RequestOptions): Promise<ApiResponse<T>>;
120
+ /**
121
+ * GET request
122
+ */
123
+ get<T>(path: string, options?: RequestOptions): Promise<ApiResponse<T>>;
124
+ /**
125
+ * POST request with JSON body
126
+ */
127
+ post<T>(path: string, body?: unknown, options?: RequestOptions): Promise<ApiResponse<T>>;
128
+ /**
129
+ * PUT request with JSON body
130
+ */
131
+ put<T>(path: string, body?: unknown, options?: RequestOptions): Promise<ApiResponse<T>>;
132
+ /**
133
+ * PATCH request with JSON body
134
+ */
135
+ patch<T>(path: string, body?: unknown, options?: RequestOptions): Promise<ApiResponse<T>>;
136
+ /**
137
+ * DELETE request
138
+ */
139
+ delete<T>(path: string, options?: RequestOptions): Promise<ApiResponse<T>>;
140
+ /**
141
+ * Upload a file using multipart/form-data
142
+ *
143
+ * Automatically includes Authorization: Bearer header for user identity.
144
+ * Supports progress callback via XMLHttpRequest when onProgress is provided.
145
+ */
146
+ upload<T>(path: string, file: File, additionalFields?: Record<string, string>, options?: RequestOptions & {
147
+ onProgress?: (progress: number) => void;
148
+ }): Promise<ApiResponse<T>>;
149
+ /**
150
+ * Upload with progress using XMLHttpRequest (with retry)
151
+ */
152
+ private uploadWithProgress;
153
+ /**
154
+ * Single upload attempt with progress using XMLHttpRequest
155
+ */
156
+ private singleUploadWithProgress;
157
+ }
158
+ /**
159
+ * Create a new ScaleMule client instance
160
+ */
161
+ declare function createClient(config: ClientConfig): ScaleMuleClient;
162
+
163
+ export { type ClientConfig, type RequestOptions, ScaleMuleClient, type ScaleMuleEnvironment, createClient };
@@ -0,0 +1,163 @@
1
+ import { i as StorageAdapter, j as ApiResponse } from './index-BkacIKdu.js';
2
+
3
+ /**
4
+ * ScaleMule API Client
5
+ *
6
+ * Core HTTP client that handles:
7
+ * - Automatic x-api-key header injection
8
+ * - Automatic Authorization: Bearer header injection when authenticated
9
+ * - Session token management
10
+ * - Error handling and response parsing
11
+ */
12
+
13
+ type ScaleMuleEnvironment = 'dev' | 'prod';
14
+ interface ClientConfig {
15
+ /** Your ScaleMule API key */
16
+ apiKey: string;
17
+ /** Your ScaleMule Application ID (required for realtime features) */
18
+ applicationId?: string;
19
+ /** Environment: 'dev' or 'prod' - automatically sets gateway URL */
20
+ environment?: ScaleMuleEnvironment;
21
+ /** Custom gateway URL (overrides environment preset) */
22
+ gatewayUrl?: string;
23
+ /** Enable debug logging */
24
+ debug?: boolean;
25
+ /** Custom storage adapter */
26
+ storage?: StorageAdapter;
27
+ /** Enable rate limit queue (automatically queues requests when rate limited) */
28
+ enableRateLimitQueue?: boolean;
29
+ /** Enable offline queue (queues requests when offline, syncs when back online) */
30
+ enableOfflineQueue?: boolean;
31
+ }
32
+ interface RequestOptions extends RequestInit {
33
+ /** Skip adding auth headers (for public endpoints) */
34
+ skipAuth?: boolean;
35
+ /** Custom timeout in milliseconds */
36
+ timeout?: number;
37
+ /** Number of retry attempts for transient failures (default: 2) */
38
+ retries?: number;
39
+ /** Skip retries */
40
+ skipRetry?: boolean;
41
+ }
42
+ /**
43
+ * ScaleMule API Client
44
+ *
45
+ * Handles all HTTP communication with the ScaleMule gateway.
46
+ */
47
+ declare class ScaleMuleClient {
48
+ private apiKey;
49
+ private applicationId;
50
+ private gatewayUrl;
51
+ private debug;
52
+ private storage;
53
+ private sessionToken;
54
+ private userId;
55
+ private rateLimitQueue;
56
+ private offlineQueue;
57
+ private enableRateLimitQueue;
58
+ private enableOfflineQueue;
59
+ constructor(config: ClientConfig);
60
+ /**
61
+ * Sync offline queue when coming back online
62
+ */
63
+ private syncOfflineQueue;
64
+ /**
65
+ * Check if client is online
66
+ */
67
+ isOnline(): boolean;
68
+ /**
69
+ * Get number of pending offline requests
70
+ */
71
+ getOfflineQueueLength(): number;
72
+ /**
73
+ * Get number of pending rate-limited requests
74
+ */
75
+ getRateLimitQueueLength(): number;
76
+ /**
77
+ * Check if currently rate limited
78
+ */
79
+ isRateLimited(): boolean;
80
+ /**
81
+ * Get the gateway URL
82
+ */
83
+ getGatewayUrl(): string;
84
+ /**
85
+ * Get the application ID (required for realtime features)
86
+ */
87
+ getApplicationId(): string | null;
88
+ /**
89
+ * Initialize client by loading persisted session
90
+ */
91
+ initialize(): Promise<void>;
92
+ /**
93
+ * Set session after login
94
+ */
95
+ setSession(token: string, userId: string): Promise<void>;
96
+ /**
97
+ * Clear session on logout
98
+ */
99
+ clearSession(): Promise<void>;
100
+ /**
101
+ * Get current session token
102
+ */
103
+ getSessionToken(): string | null;
104
+ /**
105
+ * Get current user ID
106
+ */
107
+ getUserId(): string | null;
108
+ /**
109
+ * Check if client has an active session
110
+ */
111
+ isAuthenticated(): boolean;
112
+ /**
113
+ * Build headers for a request
114
+ */
115
+ private buildHeaders;
116
+ /**
117
+ * Make an HTTP request to the ScaleMule API
118
+ */
119
+ request<T>(path: string, options?: RequestOptions): Promise<ApiResponse<T>>;
120
+ /**
121
+ * GET request
122
+ */
123
+ get<T>(path: string, options?: RequestOptions): Promise<ApiResponse<T>>;
124
+ /**
125
+ * POST request with JSON body
126
+ */
127
+ post<T>(path: string, body?: unknown, options?: RequestOptions): Promise<ApiResponse<T>>;
128
+ /**
129
+ * PUT request with JSON body
130
+ */
131
+ put<T>(path: string, body?: unknown, options?: RequestOptions): Promise<ApiResponse<T>>;
132
+ /**
133
+ * PATCH request with JSON body
134
+ */
135
+ patch<T>(path: string, body?: unknown, options?: RequestOptions): Promise<ApiResponse<T>>;
136
+ /**
137
+ * DELETE request
138
+ */
139
+ delete<T>(path: string, options?: RequestOptions): Promise<ApiResponse<T>>;
140
+ /**
141
+ * Upload a file using multipart/form-data
142
+ *
143
+ * Automatically includes Authorization: Bearer header for user identity.
144
+ * Supports progress callback via XMLHttpRequest when onProgress is provided.
145
+ */
146
+ upload<T>(path: string, file: File, additionalFields?: Record<string, string>, options?: RequestOptions & {
147
+ onProgress?: (progress: number) => void;
148
+ }): Promise<ApiResponse<T>>;
149
+ /**
150
+ * Upload with progress using XMLHttpRequest (with retry)
151
+ */
152
+ private uploadWithProgress;
153
+ /**
154
+ * Single upload attempt with progress using XMLHttpRequest
155
+ */
156
+ private singleUploadWithProgress;
157
+ }
158
+ /**
159
+ * Create a new ScaleMule client instance
160
+ */
161
+ declare function createClient(config: ClientConfig): ScaleMuleClient;
162
+
163
+ export { type ClientConfig, type RequestOptions, ScaleMuleClient, type ScaleMuleEnvironment, createClient };