import {z} from 'zod' export type GetApiApiV4OceanShipmentsIdStatusesArgs = {id: string, includeCustomAttributes?: boolean | undefined, includeMapUrl?: boolean | undefined, includePositionData?: boolean | undefined}; export type GetApiApiV4OceanShipmentsIdStatusesOptions = {baseUrl?: string | undefined, oAuth2?: string | undefined, fetch?: typeof fetch | undefined}; export const message = z.object({diagnostic: z.string().optional(), message: z.string().optional(), severity: z.enum(["ERROR", "WARNING", "INFO"]).optional(), source: z.enum(["SYSTEM", "CAPACITY_PROVIDER"]).optional()}); export const oceanAttribute = z.object({name: z.string().optional(), value: z.string().optional(), values: z.array(z.string()).optional()}); export const oceanTrackedContainer = z.object({containerId: z.string().optional(), currency: z.enum(["USD", "CAD", "MXN", "EUR"]).optional(), demurrage: z.number().optional(), lastFreeDay: z.string().optional()}); export const oceanEquipmentIdentifier = z.object({type: z.literal("CONTAINER_ID").optional(), value: z.string().optional()}); export const oceanEvent = z.object({eventCode: z.enum(["TRACKING_STARTED", "TRACKING_STOPPED", "UNKNOWN", "GATE_IN_FULL", "GATE_IN_EMPTY", "GATE_OUT_EMPTY", "GATE_OUT", "LOADED", "EMBARKED", "BERTHING", "ARRIVED", "DISCHARGED", "DEPARTED_TERMINAL", "BECAME_AVAILABLE", "CUSTOMS_HOLD_INITIATED", "LINE_HOLD_INITIATED", "OTHER_HOLD_INITIATED", "CUSTOMS_HOLD_RELEASED", "LINE_HOLD_RELEASED", "OTHER_HOLD_RELEASED"]).optional(), stopNumber: z.number().int().optional(), timeStamp: z.string().optional(), vesselNumber: z.number().int().optional()}); export const geoCoordinates = z.object({latitude: z.number().optional(), longitude: z.number().optional()}); export const oceanPosition = z.object({geoCoordinates: geoCoordinates.optional(), timeStamp: z.string().optional(), vesselNumber: z.number().int().optional()}); export const oceanShipmentIdentifier = z.object({type: z.enum(["BILL_OF_LADING", "BOOKING_NUMBER"]).optional(), value: z.string().optional()}); export const oceanState = z.object({endTime: z.string().optional(), startTime: z.string().optional(), stateCode: z.enum(["AT_STOP", "IN_TRANSIT", "ON_WATER", "LINE_HOLD", "CUSTOMS_HOLD", "OTHER_HOLD", "AT_TERMINAL", "UNKNOWN"]).optional(), stopNumber: z.number().int().optional(), vesselNumber: z.number().int().optional()}); export const countryCode = z.enum(["US", "CA", "MX", "AG", "BB", "BS", "BZ", "CR", "CU", "DM", "DO", "GD", "GT", "HN", "HT", "JM", "KN", "LC", "NI", "PA", "SV", "TT", "VC", "AI", "AW", "BL", "BM", "BQ", "CW", "GL", "GP", "KY", "MF", "MQ", "MS", "PM", "PR", "SX", "TC", "UM", "VG", "VI", "AT", "BE", "BG", "CY", "CZ", "DK", "DE", "EE", "ES", "FI", "FR", "GB", "GR", "HR", "HU", "IE", "IT", "LT", "LU", "LV", "MT", "NL", "PL", "PT", "RO", "SE", "SK", "SI", "CH", "IS", "LI", "NO", "AL", "ME", "MK", "RS", "TR", "AD", "AX", "BA", "BV", "BY", "FO", "GG", "GI", "IM", "IO", "JE", "MC", "MD", "SJ", "SM", "TF", "UA", "VA", "AE", "AF", "AM", "AZ", "BD", "BH", "BN", "BT", "CN", "GE", "HK", "ID", "IL", "IN", "IQ", "IR", "JO", "JP", "KG", "KH", "KP", "KR", "KW", "KZ", "LA", "LB", "LK", "MM", "MN", "MO", "MV", "MY", "NP", "OM", "PH", "PK", "PS", "QA", "RU", "SA", "SG", "SY", "TH", "TJ", "TL", "TM", "TW", "UZ", "VN", "YE", "AO", "BF", "BI", "BJ", "BW", "CD", "CF", "CG", "CI", "CM", "CV", "DJ", "DZ", "EG", "EH", "ER", "ET", "GA", "GH", "GM", "GN", "GQ", "GW", "HM", "KE", "KM", "LR", "LS", "LY", "MA", "MG", "ML", "MR", "MU", "MW", "MZ", "NA", "NE", "NG", "RE", "RW", "SC", "SD", "SH", "SL", "SN", "SO", "SS", "ST", "SZ", "TD", "TG", "TN", "TZ", "UG", "YT", "ZA", "ZM", "ZW", "AR", "BO", "BR", "CL", "CO", "EC", "FK", "GF", "GS", "GY", "PE", "PY", "SR", "UY", "VE", "AS", "AU", "CC", "CK", "CX", "FJ", "FM", "GU", "KI", "MH", "MP", "NC", "NF", "NR", "NU", "NZ", "PF", "PG", "PN", "PW", "SB", "TK", "TO", "TV", "VU", "WF", "WS", "AQ", "EL", "UK", "XK", "XS", "XI"]); export const address = z.object({addressLines: z.array(z.string()).optional(), city: z.string().optional(), country: countryCode.optional(), postalCode: z.string().optional(), state: z.string().optional()}); export const timingActual = z.object({dateTime: z.string().optional(), timelinessCode: z.enum(["UNKNOWN", "EARLY", "ON_TIME", "LATE"]).optional()}); export const offsetDateTimeWindow = z.object({endDateTime: z.string().optional(), startDateTime: z.string().optional()}); export const timingEstimate = z.object({estimatedTimeWindow: offsetDateTimeWindow.optional(), lastCalculatedDateTime: z.string().optional(), timelinessCode: z.enum(["UNKNOWN", "EARLY", "ON_TIME", "LATE"]).optional()}); export const timingScheduled = z.object({dateTime: z.string().optional(), timelinessCode: z.enum(["UNKNOWN", "EARLY", "ON_TIME", "LATE"]).optional()}); export const timing = z.object({actual: timingActual.optional(), estimate: timingEstimate.optional(), scheduled: timingScheduled.optional()}); export const oceanStop = z.object({address: address.optional(), arrivalTiming: timing.optional(), departureTiming: timing.optional(), geoCoordinates: geoCoordinates.optional(), id: z.string().optional(), name: z.string().optional(), portCBPCode: z.string().optional(), portLocode: z.string().optional(), stopNumber: z.number().int().optional(), stopType: z.enum(["PLACE_OF_ORIGIN", "PORT_OF_ORIGIN", "PORT_OF_LOADING", "TRANSSHIPMENT_PORT", "PORT_OF_DISCHARGE", "DESTINATION"]).optional()}); export const oceanVessel = z.object({callSign: z.string().optional(), draught: z.number().optional(), imo: z.number().int().optional(), length: z.number().optional(), lengthUnit: z.enum(["IN", "CM", "FT", "M"]).optional(), mmsi: z.number().int().optional(), name: z.string().optional(), shipType: z.string().optional(), vesselNumber: z.number().int().optional(), width: z.number().optional()}); export const oceanTrackedShipment = z.object({attributes: z.array(oceanAttribute).optional(), carrierSCACCode: z.string().optional(), containerDetails: oceanTrackedContainer.optional(), equipmentIdentifier: oceanEquipmentIdentifier.optional(), events: z.array(oceanEvent).optional(), mapUrl: z.string().optional(), masterShipmentId: z.string().optional(), oceanLegId: z.string().optional(), positions: z.array(oceanPosition).optional(), shipmentId: z.string().optional(), shipmentIdentifiers: z.array(oceanShipmentIdentifier).optional(), states: z.array(oceanState).optional(), stops: z.array(oceanStop).optional(), vessels: z.array(oceanVessel).optional()}); export const oceanTrackedShipmentConfirmation = z.object({infoMessages: z.array(message).optional(), trackedShipment: oceanTrackedShipment.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 shipment statuses by project44 id. * * GET /api/v4/ocean/shipments/{id}/statuses */ export const getApiApiV4OceanShipmentsIdStatuses = async (args: GetApiApiV4OceanShipmentsIdStatusesArgs, options?: GetApiApiV4OceanShipmentsIdStatusesOptions) => { const {baseUrl = "https://na12.api.project44.com", fetch: fetchFn = fetch, oAuth2} = options ?? {} const query = new URLSearchParams() const headers = new Headers() headers.set('accept', "application/json") if (args.includeCustomAttributes != null) query.append("includeCustomAttributes", String(args.includeCustomAttributes)) if (args.includeMapUrl != null) query.append("includeMapUrl", String(args.includeMapUrl)) if (args.includePositionData != null) query.append("includePositionData", String(args.includePositionData)) if (oAuth2 !== undefined) headers.set('authorization', `Bearer ${oAuth2}`) const url = `${baseUrl.replace(/\/+$/, '')}/api/v4/ocean/shipments/${encodeURIComponent(String(args.id))}/statuses${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(oceanTrackedShipmentConfirmation, await res.json()) };