productSchema
import { productSchema } from '@rudra-js/core';productSchema lets you check that a product from your catalog has the shape core expects.
productSchema: z.ZodObject<{ sku: z.ZodString; title: z.ZodString; category: z.ZodString; price: z.ZodNumber; currency: z.ZodDefault<z.ZodString>; imageUrl: z.ZodOptional<z.ZodString>; rating: z.ZodOptional<z.ZodNumber>; reason: z.ZodOptional<z.ZodString>; isInStock: z.ZodDefault<z.ZodBoolean>; tags: z.ZodDefault<z.ZodArray<z.ZodString>>; }, z.core.$strict>Reference
productSchema
Returns
productSchema.parse(row) returns a Product, with currency, isInStock and tags filled in when you left them out.
Caveats
- Check every product with
productSchemabefore you pass it toRudraComponent. The products ininput.candidatesfromparseTrackingInputhave passed it already. imageUrltakes anhttporhttpsURL, or a path on your own site such as/images/tr-102.png. A path a browser reads as another site fails, such as//evil.example/pixel.png.- A product with
isInStock: falseis never shown. Core leaves it out, and the renderer drops it too. reasonis your own phrase for the product, shown under its card. In'per-shopper'mode the model writes the reasons instead.- Put facts with numbers in
tags, such as3-season. Core drops any text the model wrote with a number that isn't in your tags or categories.
Fields
| Name | Type | Default | Constraints |
|---|---|---|---|
sku | string | 1 to 128 chars | |
title | string | 1 to 200 chars | |
category | string | 1 to 128 chars | |
price | number | min 0 | |
currencyoptional | string | "USD" | pattern ^[A-Z]{3}$ |
imageUrloptional | string | max 200 chars | |
ratingoptional | number | 0 to 5 | |
reasonoptional | string | 1 to 120 chars | |
isInStockoptional | boolean | true | |
tagsoptional | string[] | [] | max 20 items |
Usage
Checking your catalog before it reaches the page
Map each row from your store to the product fields, and leave the rest of the row behind. Unknown fields are rejected.
import { productSchema, type Product } from '@rudra-js/core';
interface CatalogRow {
sku: string;
name: string;
department: string;
price: number;
image: string | null;
stock: number;
supplier: string;
}
export function toProducts(rows: CatalogRow[]): Product[] {
return rows.flatMap((row) => {
const result = productSchema.safeParse({
sku: row.sku,
title: row.name,
category: row.department,
price: row.price,
imageUrl: row.image ?? undefined,
isInStock: row.stock > 0,
});
if (!result.success) {
console.warn(`Left out ${row.sku}:`, result.error.issues);
return [];
}
return [result.data];
});
}A row that fails is left out, and the rest still reach the page.
Pass the result as candidates. One bad row would otherwise make parseTrackingInput throw for the whole page view.
Troubleshooting
z.array(productSchema) fails in an app on zod 3
Core depends on zod 4. An app on zod 3 gets a second copy of zod for core. The two copies don't mix.
Build on core's schemas with their own methods, such as productSchema.array().
import { productSchema } from '@rudra-js/core';
import { z } from 'zod';
// wrong
export const productsSchema = z.array(productSchema);
// right
export const catalogSchema = productSchema.array();