npm.io
0.3.3 • Published 2 weeks agoCLI

@sampuli/data

Licence
MIT
Version
0.3.3
Deps
0
Size
1.8 MB
Vulns
0
Weekly
0

@sampuli/data

npm version downloads CI license zero deps

Synthetic test data that passes your own validators — 90 countries.

Most fake-data tools give you John Doe and a random 16-digit number. @sampuli/data gives you a KRA PIN that passes a KRA validator, a real bank's SWIFT/BIC, a valid IBAN (mod-97), an ICAO-9303 passport MRZ, a Luhn-valid card — each one shaped to its country's actual rules (checksums, prefixes, bank codes). Entirely synthetic; corresponds to no real person or account.

npm install @sampuli/data

Try it in your browser, no install: sampuli.site · or in your terminal: npx @sampuli/data ke.person

Why not faker / Mockaroo?

faker.js Mockaroo @sampuli/data
Country-specific ID / tax formats partial ✓ 90 countries
Checksum-valid (Luhn, mod-97, mod-11…)
Real bank names + SWIFT/BIC
Valid IBANs, CLABE, NUBAN…
Passport MRZ (ICAO-9303)
Coherent records (bankSWIFT, gendername) partial
Reproducible seeds · zero deps · free

Built for QA and CI at banks and fintechs — test data that passes your own format validation, so you can exercise KYC, onboarding and payment flows without touching real PII.

Older intro / disclaimer

One API, dozens of countries: Kenyan KRA PINs & M-Pesa numbers, Nigerian BVNs, German & Gulf IBANs, Italian Codice Fiscale, Brazilian CPF/CNPJ, Mexican CLABE, Turkish TCKN, Singapore NRIC — and many more.

Every value is entirely synthetic. It matches the real format only and corresponds to no real person, account, or registered number. Never present any output as a genuine ID, tax number, IBAN, or bank account.

From the terminal (CLI)

No code needed — try it with npx:

npx @sampuli/data ke.person                 # one Kenyan record (JSON)
npx @sampuli/data ke.kra_pin                # a single value
npx @sampuli/data ng.person -n 100          # 100 records
npx @sampuli/data de.person -f name,account,card,passport_mrz
npx @sampuli/data ke.person -n 500 --csv    # CSV to stdout
npx @sampuli/data ke.preset:kyc             # a KYC scenario
npx @sampuli/data --list                    # list all 90 country codes
npx @sampuli/data --list ke                 # a country's fields & presets

Quick start

import { generate, generateMany, listPacks } from '@sampuli/data'

listPacks()             // every installed country, e.g.
                        // ['KE','NG','ZA','EG','DE','FR','IT','TR','SA','BR','MX','SG', …]

// One value — the spec is `country.field`:
generate('ke.phone')    // Kenya     → '0712345678'
generate('ng.bvn')      // Nigeria   → '22803022407'
generate('de.account')  // Germany   → 'DE19100900004650895069'   (IBAN)
generate('it.id')       // Italy     → 'LNEFRC90M22F205G'         (Codice Fiscale)
generate('sg.id')       // Singapore → 'S6763250H'                (NRIC)

// A whole coherent record — any country:
generate('de.person')
// → {
//     name: 'Mia Zimmermann', phone: '0179 1480356', id: 'L0PYL465F',
//     tax: '74259823954', bank: 'HypoVereinsbank', swift: 'HYVEDEMMXXX',
//     account: 'DE68700202706388873556', amount: '€16.680,00'
//   }

generateMany('br.person', 500)   // → 500 coherent Brazilian records (core fields)

// `person` returns the common fields; ask for everything with `full`
// (or an explicit list) — cards, passport + MRZ, transaction, IP, income…:
generate('de.full')                          // every field
generate('de.person', { fields: 'all' })     // same thing
generate('de.person', { fields: ['name', 'card', 'passport_mrz'] })

// Generic types (uuid, enum, int, date, vin, isbn…) — validated where it
// counts (VIN/ISBN/IMEI check digits, RFC-4122 UUIDs):
generate('any.uuid')            // 'f47ac10b-58cc-4372-a567-0e02b2c3d479'
generate('any.enum:free,pro')   // 'pro'
generate('any.vin')             // valid VIN check digit

// Custom schema — mix generic types AND country-accurate fields, à la Mockaroo:
import { generateSchema } from '@sampuli/data'
generateSchema({
  count: 100,
  fields: [
    { name: 'id', type: 'uuid' },
    { name: 'phone', type: 'ke.phone' },     // country-accurate
    { name: 'plan', type: 'enum:free,pro,team' },
    { name: 'mrr', type: 'int:0,500', blank: 0.1 },   // 10% null
  ],
})

