@scalemule/nextjs 0.1.37 → 0.1.39
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/server/auth.js +81 -60
- package/dist/server/auth.mjs +82 -61
- package/dist/server/index.js +123 -98
- package/dist/server/index.mjs +123 -98
- package/package.json +2 -2
package/dist/server/auth.js
CHANGED
|
@@ -29,40 +29,40 @@ function validateIP(ip) {
|
|
|
29
29
|
return void 0;
|
|
30
30
|
}
|
|
31
31
|
function extractClientContext(request) {
|
|
32
|
-
const
|
|
32
|
+
const headers2 = request.headers;
|
|
33
33
|
let ip;
|
|
34
|
-
const cfConnectingIp =
|
|
34
|
+
const cfConnectingIp = headers2.get("cf-connecting-ip");
|
|
35
35
|
if (cfConnectingIp) {
|
|
36
36
|
ip = validateIP(cfConnectingIp);
|
|
37
37
|
}
|
|
38
38
|
if (!ip) {
|
|
39
|
-
const doConnectingIp =
|
|
39
|
+
const doConnectingIp = headers2.get("do-connecting-ip");
|
|
40
40
|
if (doConnectingIp) {
|
|
41
41
|
ip = validateIP(doConnectingIp);
|
|
42
42
|
}
|
|
43
43
|
}
|
|
44
44
|
if (!ip) {
|
|
45
|
-
const realIp =
|
|
45
|
+
const realIp = headers2.get("x-real-ip");
|
|
46
46
|
if (realIp) {
|
|
47
47
|
ip = validateIP(realIp);
|
|
48
48
|
}
|
|
49
49
|
}
|
|
50
50
|
if (!ip) {
|
|
51
|
-
const forwardedFor =
|
|
51
|
+
const forwardedFor = headers2.get("x-forwarded-for");
|
|
52
52
|
if (forwardedFor) {
|
|
53
53
|
const firstIp = forwardedFor.split(",")[0]?.trim();
|
|
54
54
|
ip = validateIP(firstIp);
|
|
55
55
|
}
|
|
56
56
|
}
|
|
57
57
|
if (!ip) {
|
|
58
|
-
const vercelForwarded =
|
|
58
|
+
const vercelForwarded = headers2.get("x-vercel-forwarded-for");
|
|
59
59
|
if (vercelForwarded) {
|
|
60
60
|
const firstIp = vercelForwarded.split(",")[0]?.trim();
|
|
61
61
|
ip = validateIP(firstIp);
|
|
62
62
|
}
|
|
63
63
|
}
|
|
64
64
|
if (!ip) {
|
|
65
|
-
const trueClientIp =
|
|
65
|
+
const trueClientIp = headers2.get("true-client-ip");
|
|
66
66
|
if (trueClientIp) {
|
|
67
67
|
ip = validateIP(trueClientIp);
|
|
68
68
|
}
|
|
@@ -70,10 +70,10 @@ function extractClientContext(request) {
|
|
|
70
70
|
if (!ip && request.ip) {
|
|
71
71
|
ip = validateIP(request.ip);
|
|
72
72
|
}
|
|
73
|
-
const userAgent =
|
|
74
|
-
const deviceFingerprint =
|
|
75
|
-
const referrer =
|
|
76
|
-
const anonymousId =
|
|
73
|
+
const userAgent = headers2.get("user-agent") || void 0;
|
|
74
|
+
const deviceFingerprint = headers2.get("x-device-fingerprint") || void 0;
|
|
75
|
+
const referrer = headers2.get("referer") || void 0;
|
|
76
|
+
const anonymousId = headers2.get("x-anonymous-id") || void 0;
|
|
77
77
|
return {
|
|
78
78
|
ip,
|
|
79
79
|
userAgent,
|
|
@@ -83,27 +83,27 @@ function extractClientContext(request) {
|
|
|
83
83
|
};
|
|
84
84
|
}
|
|
85
85
|
function buildClientContextHeaders(context) {
|
|
86
|
-
const
|
|
86
|
+
const headers2 = {};
|
|
87
87
|
if (!context) {
|
|
88
|
-
return
|
|
88
|
+
return headers2;
|
|
89
89
|
}
|
|
90
90
|
if (context.ip) {
|
|
91
|
-
|
|
92
|
-
|
|
91
|
+
headers2["x-sm-forwarded-client-ip"] = context.ip;
|
|
92
|
+
headers2["X-Client-IP"] = context.ip;
|
|
93
93
|
}
|
|
94
94
|
if (context.userAgent) {
|
|
95
|
-
|
|
95
|
+
headers2["X-Client-User-Agent"] = context.userAgent;
|
|
96
96
|
}
|
|
97
97
|
if (context.deviceFingerprint) {
|
|
98
|
-
|
|
98
|
+
headers2["X-Client-Device-Fingerprint"] = context.deviceFingerprint;
|
|
99
99
|
}
|
|
100
100
|
if (context.referrer) {
|
|
101
|
-
|
|
101
|
+
headers2["X-Client-Referrer"] = context.referrer;
|
|
102
102
|
}
|
|
103
103
|
if (context.anonymousId) {
|
|
104
|
-
|
|
104
|
+
headers2["x-anonymous-id"] = context.anonymousId;
|
|
105
105
|
}
|
|
106
|
-
return
|
|
106
|
+
return headers2;
|
|
107
107
|
}
|
|
108
108
|
|
|
109
109
|
// src/server/client.ts
|
|
@@ -114,6 +114,7 @@ var GATEWAY_URLS = {
|
|
|
114
114
|
function resolveGatewayUrl(config) {
|
|
115
115
|
if (config.gatewayUrl) return config.gatewayUrl;
|
|
116
116
|
if (process.env.SCALEMULE_API_URL) return process.env.SCALEMULE_API_URL;
|
|
117
|
+
if (process.env.SCALEMULE_GATEWAY_URL) return process.env.SCALEMULE_GATEWAY_URL;
|
|
117
118
|
return GATEWAY_URLS[config.environment || "prod"];
|
|
118
119
|
}
|
|
119
120
|
var ScaleMuleServer = class {
|
|
@@ -502,7 +503,7 @@ var ScaleMuleServer = class {
|
|
|
502
503
|
formData.append("file", blob, file.filename);
|
|
503
504
|
formData.append("sm_user_id", userId);
|
|
504
505
|
const url = `${this.gatewayUrl}/v1/storage/upload`;
|
|
505
|
-
const
|
|
506
|
+
const headers2 = {
|
|
506
507
|
"x-api-key": this.apiKey,
|
|
507
508
|
"x-user-id": userId,
|
|
508
509
|
...buildClientContextHeaders(options?.clientContext)
|
|
@@ -513,7 +514,7 @@ var ScaleMuleServer = class {
|
|
|
513
514
|
try {
|
|
514
515
|
const response = await fetch(url, {
|
|
515
516
|
method: "POST",
|
|
516
|
-
headers,
|
|
517
|
+
headers: headers2,
|
|
517
518
|
body: formData
|
|
518
519
|
});
|
|
519
520
|
const text = await response.text();
|
|
@@ -735,14 +736,14 @@ var ScaleMuleServer = class {
|
|
|
735
736
|
*/
|
|
736
737
|
async request(method, path, options = {}) {
|
|
737
738
|
const url = `${this.gatewayUrl}${path}`;
|
|
738
|
-
const
|
|
739
|
+
const headers2 = {
|
|
739
740
|
"x-api-key": this.apiKey,
|
|
740
741
|
"Content-Type": "application/json",
|
|
741
742
|
// Forward client context headers if provided
|
|
742
743
|
...buildClientContextHeaders(options.clientContext)
|
|
743
744
|
};
|
|
744
745
|
if (options.sessionToken) {
|
|
745
|
-
|
|
746
|
+
headers2["Authorization"] = `Bearer ${options.sessionToken}`;
|
|
746
747
|
}
|
|
747
748
|
if (this.debug) {
|
|
748
749
|
console.log(`[ScaleMule Server] ${method} ${path}`);
|
|
@@ -753,7 +754,7 @@ var ScaleMuleServer = class {
|
|
|
753
754
|
try {
|
|
754
755
|
const response = await fetch(url, {
|
|
755
756
|
method,
|
|
756
|
-
headers,
|
|
757
|
+
headers: headers2,
|
|
757
758
|
body: options.body ? JSON.stringify(options.body) : void 0
|
|
758
759
|
});
|
|
759
760
|
const rotated = response.headers.get("x-rotated-session-token");
|
|
@@ -849,66 +850,86 @@ function createCookieHeader(name, value, options = {}) {
|
|
|
849
850
|
}
|
|
850
851
|
function createClearCookieHeader(name, options = {}) {
|
|
851
852
|
const path = options.path ?? "/";
|
|
852
|
-
|
|
853
|
+
const secure = options.secure ?? process.env.NODE_ENV === "production";
|
|
854
|
+
const sameSite = options.sameSite ?? "lax";
|
|
855
|
+
let cookie = `${name}=; Path=${path}; Max-Age=0; HttpOnly; SameSite=${sameSite}`;
|
|
856
|
+
if (secure) {
|
|
857
|
+
cookie += "; Secure";
|
|
858
|
+
}
|
|
853
859
|
if (options.domain) {
|
|
854
860
|
cookie += `; Domain=${options.domain}`;
|
|
855
861
|
}
|
|
856
862
|
return cookie;
|
|
857
863
|
}
|
|
858
864
|
function withSession(loginResponse, responseBody, options = {}) {
|
|
859
|
-
const
|
|
860
|
-
|
|
861
|
-
|
|
865
|
+
const headers2 = new Headers();
|
|
866
|
+
headers2.set("Content-Type", "application/json");
|
|
867
|
+
headers2.append(
|
|
862
868
|
"Set-Cookie",
|
|
863
869
|
createCookieHeader(SESSION_COOKIE_NAME, loginResponse.session_token, options)
|
|
864
870
|
);
|
|
865
|
-
|
|
871
|
+
headers2.append(
|
|
866
872
|
"Set-Cookie",
|
|
867
873
|
createCookieHeader(USER_ID_COOKIE_NAME, loginResponse.user.id, options)
|
|
868
874
|
);
|
|
869
875
|
return new Response(JSON.stringify({ success: true, data: responseBody }), {
|
|
870
876
|
status: 200,
|
|
871
|
-
headers
|
|
877
|
+
headers: headers2
|
|
872
878
|
});
|
|
873
879
|
}
|
|
874
880
|
function withRefreshedSession(sessionToken, userId, responseBody, options = {}) {
|
|
875
|
-
const
|
|
876
|
-
|
|
877
|
-
|
|
881
|
+
const headers2 = new Headers();
|
|
882
|
+
headers2.set("Content-Type", "application/json");
|
|
883
|
+
headers2.append(
|
|
878
884
|
"Set-Cookie",
|
|
879
885
|
createCookieHeader(SESSION_COOKIE_NAME, sessionToken, options)
|
|
880
886
|
);
|
|
881
|
-
|
|
887
|
+
headers2.append(
|
|
882
888
|
"Set-Cookie",
|
|
883
889
|
createCookieHeader(USER_ID_COOKIE_NAME, userId, options)
|
|
884
890
|
);
|
|
885
891
|
return new Response(JSON.stringify({ success: true, data: responseBody }), {
|
|
886
892
|
status: 200,
|
|
887
|
-
headers
|
|
893
|
+
headers: headers2
|
|
888
894
|
});
|
|
889
895
|
}
|
|
890
896
|
function clearSession(responseBody, options = {}, status = 200) {
|
|
891
|
-
const
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
897
|
+
const headers2 = new Headers();
|
|
898
|
+
headers2.set("Content-Type", "application/json");
|
|
899
|
+
headers2.append("Set-Cookie", createClearCookieHeader(SESSION_COOKIE_NAME, options));
|
|
900
|
+
headers2.append("Set-Cookie", createClearCookieHeader(USER_ID_COOKIE_NAME, options));
|
|
895
901
|
return new Response(JSON.stringify({ success: status < 300, data: responseBody }), {
|
|
896
902
|
status,
|
|
897
|
-
headers
|
|
903
|
+
headers: headers2
|
|
898
904
|
});
|
|
899
905
|
}
|
|
900
906
|
async function getSession() {
|
|
901
907
|
const cookieStore = await headers.cookies();
|
|
902
908
|
const sessionCookie = cookieStore.get(SESSION_COOKIE_NAME);
|
|
903
909
|
const userIdCookie = cookieStore.get(USER_ID_COOKIE_NAME);
|
|
904
|
-
if (
|
|
905
|
-
return
|
|
910
|
+
if (sessionCookie?.value && userIdCookie?.value) {
|
|
911
|
+
return {
|
|
912
|
+
sessionToken: sessionCookie.value,
|
|
913
|
+
userId: userIdCookie.value,
|
|
914
|
+
expiresAt: /* @__PURE__ */ new Date()
|
|
915
|
+
// Note: actual expiry is managed by ScaleMule backend
|
|
916
|
+
};
|
|
906
917
|
}
|
|
918
|
+
const headerStore = await headers.headers();
|
|
919
|
+
return sessionFromAuthHeaders(
|
|
920
|
+
headerStore.get("authorization"),
|
|
921
|
+
headerStore.get("x-sm-user-id")
|
|
922
|
+
);
|
|
923
|
+
}
|
|
924
|
+
function sessionFromAuthHeaders(authorization, userId) {
|
|
925
|
+
if (!authorization || !userId) return null;
|
|
926
|
+
const match = /^Bearer\s+(.+)$/i.exec(authorization.trim());
|
|
927
|
+
const token = match?.[1]?.trim();
|
|
928
|
+
if (!token) return null;
|
|
907
929
|
return {
|
|
908
|
-
sessionToken:
|
|
909
|
-
userId
|
|
930
|
+
sessionToken: token,
|
|
931
|
+
userId,
|
|
910
932
|
expiresAt: /* @__PURE__ */ new Date()
|
|
911
|
-
// Note: actual expiry is managed by ScaleMule backend
|
|
912
933
|
};
|
|
913
934
|
}
|
|
914
935
|
var MAX_KNOWN_ACCOUNTS = 10;
|
|
@@ -950,7 +971,7 @@ function applyPrivacyToEntry(entry, privacy) {
|
|
|
950
971
|
};
|
|
951
972
|
}
|
|
952
973
|
}
|
|
953
|
-
function appendKnownAccountCookie(
|
|
974
|
+
function appendKnownAccountCookie(headers2, account, existingCookie, options = {}, privacy) {
|
|
954
975
|
let accounts = {};
|
|
955
976
|
if (existingCookie) {
|
|
956
977
|
try {
|
|
@@ -979,9 +1000,9 @@ function appendKnownAccountCookie(headers, account, existingCookie, options = {}
|
|
|
979
1000
|
if (options.domain) {
|
|
980
1001
|
cookie += `; Domain=${options.domain}`;
|
|
981
1002
|
}
|
|
982
|
-
|
|
1003
|
+
headers2.append("Set-Cookie", cookie);
|
|
983
1004
|
}
|
|
984
|
-
function removeKnownAccountFromCookie(
|
|
1005
|
+
function removeKnownAccountFromCookie(headers2, userId, existingCookie, options = {}) {
|
|
985
1006
|
let accounts = {};
|
|
986
1007
|
if (existingCookie) {
|
|
987
1008
|
try {
|
|
@@ -1001,15 +1022,15 @@ function removeKnownAccountFromCookie(headers, userId, existingCookie, options =
|
|
|
1001
1022
|
if (options.domain) {
|
|
1002
1023
|
cookie += `; Domain=${options.domain}`;
|
|
1003
1024
|
}
|
|
1004
|
-
|
|
1025
|
+
headers2.append("Set-Cookie", cookie);
|
|
1005
1026
|
}
|
|
1006
|
-
function clearKnownAccountsCookie(
|
|
1027
|
+
function clearKnownAccountsCookie(headers2, options = {}) {
|
|
1007
1028
|
const path = options.path ?? "/";
|
|
1008
1029
|
let cookie = `${KNOWN_ACCOUNTS_COOKIE_NAME}=; Path=${path}; Max-Age=0`;
|
|
1009
1030
|
if (options.domain) {
|
|
1010
1031
|
cookie += `; Domain=${options.domain}`;
|
|
1011
1032
|
}
|
|
1012
|
-
|
|
1033
|
+
headers2.append("Set-Cookie", cookie);
|
|
1013
1034
|
}
|
|
1014
1035
|
function getKnownAccountsFromRequest(request) {
|
|
1015
1036
|
const cookieHeader = request.headers.get("cookie");
|
|
@@ -1434,13 +1455,13 @@ function createAuthRoutes(config = {}) {
|
|
|
1434
1455
|
if (!user_id) {
|
|
1435
1456
|
return errorResponse("VALIDATION_ERROR", "user_id required", 400);
|
|
1436
1457
|
}
|
|
1437
|
-
const
|
|
1438
|
-
|
|
1458
|
+
const headers2 = new Headers();
|
|
1459
|
+
headers2.set("Content-Type", "application/json");
|
|
1439
1460
|
const existingKnown = getKnownAccountsCookieRaw(request);
|
|
1440
|
-
removeKnownAccountFromCookie(
|
|
1461
|
+
removeKnownAccountFromCookie(headers2, user_id, existingKnown, cookieOptions);
|
|
1441
1462
|
return new Response(
|
|
1442
1463
|
JSON.stringify({ success: true, data: { message: "Account forgotten" } }),
|
|
1443
|
-
{ status: 200, headers }
|
|
1464
|
+
{ status: 200, headers: headers2 }
|
|
1444
1465
|
);
|
|
1445
1466
|
}
|
|
1446
1467
|
// ==================== Forget All Accounts ====================
|
|
@@ -1448,12 +1469,12 @@ function createAuthRoutes(config = {}) {
|
|
|
1448
1469
|
if (!config.enableAccountSwitcher) {
|
|
1449
1470
|
return errorResponse("NOT_FOUND", "Account switcher not enabled", 404);
|
|
1450
1471
|
}
|
|
1451
|
-
const
|
|
1452
|
-
|
|
1453
|
-
clearKnownAccountsCookie(
|
|
1472
|
+
const headers2 = new Headers();
|
|
1473
|
+
headers2.set("Content-Type", "application/json");
|
|
1474
|
+
clearKnownAccountsCookie(headers2, cookieOptions);
|
|
1454
1475
|
return new Response(
|
|
1455
1476
|
JSON.stringify({ success: true, data: { message: "All accounts forgotten" } }),
|
|
1456
|
-
{ status: 200, headers }
|
|
1477
|
+
{ status: 200, headers: headers2 }
|
|
1457
1478
|
);
|
|
1458
1479
|
}
|
|
1459
1480
|
default:
|
package/dist/server/auth.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createMoneyClient } from '@scalemule/money';
|
|
2
|
-
import { cookies } from 'next/headers';
|
|
2
|
+
import { cookies, headers } from 'next/headers';
|
|
3
3
|
import 'next/server';
|
|
4
4
|
|
|
5
5
|
// src/types/index.ts
|
|
@@ -27,40 +27,40 @@ function validateIP(ip) {
|
|
|
27
27
|
return void 0;
|
|
28
28
|
}
|
|
29
29
|
function extractClientContext(request) {
|
|
30
|
-
const
|
|
30
|
+
const headers2 = request.headers;
|
|
31
31
|
let ip;
|
|
32
|
-
const cfConnectingIp =
|
|
32
|
+
const cfConnectingIp = headers2.get("cf-connecting-ip");
|
|
33
33
|
if (cfConnectingIp) {
|
|
34
34
|
ip = validateIP(cfConnectingIp);
|
|
35
35
|
}
|
|
36
36
|
if (!ip) {
|
|
37
|
-
const doConnectingIp =
|
|
37
|
+
const doConnectingIp = headers2.get("do-connecting-ip");
|
|
38
38
|
if (doConnectingIp) {
|
|
39
39
|
ip = validateIP(doConnectingIp);
|
|
40
40
|
}
|
|
41
41
|
}
|
|
42
42
|
if (!ip) {
|
|
43
|
-
const realIp =
|
|
43
|
+
const realIp = headers2.get("x-real-ip");
|
|
44
44
|
if (realIp) {
|
|
45
45
|
ip = validateIP(realIp);
|
|
46
46
|
}
|
|
47
47
|
}
|
|
48
48
|
if (!ip) {
|
|
49
|
-
const forwardedFor =
|
|
49
|
+
const forwardedFor = headers2.get("x-forwarded-for");
|
|
50
50
|
if (forwardedFor) {
|
|
51
51
|
const firstIp = forwardedFor.split(",")[0]?.trim();
|
|
52
52
|
ip = validateIP(firstIp);
|
|
53
53
|
}
|
|
54
54
|
}
|
|
55
55
|
if (!ip) {
|
|
56
|
-
const vercelForwarded =
|
|
56
|
+
const vercelForwarded = headers2.get("x-vercel-forwarded-for");
|
|
57
57
|
if (vercelForwarded) {
|
|
58
58
|
const firstIp = vercelForwarded.split(",")[0]?.trim();
|
|
59
59
|
ip = validateIP(firstIp);
|
|
60
60
|
}
|
|
61
61
|
}
|
|
62
62
|
if (!ip) {
|
|
63
|
-
const trueClientIp =
|
|
63
|
+
const trueClientIp = headers2.get("true-client-ip");
|
|
64
64
|
if (trueClientIp) {
|
|
65
65
|
ip = validateIP(trueClientIp);
|
|
66
66
|
}
|
|
@@ -68,10 +68,10 @@ function extractClientContext(request) {
|
|
|
68
68
|
if (!ip && request.ip) {
|
|
69
69
|
ip = validateIP(request.ip);
|
|
70
70
|
}
|
|
71
|
-
const userAgent =
|
|
72
|
-
const deviceFingerprint =
|
|
73
|
-
const referrer =
|
|
74
|
-
const anonymousId =
|
|
71
|
+
const userAgent = headers2.get("user-agent") || void 0;
|
|
72
|
+
const deviceFingerprint = headers2.get("x-device-fingerprint") || void 0;
|
|
73
|
+
const referrer = headers2.get("referer") || void 0;
|
|
74
|
+
const anonymousId = headers2.get("x-anonymous-id") || void 0;
|
|
75
75
|
return {
|
|
76
76
|
ip,
|
|
77
77
|
userAgent,
|
|
@@ -81,27 +81,27 @@ function extractClientContext(request) {
|
|
|
81
81
|
};
|
|
82
82
|
}
|
|
83
83
|
function buildClientContextHeaders(context) {
|
|
84
|
-
const
|
|
84
|
+
const headers2 = {};
|
|
85
85
|
if (!context) {
|
|
86
|
-
return
|
|
86
|
+
return headers2;
|
|
87
87
|
}
|
|
88
88
|
if (context.ip) {
|
|
89
|
-
|
|
90
|
-
|
|
89
|
+
headers2["x-sm-forwarded-client-ip"] = context.ip;
|
|
90
|
+
headers2["X-Client-IP"] = context.ip;
|
|
91
91
|
}
|
|
92
92
|
if (context.userAgent) {
|
|
93
|
-
|
|
93
|
+
headers2["X-Client-User-Agent"] = context.userAgent;
|
|
94
94
|
}
|
|
95
95
|
if (context.deviceFingerprint) {
|
|
96
|
-
|
|
96
|
+
headers2["X-Client-Device-Fingerprint"] = context.deviceFingerprint;
|
|
97
97
|
}
|
|
98
98
|
if (context.referrer) {
|
|
99
|
-
|
|
99
|
+
headers2["X-Client-Referrer"] = context.referrer;
|
|
100
100
|
}
|
|
101
101
|
if (context.anonymousId) {
|
|
102
|
-
|
|
102
|
+
headers2["x-anonymous-id"] = context.anonymousId;
|
|
103
103
|
}
|
|
104
|
-
return
|
|
104
|
+
return headers2;
|
|
105
105
|
}
|
|
106
106
|
|
|
107
107
|
// src/server/client.ts
|
|
@@ -112,6 +112,7 @@ var GATEWAY_URLS = {
|
|
|
112
112
|
function resolveGatewayUrl(config) {
|
|
113
113
|
if (config.gatewayUrl) return config.gatewayUrl;
|
|
114
114
|
if (process.env.SCALEMULE_API_URL) return process.env.SCALEMULE_API_URL;
|
|
115
|
+
if (process.env.SCALEMULE_GATEWAY_URL) return process.env.SCALEMULE_GATEWAY_URL;
|
|
115
116
|
return GATEWAY_URLS[config.environment || "prod"];
|
|
116
117
|
}
|
|
117
118
|
var ScaleMuleServer = class {
|
|
@@ -500,7 +501,7 @@ var ScaleMuleServer = class {
|
|
|
500
501
|
formData.append("file", blob, file.filename);
|
|
501
502
|
formData.append("sm_user_id", userId);
|
|
502
503
|
const url = `${this.gatewayUrl}/v1/storage/upload`;
|
|
503
|
-
const
|
|
504
|
+
const headers2 = {
|
|
504
505
|
"x-api-key": this.apiKey,
|
|
505
506
|
"x-user-id": userId,
|
|
506
507
|
...buildClientContextHeaders(options?.clientContext)
|
|
@@ -511,7 +512,7 @@ var ScaleMuleServer = class {
|
|
|
511
512
|
try {
|
|
512
513
|
const response = await fetch(url, {
|
|
513
514
|
method: "POST",
|
|
514
|
-
headers,
|
|
515
|
+
headers: headers2,
|
|
515
516
|
body: formData
|
|
516
517
|
});
|
|
517
518
|
const text = await response.text();
|
|
@@ -733,14 +734,14 @@ var ScaleMuleServer = class {
|
|
|
733
734
|
*/
|
|
734
735
|
async request(method, path, options = {}) {
|
|
735
736
|
const url = `${this.gatewayUrl}${path}`;
|
|
736
|
-
const
|
|
737
|
+
const headers2 = {
|
|
737
738
|
"x-api-key": this.apiKey,
|
|
738
739
|
"Content-Type": "application/json",
|
|
739
740
|
// Forward client context headers if provided
|
|
740
741
|
...buildClientContextHeaders(options.clientContext)
|
|
741
742
|
};
|
|
742
743
|
if (options.sessionToken) {
|
|
743
|
-
|
|
744
|
+
headers2["Authorization"] = `Bearer ${options.sessionToken}`;
|
|
744
745
|
}
|
|
745
746
|
if (this.debug) {
|
|
746
747
|
console.log(`[ScaleMule Server] ${method} ${path}`);
|
|
@@ -751,7 +752,7 @@ var ScaleMuleServer = class {
|
|
|
751
752
|
try {
|
|
752
753
|
const response = await fetch(url, {
|
|
753
754
|
method,
|
|
754
|
-
headers,
|
|
755
|
+
headers: headers2,
|
|
755
756
|
body: options.body ? JSON.stringify(options.body) : void 0
|
|
756
757
|
});
|
|
757
758
|
const rotated = response.headers.get("x-rotated-session-token");
|
|
@@ -847,66 +848,86 @@ function createCookieHeader(name, value, options = {}) {
|
|
|
847
848
|
}
|
|
848
849
|
function createClearCookieHeader(name, options = {}) {
|
|
849
850
|
const path = options.path ?? "/";
|
|
850
|
-
|
|
851
|
+
const secure = options.secure ?? process.env.NODE_ENV === "production";
|
|
852
|
+
const sameSite = options.sameSite ?? "lax";
|
|
853
|
+
let cookie = `${name}=; Path=${path}; Max-Age=0; HttpOnly; SameSite=${sameSite}`;
|
|
854
|
+
if (secure) {
|
|
855
|
+
cookie += "; Secure";
|
|
856
|
+
}
|
|
851
857
|
if (options.domain) {
|
|
852
858
|
cookie += `; Domain=${options.domain}`;
|
|
853
859
|
}
|
|
854
860
|
return cookie;
|
|
855
861
|
}
|
|
856
862
|
function withSession(loginResponse, responseBody, options = {}) {
|
|
857
|
-
const
|
|
858
|
-
|
|
859
|
-
|
|
863
|
+
const headers2 = new Headers();
|
|
864
|
+
headers2.set("Content-Type", "application/json");
|
|
865
|
+
headers2.append(
|
|
860
866
|
"Set-Cookie",
|
|
861
867
|
createCookieHeader(SESSION_COOKIE_NAME, loginResponse.session_token, options)
|
|
862
868
|
);
|
|
863
|
-
|
|
869
|
+
headers2.append(
|
|
864
870
|
"Set-Cookie",
|
|
865
871
|
createCookieHeader(USER_ID_COOKIE_NAME, loginResponse.user.id, options)
|
|
866
872
|
);
|
|
867
873
|
return new Response(JSON.stringify({ success: true, data: responseBody }), {
|
|
868
874
|
status: 200,
|
|
869
|
-
headers
|
|
875
|
+
headers: headers2
|
|
870
876
|
});
|
|
871
877
|
}
|
|
872
878
|
function withRefreshedSession(sessionToken, userId, responseBody, options = {}) {
|
|
873
|
-
const
|
|
874
|
-
|
|
875
|
-
|
|
879
|
+
const headers2 = new Headers();
|
|
880
|
+
headers2.set("Content-Type", "application/json");
|
|
881
|
+
headers2.append(
|
|
876
882
|
"Set-Cookie",
|
|
877
883
|
createCookieHeader(SESSION_COOKIE_NAME, sessionToken, options)
|
|
878
884
|
);
|
|
879
|
-
|
|
885
|
+
headers2.append(
|
|
880
886
|
"Set-Cookie",
|
|
881
887
|
createCookieHeader(USER_ID_COOKIE_NAME, userId, options)
|
|
882
888
|
);
|
|
883
889
|
return new Response(JSON.stringify({ success: true, data: responseBody }), {
|
|
884
890
|
status: 200,
|
|
885
|
-
headers
|
|
891
|
+
headers: headers2
|
|
886
892
|
});
|
|
887
893
|
}
|
|
888
894
|
function clearSession(responseBody, options = {}, status = 200) {
|
|
889
|
-
const
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
895
|
+
const headers2 = new Headers();
|
|
896
|
+
headers2.set("Content-Type", "application/json");
|
|
897
|
+
headers2.append("Set-Cookie", createClearCookieHeader(SESSION_COOKIE_NAME, options));
|
|
898
|
+
headers2.append("Set-Cookie", createClearCookieHeader(USER_ID_COOKIE_NAME, options));
|
|
893
899
|
return new Response(JSON.stringify({ success: status < 300, data: responseBody }), {
|
|
894
900
|
status,
|
|
895
|
-
headers
|
|
901
|
+
headers: headers2
|
|
896
902
|
});
|
|
897
903
|
}
|
|
898
904
|
async function getSession() {
|
|
899
905
|
const cookieStore = await cookies();
|
|
900
906
|
const sessionCookie = cookieStore.get(SESSION_COOKIE_NAME);
|
|
901
907
|
const userIdCookie = cookieStore.get(USER_ID_COOKIE_NAME);
|
|
902
|
-
if (
|
|
903
|
-
return
|
|
908
|
+
if (sessionCookie?.value && userIdCookie?.value) {
|
|
909
|
+
return {
|
|
910
|
+
sessionToken: sessionCookie.value,
|
|
911
|
+
userId: userIdCookie.value,
|
|
912
|
+
expiresAt: /* @__PURE__ */ new Date()
|
|
913
|
+
// Note: actual expiry is managed by ScaleMule backend
|
|
914
|
+
};
|
|
904
915
|
}
|
|
916
|
+
const headerStore = await headers();
|
|
917
|
+
return sessionFromAuthHeaders(
|
|
918
|
+
headerStore.get("authorization"),
|
|
919
|
+
headerStore.get("x-sm-user-id")
|
|
920
|
+
);
|
|
921
|
+
}
|
|
922
|
+
function sessionFromAuthHeaders(authorization, userId) {
|
|
923
|
+
if (!authorization || !userId) return null;
|
|
924
|
+
const match = /^Bearer\s+(.+)$/i.exec(authorization.trim());
|
|
925
|
+
const token = match?.[1]?.trim();
|
|
926
|
+
if (!token) return null;
|
|
905
927
|
return {
|
|
906
|
-
sessionToken:
|
|
907
|
-
userId
|
|
928
|
+
sessionToken: token,
|
|
929
|
+
userId,
|
|
908
930
|
expiresAt: /* @__PURE__ */ new Date()
|
|
909
|
-
// Note: actual expiry is managed by ScaleMule backend
|
|
910
931
|
};
|
|
911
932
|
}
|
|
912
933
|
var MAX_KNOWN_ACCOUNTS = 10;
|
|
@@ -948,7 +969,7 @@ function applyPrivacyToEntry(entry, privacy) {
|
|
|
948
969
|
};
|
|
949
970
|
}
|
|
950
971
|
}
|
|
951
|
-
function appendKnownAccountCookie(
|
|
972
|
+
function appendKnownAccountCookie(headers2, account, existingCookie, options = {}, privacy) {
|
|
952
973
|
let accounts = {};
|
|
953
974
|
if (existingCookie) {
|
|
954
975
|
try {
|
|
@@ -977,9 +998,9 @@ function appendKnownAccountCookie(headers, account, existingCookie, options = {}
|
|
|
977
998
|
if (options.domain) {
|
|
978
999
|
cookie += `; Domain=${options.domain}`;
|
|
979
1000
|
}
|
|
980
|
-
|
|
1001
|
+
headers2.append("Set-Cookie", cookie);
|
|
981
1002
|
}
|
|
982
|
-
function removeKnownAccountFromCookie(
|
|
1003
|
+
function removeKnownAccountFromCookie(headers2, userId, existingCookie, options = {}) {
|
|
983
1004
|
let accounts = {};
|
|
984
1005
|
if (existingCookie) {
|
|
985
1006
|
try {
|
|
@@ -999,15 +1020,15 @@ function removeKnownAccountFromCookie(headers, userId, existingCookie, options =
|
|
|
999
1020
|
if (options.domain) {
|
|
1000
1021
|
cookie += `; Domain=${options.domain}`;
|
|
1001
1022
|
}
|
|
1002
|
-
|
|
1023
|
+
headers2.append("Set-Cookie", cookie);
|
|
1003
1024
|
}
|
|
1004
|
-
function clearKnownAccountsCookie(
|
|
1025
|
+
function clearKnownAccountsCookie(headers2, options = {}) {
|
|
1005
1026
|
const path = options.path ?? "/";
|
|
1006
1027
|
let cookie = `${KNOWN_ACCOUNTS_COOKIE_NAME}=; Path=${path}; Max-Age=0`;
|
|
1007
1028
|
if (options.domain) {
|
|
1008
1029
|
cookie += `; Domain=${options.domain}`;
|
|
1009
1030
|
}
|
|
1010
|
-
|
|
1031
|
+
headers2.append("Set-Cookie", cookie);
|
|
1011
1032
|
}
|
|
1012
1033
|
function getKnownAccountsFromRequest(request) {
|
|
1013
1034
|
const cookieHeader = request.headers.get("cookie");
|
|
@@ -1432,13 +1453,13 @@ function createAuthRoutes(config = {}) {
|
|
|
1432
1453
|
if (!user_id) {
|
|
1433
1454
|
return errorResponse("VALIDATION_ERROR", "user_id required", 400);
|
|
1434
1455
|
}
|
|
1435
|
-
const
|
|
1436
|
-
|
|
1456
|
+
const headers2 = new Headers();
|
|
1457
|
+
headers2.set("Content-Type", "application/json");
|
|
1437
1458
|
const existingKnown = getKnownAccountsCookieRaw(request);
|
|
1438
|
-
removeKnownAccountFromCookie(
|
|
1459
|
+
removeKnownAccountFromCookie(headers2, user_id, existingKnown, cookieOptions);
|
|
1439
1460
|
return new Response(
|
|
1440
1461
|
JSON.stringify({ success: true, data: { message: "Account forgotten" } }),
|
|
1441
|
-
{ status: 200, headers }
|
|
1462
|
+
{ status: 200, headers: headers2 }
|
|
1442
1463
|
);
|
|
1443
1464
|
}
|
|
1444
1465
|
// ==================== Forget All Accounts ====================
|
|
@@ -1446,12 +1467,12 @@ function createAuthRoutes(config = {}) {
|
|
|
1446
1467
|
if (!config.enableAccountSwitcher) {
|
|
1447
1468
|
return errorResponse("NOT_FOUND", "Account switcher not enabled", 404);
|
|
1448
1469
|
}
|
|
1449
|
-
const
|
|
1450
|
-
|
|
1451
|
-
clearKnownAccountsCookie(
|
|
1470
|
+
const headers2 = new Headers();
|
|
1471
|
+
headers2.set("Content-Type", "application/json");
|
|
1472
|
+
clearKnownAccountsCookie(headers2, cookieOptions);
|
|
1452
1473
|
return new Response(
|
|
1453
1474
|
JSON.stringify({ success: true, data: { message: "All accounts forgotten" } }),
|
|
1454
|
-
{ status: 200, headers }
|
|
1475
|
+
{ status: 200, headers: headers2 }
|
|
1455
1476
|
);
|
|
1456
1477
|
}
|
|
1457
1478
|
default:
|