@taxbit/utilities
v7.3.0
Published
Taxbit Utilities
Keywords
Readme
Taxbit Utilities
A collection of helpers, lookups, validations, and report generators used across Taxbit applications. Everything in this package is exported from the package root, so you can import directly from '@taxbit/utilities'.
Install
- npm: npm i @taxbit/utilities
- yarn: yarn add @taxbit/utilities
Import patterns
Named imports are preferred.
import { getCountryOptions, getCountryLabel, camelCaseKeys, } from '@taxbit/utilities'
Contents overview
- Lookups (codes, labels, options, and treaty helpers)
- Treaty claims (general and special rates, limitation on benefits)
- FATCA (chapter 4 classifications, IGA categories, GIIN requirements)
- Validations (simple validators)
- Validation reports (address and tax documentation)
- Error message helpers
- Utilities (camelCaseKeys, snakeCaseKeys)
- Types and schema versions
Lookups
These functions and constants help with countries, states/provinces, months, account types, signatures, and treaty data.
Countries and phone helpers
- countryCodes: CountryCode[] — All ISO 3166-1 alpha-2 country codes supported.
- euCountryCodes: readonly string[] — EU member country codes.
- smallUsTerritoryCountryCodes: readonly ['UM','FM'] — Small US territories represented as country codes.
- normalUsTerritoryCountryCodes: readonly ['AS','GU','MP','PR','VI'] — Larger US territories (outside the 50 states).
- doesNotIssueTinCountryCodes: readonly string[] - Country codes for countries which do not issue TINs.
- doesNotRequireTinDisclosureCountryCodes: readonly ['JP'] - Country codes for countries which do not require TIN disclosures.
- highRiskCountryCodes: readonly string[] - Country codes for countries classified as high risk under OECD guidance.
- isHighRiskCountry(code: string | undefined): boolean - Whether a country is classified as high risk under OECD guidance.
- isTinNotIssuedByCountry(code: string | undefined): boolean - Whether TIN is not issued by the given country.
- isTinDisclosureNotRequiredByCountry(code: string | undefined): boolean - Whether TIN disclosure is not required by the given country.
- isTinExpectedByCountry(code: string | undefined): boolean - Whether TIN is expected by the given country.
- isEuCountryCode(code: string): boolean — Whether a code is in the EU.
- getCountry(code: CountryCode): Country | undefined — Returns the country metadata (internal shape) for a given code.
- getCountryLabel(code: string | undefined, language: string): string — Returns a localized country label. The language should be an IETF/BCP47 tag (e.g., 'en', 'fr').
- getCountryOptions(language: string): Array<{ value: string; label: string }>
- getCountryWithPhoneOptions(language: string): Array<{ value: string; label: string }> — Like getCountryOptions, but label includes phone dialing code.
- getCountryAndPhoneNumber(input: string): { countryCode?: string; phoneNumber?: string } — Extracts a leading + and the remaining number.
- getPhoneNumber(code: string, number: string, formatted?: boolean): string — Build a phone number for a country; optionally formatted.
Examples
getCountryOptions('en') // → [{ value: 'AF', label: 'Afghanistan' }, ...]
getCountryLabel('AL', 'fr') // → 'Albanie'
getCountryAndPhoneNumber('+1 206-555-1212') // → { countryCode: 'US', phoneNumber: '2065551212' }
US states
- usStateCodes: string[] — All 50 US state codes.
- getUsStateOptions(): Array<{ value: string; label: string }>
- getUsStateLabel(code?: string): string
Canada provinces
- caProvinceCodes: string[] — Canadian provincial/territory codes.
- getCaProvinceOptions(language: string): Array<{ value: string; label: string }>
- getCaProvinceLabel(code?: string, language: string): string
Months
- monthCodes: string[] — ['01', '02', ..., '12']
- getMonthOptions(language: string): Array<{ value: string; label: string }>
- getMonthLabel(month?: string, language: string): string
- getFormattedEventDate(combined: string | undefined, language: string): string — Formats a stored 'MM/DD/YYYY' date as a localized long date for display. Intl supplies both the spelled-out month and the per-locale field order, so a recited date is unambiguous in any language. Returns the input unchanged if it is not a real calendar date (incomplete, or an overflow like '02/31/2020').
Example
getFormattedEventDate('03/07/2013', 'en-US') // → 'March 7, 2013' getFormattedEventDate('03/07/2013', 'de') // → '7. März 2013' getFormattedEventDate('03/07/2013', 'ja') // → '2013年3月7日'
Account and Entity types
All of the following are readonly string literal arrays plus their corresponding union types (when present):
- accountOwnerTypes
- activeNonFinancialEntityTypes
- entityAccountHolderAccountTypes
- entityRegardedOwnerAccountTypes
- entityTypes and type EntityType
- exemptFatcaCodes
- exemptPayeeCodes
- financialInstitutionTypes
- foreignAccountHolderAccountTypes
- foreignRegardedOwnerAccountTypes
- intermediaryAccountTypes
- limitationOnBenefits and type LimitationOnBenefit
- selfCertificationAccountTypes
- signatureCapacities and type SignatureCapacity
- tinNotRequiredReasons
- usAccountHolderAccountTypes
- usLlcAccountTypes
- usRegardedOwnerAccountTypes
Controlling Person Roles
- trustRoles: readonly string[] — Roles for trust entities
- similarToTrustRoles: readonly string[] — Roles for entities similar to trusts
- otherEntityRoles: readonly string[] — Roles for other entity types
- getControllingPersonRoles(entityType: EntityType): readonly string[] — Returns appropriate roles for entity type
Additional lookup helpers
- getLimitationOnBenefit(limitationOnBenefit: string): LimitationOnBenefit — Maps camelCase keys to limitation constants
Treaty helpers
- treatyCountryCodes: string[] — Codes of countries with treaty data.
- typesOfIncomeIndividual: Array
- typesOfIncomeEntity: Array
- getTreatyCountry(countryCode?: string): TreatyCountry — Returns structured treaty data or an empty object with defaults.
- getTreatyCountryWithholding(countryCode?: string, typeOfIncome?: string): { rate: string; articleParagraph: string; additionalConditionsRequired: boolean } | undefined
- getTreatyCountryWithholdingLabel(countryCode?: string, typeOfIncome?: string): string — Friendly label like "15% - Article 12(2)"; defaults to '30%'.
- getTreatyCountryLimitationsOnBenefit(country?: string): Array
- hasLimitationOnBenefits(country?: string): boolean
- getTreatyCountryLimitationOnBenefitOtherArticleParagraphs(country?: string): string[]
- isAdditionalConditionsRequired(country?: string, typeOfIncome?: string): boolean
Example
getTreatyCountryWithholdingLabel('GB', 'ROYALTIES_OTHER') // → '0% - Article 12(1)'
Treaty claims (general and special)
A treaty claim is either a general rate (published in the treaty for an income type) or a special rate that requires additional criteria. These helpers resolve which are available for a country and income-type selection.
- getClaimsForCountry(iso: string, types: TypeOfIncome[]): { general: GeneralClaim[]; special: SpecialClaim[] } — Both claim sets for a country, narrowed to the income types requested.
- hasGeneralClaims(iso: string, types: TypeOfIncome[]): boolean
- hasSpecialClaims(iso: string, types: TypeOfIncome[]): boolean
- getSpecialTreatyClaimCriteria(iso?: string, typeOfIncome?: string): SpecialTreatyClaimCriteria | undefined — The criteria a special claim requires, or undefined when the country/income type offers none.
- getCountriesForIncomeTypes(types: TypeOfIncome[]): TreatyCountry[] — Treaty countries offering a claim for any of the income types.
- getCountryCodesForIncomeTypes(types: TypeOfIncome[]): string[] — As above, codes only.
- getNormalizedIncomeType(value: string): TypeOfIncome | undefined — Resolves a loose income-type string to the canonical union member.
- isEntityOnlySpecialIncomeType(type: TypeOfIncome): boolean
- formatRateLabel(claim: { rate: number; articleParagraph?: string }): string — Friendly label like "15% - Article 12(2)".
- ALL_TYPES_OF_INCOME: TypeOfIncome[] — Every supported income type.
- ENTITY_ONLY_SPECIAL_INCOME_TYPES: readonly TypeOfIncome[] — Special income types available to entities only.
- Types: GeneralClaim, SpecialClaim, GeneralTypeOfIncome, SpecialTreatyClaimCriteria, LobProvisionKey
FATCA classifications
Chapter 4 (FATCA) status data behind W-8BEN-E and W-8IMY collection.
- fatcaClassifications and type FatcaClassification — Every chapter 4 classification.
- type FatcaCategory — 'FFI' | 'NFFE' | 'OTHER'.
- type FatcaClaimant — 'entity' | 'intermediary' | 'both'.
- getFatcaClassificationsByCategory(category: FatcaCategory): FatcaClassification[]
- getFatcaClassificationsForClaimant(claimant: 'entity' | 'intermediary'): FatcaClassification[]
- getFatcaClassificationMetadata(classification: FatcaClassification): FatcaClassificationMetadata — Category, claimant applicability, and GIIN requirement for one classification.
- getIncompatibleFatcaClassifications(ch3: Ch3Status): FatcaClassification[] — Chapter 4 statuses that cannot pair with a given chapter 3 status.
- isFatcaClassificationBlocked(ch3: Ch3Status, ch4: FatcaClassification): boolean
- isCertifiedDeemedCompliantFfi(value: string | undefined): value is FatcaClassification
- certifiedDeemedCompliantFfiClassifications: FatcaClassification[] — The classifications grouped under the certified deemed-compliant umbrella.
- CERTIFIED_DEEMED_COMPLIANT_FFI_UMBRELLA: 'CERTIFIED_DEEMED_COMPLIANT_FFI'
- ch3Statuses and type Ch3Status — Chapter 3 statuses (18 values), used for the chapter 3 / chapter 4 compatibility checks above.
Classification sub-types
Readonly string literal arrays plus their corresponding union types:
- exemptRetirementPlanSubTypes and type ExemptRetirementPlanSubType
- ownerDocumentedFfiDocTypes and type OwnerDocumentedFfiDocType
- publiclyTradedNffeSubTypes and type PubliclyTradedNffeSubType
- sponsoredFfiSubTypes and type SponsoredFfiSubType
- restrictedDistributorProhibitionSources and type RestrictedDistributorProhibitionSource
- internationalOrgBases and type InternationalOrgBasis
- securitiesExchangeKeys and type SecuritiesExchangeKey
- securitiesExchangeLabels — Display ("Proper Format") label for each exchange key.
- type SubstantialUsOwner
IGA (Annex II) helpers
- getIgaModel(countryCode?: string): IgaModel | undefined — 'MODEL_1' | 'MODEL_2', or undefined for a non-IGA country.
- getIgaCategories(countryCode?: string): IgaCategory[] — The Annex II categories a country offers (empty for a non-IGA country).
- getIgaCategoryGiinRequirement(countryCode: string, categoryKey: string): IgaGiinRequirement | undefined — GIIN requirement for a (country, category) pairing, or undefined if not offered.
- igaCategoryKeys and type IgaCategoryKey
- igaCountryCodes and type IgaCountryCode
- type IgaModel, type IgaGiinRequirement, type GiinRequirement — 'required' | 'conditional' | 'none'.
Example
getIgaModel('DE') // → 'MODEL_1' getFatcaClassificationsByCategory('NFFE') // → ['ACTIVE_NFFE', 'PASSIVE_NFFE', ...]
Validations
Simple predicates for common fields.
- isCountryCode(value: unknown): value is CountryCode
- isSmallUsTerritoryCountryCode(value: unknown): value is SmallUsTerritoryCountryCode
- isNormalUsTerritoryCountryCode(value: unknown): value is NormalUsTerritoryCountryCode
- isValidEmailAddress(value: unknown): boolean
- isValidPhoneNumber(value: unknown): boolean
- isCorrectGiinFormat(value: unknown): boolean
Dates
All accept 'MM/DD/YYYY', padded or unpadded ('1/5/2020' and '01/05/2020').
- isValidDateFormat(dateString: unknown): boolean — Shape only: one or two digit month/day and a four digit year.
- isValidDateString(value: unknown): boolean — A real calendar date. Rejects overflow like '02/30/2020' and out-of-range months like '13/01/2020' by round-tripping the parts through a UTC Date.
- isPlausiblePastDate(date: string): boolean — Not in the future and within ~121 years. A generic "earliest date" bound reused for dates of birth and for FATCA formation / filing / determination-letter dates.
- isAboveMinimumAge(birthday: string, minAge?: number): boolean — Whether the birthday is at least minAge years ago (defaults to 0).
Examples
isCountryCode('US') // true isValidEmailAddress('[email protected]') // true isValidPhoneNumber('+14155552671') // true isValidDateFormat('3/7/2013') // true isValidDateString('02/30/2020') // false
Validation reports
Tools to build structured validation results used by forms and APIs. SchemaVersion for validation is currently '3.0'
Address validation reports
- getAddressValidationReport(address: unknown): ValidationReport
- getCaAddressValidationReport(address: CaAddress): ValidationReport
- getUsStateAddressValidationReport(address: UsStateAddress): ValidationReport
Types
- CaAddress: { city: string; country: 'CA'; stateOrProvince: CaProvinceCode; firstLine: string; secondLine?: string; postalCode: string }
- UsStateAddress: { city: string; country: 'US'; stateOrProvince: Exclude<UsStateCode, SmallUsTerritoryCountryCode | NormalUsTerritoryCountryCode>; firstLine: string; secondLine?: string; postalCode: string }
Tax documentation validation reports
- assertVerifiedClientTaxDocumentation(data: unknown): asserts data is SignedClientTaxDocumentation
- assertVerifiedComprehensiveTaxDocumentation(data: unknown): asserts data is SignedDatedComprehensiveTaxDocumentation
- getClientTaxDocumentationValidationReport(data: unknown): ValidationReport
- getComprehensiveTaxDocumentationValidationReport(data: unknown): ValidationReport
- getDpsApiValidationReport(data: unknown, isCamelCased?: boolean): ValidationReport
- getSelfCertificationApiTaxDocumentationValidationReport(data: unknown, isCamelCased?: boolean): ValidationReport
- getWFormForeignIntermediaryApiValidationReport(data: unknown): ValidationReport
- getWFormTreatyClaimApiValidationReport(data: unknown): ValidationReport
Example
import { getAddressValidationReport } from '@taxbit/utilities'
const report = getAddressValidationReport({ country: 'US', stateOrProvince: 'CA', city: 'Salt Lake City', firstLine: '123 Example St', postalCode: '84111', })
if (report.hasIssues()) { console.log(report.issues) }
Error message helpers
Each function takes a value (and sometimes additional context) and returns an array of message keys or undefined if the value is valid.
- getBusinessRegistrationNumberErrorMessages(value: unknown)
- getCaPostalCodeErrorMessages(value: unknown)
- getCaStateOrProvinceErrorMessages(value: unknown)
- getCountryErrorMessages(value: unknown)
- getDateOfBirthErrorMessages(value: unknown)
- getEmailAddressErrorMessages(value: unknown)
- getGbTinNinoErrorMessages(value: unknown)
- getPhoneNumberErrorMessages(value: unknown)
- getSignatureErrorMessages(value: unknown)
- getSpecialNumberErrorMessages(value: unknown)
- getSpecialStringErrorMessages(value: unknown)
- getTaxResidencesErrorMessages(value: unknown)
- getTaxResidenceTinErrorMessages(value: unknown)
- getUsPostalCodeErrorMessages(value: unknown)
- getUsStateOrProvinceErrorMessages(value: unknown)
- getUsTinErrorMessages(value: unknown)
- getVatIdentificationNumberErrorMessages(value: unknown)
- getWFormDateOfBirthErrorMessages(value: unknown)
- getGinnErrorMessages(value: unknown)
- getPastDateErrorMessages(value: unknown)
Utilities
- camelCaseKeys(obj: T): CamelCaseKeys
- snakeCaseKeys(obj: T): SnakeCaseKeys
Examples
camelCaseKeys({ first_name: 'A', LAST_NAME: 'B' }) // → { firstName: 'A', lastName: 'b' }
snakeCaseKeys({ firstName: 'A', lastName: 'B', nestedValue1: { myValue2: 2 } }) // → { first_name: 'A', last_name: 'B', nested_value_1: { my_value_2: 2 } }
Types
Exported types (see source for full definitions):
- From types/ClientTaxDocumentation
- ClientAddress
- ClientTaxResidence
- ControllingPerson
- ClientAccountHolderTaxDocumentation
- ClientRegardedOwnerTaxDocumentation
- ClientTaxDocumentation
- SignedClientTaxDocumentation
- From types/ComprehensiveTaxDocumentation
- SignedComprehensiveTaxDocumentation
- SignedDatedComprehensiveTaxDocumentation
- From types/ErrorMessage
- ErrorMessage
- From types/Questionnaire
- Questionnaire
- From types/TypeOfIncome
- TypeOfIncome
- From types/TreatyCountry
- TreatyCountry
- From types/SubmissionConfig
- SubmissionConfig
- From types/ValidationError
- ValidationError
- From types/CamelCaseKeys
- CamelCase
- CamelCaseKeys
- SnakeCaseKeys
- From types/Utilities
- Requiredish
- Extends
- IsExact
- RequireKeys
Notes
- Language parameters are expected to be IETF language tags (e.g., 'en', 'fr').
- Option/list helpers typically return arrays shaped as { value: string; label: string }.
Contributing
- Keep this README in sync with new exports from src/index.ts.
- When adding lookups, prefer readonly const arrays and export matching union types for better type safety.
Validation Report Notes
The getComprehensiveTaxDocumentationValidationReport function is used to validate the Submission posts.
| Package Version | Current Schema Version | Validation Report Improvements | Validated Schema Version | | :-------------: | :--------------------: | -------------------------------------------------------- | :----------------------: | | 4.0.0 | 3.1 | Schema Version removed from Validation Report functions | 3.0 | | 3.6.0 | 3.1 | OECD high risk country helper function. | 3.0 | | 3.5.0 | 3.1 | Country code helper functions. | 3.0 | | 3.4.0 | 3.1 | CARF/CRS validations. | 3.0 | | 3.3.x | 3.1 | Tax Residence Validation Refinements | 3.0 | | 3.2.x | 3.1 | W8IMY validation report. | 3.0 | | 3.1.0 | 3.1 | Self-Cert and SERR validation reports. | 2.0 | | 3.0.0 | 3.0 | Account Owner key for foreign accounts. | 2.0 | | 2.0.0 | 2.0 | Treaty Claim validation report. | 2.0 | | 0.3.3 | 1.1 | Updated validations for US territories. | 1.1 | | 0.3.1 | 1.0 | Initial release with lookups, validations, and utilities | 1.0 |
Version History
Release notes now live in CHANGELOG.md. Entries below predate it.
4.0.0
- Removing schemaVersion argument from validation report methods.
