npm package: @jysperu/schema-telefono
Description: Esquemas para números telefónicos: Mongoose, JSON Schema y Joi
Author: JYS Perú
Latest version: 1.0.3

# @jysperu/schema-telefono

[![npm version](https://badge.fury.io/js/@jysperu%2Fschema-telefono.svg)](https://badge.fury.io/js/@jysperu%2Fschema-telefono)
[![npm downloads](https://img.shields.io/npm/dm/@jysperu/schema-telefono)](https://www.npmjs.com/package/@jysperu/schema-telefono)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![TypeScript](https://img.shields.io/badge/TypeScript-007ACC?logo=typescript&logoColor=white)](https://www.typescriptlang.org/)
[![Node.js](https://img.shields.io/badge/Node.js-339933?logo=node.js&logoColor=white)](https://nodejs.org/)
[![MongoDB](https://img.shields.io/badge/MongoDB-47A248?logo=mongodb&logoColor=white)](https://www.mongodb.com/)
[![Joi](https://img.shields.io/badge/Joi-FF6B6B?logo=joi&logoColor=white)](https://joi.dev/)
[![Bundle Size](https://img.shields.io/bundlephobia/minzip/@jysperu/schema-telefono)](https://bundlephobia.com/package/@jysperu/schema-telefono)

Esquemas para números telefónicos con soporte para **Mongoose**, **JSON Schema** y **Joi**.

## 🚀 Características

- 📞 **Validación** de números telefónicos
- 🌍 **Soporte internacional** completo (E.164, códigos de país)
- 🔧 **Tipos** de línea telefónica (MOBILE, FIXED_LINE, etc.)
- 🏷️ **Clasificaciones** del uso telefónico (Trabajo, Personal, etc.)
- ✅ **Estados** de validación y verificación

## 📦 Instalación

```bash
npm install @jysperu/schema-telefono
```

## ⚡ Inicio Rápido

```typescript
import { MongoSchemaTelefono, JsonSchemaTelefono, JoiSchemaTelefono } from "@jysperu/schema-telefono";
import { ITelefono, TipoLineaTelefonica, ClasificacionTelefono } from "@jysperu/schema-telefono";

// Mongoose
const PersonaSchema = new Schema({
  telefonos: [MongoSchemaTelefono],
});

// Joi Validation
const { error, value } = JoiSchemaTelefono.validate({
  telefono: "987654321",
  countrycode: "pe", // → "PE" automáticamente
  whatsapp: true,
});

// JSON Schema
const validate = ajv.compile(JsonSchemaTelefono);
const isValid = validate(telefonoData);
```

## 📚 Esquemas Disponibles

### 1. 🍃 Mongoose Schema

```typescript
import { MongoSchemaTelefono, ITelefono } from "@jysperu/schema-telefono";
import { Schema, model, Document } from "mongoose";

interface IPersona extends Document {
  nombres: string;
  telefonos: ITelefono[];
}

const PersonaSchema = new Schema<IPersona>({
  nombres: { type: String, required: true },
  telefonos: [MongoSchemaTelefono], // Array de teléfonos
});

const PersonaModel = model<IPersona>("Persona", PersonaSchema);
```

### 2. 📋 JSON Schema

```typescript
import { JsonSchemaTelefono } from "@jysperu/schema-telefono";
import Ajv from "ajv";

const ajv = new Ajv();
const validate = ajv.compile(JsonSchemaTelefono);

const telefono = {
  telefono: "987654321",
  tipo: "Personal",
  countrycode: "PE",
  whatsapp: true,
};

const valid = validate(telefono);
if (!valid) console.log(validate.errors);
```

### 3. ✅ Joi Schema

```typescript
import { JoiSchemaTelefono } from "@jysperu/schema-telefono";

// Validación individual
const { error, value } = JoiSchemaTelefono.validate({
  telefono: "987654321",
  tipo: "Personal",
  countrycode: "pe", // Se convierte a "PE"
  whatsapp: true,
});

if (error) {
  error.details.forEach((err) => console.log(`❌ ${err.path}: ${err.message}`));
}

// Para arrays de teléfonos
import Joi from "@jysperu/joi-spanish";

const personaSchema = Joi.object({
  nombres: Joi.string().required(),
  telefonos: Joi.array().items(JoiSchemaTelefono).default([]),
});
```

## 🛠️ Casos de Uso Avanzados

### Crear persona con múltiples teléfonos

```typescript
import { MongoSchemaTelefono, ITelefono, TipoLineaTelefonica } from "@jysperu/schema-telefono";

const persona = new PersonaModel({
  nombres: "Ana García",
  telefonos: [
    {
      telefono: "987654321",
      tipo: "Personal",
      countrycode: "PE",
      type: TipoLineaTelefonica.MOBILE,
      whatsapp: true,
      valido: true,
    },
    {
      telefono: "014567890",
      tipo: "Trabajo",
      countrycode: "PE",
      type: TipoLineaTelefonica.FIXED_LINE,
      whatsapp: false,
      valido: true,
    },
  ],
});

await persona.save();
```

### Operaciones con teléfonos

```typescript
// Buscar números de WhatsApp
const whatsappNumbers = persona.telefonos.filter((tel) => tel.whatsapp);

// Encontrar móviles verificados
const mobilesVerificados = persona.telefonos.filter((tel) => tel.type === TipoLineaTelefonica.MOBILE && tel.verificado);

// Agregar nuevo teléfono
persona.telefonos.push({
  telefono: "999888777",
  tipo: "Emergencia",
  type: TipoLineaTelefonica.MOBILE,
  whatsapp: true,
  valido: true,
});

await persona.save();
```

## 📊 Esquema de Datos

### ✅ Campo Obligatorio

| Campo      | Tipo     | Validación                       | Descripción                 |
| ---------- | -------- | -------------------------------- | --------------------------- |
| `telefono` | `String` | Required, trim, contiene dígitos | Número telefónico principal |

### ⚙️ Campos Opcionales

| Campo           | Tipo      | Validación/Enum            | Defecto   | Descripción                      |
| --------------- | --------- | -------------------------- | --------- | -------------------------------- |
| `tipo`          | `String`  | Min 1 char, personalizable | "Trabajo" | Clasificación (Trabajo/Personal) |
| `countrycode`   | `String`  | ISO 2-3 chars, uppercase   | -         | Código país (PE, US, BR, etc.)   |
| `country`       | `String`  | Max 100 chars              | -         | Nombre completo del país         |
| `countrydial`   | `String`  | `+?\\d{1,4}`               | -         | Código marcado (+51, +1, +55)    |
| `e164`          | `String`  | `+[1-9]\\d{1,14}`          | -         | Formato E.164 internacional      |
| `international` | `String`  | Libre                      | -         | Formato internacional legible    |
| `national`      | `String`  | Libre                      | -         | Formato nacional del país        |
| `uri`           | `String`  | Inicia con "tel:"          | -         | URI telefónica RFC 3966          |
| `type`          | `Enum`    | TipoLineaTelefonica        | "MOBILE"  | Clasificación técnica de línea   |
| `whatsapp`      | `Boolean` | true/false                 | false     | Compatible con WhatsApp          |
| `valido`        | `Boolean` | true/false                 | false     | Número técnicamente válido       |
| `verificado`    | `Boolean` | true/false                 | false     | Verificado por el usuario        |

### 📱 Tipos de Línea Telefónica

```typescript
enum TipoLineaTelefonica {
  MOBILE = "MOBILE", // 📱 Teléfono móvil
  FIXED_LINE = "FIXED_LINE", // 🏠 Línea fija
  FIXED_LINE_OR_MOBILE = "FIXED_LINE_OR_MOBILE", // 🔄 Puede ser fijo o móvil
  TOLL_FREE = "TOLL_FREE", // 🆓 Número gratuito
  PREMIUM_RATE = "PREMIUM_RATE", // 💰 Tarifa premium
  VOIP = "VOIP", // 🌐 Voz sobre IP
  PERSONAL_NUMBER = "PERSONAL_NUMBER", // 👤 Número personal
  SHARED_COST = "SHARED_COST", // 🤝 Costo compartido
  PAGER = "PAGER", // 📟 Buscapersonas
  UAN = "UAN", // 🔗 Acceso universal
  VOICEMAIL = "VOICEMAIL", // 📧 Buzón de voz
  UNKNOWN = "UNKNOWN", // ❓ Tipo desconocido
}
```

### 🏷️ Clasificaciones Personales

```typescript
enum ClasificacionTelefono {
  TRABAJO = "Trabajo", // 🏢 Teléfono laboral
  PERSONAL = "Personal", // 👤 Teléfono personal
}
```

## 💡 Ejemplos de Datos

### 📱 Móvil Personal (Completo)

```typescript
const telefonoCompleto: ITelefono = {
  telefono: "987 654 321",
  tipo: "Personal",
  countrycode: "PE",
  country: "Peru",
  countrydial: "+51",
  e164: "+51987654321",
  international: "+51 987 654 321",
  national: "987 654 321",
  uri: "tel:+51-987-654-321",
  type: TipoLineaTelefonica.MOBILE,
  whatsapp: true,
  valido: true,
  verificado: true,
};
```

### 🏢 Fijo de Trabajo

```typescript
const telefonoTrabajo: ITelefono = {
  telefono: "(01) 456-7890",
  tipo: "Trabajo",
  countrycode: "PE",
  country: "Peru",
  e164: "+5114567890",
  international: "+51 1 456 7890",
  national: "(01) 456-7890",
  type: TipoLineaTelefonica.FIXED_LINE,
  whatsapp: false,
  valido: true,
};
```

### 🆓 Línea Gratuita

```typescript
const lineaGratuita: ITelefono = {
  telefono: "800-123-4567",
  tipo: "Soporte",
  countrycode: "US",
  country: "United States",
  type: TipoLineaTelefonica.TOLL_FREE,
  whatsapp: false,
  valido: true,
};
```

### 🌐 VOIP Internacional

```typescript
const voipSkype: ITelefono = {
  telefono: "echo123",
  tipo: "Test VOIP",
  type: TipoLineaTelefonica.VOIP,
  whatsapp: false,
  valido: true,
};
```

## 🔧 Configuración del Esquema

```typescript
// Configuración Mongoose
{
  strict: false,        // Permite campos adicionales
  timestamps: true,     // createdAt, updatedAt automáticos
  _id: true             // Cada teléfono tiene su propio ID
}

// Configuración Joi
{
  stripUnknown: false,  // Mantiene campos extra
  allowUnknown: true,   // Permite propiedades no definidas
  convert: true,        // Conversión automática de tipos
  abortEarly: false     // Muestra todos los errores
}
```

## 📋 JSON Schema Standalone

El archivo `telefono.schema.json` se genera automáticamente en cada build:

```bash
# Usar telefono.schema.json directamente
curl -O https://gitlab.com/tiny.node/schema/telefono/-/raw/main/dist/telefono.schema.json

# Validar con cualquier validador JSON Schema
cat data.json | ajv validate -s telefono.schema.json
```

## 🧪 Testing y Validación

```typescript
// Test básico con Joi
import { JoiSchemaTelefono } from "@jysperu/schema-telefono";

const testCases = [
  { telefono: "987654321", valid: true },
  { telefono: "", valid: false }, // Vacío
  { telefono: "abc", valid: false }, // Sin dígitos
  { countrycode: "pe", expected: "PE" }, // Conversion
];

testCases.forEach((test) => {
  const result = JoiSchemaTelefono.validate(test);
  console.log(`${test.telefono}: ${result.error ? "❌" : "✅"}`);
});
```

## 📦 Build y Distribución

```bash
# Construir el proyecto
npm run build

# Genera automáticamente:
# └── dist/
#     ├── telefono.es.js       # ESM
#     ├── telefono.cjs.js      # CommonJS
#     ├── telefono.umd.js      # UMD
#     ├── *.d.ts               # TypeScript definitions
#     └── telefono.schema.json # JSON Schema
```

## 🔗 Enlaces y Recursos

- 📘 **Repositorio**: [GitLab - schema-telefono](https://gitlab.com/tiny.node/schema/telefono)
- 🐛 **Issues**: [Reportar problemas](https://gitlab.com/tiny.node/schema/telefono/issues)
- 📦 **npm**: [@jysperu/schema-telefono](https://www.npmjs.com/package/@jysperu/schema-telefono)
- 📚 **Documentación Joi**: [@jysperu/joi-spanish](https://www.npmjs.com/package/@jysperu/joi-spanish)
- 🏢 **JYS Perú**: [www.jys.pe](https://www.jys.pe)

## 📄 Licencia

**MIT License** - Consulta el archivo [LICENSE](./LICENSE) para detalles completos.

```text
MIT License - Copyright (c) 2025 JYS Perú
```

---

Desarrollado con ❤️ por [**JYS Perú**](https://www.jys.pe)