// Beyond people — companies and products, correct for the country:
generate('de.company')  // → { name: 'Nova Labs GmbH', industry: 'Software',
                        //     vat: 'DE114...', phone: '0179...', currency: 'EUR', … }
generate('jp.product')  // → { name: 'Pro Speaker', price: 8250, currency: 'JPY',
                        //     ean: '4988... ' (valid EAN-13), sku: 'KT-402917', … }

Every pack uses the same spec shape — swap the country code. A pack's fields and presets vary by country; discover them with listFields(code) / listPresets(code). Records stay internally coherent (bank SWIFT, gender name, town region, email name).

CommonJS works too:

const { generate } = require('@sampuli/data')

What you can generate

generate(spec, settings?) — the spec is pack.selector:

Spec Returns
'ke.phone', 'ke.kra_pin', 'ke.national_id', … a single field value
'ke.person' (or just 'ke') a full coherent record (object)
'ke.preset:kyc' ordered [label, value] rows for a scenario

Discover what a pack offers:

import { listFields, listPresets } from '@sampuli/data'

listFields('ke')   // [{ key: 'phone', label: 'Phone', num: false, ... }, ...]
listPresets('ke')  // [{ key: 'kyc', name: 'KYC customer profile', ... }, ...]

Kenya's field keys, for example: name, phone, id, kra, bank, swift, account, amount, gender, dob, marital, occupation, town, county, gps, address, business, paybill, till, plate, email, avatar, ref. Presets: kyc, pesalink, schoolfees, fx, merchant. Other countries share the common core (name/phone/id/tax/bank/ swift/account/amount) with locale-specific extras and presets — always check listFields(code).

Every country also has payment-card and passport fields (off by default): card (Luhn-valid PAN, scheme-correct BIN), card_scheme (Visa / Mastercard / American Express), card_expiry (MM/YY), card_cvv, passport (number), passport_expiry, and passport_mrz — a full ICAO-9303 TD3 machine-readable zone with correct check digits, coherent with the record's name and gender.

generate('dk.card')          // → '4536 3094 5269 0134'  (Visa, Luhn-valid)
generate('gb.person', { fields: ['name', 'card', 'card_scheme', 'card_cvv', 'passport'] })
generate('za.passport_mrz')  // → two 44-char MRZ lines with valid ICAO check digits

And a set of cross-country extras (also off by default): a transaction (txn_datetime, txn_type, txn_status, txn_channel, txn_mcc with real ISO-18245 codes), ip / ipv6, licence (driver's licence), income (currency-magnitude-aware for the pack's currency), employer, and country.

generate('jp.income')   // → '9,970,000 JPY'   (scaled to the local currency)
generate('ke.person', { fields: ['name', 'txn_datetime', 'txn_type', 'txn_mcc', 'ip', 'income'] })

Choosing which fields a record has

generate('ke.person') returns the on-by-default columns. To include the optional PII — email, GPS, date of birth, address, occupation, avatar, plate, and the rest — pass fields (the package equivalent of the app's column toggles):

generate('ke.person', { fields: 'all' })
// → every field the pack has: name, phone, id, kra, …, gender, dob, gps,
//   address, email, avatar, ref

generate('ke.person', { fields: ['name', 'phone', 'email', 'gps', 'dob'] })
// → { name, phone, email, gps, dob } — exactly those, in that order

generateMany('za.person', 500, { fields: ['name', 'said', 'phone', 'email'] })

Records stay coherent whichever fields you pick (e.g. email derives from the generated name).

Settings

generate('ke.phone', { phoneFmt: 'plus' })         // '+254712345678'
generate('ke.phone', { network: 'safaricom' })     // Safaricom prefixes only
generate('ke.kra_pin', { pinType: 'P' })           // company PIN (P…)
generate('ke.amount', { amountStyle: 'number' })   // 12400 (number, not 'KES 12,400.00')

Records stay internally coherent: bank and swift describe the same bank, gender matches the first name, county matches the town.

Reproducible output

Pass a seed and you get the same data every time — ideal for CI snapshots:

generate('ke.person', { seed: 'test-42' })        // identical on every run
generateMany('ke.person', 100, { seed: 'batch' }) // identical batch every run

Scope

Ships every Sampuli country pack, free, with no volume caps — countries across Africa, Europe, the Middle East, Asia-Pacific and the Americas, and growing. Call listPacks() for the full set installed, or browse them at sampuli.site. Additional packs can be plugged in at runtime via registerPack(pack).

Accuracy & synthetic data

Every value is format-correct: it matches the real shape and passes standard format checks. It is entirely synthetic — invented at call time and corresponding to no real person, account, business, or registered number. It is for testing only; do not present any output as a genuine KRA PIN, national ID, tax number, IBAN, or bank account.

License

MIT.

Keywords