diff --git a/packages/core/modules-sdk/src/loaders/utils/__fixtures__/module-with-providers/provider-2/services/provider-service.ts b/packages/core/modules-sdk/src/loaders/utils/__fixtures__/module-with-providers/provider-2/services/provider-service.ts index 7e581fe2b8..8bd583bb82 100644 --- a/packages/core/modules-sdk/src/loaders/utils/__fixtures__/module-with-providers/provider-2/services/provider-service.ts +++ b/packages/core/modules-sdk/src/loaders/utils/__fixtures__/module-with-providers/provider-2/services/provider-service.ts @@ -1 +1,3 @@ -export class ModuleProvider2Service {} +export class ModuleProvider2Service { + static identifier = "provider-2" +} diff --git a/packages/core/modules-sdk/src/loaders/utils/__tests__/load-internal.spec.ts b/packages/core/modules-sdk/src/loaders/utils/__tests__/load-internal.spec.ts index aab66b84d8..f28a7fd2f9 100644 --- a/packages/core/modules-sdk/src/loaders/utils/__tests__/load-internal.spec.ts +++ b/packages/core/modules-sdk/src/loaders/utils/__tests__/load-internal.spec.ts @@ -1,5 +1,9 @@ import { IModuleService, ModuleResolution } from "@medusajs/types" -import { createMedusaContainer, upperCaseFirst } from "@medusajs/utils" +import { + createMedusaContainer, + getProviderRegistrationKey, + upperCaseFirst, +} from "@medusajs/utils" import { join } from "path" import { ModuleWithDmlMixedWithoutJoinerConfigFixtures, @@ -10,11 +14,7 @@ import { import { ModuleService as ModuleServiceWithProvider } from "../__fixtures__/module-with-providers" import { ModuleProviderService as ModuleServiceWithProviderProvider1 } from "../__fixtures__/module-with-providers/provider-1" import { ModuleProvider2Service as ModuleServiceWithProviderProvider2 } from "../__fixtures__/module-with-providers/provider-2" -import { - getProviderRegistrationKey, - loadInternalModule, - loadResources, -} from "../load-internal" +import { loadInternalModule, loadResources } from "../load-internal" describe("load internal", () => { describe("loadResources", () => { @@ -376,9 +376,10 @@ describe("load internal", () => { const moduleService = container.resolve(moduleResolution.definition.key) const provider = (moduleService as any).container[ - getProviderRegistrationKey( - ModuleServiceWithProviderProvider1.identifier - ) + getProviderRegistrationKey({ + providerId: moduleResolution.options!.providers![0].id, + providerIdentifier: ModuleServiceWithProviderProvider1.identifier, + }) ] expect(moduleService).toBeInstanceOf(ModuleServiceWithProvider) @@ -427,7 +428,10 @@ describe("load internal", () => { const moduleService = container.resolve(moduleResolution.definition.key) const provider = (moduleService as any).container[ - getProviderRegistrationKey(moduleResolution.options!.providers![0].id) + getProviderRegistrationKey({ + providerId: moduleResolution.options!.providers![0].id, + providerIdentifier: ModuleServiceWithProviderProvider2.identifier, + }) ] expect(moduleService).toBeInstanceOf(ModuleServiceWithProvider) diff --git a/packages/core/modules-sdk/src/loaders/utils/load-internal.ts b/packages/core/modules-sdk/src/loaders/utils/load-internal.ts index cd9ec01845..9abc8476c4 100644 --- a/packages/core/modules-sdk/src/loaders/utils/load-internal.ts +++ b/packages/core/modules-sdk/src/loaders/utils/load-internal.ts @@ -18,6 +18,7 @@ import { defineJoinerConfig, DmlEntity, dynamicImport, + getProviderRegistrationKey, isString, MedusaModuleProviderType, MedusaModuleType, @@ -51,17 +52,6 @@ type ResolvedModuleProvider = ModuleProviderExports & { discoveryPath: string } -export const moduleProviderRegistrationKeyPrefix = "__providers__" - -/** - * Return the key used to register a module provider in the container - * @param {string} moduleKey - * @return {string} - */ -export function getProviderRegistrationKey(moduleKey: string): string { - return moduleProviderRegistrationKeyPrefix + moduleKey -} - export async function resolveModuleExports({ resolution, }: { @@ -140,7 +130,7 @@ async function loadInternalProvider( moduleExports: !isString(providerRes) ? providerRes : undefined, definition: { ...resolution.definition, - key: provider.id, + key: provider.id!, }, resolutionPath: isString(provider.resolve) ? require.resolve(provider.resolve, { @@ -321,13 +311,39 @@ export async function loadInternalModule(args: { for (const moduleProviderService of moduleProviderServices) { const modProvider_ = moduleProviderService as any - modProvider_.identifier ??= keyName - modProvider_.__type = MedusaModuleProviderType - const registrationKey = getProviderRegistrationKey( - modProvider_.identifier + const originalIdentifier = modProvider_.identifier as string + const providerId = keyName + + if (!originalIdentifier) { + const providerResolutionName = + modProvider_.DISPLAY_NAME ?? resolution.resolutionPath + + throw new Error( + `Module provider ${providerResolutionName} does not have a static "identifier" property on its service class.` + ) + } + + const alreadyRegisteredProvider = container.hasRegistration( + getProviderRegistrationKey({ + providerId, + providerIdentifier: originalIdentifier, + }) ) + if (alreadyRegisteredProvider) { + throw new Error( + `Module provider ${originalIdentifier} has already been registered. Please provide a different "id" in the provider options.` + ) + } + + modProvider_.__type = MedusaModuleProviderType + + const registrationKey = getProviderRegistrationKey({ + providerId, + providerIdentifier: originalIdentifier, + }) + container.register({ - [registrationKey]: asFunction((cradle) => { + [registrationKey]: asFunction(() => { ;(moduleProviderService as any).__type = MedusaModuleType return new moduleProviderService( localContainer.cradle, diff --git a/packages/core/types/src/modules-sdk/module-provider.ts b/packages/core/types/src/modules-sdk/module-provider.ts index 851154fd66..2cf6d603c0 100644 --- a/packages/core/types/src/modules-sdk/module-provider.ts +++ b/packages/core/types/src/modules-sdk/module-provider.ts @@ -42,7 +42,7 @@ export type ModuleProviderLoaderFunction = ( export type ModuleProvider = { resolve: string | ModuleProviderExports - id: string + id?: string options?: Record is_default?: boolean } diff --git a/packages/core/utils/src/auth/abstract-auth-provider.ts b/packages/core/utils/src/auth/abstract-auth-provider.ts index c8f0a4628f..cefaa6a835 100644 --- a/packages/core/utils/src/auth/abstract-auth-provider.ts +++ b/packages/core/utils/src/auth/abstract-auth-provider.ts @@ -69,22 +69,32 @@ export abstract class AbstractAuthModuleProvider implements IAuthProvider { /** * @ignore */ - private static PROVIDER: string + static identifier: string /** * @ignore */ - private static DISPLAY_NAME: string + static DISPLAY_NAME: string /** * @ignore */ protected readonly container_: any + /** + * @deprecated Use `identifier` instead. * @ignore */ public get provider() { - return (this.constructor as typeof AbstractAuthModuleProvider).PROVIDER + return (this.constructor as typeof AbstractAuthModuleProvider).identifier } + + /** + * @ignore + */ + public get identifier() { + return (this.constructor as typeof AbstractAuthModuleProvider).identifier + } + /** * @ignore */ @@ -98,21 +108,6 @@ export abstract class AbstractAuthModuleProvider implements IAuthProvider { */ static validateOptions(options: Record): void | never {} - /** - * @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 ??= - config.provider - ;(this.constructor as typeof AbstractAuthModuleProvider).DISPLAY_NAME ??= - config.displayName - } - /** * This method authenticates the user. * diff --git a/packages/core/utils/src/modules-sdk/index.ts b/packages/core/utils/src/modules-sdk/index.ts index c2df880e87..1a84d3be30 100644 --- a/packages/core/utils/src/modules-sdk/index.ts +++ b/packages/core/utils/src/modules-sdk/index.ts @@ -19,3 +19,4 @@ export * from "./module-provider" export * from "./query-context" export * from "./types/links-config" export * from "./types/medusa-service" +export * from "./module-provider-registration-key" diff --git a/packages/core/utils/src/modules-sdk/module-provider-registration-key.ts b/packages/core/utils/src/modules-sdk/module-provider-registration-key.ts new file mode 100644 index 0000000000..05c86bd4ec --- /dev/null +++ b/packages/core/utils/src/modules-sdk/module-provider-registration-key.ts @@ -0,0 +1,19 @@ +export const moduleProviderRegistrationKeyPrefix = "__providers__" + +/** + * Return the key used to register a module provider in the container + * @param {string} moduleKey + * @return {string} + */ +export function getProviderRegistrationKey({ + providerId, + providerIdentifier, +}: { + providerId?: string + providerIdentifier?: string +}): string { + const registrationIdentifier = `${ + providerIdentifier ? providerIdentifier : "" + }${providerId ? `${providerIdentifier ? "_" : ""}${providerId}` : ""}` + return moduleProviderRegistrationKeyPrefix + registrationIdentifier +} diff --git a/packages/modules/auth/integration-tests/__fixtures__/providers/default-provider.ts b/packages/modules/auth/integration-tests/__fixtures__/providers/default-provider.ts index a181b2eead..cf81a6279a 100644 --- a/packages/modules/auth/integration-tests/__fixtures__/providers/default-provider.ts +++ b/packages/modules/auth/integration-tests/__fixtures__/providers/default-provider.ts @@ -10,6 +10,8 @@ import { } from "@medusajs/framework/utils" export class AuthServiceFixtures extends AbstractAuthModuleProvider { + static identifier = "plaintextpass" + constructor() { super( {}, diff --git a/packages/modules/locking/src/loaders/providers.ts b/packages/modules/locking/src/loaders/providers.ts index be2b39cc5b..293ea72394 100644 --- a/packages/modules/locking/src/loaders/providers.ts +++ b/packages/modules/locking/src/loaders/providers.ts @@ -4,7 +4,10 @@ import { ModuleProvider, ModulesSdkTypes, } from "@medusajs/framework/types" -import { ContainerRegistrationKeys } from "@medusajs/framework/utils" +import { + ContainerRegistrationKeys, + getProviderRegistrationKey, +} from "@medusajs/framework/utils" import { LockingProviderService } from "@services" import { LockingDefaultProvider, @@ -14,10 +17,20 @@ import { import { Lifetime, aliasTo, asFunction, asValue } from "awilix" import { InMemoryLockingProvider } from "../providers/in-memory" -const registrationFn = async (klass, container) => { +const registrationFn = async (klass, container, { id }) => { const key = LockingProviderService.getRegistrationIdentifier(klass) + + if (!id) { + throw new Error(`No "id" provided for provider ${key}`) + } + + const regKey = getProviderRegistrationKey({ + providerId: id, + providerIdentifier: key, + }) + container.register({ - [LockingProviderRegistrationPrefix + key]: aliasTo("__providers__" + key), + [LockingProviderRegistrationPrefix + key]: aliasTo(regKey), }) container.registerAdd(LockingIdentifiersRegistrationName, asValue(key)) diff --git a/packages/modules/payment/src/loaders/providers.ts b/packages/modules/payment/src/loaders/providers.ts index 885e88154e..676d43bf9d 100644 --- a/packages/modules/payment/src/loaders/providers.ts +++ b/packages/modules/payment/src/loaders/providers.ts @@ -5,7 +5,7 @@ import { ModuleProvider, ModulesSdkTypes, } from "@medusajs/framework/types" -import { Lifetime, asFunction, asValue } from "awilix" +import { asFunction, asValue, Lifetime } from "awilix" import { MedusaError } from "@medusajs/framework/utils" import { PaymentProviderService } from "@services" @@ -14,14 +14,16 @@ import * as providers from "../providers" const PROVIDER_REGISTRATION_KEY = "payment_providers" const registrationFn = async (klass, container, pluginOptions) => { - if (!klass?.PROVIDER) { + if (!klass?.identifier) { throw new MedusaError( MedusaError.Types.INVALID_ARGUMENT, `Trying to register a payment provider without a provider identifier.` ) } - const key = `pp_${klass.PROVIDER}_${pluginOptions.id}` + const key = `pp_${klass.identifier}${ + pluginOptions.id ? `_${pluginOptions.id}` : "" + }` container.register({ [key]: asFunction((cradle) => new klass(cradle, pluginOptions.options), { diff --git a/packages/modules/payment/src/providers/system.ts b/packages/modules/payment/src/providers/system.ts index 0a3a016ef9..f5901bf449 100644 --- a/packages/modules/payment/src/providers/system.ts +++ b/packages/modules/payment/src/providers/system.ts @@ -13,7 +13,6 @@ import { export class SystemProviderService extends AbstractPaymentProvider { static identifier = "system" - static PROVIDER = "system" async getStatus(_): Promise { return "authorized" diff --git a/packages/modules/providers/auth-emailpass/src/services/emailpass.ts b/packages/modules/providers/auth-emailpass/src/services/emailpass.ts index 1b15496116..6f9743b9ec 100644 --- a/packages/modules/providers/auth-emailpass/src/services/emailpass.ts +++ b/packages/modules/providers/auth-emailpass/src/services/emailpass.ts @@ -20,6 +20,9 @@ type InjectedDependencies = { interface LocalServiceConfig extends EmailPassAuthProviderOptions {} export class EmailPassAuthService extends AbstractAuthModuleProvider { + static identifier = "emailpass" + static DISPLAY_NAME = "Email/Password Authentication" + protected config_: LocalServiceConfig protected logger_: Logger @@ -27,10 +30,8 @@ export class EmailPassAuthService extends AbstractAuthModuleProvider { { logger }: InjectedDependencies, options: EmailPassAuthProviderOptions ) { - super( - {}, - { provider: "emailpass", displayName: "Email/Password Authentication" } - ) + // @ts-ignore + super(...arguments) this.config_ = options this.logger_ = logger } diff --git a/packages/modules/providers/auth-github/src/services/github.ts b/packages/modules/providers/auth-github/src/services/github.ts index 0aff38e1db..fd9113f3a0 100644 --- a/packages/modules/providers/auth-github/src/services/github.ts +++ b/packages/modules/providers/auth-github/src/services/github.ts @@ -18,6 +18,9 @@ interface LocalServiceConfig extends GithubAuthProviderOptions {} // TODO: Add state param that is stored in Redis, to prevent CSRF attacks export class GithubAuthService extends AbstractAuthModuleProvider { + static identifier = "github" + static DISPLAY_NAME = "Github Authentication" + protected config_: LocalServiceConfig protected logger_: Logger @@ -39,7 +42,8 @@ export class GithubAuthService extends AbstractAuthModuleProvider { { logger }: InjectedDependencies, options: GithubAuthProviderOptions ) { - super({}, { provider: "github", displayName: "Github Authentication" }) + // @ts-ignore + super(...arguments) this.config_ = options this.logger_ = logger } diff --git a/packages/modules/providers/auth-google/src/services/google.ts b/packages/modules/providers/auth-google/src/services/google.ts index 78b99a58ce..562f6e8912 100644 --- a/packages/modules/providers/auth-google/src/services/google.ts +++ b/packages/modules/providers/auth-google/src/services/google.ts @@ -19,6 +19,9 @@ interface LocalServiceConfig extends GoogleAuthProviderOptions {} // TODO: Add state param that is stored in Redis, to prevent CSRF attacks export class GoogleAuthService extends AbstractAuthModuleProvider { + static identifier = "google" + static DISPLAY_NAME = "Google Authentication" + protected config_: LocalServiceConfig protected logger_: Logger @@ -40,7 +43,8 @@ export class GoogleAuthService extends AbstractAuthModuleProvider { { logger }: InjectedDependencies, options: GoogleAuthProviderOptions ) { - super({}, { provider: "google", displayName: "Google Authentication" }) + // @ts-ignore + super(...arguments) this.config_ = options this.logger_ = logger } diff --git a/packages/modules/providers/notification-local/src/services/local.ts b/packages/modules/providers/notification-local/src/services/local.ts index 880aebd7a2..5ee0d14d7c 100644 --- a/packages/modules/providers/notification-local/src/services/local.ts +++ b/packages/modules/providers/notification-local/src/services/local.ts @@ -1,7 +1,7 @@ import { + LocalNotificationServiceOptions, Logger, NotificationTypes, - LocalNotificationServiceOptions, } from "@medusajs/framework/types" import { AbstractNotificationProviderService, @@ -15,6 +15,7 @@ type InjectedDependencies = { interface LocalServiceConfig {} export class LocalNotificationService extends AbstractNotificationProviderService { + static identifier = "notification-local" protected config_: LocalServiceConfig protected logger_: Logger diff --git a/packages/modules/providers/notification-sendgrid/src/services/sendgrid.ts b/packages/modules/providers/notification-sendgrid/src/services/sendgrid.ts index ddd2f2ca1e..987977c89f 100644 --- a/packages/modules/providers/notification-sendgrid/src/services/sendgrid.ts +++ b/packages/modules/providers/notification-sendgrid/src/services/sendgrid.ts @@ -19,6 +19,7 @@ interface SendgridServiceConfig { } export class SendgridNotificationService extends AbstractNotificationProviderService { + static identifier = "notification-sendgrid" protected config_: SendgridServiceConfig protected logger_: Logger diff --git a/packages/modules/providers/payment-stripe/src/services/stripe-bancontact.ts b/packages/modules/providers/payment-stripe/src/services/stripe-bancontact.ts index dfa487ae47..72f4d32249 100644 --- a/packages/modules/providers/payment-stripe/src/services/stripe-bancontact.ts +++ b/packages/modules/providers/payment-stripe/src/services/stripe-bancontact.ts @@ -2,7 +2,7 @@ import StripeBase from "../core/stripe-base" import { PaymentIntentOptions, PaymentProviderKeys } from "../types" class BancontactProviderService extends StripeBase { - static PROVIDER = PaymentProviderKeys.BAN_CONTACT + static identifier = PaymentProviderKeys.BAN_CONTACT constructor(_, options) { super(_, options) diff --git a/packages/modules/providers/payment-stripe/src/services/stripe-blik.ts b/packages/modules/providers/payment-stripe/src/services/stripe-blik.ts index 4f91c7b01d..c53d7b78d3 100644 --- a/packages/modules/providers/payment-stripe/src/services/stripe-blik.ts +++ b/packages/modules/providers/payment-stripe/src/services/stripe-blik.ts @@ -2,7 +2,7 @@ import StripeBase from "../core/stripe-base" import { PaymentIntentOptions, PaymentProviderKeys } from "../types" class BlikProviderService extends StripeBase { - static PROVIDER = PaymentProviderKeys.BLIK + static identifier = PaymentProviderKeys.BLIK constructor(_, options) { super(_, options) diff --git a/packages/modules/providers/payment-stripe/src/services/stripe-giropay.ts b/packages/modules/providers/payment-stripe/src/services/stripe-giropay.ts index 682aa5967d..22d07c8867 100644 --- a/packages/modules/providers/payment-stripe/src/services/stripe-giropay.ts +++ b/packages/modules/providers/payment-stripe/src/services/stripe-giropay.ts @@ -2,7 +2,7 @@ import StripeBase from "../core/stripe-base" import { PaymentIntentOptions, PaymentProviderKeys } from "../types" class GiropayProviderService extends StripeBase { - static PROVIDER = PaymentProviderKeys.GIROPAY + static identifier = PaymentProviderKeys.GIROPAY constructor(_, options) { super(_, options) diff --git a/packages/modules/providers/payment-stripe/src/services/stripe-ideal.ts b/packages/modules/providers/payment-stripe/src/services/stripe-ideal.ts index d1ff8ce03d..6fafbb6a3c 100644 --- a/packages/modules/providers/payment-stripe/src/services/stripe-ideal.ts +++ b/packages/modules/providers/payment-stripe/src/services/stripe-ideal.ts @@ -2,7 +2,7 @@ import StripeBase from "../core/stripe-base" import { PaymentIntentOptions, PaymentProviderKeys } from "../types" class IdealProviderService extends StripeBase { - static PROVIDER = PaymentProviderKeys.IDEAL + static identifier = PaymentProviderKeys.IDEAL constructor(_, options) { super(_, options) diff --git a/packages/modules/providers/payment-stripe/src/services/stripe-provider.ts b/packages/modules/providers/payment-stripe/src/services/stripe-provider.ts index 148681ac3f..9188e4e889 100644 --- a/packages/modules/providers/payment-stripe/src/services/stripe-provider.ts +++ b/packages/modules/providers/payment-stripe/src/services/stripe-provider.ts @@ -2,7 +2,7 @@ import StripeBase from "../core/stripe-base" import { PaymentIntentOptions, PaymentProviderKeys } from "../types" class StripeProviderService extends StripeBase { - static PROVIDER = PaymentProviderKeys.STRIPE + static identifier = PaymentProviderKeys.STRIPE constructor(_, options) { super(_, options) diff --git a/packages/modules/providers/payment-stripe/src/services/stripe-przelewy24.ts b/packages/modules/providers/payment-stripe/src/services/stripe-przelewy24.ts index 2fa0c8e14f..ae8a565680 100644 --- a/packages/modules/providers/payment-stripe/src/services/stripe-przelewy24.ts +++ b/packages/modules/providers/payment-stripe/src/services/stripe-przelewy24.ts @@ -2,7 +2,7 @@ import StripeBase from "../core/stripe-base" import { PaymentIntentOptions, PaymentProviderKeys } from "../types" class Przelewy24ProviderService extends StripeBase { - static PROVIDER = PaymentProviderKeys.PRZELEWY_24 + static identifier = PaymentProviderKeys.PRZELEWY_24 constructor(_, options) { super(_, options)