@feelflow/ffid-sdk 1.11.0 → 1.14.0
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/{chunk-WZZP7SQB.cjs → chunk-TMUFELR5.cjs} +377 -30
- package/dist/{chunk-GW23IWNE.js → chunk-WJI7D5C7.js} +377 -30
- package/dist/components/index.cjs +7 -7
- package/dist/components/index.d.cts +1 -1
- package/dist/components/index.d.ts +1 -1
- package/dist/components/index.js +1 -1
- package/dist/{index-DMgtXEt5.d.cts → index-DU-lFo9B.d.cts} +13 -1
- package/dist/{index-DMgtXEt5.d.ts → index-DU-lFo9B.d.ts} +13 -1
- package/dist/index.cjs +22 -22
- package/dist/index.d.cts +65 -7
- package/dist/index.d.ts +65 -7
- package/dist/index.js +2 -2
- package/dist/server/index.cjs +374 -28
- package/dist/server/index.d.cts +64 -2
- package/dist/server/index.d.ts +64 -2
- package/dist/server/index.js +374 -28
- package/package.json +1 -1
package/dist/server/index.cjs
CHANGED
|
@@ -433,7 +433,7 @@ function createBillingMethods(deps) {
|
|
|
433
433
|
}
|
|
434
434
|
|
|
435
435
|
// src/client/version-check.ts
|
|
436
|
-
var SDK_VERSION = "1.
|
|
436
|
+
var SDK_VERSION = "1.14.0";
|
|
437
437
|
var SDK_USER_AGENT = `FFID-SDK/${SDK_VERSION} (TypeScript)`;
|
|
438
438
|
var SDK_VERSION_HEADER = "X-FFID-SDK-Version";
|
|
439
439
|
function sdkHeaders() {
|
|
@@ -479,6 +479,22 @@ npm install @feelflow/ffid-sdk@latest \u3067\u30A2\u30C3\u30D7\u30C7\u30FC\u30C8
|
|
|
479
479
|
var OAUTH_TOKEN_ENDPOINT = "/api/v1/oauth/token";
|
|
480
480
|
var OAUTH_REVOKE_ENDPOINT = "/api/v1/oauth/revoke";
|
|
481
481
|
var MS_PER_SECOND = 1e3;
|
|
482
|
+
function validateTokenResponse(tokenResponse) {
|
|
483
|
+
const invalid = [];
|
|
484
|
+
if (!tokenResponse.access_token) {
|
|
485
|
+
invalid.push("access_token");
|
|
486
|
+
}
|
|
487
|
+
if (!tokenResponse.refresh_token) {
|
|
488
|
+
invalid.push("refresh_token");
|
|
489
|
+
}
|
|
490
|
+
if (typeof tokenResponse.expires_in !== "number" || tokenResponse.expires_in <= 0) {
|
|
491
|
+
invalid.push("expires_in");
|
|
492
|
+
}
|
|
493
|
+
if (invalid.length > 0) {
|
|
494
|
+
return `\u30C8\u30FC\u30AF\u30F3\u30EC\u30B9\u30DD\u30F3\u30B9\u306B\u4E0D\u6B63\u306A\u30D5\u30A3\u30FC\u30EB\u30C9\u304C\u3042\u308A\u307E\u3059: ${invalid.join(", ")}`;
|
|
495
|
+
}
|
|
496
|
+
return null;
|
|
497
|
+
}
|
|
482
498
|
function createOAuthTokenMethods(deps) {
|
|
483
499
|
const {
|
|
484
500
|
baseUrl,
|
|
@@ -548,6 +564,16 @@ function createOAuthTokenMethods(deps) {
|
|
|
548
564
|
}
|
|
549
565
|
};
|
|
550
566
|
}
|
|
567
|
+
const validationError = validateTokenResponse(tokenResponse);
|
|
568
|
+
if (validationError) {
|
|
569
|
+
logger.error("Token exchange validation failed:", validationError);
|
|
570
|
+
return {
|
|
571
|
+
error: {
|
|
572
|
+
code: errorCodes.TOKEN_EXCHANGE_ERROR,
|
|
573
|
+
message: validationError
|
|
574
|
+
}
|
|
575
|
+
};
|
|
576
|
+
}
|
|
551
577
|
tokenStore.setTokens({
|
|
552
578
|
accessToken: tokenResponse.access_token,
|
|
553
579
|
refreshToken: tokenResponse.refresh_token,
|
|
@@ -616,6 +642,16 @@ function createOAuthTokenMethods(deps) {
|
|
|
616
642
|
}
|
|
617
643
|
};
|
|
618
644
|
}
|
|
645
|
+
const validationError = validateTokenResponse(tokenResponse);
|
|
646
|
+
if (validationError) {
|
|
647
|
+
logger.error("Token refresh validation failed:", validationError);
|
|
648
|
+
return {
|
|
649
|
+
error: {
|
|
650
|
+
code: errorCodes.TOKEN_REFRESH_ERROR,
|
|
651
|
+
message: validationError
|
|
652
|
+
}
|
|
653
|
+
};
|
|
654
|
+
}
|
|
619
655
|
tokenStore.setTokens({
|
|
620
656
|
accessToken: tokenResponse.access_token,
|
|
621
657
|
refreshToken: tokenResponse.refresh_token,
|
|
@@ -869,11 +905,17 @@ async function generateCodeChallenge(verifier) {
|
|
|
869
905
|
const digest = await crypto.subtle.digest("SHA-256", data);
|
|
870
906
|
return base64UrlEncode(digest);
|
|
871
907
|
}
|
|
872
|
-
function storeCodeVerifier(verifier) {
|
|
908
|
+
function storeCodeVerifier(verifier, logger) {
|
|
873
909
|
try {
|
|
874
|
-
if (typeof window === "undefined")
|
|
910
|
+
if (typeof window === "undefined") {
|
|
911
|
+
logger?.warn("storeCodeVerifier: sessionStorage is not available in SSR context");
|
|
912
|
+
return false;
|
|
913
|
+
}
|
|
875
914
|
window.sessionStorage.setItem(VERIFIER_STORAGE_KEY, verifier);
|
|
876
|
-
|
|
915
|
+
return true;
|
|
916
|
+
} catch (error) {
|
|
917
|
+
logger?.warn("storeCodeVerifier: sessionStorage \u3078\u306E\u4FDD\u5B58\u306B\u5931\u6557\u3057\u307E\u3057\u305F:", error);
|
|
918
|
+
return false;
|
|
877
919
|
}
|
|
878
920
|
}
|
|
879
921
|
function base64UrlEncode(buffer) {
|
|
@@ -887,6 +929,7 @@ function base64UrlEncode(buffer) {
|
|
|
887
929
|
|
|
888
930
|
// src/client/redirect.ts
|
|
889
931
|
var OAUTH_AUTHORIZE_ENDPOINT = "/api/v1/oauth/authorize";
|
|
932
|
+
var AUTH_LOGOUT_ENDPOINT = "/api/v1/auth/logout";
|
|
890
933
|
var STATE_RANDOM_BYTES = 16;
|
|
891
934
|
var HEX_BASE2 = 16;
|
|
892
935
|
function generateRandomState() {
|
|
@@ -905,32 +948,34 @@ function createRedirectMethods(deps) {
|
|
|
905
948
|
} = deps;
|
|
906
949
|
async function redirectToAuthorize() {
|
|
907
950
|
const verifier = generateCodeVerifier();
|
|
908
|
-
storeCodeVerifier(verifier);
|
|
951
|
+
storeCodeVerifier(verifier, logger);
|
|
952
|
+
let challenge;
|
|
909
953
|
try {
|
|
910
|
-
|
|
911
|
-
const state = generateRandomState();
|
|
912
|
-
const redirectUri = resolvedRedirectUri ?? window.location.origin + window.location.pathname;
|
|
913
|
-
const params = new URLSearchParams({
|
|
914
|
-
response_type: "code",
|
|
915
|
-
client_id: clientId,
|
|
916
|
-
redirect_uri: redirectUri,
|
|
917
|
-
state,
|
|
918
|
-
code_challenge: challenge,
|
|
919
|
-
code_challenge_method: "S256"
|
|
920
|
-
});
|
|
921
|
-
const authorizeUrl = `${baseUrl}${OAUTH_AUTHORIZE_ENDPOINT}?${params.toString()}`;
|
|
922
|
-
logger.debug("Redirecting to authorize:", authorizeUrl);
|
|
923
|
-
window.location.href = authorizeUrl;
|
|
924
|
-
return true;
|
|
954
|
+
challenge = await generateCodeChallenge(verifier);
|
|
925
955
|
} catch (error) {
|
|
956
|
+
const errorMessage = error instanceof Error ? error.message : "PKCE \u30B3\u30FC\u30C9\u30C1\u30E3\u30EC\u30F3\u30B8\u306E\u751F\u6210\u306B\u5931\u6557\u3057\u307E\u3057\u305F";
|
|
926
957
|
logger.error("PKCE \u30B3\u30FC\u30C9\u30C1\u30E3\u30EC\u30F3\u30B8\u306E\u751F\u6210\u306B\u5931\u6557\u3057\u307E\u3057\u305F:", error);
|
|
927
|
-
return false;
|
|
958
|
+
return { success: false, error: errorMessage };
|
|
928
959
|
}
|
|
960
|
+
const state = generateRandomState();
|
|
961
|
+
const redirectUri = resolvedRedirectUri ?? window.location.origin + window.location.pathname;
|
|
962
|
+
const params = new URLSearchParams({
|
|
963
|
+
response_type: "code",
|
|
964
|
+
client_id: clientId,
|
|
965
|
+
redirect_uri: redirectUri,
|
|
966
|
+
state,
|
|
967
|
+
code_challenge: challenge,
|
|
968
|
+
code_challenge_method: "S256"
|
|
969
|
+
});
|
|
970
|
+
const authorizeUrl = `${baseUrl}${OAUTH_AUTHORIZE_ENDPOINT}?${params.toString()}`;
|
|
971
|
+
logger.debug("Redirecting to authorize:", authorizeUrl);
|
|
972
|
+
window.location.href = authorizeUrl;
|
|
973
|
+
return { success: true };
|
|
929
974
|
}
|
|
930
975
|
async function redirectToLogin() {
|
|
931
976
|
if (typeof window === "undefined") {
|
|
932
|
-
logger.
|
|
933
|
-
return false;
|
|
977
|
+
logger.warn("SSR \u74B0\u5883\u3067\u306F\u30EA\u30C0\u30A4\u30EC\u30AF\u30C8\u3067\u304D\u307E\u305B\u3093");
|
|
978
|
+
return { success: false, error: "SSR \u74B0\u5883\u3067\u306F\u30EA\u30C0\u30A4\u30EC\u30AF\u30C8\u3067\u304D\u307E\u305B\u3093" };
|
|
934
979
|
}
|
|
935
980
|
if (authMode === "token") {
|
|
936
981
|
return redirectToAuthorize();
|
|
@@ -939,17 +984,289 @@ function createRedirectMethods(deps) {
|
|
|
939
984
|
const loginUrl = `${baseUrl}/login?redirect=${encodeURIComponent(currentUrl)}&service=${encodeURIComponent(serviceCode)}`;
|
|
940
985
|
logger.debug("Redirecting to login:", loginUrl);
|
|
941
986
|
window.location.href = loginUrl;
|
|
942
|
-
return true;
|
|
987
|
+
return { success: true };
|
|
943
988
|
}
|
|
944
989
|
function getLoginUrl(redirectUrl) {
|
|
945
|
-
|
|
990
|
+
let redirect;
|
|
991
|
+
if (redirectUrl != null) {
|
|
992
|
+
redirect = redirectUrl;
|
|
993
|
+
} else if (typeof window !== "undefined") {
|
|
994
|
+
redirect = window.location.href;
|
|
995
|
+
} else {
|
|
996
|
+
logger.warn("getLoginUrl: SSR \u74B0\u5883\u3067 redirectUrl \u304C\u672A\u6307\u5B9A\u306E\u305F\u3081\u7A7A\u6587\u5B57\u306B\u30D5\u30A9\u30FC\u30EB\u30D0\u30C3\u30AF\u3057\u307E\u3059");
|
|
997
|
+
redirect = "";
|
|
998
|
+
}
|
|
946
999
|
return `${baseUrl}/login?redirect=${encodeURIComponent(redirect)}&service=${encodeURIComponent(serviceCode)}`;
|
|
947
1000
|
}
|
|
948
1001
|
function getSignupUrl(redirectUrl) {
|
|
949
|
-
|
|
1002
|
+
let redirect;
|
|
1003
|
+
if (redirectUrl != null) {
|
|
1004
|
+
redirect = redirectUrl;
|
|
1005
|
+
} else if (typeof window !== "undefined") {
|
|
1006
|
+
redirect = window.location.href;
|
|
1007
|
+
} else {
|
|
1008
|
+
logger.warn("getSignupUrl: SSR \u74B0\u5883\u3067 redirectUrl \u304C\u672A\u6307\u5B9A\u306E\u305F\u3081\u7A7A\u6587\u5B57\u306B\u30D5\u30A9\u30FC\u30EB\u30D0\u30C3\u30AF\u3057\u307E\u3059");
|
|
1009
|
+
redirect = "";
|
|
1010
|
+
}
|
|
950
1011
|
return `${baseUrl}/signup?redirect=${encodeURIComponent(redirect)}&service=${encodeURIComponent(serviceCode)}`;
|
|
951
1012
|
}
|
|
952
|
-
|
|
1013
|
+
function getLogoutUrl(postLogoutRedirectUri) {
|
|
1014
|
+
const url = new URL(`${baseUrl}${AUTH_LOGOUT_ENDPOINT}`);
|
|
1015
|
+
url.searchParams.set("client_id", clientId);
|
|
1016
|
+
if (postLogoutRedirectUri != null) {
|
|
1017
|
+
url.searchParams.set("post_logout_redirect_uri", postLogoutRedirectUri);
|
|
1018
|
+
}
|
|
1019
|
+
return url.toString();
|
|
1020
|
+
}
|
|
1021
|
+
function redirectToLogout(postLogoutRedirectUri) {
|
|
1022
|
+
if (typeof window === "undefined") {
|
|
1023
|
+
logger.warn("SSR \u74B0\u5883\u3067\u306F\u30EA\u30C0\u30A4\u30EC\u30AF\u30C8\u3067\u304D\u307E\u305B\u3093");
|
|
1024
|
+
return { success: false, error: "SSR \u74B0\u5883\u3067\u306F\u30EA\u30C0\u30A4\u30EC\u30AF\u30C8\u3067\u304D\u307E\u305B\u3093" };
|
|
1025
|
+
}
|
|
1026
|
+
const logoutUrl = getLogoutUrl(postLogoutRedirectUri);
|
|
1027
|
+
logger.debug("Redirecting to logout:", logoutUrl);
|
|
1028
|
+
window.location.href = logoutUrl;
|
|
1029
|
+
return { success: true };
|
|
1030
|
+
}
|
|
1031
|
+
return { redirectToLogin, redirectToAuthorize, getLoginUrl, getSignupUrl, getLogoutUrl, redirectToLogout };
|
|
1032
|
+
}
|
|
1033
|
+
|
|
1034
|
+
// src/client/password-reset.ts
|
|
1035
|
+
var RESET_PASSWORD_BASE = "/api/v1/auth/reset-password";
|
|
1036
|
+
function isBlank(value) {
|
|
1037
|
+
return !value || !value.trim();
|
|
1038
|
+
}
|
|
1039
|
+
function createPasswordResetMethods(deps) {
|
|
1040
|
+
const { baseUrl, logger, createError, fetchWithAuth, errorCodes } = deps;
|
|
1041
|
+
async function fetchPublic(endpoint, options = {}) {
|
|
1042
|
+
const url = `${baseUrl}${endpoint}`;
|
|
1043
|
+
logger.debug("Fetching (public):", url);
|
|
1044
|
+
let response;
|
|
1045
|
+
try {
|
|
1046
|
+
response = await fetch(url, {
|
|
1047
|
+
...options,
|
|
1048
|
+
credentials: "include",
|
|
1049
|
+
headers: {
|
|
1050
|
+
"Content-Type": "application/json",
|
|
1051
|
+
...sdkHeaders(),
|
|
1052
|
+
...options.headers
|
|
1053
|
+
}
|
|
1054
|
+
});
|
|
1055
|
+
} catch (error) {
|
|
1056
|
+
logger.error("Network error:", error);
|
|
1057
|
+
return {
|
|
1058
|
+
error: {
|
|
1059
|
+
code: errorCodes.NETWORK_ERROR,
|
|
1060
|
+
message: error instanceof Error ? error.message : "\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u30A8\u30E9\u30FC\u304C\u767A\u751F\u3057\u307E\u3057\u305F"
|
|
1061
|
+
}
|
|
1062
|
+
};
|
|
1063
|
+
}
|
|
1064
|
+
let raw;
|
|
1065
|
+
try {
|
|
1066
|
+
raw = await response.json();
|
|
1067
|
+
} catch (parseError) {
|
|
1068
|
+
logger.error("Parse error:", parseError, "Status:", response.status);
|
|
1069
|
+
return {
|
|
1070
|
+
error: {
|
|
1071
|
+
code: errorCodes.PARSE_ERROR,
|
|
1072
|
+
message: `\u30B5\u30FC\u30D0\u30FC\u304B\u3089\u4E0D\u6B63\u306A\u30EC\u30B9\u30DD\u30F3\u30B9\u3092\u53D7\u4FE1\u3057\u307E\u3057\u305F (status: ${response.status})`
|
|
1073
|
+
}
|
|
1074
|
+
};
|
|
1075
|
+
}
|
|
1076
|
+
logger.debug("Response (public):", response.status, raw);
|
|
1077
|
+
checkVersionHeader(response, logger);
|
|
1078
|
+
if (!response.ok) {
|
|
1079
|
+
return {
|
|
1080
|
+
error: raw.error ?? {
|
|
1081
|
+
code: errorCodes.UNKNOWN_ERROR,
|
|
1082
|
+
message: "\u30D1\u30B9\u30EF\u30FC\u30C9\u30EA\u30BB\u30C3\u30C8\u306B\u5931\u6557\u3057\u307E\u3057\u305F"
|
|
1083
|
+
}
|
|
1084
|
+
};
|
|
1085
|
+
}
|
|
1086
|
+
if (raw.data === void 0) {
|
|
1087
|
+
return {
|
|
1088
|
+
error: {
|
|
1089
|
+
code: errorCodes.UNKNOWN_ERROR,
|
|
1090
|
+
message: "\u30B5\u30FC\u30D0\u30FC\u304B\u3089\u30C7\u30FC\u30BF\u304C\u8FD4\u3055\u308C\u307E\u305B\u3093\u3067\u3057\u305F"
|
|
1091
|
+
}
|
|
1092
|
+
};
|
|
1093
|
+
}
|
|
1094
|
+
return { data: raw.data };
|
|
1095
|
+
}
|
|
1096
|
+
async function requestPasswordReset(email) {
|
|
1097
|
+
if (isBlank(email)) {
|
|
1098
|
+
return {
|
|
1099
|
+
error: createError("VALIDATION_ERROR", "\u30E1\u30FC\u30EB\u30A2\u30C9\u30EC\u30B9\u306F\u5FC5\u9808\u3067\u3059")
|
|
1100
|
+
};
|
|
1101
|
+
}
|
|
1102
|
+
return fetchPublic(
|
|
1103
|
+
RESET_PASSWORD_BASE,
|
|
1104
|
+
{
|
|
1105
|
+
method: "POST",
|
|
1106
|
+
body: JSON.stringify({ email })
|
|
1107
|
+
}
|
|
1108
|
+
);
|
|
1109
|
+
}
|
|
1110
|
+
async function verifyPasswordResetToken(accessToken) {
|
|
1111
|
+
if (isBlank(accessToken)) {
|
|
1112
|
+
return {
|
|
1113
|
+
error: createError("VALIDATION_ERROR", "\u30A2\u30AF\u30BB\u30B9\u30C8\u30FC\u30AF\u30F3\u306F\u5FC5\u9808\u3067\u3059")
|
|
1114
|
+
};
|
|
1115
|
+
}
|
|
1116
|
+
const query = new URLSearchParams({
|
|
1117
|
+
access_token: accessToken,
|
|
1118
|
+
type: "recovery"
|
|
1119
|
+
});
|
|
1120
|
+
return fetchPublic(
|
|
1121
|
+
`${RESET_PASSWORD_BASE}/verify?${query.toString()}`
|
|
1122
|
+
);
|
|
1123
|
+
}
|
|
1124
|
+
async function establishResetSession(accessToken, refreshToken) {
|
|
1125
|
+
if (isBlank(accessToken)) {
|
|
1126
|
+
return {
|
|
1127
|
+
error: createError("VALIDATION_ERROR", "\u30A2\u30AF\u30BB\u30B9\u30C8\u30FC\u30AF\u30F3\u306F\u5FC5\u9808\u3067\u3059")
|
|
1128
|
+
};
|
|
1129
|
+
}
|
|
1130
|
+
if (isBlank(refreshToken)) {
|
|
1131
|
+
return {
|
|
1132
|
+
error: createError("VALIDATION_ERROR", "\u30EA\u30D5\u30EC\u30C3\u30B7\u30E5\u30C8\u30FC\u30AF\u30F3\u306F\u5FC5\u9808\u3067\u3059")
|
|
1133
|
+
};
|
|
1134
|
+
}
|
|
1135
|
+
return fetchPublic(
|
|
1136
|
+
`${RESET_PASSWORD_BASE}/session`,
|
|
1137
|
+
{
|
|
1138
|
+
method: "POST",
|
|
1139
|
+
body: JSON.stringify({ accessToken, refreshToken })
|
|
1140
|
+
}
|
|
1141
|
+
);
|
|
1142
|
+
}
|
|
1143
|
+
async function confirmPasswordReset(password) {
|
|
1144
|
+
if (isBlank(password)) {
|
|
1145
|
+
return {
|
|
1146
|
+
error: createError("VALIDATION_ERROR", "\u30D1\u30B9\u30EF\u30FC\u30C9\u306F\u5FC5\u9808\u3067\u3059")
|
|
1147
|
+
};
|
|
1148
|
+
}
|
|
1149
|
+
return fetchWithAuth(
|
|
1150
|
+
`${RESET_PASSWORD_BASE}/confirm`,
|
|
1151
|
+
{
|
|
1152
|
+
method: "POST",
|
|
1153
|
+
body: JSON.stringify({ password })
|
|
1154
|
+
}
|
|
1155
|
+
);
|
|
1156
|
+
}
|
|
1157
|
+
return {
|
|
1158
|
+
requestPasswordReset,
|
|
1159
|
+
verifyPasswordResetToken,
|
|
1160
|
+
establishResetSession,
|
|
1161
|
+
confirmPasswordReset
|
|
1162
|
+
};
|
|
1163
|
+
}
|
|
1164
|
+
|
|
1165
|
+
// src/client/otp.ts
|
|
1166
|
+
var OTP_BASE = "/api/v1/auth/otp";
|
|
1167
|
+
function isBlank2(value) {
|
|
1168
|
+
return !value || !value.trim();
|
|
1169
|
+
}
|
|
1170
|
+
function createOtpMethods(deps) {
|
|
1171
|
+
const { baseUrl, logger, createError, errorCodes } = deps;
|
|
1172
|
+
async function fetchPublic(endpoint, options = {}) {
|
|
1173
|
+
const url = `${baseUrl}${endpoint}`;
|
|
1174
|
+
logger.debug("Fetching (public):", url);
|
|
1175
|
+
let response;
|
|
1176
|
+
try {
|
|
1177
|
+
response = await fetch(url, {
|
|
1178
|
+
...options,
|
|
1179
|
+
credentials: "include",
|
|
1180
|
+
headers: {
|
|
1181
|
+
"Content-Type": "application/json",
|
|
1182
|
+
...sdkHeaders(),
|
|
1183
|
+
...options.headers
|
|
1184
|
+
}
|
|
1185
|
+
});
|
|
1186
|
+
} catch (error) {
|
|
1187
|
+
logger.error("Network error:", error);
|
|
1188
|
+
return {
|
|
1189
|
+
error: {
|
|
1190
|
+
code: errorCodes.NETWORK_ERROR,
|
|
1191
|
+
message: error instanceof Error ? error.message : "\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u30A8\u30E9\u30FC\u304C\u767A\u751F\u3057\u307E\u3057\u305F"
|
|
1192
|
+
}
|
|
1193
|
+
};
|
|
1194
|
+
}
|
|
1195
|
+
let raw;
|
|
1196
|
+
try {
|
|
1197
|
+
raw = await response.json();
|
|
1198
|
+
} catch (parseError) {
|
|
1199
|
+
logger.error("Parse error:", parseError, "Status:", response.status);
|
|
1200
|
+
return {
|
|
1201
|
+
error: {
|
|
1202
|
+
code: errorCodes.PARSE_ERROR,
|
|
1203
|
+
message: `\u30B5\u30FC\u30D0\u30FC\u304B\u3089\u4E0D\u6B63\u306A\u30EC\u30B9\u30DD\u30F3\u30B9\u3092\u53D7\u4FE1\u3057\u307E\u3057\u305F (status: ${response.status})`
|
|
1204
|
+
}
|
|
1205
|
+
};
|
|
1206
|
+
}
|
|
1207
|
+
logger.debug("Response (public):", response.status, raw);
|
|
1208
|
+
checkVersionHeader(response, logger);
|
|
1209
|
+
if (!response.ok) {
|
|
1210
|
+
return {
|
|
1211
|
+
error: raw.error ?? {
|
|
1212
|
+
code: errorCodes.UNKNOWN_ERROR,
|
|
1213
|
+
message: "OTP\u8A8D\u8A3C\u306B\u5931\u6557\u3057\u307E\u3057\u305F"
|
|
1214
|
+
}
|
|
1215
|
+
};
|
|
1216
|
+
}
|
|
1217
|
+
if (raw.data === void 0) {
|
|
1218
|
+
return {
|
|
1219
|
+
error: {
|
|
1220
|
+
code: errorCodes.UNKNOWN_ERROR,
|
|
1221
|
+
message: "\u30B5\u30FC\u30D0\u30FC\u304B\u3089\u30C7\u30FC\u30BF\u304C\u8FD4\u3055\u308C\u307E\u305B\u3093\u3067\u3057\u305F"
|
|
1222
|
+
}
|
|
1223
|
+
};
|
|
1224
|
+
}
|
|
1225
|
+
return { data: raw.data };
|
|
1226
|
+
}
|
|
1227
|
+
async function sendOtp(email, options) {
|
|
1228
|
+
if (isBlank2(email)) {
|
|
1229
|
+
return {
|
|
1230
|
+
error: createError("VALIDATION_ERROR", "\u30E1\u30FC\u30EB\u30A2\u30C9\u30EC\u30B9\u306F\u5FC5\u9808\u3067\u3059")
|
|
1231
|
+
};
|
|
1232
|
+
}
|
|
1233
|
+
return fetchPublic(
|
|
1234
|
+
`${OTP_BASE}/send`,
|
|
1235
|
+
{
|
|
1236
|
+
method: "POST",
|
|
1237
|
+
body: JSON.stringify({
|
|
1238
|
+
email,
|
|
1239
|
+
...options?.redirectUrl ? { redirectUrl: options.redirectUrl } : {}
|
|
1240
|
+
})
|
|
1241
|
+
}
|
|
1242
|
+
);
|
|
1243
|
+
}
|
|
1244
|
+
async function verifyOtp(params) {
|
|
1245
|
+
if (isBlank2(params.accessToken)) {
|
|
1246
|
+
return {
|
|
1247
|
+
error: createError("VALIDATION_ERROR", "\u30A2\u30AF\u30BB\u30B9\u30C8\u30FC\u30AF\u30F3\u306F\u5FC5\u9808\u3067\u3059")
|
|
1248
|
+
};
|
|
1249
|
+
}
|
|
1250
|
+
if (isBlank2(params.refreshToken)) {
|
|
1251
|
+
return {
|
|
1252
|
+
error: createError("VALIDATION_ERROR", "\u30EA\u30D5\u30EC\u30C3\u30B7\u30E5\u30C8\u30FC\u30AF\u30F3\u306F\u5FC5\u9808\u3067\u3059")
|
|
1253
|
+
};
|
|
1254
|
+
}
|
|
1255
|
+
return fetchPublic(
|
|
1256
|
+
`${OTP_BASE}/verify`,
|
|
1257
|
+
{
|
|
1258
|
+
method: "POST",
|
|
1259
|
+
body: JSON.stringify({
|
|
1260
|
+
accessToken: params.accessToken,
|
|
1261
|
+
refreshToken: params.refreshToken
|
|
1262
|
+
})
|
|
1263
|
+
}
|
|
1264
|
+
);
|
|
1265
|
+
}
|
|
1266
|
+
return {
|
|
1267
|
+
sendOtp,
|
|
1268
|
+
verifyOtp
|
|
1269
|
+
};
|
|
953
1270
|
}
|
|
954
1271
|
|
|
955
1272
|
// src/client/ffid-client.ts
|
|
@@ -1084,6 +1401,9 @@ function createFFIDClient(config) {
|
|
|
1084
1401
|
}
|
|
1085
1402
|
};
|
|
1086
1403
|
}
|
|
1404
|
+
} else {
|
|
1405
|
+
logger.warn("Token refresh failed, returning refresh error:", refreshResult.error);
|
|
1406
|
+
return { error: refreshResult.error };
|
|
1087
1407
|
}
|
|
1088
1408
|
}
|
|
1089
1409
|
let raw;
|
|
@@ -1134,7 +1454,7 @@ function createFFIDClient(config) {
|
|
|
1134
1454
|
}
|
|
1135
1455
|
return signOutCookie();
|
|
1136
1456
|
}
|
|
1137
|
-
const { redirectToLogin, getLoginUrl, getSignupUrl } = createRedirectMethods({
|
|
1457
|
+
const { redirectToLogin, getLoginUrl, getSignupUrl, getLogoutUrl, redirectToLogout } = createRedirectMethods({
|
|
1138
1458
|
authMode,
|
|
1139
1459
|
baseUrl,
|
|
1140
1460
|
clientId,
|
|
@@ -1161,6 +1481,24 @@ function createFFIDClient(config) {
|
|
|
1161
1481
|
fetchWithAuth,
|
|
1162
1482
|
createError
|
|
1163
1483
|
});
|
|
1484
|
+
const {
|
|
1485
|
+
requestPasswordReset,
|
|
1486
|
+
verifyPasswordResetToken,
|
|
1487
|
+
establishResetSession,
|
|
1488
|
+
confirmPasswordReset
|
|
1489
|
+
} = createPasswordResetMethods({
|
|
1490
|
+
baseUrl,
|
|
1491
|
+
logger,
|
|
1492
|
+
createError,
|
|
1493
|
+
fetchWithAuth,
|
|
1494
|
+
errorCodes: FFID_ERROR_CODES
|
|
1495
|
+
});
|
|
1496
|
+
const { sendOtp, verifyOtp } = createOtpMethods({
|
|
1497
|
+
baseUrl,
|
|
1498
|
+
logger,
|
|
1499
|
+
createError,
|
|
1500
|
+
errorCodes: FFID_ERROR_CODES
|
|
1501
|
+
});
|
|
1164
1502
|
const verifyAccessToken = createVerifyAccessToken({
|
|
1165
1503
|
authMode,
|
|
1166
1504
|
baseUrl,
|
|
@@ -1177,7 +1515,9 @@ function createFFIDClient(config) {
|
|
|
1177
1515
|
getSession,
|
|
1178
1516
|
signOut,
|
|
1179
1517
|
redirectToLogin,
|
|
1518
|
+
redirectToLogout,
|
|
1180
1519
|
getLoginUrl,
|
|
1520
|
+
getLogoutUrl,
|
|
1181
1521
|
getSignupUrl,
|
|
1182
1522
|
createError,
|
|
1183
1523
|
exchangeCodeForTokens,
|
|
@@ -1186,6 +1526,12 @@ function createFFIDClient(config) {
|
|
|
1186
1526
|
createCheckoutSession,
|
|
1187
1527
|
createPortalSession,
|
|
1188
1528
|
verifyAccessToken,
|
|
1529
|
+
requestPasswordReset,
|
|
1530
|
+
verifyPasswordResetToken,
|
|
1531
|
+
establishResetSession,
|
|
1532
|
+
confirmPasswordReset,
|
|
1533
|
+
sendOtp,
|
|
1534
|
+
verifyOtp,
|
|
1189
1535
|
/** Token store (token mode only) */
|
|
1190
1536
|
tokenStore,
|
|
1191
1537
|
/** Resolved auth mode */
|
package/dist/server/index.d.cts
CHANGED
|
@@ -301,6 +301,55 @@ interface FFIDCreatePortalParams {
|
|
|
301
301
|
/** URL to redirect when user exits the portal */
|
|
302
302
|
returnUrl: string;
|
|
303
303
|
}
|
|
304
|
+
/**
|
|
305
|
+
* Result of a redirect operation (redirectToLogin / redirectToAuthorize / redirectToLogout)
|
|
306
|
+
*
|
|
307
|
+
* Structured return type so callers can inspect failure reasons
|
|
308
|
+
* instead of receiving a bare `false`.
|
|
309
|
+
*/
|
|
310
|
+
type FFIDRedirectResult = {
|
|
311
|
+
success: true;
|
|
312
|
+
} | {
|
|
313
|
+
success: false;
|
|
314
|
+
error: string;
|
|
315
|
+
};
|
|
316
|
+
|
|
317
|
+
/** OTP / magic link methods - sendOtp / verifyOtp */
|
|
318
|
+
|
|
319
|
+
/** Response from sendOtp */
|
|
320
|
+
interface FFIDOtpSendResponse {
|
|
321
|
+
message: string;
|
|
322
|
+
}
|
|
323
|
+
/** Response from verifyOtp */
|
|
324
|
+
interface FFIDOtpVerifyResponse {
|
|
325
|
+
user: {
|
|
326
|
+
id: string;
|
|
327
|
+
email: string;
|
|
328
|
+
displayName: string | null;
|
|
329
|
+
avatarUrl: string | null;
|
|
330
|
+
};
|
|
331
|
+
session: {
|
|
332
|
+
accessToken: string;
|
|
333
|
+
refreshToken: string;
|
|
334
|
+
expiresAt: number;
|
|
335
|
+
expiresIn: number;
|
|
336
|
+
};
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
/** Password reset methods - requestPasswordReset / verifyPasswordResetToken / establishResetSession / confirmPasswordReset */
|
|
340
|
+
|
|
341
|
+
/** Response from requestPasswordReset */
|
|
342
|
+
interface FFIDPasswordResetResponse {
|
|
343
|
+
message: string;
|
|
344
|
+
}
|
|
345
|
+
/** Response from verifyPasswordResetToken */
|
|
346
|
+
interface FFIDPasswordResetVerifyResponse {
|
|
347
|
+
valid: boolean;
|
|
348
|
+
}
|
|
349
|
+
/** Response from establishResetSession */
|
|
350
|
+
type FFIDResetSessionResponse = FFIDPasswordResetResponse;
|
|
351
|
+
/** Response from confirmPasswordReset */
|
|
352
|
+
type FFIDPasswordResetConfirmResponse = FFIDPasswordResetResponse;
|
|
304
353
|
|
|
305
354
|
/**
|
|
306
355
|
* Token Store
|
|
@@ -347,8 +396,10 @@ declare function createTokenStore(storageType?: 'localStorage' | 'memory'): Toke
|
|
|
347
396
|
declare function createFFIDClient(config: FFIDConfig): {
|
|
348
397
|
getSession: () => Promise<FFIDApiResponse<FFIDSessionResponse>>;
|
|
349
398
|
signOut: () => Promise<FFIDApiResponse<void>>;
|
|
350
|
-
redirectToLogin: () => Promise<
|
|
399
|
+
redirectToLogin: () => Promise<FFIDRedirectResult>;
|
|
400
|
+
redirectToLogout: (postLogoutRedirectUri?: string) => FFIDRedirectResult;
|
|
351
401
|
getLoginUrl: (redirectUrl?: string) => string;
|
|
402
|
+
getLogoutUrl: (postLogoutRedirectUri?: string) => string;
|
|
352
403
|
getSignupUrl: (redirectUrl?: string) => string;
|
|
353
404
|
createError: (code: string, message: string) => FFIDError;
|
|
354
405
|
exchangeCodeForTokens: (code: string, codeVerifier?: string) => Promise<FFIDApiResponse<void>>;
|
|
@@ -360,6 +411,17 @@ declare function createFFIDClient(config: FFIDConfig): {
|
|
|
360
411
|
createCheckoutSession: (params: FFIDCreateCheckoutParams) => Promise<FFIDApiResponse<FFIDCheckoutSessionResponse>>;
|
|
361
412
|
createPortalSession: (params: FFIDCreatePortalParams) => Promise<FFIDApiResponse<FFIDPortalSessionResponse>>;
|
|
362
413
|
verifyAccessToken: (accessToken: string, options?: FFIDVerifyAccessTokenOptions) => Promise<FFIDApiResponse<FFIDOAuthUserInfo>>;
|
|
414
|
+
requestPasswordReset: (email: string) => Promise<FFIDApiResponse<FFIDPasswordResetResponse>>;
|
|
415
|
+
verifyPasswordResetToken: (accessToken: string) => Promise<FFIDApiResponse<FFIDPasswordResetVerifyResponse>>;
|
|
416
|
+
establishResetSession: (accessToken: string, refreshToken: string) => Promise<FFIDApiResponse<FFIDResetSessionResponse>>;
|
|
417
|
+
confirmPasswordReset: (password: string) => Promise<FFIDApiResponse<FFIDPasswordResetConfirmResponse>>;
|
|
418
|
+
sendOtp: (email: string, options?: {
|
|
419
|
+
redirectUrl?: string;
|
|
420
|
+
}) => Promise<FFIDApiResponse<FFIDOtpSendResponse>>;
|
|
421
|
+
verifyOtp: (params: {
|
|
422
|
+
accessToken: string;
|
|
423
|
+
refreshToken: string;
|
|
424
|
+
}) => Promise<FFIDApiResponse<FFIDOtpVerifyResponse>>;
|
|
363
425
|
/** Token store (token mode only) */
|
|
364
426
|
tokenStore: TokenStore;
|
|
365
427
|
/** Resolved auth mode */
|
|
@@ -428,4 +490,4 @@ interface KVNamespaceLike {
|
|
|
428
490
|
*/
|
|
429
491
|
declare function createKVCacheAdapter(kv: KVNamespaceLike): FFIDCacheAdapter;
|
|
430
492
|
|
|
431
|
-
export { type FFIDCacheAdapter, type FFIDCacheConfig, type FFIDClient, type FFIDConfig, type FFIDOAuthUserInfo, type FFIDOrganization, type FFIDSubscription, type FFIDUser, type FFIDVerifyAccessTokenOptions, type KVNamespaceLike, type TokenData, type TokenStore, createFFIDClient, createKVCacheAdapter, createMemoryCacheAdapter, createTokenStore, createVerifyAccessToken };
|
|
493
|
+
export { type FFIDCacheAdapter, type FFIDCacheConfig, type FFIDClient, type FFIDConfig, type FFIDOAuthUserInfo, type FFIDOrganization, type FFIDOtpSendResponse, type FFIDOtpVerifyResponse, type FFIDPasswordResetConfirmResponse, type FFIDPasswordResetResponse, type FFIDPasswordResetVerifyResponse, type FFIDResetSessionResponse, type FFIDSubscription, type FFIDUser, type FFIDVerifyAccessTokenOptions, type KVNamespaceLike, type TokenData, type TokenStore, createFFIDClient, createKVCacheAdapter, createMemoryCacheAdapter, createTokenStore, createVerifyAccessToken };
|
package/dist/server/index.d.ts
CHANGED
|
@@ -301,6 +301,55 @@ interface FFIDCreatePortalParams {
|
|
|
301
301
|
/** URL to redirect when user exits the portal */
|
|
302
302
|
returnUrl: string;
|
|
303
303
|
}
|
|
304
|
+
/**
|
|
305
|
+
* Result of a redirect operation (redirectToLogin / redirectToAuthorize / redirectToLogout)
|
|
306
|
+
*
|
|
307
|
+
* Structured return type so callers can inspect failure reasons
|
|
308
|
+
* instead of receiving a bare `false`.
|
|
309
|
+
*/
|
|
310
|
+
type FFIDRedirectResult = {
|
|
311
|
+
success: true;
|
|
312
|
+
} | {
|
|
313
|
+
success: false;
|
|
314
|
+
error: string;
|
|
315
|
+
};
|
|
316
|
+
|
|
317
|
+
/** OTP / magic link methods - sendOtp / verifyOtp */
|
|
318
|
+
|
|
319
|
+
/** Response from sendOtp */
|
|
320
|
+
interface FFIDOtpSendResponse {
|
|
321
|
+
message: string;
|
|
322
|
+
}
|
|
323
|
+
/** Response from verifyOtp */
|
|
324
|
+
interface FFIDOtpVerifyResponse {
|
|
325
|
+
user: {
|
|
326
|
+
id: string;
|
|
327
|
+
email: string;
|
|
328
|
+
displayName: string | null;
|
|
329
|
+
avatarUrl: string | null;
|
|
330
|
+
};
|
|
331
|
+
session: {
|
|
332
|
+
accessToken: string;
|
|
333
|
+
refreshToken: string;
|
|
334
|
+
expiresAt: number;
|
|
335
|
+
expiresIn: number;
|
|
336
|
+
};
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
/** Password reset methods - requestPasswordReset / verifyPasswordResetToken / establishResetSession / confirmPasswordReset */
|
|
340
|
+
|
|
341
|
+
/** Response from requestPasswordReset */
|
|
342
|
+
interface FFIDPasswordResetResponse {
|
|
343
|
+
message: string;
|
|
344
|
+
}
|
|
345
|
+
/** Response from verifyPasswordResetToken */
|
|
346
|
+
interface FFIDPasswordResetVerifyResponse {
|
|
347
|
+
valid: boolean;
|
|
348
|
+
}
|
|
349
|
+
/** Response from establishResetSession */
|
|
350
|
+
type FFIDResetSessionResponse = FFIDPasswordResetResponse;
|
|
351
|
+
/** Response from confirmPasswordReset */
|
|
352
|
+
type FFIDPasswordResetConfirmResponse = FFIDPasswordResetResponse;
|
|
304
353
|
|
|
305
354
|
/**
|
|
306
355
|
* Token Store
|
|
@@ -347,8 +396,10 @@ declare function createTokenStore(storageType?: 'localStorage' | 'memory'): Toke
|
|
|
347
396
|
declare function createFFIDClient(config: FFIDConfig): {
|
|
348
397
|
getSession: () => Promise<FFIDApiResponse<FFIDSessionResponse>>;
|
|
349
398
|
signOut: () => Promise<FFIDApiResponse<void>>;
|
|
350
|
-
redirectToLogin: () => Promise<
|
|
399
|
+
redirectToLogin: () => Promise<FFIDRedirectResult>;
|
|
400
|
+
redirectToLogout: (postLogoutRedirectUri?: string) => FFIDRedirectResult;
|
|
351
401
|
getLoginUrl: (redirectUrl?: string) => string;
|
|
402
|
+
getLogoutUrl: (postLogoutRedirectUri?: string) => string;
|
|
352
403
|
getSignupUrl: (redirectUrl?: string) => string;
|
|
353
404
|
createError: (code: string, message: string) => FFIDError;
|
|
354
405
|
exchangeCodeForTokens: (code: string, codeVerifier?: string) => Promise<FFIDApiResponse<void>>;
|
|
@@ -360,6 +411,17 @@ declare function createFFIDClient(config: FFIDConfig): {
|
|
|
360
411
|
createCheckoutSession: (params: FFIDCreateCheckoutParams) => Promise<FFIDApiResponse<FFIDCheckoutSessionResponse>>;
|
|
361
412
|
createPortalSession: (params: FFIDCreatePortalParams) => Promise<FFIDApiResponse<FFIDPortalSessionResponse>>;
|
|
362
413
|
verifyAccessToken: (accessToken: string, options?: FFIDVerifyAccessTokenOptions) => Promise<FFIDApiResponse<FFIDOAuthUserInfo>>;
|
|
414
|
+
requestPasswordReset: (email: string) => Promise<FFIDApiResponse<FFIDPasswordResetResponse>>;
|
|
415
|
+
verifyPasswordResetToken: (accessToken: string) => Promise<FFIDApiResponse<FFIDPasswordResetVerifyResponse>>;
|
|
416
|
+
establishResetSession: (accessToken: string, refreshToken: string) => Promise<FFIDApiResponse<FFIDResetSessionResponse>>;
|
|
417
|
+
confirmPasswordReset: (password: string) => Promise<FFIDApiResponse<FFIDPasswordResetConfirmResponse>>;
|
|
418
|
+
sendOtp: (email: string, options?: {
|
|
419
|
+
redirectUrl?: string;
|
|
420
|
+
}) => Promise<FFIDApiResponse<FFIDOtpSendResponse>>;
|
|
421
|
+
verifyOtp: (params: {
|
|
422
|
+
accessToken: string;
|
|
423
|
+
refreshToken: string;
|
|
424
|
+
}) => Promise<FFIDApiResponse<FFIDOtpVerifyResponse>>;
|
|
363
425
|
/** Token store (token mode only) */
|
|
364
426
|
tokenStore: TokenStore;
|
|
365
427
|
/** Resolved auth mode */
|
|
@@ -428,4 +490,4 @@ interface KVNamespaceLike {
|
|
|
428
490
|
*/
|
|
429
491
|
declare function createKVCacheAdapter(kv: KVNamespaceLike): FFIDCacheAdapter;
|
|
430
492
|
|
|
431
|
-
export { type FFIDCacheAdapter, type FFIDCacheConfig, type FFIDClient, type FFIDConfig, type FFIDOAuthUserInfo, type FFIDOrganization, type FFIDSubscription, type FFIDUser, type FFIDVerifyAccessTokenOptions, type KVNamespaceLike, type TokenData, type TokenStore, createFFIDClient, createKVCacheAdapter, createMemoryCacheAdapter, createTokenStore, createVerifyAccessToken };
|
|
493
|
+
export { type FFIDCacheAdapter, type FFIDCacheConfig, type FFIDClient, type FFIDConfig, type FFIDOAuthUserInfo, type FFIDOrganization, type FFIDOtpSendResponse, type FFIDOtpVerifyResponse, type FFIDPasswordResetConfirmResponse, type FFIDPasswordResetResponse, type FFIDPasswordResetVerifyResponse, type FFIDResetSessionResponse, type FFIDSubscription, type FFIDUser, type FFIDVerifyAccessTokenOptions, type KVNamespaceLike, type TokenData, type TokenStore, createFFIDClient, createKVCacheAdapter, createMemoryCacheAdapter, createTokenStore, createVerifyAccessToken };
|