@supertokens-plugins/rownd-nodejs 0.5.1 → 0.6.1
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 +35 -3
- package/dist/bulkMigrate.js +24 -8
- package/dist/generateAppConfig.js +2 -1
- package/dist/index.d.mts +12 -4
- package/dist/index.d.ts +12 -4
- package/dist/index.js +127 -62
- package/dist/index.mjs +127 -62
- package/dist/initConfig.js +2 -0
- package/dist/setupCoreInstance.js +2 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -866,6 +866,9 @@ var RowndPluginError = class extends Error {
|
|
|
866
866
|
|
|
867
867
|
// src/utils.ts
|
|
868
868
|
var ROWND_OAUTH_LOGIN_CHALLENGE_PARAM = "rownd_oauth_login_challenge";
|
|
869
|
+
function resolveTenantId(req) {
|
|
870
|
+
return req.getKeyValueFromQuery("tenantId") || PUBLIC_TENANT_ID;
|
|
871
|
+
}
|
|
869
872
|
function rewriteLinkPath(inputUrl, targetPath, searchParams) {
|
|
870
873
|
try {
|
|
871
874
|
const url = new URL(inputUrl);
|
|
@@ -1497,7 +1500,7 @@ function isIdentityField(field) {
|
|
|
1497
1500
|
function isInternalMetadataField(field) {
|
|
1498
1501
|
return INTERNAL_METADATA_FIELDS.has(field);
|
|
1499
1502
|
}
|
|
1500
|
-
function mapRowndUserToSuperTokens(rowndUser) {
|
|
1503
|
+
function mapRowndUserToSuperTokens(rowndUser, tenantId) {
|
|
1501
1504
|
const loginMethods = [];
|
|
1502
1505
|
const rowndUserData = rowndUser.data || {};
|
|
1503
1506
|
const rowndUserVerifiedData = rowndUser.verified_data || {};
|
|
@@ -1511,7 +1514,8 @@ function mapRowndUserToSuperTokens(rowndUser) {
|
|
|
1511
1514
|
thirdPartyId: "google",
|
|
1512
1515
|
thirdPartyUserId: rowndUserData.google_id,
|
|
1513
1516
|
email: googleEmail,
|
|
1514
|
-
isVerified: !!rowndUserData.email && !!rowndUserVerifiedData.google_id
|
|
1517
|
+
isVerified: !!rowndUserData.email && !!rowndUserVerifiedData.google_id,
|
|
1518
|
+
...tenantId ? { tenantIds: [tenantId] } : {}
|
|
1515
1519
|
});
|
|
1516
1520
|
}
|
|
1517
1521
|
if (rowndUserData.apple_id) {
|
|
@@ -1521,21 +1525,24 @@ function mapRowndUserToSuperTokens(rowndUser) {
|
|
|
1521
1525
|
thirdPartyId: "apple",
|
|
1522
1526
|
thirdPartyUserId: rowndUserData.apple_id,
|
|
1523
1527
|
email: appleEmail,
|
|
1524
|
-
isVerified: !!rowndUserData.email && !!rowndUserVerifiedData.apple_id
|
|
1528
|
+
isVerified: !!rowndUserData.email && !!rowndUserVerifiedData.apple_id,
|
|
1529
|
+
...tenantId ? { tenantIds: [tenantId] } : {}
|
|
1525
1530
|
});
|
|
1526
1531
|
}
|
|
1527
1532
|
if (rowndUserData.phone_number) {
|
|
1528
1533
|
loginMethods.push({
|
|
1529
1534
|
recipeId: "passwordless",
|
|
1530
1535
|
phoneNumber: rowndUserData.phone_number,
|
|
1531
|
-
isVerified: !!rowndUserVerifiedData.phone_number
|
|
1536
|
+
isVerified: !!rowndUserVerifiedData.phone_number,
|
|
1537
|
+
...tenantId ? { tenantIds: [tenantId] } : {}
|
|
1532
1538
|
});
|
|
1533
1539
|
}
|
|
1534
1540
|
if (rowndUserData.email && !rowndUserData.google_id && !rowndUserData.apple_id) {
|
|
1535
1541
|
loginMethods.push({
|
|
1536
1542
|
recipeId: "passwordless",
|
|
1537
1543
|
email: rowndUserData.email,
|
|
1538
|
-
isVerified: !!rowndUserVerifiedData.email
|
|
1544
|
+
isVerified: !!rowndUserVerifiedData.email,
|
|
1545
|
+
...tenantId ? { tenantIds: [tenantId] } : {}
|
|
1539
1546
|
});
|
|
1540
1547
|
}
|
|
1541
1548
|
let authLevel = rowndUser.auth_level;
|
|
@@ -1547,7 +1554,8 @@ function mapRowndUserToSuperTokens(rowndUser) {
|
|
|
1547
1554
|
thirdPartyId,
|
|
1548
1555
|
thirdPartyUserId: rowndUserData.user_id,
|
|
1549
1556
|
email: `${rowndUserData.user_id}@anonymous.local`,
|
|
1550
|
-
isVerified: false
|
|
1557
|
+
isVerified: false,
|
|
1558
|
+
...tenantId ? { tenantIds: [tenantId] } : {}
|
|
1551
1559
|
});
|
|
1552
1560
|
}
|
|
1553
1561
|
const userMetadata = buildRowndUserMetadata(rowndUser);
|
|
@@ -2093,7 +2101,7 @@ function getPendingVerifications(metadata) {
|
|
|
2093
2101
|
function isPendingVerification(value) {
|
|
2094
2102
|
return isRecord(value) && typeof value.id === "string" && typeof value.field === "string" && typeof value.value === "string" && typeof value.created_at === "string";
|
|
2095
2103
|
}
|
|
2096
|
-
async function getUserById(userId) {
|
|
2104
|
+
async function getUserById(userId, tenantId = PUBLIC_TENANT_ID) {
|
|
2097
2105
|
const metadata = await getUserMetadata(userId);
|
|
2098
2106
|
const stUser = await import_supertokens_node2.default.getUser(userId);
|
|
2099
2107
|
if (!stUser) {
|
|
@@ -2122,7 +2130,10 @@ async function getUserById(userId) {
|
|
|
2122
2130
|
const verifiedData = {
|
|
2123
2131
|
...originalRowndUser?.verified_data || {}
|
|
2124
2132
|
};
|
|
2125
|
-
|
|
2133
|
+
const tenantLoginMethods = stUser.loginMethods.filter(
|
|
2134
|
+
(method) => method.tenantIds.includes(tenantId)
|
|
2135
|
+
);
|
|
2136
|
+
for (const method of tenantLoginMethods) {
|
|
2126
2137
|
if (method.recipeId === "passwordless") {
|
|
2127
2138
|
if (method.email && !isSuperTokensFakeEmail(method.email)) {
|
|
2128
2139
|
verifiedData.email = method.email;
|
|
@@ -2162,12 +2173,16 @@ async function getUserById(userId) {
|
|
|
2162
2173
|
if (verifiedData.phone_number === true && typeof data.phone_number === "string") {
|
|
2163
2174
|
verifiedData.phone_number = data.phone_number;
|
|
2164
2175
|
}
|
|
2165
|
-
const
|
|
2176
|
+
const tenantUser = {
|
|
2177
|
+
...stUser,
|
|
2178
|
+
loginMethods: tenantLoginMethods
|
|
2179
|
+
};
|
|
2180
|
+
const anonymousId = getAnonymousId(stUser.id, tenantUser, metadata);
|
|
2166
2181
|
if (anonymousId && data.anonymous_id === void 0) {
|
|
2167
2182
|
data.anonymous_id = anonymousId;
|
|
2168
2183
|
}
|
|
2169
2184
|
const authLevel = getEffectiveAuthLevel(
|
|
2170
|
-
|
|
2185
|
+
tenantUser,
|
|
2171
2186
|
originalRowndUser?.auth_level,
|
|
2172
2187
|
verifiedData
|
|
2173
2188
|
);
|
|
@@ -2176,15 +2191,15 @@ async function getUserById(userId) {
|
|
|
2176
2191
|
data[key] = "";
|
|
2177
2192
|
}
|
|
2178
2193
|
}
|
|
2179
|
-
const sortedByJoined = [...
|
|
2194
|
+
const sortedByJoined = [...tenantLoginMethods].sort(
|
|
2180
2195
|
(a, b) => a.timeJoined - b.timeJoined
|
|
2181
2196
|
);
|
|
2182
|
-
const latestSessionInfo = await getLatestSessionInfo(stUser.id);
|
|
2197
|
+
const latestSessionInfo = await getLatestSessionInfo(stUser.id, tenantId);
|
|
2183
2198
|
const firstMethod = sortedByJoined[0];
|
|
2184
2199
|
const latestSessionRecipeUserId = latestSessionInfo?.recipeUserId.getAsString();
|
|
2185
2200
|
const lastMethod = latestSessionRecipeUserId ? stUser.loginMethods.find(
|
|
2186
2201
|
(method) => method.recipeUserId.getAsString() === latestSessionRecipeUserId
|
|
2187
|
-
) : [...
|
|
2202
|
+
) : [...tenantLoginMethods].sort((a, b) => b.timeJoined - a.timeJoined)[0];
|
|
2188
2203
|
const lastSignInAt = latestSessionInfo?.timeCreated ?? stUser.timeJoined;
|
|
2189
2204
|
const metadataMeta = Object.fromEntries(
|
|
2190
2205
|
Object.entries(metadata).filter(
|
|
@@ -2212,11 +2227,11 @@ async function getUserById(userId) {
|
|
|
2212
2227
|
attributes: originalRowndUser?.attributes || {}
|
|
2213
2228
|
};
|
|
2214
2229
|
}
|
|
2215
|
-
async function getLatestSessionInfo(userId) {
|
|
2230
|
+
async function getLatestSessionInfo(userId, tenantId) {
|
|
2216
2231
|
const sessionHandles = await import_session.default.getAllSessionHandlesForUser(
|
|
2217
2232
|
userId,
|
|
2218
2233
|
true,
|
|
2219
|
-
|
|
2234
|
+
tenantId
|
|
2220
2235
|
);
|
|
2221
2236
|
const sessionInfos = await Promise.all(
|
|
2222
2237
|
sessionHandles.map(
|
|
@@ -2231,21 +2246,21 @@ async function getLatestSessionInfo(userId) {
|
|
|
2231
2246
|
}
|
|
2232
2247
|
return latestSessionInfo;
|
|
2233
2248
|
}
|
|
2234
|
-
async function updateUserData(userId, inputData) {
|
|
2249
|
+
async function updateUserData(userId, inputData, tenantId = PUBLIC_TENANT_ID) {
|
|
2235
2250
|
const metadata = await getUserMetadata(userId);
|
|
2236
2251
|
const updatedMetadata = {
|
|
2237
2252
|
...metadata,
|
|
2238
2253
|
...inputData
|
|
2239
2254
|
};
|
|
2240
2255
|
await import_usermetadata3.default.updateUserMetadata(userId, updatedMetadata);
|
|
2241
|
-
return getUserById(userId);
|
|
2256
|
+
return getUserById(userId, tenantId);
|
|
2242
2257
|
}
|
|
2243
2258
|
async function startPendingEmailVerification(input) {
|
|
2244
2259
|
const metadata = await getUserMetadata(input.userId);
|
|
2245
|
-
const currentEmail = (await getUserById(input.userId)).data.email;
|
|
2260
|
+
const currentEmail = (await getUserById(input.userId, input.tenantId)).data.email;
|
|
2246
2261
|
const pendingVerifications = getPendingVerifications(metadata);
|
|
2247
2262
|
const pendingEmailVerifications = pendingVerifications.filter(
|
|
2248
|
-
(pendingVerification2) => pendingVerification2.field === "email"
|
|
2263
|
+
(pendingVerification2) => pendingVerification2.field === "email" && (pendingVerification2.tenantId ?? PUBLIC_TENANT_ID) === input.tenantId
|
|
2249
2264
|
);
|
|
2250
2265
|
if (currentEmail === input.email) {
|
|
2251
2266
|
for (const pendingVerification2 of pendingEmailVerifications) {
|
|
@@ -2260,11 +2275,11 @@ async function startPendingEmailVerification(input) {
|
|
|
2260
2275
|
await import_usermetadata3.default.updateUserMetadata(input.userId, {
|
|
2261
2276
|
...metadata,
|
|
2262
2277
|
rownd_pending_verification: pendingVerifications.filter(
|
|
2263
|
-
(pendingVerification2) => pendingVerification2.field !== "email"
|
|
2278
|
+
(pendingVerification2) => pendingVerification2.field !== "email" || (pendingVerification2.tenantId ?? PUBLIC_TENANT_ID) !== input.tenantId
|
|
2264
2279
|
)
|
|
2265
2280
|
});
|
|
2266
2281
|
}
|
|
2267
|
-
return getUserById(input.userId);
|
|
2282
|
+
return getUserById(input.userId, input.tenantId);
|
|
2268
2283
|
}
|
|
2269
2284
|
for (const pendingVerification2 of pendingEmailVerifications) {
|
|
2270
2285
|
await import_emailverification.default.revokeEmailVerificationTokens(
|
|
@@ -2278,13 +2293,14 @@ async function startPendingEmailVerification(input) {
|
|
|
2278
2293
|
id: input.pendingVerificationId,
|
|
2279
2294
|
field: "email",
|
|
2280
2295
|
value: input.email,
|
|
2281
|
-
created_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
2296
|
+
created_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2297
|
+
tenantId: input.tenantId
|
|
2282
2298
|
};
|
|
2283
2299
|
await import_usermetadata3.default.updateUserMetadata(input.userId, {
|
|
2284
2300
|
...metadata,
|
|
2285
2301
|
rownd_pending_verification: [
|
|
2286
2302
|
...pendingVerifications.filter(
|
|
2287
|
-
(pendingVerification2) => pendingVerification2.field !== "email"
|
|
2303
|
+
(pendingVerification2) => pendingVerification2.field !== "email" || (pendingVerification2.tenantId ?? PUBLIC_TENANT_ID) !== input.tenantId
|
|
2288
2304
|
),
|
|
2289
2305
|
pendingVerification
|
|
2290
2306
|
]
|
|
@@ -2303,12 +2319,14 @@ async function startPendingEmailVerification(input) {
|
|
|
2303
2319
|
await completePendingEmailVerification({
|
|
2304
2320
|
recipeUserId: input.recipeUserId,
|
|
2305
2321
|
email: input.email,
|
|
2322
|
+
tenantId: input.tenantId,
|
|
2306
2323
|
userContext: input.userContext
|
|
2307
2324
|
});
|
|
2308
2325
|
}
|
|
2309
|
-
return getUserById(input.userId);
|
|
2326
|
+
return getUserById(input.userId, input.tenantId);
|
|
2310
2327
|
}
|
|
2311
2328
|
async function completePendingEmailVerification(input) {
|
|
2329
|
+
const tenantId = input.tenantId ?? PUBLIC_TENANT_ID;
|
|
2312
2330
|
const user = await import_supertokens_node2.default.getUser(
|
|
2313
2331
|
input.recipeUserId.getAsString(),
|
|
2314
2332
|
input.userContext
|
|
@@ -2319,7 +2337,8 @@ async function completePendingEmailVerification(input) {
|
|
|
2319
2337
|
const pendingVerification = pendingVerifications.find(
|
|
2320
2338
|
(pendingVerification2) => isMatchingPendingEmailVerification(
|
|
2321
2339
|
pendingVerification2,
|
|
2322
|
-
input.email
|
|
2340
|
+
input.email,
|
|
2341
|
+
tenantId
|
|
2323
2342
|
)
|
|
2324
2343
|
);
|
|
2325
2344
|
if (!pendingVerification) {
|
|
@@ -2327,7 +2346,12 @@ async function completePendingEmailVerification(input) {
|
|
|
2327
2346
|
}
|
|
2328
2347
|
let metadataUserId = userId;
|
|
2329
2348
|
let verifiedRecipeUserId = input.recipeUserId;
|
|
2330
|
-
const
|
|
2349
|
+
const tenantLoginMethods = user?.loginMethods.filter(
|
|
2350
|
+
(method) => method.tenantIds.includes(tenantId)
|
|
2351
|
+
) ?? [];
|
|
2352
|
+
const passwordlessEmailMethod = getPasswordlessEmailLoginMethod(
|
|
2353
|
+
tenantLoginMethods
|
|
2354
|
+
);
|
|
2331
2355
|
if (passwordlessEmailMethod) {
|
|
2332
2356
|
const updateResult = await import_passwordless.default.updateUser({
|
|
2333
2357
|
recipeUserId: passwordlessEmailMethod.recipeUserId,
|
|
@@ -2340,9 +2364,9 @@ async function completePendingEmailVerification(input) {
|
|
|
2340
2364
|
);
|
|
2341
2365
|
}
|
|
2342
2366
|
verifiedRecipeUserId = passwordlessEmailMethod.recipeUserId;
|
|
2343
|
-
} else if (hasOnlyGuestLoginMethods(user)) {
|
|
2367
|
+
} else if (hasOnlyGuestLoginMethods(user ? { ...user, loginMethods: tenantLoginMethods } : user)) {
|
|
2344
2368
|
const isPasswordlessSignUpAllowed = await import_accountlinking.default.isSignUpAllowed(
|
|
2345
|
-
|
|
2369
|
+
tenantId,
|
|
2346
2370
|
{
|
|
2347
2371
|
recipeId: "passwordless",
|
|
2348
2372
|
email: input.email
|
|
@@ -2356,7 +2380,7 @@ async function completePendingEmailVerification(input) {
|
|
|
2356
2380
|
}
|
|
2357
2381
|
const passwordlessUser = await import_passwordless.default.signInUp({
|
|
2358
2382
|
email: input.email,
|
|
2359
|
-
tenantId
|
|
2383
|
+
tenantId,
|
|
2360
2384
|
userContext: input.userContext
|
|
2361
2385
|
});
|
|
2362
2386
|
verifiedRecipeUserId = passwordlessUser.recipeUserId;
|
|
@@ -2400,7 +2424,8 @@ async function completePendingEmailVerification(input) {
|
|
|
2400
2424
|
rownd_pending_verification: targetPendingVerifications.filter(
|
|
2401
2425
|
(verification) => !isMatchingPendingEmailVerification(
|
|
2402
2426
|
verification,
|
|
2403
|
-
input.email
|
|
2427
|
+
input.email,
|
|
2428
|
+
tenantId
|
|
2404
2429
|
)
|
|
2405
2430
|
)
|
|
2406
2431
|
};
|
|
@@ -2410,8 +2435,8 @@ async function completePendingEmailVerification(input) {
|
|
|
2410
2435
|
recipeUserId: verifiedRecipeUserId
|
|
2411
2436
|
};
|
|
2412
2437
|
}
|
|
2413
|
-
function isMatchingPendingEmailVerification(verification, email) {
|
|
2414
|
-
return verification.field === "email" && verification.value === email;
|
|
2438
|
+
function isMatchingPendingEmailVerification(verification, email, tenantId) {
|
|
2439
|
+
return verification.field === "email" && verification.value === email && (verification.tenantId ?? PUBLIC_TENANT_ID) === tenantId;
|
|
2415
2440
|
}
|
|
2416
2441
|
async function updateUserMetadata(userId, inputMeta) {
|
|
2417
2442
|
const metadata = await getUserMetadata(userId);
|
|
@@ -2429,8 +2454,8 @@ async function updateUserMetadata(userId, inputMeta) {
|
|
|
2429
2454
|
)
|
|
2430
2455
|
};
|
|
2431
2456
|
}
|
|
2432
|
-
function getPasswordlessEmailLoginMethod(
|
|
2433
|
-
return
|
|
2457
|
+
function getPasswordlessEmailLoginMethod(loginMethods) {
|
|
2458
|
+
return loginMethods.find((method) => {
|
|
2434
2459
|
return method.recipeId === "passwordless" && !!method.email;
|
|
2435
2460
|
});
|
|
2436
2461
|
}
|
|
@@ -2440,6 +2465,7 @@ var import_crypto = require("crypto");
|
|
|
2440
2465
|
var import_supertokens_node3 = __toESM(require("supertokens-node"));
|
|
2441
2466
|
var import_session2 = __toESM(require("supertokens-node/recipe/session"));
|
|
2442
2467
|
var import_thirdparty = __toESM(require("supertokens-node/recipe/thirdparty"));
|
|
2468
|
+
var import_multitenancy = __toESM(require("supertokens-node/recipe/multitenancy"));
|
|
2443
2469
|
function isBodyString(body, key) {
|
|
2444
2470
|
return isRecord(body) && typeof body[key] === "string" && body[key].length > 0;
|
|
2445
2471
|
}
|
|
@@ -2504,7 +2530,9 @@ function handleGuestLogin(deps) {
|
|
|
2504
2530
|
return async (req, res, _session, userContext) => {
|
|
2505
2531
|
const startedAt = Date.now();
|
|
2506
2532
|
const guestId = `guest_${(0, import_crypto.randomUUID)()}`;
|
|
2533
|
+
let tenantId;
|
|
2507
2534
|
try {
|
|
2535
|
+
tenantId = resolveTenantId(req);
|
|
2508
2536
|
const body = parseGuestBody(await getJsonBody(req));
|
|
2509
2537
|
const appVariantId = getRequestedAppVariantIdFromRequest(req);
|
|
2510
2538
|
assertRowndAppVariantIsConfigured(appVariantId);
|
|
@@ -2512,7 +2540,7 @@ function handleGuestLogin(deps) {
|
|
|
2512
2540
|
const thirdPartyUserId = thirdPartyId === INSTANT_AUTH_METHOD_ID ? `anon_${(0, import_crypto.randomUUID)()}` : guestId;
|
|
2513
2541
|
const authLevel = thirdPartyId === INSTANT_AUTH_METHOD_ID ? INSTANT_AUTH_METHOD_ID : GUEST_AUTH_METHOD_ID;
|
|
2514
2542
|
const response = await import_thirdparty.default.manuallyCreateOrUpdateUser(
|
|
2515
|
-
|
|
2543
|
+
tenantId,
|
|
2516
2544
|
thirdPartyId,
|
|
2517
2545
|
thirdPartyUserId,
|
|
2518
2546
|
`${thirdPartyUserId}@anonymous.local`,
|
|
@@ -2528,7 +2556,7 @@ function handleGuestLogin(deps) {
|
|
|
2528
2556
|
await import_session2.default.createNewSession(
|
|
2529
2557
|
req,
|
|
2530
2558
|
res,
|
|
2531
|
-
|
|
2559
|
+
tenantId,
|
|
2532
2560
|
response.recipeUserId,
|
|
2533
2561
|
{
|
|
2534
2562
|
...buildRowndAudience({}, appVariantId),
|
|
@@ -2543,7 +2571,7 @@ function handleGuestLogin(deps) {
|
|
|
2543
2571
|
deps.telemetryClient.recordSuccess({
|
|
2544
2572
|
outcome: "success",
|
|
2545
2573
|
durationMs: Date.now() - startedAt,
|
|
2546
|
-
tenantId
|
|
2574
|
+
tenantId,
|
|
2547
2575
|
superTokensUserId: response.user.id
|
|
2548
2576
|
});
|
|
2549
2577
|
return {
|
|
@@ -2555,7 +2583,7 @@ function handleGuestLogin(deps) {
|
|
|
2555
2583
|
deps.telemetryClient.recordError({
|
|
2556
2584
|
error,
|
|
2557
2585
|
startedAt,
|
|
2558
|
-
tenantId
|
|
2586
|
+
tenantId
|
|
2559
2587
|
});
|
|
2560
2588
|
return {
|
|
2561
2589
|
status: "ERROR",
|
|
@@ -2567,7 +2595,7 @@ function handleGuestLogin(deps) {
|
|
|
2567
2595
|
function handleMigrate(deps) {
|
|
2568
2596
|
return async (req, res, _session, userContext) => {
|
|
2569
2597
|
const startedAt = Date.now();
|
|
2570
|
-
let tenantId
|
|
2598
|
+
let tenantId;
|
|
2571
2599
|
let rowndUserId;
|
|
2572
2600
|
let superTokensUserId;
|
|
2573
2601
|
let user;
|
|
@@ -2576,6 +2604,7 @@ function handleMigrate(deps) {
|
|
|
2576
2604
|
if (!deps.stConfig.supertokens) {
|
|
2577
2605
|
throw new Error("Supertokens config not found");
|
|
2578
2606
|
}
|
|
2607
|
+
tenantId = resolveTenantId(req);
|
|
2579
2608
|
const parsed = await parseRequest(req);
|
|
2580
2609
|
const appVariantId = getRequestedAppVariantIdFromRequest(req);
|
|
2581
2610
|
assertRowndAppVariantIsConfigured(appVariantId);
|
|
@@ -2583,13 +2612,16 @@ function handleMigrate(deps) {
|
|
|
2583
2612
|
const rowndUser = await fetchOptionalRowndUserInfo(rowndUserId);
|
|
2584
2613
|
if (!rowndUser) {
|
|
2585
2614
|
logDebugMessage(
|
|
2586
|
-
`Skipping migration because user does not exist in Rownd. tenantId: ${
|
|
2615
|
+
`Skipping migration because user does not exist in Rownd. tenantId: ${tenantId}, rowndUserId: ${rowndUserId}`
|
|
2587
2616
|
);
|
|
2588
2617
|
return { status: "OK" };
|
|
2589
2618
|
}
|
|
2590
2619
|
user = await import_supertokens_node3.default.getUser(rowndUserId, userContext);
|
|
2591
2620
|
if (!user) {
|
|
2592
|
-
const stUserImport = mapRowndUserToSuperTokens(
|
|
2621
|
+
const stUserImport = mapRowndUserToSuperTokens(
|
|
2622
|
+
rowndUser,
|
|
2623
|
+
tenantId === PUBLIC_TENANT_ID ? void 0 : tenantId
|
|
2624
|
+
);
|
|
2593
2625
|
try {
|
|
2594
2626
|
await importUser(stUserImport, deps.stConfig.supertokens);
|
|
2595
2627
|
clearSuperTokensCoreCallCache(userContext);
|
|
@@ -2607,29 +2639,43 @@ function handleMigrate(deps) {
|
|
|
2607
2639
|
superTokensUserId = user.id;
|
|
2608
2640
|
recipeUserId = user.loginMethods[0]?.recipeUserId;
|
|
2609
2641
|
logDebugMessage(
|
|
2610
|
-
`User already migrated (race condition). tenantId: ${
|
|
2642
|
+
`User already migrated (race condition). tenantId: ${tenantId}, rowndUserId: ${rowndUserId}`
|
|
2611
2643
|
);
|
|
2612
2644
|
}
|
|
2613
2645
|
logDebugMessage(
|
|
2614
|
-
`User migrated successfully. tenantId: ${
|
|
2646
|
+
`User migrated successfully. tenantId: ${tenantId}, rowndUserId: ${rowndUserId}`
|
|
2615
2647
|
);
|
|
2616
2648
|
} else {
|
|
2617
2649
|
superTokensUserId = user.id;
|
|
2618
2650
|
recipeUserId = user.loginMethods[0]?.recipeUserId;
|
|
2619
2651
|
logDebugMessage(
|
|
2620
|
-
`User already migrated. tenantId: ${
|
|
2652
|
+
`User already migrated. tenantId: ${tenantId}, rowndUserId: ${rowndUserId}`
|
|
2621
2653
|
);
|
|
2622
2654
|
}
|
|
2623
2655
|
if (superTokensUserId) {
|
|
2624
2656
|
await recordRowndAppVariantForUser(superTokensUserId, appVariantId);
|
|
2625
2657
|
}
|
|
2658
|
+
const tenantLoginMethod = user?.loginMethods.find(
|
|
2659
|
+
(method) => method.tenantIds.includes(tenantId)
|
|
2660
|
+
);
|
|
2661
|
+
recipeUserId = tenantLoginMethod?.recipeUserId ?? recipeUserId;
|
|
2626
2662
|
if (!recipeUserId) {
|
|
2627
2663
|
throw new Error("User not found or has no login methods");
|
|
2628
2664
|
}
|
|
2665
|
+
if (!tenantLoginMethod) {
|
|
2666
|
+
const associationResult = await import_multitenancy.default.associateUserToTenant(
|
|
2667
|
+
tenantId,
|
|
2668
|
+
recipeUserId,
|
|
2669
|
+
userContext
|
|
2670
|
+
);
|
|
2671
|
+
if (associationResult.status !== "OK") {
|
|
2672
|
+
throw new Error(`Failed to associate migrated user with tenant: ${associationResult.status}`);
|
|
2673
|
+
}
|
|
2674
|
+
}
|
|
2629
2675
|
await import_session2.default.createNewSession(
|
|
2630
2676
|
req,
|
|
2631
2677
|
res,
|
|
2632
|
-
|
|
2678
|
+
tenantId,
|
|
2633
2679
|
recipeUserId,
|
|
2634
2680
|
{
|
|
2635
2681
|
...buildRowndAudience({}, appVariantId)
|
|
@@ -2638,7 +2684,7 @@ function handleMigrate(deps) {
|
|
|
2638
2684
|
userContext
|
|
2639
2685
|
);
|
|
2640
2686
|
logDebugMessage(
|
|
2641
|
-
`Session migrated successfully. tenantId: ${
|
|
2687
|
+
`Session migrated successfully. tenantId: ${tenantId}, userId: ${superTokensUserId}`
|
|
2642
2688
|
);
|
|
2643
2689
|
deps.telemetryClient.recordSuccess({
|
|
2644
2690
|
outcome: "success",
|
|
@@ -2672,7 +2718,7 @@ function clearSuperTokensCoreCallCache(userContext) {
|
|
|
2672
2718
|
}
|
|
2673
2719
|
function handleGetUser() {
|
|
2674
2720
|
return async (_req, _res, session) => {
|
|
2675
|
-
const user = await getUserById(session.getUserId());
|
|
2721
|
+
const user = await getUserById(session.getUserId(), session.getTenantId());
|
|
2676
2722
|
return {
|
|
2677
2723
|
status: "OK",
|
|
2678
2724
|
...user
|
|
@@ -2698,7 +2744,11 @@ function handleUpdateUser() {
|
|
|
2698
2744
|
return permissionError;
|
|
2699
2745
|
}
|
|
2700
2746
|
if (Object.keys(dataWithoutEmail).length > 0) {
|
|
2701
|
-
await updateUserData(
|
|
2747
|
+
await updateUserData(
|
|
2748
|
+
session.getUserId(),
|
|
2749
|
+
dataWithoutEmail,
|
|
2750
|
+
session.getTenantId()
|
|
2751
|
+
);
|
|
2702
2752
|
}
|
|
2703
2753
|
if (hasEmailUpdate) {
|
|
2704
2754
|
const pendingVerificationResult = await startPendingEmailVerification({
|
|
@@ -2714,7 +2764,7 @@ function handleUpdateUser() {
|
|
|
2714
2764
|
...pendingVerificationResult
|
|
2715
2765
|
};
|
|
2716
2766
|
}
|
|
2717
|
-
const user = await getUserById(session.getUserId());
|
|
2767
|
+
const user = await getUserById(session.getUserId(), session.getTenantId());
|
|
2718
2768
|
return {
|
|
2719
2769
|
status: "OK",
|
|
2720
2770
|
...user
|
|
@@ -2781,7 +2831,7 @@ function handleGetUserField() {
|
|
|
2781
2831
|
if (!field) {
|
|
2782
2832
|
return missingFieldResponse();
|
|
2783
2833
|
}
|
|
2784
|
-
const user = await getUserById(session.getUserId());
|
|
2834
|
+
const user = await getUserById(session.getUserId(), session.getTenantId());
|
|
2785
2835
|
return {
|
|
2786
2836
|
status: "OK",
|
|
2787
2837
|
value: user.data[field]
|
|
@@ -2815,9 +2865,11 @@ function handleUpdateUserField() {
|
|
|
2815
2865
|
if (permissionError) {
|
|
2816
2866
|
return permissionError;
|
|
2817
2867
|
}
|
|
2818
|
-
const updateUserDataResult = await updateUserData(
|
|
2819
|
-
|
|
2820
|
-
|
|
2868
|
+
const updateUserDataResult = await updateUserData(
|
|
2869
|
+
session.getUserId(),
|
|
2870
|
+
{ [field]: payload.value },
|
|
2871
|
+
session.getTenantId()
|
|
2872
|
+
);
|
|
2821
2873
|
return {
|
|
2822
2874
|
status: "OK",
|
|
2823
2875
|
...updateUserDataResult
|
|
@@ -2837,6 +2889,7 @@ function validateWritableFields(fields) {
|
|
|
2837
2889
|
}
|
|
2838
2890
|
|
|
2839
2891
|
// src/plugin.ts
|
|
2892
|
+
var DISABLED_MIGRATION_ROWND_APP_KEY = "migration-disabled";
|
|
2840
2893
|
var verifyRowndUserSessionOptions = {
|
|
2841
2894
|
sessionRequired: true,
|
|
2842
2895
|
overrideGlobalClaimValidators: (validators) => validators.filter((validator) => {
|
|
@@ -2845,10 +2898,10 @@ var verifyRowndUserSessionOptions = {
|
|
|
2845
2898
|
};
|
|
2846
2899
|
var init = createPluginInitFunction(
|
|
2847
2900
|
(pluginConfig2) => {
|
|
2848
|
-
const rowndClient2 = (0, import_node.createInstance)({
|
|
2901
|
+
const rowndClient2 = !pluginConfig2.disableRowndUserMigration && pluginConfig2.rowndAppSecret ? (0, import_node.createInstance)({
|
|
2849
2902
|
app_key: pluginConfig2.rowndAppKey,
|
|
2850
2903
|
app_secret: pluginConfig2.rowndAppSecret
|
|
2851
|
-
});
|
|
2904
|
+
}) : void 0;
|
|
2852
2905
|
const telemetryClient = createClient(pluginConfig2.telemetry);
|
|
2853
2906
|
let hubBootstrapParams;
|
|
2854
2907
|
const addHubBootstrapParams = (input, linkKey, targetPath) => {
|
|
@@ -2888,6 +2941,11 @@ var init = createPluginInitFunction(
|
|
|
2888
2941
|
id: PLUGIN_ID,
|
|
2889
2942
|
compatibleSDKVersions: PLUGIN_SDK_VERSION,
|
|
2890
2943
|
init: async () => {
|
|
2944
|
+
if (pluginConfig2.disableRowndUserMigration) {
|
|
2945
|
+
console.warn(
|
|
2946
|
+
"RowndMigrationPlugin: Rownd user and session migration is disabled."
|
|
2947
|
+
);
|
|
2948
|
+
}
|
|
2891
2949
|
if (!import_supertokens_node4.default.isRecipeInitialized("session")) {
|
|
2892
2950
|
console.warn(
|
|
2893
2951
|
"RowndMigrationPlugin: Session recipe is not initialized. Session migration will fail."
|
|
@@ -2931,11 +2989,11 @@ var init = createPluginInitFunction(
|
|
|
2931
2989
|
method: "post",
|
|
2932
2990
|
handler: withRequestHandler(handleGuestLogin(routeHandlerDeps))
|
|
2933
2991
|
},
|
|
2934
|
-
{
|
|
2992
|
+
...!pluginConfig2.disableRowndUserMigration ? [{
|
|
2935
2993
|
path: `${apiBasePath}${HANDLE_BASE_PATH}/migrate`,
|
|
2936
2994
|
method: "post",
|
|
2937
2995
|
handler: withRequestHandler(handleMigrate(routeHandlerDeps))
|
|
2938
|
-
},
|
|
2996
|
+
}] : [],
|
|
2939
2997
|
{
|
|
2940
2998
|
path: `${apiBasePath}/plugin/passwordless-cross-device-confirmation/validate`,
|
|
2941
2999
|
method: "post",
|
|
@@ -2943,11 +3001,11 @@ var init = createPluginInitFunction(
|
|
|
2943
3001
|
handleValidatePasswordlessConfirmationBypass(routeHandlerDeps)
|
|
2944
3002
|
)
|
|
2945
3003
|
},
|
|
2946
|
-
{
|
|
3004
|
+
...!pluginConfig2.disableRowndUserMigration ? [{
|
|
2947
3005
|
path: `${apiBasePath}/plugin/migrate-session`,
|
|
2948
3006
|
method: "post",
|
|
2949
3007
|
handler: withRequestHandler(handleMigrate(routeHandlerDeps))
|
|
2950
|
-
},
|
|
3008
|
+
}] : [],
|
|
2951
3009
|
{
|
|
2952
3010
|
path: `${apiBasePath}${HANDLE_BASE_PATH}/signout`,
|
|
2953
3011
|
method: "post",
|
|
@@ -3300,6 +3358,7 @@ var init = createPluginInitFunction(
|
|
|
3300
3358
|
const verificationResult = await completePendingEmailVerification({
|
|
3301
3359
|
recipeUserId: response.user.recipeUserId,
|
|
3302
3360
|
email: response.user.email,
|
|
3361
|
+
tenantId: input.tenantId,
|
|
3303
3362
|
userContext: input.userContext
|
|
3304
3363
|
});
|
|
3305
3364
|
const session = input.session;
|
|
@@ -3326,9 +3385,14 @@ var init = createPluginInitFunction(
|
|
|
3326
3385
|
},
|
|
3327
3386
|
() => ({}),
|
|
3328
3387
|
(config2) => {
|
|
3329
|
-
if (
|
|
3388
|
+
if (config2?.disableRowndUserMigration !== void 0 && typeof config2.disableRowndUserMigration !== "boolean") {
|
|
3389
|
+
throw new Error(
|
|
3390
|
+
"disableRowndUserMigration must be a boolean in plugin config"
|
|
3391
|
+
);
|
|
3392
|
+
}
|
|
3393
|
+
if (!config2?.disableRowndUserMigration && (!config2?.rowndAppKey || !config2?.rowndAppSecret)) {
|
|
3330
3394
|
throw new Error(
|
|
3331
|
-
"Missing rowndAppKey or rowndAppSecret in plugin config"
|
|
3395
|
+
"Missing rowndAppKey or rowndAppSecret in plugin config. Set disableRowndUserMigration to true to disable migration."
|
|
3332
3396
|
);
|
|
3333
3397
|
}
|
|
3334
3398
|
if (config2.telemetry?.provider === "axiom") {
|
|
@@ -3349,8 +3413,9 @@ var init = createPluginInitFunction(
|
|
|
3349
3413
|
validateClientDomainUrl(key, value);
|
|
3350
3414
|
}
|
|
3351
3415
|
return {
|
|
3352
|
-
rowndAppKey: config2.rowndAppKey,
|
|
3416
|
+
rowndAppKey: config2.rowndAppKey ?? DISABLED_MIGRATION_ROWND_APP_KEY,
|
|
3353
3417
|
rowndAppSecret: config2.rowndAppSecret,
|
|
3418
|
+
disableRowndUserMigration: config2.disableRowndUserMigration === true,
|
|
3354
3419
|
enableDebugLogs: config2.enableDebugLogs,
|
|
3355
3420
|
clientDomains: config2.clientDomains,
|
|
3356
3421
|
crossDeviceConfirmationBypass: config2.crossDeviceConfirmationBypass,
|