@supertokens-plugins/rownd-nodejs 0.2.0 → 0.3.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,1096 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __create = Object.create;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getProtoOf = Object.getPrototypeOf;
8
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __commonJS = (cb, mod) => function __require() {
10
+ return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
11
+ };
12
+ var __export = (target, all) => {
13
+ for (var name in all)
14
+ __defProp(target, name, { get: all[name], enumerable: true });
15
+ };
16
+ var __copyProps = (to, from, except, desc) => {
17
+ if (from && typeof from === "object" || typeof from === "function") {
18
+ for (let key of __getOwnPropNames(from))
19
+ if (!__hasOwnProp.call(to, key) && key !== except)
20
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
21
+ }
22
+ return to;
23
+ };
24
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
25
+ // If the importer is in node compatibility mode or this is not an ESM
26
+ // file that has been converted to a CommonJS file using a Babel-
27
+ // compatible transform (i.e. "__esModule" has not been set), then set
28
+ // "default" to the CommonJS "module.exports" for node compatibility.
29
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
30
+ mod
31
+ ));
32
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
33
+
34
+ // ../../node_modules/has-flag/index.js
35
+ var require_has_flag = __commonJS({
36
+ "../../node_modules/has-flag/index.js"(exports2, module2) {
37
+ "use strict";
38
+ module2.exports = (flag, argv = process.argv) => {
39
+ const prefix = flag.startsWith("-") ? "" : flag.length === 1 ? "-" : "--";
40
+ const position = argv.indexOf(prefix + flag);
41
+ const terminatorPosition = argv.indexOf("--");
42
+ return position !== -1 && (terminatorPosition === -1 || position < terminatorPosition);
43
+ };
44
+ }
45
+ });
46
+
47
+ // ../../node_modules/supports-color/index.js
48
+ var require_supports_color = __commonJS({
49
+ "../../node_modules/supports-color/index.js"(exports2, module2) {
50
+ "use strict";
51
+ var os = require("os");
52
+ var tty = require("tty");
53
+ var hasFlag = require_has_flag();
54
+ var { env } = process;
55
+ var forceColor;
56
+ if (hasFlag("no-color") || hasFlag("no-colors") || hasFlag("color=false") || hasFlag("color=never")) {
57
+ forceColor = 0;
58
+ } else if (hasFlag("color") || hasFlag("colors") || hasFlag("color=true") || hasFlag("color=always")) {
59
+ forceColor = 1;
60
+ }
61
+ if ("FORCE_COLOR" in env) {
62
+ if (env.FORCE_COLOR === "true") {
63
+ forceColor = 1;
64
+ } else if (env.FORCE_COLOR === "false") {
65
+ forceColor = 0;
66
+ } else {
67
+ forceColor = env.FORCE_COLOR.length === 0 ? 1 : Math.min(parseInt(env.FORCE_COLOR, 10), 3);
68
+ }
69
+ }
70
+ function translateLevel(level) {
71
+ if (level === 0) {
72
+ return false;
73
+ }
74
+ return {
75
+ level,
76
+ hasBasic: true,
77
+ has256: level >= 2,
78
+ has16m: level >= 3
79
+ };
80
+ }
81
+ function supportsColor(haveStream, streamIsTTY) {
82
+ if (forceColor === 0) {
83
+ return 0;
84
+ }
85
+ if (hasFlag("color=16m") || hasFlag("color=full") || hasFlag("color=truecolor")) {
86
+ return 3;
87
+ }
88
+ if (hasFlag("color=256")) {
89
+ return 2;
90
+ }
91
+ if (haveStream && !streamIsTTY && forceColor === void 0) {
92
+ return 0;
93
+ }
94
+ const min = forceColor || 0;
95
+ if (env.TERM === "dumb") {
96
+ return min;
97
+ }
98
+ if (process.platform === "win32") {
99
+ const osRelease = os.release().split(".");
100
+ if (Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) {
101
+ return Number(osRelease[2]) >= 14931 ? 3 : 2;
102
+ }
103
+ return 1;
104
+ }
105
+ if ("CI" in env) {
106
+ if (["TRAVIS", "CIRCLECI", "APPVEYOR", "GITLAB_CI", "GITHUB_ACTIONS", "BUILDKITE"].some((sign) => sign in env) || env.CI_NAME === "codeship") {
107
+ return 1;
108
+ }
109
+ return min;
110
+ }
111
+ if ("TEAMCITY_VERSION" in env) {
112
+ return /^(9\.(0*[1-9]\d*)\.|\d{2,}\.)/.test(env.TEAMCITY_VERSION) ? 1 : 0;
113
+ }
114
+ if (env.COLORTERM === "truecolor") {
115
+ return 3;
116
+ }
117
+ if ("TERM_PROGRAM" in env) {
118
+ const version = parseInt((env.TERM_PROGRAM_VERSION || "").split(".")[0], 10);
119
+ switch (env.TERM_PROGRAM) {
120
+ case "iTerm.app":
121
+ return version >= 3 ? 3 : 2;
122
+ case "Apple_Terminal":
123
+ return 2;
124
+ }
125
+ }
126
+ if (/-256(color)?$/i.test(env.TERM)) {
127
+ return 2;
128
+ }
129
+ if (/^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux/i.test(env.TERM)) {
130
+ return 1;
131
+ }
132
+ if ("COLORTERM" in env) {
133
+ return 1;
134
+ }
135
+ return min;
136
+ }
137
+ function getSupportLevel(stream) {
138
+ const level = supportsColor(stream, stream && stream.isTTY);
139
+ return translateLevel(level);
140
+ }
141
+ module2.exports = {
142
+ supportsColor: getSupportLevel,
143
+ stdout: translateLevel(supportsColor(true, tty.isatty(1))),
144
+ stderr: translateLevel(supportsColor(true, tty.isatty(2)))
145
+ };
146
+ }
147
+ });
148
+
149
+ // scripts/bulkMigrate.ts
150
+ var bulkMigrate_exports = {};
151
+ __export(bulkMigrate_exports, {
152
+ migrateRowndUsersToSuperTokens: () => migrateRowndUsersToSuperTokens,
153
+ runCli: () => runCli,
154
+ stageUsersForImport: () => stageUsersForImport
155
+ });
156
+ module.exports = __toCommonJS(bulkMigrate_exports);
157
+ var fs2 = __toESM(require("fs/promises"));
158
+ var import_zod2 = require("zod");
159
+
160
+ // src/pluginImplementation.ts
161
+ var import_supertokens_node = __toESM(require("supertokens-node"));
162
+ var import_accountlinking = __toESM(require("supertokens-node/recipe/accountlinking"));
163
+ var import_emailverification = __toESM(require("supertokens-node/recipe/emailverification"));
164
+ var import_passwordless = __toESM(require("supertokens-node/recipe/passwordless"));
165
+ var import_session = __toESM(require("supertokens-node/recipe/session"));
166
+ var import_claims = require("supertokens-node/recipe/session/claims");
167
+ var import_thirdparty = __toESM(require("supertokens-node/recipe/thirdparty"));
168
+ var import_usermetadata2 = __toESM(require("supertokens-node/recipe/usermetadata"));
169
+
170
+ // src/constants.ts
171
+ var PLUGIN_ID = "supertokens-plugin-rownd";
172
+ var PLUGIN_SDK_VERSION = ["23.0.0", "23.0.1", ">=23.0.1"];
173
+ var GUEST_AUTH_METHOD_ID = "guest";
174
+ var ANONYMOUS_AUTH_METHOD_ID = "anonymous";
175
+
176
+ // ../../shared/nodejs/src/pluginUserMetadata.ts
177
+ var import_usermetadata = __toESM(require("supertokens-node/recipe/usermetadata"));
178
+
179
+ // ../../shared/nodejs/src/log/logger.ts
180
+ var import_util = __toESM(require("util"));
181
+
182
+ // ../../shared/nodejs/src/log/common.ts
183
+ function setup(env) {
184
+ createDebug.debug = createDebug;
185
+ createDebug.default = createDebug;
186
+ createDebug.coerce = coerce;
187
+ createDebug.disable = disable;
188
+ createDebug.enable = enable;
189
+ createDebug.enabled = enabled;
190
+ createDebug.humanize = env.humanize;
191
+ createDebug.destroy = destroy;
192
+ Object.keys(env).forEach((key) => {
193
+ createDebug[key] = env[key];
194
+ });
195
+ createDebug.names = [];
196
+ createDebug.skips = [];
197
+ createDebug.formatters = {};
198
+ function selectColor(namespace) {
199
+ let hash = 0;
200
+ for (let i = 0; i < namespace.length; i++) {
201
+ hash = (hash << 5) - hash + namespace.charCodeAt(i);
202
+ hash |= 0;
203
+ }
204
+ return createDebug.colors[Math.abs(hash) % createDebug.colors.length];
205
+ }
206
+ createDebug.selectColor = selectColor;
207
+ function createDebug(namespace) {
208
+ let prevTime;
209
+ let enableOverride = null;
210
+ let namespacesCache;
211
+ let enabledCache;
212
+ function debug(...args) {
213
+ if (!debug.enabled) {
214
+ return;
215
+ }
216
+ const self = debug;
217
+ const curr = Number(/* @__PURE__ */ new Date());
218
+ const ms = curr - (prevTime || curr);
219
+ self.diff = ms;
220
+ self.prev = prevTime;
221
+ self.curr = curr;
222
+ prevTime = curr;
223
+ args[0] = createDebug.coerce(args[0]);
224
+ if (typeof args[0] !== "string") {
225
+ args.unshift("%O");
226
+ }
227
+ let index = 0;
228
+ args[0] = args[0].replace(/%([a-zA-Z%])/g, (match, format) => {
229
+ if (match === "%%") {
230
+ return "%";
231
+ }
232
+ index++;
233
+ const formatter = createDebug.formatters[format];
234
+ if (typeof formatter === "function") {
235
+ const val = args[index];
236
+ match = formatter.call(self, val);
237
+ args.splice(index, 1);
238
+ index--;
239
+ }
240
+ return match;
241
+ });
242
+ createDebug.formatArgs.call(self, args);
243
+ const logFn = self.log || createDebug.log;
244
+ logFn.apply(self, args);
245
+ }
246
+ debug.namespace = namespace;
247
+ debug.useColors = createDebug.useColors();
248
+ debug.color = createDebug.selectColor(namespace);
249
+ debug.extend = extend;
250
+ debug.destroy = createDebug.destroy;
251
+ Object.defineProperty(debug, "enabled", {
252
+ enumerable: true,
253
+ configurable: false,
254
+ get: () => {
255
+ if (enableOverride !== null) {
256
+ return enableOverride;
257
+ }
258
+ if (namespacesCache !== createDebug.namespaces) {
259
+ namespacesCache = createDebug.namespaces;
260
+ enabledCache = createDebug.enabled(namespace);
261
+ }
262
+ return enabledCache;
263
+ },
264
+ set: (v) => {
265
+ enableOverride = v;
266
+ }
267
+ });
268
+ if (typeof createDebug.init === "function") {
269
+ createDebug.init(debug);
270
+ }
271
+ return debug;
272
+ }
273
+ function extend(namespace, delimiter) {
274
+ const newDebug = createDebug(this.namespace + (typeof delimiter === "undefined" ? ":" : delimiter) + namespace);
275
+ newDebug.log = this.log;
276
+ return newDebug;
277
+ }
278
+ function enable(namespaces) {
279
+ createDebug.save(namespaces);
280
+ createDebug.namespaces = namespaces;
281
+ createDebug.names = [];
282
+ createDebug.skips = [];
283
+ const split = (typeof namespaces === "string" ? namespaces : "").trim().replace(/\s+/g, ",").split(",").filter(Boolean);
284
+ for (const ns of split) {
285
+ if (ns[0] === "-") {
286
+ createDebug.skips.push(ns.slice(1));
287
+ } else {
288
+ createDebug.names.push(ns);
289
+ }
290
+ }
291
+ }
292
+ function matchesTemplate(search, template) {
293
+ let searchIndex = 0;
294
+ let templateIndex = 0;
295
+ let starIndex = -1;
296
+ let matchIndex = 0;
297
+ while (searchIndex < search.length) {
298
+ if (templateIndex < template.length && (template[templateIndex] === search[searchIndex] || template[templateIndex] === "*")) {
299
+ if (template[templateIndex] === "*") {
300
+ starIndex = templateIndex;
301
+ matchIndex = searchIndex;
302
+ templateIndex++;
303
+ } else {
304
+ searchIndex++;
305
+ templateIndex++;
306
+ }
307
+ } else if (starIndex !== -1) {
308
+ templateIndex = starIndex + 1;
309
+ matchIndex++;
310
+ searchIndex = matchIndex;
311
+ } else {
312
+ return false;
313
+ }
314
+ }
315
+ while (templateIndex < template.length && template[templateIndex] === "*") {
316
+ templateIndex++;
317
+ }
318
+ return templateIndex === template.length;
319
+ }
320
+ function disable() {
321
+ const namespaces = [...createDebug.names, ...createDebug.skips.map((namespace) => "-" + namespace)].join(",");
322
+ createDebug.enable("");
323
+ return namespaces;
324
+ }
325
+ function enabled(name) {
326
+ for (const skip of createDebug.skips) {
327
+ if (matchesTemplate(name, skip)) {
328
+ return false;
329
+ }
330
+ }
331
+ for (const ns of createDebug.names) {
332
+ if (matchesTemplate(name, ns)) {
333
+ return true;
334
+ }
335
+ }
336
+ return false;
337
+ }
338
+ function coerce(val) {
339
+ if (val instanceof Error) {
340
+ return val.stack || val.message;
341
+ }
342
+ return val;
343
+ }
344
+ function destroy() {
345
+ console.warn(
346
+ "Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`."
347
+ );
348
+ }
349
+ createDebug.enable(createDebug.load());
350
+ return createDebug;
351
+ }
352
+ var common_default = setup;
353
+
354
+ // ../../shared/nodejs/src/log/logger.ts
355
+ var BASIC_COLORS = [6, 2, 3, 4, 5, 1];
356
+ var EXTENDED_COLORS = [
357
+ 20,
358
+ 21,
359
+ 26,
360
+ 27,
361
+ 32,
362
+ 33,
363
+ 38,
364
+ 39,
365
+ 40,
366
+ 41,
367
+ 42,
368
+ 43,
369
+ 44,
370
+ 45,
371
+ 56,
372
+ 57,
373
+ 62,
374
+ 63,
375
+ 68,
376
+ 69,
377
+ 74,
378
+ 75,
379
+ 76,
380
+ 77,
381
+ 78,
382
+ 79,
383
+ 80,
384
+ 81,
385
+ 92,
386
+ 93,
387
+ 98,
388
+ 99,
389
+ 112,
390
+ 113,
391
+ 128,
392
+ 129,
393
+ 134,
394
+ 135,
395
+ 148,
396
+ 149,
397
+ 160,
398
+ 161,
399
+ 162,
400
+ 163,
401
+ 164,
402
+ 165,
403
+ 166,
404
+ 167,
405
+ 168,
406
+ 169,
407
+ 170,
408
+ 171,
409
+ 172,
410
+ 173,
411
+ 178,
412
+ 179,
413
+ 184,
414
+ 185,
415
+ 196,
416
+ 197,
417
+ 198,
418
+ 199,
419
+ 200,
420
+ 201,
421
+ 202,
422
+ 203,
423
+ 204,
424
+ 205,
425
+ 206,
426
+ 207,
427
+ 208,
428
+ 209,
429
+ 214,
430
+ 215,
431
+ 220,
432
+ 221
433
+ ];
434
+ function supportsExtendedColors() {
435
+ try {
436
+ const supportsColor = require_supports_color();
437
+ return supportsColor && (supportsColor.stderr || supportsColor).level >= 2;
438
+ } catch {
439
+ return false;
440
+ }
441
+ }
442
+ function shouldUseColors() {
443
+ return false;
444
+ }
445
+ function formatArgs(args) {
446
+ const { namespace, useColors, color } = this;
447
+ if (useColors) {
448
+ const colorCode = color < 8 ? `3${color}` : `38;5;${color}`;
449
+ const prefix = `\x1B[${colorCode};1m${namespace}\x1B[0m`;
450
+ args[0] = `${prefix} ${args[0]}`.split("\n").join(`
451
+ ${prefix} `);
452
+ args.push(`\x1B[${colorCode}m+${humanizeTime(this.diff)}\x1B[0m`);
453
+ } else {
454
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString();
455
+ args[0] = `${timestamp} ${namespace} ${args[0]}`;
456
+ }
457
+ }
458
+ function writeOutput(...args) {
459
+ process.stderr.write(import_util.default.format(...args) + "\n");
460
+ }
461
+ function saveConfig(namespaces) {
462
+ if (namespaces) {
463
+ process.env.DEBUG = namespaces;
464
+ } else {
465
+ delete process.env.DEBUG;
466
+ }
467
+ }
468
+ function loadConfig() {
469
+ return process.env.DEBUG;
470
+ }
471
+ function humanizeTime(milliseconds) {
472
+ if (milliseconds >= 1e3) {
473
+ const seconds = Math.round(milliseconds / 1e3);
474
+ return `${seconds}s`;
475
+ }
476
+ return `${milliseconds}ms`;
477
+ }
478
+ function createLoggerConfig() {
479
+ const colors = supportsExtendedColors() ? EXTENDED_COLORS : BASIC_COLORS;
480
+ return {
481
+ colors,
482
+ useColors: shouldUseColors,
483
+ formatArgs,
484
+ log: writeOutput,
485
+ save: saveConfig,
486
+ load: loadConfig,
487
+ humanize: humanizeTime
488
+ };
489
+ }
490
+ var config = createLoggerConfig();
491
+ var logger = common_default(config);
492
+ if (logger.formatters) {
493
+ logger.formatters.o = function(value) {
494
+ return import_util.default.inspect(value, { colors: this.useColors, compact: true }).split("\n").map((line) => line.trim()).join(" ");
495
+ };
496
+ logger.formatters.O = function(value) {
497
+ return import_util.default.inspect(value, { colors: this.useColors, compact: false });
498
+ };
499
+ }
500
+ var logger_default = logger;
501
+
502
+ // ../../shared/nodejs/src/log/index.ts
503
+ var log_default = logger_default;
504
+
505
+ // ../../shared/nodejs/src/logger.ts
506
+ var getFileLocation = () => {
507
+ let errorObject = new Error();
508
+ if (errorObject.stack === void 0) {
509
+ return "N/A";
510
+ }
511
+ let errorStack = errorObject.stack.split("\n");
512
+ for (let i = 1; i < errorStack.length; i++) {
513
+ if (!errorStack[i]?.includes("logger.js")) {
514
+ return errorStack[i]?.match(/(?<=\().+?(?=\))/g);
515
+ }
516
+ }
517
+ return "N/A";
518
+ };
519
+ var buildLogger = (pluginId, version, { fileLocation = true } = {}) => {
520
+ const namespace = `com.supertokens.plugin.${pluginId}`;
521
+ function logDebugMessage2(message) {
522
+ if (log_default.enabled(namespace)) {
523
+ log_default(namespace)(
524
+ `{t: "${(/* @__PURE__ */ new Date()).toISOString()}", message: "${message}", file: "${fileLocation ? getFileLocation() : "N/A"}" version: "${version}"}`
525
+ );
526
+ console.log();
527
+ }
528
+ }
529
+ function enableDebugLogs2() {
530
+ log_default.enable(namespace);
531
+ }
532
+ return {
533
+ logDebugMessage: logDebugMessage2,
534
+ enableDebugLogs: enableDebugLogs2
535
+ };
536
+ };
537
+
538
+ // src/logger.ts
539
+ var { logDebugMessage, enableDebugLogs } = buildLogger(
540
+ PLUGIN_ID,
541
+ PLUGIN_SDK_VERSION
542
+ );
543
+
544
+ // src/pluginImplementation.ts
545
+ function mapRowndUserToSuperTokens(rowndUser) {
546
+ const loginMethods = [];
547
+ const rowndUserData = rowndUser.data || {};
548
+ const rowndUserVerifiedData = rowndUser.verified_data || {};
549
+ if (!rowndUserData.user_id) {
550
+ throw new Error("Rownd user has no user_id");
551
+ }
552
+ if (rowndUserData.google_id) {
553
+ if (!rowndUserData.email) {
554
+ throw new Error("Rownd Google user is missing email");
555
+ }
556
+ loginMethods.push({
557
+ recipeId: "thirdparty",
558
+ thirdPartyId: "google",
559
+ thirdPartyUserId: rowndUserData.google_id,
560
+ email: rowndUserData.email,
561
+ isVerified: !!rowndUserVerifiedData.google_id
562
+ });
563
+ }
564
+ if (rowndUserData.apple_id) {
565
+ if (!rowndUserData.email) {
566
+ throw new Error("Rownd Apple user is missing email");
567
+ }
568
+ loginMethods.push({
569
+ recipeId: "thirdparty",
570
+ thirdPartyId: "apple",
571
+ thirdPartyUserId: rowndUserData.apple_id,
572
+ email: rowndUserData.email,
573
+ isVerified: !!rowndUserVerifiedData.apple_id
574
+ });
575
+ }
576
+ if (rowndUserData.phone_number) {
577
+ loginMethods.push({
578
+ recipeId: "passwordless",
579
+ phoneNumber: rowndUserData.phone_number,
580
+ isVerified: !!rowndUserVerifiedData.phone_number
581
+ });
582
+ }
583
+ if (rowndUserData.email && !rowndUserData.google_id && !rowndUserData.apple_id) {
584
+ loginMethods.push({
585
+ recipeId: "passwordless",
586
+ email: rowndUserData.email,
587
+ isVerified: !!rowndUserVerifiedData.email
588
+ });
589
+ }
590
+ let authLevel = rowndUser.auth_level;
591
+ if (loginMethods.length === 0) {
592
+ const thirdPartyId = authLevel === GUEST_AUTH_METHOD_ID ? GUEST_AUTH_METHOD_ID : ANONYMOUS_AUTH_METHOD_ID;
593
+ if (!authLevel) authLevel = thirdPartyId;
594
+ loginMethods.push({
595
+ recipeId: "thirdparty",
596
+ thirdPartyId,
597
+ thirdPartyUserId: rowndUserData.user_id,
598
+ email: `${rowndUserData.user_id}@anonymous.local`,
599
+ isVerified: false
600
+ });
601
+ }
602
+ const userMetadata = buildRowndUserMetadata(rowndUser);
603
+ return {
604
+ externalUserId: rowndUserData.user_id,
605
+ loginMethods,
606
+ userMetadata
607
+ };
608
+ }
609
+ var IDENTITY_USER_DATA_FIELDS = /* @__PURE__ */ new Set([
610
+ "user_id",
611
+ "email",
612
+ "phone_number",
613
+ "google_id",
614
+ "apple_id"
615
+ ]);
616
+ function isIdentityField(field) {
617
+ return IDENTITY_USER_DATA_FIELDS.has(field);
618
+ }
619
+ function buildRowndUserMetadata(rowndUser) {
620
+ const metadata = {
621
+ ...rowndUser.meta || {},
622
+ original_rownd_user: rowndUser
623
+ };
624
+ for (const [key, value] of Object.entries(rowndUser.data || {})) {
625
+ if (!isIdentityField(key) && value !== void 0) {
626
+ metadata[key] = value;
627
+ }
628
+ }
629
+ return metadata;
630
+ }
631
+ var RowndIsAnonymousClaim = new import_claims.BooleanClaim({
632
+ key: "is_anonymous",
633
+ fetchValue: async (userId) => {
634
+ const user = await import_supertokens_node.default.getUser(userId);
635
+ const effectiveAuthLevel = getEffectiveAuthLevel(user);
636
+ return effectiveAuthLevel === GUEST_AUTH_METHOD_ID;
637
+ }
638
+ });
639
+ function getThirdPartyId(method) {
640
+ return method.thirdPartyId || method.thirdParty?.id;
641
+ }
642
+ function getThirdPartyUserId(method) {
643
+ return method.thirdPartyUserId || method.thirdParty?.userId;
644
+ }
645
+ function getGuestAuthLevel(user) {
646
+ const guestMethod = user?.loginMethods.find(isGuestLoginMethod);
647
+ return guestMethod ? GUEST_AUTH_METHOD_ID : void 0;
648
+ }
649
+ function isGuestLoginMethod(method) {
650
+ const thirdPartyId = getThirdPartyId(method);
651
+ return method.recipeId === "thirdparty" && (thirdPartyId === GUEST_AUTH_METHOD_ID || thirdPartyId === ANONYMOUS_AUTH_METHOD_ID);
652
+ }
653
+ function hasVerifiedRealLoginMethod(user) {
654
+ return !!user?.loginMethods.some((method) => {
655
+ if (isGuestLoginMethod(method)) {
656
+ return false;
657
+ }
658
+ if (method.recipeId === "passwordless") {
659
+ return !!(method.email || method.phoneNumber);
660
+ }
661
+ if (method.recipeId === "thirdparty") {
662
+ return !!getThirdPartyUserId(method) && method.verified === true;
663
+ }
664
+ if (method.recipeId === "emailpassword") {
665
+ return !!method.email && method.verified === true;
666
+ }
667
+ return method.verified === true;
668
+ });
669
+ }
670
+ function getEffectiveAuthLevel(user, originalAuthLevel, verifiedData) {
671
+ if (hasVerifiedRealLoginMethod(user)) {
672
+ return "verified";
673
+ }
674
+ return getGuestAuthLevel(user) || originalAuthLevel || (verifiedData && Object.keys(verifiedData).length > 0 ? "verified" : "unverified");
675
+ }
676
+
677
+ // scripts/scriptUtils.ts
678
+ var fs = __toESM(require("fs/promises"));
679
+ var import_node_path = require("path");
680
+ var import_yaml = require("yaml");
681
+ var import_zod = require("zod");
682
+ var SCRIPT_DIR = __dirname;
683
+ var ConfigSchema = import_zod.z.object({
684
+ limit: import_zod.z.preprocess(
685
+ (value) => value === void 0 ? Number.POSITIVE_INFINITY : value,
686
+ import_zod.z.union([import_zod.z.literal(Number.POSITIVE_INFINITY), import_zod.z.number().int().positive()])
687
+ ),
688
+ checkpoint: import_zod.z.object({
689
+ file: import_zod.z.string(),
690
+ resume: import_zod.z.boolean().default(false)
691
+ }),
692
+ retry: import_zod.z.object({
693
+ maxAttempts: import_zod.z.number().int().positive(),
694
+ initialDelayMs: import_zod.z.number().int().positive()
695
+ }),
696
+ rownd: import_zod.z.object({
697
+ appId: import_zod.z.string(),
698
+ appKey: import_zod.z.string(),
699
+ appSecret: import_zod.z.string(),
700
+ bearerToken: import_zod.z.string().optional(),
701
+ pageSize: import_zod.z.number().int().positive()
702
+ }),
703
+ supertokens: import_zod.z.object({
704
+ connectionURI: import_zod.z.string(),
705
+ apiKey: import_zod.z.string().optional(),
706
+ batchSize: import_zod.z.number().int().positive()
707
+ }),
708
+ thirdPartyProviders: import_zod.z.array(
709
+ import_zod.z.object({
710
+ thirdPartyId: import_zod.z.string(),
711
+ name: import_zod.z.string().optional(),
712
+ clients: import_zod.z.array(
713
+ import_zod.z.object({
714
+ clientType: import_zod.z.string().optional(),
715
+ clientId: import_zod.z.string(),
716
+ clientSecret: import_zod.z.string().optional(),
717
+ scope: import_zod.z.array(import_zod.z.string()).optional()
718
+ })
719
+ )
720
+ })
721
+ ).optional()
722
+ });
723
+ var RowndUserRecordSchema = import_zod.z.looseObject({
724
+ user_id: import_zod.z.string().optional(),
725
+ rownd_user: import_zod.z.string().optional(),
726
+ subject: import_zod.z.string().optional(),
727
+ state: import_zod.z.string().optional(),
728
+ auth_level: import_zod.z.string().optional(),
729
+ data: import_zod.z.looseObject({
730
+ user_id: import_zod.z.string(),
731
+ email: import_zod.z.string().optional(),
732
+ phone_number: import_zod.z.string().optional(),
733
+ google_id: import_zod.z.string().optional(),
734
+ apple_id: import_zod.z.string().optional(),
735
+ first_name: import_zod.z.string().optional(),
736
+ last_name: import_zod.z.string().optional()
737
+ }),
738
+ verified_data: import_zod.z.record(import_zod.z.string(), import_zod.z.unknown()).default({}),
739
+ attributes: import_zod.z.record(import_zod.z.string(), import_zod.z.array(import_zod.z.string())).optional(),
740
+ groups: import_zod.z.array(import_zod.z.unknown()).optional(),
741
+ meta: import_zod.z.record(import_zod.z.string(), import_zod.z.unknown()).optional(),
742
+ connection_map: import_zod.z.record(import_zod.z.string(), import_zod.z.unknown()).optional()
743
+ });
744
+ var RowndUserListItemSchema = import_zod.z.object({
745
+ data: RowndUserRecordSchema
746
+ });
747
+ var RowndUsersPageSchema = import_zod.z.object({
748
+ results: import_zod.z.array(RowndUserRecordSchema).optional(),
749
+ data: import_zod.z.array(RowndUserListItemSchema).optional(),
750
+ total_results: import_zod.z.number().optional()
751
+ }).superRefine((value, context) => {
752
+ if (!value.results && !value.data) {
753
+ context.addIssue({
754
+ code: import_zod.z.ZodIssueCode.custom,
755
+ message: "Rownd API response is missing a results/data array."
756
+ });
757
+ }
758
+ });
759
+ function formatIssuePath(path) {
760
+ if (path.length === 0) {
761
+ return "<root>";
762
+ }
763
+ return path.map((segment, index) => {
764
+ if (typeof segment === "number") {
765
+ return `[${segment}]`;
766
+ }
767
+ return index === 0 ? segment : `.${segment}`;
768
+ }).join("");
769
+ }
770
+ function formatZodError(error) {
771
+ return error.issues.map(
772
+ (issue) => `${formatIssuePath(issue.path.filter((segment) => typeof segment === "string" || typeof segment === "number"))}: ${issue.message}`
773
+ ).join("\n");
774
+ }
775
+ function parseConfig(rawConfig, configDir = SCRIPT_DIR) {
776
+ const parsed = ConfigSchema.parse(rawConfig);
777
+ const checkpointFile = (0, import_node_path.isAbsolute)(parsed.checkpoint.file) ? parsed.checkpoint.file : (0, import_node_path.resolve)(configDir, parsed.checkpoint.file);
778
+ return {
779
+ limit: parsed.limit,
780
+ checkpoint: {
781
+ file: checkpointFile,
782
+ resume: parsed.checkpoint.resume
783
+ },
784
+ retry: parsed.retry,
785
+ rownd: parsed.rownd,
786
+ supertokens: parsed.supertokens,
787
+ thirdPartyProviders: parsed.thirdPartyProviders
788
+ };
789
+ }
790
+ async function loadConfig2(configFilePath) {
791
+ const configFile = await fs.readFile(configFilePath, "utf8");
792
+ return parseConfig((0, import_yaml.parse)(configFile), (0, import_node_path.dirname)(configFilePath));
793
+ }
794
+ function parseRequiredConfigArg(args) {
795
+ for (let i = 0; i < args.length; i += 1) {
796
+ const arg = args[i];
797
+ if (arg === "--config" || arg === "-c") {
798
+ const value = args[i + 1];
799
+ if (!value) {
800
+ throw new Error(`Missing value for ${arg}`);
801
+ }
802
+ return (0, import_node_path.resolve)(value);
803
+ }
804
+ }
805
+ throw new Error("Missing required --config <path>");
806
+ }
807
+ function hasHelpArg(args) {
808
+ return args.includes("--help") || args.includes("-h");
809
+ }
810
+ function parseRowndUser(parsed) {
811
+ const rowndUserId = parsed.data.user_id;
812
+ const rowndUser = {
813
+ state: parsed.state ?? "",
814
+ auth_level: parsed.auth_level ?? "",
815
+ data: {
816
+ ...parsed.data,
817
+ user_id: rowndUserId
818
+ },
819
+ verified_data: parsed.verified_data ?? {},
820
+ attributes: parsed.attributes,
821
+ groups: parsed.groups,
822
+ meta: parsed.meta
823
+ };
824
+ return { rowndUser, rowndUserId };
825
+ }
826
+ async function fetchRowndUsersPage(config2, cursor, pageSize) {
827
+ const url = new URL(
828
+ `/applications/${config2.rownd.appId}/users/data`,
829
+ "https://api.rownd.io"
830
+ );
831
+ if (cursor) {
832
+ url.searchParams.set("after", cursor);
833
+ }
834
+ url.searchParams.set("include_duplicates", "true");
835
+ url.searchParams.set("page_size", String(pageSize ?? config2.rownd.pageSize));
836
+ const response = await fetchWithRetry({
837
+ url: url.toString(),
838
+ requestInit: {
839
+ headers: {
840
+ "x-rownd-app-key": config2.rownd.appKey,
841
+ "x-rownd-app-secret": config2.rownd.appSecret
842
+ }
843
+ },
844
+ retryConfig: config2.retry,
845
+ operation: "Fetching Rownd users"
846
+ });
847
+ if (!response.ok) {
848
+ throw new Error(
849
+ `Rownd API error: ${response.status} ${await response.text()}`
850
+ );
851
+ }
852
+ const page = RowndUsersPageSchema.parse(await response.json());
853
+ const users = page.data?.map((entry) => entry.data) ?? page.results ?? [];
854
+ return users.map(parseRowndUser);
855
+ }
856
+ function isRetryableStatus(status) {
857
+ return status === 429 || status >= 500;
858
+ }
859
+ async function fetchWithRetry({
860
+ url,
861
+ requestInit,
862
+ retryConfig,
863
+ operation
864
+ }) {
865
+ let lastError;
866
+ for (let attempt = 1; attempt <= retryConfig.maxAttempts; attempt += 1) {
867
+ try {
868
+ const response = await fetch(url, requestInit);
869
+ if (response.ok || !isRetryableStatus(response.status) || attempt === retryConfig.maxAttempts) {
870
+ return response;
871
+ }
872
+ const responseText = await response.text();
873
+ lastError = new Error(
874
+ `${operation} failed with ${response.status}${responseText ? ` ${responseText}` : ""}`
875
+ );
876
+ } catch (error) {
877
+ if (attempt === retryConfig.maxAttempts) {
878
+ throw error;
879
+ }
880
+ lastError = error instanceof Error ? error : new Error(`${operation} failed`);
881
+ }
882
+ const delayMs = Math.round(
883
+ retryConfig.initialDelayMs * 2 ** (attempt - 1) * (1 + Math.random() * 0.2)
884
+ );
885
+ console.log(
886
+ `${operation} attempt ${attempt} failed. Retrying in ${delayMs}ms.`
887
+ );
888
+ await new Promise((resolve2) => setTimeout(resolve2, delayMs));
889
+ }
890
+ throw lastError ?? new Error(`${operation} failed`);
891
+ }
892
+
893
+ // scripts/bulkMigrate.ts
894
+ function printHelp() {
895
+ console.log(`Usage: rownd-nodejs bulk-migrate --config <path>
896
+
897
+ Options:
898
+ -c, --config <path> Path to the bulk migration config file
899
+ -h, --help Show this help message`);
900
+ }
901
+ var CheckpointSchema = import_zod2.z.object({
902
+ cursor: import_zod2.z.string().optional(),
903
+ importedCount: import_zod2.z.number().int().nonnegative().optional(),
904
+ updatedAt: import_zod2.z.string()
905
+ });
906
+ async function loadCheckpoint(checkpointFile) {
907
+ try {
908
+ const checkpoint = await fs2.readFile(checkpointFile, "utf8");
909
+ return CheckpointSchema.parse(JSON.parse(checkpoint));
910
+ } catch (error) {
911
+ if (error.code === "ENOENT") {
912
+ return null;
913
+ }
914
+ throw error;
915
+ }
916
+ }
917
+ async function saveCheckpoint(checkpointFile, checkpoint) {
918
+ const tempFile = `${checkpointFile}.tmp`;
919
+ await fs2.writeFile(tempFile, JSON.stringify(checkpoint, null, 2), "utf8");
920
+ await fs2.rename(tempFile, checkpointFile);
921
+ }
922
+ function getFailedMappingsFilePath(checkpointFile) {
923
+ return `${checkpointFile}.failed-mappings.json`;
924
+ }
925
+ async function loadFailedMappings(filePath) {
926
+ try {
927
+ const contents = await fs2.readFile(filePath, "utf8");
928
+ const parsed = JSON.parse(contents);
929
+ if (!Array.isArray(parsed)) {
930
+ throw new Error("Failed mappings file must contain a JSON array.");
931
+ }
932
+ return parsed;
933
+ } catch (error) {
934
+ if (error.code === "ENOENT") {
935
+ return [];
936
+ }
937
+ throw error;
938
+ }
939
+ }
940
+ async function appendFailedMappings(filePath, failedMappings) {
941
+ if (failedMappings.length === 0) {
942
+ return;
943
+ }
944
+ const existingMappings = await loadFailedMappings(filePath);
945
+ const tempFile = `${filePath}.tmp`;
946
+ await fs2.writeFile(
947
+ tempFile,
948
+ JSON.stringify([...existingMappings, ...failedMappings], null, 2),
949
+ "utf8"
950
+ );
951
+ await fs2.rename(tempFile, filePath);
952
+ }
953
+ async function stageUsersForImport(config2) {
954
+ const headers = {
955
+ "Content-Type": "application/json"
956
+ };
957
+ if (config2.supertokens.apiKey) {
958
+ headers["api-key"] = config2.supertokens.apiKey;
959
+ }
960
+ const response = await fetchWithRetry({
961
+ url: new URL(
962
+ "/bulk-import/users",
963
+ config2.supertokens.connectionURI
964
+ ).toString(),
965
+ requestInit: {
966
+ method: "POST",
967
+ headers,
968
+ body: JSON.stringify({ users: config2.users })
969
+ },
970
+ retryConfig: config2.retry,
971
+ operation: "Importing users into SuperTokens"
972
+ });
973
+ if (!response.ok) {
974
+ throw new Error(
975
+ `SuperTokens bulk import error: ${response.status} ${await response.text()}`
976
+ );
977
+ }
978
+ }
979
+ async function importUsersBatch(config2, users, totalImportedBeforeBatch) {
980
+ for (let index = 0; index < users.length; index += config2.supertokens.batchSize) {
981
+ const batch = users.slice(index, index + config2.supertokens.batchSize);
982
+ console.log(
983
+ `Importing batch ${Math.floor(totalImportedBeforeBatch / config2.supertokens.batchSize) + 1} (${batch.length} users)`
984
+ );
985
+ await stageUsersForImport({
986
+ users: batch.map((entry) => entry.user),
987
+ supertokens: config2.supertokens,
988
+ retry: config2.retry
989
+ });
990
+ }
991
+ }
992
+ async function migrateRowndUsersToSuperTokens(config2) {
993
+ const checkpoint = config2.checkpoint.resume ? await loadCheckpoint(config2.checkpoint.file) : null;
994
+ const failedMappingsFile = getFailedMappingsFilePath(config2.checkpoint.file);
995
+ let cursor = checkpoint?.cursor;
996
+ let totalProcessed = 0;
997
+ let totalImported = checkpoint?.importedCount ?? 0;
998
+ let totalSkipped = 0;
999
+ if (config2.checkpoint.resume) {
1000
+ console.log(
1001
+ checkpoint ? `Resuming migration from cursor ${checkpoint.cursor ?? "<start>"}` : "No checkpoint found. Starting a fresh migration."
1002
+ );
1003
+ }
1004
+ while (totalProcessed < config2.limit) {
1005
+ const remaining = Number.isFinite(config2.limit) ? Math.max(config2.limit - totalProcessed, 0) : config2.rownd.pageSize;
1006
+ const requestedPageSize = Number.isFinite(config2.limit) ? Math.min(config2.rownd.pageSize, remaining) : config2.rownd.pageSize;
1007
+ if (requestedPageSize === 0) {
1008
+ break;
1009
+ }
1010
+ console.log(
1011
+ `Fetching page ${Math.floor(totalProcessed / config2.rownd.pageSize) + 1}`
1012
+ );
1013
+ const pageUsers = await fetchRowndUsersPage(
1014
+ config2,
1015
+ cursor,
1016
+ requestedPageSize
1017
+ );
1018
+ if (pageUsers.length === 0) {
1019
+ break;
1020
+ }
1021
+ const mappedUsers = [];
1022
+ const failedMappings = [];
1023
+ for (const { rowndUser, rowndUserId } of pageUsers) {
1024
+ try {
1025
+ mappedUsers.push({
1026
+ rowndUserId,
1027
+ user: mapRowndUserToSuperTokens(rowndUser)
1028
+ });
1029
+ } catch (error) {
1030
+ const errorMessage = error instanceof Error ? error.message : "Unknown mapping error";
1031
+ failedMappings.push({
1032
+ user: rowndUser,
1033
+ error: errorMessage
1034
+ });
1035
+ console.warn(
1036
+ `Skipping Rownd user ${rowndUserId}: ${errorMessage}. Saved to ${failedMappingsFile}`
1037
+ );
1038
+ }
1039
+ }
1040
+ await appendFailedMappings(failedMappingsFile, failedMappings);
1041
+ totalSkipped += failedMappings.length;
1042
+ await importUsersBatch(config2, mappedUsers, totalImported);
1043
+ totalProcessed += pageUsers.length;
1044
+ totalImported += mappedUsers.length;
1045
+ cursor = pageUsers[pageUsers.length - 1]?.rowndUserId;
1046
+ await saveCheckpoint(config2.checkpoint.file, {
1047
+ cursor,
1048
+ importedCount: totalImported,
1049
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
1050
+ });
1051
+ console.log(`Processed ${totalProcessed} users so far`);
1052
+ console.log(`Imported ${totalImported} users so far`);
1053
+ if (pageUsers.length < requestedPageSize) {
1054
+ break;
1055
+ }
1056
+ }
1057
+ return {
1058
+ totalProcessed,
1059
+ totalImported,
1060
+ totalSkipped,
1061
+ cursor
1062
+ };
1063
+ }
1064
+ async function runCli() {
1065
+ const args = process.argv.slice(2);
1066
+ if (hasHelpArg(args)) {
1067
+ printHelp();
1068
+ return;
1069
+ }
1070
+ const config2 = await loadConfig2(parseRequiredConfigArg(args));
1071
+ const result = await migrateRowndUsersToSuperTokens(config2);
1072
+ console.log(`Migrated ${result.totalImported} users`);
1073
+ if (result.totalSkipped > 0) {
1074
+ console.warn(
1075
+ `Skipped ${result.totalSkipped} users. Details saved to ${getFailedMappingsFilePath(config2.checkpoint.file)}`
1076
+ );
1077
+ }
1078
+ }
1079
+ if (require.main === module) {
1080
+ runCli().catch((error) => {
1081
+ if (error instanceof import_zod2.z.ZodError) {
1082
+ console.error(formatZodError(error));
1083
+ } else {
1084
+ console.error(
1085
+ error instanceof Error ? error.message : "Bulk migration failed"
1086
+ );
1087
+ }
1088
+ process.exitCode = 1;
1089
+ });
1090
+ }
1091
+ // Annotate the CommonJS export names for ESM import in node:
1092
+ 0 && (module.exports = {
1093
+ migrateRowndUsersToSuperTokens,
1094
+ runCli,
1095
+ stageUsersForImport
1096
+ });