From b61f2d39e572b84ee75810585efa577920fa6fec Mon Sep 17 00:00:00 2001 From: Tharun Devaraja <154892351+d3varaja@users.noreply.github.com> Date: Sat, 27 Sep 2025 01:09:41 +0530 Subject: [PATCH 1/6] Add TanStack Router integration package Initial implementation of @asgardeo/tanstack-router, providing a ProtectedRoute component for route protection with authentication checks in TanStack Router-based React applications. Includes configuration, documentation, tests, build setup, and TypeScript support. --- packages/tanstack-router/CHANGELOG.md | 7 + packages/tanstack-router/LICENSE | 201 ++++++++++++ packages/tanstack-router/README.md | 286 ++++++++++++++++++ packages/tanstack-router/esbuild.config.mjs | 53 ++++ packages/tanstack-router/package.json | 71 +++++ packages/tanstack-router/prettier.config.cjs | 19 ++ .../src/__tests__/index.test.ts | 39 +++ .../src/components/ProtectedRoute.tsx | 108 +++++++ packages/tanstack-router/src/index.ts | 20 ++ packages/tanstack-router/tsconfig.eslint.json | 4 + packages/tanstack-router/tsconfig.json | 22 ++ packages/tanstack-router/tsconfig.lib.json | 24 ++ packages/tanstack-router/tsconfig.spec.json | 19 ++ packages/tanstack-router/vitest.config.ts | 25 ++ 14 files changed, 898 insertions(+) create mode 100644 packages/tanstack-router/CHANGELOG.md create mode 100644 packages/tanstack-router/LICENSE create mode 100644 packages/tanstack-router/README.md create mode 100644 packages/tanstack-router/esbuild.config.mjs create mode 100644 packages/tanstack-router/package.json create mode 100644 packages/tanstack-router/prettier.config.cjs create mode 100644 packages/tanstack-router/src/__tests__/index.test.ts create mode 100644 packages/tanstack-router/src/components/ProtectedRoute.tsx create mode 100644 packages/tanstack-router/src/index.ts create mode 100644 packages/tanstack-router/tsconfig.eslint.json create mode 100644 packages/tanstack-router/tsconfig.json create mode 100644 packages/tanstack-router/tsconfig.lib.json create mode 100644 packages/tanstack-router/tsconfig.spec.json create mode 100644 packages/tanstack-router/vitest.config.ts diff --git a/packages/tanstack-router/CHANGELOG.md b/packages/tanstack-router/CHANGELOG.md new file mode 100644 index 00000000..ca7861b2 --- /dev/null +++ b/packages/tanstack-router/CHANGELOG.md @@ -0,0 +1,7 @@ +# @asgardeo/tanstack-router + +## 0.0.1 + +### Patch Changes + +- Initial implementation of TanStack Router integration for Asgardeo React SDK. This package provides a `ProtectedRoute` component that enables route protection with authentication checks for applications using TanStack Router. The component supports redirects, fallback rendering, and loading states. \ No newline at end of file diff --git a/packages/tanstack-router/LICENSE b/packages/tanstack-router/LICENSE new file mode 100644 index 00000000..f49a4e16 --- /dev/null +++ b/packages/tanstack-router/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/packages/tanstack-router/README.md b/packages/tanstack-router/README.md new file mode 100644 index 00000000..bb424818 --- /dev/null +++ b/packages/tanstack-router/README.md @@ -0,0 +1,286 @@ +# @asgardeo/tanstack-router + +TanStack Router integration for Asgardeo React SDK with protected routes. + +[![npm version](https://img.shields.io/npm/v/@asgardeo/tanstack-router.svg)](https://www.npmjs.com/package/@asgardeo/tanstack-router) +[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) + +## Overview + +`@asgardeo/tanstack-router` is a supplementary package that provides seamless integration between Asgardeo authentication and TanStack Router. It offers components to easily protect routes and handle authentication flows in your React applications using TanStack Router. + +## Features + +- 🛡️ **ProtectedRoute Component**: Drop-in component for TanStack Router with built-in authentication +- ⚡ **TypeScript Support**: Full TypeScript support with comprehensive type definitions +- 🎨 **Customizable**: Flexible configuration options for different use cases +- 🔒 **Authentication Guards**: Built-in authentication checking with loading states +- 🚀 **Lightweight**: Minimal bundle size with essential features only +- 🔄 **API Consistency**: Compatible interface with `@asgardeo/react-router` for easy migration + +## Installation + +```bash +npm install @asgardeo/tanstack-router +# or +yarn add @asgardeo/tanstack-router +# or +pnpm add @asgardeo/tanstack-router +``` + +### Peer Dependencies + +This package requires the following peer dependencies: + +```bash +npm install @asgardeo/react @tanstack/react-router react +``` + +## Quick Start + +### 1. Basic Setup with ProtectedRoute + +```tsx +import React from 'react'; +import { createRouter, createRoute, createRootRoute } from '@tanstack/react-router'; +import { AsgardeoProvider } from '@asgardeo/react'; +import { ProtectedRoute } from '@asgardeo/tanstack-router'; +import Dashboard from './components/Dashboard'; +import Profile from './components/Profile'; +import SignIn from './components/SignIn'; + +const rootRoute = createRootRoute({ + component: () =>
Root Layout
, +}); + +const indexRoute = createRoute({ + getParentRoute: () => rootRoute, + path: '/', + component: () =>
Public Home Page
, +}); + +const signinRoute = createRoute({ + getParentRoute: () => rootRoute, + path: '/signin', + component: SignIn, +}); + +const dashboardRoute = createRoute({ + getParentRoute: () => rootRoute, + path: '/dashboard', + component: () => ( + + + + ), +}); + +const profileRoute = createRoute({ + getParentRoute: () => rootRoute, + path: '/profile', + component: () => ( + + + + ), +}); + +const routeTree = rootRoute.addChildren([ + indexRoute, + signinRoute, + dashboardRoute, + profileRoute, +]); + +const router = createRouter({ routeTree }); + +function App() { + return ( + + + + ); +} + +export default App; +``` + +### 2. Custom Fallback and Loading States + +```tsx +import { ProtectedRoute } from '@asgardeo/tanstack-router'; + +// Redirect to custom login page +const dashboardRoute = createRoute({ + getParentRoute: () => rootRoute, + path: '/dashboard', + component: () => ( + + + + ), +}); + +// Custom fallback component +const dashboardRoute = createRoute({ + getParentRoute: () => rootRoute, + path: '/dashboard', + component: () => ( + +

Please sign in

+

You need to be signed in to access this page.

