@scalemule/nextjs 0.1.16 → 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.
- package/dist/client.d.mts +13 -1
- package/dist/client.d.ts +13 -1
- package/dist/client.js +32 -0
- package/dist/client.mjs +32 -0
- package/dist/index.js +32 -0
- package/dist/index.mjs +32 -0
- package/dist/server/auth.js +130 -21
- package/dist/server/auth.mjs +130 -21
- package/dist/server/index.d.mts +2 -2
- package/dist/server/index.d.ts +2 -2
- package/dist/server/index.js +140 -26
- package/dist/server/index.mjs +140 -26
- package/dist/server/ledvery.js +10 -5
- package/dist/server/ledvery.mjs +10 -5
- package/dist/server/webhook-handler.d.mts +1 -1
- package/dist/server/webhook-handler.d.ts +1 -1
- package/dist/{webhook-handler-C07AK4QB.d.ts → webhook-handler-CTx4Uh8u.d.ts} +33 -7
- package/dist/{webhook-handler-CUp_A0_p.d.mts → webhook-handler-DsxJS_He.d.mts} +33 -7
- package/package.json +2 -2
package/dist/server/index.mjs
CHANGED
|
@@ -2109,23 +2109,31 @@ var ScaleMuleServer = class {
|
|
|
2109
2109
|
/**
|
|
2110
2110
|
* Logout user
|
|
2111
2111
|
*/
|
|
2112
|
-
logout: async (sessionToken) => {
|
|
2112
|
+
logout: async (sessionToken, options) => {
|
|
2113
2113
|
return this.request("POST", "/v1/auth/logout", {
|
|
2114
|
-
|
|
2114
|
+
sessionToken,
|
|
2115
|
+
body: { session_token: sessionToken },
|
|
2116
|
+
onTokenRotated: options?.onTokenRotated
|
|
2115
2117
|
});
|
|
2116
2118
|
},
|
|
2117
2119
|
/**
|
|
2118
2120
|
* Get current user from session token
|
|
2119
2121
|
*/
|
|
2120
|
-
me: async (sessionToken) => {
|
|
2121
|
-
return this.request("GET", "/v1/auth/me", {
|
|
2122
|
+
me: async (sessionToken, options) => {
|
|
2123
|
+
return this.request("GET", "/v1/auth/me", {
|
|
2124
|
+
sessionToken,
|
|
2125
|
+
onTokenRotated: options?.onTokenRotated
|
|
2126
|
+
});
|
|
2122
2127
|
},
|
|
2123
2128
|
/**
|
|
2124
2129
|
* Refresh session token
|
|
2125
2130
|
*/
|
|
2126
|
-
refresh: async (sessionToken) => {
|
|
2131
|
+
refresh: async (sessionToken, options) => {
|
|
2127
2132
|
return this.request("POST", "/v1/auth/refresh", {
|
|
2128
|
-
|
|
2133
|
+
sessionToken,
|
|
2134
|
+
clientContext: options?.clientContext,
|
|
2135
|
+
isAutoRefresh: options?.isAutoRefresh,
|
|
2136
|
+
onTokenRotated: options?.onTokenRotated
|
|
2129
2137
|
});
|
|
2130
2138
|
},
|
|
2131
2139
|
/**
|
|
@@ -2157,7 +2165,8 @@ var ScaleMuleServer = class {
|
|
|
2157
2165
|
if (options?.email) {
|
|
2158
2166
|
return this.request("POST", "/v1/auth/resend-verification", {
|
|
2159
2167
|
sessionToken: sessionTokenOrEmail,
|
|
2160
|
-
body: { email: options.email }
|
|
2168
|
+
body: { email: options.email },
|
|
2169
|
+
onTokenRotated: options?.onTokenRotated
|
|
2161
2170
|
});
|
|
2162
2171
|
}
|
|
2163
2172
|
if (sessionTokenOrEmail.includes("@")) {
|
|
@@ -2166,7 +2175,8 @@ var ScaleMuleServer = class {
|
|
|
2166
2175
|
});
|
|
2167
2176
|
}
|
|
2168
2177
|
return this.request("POST", "/v1/auth/resend-verification", {
|
|
2169
|
-
sessionToken: sessionTokenOrEmail
|
|
2178
|
+
sessionToken: sessionTokenOrEmail,
|
|
2179
|
+
onTokenRotated: options?.onTokenRotated
|
|
2170
2180
|
});
|
|
2171
2181
|
}
|
|
2172
2182
|
};
|
|
@@ -2177,37 +2187,41 @@ var ScaleMuleServer = class {
|
|
|
2177
2187
|
/**
|
|
2178
2188
|
* Update user profile
|
|
2179
2189
|
*/
|
|
2180
|
-
update: async (sessionToken, data) => {
|
|
2190
|
+
update: async (sessionToken, data, options) => {
|
|
2181
2191
|
return this.request("PATCH", "/v1/auth/profile", {
|
|
2182
2192
|
sessionToken,
|
|
2183
|
-
body: data
|
|
2193
|
+
body: data,
|
|
2194
|
+
onTokenRotated: options?.onTokenRotated
|
|
2184
2195
|
});
|
|
2185
2196
|
},
|
|
2186
2197
|
/**
|
|
2187
2198
|
* Change password
|
|
2188
2199
|
*/
|
|
2189
|
-
changePassword: async (sessionToken, currentPassword, newPassword) => {
|
|
2200
|
+
changePassword: async (sessionToken, currentPassword, newPassword, options) => {
|
|
2190
2201
|
return this.request("POST", "/v1/auth/change-password", {
|
|
2191
2202
|
sessionToken,
|
|
2192
|
-
body: { current_password: currentPassword, new_password: newPassword }
|
|
2203
|
+
body: { current_password: currentPassword, new_password: newPassword },
|
|
2204
|
+
onTokenRotated: options?.onTokenRotated
|
|
2193
2205
|
});
|
|
2194
2206
|
},
|
|
2195
2207
|
/**
|
|
2196
2208
|
* Change email
|
|
2197
2209
|
*/
|
|
2198
|
-
changeEmail: async (sessionToken, newEmail, password) => {
|
|
2210
|
+
changeEmail: async (sessionToken, newEmail, password, options) => {
|
|
2199
2211
|
return this.request("POST", "/v1/auth/change-email", {
|
|
2200
2212
|
sessionToken,
|
|
2201
|
-
body: { new_email: newEmail, password }
|
|
2213
|
+
body: { new_email: newEmail, password },
|
|
2214
|
+
onTokenRotated: options?.onTokenRotated
|
|
2202
2215
|
});
|
|
2203
2216
|
},
|
|
2204
2217
|
/**
|
|
2205
2218
|
* Delete account
|
|
2206
2219
|
*/
|
|
2207
|
-
deleteAccount: async (sessionToken, password) => {
|
|
2220
|
+
deleteAccount: async (sessionToken, password, options) => {
|
|
2208
2221
|
return this.request("DELETE", "/v1/auth/me", {
|
|
2209
2222
|
sessionToken,
|
|
2210
|
-
body: { password }
|
|
2223
|
+
body: { password },
|
|
2224
|
+
onTokenRotated: options?.onTokenRotated
|
|
2211
2225
|
});
|
|
2212
2226
|
}
|
|
2213
2227
|
};
|
|
@@ -2668,6 +2682,9 @@ var ScaleMuleServer = class {
|
|
|
2668
2682
|
this.apiKey = config.apiKey;
|
|
2669
2683
|
this.gatewayUrl = resolveGatewayUrl(config);
|
|
2670
2684
|
this.debug = config.debug || false;
|
|
2685
|
+
this.onRefreshStart = config.onRefreshStart;
|
|
2686
|
+
this.onRefreshEnd = config.onRefreshEnd;
|
|
2687
|
+
this.onAutoRefreshFailed = config.onAutoRefreshFailed;
|
|
2671
2688
|
this.money = createMoneyClient({
|
|
2672
2689
|
apiKey: this.apiKey,
|
|
2673
2690
|
gatewayUrl: this.gatewayUrl,
|
|
@@ -2711,6 +2728,10 @@ var ScaleMuleServer = class {
|
|
|
2711
2728
|
headers: headers2,
|
|
2712
2729
|
body: options.body ? JSON.stringify(options.body) : void 0
|
|
2713
2730
|
});
|
|
2731
|
+
const rotated = response.headers.get("x-rotated-session-token");
|
|
2732
|
+
if (rotated && options.onTokenRotated) {
|
|
2733
|
+
options.onTokenRotated(rotated);
|
|
2734
|
+
}
|
|
2714
2735
|
const text = await response.text();
|
|
2715
2736
|
let responseData = null;
|
|
2716
2737
|
try {
|
|
@@ -2722,6 +2743,33 @@ var ScaleMuleServer = class {
|
|
|
2722
2743
|
code: `HTTP_${response.status}`,
|
|
2723
2744
|
message: responseData?.message || text || response.statusText
|
|
2724
2745
|
};
|
|
2746
|
+
if (response.status === 401 && options.sessionToken && !options.isAutoRefresh) {
|
|
2747
|
+
if (this.debug) console.log("[ScaleMule Server] 401 received, attempting auto-refresh...");
|
|
2748
|
+
try {
|
|
2749
|
+
this.onRefreshStart?.();
|
|
2750
|
+
const refreshData = await this.auth.refresh(options.sessionToken, {
|
|
2751
|
+
clientContext: options.clientContext,
|
|
2752
|
+
isAutoRefresh: true
|
|
2753
|
+
// Prevent infinite loops
|
|
2754
|
+
});
|
|
2755
|
+
const newToken = refreshData.session_token;
|
|
2756
|
+
if (this.debug) console.log("[ScaleMule Server] Auto-refresh succeeded, retrying original request...");
|
|
2757
|
+
options.onTokenRotated?.(newToken);
|
|
2758
|
+
return this.request(method, path, {
|
|
2759
|
+
...options,
|
|
2760
|
+
sessionToken: newToken,
|
|
2761
|
+
isAutoRefresh: true
|
|
2762
|
+
// Don't refresh again on this retry
|
|
2763
|
+
});
|
|
2764
|
+
} catch (refreshErr) {
|
|
2765
|
+
if (this.debug) console.error("[ScaleMule Server] Auto-refresh failed:", refreshErr);
|
|
2766
|
+
const refreshApiError = refreshErr instanceof ScaleMuleApiError ? { code: refreshErr.code, message: refreshErr.message } : { code: "REFRESH_FAILED", message: "Auto-refresh failed" };
|
|
2767
|
+
this.onAutoRefreshFailed?.(refreshApiError);
|
|
2768
|
+
throw new ScaleMuleApiError(error);
|
|
2769
|
+
} finally {
|
|
2770
|
+
this.onRefreshEnd?.();
|
|
2771
|
+
}
|
|
2772
|
+
}
|
|
2725
2773
|
throw new ScaleMuleApiError(error);
|
|
2726
2774
|
}
|
|
2727
2775
|
const data = responseData?.data !== void 0 ? responseData.data : responseData;
|
|
@@ -3243,8 +3291,16 @@ function createAuthRoutes(config = {}) {
|
|
|
3243
3291
|
// ==================== Logout ====================
|
|
3244
3292
|
case "logout": {
|
|
3245
3293
|
const session = await getSession();
|
|
3294
|
+
let rotated = null;
|
|
3246
3295
|
if (session) {
|
|
3247
|
-
|
|
3296
|
+
try {
|
|
3297
|
+
await sm.auth.logout(session.sessionToken, {
|
|
3298
|
+
onTokenRotated: (newToken) => {
|
|
3299
|
+
rotated = newToken;
|
|
3300
|
+
}
|
|
3301
|
+
});
|
|
3302
|
+
} catch {
|
|
3303
|
+
}
|
|
3248
3304
|
}
|
|
3249
3305
|
if (config.onLogout) {
|
|
3250
3306
|
await config.onLogout();
|
|
@@ -3309,6 +3365,7 @@ function createAuthRoutes(config = {}) {
|
|
|
3309
3365
|
case "resend-verification": {
|
|
3310
3366
|
const { email } = body;
|
|
3311
3367
|
const session = await getSession();
|
|
3368
|
+
let rotated = null;
|
|
3312
3369
|
if (email) {
|
|
3313
3370
|
try {
|
|
3314
3371
|
await sm.auth.resendVerification(email);
|
|
@@ -3326,7 +3383,11 @@ function createAuthRoutes(config = {}) {
|
|
|
3326
3383
|
return errorResponse("UNAUTHORIZED", "Email or session required", 401);
|
|
3327
3384
|
}
|
|
3328
3385
|
try {
|
|
3329
|
-
await sm.auth.resendVerification(session.sessionToken
|
|
3386
|
+
await sm.auth.resendVerification(session.sessionToken, {
|
|
3387
|
+
onTokenRotated: (newToken) => {
|
|
3388
|
+
rotated = newToken;
|
|
3389
|
+
}
|
|
3390
|
+
});
|
|
3330
3391
|
} catch (err) {
|
|
3331
3392
|
const apiErr = err instanceof ScaleMuleApiError ? err : null;
|
|
3332
3393
|
return errorResponse(
|
|
@@ -3335,6 +3396,14 @@ function createAuthRoutes(config = {}) {
|
|
|
3335
3396
|
400
|
|
3336
3397
|
);
|
|
3337
3398
|
}
|
|
3399
|
+
if (rotated) {
|
|
3400
|
+
return withRefreshedSession(
|
|
3401
|
+
rotated,
|
|
3402
|
+
session.userId,
|
|
3403
|
+
{ success: true, data: { message: "Verification email sent" } },
|
|
3404
|
+
cookieOptions
|
|
3405
|
+
);
|
|
3406
|
+
}
|
|
3338
3407
|
return successResponse({ message: "Verification email sent" });
|
|
3339
3408
|
}
|
|
3340
3409
|
// ==================== Refresh Session ====================
|
|
@@ -3369,11 +3438,17 @@ function createAuthRoutes(config = {}) {
|
|
|
3369
3438
|
if (!current_password || !new_password) {
|
|
3370
3439
|
return errorResponse("VALIDATION_ERROR", "Current and new password required", 400);
|
|
3371
3440
|
}
|
|
3441
|
+
let rotated = null;
|
|
3372
3442
|
try {
|
|
3373
3443
|
await sm.user.changePassword(
|
|
3374
3444
|
session.sessionToken,
|
|
3375
3445
|
current_password,
|
|
3376
|
-
new_password
|
|
3446
|
+
new_password,
|
|
3447
|
+
{
|
|
3448
|
+
onTokenRotated: (newToken) => {
|
|
3449
|
+
rotated = newToken;
|
|
3450
|
+
}
|
|
3451
|
+
}
|
|
3377
3452
|
);
|
|
3378
3453
|
} catch (err) {
|
|
3379
3454
|
const apiErr = err instanceof ScaleMuleApiError ? err : null;
|
|
@@ -3383,6 +3458,14 @@ function createAuthRoutes(config = {}) {
|
|
|
3383
3458
|
400
|
|
3384
3459
|
);
|
|
3385
3460
|
}
|
|
3461
|
+
if (rotated) {
|
|
3462
|
+
return withRefreshedSession(
|
|
3463
|
+
rotated,
|
|
3464
|
+
session.userId,
|
|
3465
|
+
{ success: true, data: { message: "Password changed successfully" } },
|
|
3466
|
+
cookieOptions
|
|
3467
|
+
);
|
|
3468
|
+
}
|
|
3386
3469
|
return successResponse({ message: "Password changed successfully" });
|
|
3387
3470
|
}
|
|
3388
3471
|
// ==================== Switch Account ====================
|
|
@@ -3463,14 +3546,27 @@ function createAuthRoutes(config = {}) {
|
|
|
3463
3546
|
return withNorm(errorResponse("UNAUTHORIZED", "Authentication required", 401));
|
|
3464
3547
|
}
|
|
3465
3548
|
let userData;
|
|
3549
|
+
let rotated = null;
|
|
3466
3550
|
try {
|
|
3467
|
-
userData = await sm.auth.me(session.sessionToken
|
|
3551
|
+
userData = await sm.auth.me(session.sessionToken, {
|
|
3552
|
+
onTokenRotated: (newToken) => {
|
|
3553
|
+
rotated = newToken;
|
|
3554
|
+
}
|
|
3555
|
+
});
|
|
3468
3556
|
} catch {
|
|
3469
3557
|
return withNorm(clearSession(
|
|
3470
3558
|
{ error: { code: "SESSION_EXPIRED", message: "Session expired" } },
|
|
3471
3559
|
cookieOptions
|
|
3472
3560
|
));
|
|
3473
3561
|
}
|
|
3562
|
+
if (rotated) {
|
|
3563
|
+
return withNorm(withRefreshedSession(
|
|
3564
|
+
rotated,
|
|
3565
|
+
session.userId,
|
|
3566
|
+
{ user: userData, sessionToken: rotated, userId: session.userId },
|
|
3567
|
+
cookieOptions
|
|
3568
|
+
));
|
|
3569
|
+
}
|
|
3474
3570
|
return withNorm(successResponse({ user: userData, sessionToken: session.sessionToken, userId: session.userId }));
|
|
3475
3571
|
}
|
|
3476
3572
|
// ==================== Get Session Status ====================
|
|
@@ -3549,8 +3645,13 @@ function createAuthRoutes(config = {}) {
|
|
|
3549
3645
|
const body = await request.json().catch(() => ({}));
|
|
3550
3646
|
const { full_name, avatar_url } = body;
|
|
3551
3647
|
let updatedUser;
|
|
3648
|
+
let rotated = null;
|
|
3552
3649
|
try {
|
|
3553
|
-
updatedUser = await sm.user.update(session.sessionToken, { full_name, avatar_url }
|
|
3650
|
+
updatedUser = await sm.user.update(session.sessionToken, { full_name, avatar_url }, {
|
|
3651
|
+
onTokenRotated: (newToken) => {
|
|
3652
|
+
rotated = newToken;
|
|
3653
|
+
}
|
|
3654
|
+
});
|
|
3554
3655
|
} catch (err) {
|
|
3555
3656
|
const apiErr = err instanceof ScaleMuleApiError ? err : null;
|
|
3556
3657
|
return errorResponse(
|
|
@@ -3559,6 +3660,14 @@ function createAuthRoutes(config = {}) {
|
|
|
3559
3660
|
400
|
|
3560
3661
|
);
|
|
3561
3662
|
}
|
|
3663
|
+
if (rotated) {
|
|
3664
|
+
return withRefreshedSession(
|
|
3665
|
+
rotated,
|
|
3666
|
+
session.userId,
|
|
3667
|
+
{ success: true, data: { user: updatedUser } },
|
|
3668
|
+
cookieOptions
|
|
3669
|
+
);
|
|
3670
|
+
}
|
|
3562
3671
|
return successResponse({ user: updatedUser });
|
|
3563
3672
|
}
|
|
3564
3673
|
default:
|
|
@@ -3830,6 +3939,7 @@ function setLedverySession(response, session, opts) {
|
|
|
3830
3939
|
if (opts?.cookies?.sameSite) cookieOpts.sameSite = opts.cookies.sameSite;
|
|
3831
3940
|
if (opts?.cookies?.secure !== void 0) cookieOpts.secure = opts.cookies.secure;
|
|
3832
3941
|
const sessionPayload = JSON.stringify({
|
|
3942
|
+
idToken: session.idToken,
|
|
3833
3943
|
claims: session.claims,
|
|
3834
3944
|
expiresAt: session.expiresAt
|
|
3835
3945
|
});
|
|
@@ -3844,8 +3954,7 @@ function getLedverySession(request) {
|
|
|
3844
3954
|
try {
|
|
3845
3955
|
const parsed = JSON.parse(raw);
|
|
3846
3956
|
return {
|
|
3847
|
-
idToken: "",
|
|
3848
|
-
// not stored in cookie for size
|
|
3957
|
+
idToken: parsed.idToken || "",
|
|
3849
3958
|
claims: parsed.claims,
|
|
3850
3959
|
expiresAt: parsed.expiresAt
|
|
3851
3960
|
};
|
|
@@ -4050,9 +4159,14 @@ function createLedveryRoutes(config) {
|
|
|
4050
4159
|
{ status: 200, headers: { "Content-Type": "application/json" } }
|
|
4051
4160
|
);
|
|
4052
4161
|
}
|
|
4053
|
-
function handleLogout(
|
|
4162
|
+
function handleLogout(request) {
|
|
4163
|
+
const session = getLedverySession(request);
|
|
4164
|
+
const idToken = session?.idToken;
|
|
4054
4165
|
if (config.gatewayUrl) {
|
|
4055
|
-
|
|
4166
|
+
let rpLogoutUrl = `${config.gatewayUrl}/v1/auth/oauth/ledvery/logout?post_logout_redirect_uri=${encodeURIComponent(postLogoutRedirect)}`;
|
|
4167
|
+
if (idToken) {
|
|
4168
|
+
rpLogoutUrl += `&id_token_hint=${encodeURIComponent(idToken)}`;
|
|
4169
|
+
}
|
|
4056
4170
|
const response2 = new Response(null, {
|
|
4057
4171
|
status: 302,
|
|
4058
4172
|
headers: { Location: rpLogoutUrl }
|
|
@@ -4078,7 +4192,7 @@ function createLedveryRoutes(config) {
|
|
|
4078
4192
|
case "session":
|
|
4079
4193
|
return handleSession(request);
|
|
4080
4194
|
case "logout":
|
|
4081
|
-
return handleLogout();
|
|
4195
|
+
return handleLogout(request);
|
|
4082
4196
|
default:
|
|
4083
4197
|
return new Response(
|
|
4084
4198
|
JSON.stringify({ error: "not_found", message: `Unknown Ledvery route: ${action}` }),
|
package/dist/server/ledvery.js
CHANGED
|
@@ -66,6 +66,7 @@ function setLedverySession(response, session, opts) {
|
|
|
66
66
|
if (opts?.cookies?.sameSite) cookieOpts.sameSite = opts.cookies.sameSite;
|
|
67
67
|
if (opts?.cookies?.secure !== void 0) cookieOpts.secure = opts.cookies.secure;
|
|
68
68
|
const sessionPayload = JSON.stringify({
|
|
69
|
+
idToken: session.idToken,
|
|
69
70
|
claims: session.claims,
|
|
70
71
|
expiresAt: session.expiresAt
|
|
71
72
|
});
|
|
@@ -80,8 +81,7 @@ function getLedverySession(request) {
|
|
|
80
81
|
try {
|
|
81
82
|
const parsed = JSON.parse(raw);
|
|
82
83
|
return {
|
|
83
|
-
idToken: "",
|
|
84
|
-
// not stored in cookie for size
|
|
84
|
+
idToken: parsed.idToken || "",
|
|
85
85
|
claims: parsed.claims,
|
|
86
86
|
expiresAt: parsed.expiresAt
|
|
87
87
|
};
|
|
@@ -280,9 +280,14 @@ function createLedveryRoutes(config) {
|
|
|
280
280
|
{ status: 200, headers: { "Content-Type": "application/json" } }
|
|
281
281
|
);
|
|
282
282
|
}
|
|
283
|
-
function handleLogout(
|
|
283
|
+
function handleLogout(request) {
|
|
284
|
+
const session = getLedverySession(request);
|
|
285
|
+
const idToken = session?.idToken;
|
|
284
286
|
if (config.gatewayUrl) {
|
|
285
|
-
|
|
287
|
+
let rpLogoutUrl = `${config.gatewayUrl}/v1/auth/oauth/ledvery/logout?post_logout_redirect_uri=${encodeURIComponent(postLogoutRedirect)}`;
|
|
288
|
+
if (idToken) {
|
|
289
|
+
rpLogoutUrl += `&id_token_hint=${encodeURIComponent(idToken)}`;
|
|
290
|
+
}
|
|
286
291
|
const response2 = new Response(null, {
|
|
287
292
|
status: 302,
|
|
288
293
|
headers: { Location: rpLogoutUrl }
|
|
@@ -308,7 +313,7 @@ function createLedveryRoutes(config) {
|
|
|
308
313
|
case "session":
|
|
309
314
|
return handleSession(request);
|
|
310
315
|
case "logout":
|
|
311
|
-
return handleLogout();
|
|
316
|
+
return handleLogout(request);
|
|
312
317
|
default:
|
|
313
318
|
return new Response(
|
|
314
319
|
JSON.stringify({ error: "not_found", message: `Unknown Ledvery route: ${action}` }),
|
package/dist/server/ledvery.mjs
CHANGED
|
@@ -64,6 +64,7 @@ function setLedverySession(response, session, opts) {
|
|
|
64
64
|
if (opts?.cookies?.sameSite) cookieOpts.sameSite = opts.cookies.sameSite;
|
|
65
65
|
if (opts?.cookies?.secure !== void 0) cookieOpts.secure = opts.cookies.secure;
|
|
66
66
|
const sessionPayload = JSON.stringify({
|
|
67
|
+
idToken: session.idToken,
|
|
67
68
|
claims: session.claims,
|
|
68
69
|
expiresAt: session.expiresAt
|
|
69
70
|
});
|
|
@@ -78,8 +79,7 @@ function getLedverySession(request) {
|
|
|
78
79
|
try {
|
|
79
80
|
const parsed = JSON.parse(raw);
|
|
80
81
|
return {
|
|
81
|
-
idToken: "",
|
|
82
|
-
// not stored in cookie for size
|
|
82
|
+
idToken: parsed.idToken || "",
|
|
83
83
|
claims: parsed.claims,
|
|
84
84
|
expiresAt: parsed.expiresAt
|
|
85
85
|
};
|
|
@@ -278,9 +278,14 @@ function createLedveryRoutes(config) {
|
|
|
278
278
|
{ status: 200, headers: { "Content-Type": "application/json" } }
|
|
279
279
|
);
|
|
280
280
|
}
|
|
281
|
-
function handleLogout(
|
|
281
|
+
function handleLogout(request) {
|
|
282
|
+
const session = getLedverySession(request);
|
|
283
|
+
const idToken = session?.idToken;
|
|
282
284
|
if (config.gatewayUrl) {
|
|
283
|
-
|
|
285
|
+
let rpLogoutUrl = `${config.gatewayUrl}/v1/auth/oauth/ledvery/logout?post_logout_redirect_uri=${encodeURIComponent(postLogoutRedirect)}`;
|
|
286
|
+
if (idToken) {
|
|
287
|
+
rpLogoutUrl += `&id_token_hint=${encodeURIComponent(idToken)}`;
|
|
288
|
+
}
|
|
284
289
|
const response2 = new Response(null, {
|
|
285
290
|
status: 302,
|
|
286
291
|
headers: { Location: rpLogoutUrl }
|
|
@@ -306,7 +311,7 @@ function createLedveryRoutes(config) {
|
|
|
306
311
|
case "session":
|
|
307
312
|
return handleSession(request);
|
|
308
313
|
case "logout":
|
|
309
|
-
return handleLogout();
|
|
314
|
+
return handleLogout(request);
|
|
310
315
|
default:
|
|
311
316
|
return new Response(
|
|
312
317
|
JSON.stringify({ error: "not_found", message: `Unknown Ledvery route: ${action}` }),
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { MoneyClient } from '@scalemule/money';
|
|
2
|
-
import { $ as RegisterRequest, p as ClientContext, U as User, v as LoginRequest, L as LoginResponse, c as ListFilesParams, t as ListFilesResponse, a9 as StorageFile, af as UploadResponse } from './index-DTWyUcyd.js';
|
|
2
|
+
import { A as ApiError, $ as RegisterRequest, p as ClientContext, U as User, v as LoginRequest, L as LoginResponse, c as ListFilesParams, t as ListFilesResponse, a9 as StorageFile, af as UploadResponse } from './index-DTWyUcyd.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Server-Side ScaleMule Client
|
|
@@ -18,12 +18,21 @@ interface ServerConfig {
|
|
|
18
18
|
gatewayUrl?: string;
|
|
19
19
|
/** Enable debug logging */
|
|
20
20
|
debug?: boolean;
|
|
21
|
+
/** Callback when a 401 auto-refresh starts */
|
|
22
|
+
onRefreshStart?: () => void;
|
|
23
|
+
/** Callback when a 401 auto-refresh finishes */
|
|
24
|
+
onRefreshEnd?: () => void;
|
|
25
|
+
/** Callback when a 401 auto-refresh fails */
|
|
26
|
+
onAutoRefreshFailed?: (error: ApiError) => void;
|
|
21
27
|
}
|
|
22
28
|
declare function resolveGatewayUrl(config: ServerConfig): string;
|
|
23
29
|
declare class ScaleMuleServer {
|
|
24
30
|
private apiKey;
|
|
25
31
|
private gatewayUrl;
|
|
26
32
|
private debug;
|
|
33
|
+
private onRefreshStart?;
|
|
34
|
+
private onRefreshEnd?;
|
|
35
|
+
private onAutoRefreshFailed?;
|
|
27
36
|
money: MoneyClient;
|
|
28
37
|
constructor(config: ServerConfig);
|
|
29
38
|
moneyWithSession(sessionToken: string): MoneyClient;
|
|
@@ -55,15 +64,23 @@ declare class ScaleMuleServer {
|
|
|
55
64
|
/**
|
|
56
65
|
* Logout user
|
|
57
66
|
*/
|
|
58
|
-
logout: (sessionToken: string
|
|
67
|
+
logout: (sessionToken: string, options?: {
|
|
68
|
+
onTokenRotated?: (newToken: string) => void;
|
|
69
|
+
}) => Promise<void>;
|
|
59
70
|
/**
|
|
60
71
|
* Get current user from session token
|
|
61
72
|
*/
|
|
62
|
-
me: (sessionToken: string
|
|
73
|
+
me: (sessionToken: string, options?: {
|
|
74
|
+
onTokenRotated?: (newToken: string) => void;
|
|
75
|
+
}) => Promise<User>;
|
|
63
76
|
/**
|
|
64
77
|
* Refresh session token
|
|
65
78
|
*/
|
|
66
|
-
refresh: (sessionToken: string
|
|
79
|
+
refresh: (sessionToken: string, options?: {
|
|
80
|
+
clientContext?: ClientContext;
|
|
81
|
+
isAutoRefresh?: boolean;
|
|
82
|
+
onTokenRotated?: (newToken: string) => void;
|
|
83
|
+
}) => Promise<{
|
|
67
84
|
session_token: string;
|
|
68
85
|
expires_at: string;
|
|
69
86
|
}>;
|
|
@@ -99,6 +116,7 @@ declare class ScaleMuleServer {
|
|
|
99
116
|
*/
|
|
100
117
|
resendVerification: (sessionTokenOrEmail: string, options?: {
|
|
101
118
|
email?: string;
|
|
119
|
+
onTokenRotated?: (newToken: string) => void;
|
|
102
120
|
}) => Promise<{
|
|
103
121
|
message: string;
|
|
104
122
|
}>;
|
|
@@ -110,23 +128,31 @@ declare class ScaleMuleServer {
|
|
|
110
128
|
update: (sessionToken: string, data: {
|
|
111
129
|
full_name?: string;
|
|
112
130
|
avatar_url?: string;
|
|
131
|
+
}, options?: {
|
|
132
|
+
onTokenRotated?: (newToken: string) => void;
|
|
113
133
|
}) => Promise<User>;
|
|
114
134
|
/**
|
|
115
135
|
* Change password
|
|
116
136
|
*/
|
|
117
|
-
changePassword: (sessionToken: string, currentPassword: string, newPassword: string
|
|
137
|
+
changePassword: (sessionToken: string, currentPassword: string, newPassword: string, options?: {
|
|
138
|
+
onTokenRotated?: (newToken: string) => void;
|
|
139
|
+
}) => Promise<{
|
|
118
140
|
message: string;
|
|
119
141
|
}>;
|
|
120
142
|
/**
|
|
121
143
|
* Change email
|
|
122
144
|
*/
|
|
123
|
-
changeEmail: (sessionToken: string, newEmail: string, password: string
|
|
145
|
+
changeEmail: (sessionToken: string, newEmail: string, password: string, options?: {
|
|
146
|
+
onTokenRotated?: (newToken: string) => void;
|
|
147
|
+
}) => Promise<{
|
|
124
148
|
message: string;
|
|
125
149
|
}>;
|
|
126
150
|
/**
|
|
127
151
|
* Delete account
|
|
128
152
|
*/
|
|
129
|
-
deleteAccount: (sessionToken: string, password: string
|
|
153
|
+
deleteAccount: (sessionToken: string, password: string, options?: {
|
|
154
|
+
onTokenRotated?: (newToken: string) => void;
|
|
155
|
+
}) => Promise<{
|
|
130
156
|
message: string;
|
|
131
157
|
}>;
|
|
132
158
|
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { MoneyClient } from '@scalemule/money';
|
|
2
|
-
import { $ as RegisterRequest, p as ClientContext, U as User, v as LoginRequest, L as LoginResponse, c as ListFilesParams, t as ListFilesResponse, a9 as StorageFile, af as UploadResponse } from './index-DTWyUcyd.mjs';
|
|
2
|
+
import { A as ApiError, $ as RegisterRequest, p as ClientContext, U as User, v as LoginRequest, L as LoginResponse, c as ListFilesParams, t as ListFilesResponse, a9 as StorageFile, af as UploadResponse } from './index-DTWyUcyd.mjs';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Server-Side ScaleMule Client
|
|
@@ -18,12 +18,21 @@ interface ServerConfig {
|
|
|
18
18
|
gatewayUrl?: string;
|
|
19
19
|
/** Enable debug logging */
|
|
20
20
|
debug?: boolean;
|
|
21
|
+
/** Callback when a 401 auto-refresh starts */
|
|
22
|
+
onRefreshStart?: () => void;
|
|
23
|
+
/** Callback when a 401 auto-refresh finishes */
|
|
24
|
+
onRefreshEnd?: () => void;
|
|
25
|
+
/** Callback when a 401 auto-refresh fails */
|
|
26
|
+
onAutoRefreshFailed?: (error: ApiError) => void;
|
|
21
27
|
}
|
|
22
28
|
declare function resolveGatewayUrl(config: ServerConfig): string;
|
|
23
29
|
declare class ScaleMuleServer {
|
|
24
30
|
private apiKey;
|
|
25
31
|
private gatewayUrl;
|
|
26
32
|
private debug;
|
|
33
|
+
private onRefreshStart?;
|
|
34
|
+
private onRefreshEnd?;
|
|
35
|
+
private onAutoRefreshFailed?;
|
|
27
36
|
money: MoneyClient;
|
|
28
37
|
constructor(config: ServerConfig);
|
|
29
38
|
moneyWithSession(sessionToken: string): MoneyClient;
|
|
@@ -55,15 +64,23 @@ declare class ScaleMuleServer {
|
|
|
55
64
|
/**
|
|
56
65
|
* Logout user
|
|
57
66
|
*/
|
|
58
|
-
logout: (sessionToken: string
|
|
67
|
+
logout: (sessionToken: string, options?: {
|
|
68
|
+
onTokenRotated?: (newToken: string) => void;
|
|
69
|
+
}) => Promise<void>;
|
|
59
70
|
/**
|
|
60
71
|
* Get current user from session token
|
|
61
72
|
*/
|
|
62
|
-
me: (sessionToken: string
|
|
73
|
+
me: (sessionToken: string, options?: {
|
|
74
|
+
onTokenRotated?: (newToken: string) => void;
|
|
75
|
+
}) => Promise<User>;
|
|
63
76
|
/**
|
|
64
77
|
* Refresh session token
|
|
65
78
|
*/
|
|
66
|
-
refresh: (sessionToken: string
|
|
79
|
+
refresh: (sessionToken: string, options?: {
|
|
80
|
+
clientContext?: ClientContext;
|
|
81
|
+
isAutoRefresh?: boolean;
|
|
82
|
+
onTokenRotated?: (newToken: string) => void;
|
|
83
|
+
}) => Promise<{
|
|
67
84
|
session_token: string;
|
|
68
85
|
expires_at: string;
|
|
69
86
|
}>;
|
|
@@ -99,6 +116,7 @@ declare class ScaleMuleServer {
|
|
|
99
116
|
*/
|
|
100
117
|
resendVerification: (sessionTokenOrEmail: string, options?: {
|
|
101
118
|
email?: string;
|
|
119
|
+
onTokenRotated?: (newToken: string) => void;
|
|
102
120
|
}) => Promise<{
|
|
103
121
|
message: string;
|
|
104
122
|
}>;
|
|
@@ -110,23 +128,31 @@ declare class ScaleMuleServer {
|
|
|
110
128
|
update: (sessionToken: string, data: {
|
|
111
129
|
full_name?: string;
|
|
112
130
|
avatar_url?: string;
|
|
131
|
+
}, options?: {
|
|
132
|
+
onTokenRotated?: (newToken: string) => void;
|
|
113
133
|
}) => Promise<User>;
|
|
114
134
|
/**
|
|
115
135
|
* Change password
|
|
116
136
|
*/
|
|
117
|
-
changePassword: (sessionToken: string, currentPassword: string, newPassword: string
|
|
137
|
+
changePassword: (sessionToken: string, currentPassword: string, newPassword: string, options?: {
|
|
138
|
+
onTokenRotated?: (newToken: string) => void;
|
|
139
|
+
}) => Promise<{
|
|
118
140
|
message: string;
|
|
119
141
|
}>;
|
|
120
142
|
/**
|
|
121
143
|
* Change email
|
|
122
144
|
*/
|
|
123
|
-
changeEmail: (sessionToken: string, newEmail: string, password: string
|
|
145
|
+
changeEmail: (sessionToken: string, newEmail: string, password: string, options?: {
|
|
146
|
+
onTokenRotated?: (newToken: string) => void;
|
|
147
|
+
}) => Promise<{
|
|
124
148
|
message: string;
|
|
125
149
|
}>;
|
|
126
150
|
/**
|
|
127
151
|
* Delete account
|
|
128
152
|
*/
|
|
129
|
-
deleteAccount: (sessionToken: string, password: string
|
|
153
|
+
deleteAccount: (sessionToken: string, password: string, options?: {
|
|
154
|
+
onTokenRotated?: (newToken: string) => void;
|
|
155
|
+
}) => Promise<{
|
|
130
156
|
message: string;
|
|
131
157
|
}>;
|
|
132
158
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@scalemule/nextjs",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.18",
|
|
4
4
|
"description": "ScaleMule SDK for Next.js applications - authentication, storage, and user management",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
@@ -60,7 +60,7 @@
|
|
|
60
60
|
"dependencies": {
|
|
61
61
|
"@scalemule/ledvery": "^0.0.1",
|
|
62
62
|
"@scalemule/money": "^0.0.1",
|
|
63
|
-
"@scalemule/sdk": "^0.0.
|
|
63
|
+
"@scalemule/sdk": "^0.0.48"
|
|
64
64
|
},
|
|
65
65
|
"peerDependencies": {
|
|
66
66
|
"next": ">=14.0.0",
|