import {z} from 'zod' export type GetApiV1NotificationTriggersCatalogOptions = {baseUrl?: string | undefined, fetch?: typeof fetch | undefined}; export const filterValueType = z.enum(["id_list", "condition_tree"]); export const conditionOperator = z.enum(["equals", "not_equals", "greater_than", "less_than", "greater_than_or_equal_to", "less_than_or_equal_to", "in", "not_in", "contains", "starts_with", "ends_with"]); export const filterCriterion = z.object({field: z.string(), valueType: filterValueType, listEndpoint: z.string().nullable().optional(), operators: z.array(conditionOperator).nullable().optional(), nodeShape: z.string().nullable().optional(), description: z.string().optional()}); export const actionKey = z.enum(["send_message", "flag_delivery", "auto_resolve_flag", "add_custom_event"]); export const triggerAction = z.object({key: actionKey, fields: z.array(z.string()).optional()}); export const notificationTriggerSlug = z.enum(["delivery_incident_report", "status_changed_too_quickly", "dropoff_delayed", "driver_geolocation", "pickup_delayed", "driver_location_vs_delivery_status", "stuck_status", "task_reassignment", "delivery_status_transition", "autodispatch_failed", "address_validation_failed", "order_needs_attention", "order_ready_to_fulfill", "job_creation_failed", "delivery_cancellation_failed", "task_health_status", "internal_driver_not_assigned", "nash_ai_invalid_pod", "delivery_completed_too_early", "order_not_dispatched_close_to_pickup", "tasks_attempts_exhausted", "refund_request", "optimization_order_unassigned", "zone_geolocation", "api_based", "status_triggered_too_early", "optimization_action_status", "driver_stacking", "time_elapsed_since_status", "activity_status_transition", "demo", "custom_event_listener", "proof_of_delivery_uploaded", "courier_updated", "timing_updated", "ai_conversation_completed", "delivery_window_booked_timeout", "order_modified", "route_status_transition", "catchment_violation", "late_departure", "vehicle_breakdown", "customer_not_home", "adhoc_break", "vehicle_overweight", "vehicle_oversize", "refuel_request", "order_pickup_start_time", "order_pickup_end_time", "order_dropoff_start_time", "order_dropoff_end_time", "order_cutoff_time", "conversation_message_received", "conversation_assigned", "conversation_resolved", "conversation_reopened", "conversation_handler_changed"]); export const notificationTriggerType = z.enum(["18zdfialfe|Delivery Incident Report", "8e2b5ead2b|Statuses changed too quickly", "z9aaa5b61b|Dropoff Delayed - Dropoff ETA too far after specified dropoff time", "a62ccd6cf7|Driver Geolocation", "8adu432fxx|Pickup Delayed - Pickup ETA too far after specified pickup time", "2d00e8337d|Driver location inconsistent with delivery status", "d9abb5b61b|"Stuck" Status", "xuf71kdfa7|Task Reassignment", "50851e6311|Delivery Status Transition", "0slfyzlxy3|Autodispatch Failed", "qd2910zx34|Address Validation Failed", "20231018|Nash order needs attention", "20231201|Nash order ready to fulfill", "ouut3gfaey|Job Creation Failed", "6101a86efd|Delivery Cancellation Failed", "72f25b6941|Live Monitoring Status", "a0240620|Internal Driver Not Assigned", "8x567890|Invalid Proof of Delivery Photo", "9f9uu7z0|Delivery Completed Too Early", "ix38123456|Order Not Dispatched Close to Pickup", "86dc85e3|Tasks Attempts Exhausted", "8dxl093456|Refund Request", "19f1kx1j2|Optimization Unassigned Order", "pqr123f5s|Zone Geolocation", "2ef442ca|API Based", "rt32km97j|Status Triggered Too Early", "03dekfned|Optimization Action Status", "az8dfllk8|Driver Stacking", "b37098781|Time Elapsed Since Status", "44t6kh981k|Activity Status Transition", "k3m8t9zqf|Demo", "c7e4f91a3b|Custom Event Listener", "f8d2a1b3c4|Proof of Delivery Uploaded", "e7c9b5d6a2|Courier Updated", "d4f6e8a1b9|Timing Updated", "c3b7d9e2f5|AI Conversation Completed", "a9f3e0c7d2|Delivery Window Booked Timeout", "m4d1f1c8e6|Order Modified", "a8f3d91c4e|Route Status Transition", "7c8a2f9d31|Catchment Violation", "1a4d2b7c8e|Late Departure", "9b2c8e1d4a|Vehicle Breakdown", "cnh4a2b8c1|Customer Not Home", "adb3f7e2c9|Ad-hoc Break", "vow8c1a2b9|Vehicle Overweight", "voz1b9c8a4|Vehicle Oversize", "rfl5d2c7e9|Refuel Request", "9c755f719f|Order Pickup Start Time", "1f13cca356|Order Pickup End Time", "fb157fe42d|Order Dropoff Start Time", "c182d4fc52|Order Dropoff End Time", "5da6b80bd3|Order Cutoff Time", "9oe472bzqz|Conversation Message Received", "2jrtca2xgr|Conversation Assigned", "wlf7eehna2|Conversation Resolved", "6girre519g|Conversation Reopened", "rl2vhjhq0t|Conversation Handler Changed"]); export const triggerEntityType = z.enum(["route", "delivery", "task", "order", "activity", "conversation", "unknown"]); export const entityStatus = z.enum(["archived", "arrived_at_facility", "assigned", "assigned_driver", "awaiting_consignee_pickup", "awaiting_consignor_dropoff", "canceled", "canceled_by_auto_reassign", "canceled_by_customer", "canceled_by_merchant", "canceled_by_nash", "canceled_by_provider", "canceled_by_reassign", "completed", "confirmed", "contacting_provider", "created", "delayed", "departed_from_facility", "dispatch_failure", "dispatched", "dispatched_to_provider", "dropoff_arrived", "dropoff_complete", "dropoff_enroute", "expired", "failed", "in_progress", "in_transit", "items_pick_complete", "label_created", "manifested", "needs_attention", "not_assigned_driver", "partial_delivered", "pick_complete", "picking_complete", "pickup_arrived", "pickup_complete", "pickup_enroute", "pickup_in_progress", "planned_selection", "return_arrived", "return_in_progress", "returned", "returned_to_store", "running", "scheduled", "sent_to_provider", "started", "valid"]); export const filterCriterionKey = z.enum(["dispatch_strategies", "contracts", "zones", "metadata_conditions"]); export const triggerCatalogEntry = z.object({type: notificationTriggerSlug, title: z.string(), value: notificationTriggerType, entityType: triggerEntityType, category: triggerEntityType, isFlag: z.boolean().optional(), creatable: z.boolean().optional(), description: z.string().optional(), statuses: z.array(entityStatus).optional(), parametersSchema: z.record(z.string(), z.unknown()).optional(), supportedActions: z.array(actionKey).optional(), supportedFilters: z.array(filterCriterionKey).optional()}); export const notificationTriggerCatalogResponse = z.object({filterCriteria: z.record(z.string(), filterCriterion).optional(), actions: z.array(triggerAction).optional(), triggers: z.array(triggerCatalogEntry).optional()}); export const validateResponse = async ( schema: { readonly '~standard': { readonly validate: (value: unknown) => ({ readonly value: Output; readonly issues?: undefined } | { readonly issues: ReadonlyArray<{ readonly message: string; readonly path?: ReadonlyArray | undefined }> }) | Promise<{ readonly value: Output; readonly issues?: undefined } | { readonly issues: ReadonlyArray<{ readonly message: string; readonly path?: ReadonlyArray | undefined }> }> } }, value: unknown ): Promise => { const result = await schema['~standard'].validate(value) if (result.issues !== undefined) { const detail = result.issues .map(({ message, path }) => path?.length ? `${path.map((segment) => String(typeof segment === 'object' ? segment.key : segment)).join('.')}: ${message}` : message ) .join('; ') throw new Error(`Response does not match the schema: ${detail}`, { cause: { issues: result.issues } }) } return result.value }; /** * Get Notification Trigger Catalog * * GET /v1/notification-triggers/catalog */ export const getApiV1NotificationTriggersCatalog = async (options?: GetApiV1NotificationTriggersCatalogOptions) => { const {baseUrl = "https://api.sandbox.usenash.com", fetch: fetchFn = fetch} = options ?? {} const query = new URLSearchParams() const headers = new Headers() headers.set('accept', "application/json") const url = `${baseUrl.replace(/\/+$/, '')}/v1/notification-triggers/catalog${query.size > 0 ? `?${query}` : ''}` const res = await fetchFn(url, {method: "GET", headers}) if (!res.ok) throw new Error(`Request failed with status ${res.status}`, {cause: {status: res.status, body: await res.text()}}) return validateResponse(notificationTriggerCatalogResponse, await res.json()) };