UNPKG

@causalfoundry/js-sdk

Version:

Causal Foundry WEB SDK (JS/TS)

252 lines (235 loc) 7.32 kB
import { ItemObject } from "../typings"; import { ECommerceTypes } from "../typings"; import CfExceptionHandler from "../../../core/CfExceptionHandler"; import { isISOLocal } from "../../../utils"; import { z } from "zod"; const ItemObjectSchema = z.object({ id: z.string().min(1, "empty item id"), type: z.string().min(1, "invalid item type"), quantity: z.number().min(0, "invalid item quantity"), price: z.number().min(0, "invalid item price"), currency: z.string().min(2, "item currency required"), stock_status: z.string().optional(), promo_id: z.string().optional(), facility_id: z.string().optional(), discount: z.number().optional(), }); const CheckoutPropertiesSchema = z .object({ order_id: z.string().min(1, "empty checkout id"), is_successful: z.boolean(), cart_price: z.number().min(0, "negative checkout price"), items: z.array(ItemObjectSchema).min(1, "checkout empty items list"), cart_id: z.string().min(1, "empty checkout cart id"), shop_mode: z.string().optional(), meta: z.any().optional(), }) .refine( (data) => { // Check for repeated IDs in items array const itemIds = data.items.map((item) => item.id); const uniqueIds = new Set(itemIds); return uniqueIds.size === itemIds.length; }, { message: "checkout items list contains repeated ids", path: ["items"], } ); const CartPropertiesSchema = z.object({ cart_id: z.string().min(1, "empty cart id"), action: z.string().min(1, "cart action required"), item: ItemObjectSchema, meta: z.any().optional(), }); const ItemRequestPropertiesSchema = z.object({ item_id: z.string().min(1, "empty request id"), item_name: z.string().min(1, "empty request item name"), manufacturer: z.string().min(1, "empty request item manufacturer"), }); const ItemReportPropertiesSchema = z.object({ item_id: z.string().min(1, "empty item report id"), item_type: z.string().min(1, "invalid item type"), report_id: z.string().min(1, "empty report id"), report_remarks: z.string().min(1, "empty report remarks"), store_id: z.string().min(1, "report store id required"), meta: z.any().optional(), }); const CancelCheckoutPropertiesSchema = z .object({ cancel_type_id: z.string().min(1, "empty cancel checkout id"), type: z.string().min(1, "invalid cancel type"), items: z.array(z.string()).min(1, "cancel checkout empty items list"), reason: z.string().min(1, "cancel checkout reason required"), meta: z.any().optional(), }) .refine( (data) => { // Check for repeated IDs in items array const uniqueItems = new Set(data.items); return uniqueItems.size === data.items.length; }, { message: "cancel checkout items contains repeated ids", path: ["items"], } ); const DeliveryPropertiesSchema = z .object({ delivery_id: z.string().min(1, "empty delivery id"), order_id: z.string().min(1, "empty delivery order id"), is_urgent: z.boolean(), action: z.string().min(1, "delivery action required"), est_delivery_ts: z.string().optional(), delivery_coordinates: z .object({ lat: z.number(), lon: z.number(), }) .optional(), dispatch_coordinates: z .object({ lat: z.number(), lon: z.number(), }) .optional(), meta: z.any().optional(), }) .refine( (data) => { // is_urgent must be defined (not undefined) return data.is_urgent !== undefined; }, { message: "delivery is_urgent value required", path: ["is_urgent"], } ) .refine( (data) => { // Validate delivery_coordinates (lat/lon cannot be 0) if (data.delivery_coordinates) { return ( data.delivery_coordinates.lat !== 0 && data.delivery_coordinates.lon !== 0 ); } return true; }, { message: "Invalid delivery_coordinates provided", path: ["delivery_coordinates"], } ) .refine( (data) => { // Validate dispatch_coordinates (lat/lon cannot be 0) if (data.dispatch_coordinates) { return ( data.dispatch_coordinates.lat !== 0 && data.dispatch_coordinates.lon !== 0 ); } return true; }, { message: "Invalid dispatch_coordinates provided", path: ["dispatch_coordinates"], } ) .refine( (data) => { // Validate date format using isISOLocal if (data.est_delivery_ts) { return isISOLocal(data.est_delivery_ts); } return true; }, { message: "invalid delivery date format", path: ["est_delivery_ts"], } ); export const verifyItemObject = ( eventName: ECommerceTypes, itemObject: ItemObject ) => { try { ItemObjectSchema.parse(itemObject); return true; } catch (error) { if (error instanceof z.ZodError) { // Get the first validation error message const firstError = error.issues[0]; const errorMessage = firstError?.message || "validation error"; new CfExceptionHandler().throwAndLogError(eventName, errorMessage); } else { // Fallback for unexpected errors new CfExceptionHandler().throwAndLogError(eventName, "validation error"); } return false; } }; // Event type to schema mapping const eventSchemaMap = { [ECommerceTypes.Item]: { schema: ItemObjectSchema, dataExtractor: (properties: any) => properties.item, }, [ECommerceTypes.Checkout]: { schema: CheckoutPropertiesSchema, dataExtractor: (properties: any) => properties, }, [ECommerceTypes.Cart]: { schema: CartPropertiesSchema, dataExtractor: (properties: any) => properties, }, [ECommerceTypes.ItemRequest]: { schema: ItemRequestPropertiesSchema, dataExtractor: (properties: any) => properties, }, [ECommerceTypes.ItemReport]: { schema: ItemReportPropertiesSchema, dataExtractor: (properties: any) => properties, }, [ECommerceTypes.Delivery]: { schema: DeliveryPropertiesSchema, dataExtractor: (properties: any) => properties, }, [ECommerceTypes.CancelCheckout]: { schema: CancelCheckoutPropertiesSchema, dataExtractor: (properties: any) => properties, }, } as const; // Generic validation function that handles all event types export const validate = ( eventType: ECommerceTypes, properties: any ): boolean => { try { const eventConfig = eventSchemaMap[eventType]; if (!eventConfig) { new CfExceptionHandler().throwAndLogError( eventType, `Unknown event type: ${eventType}` ); return false; } const { schema, dataExtractor } = eventConfig; const dataToValidate = dataExtractor(properties); // Parse the data - this will throw if validation fails schema.parse(dataToValidate); return true; } catch (error) { if (error instanceof z.ZodError) { // Get the first validation error message const firstError = error.issues[0]; const errorMessage = firstError?.message || "validation error"; new CfExceptionHandler().throwAndLogError(eventType, errorMessage); } else { // Fallback for unexpected errors new CfExceptionHandler().throwAndLogError(eventType, "validation error"); } return false; } };