{
  "$schema": "https://registry.mercurjs.com/registry-item.json",
  "name": "requests",
  "description": "Admin approval system powered by the Custom Fields module. Admins can list, review, accept or reject entity requests.",
  "dependencies": [],
  "registryDependencies": [],
  "docs": "## Prerequisites\n\nThis block requires the **Custom Fields module** (`@mercurjs/core/modules/custom-fields`). Make sure it is registered in your `medusa-config.ts`.\n\n## Configuration\n\nAdd request-related custom fields to the entities you want to support approval workflows for. Product already has a built-in `status` field, so you only need to configure custom fields for other entities.\n\nAdd these fields to your Custom Fields module options in `medusa-config.ts`:\n\n```ts\n{\n  resolve: \"@mercurjs/core/modules/custom-fields\",\n  options: {\n    customFields: {\n      ProductCollection: {\n        request_status: {\n          type: \"enum\",\n          enum: [\"draft\", \"pending\", \"accepted\", \"rejected\"],\n          defaultValue: \"draft\",\n        },\n        submitter_id: { type: \"string\", nullable: true },\n        reviewer_id: { type: \"string\", nullable: true },\n        reviewer_note: { type: \"text\", nullable: true },\n      },\n      // Add the same fields to other entities as needed:\n      // ProductCategory, ProductType, ProductTag\n    },\n  },\n}\n```\n\n## Middlewares\n\nAdd the request middlewares to your `api/middlewares.ts`:\n\n```ts\nimport { defineMiddlewares } from \"@medusajs/medusa\";\nimport { adminRequestsMiddlewares } from \"./admin/requests/middlewares\";\nimport { vendorProductCollectionRequestsMiddlewares } from \"./vendor/requests/product-collections/middlewares\";\nimport { vendorProductCategoryRequestsMiddlewares } from \"./vendor/requests/product-categories/middlewares\";\nimport { vendorProductTypeRequestsMiddlewares } from \"./vendor/requests/product-types/middlewares\";\nimport { vendorProductTagRequestsMiddlewares } from \"./vendor/requests/product-tags/middlewares\";\n\nexport default defineMiddlewares({\n  routes: [\n    ...adminRequestsMiddlewares,\n    ...vendorProductCollectionRequestsMiddlewares,\n    ...vendorProductCategoryRequestsMiddlewares,\n    ...vendorProductTypeRequestsMiddlewares,\n    ...vendorProductTagRequestsMiddlewares,\n  ],\n});\n```\n\nIf you already have a `middlewares.ts` file, merge the middleware imports and spread them into your existing `routes` array.\n\n## Database Migrations\n\nAfter updating the custom fields configuration, run migrations:\n\n```bash\nnpx medusa db:migrate\n```\n\n## Run codegen\n\nAfter installing the block, regenerate SDK types:\n\n```bash\nnpx @mercurjs/cli@latest codegen\n```\n\n## API Endpoints\n\n### Admin\n\n- `GET /admin/requests/:type` — List entities with request custom fields (filterable by `request_status`, `submitter_id`)\n- `GET /admin/requests/:type/:id` — Retrieve entity with request custom fields\n- `POST /admin/requests/:type/:id/accept` — Accept a request\n- `POST /admin/requests/:type/:id/reject` — Reject a request\n\nSupported `:type` values: `product_collection`, `product_category`, `product_type`, `product_tag`\n\n### Vendor\n\n- `GET /vendor/requests/product-collections` — List vendor's collection requests\n- `POST /vendor/requests/product-collections` — Create a collection request\n- `GET /vendor/requests/product-categories` — List vendor's category requests\n- `POST /vendor/requests/product-categories` — Create a category request\n- `GET /vendor/requests/product-types` — List vendor's type requests\n- `POST /vendor/requests/product-types` — Create a type request\n- `GET /vendor/requests/product-tags` — List vendor's tag requests\n- `POST /vendor/requests/product-tags` — Create a tag request",
  "categories": [
    "api",
    "workflow"
  ],
  "files": [
    {
      "path": "requests/types/index.ts",
      "content": "import { PaginatedResponse } from \"@mercurjs/types\"\n\nexport enum RequestStatus {\n  DRAFT = \"draft\",\n  PENDING = \"pending\",\n  ACCEPTED = \"accepted\",\n  REJECTED = \"rejected\",\n}\n\nexport interface RequestCustomFields {\n  id: string\n  request_status: RequestStatus\n  submitter_id: string | null\n  reviewer_id: string | null\n  reviewer_note: string | null\n  created_at: Date\n  updated_at: Date\n}\n\nexport interface RequestEntityResponse {\n  id: string\n  custom_fields: RequestCustomFields\n  [key: string]: unknown\n}\n\nexport interface AdminRequestResponse {\n  request: RequestEntityResponse\n}\n\nexport type AdminRequestListResponse = PaginatedResponse<{\n  requests: RequestEntityResponse[]\n}>\n\nexport interface VendorRequestResponse {\n  request: RequestEntityResponse\n}\n\nexport type VendorRequestListResponse = PaginatedResponse<{\n  requests: RequestEntityResponse[]\n}>\n",
      "type": "registry:api"
    },
    {
      "path": "requests/workflows/requests/steps/index.ts",
      "content": "export { validateRequestStatusStep } from \"./validate-request-status\"\n",
      "type": "registry:api"
    },
    {
      "path": "requests/workflows/requests/steps/validate-request-status.ts",
      "content": "import { createStep } from \"@medusajs/framework/workflows-sdk\"\nimport { ContainerRegistrationKeys, MedusaError } from \"@medusajs/framework/utils\"\n\nimport { RequestStatus } from \"../../../types\"\nimport { Query } from \"@mercurjs/types\"\n\ntype ValidateRequestStatusStepInput = {\n  alias: string\n  entity_id: string\n  expected_status: RequestStatus | RequestStatus[]\n}\n\nexport const validateRequestStatusStep = createStep(\n  \"validate-request-status\",\n  async (input: ValidateRequestStatusStepInput, { container }) => {\n    const query = container.resolve<Query>(ContainerRegistrationKeys.QUERY)\n\n    const {\n      data: [entity],\n    } = await query.graph({\n      entity: input.alias,\n      fields: [\"id\", \"custom_fields.*\"],\n      filters: { id: input.entity_id },\n    })\n\n    if (!entity) {\n      throw new MedusaError(MedusaError.Types.NOT_FOUND, \"Request not found\")\n    }\n\n    const status = (entity as any).custom_fields?.request_status\n\n    const expected = Array.isArray(input.expected_status)\n      ? input.expected_status\n      : [input.expected_status]\n\n    if (!expected.includes(status)) {\n      throw new MedusaError(\n        MedusaError.Types.INVALID_DATA,\n        `Request status must be ${expected.join(\" or \")}, but is ${status}`\n      )\n    }\n  }\n)\n",
      "type": "registry:api"
    },
    {
      "path": "requests/workflows/requests/workflows/index.ts",
      "content": "export { acceptRequestWorkflow } from \"./accept-request\"\nexport { rejectRequestWorkflow } from \"./reject-request\"\nexport { createProductCollectionRequestWorkflow } from \"./create-product-collection-request\"\nexport { createProductCategoryRequestWorkflow } from \"./create-product-category-request\"\nexport { createProductTypeRequestWorkflow } from \"./create-product-type-request\"\nexport { createProductTagRequestWorkflow } from \"./create-product-tag-request\"\n",
      "type": "registry:api"
    },
    {
      "path": "requests/workflows/requests/workflows/accept-request.ts",
      "content": "import { createWorkflow, WorkflowResponse } from \"@medusajs/framework/workflows-sdk\"\nimport { upsertCustomFieldsStep } from \"@mercurjs/core/workflows\"\n\nimport { RequestStatus } from \"../../../types\"\nimport { validateRequestStatusStep } from \"../steps\"\n\ntype AcceptRequestWorkflowInput = {\n  alias: string\n  entity_id: string\n  reviewer_id: string\n  reviewer_note?: string\n}\n\nexport const acceptRequestWorkflow = createWorkflow(\n  \"accept-request\",\n  (input: AcceptRequestWorkflowInput) => {\n    validateRequestStatusStep({\n      alias: input.alias,\n      entity_id: input.entity_id,\n      expected_status: RequestStatus.PENDING,\n    })\n\n    const result = upsertCustomFieldsStep({\n      alias: input.alias,\n      data: {\n        id: input.entity_id,\n        request_status: RequestStatus.ACCEPTED,\n        reviewer_id: input.reviewer_id,\n        reviewer_note: input.reviewer_note ?? null,\n      },\n    })\n\n    return new WorkflowResponse(result)\n  }\n)\n",
      "type": "registry:api"
    },
    {
      "path": "requests/workflows/requests/workflows/reject-request.ts",
      "content": "import { createWorkflow, WorkflowResponse } from \"@medusajs/framework/workflows-sdk\"\nimport { upsertCustomFieldsStep } from \"@mercurjs/core/workflows\"\n\nimport { RequestStatus } from \"../../../types\"\nimport { validateRequestStatusStep } from \"../steps\"\n\ntype RejectRequestWorkflowInput = {\n  alias: string\n  entity_id: string\n  reviewer_id: string\n  reviewer_note?: string\n}\n\nexport const rejectRequestWorkflow = createWorkflow(\n  \"reject-request\",\n  (input: RejectRequestWorkflowInput) => {\n    validateRequestStatusStep({\n      alias: input.alias,\n      entity_id: input.entity_id,\n      expected_status: RequestStatus.PENDING,\n    })\n\n    const result = upsertCustomFieldsStep({\n      alias: input.alias,\n      data: {\n        id: input.entity_id,\n        request_status: RequestStatus.REJECTED,\n        reviewer_id: input.reviewer_id,\n        reviewer_note: input.reviewer_note ?? null,\n      },\n    })\n\n    return new WorkflowResponse(result)\n  }\n)\n",
      "type": "registry:api"
    },
    {
      "path": "requests/workflows/requests/workflows/create-product-collection-request.ts",
      "content": "import { createWorkflow, transform, WorkflowResponse } from \"@medusajs/framework/workflows-sdk\"\nimport { createCollectionsWorkflow } from \"@medusajs/medusa/core-flows\"\nimport { upsertCustomFieldsStep } from \"@mercurjs/core/workflows\"\n\nimport { RequestStatus } from \"../../../types\"\n\ntype CreateProductCollectionRequestWorkflowInput = {\n  product_collection: {\n    title: string\n    handle?: string\n    metadata?: Record<string, unknown>\n  }\n  submitter_id: string\n}\n\nexport const createProductCollectionRequestWorkflow = createWorkflow(\n  \"create-product-collection-request\",\n  function (input: CreateProductCollectionRequestWorkflowInput) {\n    const collections = createCollectionsWorkflow.runAsStep({\n      input: {\n        collections: [input.product_collection],\n      },\n    })\n\n    const upsertInput = transform({ collections, input }, (data) => ({\n      alias: \"product_collection\",\n      data: {\n        id: data.collections[0]!.id,\n        request_status: RequestStatus.PENDING,\n        submitter_id: data.input.submitter_id,\n      },\n    }))\n\n    upsertCustomFieldsStep(upsertInput)\n\n    const collection = transform({ collections }, (data) => data.collections[0]!)\n\n    return new WorkflowResponse(collection)\n  }\n)\n",
      "type": "registry:api"
    },
    {
      "path": "requests/api/admin/requests/validators.ts",
      "content": "import { z } from \"zod\"\nimport { createFindParams, createOperatorMap } from \"@medusajs/medusa/api/utils/validators\"\nimport { RequestStatus } from \"../../../types\"\n\nexport type AdminGetRequestsParamsType = z.infer<typeof AdminGetRequestsParams>\nexport const AdminGetRequestsParams = createFindParams({\n  offset: 0,\n  limit: 50,\n}).extend({\n  request_status: z\n    .union([z.nativeEnum(RequestStatus), z.array(z.nativeEnum(RequestStatus))])\n    .optional(),\n  submitter_id: z.union([z.string(), z.array(z.string())]).optional(),\n  created_at: createOperatorMap().optional(),\n  updated_at: createOperatorMap().optional(),\n})\n\nexport type AdminReviewNoteType = z.infer<typeof AdminReviewNote>\nexport const AdminReviewNote = z.object({\n  reviewer_note: z.string().optional(),\n})\n",
      "type": "registry:api"
    },
    {
      "path": "requests/api/admin/requests/query-config.ts",
      "content": "export const adminRequestFields = [\n  \"id\",\n  \"name\",\n  \"title\",\n  \"handle\",\n  \"value\",\n  \"description\",\n  \"is_active\",\n  \"is_internal\",\n  \"custom_fields.*\",\n  \"created_at\",\n  \"updated_at\",\n]\n\nexport const adminRequestQueryConfig = {\n  list: {\n    defaults: adminRequestFields,\n    isList: true,\n  },\n  retrieve: {\n    defaults: adminRequestFields,\n    isList: false,\n  },\n}\n",
      "type": "registry:api"
    },
    {
      "path": "requests/api/admin/requests/middlewares.ts",
      "content": "import {\n  validateAndTransformBody,\n  validateAndTransformQuery,\n} from \"@medusajs/framework\"\nimport { MiddlewareRoute } from \"@medusajs/medusa\"\n\nimport { adminRequestQueryConfig } from \"./query-config\"\nimport { AdminGetRequestsParams, AdminReviewNote } from \"./validators\"\n\nexport const adminRequestsMiddlewares: MiddlewareRoute[] = [\n  {\n    method: [\"GET\"],\n    matcher: \"/admin/requests/:type\",\n    middlewares: [\n      validateAndTransformQuery(\n        AdminGetRequestsParams,\n        adminRequestQueryConfig.list\n      ),\n    ],\n  },\n  {\n    method: [\"GET\"],\n    matcher: \"/admin/requests/:type/:id\",\n    middlewares: [\n      validateAndTransformQuery(\n        AdminGetRequestsParams,\n        adminRequestQueryConfig.retrieve\n      ),\n    ],\n  },\n  {\n    method: [\"POST\"],\n    matcher: \"/admin/requests/:type/:id/accept\",\n    middlewares: [\n      validateAndTransformBody(AdminReviewNote),\n    ],\n  },\n  {\n    method: [\"POST\"],\n    matcher: \"/admin/requests/:type/:id/reject\",\n    middlewares: [\n      validateAndTransformBody(AdminReviewNote),\n    ],\n  },\n]\n",
      "type": "registry:api"
    },
    {
      "path": "requests/api/admin/requests/[type]/route.ts",
      "content": "import { AuthenticatedMedusaRequest, MedusaResponse } from \"@medusajs/framework\"\nimport { ContainerRegistrationKeys } from \"@medusajs/framework/utils\"\n\nimport { AdminRequestListResponse } from \"../../../../types\"\nimport { AdminGetRequestsParamsType } from \"../validators\"\n\nexport async function GET(\n  req: AuthenticatedMedusaRequest<AdminGetRequestsParamsType>,\n  res: MedusaResponse<AdminRequestListResponse>\n): Promise<void> {\n  const query = req.scope.resolve(ContainerRegistrationKeys.QUERY)\n\n  const alias = req.params.type!\n\n  const { data: entities, metadata } = await query.graph({\n    entity: alias,\n    fields: req.queryConfig.fields,\n    filters: req.filterableFields,\n    pagination: req.queryConfig.pagination,\n  })\n\n  res.json({\n    requests: entities,\n    count: metadata?.count ?? 0,\n    offset: metadata?.skip ?? 0,\n    limit: metadata?.take ?? 0,\n  })\n}\n",
      "type": "registry:api"
    },
    {
      "path": "requests/api/admin/requests/[type]/[id]/route.ts",
      "content": "import { AuthenticatedMedusaRequest, MedusaResponse } from \"@medusajs/framework\"\nimport { ContainerRegistrationKeys, MedusaError } from \"@medusajs/framework/utils\"\n\nimport { AdminRequestResponse } from \"../../../../../types\"\n\nexport async function GET(\n  req: AuthenticatedMedusaRequest,\n  res: MedusaResponse<AdminRequestResponse>\n): Promise<void> {\n  const query = req.scope.resolve(ContainerRegistrationKeys.QUERY)\n\n  const alias = req.params.type!\n\n  const {\n    data: [entity],\n  } = await query.graph({\n    entity: alias,\n    fields: [\"id\", \"custom_fields.*\", ...req.queryConfig.fields],\n    filters: { id: req.params.id },\n  })\n\n  if (!entity) {\n    throw new MedusaError(MedusaError.Types.NOT_FOUND, \"Request not found\")\n  }\n\n  res.json({ request: entity })\n}\n",
      "type": "registry:api"
    },
    {
      "path": "requests/api/admin/requests/[type]/[id]/accept/route.ts",
      "content": "import { AuthenticatedMedusaRequest, MedusaResponse } from \"@medusajs/framework\"\nimport { ContainerRegistrationKeys } from \"@medusajs/framework/utils\"\n\nimport { AdminRequestResponse } from \"../../../../../../types\"\nimport { acceptRequestWorkflow } from \"../../../../../../workflows/requests/workflows\"\nimport { AdminReviewNoteType } from \"../../../validators\"\n\nexport async function POST(\n  req: AuthenticatedMedusaRequest<AdminReviewNoteType>,\n  res: MedusaResponse<AdminRequestResponse>\n): Promise<void> {\n  const query = req.scope.resolve(ContainerRegistrationKeys.QUERY)\n\n  const alias = req.params.type!\n  const entityId = req.params.id!\n\n  await acceptRequestWorkflow(req.scope).run({\n    input: {\n      alias,\n      entity_id: entityId,\n      reviewer_id: req.auth_context.actor_id,\n      reviewer_note: req.validatedBody?.reviewer_note,\n    },\n  })\n\n  const {\n    data: [entity],\n  } = await query.graph({\n    entity: alias,\n    fields: [\"id\", \"custom_fields.*\"],\n    filters: { id: entityId },\n  })\n\n  res.json({ request: entity as any })\n}\n",
      "type": "registry:api"
    },
    {
      "path": "requests/api/admin/requests/[type]/[id]/reject/route.ts",
      "content": "import { AuthenticatedMedusaRequest, MedusaResponse } from \"@medusajs/framework\"\nimport { ContainerRegistrationKeys } from \"@medusajs/framework/utils\"\n\nimport { AdminRequestResponse } from \"../../../../../../types\"\nimport { rejectRequestWorkflow } from \"../../../../../../workflows/requests/workflows\"\nimport { AdminReviewNoteType } from \"../../../validators\"\n\nexport async function POST(\n  req: AuthenticatedMedusaRequest<AdminReviewNoteType>,\n  res: MedusaResponse<AdminRequestResponse>\n): Promise<void> {\n  const query = req.scope.resolve(ContainerRegistrationKeys.QUERY)\n\n  const alias = req.params.type!\n  const entityId = req.params.id!\n\n  await rejectRequestWorkflow(req.scope).run({\n    input: {\n      alias,\n      entity_id: entityId,\n      reviewer_id: req.auth_context.actor_id,\n      reviewer_note: req.validatedBody?.reviewer_note,\n    },\n  })\n\n  const {\n    data: [entity],\n  } = await query.graph({\n    entity: alias,\n    fields: [\"id\", \"custom_fields.*\"],\n    filters: { id: entityId },\n  })\n\n  res.json({ request: entity })\n}\n",
      "type": "registry:api"
    },
    {
      "path": "requests/api/vendor/requests/product-collections/route.ts",
      "content": "import { AuthenticatedMedusaRequest, MedusaResponse } from \"@medusajs/framework\"\nimport { ContainerRegistrationKeys } from \"@medusajs/framework/utils\"\n\nimport { VendorRequestListResponse, VendorRequestResponse } from \"../../../../types\"\nimport { createProductCollectionRequestWorkflow } from \"../../../../workflows/requests/workflows\"\nimport { VendorCreateProductCollectionRequestType, VendorGetProductCollectionRequestsParamsType } from \"./validators\"\n\nexport async function GET(\n  req: AuthenticatedMedusaRequest<VendorGetProductCollectionRequestsParamsType>,\n  res: MedusaResponse<VendorRequestListResponse>\n): Promise<void> {\n  const query = req.scope.resolve(ContainerRegistrationKeys.QUERY)\n\n  const { data: entities, metadata } = await query.graph({\n    entity: \"product_collection\",\n    fields: req.queryConfig.fields,\n    filters: req.filterableFields,\n    pagination: req.queryConfig.pagination,\n  })\n\n  res.json({\n    requests: entities,\n    count: metadata?.count ?? 0,\n    offset: metadata?.skip ?? 0,\n    limit: metadata?.take ?? 0,\n  })\n}\n\nexport async function POST(\n  req: AuthenticatedMedusaRequest<VendorCreateProductCollectionRequestType>,\n  res: MedusaResponse<VendorRequestResponse>\n): Promise<void> {\n  const query = req.scope.resolve(ContainerRegistrationKeys.QUERY)\n\n  const { result: collection } = await createProductCollectionRequestWorkflow(req.scope).run({\n    input: {\n      product_collection: req.validatedBody,\n      submitter_id: req.auth_context.actor_id,\n    },\n  })\n\n  const {\n    data: [entity],\n  } = await query.graph({\n    entity: \"product_collection\",\n    fields: req.queryConfig.fields,\n    filters: { id: collection.id },\n  })\n\n  res.status(201).json({ request: entity })\n}\n",
      "type": "registry:api"
    },
    {
      "path": "requests/api/vendor/requests/product-collections/validators.ts",
      "content": "import { z } from \"zod\"\nimport { createFindParams, createOperatorMap } from \"@medusajs/medusa/api/utils/validators\"\nimport { RequestStatus } from \"../../../../types\"\n\nexport type VendorCreateProductCollectionRequestType = z.infer<typeof VendorCreateProductCollectionRequest>\nexport const VendorCreateProductCollectionRequest = z.object({\n  title: z.string(),\n  handle: z.string().optional(),\n  metadata: z.record(z.unknown()).optional(),\n})\n\nexport type VendorGetProductCollectionRequestsParamsType = z.infer<typeof VendorGetProductCollectionRequestsParams>\nexport const VendorGetProductCollectionRequestsParams = createFindParams({\n  offset: 0,\n  limit: 50,\n}).extend({\n  q: z.string().optional(),\n  request_status: z\n    .union([z.nativeEnum(RequestStatus), z.array(z.nativeEnum(RequestStatus))])\n    .optional(),\n  created_at: createOperatorMap().optional(),\n  updated_at: createOperatorMap().optional(),\n})\n",
      "type": "registry:api"
    },
    {
      "path": "requests/api/vendor/requests/product-collections/query-config.ts",
      "content": "export const defaultVendorProductCollectionRequestFields = [\n  \"id\",\n  \"title\",\n  \"handle\",\n  \"custom_fields.*\",\n  \"created_at\",\n  \"updated_at\",\n]\n\nexport const retrieveTransformQueryConfig = {\n  defaults: defaultVendorProductCollectionRequestFields,\n  isList: false,\n}\n\nexport const listTransformQueryConfig = {\n  ...retrieveTransformQueryConfig,\n  isList: true,\n}\n",
      "type": "registry:api"
    },
    {
      "path": "requests/api/vendor/requests/product-collections/middlewares.ts",
      "content": "import { MiddlewareRoute } from \"@medusajs/framework/http\"\nimport {\n  validateAndTransformBody,\n  validateAndTransformQuery,\n} from \"@medusajs/framework\"\n\nimport { listTransformQueryConfig, retrieveTransformQueryConfig } from \"./query-config\"\nimport {\n  VendorCreateProductCollectionRequest,\n  VendorGetProductCollectionRequestsParams,\n} from \"./validators\"\nimport { applyRequestCustomFieldsFilter } from \"./helpers\"\n\nexport const vendorProductCollectionRequestsMiddlewares: MiddlewareRoute[] = [\n  {\n    method: [\"GET\"],\n    matcher: \"/vendor/requests/product-collections\",\n    middlewares: [\n      validateAndTransformQuery(\n        VendorGetProductCollectionRequestsParams,\n        listTransformQueryConfig\n      ),\n      applyRequestCustomFieldsFilter(),\n    ],\n  },\n  {\n    method: [\"POST\"],\n    matcher: \"/vendor/requests/product-collections\",\n    middlewares: [\n      validateAndTransformBody(VendorCreateProductCollectionRequest),\n      validateAndTransformQuery(\n        VendorGetProductCollectionRequestsParams,\n        retrieveTransformQueryConfig\n      ),\n    ],\n  },\n]\n",
      "type": "registry:api"
    },
    {
      "path": "requests/api/vendor/requests/product-collections/helpers.ts",
      "content": "import { MedusaNextFunction, AuthenticatedMedusaRequest, MedusaResponse } from \"@medusajs/framework/http\"\nimport { MercurModules } from \"@mercurjs/types\"\nimport type { CustomFieldsModuleService } from \"@mercurjs/core/modules/custom-fields\"\n\nexport function applyRequestCustomFieldsFilter() {\n  return async function (\n    req: AuthenticatedMedusaRequest,\n    _res: MedusaResponse,\n    next: MedusaNextFunction\n  ) {\n    const customFieldsService = req.scope.resolve<CustomFieldsModuleService>(MercurModules.CUSTOM_FIELDS)\n\n    const filters: Record<string, string | string[]> = {\n      submitter_id: req.auth_context!.actor_id,\n    }\n\n    if (req.filterableFields.request_status) {\n      filters.request_status = req.filterableFields.request_status as string | string[]\n      delete req.filterableFields.request_status\n    }\n\n    const customFieldRows = await customFieldsService.list(\"product_collection\", filters, {})\n\n    const entityIds = customFieldRows.map((row) => row[\"product_collection_id\"])\n\n    req.filterableFields.id = entityIds\n\n    return next()\n  }\n}\n",
      "type": "registry:api"
    },
    {
      "path": "requests/workflows/requests/workflows/create-product-category-request.ts",
      "content": "import { createWorkflow, transform, WorkflowResponse } from \"@medusajs/framework/workflows-sdk\"\nimport { createProductCategoriesWorkflow } from \"@medusajs/medusa/core-flows\"\nimport { upsertCustomFieldsStep } from \"@mercurjs/core/workflows\"\n\nimport { RequestStatus } from \"../../../types\"\n\ntype CreateProductCategoryRequestWorkflowInput = {\n  product_category: {\n    name: string\n    handle?: string\n    description?: string\n    is_active?: boolean\n    is_internal?: boolean\n    parent_category_id?: string | null\n    metadata?: Record<string, unknown>\n  }\n  submitter_id: string\n}\n\nexport const createProductCategoryRequestWorkflow = createWorkflow(\n  \"create-product-category-request\",\n  function (input: CreateProductCategoryRequestWorkflowInput) {\n    const categories = createProductCategoriesWorkflow.runAsStep({\n      input: {\n        product_categories: [input.product_category],\n      },\n    })\n\n    const upsertInput = transform({ categories, input }, (data) => ({\n      alias: \"product_category\",\n      data: {\n        id: data.categories[0]!.id,\n        request_status: RequestStatus.PENDING,\n        submitter_id: data.input.submitter_id,\n      },\n    }))\n\n    upsertCustomFieldsStep(upsertInput)\n\n    const category = transform({ categories }, (data) => data.categories[0]!)\n\n    return new WorkflowResponse(category)\n  }\n)\n",
      "type": "registry:api"
    },
    {
      "path": "requests/api/vendor/requests/product-categories/route.ts",
      "content": "import { AuthenticatedMedusaRequest, MedusaResponse } from \"@medusajs/framework\"\nimport { ContainerRegistrationKeys } from \"@medusajs/framework/utils\"\n\nimport { VendorRequestListResponse, VendorRequestResponse } from \"../../../../types\"\nimport { createProductCategoryRequestWorkflow } from \"../../../../workflows/requests/workflows\"\nimport { VendorCreateProductCategoryRequestType, VendorGetProductCategoryRequestsParamsType } from \"./validators\"\n\nexport async function GET(\n  req: AuthenticatedMedusaRequest<VendorGetProductCategoryRequestsParamsType>,\n  res: MedusaResponse<VendorRequestListResponse>\n): Promise<void> {\n  const query = req.scope.resolve(ContainerRegistrationKeys.QUERY)\n\n  const { data: entities, metadata } = await query.graph({\n    entity: \"product_category\",\n    fields: req.queryConfig.fields,\n    filters: req.filterableFields,\n    pagination: req.queryConfig.pagination,\n  })\n\n  res.json({\n    requests: entities,\n    count: metadata?.count ?? 0,\n    offset: metadata?.skip ?? 0,\n    limit: metadata?.take ?? 0,\n  })\n}\n\nexport async function POST(\n  req: AuthenticatedMedusaRequest<VendorCreateProductCategoryRequestType>,\n  res: MedusaResponse<VendorRequestResponse>\n): Promise<void> {\n  const query = req.scope.resolve(ContainerRegistrationKeys.QUERY)\n\n  const { result: category } = await createProductCategoryRequestWorkflow(req.scope).run({\n    input: {\n      product_category: req.validatedBody,\n      submitter_id: req.auth_context.actor_id,\n    },\n  })\n\n  const {\n    data: [entity],\n  } = await query.graph({\n    entity: \"product_category\",\n    fields: req.queryConfig.fields,\n    filters: { id: category.id },\n  })\n\n  res.status(201).json({ request: entity })\n}\n",
      "type": "registry:api"
    },
    {
      "path": "requests/api/vendor/requests/product-categories/validators.ts",
      "content": "import { z } from \"zod\"\nimport { createFindParams, createOperatorMap } from \"@medusajs/medusa/api/utils/validators\"\nimport { RequestStatus } from \"../../../../types\"\n\nexport type VendorCreateProductCategoryRequestType = z.infer<typeof VendorCreateProductCategoryRequest>\nexport const VendorCreateProductCategoryRequest = z.object({\n  name: z.string(),\n  handle: z.string().optional(),\n  description: z.string().optional(),\n  is_active: z.boolean().optional(),\n  is_internal: z.boolean().optional(),\n  parent_category_id: z.string().nullish(),\n  metadata: z.record(z.unknown()).optional(),\n})\n\nexport type VendorGetProductCategoryRequestsParamsType = z.infer<typeof VendorGetProductCategoryRequestsParams>\nexport const VendorGetProductCategoryRequestsParams = createFindParams({\n  offset: 0,\n  limit: 50,\n}).extend({\n  q: z.string().optional(),\n  request_status: z\n    .union([z.nativeEnum(RequestStatus), z.array(z.nativeEnum(RequestStatus))])\n    .optional(),\n  created_at: createOperatorMap().optional(),\n  updated_at: createOperatorMap().optional(),\n})\n",
      "type": "registry:api"
    },
    {
      "path": "requests/api/vendor/requests/product-categories/query-config.ts",
      "content": "export const defaultVendorProductCategoryRequestFields = [\n  \"id\",\n  \"name\",\n  \"handle\",\n  \"description\",\n  \"is_active\",\n  \"is_internal\",\n  \"custom_fields.*\",\n  \"created_at\",\n  \"updated_at\",\n]\n\nexport const retrieveTransformQueryConfig = {\n  defaults: defaultVendorProductCategoryRequestFields,\n  isList: false,\n}\n\nexport const listTransformQueryConfig = {\n  ...retrieveTransformQueryConfig,\n  isList: true,\n}\n",
      "type": "registry:api"
    },
    {
      "path": "requests/api/vendor/requests/product-categories/middlewares.ts",
      "content": "import { MiddlewareRoute } from \"@medusajs/framework/http\"\nimport {\n  validateAndTransformBody,\n  validateAndTransformQuery,\n} from \"@medusajs/framework\"\n\nimport { listTransformQueryConfig, retrieveTransformQueryConfig } from \"./query-config\"\nimport {\n  VendorCreateProductCategoryRequest,\n  VendorGetProductCategoryRequestsParams,\n} from \"./validators\"\nimport { applyRequestCustomFieldsFilter } from \"./helpers\"\n\nexport const vendorProductCategoryRequestsMiddlewares: MiddlewareRoute[] = [\n  {\n    method: [\"GET\"],\n    matcher: \"/vendor/requests/product-categories\",\n    middlewares: [\n      validateAndTransformQuery(\n        VendorGetProductCategoryRequestsParams,\n        listTransformQueryConfig\n      ),\n      applyRequestCustomFieldsFilter(),\n    ],\n  },\n  {\n    method: [\"POST\"],\n    matcher: \"/vendor/requests/product-categories\",\n    middlewares: [\n      validateAndTransformBody(VendorCreateProductCategoryRequest),\n      validateAndTransformQuery(\n        VendorGetProductCategoryRequestsParams,\n        retrieveTransformQueryConfig\n      ),\n    ],\n  },\n]\n",
      "type": "registry:api"
    },
    {
      "path": "requests/api/vendor/requests/product-categories/helpers.ts",
      "content": "import { MedusaNextFunction, AuthenticatedMedusaRequest, MedusaResponse } from \"@medusajs/framework/http\"\nimport { MercurModules } from \"@mercurjs/types\"\nimport type { CustomFieldsModuleService } from \"@mercurjs/core/modules/custom-fields\"\n\nexport function applyRequestCustomFieldsFilter() {\n  return async function (\n    req: AuthenticatedMedusaRequest,\n    _res: MedusaResponse,\n    next: MedusaNextFunction\n  ) {\n    const customFieldsService = req.scope.resolve<CustomFieldsModuleService>(MercurModules.CUSTOM_FIELDS)\n\n    const filters: Record<string, string | string[]> = {\n      submitter_id: req.auth_context!.actor_id,\n    }\n\n    if (req.filterableFields.request_status) {\n      filters.request_status = req.filterableFields.request_status as string | string[]\n      delete req.filterableFields.request_status\n    }\n\n    const customFieldRows = await customFieldsService.list(\"product_category\", filters, {})\n\n    const entityIds = customFieldRows.map((row) => row[\"product_category_id\"])\n\n    req.filterableFields.id = entityIds\n\n    return next()\n  }\n}\n",
      "type": "registry:api"
    },
    {
      "path": "requests/workflows/requests/workflows/create-product-type-request.ts",
      "content": "import { createWorkflow, transform, WorkflowResponse } from \"@medusajs/framework/workflows-sdk\"\nimport { createProductTypesWorkflow } from \"@medusajs/medusa/core-flows\"\nimport { upsertCustomFieldsStep } from \"@mercurjs/core/workflows\"\n\nimport { RequestStatus } from \"../../../types\"\n\ntype CreateProductTypeRequestWorkflowInput = {\n  product_type: {\n    value: string\n    metadata?: Record<string, unknown>\n  }\n  submitter_id: string\n}\n\nexport const createProductTypeRequestWorkflow = createWorkflow(\n  \"create-product-type-request\",\n  function (input: CreateProductTypeRequestWorkflowInput) {\n    const productTypes = createProductTypesWorkflow.runAsStep({\n      input: {\n        product_types: [input.product_type],\n      },\n    })\n\n    const upsertInput = transform({ productTypes, input }, (data) => ({\n      alias: \"product_type\",\n      data: {\n        id: data.productTypes[0]!.id,\n        request_status: RequestStatus.PENDING,\n        submitter_id: data.input.submitter_id,\n      },\n    }))\n\n    upsertCustomFieldsStep(upsertInput)\n\n    const productType = transform({ productTypes }, (data) => data.productTypes[0]!)\n\n    return new WorkflowResponse(productType)\n  }\n)\n",
      "type": "registry:api"
    },
    {
      "path": "requests/api/vendor/requests/product-types/route.ts",
      "content": "import { AuthenticatedMedusaRequest, MedusaResponse } from \"@medusajs/framework\"\nimport { ContainerRegistrationKeys } from \"@medusajs/framework/utils\"\n\nimport { VendorRequestListResponse, VendorRequestResponse } from \"../../../../types\"\nimport { createProductTypeRequestWorkflow } from \"../../../../workflows/requests/workflows\"\nimport { VendorCreateProductTypeRequestType, VendorGetProductTypeRequestsParamsType } from \"./validators\"\n\nexport async function GET(\n  req: AuthenticatedMedusaRequest<VendorGetProductTypeRequestsParamsType>,\n  res: MedusaResponse<VendorRequestListResponse>\n): Promise<void> {\n  const query = req.scope.resolve(ContainerRegistrationKeys.QUERY)\n\n  const { data: entities, metadata } = await query.graph({\n    entity: \"product_type\",\n    fields: req.queryConfig.fields,\n    filters: req.filterableFields,\n    pagination: req.queryConfig.pagination,\n  })\n\n  res.json({\n    requests: entities,\n    count: metadata?.count ?? 0,\n    offset: metadata?.skip ?? 0,\n    limit: metadata?.take ?? 0,\n  })\n}\n\nexport async function POST(\n  req: AuthenticatedMedusaRequest<VendorCreateProductTypeRequestType>,\n  res: MedusaResponse<VendorRequestResponse>\n): Promise<void> {\n  const query = req.scope.resolve(ContainerRegistrationKeys.QUERY)\n\n  const { result: productType } = await createProductTypeRequestWorkflow(req.scope).run({\n    input: {\n      product_type: req.validatedBody,\n      submitter_id: req.auth_context.actor_id,\n    },\n  })\n\n  const {\n    data: [entity],\n  } = await query.graph({\n    entity: \"product_type\",\n    fields: req.queryConfig.fields,\n    filters: { id: productType.id },\n  })\n\n  res.status(201).json({ request: entity })\n}\n",
      "type": "registry:api"
    },
    {
      "path": "requests/api/vendor/requests/product-types/validators.ts",
      "content": "import { z } from \"zod\"\nimport { createFindParams, createOperatorMap } from \"@medusajs/medusa/api/utils/validators\"\nimport { RequestStatus } from \"../../../../types\"\n\nexport type VendorCreateProductTypeRequestType = z.infer<typeof VendorCreateProductTypeRequest>\nexport const VendorCreateProductTypeRequest = z.object({\n  value: z.string(),\n  metadata: z.record(z.unknown()).optional(),\n})\n\nexport type VendorGetProductTypeRequestsParamsType = z.infer<typeof VendorGetProductTypeRequestsParams>\nexport const VendorGetProductTypeRequestsParams = createFindParams({\n  offset: 0,\n  limit: 50,\n}).extend({\n  q: z.string().optional(),\n  request_status: z\n    .union([z.nativeEnum(RequestStatus), z.array(z.nativeEnum(RequestStatus))])\n    .optional(),\n  created_at: createOperatorMap().optional(),\n  updated_at: createOperatorMap().optional(),\n})\n",
      "type": "registry:api"
    },
    {
      "path": "requests/api/vendor/requests/product-types/query-config.ts",
      "content": "export const defaultVendorProductTypeRequestFields = [\n  \"id\",\n  \"value\",\n  \"custom_fields.*\",\n  \"created_at\",\n  \"updated_at\",\n]\n\nexport const retrieveTransformQueryConfig = {\n  defaults: defaultVendorProductTypeRequestFields,\n  isList: false,\n}\n\nexport const listTransformQueryConfig = {\n  ...retrieveTransformQueryConfig,\n  isList: true,\n}\n",
      "type": "registry:api"
    },
    {
      "path": "requests/api/vendor/requests/product-types/middlewares.ts",
      "content": "import { MiddlewareRoute } from \"@medusajs/framework/http\"\nimport {\n  validateAndTransformBody,\n  validateAndTransformQuery,\n} from \"@medusajs/framework\"\n\nimport { listTransformQueryConfig, retrieveTransformQueryConfig } from \"./query-config\"\nimport {\n  VendorCreateProductTypeRequest,\n  VendorGetProductTypeRequestsParams,\n} from \"./validators\"\nimport { applyRequestCustomFieldsFilter } from \"./helpers\"\n\nexport const vendorProductTypeRequestsMiddlewares: MiddlewareRoute[] = [\n  {\n    method: [\"GET\"],\n    matcher: \"/vendor/requests/product-types\",\n    middlewares: [\n      validateAndTransformQuery(\n        VendorGetProductTypeRequestsParams,\n        listTransformQueryConfig\n      ),\n      applyRequestCustomFieldsFilter(),\n    ],\n  },\n  {\n    method: [\"POST\"],\n    matcher: \"/vendor/requests/product-types\",\n    middlewares: [\n      validateAndTransformBody(VendorCreateProductTypeRequest),\n      validateAndTransformQuery(\n        VendorGetProductTypeRequestsParams,\n        retrieveTransformQueryConfig\n      ),\n    ],\n  },\n]\n",
      "type": "registry:api"
    },
    {
      "path": "requests/api/vendor/requests/product-types/helpers.ts",
      "content": "import { MedusaNextFunction, AuthenticatedMedusaRequest, MedusaResponse } from \"@medusajs/framework/http\"\nimport { MercurModules } from \"@mercurjs/types\"\nimport type { CustomFieldsModuleService } from \"@mercurjs/core/modules/custom-fields\"\n\nexport function applyRequestCustomFieldsFilter() {\n  return async function (\n    req: AuthenticatedMedusaRequest,\n    _res: MedusaResponse,\n    next: MedusaNextFunction\n  ) {\n    const customFieldsService = req.scope.resolve<CustomFieldsModuleService>(MercurModules.CUSTOM_FIELDS)\n\n    const filters: Record<string, string | string[]> = {\n      submitter_id: req.auth_context!.actor_id,\n    }\n\n    if (req.filterableFields.request_status) {\n      filters.request_status = req.filterableFields.request_status as string | string[]\n      delete req.filterableFields.request_status\n    }\n\n    const customFieldRows = await customFieldsService.list(\"product_type\", filters, {})\n\n    const entityIds = customFieldRows.map((row) => row[\"product_type_id\"])\n\n    req.filterableFields.id = entityIds\n\n    return next()\n  }\n}\n",
      "type": "registry:api"
    },
    {
      "path": "requests/workflows/requests/workflows/create-product-tag-request.ts",
      "content": "import { createWorkflow, transform, WorkflowResponse } from \"@medusajs/framework/workflows-sdk\"\nimport { createProductTagsWorkflow } from \"@medusajs/medusa/core-flows\"\nimport { upsertCustomFieldsStep } from \"@mercurjs/core/workflows\"\n\nimport { RequestStatus } from \"../../../types\"\n\ntype CreateProductTagRequestWorkflowInput = {\n  product_tag: {\n    value: string\n    metadata?: Record<string, unknown>\n  }\n  submitter_id: string\n}\n\nexport const createProductTagRequestWorkflow = createWorkflow(\n  \"create-product-tag-request\",\n  function (input: CreateProductTagRequestWorkflowInput) {\n    const productTags = createProductTagsWorkflow.runAsStep({\n      input: {\n        product_tags: [input.product_tag],\n      },\n    })\n\n    const upsertInput = transform({ productTags, input }, (data) => ({\n      alias: \"product_tag\",\n      data: {\n        id: data.productTags[0]!.id,\n        request_status: RequestStatus.PENDING,\n        submitter_id: data.input.submitter_id,\n      },\n    }))\n\n    upsertCustomFieldsStep(upsertInput)\n\n    const productTag = transform({ productTags }, (data) => data.productTags[0]!)\n\n    return new WorkflowResponse(productTag)\n  }\n)\n",
      "type": "registry:api"
    },
    {
      "path": "requests/api/vendor/requests/product-tags/route.ts",
      "content": "import { AuthenticatedMedusaRequest, MedusaResponse } from \"@medusajs/framework\"\nimport { ContainerRegistrationKeys } from \"@medusajs/framework/utils\"\n\nimport { VendorRequestListResponse, VendorRequestResponse } from \"../../../../types\"\nimport { createProductTagRequestWorkflow } from \"../../../../workflows/requests/workflows\"\nimport { VendorCreateProductTagRequestType, VendorGetProductTagRequestsParamsType } from \"./validators\"\n\nexport async function GET(\n  req: AuthenticatedMedusaRequest<VendorGetProductTagRequestsParamsType>,\n  res: MedusaResponse<VendorRequestListResponse>\n): Promise<void> {\n  const query = req.scope.resolve(ContainerRegistrationKeys.QUERY)\n\n  const { data: entities, metadata } = await query.graph({\n    entity: \"product_tag\",\n    fields: req.queryConfig.fields,\n    filters: req.filterableFields,\n    pagination: req.queryConfig.pagination,\n  })\n\n  res.json({\n    requests: entities,\n    count: metadata?.count ?? 0,\n    offset: metadata?.skip ?? 0,\n    limit: metadata?.take ?? 0,\n  })\n}\n\nexport async function POST(\n  req: AuthenticatedMedusaRequest<VendorCreateProductTagRequestType>,\n  res: MedusaResponse<VendorRequestResponse>\n): Promise<void> {\n  const query = req.scope.resolve(ContainerRegistrationKeys.QUERY)\n\n  const { result: productTag } = await createProductTagRequestWorkflow(req.scope).run({\n    input: {\n      product_tag: req.validatedBody,\n      submitter_id: req.auth_context.actor_id,\n    },\n  })\n\n  const {\n    data: [entity],\n  } = await query.graph({\n    entity: \"product_tag\",\n    fields: req.queryConfig.fields,\n    filters: { id: productTag.id },\n  })\n\n  res.status(201).json({ request: entity })\n}\n",
      "type": "registry:api"
    },
    {
      "path": "requests/api/vendor/requests/product-tags/validators.ts",
      "content": "import { z } from \"zod\"\nimport { createFindParams, createOperatorMap } from \"@medusajs/medusa/api/utils/validators\"\nimport { RequestStatus } from \"../../../../types\"\n\nexport type VendorCreateProductTagRequestType = z.infer<typeof VendorCreateProductTagRequest>\nexport const VendorCreateProductTagRequest = z.object({\n  value: z.string(),\n  metadata: z.record(z.unknown()).optional(),\n})\n\nexport type VendorGetProductTagRequestsParamsType = z.infer<typeof VendorGetProductTagRequestsParams>\nexport const VendorGetProductTagRequestsParams = createFindParams({\n  offset: 0,\n  limit: 50,\n}).extend({\n  q: z.string().optional(),\n  request_status: z\n    .union([z.nativeEnum(RequestStatus), z.array(z.nativeEnum(RequestStatus))])\n    .optional(),\n  created_at: createOperatorMap().optional(),\n  updated_at: createOperatorMap().optional(),\n})\n",
      "type": "registry:api"
    },
    {
      "path": "requests/api/vendor/requests/product-tags/query-config.ts",
      "content": "export const defaultVendorProductTagRequestFields = [\n  \"id\",\n  \"value\",\n  \"custom_fields.*\",\n  \"created_at\",\n  \"updated_at\",\n]\n\nexport const retrieveTransformQueryConfig = {\n  defaults: defaultVendorProductTagRequestFields,\n  isList: false,\n}\n\nexport const listTransformQueryConfig = {\n  ...retrieveTransformQueryConfig,\n  isList: true,\n}\n",
      "type": "registry:api"
    },
    {
      "path": "requests/api/vendor/requests/product-tags/middlewares.ts",
      "content": "import { MiddlewareRoute } from \"@medusajs/framework/http\"\nimport {\n  validateAndTransformBody,\n  validateAndTransformQuery,\n} from \"@medusajs/framework\"\n\nimport { listTransformQueryConfig, retrieveTransformQueryConfig } from \"./query-config\"\nimport {\n  VendorCreateProductTagRequest,\n  VendorGetProductTagRequestsParams,\n} from \"./validators\"\nimport { applyRequestCustomFieldsFilter } from \"./helpers\"\n\nexport const vendorProductTagRequestsMiddlewares: MiddlewareRoute[] = [\n  {\n    method: [\"GET\"],\n    matcher: \"/vendor/requests/product-tags\",\n    middlewares: [\n      validateAndTransformQuery(\n        VendorGetProductTagRequestsParams,\n        listTransformQueryConfig\n      ),\n      applyRequestCustomFieldsFilter(),\n    ],\n  },\n  {\n    method: [\"POST\"],\n    matcher: \"/vendor/requests/product-tags\",\n    middlewares: [\n      validateAndTransformBody(VendorCreateProductTagRequest),\n      validateAndTransformQuery(\n        VendorGetProductTagRequestsParams,\n        retrieveTransformQueryConfig\n      ),\n    ],\n  },\n]\n",
      "type": "registry:api"
    },
    {
      "path": "requests/api/vendor/requests/product-tags/helpers.ts",
      "content": "import { MedusaNextFunction, AuthenticatedMedusaRequest, MedusaResponse } from \"@medusajs/framework/http\"\nimport { MercurModules } from \"@mercurjs/types\"\nimport type { CustomFieldsModuleService } from \"@mercurjs/core/modules/custom-fields\"\n\nexport function applyRequestCustomFieldsFilter() {\n  return async function (\n    req: AuthenticatedMedusaRequest,\n    _res: MedusaResponse,\n    next: MedusaNextFunction\n  ) {\n    const customFieldsService = req.scope.resolve<CustomFieldsModuleService>(MercurModules.CUSTOM_FIELDS)\n\n    const filters: Record<string, string | string[]> = {\n      submitter_id: req.auth_context!.actor_id,\n    }\n\n    if (req.filterableFields.request_status) {\n      filters.request_status = req.filterableFields.request_status as string | string[]\n      delete req.filterableFields.request_status\n    }\n\n    const customFieldRows = await customFieldsService.list(\"product_tag\", filters, {})\n\n    const entityIds = customFieldRows.map((row) => row[\"product_tag_id\"])\n\n    req.filterableFields.id = entityIds\n\n    return next()\n  }\n}\n",
      "type": "registry:api"
    },
    {
      "path": "requests/api/store/requests/helpers.ts",
      "content": "import { MedusaNextFunction, MedusaRequest, MedusaResponse } from \"@medusajs/framework/http\"\nimport { MercurModules } from \"@mercurjs/types\"\nimport type { CustomFieldsModuleService } from \"@mercurjs/core/modules/custom-fields\"\n\nexport function excludePendingRequestEntities(alias: string) {\n  return async function (\n    req: MedusaRequest,\n    _res: MedusaResponse,\n    next: MedusaNextFunction\n  ) {\n    const customFieldsService = req.scope.resolve<CustomFieldsModuleService>(MercurModules.CUSTOM_FIELDS)\n\n    const pendingRows = await customFieldsService.list(alias, {\n      request_status: 'pending',\n    }, {})\n\n    const pendingIds = pendingRows.map((row: Record<string, string>) => row[`${alias}_id`])\n\n    if (pendingIds.length > 0) {\n      const existingIdFilter = req.filterableFields.id\n\n      if (existingIdFilter) {\n        // If there's already an id filter, intersect with non-pending\n        const existingIds = Array.isArray(existingIdFilter)\n          ? existingIdFilter\n          : [existingIdFilter]\n\n        req.filterableFields.id = existingIds.filter(\n          (id) => !pendingIds.includes(id as string)\n        )\n      } else {\n        req.filterableFields.id = { $nin: pendingIds }\n      }\n    }\n\n    return next()\n  }\n}\n",
      "type": "registry:api"
    },
    {
      "path": "requests/api/store/requests/middlewares.ts",
      "content": "import { MiddlewareRoute } from \"@medusajs/framework/http\"\n\nimport { excludePendingRequestEntities } from \"./helpers\"\n\nexport const storeRequestsMiddlewares: MiddlewareRoute[] = [\n  {\n    method: [\"GET\"],\n    matcher: \"/store/product-categories\",\n    middlewares: [excludePendingRequestEntities(\"product_category\")],\n  },\n  {\n    method: [\"GET\"],\n    matcher: \"/store/collections\",\n    middlewares: [excludePendingRequestEntities(\"product_collection\")],\n  },\n  {\n    method: [\"GET\"],\n    matcher: \"/store/product-tags\",\n    middlewares: [excludePendingRequestEntities(\"product_tag\")],\n  },\n  {\n    method: [\"GET\"],\n    matcher: \"/store/product-types\",\n    middlewares: [excludePendingRequestEntities(\"product_type\")],\n  },\n]\n",
      "type": "registry:api"
    },
    {
      "path": "requests/workflows/hooks/seller-created.ts",
      "content": "import { createSellerWorkflow } from \"@mercurjs/core/workflows\"\nimport { StepResponse } from \"@medusajs/framework/workflows-sdk\"\nimport { MedusaError } from \"@medusajs/framework/utils\"\nimport { SellerStatus } from \"@mercurjs/types\"\n\ncreateSellerWorkflow.hooks.validateSellerInput(\n  async ({ input }) => {\n    if (input.seller.status === SellerStatus.ACTIVE) {\n      throw new MedusaError(\n        MedusaError.Types.INVALID_DATA,\n        `Seller cannot be created with status \"active\". Use \"pending\" status and submit for review.`\n      )\n    }\n\n    return new StepResponse(undefined)\n  }\n)\n",
      "type": "registry:api"
    },
    {
      "path": "requests/admin/hooks/api/requests.tsx",
      "content": "import {\n  useQuery,\n  useMutation,\n  useQueryClient,\n  UseQueryOptions,\n  UseMutationOptions,\n} from \"@tanstack/react-query\";\nimport { queryKeysFactory } from \"@mercurjs/dashboard-shared\";\nimport { client } from \"../../lib/client\";\nimport {\n  ClientError,\n  InferClientInput,\n  InferClientOutput,\n} from \"@mercurjs/client\";\n\nconst REQUESTS_QUERY_KEY = \"admin_requests\" as const;\nexport const requestsQueryKeys = queryKeysFactory(REQUESTS_QUERY_KEY);\n\nexport type RequestDTO = InferClientOutput<\n  typeof client.admin.requests.$type.$id.query\n>[\"request\"];\n\nexport const useRequests = (\n  type: string,\n  query?: Record<string, any>,\n  options?: Omit<\n    UseQueryOptions<\n      unknown,\n      ClientError,\n      InferClientOutput<typeof client.admin.requests.$type.query>\n    >,\n    \"queryKey\" | \"queryFn\"\n  >,\n) => {\n  const { data, ...rest } = useQuery({\n    queryKey: requestsQueryKeys.list({ type, ...query }),\n    queryFn: async () =>\n      client.admin.requests.$type.query({\n        $type: type,\n        ...query,\n        offset: query?.offset ?? 0,\n        limit: query?.limit ?? 20,\n      }),\n    ...options,\n  });\n\n  return { ...data, ...rest };\n};\n\nexport const useRequest = (\n  type: string,\n  id: string,\n  query?: Record<string, any>,\n  options?: Omit<\n    UseQueryOptions<\n      unknown,\n      ClientError,\n      InferClientOutput<typeof client.admin.requests.$type.$id.query>\n    >,\n    \"queryKey\" | \"queryFn\"\n  >,\n) => {\n  const { data, ...rest } = useQuery({\n    queryKey: requestsQueryKeys.detail(id, { type, ...query }),\n    queryFn: async () =>\n      client.admin.requests.$type.$id.query({\n        $type: type,\n        $id: id,\n        ...query,\n      }),\n    ...options,\n  });\n\n  return { ...data, ...rest };\n};\n\nexport const useAcceptRequest = (\n  type: string,\n  id: string,\n  options?: UseMutationOptions<\n    InferClientOutput<typeof client.admin.requests.$type.$id.accept.mutate>,\n    ClientError,\n    { reviewer_note?: string }\n  >,\n) => {\n  const queryClient = useQueryClient();\n\n  return useMutation({\n    mutationFn: async (payload: { reviewer_note?: string }) =>\n      client.admin.requests.$type.$id.accept.mutate({\n        $type: type,\n        $id: id,\n        ...payload,\n      }),\n    onSuccess: (data, variables, context) => {\n      queryClient.invalidateQueries({ queryKey: requestsQueryKeys.detail(id) });\n      queryClient.invalidateQueries({ queryKey: requestsQueryKeys.lists() });\n      options?.onSuccess?.(data, variables, context);\n    },\n    ...options,\n  });\n};\n\nexport const useRejectRequest = (\n  type: string,\n  id: string,\n  options?: UseMutationOptions<\n    InferClientOutput<typeof client.admin.requests.$type.$id.reject.mutate>,\n    ClientError,\n    { reviewer_note?: string }\n  >,\n) => {\n  const queryClient = useQueryClient();\n\n  return useMutation({\n    mutationFn: async (payload: { reviewer_note?: string }) =>\n      client.admin.requests.$type.$id.reject.mutate({\n        $type: type,\n        $id: id,\n        ...payload,\n      }),\n    onSuccess: (data, variables, context) => {\n      queryClient.invalidateQueries({ queryKey: requestsQueryKeys.detail(id) });\n      queryClient.invalidateQueries({ queryKey: requestsQueryKeys.lists() });\n      options?.onSuccess?.(data, variables, context);\n    },\n    ...options,\n  });\n};\n",
      "type": "registry:admin"
    },
    {
      "path": "requests/admin/hooks/table/columns/use-request-table-columns.tsx",
      "content": "import { createColumnHelper } from \"@tanstack/react-table\";\nimport { useMemo } from \"react\";\nimport { useTranslation } from \"react-i18next\";\nimport { StatusBadge, Text } from \"@medusajs/ui\";\nimport { DateCell, DateHeader } from \"@mercurjs/dashboard-shared\";\nimport { RequestDTO } from \"../../api/requests\";\n\nconst columnHelper = createColumnHelper<RequestDTO>();\n\nconst statusColor = (status: string) => {\n  switch (status) {\n    case \"accepted\":\n      return \"green\" as const;\n    case \"pending\":\n      return \"orange\" as const;\n    case \"rejected\":\n      return \"red\" as const;\n    default:\n      return \"grey\" as const;\n  }\n};\n\nexport const useRequestTableColumns = (nameKey: string = \"name\") => {\n  const { t } = useTranslation();\n\n  return useMemo(\n    () => [\n      columnHelper.display({\n        id: \"display_name\",\n        header: () => (\n          <div className=\"flex h-full w-full items-center\">\n            <span className=\"truncate\">Name</span>\n          </div>\n        ),\n        cell: ({ row }) => (\n          <Text size=\"small\" leading=\"compact\">\n            {(row.original[nameKey] as string) ?? row.original.id}\n          </Text>\n        ),\n      }),\n      columnHelper.accessor(\"custom_fields\", {\n        header: () => (\n          <div className=\"flex h-full w-full items-center\">\n            <span className=\"truncate\">Status</span>\n          </div>\n        ),\n        cell: ({ getValue }) => {\n          const customFields = getValue() as any;\n          const status = customFields?.request_status ?? \"draft\";\n          return (\n            <StatusBadge color={statusColor(status)}>\n              {status.charAt(0).toUpperCase() + status.slice(1)}\n            </StatusBadge>\n          );\n        },\n      }),\n      columnHelper.accessor(\"created_at\", {\n        header: () => <DateHeader />,\n        cell: ({ getValue }) => {\n          const date = new Date(getValue() as string);\n          return <DateCell date={date} />;\n        },\n      }),\n    ],\n    [t, nameKey],\n  );\n};\n",
      "type": "registry:admin"
    },
    {
      "path": "requests/admin/hooks/table/filters/use-request-table-filters.tsx",
      "content": "import { useTranslation } from \"react-i18next\";\nimport { useMemo } from \"react\";\n\nimport type { Filter } from \"@mercurjs/dashboard-shared\";\n\nexport const useRequestTableFilters = (): Filter[] => {\n  const { t } = useTranslation();\n\n  return useMemo(() => {\n    const filters: Filter[] = [\n      {\n        key: \"request_status\",\n        label: \"Status\",\n        type: \"select\",\n        multiple: true,\n        options: [\n          { label: \"Draft\", value: \"draft\" },\n          { label: \"Pending\", value: \"pending\" },\n          { label: \"Accepted\", value: \"accepted\" },\n          { label: \"Rejected\", value: \"rejected\" },\n        ],\n      },\n    ];\n\n    const dateFilters: Filter[] = [\n      { label: t(\"fields.createdAt\"), key: \"created_at\" },\n      { label: t(\"fields.updatedAt\"), key: \"updated_at\" },\n    ].map((f) => ({\n      key: f.key,\n      label: f.label,\n      type: \"date\" as const,\n    }));\n\n    filters.push(...dateFilters);\n\n    return filters;\n  }, [t]);\n};\n",
      "type": "registry:admin"
    },
    {
      "path": "requests/admin/hooks/table/query/use-request-table-query.tsx",
      "content": "import { useQueryParams } from \"@mercurjs/dashboard-shared\";\n\ntype UseRequestTableQueryProps = {\n  prefix?: string;\n  pageSize?: number;\n};\n\nexport const useRequestTableQuery = ({\n  prefix,\n  pageSize = 20,\n}: UseRequestTableQueryProps) => {\n  const queryObject = useQueryParams(\n    [\"offset\", \"q\", \"created_at\", \"updated_at\", \"order\", \"request_status\"],\n    prefix,\n  );\n\n  const { offset, created_at, updated_at, q, order, request_status } = queryObject;\n\n  const searchParams: Record<string, any> = {\n    limit: pageSize,\n    offset: offset ? Number(offset) : 0,\n    created_at: created_at ? JSON.parse(created_at) : undefined,\n    updated_at: updated_at ? JSON.parse(updated_at) : undefined,\n    order: order ? order : \"-created_at\",\n    request_status: request_status || undefined,\n    q,\n  };\n\n  return {\n    searchParams,\n    raw: queryObject,\n  };\n};\n",
      "type": "registry:admin"
    },
    {
      "path": "requests/admin/routes/requests/page.tsx",
      "content": "import { Navigate } from \"react-router-dom\";\nimport type { RouteConfig } from \"@mercurjs/dashboard-sdk\";\nimport { InboxSolid } from \"@medusajs/icons\";\n\nexport const config: RouteConfig = {\n  label: \"Requests\",\n  icon: InboxSolid,\n};\n\nexport const handle = {\n  breadcrumb: () => \"Requests\",\n};\n\nconst RequestsPage = () => {\n  return <Navigate to=\"/requests/categories\" replace />;\n};\n\nexport default RequestsPage;\n",
      "type": "registry:admin"
    },
    {
      "path": "requests/admin/routes/requests/categories/page.tsx",
      "content": "import { useTranslation } from \"react-i18next\";\nimport { keepPreviousData } from \"@tanstack/react-query\";\nimport { Container, Heading } from \"@medusajs/ui\";\nimport type { RouteConfig } from \"@mercurjs/dashboard-sdk\";\n\nexport const config: RouteConfig = {\n  label: \"Categories\",\n  nested: \"/requests\",\n};\n\nexport const handle = {\n  breadcrumb: () => \"Categories\",\n};\n\nimport { useRequests } from \"../../../hooks/api/requests\";\nimport { useRequestTableColumns } from \"../../../hooks/table/columns/use-request-table-columns\";\nimport { useRequestTableQuery } from \"../../../hooks/table/query/use-request-table-query\";\nimport { useRequestTableFilters } from \"../../../hooks/table/filters/use-request-table-filters\";\nimport {\n  _DataTable,\n  SingleColumnPage,\n  useDataTable,\n} from \"@mercurjs/dashboard-shared\";\n\nconst PAGE_SIZE = 10;\n\nconst CategoryRequestsPage = () => {\n  const { t } = useTranslation();\n  const { raw, searchParams } = useRequestTableQuery({ pageSize: PAGE_SIZE });\n\n  const { requests, count, isError, error, isLoading } = useRequests(\n    \"product_category\",\n    searchParams,\n    { placeholderData: keepPreviousData },\n  );\n\n  const columns = useRequestTableColumns(\"name\");\n  const filters = useRequestTableFilters();\n\n  const { table } = useDataTable({\n    data: requests ?? [],\n    columns,\n    enablePagination: true,\n    count: count,\n    pageSize: PAGE_SIZE,\n  });\n\n  if (isError) throw error;\n\n  return (\n    <SingleColumnPage>\n      <Container className=\"divide-y p-0\">\n        <div className=\"flex items-center justify-between px-6 py-4\">\n          <Heading>Category Requests</Heading>\n        </div>\n        <_DataTable\n          columns={columns}\n          table={table}\n          pagination\n          filters={filters}\n          navigateTo={(row) => `/requests/product_category/${row.original.id}`}\n          count={count}\n          isLoading={isLoading}\n          pageSize={PAGE_SIZE}\n          orderBy={[\n            { key: \"created_at\", label: t(\"fields.createdAt\") },\n            { key: \"updated_at\", label: t(\"fields.updatedAt\") },\n          ]}\n          queryObject={raw}\n          noRecords={{ message: \"No category requests found\" }}\n        />\n      </Container>\n    </SingleColumnPage>\n  );\n};\n\nexport default CategoryRequestsPage;\n",
      "type": "registry:admin"
    },
    {
      "path": "requests/admin/routes/requests/collections/page.tsx",
      "content": "import { useTranslation } from \"react-i18next\";\nimport { keepPreviousData } from \"@tanstack/react-query\";\nimport { Container, Heading } from \"@medusajs/ui\";\nimport type { RouteConfig } from \"@mercurjs/dashboard-sdk\";\n\nexport const config: RouteConfig = {\n  label: \"Collections\",\n  nested: \"/requests\",\n};\n\nexport const handle = {\n  breadcrumb: () => \"Collections\",\n};\n\nimport { useRequests } from \"../../../hooks/api/requests\";\nimport { useRequestTableColumns } from \"../../../hooks/table/columns/use-request-table-columns\";\nimport { useRequestTableQuery } from \"../../../hooks/table/query/use-request-table-query\";\nimport { useRequestTableFilters } from \"../../../hooks/table/filters/use-request-table-filters\";\nimport {\n  _DataTable,\n  SingleColumnPage,\n  useDataTable,\n} from \"@mercurjs/dashboard-shared\";\n\nconst PAGE_SIZE = 10;\n\nconst CollectionRequestsPage = () => {\n  const { t } = useTranslation();\n  const { raw, searchParams } = useRequestTableQuery({ pageSize: PAGE_SIZE });\n\n  const { requests, count, isError, error, isLoading } = useRequests(\n    \"product_collection\",\n    searchParams,\n    { placeholderData: keepPreviousData },\n  );\n\n  const columns = useRequestTableColumns(\"title\");\n  const filters = useRequestTableFilters();\n\n  const { table } = useDataTable({\n    data: requests ?? [],\n    columns,\n    enablePagination: true,\n    count: count,\n    pageSize: PAGE_SIZE,\n  });\n\n  if (isError) throw error;\n\n  return (\n    <SingleColumnPage>\n      <Container className=\"divide-y p-0\">\n        <div className=\"flex items-center justify-between px-6 py-4\">\n          <Heading>Collection Requests</Heading>\n        </div>\n        <_DataTable\n          columns={columns}\n          table={table}\n          pagination\n          filters={filters}\n          navigateTo={(row) => `/requests/product_collection/${row.original.id}`}\n          count={count}\n          isLoading={isLoading}\n          pageSize={PAGE_SIZE}\n          orderBy={[\n            { key: \"created_at\", label: t(\"fields.createdAt\") },\n            { key: \"updated_at\", label: t(\"fields.updatedAt\") },\n          ]}\n          queryObject={raw}\n          noRecords={{ message: \"No collection requests found\" }}\n        />\n      </Container>\n    </SingleColumnPage>\n  );\n};\n\nexport default CollectionRequestsPage;\n",
      "type": "registry:admin"
    },
    {
      "path": "requests/admin/routes/requests/tags/page.tsx",
      "content": "import { useTranslation } from \"react-i18next\";\nimport { keepPreviousData } from \"@tanstack/react-query\";\nimport { Container, Heading } from \"@medusajs/ui\";\nimport type { RouteConfig } from \"@mercurjs/dashboard-sdk\";\n\nexport const config: RouteConfig = {\n  label: \"Tags\",\n  nested: \"/requests\",\n};\n\nexport const handle = {\n  breadcrumb: () => \"Tags\",\n};\n\nimport { useRequests } from \"../../../hooks/api/requests\";\nimport { useRequestTableColumns } from \"../../../hooks/table/columns/use-request-table-columns\";\nimport { useRequestTableQuery } from \"../../../hooks/table/query/use-request-table-query\";\nimport { useRequestTableFilters } from \"../../../hooks/table/filters/use-request-table-filters\";\nimport {\n  _DataTable,\n  SingleColumnPage,\n  useDataTable,\n} from \"@mercurjs/dashboard-shared\";\n\nconst PAGE_SIZE = 10;\n\nconst TagRequestsPage = () => {\n  const { t } = useTranslation();\n  const { raw, searchParams } = useRequestTableQuery({ pageSize: PAGE_SIZE });\n\n  const { requests, count, isError, error, isLoading } = useRequests(\n    \"product_tag\",\n    searchParams,\n    { placeholderData: keepPreviousData },\n  );\n\n  const columns = useRequestTableColumns(\"value\");\n  const filters = useRequestTableFilters();\n\n  const { table } = useDataTable({\n    data: requests ?? [],\n    columns,\n    enablePagination: true,\n    count: count,\n    pageSize: PAGE_SIZE,\n  });\n\n  if (isError) throw error;\n\n  return (\n    <SingleColumnPage>\n      <Container className=\"divide-y p-0\">\n        <div className=\"flex items-center justify-between px-6 py-4\">\n          <Heading>Tag Requests</Heading>\n        </div>\n        <_DataTable\n          columns={columns}\n          table={table}\n          pagination\n          filters={filters}\n          navigateTo={(row) => `/requests/product_tag/${row.original.id}`}\n          count={count}\n          isLoading={isLoading}\n          pageSize={PAGE_SIZE}\n          orderBy={[\n            { key: \"created_at\", label: t(\"fields.createdAt\") },\n            { key: \"updated_at\", label: t(\"fields.updatedAt\") },\n          ]}\n          queryObject={raw}\n          noRecords={{ message: \"No tag requests found\" }}\n        />\n      </Container>\n    </SingleColumnPage>\n  );\n};\n\nexport default TagRequestsPage;\n",
      "type": "registry:admin"
    },
    {
      "path": "requests/admin/routes/requests/types/page.tsx",
      "content": "import { useTranslation } from \"react-i18next\";\nimport { keepPreviousData } from \"@tanstack/react-query\";\nimport { Container, Heading } from \"@medusajs/ui\";\nimport type { RouteConfig } from \"@mercurjs/dashboard-sdk\";\n\nexport const config: RouteConfig = {\n  label: \"Types\",\n  nested: \"/requests\",\n};\n\nexport const handle = {\n  breadcrumb: () => \"Types\",\n};\n\nimport { useRequests } from \"../../../hooks/api/requests\";\nimport { useRequestTableColumns } from \"../../../hooks/table/columns/use-request-table-columns\";\nimport { useRequestTableQuery } from \"../../../hooks/table/query/use-request-table-query\";\nimport { useRequestTableFilters } from \"../../../hooks/table/filters/use-request-table-filters\";\nimport {\n  _DataTable,\n  SingleColumnPage,\n  useDataTable,\n} from \"@mercurjs/dashboard-shared\";\n\nconst PAGE_SIZE = 10;\n\nconst TypeRequestsPage = () => {\n  const { t } = useTranslation();\n  const { raw, searchParams } = useRequestTableQuery({ pageSize: PAGE_SIZE });\n\n  const { requests, count, isError, error, isLoading } = useRequests(\n    \"product_type\",\n    searchParams,\n    { placeholderData: keepPreviousData },\n  );\n\n  const columns = useRequestTableColumns(\"value\");\n  const filters = useRequestTableFilters();\n\n  const { table } = useDataTable({\n    data: requests ?? [],\n    columns,\n    enablePagination: true,\n    count: count,\n    pageSize: PAGE_SIZE,\n  });\n\n  if (isError) throw error;\n\n  return (\n    <SingleColumnPage>\n      <Container className=\"divide-y p-0\">\n        <div className=\"flex items-center justify-between px-6 py-4\">\n          <Heading>Type Requests</Heading>\n        </div>\n        <_DataTable\n          columns={columns}\n          table={table}\n          pagination\n          filters={filters}\n          navigateTo={(row) => `/requests/product_type/${row.original.id}`}\n          count={count}\n          isLoading={isLoading}\n          pageSize={PAGE_SIZE}\n          orderBy={[\n            { key: \"created_at\", label: t(\"fields.createdAt\") },\n            { key: \"updated_at\", label: t(\"fields.updatedAt\") },\n          ]}\n          queryObject={raw}\n          noRecords={{ message: \"No type requests found\" }}\n        />\n      </Container>\n    </SingleColumnPage>\n  );\n};\n\nexport default TypeRequestsPage;\n",
      "type": "registry:admin"
    },
    {
      "path": "requests/admin/routes/requests/[type]/[id]/page.tsx",
      "content": "import { useParams, Link, UIMatch } from \"react-router-dom\";\nimport { useTranslation } from \"react-i18next\";\nimport { useQuery } from \"@tanstack/react-query\";\nimport {\n  Avatar,\n  Badge,\n  Button,\n  Container,\n  Heading,\n  StatusBadge,\n  Text,\n  toast,\n  usePrompt,\n} from \"@medusajs/ui\";\nimport { ExclamationCircleSolid, TriangleRightMini } from \"@medusajs/icons\";\n\nimport { SingleColumnPage } from \"@mercurjs/dashboard-shared\";\nimport {\n  useRequest,\n  useAcceptRequest,\n  useRejectRequest,\n} from \"../../../../hooks/api/requests\";\nimport { client } from \"../../../../lib/client\";\n\nconst DetailBreadcrumb = (props: UIMatch) => {\n  const { type, id } = props.params || {};\n  const { request } = useRequest(type!, id!, {\n    enabled: Boolean(type && id),\n  });\n\n  if (!request) return null;\n\n  const nameKey = ENTITY_NAME_KEY[type!] ?? \"name\";\n  const name = (request as Record<string, any>)[nameKey];\n\n  return <span>{name ?? id}</span>;\n};\n\nexport const handle = {\n  breadcrumb: (match: UIMatch) => <DetailBreadcrumb {...match} />,\n};\n\nconst statusColor = (status: string) => {\n  switch (status) {\n    case \"accepted\":\n      return \"green\" as const;\n    case \"pending\":\n      return \"orange\" as const;\n    case \"rejected\":\n      return \"red\" as const;\n    default:\n      return \"grey\" as const;\n  }\n};\n\nconst TYPE_LABELS: Record<string, string> = {\n  product_category: \"Category\",\n  product_collection: \"Collection\",\n  product_tag: \"Tag\",\n  product_type: \"Type\",\n};\n\nconst ENTITY_FIELDS: Record<string, { key: string; label: string }[]> = {\n  product_category: [\n    { key: \"name\", label: \"Name\" },\n    { key: \"handle\", label: \"Handle\" },\n    { key: \"description\", label: \"Description\" },\n    { key: \"is_active\", label: \"Active\" },\n    { key: \"is_internal\", label: \"Internal\" },\n  ],\n  product_collection: [\n    { key: \"title\", label: \"Title\" },\n    { key: \"handle\", label: \"Handle\" },\n  ],\n  product_tag: [{ key: \"value\", label: \"Value\" }],\n  product_type: [{ key: \"value\", label: \"Value\" }],\n};\n\nconst ENTITY_NAME_KEY: Record<string, string> = {\n  product_category: \"name\",\n  product_collection: \"title\",\n  product_tag: \"value\",\n  product_type: \"value\",\n};\n\nconst formatFieldValue = (key: string, value: unknown): string => {\n  if (value === null || value === undefined) return \"-\";\n  if (typeof value === \"boolean\") return value ? \"Yes\" : \"No\";\n  return String(value);\n};\n\nconst SectionRow = ({\n  title,\n  value,\n}: {\n  title: string;\n  value?: string | null;\n}) => (\n  <div className=\"text-ui-fg-subtle grid grid-cols-2 items-center gap-4 px-6 py-4\">\n    <Text size=\"small\" weight=\"plus\" leading=\"compact\">\n      {title}\n    </Text>\n    <Text\n      size=\"small\"\n      leading=\"compact\"\n      className=\"whitespace-pre-line text-pretty\"\n    >\n      {value ?? \"-\"}\n    </Text>\n  </div>\n);\n\nconst useSeller = (id?: string | null) => {\n  const { data, ...rest } = useQuery({\n    queryKey: [\"seller\", id],\n    queryFn: () => client.admin.sellers.$id.query({ $id: id! }),\n    enabled: !!id,\n  });\n\n  return { seller: (data as any)?.seller, ...rest };\n};\n\nconst useUser = (id?: string | null) => {\n  const { data, ...rest } = useQuery({\n    queryKey: [\"user\", id],\n    queryFn: () => client.admin.users.$id.query({ $id: id! }),\n    enabled: !!id,\n  });\n\n  return { user: (data as any)?.user, ...rest };\n};\n\nconst RequestDetailPage = () => {\n  const { type, id } = useParams<{ type: string; id: string }>();\n  const { t } = useTranslation();\n  const prompt = usePrompt();\n\n  const { request, isLoading, isError, error } = useRequest(type!, id!);\n\n  const { mutateAsync: acceptRequest, isPending: isAccepting } =\n    useAcceptRequest(type!, id!);\n\n  const { mutateAsync: rejectRequest, isPending: isRejecting } =\n    useRejectRequest(type!, id!);\n\n  const customFields = (request?.custom_fields ?? {}) as Record<string, any>;\n\n  const { seller } = useSeller(customFields?.submitter_id);\n  const { user } = useUser(customFields?.reviewer_id);\n\n  if (isLoading || !request) {\n    return (\n      <SingleColumnPage>\n        <Container className=\"animate-pulse p-6\">\n          <div className=\"h-6 w-48 rounded bg-gray-200\" />\n        </Container>\n      </SingleColumnPage>\n    );\n  }\n\n  if (isError) throw error;\n\n  const status = customFields?.request_status ?? \"draft\";\n  const isPending = status === \"pending\";\n  const entityFields = ENTITY_FIELDS[type!] ?? [];\n  const typeLabel = TYPE_LABELS[type!] ?? type;\n  const nameKey = ENTITY_NAME_KEY[type!] ?? \"name\";\n  const entityName = (request as Record<string, any>)[nameKey] ?? request.id;\n\n  const handleAccept = async () => {\n    const res = await prompt({\n      title: \"Accept request\",\n      description:\n        \"Are you sure you want to accept this request? This action will create the entity.\",\n      verificationText: entityName,\n      confirmText: t(\"actions.confirm\"),\n      cancelText: t(\"actions.cancel\"),\n    });\n\n    if (!res) return;\n\n    await acceptRequest(\n      {},\n      {\n        onSuccess: () => toast.success(\"Request accepted\"),\n        onError: (err) => toast.error(err.message),\n      },\n    );\n  };\n\n  const handleReject = async () => {\n    const res = await prompt({\n      title: \"Reject request\",\n      description:\n        \"Are you sure you want to reject this request? This action cannot be undone.\",\n      verificationText: entityName,\n      confirmText: t(\"actions.confirm\"),\n      cancelText: t(\"actions.cancel\"),\n    });\n\n    if (!res) return;\n\n    await rejectRequest(\n      {},\n      {\n        onSuccess: () => toast.success(\"Request rejected\"),\n        onError: (err) => toast.error(err.message),\n      },\n    );\n  };\n\n  return (\n    <SingleColumnPage hasOutlet={false}>\n      {/* Pending Action Banner */}\n      {isPending && (\n        <div\n          style={{\n            background:\n              \"repeating-linear-gradient(-45deg, rgb(212, 212, 216, 0.15), rgb(212, 212, 216,.15) 10px, transparent 10px, transparent 20px)\",\n          }}\n          className=\"-m-4 mb-1 border-b border-l p-4\"\n        >\n          <Container className=\"flex items-center justify-between p-0\">\n            <div className=\"flex w-full flex-col divide-y divide-dashed\">\n              <div className=\"flex items-center gap-2 px-6 py-4\">\n                <ExclamationCircleSolid className=\"text-orange-500\" />\n                <Heading level=\"h2\">Pending review</Heading>\n              </div>\n              <div className=\"bg-ui-bg-subtle flex items-center justify-end gap-x-2 rounded-b-xl px-4 py-4\">\n                <Button\n                  variant=\"secondary\"\n                  size=\"small\"\n                  onClick={handleReject}\n                  disabled={isAccepting || isRejecting}\n                >\n                  Reject\n                </Button>\n                <Button\n                  variant=\"primary\"\n                  size=\"small\"\n                  onClick={handleAccept}\n                  disabled={isAccepting || isRejecting}\n                >\n                  Accept\n                </Button>\n              </div>\n            </div>\n          </Container>\n        </div>\n      )}\n\n      {/* General */}\n      <Container className=\"divide-y p-0\">\n        <div className=\"flex items-center justify-between px-6 py-4\">\n          <Heading>{entityName}</Heading>\n          <div className=\"flex items-center gap-x-4\">\n            <StatusBadge color={statusColor(status)}>\n              {status.charAt(0).toUpperCase() + status.slice(1)}\n            </StatusBadge>\n            <Badge size=\"2xsmall\" color=\"grey\">\n              {typeLabel}\n            </Badge>\n          </div>\n        </div>\n        {entityFields.map(({ key, label }) => {\n          const value = (request as Record<string, any>)[key];\n          if (value === undefined) return null;\n          return (\n            <SectionRow\n              key={key}\n              title={label}\n              value={formatFieldValue(key, value)}\n            />\n          );\n        })}\n      </Container>\n\n      {/* Submitter (Seller) */}\n      <Container className=\"divide-y p-0\">\n        <div className=\"px-6 py-4\">\n          <Heading level=\"h2\">Submitter</Heading>\n        </div>\n        <div className=\"px-6 py-4\">\n          {seller ? (\n            <Link\n              to={`/sellers/${seller.id}`}\n              className=\"outline-none focus-within:shadow-borders-interactive-with-focus rounded-md [&:hover>div]:bg-ui-bg-component-hover\"\n            >\n              <div className=\"shadow-elevation-card-rest bg-ui-bg-component rounded-md px-4 py-3 transition-colors\">\n                <div className=\"flex items-center gap-3\">\n                  <Avatar\n                    src={seller.logo ?? undefined}\n                    fallback={seller.name?.charAt(0).toUpperCase() ?? \"S\"}\n                  />\n                  <div className=\"flex flex-1 flex-col\">\n                    <span className=\"text-ui-fg-base txt-small font-medium\">\n                      {seller.name}\n                    </span>\n                  </div>\n                  <div className=\"size-7 flex items-center justify-center\">\n                    <TriangleRightMini className=\"text-ui-fg-muted\" />\n                  </div>\n                </div>\n              </div>\n            </Link>\n          ) : (\n            <Text size=\"small\" className=\"text-ui-fg-muted\">\n              {customFields?.submitter_id ?? \"-\"}\n            </Text>\n          )}\n        </div>\n      </Container>\n\n      {/* Reviewer (User) */}\n      {customFields?.reviewer_id && (\n        <Container className=\"divide-y p-0\">\n          <div className=\"px-6 py-4\">\n            <Heading level=\"h2\">Reviewer</Heading>\n          </div>\n          <div className=\"px-6 py-4\">\n            {user ? (\n              <div className=\"shadow-elevation-card-rest bg-ui-bg-component rounded-md px-4 py-3\">\n                <div className=\"flex items-center gap-3\">\n                  <Avatar\n                    fallback={(user.first_name ?? user.email ?? \"U\")\n                      .charAt(0)\n                      .toUpperCase()}\n                  />\n                  <div className=\"flex flex-1 flex-col\">\n                    <span className=\"text-ui-fg-base txt-small font-medium\">\n                      {[user.first_name, user.last_name]\n                        .filter(Boolean)\n                        .join(\" \") || user.email}\n                    </span>\n                    {user.first_name && user.email && (\n                      <span className=\"text-ui-fg-muted text-xs\">\n                        {user.email}\n                      </span>\n                    )}\n                  </div>\n                </div>\n              </div>\n            ) : (\n              <Text size=\"small\" className=\"text-ui-fg-muted\">\n                {customFields.reviewer_id}\n              </Text>\n            )}\n          </div>\n        </Container>\n      )}\n    </SingleColumnPage>\n  );\n};\n\nexport default RequestDetailPage;\n",
      "type": "registry:admin"
    },
    {
      "path": "requests/vendor/hooks/api/requests.tsx",
      "content": "import {\n  useQuery,\n  useMutation,\n  useQueryClient,\n  UseQueryOptions,\n  UseMutationOptions,\n} from \"@tanstack/react-query\";\nimport { queryKeysFactory } from \"@mercurjs/dashboard-shared\";\nimport { client } from \"../../lib/client\";\nimport { ClientError } from \"@mercurjs/client\";\n\nconst REQUESTS_QUERY_KEY = \"vendor_requests\" as const;\nexport const requestsQueryKeys = queryKeysFactory(REQUESTS_QUERY_KEY);\n\nexport type VendorRequestDTO = Record<string, any>;\n\ntype RequestType =\n  | \"product_category\"\n  | \"product_collection\"\n  | \"product_tag\"\n  | \"product_type\";\n\nconst clientMap = {\n  product_category: client.vendor.requests.productCategories,\n  product_collection: client.vendor.requests.productCollections,\n  product_tag: client.vendor.requests.productTags,\n  product_type: client.vendor.requests.productTypes,\n} as Record<string, any>;\n\nexport const useVendorRequests = (\n  type: RequestType,\n  query?: Record<string, any>,\n  options?: Omit<UseQueryOptions<unknown, ClientError, any>, \"queryKey\" | \"queryFn\">,\n) => {\n  const { data, ...rest } = useQuery({\n    queryKey: requestsQueryKeys.list({ type, ...query }),\n    queryFn: async () => clientMap[type].query({ ...query }),\n    ...options,\n  });\n\n  return { ...data, ...rest };\n};\n\nexport const useCreateVendorRequest = (\n  type: RequestType,\n  options?: UseMutationOptions<any, ClientError, Record<string, any>>,\n) => {\n  const queryClient = useQueryClient();\n\n  return useMutation({\n    mutationFn: (payload: Record<string, any>) =>\n      clientMap[type].mutate(payload),\n    onSuccess: (data, variables, context) => {\n      queryClient.invalidateQueries({\n        queryKey: requestsQueryKeys.lists(),\n      });\n      options?.onSuccess?.(data, variables, context);\n    },\n    ...options,\n  });\n};\n",
      "type": "registry:vendor"
    },
    {
      "path": "requests/vendor/hooks/table/columns/use-request-table-columns.tsx",
      "content": "import { createColumnHelper } from \"@tanstack/react-table\";\nimport { useMemo } from \"react\";\nimport { useTranslation } from \"react-i18next\";\nimport { StatusBadge, Text } from \"@medusajs/ui\";\nimport { DateCell, DateHeader } from \"@mercurjs/dashboard-shared\";\nimport { VendorRequestDTO } from \"../../api/requests\";\n\nconst columnHelper = createColumnHelper<VendorRequestDTO>();\n\nconst statusColor = (status: string) => {\n  switch (status) {\n    case \"accepted\":\n      return \"green\" as const;\n    case \"pending\":\n      return \"orange\" as const;\n    case \"rejected\":\n      return \"red\" as const;\n    default:\n      return \"grey\" as const;\n  }\n};\n\nexport const useRequestTableColumns = (nameKey: string = \"name\") => {\n  const { t } = useTranslation();\n\n  return useMemo(\n    () => [\n      columnHelper.display({\n        id: \"display_name\",\n        header: () => (\n          <div className=\"flex h-full w-full items-center\">\n            <span className=\"truncate\">Name</span>\n          </div>\n        ),\n        cell: ({ row }) => (\n          <Text size=\"small\" leading=\"compact\">\n            {row.original[nameKey] ?? row.original.id}\n          </Text>\n        ),\n      }),\n      columnHelper.accessor(\"custom_fields\", {\n        header: () => (\n          <div className=\"flex h-full w-full items-center\">\n            <span className=\"truncate\">Status</span>\n          </div>\n        ),\n        cell: ({ getValue }) => {\n          const customFields = getValue() as any;\n          const status = customFields?.request_status ?? \"draft\";\n          return (\n            <StatusBadge color={statusColor(status)}>\n              {status.charAt(0).toUpperCase() + status.slice(1)}\n            </StatusBadge>\n          );\n        },\n      }),\n      columnHelper.accessor(\"created_at\", {\n        header: () => <DateHeader />,\n        cell: ({ getValue }) => {\n          const date = new Date(getValue() as string);\n          return <DateCell date={date} />;\n        },\n      }),\n    ],\n    [t, nameKey],\n  );\n};\n",
      "type": "registry:vendor"
    },
    {
      "path": "requests/vendor/hooks/table/filters/use-request-table-filters.tsx",
      "content": "import { useTranslation } from \"react-i18next\";\nimport { useMemo } from \"react\";\n\nimport type { Filter } from \"@mercurjs/dashboard-shared\";\n\nexport const useRequestTableFilters = (): Filter[] => {\n  const { t } = useTranslation();\n\n  return useMemo(() => {\n    const filters: Filter[] = [\n      {\n        key: \"request_status\",\n        label: \"Status\",\n        type: \"select\",\n        multiple: true,\n        options: [\n          { label: \"Draft\", value: \"draft\" },\n          { label: \"Pending\", value: \"pending\" },\n          { label: \"Accepted\", value: \"accepted\" },\n          { label: \"Rejected\", value: \"rejected\" },\n        ],\n      },\n    ];\n\n    const dateFilters: Filter[] = [\n      { label: t(\"fields.createdAt\"), key: \"created_at\" },\n      { label: t(\"fields.updatedAt\"), key: \"updated_at\" },\n    ].map((f) => ({\n      key: f.key,\n      label: f.label,\n      type: \"date\" as const,\n    }));\n\n    filters.push(...dateFilters);\n\n    return filters;\n  }, [t]);\n};\n",
      "type": "registry:vendor"
    },
    {
      "path": "requests/vendor/hooks/table/query/use-request-table-query.tsx",
      "content": "import { useQueryParams } from \"@mercurjs/dashboard-shared\";\n\ntype UseRequestTableQueryProps = {\n  prefix?: string;\n  pageSize?: number;\n};\n\nexport const useRequestTableQuery = ({\n  prefix,\n  pageSize = 20,\n}: UseRequestTableQueryProps) => {\n  const queryObject = useQueryParams(\n    [\"offset\", \"q\", \"created_at\", \"updated_at\", \"order\", \"request_status\"],\n    prefix,\n  );\n\n  const { offset, created_at, updated_at, q, order, request_status } = queryObject;\n\n  const searchParams: Record<string, any> = {\n    limit: pageSize,\n    offset: offset ? Number(offset) : 0,\n    created_at: created_at ? JSON.parse(created_at) : undefined,\n    updated_at: updated_at ? JSON.parse(updated_at) : undefined,\n    order: order ? order : \"-created_at\",\n    request_status: request_status || undefined,\n    q,\n  };\n\n  return {\n    searchParams,\n    raw: queryObject,\n  };\n};\n",
      "type": "registry:vendor"
    },
    {
      "path": "requests/vendor/routes/requests/page.tsx",
      "content": "import { Navigate } from \"react-router-dom\";\nimport type { RouteConfig } from \"@mercurjs/dashboard-sdk\";\nimport { InboxSolid } from \"@medusajs/icons\";\n\nexport const config: RouteConfig = {\n  label: \"Requests\",\n  icon: InboxSolid,\n};\n\nexport const handle = {\n  breadcrumb: () => \"Requests\",\n};\n\nconst RequestsPage = () => {\n  return <Navigate to=\"/requests/categories\" replace />;\n};\n\nexport default RequestsPage;\n",
      "type": "registry:vendor"
    },
    {
      "path": "requests/vendor/routes/requests/categories/page.tsx",
      "content": "import { useTranslation } from \"react-i18next\";\nimport { Link } from \"react-router-dom\";\nimport { keepPreviousData } from \"@tanstack/react-query\";\nimport { Button, Container, Heading } from \"@medusajs/ui\";\nimport type { RouteConfig } from \"@mercurjs/dashboard-sdk\";\n\nexport const config: RouteConfig = {\n  label: \"Categories\",\n  nested: \"/requests\",\n};\n\nexport const handle = {\n  breadcrumb: () => \"Categories\",\n};\n\nimport { useVendorRequests } from \"../../../hooks/api/requests\";\nimport { useRequestTableColumns } from \"../../../hooks/table/columns/use-request-table-columns\";\nimport { useRequestTableQuery } from \"../../../hooks/table/query/use-request-table-query\";\nimport { useRequestTableFilters } from \"../../../hooks/table/filters/use-request-table-filters\";\nimport {\n  _DataTable,\n  SingleColumnPage,\n  useDataTable,\n} from \"@mercurjs/dashboard-shared\";\n\nconst PAGE_SIZE = 10;\n\nconst VendorCategoryRequestsPage = () => {\n  const { t } = useTranslation();\n  const { raw, searchParams } = useRequestTableQuery({ pageSize: PAGE_SIZE });\n\n  const { requests, count, isError, error, isLoading } = useVendorRequests(\n    \"product_category\",\n    searchParams,\n    { placeholderData: keepPreviousData },\n  );\n\n  const columns = useRequestTableColumns(\"name\");\n  const filters = useRequestTableFilters();\n\n  const { table } = useDataTable({\n    data: requests ?? [],\n    columns,\n    enablePagination: true,\n    count: count,\n    pageSize: PAGE_SIZE,\n  });\n\n  if (isError) throw error;\n\n  return (\n    <SingleColumnPage>\n      <Container className=\"divide-y p-0\">\n        <div className=\"flex items-center justify-between px-6 py-4\">\n          <Heading>Category Requests</Heading>\n          <Button size=\"small\" variant=\"secondary\" asChild>\n            <Link to=\"create\">{t(\"actions.create\")}</Link>\n          </Button>\n        </div>\n        <_DataTable\n          columns={columns}\n          table={table}\n          pagination\n          filters={filters}\n          count={count}\n          isLoading={isLoading}\n          pageSize={PAGE_SIZE}\n          orderBy={[\n            { key: \"created_at\", label: t(\"fields.createdAt\") },\n            { key: \"updated_at\", label: t(\"fields.updatedAt\") },\n          ]}\n          queryObject={raw}\n          noRecords={{ message: \"No category requests found\" }}\n        />\n      </Container>\n    </SingleColumnPage>\n  );\n};\n\nexport default VendorCategoryRequestsPage;\n",
      "type": "registry:vendor"
    },
    {
      "path": "requests/vendor/routes/requests/categories/create/page.tsx",
      "content": "import { zodResolver } from \"@hookform/resolvers/zod\";\nimport {\n  Button,\n  Heading,\n  Input,\n  Select,\n  Text,\n  Textarea,\n  toast,\n} from \"@medusajs/ui\";\nimport { useForm } from \"react-hook-form\";\nimport { useTranslation } from \"react-i18next\";\nimport * as zod from \"zod\";\n\nimport {\n  Form,\n  RouteFocusModal,\n  useRouteModal,\n} from \"@mercurjs/dashboard-shared\";\nimport { useCreateVendorRequest } from \"../../../../hooks/api/requests\";\n\nconst CreateCategoryRequestSchema = zod.object({\n  name: zod.string().min(1),\n  handle: zod.string().optional(),\n  description: zod.string().optional(),\n  is_active: zod.boolean().optional(),\n  is_internal: zod.boolean().optional(),\n});\n\nconst CategoryRequestCreateForm = () => {\n  const { t } = useTranslation();\n  const { handleSuccess } = useRouteModal();\n\n  const form = useForm<zod.infer<typeof CreateCategoryRequestSchema>>({\n    defaultValues: {\n      name: \"\",\n      handle: \"\",\n      description: \"\",\n      is_active: true,\n      is_internal: false,\n    },\n    resolver: zodResolver(CreateCategoryRequestSchema),\n  });\n\n  const { mutateAsync, isPending } = useCreateVendorRequest(\"product_category\");\n\n  const handleSubmit = form.handleSubmit(async ({ handle, ...data }) => {\n    const payload = handle ? { ...data, handle } : data;\n    await mutateAsync(payload, {\n      onSuccess: () => {\n        toast.success(\"Category request created successfully\");\n        handleSuccess(`/requests/categories`);\n      },\n      onError: (error) => {\n        toast.error(error.message);\n      },\n    });\n  });\n\n  return (\n    <RouteFocusModal.Form form={form}>\n      <form\n        onSubmit={handleSubmit}\n        className=\"flex h-full flex-col overflow-hidden\"\n      >\n        <RouteFocusModal.Header />\n        <RouteFocusModal.Body className=\"flex size-full flex-col items-center overflow-auto p-16\">\n          <div className=\"flex w-full max-w-[720px] flex-col gap-y-8\">\n            <div>\n              <Heading>Request Category</Heading>\n              <Text size=\"small\" className=\"text-ui-fg-subtle\">\n                Submit a request to create a new product category.\n              </Text>\n            </div>\n            <div className=\"grid grid-cols-1 gap-4 md:grid-cols-2\">\n              <Form.Field\n                control={form.control}\n                name=\"name\"\n                render={({ field }) => (\n                  <Form.Item>\n                    <Form.Label>{t(\"fields.name\")}</Form.Label>\n                    <Form.Control>\n                      <Input autoComplete=\"off\" {...field} />\n                    </Form.Control>\n                    <Form.ErrorMessage />\n                  </Form.Item>\n                )}\n              />\n              <Form.Field\n                control={form.control}\n                name=\"handle\"\n                render={({ field }) => (\n                  <Form.Item>\n                    <Form.Label optional>{t(\"fields.handle\")}</Form.Label>\n                    <Form.Control>\n                      <Input autoComplete=\"off\" {...field} />\n                    </Form.Control>\n                    <Form.ErrorMessage />\n                  </Form.Item>\n                )}\n              />\n              <Form.Field\n                control={form.control}\n                name=\"description\"\n                render={({ field }) => (\n                  <Form.Item className=\"col-span-full\">\n                    <Form.Label optional>{t(\"fields.description\")}</Form.Label>\n                    <Form.Control>\n                      <Textarea {...field} />\n                    </Form.Control>\n                    <Form.ErrorMessage />\n                  </Form.Item>\n                )}\n              />\n              <Form.Field\n                control={form.control}\n                name=\"is_active\"\n                render={({ field }) => (\n                  <Form.Item>\n                    <Form.Label>{t(\"fields.status\")}</Form.Label>\n                    <Form.Control>\n                      <Select\n                        value={field.value ? \"active\" : \"inactive\"}\n                        onValueChange={(v) => field.onChange(v === \"active\")}\n                      >\n                        <Select.Trigger>\n                          <Select.Value />\n                        </Select.Trigger>\n                        <Select.Content>\n                          <Select.Item value=\"active\">\n                            {t(\"categories.fields.status.active\")}\n                          </Select.Item>\n                          <Select.Item value=\"inactive\">\n                            {t(\"categories.fields.status.inactive\")}\n                          </Select.Item>\n                        </Select.Content>\n                      </Select>\n                    </Form.Control>\n                  </Form.Item>\n                )}\n              />\n              <Form.Field\n                control={form.control}\n                name=\"is_internal\"\n                render={({ field }) => (\n                  <Form.Item>\n                    <Form.Label>Visibility</Form.Label>\n                    <Form.Control>\n                      <Select\n                        value={field.value ? \"internal\" : \"public\"}\n                        onValueChange={(v) => field.onChange(v === \"internal\")}\n                      >\n                        <Select.Trigger>\n                          <Select.Value />\n                        </Select.Trigger>\n                        <Select.Content>\n                          <Select.Item value=\"public\">\n                            {t(\"categories.fields.visibility.public\")}\n                          </Select.Item>\n                          <Select.Item value=\"internal\">\n                            {t(\"categories.fields.visibility.internal\")}\n                          </Select.Item>\n                        </Select.Content>\n                      </Select>\n                    </Form.Control>\n                  </Form.Item>\n                )}\n              />\n            </div>\n          </div>\n        </RouteFocusModal.Body>\n        <RouteFocusModal.Footer>\n          <RouteFocusModal.Close asChild>\n            <Button size=\"small\" variant=\"secondary\">\n              {t(\"actions.cancel\")}\n            </Button>\n          </RouteFocusModal.Close>\n          <Button\n            size=\"small\"\n            variant=\"primary\"\n            type=\"submit\"\n            isLoading={isPending}\n          >\n            {t(\"actions.create\")}\n          </Button>\n        </RouteFocusModal.Footer>\n      </form>\n    </RouteFocusModal.Form>\n  );\n};\n\nconst CategoryRequestCreatePage = () => {\n  return (\n    <RouteFocusModal>\n      <CategoryRequestCreateForm />\n    </RouteFocusModal>\n  );\n};\n\nexport default CategoryRequestCreatePage;\n",
      "type": "registry:vendor"
    },
    {
      "path": "requests/vendor/routes/requests/collections/page.tsx",
      "content": "import { useTranslation } from \"react-i18next\";\nimport { Link } from \"react-router-dom\";\nimport { keepPreviousData } from \"@tanstack/react-query\";\nimport { Button, Container, Heading } from \"@medusajs/ui\";\nimport type { RouteConfig } from \"@mercurjs/dashboard-sdk\";\n\nexport const config: RouteConfig = {\n  label: \"Collections\",\n  nested: \"/requests\",\n};\n\nexport const handle = {\n  breadcrumb: () => \"Collections\",\n};\n\nimport { useVendorRequests } from \"../../../hooks/api/requests\";\nimport { useRequestTableColumns } from \"../../../hooks/table/columns/use-request-table-columns\";\nimport { useRequestTableQuery } from \"../../../hooks/table/query/use-request-table-query\";\nimport { useRequestTableFilters } from \"../../../hooks/table/filters/use-request-table-filters\";\nimport {\n  _DataTable,\n  SingleColumnPage,\n  useDataTable,\n} from \"@mercurjs/dashboard-shared\";\n\nconst PAGE_SIZE = 10;\n\nconst VendorCollectionRequestsPage = () => {\n  const { t } = useTranslation();\n  const { raw, searchParams } = useRequestTableQuery({ pageSize: PAGE_SIZE });\n\n  const { requests, count, isError, error, isLoading } = useVendorRequests(\n    \"product_collection\",\n    searchParams,\n    { placeholderData: keepPreviousData },\n  );\n\n  const columns = useRequestTableColumns(\"title\");\n  const filters = useRequestTableFilters();\n\n  const { table } = useDataTable({\n    data: requests ?? [],\n    columns,\n    enablePagination: true,\n    count: count,\n    pageSize: PAGE_SIZE,\n  });\n\n  if (isError) throw error;\n\n  return (\n    <SingleColumnPage>\n      <Container className=\"divide-y p-0\">\n        <div className=\"flex items-center justify-between px-6 py-4\">\n          <Heading>Collection Requests</Heading>\n          <Button size=\"small\" variant=\"secondary\" asChild>\n            <Link to=\"create\">{t(\"actions.create\")}</Link>\n          </Button>\n        </div>\n        <_DataTable\n          columns={columns}\n          table={table}\n          pagination\n          filters={filters}\n          count={count}\n          isLoading={isLoading}\n          pageSize={PAGE_SIZE}\n          orderBy={[\n            { key: \"created_at\", label: t(\"fields.createdAt\") },\n            { key: \"updated_at\", label: t(\"fields.updatedAt\") },\n          ]}\n          queryObject={raw}\n          noRecords={{ message: \"No collection requests found\" }}\n        />\n      </Container>\n    </SingleColumnPage>\n  );\n};\n\nexport default VendorCollectionRequestsPage;\n",
      "type": "registry:vendor"
    },
    {
      "path": "requests/vendor/routes/requests/collections/create/page.tsx",
      "content": "import { zodResolver } from \"@hookform/resolvers/zod\";\nimport { Button, Heading, Input, Text, toast } from \"@medusajs/ui\";\nimport { useForm } from \"react-hook-form\";\nimport { useTranslation } from \"react-i18next\";\nimport * as zod from \"zod\";\n\nimport {\n  Form,\n  RouteFocusModal,\n  useRouteModal,\n} from \"@mercurjs/dashboard-shared\";\nimport { useCreateVendorRequest } from \"../../../../hooks/api/requests\";\n\nconst CreateCollectionRequestSchema = zod.object({\n  title: zod.string().min(1),\n  handle: zod.string().optional(),\n});\n\nconst CollectionRequestCreateForm = () => {\n  const { t } = useTranslation();\n  const { handleSuccess } = useRouteModal();\n\n  const form = useForm<zod.infer<typeof CreateCollectionRequestSchema>>({\n    defaultValues: {\n      title: \"\",\n      handle: \"\",\n    },\n    resolver: zodResolver(CreateCollectionRequestSchema),\n  });\n\n  const { mutateAsync, isPending } = useCreateVendorRequest(\n    \"product_collection\",\n  );\n\n  const handleSubmit = form.handleSubmit(async (data) => {\n    await mutateAsync(data, {\n      onSuccess: () => {\n        toast.success(\"Collection request created successfully\");\n        handleSuccess(`/requests/collections`);\n      },\n      onError: (error) => {\n        toast.error(error.message);\n      },\n    });\n  });\n\n  return (\n    <RouteFocusModal.Form form={form}>\n      <form\n        onSubmit={handleSubmit}\n        className=\"flex h-full flex-col overflow-hidden\"\n      >\n        <RouteFocusModal.Header />\n        <RouteFocusModal.Body className=\"flex size-full flex-col items-center p-16\">\n          <div className=\"flex w-full max-w-[720px] flex-col gap-y-8\">\n            <div>\n              <Heading>Request Collection</Heading>\n              <Text size=\"small\" className=\"text-ui-fg-subtle\">\n                Submit a request to create a new product collection.\n              </Text>\n            </div>\n            <div className=\"grid grid-cols-1 gap-4 md:grid-cols-2\">\n              <Form.Field\n                control={form.control}\n                name=\"title\"\n                render={({ field }) => (\n                  <Form.Item>\n                    <Form.Label>{t(\"fields.title\")}</Form.Label>\n                    <Form.Control>\n                      <Input autoComplete=\"off\" {...field} />\n                    </Form.Control>\n                    <Form.ErrorMessage />\n                  </Form.Item>\n                )}\n              />\n              <Form.Field\n                control={form.control}\n                name=\"handle\"\n                render={({ field }) => (\n                  <Form.Item>\n                    <Form.Label optional>{t(\"fields.handle\")}</Form.Label>\n                    <Form.Control>\n                      <Input autoComplete=\"off\" {...field} />\n                    </Form.Control>\n                    <Form.ErrorMessage />\n                  </Form.Item>\n                )}\n              />\n            </div>\n          </div>\n        </RouteFocusModal.Body>\n        <RouteFocusModal.Footer>\n          <RouteFocusModal.Close asChild>\n            <Button size=\"small\" variant=\"secondary\">\n              {t(\"actions.cancel\")}\n            </Button>\n          </RouteFocusModal.Close>\n          <Button\n            size=\"small\"\n            variant=\"primary\"\n            type=\"submit\"\n            isLoading={isPending}\n          >\n            {t(\"actions.create\")}\n          </Button>\n        </RouteFocusModal.Footer>\n      </form>\n    </RouteFocusModal.Form>\n  );\n};\n\nconst CollectionRequestCreatePage = () => {\n  return (\n    <RouteFocusModal>\n      <CollectionRequestCreateForm />\n    </RouteFocusModal>\n  );\n};\n\nexport default CollectionRequestCreatePage;\n",
      "type": "registry:vendor"
    },
    {
      "path": "requests/vendor/routes/requests/tags/page.tsx",
      "content": "import { useTranslation } from \"react-i18next\";\nimport { Link } from \"react-router-dom\";\nimport { keepPreviousData } from \"@tanstack/react-query\";\nimport { Button, Container, Heading } from \"@medusajs/ui\";\nimport type { RouteConfig } from \"@mercurjs/dashboard-sdk\";\n\nexport const config: RouteConfig = {\n  label: \"Tags\",\n  nested: \"/requests\",\n};\n\nexport const handle = {\n  breadcrumb: () => \"Tags\",\n};\n\nimport { useVendorRequests } from \"../../../hooks/api/requests\";\nimport { useRequestTableColumns } from \"../../../hooks/table/columns/use-request-table-columns\";\nimport { useRequestTableQuery } from \"../../../hooks/table/query/use-request-table-query\";\nimport { useRequestTableFilters } from \"../../../hooks/table/filters/use-request-table-filters\";\nimport {\n  _DataTable,\n  SingleColumnPage,\n  useDataTable,\n} from \"@mercurjs/dashboard-shared\";\n\nconst PAGE_SIZE = 10;\n\nconst VendorTagRequestsPage = () => {\n  const { t } = useTranslation();\n  const { raw, searchParams } = useRequestTableQuery({ pageSize: PAGE_SIZE });\n\n  const { requests, count, isError, error, isLoading } = useVendorRequests(\n    \"product_tag\",\n    searchParams,\n    { placeholderData: keepPreviousData },\n  );\n\n  const columns = useRequestTableColumns(\"value\");\n  const filters = useRequestTableFilters();\n\n  const { table } = useDataTable({\n    data: requests ?? [],\n    columns,\n    enablePagination: true,\n    count: count,\n    pageSize: PAGE_SIZE,\n  });\n\n  if (isError) throw error;\n\n  return (\n    <SingleColumnPage>\n      <Container className=\"divide-y p-0\">\n        <div className=\"flex items-center justify-between px-6 py-4\">\n          <Heading>Tag Requests</Heading>\n          <Button size=\"small\" variant=\"secondary\" asChild>\n            <Link to=\"create\">{t(\"actions.create\")}</Link>\n          </Button>\n        </div>\n        <_DataTable\n          columns={columns}\n          table={table}\n          pagination\n          filters={filters}\n          count={count}\n          isLoading={isLoading}\n          pageSize={PAGE_SIZE}\n          orderBy={[\n            { key: \"created_at\", label: t(\"fields.createdAt\") },\n            { key: \"updated_at\", label: t(\"fields.updatedAt\") },\n          ]}\n          queryObject={raw}\n          noRecords={{ message: \"No tag requests found\" }}\n        />\n      </Container>\n    </SingleColumnPage>\n  );\n};\n\nexport default VendorTagRequestsPage;\n",
      "type": "registry:vendor"
    },
    {
      "path": "requests/vendor/routes/requests/tags/create/page.tsx",
      "content": "import { zodResolver } from \"@hookform/resolvers/zod\";\nimport { Button, Heading, Input, Text, toast } from \"@medusajs/ui\";\nimport { useForm } from \"react-hook-form\";\nimport { useTranslation } from \"react-i18next\";\nimport * as zod from \"zod\";\n\nimport {\n  Form,\n  RouteFocusModal,\n  useRouteModal,\n} from \"@mercurjs/dashboard-shared\";\nimport { useCreateVendorRequest } from \"../../../../hooks/api/requests\";\n\nconst CreateTagRequestSchema = zod.object({\n  value: zod.string().min(1),\n});\n\nconst TagRequestCreateForm = () => {\n  const { t } = useTranslation();\n  const { handleSuccess } = useRouteModal();\n\n  const form = useForm<zod.infer<typeof CreateTagRequestSchema>>({\n    defaultValues: {\n      value: \"\",\n    },\n    resolver: zodResolver(CreateTagRequestSchema),\n  });\n\n  const { mutateAsync, isPending } = useCreateVendorRequest(\"product_tag\");\n\n  const handleSubmit = form.handleSubmit(async (data) => {\n    await mutateAsync(data, {\n      onSuccess: () => {\n        toast.success(\"Tag request created successfully\");\n        handleSuccess(`/requests/tags`);\n      },\n      onError: (error) => {\n        toast.error(error.message);\n      },\n    });\n  });\n\n  return (\n    <RouteFocusModal.Form form={form}>\n      <form\n        onSubmit={handleSubmit}\n        className=\"flex h-full flex-col overflow-hidden\"\n      >\n        <RouteFocusModal.Header />\n        <RouteFocusModal.Body className=\"flex size-full flex-col items-center p-16\">\n          <div className=\"flex w-full max-w-[720px] flex-col gap-y-8\">\n            <div>\n              <Heading>Request Tag</Heading>\n              <Text size=\"small\" className=\"text-ui-fg-subtle\">\n                Submit a request to create a new product tag.\n              </Text>\n            </div>\n            <div className=\"grid grid-cols-1 gap-4 md:grid-cols-2\">\n              <Form.Field\n                control={form.control}\n                name=\"value\"\n                render={({ field }) => (\n                  <Form.Item>\n                    <Form.Label>\n                      {t(\"productTags.fields.value\")}\n                    </Form.Label>\n                    <Form.Control>\n                      <Input autoComplete=\"off\" {...field} />\n                    </Form.Control>\n                    <Form.ErrorMessage />\n                  </Form.Item>\n                )}\n              />\n            </div>\n          </div>\n        </RouteFocusModal.Body>\n        <RouteFocusModal.Footer>\n          <RouteFocusModal.Close asChild>\n            <Button size=\"small\" variant=\"secondary\">\n              {t(\"actions.cancel\")}\n            </Button>\n          </RouteFocusModal.Close>\n          <Button\n            size=\"small\"\n            variant=\"primary\"\n            type=\"submit\"\n            isLoading={isPending}\n          >\n            {t(\"actions.create\")}\n          </Button>\n        </RouteFocusModal.Footer>\n      </form>\n    </RouteFocusModal.Form>\n  );\n};\n\nconst TagRequestCreatePage = () => {\n  return (\n    <RouteFocusModal>\n      <TagRequestCreateForm />\n    </RouteFocusModal>\n  );\n};\n\nexport default TagRequestCreatePage;\n",
      "type": "registry:vendor"
    },
    {
      "path": "requests/vendor/routes/requests/types/page.tsx",
      "content": "import { useTranslation } from \"react-i18next\";\nimport { Link } from \"react-router-dom\";\nimport { keepPreviousData } from \"@tanstack/react-query\";\nimport { Button, Container, Heading } from \"@medusajs/ui\";\nimport type { RouteConfig } from \"@mercurjs/dashboard-sdk\";\n\nexport const config: RouteConfig = {\n  label: \"Types\",\n  nested: \"/requests\",\n};\n\nexport const handle = {\n  breadcrumb: () => \"Types\",\n};\n\nimport { useVendorRequests } from \"../../../hooks/api/requests\";\nimport { useRequestTableColumns } from \"../../../hooks/table/columns/use-request-table-columns\";\nimport { useRequestTableQuery } from \"../../../hooks/table/query/use-request-table-query\";\nimport { useRequestTableFilters } from \"../../../hooks/table/filters/use-request-table-filters\";\nimport {\n  _DataTable,\n  SingleColumnPage,\n  useDataTable,\n} from \"@mercurjs/dashboard-shared\";\n\nconst PAGE_SIZE = 10;\n\nconst VendorTypeRequestsPage = () => {\n  const { t } = useTranslation();\n  const { raw, searchParams } = useRequestTableQuery({ pageSize: PAGE_SIZE });\n\n  const { requests, count, isError, error, isLoading } = useVendorRequests(\n    \"product_type\",\n    searchParams,\n    { placeholderData: keepPreviousData },\n  );\n\n  const columns = useRequestTableColumns(\"value\");\n  const filters = useRequestTableFilters();\n\n  const { table } = useDataTable({\n    data: requests ?? [],\n    columns,\n    enablePagination: true,\n    count: count,\n    pageSize: PAGE_SIZE,\n  });\n\n  if (isError) throw error;\n\n  return (\n    <SingleColumnPage>\n      <Container className=\"divide-y p-0\">\n        <div className=\"flex items-center justify-between px-6 py-4\">\n          <Heading>Type Requests</Heading>\n          <Button size=\"small\" variant=\"secondary\" asChild>\n            <Link to=\"create\">{t(\"actions.create\")}</Link>\n          </Button>\n        </div>\n        <_DataTable\n          columns={columns}\n          table={table}\n          pagination\n          filters={filters}\n          count={count}\n          isLoading={isLoading}\n          pageSize={PAGE_SIZE}\n          orderBy={[\n            { key: \"created_at\", label: t(\"fields.createdAt\") },\n            { key: \"updated_at\", label: t(\"fields.updatedAt\") },\n          ]}\n          queryObject={raw}\n          noRecords={{ message: \"No type requests found\" }}\n        />\n      </Container>\n    </SingleColumnPage>\n  );\n};\n\nexport default VendorTypeRequestsPage;\n",
      "type": "registry:vendor"
    },
    {
      "path": "requests/vendor/routes/requests/types/create/page.tsx",
      "content": "import { zodResolver } from \"@hookform/resolvers/zod\";\nimport { Button, Heading, Input, Text, toast } from \"@medusajs/ui\";\nimport { useForm } from \"react-hook-form\";\nimport { useTranslation } from \"react-i18next\";\nimport * as zod from \"zod\";\n\nimport {\n  Form,\n  RouteFocusModal,\n  useRouteModal,\n} from \"@mercurjs/dashboard-shared\";\nimport { useCreateVendorRequest } from \"../../../../hooks/api/requests\";\n\nconst CreateTypeRequestSchema = zod.object({\n  value: zod.string().min(1),\n});\n\nconst TypeRequestCreateForm = () => {\n  const { t } = useTranslation();\n  const { handleSuccess } = useRouteModal();\n\n  const form = useForm<zod.infer<typeof CreateTypeRequestSchema>>({\n    defaultValues: {\n      value: \"\",\n    },\n    resolver: zodResolver(CreateTypeRequestSchema),\n  });\n\n  const { mutateAsync, isPending } = useCreateVendorRequest(\"product_type\");\n\n  const handleSubmit = form.handleSubmit(async (data) => {\n    await mutateAsync(data, {\n      onSuccess: () => {\n        toast.success(\"Type request created successfully\");\n        handleSuccess(`/requests/types`);\n      },\n      onError: (error) => {\n        toast.error(error.message);\n      },\n    });\n  });\n\n  return (\n    <RouteFocusModal.Form form={form}>\n      <form\n        onSubmit={handleSubmit}\n        className=\"flex h-full flex-col overflow-hidden\"\n      >\n        <RouteFocusModal.Header />\n        <RouteFocusModal.Body className=\"flex size-full flex-col items-center p-16\">\n          <div className=\"flex w-full max-w-[720px] flex-col gap-y-8\">\n            <div>\n              <Heading>Request Type</Heading>\n              <Text size=\"small\" className=\"text-ui-fg-subtle\">\n                Submit a request to create a new product type.\n              </Text>\n            </div>\n            <div className=\"grid grid-cols-1 gap-4 md:grid-cols-2\">\n              <Form.Field\n                control={form.control}\n                name=\"value\"\n                render={({ field }) => (\n                  <Form.Item>\n                    <Form.Label>\n                      {t(\"productTypes.fields.value\")}\n                    </Form.Label>\n                    <Form.Control>\n                      <Input autoComplete=\"off\" {...field} />\n                    </Form.Control>\n                    <Form.ErrorMessage />\n                  </Form.Item>\n                )}\n              />\n            </div>\n          </div>\n        </RouteFocusModal.Body>\n        <RouteFocusModal.Footer>\n          <RouteFocusModal.Close asChild>\n            <Button size=\"small\" variant=\"secondary\">\n              {t(\"actions.cancel\")}\n            </Button>\n          </RouteFocusModal.Close>\n          <Button\n            size=\"small\"\n            variant=\"primary\"\n            type=\"submit\"\n            isLoading={isPending}\n          >\n            {t(\"actions.create\")}\n          </Button>\n        </RouteFocusModal.Footer>\n      </form>\n    </RouteFocusModal.Form>\n  );\n};\n\nconst TypeRequestCreatePage = () => {\n  return (\n    <RouteFocusModal>\n      <TypeRequestCreateForm />\n    </RouteFocusModal>\n  );\n};\n\nexport default TypeRequestCreatePage;\n",
      "type": "registry:vendor"
    }
  ]
}