From 95983adf18502fabe7712632c09c91d0f89bc81e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 28 Mar 2026 12:38:10 +0000 Subject: [PATCH 1/4] Initial plan From 36b696e70116400b9e3b8241fb6e124c1b39113c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 28 Mar 2026 12:58:11 +0000 Subject: [PATCH 2/4] feat(react-auth): add createMultiAuth for multi-provider support Agent-Logs-Url: https://github.com/forwardsoftware/react-auth/sessions/0be64a5f-8e5a-4377-87d7-3978b06e89d2 Co-authored-by: panz3r <1754457+panz3r@users.noreply.github.com> --- lib/src/auth.tsx | 108 ++++++++++- lib/src/index.ts | 4 +- lib/test/multiAuth.spec.tsx | 356 ++++++++++++++++++++++++++++++++++++ 3 files changed, 464 insertions(+), 4 deletions(-) create mode 100644 lib/test/multiAuth.spec.tsx diff --git a/lib/src/auth.tsx b/lib/src/auth.tsx index 4429858..00e74d8 100644 --- a/lib/src/auth.tsx +++ b/lib/src/auth.tsx @@ -433,9 +433,23 @@ export type EnhancedAuthClient = AC & Au * @returns {EnhancedAuthClient} - An enhanced authentication client with additional features */ export function wrapAuthClient(authClient: AC): EnhancedAuthClient { - Object.setPrototypeOf(AuthClientEnhancements.prototype, authClient); + // Build a per-instance prototype so that wrapping multiple clients does not cause + // one client's methods to bleed into another. + // Chain: instance → perInstanceProto (enhancement methods) → authClient (raw AC methods) + const perInstanceProto = Object.create(authClient); + Object.getOwnPropertyNames(AuthClientEnhancements.prototype) + .filter((name) => name !== 'constructor') + .forEach((name) => { + const descriptor = Object.getOwnPropertyDescriptor(AuthClientEnhancements.prototype, name); + if (descriptor) { + Object.defineProperty(perInstanceProto, name, descriptor); + } + }); + + const instance = new AuthClientEnhancements(authClient); + Object.setPrototypeOf(instance, perInstanceProto); - return new AuthClientEnhancements(authClient) as unknown as EnhancedAuthClient; + return instance as unknown as EnhancedAuthClient; } /** @@ -543,4 +557,94 @@ export function createAuth(authC authClient: enhancedAuthClient, useAuthClient, }; +} + +/** + * Creates an authentication context and provider supporting multiple auth clients. + * Each client is identified by a string key. + * + * @template M - A map of client IDs to AuthClient implementations. + * @template E - The type of error expected during authentication flows. Defaults to `Error`. + * @param {M} authClientsMap - A map of auth client IDs to their instances. + * @returns An object containing: + * - `AuthProvider`: A React component to wrap the application or parts of it. + * - `authClients`: The map of enhanced authentication clients. + * - `useAuth`: A hook that accepts a client ID and returns the corresponding enhanced auth client. + */ +export function createMultiAuth, E extends Error = Error>( + authClientsMap: M, +) { + type EnhancedMap = { [K in keyof M]: EnhancedAuthClient }; + + const enhancedClientsMap = (Object.keys(authClientsMap) as (keyof M)[]).reduce( + (acc, id) => { + acc[id] = wrapAuthClient(authClientsMap[id]); + return acc; + }, + {} as EnhancedMap, + ); + + const clientsList = (Object.keys(enhancedClientsMap) as (keyof M)[]).map( + (id) => enhancedClientsMap[id], + ); + + const multiAuthContext = createContext(null); + + // Create the React Context Provider for all AuthClient instances. + const AuthProvider: React.FC = ({ children, ErrorComponent, LoadingComponent }) => { + const [initState, setInitState] = useState<{ allInitialized: boolean; failed: boolean }>({ + allInitialized: clientsList.length === 0, + failed: false, + }); + + useEffect(() => { + async function initAllClients() { + try { + const results = await Promise.all(clientsList.map((client) => client.init())); + setInitState({ allInitialized: true, failed: results.some((r: boolean) => !r) }); + } catch { + setInitState({ allInitialized: true, failed: true }); + } + } + + initAllClients(); + }, []); + + if (!!ErrorComponent && initState.failed) { + return ErrorComponent; + } + + if (!!LoadingComponent && !initState.allInitialized) { + return LoadingComponent; + } + + return ( + + {children} + + ); + }; + + /** + * Hook to access a specific authentication client by its ID within the AuthProvider. + * @throws Error if used outside of an AuthProvider + * @throws Error if the provided id is not registered in the clients map + */ + const useAuth = function (id: K): EnhancedAuthClient { + const ctx = useContext(multiAuthContext); + if (!ctx) { + throw new Error('useAuth hook should be used inside AuthProvider'); + } + const client = ctx[id]; + if (!client) { + throw new Error(`useAuth: no auth client registered for id "${String(id)}"`); + } + return client; + }; + + return { + AuthProvider, + authClients: enhancedClientsMap, + useAuth, + }; } \ No newline at end of file diff --git a/lib/src/index.ts b/lib/src/index.ts index 047edd1..3be55eb 100644 --- a/lib/src/index.ts +++ b/lib/src/index.ts @@ -1,2 +1,2 @@ -export { createAuth } from "./auth"; -export type { AuthClient } from "./auth"; +export { createAuth, createMultiAuth } from "./auth"; +export type { AuthClient, EnhancedAuthClient } from "./auth"; diff --git a/lib/test/multiAuth.spec.tsx b/lib/test/multiAuth.spec.tsx new file mode 100644 index 0000000..18e67a5 --- /dev/null +++ b/lib/test/multiAuth.spec.tsx @@ -0,0 +1,356 @@ +import React from 'react'; +import { describe, it, expect, vi, afterEach } from 'vitest'; +import * as rtl from '@testing-library/react'; +import { renderHook } from '@testing-library/react'; +import '@testing-library/jest-dom'; + +import { createMockAuthClient, flushPromises } from './test-utils'; + +import { createMultiAuth } from '../src'; + +afterEach(rtl.cleanup); + +describe('createMultiAuth', () => { + it('should return a new MultiAuth with initialized values', () => { + // Arrange / Act + const multiAuth = createMultiAuth({ + primary: createMockAuthClient(), + secondary: createMockAuthClient(), + }); + + // Assert + expect(multiAuth).toBeDefined(); + expect(multiAuth.AuthProvider).toBeDefined(); + expect(multiAuth.authClients).toBeDefined(); + expect(multiAuth.useAuth).toBeDefined(); + }); + + it('should expose all provided clients in authClients', () => { + // Arrange + const primaryClient = createMockAuthClient(); + const secondaryClient = createMockAuthClient(); + + // Act + const { authClients } = createMultiAuth({ primary: primaryClient, secondary: secondaryClient }); + + // Assert + expect(authClients.primary).toBeDefined(); + expect(authClients.secondary).toBeDefined(); + }); + + describe('useAuth hook', () => { + it('should throw error if used outside AuthProvider context', async () => { + // Arrange + const consoleErrorFn = vi + .spyOn(console, 'error') + .mockImplementation(() => vi.fn()); + + const { useAuth } = createMultiAuth({ primary: createMockAuthClient() }); + + // Act / Assert + expect(() => { + renderHook(() => useAuth('primary')); + }).toThrow('useAuth hook should be used inside AuthProvider'); + + consoleErrorFn.mockRestore(); + }); + + it('should return the correct client for a given id', async () => { + // Arrange + const primaryClient = createMockAuthClient(); + const secondaryClient = createMockAuthClient(); + + vi.spyOn(primaryClient, 'onInit').mockResolvedValue(null); + vi.spyOn(secondaryClient, 'onInit').mockResolvedValue(null); + + const { AuthProvider, authClients, useAuth } = createMultiAuth({ + primary: primaryClient, + secondary: secondaryClient, + }); + + let primaryFromHook: typeof authClients.primary | undefined; + let secondaryFromHook: typeof authClients.secondary | undefined; + + function Child() { + primaryFromHook = useAuth('primary'); + secondaryFromHook = useAuth('secondary'); + return
; + } + + // Act + rtl.render( + + + + ); + + await rtl.act(() => flushPromises()); + + // Assert + expect(primaryFromHook).toBe(authClients.primary); + expect(secondaryFromHook).toBe(authClients.secondary); + }); + }); + + describe('AuthProvider', () => { + describe('on initialization', () => { + it('should init all AuthClient instances', async () => { + // Arrange + const primaryClient = createMockAuthClient(); + const secondaryClient = createMockAuthClient(); + + const primaryInitSpy = vi + .spyOn(primaryClient, 'onInit') + .mockResolvedValue(null); + const secondaryInitSpy = vi + .spyOn(secondaryClient, 'onInit') + .mockResolvedValue(null); + + const { AuthProvider } = createMultiAuth({ + primary: primaryClient, + secondary: secondaryClient, + }); + + // Act + rtl.render( + +
+ + ); + + await rtl.act(() => flushPromises()); + + // Assert + expect(primaryInitSpy).toHaveBeenCalledTimes(1); + expect(secondaryInitSpy).toHaveBeenCalledTimes(1); + }); + + it('should handle errors during init of any client', async () => { + // Arrange + const primaryClient = createMockAuthClient(); + const secondaryClient = createMockAuthClient(); + + const primaryInitSpy = vi + .spyOn(primaryClient, 'onInit') + .mockResolvedValue(null); + vi + .spyOn(secondaryClient, 'onInit') + .mockRejectedValue(new Error('Secondary init error')); + + const { AuthProvider } = createMultiAuth({ + primary: primaryClient, + secondary: secondaryClient, + }); + + // Act + rtl.render( + +
+ + ); + + await rtl.act(() => flushPromises()); + + // Assert + expect(primaryInitSpy).toHaveBeenCalledTimes(1); + }); + + it('should display LoadingComponent if provided while not all clients are initialized', async () => { + // Arrange + const primaryClient = createMockAuthClient(); + const secondaryClient = createMockAuthClient(); + + vi.spyOn(primaryClient, 'onInit').mockResolvedValue(null); + vi.spyOn(secondaryClient, 'onInit').mockResolvedValue(null); + + const { AuthProvider } = createMultiAuth({ + primary: primaryClient, + secondary: secondaryClient, + }); + + // Act — render before async init completes + const tester = rtl.render( + Loading... + } + > +
+ + ); + + // Assert — LoadingComponent must be visible while clients are still initializing + expect(tester.getByTestId('LoadingComponent')).toBeVisible(); + expect(tester.getByTestId('LoadingComponent')).toHaveTextContent('Loading...'); + + // Allow init to finish so afterEach cleanup is not left with pending state + await rtl.act(() => flushPromises()); + }); + + it('should display ErrorComponent if provided when any client init fails', async () => { + // Arrange + const primaryClient = createMockAuthClient(); + const secondaryClient = createMockAuthClient(); + + vi.spyOn(primaryClient, 'onInit').mockResolvedValue(null); + vi + .spyOn(secondaryClient, 'onInit') + .mockRejectedValue(new Error('Secondary init error')); + + const { AuthProvider } = createMultiAuth({ + primary: primaryClient, + secondary: secondaryClient, + }); + + // Act + const tester = rtl.render( + Error!} + > +
+ + ); + + await rtl.act(() => flushPromises()); + + // Assert + expect(tester.getByTestId('ErrorComponent')).toBeVisible(); + expect(tester.getByTestId('ErrorComponent')).toHaveTextContent('Error!'); + }); + }); + + it('should add all auth client instances to context', async () => { + // Arrange + const primaryClient = createMockAuthClient(); + const secondaryClient = createMockAuthClient(); + + vi.spyOn(primaryClient, 'onInit').mockResolvedValue(null); + vi.spyOn(secondaryClient, 'onInit').mockResolvedValue(null); + + const { AuthProvider, useAuth } = createMultiAuth({ + primary: primaryClient, + secondary: secondaryClient, + }); + + function Child() { + const primary = useAuth('primary'); + const secondary = useAuth('secondary'); + return ( +
+
+ primary: {!!primary ? 'present' : 'absent'} +
+
+ secondary: {!!secondary ? 'present' : 'absent'} +
+
+ ); + } + + // Act + const tester = rtl.render( + + + + ); + + await rtl.act(() => flushPromises()); + + // Assert + expect(tester.getByTestId('primaryClient')).toHaveTextContent('primary: present'); + expect(tester.getByTestId('secondaryClient')).toHaveTextContent('secondary: present'); + }); + }); + + describe('client isolation', () => { + it('should route onLogin calls to the correct underlying client for each id', async () => { + // Arrange + const primaryClient = createMockAuthClient(); + const secondaryClient = createMockAuthClient(); + + const primaryLoginSpy = vi + .spyOn(primaryClient, 'onLogin') + .mockResolvedValue({ authToken: 'primary-token', refreshToken: 'primary-refresh' }); + const secondaryLoginSpy = vi + .spyOn(secondaryClient, 'onLogin') + .mockResolvedValue({ authToken: 'secondary-token', refreshToken: 'secondary-refresh' }); + + vi.spyOn(primaryClient, 'onInit').mockResolvedValue(null); + vi.spyOn(secondaryClient, 'onInit').mockResolvedValue(null); + + const { AuthProvider, authClients } = createMultiAuth({ + primary: primaryClient, + secondary: secondaryClient, + }); + + rtl.render( + +
+ + ); + + await rtl.act(() => flushPromises()); + + // Act + await authClients.primary.login(); + await authClients.secondary.login(); + + // Assert — each enhanced client delegates to its own underlying client + expect(primaryLoginSpy).toHaveBeenCalledTimes(1); + expect(secondaryLoginSpy).toHaveBeenCalledTimes(1); + }); + + it('should work correctly with an empty clients map', async () => { + // Arrange / Act + const { AuthProvider } = createMultiAuth({}); + + let contextAvailable = false; + + function Child() { + // verify the provider renders children immediately (no clients to wait on) + contextAvailable = true; + return
ready
; + } + + const tester = rtl.render( + + + + ); + + await rtl.act(() => flushPromises()); + + // Assert — no clients to init, children render immediately + expect(tester.getByTestId('child')).toHaveTextContent('ready'); + expect(contextAvailable).toBe(true); + }); + }); + + describe('useAuth — runtime guard', () => { + it('should throw a descriptive error when accessing an unregistered id at runtime', async () => { + // Arrange + const primaryClient = createMockAuthClient(); + vi.spyOn(primaryClient, 'onInit').mockResolvedValue(null); + + const { AuthProvider, useAuth } = createMultiAuth({ primary: primaryClient }); + + const consoleErrorFn = vi + .spyOn(console, 'error') + .mockImplementation(() => vi.fn()); + + // Act / Assert — cast to bypass TypeScript keyof check (simulates JS caller) + expect(() => { + rtl.render( + + {React.createElement(() => { + useAuth('nonexistent' as 'primary'); + return
; + })} + + ); + }).toThrow('useAuth: no auth client registered for id "nonexistent"'); + + consoleErrorFn.mockRestore(); + }); + }); +}); From ae29a68735c0b110eb9d536cfe44394eb68f327e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 28 Mar 2026 13:21:33 +0000 Subject: [PATCH 3/4] fix(react-auth): address review feedback and add README docs for createMultiAuth Agent-Logs-Url: https://github.com/forwardsoftware/react-auth/sessions/3e98ce4e-137e-43ea-9582-f13bfe494699 Co-authored-by: panz3r <1754457+panz3r@users.noreply.github.com> --- lib/README.md | 59 +++++++++++++++ lib/src/auth.tsx | 146 ++++++++++++------------------------- lib/test/provider.spec.tsx | 8 +- 3 files changed, 111 insertions(+), 102 deletions(-) diff --git a/lib/README.md b/lib/README.md index 096882e..92696ca 100644 --- a/lib/README.md +++ b/lib/README.md @@ -147,6 +147,65 @@ The `createAuth` function wraps your `AuthClient` implementation with an `Enhanc - `subscribe(() => { })`, subscribe to AuthClient state changes - `getSnapshot()`, returns the current state of the AuthClient +--- + +### Use multiple AuthClients + +When your app needs to support multiple authentication providers simultaneously (e.g. username/password alongside Google Sign-In), use `createMultiAuth`: + +```ts +import { createMultiAuth } from '@forward-software/react-auth'; + +export const { AuthProvider, authClients, useAuth } = createMultiAuth({ + credentials: credentialsAuthClient, + google: googleAuthClient, +}); +``` + +The `createMultiAuth` function accepts a map of `{ id: AuthClient }` pairs and returns: + +- `AuthProvider`, the context Provider component that initialises **all** clients and provides access to them +- `authClients`, a map of enhanced authentication clients keyed by the IDs you provided +- `useAuth`, a hook that accepts a client ID and returns the corresponding enhanced auth client + +#### AuthProvider + +The same `LoadingComponent` and `ErrorComponent` props are supported. `LoadingComponent` is shown until **all** clients finish initializing. `ErrorComponent` is shown if **any** client's initialization fails. + +```tsx +} + ErrorComponent={} +> + + +``` + +#### useAuth + +The `useAuth` hook is generic — the return type is automatically narrowed to the exact `EnhancedAuthClient` type for the key you provide: + +```tsx +function MyComponent() { + // Each call is fully typed based on the key + const credentialsClient = useAuth('credentials'); + const googleClient = useAuth('google'); + + return ( + <> + + + + ); +} +``` + +Each client provides the same `EnhancedAuthClient` interface described above. + ## Examples The [`examples`](https://github.com/forwardsoftware/react-auth/tree/main/examples) folder in the repository contains some examples of how you can integrate this library in your React app. diff --git a/lib/src/auth.tsx b/lib/src/auth.tsx index 00e74d8..eaddda5 100644 --- a/lib/src/auth.tsx +++ b/lib/src/auth.tsx @@ -1,6 +1,5 @@ import React, { createContext, useContext, useEffect, useState } from 'react'; import type { PropsWithChildren } from 'react'; -import { useSyncExternalStore } from 'use-sync-external-store/shim'; import { createEventEmitter, Deferred, EventReceiver } from "./utils"; import type { EventKey } from "./utils"; @@ -452,23 +451,6 @@ export function wrapAuthClient(a return instance as unknown as EnhancedAuthClient; } -/** - * Represents the current state of the authentication provider - */ -type AuthProviderState = { - isAuthenticated: boolean; - isInitialized: boolean; -}; - -/** - * The authentication context containing both the state and the enhanced auth client - * @template AC - The AuthClient implementation type - * @template E - The error type used throughout the authentication flow - */ -type AuthContext = AuthProviderState & { - authClient: EnhancedAuthClient; -}; - /** * Props that can be passed to AuthProvider */ @@ -484,81 +466,6 @@ export type AuthProviderProps = PropsWithChildren<{ LoadingComponent?: React.ReactNode; }>; -/** - * Creates an authentication context and provider for a React application. - * It wraps the provided `authClient` with enhanced state management and event handling. - * - * @template AC - The type of the base `AuthClient` implementation. - * @template E - The type of error expected during authentication flows. Defaults to `Error`. - * @param {AC} authClient - The base authentication client instance to use. - * @returns An object containing: - * - `AuthProvider`: A React component to wrap the application or parts of it. - * - `authClient`: The enhanced authentication client instance. - * - `useAuthClient`: A hook to access the enhanced `authClient` within the `AuthProvider`. - */ -export function createAuth(authClient: AC) { - // Create a React context containing an AuthClient instance. - const authContext = createContext | null>(null); - - const enhancedAuthClient = wrapAuthClient(authClient); - - // Create the React Context Provider for the AuthClient instance. - const AuthProvider: React.FC = ({ children, ErrorComponent, LoadingComponent }) => { - const [isInitFailed, setInitFailed] = useState(false); - const { isAuthenticated, isInitialized } = useSyncExternalStore(enhancedAuthClient.subscribe, enhancedAuthClient.getSnapshot); - - useEffect(() => { - async function initAuthClient() { - // Call init function - const initSuccess = await enhancedAuthClient.init(); - setInitFailed(!initSuccess); - } - - // Init AuthClient - initAuthClient(); - }, []); - - if (!!ErrorComponent && isInitFailed) { - return ErrorComponent; - } - - if (!!LoadingComponent && !isInitialized) { - return LoadingComponent; - } - - return ( - - {children} - - ); - }; - - /** - * Hook to access the authentication client within the AuthProvider - * @throws Error if used outside of an AuthProvider - */ - const useAuthClient = function (): EnhancedAuthClient { - const ctx = useContext(authContext); - if (!ctx) { - throw new Error('useAuthClient hook should be used inside AuthProvider'); - } - - return ctx.authClient; - }; - - return { - AuthProvider, - authClient: enhancedAuthClient, - useAuthClient, - }; -} - /** * Creates an authentication context and provider supporting multiple auth clients. * Each client is identified by a string key. @@ -581,7 +488,7 @@ export function createMultiAuth, E extends acc[id] = wrapAuthClient(authClientsMap[id]); return acc; }, - {} as EnhancedMap, + Object.create(null) as EnhancedMap, ); const clientsList = (Object.keys(enhancedClientsMap) as (keyof M)[]).map( @@ -599,12 +506,13 @@ export function createMultiAuth, E extends useEffect(() => { async function initAllClients() { - try { - const results = await Promise.all(clientsList.map((client) => client.init())); - setInitState({ allInitialized: true, failed: results.some((r: boolean) => !r) }); - } catch { - setInitState({ allInitialized: true, failed: true }); - } + // Each client's init() is wrapped with .catch() so that a rejection from one client + // (e.g. an onPostInit error) does not short-circuit the others; all clients always + // get the chance to finish initializing before we update the provider state. + const results = await Promise.all( + clientsList.map((client) => client.init().catch((): boolean => false)), + ); + setInitState({ allInitialized: true, failed: results.some((r) => !r) }); } initAllClients(); @@ -647,4 +555,42 @@ export function createMultiAuth, E extends authClients: enhancedClientsMap, useAuth, }; +} + +/** + * Creates an authentication context and provider for a React application. + * It wraps the provided `authClient` with enhanced state management and event handling. + * + * This is a convenience wrapper around `createMultiAuth` for the common single-provider case. + * Internally it registers the client under the key `'default'` and re-exports a + * `useAuthClient` hook that delegates to `useAuth('default')`. + * + * @template AC - The type of the base `AuthClient` implementation. + * @template E - The type of error expected during authentication flows. Defaults to `Error`. + * @param {AC} authClient - The base authentication client instance to use. + * @returns An object containing: + * - `AuthProvider`: A React component to wrap the application or parts of it. + * - `authClient`: The enhanced authentication client instance. + * - `useAuthClient`: A hook to access the enhanced `authClient` within the `AuthProvider`. + */ +export function createAuth(authClient: AC) { + const { AuthProvider, authClients, useAuth } = createMultiAuth<{ default: AC }, E>({ default: authClient }); + + /** + * Hook to access the authentication client within the AuthProvider + * @throws Error if used outside of an AuthProvider + */ + const useAuthClient = function (): EnhancedAuthClient { + try { + return useAuth('default'); + } catch { + throw new Error('useAuthClient hook should be used inside AuthProvider'); + } + }; + + return { + AuthProvider, + authClient: authClients.default, + useAuthClient, + }; } \ No newline at end of file diff --git a/lib/test/provider.spec.tsx b/lib/test/provider.spec.tsx index fc7edd0..4c0d365 100644 --- a/lib/test/provider.spec.tsx +++ b/lib/test/provider.spec.tsx @@ -52,9 +52,11 @@ describe('AuthProvider', () => { it('should diplay LoadingComponent if provided', async () => { const authClientStub = createMockAuthClient(); + vi.spyOn(authClientStub, 'onInit').mockResolvedValue(null); const { AuthProvider } = createAuth(authClientStub); + // Act — render before async init completes const tester = rtl.render( { ); - await rtl.act(() => flushPromises()); - + // Assert — LoadingComponent must be visible while the client is still initializing expect(tester.getByTestId('LoadingComponent')).toBeVisible(); expect(tester.getByTestId('LoadingComponent')).toHaveTextContent( 'Loading...' ); + + // Allow init to finish so afterEach cleanup is not left with pending state + await rtl.act(() => flushPromises()); }); it('should diplay ErrorComponent if provided', async () => { From b3ed4c258b91ea71d33d1ed08b0be7f0d7662545 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 28 Mar 2026 13:36:13 +0000 Subject: [PATCH 4/4] chore(react-auth): remove use-sync-external-store dependency Agent-Logs-Url: https://github.com/forwardsoftware/react-auth/sessions/dc5e5d91-0c76-4981-be2d-7a45d09981e6 Co-authored-by: panz3r <1754457+panz3r@users.noreply.github.com> --- lib/package.json | 5 +---- pnpm-lock.yaml | 12 ------------ 2 files changed, 1 insertion(+), 16 deletions(-) diff --git a/lib/package.json b/lib/package.json index 2121faa..3465532 100644 --- a/lib/package.json +++ b/lib/package.json @@ -40,7 +40,6 @@ "@types/node": "^25.2.3", "@types/react": "catalog:", "@types/react-dom": "catalog:", - "@types/use-sync-external-store": "^1.5.0", "@vitejs/plugin-react": "catalog:", "jsdom": "catalog:", "react": "catalog:", @@ -48,9 +47,7 @@ "vite": "catalog:", "vitest": "catalog:" }, - "dependencies": { - "use-sync-external-store": "^1.6.0" - }, + "dependencies": {}, "peerDependencies": { "react": ">=16.8" } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0019a9b..99df1cf 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -55,10 +55,6 @@ importers: version: 6.0.2 lib: - dependencies: - use-sync-external-store: - specifier: ^1.6.0 - version: 1.6.0(react@19.2.4) devDependencies: '@testing-library/dom': specifier: ^10.4.1 @@ -78,9 +74,6 @@ importers: '@types/react-dom': specifier: 'catalog:' version: 19.2.3(@types/react@19.2.14) - '@types/use-sync-external-store': - specifier: ^1.5.0 - version: 1.5.0 '@vitejs/plugin-react': specifier: 'catalog:' version: 6.0.1(vite@8.0.3(@types/node@25.5.0)) @@ -398,9 +391,6 @@ packages: '@types/react@19.2.14': resolution: {integrity: sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==} - '@types/use-sync-external-store@1.5.0': - resolution: {integrity: sha512-5dyB8nLC/qogMrlCizZnYWQTA4lnb/v+It+sqNl5YnSRAPMlIqY/X0Xn+gZw8vOL+TgTTr28VEbn3uf8fUtAkw==} - '@vitejs/plugin-react@6.0.1': resolution: {integrity: sha512-l9X/E3cDb+xY3SWzlG1MOGt2usfEHGMNIaegaUGFsLkb3RCn/k8/TOXBcab+OndDI4TBtktT8/9BwwW8Vi9KUQ==} engines: {node: ^20.19.0 || >=22.12.0} @@ -1191,8 +1181,6 @@ snapshots: dependencies: csstype: 3.2.3 - '@types/use-sync-external-store@1.5.0': {} - '@vitejs/plugin-react@6.0.1(vite@8.0.3(@types/node@25.5.0))': dependencies: '@rolldown/pluginutils': 1.0.0-rc.7