diff --git a/packages/medusa/src/api-v2/admin/products/helpers.ts b/packages/medusa/src/api-v2/admin/products/helpers.ts index 531a647d7e..2a46125dc0 100644 --- a/packages/medusa/src/api-v2/admin/products/helpers.ts +++ b/packages/medusa/src/api-v2/admin/products/helpers.ts @@ -4,8 +4,11 @@ import { ProductDTO, ProductVariantDTO, } from "@medusajs/types" -import { ContainerRegistrationKeys } from "@medusajs/utils" -import { promiseAll, remoteQueryObjectFromString } from "@medusajs/utils" +import { + promiseAll, + remoteQueryObjectFromString, + ContainerRegistrationKeys, +} from "@medusajs/utils" const isPricing = (fieldName: string) => fieldName.startsWith("variants.prices") || diff --git a/packages/medusa/src/api-v2/admin/products/route.ts b/packages/medusa/src/api-v2/admin/products/route.ts index f598ff43be..50162ef1c0 100644 --- a/packages/medusa/src/api-v2/admin/products/route.ts +++ b/packages/medusa/src/api-v2/admin/products/route.ts @@ -2,7 +2,7 @@ import { createProductsWorkflow } from "@medusajs/core-flows" import { CreateProductDTO } from "@medusajs/types" import { ContainerRegistrationKeys, - remoteQueryObjectFromString + remoteQueryObjectFromString, } from "@medusajs/utils" import { AuthenticatedMedusaRequest, diff --git a/packages/medusa/src/api-v2/admin/stores/[id]/route.ts b/packages/medusa/src/api-v2/admin/stores/[id]/route.ts index a5bd5d7010..a0944466a8 100644 --- a/packages/medusa/src/api-v2/admin/stores/[id]/route.ts +++ b/packages/medusa/src/api-v2/admin/stores/[id]/route.ts @@ -1,25 +1,37 @@ import { updateStoresWorkflow } from "@medusajs/core-flows" import { UpdateStoreDTO } from "@medusajs/types" -import { remoteQueryObjectFromString } from "@medusajs/utils" -import { MedusaRequest, MedusaResponse } from "../../../../types/routing" -import { defaultAdminStoreFields } from "../query-config" - -export const GET = async (req: MedusaRequest, res: MedusaResponse) => { - const remoteQuery = req.scope.resolve("remoteQuery") +import { + remoteQueryObjectFromString, + ContainerRegistrationKeys, +} from "@medusajs/utils" +import { + AuthenticatedMedusaRequest, + MedusaResponse, +} from "../../../../types/routing" +import { AdminGetStoreParamsType, AdminUpdateStoreType } from "../validators" +import { refetchStore } from "../helpers" +export const GET = async ( + req: AuthenticatedMedusaRequest, + res: MedusaResponse +) => { + const remoteQuery = req.scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY) const variables = { id: req.params.id } const queryObject = remoteQueryObjectFromString({ entryPoint: "store", variables, - fields: defaultAdminStoreFields, + fields: req.remoteQueryConfig.fields, }) const [store] = await remoteQuery(queryObject) res.status(200).json({ store }) } -export const POST = async (req: MedusaRequest, res: MedusaResponse) => { +export const POST = async ( + req: AuthenticatedMedusaRequest, + res: MedusaResponse +) => { const { result, errors } = await updateStoresWorkflow(req.scope).run({ input: { selector: { id: req.params.id }, @@ -32,5 +44,11 @@ export const POST = async (req: MedusaRequest, res: MedusaResponse) => { throw errors[0].error } - res.status(200).json({ store: result[0] }) + const store = await refetchStore( + result[0].id, + req.scope, + req.remoteQueryConfig.fields + ) + + res.status(200).json({ store }) } diff --git a/packages/medusa/src/api-v2/admin/stores/helpers.ts b/packages/medusa/src/api-v2/admin/stores/helpers.ts new file mode 100644 index 0000000000..f55d4924cd --- /dev/null +++ b/packages/medusa/src/api-v2/admin/stores/helpers.ts @@ -0,0 +1,23 @@ +import { MedusaContainer } from "@medusajs/types" +import { + ContainerRegistrationKeys, + remoteQueryObjectFromString, +} from "@medusajs/utils" + +export const refetchStore = async ( + storeId: string, + scope: MedusaContainer, + fields: string[] +) => { + const remoteQuery = scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY) + const queryObject = remoteQueryObjectFromString({ + entryPoint: "store", + variables: { + filters: { id: storeId }, + }, + fields: fields, + }) + + const stores = await remoteQuery(queryObject) + return stores[0] +} diff --git a/packages/medusa/src/api-v2/admin/stores/middlewares.ts b/packages/medusa/src/api-v2/admin/stores/middlewares.ts index 5091f0690b..5dd2672ee9 100644 --- a/packages/medusa/src/api-v2/admin/stores/middlewares.ts +++ b/packages/medusa/src/api-v2/admin/stores/middlewares.ts @@ -1,11 +1,12 @@ -import { transformBody, transformQuery } from "../../../api/middlewares" import { MiddlewareRoute } from "../../../loaders/helpers/routing/types" import { authenticate } from "../../../utils/authenticate-middleware" +import { validateAndTransformBody } from "../../utils/validate-body" +import { validateAndTransformQuery } from "../../utils/validate-query" import * as QueryConfig from "./query-config" import { + AdminGetStoreParams, AdminGetStoresParams, - AdminGetStoresStoreParams, - AdminPostStoresStoreReq, + AdminUpdateStore, } from "./validators" export const adminStoreRoutesMiddlewares: MiddlewareRoute[] = [ @@ -18,7 +19,7 @@ export const adminStoreRoutesMiddlewares: MiddlewareRoute[] = [ method: ["GET"], matcher: "/admin/stores", middlewares: [ - transformQuery( + validateAndTransformQuery( AdminGetStoresParams, QueryConfig.listTransformQueryConfig ), @@ -28,8 +29,8 @@ export const adminStoreRoutesMiddlewares: MiddlewareRoute[] = [ method: ["GET"], matcher: "/admin/stores/:id", middlewares: [ - transformQuery( - AdminGetStoresStoreParams, + validateAndTransformQuery( + AdminGetStoreParams, QueryConfig.retrieveTransformQueryConfig ), ], @@ -37,6 +38,12 @@ export const adminStoreRoutesMiddlewares: MiddlewareRoute[] = [ { method: ["POST"], matcher: "/admin/stores/:id", - middlewares: [transformBody(AdminPostStoresStoreReq)], + middlewares: [ + validateAndTransformBody(AdminUpdateStore), + validateAndTransformQuery( + AdminGetStoreParams, + QueryConfig.retrieveTransformQueryConfig + ), + ], }, ] diff --git a/packages/medusa/src/api-v2/admin/stores/query-config.ts b/packages/medusa/src/api-v2/admin/stores/query-config.ts index 07e49acdbf..55943d21f6 100644 --- a/packages/medusa/src/api-v2/admin/stores/query-config.ts +++ b/packages/medusa/src/api-v2/admin/stores/query-config.ts @@ -20,6 +20,6 @@ export const retrieveTransformQueryConfig = { } export const listTransformQueryConfig = { - defaultLimit: 20, + ...retrieveTransformQueryConfig, isList: true, } diff --git a/packages/medusa/src/api-v2/admin/stores/route.ts b/packages/medusa/src/api-v2/admin/stores/route.ts index ca70ca7347..3eaae6001c 100644 --- a/packages/medusa/src/api-v2/admin/stores/route.ts +++ b/packages/medusa/src/api-v2/admin/stores/route.ts @@ -2,25 +2,28 @@ import { ContainerRegistrationKeys, remoteQueryObjectFromString, } from "@medusajs/utils" -import { MedusaRequest, MedusaResponse } from "../../../types/routing" -import { defaultAdminStoreFields } from "./query-config" +import { + AuthenticatedMedusaRequest, + MedusaResponse, +} from "../../../types/routing" +import { AdminGetStoresParamsType } from "./validators" -export const GET = async (req: MedusaRequest, res: MedusaResponse) => { +export const GET = async ( + req: AuthenticatedMedusaRequest, + res: MedusaResponse +) => { const remoteQuery = req.scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY) const queryObject = remoteQueryObjectFromString({ entryPoint: "store", variables: { filters: req.filterableFields, - order: req.listConfig.order, - skip: req.listConfig.skip, - take: req.listConfig.take, + ...req.remoteQueryConfig.pagination, }, - fields: defaultAdminStoreFields, + fields: req.remoteQueryConfig.fields, }) const { rows: stores, metadata } = await remoteQuery(queryObject) - res.json({ stores, count: metadata.count, diff --git a/packages/medusa/src/api-v2/admin/stores/validators.ts b/packages/medusa/src/api-v2/admin/stores/validators.ts index ab761f3252..908f2b528a 100644 --- a/packages/medusa/src/api-v2/admin/stores/validators.ts +++ b/packages/medusa/src/api-v2/admin/stores/validators.ts @@ -1,75 +1,29 @@ -import { Type } from "class-transformer" -import { - IsArray, - IsObject, - IsOptional, - IsString, - ValidateNested, -} from "class-validator" -import { FindParams, extendedFindParamsMixin } from "../../../types/common" +import { createFindParams, createSelectParams } from "../../utils/validators" +import { z } from "zod" -export class AdminGetStoresStoreParams extends FindParams {} -/** - * Parameters used to filter and configure the pagination of the retrieved api keys. - */ -export class AdminGetStoresParams extends extendedFindParamsMixin({ +export type AdminGetStoreParamsType = z.infer +export const AdminGetStoreParams = createSelectParams() + +export type AdminGetStoresParamsType = z.infer +export const AdminGetStoresParams = createFindParams({ limit: 50, offset: 0, -}) { - /** - * Search parameter for api keys. - */ - @IsString({ each: true }) - @IsOptional() - id?: string | string[] +}).merge( + z.object({ + id: z.union([z.string(), z.array(z.string())]).optional(), + name: z.union([z.string(), z.array(z.string())]).optional(), + $and: z.lazy(() => AdminGetStoresParams.array()).optional(), + $or: z.lazy(() => AdminGetStoresParams.array()).optional(), + }) +) - /** - * Filter by title - */ - @IsString({ each: true }) - @IsOptional() - name?: string | string[] - - // Additional filters from BaseFilterable - @IsOptional() - @ValidateNested({ each: true }) - @Type(() => AdminGetStoresParams) - $and?: AdminGetStoresParams[] - - @IsOptional() - @ValidateNested({ each: true }) - @Type(() => AdminGetStoresParams) - $or?: AdminGetStoresParams[] -} - -export class AdminPostStoresStoreReq { - @IsOptional() - @IsString() - name?: string - - @IsOptional() - @IsArray() - supported_currency_codes?: string[] - - @IsOptional() - @IsString() - default_currency_code?: string - - @IsOptional() - @IsString() - default_sales_channel_id?: string - - @IsOptional() - @IsString() - default_region_id?: string - - @IsOptional() - @IsString() - default_location_id?: string - - @IsObject() - @IsOptional() - metadata?: Record -} - -export class AdminDeleteStoresStoreReq {} +export type AdminUpdateStoreType = z.infer +export const AdminUpdateStore = z.object({ + name: z.string().optional(), + supported_currency_codes: z.array(z.string()).optional(), + default_currency_code: z.string().optional(), + default_sales_channel_id: z.string().optional(), + default_region_id: z.string().optional(), + default_location_id: z.string().optional(), + metadata: z.record(z.unknown()).optional(), +}) diff --git a/packages/medusa/src/api-v2/admin/tax-rates/[id]/route.ts b/packages/medusa/src/api-v2/admin/tax-rates/[id]/route.ts index 51aa8f0baf..c8be812b48 100644 --- a/packages/medusa/src/api-v2/admin/tax-rates/[id]/route.ts +++ b/packages/medusa/src/api-v2/admin/tax-rates/[id]/route.ts @@ -3,16 +3,22 @@ import { MedusaResponse, } from "../../../../types/routing" -import { defaultAdminTaxRateFields } from "../query-config" -import { remoteQueryObjectFromString } from "@medusajs/utils" -import { AdminPostTaxRatesTaxRateReq } from "../../../../api/routes/admin/tax-rates" +import { + remoteQueryObjectFromString, + ContainerRegistrationKeys, +} from "@medusajs/utils" import { deleteTaxRatesWorkflow, updateTaxRatesWorkflow, } from "@medusajs/core-flows" +import { + AdminGetTaxRateParamsType, + AdminUpdateTaxRateType, +} from "../validators" +import { refetchTaxRate } from "../helpers" export const POST = async ( - req: AuthenticatedMedusaRequest, + req: AuthenticatedMedusaRequest, res: MedusaResponse ) => { const { errors } = await updateTaxRatesWorkflow(req.scope).run({ @@ -27,35 +33,28 @@ export const POST = async ( throw errors[0].error } - const remoteQuery = req.scope.resolve("remoteQuery") - - const queryObject = remoteQueryObjectFromString({ - entryPoint: "tax_rate", - variables: { id: req.params.id }, - fields: defaultAdminTaxRateFields, - }) - - const [taxRate] = await remoteQuery(queryObject) - + const taxRate = await refetchTaxRate( + req.params.id, + req.scope, + req.remoteQueryConfig.fields + ) res.status(200).json({ tax_rate: taxRate }) } export const GET = async ( - req: AuthenticatedMedusaRequest, + req: AuthenticatedMedusaRequest, res: MedusaResponse ) => { - const remoteQuery = req.scope.resolve("remoteQuery") - + const remoteQuery = req.scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY) const variables = { id: req.params.id } const queryObject = remoteQueryObjectFromString({ entryPoint: "tax_rate", variables, - fields: defaultAdminTaxRateFields, + fields: req.remoteQueryConfig.fields, }) const [taxRate] = await remoteQuery(queryObject) - res.status(200).json({ tax_rate: taxRate }) } @@ -64,7 +63,6 @@ export const DELETE = async ( res: MedusaResponse ) => { const id = req.params.id - const { errors } = await deleteTaxRatesWorkflow(req.scope).run({ input: { ids: [id] }, throwOnError: false, diff --git a/packages/medusa/src/api-v2/admin/tax-rates/[id]/rules/[rule_id]/route.ts b/packages/medusa/src/api-v2/admin/tax-rates/[id]/rules/[rule_id]/route.ts index 4a8dacfa02..8bb2aec0f9 100644 --- a/packages/medusa/src/api-v2/admin/tax-rates/[id]/rules/[rule_id]/route.ts +++ b/packages/medusa/src/api-v2/admin/tax-rates/[id]/rules/[rule_id]/route.ts @@ -1,10 +1,9 @@ import { deleteTaxRateRulesWorkflow } from "@medusajs/core-flows" -import { remoteQueryObjectFromString } from "@medusajs/utils" -import { defaultAdminTaxRatesFields } from "../../../../../../api/routes/admin/tax-rates" import { AuthenticatedMedusaRequest, MedusaResponse, } from "../../../../../../types/routing" +import { refetchTaxRate } from "../../../helpers" export const DELETE = async ( req: AuthenticatedMedusaRequest, @@ -19,15 +18,16 @@ export const DELETE = async ( throw errors[0].error } - const remoteQuery = req.scope.resolve("remoteQuery") + const taxRate = await refetchTaxRate( + req.params.id, + req.scope, + req.remoteQueryConfig.fields + ) - const queryObject = remoteQueryObjectFromString({ - entryPoint: "tax_rate", - variables: { id: req.params.id }, - fields: defaultAdminTaxRatesFields, + res.status(200).json({ + id: req.params.rule_id, + object: "tax_rate_rule", + deleted: true, + parent: taxRate, }) - - const [taxRate] = await remoteQuery(queryObject) - - res.status(200).json({ tax_rate: taxRate }) } diff --git a/packages/medusa/src/api-v2/admin/tax-rates/[id]/rules/route.ts b/packages/medusa/src/api-v2/admin/tax-rates/[id]/rules/route.ts index b1d8fbb8e9..6e9ce67dd7 100644 --- a/packages/medusa/src/api-v2/admin/tax-rates/[id]/rules/route.ts +++ b/packages/medusa/src/api-v2/admin/tax-rates/[id]/rules/route.ts @@ -1,14 +1,13 @@ import { createTaxRateRulesWorkflow } from "@medusajs/core-flows" -import { remoteQueryObjectFromString } from "@medusajs/utils" -import { defaultAdminTaxRatesFields } from "../../../../../api/routes/admin/tax-rates" import { AuthenticatedMedusaRequest, MedusaResponse, } from "../../../../../types/routing" -import { AdminPostTaxRatesTaxRateRulesReq } from "../../validators" +import { AdminCreateTaxRateRuleType } from "../../validators" +import { refetchTaxRate } from "../../helpers" export const POST = async ( - req: AuthenticatedMedusaRequest, + req: AuthenticatedMedusaRequest, res: MedusaResponse ) => { const { errors } = await createTaxRateRulesWorkflow(req.scope).run({ @@ -28,15 +27,10 @@ export const POST = async ( throw errors[0].error } - const remoteQuery = req.scope.resolve("remoteQuery") - - const queryObject = remoteQueryObjectFromString({ - entryPoint: "tax_rate", - variables: { id: req.params.id }, - fields: defaultAdminTaxRatesFields, - }) - - const [taxRate] = await remoteQuery(queryObject) - + const taxRate = await refetchTaxRate( + req.params.id, + req.scope, + req.remoteQueryConfig.fields + ) res.status(200).json({ tax_rate: taxRate }) } diff --git a/packages/medusa/src/api-v2/admin/tax-rates/helpers.ts b/packages/medusa/src/api-v2/admin/tax-rates/helpers.ts new file mode 100644 index 0000000000..c44b954260 --- /dev/null +++ b/packages/medusa/src/api-v2/admin/tax-rates/helpers.ts @@ -0,0 +1,23 @@ +import { MedusaContainer } from "@medusajs/types" +import { + ContainerRegistrationKeys, + remoteQueryObjectFromString, +} from "@medusajs/utils" + +export const refetchTaxRate = async ( + taxRateId: string, + scope: MedusaContainer, + fields: string[] +) => { + const remoteQuery = scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY) + const queryObject = remoteQueryObjectFromString({ + entryPoint: "tax_rate", + variables: { + filters: { id: taxRateId }, + }, + fields: fields, + }) + + const taxRates = await remoteQuery(queryObject) + return taxRates[0] +} diff --git a/packages/medusa/src/api-v2/admin/tax-rates/middlewares.ts b/packages/medusa/src/api-v2/admin/tax-rates/middlewares.ts index 3c06e57571..1a8d4274b9 100644 --- a/packages/medusa/src/api-v2/admin/tax-rates/middlewares.ts +++ b/packages/medusa/src/api-v2/admin/tax-rates/middlewares.ts @@ -1,15 +1,17 @@ import * as QueryConfig from "./query-config" import { - AdminGetTaxRatesTaxRateParams, - AdminPostTaxRatesReq, - AdminPostTaxRatesTaxRateReq, - AdminPostTaxRatesTaxRateRulesReq, + AdminCreateTaxRate, + AdminCreateTaxRateRule, + AdminGetTaxRateParams, + AdminGetTaxRatesParams, + AdminUpdateTaxRate, } from "./validators" -import { transformBody, transformQuery } from "../../../api/middlewares" import { MiddlewareRoute } from "../../../loaders/helpers/routing/types" import { authenticate } from "../../../utils/authenticate-middleware" +import { validateAndTransformBody } from "../../utils/validate-body" +import { validateAndTransformQuery } from "../../utils/validate-query" export const adminTaxRateRoutesMiddlewares: MiddlewareRoute[] = [ { @@ -20,19 +22,41 @@ export const adminTaxRateRoutesMiddlewares: MiddlewareRoute[] = [ { method: "POST", matcher: "/admin/tax-rates", - middlewares: [transformBody(AdminPostTaxRatesReq)], + middlewares: [ + validateAndTransformBody(AdminCreateTaxRate), + validateAndTransformQuery( + AdminGetTaxRateParams, + QueryConfig.retrieveTransformQueryConfig + ), + ], }, { method: "POST", matcher: "/admin/tax-rates/:id", - middlewares: [transformBody(AdminPostTaxRatesTaxRateReq)], + middlewares: [ + validateAndTransformBody(AdminUpdateTaxRate), + validateAndTransformQuery( + AdminGetTaxRateParams, + QueryConfig.retrieveTransformQueryConfig + ), + ], + }, + { + method: "GET", + matcher: "/admin/tax-rates", + middlewares: [ + validateAndTransformQuery( + AdminGetTaxRatesParams, + QueryConfig.listTransformQueryConfig + ), + ], }, { method: "GET", matcher: "/admin/tax-rates/:id", middlewares: [ - transformQuery( - AdminGetTaxRatesTaxRateParams, + validateAndTransformQuery( + AdminGetTaxRateParams, QueryConfig.retrieveTransformQueryConfig ), ], @@ -40,6 +64,22 @@ export const adminTaxRateRoutesMiddlewares: MiddlewareRoute[] = [ { method: "POST", matcher: "/admin/tax-rates/:id/rules", - middlewares: [transformBody(AdminPostTaxRatesTaxRateRulesReq)], + middlewares: [ + validateAndTransformBody(AdminCreateTaxRateRule), + validateAndTransformQuery( + AdminGetTaxRateParams, + QueryConfig.retrieveTransformQueryConfig + ), + ], + }, + { + method: "DELETE", + matcher: "/admin/tax-rates/:id/rules/:rule_id", + middlewares: [ + validateAndTransformQuery( + AdminGetTaxRateParams, + QueryConfig.retrieveTransformQueryConfig + ), + ], }, ] diff --git a/packages/medusa/src/api-v2/admin/tax-rates/query-config.ts b/packages/medusa/src/api-v2/admin/tax-rates/query-config.ts index 99a48b534c..b405ddc44c 100644 --- a/packages/medusa/src/api-v2/admin/tax-rates/query-config.ts +++ b/packages/medusa/src/api-v2/admin/tax-rates/query-config.ts @@ -16,13 +16,11 @@ export const defaultAdminTaxRateFields = [ ] export const retrieveTransformQueryConfig = { - defaultFields: defaultAdminTaxRateFields, - defaultRelations: defaultAdminTaxRateRelations, - allowedRelations: allowedAdminTaxRateRelations, + defaults: defaultAdminTaxRateFields, isList: false, } export const listTransformQueryConfig = { - defaultLimit: 20, + defaults: defaultAdminTaxRateFields, isList: true, } diff --git a/packages/medusa/src/api-v2/admin/tax-rates/route.ts b/packages/medusa/src/api-v2/admin/tax-rates/route.ts index 8c168c791d..75579d9d0d 100644 --- a/packages/medusa/src/api-v2/admin/tax-rates/route.ts +++ b/packages/medusa/src/api-v2/admin/tax-rates/route.ts @@ -1,14 +1,20 @@ import { createTaxRatesWorkflow } from "@medusajs/core-flows" -import { remoteQueryObjectFromString } from "@medusajs/utils" +import { + remoteQueryObjectFromString, + ContainerRegistrationKeys, +} from "@medusajs/utils" import { AuthenticatedMedusaRequest, MedusaResponse, } from "../../../types/routing" -import { defaultAdminTaxRateFields } from "./query-config" -import { AdminPostTaxRatesReq } from "./validators" +import { + AdminCreateTaxRateType, + AdminGetTaxRatesParamsType, +} from "./validators" +import { refetchTaxRate } from "./helpers" export const POST = async ( - req: AuthenticatedMedusaRequest, + req: AuthenticatedMedusaRequest, res: MedusaResponse ) => { const { result, errors } = await createTaxRatesWorkflow(req.scope).run({ @@ -25,34 +31,34 @@ export const POST = async ( throw errors[0].error } - const remoteQuery = req.scope.resolve("remoteQuery") - - const query = remoteQueryObjectFromString({ - entryPoint: "tax_rate", - variables: { id: result[0].id }, - fields: defaultAdminTaxRateFields, - }) - - const [taxRate] = await remoteQuery(query) - + const taxRate = await refetchTaxRate( + result[0].id, + req.scope, + req.remoteQueryConfig.fields + ) res.status(200).json({ tax_rate: taxRate }) } export const GET = async ( - req: AuthenticatedMedusaRequest, + req: AuthenticatedMedusaRequest, res: MedusaResponse ) => { - const remoteQuery = req.scope.resolve("remoteQuery") + const remoteQuery = req.scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY) + const { rows: tax_rates, metadata } = await remoteQuery( + remoteQueryObjectFromString({ + entryPoint: "tax_rate", + variables: { + filters: req.filterableFields, + ...req.remoteQueryConfig.pagination, + }, + fields: req.remoteQueryConfig.fields, + }) + ) - const variables = { id: req.params.id } - - const queryObject = remoteQueryObjectFromString({ - entryPoint: "tax_rate", - variables, - fields: defaultAdminTaxRateFields, + res.status(200).json({ + tax_rates, + count: metadata.count, + offset: metadata.skip, + limit: metadata.take, }) - - const rates = await remoteQuery(queryObject) - - res.status(200).json({ tax_rates: rates }) } diff --git a/packages/medusa/src/api-v2/admin/tax-rates/validators.ts b/packages/medusa/src/api-v2/admin/tax-rates/validators.ts index 2c39c98d1b..f84a403516 100644 --- a/packages/medusa/src/api-v2/admin/tax-rates/validators.ts +++ b/packages/medusa/src/api-v2/admin/tax-rates/validators.ts @@ -1,85 +1,40 @@ -import { Type } from "class-transformer" -import { - IsBoolean, - IsNumber, - IsObject, - IsOptional, - IsString, - ValidateNested, -} from "class-validator" -import { FindParams } from "../../../types/common" +import { createFindParams, createSelectParams } from "../../utils/validators" +import { z } from "zod" -export class AdminGetTaxRatesTaxRateParams extends FindParams {} +export type AdminGetTaxRateParamsType = z.infer +export const AdminGetTaxRateParams = createSelectParams() -class CreateTaxRateRule { - @IsString() - reference: string +export type AdminGetTaxRatesParamsType = z.infer +export const AdminGetTaxRatesParams = createFindParams({ + limit: 20, + offset: 0, +}) - @IsString() - reference_id: string -} +export type AdminCreateTaxRateRuleType = z.infer +export const AdminCreateTaxRateRule = z.object({ + reference: z.string(), + reference_id: z.string(), +}) -export class AdminPostTaxRatesReq { - @IsOptional() - @IsNumber() - rate?: number | null +export type AdminCreateTaxRateType = z.infer +export const AdminCreateTaxRate = z.object({ + rate: z.number().optional(), + code: z.string().optional(), + rules: z.array(AdminCreateTaxRateRule).optional(), + name: z.string(), + is_default: z.boolean().optional(), + is_combinable: z.boolean().optional(), + tax_region_id: z.string(), + metadata: z.record(z.unknown()).optional(), +}) - @IsOptional() - @IsString() - code?: string | null - - @ValidateNested({ each: true }) - @IsOptional() - @Type(() => CreateTaxRateRule) - rules?: CreateTaxRateRule[] - - @IsString() - name: string - - @IsBoolean() - @IsOptional() - is_default?: boolean - - @IsBoolean() - @IsOptional() - is_combinable?: boolean - - @IsString() - tax_region_id: string - - @IsObject() - @IsOptional() - metadata?: Record -} - -export class AdminPostTaxRatesTaxRateReq { - @IsOptional() - @IsNumber() - rate?: number | null - - @IsOptional() - @IsString() - code?: string | null - - @IsString() - @IsOptional() - name?: string - - @ValidateNested({ each: true }) - @Type(() => CreateTaxRateRule) - rules: CreateTaxRateRule[] - - @IsBoolean() - @IsOptional() - is_default?: boolean - - @IsBoolean() - @IsOptional() - is_combinable?: boolean - - @IsObject() - @IsOptional() - metadata?: Record -} - -export class AdminPostTaxRatesTaxRateRulesReq extends CreateTaxRateRule {} +export type AdminUpdateTaxRateType = z.infer +export const AdminUpdateTaxRate = z.object({ + rate: z.number().optional(), + code: z.string().optional(), + rules: z.array(AdminCreateTaxRateRule).optional(), + name: z.string().optional(), + is_default: z.boolean().optional(), + is_combinable: z.boolean().optional(), + metadata: z.record(z.unknown()).optional(), +}) diff --git a/packages/medusa/src/api-v2/admin/tax-regions/helpers.ts b/packages/medusa/src/api-v2/admin/tax-regions/helpers.ts new file mode 100644 index 0000000000..aefc0d083e --- /dev/null +++ b/packages/medusa/src/api-v2/admin/tax-regions/helpers.ts @@ -0,0 +1,23 @@ +import { MedusaContainer } from "@medusajs/types" +import { + ContainerRegistrationKeys, + remoteQueryObjectFromString, +} from "@medusajs/utils" + +export const refetchTaxRegion = async ( + taxRegionId: string, + scope: MedusaContainer, + fields: string[] +) => { + const remoteQuery = scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY) + const queryObject = remoteQueryObjectFromString({ + entryPoint: "tax_region", + variables: { + filters: { id: taxRegionId }, + }, + fields: fields, + }) + + const taxRegions = await remoteQuery(queryObject) + return taxRegions[0] +} diff --git a/packages/medusa/src/api-v2/admin/tax-regions/route.ts b/packages/medusa/src/api-v2/admin/tax-regions/route.ts index 0b4c4b9c32..4cf9c5b4a4 100644 --- a/packages/medusa/src/api-v2/admin/tax-regions/route.ts +++ b/packages/medusa/src/api-v2/admin/tax-regions/route.ts @@ -7,7 +7,11 @@ import { AuthenticatedMedusaRequest, MedusaResponse, } from "../../../types/routing" -import { AdminCreateTaxRegionType } from "./validators" +import { + AdminCreateTaxRegionType, + AdminGetTaxRegionsParamsType, +} from "./validators" +import { refetchTaxRegion } from "./helpers" export const POST = async ( req: AuthenticatedMedusaRequest, @@ -27,21 +31,16 @@ export const POST = async ( throw errors[0].error } - const remoteQuery = req.scope.resolve("remoteQuery") - - const query = remoteQueryObjectFromString({ - entryPoint: "tax_region", - variables: { id: result[0].id }, - fields: req.remoteQueryConfig.fields, - }) - - const [taxRegion] = await remoteQuery(query) - + const taxRegion = await refetchTaxRegion( + result[0].id, + req.scope, + req.remoteQueryConfig.fields + ) res.status(200).json({ tax_region: taxRegion }) } export const GET = async ( - req: AuthenticatedMedusaRequest, + req: AuthenticatedMedusaRequest, res: MedusaResponse ) => { const remoteQuery = req.scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY) diff --git a/packages/medusa/src/api-v2/admin/tax-regions/validators.ts b/packages/medusa/src/api-v2/admin/tax-regions/validators.ts index d107adf242..834ff1dec6 100644 --- a/packages/medusa/src/api-v2/admin/tax-regions/validators.ts +++ b/packages/medusa/src/api-v2/admin/tax-regions/validators.ts @@ -5,9 +5,12 @@ import { createSelectParams, } from "../../utils/validators" +export type AdminGetTaxRegionParamsType = z.infer< + typeof AdminGetTaxRegionParams +> export const AdminGetTaxRegionParams = createSelectParams() -export type AdminCreateTaxRegionsParams = z.infer< +export type AdminGetTaxRegionsParamsType = z.infer< typeof AdminGetTaxRegionsParams > export const AdminGetTaxRegionsParams = createFindParams({ diff --git a/packages/medusa/src/api-v2/admin/users/[id]/route.ts b/packages/medusa/src/api-v2/admin/users/[id]/route.ts index c15fb54f76..4d68e9775d 100644 --- a/packages/medusa/src/api-v2/admin/users/[id]/route.ts +++ b/packages/medusa/src/api-v2/admin/users/[id]/route.ts @@ -1,31 +1,46 @@ import { deleteUsersWorkflow, updateUsersWorkflow } from "@medusajs/core-flows" -import { IUserModuleService, UpdateUserDTO } from "@medusajs/types" +import { UpdateUserDTO } from "@medusajs/types" import { AuthenticatedMedusaRequest, MedusaResponse, } from "../../../../types/routing" -import { ModuleRegistrationName } from "@medusajs/modules-sdk" -import { AdminUpdateUserRequest } from "../validators" +import { + ContainerRegistrationKeys, + MedusaError, + remoteQueryObjectFromString, +} from "@medusajs/utils" +import { AdminUpdateUserType } from "../validators" +import { refetchUser } from "../helpers" // Get user export const GET = async ( req: AuthenticatedMedusaRequest, res: MedusaResponse ) => { + const remoteQuery = req.scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY) const { id } = req.params - const moduleService: IUserModuleService = req.scope.resolve( - ModuleRegistrationName.USER - ) - const user = await moduleService.retrieve(id, req.retrieveConfig) + const query = remoteQueryObjectFromString({ + entryPoint: "user", + variables: { id }, + fields: req.remoteQueryConfig.fields, + }) + + const [user] = await remoteQuery(query) + if (!user) { + throw new MedusaError( + MedusaError.Types.NOT_FOUND, + `User with id: ${id} was not found` + ) + } res.status(200).json({ user }) } // update user export const POST = async ( - req: AuthenticatedMedusaRequest, + req: AuthenticatedMedusaRequest, res: MedusaResponse ) => { const workflow = updateUsersWorkflow(req.scope) @@ -41,7 +56,11 @@ export const POST = async ( const { result } = await workflow.run({ input }) - const [user] = result + const user = await refetchUser( + req.params.id, + req.scope, + req.remoteQueryConfig.fields + ) res.status(200).json({ user }) } diff --git a/packages/medusa/src/api-v2/admin/users/helpers.ts b/packages/medusa/src/api-v2/admin/users/helpers.ts new file mode 100644 index 0000000000..25474edaa1 --- /dev/null +++ b/packages/medusa/src/api-v2/admin/users/helpers.ts @@ -0,0 +1,23 @@ +import { MedusaContainer } from "@medusajs/types" +import { + ContainerRegistrationKeys, + remoteQueryObjectFromString, +} from "@medusajs/utils" + +export const refetchUser = async ( + userId: string, + scope: MedusaContainer, + fields: string[] +) => { + const remoteQuery = scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY) + const queryObject = remoteQueryObjectFromString({ + entryPoint: "user", + variables: { + filters: { id: userId }, + }, + fields: fields, + }) + + const users = await remoteQuery(queryObject) + return users[0] +} diff --git a/packages/medusa/src/api-v2/admin/users/me/route.ts b/packages/medusa/src/api-v2/admin/users/me/route.ts index 7839785091..8deb874b54 100644 --- a/packages/medusa/src/api-v2/admin/users/me/route.ts +++ b/packages/medusa/src/api-v2/admin/users/me/route.ts @@ -22,7 +22,7 @@ export const GET = async ( const query = remoteQueryObjectFromString({ entryPoint: "user", variables: { id }, - fields: req.retrieveConfig.select as string[], + fields: req.remoteQueryConfig.fields, }) const [user] = await remoteQuery(query) diff --git a/packages/medusa/src/api-v2/admin/users/middlewares.ts b/packages/medusa/src/api-v2/admin/users/middlewares.ts index 1fcd15e911..0106d9cdbf 100644 --- a/packages/medusa/src/api-v2/admin/users/middlewares.ts +++ b/packages/medusa/src/api-v2/admin/users/middlewares.ts @@ -1,15 +1,16 @@ import * as QueryConfig from "./query-config" -import { transformBody, transformQuery } from "../../../api/middlewares" import { - AdminCreateUserRequest, + AdminCreateUser, + AdminGetUserParams, AdminGetUsersParams, - AdminGetUsersUserParams, - AdminUpdateUserRequest, + AdminUpdateUser, } from "./validators" import { MiddlewareRoute } from "../../../types/middlewares" import { authenticate } from "../../../utils/authenticate-middleware" +import { validateAndTransformQuery } from "../../utils/validate-query" +import { validateAndTransformBody } from "../../utils/validate-body" export const adminUserRoutesMiddlewares: MiddlewareRoute[] = [ { @@ -17,7 +18,10 @@ export const adminUserRoutesMiddlewares: MiddlewareRoute[] = [ matcher: "/admin/users", middlewares: [ authenticate("admin", ["bearer", "session"]), - transformQuery(AdminGetUsersParams, QueryConfig.listTransformQueryConfig), + validateAndTransformQuery( + AdminGetUsersParams, + QueryConfig.listTransformQueryConfig + ), ], }, { @@ -25,7 +29,11 @@ export const adminUserRoutesMiddlewares: MiddlewareRoute[] = [ matcher: "/admin/users", middlewares: [ authenticate("admin", ["bearer", "session"], { allowUnregistered: true }), - transformBody(AdminCreateUserRequest), + validateAndTransformBody(AdminCreateUser), + validateAndTransformQuery( + AdminGetUserParams, + QueryConfig.retrieveTransformQueryConfig + ), ], }, { @@ -33,8 +41,8 @@ export const adminUserRoutesMiddlewares: MiddlewareRoute[] = [ matcher: "/admin/users/:id", middlewares: [ authenticate("admin", ["bearer", "session"]), - transformQuery( - AdminGetUsersUserParams, + validateAndTransformQuery( + AdminGetUserParams, QueryConfig.retrieveTransformQueryConfig ), ], @@ -44,8 +52,8 @@ export const adminUserRoutesMiddlewares: MiddlewareRoute[] = [ matcher: "/admin/users/me", middlewares: [ authenticate("admin", ["bearer", "session"]), - transformQuery( - AdminGetUsersUserParams, + validateAndTransformQuery( + AdminGetUserParams, QueryConfig.retrieveTransformQueryConfig ), ], @@ -55,7 +63,16 @@ export const adminUserRoutesMiddlewares: MiddlewareRoute[] = [ matcher: "/admin/users/:id", middlewares: [ authenticate("admin", ["bearer", "session"]), - transformBody(AdminUpdateUserRequest), + validateAndTransformBody(AdminUpdateUser), + validateAndTransformQuery( + AdminGetUserParams, + QueryConfig.retrieveTransformQueryConfig + ), ], }, + { + method: ["DELETE"], + matcher: "/admin/users/:id", + middlewares: [authenticate("admin", ["bearer", "session"])], + }, ] diff --git a/packages/medusa/src/api-v2/admin/users/query-config.ts b/packages/medusa/src/api-v2/admin/users/query-config.ts index 78840a340b..77ed5670b8 100644 --- a/packages/medusa/src/api-v2/admin/users/query-config.ts +++ b/packages/medusa/src/api-v2/admin/users/query-config.ts @@ -1,5 +1,3 @@ -export const defaultAdminUserRelations = [] -export const allowedAdminUserRelations = [] export const defaultAdminUserFields = [ "id", "first_name", @@ -13,9 +11,7 @@ export const defaultAdminUserFields = [ ] export const retrieveTransformQueryConfig = { - defaultFields: defaultAdminUserFields, - defaultRelations: defaultAdminUserRelations, - allowedRelations: allowedAdminUserRelations, + defaults: defaultAdminUserFields, isList: false, } diff --git a/packages/medusa/src/api-v2/admin/users/route.ts b/packages/medusa/src/api-v2/admin/users/route.ts index a078cb3ff2..9033b6b4ed 100644 --- a/packages/medusa/src/api-v2/admin/users/route.ts +++ b/packages/medusa/src/api-v2/admin/users/route.ts @@ -1,6 +1,5 @@ import { createUserAccountWorkflow } from "@medusajs/core-flows" -import { ModuleRegistrationName } from "@medusajs/modules-sdk" -import { CreateUserDTO, IAuthModuleService } from "@medusajs/types" +import { CreateUserDTO } from "@medusajs/types" import { ContainerRegistrationKeys, MedusaError, @@ -11,6 +10,7 @@ import { AuthenticatedMedusaRequest, MedusaResponse, } from "../../../types/routing" +import { refetchUser } from "./helpers" export const GET = async ( req: AuthenticatedMedusaRequest, @@ -22,17 +22,12 @@ export const GET = async ( entryPoint: "user", variables: { filters: req.filterableFields, - order: req.listConfig.order, - skip: req.listConfig.skip, - take: req.listConfig.take, + ...req.remoteQueryConfig.pagination, }, - fields: req.listConfig.select as string[], - }) - - const { rows: users, metadata } = await remoteQuery({ - ...query, + fields: req.remoteQueryConfig.fields, }) + const { rows: users, metadata } = await remoteQuery(query) res.status(200).json({ users, count: metadata.count, @@ -45,10 +40,6 @@ export const POST = async ( req: AuthenticatedMedusaRequest, res: MedusaResponse ) => { - const authModuleService = req.scope.resolve( - ModuleRegistrationName.AUTH - ) - // If `actor_id` is present, the request carries authentication for an existing user if (req.auth.actor_id) { throw new MedusaError( @@ -65,10 +56,16 @@ export const POST = async ( } const { result } = await createUserAccountWorkflow(req.scope).run(input) + const user = await refetchUser( + req.auth.auth_user_id, + req.scope, + req.remoteQueryConfig.fields + ) - const { jwt_secret } = req.scope.resolve("configModule").projectConfig - const authUser = await authModuleService.retrieve(req.auth.auth_user_id) - const token = jwt.sign(authUser, jwt_secret) + const { jwt_secret } = req.scope.resolve( + ContainerRegistrationKeys.CONFIG_MODULE + ).projectConfig + const token = jwt.sign(user, jwt_secret) - res.status(200).json({ user: result, token }) + res.status(200).json({ user, token }) } diff --git a/packages/medusa/src/api-v2/admin/users/validators.ts b/packages/medusa/src/api-v2/admin/users/validators.ts index 22c539db2c..4d413d6bb0 100644 --- a/packages/medusa/src/api-v2/admin/users/validators.ts +++ b/packages/medusa/src/api-v2/admin/users/validators.ts @@ -1,112 +1,39 @@ -import { Type } from "class-transformer" -import { IsEmail, IsOptional, IsString, ValidateNested } from "class-validator" import { - DateComparisonOperator, - FindParams, - extendedFindParamsMixin, -} from "../../../types/common" -import { IsType } from "../../../utils" + createFindParams, + createOperatorMap, + createSelectParams, +} from "../../utils/validators" +import { z } from "zod" -export class AdminGetUsersUserParams extends FindParams {} +export const AdminGetUserParams = createSelectParams() -export class AdminGetUsersParams extends extendedFindParamsMixin({ - limit: 50, +export type AdminGetUsersParamsType = z.infer +export const AdminGetUsersParams = createFindParams({ offset: 0, -}) { - /** - * IDs to filter users by. - */ - @IsOptional() - @IsType([String, [String]]) - id?: string | string[] + limit: 50, +}).merge( + z.object({ + id: z.union([z.string(), z.array(z.string())]).optional(), + created_at: createOperatorMap().optional(), + updated_at: createOperatorMap().optional(), + deleted_at: createOperatorMap().optional(), + email: z.string().optional(), + first_name: z.string().optional(), + last_name: z.string().optional(), + }) +) - /** - * The field to sort the data by. By default, the sort order is ascending. To change the order to descending, prefix the field name with `-`. - */ - @IsString() - @IsOptional() - order?: string +export type AdminCreateUserType = z.infer +export const AdminCreateUser = z.object({ + email: z.string(), + first_name: z.string().optional(), + last_name: z.string().optional(), + avatar_url: z.string().optional(), +}) - /** - * Date filters to apply on the users' `update_at` date. - */ - @IsOptional() - @ValidateNested() - @Type(() => DateComparisonOperator) - updated_at?: DateComparisonOperator - - /** - * Date filters to apply on the customer users' `created_at` date. - */ - @IsOptional() - @ValidateNested() - @Type(() => DateComparisonOperator) - created_at?: DateComparisonOperator - - /** - * Date filters to apply on the users' `deleted_at` date. - */ - @IsOptional() - @ValidateNested() - @Type(() => DateComparisonOperator) - deleted_at?: DateComparisonOperator - - /** - * Filter to apply on the users' `email` field. - */ - @IsOptional() - @IsString() - email?: string - - /** - * Filter to apply on the users' `first_name` field. - */ - @IsOptional() - @IsString() - first_name?: string - - /** - * Filter to apply on the users' `last_name` field. - */ - @IsOptional() - @IsString() - last_name?: string - - /** - * Comma-separated fields that should be included in the returned users. - */ - @IsOptional() - @IsString() - fields?: string -} - -export class AdminCreateUserRequest { - @IsEmail() - email: string - - @IsOptional() - @IsString() - first_name?: string - - @IsOptional() - @IsString() - last_name?: string - - @IsString() - @IsOptional() - avatar_url: string -} - -export class AdminUpdateUserRequest { - @IsString() - @IsOptional() - first_name?: string - - @IsString() - @IsOptional() - last_name?: string - - @IsString() - @IsOptional() - avatar_url: string -} +export type AdminUpdateUserType = z.infer +export const AdminUpdateUser = z.object({ + first_name: z.string().optional(), + last_name: z.string().optional(), + avatar_url: z.string().optional(), +}) diff --git a/packages/medusa/src/api-v2/admin/workflows-executions/[id]/route.ts b/packages/medusa/src/api-v2/admin/workflows-executions/[id]/route.ts index 3583725e2c..af5aa68152 100644 --- a/packages/medusa/src/api-v2/admin/workflows-executions/[id]/route.ts +++ b/packages/medusa/src/api-v2/admin/workflows-executions/[id]/route.ts @@ -3,25 +3,25 @@ import { MedusaResponse, } from "../../../../types/routing" -import { IWorkflowEngineService } from "@medusajs/workflows-sdk" -import { ModuleRegistrationName } from "@medusajs/modules-sdk" +import { AdminGetWorkflowExecutionDetailsParamsType } from "../validators" +import { + ContainerRegistrationKeys, + remoteQueryObjectFromString, +} from "@medusajs/utils" export const GET = async ( - req: AuthenticatedMedusaRequest, + req: AuthenticatedMedusaRequest, res: MedusaResponse ) => { - const workflowEngineService: IWorkflowEngineService = req.scope.resolve( - ModuleRegistrationName.WORKFLOW_ENGINE - ) + const remoteQuery = req.scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY) + const variables = { id: req.params.id } - const { id } = req.params - - const execution = await workflowEngineService.retrieveWorkflowExecution(id, { - select: req.retrieveConfig.select, - relations: req.retrieveConfig.relations, + const queryObject = remoteQueryObjectFromString({ + entryPoint: "workflow_execution", + variables, + fields: req.remoteQueryConfig.fields, }) - res.status(200).json({ - workflow_execution: execution, - }) + const [workflowExecution] = await remoteQuery(queryObject) + res.status(200).json({ workflow_execution: workflowExecution }) } diff --git a/packages/medusa/src/api-v2/admin/workflows-executions/[workflow_id]/[transaction_id]/route.ts b/packages/medusa/src/api-v2/admin/workflows-executions/[workflow_id]/[transaction_id]/route.ts index 0301e8282a..add7ebb693 100644 --- a/packages/medusa/src/api-v2/admin/workflows-executions/[workflow_id]/[transaction_id]/route.ts +++ b/packages/medusa/src/api-v2/admin/workflows-executions/[workflow_id]/[transaction_id]/route.ts @@ -3,31 +3,28 @@ import { MedusaResponse, } from "../../../../../types/routing" -import { IWorkflowEngineService } from "@medusajs/workflows-sdk" -import { ModuleRegistrationName } from "@medusajs/modules-sdk" +import { + ContainerRegistrationKeys, + remoteQueryObjectFromString, +} from "@medusajs/utils" +import { AdminGetWorkflowExecutionDetailsParamsType } from "../../validators" export const GET = async ( - req: AuthenticatedMedusaRequest, + req: AuthenticatedMedusaRequest, res: MedusaResponse ) => { - const workflowEngineService: IWorkflowEngineService = req.scope.resolve( - ModuleRegistrationName.WORKFLOW_ENGINE - ) + const remoteQuery = req.scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY) const { workflow_id, transaction_id } = req.params + const variables = { workflow_id, transaction_id } - const execution = await workflowEngineService.retrieveWorkflowExecution( - { - workflow_id, - transaction_id, - }, - { - select: req.retrieveConfig.select, - relations: req.retrieveConfig.relations, - } - ) - - res.status(200).json({ - workflow_execution: execution, + const queryObject = remoteQueryObjectFromString({ + entryPoint: "workflow_execution", + variables, + fields: req.remoteQueryConfig.fields, }) + + const [workflowExecution] = await remoteQuery(queryObject) + + res.status(200).json({ workflow_execution: workflowExecution }) } diff --git a/packages/medusa/src/api-v2/admin/workflows-executions/[workflow_id]/run/route.ts b/packages/medusa/src/api-v2/admin/workflows-executions/[workflow_id]/run/route.ts index 1f33140f9e..1e95da82b9 100644 --- a/packages/medusa/src/api-v2/admin/workflows-executions/[workflow_id]/run/route.ts +++ b/packages/medusa/src/api-v2/admin/workflows-executions/[workflow_id]/run/route.ts @@ -7,11 +7,11 @@ import { WorkflowOrchestratorTypes, } from "@medusajs/workflows-sdk" -import { AdminPostWorkflowsRunReq } from "../../validators" import { ModuleRegistrationName } from "@medusajs/modules-sdk" +import { AdminCreateWorkflowsRunType } from "../../validators" export const POST = async ( - req: AuthenticatedMedusaRequest, + req: AuthenticatedMedusaRequest, res: MedusaResponse ) => { const workflowEngineService: IWorkflowEngineService = req.scope.resolve( diff --git a/packages/medusa/src/api-v2/admin/workflows-executions/[workflow_id]/steps/failure/route.ts b/packages/medusa/src/api-v2/admin/workflows-executions/[workflow_id]/steps/failure/route.ts index 20c4fecaee..e69274b1d8 100644 --- a/packages/medusa/src/api-v2/admin/workflows-executions/[workflow_id]/steps/failure/route.ts +++ b/packages/medusa/src/api-v2/admin/workflows-executions/[workflow_id]/steps/failure/route.ts @@ -5,11 +5,11 @@ import { import { IWorkflowEngineService, StepResponse } from "@medusajs/workflows-sdk" import { TransactionHandlerType, isDefined } from "@medusajs/utils" -import { AdminPostWorkflowsAsyncResponseReq } from "../../../validators" import { ModuleRegistrationName } from "@medusajs/modules-sdk" +import { AdminCreateWorkflowsAsyncResponseType } from "../../../validators" export const POST = async ( - req: AuthenticatedMedusaRequest, + req: AuthenticatedMedusaRequest, res: MedusaResponse ) => { const workflowEngineService: IWorkflowEngineService = req.scope.resolve( diff --git a/packages/medusa/src/api-v2/admin/workflows-executions/[workflow_id]/steps/success/route.ts b/packages/medusa/src/api-v2/admin/workflows-executions/[workflow_id]/steps/success/route.ts index 53d88f8610..2820f39c89 100644 --- a/packages/medusa/src/api-v2/admin/workflows-executions/[workflow_id]/steps/success/route.ts +++ b/packages/medusa/src/api-v2/admin/workflows-executions/[workflow_id]/steps/success/route.ts @@ -5,11 +5,11 @@ import { import { IWorkflowEngineService, StepResponse } from "@medusajs/workflows-sdk" import { TransactionHandlerType, isDefined } from "@medusajs/utils" -import { AdminPostWorkflowsAsyncResponseReq } from "../../../validators" import { ModuleRegistrationName } from "@medusajs/modules-sdk" +import { AdminCreateWorkflowsAsyncResponseType } from "../../../validators" export const POST = async ( - req: AuthenticatedMedusaRequest, + req: AuthenticatedMedusaRequest, res: MedusaResponse ) => { const workflowEngineService: IWorkflowEngineService = req.scope.resolve( diff --git a/packages/medusa/src/api-v2/admin/workflows-executions/middlewares.ts b/packages/medusa/src/api-v2/admin/workflows-executions/middlewares.ts index 40a8d8cbee..0a90fe3c8a 100644 --- a/packages/medusa/src/api-v2/admin/workflows-executions/middlewares.ts +++ b/packages/medusa/src/api-v2/admin/workflows-executions/middlewares.ts @@ -1,27 +1,28 @@ import * as QueryConfig from "./query-config" import { + AdminCreateWorkflowsAsyncResponse, + AdminCreateWorkflowsRun, AdminGetWorkflowExecutionDetailsParams, AdminGetWorkflowExecutionsParams, - AdminPostWorkflowsAsyncResponseReq, - AdminPostWorkflowsRunReq, } from "./validators" -import { transformBody, transformQuery } from "../../../api/middlewares" import { MiddlewareRoute } from "../../../loaders/helpers/routing/types" import { authenticate } from "../../../utils/authenticate-middleware" +import { validateAndTransformQuery } from "../../utils/validate-query" +import { validateAndTransformBody } from "../../utils/validate-body" export const adminWorkflowsExecutionsMiddlewares: MiddlewareRoute[] = [ { method: ["ALL"], matcher: "/admin/workflows-executions*", - middlewares: [authenticate("admin", ["bearer", "session"])], + middlewares: [authenticate("admin", ["bearer", "session", "api-key"])], }, { method: ["GET"], matcher: "/admin/workflows-executions", middlewares: [ - transformQuery( + validateAndTransformQuery( AdminGetWorkflowExecutionsParams, QueryConfig.listTransformQueryConfig ), @@ -31,7 +32,7 @@ export const adminWorkflowsExecutionsMiddlewares: MiddlewareRoute[] = [ method: ["GET"], matcher: "/admin/workflows-executions/:id", middlewares: [ - transformQuery( + validateAndTransformQuery( AdminGetWorkflowExecutionDetailsParams, QueryConfig.retrieveTransformQueryConfig ), @@ -41,7 +42,7 @@ export const adminWorkflowsExecutionsMiddlewares: MiddlewareRoute[] = [ method: ["GET"], matcher: "/admin/workflows-executions/:workflow_id/:transaction_id", middlewares: [ - transformQuery( + validateAndTransformQuery( AdminGetWorkflowExecutionDetailsParams, QueryConfig.retrieveTransformQueryConfig ), @@ -50,17 +51,17 @@ export const adminWorkflowsExecutionsMiddlewares: MiddlewareRoute[] = [ { method: ["POST"], matcher: "/admin/workflows-executions/:id/run", - middlewares: [transformBody(AdminPostWorkflowsRunReq)], + middlewares: [validateAndTransformBody(AdminCreateWorkflowsRun)], }, { method: ["POST"], matcher: "/admin/workflows-executions/:id/steps/success", - middlewares: [transformBody(AdminPostWorkflowsAsyncResponseReq)], + middlewares: [validateAndTransformBody(AdminCreateWorkflowsAsyncResponse)], }, { method: ["POST"], matcher: "/admin/workflows-executions/:id/steps/failure", - middlewares: [transformBody(AdminPostWorkflowsAsyncResponseReq)], + middlewares: [validateAndTransformBody(AdminCreateWorkflowsAsyncResponse)], }, ] diff --git a/packages/medusa/src/api-v2/admin/workflows-executions/query-config.ts b/packages/medusa/src/api-v2/admin/workflows-executions/query-config.ts index 3fd0fb7a18..46aca00b78 100644 --- a/packages/medusa/src/api-v2/admin/workflows-executions/query-config.ts +++ b/packages/medusa/src/api-v2/admin/workflows-executions/query-config.ts @@ -1,15 +1,3 @@ -export const defaultAdminWorkflowExecutionsRelations = [] -export const allowedAdminWorkflowExecutionsRelations = [] -export const defaultAdminWorkflowExecutionsFields = [ - "id", - "workflow_id", - "transaction_id", - "state", - "created_at", - "updated_at", - "deleted_at", -] - export const defaultAdminWorkflowExecutionDetailFields = [ "id", "workflow_id", @@ -22,15 +10,23 @@ export const defaultAdminWorkflowExecutionDetailFields = [ "deleted_at", ] +export const defaultAdminWorkflowExecutionsFields = [ + "id", + "workflow_id", + "transaction_id", + "state", + "created_at", + "updated_at", + "deleted_at", +] + export const retrieveTransformQueryConfig = { - defaultFields: defaultAdminWorkflowExecutionDetailFields, - defaultRelations: defaultAdminWorkflowExecutionsRelations, - allowedRelations: allowedAdminWorkflowExecutionsRelations, + defaults: defaultAdminWorkflowExecutionDetailFields, isList: false, } export const listTransformQueryConfig = { ...retrieveTransformQueryConfig, - defaultFields: defaultAdminWorkflowExecutionsFields, + defaults: defaultAdminWorkflowExecutionsFields, isList: true, } diff --git a/packages/medusa/src/api-v2/admin/workflows-executions/route.ts b/packages/medusa/src/api-v2/admin/workflows-executions/route.ts index 5caaeb7b3e..d8561574e2 100644 --- a/packages/medusa/src/api-v2/admin/workflows-executions/route.ts +++ b/packages/medusa/src/api-v2/admin/workflows-executions/route.ts @@ -3,34 +3,33 @@ import { MedusaResponse, } from "../../../types/routing" -import { IWorkflowEngineService } from "@medusajs/workflows-sdk" -import { ModuleRegistrationName } from "@medusajs/modules-sdk" +import { AdminGetWorkflowExecutionsParamsType } from "./validators" +import { + ContainerRegistrationKeys, + remoteQueryObjectFromString, +} from "@medusajs/utils" export const GET = async ( - req: AuthenticatedMedusaRequest, + req: AuthenticatedMedusaRequest, res: MedusaResponse ) => { - const workflowEngineService: IWorkflowEngineService = req.scope.resolve( - ModuleRegistrationName.WORKFLOW_ENGINE - ) + const remoteQuery = req.scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY) - const listConfig = req.listConfig + const queryObject = remoteQueryObjectFromString({ + entryPoint: "workflow_execution", + variables: { + filters: req.filterableFields, + ...req.remoteQueryConfig.pagination, + }, + fields: req.remoteQueryConfig.fields, + }) - const [workflow_executions, count] = - await workflowEngineService.listAndCountWorkflowExecution( - req.filterableFields, - { - select: req.listConfig.select, - relations: req.listConfig.relations, - skip: listConfig.skip, - take: listConfig.take, - } - ) + const { rows: workflowExecutions, metadata } = await remoteQuery(queryObject) res.json({ - workflow_executions, - count, - offset: listConfig.skip, - limit: listConfig.take, + workflow_executions: workflowExecutions, + count: metadata.count, + offset: metadata.skip, + limit: metadata.take, }) } diff --git a/packages/medusa/src/api-v2/admin/workflows-executions/validators.ts b/packages/medusa/src/api-v2/admin/workflows-executions/validators.ts index 27da3231fa..0b83ff7722 100644 --- a/packages/medusa/src/api-v2/admin/workflows-executions/validators.ts +++ b/packages/medusa/src/api-v2/admin/workflows-executions/validators.ts @@ -1,54 +1,46 @@ import { TransactionHandlerType } from "@medusajs/utils" -import { Transform } from "class-transformer" -import { IsEnum, IsOptional, IsString } from "class-validator" -import { FindParams, extendedFindParamsMixin } from "../../../types/common" -import { IsType } from "../../../utils" +import { createFindParams, createSelectParams } from "../../utils/validators" +import { z } from "zod" -export class AdminGetWorkflowExecutionDetailsParams extends FindParams {} +export type AdminGetWorkflowExecutionDetailsParamsType = z.infer< + typeof AdminGetWorkflowExecutionDetailsParams +> -export class AdminGetWorkflowExecutionsParams extends extendedFindParamsMixin({ - limit: 100, +export const AdminGetWorkflowExecutionDetailsParams = createSelectParams() + +export type AdminGetWorkflowExecutionsParamsType = z.infer< + typeof AdminGetWorkflowExecutionsParams +> +export const AdminGetWorkflowExecutionsParams = createFindParams({ offset: 0, -}) { - /** - * transaction id(s) to filter workflow executions by transaction_id. - */ - @IsOptional() - @IsType([String, [String]]) - transaction_id?: string | string[] + limit: 100, +}).merge( + z.object({ + transaction_id: z.union([z.string(), z.array(z.string())]).optional(), + workflow_id: z.union([z.string(), z.array(z.string())]).optional(), + }) +) - /** - * workflow id(s) to filter workflow executions by workflow_id - */ - @IsOptional() - @IsType([String, [String]]) - workflow_id?: string | string[] -} +export type AdminCreateWorkflowsRunType = z.infer< + typeof AdminCreateWorkflowsRun +> +export const AdminCreateWorkflowsRun = z.object({ + input: z.any().optional(), + transaction_id: z.string().optional(), +}) -export class AdminPostWorkflowsRunReq { - @IsOptional() - input?: unknown - - @IsOptional() - @IsString() - transaction_id?: string -} - -export class AdminPostWorkflowsAsyncResponseReq { - @IsString() - transaction_id: string - - @IsString() - step_id: string - - @IsOptional() - response?: unknown - - @IsOptional() - compensate_input?: unknown - - @IsOptional() - @Transform(({ value }) => (value + "").toLowerCase()) - @IsEnum(TransactionHandlerType) - action?: TransactionHandlerType -} +export type AdminCreateWorkflowsAsyncResponseType = z.infer< + typeof AdminCreateWorkflowsAsyncResponse +> +export const AdminCreateWorkflowsAsyncResponse = z.object({ + transaction_id: z.string(), + step_id: z.string(), + response: z.any().optional(), + compensate_input: z.any().optional(), + action: z + .preprocess( + (val: any) => (val + "").toLowerCase(), + z.nativeEnum(TransactionHandlerType).optional() + ) + .optional(), +})