From 872c42c6dc90d322c332e59e86182b4948267fc3 Mon Sep 17 00:00:00 2001 From: Shahed Nasser Date: Mon, 3 Jun 2024 10:41:09 +0300 Subject: [PATCH] chore(utils): added TSDocs to AbstractAuthModuleProvider (#7550) Added TSDocs to AbstractAuthModuleProvider. These are used to generate the reference on how to create an auth provider module. --- .../utils/src/auth/abstract-auth-provider.ts | 268 +++++++++++++++++- 1 file changed, 266 insertions(+), 2 deletions(-) diff --git a/packages/core/utils/src/auth/abstract-auth-provider.ts b/packages/core/utils/src/auth/abstract-auth-provider.ts index 45c2fac263..d3ef1c9e96 100644 --- a/packages/core/utils/src/auth/abstract-auth-provider.ts +++ b/packages/core/utils/src/auth/abstract-auth-provider.ts @@ -5,19 +5,99 @@ import { IAuthProvider, } from "@medusajs/types" +/** + * ### constructor + * + * The constructor allows you to access resources from the module's container using the first parameter, + * and the module's options using the second parameter. + * + * If you're creating a client or establishing a connection with a third-party service, do it in the constructor. + * + * In the constructor, you must pass to the parent constructor two parameters: + * + * 1. The first one is an empty object. + * 2. The second is an object having two properties: + * - `provider`: The ID of the provider. For example, `emailpass`. + * - `displayName`: The label or displayable name of the provider. For example, `Email and Password Authentication`. + * + * #### Example + * + * ```ts + * import { AbstractAuthModuleProvider } from "@medusajs/utils" + * import { Logger } from "@medusajs/types" + * + * type InjectedDependencies = { + * logger: Logger + * } + * + * type Options = { + * apiKey: string + * } + * + * class MyAuthProviderService extends AbstractAuthModuleProvider { + * protected logger_: Logger + * protected options_: Options + * // assuming you're initializing a client + * protected client + * + * constructor ( + * { logger }: InjectedDependencies, + * options: Options + * ) { + * super( + * {}, + * { + * provider: "my-auth", + * displayName: "My Custom Authentication" + * } + * ) + * + * this.logger_ = logger + * this.options_ = options + * + * // assuming you're initializing a client + * this.client = new Client(options) + * } + * + * // ... + * } + * + * export default MyAuthProviderService + * ``` + */ export abstract class AbstractAuthModuleProvider implements IAuthProvider { + /** + * @ignore + */ private static PROVIDER: string + /** + * @ignore + */ private static DISPLAY_NAME: string - + /** + * @ignore + */ protected readonly container_: any + /** + * @ignore + */ public get provider() { return (this.constructor as typeof AbstractAuthModuleProvider).PROVIDER } - + /** + * @ignore + */ public get displayName() { return (this.constructor as typeof AbstractAuthModuleProvider).DISPLAY_NAME } + /** + * @ignore + * + * @privateRemarks + * Documenting the constructor in the class's TSDocs as it's difficult to relay + * the necessary information with this constructor's signature. + */ protected constructor({}, config: { provider: string; displayName: string }) { this.container_ = arguments[0] ;(this.constructor as typeof AbstractAuthModuleProvider).PROVIDER ??= @@ -26,11 +106,195 @@ export abstract class AbstractAuthModuleProvider implements IAuthProvider { config.displayName } + /** + * This method authenticates the user. + * + * The authentication happens either by directly authenticating or returning a redirect URL to continue + * the authentication with a third party provider. + * + * @param {AuthenticationInput} data - The details of the authentication request. + * @param {AuthIdentityProviderService} authIdentityProviderService - The service used to retrieve or + * create an auth identity. It has two methods: `create` to create an auth identity, + * and `retrieve` to retrieve an auth identity. When you authenticate the user, you can create an auth identity + * using this service. + * @returns {Promise} The authentication response. + * + * @privateRemarks + * TODO add a link to the authentication flow document once it's public. + * + * @example + * For example, if your authentication provider doesn't require validating a callback: + * + * ```ts + * import { + * AuthIdentityProviderService, + * AuthenticationInput, + * AuthenticationResponse + * } from "@medusajs/types" + * // ... + * + * class MyAuthProviderService extends AbstractAuthModuleProvider { + * // ... + * async authenticate( + * data: AuthenticationInput, + * authIdentityProviderService: AuthIdentityProviderService + * ): Promise { + * const isAuthenticated = false + * // TODO perform custom logic to authenticate the user + * // ... + * + * if (!isAuthenticated) { + * // if the authentication didn't succeed, return + * // an object of the following format + * return { + * success: false, + * error: "Incorrect credentials" + * } + * } + * + * // authentication is successful, create an auth identity + * // if doesn't exist + * let authIdentity + * + * try { + * authIdentity = await authIdentityProviderService.retrieve({ + * entity_id: data.body.email, // email or some ID + * provider: this.provider + * }) + * } catch (e) { + * // The auth identity doesn't exist so create it + * authIdentity = await authIdentityProviderService.create({ + * entity_id: data.body.email, // email or some ID + * provider: this.provider, + * provider_metadata: { + * // can include password or any other relevant information + * } + * }) + * } + * + * return { + * success: true, + * authIdentity + * } + * } + * } + * ``` + * + * If your authentication provider requires validating callback: + * + * ```ts + * import { + * AuthIdentityProviderService, + * AuthenticationInput, + * AuthenticationResponse + * } from "@medusajs/types" + * // ... + * + * class MyAuthProviderService extends AbstractAuthModuleProvider { + * // ... + * async authenticate( + * data: AuthenticationInput, + * authIdentityProviderService: AuthIdentityProviderService + * ): Promise { + * const isAuthenticated = false + * // TODO perform custom logic to authenticate the user + * // ... + * + * if (!isAuthenticated) { + * // if the authentication didn't succeed, return + * // an object of the following format + * return { + * success: false, + * error: "Incorrect credentials" + * } + * } + * + * return { + * success: true, + * location: "some-url.com" + * } + * } + * } + * ``` + */ abstract authenticate( data: AuthenticationInput, authIdentityProviderService: AuthIdentityProviderService ): Promise + /** + * This method validates the callback of an authentication request. + * + * In an authentication flow that requires performing an action with a third-party service, such as login + * with a social account, the {@link authenticate} method is called first. + * + * Then, the third-party service redirects to the Medusa application's validate callback API route. + * That route uses this method to authenticate the user. + * + * @param {AuthenticationInput} data - The details of the authentication request. + * @param {AuthIdentityProviderService} authIdentityProviderService - The service used to retrieve or + * create an auth identity. It has two methods: `create` to create an auth identity, + * and `retrieve` to retrieve an auth identity. When you authenticate the user, you can create an auth identity + * using this service. + * @returns {Promise} The authentication response. + * + * @privateRemarks + * TODO add a link to the authentication flow document once it's public. + * + * @example + * import { + * AuthIdentityProviderService, + * AuthenticationInput, + * AuthenticationResponse + * } from "@medusajs/types" + * // ... + * + * class MyAuthProviderService extends AbstractAuthModuleProvider { + * // ... + * async validateCallback( + * data: AuthenticationInput, + * authIdentityProviderService: AuthIdentityProviderService + * ): Promise { + * const isAuthenticated = false + * // TODO perform custom logic to authenticate the user + * // ... + * + * if (!isAuthenticated) { + * // if the authentication didn't succeed, return + * // an object of the following format + * return { + * success: false, + * error: "Something went wrong" + * } + * } + * + * // authentication is successful, create an auth identity + * // if doesn't exist + * let authIdentity + * + * try { + * authIdentity = await authIdentityProviderService.retrieve({ + * entity_id: data.body.email, // email or some ID + * provider: this.provider + * }) + * } catch (e) { + * // The auth identity doesn't exist so create it + * authIdentity = await authIdentityProviderService.create({ + * entity_id: data.body.email, // email or some ID + * provider: this.provider, + * provider_metadata: { + * // can include password or any other relevant information + * } + * }) + * } + * + * return { + * success: true, + * authIdentity + * } + * } + * } + */ validateCallback( data: AuthenticationInput, authIdentityProviderService: AuthIdentityProviderService