diff --git a/.changeset/witty-lies-burn.md b/.changeset/witty-lies-burn.md new file mode 100644 index 0000000000..a35961fc1b --- /dev/null +++ b/.changeset/witty-lies-burn.md @@ -0,0 +1,6 @@ +--- +"@medusajs/types": patch +"@medusajs/utils": patch +--- + +feat: map container types for core services to interface diff --git a/packages/core/types/src/common/common.ts b/packages/core/types/src/common/common.ts index 0057b54373..03af610182 100644 --- a/packages/core/types/src/common/common.ts +++ b/packages/core/types/src/common/common.ts @@ -66,7 +66,7 @@ export interface FindConfig { /** * An array of strings, each being attribute names of the entity to retrieve in the result. */ - select?: (keyof Entity | string)[] + select?: (keyof Entity | (string & {}))[] /** * A number indicating the number of records to skip before retrieving the results. diff --git a/packages/core/utils/src/modules-sdk/__tests__/modules-to-container-types.spec.ts b/packages/core/utils/src/modules-sdk/__tests__/modules-to-container-types.spec.ts index 6ea381163f..44d7ab8074 100644 --- a/packages/core/utils/src/modules-sdk/__tests__/modules-to-container-types.spec.ts +++ b/packages/core/utils/src/modules-sdk/__tests__/modules-to-container-types.spec.ts @@ -14,10 +14,10 @@ describe("generateContainerTypes", function () { { cache: { __definition: { - key: "cache", + key: "foo-cache", label: "Cache", - defaultPackage: "@medusajs/foo", - resolvePath: "@medusajs/foo", + defaultPackage: "@medusajs/foo-cache", + resolvePath: "@medusajs/foo-cache", defaultModuleDeclaration: { scope: "internal", }, @@ -34,11 +34,46 @@ describe("generateContainerTypes", function () { expect(await fileSystem.exists("modules-bindings.d.ts")).toBeTruthy() expect(await fileSystem.contents("modules-bindings.d.ts")) .toMatchInlineSnapshot(` - "import type Cache from '@medusajs/foo' + "import type FooCache from '@medusajs/foo-cache' declare module '@medusajs/framework/types' { interface ModulesImplementations { - cache: InstanceType<(typeof Cache)['service']> + 'foo-cache': InstanceType<(typeof FooCache)['service']> + } + }" + `) + }) + + it("point inbuilt packages to their interfaces", async function () { + await generateContainerTypes( + { + cache: { + __definition: { + key: "cache", + label: "Cache", + defaultPackage: "@medusajs/foo-cache", + resolvePath: "@medusajs/foo-cache", + defaultModuleDeclaration: { + scope: "internal", + }, + }, + __joinerConfig: {}, + }, + }, + { + outputDir: fileSystem.basePath, + interfaceName: "ModulesImplementations", + } + ) + + expect(await fileSystem.exists("modules-bindings.d.ts")).toBeTruthy() + expect(await fileSystem.contents("modules-bindings.d.ts")) + .toMatchInlineSnapshot(` + "import type { ICacheService } from '@medusajs/framework/types' + + declare module '@medusajs/framework/types' { + interface ModulesImplementations { + 'cache': ICacheService } }" `) @@ -47,10 +82,10 @@ describe("generateContainerTypes", function () { it("should normalize module path pointing to a relative file", async function () { await generateContainerTypes( { - cache: { + bar: { __definition: { - key: "cache", - label: "Cache", + key: "bar", + label: "Bar", defaultPackage: "./foo/bar", resolvePath: "./foo/bar", defaultModuleDeclaration: { @@ -69,11 +104,11 @@ describe("generateContainerTypes", function () { expect(await fileSystem.exists("modules-bindings.d.ts")).toBeTruthy() expect(await fileSystem.contents("modules-bindings.d.ts")) .toMatchInlineSnapshot(` - "import type Cache from '../../foo/bar' + "import type Bar from '../../foo/bar' declare module '@medusajs/framework/types' { interface ModulesImplementations { - cache: InstanceType<(typeof Cache)['service']> + 'bar': InstanceType<(typeof Bar)['service']> } }" `) diff --git a/packages/core/utils/src/modules-sdk/modules-to-container-types.ts b/packages/core/utils/src/modules-sdk/modules-to-container-types.ts index 4cd54d410a..f77ff56ae3 100644 --- a/packages/core/utils/src/modules-sdk/modules-to-container-types.ts +++ b/packages/core/utils/src/modules-sdk/modules-to-container-types.ts @@ -1,9 +1,43 @@ import { join } from "path" +import { Modules } from "./definition" import type { LoadedModule } from "@medusajs/types" import { FileSystem } from "../common/file-system" import { toCamelCase } from "../common/to-camel-case" import { upperCaseFirst } from "../common/upper-case-first" +/** + * For known services that has interfaces, we will set the container + * type to the interface than the actual service implementation. + * + * The idea is to provide more precise types. + */ +const SERVICES_INTERFACES = { + [Modules.AUTH]: "IAuthModuleService", + [Modules.CACHE]: "ICacheService", + [Modules.CART]: "ICartModuleService", + [Modules.CUSTOMER]: "ICustomerModuleService", + [Modules.EVENT_BUS]: "IEventBusModuleService", + [Modules.INVENTORY]: "IInventoryService", + [Modules.PAYMENT]: "IPaymentModuleService", + [Modules.PRICING]: "IPricingModuleService", + [Modules.PRODUCT]: "IProductModuleService", + [Modules.PROMOTION]: "IPromotionModuleService", + [Modules.SALES_CHANNEL]: "ISalesChannelModuleService", + [Modules.TAX]: "ITaxModuleService", + [Modules.FULFILLMENT]: "IFulfillmentModuleService", + [Modules.STOCK_LOCATION]: "IStockLocationService", + [Modules.USER]: "IUserModuleService", + [Modules.WORKFLOW_ENGINE]: "IWorkflowEngineService", + [Modules.REGION]: "IRegionModuleService", + [Modules.ORDER]: "IOrderModuleService", + [Modules.API_KEY]: "IApiKeyModuleService", + [Modules.STORE]: "IStoreModuleService", + [Modules.CURRENCY]: "ICurrencyModuleService", + [Modules.FILE]: "IFileModuleService", + [Modules.NOTIFICATION]: "INotificationModuleService", + [Modules.LOCKING]: "ILockingModule", +} + /** * Modules registered inside the config file points to one * of the following paths. @@ -55,6 +89,15 @@ export async function generateContainerTypes( * Key registered within the container */ const key = service.__definition.key + const interfaceKey = `'${key}'` + + if (SERVICES_INTERFACES[key]) { + result.imports.push( + `import type { ${SERVICES_INTERFACES[key]} } from '@medusajs/framework/types'` + ) + result.mappings.push(`${interfaceKey}: ${SERVICES_INTERFACES[key]}`) + return + } /** * @todo. The property should exist on "LoadedModule" @@ -71,7 +114,7 @@ export async function generateContainerTypes( result.imports.push(`import type ${serviceName} from '${servicePath}'`) result.mappings.push( - `${key}: InstanceType<(typeof ${serviceName})['service']>` + `${interfaceKey}: InstanceType<(typeof ${serviceName})['service']>` ) }) return result diff --git a/packages/core/utils/src/modules-sdk/types/medusa-service.ts b/packages/core/utils/src/modules-sdk/types/medusa-service.ts index 635cb623a7..eb66ceeae9 100644 --- a/packages/core/utils/src/modules-sdk/types/medusa-service.ts +++ b/packages/core/utils/src/modules-sdk/types/medusa-service.ts @@ -120,7 +120,7 @@ export type AbstractModuleService< TModelName >}`]: ( id: string, - config?: FindConfig, + config?: FindConfig, sharedContext?: Context ) => Promise } & { @@ -129,7 +129,7 @@ export type AbstractModuleService< TModelName >}`]: ( filters?: any, - config?: FindConfig, + config?: FindConfig, sharedContext?: Context ) => Promise } & { @@ -137,9 +137,11 @@ export type AbstractModuleService< TModelsDtoConfig, TModelName >}`]: { - (filters?: any, config?: FindConfig, sharedContext?: Context): Promise< - [TModelsDtoConfig[TModelName]["dto"][], number] - > + ( + filters?: any, + config?: FindConfig, + sharedContext?: Context + ): Promise<[TModelsDtoConfig[TModelName]["dto"][], number]> } } & { [TModelName in keyof TModelsDtoConfig as `delete${ExtractPluralName<