diff --git a/.changeset/itchy-worms-press.md b/.changeset/itchy-worms-press.md new file mode 100644 index 0000000000..1c7c7f0ca0 --- /dev/null +++ b/.changeset/itchy-worms-press.md @@ -0,0 +1,8 @@ +--- +"@medusajs/modules-sdk": patch +"@medusajs/pricing": patch +"@medusajs/types": patch +"@medusajs/utils": patch +--- + +feat(pricing, types, utils, medusa-sdk): Pricing Module Setup + Currency service diff --git a/packages/medusa-test-utils/.babelrc b/packages/medusa-test-utils/.babelrc deleted file mode 100644 index b48db12268..0000000000 --- a/packages/medusa-test-utils/.babelrc +++ /dev/null @@ -1,9 +0,0 @@ -{ - "plugins": ["@babel/plugin-proposal-class-properties"], - "presets": ["@babel/preset-env"], - "env": { - "test": { - "plugins": ["@babel/plugin-transform-runtime"] - } - } -} diff --git a/packages/medusa-test-utils/package.json b/packages/medusa-test-utils/package.json index 9774618bf2..462ba7a265 100644 --- a/packages/medusa-test-utils/package.json +++ b/packages/medusa-test-utils/package.json @@ -9,10 +9,11 @@ "directory": "packages/medusa-test-utils" }, "scripts": { + "prepublishOnly": "cross-env NODE_ENV=production tsc --build", "prepare": "cross-env NODE_ENV=production yarn run build", - "test": "jest --passWithNoTests src", - "build": "babel src --out-dir dist/ --ignore '**/__tests__','**/__mocks__'", - "watch": "babel -w src --out-dir dist/ --ignore '**/__tests__','**/__mocks__'" + "build": "rimraf dist && tsc --build", + "watch": "tsc --build --watch", + "test": "jest --passWithNoTests src" }, "files": [ "dist" @@ -20,18 +21,16 @@ "author": "Sebastian Rindom", "license": "MIT", "devDependencies": { - "@babel/cli": "^7.7.5", - "@babel/core": "^7.7.5", - "@babel/plugin-proposal-class-properties": "^7.7.4", - "@babel/plugin-transform-runtime": "^7.7.6", - "@babel/preset-env": "^7.7.5", - "@babel/runtime": "^7.9.6", "cross-env": "^5.2.1", - "jest": "^25.5.4" + "jest": "^25.5.4", + "rimraf": "^3.0.2", + "typescript": "^5.1.6" }, "dependencies": { - "@babel/plugin-transform-classes": "^7.9.5", + "@mikro-orm/migrations": "5.7.12", + "@mikro-orm/postgresql": "5.7.12", "medusa-core-utils": "^1.2.0", + "pg-god": "^1.0.12", "randomatic": "^3.1.1" }, "gitHead": "81a7ff73d012fda722f6e9ef0bd9ba0232d37808" diff --git a/packages/medusa-test-utils/src/database.ts b/packages/medusa-test-utils/src/database.ts new file mode 100644 index 0000000000..3f694a1aca --- /dev/null +++ b/packages/medusa-test-utils/src/database.ts @@ -0,0 +1,111 @@ +import { TSMigrationGenerator } from "@mikro-orm/migrations" +import { MikroORM, Options, SqlEntityManager } from "@mikro-orm/postgresql" +import * as process from "process" + +export function getDatabaseURL(): string { + const DB_HOST = process.env.DB_HOST ?? "localhost" + const DB_USERNAME = process.env.DB_USERNAME ?? "" + const DB_PASSWORD = process.env.DB_PASSWORD + const DB_NAME = process.env.DB_TEMP_NAME + + return `postgres://${DB_USERNAME}${ + DB_PASSWORD ? `:${DB_PASSWORD}` : "" + }@${DB_HOST}/${DB_NAME}` +} + +export function getMikroOrmConfig( + mikroOrmEntities: any[], + pathToMigrations: string +): Options { + const DB_URL = getDatabaseURL() + + return { + type: "postgresql", + clientUrl: DB_URL, + entities: Object.values(mikroOrmEntities), + schema: process.env.MEDUSA_DB_SCHEMA, + debug: false, + migrations: { + path: pathToMigrations, + pathTs: pathToMigrations, + glob: "!(*.d).{js,ts}", + silent: true, + dropTables: true, + transactional: true, + allOrNothing: true, + safe: false, + generator: TSMigrationGenerator, + }, + } +} + +export interface TestDatabase { + orm: MikroORM | null + manager: SqlEntityManager | null + + setupDatabase(): Promise + clearDatabase(): Promise + getManager(): SqlEntityManager + forkManager(): SqlEntityManager + getOrm(): MikroORM +} + +export function getMikroOrmWrapper( + mikroOrmEntities: any[], + pathToMigrations: string +): TestDatabase { + return { + orm: null, + manager: null, + + getManager() { + if (this.manager === null) { + throw new Error("manager entity not available") + } + + return this.manager + }, + + forkManager() { + if (this.manager === null) { + throw new Error("manager entity not available") + } + + return this.manager.fork() + }, + + getOrm() { + if (this.orm === null) { + throw new Error("orm entity not available") + } + + return this.orm + }, + + async setupDatabase() { + const OrmConfig = getMikroOrmConfig(mikroOrmEntities, pathToMigrations) + + // Initializing the ORM + this.orm = await MikroORM.init(OrmConfig) + + if (this.orm === null) { + throw new Error("ORM not configured") + } + + this.manager = await this.orm.em + + await this.orm.schema.refreshDatabase() // ensure db exists and is fresh + }, + + async clearDatabase() { + if (this.orm === null) { + throw new Error("ORM not configured") + } + + await this.orm.close() + + this.orm = null + this.manager = null + }, + } +} diff --git a/packages/medusa-test-utils/src/id-map.js b/packages/medusa-test-utils/src/id-map.js index c3af2c5520..49bd7fb284 100644 --- a/packages/medusa-test-utils/src/id-map.js +++ b/packages/medusa-test-utils/src/id-map.js @@ -1,19 +1,19 @@ -import randomize from "randomatic"; +import randomize from "randomatic" class IdMap { - ids = {}; + ids = {} getId(key, prefix = "", length = 10) { if (this.ids[key]) { - return this.ids[key]; + return this.ids[key] } - const id = `${prefix && prefix + "_"}${randomize("Aa0", length)}`; - this.ids[key] = id; + const id = `${prefix && prefix + "_"}${randomize("Aa0", length)}` + this.ids[key] = id - return id; + return id } } -const instance = new IdMap(); -export default instance; +const instance = new IdMap() +export default instance diff --git a/packages/medusa-test-utils/src/index.js b/packages/medusa-test-utils/src/index.js deleted file mode 100644 index 777ef14117..0000000000 --- a/packages/medusa-test-utils/src/index.js +++ /dev/null @@ -1,3 +0,0 @@ -export { default as IdMap } from "./id-map"; -export { default as MockRepository } from "./mock-repository"; -export { default as MockManager } from "./mock-manager"; diff --git a/packages/medusa-test-utils/src/index.ts b/packages/medusa-test-utils/src/index.ts new file mode 100644 index 0000000000..4a01de7064 --- /dev/null +++ b/packages/medusa-test-utils/src/index.ts @@ -0,0 +1,5 @@ +export * as TestDatabaseUtils from "./database" +export { default as IdMap } from "./id-map" +export * as JestUtils from "./jest" +export { default as MockManager } from "./mock-manager" +export { default as MockRepository } from "./mock-repository" diff --git a/packages/medusa-test-utils/src/jest.ts b/packages/medusa-test-utils/src/jest.ts new file mode 100644 index 0000000000..b10817c2ae --- /dev/null +++ b/packages/medusa-test-utils/src/jest.ts @@ -0,0 +1,24 @@ +import { dropDatabase } from "pg-god" + +export function afterAllHookDropDatabase() { + const DB_HOST = process.env.DB_HOST ?? "localhost" + const DB_USERNAME = process.env.DB_USERNAME ?? "postgres" + const DB_PASSWORD = process.env.DB_PASSWORD ?? "" + const DB_NAME = process.env.DB_TEMP_NAME || "" + + const pgGodCredentials = { + user: DB_USERNAME, + password: DB_PASSWORD, + host: DB_HOST, + } + + afterAll(async () => { + try { + await dropDatabase({ databaseName: DB_NAME }, pgGodCredentials) + } catch (e) { + console.error( + `This might fail if it is run during the unit tests since there is no database to drop. Otherwise, please check what is the issue. ${e.message}` + ) + } + }) +} diff --git a/packages/medusa-test-utils/tsconfig.json b/packages/medusa-test-utils/tsconfig.json new file mode 100644 index 0000000000..40f5058e6d --- /dev/null +++ b/packages/medusa-test-utils/tsconfig.json @@ -0,0 +1,23 @@ +{ + "compilerOptions": { + "lib": ["es5", "es6", "es2019"], + "target": "es5", + "outDir": "./dist", + "esModuleInterop": true, + "declaration": false, + "module": "commonjs", + "moduleResolution": "node", + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "sourceMap": true, + "noImplicitReturns": true, + "strictNullChecks": true, + "strictFunctionTypes": true, + "noImplicitThis": true, + "allowJs": true, + "skipLibCheck": true, + "downlevelIteration": true + }, + "include": ["src"], + "exclude": ["dist", "node_modules"] +} diff --git a/packages/modules-sdk/src/definitions.ts b/packages/modules-sdk/src/definitions.ts index 00e517d17e..3db4673ce6 100644 --- a/packages/modules-sdk/src/definitions.ts +++ b/packages/modules-sdk/src/definitions.ts @@ -10,6 +10,7 @@ export enum Modules { INVENTORY = "inventoryService", CACHE = "cacheService", PRODUCT = "productService", + PRICING = "pricingService", } export enum ModuleRegistrationName { @@ -18,6 +19,7 @@ export enum ModuleRegistrationName { INVENTORY = "inventoryService", CACHE = "cacheService", PRODUCT = "productModuleService", + PRICING = "pricingModuleService", } export const MODULE_PACKAGE_NAMES = { @@ -26,6 +28,7 @@ export const MODULE_PACKAGE_NAMES = { [Modules.STOCK_LOCATION]: "@medusajs/stock-location", [Modules.INVENTORY]: "@medusajs/inventory", [Modules.CACHE]: "@medusajs/cache-inmemory", + [Modules.PRICING]: "@medusajs/pricing", } export const ModulesDefinition: { [key: string | Modules]: ModuleDefinition } = @@ -97,6 +100,20 @@ export const ModulesDefinition: { [key: string | Modules]: ModuleDefinition } = resources: MODULE_RESOURCE_TYPE.SHARED, }, }, + [Modules.PRICING]: { + key: Modules.PRICING, + registrationName: ModuleRegistrationName.PRICING, + defaultPackage: false, + label: "PricingModuleService", + isRequired: false, + canOverride: true, + isQueryable: true, + dependencies: ["logger"], + defaultModuleDeclaration: { + scope: MODULE_SCOPE.INTERNAL, + resources: MODULE_RESOURCE_TYPE.SHARED, + }, + }, } export const MODULE_DEFINITIONS: ModuleDefinition[] = diff --git a/packages/pricing/.gitignore b/packages/pricing/.gitignore new file mode 100644 index 0000000000..874c6c69d3 --- /dev/null +++ b/packages/pricing/.gitignore @@ -0,0 +1,6 @@ +/dist +node_modules +.DS_store +.env* +.env +*.sql diff --git a/packages/pricing/CHANGELOG.md b/packages/pricing/CHANGELOG.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/pricing/README.md b/packages/pricing/README.md new file mode 100644 index 0000000000..d3f2cceff2 --- /dev/null +++ b/packages/pricing/README.md @@ -0,0 +1,3 @@ +# Pricing Module + +The Pricing Module gives you access MoneyAmounts, Currency and PriceList through a standalone package that can be installed and run in Next.js functions and other Node.js compatible runtimes. diff --git a/packages/pricing/integration-tests/__fixtures__/currency/data.ts b/packages/pricing/integration-tests/__fixtures__/currency/data.ts new file mode 100644 index 0000000000..970a22a5a8 --- /dev/null +++ b/packages/pricing/integration-tests/__fixtures__/currency/data.ts @@ -0,0 +1,20 @@ +export const defaultCurrencyData = [ + { + symbol: "$", + name: "US Dollar", + symbol_native: "$", + code: "USD", + }, + { + symbol: "CA$", + name: "Canadian Dollar", + symbol_native: "$", + code: "CAD", + }, + { + symbol: "€", + name: "Euro", + symbol_native: "€", + code: "EUR", + }, +] diff --git a/packages/pricing/integration-tests/__fixtures__/currency/index.ts b/packages/pricing/integration-tests/__fixtures__/currency/index.ts new file mode 100644 index 0000000000..3aa94e5f0e --- /dev/null +++ b/packages/pricing/integration-tests/__fixtures__/currency/index.ts @@ -0,0 +1,20 @@ +import { SqlEntityManager } from "@mikro-orm/postgresql" +import { Currency } from "@models" +import { defaultCurrencyData } from "./data" + +export async function createCurrencies( + manager: SqlEntityManager, + currencyData: any[] = defaultCurrencyData +): Promise { + const currencies: Currency[] = [] + + for (let curr of currencyData) { + const currency = manager.create(Currency, curr) + + currencies.push(currency) + } + + await manager.persistAndFlush(currencies) + + return currencies +} diff --git a/packages/pricing/integration-tests/__tests__/services/currency/index.spec.ts b/packages/pricing/integration-tests/__tests__/services/currency/index.spec.ts new file mode 100644 index 0000000000..7b8a97c15b --- /dev/null +++ b/packages/pricing/integration-tests/__tests__/services/currency/index.spec.ts @@ -0,0 +1,277 @@ +import { SqlEntityManager } from "@mikro-orm/postgresql" + +import { Currency } from "@models" +import { CurrencyRepository } from "@repositories" +import { CurrencyService } from "@services" + +import { createCurrencies } from "../../../__fixtures__/currency" +import { MikroOrmWrapper } from "../../../utils" + +jest.setTimeout(30000) + +describe("Currency Service", () => { + let service: CurrencyService + let testManager: SqlEntityManager + let repositoryManager: SqlEntityManager + let data!: Currency[] + + const currencyData = [ + { + symbol: "$", + name: "US Dollar", + symbol_native: "$", + code: "USD", + }, + { + symbol: "CA$", + name: "Canadian Dollar", + symbol_native: "$", + code: "CAD", + }, + ] + + beforeEach(async () => { + await MikroOrmWrapper.setupDatabase() + repositoryManager = await MikroOrmWrapper.forkManager() + + const currencyRepository = new CurrencyRepository({ + manager: repositoryManager, + }) + + service = new CurrencyService({ + currencyRepository, + }) + + testManager = await MikroOrmWrapper.forkManager() + + data = await createCurrencies(testManager, currencyData) + }) + + afterEach(async () => { + await MikroOrmWrapper.clearDatabase() + }) + + describe("list", () => { + it("list currencies", async () => { + const currenciesResult = await service.list() + + expect(currenciesResult).toEqual([ + expect.objectContaining({ + code: "USD", + name: "US Dollar", + }), + expect.objectContaining({ + code: "CAD", + name: "Canadian Dollar", + }), + ]) + }) + + it("list currencies by code", async () => { + const currenciesResult = await service.list({ code: ["USD"] }) + + expect(currenciesResult).toEqual([ + expect.objectContaining({ + code: "USD", + name: "US Dollar", + }), + ]) + }) + }) + + describe("listAndCount", () => { + it("should return currencies and count", async () => { + const [currenciesResult, count] = await service.listAndCount() + + expect(count).toEqual(2) + expect(currenciesResult).toEqual([ + expect.objectContaining({ + code: "USD", + name: "US Dollar", + }), + expect.objectContaining({ + code: "CAD", + name: "Canadian Dollar", + }), + ]) + }) + + it("should return currencies and count when filtered", async () => { + const [currenciesResult, count] = await service.listAndCount({ + code: ["USD"], + }) + + expect(count).toEqual(1) + expect(currenciesResult).toEqual([ + expect.objectContaining({ + code: "USD", + name: "US Dollar", + }), + ]) + }) + + it("should return currencies and count when using skip and take", async () => { + const [currenciesResult, count] = await service.listAndCount( + {}, + { skip: 1, take: 1 } + ) + + expect(count).toEqual(2) + expect(currenciesResult).toEqual([ + expect.objectContaining({ + code: "CAD", + name: "Canadian Dollar", + }), + ]) + }) + + it("should return requested fields", async () => { + const [currenciesResult, count] = await service.listAndCount( + {}, + { + take: 1, + select: ["code"], + } + ) + + const serialized = JSON.parse(JSON.stringify(currenciesResult)) + + expect(count).toEqual(2) + expect(serialized).toEqual([ + { + code: "USD", + }, + ]) + }) + }) + + describe("retrieve", () => { + const code = "USD" + const name = "US Dollar" + + it("should return currency for the given code", async () => { + const currency = await service.retrieve(code) + + expect(currency).toEqual( + expect.objectContaining({ + code, + }) + ) + }) + + it("should throw an error when currency with code does not exist", async () => { + let error + + try { + await service.retrieve("does-not-exist") + } catch (e) { + error = e + } + + expect(error.message).toEqual( + "Currency with code: does-not-exist was not found" + ) + }) + + it("should throw an error when a code is not provided", async () => { + let error + + try { + await service.retrieve(undefined as unknown as string) + } catch (e) { + error = e + } + + expect(error.message).toEqual('"currencyCode" must be defined') + }) + + it("should return currency based on config select param", async () => { + const currency = await service.retrieve(code, { + select: ["code", "name"], + }) + + const serialized = JSON.parse(JSON.stringify(currency)) + + expect(serialized).toEqual({ + code, + name, + }) + }) + }) + + describe("delete", () => { + const code = "USD" + + it("should delete the currencies given an code successfully", async () => { + await service.delete([code]) + + const currencies = await service.list({ + code: [code], + }) + + expect(currencies).toHaveLength(0) + }) + }) + + describe("update", () => { + const code = "USD" + + it("should update the name of the currency successfully", async () => { + await service.update([ + { + code, + name: "United States Pounds", + }, + ]) + + const currency = await service.retrieve(code) + + expect(currency.name).toEqual("United States Pounds") + }) + + it("should throw an error when a code does not exist", async () => { + let error + + try { + await service.update([ + { + code: "does-not-exist", + name: "UK", + }, + ]) + } catch (e) { + error = e + } + + expect(error.message).toEqual( + 'Currency with code "does-not-exist" not found' + ) + }) + }) + + describe("create", () => { + it("should create a currency successfully", async () => { + await service.create([ + { + code: "TES", + name: "Test Dollars", + symbol: "TES1", + symbol_native: "TES2", + }, + ]) + + const [currency] = await service.list({ + code: ["TES"], + }) + + expect(currency).toEqual( + expect.objectContaining({ + code: "TES", + name: "Test Dollars", + symbol: "TES1", + symbol_native: "TES2", + }) + ) + }) + }) +}) diff --git a/packages/pricing/integration-tests/__tests__/services/pricing-module/currency.spec.ts b/packages/pricing/integration-tests/__tests__/services/pricing-module/currency.spec.ts new file mode 100644 index 0000000000..399c444600 --- /dev/null +++ b/packages/pricing/integration-tests/__tests__/services/pricing-module/currency.spec.ts @@ -0,0 +1,269 @@ +import { initialize } from "../../../../src" + +import { IPricingModuleService } from "@medusajs/types" + +import { SqlEntityManager } from "@mikro-orm/postgresql" + +import { Currency } from "@models" + +import { createCurrencies } from "../../../__fixtures__/currency" +import { DB_URL, MikroOrmWrapper } from "../../../utils" + +describe("PricingModuleService currency", () => { + let service: IPricingModuleService + let testManager: SqlEntityManager + let repositoryManager: SqlEntityManager + let data!: Currency[] + + beforeEach(async () => { + await MikroOrmWrapper.setupDatabase() + repositoryManager = MikroOrmWrapper.forkManager() + + service = await initialize({ + database: { + clientUrl: DB_URL, + schema: process.env.MEDUSA_PRICING_DB_SCHEMA, + }, + }) + + testManager = MikroOrmWrapper.forkManager() + + data = await createCurrencies(testManager) + }) + + afterEach(async () => { + await MikroOrmWrapper.clearDatabase() + }) + + describe("listCurrencies", () => { + it("list currencies", async () => { + const currenciesResult = await service.listCurrencies() + + expect(currenciesResult).toEqual([ + expect.objectContaining({ + code: "USD", + name: "US Dollar", + }), + expect.objectContaining({ + code: "CAD", + name: "Canadian Dollar", + }), + expect.objectContaining({ + code: "EUR", + name: "Euro", + }), + ]) + }) + + it("list currencies by code", async () => { + const currenciesResult = await service.listCurrencies({ code: ["USD"] }) + + expect(currenciesResult).toEqual([ + expect.objectContaining({ + code: "USD", + name: "US Dollar", + }), + ]) + }) + }) + + describe("listAndCountCurrencies", () => { + it("should return currencies and count", async () => { + const [currenciesResult, count] = await service.listAndCountCurrencies() + + expect(count).toEqual(3) + expect(currenciesResult).toEqual([ + expect.objectContaining({ + code: "USD", + name: "US Dollar", + }), + expect.objectContaining({ + code: "CAD", + name: "Canadian Dollar", + }), + expect.objectContaining({ + code: "EUR", + name: "Euro", + }), + ]) + }) + + it("should return currencies and count when filtered", async () => { + const [currenciesResult, count] = await service.listAndCountCurrencies({ + code: ["USD"], + }) + + expect(count).toEqual(1) + expect(currenciesResult).toEqual([ + expect.objectContaining({ + code: "USD", + name: "US Dollar", + }), + ]) + }) + + it("should return currencies and count when using skip and take", async () => { + const [currenciesResult, count] = await service.listAndCountCurrencies( + {}, + { skip: 1, take: 1 } + ) + + expect(count).toEqual(3) + expect(currenciesResult).toEqual([ + expect.objectContaining({ + code: "CAD", + name: "Canadian Dollar", + }), + ]) + }) + + it("should return requested fields", async () => { + const [currenciesResult, count] = await service.listAndCountCurrencies( + {}, + { + take: 1, + select: ["code"], + } + ) + + const serialized = JSON.parse(JSON.stringify(currenciesResult)) + + expect(count).toEqual(3) + expect(serialized).toEqual([ + { + code: "USD", + }, + ]) + }) + }) + + describe("retrieveCurrency", () => { + const code = "USD" + const name = "US Dollar" + + it("should return currency for the given code", async () => { + const currency = await service.retrieveCurrency(code) + + expect(currency).toEqual( + expect.objectContaining({ + code, + }) + ) + }) + + it("should throw an error when currency with code does not exist", async () => { + let error + + try { + await service.retrieveCurrency("does-not-exist") + } catch (e) { + error = e + } + + expect(error.message).toEqual( + "Currency with code: does-not-exist was not found" + ) + }) + + it("should throw an error when a code is not provided", async () => { + let error + + try { + await service.retrieveCurrency(undefined as unknown as string) + } catch (e) { + error = e + } + + expect(error.message).toEqual('"currencyCode" must be defined') + }) + + it("should return currency based on config select param", async () => { + const currency = await service.retrieveCurrency(code, { + select: ["code", "name"], + }) + + const serialized = JSON.parse(JSON.stringify(currency)) + + expect(serialized).toEqual({ + code, + name, + }) + }) + }) + + describe("deleteCurrencies", () => { + const code = "USD" + + it("should delete the currencies given an code successfully", async () => { + await service.deleteCurrencies([code]) + + const currencies = await service.listCurrencies({ + code: [code], + }) + + expect(currencies).toHaveLength(0) + }) + }) + + describe("updateCurrencies", () => { + const code = "USD" + + it("should update the name of the currency successfully", async () => { + await service.updateCurrencies([ + { + code, + name: "United States Pounds", + }, + ]) + + const currency = await service.retrieveCurrency(code) + + expect(currency.name).toEqual("United States Pounds") + }) + + it("should throw an error when a code does not exist", async () => { + let error + + try { + await service.updateCurrencies([ + { + code: "does-not-exist", + name: "UK", + }, + ]) + } catch (e) { + error = e + } + + expect(error.message).toEqual( + 'Currency with code "does-not-exist" not found' + ) + }) + }) + + describe("createCurrencies", () => { + it("should create a currency successfully", async () => { + await service.createCurrencies([ + { + code: "TES", + name: "Test Dollars", + symbol: "TES1", + symbol_native: "TES2", + }, + ]) + + const [currency] = await service.listCurrencies({ + code: ["TES"], + }) + + expect(currency).toEqual( + expect.objectContaining({ + code: "TES", + name: "Test Dollars", + symbol: "TES1", + symbol_native: "TES2", + }) + ) + }) + }) +}) diff --git a/packages/pricing/integration-tests/setup-env.js b/packages/pricing/integration-tests/setup-env.js new file mode 100644 index 0000000000..d3f7bdc412 --- /dev/null +++ b/packages/pricing/integration-tests/setup-env.js @@ -0,0 +1,6 @@ +if (typeof process.env.DB_TEMP_NAME === "undefined") { + const tempName = parseInt(process.env.JEST_WORKER_ID || "1") + process.env.DB_TEMP_NAME = `medusa-integration-${tempName}` +} + +process.env.MEDUSA_PRICING_DB_SCHEMA = "public" diff --git a/packages/pricing/integration-tests/setup.js b/packages/pricing/integration-tests/setup.js new file mode 100644 index 0000000000..43f99aab4a --- /dev/null +++ b/packages/pricing/integration-tests/setup.js @@ -0,0 +1,3 @@ +import { JestUtils } from "medusa-test-utils" + +JestUtils.afterAllHookDropDatabase() diff --git a/packages/pricing/integration-tests/utils/config.ts b/packages/pricing/integration-tests/utils/config.ts new file mode 100644 index 0000000000..6d3b168c42 --- /dev/null +++ b/packages/pricing/integration-tests/utils/config.ts @@ -0,0 +1,6 @@ +import { ModuleServiceInitializeOptions } from "@medusajs/types" + +export const databaseOptions: ModuleServiceInitializeOptions["database"] = { + schema: "public", + clientUrl: "medusa-pricing-test", +} diff --git a/packages/pricing/integration-tests/utils/database.ts b/packages/pricing/integration-tests/utils/database.ts new file mode 100644 index 0000000000..0601587191 --- /dev/null +++ b/packages/pricing/integration-tests/utils/database.ts @@ -0,0 +1,18 @@ +import { TestDatabaseUtils } from "medusa-test-utils" + +import * as PricingModels from "@models" + +const pathToMigrations = "../../src/migrations" +const mikroOrmEntities = PricingModels as unknown as any[] + +export const MikroOrmWrapper = TestDatabaseUtils.getMikroOrmWrapper( + mikroOrmEntities, + pathToMigrations +) + +export const MikroOrmConfig = TestDatabaseUtils.getMikroOrmConfig( + mikroOrmEntities, + pathToMigrations +) + +export const DB_URL = TestDatabaseUtils.getDatabaseURL() diff --git a/packages/pricing/integration-tests/utils/index.ts b/packages/pricing/integration-tests/utils/index.ts new file mode 100644 index 0000000000..6b917ed30e --- /dev/null +++ b/packages/pricing/integration-tests/utils/index.ts @@ -0,0 +1 @@ +export * from "./database" diff --git a/packages/pricing/jest.config.js b/packages/pricing/jest.config.js new file mode 100644 index 0000000000..860ba90a49 --- /dev/null +++ b/packages/pricing/jest.config.js @@ -0,0 +1,21 @@ +module.exports = { + moduleNameMapper: { + "^@models": "/src/models", + "^@services": "/src/services", + "^@repositories": "/src/repositories", + }, + 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/pricing/mikro-orm.config.dev.ts b/packages/pricing/mikro-orm.config.dev.ts new file mode 100644 index 0000000000..fe6da460e6 --- /dev/null +++ b/packages/pricing/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-pricing", + type: "postgresql", +} diff --git a/packages/pricing/package.json b/packages/pricing/package.json new file mode 100644 index 0000000000..f0dd800e9b --- /dev/null +++ b/packages/pricing/package.json @@ -0,0 +1,60 @@ +{ + "name": "@medusajs/pricing", + "version": "0.0.1", + "description": "Medusa Pricing module", + "main": "dist/index.js", + "types": "dist/index.d.ts", + "files": [ + "dist" + ], + "bin": { + "medusa-pricing-migrations-down": "dist/scripts/bin/run-migration-down.js", + "medusa-pricing-migrations-up": "dist/scripts/bin/run-migration-up.js", + "medusa-pricing-seed": "dist/scripts/bin/run-seed.js" + }, + "repository": { + "type": "git", + "url": "https://github.com/medusajs/medusa", + "directory": "packages/pricing" + }, + "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.7.12", + "cross-env": "^5.2.1", + "jest": "^29.6.3", + "medusa-test-utils": "^1.1.40", + "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.9.2", + "@medusajs/types": "^1.10.2", + "@medusajs/utils": "^1.9.7", + "@mikro-orm/core": "5.7.12", + "@mikro-orm/migrations": "5.7.12", + "@mikro-orm/postgresql": "5.7.12", + "awilix": "^8.0.0", + "dotenv": "^16.1.4", + "knex": "2.4.2" + } +} diff --git a/packages/pricing/src/index.ts b/packages/pricing/src/index.ts new file mode 100644 index 0000000000..45da1e739d --- /dev/null +++ b/packages/pricing/src/index.ts @@ -0,0 +1,10 @@ +import { moduleDefinition } from "./module-definition" + +export default moduleDefinition + +export * from "./scripts" +export * from "./initialize" +export * from "./types" +export * from "./loaders" +export * from "./models" +export * from "./services" diff --git a/packages/pricing/src/initialize/index.ts b/packages/pricing/src/initialize/index.ts new file mode 100644 index 0000000000..1295c2910e --- /dev/null +++ b/packages/pricing/src/initialize/index.ts @@ -0,0 +1,31 @@ +import { + ExternalModuleDeclaration, + InternalModuleDeclaration, + MedusaModule, + MODULE_PACKAGE_NAMES, + Modules, +} from "@medusajs/modules-sdk" +import { IPricingModuleService, ModulesSdkTypes } from "@medusajs/types" +import { moduleDefinition } from "../module-definition" +import { InitializeModuleInjectableDependencies } from "../types" + +export const initialize = async ( + options?: + | ModulesSdkTypes.ModuleServiceInitializeOptions + | ModulesSdkTypes.ModuleServiceInitializeCustomDataLayerOptions + | ExternalModuleDeclaration + | InternalModuleDeclaration, + injectedDependencies?: InitializeModuleInjectableDependencies +): Promise => { + const serviceKey = Modules.PRICING + + const loaded = await MedusaModule.bootstrap( + serviceKey, + MODULE_PACKAGE_NAMES[Modules.PRICING], + options as InternalModuleDeclaration | ExternalModuleDeclaration, + moduleDefinition, + injectedDependencies + ) + + return loaded[serviceKey] +} diff --git a/packages/pricing/src/joiner-config.ts b/packages/pricing/src/joiner-config.ts new file mode 100644 index 0000000000..76bb77d7c7 --- /dev/null +++ b/packages/pricing/src/joiner-config.ts @@ -0,0 +1,38 @@ +import { Modules } from "@medusajs/modules-sdk" +import { JoinerServiceConfig } from "@medusajs/types" +import { MapToConfig } from "@medusajs/utils" +import { Currency } from "@models" + +export enum LinkableKeys { + MONEY_AMOUNT_ID = "money_amount_id", + CURRENCY_CODE = "code", +} + +export const entityNameToLinkableKeysMap: MapToConfig = { + [Currency.name]: [{ mapTo: LinkableKeys.CURRENCY_CODE, valueFrom: "code" }], +} + +export const joinerConfig: JoinerServiceConfig = { + serviceName: Modules.PRICING, + primaryKeys: ["code"], + alias: [ + // { + // name: "money_amount", + // }, + // { + // name: "money_amounts", + // }, + { + name: "currency", + args: { + methodSuffix: "Currencies", + }, + }, + { + name: "currencies", + args: { + methodSuffix: "Currencies", + }, + }, + ], +} diff --git a/packages/pricing/src/loaders/connection.ts b/packages/pricing/src/loaders/connection.ts new file mode 100644 index 0000000000..ad1480d4c1 --- /dev/null +++ b/packages/pricing/src/loaders/connection.ts @@ -0,0 +1,27 @@ +import { InternalModuleDeclaration, LoaderOptions } from "@medusajs/modules-sdk" +import { ModulesSdkTypes } from "@medusajs/types" +import { ModulesSdkUtils } from "@medusajs/utils" +import { EntitySchema } from "@mikro-orm/core" +import * as PricingModels from "../models" + +export default async ( + { + options, + container, + logger, + }: LoaderOptions< + | ModulesSdkTypes.ModuleServiceInitializeOptions + | ModulesSdkTypes.ModuleServiceInitializeCustomDataLayerOptions + >, + moduleDeclaration?: InternalModuleDeclaration +): Promise => { + const entities = Object.values(PricingModels) as unknown as EntitySchema[] + + await ModulesSdkUtils.mikroOrmConnectionLoader({ + entities, + container, + options, + moduleDeclaration, + logger, + }) +} diff --git a/packages/pricing/src/loaders/container.ts b/packages/pricing/src/loaders/container.ts new file mode 100644 index 0000000000..5432813d7f --- /dev/null +++ b/packages/pricing/src/loaders/container.ts @@ -0,0 +1,41 @@ +import { ModulesSdkTypes } from "@medusajs/types" +import * as defaultRepositories from "@repositories" +import { BaseRepository, CurrencyRepository } from "@repositories" +import { CurrencyService } from "@services" + +import { LoaderOptions } from "@medusajs/modules-sdk" +import { loadCustomRepositories } from "@medusajs/utils" +import { asClass } from "awilix" + +export default async ({ + container, + options, +}: LoaderOptions< + | ModulesSdkTypes.ModuleServiceInitializeOptions + | ModulesSdkTypes.ModuleServiceInitializeCustomDataLayerOptions +>): Promise => { + const customRepositories = ( + options as ModulesSdkTypes.ModuleServiceInitializeCustomDataLayerOptions + )?.repositories + + container.register({ + currencyService: asClass(CurrencyService).singleton(), + }) + + if (customRepositories) { + loadCustomRepositories({ + defaultRepositories, + customRepositories, + container, + }) + } else { + loadDefaultRepositories({ container }) + } +} + +function loadDefaultRepositories({ container }) { + container.register({ + baseRepository: asClass(BaseRepository).singleton(), + currencyRepository: asClass(CurrencyRepository).singleton(), + }) +} diff --git a/packages/pricing/src/loaders/index.ts b/packages/pricing/src/loaders/index.ts new file mode 100644 index 0000000000..3614963d8c --- /dev/null +++ b/packages/pricing/src/loaders/index.ts @@ -0,0 +1,2 @@ +export * from "./connection" +export * from "./container" diff --git a/packages/pricing/src/migrations/.snapshot-medusa-pricing.json b/packages/pricing/src/migrations/.snapshot-medusa-pricing.json new file mode 100644 index 0000000000..c34620bb72 --- /dev/null +++ b/packages/pricing/src/migrations/.snapshot-medusa-pricing.json @@ -0,0 +1,63 @@ +{ + "namespaces": [ + "public" + ], + "name": "public", + "tables": [ + { + "columns": { + "code": { + "name": "code", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "mappedType": "text" + }, + "symbol": { + "name": "symbol", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "mappedType": "text" + }, + "symbol_native": { + "name": "symbol_native", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "mappedType": "text" + }, + "name": { + "name": "name", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "mappedType": "text" + } + }, + "name": "currency", + "schema": "public", + "indexes": [ + { + "keyName": "currency_pkey", + "columnNames": [ + "code" + ], + "composite": false, + "primary": true, + "unique": true + } + ], + "checks": [], + "foreignKeys": {} + } + ] +} diff --git a/packages/pricing/src/migrations/Migration20230828182018.ts b/packages/pricing/src/migrations/Migration20230828182018.ts new file mode 100644 index 0000000000..dc119b8223 --- /dev/null +++ b/packages/pricing/src/migrations/Migration20230828182018.ts @@ -0,0 +1,9 @@ +import { Migration } from '@mikro-orm/migrations'; + +export class Migration20230828182018 extends Migration { + + async up(): Promise { + this.addSql('create table "currency" ("code" text not null, "symbol" text not null, "symbol_native" text not null, "name" text not null, constraint "currency_pkey" primary key ("code"));'); + } + +} diff --git a/packages/pricing/src/models/currency.ts b/packages/pricing/src/models/currency.ts new file mode 100644 index 0000000000..03a073782f --- /dev/null +++ b/packages/pricing/src/models/currency.ts @@ -0,0 +1,27 @@ +import { Entity, PrimaryKey, Property } from "@mikro-orm/core" + +@Entity({ tableName: "currency" }) +class Currency { + @PrimaryKey({ columnType: "text" }) + code!: string + + @Property({ columnType: "text" }) + symbol: string + + @Property({ columnType: "text" }) + symbol_native: string + + @Property({ columnType: "text" }) + name: string + + // @Property({ persist: false }) + // get includes_tax() { + // // TODO: This comes from a feature flag + // // Figure out how we're handling FF in modules + // // For now, returning default as true + // // This should also not fall on the hands of the model + // return true + // } +} + +export default Currency diff --git a/packages/pricing/src/models/index.ts b/packages/pricing/src/models/index.ts new file mode 100644 index 0000000000..6f1a80b652 --- /dev/null +++ b/packages/pricing/src/models/index.ts @@ -0,0 +1 @@ +export { default as Currency } from "./currency" diff --git a/packages/pricing/src/module-definition.ts b/packages/pricing/src/module-definition.ts new file mode 100644 index 0000000000..721047739a --- /dev/null +++ b/packages/pricing/src/module-definition.ts @@ -0,0 +1,12 @@ +import { ModuleExports } from "@medusajs/types" +import { PricingModuleService } from "@services" +import loadConnection from "./loaders/connection" +import loadContainer from "./loaders/container" + +const service = PricingModuleService +const loaders = [loadContainer, loadConnection] as any + +export const moduleDefinition: ModuleExports = { + service, + loaders, +} diff --git a/packages/pricing/src/repositories/currency.ts b/packages/pricing/src/repositories/currency.ts new file mode 100644 index 0000000000..a0543d2d8c --- /dev/null +++ b/packages/pricing/src/repositories/currency.ts @@ -0,0 +1,127 @@ +import { + Context, + CreateCurrencyDTO, + DAL, + UpdateCurrencyDTO, +} from "@medusajs/types" +import { DALUtils, MedusaError } from "@medusajs/utils" +import { + LoadStrategy, + FilterQuery as MikroFilterQuery, + FindOptions as MikroOptions, +} from "@mikro-orm/core" +import { SqlEntityManager } from "@mikro-orm/postgresql" +import { Currency } from "@models" + +export class CurrencyRepository extends DALUtils.MikroOrmBaseRepository { + protected readonly manager_: SqlEntityManager + + constructor({ manager }: { manager: SqlEntityManager }) { + // @ts-ignore + // eslint-disable-next-line prefer-rest-params + super(...arguments) + this.manager_ = manager + } + + async find( + findOptions: DAL.FindOptions = { where: {} }, + context: Context = {} + ): Promise { + const manager = this.getActiveManager(context) + + const findOptions_ = { ...findOptions } + findOptions_.options ??= {} + + Object.assign(findOptions_.options, { + strategy: LoadStrategy.SELECT_IN, + }) + + return await manager.find( + Currency, + findOptions_.where as MikroFilterQuery, + findOptions_.options as MikroOptions + ) + } + + async findAndCount( + findOptions: DAL.FindOptions = { where: {} }, + context: Context = {} + ): Promise<[Currency[], number]> { + const manager = this.getActiveManager(context) + + const findOptions_ = { ...findOptions } + findOptions_.options ??= {} + + Object.assign(findOptions_.options, { + strategy: LoadStrategy.SELECT_IN, + }) + + return await manager.findAndCount( + Currency, + findOptions_.where as MikroFilterQuery, + findOptions_.options as MikroOptions + ) + } + + async delete(codes: string[], context: Context = {}): Promise { + const manager = this.getActiveManager(context) + await manager.nativeDelete(Currency, { code: { $in: codes } }, {}) + } + + async create( + data: CreateCurrencyDTO[], + context: Context = {} + ): Promise { + const manager = this.getActiveManager(context) + + const currencies = data.map((currencyData) => { + return manager.create(Currency, currencyData) + }) + + manager.persist(currencies) + + return currencies + } + + async update( + data: UpdateCurrencyDTO[], + context: Context = {} + ): Promise { + const manager = this.getActiveManager(context) + const currencyCodes = data.map((currencyData) => currencyData.code) + const existingCurrencies = await this.find( + { + where: { + code: { + $in: currencyCodes, + }, + }, + }, + context + ) + + const existingCurrencyMap = new Map( + existingCurrencies.map<[string, Currency]>((currency) => [ + currency.code, + currency, + ]) + ) + + const currencies = data.map((currencyData) => { + const existingCurrency = existingCurrencyMap.get(currencyData.code) + + if (!existingCurrency) { + throw new MedusaError( + MedusaError.Types.NOT_FOUND, + `Currency with code "${currencyData.code}" not found` + ) + } + + return manager.assign(existingCurrency, currencyData) + }) + + manager.persist(currencies) + + return currencies + } +} diff --git a/packages/pricing/src/repositories/index.ts b/packages/pricing/src/repositories/index.ts new file mode 100644 index 0000000000..dfaa814a72 --- /dev/null +++ b/packages/pricing/src/repositories/index.ts @@ -0,0 +1,2 @@ +export { MikroOrmBaseRepository as BaseRepository } from "@medusajs/utils" +export { CurrencyRepository } from "./currency" diff --git a/packages/pricing/src/scripts/bin/run-migration-down.ts b/packages/pricing/src/scripts/bin/run-migration-down.ts new file mode 100644 index 0000000000..e352048fd4 --- /dev/null +++ b/packages/pricing/src/scripts/bin/run-migration-down.ts @@ -0,0 +1,8 @@ +#!/usr/bin/env node + +export default (async () => { + const { revertMigration } = await import("../migration-down") + const { config } = await import("dotenv") + config() + await revertMigration() +})() diff --git a/packages/pricing/src/scripts/bin/run-migration-up.ts b/packages/pricing/src/scripts/bin/run-migration-up.ts new file mode 100644 index 0000000000..35f3bee853 --- /dev/null +++ b/packages/pricing/src/scripts/bin/run-migration-up.ts @@ -0,0 +1,8 @@ +#!/usr/bin/env node + +export default (async () => { + const { runMigrations } = await import("../migration-up") + const { config } = await import("dotenv") + config() + await runMigrations() +})() diff --git a/packages/pricing/src/scripts/bin/run-seed.ts b/packages/pricing/src/scripts/bin/run-seed.ts new file mode 100644 index 0000000000..26880f61fb --- /dev/null +++ b/packages/pricing/src/scripts/bin/run-seed.ts @@ -0,0 +1,19 @@ +#!/usr/bin/env node + +import { EOL } from "os" +import { run } from "../seed" + +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-pricing-seed ` + ) + } + + await run({ path }) +})() diff --git a/packages/pricing/src/scripts/index.ts b/packages/pricing/src/scripts/index.ts new file mode 100644 index 0000000000..cfa5c5ddf5 --- /dev/null +++ b/packages/pricing/src/scripts/index.ts @@ -0,0 +1,2 @@ +export * from "./migration-up" +export * from "./migration-down" diff --git a/packages/pricing/src/scripts/migration-down.ts b/packages/pricing/src/scripts/migration-down.ts new file mode 100644 index 0000000000..96b4d88c5b --- /dev/null +++ b/packages/pricing/src/scripts/migration-down.ts @@ -0,0 +1,39 @@ +import * as PricingModels from "@models" + +import { LoaderOptions, Logger, ModulesSdkTypes } from "@medusajs/types" + +import { DALUtils, ModulesSdkUtils } from "@medusajs/utils" +import { EntitySchema } from "@mikro-orm/core" + +/** + * This script is only valid for mikro orm managers. If a user provide a custom manager + * he is in charge of reverting the migrations. + * @param options + * @param logger + * @param moduleDeclaration + */ +export async function revertMigration({ + options, + logger, +}: Pick< + LoaderOptions, + "options" | "logger" +> = {}) { + logger ??= console as unknown as Logger + + const dbData = ModulesSdkUtils.loadDatabaseConfig("pricing", options)! + const entities = Object.values(PricingModels) as unknown as EntitySchema[] + + const orm = await DALUtils.mikroOrmCreateConnection(dbData, entities) + + try { + const migrator = orm.getMigrator() + await migrator.down() + + logger?.info("Pricing module migration executed") + } catch (error) { + logger?.error(`Pricing module migration failed to run - Error: ${error}`) + } + + await orm.close() +} diff --git a/packages/pricing/src/scripts/migration-up.ts b/packages/pricing/src/scripts/migration-up.ts new file mode 100644 index 0000000000..656ed6e3b1 --- /dev/null +++ b/packages/pricing/src/scripts/migration-up.ts @@ -0,0 +1,43 @@ +import { LoaderOptions, Logger, ModulesSdkTypes } from "@medusajs/types" +import { DALUtils, ModulesSdkUtils } from "@medusajs/utils" +import { EntitySchema } from "@mikro-orm/core" +import * as PricingModels from "@models" + +/** + * This script is only valid for mikro orm managers. If a user provide a custom manager + * he is in charge of running the migrations. + * @param options + * @param logger + * @param moduleDeclaration + */ +export async function runMigrations({ + options, + logger, +}: Pick< + LoaderOptions, + "options" | "logger" +> = {}) { + logger ??= console as unknown as Logger + + const dbData = ModulesSdkUtils.loadDatabaseConfig("pricing", options)! + const entities = Object.values(PricingModels) as unknown as EntitySchema[] + + const orm = await DALUtils.mikroOrmCreateConnection(dbData, entities) + + try { + const migrator = orm.getMigrator() + + const pendingMigrations = await migrator.getPendingMigrations() + logger.info(`Running pending migrations: ${pendingMigrations}`) + + await migrator.up({ + migrations: pendingMigrations.map((m) => m.name), + }) + + logger.info("Pricing module migration executed") + } catch (error) { + logger.error(`Pricing module migration failed to run - Error: ${error}`) + } + + await orm.close() +} diff --git a/packages/pricing/src/scripts/seed.ts b/packages/pricing/src/scripts/seed.ts new file mode 100644 index 0000000000..6e86718bbc --- /dev/null +++ b/packages/pricing/src/scripts/seed.ts @@ -0,0 +1,64 @@ +import { LoaderOptions, Logger, ModulesSdkTypes } from "@medusajs/types" +import { DALUtils, ModulesSdkUtils } from "@medusajs/utils" +import { EntitySchema, RequiredEntityData } from "@mikro-orm/core" +import { SqlEntityManager } from "@mikro-orm/postgresql" +import * as PricingModels from "@models" +import { EOL } from "os" +import { resolve } from "path" + +export async function run({ + options, + logger, + path, +}: Partial< + Pick< + LoaderOptions, + "options" | "logger" + > +> & { + path: string +}) { + logger ??= console as unknown as Logger + + logger.info(`Loading seed data from ${path}...`) + + const { currenciesData } = await import(resolve(process.cwd(), path)).catch( + (e) => { + logger?.error( + `Failed to load seed data from ${path}. Please, provide a relative path and check that you export the following currenciesData.${EOL}${e}` + ) + throw e + } + ) + + const dbData = ModulesSdkUtils.loadDatabaseConfig("pricing", options)! + const entities = Object.values(PricingModels) as unknown as EntitySchema[] + + const orm = await DALUtils.mikroOrmCreateConnection(dbData, entities) + const manager = orm.em.fork() + + try { + logger.info("Inserting currencies") + + await createCurrencies(manager, currenciesData) + } catch (e) { + logger.error( + `Failed to insert the seed data in the PostgreSQL database ${dbData.clientUrl}.${EOL}${e}` + ) + } + + await orm.close(true) +} + +async function createCurrencies( + manager: SqlEntityManager, + data: RequiredEntityData[] +) { + const currencies: any[] = data.map((currencyData) => { + return manager.create(PricingModels.Currency, currencyData) + }) + + await manager.persistAndFlush(currencies) + + return currencies +} diff --git a/packages/pricing/src/services/__fixtures__/currency.ts b/packages/pricing/src/services/__fixtures__/currency.ts new file mode 100644 index 0000000000..7a356ebbcf --- /dev/null +++ b/packages/pricing/src/services/__fixtures__/currency.ts @@ -0,0 +1,21 @@ +import { CurrencyService } from "@services" +import { asClass, asValue, createContainer } from "awilix" + +export const nonExistingCurrencyCode = "non-existing-code" +export const mockContainer = createContainer() + +mockContainer.register({ + transaction: asValue(async (task) => await task()), + currencyRepository: asValue({ + find: jest.fn().mockImplementation(async ({ where: { code } }) => { + if (code === nonExistingCurrencyCode) { + return [] + } + + return [{}] + }), + findAndCount: jest.fn().mockResolvedValue([[], 0]), + getFreshManager: jest.fn().mockResolvedValue({}), + }), + currencyService: asClass(CurrencyService), +}) diff --git a/packages/pricing/src/services/__tests__/currency.spec.ts b/packages/pricing/src/services/__tests__/currency.spec.ts new file mode 100644 index 0000000000..af8ca20a94 --- /dev/null +++ b/packages/pricing/src/services/__tests__/currency.spec.ts @@ -0,0 +1,203 @@ +import { + mockContainer, + nonExistingCurrencyCode, +} from "../__fixtures__/currency" + +const code = "existing-currency" + +describe("Currency service", function () { + beforeEach(function () { + jest.clearAllMocks() + }) + + it("should retrieve a currency", async function () { + const currencyService = mockContainer.resolve("currencyService") + const currencyRepository = mockContainer.resolve("currencyRepository") + + await currencyService.retrieve(code) + + expect(currencyRepository.find).toHaveBeenCalledWith( + { + where: { + code, + }, + options: { + fields: undefined, + limit: 15, + offset: undefined, + populate: [], + }, + }, + expect.any(Object) + ) + }) + + it("should fail to retrieve a currency", async function () { + const currencyService = mockContainer.resolve("currencyService") + const currencyRepository = mockContainer.resolve("currencyRepository") + + const err = await currencyService + .retrieve(nonExistingCurrencyCode) + .catch((e) => e) + + expect(currencyRepository.find).toHaveBeenCalledWith( + { + where: { + code: nonExistingCurrencyCode, + }, + options: { + fields: undefined, + limit: 15, + offset: undefined, + populate: [], + withDeleted: undefined, + }, + }, + expect.any(Object) + ) + + expect(err.message).toBe( + `Currency with code: ${nonExistingCurrencyCode} was not found` + ) + }) + + it("should list currencys", async function () { + const currencyService = mockContainer.resolve("currencyService") + const currencyRepository = mockContainer.resolve("currencyRepository") + + const filters = {} + const config = { + relations: [], + } + + await currencyService.list(filters, config) + + expect(currencyRepository.find).toHaveBeenCalledWith( + { + where: {}, + options: { + fields: undefined, + limit: 15, + offset: undefined, + populate: [], + withDeleted: undefined, + }, + }, + expect.any(Object) + ) + }) + + it("should list currencys with filters", async function () { + const currencyService = mockContainer.resolve("currencyService") + const currencyRepository = mockContainer.resolve("currencyRepository") + + const filters = { + tags: { + value: { + $in: ["test"], + }, + }, + } + const config = { + relations: [], + } + + await currencyService.list(filters, config) + + expect(currencyRepository.find).toHaveBeenCalledWith( + { + where: { + tags: { + value: { + $in: ["test"], + }, + }, + }, + options: { + fields: undefined, + limit: 15, + offset: undefined, + populate: [], + withDeleted: undefined, + }, + }, + expect.any(Object) + ) + }) + + it("should list currencys with filters and relations", async function () { + const currencyService = mockContainer.resolve("currencyService") + const currencyRepository = mockContainer.resolve("currencyRepository") + + const filters = { + tags: { + value: { + $in: ["test"], + }, + }, + } + const config = { + relations: ["tags"], + } + + await currencyService.list(filters, config) + + expect(currencyRepository.find).toHaveBeenCalledWith( + { + where: { + tags: { + value: { + $in: ["test"], + }, + }, + }, + options: { + fields: undefined, + limit: 15, + offset: undefined, + withDeleted: undefined, + populate: ["tags"], + }, + }, + expect.any(Object) + ) + }) + + it("should list and count the currencys with filters and relations", async function () { + const currencyService = mockContainer.resolve("currencyService") + const currencyRepository = mockContainer.resolve("currencyRepository") + + const filters = { + tags: { + value: { + $in: ["test"], + }, + }, + } + const config = { + relations: ["tags"], + } + + await currencyService.listAndCount(filters, config) + + expect(currencyRepository.findAndCount).toHaveBeenCalledWith( + { + where: { + tags: { + value: { + $in: ["test"], + }, + }, + }, + options: { + fields: undefined, + limit: 15, + offset: undefined, + withDeleted: undefined, + populate: ["tags"], + }, + }, + expect.any(Object) + ) + }) +}) diff --git a/packages/pricing/src/services/currency.ts b/packages/pricing/src/services/currency.ts new file mode 100644 index 0000000000..cf806794c4 --- /dev/null +++ b/packages/pricing/src/services/currency.ts @@ -0,0 +1,107 @@ +import { Context, DAL, FindConfig, PricingTypes } from "@medusajs/types" +import { + InjectManager, + InjectTransactionManager, + MedusaContext, + ModulesSdkUtils, + retrieveEntity, +} from "@medusajs/utils" +import { Currency } from "@models" +import { CurrencyRepository } from "@repositories" + +import { doNotForceTransaction, shouldForceTransaction } from "@medusajs/utils" + +type InjectedDependencies = { + currencyRepository: DAL.RepositoryService +} + +export default class CurrencyService { + protected readonly currencyRepository_: DAL.RepositoryService + + constructor({ currencyRepository }: InjectedDependencies) { + this.currencyRepository_ = currencyRepository + } + + @InjectManager("currencyRepository_") + async retrieve( + currencyCode: string, + config: FindConfig = {}, + @MedusaContext() sharedContext: Context = {} + ): Promise { + return (await retrieveEntity({ + id: currencyCode, + identifierColumn: "code", + entityName: Currency.name, + repository: this.currencyRepository_, + config, + sharedContext, + })) as TEntity + } + + @InjectManager("currencyRepository_") + async list( + filters: PricingTypes.FilterableCurrencyProps = {}, + config: FindConfig = {}, + @MedusaContext() sharedContext: Context = {} + ): Promise { + return (await this.currencyRepository_.find( + this.buildQueryForList(filters, config), + sharedContext + )) as TEntity[] + } + + @InjectManager("currencyRepository_") + async listAndCount( + filters: PricingTypes.FilterableCurrencyProps = {}, + config: FindConfig = {}, + @MedusaContext() sharedContext: Context = {} + ): Promise<[TEntity[], number]> { + return (await this.currencyRepository_.findAndCount( + this.buildQueryForList(filters, config), + sharedContext + )) as [TEntity[], number] + } + + private buildQueryForList( + filters: PricingTypes.FilterableCurrencyProps = {}, + config: FindConfig = {} + ) { + const queryOptions = ModulesSdkUtils.buildQuery(filters, config) + + if (filters.code) { + queryOptions.where["code"] = { $in: filters.code } + } + + return queryOptions + } + + @InjectTransactionManager(shouldForceTransaction, "currencyRepository_") + async create( + data: PricingTypes.CreateCurrencyDTO[], + @MedusaContext() sharedContext: Context = {} + ): Promise { + return (await (this.currencyRepository_ as CurrencyRepository).create( + data, + sharedContext + )) as TEntity[] + } + + @InjectTransactionManager(shouldForceTransaction, "currencyRepository_") + async update( + data: PricingTypes.UpdateCurrencyDTO[], + @MedusaContext() sharedContext: Context = {} + ): Promise { + return (await (this.currencyRepository_ as CurrencyRepository).update( + data, + sharedContext + )) as TEntity[] + } + + @InjectTransactionManager(doNotForceTransaction, "currencyRepository_") + async delete( + ids: string[], + @MedusaContext() sharedContext: Context = {} + ): Promise { + await this.currencyRepository_.delete(ids, sharedContext) + } +} diff --git a/packages/pricing/src/services/index.ts b/packages/pricing/src/services/index.ts new file mode 100644 index 0000000000..d605c402ad --- /dev/null +++ b/packages/pricing/src/services/index.ts @@ -0,0 +1,2 @@ +export { default as CurrencyService } from "./currency" +export { default as PricingModuleService } from "./pricing-module" diff --git a/packages/pricing/src/services/pricing-module.ts b/packages/pricing/src/services/pricing-module.ts new file mode 100644 index 0000000000..c3a151051e --- /dev/null +++ b/packages/pricing/src/services/pricing-module.ts @@ -0,0 +1,141 @@ +import { + Context, + DAL, + FindConfig, + InternalModuleDeclaration, + JoinerServiceConfig, + PricingTypes, +} from "@medusajs/types" +import { Currency } from "@models" +import { CurrencyService } from "@services" + +import { + InjectManager, + InjectTransactionManager, + MedusaContext, +} from "@medusajs/utils" + +import { shouldForceTransaction } from "@medusajs/utils" +import { joinerConfig } from "../joiner-config" + +type InjectedDependencies = { + baseRepository: DAL.RepositoryService + currencyService: CurrencyService +} + +export default class PricingModuleService + implements PricingTypes.IPricingModuleService +{ + protected baseRepository_: DAL.RepositoryService + protected readonly currencyService_: CurrencyService + + constructor( + { baseRepository, currencyService }: InjectedDependencies, + protected readonly moduleDeclaration: InternalModuleDeclaration + ) { + this.baseRepository_ = baseRepository + this.currencyService_ = currencyService + } + + __joinerConfig(): JoinerServiceConfig { + return joinerConfig + } + + @InjectManager("baseRepository_") + async retrieveCurrency( + code: string, + config: FindConfig = {}, + @MedusaContext() sharedContext: Context = {} + ): Promise { + const currency = await this.currencyService_.retrieve( + code, + config, + sharedContext + ) + + return this.baseRepository_.serialize(currency, { + populate: true, + }) + } + + @InjectManager("baseRepository_") + async listCurrencies( + filters: PricingTypes.FilterableCurrencyProps = {}, + config: FindConfig = {}, + @MedusaContext() sharedContext: Context = {} + ): Promise { + const currencies = await this.currencyService_.list( + filters, + config, + sharedContext + ) + + return this.baseRepository_.serialize( + currencies, + { + populate: true, + } + ) + } + + @InjectManager("baseRepository_") + async listAndCountCurrencies( + filters: PricingTypes.FilterableCurrencyProps = {}, + config: FindConfig = {}, + @MedusaContext() sharedContext: Context = {} + ): Promise<[PricingTypes.CurrencyDTO[], number]> { + const [currencies, count] = await this.currencyService_.listAndCount( + filters, + config, + sharedContext + ) + + return [ + await this.baseRepository_.serialize( + currencies, + { + populate: true, + } + ), + count, + ] + } + + @InjectTransactionManager(shouldForceTransaction, "baseRepository_") + async createCurrencies( + data: PricingTypes.CreateCurrencyDTO[], + @MedusaContext() sharedContext: Context = {} + ) { + const currencies = await this.currencyService_.create(data, sharedContext) + + return this.baseRepository_.serialize( + currencies, + { + populate: true, + } + ) + } + + @InjectTransactionManager(shouldForceTransaction, "baseRepository_") + async updateCurrencies( + data: PricingTypes.UpdateCurrencyDTO[], + @MedusaContext() sharedContext: Context = {} + ) { + const currencies = await this.currencyService_.update(data, sharedContext) + + return this.baseRepository_.serialize( + currencies, + { + populate: true, + } + ) + } + + @InjectTransactionManager(shouldForceTransaction, "baseRepository_") + async deleteCurrencies( + currencyCodes: string[], + @MedusaContext() sharedContext: Context = {} + ): Promise { + await this.currencyService_.delete(currencyCodes, sharedContext) + } +} diff --git a/packages/pricing/src/types/index.ts b/packages/pricing/src/types/index.ts new file mode 100644 index 0000000000..0f252977b0 --- /dev/null +++ b/packages/pricing/src/types/index.ts @@ -0,0 +1,5 @@ +import { Logger } from "@medusajs/types" + +export type InitializeModuleInjectableDependencies = { + logger?: Logger +} diff --git a/packages/pricing/tsconfig.json b/packages/pricing/tsconfig.json new file mode 100644 index 0000000000..213e38fc55 --- /dev/null +++ b/packages/pricing/tsconfig.json @@ -0,0 +1,36 @@ +{ + "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"] + } + }, + "include": ["src"], + "exclude": [ + "dist", + "./src/**/__tests__", + "./src/**/__mocks__", + "./src/**/__fixtures__", + "node_modules" + ] +} diff --git a/packages/pricing/tsconfig.spec.json b/packages/pricing/tsconfig.spec.json new file mode 100644 index 0000000000..b887bbfa39 --- /dev/null +++ b/packages/pricing/tsconfig.spec.json @@ -0,0 +1,5 @@ +{ + "extends": "./tsconfig.json", + "include": ["src", "integration-tests"], + "exclude": ["node_modules", "dist"] +} diff --git a/packages/types/src/bundles.ts b/packages/types/src/bundles.ts index 4982b6d250..1bacfa8434 100644 --- a/packages/types/src/bundles.ts +++ b/packages/types/src/bundles.ts @@ -1,14 +1,15 @@ export * as CacheTypes from "./cache" export * as CommonTypes from "./common" +export * as DAL from "./dal" export * as EventBusTypes from "./event-bus" +export * as FeatureFlagTypes from "./feature-flag" export * as InventoryTypes from "./inventory" -export * as ProductTypes from "./product" +export * as LoggerTypes from "./logger" export * as ModulesSdkTypes from "./modules-sdk" +export * as PricingTypes from "./pricing" +export * as ProductTypes from "./product" +export * as SalesChannelTypes from "./sales-channel" export * as SearchTypes from "./search" export * as StockLocationTypes from "./stock-location" export * as TransactionBaseTypes from "./transaction-base" -export * as DAL from "./dal" -export * as LoggerTypes from "./logger" -export * as FeatureFlagTypes from "./feature-flag" -export * as SalesChannelTypes from "./sales-channel" export * as WorkflowTypes from "./workflow" diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts index 311276e868..6b0e3d558d 100644 --- a/packages/types/src/index.ts +++ b/packages/types/src/index.ts @@ -11,6 +11,7 @@ export * from "./inventory" export * from "./joiner" export * from "./logger" export * from "./modules-sdk" +export * from "./pricing" export * from "./product" export * from "./product-category" export * from "./sales-channel" diff --git a/packages/types/src/pricing/common/currency.ts b/packages/types/src/pricing/common/currency.ts new file mode 100644 index 0000000000..617abd5653 --- /dev/null +++ b/packages/types/src/pricing/common/currency.ts @@ -0,0 +1,27 @@ +import { BaseFilterable } from "../../dal" + +export interface CurrencyDTO { + code: string + symbol?: string + symbol_native?: string + name?: string +} + +export interface CreateCurrencyDTO { + code: string + symbol: string + symbol_native: string + name: string +} + +export interface UpdateCurrencyDTO { + code: string + symbol?: string + symbol_native?: string + name?: string +} + +export interface FilterableCurrencyProps + extends BaseFilterable { + code?: string[] +} diff --git a/packages/types/src/pricing/common/index.ts b/packages/types/src/pricing/common/index.ts new file mode 100644 index 0000000000..68cb50031c --- /dev/null +++ b/packages/types/src/pricing/common/index.ts @@ -0,0 +1 @@ +export * from "./currency" diff --git a/packages/types/src/pricing/index.ts b/packages/types/src/pricing/index.ts new file mode 100644 index 0000000000..eade309433 --- /dev/null +++ b/packages/types/src/pricing/index.ts @@ -0,0 +1,2 @@ +export * from "./common" +export * from "./service" diff --git a/packages/types/src/pricing/service.ts b/packages/types/src/pricing/service.ts new file mode 100644 index 0000000000..b126719ecf --- /dev/null +++ b/packages/types/src/pricing/service.ts @@ -0,0 +1,45 @@ +import { FindConfig } from "../common" +import { JoinerServiceConfig } from "../joiner" +import { Context } from "../shared-context" +import { + CreateCurrencyDTO, + CurrencyDTO, + FilterableCurrencyProps, + UpdateCurrencyDTO, +} from "./common" +export interface IPricingModuleService { + __joinerConfig(): JoinerServiceConfig + + retrieveCurrency( + code: string, + config?: FindConfig, + sharedContext?: Context + ): Promise + + listCurrencies( + filters?: FilterableCurrencyProps, + config?: FindConfig, + sharedContext?: Context + ): Promise + + listAndCountCurrencies( + filters?: FilterableCurrencyProps, + config?: FindConfig, + sharedContext?: Context + ): Promise<[CurrencyDTO[], number]> + + createCurrencies( + data: CreateCurrencyDTO[], + sharedContext?: Context + ): Promise + + updateCurrencies( + data: UpdateCurrencyDTO[], + sharedContext?: Context + ): Promise + + deleteCurrencies( + currencyCodes: string[], + sharedContext?: Context + ): Promise +} diff --git a/packages/utils/src/bundles.ts b/packages/utils/src/bundles.ts index d444b56ac9..231a15d132 100644 --- a/packages/utils/src/bundles.ts +++ b/packages/utils/src/bundles.ts @@ -1,8 +1,8 @@ +export * as DALUtils from "./dal" export * as DecoratorUtils from "./decorators" export * as EventBusUtils from "./event-bus" -export * as SearchUtils from "./search" -export * as ModulesSdkUtils from "./modules-sdk" -export * as DALUtils from "./dal" export * as FeatureFlagUtils from "./feature-flags" -export * as ShippingProfileUtils from "./shipping" +export * as ModulesSdkUtils from "./modules-sdk" export * as ProductUtils from "./product" +export * as SearchUtils from "./search" +export * as ShippingProfileUtils from "./shipping" diff --git a/packages/utils/src/common/index.ts b/packages/utils/src/common/index.ts index 0519707531..de50c3db51 100644 --- a/packages/utils/src/common/index.ts +++ b/packages/utils/src/common/index.ts @@ -1,4 +1,5 @@ export * from "./build-query" +export * from "./container" export * from "./deduplicate" export * from "./errors" export * from "./generate-entity-id" @@ -20,6 +21,6 @@ export * from "./stringify-circular" export * from "./to-camel-case" export * from "./to-kebab-case" export * from "./to-pascal-case" +export * from "./transaction" export * from "./upper-case-first" export * from "./wrap-handler" -export * from "./container" diff --git a/packages/utils/src/common/transaction/do-not-force-transaction.ts b/packages/utils/src/common/transaction/do-not-force-transaction.ts new file mode 100644 index 0000000000..a6bfce23f8 --- /dev/null +++ b/packages/utils/src/common/transaction/do-not-force-transaction.ts @@ -0,0 +1,3 @@ +export function doNotForceTransaction(): boolean { + return false +} diff --git a/packages/utils/src/common/transaction/index.ts b/packages/utils/src/common/transaction/index.ts new file mode 100644 index 0000000000..08a9e0d6a4 --- /dev/null +++ b/packages/utils/src/common/transaction/index.ts @@ -0,0 +1,2 @@ +export * from "./do-not-force-transaction" +export * from "./should-force-transaction" diff --git a/packages/utils/src/common/transaction/should-force-transaction.ts b/packages/utils/src/common/transaction/should-force-transaction.ts new file mode 100644 index 0000000000..f8a0b35882 --- /dev/null +++ b/packages/utils/src/common/transaction/should-force-transaction.ts @@ -0,0 +1,5 @@ +import { MODULE_RESOURCE_TYPE } from "@medusajs/types" + +export function shouldForceTransaction(target: any): boolean { + return target.moduleDeclaration?.resources === MODULE_RESOURCE_TYPE.ISOLATED +} diff --git a/packages/utils/src/dal/index.ts b/packages/utils/src/dal/index.ts index 2b2af46cb5..5085c6d0a3 100644 --- a/packages/utils/src/dal/index.ts +++ b/packages/utils/src/dal/index.ts @@ -1,6 +1,7 @@ +export * from "./mikro-orm/mikro-orm-create-connection" export * from "./mikro-orm/mikro-orm-repository" +export * from "./mikro-orm/mikro-orm-soft-deletable-filter" +export * from "./mikro-orm/utils" +export * from "./repositories" export * from "./repository" export * from "./utils" -export * from "./mikro-orm/utils" -export * from "./mikro-orm/mikro-orm-create-connection" -export * from "./mikro-orm/mikro-orm-soft-deletable-filter" diff --git a/packages/utils/src/dal/repositories/index.ts b/packages/utils/src/dal/repositories/index.ts new file mode 100644 index 0000000000..50f5b9b41d --- /dev/null +++ b/packages/utils/src/dal/repositories/index.ts @@ -0,0 +1 @@ +export * from "./load-custom-repositories" diff --git a/packages/utils/src/dal/repositories/load-custom-repositories.ts b/packages/utils/src/dal/repositories/load-custom-repositories.ts new file mode 100644 index 0000000000..7a14507c6f --- /dev/null +++ b/packages/utils/src/dal/repositories/load-custom-repositories.ts @@ -0,0 +1,35 @@ +import { Constructor, DAL } from "@medusajs/types" +import { asClass } from "awilix" +import { lowerCaseFirst } from "../../common" + +/** + * Load the repositories from the custom repositories object. If a repository is not + * present in the custom repositories object, the default repository will be used. + * + * @param customRepositories + * @param container + */ +export function loadCustomRepositories({ + defaultRepositories, + customRepositories, + container, +}) { + const customRepositoriesMap = new Map(Object.entries(customRepositories)) + + Object.entries(defaultRepositories).forEach(([key, defaultRepository]) => { + let finalRepository = customRepositoriesMap.get(key) + + if ( + !finalRepository || + !(finalRepository as Constructor).prototype.find + ) { + finalRepository = defaultRepository + } + + container.register({ + [lowerCaseFirst(key)]: asClass( + finalRepository as Constructor + ).singleton(), + }) + }) +} diff --git a/packages/utils/src/index.ts b/packages/utils/src/index.ts index e850b04728..50bceb4955 100644 --- a/packages/utils/src/index.ts +++ b/packages/utils/src/index.ts @@ -1,10 +1,10 @@ export * from "./bundles" export * from "./common" +export * from "./dal" export * from "./decorators" export * from "./event-bus" -export * from "./search" -export * from "./modules-sdk" -export * from "./dal" export * from "./feature-flags" -export * from "./shipping" +export * from "./modules-sdk" export * from "./product" +export * from "./search" +export * from "./shipping" diff --git a/packages/utils/src/modules-sdk/retrieve-entity.ts b/packages/utils/src/modules-sdk/retrieve-entity.ts index 47f1f660ff..62f68a06a2 100644 --- a/packages/utils/src/modules-sdk/retrieve-entity.ts +++ b/packages/utils/src/modules-sdk/retrieve-entity.ts @@ -1,20 +1,24 @@ -import { FindConfig, DAL, Context } from "@medusajs/types" -import { MedusaError, isDefined, lowerCaseFirst } from "../common" +import { Context, DAL, FindConfig } from "@medusajs/types" +import { + MedusaError, + isDefined, + lowerCaseFirst, + upperCaseFirst, +} from "../common" import { buildQuery } from "./build-query" type RetrieveEntityParams = { - id: string, - entityName: string, + id: string + identifierColumn?: string + entityName: string repository: DAL.TreeRepositoryService | DAL.RepositoryService config: FindConfig sharedContext?: Context } -export async function retrieveEntity< - TEntity, - TDTO, ->({ +export async function retrieveEntity({ id, + identifierColumn = "id", entityName, repository, config = {}, @@ -23,23 +27,25 @@ export async function retrieveEntity< if (!isDefined(id)) { throw new MedusaError( MedusaError.Types.NOT_FOUND, - `"${lowerCaseFirst(entityName)}Id" must be defined` + `"${lowerCaseFirst(entityName)}${upperCaseFirst( + identifierColumn + )}" must be defined` ) } - const queryOptions = buildQuery({ - id, - }, config) - - const entities = await repository.find( - queryOptions, - sharedContext + const queryOptions = buildQuery( + { + [identifierColumn]: id, + }, + config ) + const entities = await repository.find(queryOptions, sharedContext) + if (!entities?.length) { throw new MedusaError( MedusaError.Types.NOT_FOUND, - `${entityName} with id: ${id} was not found` + `${entityName} with ${identifierColumn}: ${id} was not found` ) } diff --git a/yarn.lock b/yarn.lock index fd05d3f494..5d31fbe098 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4772,6 +4772,20 @@ __metadata: languageName: node linkType: hard +"@jest/console@npm:^29.6.4": + version: 29.6.4 + resolution: "@jest/console@npm:29.6.4" + dependencies: + "@jest/types": ^29.6.3 + "@types/node": "*" + chalk: ^4.0.0 + jest-message-util: ^29.6.3 + jest-util: ^29.6.3 + slash: ^3.0.0 + checksum: 350092f3b77de6fbaee7b385831c55fed238005fa6e39fcbab46079160c0e24ed7fef2f5118188173fbca361c50fe5c7b1baab28f86f233c50fb97689bb4f7c1 + languageName: node + linkType: hard + "@jest/core@npm:^25.5.4": version: 25.5.4 resolution: "@jest/core@npm:25.5.4" @@ -4926,6 +4940,47 @@ __metadata: languageName: node linkType: hard +"@jest/core@npm:^29.6.4": + version: 29.6.4 + resolution: "@jest/core@npm:29.6.4" + dependencies: + "@jest/console": ^29.6.4 + "@jest/reporters": ^29.6.4 + "@jest/test-result": ^29.6.4 + "@jest/transform": ^29.6.4 + "@jest/types": ^29.6.3 + "@types/node": "*" + ansi-escapes: ^4.2.1 + chalk: ^4.0.0 + ci-info: ^3.2.0 + exit: ^0.1.2 + graceful-fs: ^4.2.9 + jest-changed-files: ^29.6.3 + jest-config: ^29.6.4 + jest-haste-map: ^29.6.4 + jest-message-util: ^29.6.3 + jest-regex-util: ^29.6.3 + jest-resolve: ^29.6.4 + jest-resolve-dependencies: ^29.6.4 + jest-runner: ^29.6.4 + jest-runtime: ^29.6.4 + jest-snapshot: ^29.6.4 + jest-util: ^29.6.3 + jest-validate: ^29.6.3 + jest-watcher: ^29.6.4 + micromatch: ^4.0.4 + pretty-format: ^29.6.3 + slash: ^3.0.0 + strip-ansi: ^6.0.0 + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + checksum: c1af87534d1e3ee881af413bb16bde9ff6ead0d17e675eafb6fa5020e714cacd5d38b842c9184bffee01d33811695fcc03addc5c02e15ec77e5686bbb9d24496 + languageName: node + linkType: hard + "@jest/environment@npm:^25.5.0": version: 25.5.0 resolution: "@jest/environment@npm:25.5.0" @@ -4973,6 +5028,18 @@ __metadata: languageName: node linkType: hard +"@jest/environment@npm:^29.6.4": + version: 29.6.4 + resolution: "@jest/environment@npm:29.6.4" + dependencies: + "@jest/fake-timers": ^29.6.4 + "@jest/types": ^29.6.3 + "@types/node": "*" + jest-mock: ^29.6.3 + checksum: c5d23384294e775081bd3274e6632f442c09ae988222f3e09e3b3ba7f40cfc0f908815f1feee2960210cf6a88a7e153869773a3921042b9dab7878f1b5df75f7 + languageName: node + linkType: hard + "@jest/expect-utils@npm:^29.5.0": version: 29.5.0 resolution: "@jest/expect-utils@npm:29.5.0" @@ -4982,6 +5049,15 @@ __metadata: languageName: node linkType: hard +"@jest/expect-utils@npm:^29.6.4": + version: 29.6.4 + resolution: "@jest/expect-utils@npm:29.6.4" + dependencies: + jest-get-type: ^29.6.3 + checksum: 17d87d551090f6b460fa45605c614b2ad28e257360a5b8152216fe983370f4cfb8482d2d017552c2be43be1caa0ff5594f1381be17798dcad3899e05b297fe83 + languageName: node + linkType: hard + "@jest/expect@npm:^29.5.0": version: 29.5.0 resolution: "@jest/expect@npm:29.5.0" @@ -4992,6 +5068,16 @@ __metadata: languageName: node linkType: hard +"@jest/expect@npm:^29.6.4": + version: 29.6.4 + resolution: "@jest/expect@npm:29.6.4" + dependencies: + expect: ^29.6.4 + jest-snapshot: ^29.6.4 + checksum: 1215ea06df304941a87f5411516019712809c98b5698551438339fc0f195c75dc6089b904c11c7fb2d468ffad5854dc05ef989ea808730f704703aa68eea4f16 + languageName: node + linkType: hard + "@jest/fake-timers@npm:^25.5.0": version: 25.5.0 resolution: "@jest/fake-timers@npm:25.5.0" @@ -5047,6 +5133,20 @@ __metadata: languageName: node linkType: hard +"@jest/fake-timers@npm:^29.6.4": + version: 29.6.4 + resolution: "@jest/fake-timers@npm:29.6.4" + dependencies: + "@jest/types": ^29.6.3 + "@sinonjs/fake-timers": ^10.0.2 + "@types/node": "*" + jest-message-util: ^29.6.3 + jest-mock: ^29.6.3 + jest-util: ^29.6.3 + checksum: b4ca14ece8fa46d8c0ab64368a95d40c32d920fb270b94d9e0f67b61f11c019cd89e19e4e8a367bdf262337674d48cbfbe489fb01109761fc2ae1b0c34c672c7 + languageName: node + linkType: hard + "@jest/globals@npm:^25.5.2": version: 25.5.2 resolution: "@jest/globals@npm:25.5.2" @@ -5092,6 +5192,18 @@ __metadata: languageName: node linkType: hard +"@jest/globals@npm:^29.6.4": + version: 29.6.4 + resolution: "@jest/globals@npm:29.6.4" + dependencies: + "@jest/environment": ^29.6.4 + "@jest/expect": ^29.6.4 + "@jest/types": ^29.6.3 + jest-mock: ^29.6.3 + checksum: ae167fc518f58dabee6b1852a1631c171383ad75b9aeae3260f18a6cc25ad6e5a1caee3bc9bff5c53b33166df36e9a2395aca728b9ea3b9e881fe15244582e9f + languageName: node + linkType: hard + "@jest/reporters@npm:^25.5.1": version: 25.5.1 resolution: "@jest/reporters@npm:25.5.1" @@ -5239,6 +5351,43 @@ __metadata: languageName: node linkType: hard +"@jest/reporters@npm:^29.6.4": + version: 29.6.4 + resolution: "@jest/reporters@npm:29.6.4" + dependencies: + "@bcoe/v8-coverage": ^0.2.3 + "@jest/console": ^29.6.4 + "@jest/test-result": ^29.6.4 + "@jest/transform": ^29.6.4 + "@jest/types": ^29.6.3 + "@jridgewell/trace-mapping": ^0.3.18 + "@types/node": "*" + chalk: ^4.0.0 + collect-v8-coverage: ^1.0.0 + exit: ^0.1.2 + glob: ^7.1.3 + graceful-fs: ^4.2.9 + istanbul-lib-coverage: ^3.0.0 + istanbul-lib-instrument: ^6.0.0 + istanbul-lib-report: ^3.0.0 + istanbul-lib-source-maps: ^4.0.0 + istanbul-reports: ^3.1.3 + jest-message-util: ^29.6.3 + jest-util: ^29.6.3 + jest-worker: ^29.6.4 + slash: ^3.0.0 + string-length: ^4.0.1 + strip-ansi: ^6.0.0 + v8-to-istanbul: ^9.0.1 + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + checksum: 6c393316518ad64c69a67c3e479f042c4daedb746e591356f9686e5959f1a1c878f3f62f8ea3e49a0d6bf186c49cdc3e11536aa55e51a73ef887834b8c45957e + languageName: node + linkType: hard + "@jest/schemas@npm:^29.4.3": version: 29.4.3 resolution: "@jest/schemas@npm:29.4.3" @@ -5248,6 +5397,15 @@ __metadata: languageName: node linkType: hard +"@jest/schemas@npm:^29.6.3": + version: 29.6.3 + resolution: "@jest/schemas@npm:29.6.3" + dependencies: + "@sinclair/typebox": ^0.27.8 + checksum: b329e89cd5f20b9278ae1233df74016ebf7b385e0d14b9f4c1ad18d096c4c19d1e687aa113a9c976b16ec07f021ae53dea811fb8c1248a50ac34fbe009fdf6be + languageName: node + linkType: hard + "@jest/source-map@npm:^25.5.0": version: 25.5.0 resolution: "@jest/source-map@npm:25.5.0" @@ -5292,6 +5450,17 @@ __metadata: languageName: node linkType: hard +"@jest/source-map@npm:^29.6.3": + version: 29.6.3 + resolution: "@jest/source-map@npm:29.6.3" + dependencies: + "@jridgewell/trace-mapping": ^0.3.18 + callsites: ^3.0.0 + graceful-fs: ^4.2.9 + checksum: a2f177081830a2e8ad3f2e29e20b63bd40bade294880b595acf2fc09ec74b6a9dd98f126a2baa2bf4941acd89b13a4ade5351b3885c224107083a0059b60a219 + languageName: node + linkType: hard + "@jest/test-result@npm:^25.5.0": version: 25.5.0 resolution: "@jest/test-result@npm:25.5.0" @@ -5340,6 +5509,18 @@ __metadata: languageName: node linkType: hard +"@jest/test-result@npm:^29.6.4": + version: 29.6.4 + resolution: "@jest/test-result@npm:29.6.4" + dependencies: + "@jest/console": ^29.6.4 + "@jest/types": ^29.6.3 + "@types/istanbul-lib-coverage": ^2.0.0 + collect-v8-coverage: ^1.0.0 + checksum: 62daf70ceb29f9048fef478b0b47ea93f60017d14726f5c1baeadc9dcb02d4429a7934f4638d32987dcea88b993f7e92141ade7916b65a86c0994e4fc041482e + languageName: node + linkType: hard + "@jest/test-sequencer@npm:^25.5.4": version: 25.5.4 resolution: "@jest/test-sequencer@npm:25.5.4" @@ -5390,6 +5571,18 @@ __metadata: languageName: node linkType: hard +"@jest/test-sequencer@npm:^29.6.4": + version: 29.6.4 + resolution: "@jest/test-sequencer@npm:29.6.4" + dependencies: + "@jest/test-result": ^29.6.4 + graceful-fs: ^4.2.9 + jest-haste-map: ^29.6.4 + slash: ^3.0.0 + checksum: 2ac9ff9ebea367a41cf923f0229860b2ed691c0080b72395c4afec8882e998086aacb98fe0d780c3b03a724a1d52d856bb2447d0ea777bbaf5841f6b3cd07790 + languageName: node + linkType: hard + "@jest/transform@npm:^25.5.1": version: 25.5.1 resolution: "@jest/transform@npm:25.5.1" @@ -5483,6 +5676,29 @@ __metadata: languageName: node linkType: hard +"@jest/transform@npm:^29.6.4": + version: 29.6.4 + resolution: "@jest/transform@npm:29.6.4" + dependencies: + "@babel/core": ^7.11.6 + "@jest/types": ^29.6.3 + "@jridgewell/trace-mapping": ^0.3.18 + babel-plugin-istanbul: ^6.1.1 + chalk: ^4.0.0 + convert-source-map: ^2.0.0 + fast-json-stable-stringify: ^2.1.0 + graceful-fs: ^4.2.9 + jest-haste-map: ^29.6.4 + jest-regex-util: ^29.6.3 + jest-util: ^29.6.3 + micromatch: ^4.0.4 + pirates: ^4.0.4 + slash: ^3.0.0 + write-file-atomic: ^4.0.2 + checksum: 75a540f1a5075c57f83afed1caa39ef695ddd8890648d348f9bd94b26c81a872624c9d8feb9e0849d16c222348972dd2f5538bdb00f9e55c0cd07ef3b67e9e84 + languageName: node + linkType: hard + "@jest/types@npm:^25.5.0": version: 25.5.0 resolution: "@jest/types@npm:25.5.0" @@ -5535,6 +5751,20 @@ __metadata: languageName: node linkType: hard +"@jest/types@npm:^29.6.3": + version: 29.6.3 + resolution: "@jest/types@npm:29.6.3" + dependencies: + "@jest/schemas": ^29.6.3 + "@types/istanbul-lib-coverage": ^2.0.0 + "@types/istanbul-reports": ^3.0.0 + "@types/node": "*" + "@types/yargs": ^17.0.8 + chalk: ^4.0.0 + checksum: ea4e493dd3fb47933b8ccab201ae573dcc451f951dc44ed2a86123cd8541b82aa9d2b1031caf9b1080d6673c517e2dcc25a44b2dc4f3fbc37bfc965d444888c0 + languageName: node + linkType: hard + "@jridgewell/gen-mapping@npm:^0.3.0, @jridgewell/gen-mapping@npm:^0.3.2": version: 0.3.3 resolution: "@jridgewell/gen-mapping@npm:0.3.3" @@ -5553,7 +5783,7 @@ __metadata: languageName: node linkType: hard -"@jridgewell/resolve-uri@npm:^3.0.3": +"@jridgewell/resolve-uri@npm:^3.0.3, @jridgewell/resolve-uri@npm:^3.1.0": version: 3.1.1 resolution: "@jridgewell/resolve-uri@npm:3.1.1" checksum: 0dbc9e29bc640bbbdc5b9876d2859c69042bfcf1423c1e6421bcca53e826660bff4e41c7d4bcb8dbea696404231a6f902f76ba41835d049e20f2dd6cffb713bf @@ -5581,7 +5811,7 @@ __metadata: languageName: node linkType: hard -"@jridgewell/sourcemap-codec@npm:^1.4.10, @jridgewell/sourcemap-codec@npm:^1.4.13": +"@jridgewell/sourcemap-codec@npm:^1.4.10, @jridgewell/sourcemap-codec@npm:^1.4.13, @jridgewell/sourcemap-codec@npm:^1.4.14": version: 1.4.15 resolution: "@jridgewell/sourcemap-codec@npm:1.4.15" checksum: 0c6b5ae663087558039052a626d2d7ed5208da36cfd707dcc5cea4a07cfc918248403dcb5989a8f7afaf245ce0573b7cc6fd94c4a30453bd10e44d9363940ba5 @@ -5608,6 +5838,16 @@ __metadata: languageName: node linkType: hard +"@jridgewell/trace-mapping@npm:^0.3.18": + version: 0.3.19 + resolution: "@jridgewell/trace-mapping@npm:0.3.19" + dependencies: + "@jridgewell/resolve-uri": ^3.1.0 + "@jridgewell/sourcemap-codec": ^1.4.14 + checksum: 845e6c6efca621b2b85e4d13fd25c319b6e4ab1ea78d4385ff6c0f78322ea0fcdfec8ac763aa4b56e8378c96d7bef101a2638c7a1a076f7d62f6376230c940a7 + languageName: node + linkType: hard + "@jsdevtools/ono@npm:^7.1.3": version: 7.1.3 resolution: "@jsdevtools/ono@npm:7.1.3" @@ -6325,6 +6565,35 @@ __metadata: languageName: unknown linkType: soft +"@medusajs/pricing@workspace:packages/pricing": + version: 0.0.0-use.local + resolution: "@medusajs/pricing@workspace:packages/pricing" + dependencies: + "@medusajs/modules-sdk": ^1.9.2 + "@medusajs/types": ^1.10.2 + "@medusajs/utils": ^1.9.7 + "@mikro-orm/cli": 5.7.12 + "@mikro-orm/core": 5.7.12 + "@mikro-orm/migrations": 5.7.12 + "@mikro-orm/postgresql": 5.7.12 + awilix: ^8.0.0 + cross-env: ^5.2.1 + dotenv: ^16.1.4 + jest: ^29.6.3 + knex: 2.4.2 + medusa-test-utils: ^1.1.40 + 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-pricing-migrations-down: dist/scripts/bin/run-migration-down.js + medusa-pricing-migrations-up: dist/scripts/bin/run-migration-up.js + medusa-pricing-seed: dist/scripts/bin/run-seed.js + languageName: unknown + linkType: soft + "@medusajs/product@workspace:^, @medusajs/product@workspace:packages/product": version: 0.0.0-use.local resolution: "@medusajs/product@workspace:packages/product" @@ -9431,6 +9700,13 @@ __metadata: languageName: node linkType: hard +"@sinclair/typebox@npm:^0.27.8": + version: 0.27.8 + resolution: "@sinclair/typebox@npm:0.27.8" + checksum: ef6351ae073c45c2ac89494dbb3e1f87cc60a93ce4cde797b782812b6f97da0d620ae81973f104b43c9b7eaa789ad20ba4f6a1359f1cc62f63729a55a7d22d4e + languageName: node + linkType: hard + "@sindresorhus/is@npm:^0.14.0": version: 0.14.0 resolution: "@sindresorhus/is@npm:0.14.0" @@ -16015,6 +16291,23 @@ __metadata: languageName: node linkType: hard +"babel-jest@npm:^29.6.4": + version: 29.6.4 + resolution: "babel-jest@npm:29.6.4" + dependencies: + "@jest/transform": ^29.6.4 + "@types/babel__core": ^7.1.14 + babel-plugin-istanbul: ^6.1.1 + babel-preset-jest: ^29.6.3 + chalk: ^4.0.0 + graceful-fs: ^4.2.9 + slash: ^3.0.0 + peerDependencies: + "@babel/core": ^7.8.0 + checksum: 983108bef8a65868f974c77f7a06da32fed1c63b7c15dcaec6cac278739c9790e35784197af042b6fc3a2c26e85db9355aa90cdef689d652d0736a968e7b4e6a + languageName: node + linkType: hard + "babel-jsx-utils@npm:^1.1.0": version: 1.1.0 resolution: "babel-jsx-utils@npm:1.1.0" @@ -16141,6 +16434,18 @@ __metadata: languageName: node linkType: hard +"babel-plugin-jest-hoist@npm:^29.6.3": + version: 29.6.3 + resolution: "babel-plugin-jest-hoist@npm:29.6.3" + dependencies: + "@babel/template": ^7.3.3 + "@babel/types": ^7.3.3 + "@types/babel__core": ^7.1.14 + "@types/babel__traverse": ^7.0.6 + checksum: 7e6451caaf7dce33d010b8aafb970e62f1b0c0b57f4978c37b0d457bbcf0874d75a395a102daf0bae0bd14eafb9f6e9a165ee5e899c0a4f1f3bb2e07b304ed2e + languageName: node + linkType: hard + "babel-plugin-lodash@npm:^3.3.4": version: 3.3.4 resolution: "babel-plugin-lodash@npm:3.3.4" @@ -16448,6 +16753,18 @@ __metadata: languageName: node linkType: hard +"babel-preset-jest@npm:^29.6.3": + version: 29.6.3 + resolution: "babel-preset-jest@npm:29.6.3" + dependencies: + babel-plugin-jest-hoist: ^29.6.3 + babel-preset-current-node-syntax: ^1.0.0 + peerDependencies: + "@babel/core": ^7.0.0 + checksum: ec5fd0276b5630b05f0c14bb97cc3815c6b31600c683ebb51372e54dcb776cff790bdeeabd5b8d01ede375a040337ccbf6a3ccd68d3a34219125945e167ad943 + languageName: node + linkType: hard + "babel-preset-medusa-package@*, babel-preset-medusa-package@^1.0.0, babel-preset-medusa-package@^1.1.19, babel-preset-medusa-package@workspace:packages/babel-preset-medusa-package": version: 0.0.0-use.local resolution: "babel-preset-medusa-package@workspace:packages/babel-preset-medusa-package" @@ -19614,6 +19931,18 @@ __metadata: languageName: node linkType: hard +"dedent@npm:^1.0.0": + version: 1.5.1 + resolution: "dedent@npm:1.5.1" + peerDependencies: + babel-plugin-macros: ^3.1.0 + peerDependenciesMeta: + babel-plugin-macros: + optional: true + checksum: f8612cd5b00aab58b18bb95572dca08dc2d49720bfa7201a444c3dae430291e8a06d4928614a6ec8764d713927f44bce9c990d3b8238fca2f430990ddc17c070 + languageName: node + linkType: hard + "deep-equal@npm:^2.0.5": version: 2.2.1 resolution: "deep-equal@npm:2.2.1" @@ -20067,6 +20396,13 @@ __metadata: languageName: node linkType: hard +"diff-sequences@npm:^29.6.3": + version: 29.6.3 + resolution: "diff-sequences@npm:29.6.3" + checksum: 32e27ac7dbffdf2fb0eb5a84efd98a9ad084fbabd5ac9abb8757c6770d5320d2acd172830b28c4add29bb873d59420601dfc805ac4064330ce59b1adfd0593b2 + languageName: node + linkType: hard + "diff@npm:^4.0.1": version: 4.0.2 resolution: "diff@npm:4.0.2" @@ -22029,6 +22365,19 @@ __metadata: languageName: node linkType: hard +"expect@npm:^29.6.4": + version: 29.6.4 + resolution: "expect@npm:29.6.4" + dependencies: + "@jest/expect-utils": ^29.6.4 + jest-get-type: ^29.6.3 + jest-matcher-utils: ^29.6.4 + jest-message-util: ^29.6.3 + jest-util: ^29.6.3 + checksum: d3f4ed2fcc33f743b1dd9cf25a07c2f56c9ddd7e1b327d3e74b5febfc90880a9e2ab10c56b3bf31e14d5ead69dc4cb68f718b7fbc3fae8571f8e18675ffe8080 + languageName: node + linkType: hard + "expected-node-version@npm:^1.0.0": version: 1.0.2 resolution: "expected-node-version@npm:1.0.2" @@ -26689,6 +27038,19 @@ __metadata: languageName: node linkType: hard +"istanbul-lib-instrument@npm:^6.0.0": + version: 6.0.0 + resolution: "istanbul-lib-instrument@npm:6.0.0" + dependencies: + "@babel/core": ^7.12.3 + "@babel/parser": ^7.14.7 + "@istanbuljs/schema": ^0.1.2 + istanbul-lib-coverage: ^3.2.0 + semver: ^7.5.4 + checksum: ee86777f3692f95c3ae35c5cbc9aa979b551241da2de1284f75c507a2bdef948cc56ca90214c3bb47b5dc2ebe748610eb4f7c4d39b304f24a933bcd0867a05e8 + languageName: node + linkType: hard + "istanbul-lib-report@npm:^3.0.0": version: 3.0.0 resolution: "istanbul-lib-report@npm:3.0.0" @@ -26801,6 +27163,17 @@ __metadata: languageName: node linkType: hard +"jest-changed-files@npm:^29.6.3": + version: 29.6.3 + resolution: "jest-changed-files@npm:29.6.3" + dependencies: + execa: ^5.0.0 + jest-util: ^29.6.3 + p-limit: ^3.1.0 + checksum: c73e684832ca296276853f591569f0af265ca3d9de48907e3df5821e33b5e1b85bc2add4e7a4397878ed715bcebb99cedae6c4f03499420ae30ea5853eeb2f1f + languageName: node + linkType: hard + "jest-circus@npm:^27.5.1": version: 27.5.1 resolution: "jest-circus@npm:27.5.1" @@ -26856,6 +27229,34 @@ __metadata: languageName: node linkType: hard +"jest-circus@npm:^29.6.4": + version: 29.6.4 + resolution: "jest-circus@npm:29.6.4" + dependencies: + "@jest/environment": ^29.6.4 + "@jest/expect": ^29.6.4 + "@jest/test-result": ^29.6.4 + "@jest/types": ^29.6.3 + "@types/node": "*" + chalk: ^4.0.0 + co: ^4.6.0 + dedent: ^1.0.0 + is-generator-fn: ^2.0.0 + jest-each: ^29.6.3 + jest-matcher-utils: ^29.6.4 + jest-message-util: ^29.6.3 + jest-runtime: ^29.6.4 + jest-snapshot: ^29.6.4 + jest-util: ^29.6.3 + p-limit: ^3.1.0 + pretty-format: ^29.6.3 + pure-rand: ^6.0.0 + slash: ^3.0.0 + stack-utils: ^2.0.3 + checksum: b770c62e43e097885a165117a261c225805f73339b38b12bcaabe819589d9fc72e6d60cb07fd1c493efbde7af979f87ca714b3f590226603cdb08d34ca6049e3 + languageName: node + linkType: hard + "jest-cli@npm:^25.5.4": version: 25.5.4 resolution: "jest-cli@npm:25.5.4" @@ -26957,6 +27358,33 @@ __metadata: languageName: node linkType: hard +"jest-cli@npm:^29.6.4": + version: 29.6.4 + resolution: "jest-cli@npm:29.6.4" + dependencies: + "@jest/core": ^29.6.4 + "@jest/test-result": ^29.6.4 + "@jest/types": ^29.6.3 + chalk: ^4.0.0 + exit: ^0.1.2 + graceful-fs: ^4.2.9 + import-local: ^3.0.2 + jest-config: ^29.6.4 + jest-util: ^29.6.3 + jest-validate: ^29.6.3 + prompts: ^2.0.1 + yargs: ^17.3.1 + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + bin: + jest: bin/jest.js + checksum: c6198eb2769711b81fb71092b5a353c6d8fd97f9d1bab8cea1526769d5039dee831908d4213ac6ed7d698df215839d8cf2a1e17e518b1e141597709584c1ab2f + languageName: node + linkType: hard + "jest-config@npm:^25.5.4": version: 25.5.4 resolution: "jest-config@npm:25.5.4" @@ -27090,6 +27518,44 @@ __metadata: languageName: node linkType: hard +"jest-config@npm:^29.6.4": + version: 29.6.4 + resolution: "jest-config@npm:29.6.4" + dependencies: + "@babel/core": ^7.11.6 + "@jest/test-sequencer": ^29.6.4 + "@jest/types": ^29.6.3 + babel-jest: ^29.6.4 + chalk: ^4.0.0 + ci-info: ^3.2.0 + deepmerge: ^4.2.2 + glob: ^7.1.3 + graceful-fs: ^4.2.9 + jest-circus: ^29.6.4 + jest-environment-node: ^29.6.4 + jest-get-type: ^29.6.3 + jest-regex-util: ^29.6.3 + jest-resolve: ^29.6.4 + jest-runner: ^29.6.4 + jest-util: ^29.6.3 + jest-validate: ^29.6.3 + micromatch: ^4.0.4 + parse-json: ^5.2.0 + pretty-format: ^29.6.3 + slash: ^3.0.0 + strip-json-comments: ^3.1.1 + peerDependencies: + "@types/node": "*" + ts-node: ">=9.0.0" + peerDependenciesMeta: + "@types/node": + optional: true + ts-node: + optional: true + checksum: 0c2411c9f6fd98ad1a42d6b908951fc0e6d8a31eaac8c419f4ae92e7a496ed2a6a0c3494954377a0a7ad0723bb192c030e0acffe7ad34443be616f0acce13dda + languageName: node + linkType: hard + "jest-diff@npm:^25.5.0": version: 25.5.0 resolution: "jest-diff@npm:25.5.0" @@ -27138,6 +27604,18 @@ __metadata: languageName: node linkType: hard +"jest-diff@npm:^29.6.4": + version: 29.6.4 + resolution: "jest-diff@npm:29.6.4" + dependencies: + chalk: ^4.0.0 + diff-sequences: ^29.6.3 + jest-get-type: ^29.6.3 + pretty-format: ^29.6.3 + checksum: 5f96be0f15ba8e70acfa5512ca49ba67363678e7ce222889612385a8d9dd042822fdd22a514394fe726b1f462e605bc5d7fc130bd81fa2247e7d40413975d576 + languageName: node + linkType: hard + "jest-docblock@npm:^25.3.0": version: 25.3.0 resolution: "jest-docblock@npm:25.3.0" @@ -27174,6 +27652,15 @@ __metadata: languageName: node linkType: hard +"jest-docblock@npm:^29.6.3": + version: 29.6.3 + resolution: "jest-docblock@npm:29.6.3" + dependencies: + detect-newline: ^3.0.0 + checksum: e22c78dd305a3d5211d83cfa0e25e6ea571cfab935e261dc18b17db1a547ecde014c9031334fdc30626e8d157196df981f0c87ef6561978d6e2466adb6bebe09 + languageName: node + linkType: hard + "jest-each@npm:^25.5.0": version: 25.5.0 resolution: "jest-each@npm:25.5.0" @@ -27226,6 +27713,19 @@ __metadata: languageName: node linkType: hard +"jest-each@npm:^29.6.3": + version: 29.6.3 + resolution: "jest-each@npm:29.6.3" + dependencies: + "@jest/types": ^29.6.3 + chalk: ^4.0.0 + jest-get-type: ^29.6.3 + jest-util: ^29.6.3 + pretty-format: ^29.6.3 + checksum: dabbe7cfc087d9a7d679344f880c633e4f12d47bb51076473d642cc6d5d7b5c0a0f6947e0934a38781c5d7e5b8094b7e4e7164074d8b24fa4fc8dcfcbd0ce55d + languageName: node + linkType: hard + "jest-environment-jsdom@npm:^25.5.0": version: 25.5.0 resolution: "jest-environment-jsdom@npm:25.5.0" @@ -27347,6 +27847,20 @@ __metadata: languageName: node linkType: hard +"jest-environment-node@npm:^29.6.4": + version: 29.6.4 + resolution: "jest-environment-node@npm:29.6.4" + dependencies: + "@jest/environment": ^29.6.4 + "@jest/fake-timers": ^29.6.4 + "@jest/types": ^29.6.3 + "@types/node": "*" + jest-mock: ^29.6.3 + jest-util: ^29.6.3 + checksum: 768d2c2a5b70b91435f1c8642377f2e92377e922d51e758e475958ff31f0b2c57c4c1f91041328c604256ba9fc284cbefa6203448b1ac67b2d53ac188807b66a + languageName: node + linkType: hard + "jest-get-type@npm:^25.2.6": version: 25.2.6 resolution: "jest-get-type@npm:25.2.6" @@ -27375,6 +27889,13 @@ __metadata: languageName: node linkType: hard +"jest-get-type@npm:^29.6.3": + version: 29.6.3 + resolution: "jest-get-type@npm:29.6.3" + checksum: 552e7a97a983d3c2d4e412a44eb7de0430ff773dd99f7500962c268d6dfbfa431d7d08f919c9d960530e5f7f78eb47f267ad9b318265e5092b3ff9ede0db7c2b + languageName: node + linkType: hard + "jest-haste-map@npm:^25.5.1": version: 25.5.1 resolution: "jest-haste-map@npm:25.5.1" @@ -27471,6 +27992,29 @@ __metadata: languageName: node linkType: hard +"jest-haste-map@npm:^29.6.4": + version: 29.6.4 + resolution: "jest-haste-map@npm:29.6.4" + dependencies: + "@jest/types": ^29.6.3 + "@types/graceful-fs": ^4.1.3 + "@types/node": "*" + anymatch: ^3.0.3 + fb-watchman: ^2.0.0 + fsevents: ^2.3.2 + graceful-fs: ^4.2.9 + jest-regex-util: ^29.6.3 + jest-util: ^29.6.3 + jest-worker: ^29.6.4 + micromatch: ^4.0.4 + walker: ^1.0.8 + dependenciesMeta: + fsevents: + optional: true + checksum: 86dfe6c767941cb47dc201cf185b81380cfc91851b0f1e9115ded5a6f4a5aa442e0e8291ff76cb4c72a7cc568dfc9bc3b86257db79b18e6c6294a526e40acab8 + languageName: node + linkType: hard + "jest-jasmine2@npm:^25.5.4": version: 25.5.4 resolution: "jest-jasmine2@npm:25.5.4" @@ -27587,6 +28131,16 @@ __metadata: languageName: node linkType: hard +"jest-leak-detector@npm:^29.6.3": + version: 29.6.3 + resolution: "jest-leak-detector@npm:29.6.3" + dependencies: + jest-get-type: ^29.6.3 + pretty-format: ^29.6.3 + checksum: 18863c20a8639398b28d72ab8dd23e4c5dbec90fa81cc8bd52c6e0891f0954e8bfdaedbf4c19b0bbcdaaff24bc71002a6dc3e7ef1eefc75b46581f651a9a47c7 + languageName: node + linkType: hard + "jest-matcher-utils@npm:^25.5.0": version: 25.5.0 resolution: "jest-matcher-utils@npm:25.5.0" @@ -27635,6 +28189,18 @@ __metadata: languageName: node linkType: hard +"jest-matcher-utils@npm:^29.6.4": + version: 29.6.4 + resolution: "jest-matcher-utils@npm:29.6.4" + dependencies: + chalk: ^4.0.0 + jest-diff: ^29.6.4 + jest-get-type: ^29.6.3 + pretty-format: ^29.6.3 + checksum: aa54f7075438160bd29e8c0a02d6b7e6ed1f18bab5670d161d1555e5cfa9b61e86306a260ca0304680fb1b357a944fd1d007b6519f91fc6f67d72997b1a7fdb8 + languageName: node + linkType: hard + "jest-message-util@npm:^25.5.0": version: 25.5.0 resolution: "jest-message-util@npm:25.5.0" @@ -27702,6 +28268,23 @@ __metadata: languageName: node linkType: hard +"jest-message-util@npm:^29.6.3": + version: 29.6.3 + resolution: "jest-message-util@npm:29.6.3" + dependencies: + "@babel/code-frame": ^7.12.13 + "@jest/types": ^29.6.3 + "@types/stack-utils": ^2.0.0 + chalk: ^4.0.0 + graceful-fs: ^4.2.9 + micromatch: ^4.0.4 + pretty-format: ^29.6.3 + slash: ^3.0.0 + stack-utils: ^2.0.3 + checksum: 5ae17c0aa8076bd0d4c68a036865cf156084cf7b4f69b4ffee0f49da61f7fe9eb38c6405c1f6967df031ffe14f8a31830baa1f04f1dbea52f239689cd4e5b326 + languageName: node + linkType: hard + "jest-mock@npm:^25.5.0": version: 25.5.0 resolution: "jest-mock@npm:25.5.0" @@ -27742,6 +28325,17 @@ __metadata: languageName: node linkType: hard +"jest-mock@npm:^29.6.3": + version: 29.6.3 + resolution: "jest-mock@npm:29.6.3" + dependencies: + "@jest/types": ^29.6.3 + "@types/node": "*" + jest-util: ^29.6.3 + checksum: 2801f1d717de6bbebe05871fff71b245771f91fa9c6b543df58060aa4e972a8d1fd4dfea8c5c7b37ee02be5a5e3a9edb048d8a114e7186e101b52e50d61d5c07 + languageName: node + linkType: hard + "jest-pnp-resolver@npm:^1.2.1, jest-pnp-resolver@npm:^1.2.2": version: 1.2.3 resolution: "jest-pnp-resolver@npm:1.2.3" @@ -27782,6 +28376,13 @@ __metadata: languageName: node linkType: hard +"jest-regex-util@npm:^29.6.3": + version: 29.6.3 + resolution: "jest-regex-util@npm:29.6.3" + checksum: 4e33fb16c4f42111159cafe26397118dcfc4cf08bc178a67149fb05f45546a91928b820894572679d62559839d0992e21080a1527faad65daaae8743a5705a3b + languageName: node + linkType: hard + "jest-resolve-dependencies@npm:^25.5.4": version: 25.5.4 resolution: "jest-resolve-dependencies@npm:25.5.4" @@ -27825,6 +28426,16 @@ __metadata: languageName: node linkType: hard +"jest-resolve-dependencies@npm:^29.6.4": + version: 29.6.4 + resolution: "jest-resolve-dependencies@npm:29.6.4" + dependencies: + jest-regex-util: ^29.6.3 + jest-snapshot: ^29.6.4 + checksum: 96af4418b1bd017f658233c2f1a4deda39d8d9d85525be384c808347f57bd969f5275af8ab3be25d642b49bfee47cb1fefce02b12a729720cb75bb6b7d4426fa + languageName: node + linkType: hard + "jest-resolve@npm:^25.5.1": version: 25.5.1 resolution: "jest-resolve@npm:25.5.1" @@ -27893,6 +28504,23 @@ __metadata: languageName: node linkType: hard +"jest-resolve@npm:^29.6.4": + version: 29.6.4 + resolution: "jest-resolve@npm:29.6.4" + dependencies: + chalk: ^4.0.0 + graceful-fs: ^4.2.9 + jest-haste-map: ^29.6.4 + jest-pnp-resolver: ^1.2.2 + jest-util: ^29.6.3 + jest-validate: ^29.6.3 + resolve: ^1.20.0 + resolve.exports: ^2.0.0 + slash: ^3.0.0 + checksum: 3924185caacc4a8f1a3ee7f580327987b8533446f8654d86713f0ba3eaf942ee3e6cef159e96cedad074df8bd7a2d2b6395d2dd2b3b7cf396d9d090943ffb897 + languageName: node + linkType: hard + "jest-runner@npm:^25.5.4": version: 25.5.4 resolution: "jest-runner@npm:25.5.4" @@ -28006,6 +28634,35 @@ __metadata: languageName: node linkType: hard +"jest-runner@npm:^29.6.4": + version: 29.6.4 + resolution: "jest-runner@npm:29.6.4" + dependencies: + "@jest/console": ^29.6.4 + "@jest/environment": ^29.6.4 + "@jest/test-result": ^29.6.4 + "@jest/transform": ^29.6.4 + "@jest/types": ^29.6.3 + "@types/node": "*" + chalk: ^4.0.0 + emittery: ^0.13.1 + graceful-fs: ^4.2.9 + jest-docblock: ^29.6.3 + jest-environment-node: ^29.6.4 + jest-haste-map: ^29.6.4 + jest-leak-detector: ^29.6.3 + jest-message-util: ^29.6.3 + jest-resolve: ^29.6.4 + jest-runtime: ^29.6.4 + jest-util: ^29.6.3 + jest-watcher: ^29.6.4 + jest-worker: ^29.6.4 + p-limit: ^3.1.0 + source-map-support: 0.5.13 + checksum: 5af7657c1f6db038bc5146ddb04ebc324cd82d623818607de508d926678ba494e08affef48879e7a6fca1d6ea6255d3d8dbbb80f1b9951b08844b8533f8747a5 + languageName: node + linkType: hard + "jest-runtime@npm:^25.5.4": version: 25.5.4 resolution: "jest-runtime@npm:25.5.4" @@ -28139,6 +28796,36 @@ __metadata: languageName: node linkType: hard +"jest-runtime@npm:^29.6.4": + version: 29.6.4 + resolution: "jest-runtime@npm:29.6.4" + dependencies: + "@jest/environment": ^29.6.4 + "@jest/fake-timers": ^29.6.4 + "@jest/globals": ^29.6.4 + "@jest/source-map": ^29.6.3 + "@jest/test-result": ^29.6.4 + "@jest/transform": ^29.6.4 + "@jest/types": ^29.6.3 + "@types/node": "*" + chalk: ^4.0.0 + cjs-module-lexer: ^1.0.0 + collect-v8-coverage: ^1.0.0 + glob: ^7.1.3 + graceful-fs: ^4.2.9 + jest-haste-map: ^29.6.4 + jest-message-util: ^29.6.3 + jest-mock: ^29.6.3 + jest-regex-util: ^29.6.3 + jest-resolve: ^29.6.4 + jest-snapshot: ^29.6.4 + jest-util: ^29.6.3 + slash: ^3.0.0 + strip-bom: ^4.0.0 + checksum: 82c63b944ac84808480e89d6f1ad294d0bf7c1efce566493be3ff103ee706020addb430ebc0f43d44e8a1adb59a749385a30efc1619cb3511db690ad5d42a392 + languageName: node + linkType: hard + "jest-serializer@npm:^25.5.0": version: 25.5.0 resolution: "jest-serializer@npm:25.5.0" @@ -28276,6 +28963,34 @@ __metadata: languageName: node linkType: hard +"jest-snapshot@npm:^29.6.4": + version: 29.6.4 + resolution: "jest-snapshot@npm:29.6.4" + dependencies: + "@babel/core": ^7.11.6 + "@babel/generator": ^7.7.2 + "@babel/plugin-syntax-jsx": ^7.7.2 + "@babel/plugin-syntax-typescript": ^7.7.2 + "@babel/types": ^7.3.3 + "@jest/expect-utils": ^29.6.4 + "@jest/transform": ^29.6.4 + "@jest/types": ^29.6.3 + babel-preset-current-node-syntax: ^1.0.0 + chalk: ^4.0.0 + expect: ^29.6.4 + graceful-fs: ^4.2.9 + jest-diff: ^29.6.4 + jest-get-type: ^29.6.3 + jest-matcher-utils: ^29.6.4 + jest-message-util: ^29.6.3 + jest-util: ^29.6.3 + natural-compare: ^1.4.0 + pretty-format: ^29.6.3 + semver: ^7.5.3 + checksum: 696db4e73131d8e0df97a0bdd19c8b6e89910021b6823ce603a12a128671f42a7e7aede9d7b42ed79e4f583b7cdb46e140635c4bc6a65e072baa2ddf46fb15fc + languageName: node + linkType: hard + "jest-util@npm:^25.5.0": version: 25.5.0 resolution: "jest-util@npm:25.5.0" @@ -28331,6 +29046,20 @@ __metadata: languageName: node linkType: hard +"jest-util@npm:^29.6.3": + version: 29.6.3 + resolution: "jest-util@npm:29.6.3" + dependencies: + "@jest/types": ^29.6.3 + "@types/node": "*" + chalk: ^4.0.0 + ci-info: ^3.2.0 + graceful-fs: ^4.2.9 + picomatch: ^2.2.3 + checksum: 9428c07696f27aa8f230a13a35546559f9a087f3e3744f53f69a620598234c03004b808b1b4a12120cc5771a88403bf0a1e3f95a7ccd610acf03d90c36135e88 + languageName: node + linkType: hard + "jest-validate@npm:^25.5.0": version: 25.5.0 resolution: "jest-validate@npm:25.5.0" @@ -28387,6 +29116,20 @@ __metadata: languageName: node linkType: hard +"jest-validate@npm:^29.6.3": + version: 29.6.3 + resolution: "jest-validate@npm:29.6.3" + dependencies: + "@jest/types": ^29.6.3 + camelcase: ^6.2.0 + chalk: ^4.0.0 + jest-get-type: ^29.6.3 + leven: ^3.1.0 + pretty-format: ^29.6.3 + checksum: 148bacc985abf4e35cba5fd09e145ef00f3835a7625a0df18caf6c93c7a4297f492b7ae61d767f2dc37c7c2c67034ed3e8922dc1336407b4e9db235b107ddde9 + languageName: node + linkType: hard + "jest-watcher@npm:^25.5.0": version: 25.5.0 resolution: "jest-watcher@npm:25.5.0" @@ -28447,6 +29190,22 @@ __metadata: languageName: node linkType: hard +"jest-watcher@npm:^29.6.4": + version: 29.6.4 + resolution: "jest-watcher@npm:29.6.4" + dependencies: + "@jest/test-result": ^29.6.4 + "@jest/types": ^29.6.3 + "@types/node": "*" + ansi-escapes: ^4.2.1 + chalk: ^4.0.0 + emittery: ^0.13.1 + jest-util: ^29.6.3 + string-length: ^4.0.1 + checksum: a3f4e9b16353fd3e4ee19b71308324bf113d12d538bf4894a46a6a8dcbcea6f00c60b3f02ad0865f6cea9b44938b8c8f4aa05433e50d609b8285e8ebc20400cf + languageName: node + linkType: hard + "jest-worker@npm:^25.5.0": version: 25.5.0 resolution: "jest-worker@npm:25.5.0" @@ -28491,6 +29250,18 @@ __metadata: languageName: node linkType: hard +"jest-worker@npm:^29.6.4": + version: 29.6.4 + resolution: "jest-worker@npm:29.6.4" + dependencies: + "@types/node": "*" + jest-util: ^29.6.3 + merge-stream: ^2.0.0 + supports-color: ^8.0.0 + checksum: cbad6f05097555c805daa105eefe73352e0d37702cd87d4265b9383e76bf20e7ab1318e7d37f44c190ba104308bcfca5b41a9fce563a0473c99c86a9ba849f46 + languageName: node + linkType: hard + "jest@npm:25.5.4, jest@npm:^25.5.2, jest@npm:^25.5.4": version: 25.5.4 resolution: "jest@npm:25.5.4" @@ -28554,6 +29325,25 @@ __metadata: languageName: node linkType: hard +"jest@npm:^29.6.3": + version: 29.6.4 + resolution: "jest@npm:29.6.4" + dependencies: + "@jest/core": ^29.6.4 + "@jest/types": ^29.6.3 + import-local: ^3.0.2 + jest-cli: ^29.6.4 + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + bin: + jest: bin/jest.js + checksum: 7f4519a30b2c58d116f118cc841dbf9558fb9c47ed3b651a8feef0e98fbc96ce5bd9b574ace9bbef9d31f1f5720f121065f2d0351416449a088f1d655517bf39 + languageName: node + linkType: hard + "jiti@npm:^1.18.2": version: 1.18.2 resolution: "jiti@npm:1.18.2" @@ -31138,17 +31928,15 @@ __metadata: version: 0.0.0-use.local resolution: "medusa-test-utils@workspace:packages/medusa-test-utils" dependencies: - "@babel/cli": ^7.7.5 - "@babel/core": ^7.7.5 - "@babel/plugin-proposal-class-properties": ^7.7.4 - "@babel/plugin-transform-classes": ^7.9.5 - "@babel/plugin-transform-runtime": ^7.7.6 - "@babel/preset-env": ^7.7.5 - "@babel/runtime": ^7.9.6 + "@mikro-orm/migrations": 5.7.12 + "@mikro-orm/postgresql": 5.7.12 cross-env: ^5.2.1 jest: ^25.5.4 medusa-core-utils: ^1.2.0 + pg-god: ^1.0.12 randomatic: ^3.1.1 + rimraf: ^3.0.2 + typescript: ^5.1.6 languageName: unknown linkType: soft @@ -35430,6 +36218,17 @@ __metadata: languageName: node linkType: hard +"pretty-format@npm:^29.6.3": + version: 29.6.3 + resolution: "pretty-format@npm:29.6.3" + dependencies: + "@jest/schemas": ^29.6.3 + ansi-styles: ^5.0.0 + react-is: ^18.0.0 + checksum: 73c6a46acdad4cb9337add02c850769fb831d7154cdb50b1152f3970a8fbf8292188dcccd1ba597f3e34c360af71fc0b63f1db4cf155a0098ffe2812eb7a6b22 + languageName: node + linkType: hard + "pretty-hrtime@npm:^1.0.3": version: 1.0.3 resolution: "pretty-hrtime@npm:1.0.3" @@ -38237,6 +39036,17 @@ __metadata: languageName: node linkType: hard +"semver@npm:^7.5.4": + version: 7.5.4 + resolution: "semver@npm:7.5.4" + dependencies: + lru-cache: ^6.0.0 + bin: + semver: bin/semver.js + checksum: 5160b06975a38b11c1ab55950cb5b8a23db78df88275d3d8a42ccf1f29e55112ac995b3a26a522c36e3b5f76b0445f1eef70d696b8c7862a2b4303d7b0e7609e + languageName: node + linkType: hard + "send@npm:0.17.1": version: 0.17.1 resolution: "send@npm:0.17.1" @@ -40925,7 +41735,7 @@ __metadata: languageName: node linkType: hard -"ts-jest@npm:^29.0.5, ts-jest@npm:^29.1.0": +"ts-jest@npm:^29.0.5, ts-jest@npm:^29.1.0, ts-jest@npm:^29.1.1": version: 29.1.1 resolution: "ts-jest@npm:29.1.1" dependencies: @@ -41594,6 +42404,16 @@ __metadata: languageName: node linkType: hard +"typescript@npm:^5.1.6": + version: 5.2.2 + resolution: "typescript@npm:5.2.2" + bin: + tsc: bin/tsc + tsserver: bin/tsserver + checksum: 91ae3e6193d0ddb8656d4c418a033f0f75dec5e077ebbc2bd6d76439b93f35683936ee1bdc0e9cf94ec76863aa49f27159b5788219b50e1cd0cd6d110aa34b07 + languageName: node + linkType: hard + "typescript@patch:typescript@4.9.5#~builtin, typescript@patch:typescript@^4.1.3#~builtin, typescript@patch:typescript@^4.4.4#~builtin, typescript@patch:typescript@^4.5.2#~builtin, typescript@patch:typescript@^4.9.3#~builtin, typescript@patch:typescript@^4.9.5#~builtin": version: 4.9.5 resolution: "typescript@patch:typescript@npm%3A4.9.5#~builtin::version=4.9.5&hash=7ad353" @@ -41614,6 +42434,16 @@ __metadata: languageName: node linkType: hard +"typescript@patch:typescript@^5.1.6#~builtin": + version: 5.2.2 + resolution: "typescript@patch:typescript@npm%3A5.2.2#~builtin::version=5.2.2&hash=7ad353" + bin: + tsc: bin/tsc + tsserver: bin/tsserver + checksum: 303979762f9b8932c53f8149e866521a1265168b5c0fde8cc8ad83ac3d0e8ede8096cb02dff5f2de048e7f118a6f61902f81da12d5972c7fb582f09f2f18d169 + languageName: node + linkType: hard + "ua-parser-js@npm:^0.7.30": version: 0.7.35 resolution: "ua-parser-js@npm:0.7.35"