import {z} from 'zod' export type GetApiV1WaybillArgs = {equipmentInitial: string, equipmentNumber: string}; export type GetApiV1WaybillOptions = {baseUrl?: string | undefined, fetch?: typeof fetch | undefined}; export const waybillDetails = z.object({customerWaybillDetails: z.object({equipmentInitial: z.string(), equipmentNumber: z.string(), loadEmptyCode: z.string().optional(), equipmentGrossScaleWeightPounds: z.string().optional(), equipmentTareWeightPounds: z.string().optional(), shipmentNetScaleWeightPounds: z.string().optional(), carKindCode: z.string().optional(), billOfLadingId: z.string().optional(), waybillNumber: z.string().optional(), waybillVersionNumber: z.string().optional(), shippingManifestId: z.string().optional(), waybillDate: z.string().optional(), waybillEdiCode: z.string().optional(), waybillStatusCode: z.string().optional(), waybillParties: z.array(z.object({waybillPartyRoleName: z.string().optional(), waybillPartyFullName: z.string().optional()})).optional(), waybillDetails: z.object({originStationName: z.string().optional(), originStateCode: z.string().optional(), destinationStationName: z.string().optional(), destinationStateCode: z.string().optional(), stcc: z.string().optional(), commodityDescription: z.string().optional(), contractFreightRateQuoteNumber: z.string().optional(), aarRule11Indicator: z.string().optional(), shipmentUnitCount: z.string().optional()}).optional(), waybillRoutes: z.array(z.object({waybillRouteScac: z.string().optional(), aarRule260JunctionAbbreviation: z.string().optional(), waybillRouteSequenceNumber: z.string().optional()})).optional(), waybillDiversions: z.array(z.object({consigneeFullName: z.string().optional(), waybillDiversionAuthorizedByName: z.string().optional(), waybillDiversionRequesterPhoneNumber: z.string().optional(), waybillDiversionDate: z.string().optional(), waybillDiversionTime: z.string().optional(), waybillDiversionComments: z.array(z.object({waybillDiversionComment: z.string().optional()})).optional()})).optional(), waybillHazardousCommodities: z.array(z.object({unNorthAmericanHazardousCommodityNumber: z.string().optional(), hazardousCommodityTechnicalName: z.string().optional(), hazardousCommodityProperShippingName: z.string().optional(), hazardousSubstanceChemicalComponent: z.string().optional(), hazardousCommodityClassificationCode: z.string().optional(), canadianHazardousCommoditySubsidiaryClassification1: z.string().optional(), canadianHazardousCommoditySubsidiaryClassification2: z.string().optional(), packagingGroupCode: z.string().optional(), stcc: z.string().optional(), commodityAdditionalDescriptiveInformation: z.string().optional(), hazardousMaterialShipmentWeightPounds: z.string().optional(), reportableHazardousMaterialQuantityIndicator: z.string().optional(), customerNotificationPhoneNumber: z.string().optional(), waybillHazardousMaterialComment: z.string().optional()})).optional(), waybillVessels: z.array(z.object({sailingDate: z.string().optional(), sailingTime: z.string().optional(), vesselInboundOutboundCode: z.string().optional(), vesselName: z.string().optional(), vesselVoyageNumber: z.string().optional(), vesselTerminalName: z.string().optional(), vesselPortName: z.string().optional(), pierName: z.string().optional(), vesselBookingNumber: z.string().optional(), vesselBookingDate: z.string().optional(), scheduledUnitAvailabilityDate: z.string().optional(), scheduledUnitAvailabilityTime: z.string().optional()})).optional(), integratedServiceDetails: z.object({requestedUnitAvailabilityDate: z.string().optional(), requestedUnitAvailabilityTime: z.string().optional(), plannedUnitAvailabilityDate: z.string().optional(), plannedUnitAvailabilityTime: z.string().optional()}).optional(), waybillErrors: z.array(z.object({waybillErrorDescription: z.string().optional()})).optional(), waybillSpecialInstructions: z.array(z.object({waybillSpecialInstructions: z.string().optional()})).optional(), waybillSpecialConditions: z.array(z.object({waybillSpecialConditionCode: z.string().optional(), waybillSpecialConditionName: z.string().optional()})).optional(), waybillAdditionalUnits: z.array(z.object({equipmentInitial: z.string().optional(), equipmentNumber: z.string().optional(), totalLadingWeightPounds: z.string().optional()})).optional(), customerWaybillReferenceNumbers: z.array(z.object({waybillReferenceNumberTypeCode: z.string().optional(), waybillReferenceNumberTypeName: z.string().optional(), waybillReferenceNumber: z.string().optional()})).optional()}).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 }; /** * Retrieve Waybill - Retrieve current active waybill/bill of lading information for a given equipment. * * GET /v1/waybill */ export const getApiV1Waybill = async (args: GetApiV1WaybillArgs, options?: GetApiV1WaybillOptions) => { const {baseUrl = "https://api.bnsf.com:6443", fetch: fetchFn = fetch} = options ?? {} const query = new URLSearchParams() const headers = new Headers() headers.set('accept', "application/json") if (args.equipmentInitial != null) query.append("equipmentInitial", String(args.equipmentInitial)) if (args.equipmentNumber != null) query.append("equipmentNumber", String(args.equipmentNumber)) const url = `${baseUrl.replace(/\/+$/, '')}/v1/waybill${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(waybillDetails, await res.json()) };