@supertokens-plugins/rownd-nodejs 0.3.0-beta.0 → 0.3.0-beta.2
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/README.md +16 -0
- package/dist/bulkMigrate.js +44 -584
- package/dist/index.d.mts +12 -3
- package/dist/index.d.ts +12 -3
- package/dist/index.js +1466 -1330
- package/dist/index.mjs +1460 -1327
- package/package.json +1 -3
package/dist/index.js
CHANGED
|
@@ -271,8 +271,11 @@ __export(index_exports, {
|
|
|
271
271
|
DEFAULT_ROWND_SCHEMA: () => DEFAULT_ROWND_SCHEMA,
|
|
272
272
|
GUEST_AUTH_METHOD_ID: () => GUEST_AUTH_METHOD_ID,
|
|
273
273
|
HANDLE_BASE_PATH: () => HANDLE_BASE_PATH,
|
|
274
|
+
HUB_LOGIN_PAGE_PATH: () => HUB_LOGIN_PAGE_PATH,
|
|
275
|
+
HUB_VERIFY_EMAIL_PAGE_PATH: () => HUB_VERIFY_EMAIL_PAGE_PATH,
|
|
274
276
|
PLUGIN_ID: () => PLUGIN_ID,
|
|
275
277
|
PLUGIN_SDK_VERSION: () => PLUGIN_SDK_VERSION,
|
|
278
|
+
PLUGIN_VERSION: () => PLUGIN_VERSION,
|
|
276
279
|
PUBLIC_TENANT_ID: () => PUBLIC_TENANT_ID,
|
|
277
280
|
ROWND_JWT_CLAIMS: () => ROWND_JWT_CLAIMS,
|
|
278
281
|
ROWND_PLUGIN_ERROR_MESSAGES: () => ROWND_PLUGIN_ERROR_MESSAGES,
|
|
@@ -678,10 +681,11 @@ var buildLogger = (pluginId, version, { fileLocation = true } = {}) => {
|
|
|
678
681
|
|
|
679
682
|
// src/plugin.ts
|
|
680
683
|
var import_node = require("@rownd/node");
|
|
681
|
-
var
|
|
684
|
+
var import_supertokens_node4 = __toESM(require("supertokens-node"));
|
|
682
685
|
|
|
683
686
|
// src/constants.ts
|
|
684
687
|
var PLUGIN_ID = "supertokens-plugin-rownd";
|
|
688
|
+
var PLUGIN_VERSION = "0.3.0";
|
|
685
689
|
var PLUGIN_SDK_VERSION = ["23.0.0", "23.0.1", ">=23.0.1"];
|
|
686
690
|
var HANDLE_BASE_PATH = "/plugin/rownd";
|
|
687
691
|
var PUBLIC_TENANT_ID = "public";
|
|
@@ -718,11 +722,13 @@ var DEFAULT_ROWND_SCHEMA = {
|
|
|
718
722
|
user_visible: true
|
|
719
723
|
}
|
|
720
724
|
};
|
|
725
|
+
var HUB_LOGIN_PAGE_PATH = "/account/login";
|
|
726
|
+
var HUB_VERIFY_EMAIL_PAGE_PATH = "/account/verify-email";
|
|
721
727
|
|
|
722
728
|
// src/logger.ts
|
|
723
729
|
var { logDebugMessage, enableDebugLogs } = buildLogger(
|
|
724
730
|
PLUGIN_ID,
|
|
725
|
-
|
|
731
|
+
PLUGIN_VERSION
|
|
726
732
|
);
|
|
727
733
|
|
|
728
734
|
// src/telemetry/axiomTelemetryClient.ts
|
|
@@ -839,17 +845,6 @@ function safeRecordEvent(client, event, outcome) {
|
|
|
839
845
|
}
|
|
840
846
|
}
|
|
841
847
|
|
|
842
|
-
// src/pluginImplementation.ts
|
|
843
|
-
var import_crypto = require("crypto");
|
|
844
|
-
var import_supertokens_node = __toESM(require("supertokens-node"));
|
|
845
|
-
var import_accountlinking = __toESM(require("supertokens-node/recipe/accountlinking"));
|
|
846
|
-
var import_emailverification = __toESM(require("supertokens-node/recipe/emailverification"));
|
|
847
|
-
var import_passwordless = __toESM(require("supertokens-node/recipe/passwordless"));
|
|
848
|
-
var import_session = __toESM(require("supertokens-node/recipe/session"));
|
|
849
|
-
var import_claims = require("supertokens-node/recipe/session/claims");
|
|
850
|
-
var import_thirdparty = __toESM(require("supertokens-node/recipe/thirdparty"));
|
|
851
|
-
var import_usermetadata2 = __toESM(require("supertokens-node/recipe/usermetadata"));
|
|
852
|
-
|
|
853
848
|
// src/errors.ts
|
|
854
849
|
var ROWND_PLUGIN_ERROR_MESSAGES = {
|
|
855
850
|
MISSING_AUTHORIZATION_HEADER: "Missing authorization header",
|
|
@@ -862,7 +857,7 @@ var RowndPluginError = class extends Error {
|
|
|
862
857
|
}
|
|
863
858
|
};
|
|
864
859
|
|
|
865
|
-
// src/
|
|
860
|
+
// src/utils.ts
|
|
866
861
|
function rewriteLinkPath(inputUrl, targetPath, searchParams) {
|
|
867
862
|
try {
|
|
868
863
|
const url = new URL(inputUrl);
|
|
@@ -881,19 +876,25 @@ function rewriteLinkPath(inputUrl, targetPath, searchParams) {
|
|
|
881
876
|
return queryString ? `${path}?${queryString}` : path;
|
|
882
877
|
}
|
|
883
878
|
}
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
879
|
+
function rewriteLinkToBaseUrl(inputUrl, targetPath, baseUrl, searchParams) {
|
|
880
|
+
const normalizedBaseUrl = baseUrl.endsWith("://") ? baseUrl : baseUrl.replace(/\/+$/, "") + "/";
|
|
881
|
+
const targetUrl = new URL(
|
|
882
|
+
`${normalizedBaseUrl}${targetPath.replace(/^\//, "")}`
|
|
883
|
+
);
|
|
884
|
+
try {
|
|
885
|
+
const sourceUrl = new URL(inputUrl);
|
|
886
|
+
targetUrl.search = sourceUrl.search;
|
|
887
|
+
targetUrl.hash = sourceUrl.hash;
|
|
888
|
+
} catch {
|
|
889
|
+
const [, query = ""] = inputUrl.split("?");
|
|
890
|
+
targetUrl.search = query ? `?${query.split("#")[0]}` : "";
|
|
891
|
+
const hash = inputUrl.split("#")[1];
|
|
892
|
+
targetUrl.hash = hash ? `#${hash}` : "";
|
|
892
893
|
}
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
894
|
+
for (const [key, value] of Object.entries(searchParams ?? {})) {
|
|
895
|
+
targetUrl.searchParams.set(key, value);
|
|
896
|
+
}
|
|
897
|
+
return targetUrl.toString();
|
|
897
898
|
}
|
|
898
899
|
async function parseRequest(req) {
|
|
899
900
|
const authHeader = req.getHeaderValue("authorization");
|
|
@@ -908,386 +909,37 @@ async function parseRequest(req) {
|
|
|
908
909
|
token
|
|
909
910
|
};
|
|
910
911
|
}
|
|
911
|
-
function
|
|
912
|
-
return
|
|
913
|
-
const appVariantId = getRequestedAppVariantIdFromRequest(req);
|
|
914
|
-
const appConfig = buildAppConfig(
|
|
915
|
-
deps.pluginConfig,
|
|
916
|
-
deps.stConfig,
|
|
917
|
-
appVariantId
|
|
918
|
-
);
|
|
919
|
-
if (!appConfig) {
|
|
920
|
-
return {
|
|
921
|
-
status: "ERROR",
|
|
922
|
-
message: `Unknown Rownd app variant: ${appVariantId}`
|
|
923
|
-
};
|
|
924
|
-
}
|
|
925
|
-
return {
|
|
926
|
-
status: "OK",
|
|
927
|
-
...appConfig
|
|
928
|
-
};
|
|
929
|
-
};
|
|
912
|
+
async function getJsonBody(req) {
|
|
913
|
+
return req.getJSONBody();
|
|
930
914
|
}
|
|
931
|
-
function
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
const appVariantId = getRequestedAppVariantIdFromRequest(req);
|
|
938
|
-
assertRowndAppVariantIsConfigured(appVariantId);
|
|
939
|
-
const thirdPartyId = body.authLevel === ANONYMOUS_AUTH_METHOD_ID ? ANONYMOUS_AUTH_METHOD_ID : GUEST_AUTH_METHOD_ID;
|
|
940
|
-
const thirdPartyUserId = thirdPartyId === ANONYMOUS_AUTH_METHOD_ID ? `anon_${(0, import_crypto.randomUUID)()}` : guestId;
|
|
941
|
-
const response = await import_thirdparty.default.manuallyCreateOrUpdateUser(
|
|
942
|
-
PUBLIC_TENANT_ID,
|
|
943
|
-
thirdPartyId,
|
|
944
|
-
thirdPartyUserId,
|
|
945
|
-
`${thirdPartyUserId}@anonymous.local`,
|
|
946
|
-
false,
|
|
947
|
-
void 0,
|
|
948
|
-
userContext
|
|
949
|
-
);
|
|
950
|
-
if (response.status !== "OK") {
|
|
951
|
-
throw new Error(
|
|
952
|
-
`Guest user creation failed with status: ${response.status}`
|
|
953
|
-
);
|
|
954
|
-
}
|
|
955
|
-
await import_session.default.createNewSession(
|
|
956
|
-
req,
|
|
957
|
-
res,
|
|
958
|
-
PUBLIC_TENANT_ID,
|
|
959
|
-
response.recipeUserId,
|
|
960
|
-
{
|
|
961
|
-
...buildRowndAudience({}, appVariantId),
|
|
962
|
-
auth_level: GUEST_AUTH_METHOD_ID,
|
|
963
|
-
is_anonymous: true,
|
|
964
|
-
app_user_id: response.user.id
|
|
965
|
-
},
|
|
966
|
-
{},
|
|
967
|
-
userContext
|
|
968
|
-
);
|
|
969
|
-
logDebugMessage(`Guest session created for user: ${response.user.id}`);
|
|
970
|
-
deps.telemetryClient.recordSuccess({
|
|
971
|
-
outcome: "success",
|
|
972
|
-
durationMs: Date.now() - startedAt,
|
|
973
|
-
tenantId: PUBLIC_TENANT_ID,
|
|
974
|
-
superTokensUserId: response.user.id
|
|
975
|
-
});
|
|
976
|
-
return {
|
|
977
|
-
status: "OK",
|
|
978
|
-
createdNewRecipeUser: response.createdNewRecipeUser
|
|
979
|
-
};
|
|
980
|
-
} catch (error) {
|
|
981
|
-
logDebugMessage(`Guest login failed. Error: ${getErrorMessage(error)}`);
|
|
982
|
-
deps.telemetryClient.recordError({
|
|
983
|
-
error,
|
|
984
|
-
startedAt,
|
|
985
|
-
tenantId: PUBLIC_TENANT_ID
|
|
986
|
-
});
|
|
987
|
-
return {
|
|
988
|
-
status: "ERROR",
|
|
989
|
-
message: "Guest login failed"
|
|
990
|
-
};
|
|
991
|
-
}
|
|
915
|
+
function parseGuestBody(value) {
|
|
916
|
+
if (!isJsonRecord(value)) {
|
|
917
|
+
return {};
|
|
918
|
+
}
|
|
919
|
+
return {
|
|
920
|
+
authLevel: typeof value.auth_level === "string" ? value.auth_level : void 0
|
|
992
921
|
};
|
|
993
922
|
}
|
|
994
|
-
function
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
let recipeUserId;
|
|
1002
|
-
try {
|
|
1003
|
-
if (!deps.stConfig.supertokens) {
|
|
1004
|
-
throw new Error("Supertokens config not found");
|
|
1005
|
-
}
|
|
1006
|
-
const parsed = await parseRequest(req);
|
|
1007
|
-
const appVariantId = getRequestedAppVariantIdFromRequest(req);
|
|
1008
|
-
assertRowndAppVariantIsConfigured(appVariantId);
|
|
1009
|
-
rowndUserId = await validateRowndToken(parsed.token);
|
|
1010
|
-
user = await import_supertokens_node.default.getUser(rowndUserId, userContext);
|
|
1011
|
-
if (!user) {
|
|
1012
|
-
const rowndUser = await fetchRowndUserInfo(rowndUserId);
|
|
1013
|
-
const stUserImport = mapRowndUserToSuperTokens(rowndUser);
|
|
1014
|
-
try {
|
|
1015
|
-
const importedUser = await importUser(
|
|
1016
|
-
stUserImport,
|
|
1017
|
-
deps.stConfig.supertokens
|
|
1018
|
-
);
|
|
1019
|
-
superTokensUserId = importedUser.id;
|
|
1020
|
-
if (importedUser.loginMethods[0]?.recipeUserId) {
|
|
1021
|
-
recipeUserId = import_supertokens_node.default.convertToRecipeUserId(
|
|
1022
|
-
importedUser.loginMethods[0].recipeUserId
|
|
1023
|
-
);
|
|
1024
|
-
}
|
|
1025
|
-
} catch (err) {
|
|
1026
|
-
user = await import_supertokens_node.default.getUser(rowndUserId, userContext);
|
|
1027
|
-
if (!user) {
|
|
1028
|
-
throw err;
|
|
1029
|
-
}
|
|
1030
|
-
superTokensUserId = user.id;
|
|
1031
|
-
recipeUserId = user.loginMethods[0]?.recipeUserId;
|
|
1032
|
-
logDebugMessage(
|
|
1033
|
-
`User already migrated (race condition). tenantId: ${PUBLIC_TENANT_ID}, rowndUserId: ${rowndUserId}`
|
|
1034
|
-
);
|
|
1035
|
-
}
|
|
1036
|
-
logDebugMessage(
|
|
1037
|
-
`User migrated successfully. tenantId: ${PUBLIC_TENANT_ID}, rowndUserId: ${rowndUserId}`
|
|
1038
|
-
);
|
|
1039
|
-
} else {
|
|
1040
|
-
superTokensUserId = user.id;
|
|
1041
|
-
recipeUserId = user.loginMethods[0]?.recipeUserId;
|
|
1042
|
-
logDebugMessage(
|
|
1043
|
-
`User already migrated. tenantId: ${PUBLIC_TENANT_ID}, rowndUserId: ${rowndUserId}`
|
|
1044
|
-
);
|
|
1045
|
-
}
|
|
1046
|
-
if (superTokensUserId) {
|
|
1047
|
-
await recordRowndAppVariantForUser(superTokensUserId, appVariantId);
|
|
1048
|
-
}
|
|
1049
|
-
if (!recipeUserId) {
|
|
1050
|
-
throw new Error("User not found or has no login methods");
|
|
1051
|
-
}
|
|
1052
|
-
await import_session.default.createNewSession(
|
|
1053
|
-
req,
|
|
1054
|
-
res,
|
|
1055
|
-
PUBLIC_TENANT_ID,
|
|
1056
|
-
recipeUserId,
|
|
1057
|
-
{
|
|
1058
|
-
...buildRowndAudience({}, appVariantId)
|
|
1059
|
-
},
|
|
1060
|
-
{},
|
|
1061
|
-
userContext
|
|
1062
|
-
);
|
|
1063
|
-
logDebugMessage(
|
|
1064
|
-
`Session migrated successfully. tenantId: ${PUBLIC_TENANT_ID}, userId: ${superTokensUserId}`
|
|
1065
|
-
);
|
|
1066
|
-
deps.telemetryClient.recordSuccess({
|
|
1067
|
-
outcome: "success",
|
|
1068
|
-
durationMs: Date.now() - startedAt,
|
|
1069
|
-
tenantId,
|
|
1070
|
-
rowndUserId,
|
|
1071
|
-
superTokensUserId
|
|
1072
|
-
});
|
|
1073
|
-
return { status: "OK" };
|
|
1074
|
-
} catch (error) {
|
|
1075
|
-
logDebugMessage(`Migration failed. Error: ${getErrorMessage(error)}`);
|
|
1076
|
-
deps.telemetryClient.recordError({
|
|
1077
|
-
error,
|
|
1078
|
-
startedAt,
|
|
1079
|
-
tenantId,
|
|
1080
|
-
rowndUserId,
|
|
1081
|
-
superTokensUserId
|
|
1082
|
-
});
|
|
1083
|
-
return {
|
|
1084
|
-
status: "ERROR",
|
|
1085
|
-
message: error instanceof RowndPluginError ? error.message : "Migration failed"
|
|
1086
|
-
};
|
|
1087
|
-
}
|
|
923
|
+
function parseUpdateUserBody(value) {
|
|
924
|
+
if (!isJsonRecord(value) || !isJsonRecord(value.data)) {
|
|
925
|
+
return {};
|
|
926
|
+
}
|
|
927
|
+
return {
|
|
928
|
+
data: value.data,
|
|
929
|
+
...isJsonRecord(value.context) ? { context: value.context } : {}
|
|
1088
930
|
};
|
|
1089
931
|
}
|
|
1090
|
-
function
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
...await getUserById(session.getUserId())
|
|
1096
|
-
};
|
|
1097
|
-
};
|
|
932
|
+
function parseUpdateMetaBody(value) {
|
|
933
|
+
if (!isJsonRecord(value) || !isJsonRecord(value.meta)) {
|
|
934
|
+
return {};
|
|
935
|
+
}
|
|
936
|
+
return { meta: value.meta };
|
|
1098
937
|
}
|
|
1099
|
-
function
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
const payload = parseUpdateUserBody(await getJsonBody(req));
|
|
1105
|
-
const inputData = payload.data ?? {};
|
|
1106
|
-
const requestUserContext = {
|
|
1107
|
-
...userContext,
|
|
1108
|
-
...payload.context
|
|
1109
|
-
};
|
|
1110
|
-
const { email, ...dataWithoutEmail } = inputData;
|
|
1111
|
-
const hasEmailUpdate = hasOwn(inputData, "email") && typeof email === "string";
|
|
1112
|
-
const permissionError = validateWritableFields(
|
|
1113
|
-
Object.keys(dataWithoutEmail)
|
|
1114
|
-
);
|
|
1115
|
-
if (permissionError) {
|
|
1116
|
-
return permissionError;
|
|
1117
|
-
}
|
|
1118
|
-
if (Object.keys(dataWithoutEmail).length > 0) {
|
|
1119
|
-
await updateUserData(session.getUserId(), dataWithoutEmail);
|
|
1120
|
-
}
|
|
1121
|
-
if (hasEmailUpdate) {
|
|
1122
|
-
return {
|
|
1123
|
-
status: "OK",
|
|
1124
|
-
...await startPendingEmailVerification({
|
|
1125
|
-
userId: session.getUserId(),
|
|
1126
|
-
recipeUserId: session.getRecipeUserId(),
|
|
1127
|
-
tenantId: session.getTenantId(),
|
|
1128
|
-
email,
|
|
1129
|
-
pendingVerificationId: (0, import_crypto.randomUUID)(),
|
|
1130
|
-
userContext: appVariantId ? { ...requestUserContext, rowndAppVariantId: appVariantId } : requestUserContext
|
|
1131
|
-
})
|
|
1132
|
-
};
|
|
1133
|
-
}
|
|
1134
|
-
return {
|
|
1135
|
-
status: "OK",
|
|
1136
|
-
...await getUserById(session.getUserId())
|
|
1137
|
-
};
|
|
1138
|
-
};
|
|
1139
|
-
}
|
|
1140
|
-
function handleDeleteUser() {
|
|
1141
|
-
return async (_req, _res, maybeSession) => {
|
|
1142
|
-
const session = requireSession(maybeSession);
|
|
1143
|
-
await import_supertokens_node.default.deleteUser(session.getUserId(), true);
|
|
1144
|
-
return { status: "OK" };
|
|
1145
|
-
};
|
|
1146
|
-
}
|
|
1147
|
-
function handleSignOut() {
|
|
1148
|
-
return async (_req, _res, maybeSession, userContext) => {
|
|
1149
|
-
const session = requireSession(maybeSession);
|
|
1150
|
-
await import_session.default.revokeAllSessionsForUser(
|
|
1151
|
-
session.getUserId(),
|
|
1152
|
-
true,
|
|
1153
|
-
session.getTenantId(),
|
|
1154
|
-
userContext
|
|
1155
|
-
);
|
|
1156
|
-
return { status: "OK" };
|
|
1157
|
-
};
|
|
1158
|
-
}
|
|
1159
|
-
function handleGetUserMeta() {
|
|
1160
|
-
return async (_req, _res, maybeSession) => {
|
|
1161
|
-
const session = requireSession(maybeSession);
|
|
1162
|
-
const metadata = await getUserMetadata(session.getUserId());
|
|
1163
|
-
return {
|
|
1164
|
-
status: "OK",
|
|
1165
|
-
id: session.getUserId(),
|
|
1166
|
-
meta: Object.fromEntries(
|
|
1167
|
-
Object.entries(metadata).filter(
|
|
1168
|
-
([key]) => !isInternalMetadataField(key)
|
|
1169
|
-
)
|
|
1170
|
-
)
|
|
1171
|
-
};
|
|
1172
|
-
};
|
|
1173
|
-
}
|
|
1174
|
-
function handleUpdateUserMeta() {
|
|
1175
|
-
return async (req, _res, maybeSession) => {
|
|
1176
|
-
const session = requireSession(maybeSession);
|
|
1177
|
-
const payload = parseUpdateMetaBody(await getJsonBody(req));
|
|
1178
|
-
const internalField = Object.keys(payload.meta ?? {}).find(
|
|
1179
|
-
isInternalMetadataField
|
|
1180
|
-
);
|
|
1181
|
-
if (internalField) {
|
|
1182
|
-
return {
|
|
1183
|
-
status: "ERROR",
|
|
1184
|
-
code: 403,
|
|
1185
|
-
message: `field is not writable: ${internalField}`
|
|
1186
|
-
};
|
|
1187
|
-
}
|
|
1188
|
-
return {
|
|
1189
|
-
status: "OK",
|
|
1190
|
-
...await updateUserMetadata(session.getUserId(), payload.meta ?? {})
|
|
1191
|
-
};
|
|
1192
|
-
};
|
|
1193
|
-
}
|
|
1194
|
-
function handleGetUserField() {
|
|
1195
|
-
return async (req, _res, maybeSession) => {
|
|
1196
|
-
const session = requireSession(maybeSession);
|
|
1197
|
-
const field = req.getKeyValueFromQuery("field");
|
|
1198
|
-
if (!field) {
|
|
1199
|
-
return missingFieldResponse();
|
|
1200
|
-
}
|
|
1201
|
-
const user = await getUserById(session.getUserId());
|
|
1202
|
-
return {
|
|
1203
|
-
status: "OK",
|
|
1204
|
-
value: user.data[field]
|
|
1205
|
-
};
|
|
1206
|
-
};
|
|
1207
|
-
}
|
|
1208
|
-
function handleUpdateUserField() {
|
|
1209
|
-
return async (req, _res, maybeSession, userContext) => {
|
|
1210
|
-
const session = requireSession(maybeSession);
|
|
1211
|
-
const appVariantId = getRequestedAppVariantIdFromRequest(req);
|
|
1212
|
-
assertRowndAppVariantIsConfigured(appVariantId);
|
|
1213
|
-
const field = req.getKeyValueFromQuery("field");
|
|
1214
|
-
if (!field) {
|
|
1215
|
-
return missingFieldResponse();
|
|
1216
|
-
}
|
|
1217
|
-
const payload = parseUpdateFieldBody(await getJsonBody(req));
|
|
1218
|
-
if (field === "email" && typeof payload.value === "string") {
|
|
1219
|
-
return {
|
|
1220
|
-
status: "OK",
|
|
1221
|
-
...await startPendingEmailVerification({
|
|
1222
|
-
userId: session.getUserId(),
|
|
1223
|
-
recipeUserId: session.getRecipeUserId(),
|
|
1224
|
-
tenantId: session.getTenantId(),
|
|
1225
|
-
email: payload.value,
|
|
1226
|
-
pendingVerificationId: (0, import_crypto.randomUUID)(),
|
|
1227
|
-
userContext: appVariantId ? { ...userContext, rowndAppVariantId: appVariantId } : userContext
|
|
1228
|
-
})
|
|
1229
|
-
};
|
|
1230
|
-
}
|
|
1231
|
-
const permissionError = validateWritableFields([field]);
|
|
1232
|
-
if (permissionError) {
|
|
1233
|
-
return permissionError;
|
|
1234
|
-
}
|
|
1235
|
-
return {
|
|
1236
|
-
status: "OK",
|
|
1237
|
-
...await updateUserData(session.getUserId(), {
|
|
1238
|
-
[field]: payload.value
|
|
1239
|
-
})
|
|
1240
|
-
};
|
|
1241
|
-
};
|
|
1242
|
-
}
|
|
1243
|
-
function requireSession(session) {
|
|
1244
|
-
if (!session) {
|
|
1245
|
-
throw new Error("Session not found");
|
|
1246
|
-
}
|
|
1247
|
-
return session;
|
|
1248
|
-
}
|
|
1249
|
-
async function getJsonBody(req) {
|
|
1250
|
-
return req.getJSONBody();
|
|
1251
|
-
}
|
|
1252
|
-
function parseGuestBody(value) {
|
|
1253
|
-
if (!isJsonRecord(value)) {
|
|
1254
|
-
return {};
|
|
1255
|
-
}
|
|
1256
|
-
return {
|
|
1257
|
-
authLevel: typeof value.auth_level === "string" ? value.auth_level : void 0
|
|
1258
|
-
};
|
|
1259
|
-
}
|
|
1260
|
-
function parseUpdateUserBody(value) {
|
|
1261
|
-
if (!isJsonRecord(value) || !isJsonRecord(value.data)) {
|
|
1262
|
-
return {};
|
|
1263
|
-
}
|
|
1264
|
-
return {
|
|
1265
|
-
data: value.data,
|
|
1266
|
-
...isJsonRecord(value.context) ? { context: value.context } : {}
|
|
1267
|
-
};
|
|
1268
|
-
}
|
|
1269
|
-
function parseUpdateMetaBody(value) {
|
|
1270
|
-
if (!isJsonRecord(value) || !isJsonRecord(value.meta)) {
|
|
1271
|
-
return {};
|
|
1272
|
-
}
|
|
1273
|
-
return { meta: value.meta };
|
|
1274
|
-
}
|
|
1275
|
-
function parseUpdateFieldBody(value) {
|
|
1276
|
-
if (!isJsonRecord(value) || !hasOwn(value, "value")) {
|
|
1277
|
-
return {};
|
|
1278
|
-
}
|
|
1279
|
-
return { value: value.value };
|
|
1280
|
-
}
|
|
1281
|
-
function validateWritableFields(fields) {
|
|
1282
|
-
const readOnlyField = fields.find((field) => !canUpdateUserDataField(field));
|
|
1283
|
-
if (!readOnlyField) {
|
|
1284
|
-
return void 0;
|
|
1285
|
-
}
|
|
1286
|
-
return {
|
|
1287
|
-
status: "ERROR",
|
|
1288
|
-
code: 403,
|
|
1289
|
-
message: `field is not writable: ${readOnlyField}`
|
|
1290
|
-
};
|
|
938
|
+
function parseUpdateFieldBody(value) {
|
|
939
|
+
if (!isJsonRecord(value) || !hasOwn(value, "value")) {
|
|
940
|
+
return {};
|
|
941
|
+
}
|
|
942
|
+
return { value: value.value };
|
|
1291
943
|
}
|
|
1292
944
|
function missingFieldResponse() {
|
|
1293
945
|
return {
|
|
@@ -1299,138 +951,21 @@ function missingFieldResponse() {
|
|
|
1299
951
|
function isJsonRecord(value) {
|
|
1300
952
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1301
953
|
}
|
|
954
|
+
function isRecord(value) {
|
|
955
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
956
|
+
}
|
|
1302
957
|
function hasOwn(value, key) {
|
|
1303
958
|
return Object.prototype.hasOwnProperty.call(value, key);
|
|
1304
959
|
}
|
|
1305
|
-
function getErrorMessage(error) {
|
|
1306
|
-
return error instanceof Error ? error.message : "Unknown error";
|
|
1307
|
-
}
|
|
1308
|
-
function mapRowndUserToSuperTokens(rowndUser) {
|
|
1309
|
-
const loginMethods = [];
|
|
1310
|
-
const rowndUserData = rowndUser.data || {};
|
|
1311
|
-
const rowndUserVerifiedData = rowndUser.verified_data || {};
|
|
1312
|
-
if (!rowndUserData.user_id) {
|
|
1313
|
-
throw new Error("Rownd user has no user_id");
|
|
1314
|
-
}
|
|
1315
|
-
if (rowndUserData.google_id) {
|
|
1316
|
-
if (!rowndUserData.email) {
|
|
1317
|
-
throw new Error("Rownd Google user is missing email");
|
|
1318
|
-
}
|
|
1319
|
-
loginMethods.push({
|
|
1320
|
-
recipeId: "thirdparty",
|
|
1321
|
-
thirdPartyId: "google",
|
|
1322
|
-
thirdPartyUserId: rowndUserData.google_id,
|
|
1323
|
-
email: rowndUserData.email,
|
|
1324
|
-
isVerified: !!rowndUserVerifiedData.google_id
|
|
1325
|
-
});
|
|
1326
|
-
}
|
|
1327
|
-
if (rowndUserData.apple_id) {
|
|
1328
|
-
if (!rowndUserData.email) {
|
|
1329
|
-
throw new Error("Rownd Apple user is missing email");
|
|
1330
|
-
}
|
|
1331
|
-
loginMethods.push({
|
|
1332
|
-
recipeId: "thirdparty",
|
|
1333
|
-
thirdPartyId: "apple",
|
|
1334
|
-
thirdPartyUserId: rowndUserData.apple_id,
|
|
1335
|
-
email: rowndUserData.email,
|
|
1336
|
-
isVerified: !!rowndUserVerifiedData.apple_id
|
|
1337
|
-
});
|
|
1338
|
-
}
|
|
1339
|
-
if (rowndUserData.phone_number) {
|
|
1340
|
-
loginMethods.push({
|
|
1341
|
-
recipeId: "passwordless",
|
|
1342
|
-
phoneNumber: rowndUserData.phone_number,
|
|
1343
|
-
isVerified: !!rowndUserVerifiedData.phone_number
|
|
1344
|
-
});
|
|
1345
|
-
}
|
|
1346
|
-
if (rowndUserData.email && !rowndUserData.google_id && !rowndUserData.apple_id) {
|
|
1347
|
-
loginMethods.push({
|
|
1348
|
-
recipeId: "passwordless",
|
|
1349
|
-
email: rowndUserData.email,
|
|
1350
|
-
isVerified: !!rowndUserVerifiedData.email
|
|
1351
|
-
});
|
|
1352
|
-
}
|
|
1353
|
-
let authLevel = rowndUser.auth_level;
|
|
1354
|
-
if (loginMethods.length === 0) {
|
|
1355
|
-
const thirdPartyId = authLevel === GUEST_AUTH_METHOD_ID ? GUEST_AUTH_METHOD_ID : ANONYMOUS_AUTH_METHOD_ID;
|
|
1356
|
-
if (!authLevel) authLevel = thirdPartyId;
|
|
1357
|
-
loginMethods.push({
|
|
1358
|
-
recipeId: "thirdparty",
|
|
1359
|
-
thirdPartyId,
|
|
1360
|
-
thirdPartyUserId: rowndUserData.user_id,
|
|
1361
|
-
email: `${rowndUserData.user_id}@anonymous.local`,
|
|
1362
|
-
isVerified: false
|
|
1363
|
-
});
|
|
1364
|
-
}
|
|
1365
|
-
const userMetadata = buildRowndUserMetadata(rowndUser);
|
|
1366
|
-
return {
|
|
1367
|
-
externalUserId: rowndUserData.user_id,
|
|
1368
|
-
loginMethods,
|
|
1369
|
-
userMetadata
|
|
1370
|
-
};
|
|
1371
|
-
}
|
|
1372
|
-
async function importUser(stUser, config2) {
|
|
1373
|
-
const headers = {
|
|
1374
|
-
"Content-Type": "application/json"
|
|
1375
|
-
};
|
|
1376
|
-
if (config2.apiKey) {
|
|
1377
|
-
headers["api-key"] = config2.apiKey;
|
|
1378
|
-
}
|
|
1379
|
-
const response = await fetch(`${config2.connectionURI}/bulk-import/import`, {
|
|
1380
|
-
method: "POST",
|
|
1381
|
-
headers,
|
|
1382
|
-
body: JSON.stringify(stUser)
|
|
1383
|
-
});
|
|
1384
|
-
if (!response.ok) {
|
|
1385
|
-
const errorText = await response.text();
|
|
1386
|
-
throw new Error(
|
|
1387
|
-
`Bulk import failed with status ${response.status}: ${errorText}`
|
|
1388
|
-
);
|
|
1389
|
-
}
|
|
1390
|
-
const importResponse = await response.json();
|
|
1391
|
-
if (importResponse.status !== "OK" || !importResponse.user) {
|
|
1392
|
-
throw new Error(
|
|
1393
|
-
`Bulk import failed: ${importResponse.message || "Missing user in response"}`
|
|
1394
|
-
);
|
|
1395
|
-
}
|
|
1396
|
-
return importResponse.user;
|
|
1397
|
-
}
|
|
1398
|
-
async function validateRowndToken(token) {
|
|
1399
|
-
const client = getRowndClient();
|
|
1400
|
-
const tokenInfo = await client.validateToken(token);
|
|
1401
|
-
return tokenInfo.user_id;
|
|
1402
|
-
}
|
|
1403
|
-
async function fetchRowndUserInfo(userId) {
|
|
1404
|
-
const client = getRowndClient();
|
|
1405
|
-
const rowndUser = await client.fetchUserInfo({ user_id: userId });
|
|
1406
|
-
if (!rowndUser) {
|
|
1407
|
-
throw new RowndPluginError("ROWND_USER_NOT_FOUND");
|
|
1408
|
-
}
|
|
1409
|
-
return rowndUser;
|
|
1410
|
-
}
|
|
1411
|
-
var IDENTITY_USER_DATA_FIELDS = /* @__PURE__ */ new Set([
|
|
1412
|
-
"user_id",
|
|
1413
|
-
"email",
|
|
1414
|
-
"phone_number",
|
|
1415
|
-
"google_id",
|
|
1416
|
-
"apple_id"
|
|
1417
|
-
]);
|
|
1418
|
-
var INTERNAL_METADATA_FIELDS = /* @__PURE__ */ new Set([
|
|
1419
|
-
"original_rownd_user",
|
|
1420
|
-
"rownd_pending_verification"
|
|
1421
|
-
]);
|
|
1422
|
-
function isIdentityField(field) {
|
|
1423
|
-
return IDENTITY_USER_DATA_FIELDS.has(field);
|
|
1424
|
-
}
|
|
1425
|
-
function isInternalMetadataField(field) {
|
|
1426
|
-
return INTERNAL_METADATA_FIELDS.has(field);
|
|
1427
|
-
}
|
|
1428
960
|
function getStringList(value) {
|
|
1429
961
|
if (Array.isArray(value)) {
|
|
1430
962
|
return value.filter((entry) => typeof entry === "string");
|
|
1431
963
|
}
|
|
1432
964
|
return typeof value === "string" ? [value] : [];
|
|
1433
965
|
}
|
|
966
|
+
function getErrorMessage(error) {
|
|
967
|
+
return error instanceof Error ? error.message : "Unknown error";
|
|
968
|
+
}
|
|
1434
969
|
function getRequestedAppVariantIdFromRequest(req) {
|
|
1435
970
|
return req.getKeyValueFromQuery("app_variant_id");
|
|
1436
971
|
}
|
|
@@ -1438,518 +973,626 @@ function getRequestedDisplayContextFromRequest(req) {
|
|
|
1438
973
|
const displayContext = req.getKeyValueFromQuery("rownd_display_context");
|
|
1439
974
|
return displayContext === "browser" || displayContext === "mobile_app" || displayContext === "customer_web_view" ? displayContext : void 0;
|
|
1440
975
|
}
|
|
976
|
+
function getRequestedClientDomainFromRequest(req) {
|
|
977
|
+
const clientDomain = req.getKeyValueFromQuery("rownd_client_domain");
|
|
978
|
+
return typeof clientDomain === "string" && clientDomain.length > 0 ? clientDomain : void 0;
|
|
979
|
+
}
|
|
1441
980
|
function getRequestedRedirectToPathFromRequest(req) {
|
|
1442
981
|
const redirectToPath = req.getKeyValueFromQuery("rownd_redirect_to_path");
|
|
1443
982
|
return typeof redirectToPath === "string" && redirectToPath.length > 0 ? redirectToPath : void 0;
|
|
1444
983
|
}
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
throw new Error(`Unknown Rownd app variant: ${appVariantId}`);
|
|
1451
|
-
}
|
|
984
|
+
|
|
985
|
+
// src/config.ts
|
|
986
|
+
var pluginConfig;
|
|
987
|
+
function setPluginConfig(config2) {
|
|
988
|
+
pluginConfig = config2;
|
|
1452
989
|
}
|
|
1453
|
-
|
|
990
|
+
function getPluginConfig() {
|
|
991
|
+
return pluginConfig;
|
|
992
|
+
}
|
|
993
|
+
function assertRowndAppVariantIsConfigured(appVariantId) {
|
|
1454
994
|
if (!appVariantId) {
|
|
1455
995
|
return;
|
|
1456
996
|
}
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
const originalRowndUser = isJsonRecord(metadata.original_rownd_user) ? metadata.original_rownd_user : {};
|
|
1460
|
-
const attributes = isJsonRecord(originalRowndUser.attributes) ? originalRowndUser.attributes : {};
|
|
1461
|
-
const appVariants = getStringList(attributes["rownd:app_variants"]);
|
|
1462
|
-
if (appVariants.includes(appVariantId)) {
|
|
1463
|
-
return;
|
|
997
|
+
if (pluginConfig?.subBrands && !pluginConfig.subBrands[appVariantId]) {
|
|
998
|
+
throw new Error(`Unknown Rownd app variant: ${appVariantId}`);
|
|
1464
999
|
}
|
|
1465
|
-
await import_usermetadata2.default.updateUserMetadata(userId, {
|
|
1466
|
-
...metadata,
|
|
1467
|
-
original_rownd_user: {
|
|
1468
|
-
...originalRowndUser,
|
|
1469
|
-
data: isJsonRecord(originalRowndUser.data) ? originalRowndUser.data : { user_id: userId },
|
|
1470
|
-
verified_data: isJsonRecord(originalRowndUser.verified_data) ? originalRowndUser.verified_data : {},
|
|
1471
|
-
attributes: {
|
|
1472
|
-
...attributes,
|
|
1473
|
-
"rownd:app_variants": [...appVariants, appVariantId]
|
|
1474
|
-
}
|
|
1475
|
-
}
|
|
1476
|
-
});
|
|
1477
1000
|
}
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1001
|
+
var BUILTIN_SIGN_IN_METHOD_KEYS = [
|
|
1002
|
+
"email",
|
|
1003
|
+
"phone",
|
|
1004
|
+
"google",
|
|
1005
|
+
"apple",
|
|
1006
|
+
"anonymous"
|
|
1007
|
+
];
|
|
1008
|
+
function normalizeSchemaField(key, field) {
|
|
1009
|
+
let ownedBy = field.owned_by;
|
|
1010
|
+
if (key === "google_id" || key === "apple_id") {
|
|
1011
|
+
ownedBy = "app";
|
|
1012
|
+
} else if (!ownedBy) {
|
|
1013
|
+
ownedBy = "user";
|
|
1487
1014
|
}
|
|
1488
|
-
return
|
|
1015
|
+
return {
|
|
1016
|
+
display_name: field.display_name,
|
|
1017
|
+
type: field.type,
|
|
1018
|
+
owned_by: ownedBy,
|
|
1019
|
+
user_visible: field.user_visible,
|
|
1020
|
+
read_only: field.read_only ?? ownedBy === "app",
|
|
1021
|
+
show_empty: field.show_empty ?? false
|
|
1022
|
+
};
|
|
1489
1023
|
}
|
|
1490
|
-
var
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
}
|
|
1498
|
-
async function buildRowndSessionClaims(userId, currentPayload = {}, appVariantId) {
|
|
1499
|
-
const user = await import_supertokens_node.default.getUser(userId);
|
|
1500
|
-
const metadata = user ? await getUserMetadata(user.id) : void 0;
|
|
1501
|
-
const originalRowndUser = metadata?.original_rownd_user;
|
|
1502
|
-
const verifiedData = originalRowndUser?.verified_data;
|
|
1503
|
-
const authLevel = getEffectiveAuthLevel(
|
|
1504
|
-
user,
|
|
1505
|
-
originalRowndUser?.auth_level,
|
|
1506
|
-
verifiedData
|
|
1024
|
+
var DEFAULT_PRIMARY_COLOR = "#5b5bd6";
|
|
1025
|
+
function buildSignInMethodsConfig(methodsArray) {
|
|
1026
|
+
const methods = (methodsArray ?? []).reduce(
|
|
1027
|
+
(acc, curr) => {
|
|
1028
|
+
acc[curr.method] = curr;
|
|
1029
|
+
return acc;
|
|
1030
|
+
},
|
|
1031
|
+
{}
|
|
1507
1032
|
);
|
|
1508
|
-
const
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1033
|
+
const customProviders = Object.fromEntries(
|
|
1034
|
+
Object.entries(methods).filter(([key]) => !BUILTIN_SIGN_IN_METHOD_KEYS.includes(key)).map(([key, val]) => {
|
|
1035
|
+
return val ? [
|
|
1036
|
+
key,
|
|
1037
|
+
{
|
|
1038
|
+
enabled: true,
|
|
1039
|
+
display_name: getStringMethodProperty(val, "displayName") ?? key,
|
|
1040
|
+
icon_light_url: getStringMethodProperty(val, "iconLightUrl"),
|
|
1041
|
+
icon_dark_url: getStringMethodProperty(val, "iconDarkUrl")
|
|
1042
|
+
}
|
|
1043
|
+
] : [key, void 0];
|
|
1044
|
+
}).filter(([, v]) => v !== void 0)
|
|
1045
|
+
);
|
|
1046
|
+
const googleMethod = methods.google;
|
|
1047
|
+
const appleMethod = methods.apple;
|
|
1048
|
+
const anonymousMethod = methods.anonymous;
|
|
1049
|
+
const anonymousType = getAnonymousType(anonymousMethod);
|
|
1050
|
+
const googleOneTap = getOneTapConfig(googleMethod);
|
|
1514
1051
|
return {
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1052
|
+
email: { enabled: !!methods.email },
|
|
1053
|
+
phone: { enabled: !!methods.phone },
|
|
1054
|
+
google: {
|
|
1055
|
+
enabled: !!googleMethod,
|
|
1056
|
+
client_id: getStringMethodProperty(googleMethod, "clientId") ?? "",
|
|
1057
|
+
ios_client_id: getStringMethodProperty(googleMethod, "iosClientId") ?? "",
|
|
1058
|
+
scopes: getStringArrayMethodProperty(googleMethod, "scopes") ?? [],
|
|
1059
|
+
...getSignInFasterWithGoogle(googleMethod) ? { sign_in_faster_with_google: getSignInFasterWithGoogle(googleMethod) } : {},
|
|
1060
|
+
one_tap: {
|
|
1061
|
+
browser: {
|
|
1062
|
+
auto_prompt: googleOneTap?.browser?.autoPrompt ?? false,
|
|
1063
|
+
delay: googleOneTap?.browser?.delay ?? 7e3
|
|
1064
|
+
},
|
|
1065
|
+
mobile_app: {
|
|
1066
|
+
auto_prompt: googleOneTap?.mobileApp?.autoPrompt ?? false,
|
|
1067
|
+
delay: googleOneTap?.mobileApp?.delay ?? 7e3
|
|
1068
|
+
}
|
|
1069
|
+
}
|
|
1070
|
+
},
|
|
1071
|
+
apple: {
|
|
1072
|
+
enabled: !!appleMethod,
|
|
1073
|
+
client_id: getStringMethodProperty(appleMethod, "clientId") ?? ""
|
|
1074
|
+
},
|
|
1075
|
+
anonymous: {
|
|
1076
|
+
enabled: !!anonymousMethod && anonymousType !== "instant",
|
|
1077
|
+
...anonymousMethod && anonymousType !== "instant" ? { type: anonymousType } : {},
|
|
1078
|
+
...anonymousType !== "instant" && getStringMethodProperty(anonymousMethod, "displayName") !== void 0 ? {
|
|
1079
|
+
display_name: getStringMethodProperty(
|
|
1080
|
+
anonymousMethod,
|
|
1081
|
+
"displayName"
|
|
1082
|
+
)
|
|
1083
|
+
} : {},
|
|
1084
|
+
...anonymousType !== "instant" && getStringMethodProperty(anonymousMethod, "iconLightUrl") !== void 0 ? {
|
|
1085
|
+
icon_light_url: getStringMethodProperty(
|
|
1086
|
+
anonymousMethod,
|
|
1087
|
+
"iconLightUrl"
|
|
1088
|
+
)
|
|
1089
|
+
} : {},
|
|
1090
|
+
...anonymousType !== "instant" && getStringMethodProperty(anonymousMethod, "iconDarkUrl") !== void 0 ? {
|
|
1091
|
+
icon_dark_url: getStringMethodProperty(
|
|
1092
|
+
anonymousMethod,
|
|
1093
|
+
"iconDarkUrl"
|
|
1094
|
+
)
|
|
1095
|
+
} : {}
|
|
1096
|
+
},
|
|
1097
|
+
...customProviders
|
|
1525
1098
|
};
|
|
1526
1099
|
}
|
|
1527
|
-
function
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
const schema = pluginConfig?.schema || DEFAULT_ROWND_SCHEMA;
|
|
1532
|
-
const claims = {};
|
|
1533
|
-
for (const [key, field] of Object.entries(schema)) {
|
|
1534
|
-
if (field.include_in_session_claims !== true) {
|
|
1535
|
-
continue;
|
|
1536
|
-
}
|
|
1537
|
-
const value = metadata.original_rownd_user?.data?.[key] ?? metadata[key];
|
|
1538
|
-
if (value !== void 0) {
|
|
1539
|
-
claims[field.session_claim_name || key] = value;
|
|
1540
|
-
}
|
|
1541
|
-
}
|
|
1542
|
-
return claims;
|
|
1100
|
+
function isInstantAnonymousMethod(methods) {
|
|
1101
|
+
return (methods ?? []).some(
|
|
1102
|
+
(method) => method.method === "anonymous" && getAnonymousType(method) === "instant"
|
|
1103
|
+
);
|
|
1543
1104
|
}
|
|
1544
|
-
function
|
|
1545
|
-
const
|
|
1546
|
-
|
|
1547
|
-
return originalUserId;
|
|
1548
|
-
}
|
|
1549
|
-
if (typeof currentPayload.app_user_id === "string") {
|
|
1550
|
-
return currentPayload.app_user_id;
|
|
1551
|
-
}
|
|
1552
|
-
return user?.id || userId;
|
|
1105
|
+
function getAnonymousType(method) {
|
|
1106
|
+
const type = getStringMethodProperty(method, "type");
|
|
1107
|
+
return type === "instant" ? "instant" : "guest";
|
|
1553
1108
|
}
|
|
1554
|
-
function
|
|
1555
|
-
const
|
|
1556
|
-
|
|
1557
|
-
if (appId) {
|
|
1558
|
-
audience.push(`app:${appId}`);
|
|
1559
|
-
}
|
|
1560
|
-
if (appVariantId) {
|
|
1561
|
-
audience.push(`app_variant:${appVariantId}`);
|
|
1562
|
-
}
|
|
1563
|
-
return audience.length > 0 ? { aud: [...new Set(audience)] } : {};
|
|
1109
|
+
function getSignInFasterWithGoogle(method) {
|
|
1110
|
+
const value = getStringMethodProperty(method, "signInFasterWithGoogle");
|
|
1111
|
+
return value === "enabled" || value === "disabled" ? value : void 0;
|
|
1564
1112
|
}
|
|
1565
|
-
function
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
return originalAnonymousId;
|
|
1113
|
+
function getMethodProperty(method, property) {
|
|
1114
|
+
if (!method) {
|
|
1115
|
+
return void 0;
|
|
1569
1116
|
}
|
|
1570
|
-
|
|
1571
|
-
return loginMethod.recipeId === "thirdparty" && getThirdPartyId(loginMethod) === ANONYMOUS_AUTH_METHOD_ID;
|
|
1572
|
-
});
|
|
1573
|
-
const thirdPartyUserId = anonymousMethod ? getThirdPartyUserId(anonymousMethod) : void 0;
|
|
1574
|
-
return thirdPartyUserId || (hasAnonymousLoginMethod(user) ? `anon_${userId}` : void 0);
|
|
1117
|
+
return method[property];
|
|
1575
1118
|
}
|
|
1576
|
-
|
|
1577
|
-
const
|
|
1578
|
-
|
|
1119
|
+
function getStringMethodProperty(method, property) {
|
|
1120
|
+
const value = getMethodProperty(method, property);
|
|
1121
|
+
return typeof value === "string" ? value : void 0;
|
|
1122
|
+
}
|
|
1123
|
+
function getStringArrayMethodProperty(method, property) {
|
|
1124
|
+
const value = getMethodProperty(method, property);
|
|
1125
|
+
return Array.isArray(value) && value.every((entry) => typeof entry === "string") ? value : void 0;
|
|
1126
|
+
}
|
|
1127
|
+
function getOneTapConfig(method) {
|
|
1128
|
+
const oneTap = getMethodProperty(method, "oneTap");
|
|
1129
|
+
if (!isRecord(oneTap)) {
|
|
1579
1130
|
return void 0;
|
|
1580
1131
|
}
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
if (!currentUser || isGuestAccountInfo(newAccountInfo)) {
|
|
1132
|
+
return {
|
|
1133
|
+
browser: parseOneTapPlatform(oneTap.browser),
|
|
1134
|
+
mobileApp: parseOneTapPlatform(oneTap.mobileApp)
|
|
1135
|
+
};
|
|
1136
|
+
}
|
|
1137
|
+
function parseOneTapPlatform(value) {
|
|
1138
|
+
if (!isRecord(value)) {
|
|
1589
1139
|
return void 0;
|
|
1590
1140
|
}
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
};
|
|
1596
|
-
}
|
|
1597
|
-
return void 0;
|
|
1598
|
-
}
|
|
1599
|
-
async function getUserMetadata(userId) {
|
|
1600
|
-
const metadata = await import_usermetadata2.default.getUserMetadata(userId);
|
|
1601
|
-
return metadata.metadata || {};
|
|
1141
|
+
return {
|
|
1142
|
+
autoPrompt: typeof value.autoPrompt === "boolean" ? value.autoPrompt : void 0,
|
|
1143
|
+
delay: typeof value.delay === "number" ? value.delay : void 0
|
|
1144
|
+
};
|
|
1602
1145
|
}
|
|
1603
|
-
function
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
return pendingVerification.filter(isPendingVerification);
|
|
1146
|
+
function getSubBrandVariant(app) {
|
|
1147
|
+
if (isRecord(app) && isRecord(app.variant) && typeof app.variant.id === "string") {
|
|
1148
|
+
return app.variant;
|
|
1607
1149
|
}
|
|
1608
|
-
return
|
|
1609
|
-
}
|
|
1610
|
-
function isPendingVerification(value) {
|
|
1611
|
-
return isRecord(value) && typeof value.id === "string" && typeof value.field === "string" && typeof value.value === "string" && typeof value.created_at === "string";
|
|
1150
|
+
return void 0;
|
|
1612
1151
|
}
|
|
1613
|
-
|
|
1614
|
-
const
|
|
1615
|
-
const
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
}
|
|
1619
|
-
const originalRowndUser = metadata.original_rownd_user;
|
|
1620
|
-
const rowndUser = originalRowndUser?.data?.user_id || userId;
|
|
1621
|
-
const state = originalRowndUser?.state || "enabled";
|
|
1622
|
-
const dataFieldKeys = /* @__PURE__ */ new Set();
|
|
1623
|
-
const data = {
|
|
1624
|
-
user_id: userId
|
|
1625
|
-
};
|
|
1626
|
-
for (const [key, value] of Object.entries(originalRowndUser?.data || {})) {
|
|
1627
|
-
if (!isIdentityField(key)) {
|
|
1628
|
-
data[key] = value;
|
|
1629
|
-
dataFieldKeys.add(key);
|
|
1630
|
-
}
|
|
1631
|
-
}
|
|
1632
|
-
const schema = pluginConfig?.schema || DEFAULT_ROWND_SCHEMA;
|
|
1633
|
-
for (const key of Object.keys(schema)) {
|
|
1634
|
-
dataFieldKeys.add(key);
|
|
1635
|
-
if (!isInternalMetadataField(key) && !isIdentityField(key) && metadata[key] !== void 0) {
|
|
1636
|
-
data[key] = metadata[key];
|
|
1152
|
+
function mergeConfigInput(base, override) {
|
|
1153
|
+
const result = { ...base };
|
|
1154
|
+
for (const [key, value] of Object.entries(override)) {
|
|
1155
|
+
if (value === void 0) {
|
|
1156
|
+
continue;
|
|
1637
1157
|
}
|
|
1158
|
+
const existing = result[key];
|
|
1159
|
+
result[key] = isRecord(existing) && isRecord(value) ? mergeConfigInput(existing, value) : value;
|
|
1638
1160
|
}
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
if (method.email) {
|
|
1649
|
-
verifiedData.email = method.email;
|
|
1650
|
-
if (data.email === void 0) data.email = method.email;
|
|
1651
|
-
}
|
|
1652
|
-
if (method.phoneNumber) {
|
|
1653
|
-
verifiedData.phone_number = method.phoneNumber;
|
|
1654
|
-
if (data.phone_number === void 0)
|
|
1655
|
-
data.phone_number = method.phoneNumber;
|
|
1656
|
-
}
|
|
1657
|
-
} else if (method.recipeId === "thirdparty") {
|
|
1658
|
-
const thirdPartyId = getThirdPartyId(method);
|
|
1659
|
-
const thirdPartyUserId = getThirdPartyUserId(method);
|
|
1660
|
-
if (method.verified && method.email) {
|
|
1661
|
-
verifiedData.email = method.email;
|
|
1662
|
-
}
|
|
1663
|
-
if (method.email && data.email === void 0) {
|
|
1664
|
-
data.email = method.email;
|
|
1665
|
-
}
|
|
1666
|
-
if (thirdPartyId === "google" && thirdPartyUserId) {
|
|
1667
|
-
data.google_id = thirdPartyUserId;
|
|
1668
|
-
verifiedData.google_id = thirdPartyUserId;
|
|
1669
|
-
}
|
|
1670
|
-
if (thirdPartyId === "apple" && thirdPartyUserId) {
|
|
1671
|
-
data.apple_id = thirdPartyUserId;
|
|
1672
|
-
verifiedData.apple_id = thirdPartyUserId;
|
|
1673
|
-
}
|
|
1674
|
-
} else if (method.recipeId === "emailpassword") {
|
|
1675
|
-
if (method.email && data.email === void 0) {
|
|
1676
|
-
data.email = method.email;
|
|
1677
|
-
}
|
|
1678
|
-
}
|
|
1161
|
+
return result;
|
|
1162
|
+
}
|
|
1163
|
+
function buildRowndAppConfig(config2, stConfig, appVariantId) {
|
|
1164
|
+
const userSchema = config2.schema ?? DEFAULT_ROWND_SCHEMA;
|
|
1165
|
+
const baseApp = config2.appConfig ?? {};
|
|
1166
|
+
const subBrand = appVariantId ? config2.subBrands?.[appVariantId] : void 0;
|
|
1167
|
+
const app = appVariantId ? subBrand && mergeConfigInput(baseApp, subBrand) : baseApp;
|
|
1168
|
+
if (!app) {
|
|
1169
|
+
return void 0;
|
|
1679
1170
|
}
|
|
1680
|
-
|
|
1681
|
-
|
|
1171
|
+
const branding = app.branding ?? {};
|
|
1172
|
+
const auth = app.auth ?? {};
|
|
1173
|
+
const signInMethods = buildSignInMethodsConfig(app.signInMethods);
|
|
1174
|
+
const variant = getSubBrandVariant(app);
|
|
1175
|
+
const finalSchema = { ...userSchema };
|
|
1176
|
+
if (signInMethods.email.enabled && !finalSchema.email) {
|
|
1177
|
+
finalSchema.email = {
|
|
1178
|
+
display_name: "Email",
|
|
1179
|
+
type: "string",
|
|
1180
|
+
user_visible: true
|
|
1181
|
+
};
|
|
1682
1182
|
}
|
|
1683
|
-
if (
|
|
1684
|
-
|
|
1183
|
+
if (signInMethods.phone.enabled && !finalSchema.phone_number) {
|
|
1184
|
+
finalSchema.phone_number = {
|
|
1185
|
+
display_name: "Phone number",
|
|
1186
|
+
type: "string",
|
|
1187
|
+
user_visible: true
|
|
1188
|
+
};
|
|
1685
1189
|
}
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1190
|
+
if (signInMethods.google.enabled && !finalSchema.google_id) {
|
|
1191
|
+
finalSchema.google_id = {
|
|
1192
|
+
display_name: "Google ID",
|
|
1193
|
+
type: "string",
|
|
1194
|
+
user_visible: false
|
|
1195
|
+
};
|
|
1689
1196
|
}
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
if (data[key] === void 0 && field.type === "string") {
|
|
1697
|
-
data[key] = "";
|
|
1698
|
-
}
|
|
1197
|
+
if (signInMethods.apple.enabled && !finalSchema.apple_id) {
|
|
1198
|
+
finalSchema.apple_id = {
|
|
1199
|
+
display_name: "Apple ID",
|
|
1200
|
+
type: "string",
|
|
1201
|
+
user_visible: false
|
|
1202
|
+
};
|
|
1699
1203
|
}
|
|
1700
|
-
const mapMethod = (method) => {
|
|
1701
|
-
if (method.recipeId === "thirdparty") {
|
|
1702
|
-
if (getThirdPartyId(method) === "google") return "google";
|
|
1703
|
-
if (getThirdPartyId(method) === "apple") return "apple";
|
|
1704
|
-
} else if (method.recipeId === "passwordless") {
|
|
1705
|
-
if (method.email) return "email";
|
|
1706
|
-
if (method.phoneNumber) return "phone";
|
|
1707
|
-
} else if (method.recipeId === "emailpassword") {
|
|
1708
|
-
return "email";
|
|
1709
|
-
}
|
|
1710
|
-
return "email";
|
|
1711
|
-
};
|
|
1712
|
-
const sortedByJoined = [...stUser.loginMethods].sort(
|
|
1713
|
-
(a, b) => a.timeJoined - b.timeJoined
|
|
1714
|
-
);
|
|
1715
|
-
const sortedByLastUsed = [
|
|
1716
|
-
...stUser.loginMethods
|
|
1717
|
-
].sort((a, b) => (b.lastUsed || b.timeJoined) - (a.lastUsed || a.timeJoined));
|
|
1718
|
-
const firstMethod = sortedByJoined[0];
|
|
1719
|
-
const lastMethod = sortedByLastUsed[0];
|
|
1720
|
-
const metadataMeta = Object.fromEntries(
|
|
1721
|
-
Object.entries(metadata).filter(
|
|
1722
|
-
([key]) => !isInternalMetadataField(key) && !dataFieldKeys.has(key)
|
|
1723
|
-
)
|
|
1724
|
-
);
|
|
1725
|
-
const meta = {
|
|
1726
|
-
...metadataMeta,
|
|
1727
|
-
created: new Date(stUser.timeJoined).toISOString(),
|
|
1728
|
-
first_sign_in: new Date(stUser.timeJoined).toISOString(),
|
|
1729
|
-
last_sign_in: new Date(lastUsedAt).toISOString(),
|
|
1730
|
-
last_active: new Date(lastUsedAt).toISOString(),
|
|
1731
|
-
first_sign_in_method: firstMethod ? mapMethod(firstMethod) : "email",
|
|
1732
|
-
last_sign_in_method: lastMethod ? mapMethod(lastMethod) : "email"
|
|
1733
|
-
};
|
|
1734
1204
|
return {
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
const metadata = await getUserMetadata(userId);
|
|
1748
|
-
const updatedMetadata = {
|
|
1749
|
-
...metadata,
|
|
1750
|
-
...inputData
|
|
1751
|
-
};
|
|
1752
|
-
await import_usermetadata2.default.updateUserMetadata(userId, updatedMetadata);
|
|
1753
|
-
return getUserById(userId);
|
|
1754
|
-
}
|
|
1755
|
-
async function startPendingEmailVerification(input) {
|
|
1756
|
-
const metadata = await getUserMetadata(input.userId);
|
|
1757
|
-
const currentEmail = (await getUserById(input.userId)).data.email;
|
|
1758
|
-
if (currentEmail === input.email) {
|
|
1759
|
-
return getUserById(input.userId);
|
|
1760
|
-
}
|
|
1761
|
-
const pendingVerifications = getPendingVerifications(metadata);
|
|
1762
|
-
const pendingEmailVerifications = pendingVerifications.filter(
|
|
1763
|
-
(pendingVerification2) => pendingVerification2.field === "email"
|
|
1764
|
-
);
|
|
1765
|
-
for (const pendingVerification2 of pendingEmailVerifications) {
|
|
1766
|
-
await import_emailverification.default.revokeEmailVerificationTokens(
|
|
1767
|
-
input.tenantId,
|
|
1768
|
-
input.recipeUserId,
|
|
1769
|
-
pendingVerification2.value,
|
|
1770
|
-
input.userContext
|
|
1771
|
-
);
|
|
1772
|
-
}
|
|
1773
|
-
const pendingVerification = {
|
|
1774
|
-
id: input.pendingVerificationId,
|
|
1775
|
-
field: "email",
|
|
1776
|
-
value: input.email,
|
|
1777
|
-
created_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
1778
|
-
};
|
|
1779
|
-
await import_usermetadata2.default.updateUserMetadata(input.userId, {
|
|
1780
|
-
...metadata,
|
|
1781
|
-
rownd_pending_verification: [
|
|
1782
|
-
...pendingVerifications.filter(
|
|
1783
|
-
(pendingVerification2) => pendingVerification2.field !== "email"
|
|
1205
|
+
config_type: appVariantId ? "variant" : "app",
|
|
1206
|
+
...variant ? { variant } : {},
|
|
1207
|
+
app: {
|
|
1208
|
+
id: app.id ?? "",
|
|
1209
|
+
name: app.name ?? stConfig.appInfo.appName,
|
|
1210
|
+
icon: app.icon ?? "",
|
|
1211
|
+
...app.userVerificationFields ? { user_verification_fields: app.userVerificationFields } : {},
|
|
1212
|
+
schema: Object.fromEntries(
|
|
1213
|
+
Object.entries(finalSchema).map(([key, field]) => [
|
|
1214
|
+
key,
|
|
1215
|
+
normalizeSchemaField(key, field)
|
|
1216
|
+
])
|
|
1784
1217
|
),
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
rowndPendingVerificationId: pendingVerification.id
|
|
1796
|
-
}
|
|
1797
|
-
);
|
|
1798
|
-
if (response.status === "EMAIL_ALREADY_VERIFIED_ERROR") {
|
|
1799
|
-
await completePendingEmailVerification({
|
|
1800
|
-
recipeUserId: input.recipeUserId,
|
|
1801
|
-
email: input.email,
|
|
1802
|
-
userContext: input.userContext
|
|
1803
|
-
});
|
|
1804
|
-
}
|
|
1805
|
-
return getUserById(input.userId);
|
|
1806
|
-
}
|
|
1807
|
-
async function completePendingEmailVerification(input) {
|
|
1808
|
-
const user = await import_supertokens_node.default.getUser(
|
|
1809
|
-
input.recipeUserId.getAsString(),
|
|
1810
|
-
input.userContext
|
|
1811
|
-
);
|
|
1812
|
-
const userId = user?.id ?? input.recipeUserId.getAsString();
|
|
1813
|
-
const metadata = await getUserMetadata(userId);
|
|
1814
|
-
const pendingVerifications = getPendingVerifications(metadata);
|
|
1815
|
-
const pendingVerification = pendingVerifications.find(
|
|
1816
|
-
(pendingVerification2) => pendingVerification2.field === "email" && pendingVerification2.value === input.email
|
|
1817
|
-
);
|
|
1818
|
-
if (!pendingVerification) {
|
|
1819
|
-
return;
|
|
1820
|
-
}
|
|
1821
|
-
let metadataUserId = userId;
|
|
1822
|
-
const passwordlessEmailMethod = getPasswordlessEmailLoginMethod(user);
|
|
1823
|
-
if (passwordlessEmailMethod) {
|
|
1824
|
-
const updateResult = await import_passwordless.default.updateUser({
|
|
1825
|
-
recipeUserId: passwordlessEmailMethod.recipeUserId,
|
|
1826
|
-
email: input.email,
|
|
1827
|
-
userContext: input.userContext
|
|
1828
|
-
});
|
|
1829
|
-
if (updateResult.status !== "OK") {
|
|
1830
|
-
throw new Error(
|
|
1831
|
-
`Failed to update verified email method: ${updateResult.status}`
|
|
1832
|
-
);
|
|
1833
|
-
}
|
|
1834
|
-
} else if (hasOnlyGuestLoginMethods(user)) {
|
|
1835
|
-
const isPasswordlessSignUpAllowed = await import_accountlinking.default.isSignUpAllowed(
|
|
1836
|
-
PUBLIC_TENANT_ID,
|
|
1837
|
-
{
|
|
1838
|
-
recipeId: "passwordless",
|
|
1839
|
-
email: input.email
|
|
1840
|
-
},
|
|
1841
|
-
true,
|
|
1842
|
-
void 0,
|
|
1843
|
-
input.userContext
|
|
1844
|
-
);
|
|
1845
|
-
if (!isPasswordlessSignUpAllowed) {
|
|
1846
|
-
throw new Error("Passwordless sign up is not allowed for this email");
|
|
1847
|
-
}
|
|
1848
|
-
const passwordlessUser = await import_passwordless.default.signInUp({
|
|
1849
|
-
email: input.email,
|
|
1850
|
-
tenantId: PUBLIC_TENANT_ID,
|
|
1851
|
-
userContext: input.userContext
|
|
1852
|
-
});
|
|
1853
|
-
const primaryUserResult = await import_accountlinking.default.createPrimaryUser(
|
|
1854
|
-
passwordlessUser.recipeUserId,
|
|
1855
|
-
input.userContext
|
|
1856
|
-
);
|
|
1857
|
-
const primaryUserId = primaryUserResult.status === "OK" ? primaryUserResult.user.id : primaryUserResult.status === "RECIPE_USER_ID_ALREADY_LINKED_WITH_PRIMARY_USER_ID_ERROR" ? primaryUserResult.primaryUserId : passwordlessUser.user.id;
|
|
1858
|
-
if (userId !== primaryUserId) {
|
|
1859
|
-
const linkResult = await import_accountlinking.default.linkAccounts(
|
|
1860
|
-
input.recipeUserId,
|
|
1861
|
-
primaryUserId,
|
|
1862
|
-
input.userContext
|
|
1863
|
-
);
|
|
1864
|
-
if (linkResult.status !== "OK") {
|
|
1865
|
-
throw new Error(
|
|
1866
|
-
`Failed to link verified email method: ${linkResult.status}`
|
|
1867
|
-
);
|
|
1868
|
-
}
|
|
1869
|
-
}
|
|
1870
|
-
metadataUserId = primaryUserId;
|
|
1871
|
-
}
|
|
1872
|
-
const updatedMetadata = {
|
|
1873
|
-
...metadata,
|
|
1874
|
-
...metadata.original_rownd_user ? {
|
|
1875
|
-
original_rownd_user: {
|
|
1876
|
-
...metadata.original_rownd_user,
|
|
1877
|
-
data: {
|
|
1878
|
-
...metadata.original_rownd_user.data,
|
|
1879
|
-
email: input.email
|
|
1218
|
+
config: {
|
|
1219
|
+
...app.capabilities ? { capabilities: app.capabilities } : {},
|
|
1220
|
+
...app.web ? { web: app.web } : {},
|
|
1221
|
+
...app.bottomSheet ? { bottom_sheet: app.bottomSheet } : {},
|
|
1222
|
+
...app.profileStorageVersion ? { profile_storage_version: app.profileStorageVersion } : {},
|
|
1223
|
+
customizations: {
|
|
1224
|
+
primary_color: branding.primaryColor ?? DEFAULT_PRIMARY_COLOR,
|
|
1225
|
+
...branding.logo ? { logo: branding.logo } : {},
|
|
1226
|
+
...branding.logoDarkMode ? { logo_dark_mode: branding.logoDarkMode } : {},
|
|
1227
|
+
...branding.animations ? { animations: branding.animations } : {}
|
|
1880
1228
|
},
|
|
1881
|
-
|
|
1882
|
-
...
|
|
1883
|
-
|
|
1229
|
+
hub: {
|
|
1230
|
+
...app.allowedWebOrigins ? { allowed_web_origins: app.allowedWebOrigins } : {},
|
|
1231
|
+
customizations: {
|
|
1232
|
+
rounded_corners: branding.roundedCorners ?? true,
|
|
1233
|
+
...branding.containerBorderRadius !== void 0 ? { container_border_radius: branding.containerBorderRadius } : {},
|
|
1234
|
+
...branding.placement !== void 0 ? { placement: branding.placement } : {},
|
|
1235
|
+
...branding.hubPrimaryColor !== void 0 ? { primary_color: branding.hubPrimaryColor } : {},
|
|
1236
|
+
...branding.primaryColorDarkMode !== void 0 ? { primary_color_dark_mode: branding.primaryColorDarkMode } : {},
|
|
1237
|
+
...branding.backgroundColor !== void 0 ? { background_color: branding.backgroundColor } : {},
|
|
1238
|
+
...branding.fontFamily !== void 0 ? { font_family: branding.fontFamily } : {},
|
|
1239
|
+
...branding.hideVerificationIcons !== void 0 ? { hide_verification_icons: branding.hideVerificationIcons } : {},
|
|
1240
|
+
visual_swoops: branding.visualSwoops ?? true,
|
|
1241
|
+
blur_background: branding.blurBackground ?? true,
|
|
1242
|
+
...branding.blurBackgroundOpacity !== void 0 ? { blur_background_opacity: branding.blurBackgroundOpacity } : {},
|
|
1243
|
+
...branding.offsetX !== void 0 ? { offset_x: branding.offsetX } : {},
|
|
1244
|
+
...branding.offsetY !== void 0 ? { offset_y: branding.offsetY } : {},
|
|
1245
|
+
...branding.propertyOverrides ? { property_overrides: branding.propertyOverrides } : {},
|
|
1246
|
+
dark_mode: branding.darkMode ?? "auto"
|
|
1247
|
+
},
|
|
1248
|
+
...branding.customScripts ? { custom_scripts: branding.customScripts } : {},
|
|
1249
|
+
...branding.customStyles ? { custom_styles: branding.customStyles } : {},
|
|
1250
|
+
auth: {
|
|
1251
|
+
email: buildAuthEmailConfig(auth.email),
|
|
1252
|
+
...auth.mobile ? { mobile: buildAuthMobileConfig(auth.mobile) } : {},
|
|
1253
|
+
sign_in_methods: signInMethods,
|
|
1254
|
+
additional_fields: auth.additionalFields ?? [],
|
|
1255
|
+
...auth.rememberSignInMethod !== void 0 ? { remember_sign_in_method: auth.rememberSignInMethod } : {},
|
|
1256
|
+
...auth.useExplicitSignUpFlow !== void 0 ? { use_explicit_sign_up_flow: auth.useExplicitSignUpFlow } : {},
|
|
1257
|
+
...auth.allowUnverifiedUsers !== void 0 ? { allow_unverified_users: auth.allowUnverifiedUsers } : {},
|
|
1258
|
+
...auth.primarySignUpMethod ? { primary_sign_up_method: auth.primarySignUpMethod } : {},
|
|
1259
|
+
...auth.preferredMethod ? { preferred_method: auth.preferredMethod } : {},
|
|
1260
|
+
...auth.order ? { order: auth.order } : {},
|
|
1261
|
+
...isInstantAnonymousMethod(app.signInMethods) ? { instant_user: { enabled: true } } : {},
|
|
1262
|
+
show_app_icon: branding.showAppIcon ?? false
|
|
1263
|
+
},
|
|
1264
|
+
legal: {
|
|
1265
|
+
...app.legal?.companyName ? { company_name: app.legal.companyName } : {},
|
|
1266
|
+
...app.legal?.privacyPolicyUrl ? { privacy_policy_url: app.legal.privacyPolicyUrl } : {},
|
|
1267
|
+
...app.legal?.termsConditionsUrl ? { terms_conditions_url: app.legal.termsConditionsUrl } : {},
|
|
1268
|
+
...app.legal?.supportEmail ? { support_email: app.legal.supportEmail } : {}
|
|
1269
|
+
},
|
|
1270
|
+
custom_content: {
|
|
1271
|
+
...app.customContent?.signInModal ? {
|
|
1272
|
+
sign_in_modal: {
|
|
1273
|
+
...app.customContent.signInModal.title ? { title: app.customContent.signInModal.title } : {},
|
|
1274
|
+
...app.customContent.signInModal.subtitle ? { subtitle: app.customContent.signInModal.subtitle } : {},
|
|
1275
|
+
...app.customContent.signInModal.signInTitle ? {
|
|
1276
|
+
sign_in_title: app.customContent.signInModal.signInTitle
|
|
1277
|
+
} : {},
|
|
1278
|
+
...app.customContent.signInModal.signUpTitle ? {
|
|
1279
|
+
sign_up_title: app.customContent.signInModal.signUpTitle
|
|
1280
|
+
} : {},
|
|
1281
|
+
...app.customContent.signInModal.signInSubtitle ? {
|
|
1282
|
+
sign_in_subtitle: app.customContent.signInModal.signInSubtitle
|
|
1283
|
+
} : {},
|
|
1284
|
+
...app.customContent.signInModal.signUpSubtitle ? {
|
|
1285
|
+
sign_up_subtitle: app.customContent.signInModal.signUpSubtitle
|
|
1286
|
+
} : {},
|
|
1287
|
+
...app.customContent.signInModal.signInButton ? {
|
|
1288
|
+
sign_in_button: app.customContent.signInModal.signInButton
|
|
1289
|
+
} : {},
|
|
1290
|
+
...app.customContent.signInModal.signUpButton ? {
|
|
1291
|
+
sign_up_button: app.customContent.signInModal.signUpButton
|
|
1292
|
+
} : {}
|
|
1293
|
+
}
|
|
1294
|
+
} : {},
|
|
1295
|
+
...app.customContent?.profileModal ? { profile_modal: app.customContent.profileModal } : {},
|
|
1296
|
+
...app.customContent?.verificationModal ? {
|
|
1297
|
+
verification_modal: {
|
|
1298
|
+
...app.customContent.verificationModal.title ? { title: app.customContent.verificationModal.title } : {},
|
|
1299
|
+
...app.customContent.verificationModal.subtitle ? { subtitle: app.customContent.verificationModal.subtitle } : {}
|
|
1300
|
+
}
|
|
1301
|
+
} : {},
|
|
1302
|
+
...app.customContent?.signInFailureModal ? {
|
|
1303
|
+
sign_in_failure_modal: {
|
|
1304
|
+
failure_message: app.customContent.signInFailureModal.failureMessage
|
|
1305
|
+
}
|
|
1306
|
+
} : {},
|
|
1307
|
+
...app.customContent?.noAccountMessage ? { no_account_message: app.customContent.noAccountMessage } : {},
|
|
1308
|
+
...app.customContent?.mobile ? { mobile: app.customContent.mobile } : {}
|
|
1309
|
+
},
|
|
1310
|
+
profile: {
|
|
1311
|
+
...app.profile?.accountInformation ? { account_information: app.profile.accountInformation } : {},
|
|
1312
|
+
...app.profile?.personalInformation ? { personal_information: app.profile.personalInformation } : {},
|
|
1313
|
+
...app.profile?.preferences ? { preferences: app.profile.preferences } : {},
|
|
1314
|
+
...app.profile?.signOutButton ? { sign_out_button: app.profile.signOutButton } : {},
|
|
1315
|
+
...app.profile?.deleteAccountButton ? { delete_account_button: app.profile.deleteAccountButton } : {},
|
|
1316
|
+
...app.profile?.addSignInMethodsButton ? { add_sign_in_methods_button: app.profile.addSignInMethodsButton } : {}
|
|
1317
|
+
}
|
|
1884
1318
|
}
|
|
1885
1319
|
}
|
|
1886
|
-
}
|
|
1887
|
-
rownd_pending_verification: pendingVerifications.filter(
|
|
1888
|
-
(verification) => verification !== pendingVerification
|
|
1889
|
-
)
|
|
1320
|
+
}
|
|
1890
1321
|
};
|
|
1891
|
-
await import_usermetadata2.default.updateUserMetadata(metadataUserId, updatedMetadata);
|
|
1892
1322
|
}
|
|
1893
|
-
|
|
1894
|
-
const metadata = await getUserMetadata(userId);
|
|
1895
|
-
const updatedMetadata = {
|
|
1896
|
-
...metadata,
|
|
1897
|
-
...inputMeta
|
|
1898
|
-
};
|
|
1899
|
-
await import_usermetadata2.default.updateUserMetadata(userId, updatedMetadata);
|
|
1323
|
+
function buildAuthEmailConfig(authEmail) {
|
|
1900
1324
|
return {
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1325
|
+
from_address: authEmail?.fromAddress ?? "no-reply@rownd.io",
|
|
1326
|
+
image: authEmail?.image ?? "",
|
|
1327
|
+
...authEmail?.subject ? { subject: authEmail.subject } : {},
|
|
1328
|
+
...authEmail?.callToActionText ? { call_to_action_text: authEmail.callToActionText } : {},
|
|
1329
|
+
...authEmail?.verifyTemplate ? { verify_template: authEmail.verifyTemplate } : {},
|
|
1330
|
+
...authEmail?.customContent ? { custom_content: authEmail.customContent } : {},
|
|
1331
|
+
...authEmail?.customClosingContent ? { custom_closing_content: authEmail.customClosingContent } : {}
|
|
1907
1332
|
};
|
|
1908
1333
|
}
|
|
1909
|
-
function
|
|
1910
|
-
return
|
|
1911
|
-
}
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
}
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
}
|
|
1919
|
-
function hasAnonymousLoginMethod(user) {
|
|
1920
|
-
return !!user?.loginMethods.some((loginMethod) => {
|
|
1921
|
-
return loginMethod.recipeId === "thirdparty" && getThirdPartyId(loginMethod) === ANONYMOUS_AUTH_METHOD_ID;
|
|
1922
|
-
});
|
|
1923
|
-
}
|
|
1924
|
-
function getPasswordlessEmailLoginMethod(user) {
|
|
1925
|
-
return user?.loginMethods.find((method) => {
|
|
1926
|
-
return method.recipeId === "passwordless" && !!method.email;
|
|
1927
|
-
});
|
|
1928
|
-
}
|
|
1929
|
-
function hasOnlyGuestLoginMethods(user) {
|
|
1930
|
-
return !!user?.loginMethods.length && user.loginMethods.every(isGuestLoginMethod);
|
|
1334
|
+
function buildAuthMobileConfig(authMobile) {
|
|
1335
|
+
return {
|
|
1336
|
+
...authMobile?.title ? { title: authMobile.title } : {},
|
|
1337
|
+
...authMobile?.image ? { image: authMobile.image } : {},
|
|
1338
|
+
...authMobile?.callToActionText ? { call_to_action_text: authMobile.callToActionText } : {},
|
|
1339
|
+
...authMobile?.hyperlinkText ? { hyperlink_text: authMobile.hyperlinkText } : {},
|
|
1340
|
+
...authMobile?.hyperlinkRedirectUrl ? { hyperlink_redirect_url: authMobile.hyperlinkRedirectUrl } : {},
|
|
1341
|
+
...authMobile?.customContent ? { custom_content: authMobile.customContent } : {}
|
|
1342
|
+
};
|
|
1931
1343
|
}
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1344
|
+
|
|
1345
|
+
// src/rownd-compatibility.ts
|
|
1346
|
+
var import_supertokens_node = __toESM(require("supertokens-node"));
|
|
1347
|
+
var IDENTITY_USER_DATA_FIELDS = /* @__PURE__ */ new Set([
|
|
1348
|
+
"user_id",
|
|
1349
|
+
"email",
|
|
1350
|
+
"phone_number",
|
|
1351
|
+
"google_id",
|
|
1352
|
+
"apple_id"
|
|
1353
|
+
]);
|
|
1354
|
+
var INTERNAL_METADATA_FIELDS = /* @__PURE__ */ new Set([
|
|
1355
|
+
"original_rownd_user",
|
|
1356
|
+
"rownd_pending_verification"
|
|
1357
|
+
]);
|
|
1358
|
+
function isIdentityField(field) {
|
|
1359
|
+
return IDENTITY_USER_DATA_FIELDS.has(field);
|
|
1935
1360
|
}
|
|
1936
|
-
function
|
|
1937
|
-
return
|
|
1361
|
+
function isInternalMetadataField(field) {
|
|
1362
|
+
return INTERNAL_METADATA_FIELDS.has(field);
|
|
1938
1363
|
}
|
|
1939
|
-
function
|
|
1940
|
-
|
|
1941
|
-
|
|
1364
|
+
function mapRowndUserToSuperTokens(rowndUser) {
|
|
1365
|
+
const loginMethods = [];
|
|
1366
|
+
const rowndUserData = rowndUser.data || {};
|
|
1367
|
+
const rowndUserVerifiedData = rowndUser.verified_data || {};
|
|
1368
|
+
if (!rowndUserData.user_id) {
|
|
1369
|
+
throw new Error("Rownd user has no user_id");
|
|
1942
1370
|
}
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1371
|
+
if (rowndUserData.google_id) {
|
|
1372
|
+
if (!rowndUserData.email) {
|
|
1373
|
+
throw new Error("Rownd Google user is missing email");
|
|
1374
|
+
}
|
|
1375
|
+
loginMethods.push({
|
|
1376
|
+
recipeId: "thirdparty",
|
|
1377
|
+
thirdPartyId: "google",
|
|
1378
|
+
thirdPartyUserId: rowndUserData.google_id,
|
|
1379
|
+
email: rowndUserData.email,
|
|
1380
|
+
isVerified: !!rowndUserVerifiedData.google_id
|
|
1950
1381
|
});
|
|
1951
1382
|
}
|
|
1952
|
-
if (
|
|
1383
|
+
if (rowndUserData.apple_id) {
|
|
1384
|
+
if (!rowndUserData.email) {
|
|
1385
|
+
throw new Error("Rownd Apple user is missing email");
|
|
1386
|
+
}
|
|
1387
|
+
loginMethods.push({
|
|
1388
|
+
recipeId: "thirdparty",
|
|
1389
|
+
thirdPartyId: "apple",
|
|
1390
|
+
thirdPartyUserId: rowndUserData.apple_id,
|
|
1391
|
+
email: rowndUserData.email,
|
|
1392
|
+
isVerified: !!rowndUserVerifiedData.apple_id
|
|
1393
|
+
});
|
|
1394
|
+
}
|
|
1395
|
+
if (rowndUserData.phone_number) {
|
|
1396
|
+
loginMethods.push({
|
|
1397
|
+
recipeId: "passwordless",
|
|
1398
|
+
phoneNumber: rowndUserData.phone_number,
|
|
1399
|
+
isVerified: !!rowndUserVerifiedData.phone_number
|
|
1400
|
+
});
|
|
1401
|
+
}
|
|
1402
|
+
if (rowndUserData.email && !rowndUserData.google_id && !rowndUserData.apple_id) {
|
|
1403
|
+
loginMethods.push({
|
|
1404
|
+
recipeId: "passwordless",
|
|
1405
|
+
email: rowndUserData.email,
|
|
1406
|
+
isVerified: !!rowndUserVerifiedData.email
|
|
1407
|
+
});
|
|
1408
|
+
}
|
|
1409
|
+
let authLevel = rowndUser.auth_level;
|
|
1410
|
+
if (loginMethods.length === 0) {
|
|
1411
|
+
const thirdPartyId = authLevel === GUEST_AUTH_METHOD_ID ? GUEST_AUTH_METHOD_ID : ANONYMOUS_AUTH_METHOD_ID;
|
|
1412
|
+
if (!authLevel) authLevel = thirdPartyId;
|
|
1413
|
+
loginMethods.push({
|
|
1414
|
+
recipeId: "thirdparty",
|
|
1415
|
+
thirdPartyId,
|
|
1416
|
+
thirdPartyUserId: rowndUserData.user_id,
|
|
1417
|
+
email: `${rowndUserData.user_id}@anonymous.local`,
|
|
1418
|
+
isVerified: false
|
|
1419
|
+
});
|
|
1420
|
+
}
|
|
1421
|
+
const userMetadata = buildRowndUserMetadata(rowndUser);
|
|
1422
|
+
return {
|
|
1423
|
+
externalUserId: rowndUserData.user_id,
|
|
1424
|
+
loginMethods,
|
|
1425
|
+
userMetadata
|
|
1426
|
+
};
|
|
1427
|
+
}
|
|
1428
|
+
function buildRowndUserMetadata(rowndUser) {
|
|
1429
|
+
const metadata = {
|
|
1430
|
+
...rowndUser.meta || {},
|
|
1431
|
+
original_rownd_user: rowndUser
|
|
1432
|
+
};
|
|
1433
|
+
for (const [key, value] of Object.entries(rowndUser.data || {})) {
|
|
1434
|
+
if (!isIdentityField(key) && value !== void 0) {
|
|
1435
|
+
metadata[key] = value;
|
|
1436
|
+
}
|
|
1437
|
+
}
|
|
1438
|
+
return metadata;
|
|
1439
|
+
}
|
|
1440
|
+
function buildRowndAudience(currentPayload, appVariantId) {
|
|
1441
|
+
const audience = getStringList(currentPayload.aud);
|
|
1442
|
+
const appId = getPluginConfig()?.appConfig?.id;
|
|
1443
|
+
if (appId) {
|
|
1444
|
+
audience.push(`app:${appId}`);
|
|
1445
|
+
}
|
|
1446
|
+
if (appVariantId) {
|
|
1447
|
+
audience.push(`app_variant:${appVariantId}`);
|
|
1448
|
+
}
|
|
1449
|
+
return audience.length > 0 ? { aud: [...new Set(audience)] } : {};
|
|
1450
|
+
}
|
|
1451
|
+
function buildConfiguredSessionClaims(metadata) {
|
|
1452
|
+
if (!metadata) {
|
|
1453
|
+
return {};
|
|
1454
|
+
}
|
|
1455
|
+
const schema = getPluginConfig()?.schema || DEFAULT_ROWND_SCHEMA;
|
|
1456
|
+
const claims = {};
|
|
1457
|
+
for (const [key, field] of Object.entries(schema)) {
|
|
1458
|
+
if (field.include_in_session_claims !== true) {
|
|
1459
|
+
continue;
|
|
1460
|
+
}
|
|
1461
|
+
const value = metadata.original_rownd_user?.data?.[key] ?? metadata[key];
|
|
1462
|
+
if (value !== void 0) {
|
|
1463
|
+
claims[field.session_claim_name || key] = value;
|
|
1464
|
+
}
|
|
1465
|
+
}
|
|
1466
|
+
return claims;
|
|
1467
|
+
}
|
|
1468
|
+
function getRowndAppUserId(userId, user, currentPayload, metadata) {
|
|
1469
|
+
const originalUserId = metadata?.original_rownd_user?.data?.user_id;
|
|
1470
|
+
if (typeof originalUserId === "string") {
|
|
1471
|
+
return originalUserId;
|
|
1472
|
+
}
|
|
1473
|
+
if (typeof currentPayload.app_user_id === "string") {
|
|
1474
|
+
return currentPayload.app_user_id;
|
|
1475
|
+
}
|
|
1476
|
+
return user?.id || userId;
|
|
1477
|
+
}
|
|
1478
|
+
function getAnonymousId(userId, user, metadata) {
|
|
1479
|
+
const originalAnonymousId = metadata?.original_rownd_user?.data?.anonymous_id;
|
|
1480
|
+
if (typeof originalAnonymousId === "string") {
|
|
1481
|
+
return originalAnonymousId;
|
|
1482
|
+
}
|
|
1483
|
+
const anonymousMethod = user?.loginMethods.find((loginMethod) => {
|
|
1484
|
+
return loginMethod.recipeId === "thirdparty" && getThirdPartyId(loginMethod) === ANONYMOUS_AUTH_METHOD_ID;
|
|
1485
|
+
});
|
|
1486
|
+
const thirdPartyUserId = anonymousMethod ? getThirdPartyUserId(anonymousMethod) : void 0;
|
|
1487
|
+
return thirdPartyUserId || (hasAnonymousLoginMethod(user) ? `anon_${userId}` : void 0);
|
|
1488
|
+
}
|
|
1489
|
+
function buildRowndSessionClaimPayload(input) {
|
|
1490
|
+
const currentPayload = input.currentPayload ?? {};
|
|
1491
|
+
const originalRowndUser = input.metadata?.original_rownd_user;
|
|
1492
|
+
const verifiedData = originalRowndUser?.verified_data;
|
|
1493
|
+
const authLevel = getEffectiveAuthLevel(
|
|
1494
|
+
input.user,
|
|
1495
|
+
originalRowndUser?.auth_level,
|
|
1496
|
+
verifiedData
|
|
1497
|
+
);
|
|
1498
|
+
const appUserId = getRowndAppUserId(
|
|
1499
|
+
input.userId,
|
|
1500
|
+
input.user,
|
|
1501
|
+
currentPayload,
|
|
1502
|
+
input.metadata
|
|
1503
|
+
);
|
|
1504
|
+
const isAnonymous = authLevel === GUEST_AUTH_METHOD_ID;
|
|
1505
|
+
const anonymousId = getAnonymousId(input.userId, input.user, input.metadata);
|
|
1506
|
+
const isVerifiedUser = authLevel !== "unverified";
|
|
1507
|
+
const audience = buildRowndAudience(currentPayload, input.appVariantId);
|
|
1508
|
+
const configuredClaims = buildConfiguredSessionClaims(input.metadata);
|
|
1509
|
+
return {
|
|
1510
|
+
...audience,
|
|
1511
|
+
...configuredClaims,
|
|
1512
|
+
app_user_id: appUserId,
|
|
1513
|
+
auth_level: authLevel,
|
|
1514
|
+
is_verified_user: isVerifiedUser,
|
|
1515
|
+
[ROWND_JWT_CLAIMS.AppUserId]: appUserId,
|
|
1516
|
+
[ROWND_JWT_CLAIMS.AuthLevel]: authLevel,
|
|
1517
|
+
[ROWND_JWT_CLAIMS.IsVerifiedUser]: isVerifiedUser,
|
|
1518
|
+
[ROWND_JWT_CLAIMS.IsAnonymous]: isAnonymous,
|
|
1519
|
+
...anonymousId ? { anonymous_id: anonymousId } : {}
|
|
1520
|
+
};
|
|
1521
|
+
}
|
|
1522
|
+
async function shouldLinkRowndAccounts(input) {
|
|
1523
|
+
const [newAccountInfo, , session] = input;
|
|
1524
|
+
if (!session) {
|
|
1525
|
+
return void 0;
|
|
1526
|
+
}
|
|
1527
|
+
const currentUser = await import_supertokens_node.default.getUser(session.getUserId());
|
|
1528
|
+
if (hasOnlyGuestLoginMethods(currentUser)) {
|
|
1529
|
+
return {
|
|
1530
|
+
shouldAutomaticallyLink: true,
|
|
1531
|
+
shouldRequireVerification: false
|
|
1532
|
+
};
|
|
1533
|
+
}
|
|
1534
|
+
if (!currentUser || isGuestAccountInfo(newAccountInfo)) {
|
|
1535
|
+
return void 0;
|
|
1536
|
+
}
|
|
1537
|
+
if (doesAccountInfoMatchAuthMethod(currentUser, newAccountInfo)) {
|
|
1538
|
+
return {
|
|
1539
|
+
shouldAutomaticallyLink: true,
|
|
1540
|
+
shouldRequireVerification: true
|
|
1541
|
+
};
|
|
1542
|
+
}
|
|
1543
|
+
return void 0;
|
|
1544
|
+
}
|
|
1545
|
+
function mapMethod(method) {
|
|
1546
|
+
if (method.recipeId === "thirdparty") {
|
|
1547
|
+
if (getThirdPartyId(method) === "google") return "google";
|
|
1548
|
+
if (getThirdPartyId(method) === "apple") return "apple";
|
|
1549
|
+
} else if (method.recipeId === "passwordless") {
|
|
1550
|
+
if (method.email) return "email";
|
|
1551
|
+
if (method.phoneNumber) return "phone";
|
|
1552
|
+
} else if (method.recipeId === "emailpassword") {
|
|
1553
|
+
return "email";
|
|
1554
|
+
}
|
|
1555
|
+
return "email";
|
|
1556
|
+
}
|
|
1557
|
+
function getThirdPartyId(method) {
|
|
1558
|
+
return method.thirdParty?.id;
|
|
1559
|
+
}
|
|
1560
|
+
function getThirdPartyUserId(method) {
|
|
1561
|
+
return method.thirdParty?.userId;
|
|
1562
|
+
}
|
|
1563
|
+
function getGuestAuthLevel(user) {
|
|
1564
|
+
const guestMethod = user?.loginMethods.find(isGuestLoginMethod);
|
|
1565
|
+
return guestMethod ? GUEST_AUTH_METHOD_ID : void 0;
|
|
1566
|
+
}
|
|
1567
|
+
function hasAnonymousLoginMethod(user) {
|
|
1568
|
+
return !!user?.loginMethods.some((loginMethod) => {
|
|
1569
|
+
return loginMethod.recipeId === "thirdparty" && getThirdPartyId(loginMethod) === ANONYMOUS_AUTH_METHOD_ID;
|
|
1570
|
+
});
|
|
1571
|
+
}
|
|
1572
|
+
function hasOnlyGuestLoginMethods(user) {
|
|
1573
|
+
return !!user?.loginMethods.length && user.loginMethods.every(isGuestLoginMethod);
|
|
1574
|
+
}
|
|
1575
|
+
function isGuestLoginMethod(method) {
|
|
1576
|
+
const thirdPartyId = getThirdPartyId(method);
|
|
1577
|
+
return method.recipeId === "thirdparty" && (thirdPartyId === GUEST_AUTH_METHOD_ID || thirdPartyId === ANONYMOUS_AUTH_METHOD_ID);
|
|
1578
|
+
}
|
|
1579
|
+
function isGuestAccountInfo(input) {
|
|
1580
|
+
return input?.recipeId === "thirdparty" && (input.thirdParty?.id === GUEST_AUTH_METHOD_ID || input.thirdParty?.id === ANONYMOUS_AUTH_METHOD_ID);
|
|
1581
|
+
}
|
|
1582
|
+
function doesAccountInfoMatchAuthMethod(user, accountInfo) {
|
|
1583
|
+
if (!user) {
|
|
1584
|
+
return false;
|
|
1585
|
+
}
|
|
1586
|
+
const normalizedEmail = accountInfo.email?.toLowerCase();
|
|
1587
|
+
if (normalizedEmail) {
|
|
1588
|
+
return user.loginMethods.some((method) => {
|
|
1589
|
+
if (isGuestLoginMethod(method) || !method.email) {
|
|
1590
|
+
return false;
|
|
1591
|
+
}
|
|
1592
|
+
return method.email.toLowerCase() === normalizedEmail;
|
|
1593
|
+
});
|
|
1594
|
+
}
|
|
1595
|
+
if (accountInfo.phoneNumber) {
|
|
1953
1596
|
return user.loginMethods.some((method) => {
|
|
1954
1597
|
return !isGuestLoginMethod(method) && method.phoneNumber === accountInfo.phoneNumber;
|
|
1955
1598
|
});
|
|
@@ -1980,7 +1623,7 @@ function getEffectiveAuthLevel(user, originalAuthLevel, verifiedData) {
|
|
|
1980
1623
|
return getGuestAuthLevel(user) || originalAuthLevel || (verifiedData && Object.keys(verifiedData).length > 0 ? "verified" : "unverified");
|
|
1981
1624
|
}
|
|
1982
1625
|
function canUpdateUserDataField(field) {
|
|
1983
|
-
const schema =
|
|
1626
|
+
const schema = getPluginConfig()?.schema || DEFAULT_ROWND_SCHEMA;
|
|
1984
1627
|
const schemaField = schema[field];
|
|
1985
1628
|
if (!schemaField) {
|
|
1986
1629
|
return false;
|
|
@@ -1988,350 +1631,806 @@ function canUpdateUserDataField(field) {
|
|
|
1988
1631
|
const ownedBy = field === "google_id" || field === "apple_id" ? "app" : schemaField.owned_by || "user";
|
|
1989
1632
|
return ownedBy !== "app" && schemaField.read_only !== true;
|
|
1990
1633
|
}
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
if (key === "google_id" || key === "apple_id") {
|
|
2001
|
-
ownedBy = "app";
|
|
2002
|
-
} else if (!ownedBy) {
|
|
2003
|
-
ownedBy = "user";
|
|
1634
|
+
|
|
1635
|
+
// src/rownd-repository.ts
|
|
1636
|
+
var rowndClient;
|
|
1637
|
+
function setRowndClient(client) {
|
|
1638
|
+
rowndClient = client;
|
|
1639
|
+
}
|
|
1640
|
+
function getRowndClient() {
|
|
1641
|
+
if (!rowndClient) {
|
|
1642
|
+
throw new Error("Rownd client not initialized");
|
|
2004
1643
|
}
|
|
2005
|
-
return
|
|
2006
|
-
display_name: field.display_name,
|
|
2007
|
-
type: field.type,
|
|
2008
|
-
owned_by: ownedBy,
|
|
2009
|
-
user_visible: field.user_visible,
|
|
2010
|
-
read_only: field.read_only ?? ownedBy === "app",
|
|
2011
|
-
show_empty: field.show_empty ?? false
|
|
2012
|
-
};
|
|
1644
|
+
return rowndClient;
|
|
2013
1645
|
}
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
const
|
|
2017
|
-
|
|
2018
|
-
acc[curr.method] = curr;
|
|
2019
|
-
return acc;
|
|
2020
|
-
},
|
|
2021
|
-
{}
|
|
2022
|
-
);
|
|
2023
|
-
const customProviders = Object.fromEntries(
|
|
2024
|
-
Object.entries(methods).filter(([key]) => !BUILTIN_SIGN_IN_METHOD_KEYS.includes(key)).map(([key, val]) => {
|
|
2025
|
-
return val ? [
|
|
2026
|
-
key,
|
|
2027
|
-
{
|
|
2028
|
-
enabled: true,
|
|
2029
|
-
display_name: getStringMethodProperty(val, "displayName") ?? key,
|
|
2030
|
-
icon_light_url: getStringMethodProperty(val, "iconLightUrl"),
|
|
2031
|
-
icon_dark_url: getStringMethodProperty(val, "iconDarkUrl")
|
|
2032
|
-
}
|
|
2033
|
-
] : [key, void 0];
|
|
2034
|
-
}).filter(([, v]) => v !== void 0)
|
|
2035
|
-
);
|
|
2036
|
-
const googleMethod = methods.google;
|
|
2037
|
-
const appleMethod = methods.apple;
|
|
2038
|
-
const anonymousMethod = methods.anonymous;
|
|
2039
|
-
const anonymousType = getAnonymousType(anonymousMethod);
|
|
2040
|
-
const googleOneTap = getOneTapConfig(googleMethod);
|
|
2041
|
-
return {
|
|
2042
|
-
email: { enabled: !!methods.email },
|
|
2043
|
-
phone: { enabled: !!methods.phone },
|
|
2044
|
-
google: {
|
|
2045
|
-
enabled: !!googleMethod,
|
|
2046
|
-
client_id: getStringMethodProperty(googleMethod, "clientId") ?? "",
|
|
2047
|
-
ios_client_id: getStringMethodProperty(googleMethod, "iosClientId") ?? "",
|
|
2048
|
-
scopes: getStringArrayMethodProperty(googleMethod, "scopes") ?? [],
|
|
2049
|
-
...getSignInFasterWithGoogle(googleMethod) ? { sign_in_faster_with_google: getSignInFasterWithGoogle(googleMethod) } : {},
|
|
2050
|
-
one_tap: {
|
|
2051
|
-
browser: {
|
|
2052
|
-
auto_prompt: googleOneTap?.browser?.autoPrompt ?? false,
|
|
2053
|
-
delay: googleOneTap?.browser?.delay ?? 7e3
|
|
2054
|
-
},
|
|
2055
|
-
mobile_app: {
|
|
2056
|
-
auto_prompt: googleOneTap?.mobileApp?.autoPrompt ?? false,
|
|
2057
|
-
delay: googleOneTap?.mobileApp?.delay ?? 7e3
|
|
2058
|
-
}
|
|
2059
|
-
}
|
|
2060
|
-
},
|
|
2061
|
-
apple: {
|
|
2062
|
-
enabled: !!appleMethod,
|
|
2063
|
-
client_id: getStringMethodProperty(appleMethod, "clientId") ?? ""
|
|
2064
|
-
},
|
|
2065
|
-
anonymous: {
|
|
2066
|
-
enabled: !!anonymousMethod && anonymousType !== "instant",
|
|
2067
|
-
...anonymousMethod && anonymousType !== "instant" ? { type: anonymousType } : {},
|
|
2068
|
-
...anonymousType !== "instant" && getStringMethodProperty(anonymousMethod, "displayName") !== void 0 ? {
|
|
2069
|
-
display_name: getStringMethodProperty(
|
|
2070
|
-
anonymousMethod,
|
|
2071
|
-
"displayName"
|
|
2072
|
-
)
|
|
2073
|
-
} : {},
|
|
2074
|
-
...anonymousType !== "instant" && getStringMethodProperty(anonymousMethod, "iconLightUrl") !== void 0 ? {
|
|
2075
|
-
icon_light_url: getStringMethodProperty(
|
|
2076
|
-
anonymousMethod,
|
|
2077
|
-
"iconLightUrl"
|
|
2078
|
-
)
|
|
2079
|
-
} : {},
|
|
2080
|
-
...anonymousType !== "instant" && getStringMethodProperty(anonymousMethod, "iconDarkUrl") !== void 0 ? {
|
|
2081
|
-
icon_dark_url: getStringMethodProperty(
|
|
2082
|
-
anonymousMethod,
|
|
2083
|
-
"iconDarkUrl"
|
|
2084
|
-
)
|
|
2085
|
-
} : {}
|
|
2086
|
-
},
|
|
2087
|
-
...customProviders
|
|
2088
|
-
};
|
|
2089
|
-
}
|
|
2090
|
-
function isInstantAnonymousMethod(methods) {
|
|
2091
|
-
return (methods ?? []).some(
|
|
2092
|
-
(method) => method.method === "anonymous" && getAnonymousType(method) === "instant"
|
|
2093
|
-
);
|
|
1646
|
+
async function validateRowndToken(token) {
|
|
1647
|
+
const client = getRowndClient();
|
|
1648
|
+
const tokenInfo = await client.validateToken(token);
|
|
1649
|
+
return tokenInfo.user_id;
|
|
2094
1650
|
}
|
|
2095
|
-
function
|
|
2096
|
-
const
|
|
2097
|
-
|
|
1651
|
+
async function fetchRowndUserInfo(userId) {
|
|
1652
|
+
const client = getRowndClient();
|
|
1653
|
+
const rowndUser = await client.fetchUserInfo({ user_id: userId });
|
|
1654
|
+
if (!rowndUser) {
|
|
1655
|
+
throw new RowndPluginError("ROWND_USER_NOT_FOUND");
|
|
1656
|
+
}
|
|
1657
|
+
return rowndUser;
|
|
2098
1658
|
}
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
1659
|
+
|
|
1660
|
+
// src/supertokens-repository.ts
|
|
1661
|
+
var import_supertokens_node2 = __toESM(require("supertokens-node"));
|
|
1662
|
+
var import_accountlinking = __toESM(require("supertokens-node/recipe/accountlinking"));
|
|
1663
|
+
var import_emailverification = __toESM(require("supertokens-node/recipe/emailverification"));
|
|
1664
|
+
var import_passwordless = __toESM(require("supertokens-node/recipe/passwordless"));
|
|
1665
|
+
var import_session = __toESM(require("supertokens-node/recipe/session"));
|
|
1666
|
+
var import_claims = require("supertokens-node/recipe/session/claims");
|
|
1667
|
+
var import_usermetadata2 = __toESM(require("supertokens-node/recipe/usermetadata"));
|
|
1668
|
+
async function importUser(stUser, config2) {
|
|
1669
|
+
const headers = {
|
|
1670
|
+
"Content-Type": "application/json"
|
|
1671
|
+
};
|
|
1672
|
+
if (config2.apiKey) {
|
|
1673
|
+
headers["api-key"] = config2.apiKey;
|
|
1674
|
+
}
|
|
1675
|
+
const response = await fetch(`${config2.connectionURI}/bulk-import/import`, {
|
|
1676
|
+
method: "POST",
|
|
1677
|
+
headers,
|
|
1678
|
+
body: JSON.stringify(stUser)
|
|
1679
|
+
});
|
|
1680
|
+
if (!response.ok) {
|
|
1681
|
+
const errorText = await response.text();
|
|
1682
|
+
throw new Error(
|
|
1683
|
+
`Bulk import failed with status ${response.status}: ${errorText}`
|
|
1684
|
+
);
|
|
1685
|
+
}
|
|
1686
|
+
const importResponse = await response.json();
|
|
1687
|
+
if (importResponse.status !== "OK" || !importResponse.user) {
|
|
1688
|
+
throw new Error(
|
|
1689
|
+
`Bulk import failed: ${importResponse.message || "Missing user in response"}`
|
|
1690
|
+
);
|
|
1691
|
+
}
|
|
1692
|
+
return importResponse.user;
|
|
2102
1693
|
}
|
|
2103
|
-
function
|
|
2104
|
-
if (!
|
|
2105
|
-
return
|
|
1694
|
+
async function recordRowndAppVariantForUser(userId, appVariantId) {
|
|
1695
|
+
if (!appVariantId) {
|
|
1696
|
+
return;
|
|
2106
1697
|
}
|
|
2107
|
-
|
|
1698
|
+
assertRowndAppVariantIsConfigured(appVariantId);
|
|
1699
|
+
const metadata = await getUserMetadata(userId);
|
|
1700
|
+
const originalRowndUser = isJsonRecord(metadata.original_rownd_user) ? metadata.original_rownd_user : {};
|
|
1701
|
+
const attributes = isJsonRecord(originalRowndUser.attributes) ? originalRowndUser.attributes : {};
|
|
1702
|
+
const appVariants = getStringList(attributes["rownd:app_variants"]);
|
|
1703
|
+
if (appVariants.includes(appVariantId)) {
|
|
1704
|
+
return;
|
|
1705
|
+
}
|
|
1706
|
+
await import_usermetadata2.default.updateUserMetadata(userId, {
|
|
1707
|
+
...metadata,
|
|
1708
|
+
original_rownd_user: {
|
|
1709
|
+
...originalRowndUser,
|
|
1710
|
+
data: isJsonRecord(originalRowndUser.data) ? originalRowndUser.data : { user_id: userId },
|
|
1711
|
+
verified_data: isJsonRecord(originalRowndUser.verified_data) ? originalRowndUser.verified_data : {},
|
|
1712
|
+
attributes: {
|
|
1713
|
+
...attributes,
|
|
1714
|
+
"rownd:app_variants": [...appVariants, appVariantId]
|
|
1715
|
+
}
|
|
1716
|
+
}
|
|
1717
|
+
});
|
|
2108
1718
|
}
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
1719
|
+
var RowndIsAnonymousClaim = new import_claims.BooleanClaim({
|
|
1720
|
+
key: "is_anonymous",
|
|
1721
|
+
fetchValue: async (userId) => {
|
|
1722
|
+
const user = await import_supertokens_node2.default.getUser(userId);
|
|
1723
|
+
const effectiveAuthLevel = getEffectiveAuthLevel(user);
|
|
1724
|
+
return effectiveAuthLevel === GUEST_AUTH_METHOD_ID;
|
|
1725
|
+
}
|
|
1726
|
+
});
|
|
1727
|
+
async function buildRowndSessionClaims(userId, currentPayload = {}, appVariantId) {
|
|
1728
|
+
const user = await import_supertokens_node2.default.getUser(userId);
|
|
1729
|
+
const metadata = user ? await getUserMetadata(user.id) : void 0;
|
|
1730
|
+
return buildRowndSessionClaimPayload({
|
|
1731
|
+
userId,
|
|
1732
|
+
user,
|
|
1733
|
+
metadata,
|
|
1734
|
+
currentPayload,
|
|
1735
|
+
appVariantId
|
|
1736
|
+
});
|
|
2112
1737
|
}
|
|
2113
|
-
function
|
|
2114
|
-
const
|
|
2115
|
-
return
|
|
1738
|
+
async function getUserMetadata(userId) {
|
|
1739
|
+
const metadata = await import_usermetadata2.default.getUserMetadata(userId);
|
|
1740
|
+
return metadata.metadata || {};
|
|
2116
1741
|
}
|
|
2117
|
-
function
|
|
2118
|
-
const
|
|
2119
|
-
if (
|
|
2120
|
-
return
|
|
1742
|
+
function getPendingVerifications(metadata) {
|
|
1743
|
+
const pendingVerification = metadata.rownd_pending_verification;
|
|
1744
|
+
if (Array.isArray(pendingVerification)) {
|
|
1745
|
+
return pendingVerification.filter(isPendingVerification);
|
|
2121
1746
|
}
|
|
2122
|
-
return
|
|
2123
|
-
browser: parseOneTapPlatform(oneTap.browser),
|
|
2124
|
-
mobileApp: parseOneTapPlatform(oneTap.mobileApp)
|
|
2125
|
-
};
|
|
1747
|
+
return [];
|
|
2126
1748
|
}
|
|
2127
|
-
function
|
|
2128
|
-
|
|
2129
|
-
|
|
1749
|
+
function isPendingVerification(value) {
|
|
1750
|
+
return isRecord(value) && typeof value.id === "string" && typeof value.field === "string" && typeof value.value === "string" && typeof value.created_at === "string";
|
|
1751
|
+
}
|
|
1752
|
+
async function getUserById(userId) {
|
|
1753
|
+
const metadata = await getUserMetadata(userId);
|
|
1754
|
+
const stUser = await import_supertokens_node2.default.getUser(userId);
|
|
1755
|
+
if (!stUser) {
|
|
1756
|
+
throw new RowndPluginError("ROWND_USER_NOT_FOUND");
|
|
2130
1757
|
}
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
1758
|
+
const originalRowndUser = metadata.original_rownd_user;
|
|
1759
|
+
const rowndUser = originalRowndUser?.data?.user_id || userId;
|
|
1760
|
+
const state = originalRowndUser?.state || "enabled";
|
|
1761
|
+
const dataFieldKeys = /* @__PURE__ */ new Set();
|
|
1762
|
+
const data = {
|
|
1763
|
+
user_id: userId
|
|
2134
1764
|
};
|
|
2135
|
-
}
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
if (isRecord(app) && isRecord(app.variant) && typeof app.variant.id === "string") {
|
|
2141
|
-
return app.variant;
|
|
1765
|
+
for (const [key, value] of Object.entries(originalRowndUser?.data || {})) {
|
|
1766
|
+
if (!isIdentityField(key)) {
|
|
1767
|
+
data[key] = value;
|
|
1768
|
+
dataFieldKeys.add(key);
|
|
1769
|
+
}
|
|
2142
1770
|
}
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
if (value === void 0) {
|
|
2149
|
-
continue;
|
|
1771
|
+
const schema = getPluginConfig()?.schema || DEFAULT_ROWND_SCHEMA;
|
|
1772
|
+
for (const key of Object.keys(schema)) {
|
|
1773
|
+
dataFieldKeys.add(key);
|
|
1774
|
+
if (!isInternalMetadataField(key) && !isIdentityField(key) && metadata[key] !== void 0) {
|
|
1775
|
+
data[key] = metadata[key];
|
|
2150
1776
|
}
|
|
2151
|
-
const existing = result[key];
|
|
2152
|
-
result[key] = isRecord(existing) && isRecord(value) ? mergeConfigInput(existing, value) : value;
|
|
2153
1777
|
}
|
|
2154
|
-
|
|
2155
|
-
}
|
|
2156
|
-
|
|
2157
|
-
const
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
1778
|
+
const verifiedData = {
|
|
1779
|
+
...originalRowndUser?.verified_data || {}
|
|
1780
|
+
};
|
|
1781
|
+
for (const method of stUser.loginMethods) {
|
|
1782
|
+
if (method.recipeId === "passwordless") {
|
|
1783
|
+
if (method.email) {
|
|
1784
|
+
verifiedData.email = method.email;
|
|
1785
|
+
if (data.email === void 0) data.email = method.email;
|
|
1786
|
+
}
|
|
1787
|
+
if (method.phoneNumber) {
|
|
1788
|
+
verifiedData.phone_number = method.phoneNumber;
|
|
1789
|
+
if (data.phone_number === void 0)
|
|
1790
|
+
data.phone_number = method.phoneNumber;
|
|
1791
|
+
}
|
|
1792
|
+
} else if (method.recipeId === "thirdparty") {
|
|
1793
|
+
const thirdPartyId = getThirdPartyId(method);
|
|
1794
|
+
const thirdPartyUserId = getThirdPartyUserId(method);
|
|
1795
|
+
if (method.verified && method.email) {
|
|
1796
|
+
verifiedData.email = method.email;
|
|
1797
|
+
}
|
|
1798
|
+
if (method.email && data.email === void 0) {
|
|
1799
|
+
data.email = method.email;
|
|
1800
|
+
}
|
|
1801
|
+
if (thirdPartyId === "google" && thirdPartyUserId) {
|
|
1802
|
+
data.google_id = thirdPartyUserId;
|
|
1803
|
+
verifiedData.google_id = thirdPartyUserId;
|
|
1804
|
+
}
|
|
1805
|
+
if (thirdPartyId === "apple" && thirdPartyUserId) {
|
|
1806
|
+
data.apple_id = thirdPartyUserId;
|
|
1807
|
+
verifiedData.apple_id = thirdPartyUserId;
|
|
1808
|
+
}
|
|
1809
|
+
} else if (method.recipeId === "emailpassword") {
|
|
1810
|
+
if (method.email && data.email === void 0) {
|
|
1811
|
+
data.email = method.email;
|
|
1812
|
+
}
|
|
1813
|
+
}
|
|
2163
1814
|
}
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
const signInMethods = buildSignInMethodsConfig(app.signInMethods);
|
|
2167
|
-
const variant = getSubBrandVariant(app);
|
|
2168
|
-
const finalSchema = { ...userSchema };
|
|
2169
|
-
if (signInMethods.email.enabled && !finalSchema.email) {
|
|
2170
|
-
finalSchema.email = {
|
|
2171
|
-
display_name: "Email",
|
|
2172
|
-
type: "string",
|
|
2173
|
-
user_visible: true
|
|
2174
|
-
};
|
|
1815
|
+
if (verifiedData.email === true && typeof data.email === "string") {
|
|
1816
|
+
verifiedData.email = data.email;
|
|
2175
1817
|
}
|
|
2176
|
-
if (
|
|
2177
|
-
|
|
2178
|
-
display_name: "Phone number",
|
|
2179
|
-
type: "string",
|
|
2180
|
-
user_visible: true
|
|
2181
|
-
};
|
|
1818
|
+
if (verifiedData.phone_number === true && typeof data.phone_number === "string") {
|
|
1819
|
+
verifiedData.phone_number = data.phone_number;
|
|
2182
1820
|
}
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
type: "string",
|
|
2187
|
-
user_visible: false
|
|
2188
|
-
};
|
|
1821
|
+
const anonymousId = getAnonymousId(stUser.id, stUser, metadata);
|
|
1822
|
+
if (anonymousId && data.anonymous_id === void 0) {
|
|
1823
|
+
data.anonymous_id = anonymousId;
|
|
2189
1824
|
}
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
|
|
1825
|
+
const authLevel = getEffectiveAuthLevel(
|
|
1826
|
+
stUser,
|
|
1827
|
+
originalRowndUser?.auth_level,
|
|
1828
|
+
verifiedData
|
|
1829
|
+
);
|
|
1830
|
+
for (const [key, field] of Object.entries(schema)) {
|
|
1831
|
+
if (data[key] === void 0 && field.type === "string") {
|
|
1832
|
+
data[key] = "";
|
|
1833
|
+
}
|
|
2196
1834
|
}
|
|
1835
|
+
const sortedByJoined = [...stUser.loginMethods].sort(
|
|
1836
|
+
(a, b) => a.timeJoined - b.timeJoined
|
|
1837
|
+
);
|
|
1838
|
+
const latestSessionInfo = await getLatestSessionInfo(stUser.id);
|
|
1839
|
+
const firstMethod = sortedByJoined[0];
|
|
1840
|
+
const latestSessionRecipeUserId = latestSessionInfo?.recipeUserId.getAsString();
|
|
1841
|
+
const lastMethod = latestSessionRecipeUserId ? stUser.loginMethods.find(
|
|
1842
|
+
(method) => method.recipeUserId.getAsString() === latestSessionRecipeUserId
|
|
1843
|
+
) : [...stUser.loginMethods].sort((a, b) => b.timeJoined - a.timeJoined)[0];
|
|
1844
|
+
const lastSignInAt = latestSessionInfo?.timeCreated ?? stUser.timeJoined;
|
|
1845
|
+
const metadataMeta = Object.fromEntries(
|
|
1846
|
+
Object.entries(metadata).filter(
|
|
1847
|
+
([key]) => !isInternalMetadataField(key) && !dataFieldKeys.has(key)
|
|
1848
|
+
)
|
|
1849
|
+
);
|
|
1850
|
+
const meta = {
|
|
1851
|
+
...metadataMeta,
|
|
1852
|
+
created: new Date(stUser.timeJoined).toISOString(),
|
|
1853
|
+
first_sign_in: new Date(stUser.timeJoined).toISOString(),
|
|
1854
|
+
last_sign_in: new Date(lastSignInAt).toISOString(),
|
|
1855
|
+
last_active: new Date(lastSignInAt).toISOString(),
|
|
1856
|
+
first_sign_in_method: firstMethod ? mapMethod(firstMethod) : "email",
|
|
1857
|
+
last_sign_in_method: lastMethod ? mapMethod(lastMethod) : "email"
|
|
1858
|
+
};
|
|
2197
1859
|
return {
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
1860
|
+
rownd_user: rowndUser,
|
|
1861
|
+
data,
|
|
1862
|
+
meta,
|
|
1863
|
+
verified_data: verifiedData,
|
|
1864
|
+
state,
|
|
1865
|
+
auth_level: authLevel,
|
|
1866
|
+
redacted: [],
|
|
1867
|
+
groups: originalRowndUser?.groups || [],
|
|
1868
|
+
attributes: originalRowndUser?.attributes || {}
|
|
1869
|
+
};
|
|
1870
|
+
}
|
|
1871
|
+
async function getLatestSessionInfo(userId) {
|
|
1872
|
+
const sessionHandles = await import_session.default.getAllSessionHandlesForUser(
|
|
1873
|
+
userId,
|
|
1874
|
+
true,
|
|
1875
|
+
PUBLIC_TENANT_ID
|
|
1876
|
+
);
|
|
1877
|
+
const sessionInfos = await Promise.all(
|
|
1878
|
+
sessionHandles.map(
|
|
1879
|
+
(sessionHandle) => import_session.default.getSessionInformation(sessionHandle)
|
|
1880
|
+
)
|
|
1881
|
+
);
|
|
1882
|
+
let latestSessionInfo;
|
|
1883
|
+
for (const sessionInfo of sessionInfos) {
|
|
1884
|
+
if (sessionInfo && (!latestSessionInfo || sessionInfo.timeCreated > latestSessionInfo.timeCreated)) {
|
|
1885
|
+
latestSessionInfo = sessionInfo;
|
|
1886
|
+
}
|
|
1887
|
+
}
|
|
1888
|
+
return latestSessionInfo;
|
|
1889
|
+
}
|
|
1890
|
+
async function updateUserData(userId, inputData) {
|
|
1891
|
+
const metadata = await getUserMetadata(userId);
|
|
1892
|
+
const updatedMetadata = {
|
|
1893
|
+
...metadata,
|
|
1894
|
+
...inputData
|
|
1895
|
+
};
|
|
1896
|
+
await import_usermetadata2.default.updateUserMetadata(userId, updatedMetadata);
|
|
1897
|
+
return getUserById(userId);
|
|
1898
|
+
}
|
|
1899
|
+
async function startPendingEmailVerification(input) {
|
|
1900
|
+
const metadata = await getUserMetadata(input.userId);
|
|
1901
|
+
const currentEmail = (await getUserById(input.userId)).data.email;
|
|
1902
|
+
const pendingVerifications = getPendingVerifications(metadata);
|
|
1903
|
+
const pendingEmailVerifications = pendingVerifications.filter(
|
|
1904
|
+
(pendingVerification2) => pendingVerification2.field === "email"
|
|
1905
|
+
);
|
|
1906
|
+
if (currentEmail === input.email) {
|
|
1907
|
+
for (const pendingVerification2 of pendingEmailVerifications) {
|
|
1908
|
+
await import_emailverification.default.revokeEmailVerificationTokens(
|
|
1909
|
+
input.tenantId,
|
|
1910
|
+
input.recipeUserId,
|
|
1911
|
+
pendingVerification2.value,
|
|
1912
|
+
input.userContext
|
|
1913
|
+
);
|
|
1914
|
+
}
|
|
1915
|
+
if (pendingEmailVerifications.length > 0) {
|
|
1916
|
+
await import_usermetadata2.default.updateUserMetadata(input.userId, {
|
|
1917
|
+
...metadata,
|
|
1918
|
+
rownd_pending_verification: pendingVerifications.filter(
|
|
1919
|
+
(pendingVerification2) => pendingVerification2.field !== "email"
|
|
1920
|
+
)
|
|
1921
|
+
});
|
|
1922
|
+
}
|
|
1923
|
+
return getUserById(input.userId);
|
|
1924
|
+
}
|
|
1925
|
+
for (const pendingVerification2 of pendingEmailVerifications) {
|
|
1926
|
+
await import_emailverification.default.revokeEmailVerificationTokens(
|
|
1927
|
+
input.tenantId,
|
|
1928
|
+
input.recipeUserId,
|
|
1929
|
+
pendingVerification2.value,
|
|
1930
|
+
input.userContext
|
|
1931
|
+
);
|
|
1932
|
+
}
|
|
1933
|
+
const pendingVerification = {
|
|
1934
|
+
id: input.pendingVerificationId,
|
|
1935
|
+
field: "email",
|
|
1936
|
+
value: input.email,
|
|
1937
|
+
created_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
1938
|
+
};
|
|
1939
|
+
await import_usermetadata2.default.updateUserMetadata(input.userId, {
|
|
1940
|
+
...metadata,
|
|
1941
|
+
rownd_pending_verification: [
|
|
1942
|
+
...pendingVerifications.filter(
|
|
1943
|
+
(pendingVerification2) => pendingVerification2.field !== "email"
|
|
2210
1944
|
),
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
1945
|
+
pendingVerification
|
|
1946
|
+
]
|
|
1947
|
+
});
|
|
1948
|
+
const response = await import_emailverification.default.sendEmailVerificationEmail(
|
|
1949
|
+
input.tenantId,
|
|
1950
|
+
input.userId,
|
|
1951
|
+
input.recipeUserId,
|
|
1952
|
+
input.email,
|
|
1953
|
+
{
|
|
1954
|
+
...input.userContext,
|
|
1955
|
+
rowndPendingVerificationId: pendingVerification.id
|
|
1956
|
+
}
|
|
1957
|
+
);
|
|
1958
|
+
if (response.status === "EMAIL_ALREADY_VERIFIED_ERROR") {
|
|
1959
|
+
await completePendingEmailVerification({
|
|
1960
|
+
recipeUserId: input.recipeUserId,
|
|
1961
|
+
email: input.email,
|
|
1962
|
+
userContext: input.userContext
|
|
1963
|
+
});
|
|
1964
|
+
}
|
|
1965
|
+
return getUserById(input.userId);
|
|
1966
|
+
}
|
|
1967
|
+
async function completePendingEmailVerification(input) {
|
|
1968
|
+
const user = await import_supertokens_node2.default.getUser(
|
|
1969
|
+
input.recipeUserId.getAsString(),
|
|
1970
|
+
input.userContext
|
|
1971
|
+
);
|
|
1972
|
+
const userId = user?.id ?? input.recipeUserId.getAsString();
|
|
1973
|
+
const metadata = await getUserMetadata(userId);
|
|
1974
|
+
const pendingVerifications = getPendingVerifications(metadata);
|
|
1975
|
+
const pendingVerification = pendingVerifications.find(
|
|
1976
|
+
(pendingVerification2) => isMatchingPendingEmailVerification(
|
|
1977
|
+
pendingVerification2,
|
|
1978
|
+
input.email
|
|
1979
|
+
)
|
|
1980
|
+
);
|
|
1981
|
+
if (!pendingVerification) {
|
|
1982
|
+
return;
|
|
1983
|
+
}
|
|
1984
|
+
let metadataUserId = userId;
|
|
1985
|
+
const passwordlessEmailMethod = getPasswordlessEmailLoginMethod(user);
|
|
1986
|
+
if (passwordlessEmailMethod) {
|
|
1987
|
+
const updateResult = await import_passwordless.default.updateUser({
|
|
1988
|
+
recipeUserId: passwordlessEmailMethod.recipeUserId,
|
|
1989
|
+
email: input.email,
|
|
1990
|
+
userContext: input.userContext
|
|
1991
|
+
});
|
|
1992
|
+
if (updateResult.status !== "OK") {
|
|
1993
|
+
throw new Error(
|
|
1994
|
+
`Failed to update verified email method: ${updateResult.status}`
|
|
1995
|
+
);
|
|
1996
|
+
}
|
|
1997
|
+
} else if (hasOnlyGuestLoginMethods(user)) {
|
|
1998
|
+
const isPasswordlessSignUpAllowed = await import_accountlinking.default.isSignUpAllowed(
|
|
1999
|
+
PUBLIC_TENANT_ID,
|
|
2000
|
+
{
|
|
2001
|
+
recipeId: "passwordless",
|
|
2002
|
+
email: input.email
|
|
2003
|
+
},
|
|
2004
|
+
true,
|
|
2005
|
+
void 0,
|
|
2006
|
+
input.userContext
|
|
2007
|
+
);
|
|
2008
|
+
if (!isPasswordlessSignUpAllowed) {
|
|
2009
|
+
throw new Error("Passwordless sign up is not allowed for this email");
|
|
2010
|
+
}
|
|
2011
|
+
const passwordlessUser = await import_passwordless.default.signInUp({
|
|
2012
|
+
email: input.email,
|
|
2013
|
+
tenantId: PUBLIC_TENANT_ID,
|
|
2014
|
+
userContext: input.userContext
|
|
2015
|
+
});
|
|
2016
|
+
const primaryUserResult = await import_accountlinking.default.createPrimaryUser(
|
|
2017
|
+
passwordlessUser.recipeUserId,
|
|
2018
|
+
input.userContext
|
|
2019
|
+
);
|
|
2020
|
+
const primaryUserId = primaryUserResult.status === "OK" ? primaryUserResult.user.id : primaryUserResult.status === "RECIPE_USER_ID_ALREADY_LINKED_WITH_PRIMARY_USER_ID_ERROR" ? primaryUserResult.primaryUserId : passwordlessUser.user.id;
|
|
2021
|
+
if (userId !== primaryUserId) {
|
|
2022
|
+
const linkResult = await import_accountlinking.default.linkAccounts(
|
|
2023
|
+
input.recipeUserId,
|
|
2024
|
+
primaryUserId,
|
|
2025
|
+
input.userContext
|
|
2026
|
+
);
|
|
2027
|
+
if (linkResult.status !== "OK") {
|
|
2028
|
+
throw new Error(
|
|
2029
|
+
`Failed to link verified email method: ${linkResult.status}`
|
|
2030
|
+
);
|
|
2031
|
+
}
|
|
2032
|
+
}
|
|
2033
|
+
metadataUserId = primaryUserId;
|
|
2034
|
+
}
|
|
2035
|
+
const targetMetadata = metadataUserId === userId ? metadata : await getUserMetadata(metadataUserId);
|
|
2036
|
+
const originalRowndUser = targetMetadata.original_rownd_user ?? metadata.original_rownd_user;
|
|
2037
|
+
const targetPendingVerifications = getPendingVerifications(targetMetadata);
|
|
2038
|
+
const updatedMetadata = {
|
|
2039
|
+
...targetMetadata,
|
|
2040
|
+
...originalRowndUser ? {
|
|
2041
|
+
original_rownd_user: {
|
|
2042
|
+
...originalRowndUser,
|
|
2043
|
+
data: {
|
|
2044
|
+
...originalRowndUser.data,
|
|
2045
|
+
email: input.email
|
|
2221
2046
|
},
|
|
2222
|
-
|
|
2223
|
-
...
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2047
|
+
verified_data: {
|
|
2048
|
+
...originalRowndUser.verified_data,
|
|
2049
|
+
email: input.email
|
|
2050
|
+
}
|
|
2051
|
+
}
|
|
2052
|
+
} : {},
|
|
2053
|
+
rownd_pending_verification: targetPendingVerifications.filter(
|
|
2054
|
+
(verification) => !isMatchingPendingEmailVerification(
|
|
2055
|
+
verification,
|
|
2056
|
+
input.email
|
|
2057
|
+
)
|
|
2058
|
+
)
|
|
2059
|
+
};
|
|
2060
|
+
await import_usermetadata2.default.updateUserMetadata(metadataUserId, updatedMetadata);
|
|
2061
|
+
}
|
|
2062
|
+
function isMatchingPendingEmailVerification(verification, email) {
|
|
2063
|
+
return verification.field === "email" && verification.value === email;
|
|
2064
|
+
}
|
|
2065
|
+
async function updateUserMetadata(userId, inputMeta) {
|
|
2066
|
+
const metadata = await getUserMetadata(userId);
|
|
2067
|
+
const updatedMetadata = {
|
|
2068
|
+
...metadata,
|
|
2069
|
+
...inputMeta
|
|
2070
|
+
};
|
|
2071
|
+
await import_usermetadata2.default.updateUserMetadata(userId, updatedMetadata);
|
|
2072
|
+
return {
|
|
2073
|
+
id: userId,
|
|
2074
|
+
meta: Object.fromEntries(
|
|
2075
|
+
Object.entries(updatedMetadata).filter(
|
|
2076
|
+
([key]) => !isInternalMetadataField(key)
|
|
2077
|
+
)
|
|
2078
|
+
)
|
|
2079
|
+
};
|
|
2080
|
+
}
|
|
2081
|
+
function getPasswordlessEmailLoginMethod(user) {
|
|
2082
|
+
return user?.loginMethods.find((method) => {
|
|
2083
|
+
return method.recipeId === "passwordless" && !!method.email;
|
|
2084
|
+
});
|
|
2085
|
+
}
|
|
2086
|
+
|
|
2087
|
+
// src/pluginImplementation.ts
|
|
2088
|
+
var import_crypto = require("crypto");
|
|
2089
|
+
var import_supertokens_node3 = __toESM(require("supertokens-node"));
|
|
2090
|
+
var import_session2 = __toESM(require("supertokens-node/recipe/session"));
|
|
2091
|
+
var import_thirdparty = __toESM(require("supertokens-node/recipe/thirdparty"));
|
|
2092
|
+
function handleGetAppConfig(deps) {
|
|
2093
|
+
return async (req) => {
|
|
2094
|
+
const appVariantId = getRequestedAppVariantIdFromRequest(req);
|
|
2095
|
+
const appConfig = buildRowndAppConfig(
|
|
2096
|
+
deps.pluginConfig,
|
|
2097
|
+
deps.stConfig,
|
|
2098
|
+
appVariantId
|
|
2099
|
+
);
|
|
2100
|
+
if (!appConfig) {
|
|
2101
|
+
return {
|
|
2102
|
+
status: "ERROR",
|
|
2103
|
+
message: `Unknown Rownd app variant: ${appVariantId}`
|
|
2104
|
+
};
|
|
2105
|
+
}
|
|
2106
|
+
return {
|
|
2107
|
+
status: "OK",
|
|
2108
|
+
...appConfig
|
|
2109
|
+
};
|
|
2110
|
+
};
|
|
2111
|
+
}
|
|
2112
|
+
function handleGuestLogin(deps) {
|
|
2113
|
+
return async (req, res, _session, userContext) => {
|
|
2114
|
+
const startedAt = Date.now();
|
|
2115
|
+
const guestId = `guest_${(0, import_crypto.randomUUID)()}`;
|
|
2116
|
+
try {
|
|
2117
|
+
const body = parseGuestBody(await getJsonBody(req));
|
|
2118
|
+
const appVariantId = getRequestedAppVariantIdFromRequest(req);
|
|
2119
|
+
assertRowndAppVariantIsConfigured(appVariantId);
|
|
2120
|
+
const thirdPartyId = body.authLevel === ANONYMOUS_AUTH_METHOD_ID ? ANONYMOUS_AUTH_METHOD_ID : GUEST_AUTH_METHOD_ID;
|
|
2121
|
+
const thirdPartyUserId = thirdPartyId === ANONYMOUS_AUTH_METHOD_ID ? `anon_${(0, import_crypto.randomUUID)()}` : guestId;
|
|
2122
|
+
const response = await import_thirdparty.default.manuallyCreateOrUpdateUser(
|
|
2123
|
+
PUBLIC_TENANT_ID,
|
|
2124
|
+
thirdPartyId,
|
|
2125
|
+
thirdPartyUserId,
|
|
2126
|
+
`${thirdPartyUserId}@anonymous.local`,
|
|
2127
|
+
false,
|
|
2128
|
+
void 0,
|
|
2129
|
+
userContext
|
|
2130
|
+
);
|
|
2131
|
+
if (response.status !== "OK") {
|
|
2132
|
+
throw new Error(
|
|
2133
|
+
`Guest user creation failed with status: ${response.status}`
|
|
2134
|
+
);
|
|
2135
|
+
}
|
|
2136
|
+
await import_session2.default.createNewSession(
|
|
2137
|
+
req,
|
|
2138
|
+
res,
|
|
2139
|
+
PUBLIC_TENANT_ID,
|
|
2140
|
+
response.recipeUserId,
|
|
2141
|
+
{
|
|
2142
|
+
...buildRowndAudience({}, appVariantId),
|
|
2143
|
+
auth_level: GUEST_AUTH_METHOD_ID,
|
|
2144
|
+
is_anonymous: true,
|
|
2145
|
+
app_user_id: response.user.id
|
|
2146
|
+
},
|
|
2147
|
+
{},
|
|
2148
|
+
userContext
|
|
2149
|
+
);
|
|
2150
|
+
logDebugMessage(`Guest session created for user: ${response.user.id}`);
|
|
2151
|
+
deps.telemetryClient.recordSuccess({
|
|
2152
|
+
outcome: "success",
|
|
2153
|
+
durationMs: Date.now() - startedAt,
|
|
2154
|
+
tenantId: PUBLIC_TENANT_ID,
|
|
2155
|
+
superTokensUserId: response.user.id
|
|
2156
|
+
});
|
|
2157
|
+
return {
|
|
2158
|
+
status: "OK",
|
|
2159
|
+
createdNewRecipeUser: response.createdNewRecipeUser
|
|
2160
|
+
};
|
|
2161
|
+
} catch (error) {
|
|
2162
|
+
logDebugMessage(`Guest login failed. Error: ${getErrorMessage(error)}`);
|
|
2163
|
+
deps.telemetryClient.recordError({
|
|
2164
|
+
error,
|
|
2165
|
+
startedAt,
|
|
2166
|
+
tenantId: PUBLIC_TENANT_ID
|
|
2167
|
+
});
|
|
2168
|
+
return {
|
|
2169
|
+
status: "ERROR",
|
|
2170
|
+
message: "Guest login failed"
|
|
2171
|
+
};
|
|
2172
|
+
}
|
|
2173
|
+
};
|
|
2174
|
+
}
|
|
2175
|
+
function handleMigrate(deps) {
|
|
2176
|
+
return async (req, res, _session, userContext) => {
|
|
2177
|
+
const startedAt = Date.now();
|
|
2178
|
+
let tenantId = PUBLIC_TENANT_ID;
|
|
2179
|
+
let rowndUserId;
|
|
2180
|
+
let superTokensUserId;
|
|
2181
|
+
let user;
|
|
2182
|
+
let recipeUserId;
|
|
2183
|
+
try {
|
|
2184
|
+
if (!deps.stConfig.supertokens) {
|
|
2185
|
+
throw new Error("Supertokens config not found");
|
|
2186
|
+
}
|
|
2187
|
+
const parsed = await parseRequest(req);
|
|
2188
|
+
const appVariantId = getRequestedAppVariantIdFromRequest(req);
|
|
2189
|
+
assertRowndAppVariantIsConfigured(appVariantId);
|
|
2190
|
+
rowndUserId = await validateRowndToken(parsed.token);
|
|
2191
|
+
user = await import_supertokens_node3.default.getUser(rowndUserId, userContext);
|
|
2192
|
+
if (!user) {
|
|
2193
|
+
const rowndUser = await fetchRowndUserInfo(rowndUserId);
|
|
2194
|
+
const stUserImport = mapRowndUserToSuperTokens(rowndUser);
|
|
2195
|
+
try {
|
|
2196
|
+
const importedUser = await importUser(
|
|
2197
|
+
stUserImport,
|
|
2198
|
+
deps.stConfig.supertokens
|
|
2199
|
+
);
|
|
2200
|
+
superTokensUserId = importedUser.id;
|
|
2201
|
+
if (importedUser.loginMethods[0]?.recipeUserId) {
|
|
2202
|
+
recipeUserId = import_supertokens_node3.default.convertToRecipeUserId(
|
|
2203
|
+
importedUser.loginMethods[0].recipeUserId
|
|
2204
|
+
);
|
|
2205
|
+
}
|
|
2206
|
+
} catch (err) {
|
|
2207
|
+
user = await import_supertokens_node3.default.getUser(rowndUserId, userContext);
|
|
2208
|
+
if (!user) {
|
|
2209
|
+
throw err;
|
|
2310
2210
|
}
|
|
2211
|
+
superTokensUserId = user.id;
|
|
2212
|
+
recipeUserId = user.loginMethods[0]?.recipeUserId;
|
|
2213
|
+
logDebugMessage(
|
|
2214
|
+
`User already migrated (race condition). tenantId: ${PUBLIC_TENANT_ID}, rowndUserId: ${rowndUserId}`
|
|
2215
|
+
);
|
|
2311
2216
|
}
|
|
2217
|
+
logDebugMessage(
|
|
2218
|
+
`User migrated successfully. tenantId: ${PUBLIC_TENANT_ID}, rowndUserId: ${rowndUserId}`
|
|
2219
|
+
);
|
|
2220
|
+
} else {
|
|
2221
|
+
superTokensUserId = user.id;
|
|
2222
|
+
recipeUserId = user.loginMethods[0]?.recipeUserId;
|
|
2223
|
+
logDebugMessage(
|
|
2224
|
+
`User already migrated. tenantId: ${PUBLIC_TENANT_ID}, rowndUserId: ${rowndUserId}`
|
|
2225
|
+
);
|
|
2226
|
+
}
|
|
2227
|
+
if (superTokensUserId) {
|
|
2228
|
+
await recordRowndAppVariantForUser(superTokensUserId, appVariantId);
|
|
2229
|
+
}
|
|
2230
|
+
if (!recipeUserId) {
|
|
2231
|
+
throw new Error("User not found or has no login methods");
|
|
2312
2232
|
}
|
|
2233
|
+
await import_session2.default.createNewSession(
|
|
2234
|
+
req,
|
|
2235
|
+
res,
|
|
2236
|
+
PUBLIC_TENANT_ID,
|
|
2237
|
+
recipeUserId,
|
|
2238
|
+
{
|
|
2239
|
+
...buildRowndAudience({}, appVariantId)
|
|
2240
|
+
},
|
|
2241
|
+
{},
|
|
2242
|
+
userContext
|
|
2243
|
+
);
|
|
2244
|
+
logDebugMessage(
|
|
2245
|
+
`Session migrated successfully. tenantId: ${PUBLIC_TENANT_ID}, userId: ${superTokensUserId}`
|
|
2246
|
+
);
|
|
2247
|
+
deps.telemetryClient.recordSuccess({
|
|
2248
|
+
outcome: "success",
|
|
2249
|
+
durationMs: Date.now() - startedAt,
|
|
2250
|
+
tenantId,
|
|
2251
|
+
rowndUserId,
|
|
2252
|
+
superTokensUserId
|
|
2253
|
+
});
|
|
2254
|
+
return { status: "OK" };
|
|
2255
|
+
} catch (error) {
|
|
2256
|
+
logDebugMessage(`Migration failed. Error: ${getErrorMessage(error)}`);
|
|
2257
|
+
deps.telemetryClient.recordError({
|
|
2258
|
+
error,
|
|
2259
|
+
startedAt,
|
|
2260
|
+
tenantId,
|
|
2261
|
+
rowndUserId,
|
|
2262
|
+
superTokensUserId
|
|
2263
|
+
});
|
|
2264
|
+
return {
|
|
2265
|
+
status: "ERROR",
|
|
2266
|
+
message: error instanceof RowndPluginError ? error.message : "Migration failed"
|
|
2267
|
+
};
|
|
2313
2268
|
}
|
|
2314
2269
|
};
|
|
2315
2270
|
}
|
|
2316
|
-
function
|
|
2317
|
-
return {
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
...authEmail?.customContent ? { custom_content: authEmail.customContent } : {},
|
|
2324
|
-
...authEmail?.customClosingContent ? { custom_closing_content: authEmail.customClosingContent } : {}
|
|
2271
|
+
function handleGetUser() {
|
|
2272
|
+
return async (_req, _res, session) => {
|
|
2273
|
+
const user = await getUserById(session.getUserId());
|
|
2274
|
+
return {
|
|
2275
|
+
status: "OK",
|
|
2276
|
+
...user
|
|
2277
|
+
};
|
|
2325
2278
|
};
|
|
2326
2279
|
}
|
|
2327
|
-
function
|
|
2280
|
+
function handleUpdateUser() {
|
|
2281
|
+
return async (req, _res, session, userContext) => {
|
|
2282
|
+
const appVariantId = getRequestedAppVariantIdFromRequest(req);
|
|
2283
|
+
assertRowndAppVariantIsConfigured(appVariantId);
|
|
2284
|
+
const payload = parseUpdateUserBody(await getJsonBody(req));
|
|
2285
|
+
const inputData = payload.data ?? {};
|
|
2286
|
+
const requestUserContext = {
|
|
2287
|
+
...userContext,
|
|
2288
|
+
...payload.context
|
|
2289
|
+
};
|
|
2290
|
+
const { email, ...dataWithoutEmail } = inputData;
|
|
2291
|
+
const hasEmailUpdate = hasOwn(inputData, "email") && typeof email === "string";
|
|
2292
|
+
const permissionError = validateWritableFields(
|
|
2293
|
+
Object.keys(dataWithoutEmail)
|
|
2294
|
+
);
|
|
2295
|
+
if (permissionError) {
|
|
2296
|
+
return permissionError;
|
|
2297
|
+
}
|
|
2298
|
+
if (Object.keys(dataWithoutEmail).length > 0) {
|
|
2299
|
+
await updateUserData(session.getUserId(), dataWithoutEmail);
|
|
2300
|
+
}
|
|
2301
|
+
if (hasEmailUpdate) {
|
|
2302
|
+
const pendingVerificationResult = await startPendingEmailVerification({
|
|
2303
|
+
userId: session.getUserId(),
|
|
2304
|
+
recipeUserId: session.getRecipeUserId(),
|
|
2305
|
+
tenantId: session.getTenantId(),
|
|
2306
|
+
email,
|
|
2307
|
+
pendingVerificationId: (0, import_crypto.randomUUID)(),
|
|
2308
|
+
userContext: appVariantId ? { ...requestUserContext, rowndAppVariantId: appVariantId } : requestUserContext
|
|
2309
|
+
});
|
|
2310
|
+
return {
|
|
2311
|
+
status: "OK",
|
|
2312
|
+
...pendingVerificationResult
|
|
2313
|
+
};
|
|
2314
|
+
}
|
|
2315
|
+
const user = await getUserById(session.getUserId());
|
|
2316
|
+
return {
|
|
2317
|
+
status: "OK",
|
|
2318
|
+
...user
|
|
2319
|
+
};
|
|
2320
|
+
};
|
|
2321
|
+
}
|
|
2322
|
+
function handleDeleteUser() {
|
|
2323
|
+
return async (_req, _res, session) => {
|
|
2324
|
+
await import_supertokens_node3.default.deleteUser(session.getUserId(), true);
|
|
2325
|
+
return { status: "OK" };
|
|
2326
|
+
};
|
|
2327
|
+
}
|
|
2328
|
+
function handleSignOut() {
|
|
2329
|
+
return async (_req, _res, session, userContext) => {
|
|
2330
|
+
await import_session2.default.revokeAllSessionsForUser(
|
|
2331
|
+
session.getUserId(),
|
|
2332
|
+
true,
|
|
2333
|
+
session.getTenantId(),
|
|
2334
|
+
userContext
|
|
2335
|
+
);
|
|
2336
|
+
return { status: "OK" };
|
|
2337
|
+
};
|
|
2338
|
+
}
|
|
2339
|
+
function handleGetUserMeta() {
|
|
2340
|
+
return async (_req, _res, session) => {
|
|
2341
|
+
const metadata = await getUserMetadata(session.getUserId());
|
|
2342
|
+
return {
|
|
2343
|
+
status: "OK",
|
|
2344
|
+
id: session.getUserId(),
|
|
2345
|
+
meta: Object.fromEntries(
|
|
2346
|
+
Object.entries(metadata).filter(
|
|
2347
|
+
([key]) => !isInternalMetadataField(key)
|
|
2348
|
+
)
|
|
2349
|
+
)
|
|
2350
|
+
};
|
|
2351
|
+
};
|
|
2352
|
+
}
|
|
2353
|
+
function handleUpdateUserMeta() {
|
|
2354
|
+
return async (req, _res, session) => {
|
|
2355
|
+
const payload = parseUpdateMetaBody(await getJsonBody(req));
|
|
2356
|
+
const internalField = Object.keys(payload.meta ?? {}).find(
|
|
2357
|
+
isInternalMetadataField
|
|
2358
|
+
);
|
|
2359
|
+
if (internalField) {
|
|
2360
|
+
return {
|
|
2361
|
+
status: "ERROR",
|
|
2362
|
+
code: 403,
|
|
2363
|
+
message: `field is not writable: ${internalField}`
|
|
2364
|
+
};
|
|
2365
|
+
}
|
|
2366
|
+
const updateMetadataResult = await updateUserMetadata(
|
|
2367
|
+
session.getUserId(),
|
|
2368
|
+
payload.meta ?? {}
|
|
2369
|
+
);
|
|
2370
|
+
return {
|
|
2371
|
+
status: "OK",
|
|
2372
|
+
...updateMetadataResult
|
|
2373
|
+
};
|
|
2374
|
+
};
|
|
2375
|
+
}
|
|
2376
|
+
function handleGetUserField() {
|
|
2377
|
+
return async (req, _res, session) => {
|
|
2378
|
+
const field = req.getKeyValueFromQuery("field");
|
|
2379
|
+
if (!field) {
|
|
2380
|
+
return missingFieldResponse();
|
|
2381
|
+
}
|
|
2382
|
+
const user = await getUserById(session.getUserId());
|
|
2383
|
+
return {
|
|
2384
|
+
status: "OK",
|
|
2385
|
+
value: user.data[field]
|
|
2386
|
+
};
|
|
2387
|
+
};
|
|
2388
|
+
}
|
|
2389
|
+
function handleUpdateUserField() {
|
|
2390
|
+
return async (req, _res, session, userContext) => {
|
|
2391
|
+
const appVariantId = getRequestedAppVariantIdFromRequest(req);
|
|
2392
|
+
assertRowndAppVariantIsConfigured(appVariantId);
|
|
2393
|
+
const field = req.getKeyValueFromQuery("field");
|
|
2394
|
+
if (!field) {
|
|
2395
|
+
return missingFieldResponse();
|
|
2396
|
+
}
|
|
2397
|
+
const payload = parseUpdateFieldBody(await getJsonBody(req));
|
|
2398
|
+
if (field === "email" && typeof payload.value === "string") {
|
|
2399
|
+
const pendingVerificationResult = await startPendingEmailVerification({
|
|
2400
|
+
userId: session.getUserId(),
|
|
2401
|
+
recipeUserId: session.getRecipeUserId(),
|
|
2402
|
+
tenantId: session.getTenantId(),
|
|
2403
|
+
email: payload.value,
|
|
2404
|
+
pendingVerificationId: (0, import_crypto.randomUUID)(),
|
|
2405
|
+
userContext: appVariantId ? { ...userContext, rowndAppVariantId: appVariantId } : userContext
|
|
2406
|
+
});
|
|
2407
|
+
return {
|
|
2408
|
+
status: "OK",
|
|
2409
|
+
...pendingVerificationResult
|
|
2410
|
+
};
|
|
2411
|
+
}
|
|
2412
|
+
const permissionError = validateWritableFields([field]);
|
|
2413
|
+
if (permissionError) {
|
|
2414
|
+
return permissionError;
|
|
2415
|
+
}
|
|
2416
|
+
const updateUserDataResult = await updateUserData(session.getUserId(), {
|
|
2417
|
+
[field]: payload.value
|
|
2418
|
+
});
|
|
2419
|
+
return {
|
|
2420
|
+
status: "OK",
|
|
2421
|
+
...updateUserDataResult
|
|
2422
|
+
};
|
|
2423
|
+
};
|
|
2424
|
+
}
|
|
2425
|
+
function validateWritableFields(fields) {
|
|
2426
|
+
const readOnlyField = fields.find((field) => !canUpdateUserDataField(field));
|
|
2427
|
+
if (!readOnlyField) {
|
|
2428
|
+
return void 0;
|
|
2429
|
+
}
|
|
2328
2430
|
return {
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
...authMobile?.hyperlinkText ? { hyperlink_text: authMobile.hyperlinkText } : {},
|
|
2333
|
-
...authMobile?.hyperlinkRedirectUrl ? { hyperlink_redirect_url: authMobile.hyperlinkRedirectUrl } : {},
|
|
2334
|
-
...authMobile?.customContent ? { custom_content: authMobile.customContent } : {}
|
|
2431
|
+
status: "ERROR",
|
|
2432
|
+
code: 403,
|
|
2433
|
+
message: `field is not writable: ${readOnlyField}`
|
|
2335
2434
|
};
|
|
2336
2435
|
}
|
|
2337
2436
|
|
|
@@ -2348,6 +2447,9 @@ var init = createPluginInitFunction(
|
|
|
2348
2447
|
const appVariantId = input?.userContext?.rowndAppVariantId;
|
|
2349
2448
|
const displayContext = input?.userContext?.rowndDisplayContext;
|
|
2350
2449
|
const redirectToPath = input?.userContext?.rowndRedirectToPath;
|
|
2450
|
+
const clientDomain = input?.userContext?.rowndClientDomain;
|
|
2451
|
+
const clientDomainKey = clientDomain ?? (displayContext === "mobile_app" ? "mobile" : "browser");
|
|
2452
|
+
const clientBaseUrl = pluginConfig2.clientDomains?.[clientDomainKey];
|
|
2351
2453
|
const bootstrapParams = {
|
|
2352
2454
|
appKey: pluginConfig2.rowndAppKey,
|
|
2353
2455
|
...hubBootstrapParams ?? {},
|
|
@@ -2355,9 +2457,15 @@ var init = createPluginInitFunction(
|
|
|
2355
2457
|
...typeof displayContext === "string" ? { displayContext } : {},
|
|
2356
2458
|
...typeof redirectToPath === "string" ? { redirectToPath } : {}
|
|
2357
2459
|
};
|
|
2460
|
+
const rewrittenLink = input[linkKey] ? clientBaseUrl ? rewriteLinkToBaseUrl(
|
|
2461
|
+
input[linkKey],
|
|
2462
|
+
targetPath,
|
|
2463
|
+
clientBaseUrl,
|
|
2464
|
+
bootstrapParams
|
|
2465
|
+
) : rewriteLinkPath(input[linkKey], targetPath, bootstrapParams) : input[linkKey];
|
|
2358
2466
|
return {
|
|
2359
2467
|
...input,
|
|
2360
|
-
[linkKey]:
|
|
2468
|
+
[linkKey]: rewrittenLink
|
|
2361
2469
|
};
|
|
2362
2470
|
};
|
|
2363
2471
|
setRowndClient(rowndClient2);
|
|
@@ -2370,17 +2478,17 @@ var init = createPluginInitFunction(
|
|
|
2370
2478
|
id: PLUGIN_ID,
|
|
2371
2479
|
compatibleSDKVersions: PLUGIN_SDK_VERSION,
|
|
2372
2480
|
init: async () => {
|
|
2373
|
-
if (!
|
|
2481
|
+
if (!import_supertokens_node4.default.isRecipeInitialized("session")) {
|
|
2374
2482
|
console.warn(
|
|
2375
2483
|
"RowndMigrationPlugin: Session recipe is not initialized. Session migration will fail."
|
|
2376
2484
|
);
|
|
2377
2485
|
}
|
|
2378
|
-
if (!
|
|
2486
|
+
if (!import_supertokens_node4.default.isRecipeInitialized("thirdparty")) {
|
|
2379
2487
|
console.warn(
|
|
2380
2488
|
"RowndMigrationPlugin: ThirdParty recipe is not initialized. Guest login will fail."
|
|
2381
2489
|
);
|
|
2382
2490
|
}
|
|
2383
|
-
if (!
|
|
2491
|
+
if (!import_supertokens_node4.default.isRecipeInitialized("emailverification")) {
|
|
2384
2492
|
console.warn(
|
|
2385
2493
|
"RowndMigrationPlugin: EmailVerification recipe is not initialized. Verified email profile updates will fail."
|
|
2386
2494
|
);
|
|
@@ -2493,13 +2601,13 @@ var init = createPluginInitFunction(
|
|
|
2493
2601
|
return {
|
|
2494
2602
|
...implementation,
|
|
2495
2603
|
sendEmail: async function(input) {
|
|
2496
|
-
return implementation.sendEmail(
|
|
2497
|
-
|
|
2604
|
+
return implementation.sendEmail(
|
|
2605
|
+
addHubBootstrapParams(
|
|
2498
2606
|
input,
|
|
2499
2607
|
"urlWithLinkCode",
|
|
2500
|
-
|
|
2608
|
+
HUB_LOGIN_PAGE_PATH
|
|
2501
2609
|
)
|
|
2502
|
-
|
|
2610
|
+
);
|
|
2503
2611
|
}
|
|
2504
2612
|
};
|
|
2505
2613
|
}
|
|
@@ -2514,13 +2622,13 @@ var init = createPluginInitFunction(
|
|
|
2514
2622
|
return {
|
|
2515
2623
|
...implementation,
|
|
2516
2624
|
sendSms: async function(input) {
|
|
2517
|
-
return implementation.sendSms(
|
|
2518
|
-
|
|
2625
|
+
return implementation.sendSms(
|
|
2626
|
+
addHubBootstrapParams(
|
|
2519
2627
|
input,
|
|
2520
2628
|
"urlWithLinkCode",
|
|
2521
|
-
|
|
2629
|
+
HUB_LOGIN_PAGE_PATH
|
|
2522
2630
|
)
|
|
2523
|
-
|
|
2631
|
+
);
|
|
2524
2632
|
}
|
|
2525
2633
|
};
|
|
2526
2634
|
}
|
|
@@ -2536,22 +2644,29 @@ var init = createPluginInitFunction(
|
|
|
2536
2644
|
const displayContext = getRequestedDisplayContextFromRequest(
|
|
2537
2645
|
input.options.req
|
|
2538
2646
|
);
|
|
2647
|
+
if (displayContext) {
|
|
2648
|
+
input.userContext.rowndDisplayContext = displayContext;
|
|
2649
|
+
}
|
|
2539
2650
|
const redirectToPath = getRequestedRedirectToPathFromRequest(
|
|
2540
2651
|
input.options.req
|
|
2541
2652
|
);
|
|
2653
|
+
if (redirectToPath) {
|
|
2654
|
+
input.userContext.rowndRedirectToPath = redirectToPath;
|
|
2655
|
+
}
|
|
2656
|
+
const clientDomain = getRequestedClientDomainFromRequest(
|
|
2657
|
+
input.options.req
|
|
2658
|
+
);
|
|
2659
|
+
if (clientDomain) {
|
|
2660
|
+
input.userContext.rowndClientDomain = clientDomain;
|
|
2661
|
+
}
|
|
2542
2662
|
const appVariantId = getRequestedAppVariantIdFromRequest(
|
|
2543
2663
|
input.options.req
|
|
2544
2664
|
);
|
|
2665
|
+
if (appVariantId) {
|
|
2666
|
+
input.userContext.rowndAppVariantId = appVariantId;
|
|
2667
|
+
}
|
|
2545
2668
|
assertRowndAppVariantIsConfigured(appVariantId);
|
|
2546
|
-
return originalImplementation.createCodePOST(
|
|
2547
|
-
...input,
|
|
2548
|
-
userContext: displayContext || redirectToPath || appVariantId ? {
|
|
2549
|
-
...input.userContext,
|
|
2550
|
-
...appVariantId ? { rowndAppVariantId: appVariantId } : {},
|
|
2551
|
-
...displayContext ? { rowndDisplayContext: displayContext } : {},
|
|
2552
|
-
...redirectToPath ? { rowndRedirectToPath: redirectToPath } : {}
|
|
2553
|
-
} : input.userContext
|
|
2554
|
-
});
|
|
2669
|
+
return originalImplementation.createCodePOST(input);
|
|
2555
2670
|
},
|
|
2556
2671
|
consumeCodePOST: async (input) => {
|
|
2557
2672
|
if (originalImplementation.consumeCodePOST === void 0) {
|
|
@@ -2562,11 +2677,11 @@ var init = createPluginInitFunction(
|
|
|
2562
2677
|
const appVariantId = getRequestedAppVariantIdFromRequest(
|
|
2563
2678
|
input.options.req
|
|
2564
2679
|
);
|
|
2680
|
+
if (appVariantId) {
|
|
2681
|
+
input.userContext.rowndAppVariantId = appVariantId;
|
|
2682
|
+
}
|
|
2565
2683
|
assertRowndAppVariantIsConfigured(appVariantId);
|
|
2566
|
-
const response = await originalImplementation.consumeCodePOST(
|
|
2567
|
-
...input,
|
|
2568
|
-
userContext: appVariantId ? { ...input.userContext, rowndAppVariantId: appVariantId } : input.userContext
|
|
2569
|
-
});
|
|
2684
|
+
const response = await originalImplementation.consumeCodePOST(input);
|
|
2570
2685
|
if (response.status === "OK") {
|
|
2571
2686
|
await recordRowndAppVariantForUser(
|
|
2572
2687
|
response.user.id,
|
|
@@ -2587,11 +2702,11 @@ var init = createPluginInitFunction(
|
|
|
2587
2702
|
const appVariantId = getRequestedAppVariantIdFromRequest(
|
|
2588
2703
|
input.options.req
|
|
2589
2704
|
);
|
|
2705
|
+
if (appVariantId) {
|
|
2706
|
+
input.userContext.rowndAppVariantId = appVariantId;
|
|
2707
|
+
}
|
|
2590
2708
|
assertRowndAppVariantIsConfigured(appVariantId);
|
|
2591
|
-
const response = await originalImplementation.signInUpPOST(
|
|
2592
|
-
...input,
|
|
2593
|
-
userContext: appVariantId ? { ...input.userContext, rowndAppVariantId: appVariantId } : input.userContext
|
|
2594
|
-
});
|
|
2709
|
+
const response = await originalImplementation.signInUpPOST(input);
|
|
2595
2710
|
if (response.status === "OK") {
|
|
2596
2711
|
await recordRowndAppVariantForUser(
|
|
2597
2712
|
response.user.id,
|
|
@@ -2629,19 +2744,23 @@ var init = createPluginInitFunction(
|
|
|
2629
2744
|
functions: (originalImplementation) => ({
|
|
2630
2745
|
...originalImplementation,
|
|
2631
2746
|
createNewSession: async (input) => {
|
|
2632
|
-
|
|
2633
|
-
|
|
2634
|
-
...await buildRowndSessionClaims(
|
|
2747
|
+
const [rowndSessionClaims, rowndIsAnonymousClaim] = await Promise.all([
|
|
2748
|
+
buildRowndSessionClaims(
|
|
2635
2749
|
input.userId,
|
|
2636
2750
|
input.accessTokenPayload
|
|
2637
2751
|
),
|
|
2638
|
-
|
|
2752
|
+
RowndIsAnonymousClaim.build(
|
|
2639
2753
|
input.userId,
|
|
2640
2754
|
input.recipeUserId,
|
|
2641
2755
|
input.tenantId,
|
|
2642
2756
|
input.accessTokenPayload,
|
|
2643
2757
|
input.userContext
|
|
2644
2758
|
)
|
|
2759
|
+
]);
|
|
2760
|
+
input.accessTokenPayload = {
|
|
2761
|
+
...input.accessTokenPayload,
|
|
2762
|
+
...rowndSessionClaims,
|
|
2763
|
+
...rowndIsAnonymousClaim
|
|
2645
2764
|
};
|
|
2646
2765
|
return originalImplementation.createNewSession(input);
|
|
2647
2766
|
}
|
|
@@ -2667,7 +2786,7 @@ var init = createPluginInitFunction(
|
|
|
2667
2786
|
...addHubBootstrapParams(
|
|
2668
2787
|
input,
|
|
2669
2788
|
"emailVerifyLink",
|
|
2670
|
-
|
|
2789
|
+
HUB_VERIFY_EMAIL_PAGE_PATH
|
|
2671
2790
|
)
|
|
2672
2791
|
});
|
|
2673
2792
|
}
|
|
@@ -2720,10 +2839,14 @@ var init = createPluginInitFunction(
|
|
|
2720
2839
|
);
|
|
2721
2840
|
}
|
|
2722
2841
|
}
|
|
2842
|
+
for (const [key, value] of Object.entries(config2.clientDomains ?? {})) {
|
|
2843
|
+
validateClientDomainUrl(key, value);
|
|
2844
|
+
}
|
|
2723
2845
|
return {
|
|
2724
2846
|
rowndAppKey: config2.rowndAppKey,
|
|
2725
2847
|
rowndAppSecret: config2.rowndAppSecret,
|
|
2726
2848
|
enableDebugLogs: config2.enableDebugLogs,
|
|
2849
|
+
clientDomains: config2.clientDomains,
|
|
2727
2850
|
telemetry: config2.telemetry,
|
|
2728
2851
|
schema: config2.schema,
|
|
2729
2852
|
appConfig: config2.appConfig,
|
|
@@ -2731,6 +2854,16 @@ var init = createPluginInitFunction(
|
|
|
2731
2854
|
};
|
|
2732
2855
|
}
|
|
2733
2856
|
);
|
|
2857
|
+
function validateClientDomainUrl(key, value) {
|
|
2858
|
+
try {
|
|
2859
|
+
if (typeof value !== "string" || !/^[A-Za-z][A-Za-z0-9+.-]*:\/\//.test(value)) {
|
|
2860
|
+
throw new Error();
|
|
2861
|
+
}
|
|
2862
|
+
new URL(value);
|
|
2863
|
+
} catch {
|
|
2864
|
+
throw new Error(`Invalid clientDomains.${key} in plugin config`);
|
|
2865
|
+
}
|
|
2866
|
+
}
|
|
2734
2867
|
|
|
2735
2868
|
// src/index.ts
|
|
2736
2869
|
var index_default = { init };
|
|
@@ -2740,8 +2873,11 @@ var index_default = { init };
|
|
|
2740
2873
|
DEFAULT_ROWND_SCHEMA,
|
|
2741
2874
|
GUEST_AUTH_METHOD_ID,
|
|
2742
2875
|
HANDLE_BASE_PATH,
|
|
2876
|
+
HUB_LOGIN_PAGE_PATH,
|
|
2877
|
+
HUB_VERIFY_EMAIL_PAGE_PATH,
|
|
2743
2878
|
PLUGIN_ID,
|
|
2744
2879
|
PLUGIN_SDK_VERSION,
|
|
2880
|
+
PLUGIN_VERSION,
|
|
2745
2881
|
PUBLIC_TENANT_ID,
|
|
2746
2882
|
ROWND_JWT_CLAIMS,
|
|
2747
2883
|
ROWND_PLUGIN_ERROR_MESSAGES,
|