@scalemule/nextjs 0.1.17 → 0.1.18

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.
@@ -130,23 +130,31 @@ var ScaleMuleServer = class {
130
130
  /**
131
131
  * Logout user
132
132
  */
133
- logout: async (sessionToken) => {
133
+ logout: async (sessionToken, options) => {
134
134
  return this.request("POST", "/v1/auth/logout", {
135
- body: { session_token: sessionToken }
135
+ sessionToken,
136
+ body: { session_token: sessionToken },
137
+ onTokenRotated: options?.onTokenRotated
136
138
  });
137
139
  },
138
140
  /**
139
141
  * Get current user from session token
140
142
  */
141
- me: async (sessionToken) => {
142
- return this.request("GET", "/v1/auth/me", { sessionToken });
143
+ me: async (sessionToken, options) => {
144
+ return this.request("GET", "/v1/auth/me", {
145
+ sessionToken,
146
+ onTokenRotated: options?.onTokenRotated
147
+ });
143
148
  },
144
149
  /**
145
150
  * Refresh session token
146
151
  */
147
- refresh: async (sessionToken) => {
152
+ refresh: async (sessionToken, options) => {
148
153
  return this.request("POST", "/v1/auth/refresh", {
149
- body: { session_token: sessionToken }
154
+ sessionToken,
155
+ clientContext: options?.clientContext,
156
+ isAutoRefresh: options?.isAutoRefresh,
157
+ onTokenRotated: options?.onTokenRotated
150
158
  });
151
159
  },
152
160
  /**
@@ -178,7 +186,8 @@ var ScaleMuleServer = class {
178
186
  if (options?.email) {
179
187
  return this.request("POST", "/v1/auth/resend-verification", {
180
188
  sessionToken: sessionTokenOrEmail,
181
- body: { email: options.email }
189
+ body: { email: options.email },
190
+ onTokenRotated: options?.onTokenRotated
182
191
  });
183
192
  }
184
193
  if (sessionTokenOrEmail.includes("@")) {
@@ -187,7 +196,8 @@ var ScaleMuleServer = class {
187
196
  });
188
197
  }
189
198
  return this.request("POST", "/v1/auth/resend-verification", {
190
- sessionToken: sessionTokenOrEmail
199
+ sessionToken: sessionTokenOrEmail,
200
+ onTokenRotated: options?.onTokenRotated
191
201
  });
192
202
  }
193
203
  };
@@ -198,37 +208,41 @@ var ScaleMuleServer = class {
198
208
  /**
199
209
  * Update user profile
200
210
  */
201
- update: async (sessionToken, data) => {
211
+ update: async (sessionToken, data, options) => {
202
212
  return this.request("PATCH", "/v1/auth/profile", {
203
213
  sessionToken,
204
- body: data
214
+ body: data,
215
+ onTokenRotated: options?.onTokenRotated
205
216
  });
206
217
  },
207
218
  /**
208
219
  * Change password
209
220
  */
210
- changePassword: async (sessionToken, currentPassword, newPassword) => {
221
+ changePassword: async (sessionToken, currentPassword, newPassword, options) => {
211
222
  return this.request("POST", "/v1/auth/change-password", {
212
223
  sessionToken,
213
- body: { current_password: currentPassword, new_password: newPassword }
224
+ body: { current_password: currentPassword, new_password: newPassword },
225
+ onTokenRotated: options?.onTokenRotated
214
226
  });
215
227
  },
216
228
  /**
217
229
  * Change email
218
230
  */
219
- changeEmail: async (sessionToken, newEmail, password) => {
231
+ changeEmail: async (sessionToken, newEmail, password, options) => {
220
232
  return this.request("POST", "/v1/auth/change-email", {
221
233
  sessionToken,
222
- body: { new_email: newEmail, password }
234
+ body: { new_email: newEmail, password },
235
+ onTokenRotated: options?.onTokenRotated
223
236
  });
224
237
  },
225
238
  /**
226
239
  * Delete account
227
240
  */
228
- deleteAccount: async (sessionToken, password) => {
241
+ deleteAccount: async (sessionToken, password, options) => {
229
242
  return this.request("DELETE", "/v1/auth/me", {
230
243
  sessionToken,
231
- body: { password }
244
+ body: { password },
245
+ onTokenRotated: options?.onTokenRotated
232
246
  });
233
247
  }
234
248
  };
@@ -689,6 +703,9 @@ var ScaleMuleServer = class {
689
703
  this.apiKey = config.apiKey;
690
704
  this.gatewayUrl = resolveGatewayUrl(config);
691
705
  this.debug = config.debug || false;
706
+ this.onRefreshStart = config.onRefreshStart;
707
+ this.onRefreshEnd = config.onRefreshEnd;
708
+ this.onAutoRefreshFailed = config.onAutoRefreshFailed;
692
709
  this.money = createMoneyClient({
693
710
  apiKey: this.apiKey,
694
711
  gatewayUrl: this.gatewayUrl,
@@ -732,6 +749,10 @@ var ScaleMuleServer = class {
732
749
  headers,
733
750
  body: options.body ? JSON.stringify(options.body) : void 0
734
751
  });
752
+ const rotated = response.headers.get("x-rotated-session-token");
753
+ if (rotated && options.onTokenRotated) {
754
+ options.onTokenRotated(rotated);
755
+ }
735
756
  const text = await response.text();
736
757
  let responseData = null;
737
758
  try {
@@ -743,6 +764,33 @@ var ScaleMuleServer = class {
743
764
  code: `HTTP_${response.status}`,
744
765
  message: responseData?.message || text || response.statusText
745
766
  };
767
+ if (response.status === 401 && options.sessionToken && !options.isAutoRefresh) {
768
+ if (this.debug) console.log("[ScaleMule Server] 401 received, attempting auto-refresh...");
769
+ try {
770
+ this.onRefreshStart?.();
771
+ const refreshData = await this.auth.refresh(options.sessionToken, {
772
+ clientContext: options.clientContext,
773
+ isAutoRefresh: true
774
+ // Prevent infinite loops
775
+ });
776
+ const newToken = refreshData.session_token;
777
+ if (this.debug) console.log("[ScaleMule Server] Auto-refresh succeeded, retrying original request...");
778
+ options.onTokenRotated?.(newToken);
779
+ return this.request(method, path, {
780
+ ...options,
781
+ sessionToken: newToken,
782
+ isAutoRefresh: true
783
+ // Don't refresh again on this retry
784
+ });
785
+ } catch (refreshErr) {
786
+ if (this.debug) console.error("[ScaleMule Server] Auto-refresh failed:", refreshErr);
787
+ const refreshApiError = refreshErr instanceof ScaleMuleApiError ? { code: refreshErr.code, message: refreshErr.message } : { code: "REFRESH_FAILED", message: "Auto-refresh failed" };
788
+ this.onAutoRefreshFailed?.(refreshApiError);
789
+ throw new ScaleMuleApiError(error);
790
+ } finally {
791
+ this.onRefreshEnd?.();
792
+ }
793
+ }
746
794
  throw new ScaleMuleApiError(error);
747
795
  }
748
796
  const data = responseData?.data !== void 0 ? responseData.data : responseData;
@@ -1171,8 +1219,16 @@ function createAuthRoutes(config = {}) {
1171
1219
  // ==================== Logout ====================
1172
1220
  case "logout": {
1173
1221
  const session = await getSession();
1222
+ let rotated = null;
1174
1223
  if (session) {
1175
- await sm.auth.logout(session.sessionToken);
1224
+ try {
1225
+ await sm.auth.logout(session.sessionToken, {
1226
+ onTokenRotated: (newToken) => {
1227
+ rotated = newToken;
1228
+ }
1229
+ });
1230
+ } catch {
1231
+ }
1176
1232
  }
1177
1233
  if (config.onLogout) {
1178
1234
  await config.onLogout();
@@ -1237,6 +1293,7 @@ function createAuthRoutes(config = {}) {
1237
1293
  case "resend-verification": {
1238
1294
  const { email } = body;
1239
1295
  const session = await getSession();
1296
+ let rotated = null;
1240
1297
  if (email) {
1241
1298
  try {
1242
1299
  await sm.auth.resendVerification(email);
@@ -1254,7 +1311,11 @@ function createAuthRoutes(config = {}) {
1254
1311
  return errorResponse("UNAUTHORIZED", "Email or session required", 401);
1255
1312
  }
1256
1313
  try {
1257
- await sm.auth.resendVerification(session.sessionToken);
1314
+ await sm.auth.resendVerification(session.sessionToken, {
1315
+ onTokenRotated: (newToken) => {
1316
+ rotated = newToken;
1317
+ }
1318
+ });
1258
1319
  } catch (err) {
1259
1320
  const apiErr = err instanceof ScaleMuleApiError ? err : null;
1260
1321
  return errorResponse(
@@ -1263,6 +1324,14 @@ function createAuthRoutes(config = {}) {
1263
1324
  400
1264
1325
  );
1265
1326
  }
1327
+ if (rotated) {
1328
+ return withRefreshedSession(
1329
+ rotated,
1330
+ session.userId,
1331
+ { success: true, data: { message: "Verification email sent" } },
1332
+ cookieOptions
1333
+ );
1334
+ }
1266
1335
  return successResponse({ message: "Verification email sent" });
1267
1336
  }
1268
1337
  // ==================== Refresh Session ====================
@@ -1297,11 +1366,17 @@ function createAuthRoutes(config = {}) {
1297
1366
  if (!current_password || !new_password) {
1298
1367
  return errorResponse("VALIDATION_ERROR", "Current and new password required", 400);
1299
1368
  }
1369
+ let rotated = null;
1300
1370
  try {
1301
1371
  await sm.user.changePassword(
1302
1372
  session.sessionToken,
1303
1373
  current_password,
1304
- new_password
1374
+ new_password,
1375
+ {
1376
+ onTokenRotated: (newToken) => {
1377
+ rotated = newToken;
1378
+ }
1379
+ }
1305
1380
  );
1306
1381
  } catch (err) {
1307
1382
  const apiErr = err instanceof ScaleMuleApiError ? err : null;
@@ -1311,6 +1386,14 @@ function createAuthRoutes(config = {}) {
1311
1386
  400
1312
1387
  );
1313
1388
  }
1389
+ if (rotated) {
1390
+ return withRefreshedSession(
1391
+ rotated,
1392
+ session.userId,
1393
+ { success: true, data: { message: "Password changed successfully" } },
1394
+ cookieOptions
1395
+ );
1396
+ }
1314
1397
  return successResponse({ message: "Password changed successfully" });
1315
1398
  }
1316
1399
  // ==================== Switch Account ====================
@@ -1391,14 +1474,27 @@ function createAuthRoutes(config = {}) {
1391
1474
  return withNorm(errorResponse("UNAUTHORIZED", "Authentication required", 401));
1392
1475
  }
1393
1476
  let userData;
1477
+ let rotated = null;
1394
1478
  try {
1395
- userData = await sm.auth.me(session.sessionToken);
1479
+ userData = await sm.auth.me(session.sessionToken, {
1480
+ onTokenRotated: (newToken) => {
1481
+ rotated = newToken;
1482
+ }
1483
+ });
1396
1484
  } catch {
1397
1485
  return withNorm(clearSession(
1398
1486
  { error: { code: "SESSION_EXPIRED", message: "Session expired" } },
1399
1487
  cookieOptions
1400
1488
  ));
1401
1489
  }
1490
+ if (rotated) {
1491
+ return withNorm(withRefreshedSession(
1492
+ rotated,
1493
+ session.userId,
1494
+ { user: userData, sessionToken: rotated, userId: session.userId },
1495
+ cookieOptions
1496
+ ));
1497
+ }
1402
1498
  return withNorm(successResponse({ user: userData, sessionToken: session.sessionToken, userId: session.userId }));
1403
1499
  }
1404
1500
  // ==================== Get Session Status ====================
@@ -1477,8 +1573,13 @@ function createAuthRoutes(config = {}) {
1477
1573
  const body = await request.json().catch(() => ({}));
1478
1574
  const { full_name, avatar_url } = body;
1479
1575
  let updatedUser;
1576
+ let rotated = null;
1480
1577
  try {
1481
- updatedUser = await sm.user.update(session.sessionToken, { full_name, avatar_url });
1578
+ updatedUser = await sm.user.update(session.sessionToken, { full_name, avatar_url }, {
1579
+ onTokenRotated: (newToken) => {
1580
+ rotated = newToken;
1581
+ }
1582
+ });
1482
1583
  } catch (err) {
1483
1584
  const apiErr = err instanceof ScaleMuleApiError ? err : null;
1484
1585
  return errorResponse(
@@ -1487,6 +1588,14 @@ function createAuthRoutes(config = {}) {
1487
1588
  400
1488
1589
  );
1489
1590
  }
1591
+ if (rotated) {
1592
+ return withRefreshedSession(
1593
+ rotated,
1594
+ session.userId,
1595
+ { success: true, data: { user: updatedUser } },
1596
+ cookieOptions
1597
+ );
1598
+ }
1490
1599
  return successResponse({ user: updatedUser });
1491
1600
  }
1492
1601
  default:
@@ -1,5 +1,5 @@
1
- import { S as ServerConfig } from '../webhook-handler-CUp_A0_p.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-CUp_A0_p.mjs';
1
+ import { S as ServerConfig } from '../webhook-handler-DsxJS_He.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-DsxJS_He.mjs';
3
3
  import { p as ClientContext, A as ApiError } from '../index-DTWyUcyd.mjs';
4
4
  export { L as LedveryRoutesConfig, a as LedverySessionData, S as SM_LEDVERY_ACCESS_TOKEN_COOKIE, b as SM_LEDVERY_ID_TOKEN_COOKIE, c as SM_LEDVERY_NONCE_COOKIE, d as SM_LEDVERY_PKCE_VERIFIER_COOKIE, e as SM_LEDVERY_STATE_COOKIE, f as createLedveryRoutes, g as getLedverySession } from '../ledvery-CxPzZpxP.mjs';
5
5
  import { NextRequest, NextResponse } from 'next/server';
@@ -1,5 +1,5 @@
1
- import { S as ServerConfig } from '../webhook-handler-C07AK4QB.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-C07AK4QB.js';
1
+ import { S as ServerConfig } from '../webhook-handler-CTx4Uh8u.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-CTx4Uh8u.js';
3
3
  import { p as ClientContext, A as ApiError } from '../index-DTWyUcyd.js';
4
4
  export { L as LedveryRoutesConfig, a as LedverySessionData, S as SM_LEDVERY_ACCESS_TOKEN_COOKIE, b as SM_LEDVERY_ID_TOKEN_COOKIE, c as SM_LEDVERY_NONCE_COOKIE, d as SM_LEDVERY_PKCE_VERIFIER_COOKIE, e as SM_LEDVERY_STATE_COOKIE, f as createLedveryRoutes, g as getLedverySession } from '../ledvery-CxPzZpxP.js';
5
5
  import { NextRequest, NextResponse } from 'next/server';
@@ -2111,23 +2111,31 @@ var ScaleMuleServer = class {
2111
2111
  /**
2112
2112
  * Logout user
2113
2113
  */
2114
- logout: async (sessionToken) => {
2114
+ logout: async (sessionToken, options) => {
2115
2115
  return this.request("POST", "/v1/auth/logout", {
2116
- body: { session_token: sessionToken }
2116
+ sessionToken,
2117
+ body: { session_token: sessionToken },
2118
+ onTokenRotated: options?.onTokenRotated
2117
2119
  });
2118
2120
  },
2119
2121
  /**
2120
2122
  * Get current user from session token
2121
2123
  */
2122
- me: async (sessionToken) => {
2123
- return this.request("GET", "/v1/auth/me", { sessionToken });
2124
+ me: async (sessionToken, options) => {
2125
+ return this.request("GET", "/v1/auth/me", {
2126
+ sessionToken,
2127
+ onTokenRotated: options?.onTokenRotated
2128
+ });
2124
2129
  },
2125
2130
  /**
2126
2131
  * Refresh session token
2127
2132
  */
2128
- refresh: async (sessionToken) => {
2133
+ refresh: async (sessionToken, options) => {
2129
2134
  return this.request("POST", "/v1/auth/refresh", {
2130
- body: { session_token: sessionToken }
2135
+ sessionToken,
2136
+ clientContext: options?.clientContext,
2137
+ isAutoRefresh: options?.isAutoRefresh,
2138
+ onTokenRotated: options?.onTokenRotated
2131
2139
  });
2132
2140
  },
2133
2141
  /**
@@ -2159,7 +2167,8 @@ var ScaleMuleServer = class {
2159
2167
  if (options?.email) {
2160
2168
  return this.request("POST", "/v1/auth/resend-verification", {
2161
2169
  sessionToken: sessionTokenOrEmail,
2162
- body: { email: options.email }
2170
+ body: { email: options.email },
2171
+ onTokenRotated: options?.onTokenRotated
2163
2172
  });
2164
2173
  }
2165
2174
  if (sessionTokenOrEmail.includes("@")) {
@@ -2168,7 +2177,8 @@ var ScaleMuleServer = class {
2168
2177
  });
2169
2178
  }
2170
2179
  return this.request("POST", "/v1/auth/resend-verification", {
2171
- sessionToken: sessionTokenOrEmail
2180
+ sessionToken: sessionTokenOrEmail,
2181
+ onTokenRotated: options?.onTokenRotated
2172
2182
  });
2173
2183
  }
2174
2184
  };
@@ -2179,37 +2189,41 @@ var ScaleMuleServer = class {
2179
2189
  /**
2180
2190
  * Update user profile
2181
2191
  */
2182
- update: async (sessionToken, data) => {
2192
+ update: async (sessionToken, data, options) => {
2183
2193
  return this.request("PATCH", "/v1/auth/profile", {
2184
2194
  sessionToken,
2185
- body: data
2195
+ body: data,
2196
+ onTokenRotated: options?.onTokenRotated
2186
2197
  });
2187
2198
  },
2188
2199
  /**
2189
2200
  * Change password
2190
2201
  */
2191
- changePassword: async (sessionToken, currentPassword, newPassword) => {
2202
+ changePassword: async (sessionToken, currentPassword, newPassword, options) => {
2192
2203
  return this.request("POST", "/v1/auth/change-password", {
2193
2204
  sessionToken,
2194
- body: { current_password: currentPassword, new_password: newPassword }
2205
+ body: { current_password: currentPassword, new_password: newPassword },
2206
+ onTokenRotated: options?.onTokenRotated
2195
2207
  });
2196
2208
  },
2197
2209
  /**
2198
2210
  * Change email
2199
2211
  */
2200
- changeEmail: async (sessionToken, newEmail, password) => {
2212
+ changeEmail: async (sessionToken, newEmail, password, options) => {
2201
2213
  return this.request("POST", "/v1/auth/change-email", {
2202
2214
  sessionToken,
2203
- body: { new_email: newEmail, password }
2215
+ body: { new_email: newEmail, password },
2216
+ onTokenRotated: options?.onTokenRotated
2204
2217
  });
2205
2218
  },
2206
2219
  /**
2207
2220
  * Delete account
2208
2221
  */
2209
- deleteAccount: async (sessionToken, password) => {
2222
+ deleteAccount: async (sessionToken, password, options) => {
2210
2223
  return this.request("DELETE", "/v1/auth/me", {
2211
2224
  sessionToken,
2212
- body: { password }
2225
+ body: { password },
2226
+ onTokenRotated: options?.onTokenRotated
2213
2227
  });
2214
2228
  }
2215
2229
  };
@@ -2670,6 +2684,9 @@ var ScaleMuleServer = class {
2670
2684
  this.apiKey = config.apiKey;
2671
2685
  this.gatewayUrl = resolveGatewayUrl(config);
2672
2686
  this.debug = config.debug || false;
2687
+ this.onRefreshStart = config.onRefreshStart;
2688
+ this.onRefreshEnd = config.onRefreshEnd;
2689
+ this.onAutoRefreshFailed = config.onAutoRefreshFailed;
2673
2690
  this.money = money.createMoneyClient({
2674
2691
  apiKey: this.apiKey,
2675
2692
  gatewayUrl: this.gatewayUrl,
@@ -2713,6 +2730,10 @@ var ScaleMuleServer = class {
2713
2730
  headers: headers2,
2714
2731
  body: options.body ? JSON.stringify(options.body) : void 0
2715
2732
  });
2733
+ const rotated = response.headers.get("x-rotated-session-token");
2734
+ if (rotated && options.onTokenRotated) {
2735
+ options.onTokenRotated(rotated);
2736
+ }
2716
2737
  const text = await response.text();
2717
2738
  let responseData = null;
2718
2739
  try {
@@ -2724,6 +2745,33 @@ var ScaleMuleServer = class {
2724
2745
  code: `HTTP_${response.status}`,
2725
2746
  message: responseData?.message || text || response.statusText
2726
2747
  };
2748
+ if (response.status === 401 && options.sessionToken && !options.isAutoRefresh) {
2749
+ if (this.debug) console.log("[ScaleMule Server] 401 received, attempting auto-refresh...");
2750
+ try {
2751
+ this.onRefreshStart?.();
2752
+ const refreshData = await this.auth.refresh(options.sessionToken, {
2753
+ clientContext: options.clientContext,
2754
+ isAutoRefresh: true
2755
+ // Prevent infinite loops
2756
+ });
2757
+ const newToken = refreshData.session_token;
2758
+ if (this.debug) console.log("[ScaleMule Server] Auto-refresh succeeded, retrying original request...");
2759
+ options.onTokenRotated?.(newToken);
2760
+ return this.request(method, path, {
2761
+ ...options,
2762
+ sessionToken: newToken,
2763
+ isAutoRefresh: true
2764
+ // Don't refresh again on this retry
2765
+ });
2766
+ } catch (refreshErr) {
2767
+ if (this.debug) console.error("[ScaleMule Server] Auto-refresh failed:", refreshErr);
2768
+ const refreshApiError = refreshErr instanceof ScaleMuleApiError ? { code: refreshErr.code, message: refreshErr.message } : { code: "REFRESH_FAILED", message: "Auto-refresh failed" };
2769
+ this.onAutoRefreshFailed?.(refreshApiError);
2770
+ throw new ScaleMuleApiError(error);
2771
+ } finally {
2772
+ this.onRefreshEnd?.();
2773
+ }
2774
+ }
2727
2775
  throw new ScaleMuleApiError(error);
2728
2776
  }
2729
2777
  const data = responseData?.data !== void 0 ? responseData.data : responseData;
@@ -3245,8 +3293,16 @@ function createAuthRoutes(config = {}) {
3245
3293
  // ==================== Logout ====================
3246
3294
  case "logout": {
3247
3295
  const session = await getSession();
3296
+ let rotated = null;
3248
3297
  if (session) {
3249
- await sm.auth.logout(session.sessionToken);
3298
+ try {
3299
+ await sm.auth.logout(session.sessionToken, {
3300
+ onTokenRotated: (newToken) => {
3301
+ rotated = newToken;
3302
+ }
3303
+ });
3304
+ } catch {
3305
+ }
3250
3306
  }
3251
3307
  if (config.onLogout) {
3252
3308
  await config.onLogout();
@@ -3311,6 +3367,7 @@ function createAuthRoutes(config = {}) {
3311
3367
  case "resend-verification": {
3312
3368
  const { email } = body;
3313
3369
  const session = await getSession();
3370
+ let rotated = null;
3314
3371
  if (email) {
3315
3372
  try {
3316
3373
  await sm.auth.resendVerification(email);
@@ -3328,7 +3385,11 @@ function createAuthRoutes(config = {}) {
3328
3385
  return errorResponse("UNAUTHORIZED", "Email or session required", 401);
3329
3386
  }
3330
3387
  try {
3331
- await sm.auth.resendVerification(session.sessionToken);
3388
+ await sm.auth.resendVerification(session.sessionToken, {
3389
+ onTokenRotated: (newToken) => {
3390
+ rotated = newToken;
3391
+ }
3392
+ });
3332
3393
  } catch (err) {
3333
3394
  const apiErr = err instanceof ScaleMuleApiError ? err : null;
3334
3395
  return errorResponse(
@@ -3337,6 +3398,14 @@ function createAuthRoutes(config = {}) {
3337
3398
  400
3338
3399
  );
3339
3400
  }
3401
+ if (rotated) {
3402
+ return withRefreshedSession(
3403
+ rotated,
3404
+ session.userId,
3405
+ { success: true, data: { message: "Verification email sent" } },
3406
+ cookieOptions
3407
+ );
3408
+ }
3340
3409
  return successResponse({ message: "Verification email sent" });
3341
3410
  }
3342
3411
  // ==================== Refresh Session ====================
@@ -3371,11 +3440,17 @@ function createAuthRoutes(config = {}) {
3371
3440
  if (!current_password || !new_password) {
3372
3441
  return errorResponse("VALIDATION_ERROR", "Current and new password required", 400);
3373
3442
  }
3443
+ let rotated = null;
3374
3444
  try {
3375
3445
  await sm.user.changePassword(
3376
3446
  session.sessionToken,
3377
3447
  current_password,
3378
- new_password
3448
+ new_password,
3449
+ {
3450
+ onTokenRotated: (newToken) => {
3451
+ rotated = newToken;
3452
+ }
3453
+ }
3379
3454
  );
3380
3455
  } catch (err) {
3381
3456
  const apiErr = err instanceof ScaleMuleApiError ? err : null;
@@ -3385,6 +3460,14 @@ function createAuthRoutes(config = {}) {
3385
3460
  400
3386
3461
  );
3387
3462
  }
3463
+ if (rotated) {
3464
+ return withRefreshedSession(
3465
+ rotated,
3466
+ session.userId,
3467
+ { success: true, data: { message: "Password changed successfully" } },
3468
+ cookieOptions
3469
+ );
3470
+ }
3388
3471
  return successResponse({ message: "Password changed successfully" });
3389
3472
  }
3390
3473
  // ==================== Switch Account ====================
@@ -3465,14 +3548,27 @@ function createAuthRoutes(config = {}) {
3465
3548
  return withNorm(errorResponse("UNAUTHORIZED", "Authentication required", 401));
3466
3549
  }
3467
3550
  let userData;
3551
+ let rotated = null;
3468
3552
  try {
3469
- userData = await sm.auth.me(session.sessionToken);
3553
+ userData = await sm.auth.me(session.sessionToken, {
3554
+ onTokenRotated: (newToken) => {
3555
+ rotated = newToken;
3556
+ }
3557
+ });
3470
3558
  } catch {
3471
3559
  return withNorm(clearSession(
3472
3560
  { error: { code: "SESSION_EXPIRED", message: "Session expired" } },
3473
3561
  cookieOptions
3474
3562
  ));
3475
3563
  }
3564
+ if (rotated) {
3565
+ return withNorm(withRefreshedSession(
3566
+ rotated,
3567
+ session.userId,
3568
+ { user: userData, sessionToken: rotated, userId: session.userId },
3569
+ cookieOptions
3570
+ ));
3571
+ }
3476
3572
  return withNorm(successResponse({ user: userData, sessionToken: session.sessionToken, userId: session.userId }));
3477
3573
  }
3478
3574
  // ==================== Get Session Status ====================
@@ -3551,8 +3647,13 @@ function createAuthRoutes(config = {}) {
3551
3647
  const body = await request.json().catch(() => ({}));
3552
3648
  const { full_name, avatar_url } = body;
3553
3649
  let updatedUser;
3650
+ let rotated = null;
3554
3651
  try {
3555
- updatedUser = await sm.user.update(session.sessionToken, { full_name, avatar_url });
3652
+ updatedUser = await sm.user.update(session.sessionToken, { full_name, avatar_url }, {
3653
+ onTokenRotated: (newToken) => {
3654
+ rotated = newToken;
3655
+ }
3656
+ });
3556
3657
  } catch (err) {
3557
3658
  const apiErr = err instanceof ScaleMuleApiError ? err : null;
3558
3659
  return errorResponse(
@@ -3561,6 +3662,14 @@ function createAuthRoutes(config = {}) {
3561
3662
  400
3562
3663
  );
3563
3664
  }
3665
+ if (rotated) {
3666
+ return withRefreshedSession(
3667
+ rotated,
3668
+ session.userId,
3669
+ { success: true, data: { user: updatedUser } },
3670
+ cookieOptions
3671
+ );
3672
+ }
3564
3673
  return successResponse({ user: updatedUser });
3565
3674
  }
3566
3675
  default: