# vcard (adapter system)

vCard / contact data-model pack (CRM primitive): build, parse, convert and validate electronic business cards. create(): a contact JSON (name, org, phones, emails, addresses, urls, birthday, note...


The **contact data-model** pack — a CRM primitive. It turns structured contact JSON into the
interchange formats real address books speak, and parses them back:

- **vCard 3.0 / 4.0** (RFC 2426 / RFC 6350) — the `.vcf` electronic business card, with correct
  CRLF line endings, 75-octet line folding, and value escaping (`\` `,` `;` newline).
- **MECARD** — the compact single-line `MECARD:...;;` string embedded inside contact QR codes.
- **h-card** — microformats2 HTML for putting a machine-readable contact on a web page (SEO/parsers).

`parse()` round-trips `create()`. **Pure JavaScript — Node built-ins only, zero npm deps.**

## Tools (`adapters`)

| tool | args | result |
|------|------|--------|
| `create` | `{ contact, version? }` | `{ version, vcard, mimeType, extension }` — one .vcf card |
| `parse` | `{ vcard }` | `{ count, contacts[], contact }` — JSON from .vcf text |
| `fromJson` | `{ contact }` | `{ contact }` — loose payload normalized to the canonical shape |
| `toMeCard` | `{ contact }` | `{ mecard, length, note }` — compact QR payload string |
| `toHCard` | `{ contact }` | `{ html, format, spec }` — h-card microformat HTML |
| `validate` | `{ contact }` | `{ valid, errors[], warnings[], summary }` |
| `batch` | `{ contacts[], version? }` | `{ count, skipped, errors[], vcard, ... }` — one multi-card book |
| `fields` | — | `{ count, fields[] }` — every supported field, its type + aliases |

`version` is `"3.0"` (default) or `"4.0"`.

### Contact shape

Canonical keys (see `fields()` for the full list + accepted aliases):
`firstName`, `lastName`, `middleName`, `prefix`, `suffix`, `fullName`, `nickname`, `org`, `title`,
`phones[]`, `emails[]`, `urls[]` (each `{ type, value }` or a bare string), `addresses[]`
(`{ type, street, city, region, postalCode, country }`), `birthday`, `note`, `photo`, `geo{lat,lng}`,
`categories[]`. Input is aliased generously — `name`, `company`, `mobile`, `e-mail`, `website`, `zip`,
etc. all fold into the canonical keys via `fromJson`.

## Usage

```js
import vcard from './index.js';

const { vcard: vcf } = vcard.adapters.create({
  contact: {
    firstName: 'Ada', lastName: 'Lovelace', org: 'Analytical Engines',
    emails: ['ada@example.com'], phones: [{ type: 'cell', value: '+1-555-0100' }],
    urls: ['https://example.com'],
  },
  version: '3.0',
});

const { contact } = vcard.adapters.parse({ vcard: vcf }); // round-trips
const { mecard } = vcard.adapters.toMeCard({ contact });   // -> feed to a QR encoder
```

## DRY boundary

This pack is the **contact data model**; it does **not** rasterize anything. The sibling **`qr`**
pack *encodes* a payload string into a QR image — `toMeCard()` here produces exactly the string you
would hand to `qr.render` (`type: "text"`). Keep encoding/rendering in `qr`; keep the vCard/MECARD/
h-card contact model here.


---
Source: shared/engines/adapters/domain/vcard/README.md
Canonical: https://docs.leumas.tech/p/adapters/domain/vcard
