From a91ada047bc0314e9658b9268c91cb5d34c05b36 Mon Sep 17 00:00:00 2001 From: Bogdan Carpusor Date: Tue, 21 Apr 2026 20:06:42 +0300 Subject: [PATCH 1/3] feat: Add supertokens lazy migration --- src/context/ReactRowndProvider.tsx | 54 +++++++++++++++++++++++++----- src/context/RowndContext.tsx | 7 ++++ src/utils/supertokens-sync.ts | 21 ++++++++++++ 3 files changed, 74 insertions(+), 8 deletions(-) create mode 100644 src/utils/supertokens-sync.ts diff --git a/src/context/ReactRowndProvider.tsx b/src/context/ReactRowndProvider.tsx index 7e0c1e3..f8944b7 100644 --- a/src/context/ReactRowndProvider.tsx +++ b/src/context/ReactRowndProvider.tsx @@ -1,4 +1,4 @@ -import React, { useCallback, useEffect } from 'react'; +import React, { useCallback, useEffect, useRef } from 'react'; import { RowndContext, RowndProviderProps } from './RowndContext'; import InternalProviderHubScriptInjector from './HubScriptInjector/InternalProviderHubScriptInjector'; import useHub from '../hooks/useHub'; @@ -9,6 +9,7 @@ import { getOnAuthenticatedListeners, unsubscribeOnAuthenticatedListener, } from '../utils/listeners'; +import { syncUserToSuperTokens } from '../utils/supertokens-sync'; export const ReactRowndProvider: React.FC = ({ children, @@ -47,15 +48,52 @@ export const ReactRowndProvider: React.FC = ({ ); }, [is_authenticated, is_initializing, user.data.user_id]); - const stateListener = useCallback(({ state, api }) => { - hubListenerCb({ state, api, callback: setHubState }) - }, [hubListenerCb]); + const stateListener = useCallback( + ({ state, api }) => { + hubListenerCb({ state, api, callback: setHubState }); + }, + [hubListenerCb] + ); + + // Only sync new sign ups + const shouldSyncToSuperTokens = useRef(false); + useEffect(() => { + const handleSignInCompleted = (event: Event) => { + console.log('sign in completed'); + const detail = (event as CustomEvent<{ user_type?: string }>).detail; + + if (detail?.user_type === 'new_user') { + shouldSyncToSuperTokens.current = true; + } + }; + console.log('registering listener'); + + hubState.events.addEventListener( + 'sign_in_completed', + handleSignInCompleted + ); + + return () => { + hubState.events.removeEventListener( + 'sign_in_completed', + handleSignInCompleted + ); + }; + }, [hubState.events]); + + useEffect(() => { + const accessToken = hubState.access_token; + const appInfo = props.supertokens?.appInfo; + if (!accessToken || !appInfo || !shouldSyncToSuperTokens.current) { + return; + } + + shouldSyncToSuperTokens.current = false; + syncUserToSuperTokens(accessToken, appInfo).catch(() => {}); + }, [hubState.access_token, props.supertokens]); return ( - + {children} diff --git a/src/context/RowndContext.tsx b/src/context/RowndContext.tsx index b0cab87..02ece0d 100644 --- a/src/context/RowndContext.tsx +++ b/src/context/RowndContext.tsx @@ -21,6 +21,13 @@ export type RowndProviderProps = { * Set to an earlier date to opt-out of newer behaviors. */ apiVersion?: string; + /** + * SuperTokens application info. When set, the React SDK will call the + * customer's migration endpoint after a Rownd sign-up completes. + */ + supertokens?: { + appInfo: { appName: string; apiDomain: string; apiBasePath: string }; + }; children: React.ReactNode; }; diff --git a/src/utils/supertokens-sync.ts b/src/utils/supertokens-sync.ts new file mode 100644 index 0000000..7b3f028 --- /dev/null +++ b/src/utils/supertokens-sync.ts @@ -0,0 +1,21 @@ +export async function syncUserToSuperTokens( + accessToken: string, + appInfo: { appName: string; apiDomain: string; apiBasePath: string } +): Promise { + const base = `${appInfo.apiDomain}${appInfo.apiBasePath}`; + const headers = { Authorization: `Bearer ${accessToken}` }; + + try { + const res = await fetch(`${base}/plugin/rownd/migrate`, { + method: 'POST', + headers, + credentials: 'include', + }); + if (!res.ok) { + console.warn(`[Rownd->ST] migrate failed with status: ${res.status}`); + } + console.log('[Rownd->ST] migrate success'); + } catch (e) { + console.warn('[Rownd->ST] migrate failed (non-fatal):', e); + } +} From fcbf3aee960d385b262225ab124e0fca1ac6e545 Mon Sep 17 00:00:00 2001 From: Bogdan Carpusor Date: Tue, 21 Apr 2026 20:19:36 +0300 Subject: [PATCH 2/3] chore: Add example app --- .../backend/.env.example | 12 + examples/supertokens-migration/backend/.npmrc | 1 + .../backend/package.json | 23 + .../backend/src/index.ts | 88 ++ .../backend/tsconfig.json | 12 + .../supertokens-migration/frontend/index.html | 12 + .../frontend/package-lock.json | 1022 +++++++++++++++++ .../frontend/package.json | 23 + .../frontend/src/App.tsx | 30 + .../frontend/src/main.tsx | 21 + .../frontend/tsconfig.json | 21 + .../frontend/tsconfig.node.json | 10 + .../frontend/vite.config.ts | 6 + src/context/ReactRowndProvider.tsx | 2 - src/utils/supertokens-sync.ts | 1 - 15 files changed, 1281 insertions(+), 3 deletions(-) create mode 100644 examples/supertokens-migration/backend/.env.example create mode 100644 examples/supertokens-migration/backend/.npmrc create mode 100644 examples/supertokens-migration/backend/package.json create mode 100644 examples/supertokens-migration/backend/src/index.ts create mode 100644 examples/supertokens-migration/backend/tsconfig.json create mode 100644 examples/supertokens-migration/frontend/index.html create mode 100644 examples/supertokens-migration/frontend/package-lock.json create mode 100644 examples/supertokens-migration/frontend/package.json create mode 100644 examples/supertokens-migration/frontend/src/App.tsx create mode 100644 examples/supertokens-migration/frontend/src/main.tsx create mode 100644 examples/supertokens-migration/frontend/tsconfig.json create mode 100644 examples/supertokens-migration/frontend/tsconfig.node.json create mode 100644 examples/supertokens-migration/frontend/vite.config.ts diff --git a/examples/supertokens-migration/backend/.env.example b/examples/supertokens-migration/backend/.env.example new file mode 100644 index 0000000..e90bf8a --- /dev/null +++ b/examples/supertokens-migration/backend/.env.example @@ -0,0 +1,12 @@ +SUPERTOKENS_CONNECTION_URI=http://localhost:3567 +# SUPERTOKENS_API_KEY=your_core_api_key # only needed if you set one in supertokens-core + +ROWND_APP_KEY=your_rownd_app_key +ROWND_APP_SECRET=your_rownd_app_secret + +PORT=3001 + +# Origin of the Rownd Hub iframe — migration fetches come from here, not from +# the host app. Use http://localhost:8787 when running the Hub dev server +# locally, or https://hub.rownd.io for production. +HUB_ORIGIN=http://localhost:8787 diff --git a/examples/supertokens-migration/backend/.npmrc b/examples/supertokens-migration/backend/.npmrc new file mode 100644 index 0000000..c7d3517 --- /dev/null +++ b/examples/supertokens-migration/backend/.npmrc @@ -0,0 +1 @@ +install-links=true diff --git a/examples/supertokens-migration/backend/package.json b/examples/supertokens-migration/backend/package.json new file mode 100644 index 0000000..e0583b8 --- /dev/null +++ b/examples/supertokens-migration/backend/package.json @@ -0,0 +1,23 @@ +{ + "name": "user-migration-backend", + "version": "0.0.0", + "private": true, + "scripts": { + "dev": "tsx watch src/index.ts", + "start": "tsx src/index.ts" + }, + "dependencies": { + "@supertokens-plugins/rownd-nodejs": "latest", + "cors": "^2.8.5", + "dotenv": "^16.0.0", + "express": "^4.18.0", + "supertokens-node": "^23.0.0" + }, + "devDependencies": { + "@types/cors": "^2.8.13", + "@types/express": "^4.17.21", + "@types/node": "^20.0.0", + "tsx": "^4.0.0", + "typescript": "^5.0.0" + } +} diff --git a/examples/supertokens-migration/backend/src/index.ts b/examples/supertokens-migration/backend/src/index.ts new file mode 100644 index 0000000..c46328d --- /dev/null +++ b/examples/supertokens-migration/backend/src/index.ts @@ -0,0 +1,88 @@ +import 'dotenv/config'; +import express from 'express'; +import cors from 'cors'; +import supertokens from 'supertokens-node'; +import Session from 'supertokens-node/recipe/session'; +import Passwordless from 'supertokens-node/recipe/passwordless'; +import UserMetadata from 'supertokens-node/recipe/usermetadata'; +import AccountLinking from 'supertokens-node/recipe/accountlinking'; +import { middleware, errorHandler } from 'supertokens-node/framework/express'; +import RowndPlugin from '@supertokens-plugins/rownd-nodejs'; + +const PORT = Number(process.env.PORT) || 3001; + +const WEBSITE_ORIGIN = process.env.WEBSITE_ORIGIN || 'http://localhost:5173'; +const HUB_ORIGIN = process.env.HUB_ORIGIN || 'http://localhost:8787'; + +const ALLOWED_ORIGINS = [WEBSITE_ORIGIN, HUB_ORIGIN]; + +supertokens.init({ + framework: 'express', + supertokens: { + connectionURI: + process.env.SUPERTOKENS_CONNECTION_URI || 'http://localhost:3567', + apiKey: process.env.SUPERTOKENS_API_KEY, + }, + appInfo: { + appName: 'User Migration Example', + apiDomain: `http://localhost:${PORT}`, + websiteDomain: WEBSITE_ORIGIN, + apiBasePath: '/auth', + websiteBasePath: '/auth', + }, + recipeList: [ + Passwordless.init({ + contactMethod: 'EMAIL_OR_PHONE', + flowType: 'USER_INPUT_CODE', + }), + Session.init({ + tokenTransferMethod: 'header', + }), + UserMetadata.init(), + AccountLinking.init({ + shouldDoAutomaticAccountLinking: async () => ({ + shouldAutomaticallyLink: true, + shouldRequireVerification: false, + }), + }), + ], + experimental: { + plugins: [ + RowndPlugin.init({ + rowndAppKey: process.env.ROWND_APP_KEY!, + rowndAppSecret: process.env.ROWND_APP_SECRET!, + enableDebugLogs: true, + }), + ], + }, +}); + +const app = express(); + +app.use( + cors({ + origin: ALLOWED_ORIGINS, + allowedHeaders: ['content-type', ...supertokens.getAllCORSHeaders()], + credentials: true, + }) +); + +app.use(express.json()); + +app.use((req, _res, next) => { + console.log( + `[${new Date().toISOString()}] ${req.method} ${req.url} (origin: ${req.headers.origin ?? 'none'})` + ); + next(); +}); + +app.use(middleware()); + +app.use(errorHandler()); + +app.listen(PORT, () => { + console.log(`Backend running on http://localhost:${PORT}`); + console.log( + `SuperTokens Core: ${process.env.SUPERTOKENS_CONNECTION_URI || 'http://localhost:3567'}` + ); +}); diff --git a/examples/supertokens-migration/backend/tsconfig.json b/examples/supertokens-migration/backend/tsconfig.json new file mode 100644 index 0000000..618754e --- /dev/null +++ b/examples/supertokens-migration/backend/tsconfig.json @@ -0,0 +1,12 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "CommonJS", + "moduleResolution": "node", + "esModuleInterop": true, + "strict": true, + "skipLibCheck": true, + "outDir": "dist" + }, + "include": ["src"] +} diff --git a/examples/supertokens-migration/frontend/index.html b/examples/supertokens-migration/frontend/index.html new file mode 100644 index 0000000..fbe61ae --- /dev/null +++ b/examples/supertokens-migration/frontend/index.html @@ -0,0 +1,12 @@ + + + + + + User Migration Example + + +
+ + + diff --git a/examples/supertokens-migration/frontend/package-lock.json b/examples/supertokens-migration/frontend/package-lock.json new file mode 100644 index 0000000..a41b32a --- /dev/null +++ b/examples/supertokens-migration/frontend/package-lock.json @@ -0,0 +1,1022 @@ +{ + "name": "user-migration-example", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "user-migration-example", + "version": "0.0.0", + "dependencies": { + "react": "^18.2.0", + "react-dom": "^18.2.0", + "supertokens-rownd-react": "file:../../.." + }, + "devDependencies": { + "@types/react": "^18.2.15", + "@types/react-dom": "^18.2.7", + "@vitejs/plugin-react-swc": "^3.3.2", + "typescript": "^5.0.2", + "vite": "^4.4.5" + } + }, + "../../..": { + "name": "@rownd/react", + "version": "2.9.0", + "license": "MIT", + "dependencies": { + "jose": "^5.9.6" + }, + "devDependencies": { + "@release-it/conventional-changelog": "^8.0.1", + "@size-limit/preset-small-lib": "^7.0.8", + "@testing-library/dom": "^10.4.0", + "@testing-library/react": "^16.3.0", + "@types/react": "^18.3.23", + "@types/react-dom": "^18.3.7", + "@vitest/coverage-v8": "^3.2.2", + "eslint": "^8.56.0", + "eslint-plugin-react": "^7.33.2", + "happy-dom": "^13.3.8", + "husky": "^7.0.4", + "jsdom": "^26.1.0", + "prop-types": "^15.8.1", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "release-it": "^17.1.1", + "rollup-preserve-directives": "^1.1.1", + "size-limit": "^7.0.8", + "tslib": "^2.3.1", + "typescript": "^4.9.5", + "typescript-eslint": "^7.0.2", + "vite": "^5.1.3", + "vite-bundle-visualizer": "^1.0.1", + "vite-plugin-dts": "^3.7.2", + "vite-tsconfig-paths": "^5.1.4", + "vitest": "^3.2.2", + "vitest-fetch-mock": "^0.4.5", + "vitest-mock-extended": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "react": ">=17.0", + "react-dom": ">=17.0" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.20.tgz", + "integrity": "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz", + "integrity": "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.20.tgz", + "integrity": "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz", + "integrity": "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz", + "integrity": "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz", + "integrity": "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz", + "integrity": "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz", + "integrity": "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz", + "integrity": "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz", + "integrity": "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz", + "integrity": "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz", + "integrity": "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz", + "integrity": "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz", + "integrity": "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz", + "integrity": "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz", + "integrity": "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz", + "integrity": "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz", + "integrity": "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz", + "integrity": "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz", + "integrity": "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz", + "integrity": "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz", + "integrity": "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-beta.27", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz", + "integrity": "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@swc/core": { + "version": "1.15.24", + "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.15.24.tgz", + "integrity": "sha512-5Hj8aNasue7yusUt8LGCUe/AjM7RMAce8ZoyDyiFwx7Al+GbYKL+yE7g4sJk8vEr1dKIkTRARkNIJENc4CjkBQ==", + "dev": true, + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@swc/counter": "^0.1.3", + "@swc/types": "^0.1.26" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/swc" + }, + "optionalDependencies": { + "@swc/core-darwin-arm64": "1.15.24", + "@swc/core-darwin-x64": "1.15.24", + "@swc/core-linux-arm-gnueabihf": "1.15.24", + "@swc/core-linux-arm64-gnu": "1.15.24", + "@swc/core-linux-arm64-musl": "1.15.24", + "@swc/core-linux-ppc64-gnu": "1.15.24", + "@swc/core-linux-s390x-gnu": "1.15.24", + "@swc/core-linux-x64-gnu": "1.15.24", + "@swc/core-linux-x64-musl": "1.15.24", + "@swc/core-win32-arm64-msvc": "1.15.24", + "@swc/core-win32-ia32-msvc": "1.15.24", + "@swc/core-win32-x64-msvc": "1.15.24" + }, + "peerDependencies": { + "@swc/helpers": ">=0.5.17" + }, + "peerDependenciesMeta": { + "@swc/helpers": { + "optional": true + } + } + }, + "node_modules/@swc/core-darwin-arm64": { + "version": "1.15.24", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.15.24.tgz", + "integrity": "sha512-uM5ZGfFXjtvtJ+fe448PVBEbn/CSxS3UAyLj3O9xOqKIWy3S6hPTXSPbszxkSsGDYKi+YFhzAsR4r/eXLxEQ0g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-darwin-x64": { + "version": "1.15.24", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.15.24.tgz", + "integrity": "sha512-fMIb/Zfn929pw25VMBhV7Ji2Dl+lCWtUPNdYJQYOke+00E5fcQ9ynxtP8+qhUo/HZc+mYQb1gJxwHM9vty+lXg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm-gnueabihf": { + "version": "1.15.24", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.15.24.tgz", + "integrity": "sha512-vOkjsyjjxnoYx3hMEWcGxQrMgnNrRm6WAegBXrN8foHtDAR+zpdhpGF5a4lj1bNPgXAvmysjui8cM1ov/Clkaw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm64-gnu": { + "version": "1.15.24", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.15.24.tgz", + "integrity": "sha512-h/oNu+upkXJ6Cicnq7YGVj9PkdfarLCdQa8l/FlHYvfv8CEiMaeeTnpLU7gSBH/rGxosM6Qkfa/J9mThGF9CLA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm64-musl": { + "version": "1.15.24", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.15.24.tgz", + "integrity": "sha512-ZpF/pRe1guk6sKzQI9D1jAORtjTdNlyeXn9GDz8ophof/w2WhojRblvSDJaGe7rJjcPN8AaOkhwdRUh7q8oYIg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-ppc64-gnu": { + "version": "1.15.24", + "resolved": "https://registry.npmjs.org/@swc/core-linux-ppc64-gnu/-/core-linux-ppc64-gnu-1.15.24.tgz", + "integrity": "sha512-QZEsZfisHTSJlmyChgDFNmKPb3W6Lhbfo/O76HhIngfEdnQNmukS38/VSe1feho+xkV5A5hETyCbx3sALBZKAQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-s390x-gnu": { + "version": "1.15.24", + "resolved": "https://registry.npmjs.org/@swc/core-linux-s390x-gnu/-/core-linux-s390x-gnu-1.15.24.tgz", + "integrity": "sha512-DLdJKVsJgglqQrJBuoUYNmzm3leI7kUZhLbZGHv42onfKsGf6JDS3+bzCUQfte/XOqDjh/tmmn1DR/CF/tCJFw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-x64-gnu": { + "version": "1.15.24", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.15.24.tgz", + "integrity": "sha512-IpLYfposPA/XLxYOKpRfeccl1p5dDa3+okZDHHTchBkXEaVCnq5MADPmIWwIYj1tudt7hORsEHccG5no6IUQRw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-x64-musl": { + "version": "1.15.24", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.15.24.tgz", + "integrity": "sha512-JHy3fMSc0t/EPWgo74+OK5TGr51aElnzqfUPaiRf2qJ/BfX5CUCfMiWVBuhI7qmVMBnk1jTRnL/xZnOSHDPLYg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-arm64-msvc": { + "version": "1.15.24", + "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.15.24.tgz", + "integrity": "sha512-Txj+qUH1z2bUd1P3JvwByfjKFti3cptlAxhWgmunBUUxy/IW3CXLZ6l6Gk4liANadKkU71nIU1X30Z5vpMT3BA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-ia32-msvc": { + "version": "1.15.24", + "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.15.24.tgz", + "integrity": "sha512-15D/nl3XwrhFpMv+MADFOiVwv3FvH9j8c6Rf8EXBT3Q5LoMh8YnDnSgPYqw1JzPnksvsBX6QPXLiPqmcR/Z4qQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-x64-msvc": { + "version": "1.15.24", + "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.15.24.tgz", + "integrity": "sha512-PR0PlTlPra2JbaDphrOAzm6s0v9rA0F17YzB+XbWD95B4g2cWcZY9LAeTa4xll70VLw9Jr7xBrlohqlQmelMFQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/counter": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz", + "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/@swc/types": { + "version": "0.1.26", + "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.26.tgz", + "integrity": "sha512-lyMwd7WGgG79RS7EERZV3T8wMdmPq3xwyg+1nmAM64kIhx5yl+juO2PYIHb7vTiPgPCj8LYjsNV2T5wiQHUEaw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@swc/counter": "^0.1.3" + } + }, + "node_modules/@types/prop-types": { + "version": "15.7.15", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz", + "integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/react": { + "version": "18.3.28", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.28.tgz", + "integrity": "sha512-z9VXpC7MWrhfWipitjNdgCauoMLRdIILQsAEV+ZesIzBq/oUlxk0m3ApZuMFCXdnS4U7KrI+l3WRUEGQ8K1QKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/prop-types": "*", + "csstype": "^3.2.2" + } + }, + "node_modules/@types/react-dom": { + "version": "18.3.7", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.7.tgz", + "integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^18.0.0" + } + }, + "node_modules/@vitejs/plugin-react-swc": { + "version": "3.11.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react-swc/-/plugin-react-swc-3.11.0.tgz", + "integrity": "sha512-YTJCGFdNMHCMfjODYtxRNVAYmTWQ1Lb8PulP/2/f/oEEtglw8oKxKIZmmRkyXrVrHfsKOaVkAc3NT9/dMutO5w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rolldown/pluginutils": "1.0.0-beta.27", + "@swc/core": "^1.12.11" + }, + "peerDependencies": { + "vite": "^4 || ^5 || ^6 || ^7" + } + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/esbuild": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.20.tgz", + "integrity": "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/android-arm": "0.18.20", + "@esbuild/android-arm64": "0.18.20", + "@esbuild/android-x64": "0.18.20", + "@esbuild/darwin-arm64": "0.18.20", + "@esbuild/darwin-x64": "0.18.20", + "@esbuild/freebsd-arm64": "0.18.20", + "@esbuild/freebsd-x64": "0.18.20", + "@esbuild/linux-arm": "0.18.20", + "@esbuild/linux-arm64": "0.18.20", + "@esbuild/linux-ia32": "0.18.20", + "@esbuild/linux-loong64": "0.18.20", + "@esbuild/linux-mips64el": "0.18.20", + "@esbuild/linux-ppc64": "0.18.20", + "@esbuild/linux-riscv64": "0.18.20", + "@esbuild/linux-s390x": "0.18.20", + "@esbuild/linux-x64": "0.18.20", + "@esbuild/netbsd-x64": "0.18.20", + "@esbuild/openbsd-x64": "0.18.20", + "@esbuild/sunos-x64": "0.18.20", + "@esbuild/win32-arm64": "0.18.20", + "@esbuild/win32-ia32": "0.18.20", + "@esbuild/win32-x64": "0.18.20" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "license": "MIT" + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/postcss": { + "version": "8.5.9", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.9.tgz", + "integrity": "sha512-7a70Nsot+EMX9fFU3064K/kdHWZqGVY+BADLyXc8Dfv+mTLLVl6JzJpPaCZ2kQL9gIJvKXSLMHhqdRRjwQeFtw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/react": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.2" + }, + "peerDependencies": { + "react": "^18.3.1" + } + }, + "node_modules/rollup": { + "version": "3.30.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.30.0.tgz", + "integrity": "sha512-kQvGasUgN+AlWGliFn2POSajRQEsULVYFGTvOZmK06d7vCD+YhZztt70kGk3qaeAXeWYL5eO7zx+rAubBc55eA==", + "dev": true, + "license": "MIT", + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=14.18.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/scheduler": { + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/supertokens-rownd-react": { + "resolved": "../../..", + "link": true + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/vite": { + "version": "4.5.14", + "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.14.tgz", + "integrity": "sha512-+v57oAaoYNnO3hIu5Z/tJRZjq5aHM2zDve9YZ8HngVHbhk66RStobhb1sqPMIPEleV6cNKYK4eGrAbE9Ulbl2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.18.10", + "postcss": "^8.4.27", + "rollup": "^3.27.1" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + }, + "peerDependencies": { + "@types/node": ">= 14", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + } + } +} diff --git a/examples/supertokens-migration/frontend/package.json b/examples/supertokens-migration/frontend/package.json new file mode 100644 index 0000000..7d98251 --- /dev/null +++ b/examples/supertokens-migration/frontend/package.json @@ -0,0 +1,23 @@ +{ + "name": "user-migration-example", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "tsc && vite build", + "preview": "vite preview" + }, + "dependencies": { + "supertokens-rownd-react": "file:../../..", + "react": "^18.2.0", + "react-dom": "^18.2.0" + }, + "devDependencies": { + "@types/react": "^18.2.15", + "@types/react-dom": "^18.2.7", + "@vitejs/plugin-react-swc": "^3.3.2", + "typescript": "^5.0.2", + "vite": "^4.4.5" + } +} diff --git a/examples/supertokens-migration/frontend/src/App.tsx b/examples/supertokens-migration/frontend/src/App.tsx new file mode 100644 index 0000000..70e45db --- /dev/null +++ b/examples/supertokens-migration/frontend/src/App.tsx @@ -0,0 +1,30 @@ +import { useRownd } from 'supertokens-rownd-react'; + +function App() { + const { is_authenticated, access_token, user, requestSignIn, signOut } = useRownd(); + + return ( +
+

User Migration Example

+ {is_authenticated ? ( +
+

Signed in as: {user.data?.email as string}

+

+ Access token:{' '} + + {access_token} + +

+ +
+ ) : ( +
+

Not signed in.

+ +
+ )} +
+ ); +} + +export default App; diff --git a/examples/supertokens-migration/frontend/src/main.tsx b/examples/supertokens-migration/frontend/src/main.tsx new file mode 100644 index 0000000..56eaf3e --- /dev/null +++ b/examples/supertokens-migration/frontend/src/main.tsx @@ -0,0 +1,21 @@ +import React from 'react'; +import ReactDOM from 'react-dom/client'; +import App from './App.tsx'; +import { RowndProvider } from 'supertokens-rownd-react'; + +ReactDOM.createRoot(document.getElementById('root')!).render( + + + + + +); diff --git a/examples/supertokens-migration/frontend/tsconfig.json b/examples/supertokens-migration/frontend/tsconfig.json new file mode 100644 index 0000000..3934b8f --- /dev/null +++ b/examples/supertokens-migration/frontend/tsconfig.json @@ -0,0 +1,21 @@ +{ + "compilerOptions": { + "target": "ES2020", + "useDefineForClassFields": true, + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "module": "ESNext", + "skipLibCheck": true, + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "jsx": "react-jsx", + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true + }, + "include": ["src"], + "references": [{ "path": "./tsconfig.node.json" }] +} diff --git a/examples/supertokens-migration/frontend/tsconfig.node.json b/examples/supertokens-migration/frontend/tsconfig.node.json new file mode 100644 index 0000000..42872c5 --- /dev/null +++ b/examples/supertokens-migration/frontend/tsconfig.node.json @@ -0,0 +1,10 @@ +{ + "compilerOptions": { + "composite": true, + "skipLibCheck": true, + "module": "ESNext", + "moduleResolution": "bundler", + "allowSyntheticDefaultImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/examples/supertokens-migration/frontend/vite.config.ts b/examples/supertokens-migration/frontend/vite.config.ts new file mode 100644 index 0000000..7af9f6f --- /dev/null +++ b/examples/supertokens-migration/frontend/vite.config.ts @@ -0,0 +1,6 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react-swc' + +export default defineConfig({ + plugins: [react()], +}) diff --git a/src/context/ReactRowndProvider.tsx b/src/context/ReactRowndProvider.tsx index f8944b7..52978a4 100644 --- a/src/context/ReactRowndProvider.tsx +++ b/src/context/ReactRowndProvider.tsx @@ -59,14 +59,12 @@ export const ReactRowndProvider: React.FC = ({ const shouldSyncToSuperTokens = useRef(false); useEffect(() => { const handleSignInCompleted = (event: Event) => { - console.log('sign in completed'); const detail = (event as CustomEvent<{ user_type?: string }>).detail; if (detail?.user_type === 'new_user') { shouldSyncToSuperTokens.current = true; } }; - console.log('registering listener'); hubState.events.addEventListener( 'sign_in_completed', diff --git a/src/utils/supertokens-sync.ts b/src/utils/supertokens-sync.ts index 7b3f028..1ee7dce 100644 --- a/src/utils/supertokens-sync.ts +++ b/src/utils/supertokens-sync.ts @@ -14,7 +14,6 @@ export async function syncUserToSuperTokens( if (!res.ok) { console.warn(`[Rownd->ST] migrate failed with status: ${res.status}`); } - console.log('[Rownd->ST] migrate success'); } catch (e) { console.warn('[Rownd->ST] migrate failed (non-fatal):', e); } From 4434043e4b3f3971dc362914a2046fd2372b786f Mon Sep 17 00:00:00 2001 From: Bogdan Carpusor Date: Wed, 22 Apr 2026 18:31:17 +0300 Subject: [PATCH 3/3] fix: Code review fixes --- .../frontend/package-lock.json | 120 +++++++++--------- .../frontend/package.json | 2 +- .../frontend/src/App.tsx | 5 +- .../frontend/src/main.tsx | 4 +- src/context/ReactRowndProvider.tsx | 44 ++++--- src/utils/supertokens-sync.ts | 32 ++++- 6 files changed, 123 insertions(+), 84 deletions(-) diff --git a/examples/supertokens-migration/frontend/package-lock.json b/examples/supertokens-migration/frontend/package-lock.json index a41b32a..1ced4be 100644 --- a/examples/supertokens-migration/frontend/package-lock.json +++ b/examples/supertokens-migration/frontend/package-lock.json @@ -8,9 +8,9 @@ "name": "user-migration-example", "version": "0.0.0", "dependencies": { + "@rownd/react": "file:../../..", "react": "^18.2.0", - "react-dom": "^18.2.0", - "supertokens-rownd-react": "file:../../.." + "react-dom": "^18.2.0" }, "devDependencies": { "@types/react": "^18.2.15", @@ -446,10 +446,14 @@ "dev": true, "license": "MIT" }, + "node_modules/@rownd/react": { + "resolved": "../../..", + "link": true + }, "node_modules/@swc/core": { - "version": "1.15.24", - "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.15.24.tgz", - "integrity": "sha512-5Hj8aNasue7yusUt8LGCUe/AjM7RMAce8ZoyDyiFwx7Al+GbYKL+yE7g4sJk8vEr1dKIkTRARkNIJENc4CjkBQ==", + "version": "1.15.30", + "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.15.30.tgz", + "integrity": "sha512-R8VQbQY1BZcbIF2p3gjlTCwAQzx1A194ugWfwld5y+WgVVWqVKm7eURGGOVbQVubgKWzidP2agomBbg96rZilQ==", "dev": true, "hasInstallScript": true, "license": "Apache-2.0", @@ -465,18 +469,18 @@ "url": "https://opencollective.com/swc" }, "optionalDependencies": { - "@swc/core-darwin-arm64": "1.15.24", - "@swc/core-darwin-x64": "1.15.24", - "@swc/core-linux-arm-gnueabihf": "1.15.24", - "@swc/core-linux-arm64-gnu": "1.15.24", - "@swc/core-linux-arm64-musl": "1.15.24", - "@swc/core-linux-ppc64-gnu": "1.15.24", - "@swc/core-linux-s390x-gnu": "1.15.24", - "@swc/core-linux-x64-gnu": "1.15.24", - "@swc/core-linux-x64-musl": "1.15.24", - "@swc/core-win32-arm64-msvc": "1.15.24", - "@swc/core-win32-ia32-msvc": "1.15.24", - "@swc/core-win32-x64-msvc": "1.15.24" + "@swc/core-darwin-arm64": "1.15.30", + "@swc/core-darwin-x64": "1.15.30", + "@swc/core-linux-arm-gnueabihf": "1.15.30", + "@swc/core-linux-arm64-gnu": "1.15.30", + "@swc/core-linux-arm64-musl": "1.15.30", + "@swc/core-linux-ppc64-gnu": "1.15.30", + "@swc/core-linux-s390x-gnu": "1.15.30", + "@swc/core-linux-x64-gnu": "1.15.30", + "@swc/core-linux-x64-musl": "1.15.30", + "@swc/core-win32-arm64-msvc": "1.15.30", + "@swc/core-win32-ia32-msvc": "1.15.30", + "@swc/core-win32-x64-msvc": "1.15.30" }, "peerDependencies": { "@swc/helpers": ">=0.5.17" @@ -488,9 +492,9 @@ } }, "node_modules/@swc/core-darwin-arm64": { - "version": "1.15.24", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.15.24.tgz", - "integrity": "sha512-uM5ZGfFXjtvtJ+fe448PVBEbn/CSxS3UAyLj3O9xOqKIWy3S6hPTXSPbszxkSsGDYKi+YFhzAsR4r/eXLxEQ0g==", + "version": "1.15.30", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.15.30.tgz", + "integrity": "sha512-VvpP+vq08HmGYewMWvrdsxh9s2lthz/808zXm8Yu5kaqeR8Yia2b0eYXleHQ3VAjoStUDk6LzTheBW9KXYQdMA==", "cpu": [ "arm64" ], @@ -505,9 +509,9 @@ } }, "node_modules/@swc/core-darwin-x64": { - "version": "1.15.24", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.15.24.tgz", - "integrity": "sha512-fMIb/Zfn929pw25VMBhV7Ji2Dl+lCWtUPNdYJQYOke+00E5fcQ9ynxtP8+qhUo/HZc+mYQb1gJxwHM9vty+lXg==", + "version": "1.15.30", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.15.30.tgz", + "integrity": "sha512-WiJA0hiZI3nwQAO6mu5RqigtWGDtth4Hiq6rbZxAaQyhIcqKIg5IoMRc1Y071lrNJn29eEDMC86Rq58xgUxlDg==", "cpu": [ "x64" ], @@ -522,9 +526,9 @@ } }, "node_modules/@swc/core-linux-arm-gnueabihf": { - "version": "1.15.24", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.15.24.tgz", - "integrity": "sha512-vOkjsyjjxnoYx3hMEWcGxQrMgnNrRm6WAegBXrN8foHtDAR+zpdhpGF5a4lj1bNPgXAvmysjui8cM1ov/Clkaw==", + "version": "1.15.30", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.15.30.tgz", + "integrity": "sha512-YANuFUo48kIT6plJgCD0keae9HFXfjxsbvsgevqc0hr/07X/p7sAWTFOGYEc2SXcASaK7UvuQqzlbW8pr7R79g==", "cpu": [ "arm" ], @@ -539,9 +543,9 @@ } }, "node_modules/@swc/core-linux-arm64-gnu": { - "version": "1.15.24", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.15.24.tgz", - "integrity": "sha512-h/oNu+upkXJ6Cicnq7YGVj9PkdfarLCdQa8l/FlHYvfv8CEiMaeeTnpLU7gSBH/rGxosM6Qkfa/J9mThGF9CLA==", + "version": "1.15.30", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.15.30.tgz", + "integrity": "sha512-VndG8jaR4ugY6u+iVOT0Q+d2fZd7sLgjPgN8W/Le+3EbZKl+cRfFxV7Eoz4gfLqhmneZPdcIzf9T3LkgkmqNLg==", "cpu": [ "arm64" ], @@ -556,9 +560,9 @@ } }, "node_modules/@swc/core-linux-arm64-musl": { - "version": "1.15.24", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.15.24.tgz", - "integrity": "sha512-ZpF/pRe1guk6sKzQI9D1jAORtjTdNlyeXn9GDz8ophof/w2WhojRblvSDJaGe7rJjcPN8AaOkhwdRUh7q8oYIg==", + "version": "1.15.30", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.15.30.tgz", + "integrity": "sha512-1SYGs2l0Yyyi0pR/P/NKz/x0kqxkoiw+BXeJjLUdecSk/KasncWlJrc6hOvFSgKHOBrzgM5jwuluKtlT8dnrcA==", "cpu": [ "arm64" ], @@ -573,9 +577,9 @@ } }, "node_modules/@swc/core-linux-ppc64-gnu": { - "version": "1.15.24", - "resolved": "https://registry.npmjs.org/@swc/core-linux-ppc64-gnu/-/core-linux-ppc64-gnu-1.15.24.tgz", - "integrity": "sha512-QZEsZfisHTSJlmyChgDFNmKPb3W6Lhbfo/O76HhIngfEdnQNmukS38/VSe1feho+xkV5A5hETyCbx3sALBZKAQ==", + "version": "1.15.30", + "resolved": "https://registry.npmjs.org/@swc/core-linux-ppc64-gnu/-/core-linux-ppc64-gnu-1.15.30.tgz", + "integrity": "sha512-TXREtiXeRhbfDFbmhnkIsXpKfzbfT73YkV2ZF6w0sfxgjC5zI2ZAbaCOq25qxvegofj2K93DtOpm9RLaBgqR2g==", "cpu": [ "ppc64" ], @@ -590,9 +594,9 @@ } }, "node_modules/@swc/core-linux-s390x-gnu": { - "version": "1.15.24", - "resolved": "https://registry.npmjs.org/@swc/core-linux-s390x-gnu/-/core-linux-s390x-gnu-1.15.24.tgz", - "integrity": "sha512-DLdJKVsJgglqQrJBuoUYNmzm3leI7kUZhLbZGHv42onfKsGf6JDS3+bzCUQfte/XOqDjh/tmmn1DR/CF/tCJFw==", + "version": "1.15.30", + "resolved": "https://registry.npmjs.org/@swc/core-linux-s390x-gnu/-/core-linux-s390x-gnu-1.15.30.tgz", + "integrity": "sha512-DCR2YYeyd6DQE4OuDhImouuNcjXEiEdnn1Y0DyGteugPEDvVuvYk8Xddi+4o2SgWH6jiW8/I+3emZvbep1NC+g==", "cpu": [ "s390x" ], @@ -607,9 +611,9 @@ } }, "node_modules/@swc/core-linux-x64-gnu": { - "version": "1.15.24", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.15.24.tgz", - "integrity": "sha512-IpLYfposPA/XLxYOKpRfeccl1p5dDa3+okZDHHTchBkXEaVCnq5MADPmIWwIYj1tudt7hORsEHccG5no6IUQRw==", + "version": "1.15.30", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.15.30.tgz", + "integrity": "sha512-5Pizw3NgfOJ5BJOBK8TIRa59xFW2avESTOBDPTAYwZYa1JNDs+KMF9lUfjJiJLM5HiMs/wPheA9eiT0q9m2AoA==", "cpu": [ "x64" ], @@ -624,9 +628,9 @@ } }, "node_modules/@swc/core-linux-x64-musl": { - "version": "1.15.24", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.15.24.tgz", - "integrity": "sha512-JHy3fMSc0t/EPWgo74+OK5TGr51aElnzqfUPaiRf2qJ/BfX5CUCfMiWVBuhI7qmVMBnk1jTRnL/xZnOSHDPLYg==", + "version": "1.15.30", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.15.30.tgz", + "integrity": "sha512-qyqydP/wyH8alcIP4a2hnGSjHLJjm9H7yDFup+CPy9oTahFgLLwnNcv5UHXqO2Qs3AIND+cls5f/Bb6hqpxdgA==", "cpu": [ "x64" ], @@ -641,9 +645,9 @@ } }, "node_modules/@swc/core-win32-arm64-msvc": { - "version": "1.15.24", - "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.15.24.tgz", - "integrity": "sha512-Txj+qUH1z2bUd1P3JvwByfjKFti3cptlAxhWgmunBUUxy/IW3CXLZ6l6Gk4liANadKkU71nIU1X30Z5vpMT3BA==", + "version": "1.15.30", + "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.15.30.tgz", + "integrity": "sha512-CaQENgDHVGOg1mSF5sQVgvfFHG9kjMor2rkLMLeLOkfZYNj13ppnJ9+lfaBZLZUMMbnlGQnavCJb8PVBUOso7Q==", "cpu": [ "arm64" ], @@ -658,9 +662,9 @@ } }, "node_modules/@swc/core-win32-ia32-msvc": { - "version": "1.15.24", - "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.15.24.tgz", - "integrity": "sha512-15D/nl3XwrhFpMv+MADFOiVwv3FvH9j8c6Rf8EXBT3Q5LoMh8YnDnSgPYqw1JzPnksvsBX6QPXLiPqmcR/Z4qQ==", + "version": "1.15.30", + "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.15.30.tgz", + "integrity": "sha512-30VdLeGk6fugiUs/kUdJ/pAg7z/zpvVbR11RH60jZ0Z42WIeIniYx0rLEWN7h/pKJ3CopqsQ3RsogCAkRKiA2g==", "cpu": [ "ia32" ], @@ -675,9 +679,9 @@ } }, "node_modules/@swc/core-win32-x64-msvc": { - "version": "1.15.24", - "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.15.24.tgz", - "integrity": "sha512-PR0PlTlPra2JbaDphrOAzm6s0v9rA0F17YzB+XbWD95B4g2cWcZY9LAeTa4xll70VLw9Jr7xBrlohqlQmelMFQ==", + "version": "1.15.30", + "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.15.30.tgz", + "integrity": "sha512-4iObHPR+Q4oDY110EF5SF5eIaaVJNpMdG9C0q3Q92BsJ5y467uHz7sYQhP60WYlLFsLQ1el2YrIPUItUAQGOKg==", "cpu": [ "x64" ], @@ -855,9 +859,9 @@ "license": "ISC" }, "node_modules/postcss": { - "version": "8.5.9", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.9.tgz", - "integrity": "sha512-7a70Nsot+EMX9fFU3064K/kdHWZqGVY+BADLyXc8Dfv+mTLLVl6JzJpPaCZ2kQL9gIJvKXSLMHhqdRRjwQeFtw==", + "version": "8.5.10", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.10.tgz", + "integrity": "sha512-pMMHxBOZKFU6HgAZ4eyGnwXF/EvPGGqUr0MnZ5+99485wwW41kW91A4LOGxSHhgugZmSChL5AlElNdwlNgcnLQ==", "dev": true, "funding": [ { @@ -944,10 +948,6 @@ "node": ">=0.10.0" } }, - "node_modules/supertokens-rownd-react": { - "resolved": "../../..", - "link": true - }, "node_modules/typescript": { "version": "5.9.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", diff --git a/examples/supertokens-migration/frontend/package.json b/examples/supertokens-migration/frontend/package.json index 7d98251..92a7755 100644 --- a/examples/supertokens-migration/frontend/package.json +++ b/examples/supertokens-migration/frontend/package.json @@ -9,7 +9,7 @@ "preview": "vite preview" }, "dependencies": { - "supertokens-rownd-react": "file:../../..", + "@rownd/react": "file:../../..", "react": "^18.2.0", "react-dom": "^18.2.0" }, diff --git a/examples/supertokens-migration/frontend/src/App.tsx b/examples/supertokens-migration/frontend/src/App.tsx index 70e45db..d86b6aa 100644 --- a/examples/supertokens-migration/frontend/src/App.tsx +++ b/examples/supertokens-migration/frontend/src/App.tsx @@ -1,7 +1,8 @@ -import { useRownd } from 'supertokens-rownd-react'; +import { useRownd } from '@rownd/react'; function App() { - const { is_authenticated, access_token, user, requestSignIn, signOut } = useRownd(); + const { is_authenticated, access_token, user, requestSignIn, signOut } = + useRownd(); return (
diff --git a/examples/supertokens-migration/frontend/src/main.tsx b/examples/supertokens-migration/frontend/src/main.tsx index 56eaf3e..956d140 100644 --- a/examples/supertokens-migration/frontend/src/main.tsx +++ b/examples/supertokens-migration/frontend/src/main.tsx @@ -1,12 +1,12 @@ import React from 'react'; import ReactDOM from 'react-dom/client'; import App from './App.tsx'; -import { RowndProvider } from 'supertokens-rownd-react'; +import { RowndProvider } from '@rownd/react'; ReactDOM.createRoot(document.getElementById('root')!).render( = ({ children, @@ -36,8 +39,22 @@ export const ReactRowndProvider: React.FC = ({ ...setInitialHubState(), onAuthenticated, }); + const accessTokenRef = useRef(hubState.access_token); + const supertokensAppInfoRef = useRef( + normalizeSuperTokensAppInfo(props.supertokens?.appInfo) + ); const { user, is_authenticated, is_initializing } = hubState; + useEffect(() => { + accessTokenRef.current = hubState.access_token; + }, [hubState.access_token]); + + useEffect(() => { + supertokensAppInfoRef.current = normalizeSuperTokensAppInfo( + props.supertokens?.appInfo + ); + }, [props.supertokens]); + useEffect(() => { if (!is_authenticated || is_initializing || !user.data.user_id) { return; @@ -55,15 +72,21 @@ export const ReactRowndProvider: React.FC = ({ [hubListenerCb] ); - // Only sync new sign ups - const shouldSyncToSuperTokens = useRef(false); useEffect(() => { const handleSignInCompleted = (event: Event) => { const detail = (event as CustomEvent<{ user_type?: string }>).detail; - if (detail?.user_type === 'new_user') { - shouldSyncToSuperTokens.current = true; + if (detail?.user_type !== 'new_user') { + return; } + + const accessToken = accessTokenRef.current; + const appInfo = supertokensAppInfoRef.current; + if (!accessToken || !appInfo) { + return; + } + + syncUserToSuperTokens(accessToken, appInfo).catch(() => {}); }; hubState.events.addEventListener( @@ -79,17 +102,6 @@ export const ReactRowndProvider: React.FC = ({ }; }, [hubState.events]); - useEffect(() => { - const accessToken = hubState.access_token; - const appInfo = props.supertokens?.appInfo; - if (!accessToken || !appInfo || !shouldSyncToSuperTokens.current) { - return; - } - - shouldSyncToSuperTokens.current = false; - syncUserToSuperTokens(accessToken, appInfo).catch(() => {}); - }, [hubState.access_token, props.supertokens]); - return ( diff --git a/src/utils/supertokens-sync.ts b/src/utils/supertokens-sync.ts index 1ee7dce..bb5d042 100644 --- a/src/utils/supertokens-sync.ts +++ b/src/utils/supertokens-sync.ts @@ -1,12 +1,38 @@ +type SuperTokensAppInfo = { + appName: string; + apiDomain: string; + apiBasePath: string; +}; + +export function normalizeSuperTokensAppInfo( + appInfo?: SuperTokensAppInfo +): SuperTokensAppInfo | undefined { + if (!appInfo) { + return undefined; + } + + const apiDomain = appInfo.apiDomain.replace(/\/+$/, ''); + const trimmedBasePath = appInfo.apiBasePath.trim().replace(/^\/+|\/+$/g, ''); + + return { + ...appInfo, + apiDomain, + apiBasePath: trimmedBasePath ? `/${trimmedBasePath}` : '', + }; +} + export async function syncUserToSuperTokens( accessToken: string, - appInfo: { appName: string; apiDomain: string; apiBasePath: string } + appInfo: SuperTokensAppInfo ): Promise { - const base = `${appInfo.apiDomain}${appInfo.apiBasePath}`; + const migrateUrl = new URL( + `${appInfo.apiBasePath}/plugin/rownd/migrate`, + `${appInfo.apiDomain}/` + ); const headers = { Authorization: `Bearer ${accessToken}` }; try { - const res = await fetch(`${base}/plugin/rownd/migrate`, { + const res = await fetch(migrateUrl.toString(), { method: 'POST', headers, credentials: 'include',