import {z} from 'zod' export type GetApiTitleTitleNumberArgs = {titleNumber: string}; export type GetApiTitleTitleNumberOptions = {baseUrl?: string | undefined, bearerAuth?: string | undefined, fetch?: typeof fetch | undefined}; export const dataQualityIssueType = z.enum(["data_quality_language_code_invalid", "data_quality_class_of_title_invalid", "data_quality_tenure_invalid", "data_quality_no_entry_text", "data_quality_estate_interest_invalid", "data_quality_class_invalid_for_tenure", "data_quality_schedule_code_invalid", "data_quality_multiple_h_schedules", "data_quality_multiple_q_schedules", "data_quality_timeshare_lease_code_invalid", "data_quality_commonhold_type_invalid", "data_quality_continued_relationship_invalid", "data_quality_previous_relationship_invalid", "data_quality_previous_title_number_invalid", "data_quality_continued_title_number_invalid", "data_quality_proprietor_type_invalid", "data_quality_address_multiple_rdes", "data_quality_rdes_address_missing", "data_quality_schedule_address_blank", "data_quality_no_entry_role_code", "data_quality_price_paid_amount_missing", "data_quality_price_paid_date_missing", "data_quality_price_paid_lower_amount_missing", "data_quality_price_paid_upper_amount_missing", "data_quality_price_paid_additional_properties_missing", "data_quality_alias_name_missing", "data_quality_proprietor_address_missing", "data_quality_proprietor_address_description_missing", "data_quality_proprietor_surname_missing", "data_quality_proprietor_name_missing", "data_quality_price_paid_draft_entry_version_unknown", "data_quality_charge_date_missing", "data_quality_chargee_missing", "data_quality_chargee_surname_missing", "data_quality_chargee_name_missing", "data_quality_chargee_postal_address_missing", "data_quality_chargee_address_description_missing", "data_quality_multiple_charge_on_chargee_entry", "data_quality_invalid_value_for_covenantor", "data_quality_covenant_missing_source_type", "data_quality_incorrect_spelling_of_covenantor", "data_quality_validation_issue", "data_quality_incorrect_number_of_infills", "data_quality_charge_date_mismatch_on_obligation", "data_quality_obligation_exists_but_no_charge_exists", "data_quality_charge_date_missing_from_obligation", "data_quality_charge_date_missing_from_charge_restriction", "data_quality_charge_party_missing_from_charge_restriction", "data_quality_charge_missing_for_charge_restriction", "data_quality_charge_id_missing_for_charge_restriction", "data_quality_charge_date_missing_from_postponement", "data_quality_charge_date_mismatch_on_postponement", "data_quality_postponement_exists_but_no_charge_exists", "data_quality_postponement_charge_date_infill_number_mismatches_number_of_charges_on_postponement", "data_quality_multiple_price_paid_entries_exist_but_single_price_paid_expected", "data_quality_no_interests", "data_quality_entry_date_missing_from_restriction", "data_quality_beneficiary_missing_from_notice", "data_quality_beneficiary_missing_from_charge", "data_quality_charging_order_type_incorrect_on_equitable_charge", "data_quality_charging_order_type_missing_from_equitable_charge", "data_quality_source_parties_missing_from_charge", "data_quality_expiry_date_missing_from_charge", "data_quality_incorrect_spelling_of_other_than_a_charge", "data_quality_invalid_other_than_a_charge_when_not_disposition", "data_quality_invalid_other_than_a_charge", "data_quality_missing_charge_id", "data_quality_impacted_action_corrected", "data_quality_invalid_impacted_action", "data_quality_unilateral_notice_missing", "data_quality_beneficiary_missing_from_unilateral_notice", "data_quality_notice_date_missing_from_notice", "data_quality_charge_date_missing_from_notice", "data_quality_church_missing_from_notice", "data_quality_deed_parties_missing_from_notice", "data_quality_deed_type_missing_from_notice", "data_quality_deed_date_missing_from_notice", "data_quality_protected_interest_missing_from_notice", "data_quality_lease_term_missing_or_incomplete_from_notice"]); export const dataIssue = z.object({reference: z.string(), code: dataQualityIssueType, message: z.string(), property_name: z.string()}); export const schemeStatus = z.enum(["current scheme title", "pre-allocated scheme title, no applications pending", "title is not a scheme title"]).max(52); export const pricePaidDate = z.object({description: z.string(), value: z.string().optional()}); export const pricePaidType = z.enum(["price", "value stated"]); export const pricePaid = z.object({date: pricePaidDate, sequence: z.number().int().gte(1).optional(), amount: z.discriminatedUnion("amount_type", [z.object({amount_type: z.literal("single amount"), description: z.string().optional()}), z.object({amount_type: z.literal("amount range"), lower_description: z.string().optional(), upper_description: z.string().optional()})]).optional(), price_paid_type: pricePaidType, legacy_entry_id: z.string().optional(), additional_properties: z.string().optional()}); export const privateIndividualAlias = z.object({sequence: z.number().int().gte(1).optional(), decor: z.string().optional(), surname: z.string().optional(), name: z.string().optional(), legacy_name_id: z.string(), title: z.string().optional(), forenames: z.string().optional()}); export const addressType = z.enum(["uk", "bfpo", "foreign", "dx", "electronic", "unknown"]); export const proprietorAddress = z.object({building_name: z.string().optional(), double_dependent_locality: z.string().optional(), postcode: z.string().optional(), description: z.string().max(1000).optional(), sub_building_name: z.string().optional(), care_of_name: z.string().optional(), type: addressType.optional(), thoroughfare: z.string().optional(), sequence: z.number().int().gte(1).optional(), dependent_locality: z.string().optional(), post_town: z.string().optional(), care_of_indicator: z.boolean().optional(), dependent_thoroughfare: z.string().optional(), legacy_addr_id: z.string().optional(), building_number: z.number().int().optional()}); export const organisationType = z.enum(["private individual", "limited company or public limited company", "county council", "local authority", "corporate body", "industrial and provident society (company)", "industrial and provident society (corporate body)", "unknown (used for customer names only)", "unlimited company", "limited liability partnership", "housing association/society (company)", "housing association/society (corporate body)", "official custodian for charities", "official custodian for charities (on behalf of trustees)", "co-operative society (company)", "co-operative society (corporate body)", "community benefit society (company)", "community benefit society (corporate body)", "registered society (company)", "registered society (corporate body)", "housing association co-operative society (company)", "housing association co-operative society (corporate body)", "housing association community benefit society (company)", "housing association community benefit society (corporate body)", "housing association registered society (company)", "housing association registered society (corporate body)", "unknown (proprietor has no IOPN delimiters)"]); export const companyLocation = z.enum(["england or wales", "scotland", "northern ireland", "overseas"]); export const languageCode = z.enum(["eng", "cym"]); export const scheduleCode = z.enum(["D", "F", "H", "L", "M", "P", "Q", "R", "S", "T", "W", "X", "Y", "Z"]); export const scheduleInfo = z.object({sequence: z.number().int().gte(1), code: scheduleCode, header: z.record(z.string(), z.string()).optional()}); export const subRegister = z.enum(["A", "B", "C"]); export const registerEntry = z.object({entry_text: z.string().optional(), language_code: languageCode.optional(), schedule: scheduleInfo.optional(), legacy_entry_id: z.string(), draft_entry_code: z.string().min(5).max(5).optional(), sub_register_sequence: z.number().int().gte(1).optional(), role_code: z.string().min(4).max(4).optional(), draft_entry_version: z.number().int().gte(1).optional(), entry_sequence: z.number().int().gte(1).optional(), entry_date: z.string().optional(), sub_register_code: subRegister.optional()}); export const estateInterest = z.enum(["estate in land", "affecting franchise", "relating franchise", "manor", "profit à prendre in gross", "rentcharge", "perpetual rentcharge", "terminable rentcharge"]); export const address = z.object({legacy_addr_id: z.string(), description: z.string().max(1000)}); export const property = z.object({sequence: z.number().int().gte(1), address: address}); export const classOfTitle = z.enum(["absolute", "good", "qualified", "possessory"]); export const tenure = z.enum(["freehold", "leasehold"]); export const commonholdType = z.enum(["part", "unit"]); export const developerStatus = z.enum(["currently a developing title", "previously a developing title", "title is not a developing title"]); export const titleStatus = z.enum(["open", "closed", "pending new title"]); export const titleStatusInfo = z.object({date: z.string().optional(), value: titleStatus}); export const party = z.object({names: z.array(z.string()).optional(), role: z.string().optional()}); export const source = z.object({date: z.string().optional(), parties: z.array(party).optional(), type: z.string().optional()}); export const notice = z.object({protected_interests: z.array(z.string()).optional(), additional_considerations: z.array(z.string()).optional(), notes: z.array(z.string()).optional(), sources: z.array(source).optional(), expiry_condition: z.string().optional(), subject: z.string().optional(), parish_church: z.string().optional(), notice_type: z.enum(["agreed notice", "crown rent notice", "death duty notice", "home rights notice", "section 49 notice", "unilateral notice", "unknown"]).optional(), legacy_entry_ids: z.array(z.string()), notice_date: z.string().optional(), lease_term: z.string().optional(), served_by: z.string().optional(), entry_dates: z.array(z.string()).optional(), beneficiaries: z.array(z.string()).optional(), statute: z.string().optional(), object: z.string().optional()}); export const impliedCovenant = z.object({notes: z.array(z.string()).optional(), legacy_entry_id: z.string(), covenant_type: z.string().optional(), subject: z.string(), statute: z.string().optional(), entry_date: z.string().optional(), object: z.string().optional()}); export const personalCovenant = z.object({notes: z.array(z.string()).optional(), sources: z.array(source).optional(), legacy_entry_id: z.string(), covenantor: z.enum(["purchaser", "vendor"]).optional(), covenant_type: z.enum(["positive covenant", "indemnity covenant"]).optional(), subject: z.string(), entry_date: z.string().optional(), object: z.string().optional()}); export const interestsCovenants = z.object({implied_covenants: z.array(impliedCovenant).optional(), personal_covenants: z.array(personalCovenant).optional()}); export const authority = z.object({authority: z.string().optional(), description: z.string().optional()}); export const compliance = z.object({authority_title_number: z.string().optional(), form_of_compliance: z.string().optional(), alternative_authorities: z.array(authority), authority: z.string().optional(), additional_authorities: z.array(authority), description: z.string().optional(), compliance_type: z.string().optional()}); export const exemption = z.object({context: z.string().optional(), exemption: z.string().optional()}); export const restriction = z.object({restriction_type: z.string().optional(), additional_considerations: z.array(z.string()).optional(), notes: z.array(z.string()).optional(), restricted_parties: z.array(z.string()).optional(), legacy_entry_id: z.string(), expiry_condition: z.string().optional(), subject: z.string().optional(), expiry_date: z.string().optional(), impacted_action_condition: z.string().optional(), legacy_charge_id: z.string().optional(), entry_date: z.string().optional(), compliances: z.array(compliance).optional(), impacted_action_condition_date: z.string().optional(), restriction_form: z.enum(["A", "AA", "B", "BB", "C", "CC", "D", "DD", "E", "EE", "F", "FF", "G", "GG", "H", "HH", "I", "II", "J", "JJ", "K", "KK", "L", "LL", "M", "MM", "N", "NN", "O", "OO", "P", "PP", "Q", "QQ", "R", "RR", "S", "SS", "T", "U", "V", "W", "X", "Y", "NO FORM"]).optional(), housing_association_impact: z.string().optional(), exemptions: z.array(exemption).optional(), restricted_charge_date: z.string().optional(), restriction_form_description: z.enum(["Restriction on dispositions by sole proprietor", "Freezing order on the registered estate", "Dispositions by trustees of the legal estate – certificates required", "Freezing order on charge", "Dispositions by personal representatives – certificate required", "Application for freezing order on the registered estate", "Parsonage, diocesan glebe, church or churchyard land", "Application for freezing order on charge", "Non-exempt charity – certificate required", "Restraint order or interim receiving order on the registered estate", "Land vested in official custodian on trust for non-exempt charity – authority required", "Restraint order or interim receiving order on charge", "Tenant for life as registered proprietor of settled land, where there are trustees of the settlement", "Application for restraint order or interim receiving order on the registered estate", "Statutory owners as trustees of the settlement and registered proprietors of settled land", "Application for restraint order or interim receiving order on charge", "Tenant for life as registered proprietor of settled land – no trustees of the settlement", "Beneficial interest that is a right or claim in relation to a registered estate", "Trustee in bankruptcy and beneficial interest – certificate required", "Statutory charge of beneficial interest in favour of the Lord Chancellor", "Charging order affecting beneficial interest – certificate required", "Lease of property in Wales by registered social landlord", "Disposition by registered proprietor of a registered estate or proprietor of charge – certificate required", "Restriction as to evidence of execution", "Disposition by registered proprietor of registered estate or proprietor of charge – certificate of registered proprietor of specified title number required", "Interest in beneficial joint tenancy subject to charge under section 22(1) of the Health and Social Services and Social Security Adjudications Act 1983 or section 71 of the Social Services and Well-being (Wales) Act 2014", "Disposition by registered proprietor of registered estate or proprietor of charge – consent required", "Disposition by registered proprietor of registered estate or proprietor of charge – consent or certificate required", "Disposition by registered proprietor of registered estate or proprietor of charge – consent of registered proprietor of specified title number or certificate required", "Disposition by proprietor of charge – consent or certificate required", "Disposition by registered proprietor of registered estate or proprietor of charge – consent of proprietor of specified charge or certificate required", "Disposition by registered proprietor of registered estate or proprietor of charge – certificate of landlord or of a conveyancer, required", "Disposition by registered proprietor of registered estate or proprietor of charge – consent of personal representatives required", "Land included in a list of assets of community value maintained under section 87(1) of the Localism Act 2011", "Disposition by registered proprietor of registered estate or proprietor of charge – evidence of compliance with club rules required", "Deputy appointed under section 16 of the Mental Capacity Act 2005 – solely owned property", "Disposition by proprietor of charge – certificate of compliance required", "Trustee appointed in place of a person who lacks capacity – jointly owned property", "Disposition by proprietor of charge – consent required", "Section 37 of the Housing Act 1985", "Section 157 of the Housing Act 1985", "Paragraph 4 of Schedule 9A to the Housing Act 1985", "Section 133 of the Housing Act 1988 or section 173 of the Local Government and Housing Act 1989", "Section 13 of the Housing Act 1996", "The restriction is in a non-standard form"]).optional(), actions: z.array(z.string()), object: z.string().optional()}); export const interests = z.object({notices: z.array(notice).optional(), covenants: interestsCovenants.optional(), charges: z.array(z.union([z.object({additional_considerations: z.array(z.string()).optional(), charge_type: z.enum(["unknown", "registered charge", "equitable charge"]), notes: z.array(z.string()).optional(), sources: z.array(source).optional(), legacy_postponement_entry_ids: z.array(z.string()).optional(), subject: z.string().optional(), legacy_charge_id: z.string().optional(), charge_date: z.string().optional(), statute: z.string().optional(), object: z.string().optional(), discount_charge: z.boolean().optional(), legacy_charge_entry_id: z.string().optional(), entry_date: z.string().optional(), chargees: z.array(z.union([z.object({aliases: z.array(privateIndividualAlias).optional(), proprietor_type: z.literal("private individual"), sequence: z.number().int().gte(1).optional(), addresses: z.array(proprietorAddress).optional(), legacy_name_id: z.string().optional(), decor: z.string().optional(), surname: z.string().optional(), name: z.string(), title: z.string().optional(), forenames: z.string().optional()}), z.object({sequence: z.number().int().gte(1), addresses: z.array(proprietorAddress).optional(), legacy_name_id: z.string(), organisation_type: organisationType, name: z.string().max(366), company_registration_number: z.string().max(30).optional(), location: companyLocation, proprietor_type: z.literal("organisation")})])).optional(), legacy_chargee_entry_id: z.string().optional(), legacy_charge_restriction_entry_ids: z.array(z.string()).optional(), legacy_obligation_entry_ids: z.array(z.string()).optional(), expiry_date: z.string().optional()}), z.object({additional_considerations: z.array(z.string()).optional(), charge_type: z.enum(["unknown", "registered charge", "equitable charge"]), notes: z.array(z.string()).optional(), sources: z.array(source).optional(), legacy_postponement_entry_ids: z.array(z.string()).optional(), subject: z.string().optional(), legacy_charge_id: z.string().optional(), charge_date: z.string().optional(), statute: z.string().optional(), object: z.string().optional(), discount_charge: z.boolean().optional(), legacy_charge_entry_id: z.string().optional(), entry_date: z.string().optional(), beneficiaries: z.array(z.string()).optional()})])).optional(), restrictions: z.array(restriction).optional()}); export const postponement = z.object({additional_considerations: z.array(z.string()).optional(), legacy_entry_id: z.string(), postponement_charges: z.array(z.string()).optional(), entry_date: z.string().optional()}); export const concerns = z.object({postponements: z.array(postponement).optional()}); export const titleResponse = z.object({data_issues: z.array(dataIssue).optional(), previous_title_number: z.string().max(9).optional(), title_number: z.string().max(9), scheme_status: schemeStatus.optional(), continuation_title_number: z.string().max(9).optional(), application_timestamp: z.string().optional(), caution_against_first_registration: z.boolean(), application_reference: z.string(), timeshare_lease_issued: z.boolean().optional(), prices_paid: z.array(pricePaid), proprietors: z.array(z.discriminatedUnion("proprietor_type", [z.object({aliases: z.array(privateIndividualAlias).optional(), proprietor_type: z.literal("private individual"), sequence: z.number().int().gte(1).optional(), addresses: z.array(proprietorAddress).optional(), legacy_name_id: z.string().optional(), decor: z.string().optional(), surname: z.string().optional(), name: z.string(), title: z.string().optional(), forenames: z.string().optional()}), z.object({sequence: z.number().int().gte(1), addresses: z.array(proprietorAddress).optional(), legacy_name_id: z.string(), organisation_type: organisationType, name: z.string().max(366), company_registration_number: z.string().max(30).optional(), location: companyLocation, proprietor_type: z.literal("organisation")})])), district_name: z.string().max(38).optional(), entries: z.array(registerEntry), pre_act_caution: z.boolean().optional(), edition_date: z.string().optional(), estate_interest: estateInterest.optional(), properties: z.array(property), class_of_title: classOfTitle.optional(), tenure: tenure.optional(), commonhold_type: commonholdType.optional(), developer_status: developerStatus.optional(), status: titleStatusInfo, interests: interests.optional(), concerns: concerns.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 }; /** * Gets summary information for the title with the specified title number. * * GET /title/{titleNumber} */ export const getApiTitleTitleNumber = async (args: GetApiTitleTitleNumberArgs, options?: GetApiTitleTitleNumberOptions) => { const {baseUrl = "http://localhost:8080/api/v1", fetch: fetchFn = fetch, bearerAuth} = options ?? {} const query = new URLSearchParams() const headers = new Headers() headers.set('accept', "application/json") if (bearerAuth !== undefined) headers.set('authorization', `Bearer ${bearerAuth}`) const url = `${baseUrl.replace(/\/+$/, '')}/title/${encodeURIComponent(String(args.titleNumber))}${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(titleResponse, await res.json()) };