TypeScript library providing normalized, serializable DTOs for client data (persons and companies) used in CYRRUS DocHub API and Cytron business core system integrations.
Version: 9.x (Cytron-compatible) | Legacy: Version 8.x documentation
npm install @cyrrus/client-data-structureimport { ClientData } from '@cyrrus/client-data-structure'
// Create client data
const client = new ClientData({
client: { type: 'person', isResident: true },
personal: { firstName: 'John', lastName: 'Doe' },
contact: { email: 'john@example.com' },
address: { address: { street: '123 Main St', city: 'Prague' } },
bankAccounts: []
})
// Serialize
const json = JSON.stringify(client)
const plain = client.toPlainObject()
// Validate (requires peer dependencies)
client.validate() // throws on error with details in error.causeClientData contains seven main components:
| Component | Type | Usage | Key Fields |
|---|---|---|---|
client |
ClientInformation |
System metadata | type, internalId, contactId, isResident, investmentParameters, brokerContactId |
personal |
PersonalInformation |
Personal details | firstName, lastName, dateOfBirth, birthNumber, citizenship |
idCard |
IdCardInformation |
ID document | number, type, issuedBy, validUntil |
address |
AddressInformation |
Addresses | address (postal), mailingAddress, useMailingAddress |
contact |
ContactInformation |
Communication | email, phoneNumber |
bankAccounts |
BankAccount[] |
Bank accounts | accountNumber, bankCode, iban, swift, currency |
company |
CompanyInformation |
Company data | name, ic, dic, lei, representatives[] |
Client Types: person, company, selfemployed
- Person/Self-employed: Uses
personal,idCard - Company: Uses
companywithrepresentatives[]array
See dataExamples/person.json and dataExamples/company.json for complete examples.
Validation is opt-in - install peer dependencies:
npm install ajv ajv-formats cdigit ibantools libphonenumber-jsAll classes extend AbstractBase providing:
validate()- Throws with validation errors inerror.causetoJSONSchema()- Returns JSON Schema definitiontoPlainObject()/toJSON()- Serialization
- Private readonly fields (
#field) with public getters - No setters - instances cannot be mutated after creation
- Constructor accepts
Partial<XInput>with defaults
getStringOrNull()- Normalizes strings, returnsnullfor emptygetNormalizedDate()- Parses dates toYYYY-MM-DDTHH:MM:SS.SSSZformat (noon UTC)getInstanceOfClass()- Handles both plain objects and class instances
Legal identifiers are sanitized during construction using the internal legal ID normalizer.
- Affects:
PersonalInformation.birthNumber,CompanyInformation.ic,CompanyInformation.dic,CompanyInformation.lei - Behavior: trims, converts to uppercase, removes all non-alphanumeric characters
- Invalid input type behavior: non-string values are normalized to
null
new PersonalInformation({ birthNumber: ' 900101/1234 ' }).birthNumber // -> '9001011234'
new CompanyInformation({ ic: ' cz-123 45 678 ' }).ic // -> 'CZ12345678'
new CompanyInformation({ dic: 123456 as unknown as string }).dic // -> nullEach class exports three types:
XInput- Constructor input (partial/optional fields)XOutput- Serialized output (plain object)XJSONSchema- JSON Schema type definition
Key breaking changes from version 8.x:
| Change Type | v8 | v9 | Location | Notes |
|---|---|---|---|---|
| Field Rename | dataOriginId |
internalId |
ClientInformation | |
| Field Rename | residency |
isResident |
ClientInformation | |
| Field Rename | foreign |
isForeign |
BankAccount | |
| Field Rename | added |
addedAt |
InvestmentParameter | |
| Enum Value | 'OP' |
'id' |
IdCardInformation.type | |
| Enum Value | 'Pas' |
'passport' |
IdCardInformation.type | |
| Removed | capitolId |
(removed) | ClientInformation | Capitol → Cytron |
| Removed | brokerId |
(removed) | ClientInformation | Capitol → Cytron |
| Removed | externalBrokerCapitolId |
(removed) | ClientInformation | Capitol → Cytron |
| Removed | externalBrokerAgentCapitolId |
(removed) | ClientInformation | Capitol → Cytron |
| Removed | crmId |
(removed) | ClientInformation | Capitol → Cytron |
| Removed | bankAccountsConfirmedByAffidavit |
(removed) | ClientInformation | Moved to BankAccount |
| Removed | investmentProfiles |
(removed) | ClientInformation | Simplified structure |
| Removed | capitolId |
(removed) | Representative | Capitol → Cytron |
| Removed | capitolContactId |
(removed) | Representative | Capitol → Cytron |
| Removed | position |
(removed) | Representative | |
| Removed | capitolId |
(removed) | BankAccount | Capitol → Cytron |
| Removed | phonePassword |
(removed) | ContactInformation | |
| Added | (new) | contactId |
ClientInformation | Set to null |
| Added | (new) | brokerContactId |
ClientInformation | Set to null |
| Added | (new) | externalBrokerContactId |
ClientInformation | Set to null |
| Added | (new) | externalBrokerAgentContactId |
ClientInformation | Set to null |
| Added | legislation |
preferredLanguage |
ClientInformation | Field renamed/remapped |
| Added | (new) | cytronId |
Representative | Set to null |
| Added | (new) | contactId |
Representative | Set to null |
| Added | (new) | cytronId |
BankAccount | Set to null |
| Added | (new) | isConfirmedByAffidavit |
BankAccount | From client.bankAccountsConfirmedByAffidavit |
| Entity Removed | InvestmentProfile |
(removed) | - | Simplified to InvestmentParameter only |
| Entity Removed | InvestmentService |
(removed) | - | No longer supported |
All country code fields now store and output ISO 3166-1 alpha-2 codes (e.g. 'CZ', 'SK', 'DE') instead of alpha-3 codes (e.g. 'CZE', 'SVK', 'DEU'). This aligns with the Cytron business core system which uses alpha-2 codes natively.
Affected fields: Address.country, IdCardInformation.country, PersonalInformation.birthNumberCountry, PersonalInformation.taxDomicile, PersonalInformation.citizenship, CompanyInformation.taxDomicile.
The constructors accept both alpha-2 and alpha-3 input — alpha-3 values are automatically normalized to alpha-2 on construction. Invalid or unrecognized country codes are stored as null.
// Both inputs produce the same stored alpha-2 code
new PersonalInformation({ citizenship: 'CZE' }).citizenship // → 'CZ'
new PersonalInformation({ citizenship: 'CZ' }).citizenship // → 'CZ'
new PersonalInformation({ citizenship: 'xyz' }).citizenship // → nullLocalized country names are available via dedicated getters and locale methods:
| Class | Czech name getter | Localized name method |
|---|---|---|
Address |
countryName |
localizedCountryName(locale) |
IdCardInformation |
countryName |
localizedCountryName(locale) |
PersonalInformation |
birthNumberCountryName, citizenshipCountryName, taxDomicileCountryName |
localizedBirthNumberCountryName(locale), localizedCitizenshipCountryName(locale), localizedTaxDomicileCountryName(locale) |
const personal = new PersonalInformation({ citizenship: 'CZ' })
personal.citizenship // → 'CZ'
personal.citizenshipCountryName // → 'Česká republika' (Czech locale)
personal.localizedCitizenshipCountryName(AvailableLanguages.en_US) // → 'Czech Republic'Migration impact: If your code stores or compares country codes, update any hardcoded alpha-3 literals to alpha-2. The fromLegacyClientData() migration helper handles this conversion automatically for v8 data.
Use migration helper:
import { fromLegacyClientData } from '@cyrrus/client-data-structure'
const v9Client = fromLegacyClientData(v8Data)npm run build # Build ESM + CJS + types to dist/
npm test # Run Jest tests (builds test bundle first)
npm run docs # Generate TypeDoc documentation
npm run lint # ESLint with TypeScript strict rulesBuild Output: Dual-format (ESM .js + CJS .cjs) with source maps and type definitions
MIT