Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/modules/commerce/commerces/store.controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
deleteStoreService
} from "./store.service.js";
import jwt from "jsonwebtoken";
import { StoreProductsPageDTO } from "../../global/dtos/commerce/filter-store-products.response.js";
import { StoreProductsPageDTO } from "../../global/dtos/commerce/filter-store-products.response.ts";

export const createStore = async (req, res) => {
try {
Expand Down
4 changes: 2 additions & 2 deletions src/modules/commerce/commerces/store.routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {
} from "./store.controller.js";
import { parsePagination } from "../../../middlewares/pagination.middleware.js";
import { validate } from "../../../middlewares/validate.middleware.js";
import { FilterStoreProductsDTO } from "../../global/dtos/commerce/filter-store-products.dto.js";
import { FilterStoreProductsDTO } from "../../global/dtos/commerce/filter-store-products.dto.ts";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verificar configuración de TypeScript y scripts de build
cat tsconfig.json 2>/dev/null || echo "No tsconfig.json found"
cat package.json | jq '.scripts' 2>/dev/null

Repository: CrisNAC/BackendMarketplace

Length of output: 530


🏁 Script executed:

# Check if the target .ts file exists
fd -t f "filter-store-products.dto.ts"

Repository: CrisNAC/BackendMarketplace

Length of output: 131


🏁 Script executed:

# Check the content of src/server.js to see how it's bootstrapped
head -30 src/server.js

Repository: CrisNAC/BackendMarketplace

Length of output: 279


🏁 Script executed:

# Check if tsx or ts-node are installed as dependencies
jq '.dependencies, .devDependencies' package.json | grep -E "(tsx|ts-node|esbuild|webpack)" || echo "No tsx/ts-node found"

Repository: CrisNAC/BackendMarketplace

Length of output: 89


🏁 Script executed:

# Check the actual store.routes.js file to understand the context better
cat src/modules/commerce/commerces/store.routes.js | head -20

Repository: CrisNAC/BackendMarketplace

Length of output: 650


🏁 Script executed:

# Check if app.js and app.ts both exist
ls -la src/app.* 2>/dev/null || echo "No app files found"

Repository: CrisNAC/BackendMarketplace

Length of output: 129


🏁 Script executed:

# Check if there's any build setup or if files are pre-compiled
ls -la src/ | head -20

Repository: CrisNAC/BackendMarketplace

Length of output: 754


🏁 Script executed:

# Check if package.json has a prepare script or if build is automatically run
jq '.scripts | to_entries | .[]' package.json

Repository: CrisNAC/BackendMarketplace

Length of output: 366


🏁 Script executed:

# Verify how the actual imports work - check if .ts is being transpiled in build
cat package.json | jq '.build, .type'

Repository: CrisNAC/BackendMarketplace

Length of output: 83


Importación de archivo .ts desde archivo .js causará error de runtime.

La importación directa con extensión .ts desde un archivo JavaScript no funcionará. Node.js no puede resolver extensiones .ts en runtime con los scripts actuales (node sin tsx). Aunque tsx está instalado como dependencia, los scripts de start y dev usan node y nodemon directamente, no tsx.

Opciones para resolver:

  1. Cambiar el import a: import { FilterStoreProductsDTO } from "../../global/dtos/commerce/filter-store-products.dto.js"; (si el archivo está compilado a .js)
  2. O usar tsx en los scripts: "start": "tsx src/server.js" y "dev": "nodemon --exec tsx src/server.js"
  3. O asegurar que el build con tsc se ejecute antes de start (agregar step previo)

Este cambio causará un error de módulo no encontrado cuando la app intente iniciarse.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/modules/commerce/commerces/store.routes.js` at line 14, The import of
FilterStoreProductsDTO using a .ts extension in store.routes.js will cause a
runtime module resolution error; fix by either changing the import to reference
the compiled .js output of FilterStoreProductsDTO, update your start/dev scripts
to run via tsx (so Node can load .ts at runtime), or ensure tsc builds the
project before start and keep the import pointing to the compiled .js file;
locate the import statement for FilterStoreProductsDTO in store.routes.js and
apply one of these three fixes so the module can be resolved at runtime.


const router = Router();

Expand Down Expand Up @@ -352,4 +352,4 @@ router.get(
*/
router.delete("/:id", deleteStore);

export default router;
export default router;
55 changes: 51 additions & 4 deletions src/modules/commerce/commerces/store.service.js
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,33 @@ const parseBooleanField = (value, fieldName) => {
};
};

const parseOptionalFiniteNumberField = (value, fieldName) => {
if (value === undefined || value === null) {
return undefined;
}

const normalizedValue =
typeof value === "string" ? value.trim() : String(value).trim();

if (!normalizedValue) {
throw {
status: 400,
message: `${fieldName} debe ser un numero valido`
};
}

const parsedValue = Number(normalizedValue);

if (!Number.isFinite(parsedValue)) {
throw {
status: 400,
message: `${fieldName} debe ser un numero valido`
};
}

return parsedValue;
};

const mapStoreProductPricing = (product) => {
const pricing = getProductPricing(product);

Expand Down Expand Up @@ -838,13 +865,33 @@ export const filterStoreProductsService = async (id, filters, pagination) => {
const resolvedMinPrice = minPrice ?? price_min;
const resolvedMaxPrice = maxPrice ?? price_max;

const normalizedMinPrice = parseOptionalFiniteNumberField(
resolvedMinPrice,
"price_min"
);
const normalizedMaxPrice = parseOptionalFiniteNumberField(
resolvedMaxPrice,
"price_max"
);

if (
normalizedMinPrice !== undefined &&
normalizedMaxPrice !== undefined &&
normalizedMinPrice > normalizedMaxPrice
) {
throw {
status: 400,
message: "price_min no puede ser mayor que price_max"
};
}

const effectivePriceRange = {};
if (resolvedMinPrice !== undefined && resolvedMinPrice !== null) {
effectivePriceRange.gte = Number(resolvedMinPrice);
if (normalizedMinPrice !== undefined) {
effectivePriceRange.gte = normalizedMinPrice;
}

if (resolvedMaxPrice !== undefined && resolvedMaxPrice !== null) {
effectivePriceRange.lte = Number(resolvedMaxPrice);
if (normalizedMaxPrice !== undefined) {
effectivePriceRange.lte = normalizedMaxPrice;
}

if (Object.keys(effectivePriceRange).length > 0) {
Expand Down
77 changes: 0 additions & 77 deletions src/modules/global/dtos/commerce/filter-store-products.dto.js

This file was deleted.

84 changes: 84 additions & 0 deletions src/modules/global/dtos/commerce/filter-store-products.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import { z } from "zod";

const emptyToUndefined = (value: unknown) =>
value === "" || value === null ? undefined : value;

export const FilterStoreProductsDTO = z
.object({
name: z.string().trim().optional(),

category: z.preprocess(
emptyToUndefined,
z
.string()
.transform(Number)
.pipe(z.number().int().positive("category debe ser un ID valido"))
.optional()
),

price_min: z.preprocess(
emptyToUndefined,
z
.string()
.transform(Number)
.pipe(z.number().min(0, "price_min debe ser mayor o igual a 0"))
.optional()
),

price_max: z.preprocess(
emptyToUndefined,
z
.string()
.transform(Number)
.pipe(z.number().min(0, "price_max debe ser mayor o igual a 0"))
.optional()
),

available: z.preprocess(
emptyToUndefined,
z
.enum(["true", "false", "1", "0"])
.transform((value) => value === "true" || value === "1")
.optional()
),

isOffer: z.preprocess(
emptyToUndefined,
z
.enum(["true", "false", "1", "0"])
.transform((value) => value === "true" || value === "1")
.optional()
),

sortBy: z.preprocess(
emptyToUndefined,
z
.enum(["created_at", "price", "name"], {
error: "sortBy debe ser created_at, price o name"
})
.optional()
.default("created_at")
),

sortOrder: z.preprocess(
emptyToUndefined,
z
.enum(["asc", "desc"], {
error: "sortOrder debe ser asc o desc"
})
.optional()
.default("desc")
)
Comment on lines +53 to +71

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🌐 Web query:

Zod 4 z.enum error customization syntax and parameters

💡 Result:

In Zod 4, error customization for z.enum uses the unified error parameter, replacing the Zod 3 errorMap. The error param accepts either a static string (applied to all errors from the schema) or a function that receives an issue object (iss) and returns a string or {message: string}. Syntax: - Static string: z.enum(["a", "b"], "Must be a or b!") - Function (error map): z.enum(["a", "b"], { error: (iss) => "Custom message" }) The function receives iss with properties like code (e.g., "invalid_type", "invalid_value" for enum), input, expected. Return undefined to fall back to default. Example for z.enum: const StatusSchema = z.enum(["draft", "published"], { error: (issue) => { if (issue.code === "invalid_value") { return "Status must be 'draft' or 'published'"; } return "Invalid status"; } }); This applies to all issues from the z.enum schema (invalid type, invalid enum value). For refinements on the enum, use separate error params. Zod 3 used errorMap: (issue, ctx) => ({message: string}); Zod 4 simplifies to error: (issue) => string | {message: string} | undefined, dropping ctx and specific params like invalid_type_error. Precedence: schema-level > per-parse > global > locale.

Citations:


Corregir la sintaxis de personalización de errores en z.enum() para Zod 4.

La sintaxis { error: "mensaje" } no es válida en Zod 4. Debe ser o bien una cadena de texto como segundo argumento: z.enum([...], "mensaje"), o una función dentro del objeto: { error: (iss) => "mensaje" }. Esto aplica a los campos sortBy (línea 57) y sortOrder (línea 67).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/modules/global/dtos/commerce/filter-store-products.dto.ts` around lines
53 - 71, Los validators `sortBy` y `sortOrder` usan la forma inválida `{ error:
"..." }` en z.enum; actualiza ambos para usar la API correcta de Zod 4 — por
ejemplo reemplaza `z.enum([...], { error: "mensaje" })` por `z.enum([...],
"mensaje")` (o alternadamente `{ error: (issues) => "mensaje" }`), manteniendo
la envoltura con `z.preprocess(emptyToUndefined, ...)`, las llamadas a `z.enum`
y las propiedades `.optional().default(...)` intactas para `sortBy` y
`sortOrder`.

})
.refine(
(data) =>
data.price_min === undefined ||
data.price_max === undefined ||
data.price_min <= data.price_max,
{
message: "price_min no puede ser mayor que price_max",
path: ["price_min"]
}
);

export type FilterStoreProductsDTOType = z.infer<typeof FilterStoreProductsDTO>;
48 changes: 0 additions & 48 deletions src/modules/global/dtos/commerce/filter-store-products.response.js

This file was deleted.

Loading
Loading