@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 CHANGED
@@ -44,6 +44,26 @@ SuperTokens.init({
44
44
  });
45
45
  ```
46
46
 
47
+ ### Disabling Rownd User Migration
48
+
49
+ After migration is complete, disable Rownd user and session migration to run
50
+ the compatibility endpoints without Rownd credentials:
51
+
52
+ ```typescript
53
+ RowndMigrationPlugin.init({
54
+ disableRowndUserMigration: true,
55
+ });
56
+ ```
57
+
58
+ This prevents the Rownd API client and the `/plugin/rownd/migrate` and
59
+ `/plugin/migrate-session` routes from being initialized. Other compatibility
60
+ endpoints remain enabled. Passwordless and email-verification links continue to
61
+ use the Rownd Hub with an internal dummy app key when `rowndAppKey` is omitted.
62
+ The plugin logs a warning during initialization while migration is disabled.
63
+
64
+ Without `disableRowndUserMigration: true`, both `rowndAppKey` and
65
+ `rowndAppSecret` are required.
66
+
47
67
  ### Session Claim Fields
48
68
 
49
69
  Schema fields can be copied into the SuperTokens access-token payload by setting `include_in_session_claims: true`. Use `session_claim_name` when the claim name should differ from the Rownd data field name.
@@ -116,6 +136,7 @@ import { createMagicLinkWithConfirmationBypass } from "@supertokens-plugins/rown
116
136
 
117
137
  const magicLink = await createMagicLinkWithConfirmationBypass({
118
138
  email: "user@example.com",
139
+ tenantId: "tenant-a",
119
140
  clientDomain: "browser",
120
141
  redirectToPath: "/profile",
121
142
  displayContext: "browser",
@@ -126,7 +147,7 @@ const magicLink = await createMagicLinkWithConfirmationBypass({
126
147
 
127
148
  `clientDomain` must be a configured `clientDomains` key, not a raw domain. Omit it to use the SuperTokens website domain.
128
149
 
129
- Pass exactly one of `email` or `phoneNumber`. The helper returns the rewritten magic link with `bypassDeviceConfirmation=true`.
150
+ Pass exactly one of `email` or `phoneNumber`. `tenantId` defaults to `public`. The helper returns the rewritten magic link with `bypassDeviceConfirmation=true`.
130
151
 
131
152
  Before skipping the cross-device confirmation prompt, the frontend should validate the callback against the plugin. Routes are mounted under your SuperTokens `apiBasePath`, which defaults to `/auth`.
132
153
 
@@ -141,16 +162,25 @@ If validation fails, the frontend should show the normal cross-device confirmati
141
162
 
142
163
  Routes are mounted under your SuperTokens `apiBasePath`, which defaults to `/auth`. The migration endpoint is the main Rownd-to-SuperTokens session handoff endpoint; the plugin also exposes Rownd-compatible app config, guest, user, metadata, field, and sign-out endpoints under `{apiBasePath}/plugin/rownd/...`.
143
164
 
165
+ Unauthenticated migration and guest routes accept an optional `tenantId` query parameter. It defaults to `public`. SuperTokens Core validates the tenant when the operation runs. Authenticated identity-field and sign-out operations use the tenant from the current session; custom Rownd metadata remains global to the SuperTokens user.
166
+
144
167
  > [!IMPORTANT]
145
- > The plugin always migrates users and sessions into the `public` tenant.
146
168
  > Rownd users with multiple supported login methods are rejected unless SuperTokens account linking is enabled in the target environment.
147
169
 
148
170
  ### Migrate
149
171
 
150
172
  - **POST** `{apiBasePath}/plugin/rownd/migrate`
151
173
  - **Default**: `POST /auth/plugin/rownd/migrate`
174
+ - **Non-public tenant**: `POST /auth/plugin/rownd/migrate?tenantId=tenant-a`
152
175
  - **Headers**: `Authorization: Bearer <Rownd_JWT>`. Header-token clients should also send `rid: session`, `fdi-version: 1.18`, and `st-auth-mode: header`.
153
- - **Description**: Validates the Rownd JWT, ensures the user is migrated to SuperTokens in the `public` tenant, syncs Rownd user data to SuperTokens UserMetadata, and then creates a new SuperTokens session for that user. Header-token clients must receive `st-access-token`, `st-refresh-token`, and `front-token` response headers.
176
+ - **Description**: Validates the Rownd JWT, imports new users with their Rownd profile data, ensures the selected login method is associated with the requested SuperTokens tenant, and then creates a new SuperTokens session in that tenant. Header-token clients must receive `st-access-token`, `st-refresh-token`, and `front-token` response headers.
177
+
178
+ ### Guest
179
+
180
+ - **POST** `{apiBasePath}/plugin/rownd/guest`
181
+ - **Default**: `POST /auth/plugin/rownd/guest`
182
+ - **Non-public tenant**: `POST /auth/plugin/rownd/guest?tenantId=tenant-a`
183
+ - **Description**: Creates a guest or instant user and session in the requested tenant.
154
184
 
155
185
  ## Debug Logging
156
186
 
@@ -228,6 +258,8 @@ RowndMigrationPlugin.init({
228
258
 
229
259
  The package includes a bulk migration script for importing Rownd users into SuperTokens.
230
260
 
261
+ Set `supertokens.tenantId` in the generated configuration to associate every imported login method with a non-public tenant. It defaults to `public` when omitted. Resuming from a checkpoint with a different tenant is rejected.
262
+
231
263
  The script runs from a YAML config file generated from the included template.
232
264
 
233
265
  ### Usage
@@ -64,7 +64,7 @@ function buildSuperTokensFakeEmail(thirdPartyUserId, thirdPartyId) {
64
64
  function isIdentityField(field) {
65
65
  return IDENTITY_USER_DATA_FIELDS.has(field);
66
66
  }
67
- function mapRowndUserToSuperTokens(rowndUser) {
67
+ function mapRowndUserToSuperTokens(rowndUser, tenantId) {
68
68
  const loginMethods = [];
69
69
  const rowndUserData = rowndUser.data || {};
70
70
  const rowndUserVerifiedData = rowndUser.verified_data || {};
@@ -78,7 +78,8 @@ function mapRowndUserToSuperTokens(rowndUser) {
78
78
  thirdPartyId: "google",
79
79
  thirdPartyUserId: rowndUserData.google_id,
80
80
  email: googleEmail,
81
- isVerified: !!rowndUserData.email && !!rowndUserVerifiedData.google_id
81
+ isVerified: !!rowndUserData.email && !!rowndUserVerifiedData.google_id,
82
+ ...tenantId ? { tenantIds: [tenantId] } : {}
82
83
  });
83
84
  }
84
85
  if (rowndUserData.apple_id) {
@@ -88,21 +89,24 @@ function mapRowndUserToSuperTokens(rowndUser) {
88
89
  thirdPartyId: "apple",
89
90
  thirdPartyUserId: rowndUserData.apple_id,
90
91
  email: appleEmail,
91
- isVerified: !!rowndUserData.email && !!rowndUserVerifiedData.apple_id
92
+ isVerified: !!rowndUserData.email && !!rowndUserVerifiedData.apple_id,
93
+ ...tenantId ? { tenantIds: [tenantId] } : {}
92
94
  });
93
95
  }
94
96
  if (rowndUserData.phone_number) {
95
97
  loginMethods.push({
96
98
  recipeId: "passwordless",
97
99
  phoneNumber: rowndUserData.phone_number,
98
- isVerified: !!rowndUserVerifiedData.phone_number
100
+ isVerified: !!rowndUserVerifiedData.phone_number,
101
+ ...tenantId ? { tenantIds: [tenantId] } : {}
99
102
  });
100
103
  }
101
104
  if (rowndUserData.email && !rowndUserData.google_id && !rowndUserData.apple_id) {
102
105
  loginMethods.push({
103
106
  recipeId: "passwordless",
104
107
  email: rowndUserData.email,
105
- isVerified: !!rowndUserVerifiedData.email
108
+ isVerified: !!rowndUserVerifiedData.email,
109
+ ...tenantId ? { tenantIds: [tenantId] } : {}
106
110
  });
107
111
  }
108
112
  let authLevel = rowndUser.auth_level;
@@ -114,7 +118,8 @@ function mapRowndUserToSuperTokens(rowndUser) {
114
118
  thirdPartyId,
115
119
  thirdPartyUserId: rowndUserData.user_id,
116
120
  email: `${rowndUserData.user_id}@anonymous.local`,
117
- isVerified: false
121
+ isVerified: false,
122
+ ...tenantId ? { tenantIds: [tenantId] } : {}
118
123
  });
119
124
  }
120
125
  const userMetadata = buildRowndUserMetadata(rowndUser);
@@ -168,7 +173,8 @@ var ConfigSchema = import_zod.z.object({
168
173
  supertokens: import_zod.z.object({
169
174
  connectionURI: import_zod.z.string(),
170
175
  apiKey: import_zod.z.string().optional(),
171
- batchSize: import_zod.z.number().int().positive()
176
+ batchSize: import_zod.z.number().int().positive(),
177
+ tenantId: import_zod.z.string().min(1).default("public")
172
178
  }),
173
179
  thirdPartyProviders: import_zod.z.array(
174
180
  import_zod.z.object({
@@ -366,6 +372,7 @@ Options:
366
372
  var CheckpointSchema = import_zod2.z.object({
367
373
  cursor: import_zod2.z.string().optional(),
368
374
  importedCount: import_zod2.z.number().int().nonnegative().optional(),
375
+ tenantId: import_zod2.z.string().optional(),
369
376
  updatedAt: import_zod2.z.string()
370
377
  });
371
378
  async function loadCheckpoint(checkpointFile) {
@@ -456,6 +463,11 @@ async function importUsersBatch(config, users, totalImportedBeforeBatch) {
456
463
  }
457
464
  async function migrateRowndUsersToSuperTokens(config) {
458
465
  const checkpoint = config.checkpoint.resume ? await loadCheckpoint(config.checkpoint.file) : null;
466
+ if (checkpoint && (checkpoint.tenantId ?? "public") !== config.supertokens.tenantId) {
467
+ throw new Error(
468
+ `Checkpoint tenant ${checkpoint.tenantId ?? "public"} does not match configured tenant ${config.supertokens.tenantId}`
469
+ );
470
+ }
459
471
  const failedMappingsFile = getFailedMappingsFilePath(config.checkpoint.file);
460
472
  let cursor = checkpoint?.cursor;
461
473
  let totalProcessed = 0;
@@ -489,7 +501,10 @@ async function migrateRowndUsersToSuperTokens(config) {
489
501
  try {
490
502
  mappedUsers.push({
491
503
  rowndUserId,
492
- user: mapRowndUserToSuperTokens(rowndUser)
504
+ user: mapRowndUserToSuperTokens(
505
+ rowndUser,
506
+ config.supertokens.tenantId === "public" ? void 0 : config.supertokens.tenantId
507
+ )
493
508
  });
494
509
  } catch (error) {
495
510
  const errorMessage = error instanceof Error ? error.message : "Unknown mapping error";
@@ -511,6 +526,7 @@ async function migrateRowndUsersToSuperTokens(config) {
511
526
  await saveCheckpoint(config.checkpoint.file, {
512
527
  cursor,
513
528
  importedCount: totalImported,
529
+ tenantId: config.supertokens.tenantId,
514
530
  updatedAt: (/* @__PURE__ */ new Date()).toISOString()
515
531
  });
516
532
  console.log(`Processed ${totalProcessed} users so far`);
@@ -68,7 +68,8 @@ var ConfigSchema = import_zod.z.object({
68
68
  supertokens: import_zod.z.object({
69
69
  connectionURI: import_zod.z.string(),
70
70
  apiKey: import_zod.z.string().optional(),
71
- batchSize: import_zod.z.number().int().positive()
71
+ batchSize: import_zod.z.number().int().positive(),
72
+ tenantId: import_zod.z.string().min(1).default("public")
72
73
  }),
73
74
  thirdPartyProviders: import_zod.z.array(
74
75
  import_zod.z.object({
package/dist/index.d.mts CHANGED
@@ -670,8 +670,14 @@ type RowndSubBrandConfigInput = RowndAppConfigInput & {
670
670
  };
671
671
  };
672
672
  interface RowndPluginConfig {
673
- rowndAppKey: string;
674
- rowndAppSecret: string;
673
+ rowndAppKey?: string;
674
+ rowndAppSecret?: string;
675
+ /**
676
+ * Disables Rownd user and session migration. This must be enabled when
677
+ * rowndAppKey or rowndAppSecret is omitted.
678
+ * @default false
679
+ */
680
+ disableRowndUserMigration?: boolean;
675
681
  enableDebugLogs?: boolean;
676
682
  clientDomains?: RowndClientDomains;
677
683
  crossDeviceConfirmationBypass?: {
@@ -746,6 +752,7 @@ type RowndUserMetadata = {
746
752
  field: string;
747
753
  value: string;
748
754
  created_at: string;
755
+ tenantId?: string;
749
756
  }>;
750
757
  [key: string]: unknown;
751
758
  };
@@ -755,7 +762,8 @@ interface MigrationResponse {
755
762
  }
756
763
  interface RowndPluginNormalisedConfig {
757
764
  rowndAppKey: string;
758
- rowndAppSecret: string;
765
+ rowndAppSecret?: string;
766
+ disableRowndUserMigration: boolean;
759
767
  enableDebugLogs?: boolean;
760
768
  clientDomains?: RowndClientDomains;
761
769
  crossDeviceConfirmationBypass?: {
@@ -860,7 +868,7 @@ type CreateMagicLinkWithConfirmationBypassInput = {
860
868
  };
861
869
  declare function createMagicLinkWithConfirmationBypass(input: CreateMagicLinkWithConfirmationBypassInput): Promise<string>;
862
870
 
863
- declare function setRowndClient(client: IRowndClient): void;
871
+ declare function setRowndClient(client: IRowndClient | undefined): void;
864
872
  declare function getRowndClient(): IRowndClient;
865
873
 
866
874
  declare const _default: {
package/dist/index.d.ts CHANGED
@@ -670,8 +670,14 @@ type RowndSubBrandConfigInput = RowndAppConfigInput & {
670
670
  };
671
671
  };
672
672
  interface RowndPluginConfig {
673
- rowndAppKey: string;
674
- rowndAppSecret: string;
673
+ rowndAppKey?: string;
674
+ rowndAppSecret?: string;
675
+ /**
676
+ * Disables Rownd user and session migration. This must be enabled when
677
+ * rowndAppKey or rowndAppSecret is omitted.
678
+ * @default false
679
+ */
680
+ disableRowndUserMigration?: boolean;
675
681
  enableDebugLogs?: boolean;
676
682
  clientDomains?: RowndClientDomains;
677
683
  crossDeviceConfirmationBypass?: {
@@ -746,6 +752,7 @@ type RowndUserMetadata = {
746
752
  field: string;
747
753
  value: string;
748
754
  created_at: string;
755
+ tenantId?: string;
749
756
  }>;
750
757
  [key: string]: unknown;
751
758
  };
@@ -755,7 +762,8 @@ interface MigrationResponse {
755
762
  }
756
763
  interface RowndPluginNormalisedConfig {
757
764
  rowndAppKey: string;
758
- rowndAppSecret: string;
765
+ rowndAppSecret?: string;
766
+ disableRowndUserMigration: boolean;
759
767
  enableDebugLogs?: boolean;
760
768
  clientDomains?: RowndClientDomains;
761
769
  crossDeviceConfirmationBypass?: {
@@ -860,7 +868,7 @@ type CreateMagicLinkWithConfirmationBypassInput = {
860
868
  };
861
869
  declare function createMagicLinkWithConfirmationBypass(input: CreateMagicLinkWithConfirmationBypassInput): Promise<string>;
862
870
 
863
- declare function setRowndClient(client: IRowndClient): void;
871
+ declare function setRowndClient(client: IRowndClient | undefined): void;
864
872
  declare function getRowndClient(): IRowndClient;
865
873
 
866
874
  declare const _default: {