@scalemule/nextjs 0.1.38 → 0.1.40
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 +1 -1
- package/dist/client.d.ts +1 -1
- package/dist/client.js +33 -3
- package/dist/client.mjs +33 -3
- package/dist/{index-Tq5WdDfS.d.mts → index-Bv1m_qQ8.d.mts} +20 -0
- package/dist/{index-Tq5WdDfS.d.ts → index-Bv1m_qQ8.d.ts} +20 -0
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +33 -3
- package/dist/index.mjs +33 -3
- package/dist/server/auth.js +110 -62
- package/dist/server/auth.mjs +111 -63
- package/dist/server/index.d.mts +24 -4
- package/dist/server/index.d.ts +24 -4
- package/dist/server/index.js +161 -103
- package/dist/server/index.mjs +161 -103
- package/dist/server/webhook-handler.d.mts +2 -2
- package/dist/server/webhook-handler.d.ts +2 -2
- package/dist/testing.d.mts +1 -1
- package/dist/testing.d.ts +1 -1
- package/dist/testing.js +3 -0
- package/dist/testing.mjs +3 -0
- package/dist/{webhook-handler-Cfa7-yKN.d.ts → webhook-handler-5ymVecTD.d.ts} +1 -1
- package/dist/{webhook-handler-DN4WBjbm.d.mts → webhook-handler-CVmBvPFN.d.mts} +1 -1
- package/package.json +4 -3
package/dist/server/auth.js
CHANGED
|
@@ -12,6 +12,9 @@ var ScaleMuleApiError = class extends Error {
|
|
|
12
12
|
this.code = error.code;
|
|
13
13
|
this.field = error.field;
|
|
14
14
|
this.status = status;
|
|
15
|
+
this.requestId = error.requestId;
|
|
16
|
+
this.traceId = error.traceId;
|
|
17
|
+
this.problem = error.problem;
|
|
15
18
|
}
|
|
16
19
|
};
|
|
17
20
|
|
|
@@ -29,40 +32,40 @@ function validateIP(ip) {
|
|
|
29
32
|
return void 0;
|
|
30
33
|
}
|
|
31
34
|
function extractClientContext(request) {
|
|
32
|
-
const
|
|
35
|
+
const headers2 = request.headers;
|
|
33
36
|
let ip;
|
|
34
|
-
const cfConnectingIp =
|
|
37
|
+
const cfConnectingIp = headers2.get("cf-connecting-ip");
|
|
35
38
|
if (cfConnectingIp) {
|
|
36
39
|
ip = validateIP(cfConnectingIp);
|
|
37
40
|
}
|
|
38
41
|
if (!ip) {
|
|
39
|
-
const doConnectingIp =
|
|
42
|
+
const doConnectingIp = headers2.get("do-connecting-ip");
|
|
40
43
|
if (doConnectingIp) {
|
|
41
44
|
ip = validateIP(doConnectingIp);
|
|
42
45
|
}
|
|
43
46
|
}
|
|
44
47
|
if (!ip) {
|
|
45
|
-
const realIp =
|
|
48
|
+
const realIp = headers2.get("x-real-ip");
|
|
46
49
|
if (realIp) {
|
|
47
50
|
ip = validateIP(realIp);
|
|
48
51
|
}
|
|
49
52
|
}
|
|
50
53
|
if (!ip) {
|
|
51
|
-
const forwardedFor =
|
|
54
|
+
const forwardedFor = headers2.get("x-forwarded-for");
|
|
52
55
|
if (forwardedFor) {
|
|
53
56
|
const firstIp = forwardedFor.split(",")[0]?.trim();
|
|
54
57
|
ip = validateIP(firstIp);
|
|
55
58
|
}
|
|
56
59
|
}
|
|
57
60
|
if (!ip) {
|
|
58
|
-
const vercelForwarded =
|
|
61
|
+
const vercelForwarded = headers2.get("x-vercel-forwarded-for");
|
|
59
62
|
if (vercelForwarded) {
|
|
60
63
|
const firstIp = vercelForwarded.split(",")[0]?.trim();
|
|
61
64
|
ip = validateIP(firstIp);
|
|
62
65
|
}
|
|
63
66
|
}
|
|
64
67
|
if (!ip) {
|
|
65
|
-
const trueClientIp =
|
|
68
|
+
const trueClientIp = headers2.get("true-client-ip");
|
|
66
69
|
if (trueClientIp) {
|
|
67
70
|
ip = validateIP(trueClientIp);
|
|
68
71
|
}
|
|
@@ -70,10 +73,10 @@ function extractClientContext(request) {
|
|
|
70
73
|
if (!ip && request.ip) {
|
|
71
74
|
ip = validateIP(request.ip);
|
|
72
75
|
}
|
|
73
|
-
const userAgent =
|
|
74
|
-
const deviceFingerprint =
|
|
75
|
-
const referrer =
|
|
76
|
-
const anonymousId =
|
|
76
|
+
const userAgent = headers2.get("user-agent") || void 0;
|
|
77
|
+
const deviceFingerprint = headers2.get("x-device-fingerprint") || void 0;
|
|
78
|
+
const referrer = headers2.get("referer") || void 0;
|
|
79
|
+
const anonymousId = headers2.get("x-anonymous-id") || void 0;
|
|
77
80
|
return {
|
|
78
81
|
ip,
|
|
79
82
|
userAgent,
|
|
@@ -83,27 +86,46 @@ function extractClientContext(request) {
|
|
|
83
86
|
};
|
|
84
87
|
}
|
|
85
88
|
function buildClientContextHeaders(context) {
|
|
86
|
-
const
|
|
89
|
+
const headers2 = {};
|
|
87
90
|
if (!context) {
|
|
88
|
-
return
|
|
91
|
+
return headers2;
|
|
89
92
|
}
|
|
90
93
|
if (context.ip) {
|
|
91
|
-
|
|
92
|
-
|
|
94
|
+
headers2["x-sm-forwarded-client-ip"] = context.ip;
|
|
95
|
+
headers2["X-Client-IP"] = context.ip;
|
|
93
96
|
}
|
|
94
97
|
if (context.userAgent) {
|
|
95
|
-
|
|
98
|
+
headers2["X-Client-User-Agent"] = context.userAgent;
|
|
96
99
|
}
|
|
97
100
|
if (context.deviceFingerprint) {
|
|
98
|
-
|
|
101
|
+
headers2["X-Client-Device-Fingerprint"] = context.deviceFingerprint;
|
|
99
102
|
}
|
|
100
103
|
if (context.referrer) {
|
|
101
|
-
|
|
104
|
+
headers2["X-Client-Referrer"] = context.referrer;
|
|
102
105
|
}
|
|
103
106
|
if (context.anonymousId) {
|
|
104
|
-
|
|
107
|
+
headers2["x-anonymous-id"] = context.anonymousId;
|
|
105
108
|
}
|
|
106
|
-
return
|
|
109
|
+
return headers2;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// src/error-context.ts
|
|
113
|
+
function withErrorContext(error, responseData, headers2) {
|
|
114
|
+
const enriched = { ...error };
|
|
115
|
+
const meta = responseData?.meta;
|
|
116
|
+
const requestId = meta?.request_id ?? headers2?.get("x-request-id") ?? void 0;
|
|
117
|
+
if (requestId !== void 0 && enriched.requestId === void 0) {
|
|
118
|
+
enriched.requestId = requestId;
|
|
119
|
+
}
|
|
120
|
+
const traceId = meta?.trace_id;
|
|
121
|
+
if (traceId !== void 0 && enriched.traceId === void 0) {
|
|
122
|
+
enriched.traceId = traceId;
|
|
123
|
+
}
|
|
124
|
+
const rawError = responseData?.error;
|
|
125
|
+
if (rawError !== null && typeof rawError === "object" && enriched.problem === void 0) {
|
|
126
|
+
enriched.problem = rawError;
|
|
127
|
+
}
|
|
128
|
+
return enriched;
|
|
107
129
|
}
|
|
108
130
|
|
|
109
131
|
// src/server/client.ts
|
|
@@ -114,6 +136,7 @@ var GATEWAY_URLS = {
|
|
|
114
136
|
function resolveGatewayUrl(config) {
|
|
115
137
|
if (config.gatewayUrl) return config.gatewayUrl;
|
|
116
138
|
if (process.env.SCALEMULE_API_URL) return process.env.SCALEMULE_API_URL;
|
|
139
|
+
if (process.env.SCALEMULE_GATEWAY_URL) return process.env.SCALEMULE_GATEWAY_URL;
|
|
117
140
|
return GATEWAY_URLS[config.environment || "prod"];
|
|
118
141
|
}
|
|
119
142
|
var ScaleMuleServer = class {
|
|
@@ -502,7 +525,7 @@ var ScaleMuleServer = class {
|
|
|
502
525
|
formData.append("file", blob, file.filename);
|
|
503
526
|
formData.append("sm_user_id", userId);
|
|
504
527
|
const url = `${this.gatewayUrl}/v1/storage/upload`;
|
|
505
|
-
const
|
|
528
|
+
const headers2 = {
|
|
506
529
|
"x-api-key": this.apiKey,
|
|
507
530
|
"x-user-id": userId,
|
|
508
531
|
...buildClientContextHeaders(options?.clientContext)
|
|
@@ -513,7 +536,7 @@ var ScaleMuleServer = class {
|
|
|
513
536
|
try {
|
|
514
537
|
const response = await fetch(url, {
|
|
515
538
|
method: "POST",
|
|
516
|
-
headers,
|
|
539
|
+
headers: headers2,
|
|
517
540
|
body: formData
|
|
518
541
|
});
|
|
519
542
|
const text = await response.text();
|
|
@@ -524,7 +547,11 @@ var ScaleMuleServer = class {
|
|
|
524
547
|
}
|
|
525
548
|
if (!response.ok) {
|
|
526
549
|
throw new ScaleMuleApiError(
|
|
527
|
-
|
|
550
|
+
withErrorContext(
|
|
551
|
+
responseData?.error || { code: "UPLOAD_FAILED", message: text || "Upload failed" },
|
|
552
|
+
responseData,
|
|
553
|
+
response.headers
|
|
554
|
+
)
|
|
528
555
|
);
|
|
529
556
|
}
|
|
530
557
|
const data = responseData?.data !== void 0 ? responseData.data : responseData;
|
|
@@ -735,14 +762,14 @@ var ScaleMuleServer = class {
|
|
|
735
762
|
*/
|
|
736
763
|
async request(method, path, options = {}) {
|
|
737
764
|
const url = `${this.gatewayUrl}${path}`;
|
|
738
|
-
const
|
|
765
|
+
const headers2 = {
|
|
739
766
|
"x-api-key": this.apiKey,
|
|
740
767
|
"Content-Type": "application/json",
|
|
741
768
|
// Forward client context headers if provided
|
|
742
769
|
...buildClientContextHeaders(options.clientContext)
|
|
743
770
|
};
|
|
744
771
|
if (options.sessionToken) {
|
|
745
|
-
|
|
772
|
+
headers2["Authorization"] = `Bearer ${options.sessionToken}`;
|
|
746
773
|
}
|
|
747
774
|
if (this.debug) {
|
|
748
775
|
console.log(`[ScaleMule Server] ${method} ${path}`);
|
|
@@ -753,7 +780,7 @@ var ScaleMuleServer = class {
|
|
|
753
780
|
try {
|
|
754
781
|
const response = await fetch(url, {
|
|
755
782
|
method,
|
|
756
|
-
headers,
|
|
783
|
+
headers: headers2,
|
|
757
784
|
body: options.body ? JSON.stringify(options.body) : void 0
|
|
758
785
|
});
|
|
759
786
|
const rotated = response.headers.get("x-rotated-session-token");
|
|
@@ -767,10 +794,11 @@ var ScaleMuleServer = class {
|
|
|
767
794
|
} catch {
|
|
768
795
|
}
|
|
769
796
|
if (!response.ok) {
|
|
770
|
-
const
|
|
797
|
+
const baseError = responseData?.error || {
|
|
771
798
|
code: `HTTP_${response.status}`,
|
|
772
799
|
message: responseData?.message || text || response.statusText
|
|
773
800
|
};
|
|
801
|
+
const error = withErrorContext(baseError, responseData, response.headers);
|
|
774
802
|
if (response.status === 401 && options.sessionToken && !options.isAutoRefresh) {
|
|
775
803
|
if (this.debug) console.log("[ScaleMule Server] 401 received, attempting auto-refresh...");
|
|
776
804
|
try {
|
|
@@ -849,66 +877,86 @@ function createCookieHeader(name, value, options = {}) {
|
|
|
849
877
|
}
|
|
850
878
|
function createClearCookieHeader(name, options = {}) {
|
|
851
879
|
const path = options.path ?? "/";
|
|
852
|
-
|
|
880
|
+
const secure = options.secure ?? process.env.NODE_ENV === "production";
|
|
881
|
+
const sameSite = options.sameSite ?? "lax";
|
|
882
|
+
let cookie = `${name}=; Path=${path}; Max-Age=0; HttpOnly; SameSite=${sameSite}`;
|
|
883
|
+
if (secure) {
|
|
884
|
+
cookie += "; Secure";
|
|
885
|
+
}
|
|
853
886
|
if (options.domain) {
|
|
854
887
|
cookie += `; Domain=${options.domain}`;
|
|
855
888
|
}
|
|
856
889
|
return cookie;
|
|
857
890
|
}
|
|
858
891
|
function withSession(loginResponse, responseBody, options = {}) {
|
|
859
|
-
const
|
|
860
|
-
|
|
861
|
-
|
|
892
|
+
const headers2 = new Headers();
|
|
893
|
+
headers2.set("Content-Type", "application/json");
|
|
894
|
+
headers2.append(
|
|
862
895
|
"Set-Cookie",
|
|
863
896
|
createCookieHeader(SESSION_COOKIE_NAME, loginResponse.session_token, options)
|
|
864
897
|
);
|
|
865
|
-
|
|
898
|
+
headers2.append(
|
|
866
899
|
"Set-Cookie",
|
|
867
900
|
createCookieHeader(USER_ID_COOKIE_NAME, loginResponse.user.id, options)
|
|
868
901
|
);
|
|
869
902
|
return new Response(JSON.stringify({ success: true, data: responseBody }), {
|
|
870
903
|
status: 200,
|
|
871
|
-
headers
|
|
904
|
+
headers: headers2
|
|
872
905
|
});
|
|
873
906
|
}
|
|
874
907
|
function withRefreshedSession(sessionToken, userId, responseBody, options = {}) {
|
|
875
|
-
const
|
|
876
|
-
|
|
877
|
-
|
|
908
|
+
const headers2 = new Headers();
|
|
909
|
+
headers2.set("Content-Type", "application/json");
|
|
910
|
+
headers2.append(
|
|
878
911
|
"Set-Cookie",
|
|
879
912
|
createCookieHeader(SESSION_COOKIE_NAME, sessionToken, options)
|
|
880
913
|
);
|
|
881
|
-
|
|
914
|
+
headers2.append(
|
|
882
915
|
"Set-Cookie",
|
|
883
916
|
createCookieHeader(USER_ID_COOKIE_NAME, userId, options)
|
|
884
917
|
);
|
|
885
918
|
return new Response(JSON.stringify({ success: true, data: responseBody }), {
|
|
886
919
|
status: 200,
|
|
887
|
-
headers
|
|
920
|
+
headers: headers2
|
|
888
921
|
});
|
|
889
922
|
}
|
|
890
923
|
function clearSession(responseBody, options = {}, status = 200) {
|
|
891
|
-
const
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
924
|
+
const headers2 = new Headers();
|
|
925
|
+
headers2.set("Content-Type", "application/json");
|
|
926
|
+
headers2.append("Set-Cookie", createClearCookieHeader(SESSION_COOKIE_NAME, options));
|
|
927
|
+
headers2.append("Set-Cookie", createClearCookieHeader(USER_ID_COOKIE_NAME, options));
|
|
895
928
|
return new Response(JSON.stringify({ success: status < 300, data: responseBody }), {
|
|
896
929
|
status,
|
|
897
|
-
headers
|
|
930
|
+
headers: headers2
|
|
898
931
|
});
|
|
899
932
|
}
|
|
900
933
|
async function getSession() {
|
|
901
934
|
const cookieStore = await headers.cookies();
|
|
902
935
|
const sessionCookie = cookieStore.get(SESSION_COOKIE_NAME);
|
|
903
936
|
const userIdCookie = cookieStore.get(USER_ID_COOKIE_NAME);
|
|
904
|
-
if (
|
|
905
|
-
return
|
|
937
|
+
if (sessionCookie?.value && userIdCookie?.value) {
|
|
938
|
+
return {
|
|
939
|
+
sessionToken: sessionCookie.value,
|
|
940
|
+
userId: userIdCookie.value,
|
|
941
|
+
expiresAt: /* @__PURE__ */ new Date()
|
|
942
|
+
// Note: actual expiry is managed by ScaleMule backend
|
|
943
|
+
};
|
|
906
944
|
}
|
|
945
|
+
const headerStore = await headers.headers();
|
|
946
|
+
return sessionFromAuthHeaders(
|
|
947
|
+
headerStore.get("authorization"),
|
|
948
|
+
headerStore.get("x-sm-user-id")
|
|
949
|
+
);
|
|
950
|
+
}
|
|
951
|
+
function sessionFromAuthHeaders(authorization, userId) {
|
|
952
|
+
if (!authorization || !userId) return null;
|
|
953
|
+
const match = /^Bearer\s+(.+)$/i.exec(authorization.trim());
|
|
954
|
+
const token = match?.[1]?.trim();
|
|
955
|
+
if (!token) return null;
|
|
907
956
|
return {
|
|
908
|
-
sessionToken:
|
|
909
|
-
userId
|
|
957
|
+
sessionToken: token,
|
|
958
|
+
userId,
|
|
910
959
|
expiresAt: /* @__PURE__ */ new Date()
|
|
911
|
-
// Note: actual expiry is managed by ScaleMule backend
|
|
912
960
|
};
|
|
913
961
|
}
|
|
914
962
|
var MAX_KNOWN_ACCOUNTS = 10;
|
|
@@ -950,7 +998,7 @@ function applyPrivacyToEntry(entry, privacy) {
|
|
|
950
998
|
};
|
|
951
999
|
}
|
|
952
1000
|
}
|
|
953
|
-
function appendKnownAccountCookie(
|
|
1001
|
+
function appendKnownAccountCookie(headers2, account, existingCookie, options = {}, privacy) {
|
|
954
1002
|
let accounts = {};
|
|
955
1003
|
if (existingCookie) {
|
|
956
1004
|
try {
|
|
@@ -979,9 +1027,9 @@ function appendKnownAccountCookie(headers, account, existingCookie, options = {}
|
|
|
979
1027
|
if (options.domain) {
|
|
980
1028
|
cookie += `; Domain=${options.domain}`;
|
|
981
1029
|
}
|
|
982
|
-
|
|
1030
|
+
headers2.append("Set-Cookie", cookie);
|
|
983
1031
|
}
|
|
984
|
-
function removeKnownAccountFromCookie(
|
|
1032
|
+
function removeKnownAccountFromCookie(headers2, userId, existingCookie, options = {}) {
|
|
985
1033
|
let accounts = {};
|
|
986
1034
|
if (existingCookie) {
|
|
987
1035
|
try {
|
|
@@ -1001,15 +1049,15 @@ function removeKnownAccountFromCookie(headers, userId, existingCookie, options =
|
|
|
1001
1049
|
if (options.domain) {
|
|
1002
1050
|
cookie += `; Domain=${options.domain}`;
|
|
1003
1051
|
}
|
|
1004
|
-
|
|
1052
|
+
headers2.append("Set-Cookie", cookie);
|
|
1005
1053
|
}
|
|
1006
|
-
function clearKnownAccountsCookie(
|
|
1054
|
+
function clearKnownAccountsCookie(headers2, options = {}) {
|
|
1007
1055
|
const path = options.path ?? "/";
|
|
1008
1056
|
let cookie = `${KNOWN_ACCOUNTS_COOKIE_NAME}=; Path=${path}; Max-Age=0`;
|
|
1009
1057
|
if (options.domain) {
|
|
1010
1058
|
cookie += `; Domain=${options.domain}`;
|
|
1011
1059
|
}
|
|
1012
|
-
|
|
1060
|
+
headers2.append("Set-Cookie", cookie);
|
|
1013
1061
|
}
|
|
1014
1062
|
function getKnownAccountsFromRequest(request) {
|
|
1015
1063
|
const cookieHeader = request.headers.get("cookie");
|
|
@@ -1434,13 +1482,13 @@ function createAuthRoutes(config = {}) {
|
|
|
1434
1482
|
if (!user_id) {
|
|
1435
1483
|
return errorResponse("VALIDATION_ERROR", "user_id required", 400);
|
|
1436
1484
|
}
|
|
1437
|
-
const
|
|
1438
|
-
|
|
1485
|
+
const headers2 = new Headers();
|
|
1486
|
+
headers2.set("Content-Type", "application/json");
|
|
1439
1487
|
const existingKnown = getKnownAccountsCookieRaw(request);
|
|
1440
|
-
removeKnownAccountFromCookie(
|
|
1488
|
+
removeKnownAccountFromCookie(headers2, user_id, existingKnown, cookieOptions);
|
|
1441
1489
|
return new Response(
|
|
1442
1490
|
JSON.stringify({ success: true, data: { message: "Account forgotten" } }),
|
|
1443
|
-
{ status: 200, headers }
|
|
1491
|
+
{ status: 200, headers: headers2 }
|
|
1444
1492
|
);
|
|
1445
1493
|
}
|
|
1446
1494
|
// ==================== Forget All Accounts ====================
|
|
@@ -1448,12 +1496,12 @@ function createAuthRoutes(config = {}) {
|
|
|
1448
1496
|
if (!config.enableAccountSwitcher) {
|
|
1449
1497
|
return errorResponse("NOT_FOUND", "Account switcher not enabled", 404);
|
|
1450
1498
|
}
|
|
1451
|
-
const
|
|
1452
|
-
|
|
1453
|
-
clearKnownAccountsCookie(
|
|
1499
|
+
const headers2 = new Headers();
|
|
1500
|
+
headers2.set("Content-Type", "application/json");
|
|
1501
|
+
clearKnownAccountsCookie(headers2, cookieOptions);
|
|
1454
1502
|
return new Response(
|
|
1455
1503
|
JSON.stringify({ success: true, data: { message: "All accounts forgotten" } }),
|
|
1456
|
-
{ status: 200, headers }
|
|
1504
|
+
{ status: 200, headers: headers2 }
|
|
1457
1505
|
);
|
|
1458
1506
|
}
|
|
1459
1507
|
default:
|