diff --git a/eslint.config.mjs b/eslint.config.mjs index b5e9db49..b5bb3924 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -2,6 +2,7 @@ import { fixupConfigRules } from '@eslint/compat'; import { FlatCompat } from '@eslint/eslintrc'; import js from '@eslint/js'; import prettier from 'eslint-plugin-prettier'; +import tseslint from 'typescript-eslint'; import { defineConfig } from 'eslint/config'; import path from 'node:path'; import { fileURLToPath } from 'node:url'; @@ -32,6 +33,23 @@ export default defineConfig([ ], }, }, + // TypeScript-specific configuration for type-checked rules + { + files: ['**/*.ts', '**/*.tsx'], + ignores: ['**/__tests__/**', '**/__mocks__/**', '**/*.spec.ts', '**/*.spec.tsx', '**/*.test.ts', '**/*.test.tsx'], + languageOptions: { + parserOptions: { + project: true, + tsconfigRootDir: import.meta.dirname, + }, + }, + rules: { + // Enable unbound-method rule to catch interface typing issues + // This helps ensure methods in interfaces use arrow function syntax + // instead of method syntax when they don't use 'this' + '@typescript-eslint/unbound-method': 'error', + }, + }, { ignores: ['node_modules/', 'lib/', 'docs'], }, diff --git a/package.json b/package.json index ce4f8122..6f5007c4 100644 --- a/package.json +++ b/package.json @@ -132,7 +132,8 @@ "typedoc": "^0.28.2", "typedoc-plugin-missing-exports": "^4.0.0", "typedoc-plugin-replace-text": "^4.2.0", - "typescript": "5.2.2" + "typescript": "5.2.2", + "typescript-eslint": "^8.46.2" }, "dependencies": { "@auth0/auth0-spa-js": "2.7.0", diff --git a/src/hooks/Auth0Context.ts b/src/hooks/Auth0Context.ts index 0d396085..44140373 100644 --- a/src/hooks/Auth0Context.ts +++ b/src/hooks/Auth0Context.ts @@ -39,10 +39,10 @@ export interface Auth0ContextInterface extends AuthState { * @returns A promise that resolves with the user's credentials upon successful authentication. * @throws {AuthError} If the authentication fails. */ - authorize( + authorize: ( parameters?: WebAuthorizeParameters, options?: NativeAuthorizeOptions - ): Promise; + ) => Promise; /** * Clears the user's session and logs them out. @@ -51,10 +51,10 @@ export interface Auth0ContextInterface extends AuthState { * @returns A promise that resolves when the session has been cleared. * @throws {AuthError} If the logout fails. */ - clearSession( + clearSession: ( parameters?: ClearSessionParameters, options?: NativeClearSessionOptions - ): Promise; + ) => Promise; /** * Saves the user's credentials. @@ -62,7 +62,7 @@ export interface Auth0ContextInterface extends AuthState { * @returns A promise that resolves when the credentials have been saved. * @throws {AuthError} If the save fails. */ - saveCredentials(credentials: Credentials): Promise; + saveCredentials: (credentials: Credentials) => Promise; /** * Retrieves the stored credentials, refreshing them if necessary. @@ -73,12 +73,12 @@ export interface Auth0ContextInterface extends AuthState { * @returns A promise that resolves with the user's credentials. * @throws {AuthError} If credentials cannot be retrieved or refreshed. */ - getCredentials( + getCredentials: ( scope?: string, minTtl?: number, parameters?: Record, forceRefresh?: boolean - ): Promise; + ) => Promise; /** * Clears the user's credentials without clearing their web session and logs them out. @@ -96,13 +96,13 @@ export interface Auth0ContextInterface extends AuthState { * @param minTtl The minimum time-to-live (in seconds) required for the access token to be considered valid. Defaults to 0. * @returns A promise that resolves with `true` if valid credentials exist, `false` otherwise. */ - hasValidCredentials(minTtl?: number): Promise; + hasValidCredentials: (minTtl?: number) => Promise; /** * Cancels the ongoing web authentication process. * This works only on iOS. On other platforms, it will resolve without performing an action. */ - cancelWebAuth(): Promise; + cancelWebAuth: () => Promise; /** * Authenticates a user with their username and password. @@ -111,9 +111,9 @@ export interface Auth0ContextInterface extends AuthState { * @returns A promise that resolves with the user's credentials. * @throws {AuthError} If the authentication fails. */ - loginWithPasswordRealm( + loginWithPasswordRealm: ( parameters: PasswordRealmParameters - ): Promise; + ) => Promise; /** * Creates a new user in a database connection. @@ -121,7 +121,7 @@ export interface Auth0ContextInterface extends AuthState { * @returns A promise that resolves with the new user's profile information. * @throws {AuthError} If the user creation fails. */ - createUser(parameters: CreateUserParameters): Promise>; + createUser: (parameters: CreateUserParameters) => Promise>; /** * Resets the user's password. @@ -129,7 +129,7 @@ export interface Auth0ContextInterface extends AuthState { * @returns A promise that resolves when the password has been reset. * @throws {AuthError} If the reset fails. */ - resetPassword(parameters: ResetPasswordParameters): Promise; + resetPassword: (parameters: ResetPasswordParameters) => Promise; /** * Exchanges an authorization code for tokens. @@ -138,7 +138,9 @@ export interface Auth0ContextInterface extends AuthState { * @returns A promise that resolves with the user's credentials. * @throws {AuthError} If the exchange fails. */ - authorizeWithExchange(parameters: ExchangeParameters): Promise; + authorizeWithExchange: ( + parameters: ExchangeParameters + ) => Promise; /** * Exchanges an authorization code for native social tokens. @@ -146,16 +148,16 @@ export interface Auth0ContextInterface extends AuthState { * @returns A promise that resolves with the user's credentials. * @throws {AuthError} If the exchange fails. */ - authorizeWithExchangeNativeSocial( + authorizeWithExchangeNativeSocial: ( parameters: ExchangeNativeSocialParameters - ): Promise; + ) => Promise; /** * Sends a verification code to the user's email. * @param parameters The parameters for sending the email code. * @throws {AuthError} If sending the email code fails. */ - sendEmailCode(parameters: PasswordlessEmailParameters): Promise; + sendEmailCode: (parameters: PasswordlessEmailParameters) => Promise; /** * Authorizes a user with their email. @@ -163,7 +165,9 @@ export interface Auth0ContextInterface extends AuthState { * @returns A promise that resolves with the user's credentials. * @throws {AuthError} If the authorization fails. */ - authorizeWithEmail(parameters: LoginEmailParameters): Promise; + authorizeWithEmail: ( + parameters: LoginEmailParameters + ) => Promise; /** /** @@ -171,7 +175,7 @@ export interface Auth0ContextInterface extends AuthState { * @param parameters The parameters for sending the SMS code. * @throws {AuthError} If sending the SMS code fails. */ - sendSMSCode(parameters: PasswordlessSmsParameters): Promise; + sendSMSCode: (parameters: PasswordlessSmsParameters) => Promise; /** * Authorizes a user with their SMS. @@ -179,7 +183,7 @@ export interface Auth0ContextInterface extends AuthState { * @returns A promise that resolves with the user's credentials. * @throws {AuthError} If the authorization fails. */ - authorizeWithSMS(parameters: LoginSmsParameters): Promise; + authorizeWithSMS: (parameters: LoginSmsParameters) => Promise; /** * Sends a multifactor challenge to the user. @@ -187,9 +191,9 @@ export interface Auth0ContextInterface extends AuthState { * @returns A promise that resolves when the challenge has been sent. * @throws {AuthError} If sending the challenge fails. */ - sendMultifactorChallenge( + sendMultifactorChallenge: ( parameters: MfaChallengeParameters - ): Promise; + ) => Promise; /** * Authorizes a user with out-of-band (OOB) authentication. @@ -197,7 +201,7 @@ export interface Auth0ContextInterface extends AuthState { * @returns A promise that resolves with the user's credentials. * @throws {AuthError} If the authorization fails. */ - authorizeWithOOB(parameters: LoginOobParameters): Promise; + authorizeWithOOB: (parameters: LoginOobParameters) => Promise; /** * Authorizes a user with a one-time password (OTP). @@ -205,7 +209,7 @@ export interface Auth0ContextInterface extends AuthState { * @returns A promise that resolves with the user's credentials. * @throws {AuthError} If the authorization fails. */ - authorizeWithOTP(parameters: LoginOtpParameters): Promise; + authorizeWithOTP: (parameters: LoginOtpParameters) => Promise; /** * Authorizes a user with a recovery code. @@ -213,12 +217,12 @@ export interface Auth0ContextInterface extends AuthState { * @returns A promise that resolves with the user's credentials. * @throws {AuthError} If the authorization fails. */ - authorizeWithRecoveryCode( + authorizeWithRecoveryCode: ( parameters: LoginRecoveryCodeParameters - ): Promise; + ) => Promise; // Token Management - revokeRefreshToken(parameters: RevokeOptions): Promise; + revokeRefreshToken: (parameters: RevokeOptions) => Promise; /** * Generates DPoP headers for making authenticated requests to custom APIs. @@ -244,7 +248,9 @@ export interface Auth0ContextInterface extends AuthState { * } * ``` */ - getDPoPHeaders(params: DPoPHeadersParams): Promise>; + getDPoPHeaders: ( + params: DPoPHeadersParams + ) => Promise>; } const stub = (): any => { diff --git a/src/platforms/native/bridge/NativeBridgeManager.ts b/src/platforms/native/bridge/NativeBridgeManager.ts index 8b242ab6..dbf82f68 100644 --- a/src/platforms/native/bridge/NativeBridgeManager.ts +++ b/src/platforms/native/bridge/NativeBridgeManager.ts @@ -40,7 +40,9 @@ export class NativeBridgeManager implements INativeBridge { async hasValidInstance(clientId: string, domain: string): Promise { return this.a0_call( - Auth0NativeModule.hasValidAuth0InstanceWithConfiguration, + Auth0NativeModule.hasValidAuth0InstanceWithConfiguration.bind( + Auth0NativeModule + ), clientId, domain ); @@ -55,7 +57,9 @@ export class NativeBridgeManager implements INativeBridge { // This is a new method we'd add to the native side to ensure the // underlying Auth0.swift/Auth0.android SDKs are configured. return this.a0_call( - Auth0NativeModule.initializeAuth0WithConfiguration, + Auth0NativeModule.initializeAuth0WithConfiguration.bind( + Auth0NativeModule + ), clientId, domain, localAuthenticationOptions, @@ -64,7 +68,9 @@ export class NativeBridgeManager implements INativeBridge { } getBundleIdentifier(): Promise { - return this.a0_call(Auth0NativeModule.getBundleIdentifier); + return this.a0_call( + Auth0NativeModule.getBundleIdentifier.bind(Auth0NativeModule) + ); } async authorize( @@ -79,7 +85,7 @@ export class NativeBridgeManager implements INativeBridge { const scheme = parameters.redirectUrl?.split('://')[0] ?? options.customScheme; const credential = await this.a0_call( - Auth0NativeModule.webAuth, + Auth0NativeModule.webAuth.bind(Auth0NativeModule), scheme, parameters.redirectUrl, parameters.state, @@ -104,7 +110,7 @@ export class NativeBridgeManager implements INativeBridge { options: NativeClearSessionOptions ): Promise { return this.a0_call( - Auth0NativeModule.webAuthLogout, + Auth0NativeModule.webAuthLogout.bind(Auth0NativeModule), options.customScheme, parameters.federated ?? false, parameters.returnToUrl @@ -112,11 +118,16 @@ export class NativeBridgeManager implements INativeBridge { } async cancelWebAuth(): Promise { - return this.a0_call(Auth0NativeModule.cancelWebAuth); + return this.a0_call( + Auth0NativeModule.cancelWebAuth.bind(Auth0NativeModule) + ); } async saveCredentials(credentials: Credentials): Promise { - return this.a0_call(Auth0NativeModule.saveCredentials, credentials); + return this.a0_call( + Auth0NativeModule.saveCredentials.bind(Auth0NativeModule), + credentials + ); } async getCredentials( @@ -128,7 +139,7 @@ export class NativeBridgeManager implements INativeBridge { // Assuming the native side can take an empty object for parameters. const params = parameters ?? {}; return this.a0_call( - Auth0NativeModule.getCredentials, + Auth0NativeModule.getCredentials.bind(Auth0NativeModule), scope, minTtl ?? 0, params, @@ -137,22 +148,30 @@ export class NativeBridgeManager implements INativeBridge { } async hasValidCredentials(minTtl?: number): Promise { - return this.a0_call(Auth0NativeModule.hasValidCredentials, minTtl ?? 0); + return this.a0_call( + Auth0NativeModule.hasValidCredentials.bind(Auth0NativeModule), + minTtl ?? 0 + ); } async clearCredentials(): Promise { - return this.a0_call(Auth0NativeModule.clearCredentials); + return this.a0_call( + Auth0NativeModule.clearCredentials.bind(Auth0NativeModule) + ); } async resumeWebAuth(url: string): Promise { - return this.a0_call(Auth0NativeModule.resumeWebAuth, url); + return this.a0_call( + Auth0NativeModule.resumeWebAuth.bind(Auth0NativeModule), + url + ); } async getDPoPHeaders( params: DPoPHeadersParams ): Promise> { return this.a0_call( - Auth0NativeModule.getDPoPHeaders, + Auth0NativeModule.getDPoPHeaders.bind(Auth0NativeModule), params.url, params.method, params.accessToken, @@ -162,6 +181,6 @@ export class NativeBridgeManager implements INativeBridge { } async clearDPoPKey(): Promise { - return this.a0_call(Auth0NativeModule.clearDPoPKey); + return this.a0_call(Auth0NativeModule.clearDPoPKey.bind(Auth0NativeModule)); } } diff --git a/yarn.lock b/yarn.lock index fbe690b2..f4efe7f1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4634,6 +4634,27 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/eslint-plugin@npm:8.46.2": + version: 8.46.2 + resolution: "@typescript-eslint/eslint-plugin@npm:8.46.2" + dependencies: + "@eslint-community/regexpp": ^4.10.0 + "@typescript-eslint/scope-manager": 8.46.2 + "@typescript-eslint/type-utils": 8.46.2 + "@typescript-eslint/utils": 8.46.2 + "@typescript-eslint/visitor-keys": 8.46.2 + graphemer: ^1.4.0 + ignore: ^7.0.0 + natural-compare: ^1.4.0 + ts-api-utils: ^2.1.0 + peerDependencies: + "@typescript-eslint/parser": ^8.46.2 + eslint: ^8.57.0 || ^9.0.0 + typescript: ">=4.8.4 <6.0.0" + checksum: 9292f1f984f50166a7d7b17d73df6a05263b40f18c88be62830f90ae3836ea7f94d15bbc035d85ddbc4793b27d9ea15829bf1b3d35771bdb1bd1cd41f0760ddb + languageName: node + linkType: hard + "@typescript-eslint/eslint-plugin@npm:^8.32.0, @typescript-eslint/eslint-plugin@npm:^8.36.0": version: 8.46.1 resolution: "@typescript-eslint/eslint-plugin@npm:8.46.1" @@ -4655,6 +4676,22 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/parser@npm:8.46.2": + version: 8.46.2 + resolution: "@typescript-eslint/parser@npm:8.46.2" + dependencies: + "@typescript-eslint/scope-manager": 8.46.2 + "@typescript-eslint/types": 8.46.2 + "@typescript-eslint/typescript-estree": 8.46.2 + "@typescript-eslint/visitor-keys": 8.46.2 + debug: ^4.3.4 + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: ">=4.8.4 <6.0.0" + checksum: fc65446e11cc2d21550c1848526458f1dc0ea02bad6454d6a1477f5fa997bbf2a64b4e00b289128e17c69a8b41840367091650075810b458a3cae4a9ab8736cd + languageName: node + linkType: hard + "@typescript-eslint/parser@npm:^8.32.0, @typescript-eslint/parser@npm:^8.36.0": version: 8.46.1 resolution: "@typescript-eslint/parser@npm:8.46.1" @@ -4697,6 +4734,19 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/project-service@npm:8.46.2": + version: 8.46.2 + resolution: "@typescript-eslint/project-service@npm:8.46.2" + dependencies: + "@typescript-eslint/tsconfig-utils": ^8.46.2 + "@typescript-eslint/types": ^8.46.2 + debug: ^4.3.4 + peerDependencies: + typescript: ">=4.8.4 <6.0.0" + checksum: 9fb4d2eafd949f430b498a12b886cf6b5414108c84490e7906b877be711ff7e8db996f94861d47ad1bb4c0d323adbc9522100766094a47f5bc8671f1bf820368 + languageName: node + linkType: hard + "@typescript-eslint/scope-manager@npm:8.41.0": version: 8.41.0 resolution: "@typescript-eslint/scope-manager@npm:8.41.0" @@ -4717,6 +4767,16 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/scope-manager@npm:8.46.2": + version: 8.46.2 + resolution: "@typescript-eslint/scope-manager@npm:8.46.2" + dependencies: + "@typescript-eslint/types": 8.46.2 + "@typescript-eslint/visitor-keys": 8.46.2 + checksum: 2df38694957a1f4a440f97c39839989bb99871a2cb2e10d715b4c91b64cb08377b57fe39122a3d8fe8e90a9eadd48655093316c8372253db724696446c441a96 + languageName: node + linkType: hard + "@typescript-eslint/tsconfig-utils@npm:8.41.0, @typescript-eslint/tsconfig-utils@npm:^8.41.0": version: 8.41.0 resolution: "@typescript-eslint/tsconfig-utils@npm:8.41.0" @@ -4735,6 +4795,15 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/tsconfig-utils@npm:8.46.2, @typescript-eslint/tsconfig-utils@npm:^8.46.2": + version: 8.46.2 + resolution: "@typescript-eslint/tsconfig-utils@npm:8.46.2" + peerDependencies: + typescript: ">=4.8.4 <6.0.0" + checksum: 4a8caad6e6d27d1cc5f35db201906d3b008edacea0dd880cd0a3e62cbbdcf84907c231862acfbfa5c326516d6c043f185f1db190d8d8f48f90f2bb0e699fdf8d + languageName: node + linkType: hard + "@typescript-eslint/type-utils@npm:8.46.1": version: 8.46.1 resolution: "@typescript-eslint/type-utils@npm:8.46.1" @@ -4751,6 +4820,22 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/type-utils@npm:8.46.2": + version: 8.46.2 + resolution: "@typescript-eslint/type-utils@npm:8.46.2" + dependencies: + "@typescript-eslint/types": 8.46.2 + "@typescript-eslint/typescript-estree": 8.46.2 + "@typescript-eslint/utils": 8.46.2 + debug: ^4.3.4 + ts-api-utils: ^2.1.0 + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: ">=4.8.4 <6.0.0" + checksum: b16aa99d3517de0b138a5d89d5dd06ccf19f7f522fc8bb205db05c7bcef47bbbb206bb694b57feb7e8102c61d3ce580a1a6c8d3efdd788d42566b718edea97dd + languageName: node + linkType: hard + "@typescript-eslint/types@npm:8.41.0, @typescript-eslint/types@npm:^8.41.0": version: 8.41.0 resolution: "@typescript-eslint/types@npm:8.41.0" @@ -4765,6 +4850,13 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/types@npm:8.46.2, @typescript-eslint/types@npm:^8.46.2": + version: 8.46.2 + resolution: "@typescript-eslint/types@npm:8.46.2" + checksum: c1c1c3a99b62ed51784d35c47547c2fa30c1896edf9843dcff3d39571b18b04daab1093f4ff59ae5f65a94fe78f2e7c73d3903b68c51d195204016ba909ca0d3 + languageName: node + linkType: hard + "@typescript-eslint/typescript-estree@npm:8.41.0": version: 8.41.0 resolution: "@typescript-eslint/typescript-estree@npm:8.41.0" @@ -4805,6 +4897,26 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/typescript-estree@npm:8.46.2": + version: 8.46.2 + resolution: "@typescript-eslint/typescript-estree@npm:8.46.2" + dependencies: + "@typescript-eslint/project-service": 8.46.2 + "@typescript-eslint/tsconfig-utils": 8.46.2 + "@typescript-eslint/types": 8.46.2 + "@typescript-eslint/visitor-keys": 8.46.2 + debug: ^4.3.4 + fast-glob: ^3.3.2 + is-glob: ^4.0.3 + minimatch: ^9.0.4 + semver: ^7.6.0 + ts-api-utils: ^2.1.0 + peerDependencies: + typescript: ">=4.8.4 <6.0.0" + checksum: e86da0546983e7e46a388af90fbd04ba19192d5f0c32b907d684890e0b363abbcdaf24a6f9a9909d5671ecefd67f3b1bc9e867e69dbca888aa6fc6554430d9e9 + languageName: node + linkType: hard + "@typescript-eslint/utils@npm:8.46.1, @typescript-eslint/utils@npm:^8.0.0": version: 8.46.1 resolution: "@typescript-eslint/utils@npm:8.46.1" @@ -4820,6 +4932,21 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/utils@npm:8.46.2": + version: 8.46.2 + resolution: "@typescript-eslint/utils@npm:8.46.2" + dependencies: + "@eslint-community/eslint-utils": ^4.7.0 + "@typescript-eslint/scope-manager": 8.46.2 + "@typescript-eslint/types": 8.46.2 + "@typescript-eslint/typescript-estree": 8.46.2 + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: ">=4.8.4 <6.0.0" + checksum: dd3492454015340ae61e41b83ced7fe3fdcb47eeba3add1bd1ddb8a4b0551dcaf1479b4f74675074a48a36007a13dffa159258a6407fcb7aadfa637c27117b7b + languageName: node + linkType: hard + "@typescript-eslint/utils@npm:^6.0.0 || ^7.0.0 || ^8.0.0": version: 8.41.0 resolution: "@typescript-eslint/utils@npm:8.41.0" @@ -4855,6 +4982,16 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/visitor-keys@npm:8.46.2": + version: 8.46.2 + resolution: "@typescript-eslint/visitor-keys@npm:8.46.2" + dependencies: + "@typescript-eslint/types": 8.46.2 + eslint-visitor-keys: ^4.2.1 + checksum: 0f3a79175521c3bd99c6f000e8ec2211b8e24440a71526ae7aa2a02bea4e5226192df14c13c57fe3e6d6d568960f09f7138380e8b7cc89c9fac39fcb51ac0be8 + languageName: node + linkType: hard + "@urql/core@npm:^5.0.6, @urql/core@npm:^5.1.2": version: 5.2.0 resolution: "@urql/core@npm:5.2.0" @@ -14619,6 +14756,7 @@ __metadata: typedoc-plugin-missing-exports: ^4.0.0 typedoc-plugin-replace-text: ^4.2.0 typescript: 5.2.2 + typescript-eslint: ^8.46.2 url: ^0.11.4 peerDependencies: react: ">=19.0.0" @@ -16926,6 +17064,21 @@ __metadata: languageName: node linkType: hard +"typescript-eslint@npm:^8.46.2": + version: 8.46.2 + resolution: "typescript-eslint@npm:8.46.2" + dependencies: + "@typescript-eslint/eslint-plugin": 8.46.2 + "@typescript-eslint/parser": 8.46.2 + "@typescript-eslint/typescript-estree": 8.46.2 + "@typescript-eslint/utils": 8.46.2 + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: ">=4.8.4 <6.0.0" + checksum: ed9e4587f6b437642413699a55caf50c7c2b912c9b251e6f1d055a5adee09a7ac0cc4fb0fa96a4ea9dcf32b11e3a4f386ec1d2b20cf6ba34ecba388215a04e62 + languageName: node + linkType: hard + "typescript@npm:5.2.2": version: 5.2.2 resolution: "typescript@npm:5.2.2"