diff --git a/packages/modules-sdk/src/definitions.ts b/packages/modules-sdk/src/definitions.ts index b66a259ea2468..8c1d275837d72 100644 --- a/packages/modules-sdk/src/definitions.ts +++ b/packages/modules-sdk/src/definitions.ts @@ -27,6 +27,7 @@ export enum Modules { REGION = "region", ORDER = "order", API_KEY = "apiKey", + STORE = "store", } export enum ModuleRegistrationName { @@ -49,6 +50,7 @@ export enum ModuleRegistrationName { REGION = "regionModuleService", ORDER = "orderModuleService", API_KEY = "apiKeyModuleService", + STORE = "storeModuleService", } export const MODULE_PACKAGE_NAMES = { @@ -72,6 +74,7 @@ export const MODULE_PACKAGE_NAMES = { [Modules.REGION]: "@medusajs/region", [Modules.ORDER]: "@medusajs/order", [Modules.API_KEY]: "@medusajs/api-key", + [Modules.STORE]: "@medusajs/store", } export const ModulesDefinition: { [key: string | Modules]: ModuleDefinition } = @@ -324,6 +327,19 @@ export const ModulesDefinition: { [key: string | Modules]: ModuleDefinition } = resources: MODULE_RESOURCE_TYPE.SHARED, }, }, + [Modules.STORE]: { + key: Modules.STORE, + registrationName: ModuleRegistrationName.STORE, + defaultPackage: false, + label: upperCaseFirst(ModuleRegistrationName.STORE), + isRequired: false, + isQueryable: true, + dependencies: ["logger"], + defaultModuleDeclaration: { + scope: MODULE_SCOPE.INTERNAL, + resources: MODULE_RESOURCE_TYPE.SHARED, + }, + }, } export const MODULE_DEFINITIONS: ModuleDefinition[] = diff --git a/packages/store/.gitignore b/packages/store/.gitignore new file mode 100644 index 0000000000000..874c6c69d3341 --- /dev/null +++ b/packages/store/.gitignore @@ -0,0 +1,6 @@ +/dist +node_modules +.DS_store +.env* +.env +*.sql diff --git a/packages/store/README.md b/packages/store/README.md new file mode 100644 index 0000000000000..026e0d7739017 --- /dev/null +++ b/packages/store/README.md @@ -0,0 +1 @@ +# Store Module diff --git a/packages/store/integration-tests/__fixtures__/index.ts b/packages/store/integration-tests/__fixtures__/index.ts new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/packages/store/integration-tests/__tests__/store-module-service.spec.ts b/packages/store/integration-tests/__tests__/store-module-service.spec.ts new file mode 100644 index 0000000000000..f680e7ae172a7 --- /dev/null +++ b/packages/store/integration-tests/__tests__/store-module-service.spec.ts @@ -0,0 +1,21 @@ +import { Modules } from "@medusajs/modules-sdk" +import { IStoreModuleService } from "@medusajs/types" +import { moduleIntegrationTestRunner, SuiteOptions } from "medusa-test-utils" + +jest.setTimeout(100000) + +moduleIntegrationTestRunner({ + moduleName: Modules.STORE, + testSuite: ({ + MikroOrmWrapper, + service, + }: SuiteOptions) => { + describe("Store Module Service", () => { + describe("noop", function () { + it("should run", function () { + expect(true).toBe(true) + }) + }) + }) + }, +}) diff --git a/packages/store/jest.config.js b/packages/store/jest.config.js new file mode 100644 index 0000000000000..456054fe8ae27 --- /dev/null +++ b/packages/store/jest.config.js @@ -0,0 +1,22 @@ +module.exports = { + moduleNameMapper: { + "^@models": "/src/models", + "^@services": "/src/services", + "^@repositories": "/src/repositories", + "^@types": "/src/types", + }, + transform: { + "^.+\\.[jt]s?$": [ + "ts-jest", + { + tsConfig: "tsconfig.spec.json", + isolatedModules: true, + }, + ], + }, + testEnvironment: `node`, + moduleFileExtensions: [`js`, `ts`], + modulePathIgnorePatterns: ["dist/"], + setupFiles: ["/integration-tests/setup-env.js"], + setupFilesAfterEnv: ["/integration-tests/setup.js"], +} diff --git a/packages/store/mikro-orm.config.dev.ts b/packages/store/mikro-orm.config.dev.ts new file mode 100644 index 0000000000000..3c666f1f69f70 --- /dev/null +++ b/packages/store/mikro-orm.config.dev.ts @@ -0,0 +1,8 @@ +import * as entities from "./src/models" + +module.exports = { + entities: Object.values(entities), + schema: "public", + clientUrl: "postgres://postgres@localhost/medusa-store", + type: "postgresql", +} diff --git a/packages/store/package.json b/packages/store/package.json new file mode 100644 index 0000000000000..37d62e207898c --- /dev/null +++ b/packages/store/package.json @@ -0,0 +1,61 @@ +{ + "name": "@medusajs/store", + "version": "0.1.0", + "description": "Medusa Store module", + "main": "dist/index.js", + "types": "dist/index.d.ts", + "files": [ + "dist" + ], + "engines": { + "node": ">=16" + }, + "bin": { + "medusa-store-seed": "dist/scripts/bin/run-seed.js" + }, + "repository": { + "type": "git", + "url": "https://github.com/medusajs/medusa", + "directory": "packages/store" + }, + "publishConfig": { + "access": "public" + }, + "author": "Medusa", + "license": "MIT", + "scripts": { + "watch": "tsc --build --watch", + "watch:test": "tsc --build tsconfig.spec.json --watch", + "prepublishOnly": "cross-env NODE_ENV=production tsc --build && tsc-alias -p tsconfig.json", + "build": "rimraf dist && tsc --build && tsc-alias -p tsconfig.json", + "test": "jest --runInBand --bail --forceExit -- src/**/__tests__/**/*.ts", + "test:integration": "jest --runInBand --forceExit -- integration-tests/**/__tests__/**/*.ts", + "migration:generate": " MIKRO_ORM_CLI=./mikro-orm.config.dev.ts mikro-orm migration:generate", + "migration:initial": " MIKRO_ORM_CLI=./mikro-orm.config.dev.ts mikro-orm migration:create --initial", + "migration:create": " MIKRO_ORM_CLI=./mikro-orm.config.dev.ts mikro-orm migration:create", + "migration:up": " MIKRO_ORM_CLI=./mikro-orm.config.dev.ts mikro-orm migration:up", + "orm:cache:clear": " MIKRO_ORM_CLI=./mikro-orm.config.dev.ts mikro-orm cache:clear" + }, + "devDependencies": { + "@mikro-orm/cli": "5.9.7", + "cross-env": "^5.2.1", + "jest": "^29.6.3", + "medusa-test-utils": "workspace:^", + "rimraf": "^3.0.2", + "ts-jest": "^29.1.1", + "ts-node": "^10.9.1", + "tsc-alias": "^1.8.6", + "typescript": "^5.1.6" + }, + "dependencies": { + "@medusajs/modules-sdk": "^1.12.4", + "@medusajs/types": "^1.11.8", + "@medusajs/utils": "^1.11.1", + "@mikro-orm/core": "5.9.7", + "@mikro-orm/migrations": "5.9.7", + "@mikro-orm/postgresql": "5.9.7", + "awilix": "^8.0.0", + "dotenv": "^16.1.4", + "knex": "2.4.2" + } +} diff --git a/packages/store/src/index.ts b/packages/store/src/index.ts new file mode 100644 index 0000000000000..7b774fa27804f --- /dev/null +++ b/packages/store/src/index.ts @@ -0,0 +1,14 @@ +import { moduleDefinition } from "./module-definition" +import { initializeFactory, Modules } from "@medusajs/modules-sdk" + +export * from "./types" +export * from "./models" +export * from "./services" + +export const initialize = initializeFactory({ + moduleName: Modules.STORE, + moduleDefinition, +}) +export const runMigrations = moduleDefinition.runMigrations +export const revertMigration = moduleDefinition.revertMigration +export default moduleDefinition diff --git a/packages/store/src/joiner-config.ts b/packages/store/src/joiner-config.ts new file mode 100644 index 0000000000000..ce3bba36c086a --- /dev/null +++ b/packages/store/src/joiner-config.ts @@ -0,0 +1,29 @@ +import { Modules } from "@medusajs/modules-sdk" +import { ModuleJoinerConfig } from "@medusajs/types" +import { MapToConfig } from "@medusajs/utils" +import Store from "./models/store" + +export const LinkableKeys: Record = {} + +const entityLinkableKeysMap: MapToConfig = {} +Object.entries(LinkableKeys).forEach(([key, value]) => { + entityLinkableKeysMap[value] ??= [] + entityLinkableKeysMap[value].push({ + mapTo: key, + valueFrom: key.split("_").pop()!, + }) +}) + +export const entityNameToLinkableKeysMap: MapToConfig = entityLinkableKeysMap + +export const joinerConfig: ModuleJoinerConfig = { + serviceName: Modules.STORE, + primaryKeys: ["id"], + linkableKeys: LinkableKeys, + alias: [ + { + name: ["store", "stores"], + args: { entity: Store.name }, + }, + ], +} as ModuleJoinerConfig diff --git a/packages/store/src/models/index.ts b/packages/store/src/models/index.ts new file mode 100644 index 0000000000000..958612afdfbd3 --- /dev/null +++ b/packages/store/src/models/index.ts @@ -0,0 +1 @@ +export { default as Store } from "./store" diff --git a/packages/store/src/models/store.ts b/packages/store/src/models/store.ts new file mode 100644 index 0000000000000..4b5d073382403 --- /dev/null +++ b/packages/store/src/models/store.ts @@ -0,0 +1,32 @@ +import { generateEntityId } from "@medusajs/utils" + +import { + BeforeCreate, + Entity, + OnInit, + PrimaryKey, + Property, +} from "@mikro-orm/core" + +@Entity() +export default class Store { + @PrimaryKey({ columnType: "text" }) + id: string + + @Property({ + onCreate: () => new Date(), + columnType: "timestamptz", + defaultRaw: "now()", + }) + created_at: Date + + @BeforeCreate() + onCreate() { + this.id = generateEntityId(this.id, "store") + } + + @OnInit() + onInit() { + this.id = generateEntityId(this.id, "store") + } +} diff --git a/packages/store/src/module-definition.ts b/packages/store/src/module-definition.ts new file mode 100644 index 0000000000000..6f9761f73e0d7 --- /dev/null +++ b/packages/store/src/module-definition.ts @@ -0,0 +1,44 @@ +import { ModuleExports } from "@medusajs/types" +import * as ModuleServices from "@services" +import { StoreModuleService } from "@services" +import { Modules } from "@medusajs/modules-sdk" +import * as Models from "@models" +import * as ModuleModels from "@models" +import { ModulesSdkUtils } from "@medusajs/utils" +import * as ModuleRepositories from "@repositories" + +const migrationScriptOptions = { + moduleName: Modules.STORE, + models: Models, + pathToMigrations: __dirname + "/migrations", +} + +const runMigrations = ModulesSdkUtils.buildMigrationScript( + migrationScriptOptions +) + +const revertMigration = ModulesSdkUtils.buildRevertMigrationScript( + migrationScriptOptions +) + +const containerLoader = ModulesSdkUtils.moduleContainerLoaderFactory({ + moduleModels: ModuleModels, + moduleRepositories: ModuleRepositories, + moduleServices: ModuleServices, +}) + +const connectionLoader = ModulesSdkUtils.mikroOrmConnectionLoaderFactory({ + moduleName: Modules.STORE, + moduleModels: Object.values(Models), + migrationsPath: __dirname + "/migrations", +}) + +const service = StoreModuleService +const loaders = [containerLoader, connectionLoader] as any + +export const moduleDefinition: ModuleExports = { + service, + loaders, + revertMigration, + runMigrations, +} diff --git a/packages/store/src/repositories/index.ts b/packages/store/src/repositories/index.ts new file mode 100644 index 0000000000000..147c9cc259fa4 --- /dev/null +++ b/packages/store/src/repositories/index.ts @@ -0,0 +1 @@ +export { MikroOrmBaseRepository as BaseRepository } from "@medusajs/utils" diff --git a/packages/store/src/scripts/bin/run-seed.ts b/packages/store/src/scripts/bin/run-seed.ts new file mode 100644 index 0000000000000..9860747c5e908 --- /dev/null +++ b/packages/store/src/scripts/bin/run-seed.ts @@ -0,0 +1,29 @@ +#!/usr/bin/env node + +import { ModulesSdkUtils } from "@medusajs/utils" +import { Modules } from "@medusajs/modules-sdk" +import * as Models from "@models" +import { EOL } from "os" + +const args = process.argv +const path = args.pop() as string + +export default (async () => { + const { config } = await import("dotenv") + config() + if (!path) { + throw new Error( + `filePath is required.${EOL}Example: medusa-store-seed ` + ) + } + + const run = ModulesSdkUtils.buildSeedScript({ + moduleName: Modules.STORE, + models: Models, + pathToMigrations: __dirname + "/../../migrations", + seedHandler: async ({ manager, data }) => { + // TODO: Add seed logic + }, + }) + await run({ path }) +})() diff --git a/packages/store/src/services/__tests__/noop.ts b/packages/store/src/services/__tests__/noop.ts new file mode 100644 index 0000000000000..333c84c1ddbf2 --- /dev/null +++ b/packages/store/src/services/__tests__/noop.ts @@ -0,0 +1,5 @@ +describe("noop", function () { + it("should run", function () { + expect(true).toBe(true) + }) +}) diff --git a/packages/store/src/services/index.ts b/packages/store/src/services/index.ts new file mode 100644 index 0000000000000..43b596de6b270 --- /dev/null +++ b/packages/store/src/services/index.ts @@ -0,0 +1 @@ +export { default as StoreModuleService } from "./store-module-service" diff --git a/packages/store/src/services/store-module-service.ts b/packages/store/src/services/store-module-service.ts new file mode 100644 index 0000000000000..7f861cd1e8837 --- /dev/null +++ b/packages/store/src/services/store-module-service.ts @@ -0,0 +1,47 @@ +import { + DAL, + InternalModuleDeclaration, + ModuleJoinerConfig, + ModulesSdkTypes, + IStoreModuleService, + StoreTypes, +} from "@medusajs/types" +import { ModulesSdkUtils } from "@medusajs/utils" + +import { Store } from "@models" +import { entityNameToLinkableKeysMap, joinerConfig } from "../joiner-config" + +const generateMethodForModels = [] + +type InjectedDependencies = { + baseRepository: DAL.RepositoryService + storeService: ModulesSdkTypes.InternalModuleService +} + +export default class StoreModuleService + extends ModulesSdkUtils.abstractModuleServiceFactory< + InjectedDependencies, + StoreTypes.StoreDTO, + { + Store: { dto: StoreTypes.StoreDTO } + } + >(Store, generateMethodForModels, entityNameToLinkableKeysMap) + implements IStoreModuleService +{ + protected baseRepository_: DAL.RepositoryService + protected readonly storeService_: ModulesSdkTypes.InternalModuleService + + constructor( + { baseRepository, storeService }: InjectedDependencies, + protected readonly moduleDeclaration: InternalModuleDeclaration + ) { + // @ts-ignore + super(...arguments) + this.baseRepository_ = baseRepository + this.storeService_ = storeService + } + + __joinerConfig(): ModuleJoinerConfig { + return joinerConfig + } +} diff --git a/packages/store/src/types/index.ts b/packages/store/src/types/index.ts new file mode 100644 index 0000000000000..fdac085753676 --- /dev/null +++ b/packages/store/src/types/index.ts @@ -0,0 +1,6 @@ +import { IEventBusModuleService, Logger } from "@medusajs/types" + +export type InitializeModuleInjectableDependencies = { + logger?: Logger + eventBusService?: IEventBusModuleService +} diff --git a/packages/store/tsconfig.json b/packages/store/tsconfig.json new file mode 100644 index 0000000000000..4b79cd603235c --- /dev/null +++ b/packages/store/tsconfig.json @@ -0,0 +1,37 @@ +{ + "compilerOptions": { + "lib": ["es2020"], + "target": "es2020", + "outDir": "./dist", + "esModuleInterop": true, + "declaration": true, + "module": "commonjs", + "moduleResolution": "node", + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "sourceMap": false, + "noImplicitReturns": true, + "strictNullChecks": true, + "strictFunctionTypes": true, + "noImplicitThis": true, + "allowJs": true, + "skipLibCheck": true, + "downlevelIteration": true, // to use ES5 specific tooling + "baseUrl": ".", + "resolveJsonModule": true, + "paths": { + "@models": ["./src/models"], + "@services": ["./src/services"], + "@repositories": ["./src/repositories"], + "@types": ["./src/types"] + } + }, + "include": ["src"], + "exclude": [ + "dist", + "./src/**/__tests__", + "./src/**/__mocks__", + "./src/**/__fixtures__", + "node_modules" + ] +} diff --git a/packages/store/tsconfig.spec.json b/packages/store/tsconfig.spec.json new file mode 100644 index 0000000000000..48e47e8cbb3be --- /dev/null +++ b/packages/store/tsconfig.spec.json @@ -0,0 +1,8 @@ +{ + "extends": "./tsconfig.json", + "include": ["src", "integration-tests"], + "exclude": ["node_modules", "dist"], + "compilerOptions": { + "sourceMap": true + } +} diff --git a/packages/types/src/bundles.ts b/packages/types/src/bundles.ts index 1eb2ddac7428a..b17099fa8a501 100644 --- a/packages/types/src/bundles.ts +++ b/packages/types/src/bundles.ts @@ -23,3 +23,4 @@ export * as TransactionBaseTypes from "./transaction-base" export * as UserTypes from "./user" export * as WorkflowTypes from "./workflow" export * as ApiKeyTypes from "./api-key" +export * as StoreTypes from "./store" diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts index 5017d410c0d46..3958e296ebb8d 100644 --- a/packages/types/src/index.ts +++ b/packages/types/src/index.ts @@ -33,3 +33,4 @@ export * from "./transaction-base" export * from "./user" export * from "./workflow" export * from "./api-key" +export * from "./store" diff --git a/packages/types/src/store/common/index.ts b/packages/types/src/store/common/index.ts new file mode 100644 index 0000000000000..83c6d56aa523c --- /dev/null +++ b/packages/types/src/store/common/index.ts @@ -0,0 +1 @@ +export * from "./store" diff --git a/packages/types/src/store/common/store.ts b/packages/types/src/store/common/store.ts new file mode 100644 index 0000000000000..08792fb31f0fc --- /dev/null +++ b/packages/types/src/store/common/store.ts @@ -0,0 +1,3 @@ +export interface StoreDTO { + id: string +} diff --git a/packages/types/src/store/index.ts b/packages/types/src/store/index.ts new file mode 100644 index 0000000000000..0c73656566caa --- /dev/null +++ b/packages/types/src/store/index.ts @@ -0,0 +1,3 @@ +export * from "./common" +export * from "./mutations" +export * from "./service" diff --git a/packages/types/src/store/mutations/index.ts b/packages/types/src/store/mutations/index.ts new file mode 100644 index 0000000000000..83c6d56aa523c --- /dev/null +++ b/packages/types/src/store/mutations/index.ts @@ -0,0 +1 @@ +export * from "./store" diff --git a/packages/types/src/store/mutations/store.ts b/packages/types/src/store/mutations/store.ts new file mode 100644 index 0000000000000..0b0e8b2d01c65 --- /dev/null +++ b/packages/types/src/store/mutations/store.ts @@ -0,0 +1 @@ +export interface CreateStoreDTO {} diff --git a/packages/types/src/store/service.ts b/packages/types/src/store/service.ts new file mode 100644 index 0000000000000..595c7c74c8a1f --- /dev/null +++ b/packages/types/src/store/service.ts @@ -0,0 +1,3 @@ +import { IModuleService } from "../modules-sdk" + +export interface IStoreModuleService extends IModuleService {} diff --git a/yarn.lock b/yarn.lock index 63b4c1eb3a0bb..c5e0a085fb1b9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8732,6 +8732,33 @@ __metadata: languageName: unknown linkType: soft +"@medusajs/store@workspace:packages/store": + version: 0.0.0-use.local + resolution: "@medusajs/store@workspace:packages/store" + dependencies: + "@medusajs/modules-sdk": ^1.12.4 + "@medusajs/types": ^1.11.8 + "@medusajs/utils": ^1.11.1 + "@mikro-orm/cli": 5.9.7 + "@mikro-orm/core": 5.9.7 + "@mikro-orm/migrations": 5.9.7 + "@mikro-orm/postgresql": 5.9.7 + awilix: ^8.0.0 + cross-env: ^5.2.1 + dotenv: ^16.1.4 + jest: ^29.6.3 + knex: 2.4.2 + medusa-test-utils: "workspace:^" + rimraf: ^3.0.2 + ts-jest: ^29.1.1 + ts-node: ^10.9.1 + tsc-alias: ^1.8.6 + typescript: ^5.1.6 + bin: + medusa-store-seed: dist/scripts/bin/run-seed.js + languageName: unknown + linkType: soft + "@medusajs/tax@workspace:packages/tax": version: 0.0.0-use.local resolution: "@medusajs/tax@workspace:packages/tax"