+ + }> + +
+ ), +}); + +// Custom loading state +const dashboardRoute = createRoute({ + getParentRoute: () => rootRoute, + path: '/dashboard', + component: () => ( + Loading...} + > + + + ), +}); +``` + +### 3. Integration with Route Layouts + +```tsx +import { ProtectedRoute } from '@asgardeo/tanstack-router'; + +const appLayoutRoute = createRoute({ + getParentRoute: () => rootRoute, + path: '/app', + component: AppLayout, +}); + +const appDashboardRoute = createRoute({ + getParentRoute: () => appLayoutRoute, + path: '/dashboard', + component: () => ( + + + + ), +}); + +const appProfileRoute = createRoute({ + getParentRoute: () => appLayoutRoute, + path: '/profile', + component: () => ( + + + + ), +}); + +const appSettingsRoute = createRoute({ + getParentRoute: () => appLayoutRoute, + path: '/settings', + component: () => ( + + + + ), +}); +``` + +## API Reference + +### Components + +#### ProtectedRoute + +A component that protects routes based on authentication status. Should be used as the component prop of a TanStack Router route. + +```tsx +interface ProtectedRouteProps { + children: React.ReactElement; + fallback?: React.ReactElement; + redirectTo?: string; + loader?: React.ReactNode; +} +``` + +**Props:** + +- `children` - The component to render when authenticated +- `fallback` - Custom component to render when not authenticated (takes precedence over redirectTo) +- `redirectTo` - URL to redirect to when not authenticated (required unless fallback is provided) +- `loader` - Custom loading component to render while authentication status is being determined + +**Note:** Either `fallback` or `redirectTo` must be provided to handle unauthenticated users. + +## Migration from @asgardeo/react-router + +This package provides the same API as `@asgardeo/react-router`, making migration straightforward: + +```tsx +// Before (React Router) + + + + } +/> + +// After (TanStack Router) +const dashboardRoute = createRoute({ + getParentRoute: () => rootRoute, + path: '/dashboard', + component: () => ( + + + + ), +}); +``` + +## Examples + +Check out our sample applications in the repository: + +- [React Sample](../../samples/asgardeo-react) - Complete React application with Asgardeo authentication +- [Next.js Sample](../../samples/asgardeo-nextjs) - Next.js application example +- [Teamspace React](../../samples/teamspace-react) - Team collaboration app with React +- [Teamspace Next.js](../../samples/teamspace-nextjs) - Team collaboration app with Next.js + +## TypeScript Support + +This package is written in TypeScript and provides comprehensive type definitions. All components are fully typed for the best development experience. + +```tsx +import type { ProtectedRouteProps } from '@asgardeo/tanstack-router'; +``` + +## Contributing + +We welcome contributions! Please see our [Contributing Guide](../../CONTRIBUTING.md) for details. + +## License + +This project is licensed under the Apache License 2.0. See the [LICENSE](LICENSE) file for details. + +## Support + +- 📖 [Documentation](https://wso2.com/asgardeo/docs/sdks/react/) +- 💬 [Community Forum](https://stackoverflow.com/questions/tagged/asgardeo) +- 🐛 [Issues](https://github.com/asgardeo/javascript/issues) + +--- + +Built with ❤️ by the [Asgardeo](https://wso2.com/asgardeo/) team. \ No newline at end of file diff --git a/packages/tanstack-router/esbuild.config.mjs b/packages/tanstack-router/esbuild.config.mjs new file mode 100644 index 00000000..6fe710ae --- /dev/null +++ b/packages/tanstack-router/esbuild.config.mjs @@ -0,0 +1,53 @@ +/** + * Copyright (c) 2025, WSO2 LLC. (https://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import {readFileSync} from 'fs'; +import {build} from 'esbuild'; +import {preserveDirectivesPlugin} from 'esbuild-plugin-preserve-directives'; + +const pkg = JSON.parse(readFileSync('./package.json', 'utf8')); + +const commonOptions = { + bundle: true, + entryPoints: ['src/index.ts'], + external: [...Object.keys(pkg.dependencies || {}), ...Object.keys(pkg.peerDependencies || {})], + metafile: true, + platform: 'browser', + plugins: [ + preserveDirectivesPlugin({ + directives: ['use client', 'use strict'], + include: /\.(js|ts|jsx|tsx)$/, + exclude: /node_modules/, + }), + ], + target: ['es2020'], +}; + +await build({ + ...commonOptions, + format: 'esm', + outfile: 'dist/index.js', + sourcemap: true, +}); + +await build({ + ...commonOptions, + format: 'cjs', + outfile: 'dist/cjs/index.js', + sourcemap: true, +}); \ No newline at end of file diff --git a/packages/tanstack-router/package.json b/packages/tanstack-router/package.json new file mode 100644 index 00000000..61c6293e --- /dev/null +++ b/packages/tanstack-router/package.json @@ -0,0 +1,71 @@ +{ + "name": "@asgardeo/tanstack-router", + "version": "0.0.1", + "description": "TanStack Router integration for Asgardeo React SDK with protected routes.", + "keywords": [ + "asgardeo", + "react", + "tanstack-router", + "protected-routes", + "authentication" + ], + "homepage": "https://github.com/asgardeo/javascript/tree/main/packages/tanstack-router#readme", + "bugs": { + "url": "https://github.com/asgardeo/javascript/issues" + }, + "author": "WSO2", + "license": "Apache-2.0", + "type": "module", + "main": "dist/cjs/index.js", + "module": "dist/index.js", + "exports": { + "import": "./dist/index.js", + "require": "./dist/cjs/index.js" + }, + "files": [ + "dist", + "README.md", + "LICENSE" + ], + "types": "dist/index.d.ts", + "repository": { + "type": "git", + "url": "https://github.com/asgardeo/javascript", + "directory": "packages/tanstack-router" + }, + "scripts": { + "build": "pnpm clean && node esbuild.config.mjs && tsc -p tsconfig.lib.json --emitDeclarationOnly --outDir dist", + "clean": "rimraf dist", + "fix:lint": "eslint . --ext .js,.jsx,.ts,.tsx,.cjs,.mjs", + "lint": "eslint . --ext .js,.jsx,.ts,.tsx,.cjs,.mjs", + "test": "vitest", + "test:browser": "vitest --workspace=vitest.workspace.ts", + "typecheck": "tsc -p tsconfig.lib.json" + }, + "devDependencies": { + "@types/node": "^22.15.3", + "@types/react": "^19.1.4", + "@wso2/eslint-plugin": "catalog:", + "@wso2/prettier-config": "catalog:", + "esbuild-plugin-preserve-directives": "^0.0.11", + "esbuild": "^0.25.9", + "eslint": "8.57.0", + "prettier": "^2.6.2", + "react": "^19.1.0", + "@tanstack/react-router": "^1.132.6", + "rimraf": "^6.0.1", + "typescript": "~5.7.2", + "vitest": "^3.1.3" + }, + "peerDependencies": { + "@asgardeo/react": "workspace:^", + "react": ">=16.8.0", + "@tanstack/react-router": ">=1.132.0" + }, + "dependencies": { + "tslib": "^2.8.1" + }, + "publishConfig": { + "access": "public" + } +} \ No newline at end of file diff --git a/packages/tanstack-router/prettier.config.cjs b/packages/tanstack-router/prettier.config.cjs new file mode 100644 index 00000000..0f93eb3d --- /dev/null +++ b/packages/tanstack-router/prettier.config.cjs @@ -0,0 +1,19 @@ +/** + * Copyright (c) 2025, WSO2 LLC. (https://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +module.exports = require('@wso2/prettier-config'); \ No newline at end of file diff --git a/packages/tanstack-router/src/__tests__/index.test.ts b/packages/tanstack-router/src/__tests__/index.test.ts new file mode 100644 index 00000000..fa15644a --- /dev/null +++ b/packages/tanstack-router/src/__tests__/index.test.ts @@ -0,0 +1,39 @@ +/** + * Copyright (c) 2025, WSO2 LLC. (https://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { describe, it, expect } from 'vitest'; + +describe('@asgardeo/tanstack-router', () => { + it('should export ProtectedRoute', async () => { + const { ProtectedRoute } = await import('../index'); + expect(ProtectedRoute).toBeDefined(); + }); + + it('should export ProtectedRouteProps interface', async () => { + const exports = await import('../index'); + // Interface check - should not throw + const _: typeof exports.ProtectedRouteProps = undefined as any; + expect(true).toBe(true); + }); + + it('should have the correct named exports', async () => { + const exports = await import('../index'); + const exportNames = Object.keys(exports); + expect(exportNames).toContain('ProtectedRoute'); + }); +}); \ No newline at end of file diff --git a/packages/tanstack-router/src/components/ProtectedRoute.tsx b/packages/tanstack-router/src/components/ProtectedRoute.tsx new file mode 100644 index 00000000..7a58f2bc --- /dev/null +++ b/packages/tanstack-router/src/components/ProtectedRoute.tsx @@ -0,0 +1,108 @@ +/** + * Copyright (c) 2025, WSO2 LLC. (https://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { FC, ReactElement, ReactNode } from 'react'; +import { Navigate } from '@tanstack/react-router'; +import { useAsgardeo, AsgardeoRuntimeError } from '@asgardeo/react'; + +/** + * Props for the ProtectedRoute component. + */ +export interface ProtectedRouteProps { + /** + * The element to render when the user is authenticated. + */ + children: ReactElement; + /** + * Custom fallback element to render when the user is not authenticated. + * If provided, this takes precedence over redirectTo. + */ + fallback?: ReactElement; + /** + * URL to redirect to when the user is not authenticated. + * Required unless a fallback element is provided. + */ + redirectTo?: string; + /** + * Custom loading element to render while authentication status is being determined. + */ + loader?: ReactNode; +} + +/** + * A protected route component that requires authentication to access. + * + * This component should be used as the component prop of a TanStack Router route. + * It checks authentication status and either renders the protected content, + * shows a loading state, redirects, or shows a fallback. + * + * Either a `redirectTo` prop or a `fallback` prop must be provided to handle + * unauthenticated users. + * + * @example Basic usage with redirect + * ```tsx + * const dashboardRoute = createRouteConfig({ + * path: '/dashboard', + * component: () => ( + * + * + * + * ) + * }) + * ``` + * + * @example With custom fallback + * ```tsx + * const adminRoute = createRouteConfig({ + * path: '/admin', + * component: () => ( + * Access denied}> + * + * + * ) + * }) + * ``` + */ +const ProtectedRoute: FC = ({ children, fallback, redirectTo, loader = null }) => { + const { isSignedIn, isLoading } = useAsgardeo(); + + if (isLoading) { + return loader; + } + + if (isSignedIn) { + return children; + } + + if (fallback) { + return fallback; + } + + if (redirectTo) { + return ; + } + + throw new AsgardeoRuntimeError( + '"fallback" or "redirectTo" prop is required.', + 'ProtectedRoute-ValidationError-001', + 'tanstack-router', + 'Either "fallback" or "redirectTo" prop must be provided to handle unauthenticated users.', + ); +}; + +export default ProtectedRoute; \ No newline at end of file diff --git a/packages/tanstack-router/src/index.ts b/packages/tanstack-router/src/index.ts new file mode 100644 index 00000000..a9b87e3c --- /dev/null +++ b/packages/tanstack-router/src/index.ts @@ -0,0 +1,20 @@ +/** + * Copyright (c) 2025, WSO2 LLC. (https://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +export { default as ProtectedRoute } from './components/ProtectedRoute'; +export * from './components/ProtectedRoute'; \ No newline at end of file diff --git a/packages/tanstack-router/tsconfig.eslint.json b/packages/tanstack-router/tsconfig.eslint.json new file mode 100644 index 00000000..36f6e575 --- /dev/null +++ b/packages/tanstack-router/tsconfig.eslint.json @@ -0,0 +1,4 @@ +{ + "extends": "./tsconfig.json", + "include": ["**/.*.js", "**/.*.cjs", "**/.*.ts", "**/*.js", "**/*.cjs", "**/*.ts"] +} \ No newline at end of file diff --git a/packages/tanstack-router/tsconfig.json b/packages/tanstack-router/tsconfig.json new file mode 100644 index 00000000..e927e2f4 --- /dev/null +++ b/packages/tanstack-router/tsconfig.json @@ -0,0 +1,22 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "lib": ["dom", "dom.iterable", "es6"], + "allowJs": true, + "skipLibCheck": true, + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, + "strict": true, + "forceConsistentCasingInFileNames": true, + "noFallthroughCasesInSwitch": true, + "module": "esnext", + "moduleResolution": "node", + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "jsx": "react-jsx" + }, + "include": [ + "src" + ] +} \ No newline at end of file diff --git a/packages/tanstack-router/tsconfig.lib.json b/packages/tanstack-router/tsconfig.lib.json new file mode 100644 index 00000000..cb34fb79 --- /dev/null +++ b/packages/tanstack-router/tsconfig.lib.json @@ -0,0 +1,24 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "declaration": true, + "outDir": "dist", + "declarationDir": "dist", + "types": ["node"], + "skipLibCheck": true, + "declarationMap": true + }, + "exclude": [ + "**/*.spec.ts", + "**/*.test.ts", + "**/*.spec.tsx", + "**/*.test.tsx", + "**/*.spec.js", + "**/*.test.js", + "**/*.spec.jsx", + "**/*.test.jsx", + "node_modules", + "dist" + ], + "include": ["src/**/*.ts", "src/**/*.tsx"] +} \ No newline at end of file diff --git a/packages/tanstack-router/tsconfig.spec.json b/packages/tanstack-router/tsconfig.spec.json new file mode 100644 index 00000000..9fab35c4 --- /dev/null +++ b/packages/tanstack-router/tsconfig.spec.json @@ -0,0 +1,19 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc", + "types": ["vitest/globals", "vitest/importMeta", "vite/client", "node"] + }, + "include": [ + "vite.config.ts", + "src/**/*.test.ts", + "src/**/*.spec.ts", + "src/**/*.test.tsx", + "src/**/*.spec.tsx", + "src/**/*.test.js", + "src/**/*.spec.js", + "src/**/*.test.jsx", + "src/**/*.spec.jsx", + "src/**/*.d.ts" + ] +} \ No newline at end of file diff --git a/packages/tanstack-router/vitest.config.ts b/packages/tanstack-router/vitest.config.ts new file mode 100644 index 00000000..1644bfd5 --- /dev/null +++ b/packages/tanstack-router/vitest.config.ts @@ -0,0 +1,25 @@ +/** + * Copyright (c) 2025, WSO2 LLC. (https://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import {defineConfig} from 'vitest/config'; + +export default defineConfig({ + test: { + environment: 'jsdom', + }, +}); \ No newline at end of file From e15f3cc35e15e9220db07257b39e8a0a740d0f3a Mon Sep 17 00:00:00 2001 From: Tharun Devaraja <154892351+d3varaja@users.noreply.github.com> Date: Wed, 1 Oct 2025 13:24:15 +0530 Subject: [PATCH 2/6] Update packages/tanstack-router/package.json Co-authored-by: Brion Mario --- packages/tanstack-router/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/tanstack-router/package.json b/packages/tanstack-router/package.json index 61c6293e..c7cc0f48 100644 --- a/packages/tanstack-router/package.json +++ b/packages/tanstack-router/package.json @@ -1,6 +1,6 @@ { "name": "@asgardeo/tanstack-router", - "version": "0.0.1", + "version": "0.0.0", "description": "TanStack Router integration for Asgardeo React SDK with protected routes.", "keywords": [ "asgardeo", From 99096022f6894afcd02ad1d47e33570642aa2ec1 Mon Sep 17 00:00:00 2001 From: Tharun Devaraja <154892351+d3varaja@users.noreply.github.com> Date: Wed, 1 Oct 2025 13:34:16 +0530 Subject: [PATCH 3/6] Add tests for ProtectedRoute component Introduces a comprehensive test suite for the ProtectedRoute component, covering scenarios for authentication, loading state, fallback and redirect behavior, and error handling. This improves test coverage and ensures correct behavior under various conditions. --- packages/tanstack-router/esbuild.config.mjs | 2 +- .../__tests__/ProtectedRoute.test.tsx | 169 ++++++++++++++++++ 2 files changed, 170 insertions(+), 1 deletion(-) create mode 100644 packages/tanstack-router/src/components/__tests__/ProtectedRoute.test.tsx diff --git a/packages/tanstack-router/esbuild.config.mjs b/packages/tanstack-router/esbuild.config.mjs index 6fe710ae..efecbbeb 100644 --- a/packages/tanstack-router/esbuild.config.mjs +++ b/packages/tanstack-router/esbuild.config.mjs @@ -50,4 +50,4 @@ await build({ format: 'cjs', outfile: 'dist/cjs/index.js', sourcemap: true, -}); \ No newline at end of file +}); diff --git a/packages/tanstack-router/src/components/__tests__/ProtectedRoute.test.tsx b/packages/tanstack-router/src/components/__tests__/ProtectedRoute.test.tsx new file mode 100644 index 00000000..74f2c7eb --- /dev/null +++ b/packages/tanstack-router/src/components/__tests__/ProtectedRoute.test.tsx @@ -0,0 +1,169 @@ +/** + * Copyright (c) 2025, WSO2 LLC. (https://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { describe, it, expect, vi, beforeEach } from 'vitest'; +import { render, screen } from '@testing-library/react'; +import ProtectedRoute from '../ProtectedRoute'; +import { useAsgardeo } from '@asgardeo/react'; + +// Mock the dependencies +vi.mock('@asgardeo/react', () => ({ + useAsgardeo: vi.fn(), + AsgardeoRuntimeError: class AsgardeoRuntimeError extends Error { + code: string; + component: string; + traceId: string | undefined; + + constructor(message: string, code: string, component: string, traceId?: string) { + super(message); + this.name = 'AsgardeoRuntimeError'; + this.code = code; + this.component = component; + this.traceId = traceId; + } + }, +})); + +vi.mock('@tanstack/react-router', () => ({ + Navigate: ({ to }: { to: string }) =>
Navigate to: {to}
, +})); + +describe('ProtectedRoute', () => { + beforeEach(() => { + vi.clearAllMocks(); + }); + + it('should render loader when isLoading is true', () => { + vi.mocked(useAsgardeo).mockReturnValue({ + isSignedIn: false, + isLoading: true, + } as any); + + render( + Loading...}> +
Protected Content
+
+ ); + + expect(screen.getByTestId('loader')).toBeDefined(); + expect(screen.queryByTestId('protected-content')).toBeNull(); + }); + + it('should render children when user is authenticated', () => { + vi.mocked(useAsgardeo).mockReturnValue({ + isSignedIn: true, + isLoading: false, + } as any); + + render( + +
Protected Content
+
+ ); + + expect(screen.getByTestId('protected-content')).toBeDefined(); + }); + + it('should render fallback when user is not authenticated and fallback is provided', () => { + vi.mocked(useAsgardeo).mockReturnValue({ + isSignedIn: false, + isLoading: false, + } as any); + + render( + Access Denied} + > +
Protected Content
+
+ ); + + expect(screen.getByTestId('fallback')).toBeDefined(); + expect(screen.queryByTestId('protected-content')).toBeNull(); + }); + + it('should navigate to redirectTo when user is not authenticated and no fallback is provided', () => { + vi.mocked(useAsgardeo).mockReturnValue({ + isSignedIn: false, + isLoading: false, + } as any); + + render( + +
Protected Content
+
+ ); + + const navigate = screen.getByTestId('navigate'); + expect(navigate).toBeDefined(); + expect(navigate.textContent).toBe('Navigate to: /signin'); + expect(screen.queryByTestId('protected-content')).toBeNull(); + }); + + it('should throw error when neither fallback nor redirectTo is provided', () => { + vi.mocked(useAsgardeo).mockReturnValue({ + isSignedIn: false, + isLoading: false, + } as any); + + expect(() => { + render( + +
Protected Content
+
+ ); + }).toThrow('"fallback" or "redirectTo" prop is required.'); + }); + + it('should render null loader by default when isLoading is true and no loader is provided', () => { + vi.mocked(useAsgardeo).mockReturnValue({ + isSignedIn: false, + isLoading: true, + } as any); + + const { container } = render( + +
Protected Content
+
+ ); + + expect(container.textContent).toBe(''); + expect(screen.queryByTestId('protected-content')).toBeNull(); + }); + + it('should prioritize fallback over redirectTo when both are provided', () => { + vi.mocked(useAsgardeo).mockReturnValue({ + isSignedIn: false, + isLoading: false, + } as any); + + render( + Custom Fallback} + > +
Protected Content
+
+ ); + + expect(screen.getByTestId('fallback')).toBeDefined(); + expect(screen.queryByTestId('navigate')).toBeNull(); + expect(screen.queryByTestId('protected-content')).toBeNull(); + }); +}); From 3aa740d9413dcc23d2cd60c8f70b5e4819d477f7 Mon Sep 17 00:00:00 2001 From: Tharun Devaraja <154892351+d3varaja@users.noreply.github.com> Date: Wed, 1 Oct 2025 14:36:10 +0530 Subject: [PATCH 4/6] Add React TanStack Router sample app Introduced a new sample application under samples/react-tanstack-router demonstrating integration of Asgardeo authentication with TanStack Router in a React app. Updated the TanStack Router package README to reference the new sample. Added related configuration, source files, and dependencies. --- packages/tanstack-router/README.md | 5 +- .../__tests__/ProtectedRoute.test.tsx | 9 +- pnpm-lock.yaml | 329 +++++++++++++----- samples/react-tanstack-router/README.md | 149 ++++++++ .../react-tanstack-router/eslint.config.js | 28 ++ samples/react-tanstack-router/index.html | 13 + samples/react-tanstack-router/package.json | 32 ++ samples/react-tanstack-router/public/vite.svg | 1 + samples/react-tanstack-router/src/index.css | 219 ++++++++++++ samples/react-tanstack-router/src/main.tsx | 49 +++ .../src/pages/Dashboard.tsx | 88 +++++ .../react-tanstack-router/src/pages/Home.tsx | 83 +++++ .../react-tanstack-router/src/vite-env.d.ts | 1 + .../react-tanstack-router/tsconfig.app.json | 27 ++ samples/react-tanstack-router/tsconfig.json | 5 + .../react-tanstack-router/tsconfig.node.json | 25 ++ samples/react-tanstack-router/vite.config.ts | 8 + 17 files changed, 967 insertions(+), 104 deletions(-) create mode 100644 samples/react-tanstack-router/README.md create mode 100644 samples/react-tanstack-router/eslint.config.js create mode 100644 samples/react-tanstack-router/index.html create mode 100644 samples/react-tanstack-router/package.json create mode 100644 samples/react-tanstack-router/public/vite.svg create mode 100644 samples/react-tanstack-router/src/index.css create mode 100644 samples/react-tanstack-router/src/main.tsx create mode 100644 samples/react-tanstack-router/src/pages/Dashboard.tsx create mode 100644 samples/react-tanstack-router/src/pages/Home.tsx create mode 100644 samples/react-tanstack-router/src/vite-env.d.ts create mode 100644 samples/react-tanstack-router/tsconfig.app.json create mode 100644 samples/react-tanstack-router/tsconfig.json create mode 100644 samples/react-tanstack-router/tsconfig.node.json create mode 100644 samples/react-tanstack-router/vite.config.ts diff --git a/packages/tanstack-router/README.md b/packages/tanstack-router/README.md index bb424818..434eb38d 100644 --- a/packages/tanstack-router/README.md +++ b/packages/tanstack-router/README.md @@ -254,10 +254,7 @@ const dashboardRoute = createRoute({ Check out our sample applications in the repository: -- [React Sample](../../samples/asgardeo-react) - Complete React application with Asgardeo authentication -- [Next.js Sample](../../samples/asgardeo-nextjs) - Next.js application example -- [Teamspace React](../../samples/teamspace-react) - Team collaboration app with React -- [Teamspace Next.js](../../samples/teamspace-nextjs) - Team collaboration app with Next.js +- [React TanStack Router Sample](../../samples/react-tanstack-router) - Simple React application demonstrating TanStack Router integration with protected routes ## TypeScript Support diff --git a/packages/tanstack-router/src/components/__tests__/ProtectedRoute.test.tsx b/packages/tanstack-router/src/components/__tests__/ProtectedRoute.test.tsx index 74f2c7eb..a0e485c5 100644 --- a/packages/tanstack-router/src/components/__tests__/ProtectedRoute.test.tsx +++ b/packages/tanstack-router/src/components/__tests__/ProtectedRoute.test.tsx @@ -16,12 +16,11 @@ * under the License. */ -import { describe, it, expect, vi, beforeEach } from 'vitest'; -import { render, screen } from '@testing-library/react'; +import {describe, it, expect, vi, beforeEach} from 'vitest'; +import {render, screen} from '@testing-library/react'; import ProtectedRoute from '../ProtectedRoute'; -import { useAsgardeo } from '@asgardeo/react'; +import {useAsgardeo} from '@asgardeo/react'; -// Mock the dependencies vi.mock('@asgardeo/react', () => ({ useAsgardeo: vi.fn(), AsgardeoRuntimeError: class AsgardeoRuntimeError extends Error { @@ -40,7 +39,7 @@ vi.mock('@asgardeo/react', () => ({ })); vi.mock('@tanstack/react-router', () => ({ - Navigate: ({ to }: { to: string }) =>
Navigate to: {to}
, + Navigate: ({to}: {to: string}) =>
Navigate to: {to}
, })); describe('ProtectedRoute', () => { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a741c5af..f511018b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -170,45 +170,8 @@ importers: specifier: ^3.1.3 version: 3.1.3(@types/node@22.15.30)(@vitest/browser@3.1.3)(jiti@2.6.0)(jsdom@26.1.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(terser@5.39.2)(yaml@2.8.0) - packages/i18n: - dependencies: - tslib: - specifier: ^2.8.1 - version: 2.8.1 - devDependencies: - '@types/node': - specifier: ^22.15.30 - version: 22.15.30 - '@wso2/eslint-plugin': - specifier: 'catalog:' - version: https://gitpkg.now.sh/brionmario/wso2-ui-configs/packages/eslint-plugin?a1fc6eb570653c999828aea9f5027cba06af4391(eslint@8.57.0)(typescript@5.7.3) - '@wso2/prettier-config': - specifier: 'catalog:' - version: https://gitpkg.now.sh/brionmario/wso2-ui-configs/packages/prettier-config?a1fc6eb570653c999828aea9f5027cba06af4391(prettier@2.8.8)(typescript@5.7.3) - esbuild: - specifier: ^0.25.9 - version: 0.25.10 - eslint: - specifier: 8.57.0 - version: 8.57.0 - prettier: - specifier: ^2.6.2 - version: 2.8.8 - rimraf: - specifier: ^6.0.1 - version: 6.0.1 - typescript: - specifier: ~5.7.2 - version: 5.7.3 - vitest: - specifier: ^3.1.3 - version: 3.1.3(@types/node@22.15.30)(@vitest/browser@3.1.3)(jiti@2.6.0)(jsdom@26.1.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(terser@5.39.2)(yaml@2.8.0) - packages/javascript: dependencies: - '@asgardeo/i18n': - specifier: workspace:^ - version: link:../i18n tslib: specifier: ^2.8.1 version: 2.8.1 @@ -359,9 +322,6 @@ importers: '@asgardeo/browser': specifier: workspace:^ version: link:../browser - '@asgardeo/i18n': - specifier: workspace:^ - version: link:../i18n '@emotion/css': specifier: ^11.13.5 version: 11.13.5 @@ -476,6 +436,55 @@ importers: specifier: ^3.1.3 version: 3.1.3(@types/node@22.15.30)(@vitest/browser@3.1.3)(jiti@2.6.0)(jsdom@26.1.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(terser@5.39.2)(yaml@2.8.0) + packages/tanstack-router: + dependencies: + '@asgardeo/react': + specifier: workspace:^ + version: link:../react + tslib: + specifier: ^2.8.1 + version: 2.8.1 + devDependencies: + '@tanstack/react-router': + specifier: ^1.132.6 + version: 1.132.27(react-dom@19.1.1(react@19.1.0))(react@19.1.0) + '@types/node': + specifier: ^22.15.3 + version: 22.15.30 + '@types/react': + specifier: ^19.1.4 + version: 19.1.5 + '@wso2/eslint-plugin': + specifier: 'catalog:' + version: https://gitpkg.now.sh/brionmario/wso2-ui-configs/packages/eslint-plugin?a1fc6eb570653c999828aea9f5027cba06af4391(eslint@8.57.0)(typescript@5.7.3) + '@wso2/prettier-config': + specifier: 'catalog:' + version: https://gitpkg.now.sh/brionmario/wso2-ui-configs/packages/prettier-config?a1fc6eb570653c999828aea9f5027cba06af4391(prettier@2.8.8)(typescript@5.7.3) + esbuild: + specifier: ^0.25.9 + version: 0.25.10 + esbuild-plugin-preserve-directives: + specifier: ^0.0.11 + version: 0.0.11(esbuild@0.25.10) + eslint: + specifier: 8.57.0 + version: 8.57.0 + prettier: + specifier: ^2.6.2 + version: 2.8.8 + react: + specifier: ^19.1.0 + version: 19.1.0 + rimraf: + specifier: ^6.0.1 + version: 6.0.1 + typescript: + specifier: ~5.7.2 + version: 5.7.3 + vitest: + specifier: ^3.1.3 + version: 3.1.3(@types/node@22.15.30)(@vitest/browser@3.1.3)(jiti@2.6.0)(jsdom@26.1.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(terser@5.39.2)(yaml@2.8.0) + packages/vue: dependencies: '@asgardeo/auth-spa': @@ -585,11 +594,60 @@ importers: specifier: ^2.2.2 version: 2.2.10(typescript@5.1.6) - samples/teamspace-react: + samples/react-tanstack-router: dependencies: - '@asgardeo/i18n': + '@asgardeo/react': + specifier: workspace:^ + version: link:../../packages/react + '@asgardeo/tanstack-router': specifier: workspace:^ - version: link:../../packages/i18n + version: link:../../packages/tanstack-router + '@tanstack/react-router': + specifier: ^1.132.6 + version: 1.132.27(react-dom@19.1.1(react@19.1.0))(react@19.1.0) + react: + specifier: ^19.1.0 + version: 19.1.0 + react-dom: + specifier: ^19.1.0 + version: 19.1.1(react@19.1.0) + devDependencies: + '@types/react': + specifier: ^19.1.2 + version: 19.1.5 + '@types/react-dom': + specifier: ^19.1.2 + version: 19.1.5(@types/react@19.1.5) + '@vitejs/plugin-basic-ssl': + specifier: ^2.0.0 + version: 2.0.0(vite@6.3.5(@types/node@24.0.3)(jiti@2.6.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(terser@5.39.2)(yaml@2.8.0)) + '@vitejs/plugin-react': + specifier: ^4.4.1 + version: 4.5.1(vite@6.3.5(@types/node@24.0.3)(jiti@2.6.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(terser@5.39.2)(yaml@2.8.0)) + eslint: + specifier: ^9.25.0 + version: 9.28.0(jiti@2.6.0) + eslint-plugin-react-hooks: + specifier: ^5.2.0 + version: 5.2.0(eslint@9.28.0(jiti@2.6.0)) + eslint-plugin-react-refresh: + specifier: ^0.4.19 + version: 0.4.20(eslint@9.28.0(jiti@2.6.0)) + globals: + specifier: ^16.0.0 + version: 16.1.0 + typescript: + specifier: ~5.8.3 + version: 5.8.3 + typescript-eslint: + specifier: ^8.30.1 + version: 8.33.1(eslint@9.28.0(jiti@2.6.0))(typescript@5.8.3) + vite: + specifier: ^6.3.5 + version: 6.3.5(@types/node@24.0.3)(jiti@2.6.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(terser@5.39.2)(yaml@2.8.0) + + samples/teamspace-react: + dependencies: '@asgardeo/react': specifier: workspace:^ version: link:../../packages/react @@ -2180,6 +2238,30 @@ packages: peerDependencies: vite: ^5.2.0 || ^6 + '@tanstack/history@1.132.21': + resolution: {integrity: sha512-5ziPz3YarKU5cBJoEJ4muV8cy+5W4oWdJMqW7qosMrK5fb9Qfm+QWX+kO3emKJMu4YOUofVu3toEuuD3x1zXKw==} + engines: {node: '>=12'} + + '@tanstack/react-router@1.132.27': + resolution: {integrity: sha512-fxSm1kxrtl3dQslqqKgYnIbQf7qW4fyWXKQhZYCWBFHO2GT11DWPZTNkTXw5YifOpw2RTmYJBH3C44t1HF95Cw==} + engines: {node: '>=12'} + peerDependencies: + react: '>=18.0.0 || >=19.0.0' + react-dom: '>=18.0.0 || >=19.0.0' + + '@tanstack/react-store@0.7.7': + resolution: {integrity: sha512-qqT0ufegFRDGSof9D/VqaZgjNgp4tRPHZIJq2+QIHkMUtHjaJ0lYrrXjeIUJvjnTbgPfSD1XgOMEt0lmANn6Zg==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + + '@tanstack/router-core@1.132.27': + resolution: {integrity: sha512-mNx+nba7mXc7sJdX+kYH4rSW8f7Jx/+0hPOkX4XAnqiq7I1ng3gGqmGuf4+2BYTG2aD+aTSPExUPczy9VNgRfQ==} + engines: {node: '>=12'} + + '@tanstack/store@0.7.7': + resolution: {integrity: sha512-xa6pTan1bcaqYDS9BDpSiS63qa6EoDkPN9RsRaxHuDdVDNntzq3xNwR5YKTU/V3SkSyC9T4YVOPh2zRQN0nhIQ==} + '@testing-library/dom@10.4.0': resolution: {integrity: sha512-pemlzrSESWbdAloYml3bAJMEfNh1Z7EduzqPKprCH5S341frlpYnUEW0H72dLxa6IsYr+mPno20GiSm+h9dEdQ==} engines: {node: '>=18'} @@ -3062,6 +3144,9 @@ packages: convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + cookie-es@2.0.0: + resolution: {integrity: sha512-RAj4E421UYRgqokKUmotqAwuplYw15qtdXfY+hGzgCJ/MBjCVZcSoHK/kH9kocfjRjcDME7IiDWR/1WX1TM2Pg==} + cookie-signature@1.2.2: resolution: {integrity: sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==} engines: {node: '>=6.6.0'} @@ -3663,10 +3748,6 @@ packages: resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - eslint-scope@8.3.0: - resolution: {integrity: sha512-pUNxi75F8MJ/GdeKtVLSbYg4ZI34J6C0C7sbL4YOp2exGwen7ZsuBqKzUhXd0qMQ362yET3z+uPwKeg/0C2XCQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - eslint-scope@8.4.0: resolution: {integrity: sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -3693,10 +3774,6 @@ packages: resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - eslint-visitor-keys@4.2.0: - resolution: {integrity: sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - eslint-visitor-keys@4.2.1: resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -3717,10 +3794,6 @@ packages: jiti: optional: true - espree@10.3.0: - resolution: {integrity: sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - espree@10.4.0: resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -4368,6 +4441,10 @@ packages: isarray@2.0.5: resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} + isbot@5.1.31: + resolution: {integrity: sha512-DPgQshehErHAqSCKDb3rNW03pa2wS/v5evvUqtxt6TTnHRqAG8FdzcSSJs9656pK6Y+NT7K9R4acEYXLHYfpUQ==} + engines: {node: '>=18'} + isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} @@ -5801,6 +5878,16 @@ packages: resolution: {integrity: sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==} engines: {node: '>= 18'} + seroval-plugins@1.3.3: + resolution: {integrity: sha512-16OL3NnUBw8JG1jBLUoZJsLnQq0n5Ua6aHalhJK4fMQkz1lqR7Osz1sA30trBtd9VUDc2NgkuRCn8+/pBwqZ+w==} + engines: {node: '>=10'} + peerDependencies: + seroval: ^1.0 + + seroval@1.3.2: + resolution: {integrity: sha512-RbcPH1n5cfwKrru7v7+zrZvjLurgHhGyso3HTyGtRivGWgYjbOmGuivCQaORNELjNONoK35nj28EoWul9sb1zQ==} + engines: {node: '>=10'} + serve-static@2.2.0: resolution: {integrity: sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==} engines: {node: '>= 18'} @@ -6142,6 +6229,12 @@ packages: text-table@0.2.0: resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} + tiny-invariant@1.3.3: + resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==} + + tiny-warning@1.0.3: + resolution: {integrity: sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==} + tinybench@2.9.0: resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} @@ -6343,6 +6436,11 @@ packages: uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + use-sync-external-store@1.5.0: + resolution: {integrity: sha512-Rb46I4cGGVBmjamjphe8L/UnvJD+uPPtTkNvX5mZgqdbavhI4EbgIWJiIHXJ8bc/i9EQGPRh4DwEURJ552Do0A==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} @@ -7252,14 +7350,14 @@ snapshots: eslint: 8.57.0 eslint-visitor-keys: 3.4.3 - '@eslint-community/eslint-utils@4.7.0(eslint@9.28.0(jiti@2.6.0))': + '@eslint-community/eslint-utils@4.8.0(eslint@8.57.0)': dependencies: - eslint: 9.28.0(jiti@2.6.0) + eslint: 8.57.0 eslint-visitor-keys: 3.4.3 - '@eslint-community/eslint-utils@4.8.0(eslint@8.57.0)': + '@eslint-community/eslint-utils@4.8.0(eslint@9.28.0(jiti@2.6.0))': dependencies: - eslint: 8.57.0 + eslint: 9.28.0(jiti@2.6.0) eslint-visitor-keys: 3.4.3 '@eslint-community/regexpp@4.12.1': {} @@ -7296,7 +7394,7 @@ snapshots: dependencies: ajv: 6.12.6 debug: 4.4.1 - espree: 10.3.0 + espree: 10.4.0 globals: 14.0.0 ignore: 5.3.2 import-fresh: 3.3.1 @@ -7977,6 +8075,38 @@ snapshots: tailwindcss: 4.1.8 vite: 6.3.5(@types/node@24.0.3)(jiti@2.6.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(terser@5.39.2)(yaml@2.8.0) + '@tanstack/history@1.132.21': {} + + '@tanstack/react-router@1.132.27(react-dom@19.1.1(react@19.1.0))(react@19.1.0)': + dependencies: + '@tanstack/history': 1.132.21 + '@tanstack/react-store': 0.7.7(react-dom@19.1.1(react@19.1.0))(react@19.1.0) + '@tanstack/router-core': 1.132.27 + isbot: 5.1.31 + react: 19.1.0 + react-dom: 19.1.1(react@19.1.0) + tiny-invariant: 1.3.3 + tiny-warning: 1.0.3 + + '@tanstack/react-store@0.7.7(react-dom@19.1.1(react@19.1.0))(react@19.1.0)': + dependencies: + '@tanstack/store': 0.7.7 + react: 19.1.0 + react-dom: 19.1.1(react@19.1.0) + use-sync-external-store: 1.5.0(react@19.1.0) + + '@tanstack/router-core@1.132.27': + dependencies: + '@tanstack/history': 1.132.21 + '@tanstack/store': 0.7.7 + cookie-es: 2.0.0 + seroval: 1.3.2 + seroval-plugins: 1.3.3(seroval@1.3.2) + tiny-invariant: 1.3.3 + tiny-warning: 1.0.3 + + '@tanstack/store@0.7.7': {} + '@testing-library/dom@10.4.0': dependencies: '@babel/code-frame': 7.27.1 @@ -8387,7 +8517,7 @@ snapshots: '@typescript-eslint/utils@6.21.0(eslint@8.57.0)(typescript@5.1.6)': dependencies: - '@eslint-community/eslint-utils': 4.7.0(eslint@8.57.0) + '@eslint-community/eslint-utils': 4.8.0(eslint@8.57.0) '@types/json-schema': 7.0.15 '@types/semver': 7.7.0 '@typescript-eslint/scope-manager': 6.21.0 @@ -8401,7 +8531,7 @@ snapshots: '@typescript-eslint/utils@8.33.1(eslint@9.28.0(jiti@2.6.0))(typescript@5.8.3)': dependencies: - '@eslint-community/eslint-utils': 4.7.0(eslint@9.28.0(jiti@2.6.0)) + '@eslint-community/eslint-utils': 4.8.0(eslint@9.28.0(jiti@2.6.0)) '@typescript-eslint/scope-manager': 8.33.1 '@typescript-eslint/types': 8.33.1 '@typescript-eslint/typescript-estree': 8.33.1(typescript@5.8.3) @@ -9222,6 +9352,8 @@ snapshots: convert-source-map@2.0.0: {} + cookie-es@2.0.0: {} + cookie-signature@1.2.2: {} cookie@0.7.2: {} @@ -9703,6 +9835,10 @@ snapshots: esbuild: 0.25.9 import-meta-resolve: 3.1.1 + esbuild-plugin-preserve-directives@0.0.11(esbuild@0.25.10): + dependencies: + esbuild: 0.25.10 + esbuild-plugin-preserve-directives@0.0.11(esbuild@0.25.9): dependencies: esbuild: 0.25.9 @@ -10106,11 +10242,6 @@ snapshots: esrecurse: 4.3.0 estraverse: 5.3.0 - eslint-scope@8.3.0: - dependencies: - esrecurse: 4.3.0 - estraverse: 5.3.0 - eslint-scope@8.4.0: dependencies: esrecurse: 4.3.0 @@ -10131,13 +10262,11 @@ snapshots: eslint-visitor-keys@3.4.3: {} - eslint-visitor-keys@4.2.0: {} - eslint-visitor-keys@4.2.1: {} eslint@8.57.0: dependencies: - '@eslint-community/eslint-utils': 4.8.0(eslint@8.57.0) + '@eslint-community/eslint-utils': 4.7.0(eslint@8.57.0) '@eslint-community/regexpp': 4.12.1 '@eslint/eslintrc': 2.1.4 '@eslint/js': 8.57.0 @@ -10180,7 +10309,7 @@ snapshots: eslint@9.28.0(jiti@2.6.0): dependencies: - '@eslint-community/eslint-utils': 4.7.0(eslint@9.28.0(jiti@2.6.0)) + '@eslint-community/eslint-utils': 4.8.0(eslint@9.28.0(jiti@2.6.0)) '@eslint-community/regexpp': 4.12.1 '@eslint/config-array': 0.20.0 '@eslint/config-helpers': 0.2.2 @@ -10191,16 +10320,16 @@ snapshots: '@humanfs/node': 0.16.6 '@humanwhocodes/module-importer': 1.0.1 '@humanwhocodes/retry': 0.4.3 - '@types/estree': 1.0.7 + '@types/estree': 1.0.8 '@types/json-schema': 7.0.15 ajv: 6.12.6 chalk: 4.1.2 cross-spawn: 7.0.6 debug: 4.4.1 escape-string-regexp: 4.0.0 - eslint-scope: 8.3.0 - eslint-visitor-keys: 4.2.0 - espree: 10.3.0 + eslint-scope: 8.4.0 + eslint-visitor-keys: 4.2.1 + espree: 10.4.0 esquery: 1.6.0 esutils: 2.0.3 fast-deep-equal: 3.1.3 @@ -10220,12 +10349,6 @@ snapshots: transitivePeerDependencies: - supports-color - espree@10.3.0: - dependencies: - acorn: 8.14.1 - acorn-jsx: 5.3.2(acorn@8.14.1) - eslint-visitor-keys: 4.2.0 - espree@10.4.0: dependencies: acorn: 8.15.0 @@ -10234,8 +10357,8 @@ snapshots: espree@9.6.1: dependencies: - acorn: 8.15.0 - acorn-jsx: 5.3.2(acorn@8.15.0) + acorn: 8.14.1 + acorn-jsx: 5.3.2(acorn@8.14.1) eslint-visitor-keys: 3.4.3 esprima@4.0.1: {} @@ -10892,6 +11015,8 @@ snapshots: isarray@2.0.5: {} + isbot@5.1.31: {} + isexe@2.0.0: {} istanbul-lib-coverage@3.2.2: {} @@ -12408,6 +12533,12 @@ snapshots: transitivePeerDependencies: - supports-color + seroval-plugins@1.3.3(seroval@1.3.2): + dependencies: + seroval: 1.3.2 + + seroval@1.3.2: {} + serve-static@2.2.0: dependencies: encodeurl: 2.0.0 @@ -12865,6 +12996,10 @@ snapshots: text-table@0.2.0: {} + tiny-invariant@1.3.3: {} + + tiny-warning@1.0.3: {} + tinybench@2.9.0: {} tinyexec@0.3.2: {} @@ -13057,6 +13192,10 @@ snapshots: dependencies: punycode: 2.3.1 + use-sync-external-store@1.5.0(react@19.1.0): + dependencies: + react: 19.1.0 + util-deprecate@1.0.2: {} uuid@11.1.0: {} @@ -13118,11 +13257,11 @@ snapshots: vite@6.3.5(@types/node@20.17.50)(jiti@2.6.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.89.0)(terser@5.39.2)(yaml@2.8.0): dependencies: esbuild: 0.25.10 - fdir: 6.4.4(picomatch@4.0.2) - picomatch: 4.0.2 + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 postcss: 8.5.6 - rollup: 4.40.2 - tinyglobby: 0.2.13 + rollup: 4.50.0 + tinyglobby: 0.2.14 optionalDependencies: '@types/node': 20.17.50 fsevents: 2.3.3 @@ -13136,11 +13275,11 @@ snapshots: vite@6.3.5(@types/node@22.15.30)(jiti@2.6.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(terser@5.39.2)(yaml@2.8.0): dependencies: esbuild: 0.25.10 - fdir: 6.4.4(picomatch@4.0.2) - picomatch: 4.0.2 + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 postcss: 8.5.6 - rollup: 4.40.2 - tinyglobby: 0.2.13 + rollup: 4.50.0 + tinyglobby: 0.2.14 optionalDependencies: '@types/node': 22.15.30 fsevents: 2.3.3 @@ -13154,11 +13293,11 @@ snapshots: vite@6.3.5(@types/node@24.0.3)(jiti@2.6.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(terser@5.39.2)(yaml@2.8.0): dependencies: esbuild: 0.25.10 - fdir: 6.4.4(picomatch@4.0.2) - picomatch: 4.0.2 + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 postcss: 8.5.6 - rollup: 4.40.2 - tinyglobby: 0.2.13 + rollup: 4.50.0 + tinyglobby: 0.2.14 optionalDependencies: '@types/node': 24.0.3 fsevents: 2.3.3 diff --git a/samples/react-tanstack-router/README.md b/samples/react-tanstack-router/README.md new file mode 100644 index 00000000..a885623d --- /dev/null +++ b/samples/react-tanstack-router/README.md @@ -0,0 +1,149 @@ +# Asgardeo TanStack Router Sample Application + +This is a sample application demonstrating how to integrate [Asgardeo](https://wso2.com/asgardeo/) authentication with [TanStack Router](https://tanstack.com/router) using the `@asgardeo/tanstack-router` package. + +## Features + +- ✅ Authentication with Asgardeo +- ✅ Protected routes using `ProtectedRoute` component +- ✅ TanStack Router integration +- ✅ TypeScript support +- ✅ Vite for fast development + +## Prerequisites + +- Node.js (v18 or higher) +- pnpm +- An Asgardeo account and application + +## Getting Started + +### 1. Set up Asgardeo + +1. Create an account at [Asgardeo](https://wso2.com/asgardeo/) +2. Create a new Single Page Application (SPA) +3. Note down your: + - Organization name + - Client ID +4. Configure the following in your Asgardeo application: + - **Authorized redirect URLs**: `https://localhost:5173` + - **Allowed origins**: `https://localhost:5173` + +### 2. Configure Environment Variables + +Create a `.env.local` file in the root of this sample directory: + +```bash +cp .env.local.example .env.local +``` + +Edit `.env.local` and add your Asgardeo credentials: + +```bash +VITE_ASGARDEO_BASE_URL='https://api.asgardeo.io/t/' +VITE_ASGARDEO_CLIENT_ID='' +``` + +### 3. Install Dependencies + +From the root of the monorepo, run: + +```bash +pnpm install +``` + +### 4. Run the Application + +```bash +cd samples/react-tanstack-router +pnpm dev +``` + +The application will be available at `https://localhost:5173` + +## Project Structure + +``` +src/ +├── pages/ +│ ├── Home.tsx # Unprotected home page +│ └── Dashboard.tsx # Protected dashboard page +├── main.tsx # App entry point with router configuration +├── index.css # Global styles +└── vite-env.d.ts # Vite type definitions +``` + +## Key Implementation Details + +### Protected Routes + +The Dashboard page is protected using the `ProtectedRoute` component from `@asgardeo/tanstack-router`: + +```tsx +import {ProtectedRoute} from '@asgardeo/tanstack-router'; +import Dashboard from './pages/Dashboard'; + +const dashboardRoute = createRoute({ + getParentRoute: () => rootRoute, + path: '/dashboard', + component: () => ( + + + + ), +}); +``` + +### Router Setup + +The application uses TanStack Router's imperative API to create routes: + +```tsx +import {createRouter, createRootRoute, createRoute} from '@tanstack/react-router'; + +const rootRoute = createRootRoute(); +const indexRoute = createRoute({ + getParentRoute: () => rootRoute, + path: '/', + component: Home, +}); + +const routeTree = rootRoute.addChildren([indexRoute, dashboardRoute]); +const router = createRouter({routeTree}); +``` + +### Asgardeo Provider + +The app is wrapped with `AsgardeoProvider` in `main.tsx`: + +```tsx + + + +``` + +## Authentication Flow + +1. User visits the home page (unprotected) +2. User clicks "Sign In" button +3. User is redirected to Asgardeo for authentication +4. After successful authentication, user is redirected back to the application +5. User can now access protected routes like the Dashboard +6. Attempting to access protected routes without authentication redirects to the home page + +## Learn More + +- [Asgardeo Documentation](https://wso2.com/asgardeo/docs/) +- [TanStack Router Documentation](https://tanstack.com/router/latest) +- [@asgardeo/react Documentation](https://github.com/asgardeo/asgardeo-auth-react-sdk) +- [@asgardeo/tanstack-router Package](../../packages/tanstack-router) + +## License + +Apache-2.0 diff --git a/samples/react-tanstack-router/eslint.config.js b/samples/react-tanstack-router/eslint.config.js new file mode 100644 index 00000000..092408a9 --- /dev/null +++ b/samples/react-tanstack-router/eslint.config.js @@ -0,0 +1,28 @@ +import js from '@eslint/js' +import globals from 'globals' +import reactHooks from 'eslint-plugin-react-hooks' +import reactRefresh from 'eslint-plugin-react-refresh' +import tseslint from 'typescript-eslint' + +export default tseslint.config( + { ignores: ['dist'] }, + { + extends: [js.configs.recommended, ...tseslint.configs.recommended], + files: ['**/*.{ts,tsx}'], + languageOptions: { + ecmaVersion: 2020, + globals: globals.browser, + }, + plugins: { + 'react-hooks': reactHooks, + 'react-refresh': reactRefresh, + }, + rules: { + ...reactHooks.configs.recommended.rules, + 'react-refresh/only-export-components': [ + 'warn', + { allowConstantExport: true }, + ], + }, + }, +) diff --git a/samples/react-tanstack-router/index.html b/samples/react-tanstack-router/index.html new file mode 100644 index 00000000..06de12e1 --- /dev/null +++ b/samples/react-tanstack-router/index.html @@ -0,0 +1,13 @@ + + + + + + + Asgardeo TanStack Router Sample + + +
+ + + diff --git a/samples/react-tanstack-router/package.json b/samples/react-tanstack-router/package.json new file mode 100644 index 00000000..71a19045 --- /dev/null +++ b/samples/react-tanstack-router/package.json @@ -0,0 +1,32 @@ +{ + "private": true, + "name": "@asgardeo/react-tanstack-router-sample", + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "tsc -b && vite build", + "lint": "eslint .", + "preview": "vite preview" + }, + "dependencies": { + "@asgardeo/react": "workspace:^", + "@asgardeo/tanstack-router": "workspace:^", + "@tanstack/react-router": "^1.132.6", + "react": "^19.1.0", + "react-dom": "^19.1.0" + }, + "devDependencies": { + "@types/react": "^19.1.2", + "@types/react-dom": "^19.1.2", + "@vitejs/plugin-basic-ssl": "^2.0.0", + "@vitejs/plugin-react": "^4.4.1", + "eslint": "^9.25.0", + "eslint-plugin-react-hooks": "^5.2.0", + "eslint-plugin-react-refresh": "^0.4.19", + "globals": "^16.0.0", + "typescript": "~5.8.3", + "typescript-eslint": "^8.30.1", + "vite": "^6.3.5" + } +} diff --git a/samples/react-tanstack-router/public/vite.svg b/samples/react-tanstack-router/public/vite.svg new file mode 100644 index 00000000..e7b8dfb1 --- /dev/null +++ b/samples/react-tanstack-router/public/vite.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/samples/react-tanstack-router/src/index.css b/samples/react-tanstack-router/src/index.css new file mode 100644 index 00000000..7e877615 --- /dev/null +++ b/samples/react-tanstack-router/src/index.css @@ -0,0 +1,219 @@ +:root { + font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; + line-height: 1.5; + font-weight: 400; + + color-scheme: light dark; + color: rgba(255, 255, 255, 0.87); + background-color: #242424; + + font-synthesis: none; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +body { + margin: 0; + display: flex; + place-items: center; + min-width: 320px; + min-height: 100vh; +} + +#root { + width: 100%; + min-height: 100vh; +} + +a { + font-weight: 500; + color: #646cff; + text-decoration: inherit; +} + +a:hover { + color: #535bf2; +} + +h1 { + font-size: 3.2em; + line-height: 1.1; +} + +button { + border-radius: 8px; + border: 1px solid transparent; + padding: 0.6em 1.2em; + font-size: 1em; + font-weight: 500; + font-family: inherit; + background-color: #1a1a1a; + cursor: pointer; + transition: border-color 0.25s; +} + +button:hover { + border-color: #646cff; +} + +button:focus, +button:focus-visible { + outline: 4px auto -webkit-focus-ring-color; +} + +@media (prefers-color-scheme: light) { + :root { + color: #213547; + background-color: #ffffff; + } + + a:hover { + color: #747bff; + } + + button { + background-color: #f9f9f9; + } +} + +/* Layout Styles */ +.container { + max-width: 1200px; + margin: 0 auto; + padding: 2rem; +} + +.nav { + display: flex; + justify-content: space-between; + align-items: center; + padding: 1rem 2rem; + background-color: #1a1a1a; + margin-bottom: 2rem; +} + +@media (prefers-color-scheme: light) { + .nav { + background-color: #f5f5f5; + border-bottom: 1px solid #e0e0e0; + } +} + +.nav-links { + display: flex; + gap: 1rem; + align-items: center; +} + +.hero { + text-align: center; + padding: 4rem 2rem; +} + +.hero h1 { + margin-bottom: 1rem; +} + +.hero p { + font-size: 1.2em; + margin-bottom: 2rem; + opacity: 0.9; +} + +.page-header { + margin-bottom: 2rem; +} + +.page-header h1 { + margin-bottom: 0.5rem; +} + +.page-header p { + font-size: 1.1em; + opacity: 0.8; +} + +.card { + padding: 2em; + margin: 1rem 0; + border-radius: 8px; + background-color: #1a1a1a; +} + +@media (prefers-color-scheme: light) { + .card { + background-color: #f9f9f9; + border: 1px solid #e0e0e0; + } +} + +.card h2 { + margin-bottom: 0.5rem; +} + +.card p { + margin-top: 1rem; +} + +.card code { + background-color: rgba(100, 108, 255, 0.1); + padding: 0.2em 0.4em; + border-radius: 3px; + font-family: 'Courier New', Courier, monospace; +} + +.grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); + gap: 1.5rem; + margin-top: 2rem; + margin-bottom: 3rem; +} + +.stat-card { + padding: 1.5rem; + border-radius: 8px; + background-color: #2a2a2a; + text-align: center; +} + +@media (prefers-color-scheme: light) { + .stat-card { + background-color: #ffffff; + border: 1px solid #e0e0e0; + } +} + +.stat-card h3 { + font-size: 2em; + margin-bottom: 0.5rem; + color: #646cff; +} + +.user-info { + display: flex; + gap: 1rem; + margin-bottom: 2rem; + padding: 1rem; + border-radius: 8px; + background-color: #2a2a2a; + align-items: center; +} + +@media (prefers-color-scheme: light) { + .user-info { + background-color: #ffffff; + border: 1px solid #e0e0e0; + } +} + +.user-info strong { + color: #646cff; +} diff --git a/samples/react-tanstack-router/src/main.tsx b/samples/react-tanstack-router/src/main.tsx new file mode 100644 index 00000000..9edd43c4 --- /dev/null +++ b/samples/react-tanstack-router/src/main.tsx @@ -0,0 +1,49 @@ +import {StrictMode} from 'react'; +import {createRoot} from 'react-dom/client'; +import {RouterProvider, createRouter, createRootRoute, createRoute} from '@tanstack/react-router'; +import {AsgardeoProvider} from '@asgardeo/react'; +import {ProtectedRoute} from '@asgardeo/tanstack-router'; +import './index.css'; +import Home from './pages/Home'; +import Dashboard from './pages/Dashboard'; + +const rootRoute = createRootRoute(); + +const indexRoute = createRoute({ + getParentRoute: () => rootRoute, + path: '/', + component: Home, +}); + +const dashboardRoute = createRoute({ + getParentRoute: () => rootRoute, + path: '/dashboard', + component: () => ( + + + + ), +}); + +const routeTree = rootRoute.addChildren([indexRoute, dashboardRoute]); +const router = createRouter({routeTree}); + +declare module '@tanstack/react-router' { + interface Register { + router: typeof router; + } +} + +createRoot(document.getElementById('root')!).render( + + + + + , +); diff --git a/samples/react-tanstack-router/src/pages/Dashboard.tsx b/samples/react-tanstack-router/src/pages/Dashboard.tsx new file mode 100644 index 00000000..ea0f874e --- /dev/null +++ b/samples/react-tanstack-router/src/pages/Dashboard.tsx @@ -0,0 +1,88 @@ +import {Link} from '@tanstack/react-router'; +import {useAsgardeo, User} from '@asgardeo/react'; + +export default function Dashboard() { + const {signOut} = useAsgardeo(); + + return ( +
+ + +
+
+

Dashboard

+

This is a protected page. You can only see this because you're authenticated!

+
+ +
+

User Information

+ + {user => ( +
+ {user ? ( +
+
+

+ Name:{' '} + {user?.givenName || user?.name?.givenName || user?.given_name}{' '} + {user?.name?.familyName || user?.familyName || user?.family_name || ''} +

+

+ Email: {user?.email || 'N/A'} +

+

+ Username: {user?.username || 'N/A'} +

+
+
+ ) : ( +

Loading user information...

+ )} +
+ )} +
+
+ +
+
+

24

+

Active Projects

+
+
+

152

+

Tasks Completed

+
+
+

8

+

Team Members

+
+
+

98%

+

Success Rate

+
+
+ +
+

About Protected Routes

+

+ This Dashboard page is wrapped with the ProtectedRoute component from{' '} + @asgardeo/tanstack-router. This ensures that only authenticated users can access this page. +

+

+ If an unauthenticated user tries to access this route, they will be redirected to the home page + automatically. +

+
+
+
+ ); +} diff --git a/samples/react-tanstack-router/src/pages/Home.tsx b/samples/react-tanstack-router/src/pages/Home.tsx new file mode 100644 index 00000000..531167ab --- /dev/null +++ b/samples/react-tanstack-router/src/pages/Home.tsx @@ -0,0 +1,83 @@ +import {Link} from '@tanstack/react-router'; +import {useAsgardeo, SignInButton} from '@asgardeo/react'; + +export default function Home() { + const {isSignedIn, signOut} = useAsgardeo(); + + return ( +
+ + +
+

Welcome to Asgardeo TanStack Router Sample

+

+ This is a sample application demonstrating the integration of Asgardeo authentication with TanStack Router. +

+ + {!isSignedIn && ( +
+ + {isLoading => } + +
+ )} + + {isSignedIn && ( +
+ + + +
+ )} +
+ +
+
+
+

🔐

+

Secure Authentication

+

Powered by Asgardeo

+
+
+

🚀

+

Fast Routing

+

Built with TanStack Router

+
+
+

+

Protected Routes

+

Easy route protection

+
+
+ +
+

About This Sample

+

+ This sample demonstrates how to use the @asgardeo/tanstack-router package to protect routes in + your TanStack Router application. The Dashboard page is protected and requires authentication to access. +

+

+ Try signing in and navigating to the Dashboard to see the ProtectedRoute component in action! +

+
+
+
+ ); +} diff --git a/samples/react-tanstack-router/src/vite-env.d.ts b/samples/react-tanstack-router/src/vite-env.d.ts new file mode 100644 index 00000000..11f02fe2 --- /dev/null +++ b/samples/react-tanstack-router/src/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/samples/react-tanstack-router/tsconfig.app.json b/samples/react-tanstack-router/tsconfig.app.json new file mode 100644 index 00000000..c9ccbd4c --- /dev/null +++ b/samples/react-tanstack-router/tsconfig.app.json @@ -0,0 +1,27 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2020", + "useDefineForClassFields": true, + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "module": "ESNext", + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/samples/react-tanstack-router/tsconfig.json b/samples/react-tanstack-router/tsconfig.json new file mode 100644 index 00000000..3fb7c780 --- /dev/null +++ b/samples/react-tanstack-router/tsconfig.json @@ -0,0 +1,5 @@ +{ + "extends": "../../tsconfig.json", + "files": [], + "references": [{"path": "./tsconfig.app.json"}, {"path": "./tsconfig.node.json"}] +} diff --git a/samples/react-tanstack-router/tsconfig.node.json b/samples/react-tanstack-router/tsconfig.node.json new file mode 100644 index 00000000..9728af2d --- /dev/null +++ b/samples/react-tanstack-router/tsconfig.node.json @@ -0,0 +1,25 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2022", + "lib": ["ES2023"], + "module": "ESNext", + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/samples/react-tanstack-router/vite.config.ts b/samples/react-tanstack-router/vite.config.ts new file mode 100644 index 00000000..82c30cdb --- /dev/null +++ b/samples/react-tanstack-router/vite.config.ts @@ -0,0 +1,8 @@ +import {defineConfig} from 'vite'; +import react from '@vitejs/plugin-react'; +import basicSsl from '@vitejs/plugin-basic-ssl'; + +// https://vite.dev/config/ +export default defineConfig({ + plugins: [react(), basicSsl()], +}); From f9941d051f10783fa990901e7fb7df92a0c74a66 Mon Sep 17 00:00:00 2001 From: Tharun Devaraja <154892351+d3varaja@users.noreply.github.com> Date: Fri, 3 Oct 2025 15:28:31 +0530 Subject: [PATCH 5/6] chore(i18n): update lockfile to sync with package.json dependencies Add lockfile entries for newly added i18n package dependencies including build tools, linting, and testing packages --- pnpm-lock.yaml | 102 ++++++++++++++++++++++++------------------------- 1 file changed, 51 insertions(+), 51 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f511018b..144b2fc8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -170,8 +170,45 @@ importers: specifier: ^3.1.3 version: 3.1.3(@types/node@22.15.30)(@vitest/browser@3.1.3)(jiti@2.6.0)(jsdom@26.1.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(terser@5.39.2)(yaml@2.8.0) + packages/i18n: + dependencies: + tslib: + specifier: ^2.8.1 + version: 2.8.1 + devDependencies: + '@types/node': + specifier: ^22.15.30 + version: 22.15.30 + '@wso2/eslint-plugin': + specifier: 'catalog:' + version: https://gitpkg.now.sh/brionmario/wso2-ui-configs/packages/eslint-plugin?a1fc6eb570653c999828aea9f5027cba06af4391(eslint@8.57.0)(typescript@5.7.3) + '@wso2/prettier-config': + specifier: 'catalog:' + version: https://gitpkg.now.sh/brionmario/wso2-ui-configs/packages/prettier-config?a1fc6eb570653c999828aea9f5027cba06af4391(prettier@2.8.8)(typescript@5.7.3) + esbuild: + specifier: ^0.25.9 + version: 0.25.10 + eslint: + specifier: 8.57.0 + version: 8.57.0 + prettier: + specifier: ^2.6.2 + version: 2.8.8 + rimraf: + specifier: ^6.0.1 + version: 6.0.1 + typescript: + specifier: ~5.7.2 + version: 5.7.3 + vitest: + specifier: ^3.1.3 + version: 3.1.3(@types/node@22.15.30)(@vitest/browser@3.1.3)(jiti@2.6.0)(jsdom@26.1.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(terser@5.39.2)(yaml@2.8.0) + packages/javascript: dependencies: + '@asgardeo/i18n': + specifier: workspace:^ + version: link:../i18n tslib: specifier: ^2.8.1 version: 2.8.1 @@ -322,6 +359,9 @@ importers: '@asgardeo/browser': specifier: workspace:^ version: link:../browser + '@asgardeo/i18n': + specifier: workspace:^ + version: link:../i18n '@emotion/css': specifier: ^11.13.5 version: 11.13.5 @@ -648,6 +688,9 @@ importers: samples/teamspace-react: dependencies: + '@asgardeo/i18n': + specifier: workspace:^ + version: link:../../packages/i18n '@asgardeo/react': specifier: workspace:^ version: link:../../packages/react @@ -1315,12 +1358,6 @@ packages: cpu: [x64] os: [win32] - '@eslint-community/eslint-utils@4.7.0': - resolution: {integrity: sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 - '@eslint-community/eslint-utils@4.8.0': resolution: {integrity: sha512-MJQFqrZgcW0UNYLGOuQpey/oTN59vyWwplvCGZztn1cKz9agZPPYpJB7h2OMmuu7VLqkvEjN8feFZJmxNF9D+Q==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -2739,11 +2776,6 @@ packages: peerDependencies: acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 - acorn@8.14.1: - resolution: {integrity: sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==} - engines: {node: '>=0.4.0'} - hasBin: true - acorn@8.15.0: resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==} engines: {node: '>=0.4.0'} @@ -3890,14 +3922,6 @@ packages: fastq@1.19.1: resolution: {integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==} - fdir@6.4.4: - resolution: {integrity: sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg==} - peerDependencies: - picomatch: ^3 || ^4 - peerDependenciesMeta: - picomatch: - optional: true - fdir@6.5.0: resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} engines: {node: '>=12.0.0'} @@ -6241,10 +6265,6 @@ packages: tinyexec@0.3.2: resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} - tinyglobby@0.2.13: - resolution: {integrity: sha512-mEwzpUgrLySlveBwEVDMKk5B57bhLPYovRfPAXD5gA/98Opn0rCDj3GtLwFvCvH5RK9uPCExUROW5NjDwvqkxw==} - engines: {node: '>=12.0.0'} - tinyglobby@0.2.14: resolution: {integrity: sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==} engines: {node: '>=12.0.0'} @@ -7345,11 +7365,6 @@ snapshots: '@esbuild/win32-x64@0.25.9': optional: true - '@eslint-community/eslint-utils@4.7.0(eslint@8.57.0)': - dependencies: - eslint: 8.57.0 - eslint-visitor-keys: 3.4.3 - '@eslint-community/eslint-utils@4.8.0(eslint@8.57.0)': dependencies: eslint: 8.57.0 @@ -8487,7 +8502,7 @@ snapshots: '@typescript-eslint/utils@5.62.0(eslint@8.57.0)(typescript@5.1.6)': dependencies: - '@eslint-community/eslint-utils': 4.7.0(eslint@8.57.0) + '@eslint-community/eslint-utils': 4.8.0(eslint@8.57.0) '@types/json-schema': 7.0.15 '@types/semver': 7.7.0 '@typescript-eslint/scope-manager': 5.62.0 @@ -8502,7 +8517,7 @@ snapshots: '@typescript-eslint/utils@5.62.0(eslint@8.57.0)(typescript@5.7.3)': dependencies: - '@eslint-community/eslint-utils': 4.7.0(eslint@8.57.0) + '@eslint-community/eslint-utils': 4.8.0(eslint@8.57.0) '@types/json-schema': 7.0.15 '@types/semver': 7.7.0 '@typescript-eslint/scope-manager': 5.62.0 @@ -8888,16 +8903,10 @@ snapshots: mime-types: 3.0.1 negotiator: 1.0.0 - acorn-jsx@5.3.2(acorn@8.14.1): - dependencies: - acorn: 8.14.1 - acorn-jsx@5.3.2(acorn@8.15.0): dependencies: acorn: 8.15.0 - acorn@8.14.1: {} - acorn@8.15.0: {} agent-base@7.1.3: @@ -10266,7 +10275,7 @@ snapshots: eslint@8.57.0: dependencies: - '@eslint-community/eslint-utils': 4.7.0(eslint@8.57.0) + '@eslint-community/eslint-utils': 4.8.0(eslint@8.57.0) '@eslint-community/regexpp': 4.12.1 '@eslint/eslintrc': 2.1.4 '@eslint/js': 8.57.0 @@ -10357,8 +10366,8 @@ snapshots: espree@9.6.1: dependencies: - acorn: 8.14.1 - acorn-jsx: 5.3.2(acorn@8.14.1) + acorn: 8.15.0 + acorn-jsx: 5.3.2(acorn@8.15.0) eslint-visitor-keys: 3.4.3 esprima@4.0.1: {} @@ -10462,10 +10471,6 @@ snapshots: dependencies: reusify: 1.1.0 - fdir@6.4.4(picomatch@4.0.2): - optionalDependencies: - picomatch: 4.0.2 - fdir@6.5.0(picomatch@4.0.3): optionalDependencies: picomatch: 4.0.3 @@ -11433,7 +11438,7 @@ snapshots: mlly@1.7.4: dependencies: - acorn: 8.14.1 + acorn: 8.15.0 pathe: 2.0.3 pkg-types: 1.3.1 ufo: 1.6.1 @@ -13004,11 +13009,6 @@ snapshots: tinyexec@0.3.2: {} - tinyglobby@0.2.13: - dependencies: - fdir: 6.4.4(picomatch@4.0.2) - picomatch: 4.0.2 - tinyglobby@0.2.14: dependencies: fdir: 6.5.0(picomatch@4.0.3) @@ -13353,7 +13353,7 @@ snapshots: std-env: 3.9.0 tinybench: 2.9.0 tinyexec: 0.3.2 - tinyglobby: 0.2.13 + tinyglobby: 0.2.14 tinypool: 1.0.2 tinyrainbow: 2.0.0 vite: 6.3.5(@types/node@20.17.50)(jiti@2.6.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.89.0)(terser@5.39.2)(yaml@2.8.0) @@ -13393,7 +13393,7 @@ snapshots: std-env: 3.9.0 tinybench: 2.9.0 tinyexec: 0.3.2 - tinyglobby: 0.2.13 + tinyglobby: 0.2.14 tinypool: 1.0.2 tinyrainbow: 2.0.0 vite: 6.3.5(@types/node@22.15.30)(jiti@2.6.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(terser@5.39.2)(yaml@2.8.0) From 966a562f008fd4bd213ac7102816ec289ec0afe6 Mon Sep 17 00:00:00 2001 From: Tharun Devaraja <154892351+d3varaja@users.noreply.github.com> Date: Fri, 3 Oct 2025 15:36:51 +0530 Subject: [PATCH 6/6] chore: add changeset --- .changeset/little-beans-repair.md | 35 +++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 .changeset/little-beans-repair.md diff --git a/.changeset/little-beans-repair.md b/.changeset/little-beans-repair.md new file mode 100644 index 00000000..5c4d7f1b --- /dev/null +++ b/.changeset/little-beans-repair.md @@ -0,0 +1,35 @@ +--- +'@asgardeo/tanstack-router': major +--- + +Add TanStack Router integration package with protected route support + +Introduce `@asgardeo/tanstack-router` - a new integration package that provides seamless authentication support for TanStack Router applications. + +**Key Features:** +- `` component for auth-guarded routes +- Automatic redirect to sign-in for unauthenticated users +- Integration with Asgardeo authentication context +- Type-safe route protection + +**Usage:** + +```tsx +import { ProtectedRoute } from '@asgardeo/tanstack-router'; + +const Route = createFileRoute('/dashboard')({ + component: () => ( + + + + ), +}); +``` + +**Installation:** + +```bash +npm install @asgardeo/tanstack-router +``` + +This is the initial release of the TanStack Router integration package. \ No newline at end of file