Repository: authts/oidc-client-ts (ts)

Issue:
OIDC Client; can refresh token externally as RefreshState is not exportered
I am using the OIDC client instead of the user manager as need to do some low level stuff with service workers.

But the `useRefreshToken` method of the needs an instance of  RefreshState; which is not exported 

Pull request:
Make 'RefreshState' public
Should fix #1157

Patch:
diff --git a/docs/oidc-client-ts.api.md b/docs/oidc-client-ts.api.md
index a7b7a237..65372e72 100644
--- a/docs/oidc-client-ts.api.md
+++ b/docs/oidc-client-ts.api.md
@@ -128,6 +128,14 @@ export interface ILogger {
     warn(...args: unknown[]): void;
 }
 
+// @public (undocumented)
+export interface INavigator {
+    // (undocumented)
+    callback(url: string, params?: unknown): Promise<void>;
+    // (undocumented)
+    prepare(params: unknown): Promise<IWindow>;
+}
+
 // @public (undocumented)
 export class InMemoryWebStorage implements Storage {
     // (undocumented)
@@ -144,6 +152,14 @@ export class InMemoryWebStorage implements Storage {
     setItem(key: string, value: string): void;
 }
 
+// @public (undocumented)
+export interface IWindow {
+    // (undocumented)
+    close(): void;
+    // (undocumented)
+    navigate(params: NavigateParams): Promise<NavigateResponse>;
+}
+
 // @public
 export interface JwtClaims {
     // (undocumented)
@@ -243,6 +259,24 @@ export class MetadataService {
     resetSigningKeys(): void;
 }
 
+// @public (undocumented)
+export interface NavigateParams {
+    nonce?: string;
+    // (undocumented)
+    response_mode?: "query" | "fragment";
+    // (undocumented)
+    scriptOrigin?: string;
+    state?: string;
+    // (undocumented)
+    url: string;
+}
+
+// @public (undocumented)
+export interface NavigateResponse {
+    // (undocumented)
+    url: string;
+}
+
 // @public
 export interface OidcAddressClaim {
     country?: string;
@@ -530,6 +564,31 @@ export interface RedirectParams {
     redirectTarget?: "top" | "self";
 }
 
+// @public
+export class RefreshState {
+    constructor(args: {
+        refresh_token: string;
+        id_token?: string;
+        session_state: string | null;
+        scope?: string;
+        profile: UserProfile;
+        state?: unknown;
+    }, resource?: string | string[]);
+    readonly data?: unknown;
+    // (undocumented)
+    readonly id_token?: string;
+    // (undocumented)
+    readonly profile: UserProfile;
+    // (undocumented)
+    readonly refresh_token: string;
+    // (undocumented)
+    readonly resource?: string | string[];
+    // (undocumented)
+    readonly scope?: string;
+    // (undocumented)
+    readonly session_state: string | null;
+}
+
 // @public (undocumented)
 export type RevokeTokensTypes = UserManagerSettings["revokeTokenTypes"];
 
@@ -835,8 +894,6 @@ export class User {
 
 // @public (undocumented)
 export interface UseRefreshTokenArgs {
-    // Warning: (ae-forgotten-export) The symbol "RefreshState" needs to be exported by the entry point index.d.ts
-    //
     // (undocumented)
     state: RefreshState;
     // (undocumented)
@@ -848,7 +905,7 @@ export type UserLoadedCallback = (user: User) => Promise<void> | void;
 
 // @public
 export class UserManager {
-    constructor(settings: UserManagerSettings);
+    constructor(settings: UserManagerSettings, redirectNavigator?: INavigator, popupNavigator?: INavigator, iframeNavigator?: INavigator);
     // (undocumented)
     protected _buildUser(signinResponse: SigninResponse, verifySub?: string): Promise<User>;
     clearStaleState(): Promise<void>;
@@ -858,24 +915,18 @@ export class UserManager {
     // (undocumented)
     protected readonly _events: UserManagerEvents;
     getUser(): Promise<User | null>;
-    // Warning: (ae-forgotten-export) The symbol "IFrameNavigator" needs to be exported by the entry point index.d.ts
-    //
     // (undocumented)
-    protected readonly _iframeNavigator: IFrameNavigator;
+    protected readonly _iframeNavigator: INavigator;
     // (undocumented)
     protected _loadUser(): Promise<User | null>;
     // (undocumented)
     protected readonly _logger: Logger;
     get metadataService(): MetadataService;
-    // Warning: (ae-forgotten-export) The symbol "PopupNavigator" needs to be exported by the entry point index.d.ts
-    //
     // (undocumented)
-    protected readonly _popupNavigator: PopupNavigator;
+    protected readonly _popupNavigator: INavigator;
     querySessionStatus(args?: QuerySessionStatusArgs): Promise<SessionStatus | null>;
-    // Warning: (ae-forgotten-export) The symbol "RedirectNavigator" needs to be exported by the entry point index.d.ts
-    //
     // (undocumented)
-    protected readonly _redirectNavigator: RedirectNavigator;
+    protected readonly _redirectNavigator: INavigator;
     removeUser(): Promise<void>;
     // (undocumented)
     protected _revokeInternal(user: User | null, types?: ("access_token" | "refresh_token")[]): Promise<void>;
@@ -884,8 +935,6 @@ export class UserManager {
     // (undocumented)
     protected readonly _sessionMonitor: SessionMonitor | null;
     readonly settings: UserManagerSettingsStore;
-    // Warning: (ae-forgotten-export) The symbol "IWindow" needs to be exported by the entry point index.d.ts
-    //
     // (undocumented)
     protected _signin(args: CreateSigninRequestArgs, handle: IWindow, verifySub?: string): Promise<User>;
     // (undocumented)
@@ -899,8 +948,6 @@ export class UserManager {
     signinResourceOwnerCredentials({ username, password, skipUserInfo, }: SigninResourceOwnerCredentialsArgs): Promise<User>;
     signinSilent(args?: SigninSilentArgs): Promise<User | null>;
     signinSilentCallback(url?: string): Promise<void>;
-    // Warning: (ae-forgotten-export) The symbol "NavigateResponse" needs to be exported by the entry point index.d.ts
-    //
     // (undocumented)
     protected _signinStart(args: CreateSigninRequestArgs, handle: IWindow): Promise<NavigateResponse>;
     // (undocumented)
diff --git a/src/RefreshState.ts b/src/RefreshState.ts
index 794a07ee..c2187aa7 100644
--- a/src/RefreshState.ts
+++ b/src/RefreshState.ts
@@ -6,7 +6,7 @@ import type { UserProfile } from "./User";
 /**
  * Fake state store implementation necessary for validating refresh token requests.
  *
- * @internal
+ * @public
  */
 export class RefreshState {
     /** custom "state", which can be used by a caller to have "data" round tripped */
diff --git a/src/UserManager.ts b/src/UserManager.ts
index 810c6f8c..35ab80cc 100644
--- a/src/UserManager.ts
+++ b/src/UserManager.ts
@@ -3,8 +3,7 @@
 
 import { Logger } from "./utils";
 import { ErrorResponse } from "./errors";
-import { IFrameNavigator, type NavigateResponse, PopupNavigator, RedirectNavigator, type PopupWindowParams,
-    type IWindow, type IFrameWindowParams, type RedirectParams } from "./navigators";
+import { type NavigateResponse, type PopupWindowParams, type IWindow, type IFrameWindowParams, type RedirectParams, RedirectNavigator, PopupNavigator, IFrameNavigator, type INavigator } from "./navigators";
 import { OidcClient, type CreateSigninRequestArgs, type CreateSignoutRequestArgs, type ProcessResourceOwnerPasswordCredentialsArgs } from "./OidcClient";
 import { type UserManagerSettings, UserManagerSettingsStore } from "./UserManagerSettings";
 import { User } from "./User";
@@ -83,21 +82,21 @@ export class UserManager {
     protected readonly _logger = new Logger("UserManager");
 
     protected readonly _client: OidcClient;
-    protected readonly _redirectNavigator: RedirectNavigator;
-    protected readonly _popupNavigator: PopupNavigator;
-    protected readonly _iframeNavigator: IFrameNavigator;
+    protected readonly _redirectNavigator: INavigator;
+    protected readonly _popupNavigator: INavigator;
+    protected readonly _iframeNavigator: INavigator;
     protected readonly _events: UserManagerEvents;
     protected readonly _silentRenewService: SilentRenewService;
     protected readonly _sessionMonitor: SessionMonitor | null;
 
-    public constructor(settings: UserManagerSettings) {
+    public constructor(settings: UserManagerSettings, redirectNavigator?: INavigator, popupNavigator?: INavigator, iframeNavigator?: INavigator) {
         this.settings = new UserManagerSettingsStore(settings);
 
         this._client = new OidcClient(settings);
 
-        this._redirectNavigator = new RedirectNavigator(this.settings);
-        this._popupNavigator = new PopupNavigator(this.settings);
-        this._iframeNavigator = new IFrameNavigator(this.settings);
+        this._redirectNavigator = redirectNavigator ?? new RedirectNavigator(this.settings);
+        this._popupNavigator = popupNavigator ?? new PopupNavigator(this.settings);
+        this._iframeNavigator = iframeNavigator ?? new IFrameNavigator(this.settings);
 
         this._events = new UserManagerEvents(this.settings);
         this._silentRenewService = new SilentRenewService(this);
@@ -244,7 +243,7 @@ export class UserManager {
      */
     public async signinPopupCallback(url = window.location.href, keepOpen = false): Promise<void> {
         const logger = this._logger.create("signinPopupCallback");
-        await this._popupNavigator.callback(url, keepOpen);
+        await this._popupNavigator.callback(url, { keepOpen });
         logger.info("success");
     }
 
@@ -525,7 +524,7 @@ export class UserManager {
      */
     public async signoutPopupCallback(url = window.location.href, keepOpen = false): Promise<void> {
         const logger = this._logger.create("signoutPopupCallback");
-        await this._popupNavigator.callback(url, keepOpen);
+        await this._popupNavigator.callback(url, { keepOpen });
         logger.info("success");
     }
 
diff --git a/src/index.ts b/src/index.ts
index e69e2d55..7f630196 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -2,7 +2,7 @@
 // Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
 
 export { ErrorResponse, ErrorTimeout } from "./errors";
-export type { IFrameWindowParams, PopupWindowParams, RedirectParams } from "./navigators";
+export type { INavigator, IFrameWindowParams, IWindow, NavigateParams, NavigateResponse, PopupWindowParams, RedirectParams } from "./navigators";
 export { Log, Logger } from "./utils";
 export type { ILogger, PopupWindowFeatures } from "./utils";
 export type { OidcAddressClaim, OidcStandardClaims, IdTokenClaims, JwtClaims } from "./Claims";
@@ -20,6 +20,7 @@ export type { OidcMetadata } from "./OidcMetadata";
 export { SessionMonitor } from "./SessionMonitor";
 export type { SessionStatus } from "./SessionStatus";
 export type { SigninRequest, SigninRequestArgs } from "./SigninRequest";
+export type { RefreshState } from "./RefreshState";
 export { SigninResponse } from "./SigninResponse";
 export { SigninState } from "./SigninState";
 export type { SignoutRequest, SignoutRequestArgs } from "./SignoutRequest";
diff --git a/src/navigators/INavigator.ts b/src/navigators/INavigator.ts
index 09b24827..b99696dd 100644
--- a/src/navigators/INavigator.ts
+++ b/src/navigators/INavigator.ts
@@ -4,8 +4,10 @@
 import type { IWindow } from "./IWindow";
 
 /**
- * @internal
+ * @public
  */
 export interface INavigator {
     prepare(params: unknown): Promise<IWindow>;
+
+    callback(url: string, params?: unknown): Promise<void>;
 }
diff --git a/src/navigators/IWindow.ts b/src/navigators/IWindow.ts
index 0975aa63..5792205c 100644
--- a/src/navigators/IWindow.ts
+++ b/src/navigators/IWindow.ts
@@ -1,7 +1,7 @@
 // Copyright (c) Brock Allen & Dominick Baier. All rights reserved.
 // Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
 /**
- * @internal
+ * @public
  */
 export interface NavigateParams {
     url: string;
@@ -14,14 +14,14 @@ export interface NavigateParams {
 }
 
 /**
- * @internal
+ * @public
  */
 export interface NavigateResponse {
     url: string;
 }
 
 /**
- * @internal
+ * @public
  */
 export interface IWindow {
     navigate(params: NavigateParams): Promise<NavigateResponse>;
diff --git a/src/navigators/PopupNavigator.ts b/src/navigators/PopupNavigator.ts
index b2666ec0..11c80fce 100644
--- a/src/navigators/PopupNavigator.ts
+++ b/src/navigators/PopupNavigator.ts
@@ -21,7 +21,7 @@ export class PopupNavigator implements INavigator {
         return new PopupWindow({ popupWindowFeatures, popupWindowTarget });
     }
 
-    public async callback(url: string, keepOpen = false): Promise<void> {
+    public async callback(url: string, { keepOpen = false }): Promise<void> {
         this._logger.create("callback");
 
         PopupWindow.notifyOpener(url, keepOpen);
diff --git a/src/navigators/RedirectNavigator.ts b/src/navigators/RedirectNavigator.ts
index 2c16b9ed..e5cb2757 100644
--- a/src/navigators/RedirectNavigator.ts
+++ b/src/navigators/RedirectNavigator.ts
@@ -52,4 +52,8 @@ export class RedirectNavigator implements INavigator {
             },
         };
     }
+
+    public async callback(): Promise<void> {
+        return;
+    }
 }


Test patch:
diff --git a/src/UserManager.test.ts b/src/UserManager.test.ts
index 25fe9646..30ef5c5c 100644
--- a/src/UserManager.test.ts
+++ b/src/UserManager.test.ts
@@ -2,7 +2,7 @@
 // Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
 
 import { once } from "events";
-import type { PopupWindow } from "./navigators";
+import { RedirectNavigator, type PopupWindow, PopupNavigator, IFrameNavigator } from "./navigators";
 import type { SigninResponse } from "./SigninResponse";
 import type { SignoutResponse } from "./SignoutResponse";
 import { UserManager, type SigninPopupArgs, type SigninRedirectArgs, type SigninSilentArgs, type SignoutSilentArgs } from "./UserManager";
@@ -59,6 +59,30 @@ describe("UserManager", () => {
                 expect(sessionMonitor).toBeNull();
             }
         });
+
+        it("should accept redirectNavigator", () => {
+            const customRedirectNavigator = new RedirectNavigator(subject.settings);
+
+            const userManager = new UserManager(subject.settings, customRedirectNavigator);
+
+            expect(userManager["_redirectNavigator"]).toBe(customRedirectNavigator);
+        });
+
+        it("should accept popupNavigator", () => {
+            const customPopupNavigator = new PopupNavigator(subject.settings);
+
+            const userManager = new UserManager(subject.settings, undefined, customPopupNavigator);
+
+            expect(userManager["_popupNavigator"]).toBe(customPopupNavigator);
+        });
+
+        it("should accept iframeNavigator", () => {
+            const customiframeNavigator = new IFrameNavigator(subject.settings);
+
+            const userManager = new UserManager(subject.settings, undefined, undefined, customiframeNavigator);
+
+            expect(userManager["_iframeNavigator"]).toBe(customiframeNavigator);
+        });
     });
 
     describe("settings", () => {
@@ -248,11 +272,6 @@ describe("UserManager", () => {
             // arrange
             const spy = jest.spyOn(subject["_client"], "processSigninResponse")
                 .mockResolvedValue({} as SigninResponse);
-            await userStoreMock.set("test", JSON.stringify({
-                id: "test",
-                request_type: "si:r",
-                ...subject.settings,
-            }));
 
             // act
             const user = await subject.signinRedirectCallback("http://app/cb?state=test&code=code");
@@ -375,7 +394,7 @@ describe("UserManager", () => {
             await subject.signinPopupCallback(url, keepOpen);
 
             // assert
-            expect(callbackMock).toBeCalledWith(url, keepOpen);
+            expect(callbackMock).toBeCalledWith(url, { keepOpen });
         });
     });