# wundertec-core

**Librería estándar de utilidades e integraciones AWS + helpers generales en TypeScript**

---

## 💡 Características

- **AWS SDK v3**: S3, SES y SNS con funciones para operaciones comunes y URLs firmados.
- **Fechas y zonas horarias**: `moment-timezone` con zona por defecto CDMX y opción de cambiar.
- **Temporizadores**: `sleep` y `withTimeout` para control de flujos asíncronos.
- **Colecciones**: `chunk`, `flatten`, `uniq`, `groupBy`.
- **Reintentos**: `retry` con `exponentialBackoff` configurable.
- **HTTP**: `AxiosClient` con métodos `get`, `post`, `put`, `delete`.
- **Configuración**: `loadEnv`, `getConfig` para manejo de `.env` y variables.
- **Logging**: `Logger` con niveles `info`, `warn`, `error`, `debug`.

---

## 🚀 Instalación

```bash
npm install wundertec-core
# o con yarn
yarn add wundertec-core
```

---

## ⚙️ Configuración de entorno

Si usas un archivo `.env`, al inicio de tu aplicación (por ejemplo en `src/index.ts`):

```ts
import { loadEnv } from "wundertec-core";
loadEnv(); // carga variables desde .env
```

| Variable                | Descripción                                            |
| ----------------------- | ------------------------------------------------------ |
| `DEFAULT_TIMEZONE`      | Zona horaria por defecto (e.g. `America/Mexico_City`). |
| `AWS_REGION`            | Región AWS (p.ej. `us-east-1`).                        |
| `AWS_ACCESS_KEY_ID`     | ID de acceso AWS (si no usas roles).                   |
| `AWS_SECRET_ACCESS_KEY` | Clave secreta AWS.                                     |
| `SES_FROM_ADDRESS`      | Direccion “From” por defecto para SES.                 |
| `DEBUG`                 | Activa logs `debug` (`"true"` o `"false"`).            |

> Si faltan variables, la librería usará defaults o fallará con error claro.

---

## 📦 Uso detallado

Importa todo desde el entrypoint:

```ts
import {
  /* AWS S3 */
  uploadObject,
  getObject,
  deleteObject,
  getSignedGetUrl,
  getSignedPutUrl,
  /* AWS SES */
  sendEmail,
  sendRawEmail,
  /* AWS SNS */
  sendSMS,
  publishTopic,
  /* Fechas */
  now,
  format,
  diff,
  add,
  subtract,
  /* Temporizadores */
  sleep,
  withTimeout,
  /* Colecciones */
  chunk,
  flatten,
  uniq,
  groupBy,
  /* Reintentos */
  retry,
  exponentialBackoff,
  /* HTTP */
  AxiosClient,
  /* Configuración */
  getConfig,
  /* Logging */
  Logger,
} from "wundertec-core";
```

### ☁️ AWS S3

```ts
// Subir archivo
await uploadObject("mi-bucket", "path/archivo.txt", Buffer.from("Hola"));

// Obtener contenido
const data: Buffer = await getObject("mi-bucket", "path/archivo.txt");

// Eliminar objeto
await deleteObject("mi-bucket", "path/archivo.txt");

// URL firmado GET
const urlGet = await getSignedGetUrl("mi-bucket", "path/privado.jpg", 600);

// URL firmado PUT
const urlPut = await getSignedPutUrl("mi-bucket", "path/subida.bin", 600);
```

### ✉️ AWS SES

```ts
// Enviar email HTML
await sendEmail(
  ["user@example.com"],
  "Asunto de prueba",
  "<h1>Hola</h1><p>Este es un email</p>"
);

// Envío raw (p.ej con attachments)
await sendRawEmail({ RawMessage: { Data: rawBuffer } });
```

### 📲 AWS SNS / SMS

```ts
// Enviar SMS directo
await sendSMS("+5215550000000", "Mensaje de prueba");

// Publicar en tópico SNS
await publishTopic(
  "arn:aws:sns:us-east-1:123456789012:mi-topic",
  "Notificación importante"
);
```

### 📆 Fecha y hora (`moment-timezone`)

```ts
// Momento actual en CDMX
console.log(now().format());

// Formato específico y zona ET
console.log(format(new Date(), "YYYY-MM-DD HH:mm", "America/New_York"));

// Diferencia en días
console.log(diff("2025-05-01", "2025-04-24", "days"));

// Sumar 3 horas
const plus3 = add("2025-04-24T12:00:00Z", 3, "hours");

// Restar 30 minutos\console.log(subtract(plus3, 30, 'minutes').format());
```

### ⏱️ Temporizadores

```ts
// Pausar 2s
await sleep(2000);

// Timeout en promesa
await withTimeout(fetchData(), 5000, new Error("Tiempo excedido"));
```

### 🔢 Colecciones

```ts
// Chunk de 5 en 2
console.log(chunk([1, 2, 3, 4, 5], 2)); // [[1,2],[3,4],[5]]

// Aplanar
console.log(flatten([[1], [2, 3], []])); // [1,2,3]

// Únicos
console.log(uniq([1, 2, 2, 3, 3, 3])); // [1,2,3]

// Agrupar por clave
type Item = { type: string; value: number };
const items: Item[] = [
  { type: "A", value: 1 },
  { type: "B", value: 2 },
  { type: "A", value: 3 },
];
console.log(groupBy(items, (x) => x.type));
// => { A: [{...},{...}], B: [...] }
```

### 🔄 Reintentos y Backoff

```ts
// Backoff exponencial
console.log(exponentialBackoff(0)); // 100
console.log(exponentialBackoff(1)); // 200

// Retry automático
const result = await retry(() => fetchUnstable(), {
  retries: 5,
  baseDelay: 200,
  maxDelay: 5000,
});
```

### 🌐 HTTP con Axios

```ts
const api = new AxiosClient({
  baseURL: "https://api.miservicio.com",
  timeout: 8000,
});

// GET JSON
const users = await api.get<User[]>("/users");

// POST datos y recibir respuest
const newUser = await api.post<User>("/users", { name: "Juan" });

// PUT y DELETE similares
await api.put("/items/1", { qty: 10 });
await api.delete("/items/2");
```

### ⚙️ Configuración y Variables

```ts
// Leer var con fallback
const port = getConfig("PORT", "3000");
console.log(`App corriendo en puerto ${port}`);
```

### 📝 Logging

```ts
const log = new Logger("MiApp");
log.info("Inicio de aplicación");
log.warn("Esto es una advertencia");
log.error("Ha ocurrido un error");
log.debug("Valor X:", x); // solo si DEBUG=true
```

---

## 🧪 Tests

```bash
npm test   # Jest con coverage
```

---

## 🔁 CI/CD & Publicación

- Lint: `npm run lint`
- Build: `npm run build`
- Test: `npm test`
- Release: `npm run release` (publicación automática en NPM al mergear en `main`)

> Revisa [Jenkinsfile](./Jenkinsfile) para pipeline de ejemplo.

---

## 🤝 Contribuciones

¡Bienvenidos PRs y issues! Sigue las guías de estilo y testing.

---

## 📄 Licencia

[MIT](LICENSE) © Hypernetics
