@controldealquiler/sdk 0.0.0-stage → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,41 @@
1
+ **Licencia del SDK de controldealquiler.com**
2
+
3
+ Copyright © 2026 Trajano Labs, S.L. (CIF B05655378). Todos los derechos reservados.
4
+
5
+ **1. Qué te permitimos.** Puedes, gratis y sin exclusiva, instalar, ejecutar y copiar este paquete, sin modificarlo, e
6
+ incluirlo sin modificar en tus programas y distribuirlo con ellos, solo para conectar esos programas con
7
+ controldealquiler.com. Para usar la API necesitas, además, una API key y aceptar las Condiciones de la API para
8
+ agencias, en controldealquiler.com/condiciones-api.
9
+
10
+ **2. Lo que no te permitimos.** No puedes:
11
+ - modificar el paquete, traducirlo ni hacer obras derivadas de él, salvo lo que el punto 3 dice que la ley te permite
12
+ siempre;
13
+ - usar el código propio de Trajano Labs que contiene (como su lector de documentos o su cifrado) con otro servicio, o
14
+ fuera de una integración con controldealquiler.com. Los componentes de terceros se rigen por su propia licencia
15
+ (punto 4);
16
+ - usarlo para producir lecturas que no salgan de su lector sin cambios;
17
+ - quitar o alterar este aviso ni los de los componentes de terceros;
18
+ - usar el nombre o la marca controldealquiler.com más allá de decir que tu programa se integra con ella.
19
+
20
+ **3. Lo que la ley te permite siempre.** Nada de esta licencia limita lo que el artículo 100 del texto refundido de la
21
+ Ley de Propiedad Intelectual permite a quien tiene derecho a usar un programa:
22
+ - hacer la copia de seguridad necesaria para usarlo;
23
+ - observar, estudiar o verificar su funcionamiento mientras lo carga, ejecuta o almacena, para conocer las ideas y
24
+ principios en que se basa;
25
+ - y lo que permite para conseguir la interoperabilidad de un programa creado de forma independiente.
26
+
27
+ **4. Componentes de terceros.** El paquete incluye componentes de terceros. Su lista, con la licencia completa de cada
28
+ uno y, si la traen, sus avisos (NOTICE), está en el fichero THIRD_PARTY_NOTICES. Para esos componentes manda su licencia, y nada de esta te quita lo que ella te
29
+ permite.
30
+
31
+ **5. Qué datos envía.** El paquete solo se comunica con la dirección de la API que configures y con las direcciones de
32
+ subida de ficheros que esa API le da. No nos envía datos de uso.
33
+
34
+ **6. Sin garantía.** El paquete se ofrece tal cual. En la medida en que la ley lo permita, no respondemos de los daños
35
+ que cause su uso, salvo dolo o culpa grave nuestros. Lo que hagas con la API se rige por las Condiciones de la API para
36
+ agencias. Esta cláusula no limita lo que nos obliga el Anexo de encargo de tratamiento para agencias ni la normativa de
37
+ protección de datos.
38
+
39
+ **7. Fin.** Esta licencia termina si la incumples. Entonces tienes que dejar de usar y distribuir el paquete.
40
+
41
+ **8. Ley.** Esta licencia se rige por la ley española.
package/README.md CHANGED
@@ -1,3 +1,200 @@
1
- # Temporary Holding Version
1
+ # @controldealquiler/sdk
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ SDK de Node.js y línea de comandos (`controldealquiler`) para la API de agencias de
4
+ [controldealquiler.com](https://controldealquiler.com).
5
+
6
+ - Documentación para desarrolladores: https://controldealquiler.com/desarrolladores
7
+ - Especificación OpenAPI 3.1: https://controldealquiler.com/openapi/v1.json
8
+ - Condiciones de la API para agencias: https://controldealquiler.com/condiciones-api
9
+
10
+ Necesitas una API key de tu cuenta de agencia y haber aceptado las Condiciones de la API. Requiere Node.js 20 o superior.
11
+
12
+ ## Instalación
13
+
14
+ ```sh
15
+ npm install @controldealquiler/sdk
16
+ ```
17
+
18
+ El paquete es ESM (`"type": "module"`).
19
+
20
+ ## Uso
21
+
22
+ ```js
23
+ import { crearCliente, descifradorDeFichero, sobreDeB64 } from '@controldealquiler/sdk'
24
+ import { readFileSync } from 'node:fs'
25
+
26
+ const sobre = sobreDeB64(JSON.parse(readFileSync('sobre-integracion.json', 'utf8')))
27
+
28
+ const cliente = crearCliente({
29
+ apiKey: process.env.CDA_API_KEY,
30
+ descifrador: descifradorDeFichero('clave-integracion.pem', sobre),
31
+ // baseUrl: 'https://controldealquiler.com/api', // por defecto
32
+ // Para el sandbox: baseUrl: URL_BASE_SANDBOX con una key `cda_test_`.
33
+ })
34
+
35
+ // Llamada de bajo nivel a cualquier ruta de la API
36
+ const respuesta = await cliente.peticion({ metodo: 'GET', ruta: '/v1/eventos' })
37
+
38
+ // Alta de un cliente con sus viviendas y ficheros
39
+ const alta = await cliente.clientes.crear({ /* ver /desarrolladores */ })
40
+
41
+ // Una pasada de entrega de lo pendiente
42
+ const pasada = await cliente.mantenimiento.ejecutar()
43
+ ```
44
+
45
+ ### Altas en lote y errores del alta
46
+
47
+ `clientes.crear` lanza siempre un `ErrorAlta` (subclase de `ErrorApiSdk`, con `cause` = el error original). Su `message` es
48
+ `<ref>: <paso> → <status> <code>` y nunca lleva correos ni direcciones. Sus campos:
49
+
50
+ | Campo | Qué dice |
51
+ |---|---|
52
+ | `ref`, `paso` | Qué cliente y en qué paso falló: `validar`, `foto`, `abrir`, `vivienda`, `fichero`, `leer`, `cotejar`, `listo`, `paquete`, `lote` o `enlace` |
53
+ | `vivienda`, `caja`, `fichero` | La vivienda y el fichero en curso, si el fallo ocurrió en uno |
54
+ | `loteId`, `indice` | El lote y la posición del cliente en él, si el fallo ocurrió después de enviarlo |
55
+ | `clientId` | El cliente, si ya existía cuando falló |
56
+ | `status`, `code`, `requestId` | Lo que respondió la API (`status` 0 si el fallo fue local o de red); cítanos el `requestId` si escribes a soporte |
57
+ | `creado` | `false`: no se creó nada. `true`: el cliente existe (por ejemplo, falló el enlace). `'desconocido'`: puede que se haya creado, no se sabe |
58
+ | `reintentable` | `true` si repetir el alta puede arreglarlo |
59
+ | `consejo` | `'repetir'`: repite el alta, es idempotente por `ref`. `'manifiesto'`: corrige la entrada, repetir igual no sirve. `'cuenta'`: revisa la cuenta o escríbenos con el `requestId` |
60
+ | `corta` | `true` si el fallo afectaría a todos los clientes (credenciales, key de otro entorno, cuota, clave de integración) |
61
+
62
+ Un 500 al abrir el borrador (`paso: 'abrir'`) tiene un origen ambiguo: puede ser un fallo del servidor o que otro proceso esté
63
+ creando esa misma `ref` en ese momento, y desde el SDK no se distinguen. Es `reintentable`; repite el alta pasado un rato (con
64
+ `crearVarios` se repite sola).
65
+
66
+ `clientes.crearVarios(entradas, { aLaVez, repetir })` da de alta varios clientes y **nunca lanza**: devuelve
67
+ `{ completados, fallidos, noIntentados, cortadoPor }`.
68
+
69
+ ```js
70
+ const informe = await cliente.clientes.crearVarios(entradas, { aLaVez: 1, repetir: 1 })
71
+ for (const f of informe.fallidos) console.warn(f.ref, f.paso, f.code, f.creado, f.consejo, f.requestId)
72
+ ```
73
+
74
+ - `aLaVez` (1 o 2, por defecto 1): altas simultáneas. `repetir` (0 a 2, por defecto 1): cuántas veces se repite un alta
75
+ `reintentable`; la espera es de 2 s, y de 30 s si el intento anterior quedó en `creado: 'desconocido'`.
76
+ - Cada elemento de `completados` lleva `intentos`. Con `estado: 'ya_existia'` e `intentos > 1`, el cliente puede haberlo creado
77
+ tu propio intento anterior, que dio error pero llegó a crearlo: no implica que ya lo tuvieras de antes.
78
+ - Una `ref` repetida en `entradas` no se envía: la segunda y siguientes van a `fallidos` con `paso: 'validar'`,
79
+ `code: 'ENTRADA_INVALIDA'` e `intentos: 0`.
80
+ - La pasada se corta (`cortadoPor`, y el resto en `noIntentados`) ante un fallo que afecta a todos los clientes: 401 o 403, key
81
+ de pruebas o de producción cruzada, API desactivada, cuota o tope de borradores, entorno mal configurado, clave de
82
+ integración, o tres `RED` o tres `TIEMPO_AGOTADO` seguidos.
83
+
84
+ Opción `concurrenciaFicheros` de `crearCliente` (1 a 8; si no la fijas, el SDK usa la que sugiere `GET /v1/yo`, o 4): ficheros de una vivienda que se suben y leen a la vez; la API admite 10 peticiones/s por cuenta con ráfaga de 50 y un 429 se reintenta solo.
85
+
86
+ `crearCliente` devuelve estos grupos: `peticion`, `http`, `descifrador`, `borradores`, `clientes`, `viviendas`, `remitentes`,
87
+ `creditos`, `renovacion`, `webhooks` y `mantenimiento`. Las firmas completas están en los tipos incluidos en el paquete y en la
88
+ documentación de desarrolladores.
89
+
90
+ ### Datos de la vivienda y de los ficheros
91
+
92
+ - `provincia`: obligatoria, dos dígitos (el código de provincia, por ejemplo `28`).
93
+ - `municipio`: opcional; el código INE de cinco dígitos (por ejemplo `28079`); sus dos primeros dígitos son la provincia.
94
+ - `cp`: cinco dígitos, obligatorio.
95
+ - `caja` de cada fichero: `contract`, `tenant_id`, `other`, `acta`, `movimientos` o `foto`. Solo se admite una `foto` por vivienda.
96
+ - Las escrituras se pueden reintentar con la misma `Idempotency-Key` durante 24 horas.
97
+
98
+ ## Qué viaja cifrado
99
+
100
+ El SDK sella en tu sistema, con la clave pública de tu agencia, el nombre de tus clientes, la calle y el código postal de cada vivienda y los ficheros: nuestro servidor no puede abrirlos. Llegan y se guardan legibles el correo de tu cliente, la provincia y el municipio de cada vivienda, el porcentaje de propiedad, tus referencias y lo que lee el lector (importes, fechas y conceptos y, de un contrato, sus fechas, la renta y el número de inquilinos). No uses como referencia el nombre, el documento de identidad ni el correo de un cliente.
101
+
102
+ Si pasamos a leer en nuestro servidor (las [Condiciones de la API](https://controldealquiler.com/condiciones-api) dicen que te avisaremos antes), la API responde `409 AGENCIA_MODO_SERVIDOR` y el SDK, por su cuenta y sin opción para evitarlo, manda además una copia del fichero sin el cifrado de extremo a extremo, protegida solo en el camino, para que la leamos en memoria sin guardarla. La copia que se guarda sigue sellada. `controldealquiler alta` hace lo mismo. Por su cuenta, el SDK no pide escaneos con inteligencia artificial.
103
+
104
+ ## Gestión de clientes y de la cuenta
105
+
106
+ Todas las escrituras llevan `Idempotency-Key`, salvo las excepciones de Idempotencia (la pone el SDK y los reintentos la reutilizan). `desvincular` y `editar` llevan además
107
+ `If-Match`, que es obligatorio: pasa en `{ ifMatch }` la `version` que leíste con `clientes.leer`. El SDK nunca lo rellena por ti
108
+ (anularía el control de concurrencia). Si otra persona cambió el cliente entre tu lectura y tu escritura, la API responde 412
109
+ (`ErrorApiSdk` con `code: 'PRECONDICION_FALLIDA'`): vuelve a leer con `clientes.leer`, revisa el cambio y reintenta con la versión nueva.
110
+
111
+ ```js
112
+ // Todos los clientes, página a página, hasta la página vacía
113
+ for await (const c of cliente.clientes.listar({ estado: 'invitado' })) console.log(c.client_id, c.version)
114
+
115
+ const uno = await cliente.clientes.leer(id, { incluir: 'viviendas' })
116
+
117
+ // Editar: el nombre, la calle y el código postal se sellan en el SDK con la clave pública de tu agencia, y el servidor no puede abrirlos. La provincia, el municipio y tus referencias viajan legibles.
118
+ await cliente.clientes.editar(id, { ref: 'CRM-17', nombre: 'Ana Pérez', viviendas: [{ vivienda: viviendaId, direccion: 'Calle Mayor 1', cp: '28001', municipio: '28079' }] }, { ifMatch: uno.version })
119
+
120
+ await cliente.clientes.correo(id, 'nuevo@ejemplo.es') // corrige el correo de un invitado sin confirmar
121
+ await cliente.clientes.revocarEnlace(id) // revoca su enlace de activación vivo
122
+ await cliente.clientes.desvincular(id, { ifMatch: uno.version })
123
+
124
+ const viviendas = await cliente.viviendas.listar(id)
125
+ const { saldo } = await cliente.creditos.leer()
126
+ await cliente.remitentes.anadir('facturas@ejemplo.es') // también .listar() y .quitar(correo)
127
+ await cliente.renovacion.fijar({ nivel: 'agencia', renovacion: 'manual' }) // también .leer()
128
+ ```
129
+
130
+ ### Webhooks
131
+
132
+ ```js
133
+ const w = await cliente.webhooks.crear({ url: 'https://ejemplo.es/hook', tipos: ['cliente.activado'] })
134
+ // w.secreto (whsec_…) solo se devuelve esta vez; guárdalo. También: listar, rotarSecreto, entregas, reenviar, borrar.
135
+
136
+ import { verificarWebhook, ErrorFirmaWebhook } from '@controldealquiler/sdk'
137
+ try {
138
+ // cuerpo CRUDO recibido (sin re-serializar) y cabeceras; acepta uno o varios secretos (rotación)
139
+ const { id, timestamp } = verificarWebhook(cuerpoCrudo, req.headers, process.env.CDA_WEBHOOK_SECRETO)
140
+ } catch (e) {
141
+ if (e instanceof ErrorFirmaWebhook) console.warn(e.motivo) // CABECERAS | TIMESTAMP | FUERA_DE_VENTANA | SECRETO | FIRMA
142
+ }
143
+ ```
144
+
145
+ `verificarWebhook` rechaza una entrega cuyo `webhook-timestamp` se aparte más de 5 minutos del reloj local.
146
+
147
+ ## Clave de integración
148
+
149
+ Crear clientes exige que tu API key tenga una clave de integración, y en el SDK también la necesitan la pasada de entrega (`mantenimiento.ejecutar`) y editar el nombre o la dirección. Se fija para cada key (cada key nueva necesita la suya), pero lo que abre es de toda tu agencia: quien tenga la clave privada de integración y el sobre puede abrir todo lo que controldealquiler.com entrega sellado a tu agencia, como dicen las [Condiciones de la API](https://controldealquiler.com/condiciones-api) (punto 8).
150
+
151
+ 1. Genera el par con `npx controldealquiler clave-integracion`. La privada queda en `clave-integracion.pem` (modo 0600, sin cifrar) y la pública sale por pantalla. Guárdala en un gestor de secretos, en una variable de entorno de la infraestructura en que se ejecuta tu integración o en un fichero en un servidor bajo tu control, con el acceso limitado a quien la necesita, como piden las Condiciones de la API (punto 8). Si la pasas a un gestor de secretos o a una variable de entorno, borra el fichero cuando compruebes que funciona.
152
+ 2. Pega la pública así: en el panel de tu agencia, pulsa «Remitentes autorizados» y, en el diálogo, ve al apartado «Clave de integración»: elige la API key, pega la clave pública y pulsa «Fijar la clave», con la caja fuerte desbloqueada. Tu navegador sella la clave privada de tu agencia para esa clave pública; a nuestro servidor llegan la pública y el sobre cerrado. Se fija una sola vez por API key; para cambiarla, crea otra key y, cuando funcione, revoca la anterior, que mientras siga activa puede bajar su sobre. Si crees que la privada se ha expuesto, revoca la key enseguida (condiciones de la API, punto 8).
153
+ 3. Baja el sobre con `GET /v1/integracion` y guarda el campo `sobre` de la respuesta como un fichero JSON.
154
+ 4. Configura `CDA_CLAVE_INTEGRACION` (ruta a la privada) o, si la guardas en un gestor de secretos o en una variable de entorno, `CDA_CLAVE_INTEGRACION_PEM` (el contenido del PEM; si están las dos, gana esta), y `CDA_SOBRE_INTEGRACION` (ruta al JSON del sobre), como en la tabla de abajo. En código, `descifradorDeClave({ pem, ruta })` lee la privada de la opción `pem`, de `CDA_CLAVE_INTEGRACION_PEM` o del fichero, por ese orden.
155
+
156
+ Sin ella, abrir un alta (`POST /v1/borradores`) y bajar el sobre (`GET /v1/integracion`) responden `403 SIN_CLAVE_INTEGRACION`; editar un cliente, cambiar su correo o desvincularlo también lo devuelven si la agencia aún no tiene caja fuerte. Además, el SDK no puede hacer la pasada de entrega ni sellar el nombre o la dirección al editar.
157
+
158
+ ## Línea de comandos
159
+
160
+ ```sh
161
+ npx controldealquiler clave-integracion # genera el par de claves de la integración
162
+ npx controldealquiler alta manifiesto.json # da de alta uno o varios clientes (un objeto o un array)
163
+ npx controldealquiler mantenimiento # una pasada de entrega
164
+ npx controldealquiler lector fichero.pdf # lee un fichero en local y escribe el resultado estructurado
165
+ ```
166
+
167
+ `alta` acepta un manifiesto que sea un objeto (un cliente) o un array (varios). Cada cliente lee sus ficheros justo antes de su alta;
168
+ si un fichero no se puede leer, ese cliente sale como fallido (`paso: 'validar'`, con el código de sistema, por ejemplo `ENOENT`, y nunca la ruta) y
169
+ los demás siguen. Opciones: `--a-la-vez <1|2>` (por defecto 1) y `--repetir <0-2>` (por defecto 1).
170
+
171
+ - **stdout:** el informe JSON `{ completados, fallidos, noIntentados, cortadoPor }`, también con un manifiesto objeto.
172
+ - **stderr:** una línea por fallido: `No se completó <ref>`, `<ref> creado, sin enlace` o `Puede que <ref> se haya creado`, seguido de
173
+ `: <paso>[ vivienda X][ fichero N (caja)] → <status> <code> · request_id <id> | lote <loteId>#<indice> · <consejo>`, donde el consejo es
174
+ «repite el alta, es idempotente», «corrige el manifiesto» o «revisa la cuenta o escríbenos con el request_id». Si la pasada se corta,
175
+ una línea más: `Pasada cortada por <status> <code>: no se intentaron <n> clientes`.
176
+ - **Salida:** 1 si hay fallidos o la pasada se cortó; 0 si no. Un error de uso (falta una variable, una opción inválida) escribe su mensaje y sale con 2. Un manifiesto que no es JSON válido o un error de sistema no entran en este informe: salen con una sola línea `Error: <código>` y salida 1.
177
+
178
+ Se configura por entorno:
179
+
180
+ | Variable | Qué es |
181
+ |---|---|
182
+ | `CDA_API_KEY` | Tu API key |
183
+ | `CDA_BASE_URL` | Opcional. Dirección de la API. Para el sandbox: `https://sandbox.controldealquiler.com/api` con una key `cda_test_`; el SDK rechaza en local cruzar una key de un entorno con la base del otro |
184
+ | `CDA_CLAVE_INTEGRACION` | Ruta al fichero PEM de la clave privada de la integración (no la clave) |
185
+ | `CDA_CLAVE_INTEGRACION_PEM` | Alternativa a la ruta: el contenido del PEM de la clave privada, con sus saltos de línea. Gana a `CDA_CLAVE_INTEGRACION` |
186
+ | `CDA_SOBRE_INTEGRACION` | Ruta a un fichero JSON con el sobre de integración: el campo `sobre` de la respuesta de `GET /v1/integracion` |
187
+
188
+ `controldealquiler` sin argumentos muestra la ayuda de cada comando.
189
+
190
+ ## Cambios en 1.2.0
191
+
192
+ - `clientes.crear` lanza `ErrorAlta` (sigue siendo un `ErrorApiSdk`, así que `instanceof ErrorApiSdk`, `status` y `code` funcionan como antes) con el paso, la vivienda, el fichero y si se creó algo.
193
+ - Nuevo `clientes.crearVarios`, que nunca lanza, repite lo transitorio y corta lo que afecta a todos los clientes.
194
+ - `controldealquiler alta` acepta un array y explica cada fallido. **Cambio de salida:** con un manifiesto objeto, stdout ya no es el resultado del alta sino el informe `{ completados, fallidos, noIntentados, cortadoPor }`, y sale con 1 si hubo fallidos.
195
+ - **Requiere un servidor que devuelva `nuevo` en `POST /v1/borradores`.** Contra un servidor que aún no lo hace, las altas fallan con un 502.
196
+
197
+ ## Licencia
198
+
199
+ Licencia propietaria de uso libre para integrarse con controldealquiler.com: ver [LICENSE](./LICENSE). Los componentes
200
+ de terceros incluidos y sus licencias están en [THIRD_PARTY_NOTICES](./THIRD_PARTY_NOTICES).
@@ -0,0 +1,217 @@
1
+ Avisos de componentes de terceros de @controldealquiler/sdk
2
+
3
+ Este paquete incluye, dentro de dist/, los componentes de terceros que siguen. Cada uno se rige por su propia licencia,
4
+ cuyo texto completo va a continuación (ver también el punto 4 del fichero LICENSE).
5
+
6
+ ================================================================================
7
+ pdfjs-dist 6.2.108
8
+ Licencia: Apache-2.0
9
+ https://mozilla.github.io/pdf.js/
10
+ ================================================================================
11
+
12
+ --- LICENSE ---
13
+ Apache License
14
+ Version 2.0, January 2004
15
+ http://www.apache.org/licenses/
16
+
17
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
18
+
19
+ 1. Definitions.
20
+
21
+ "License" shall mean the terms and conditions for use, reproduction,
22
+ and distribution as defined by Sections 1 through 9 of this document.
23
+
24
+ "Licensor" shall mean the copyright owner or entity authorized by
25
+ the copyright owner that is granting the License.
26
+
27
+ "Legal Entity" shall mean the union of the acting entity and all
28
+ other entities that control, are controlled by, or are under common
29
+ control with that entity. For the purposes of this definition,
30
+ "control" means (i) the power, direct or indirect, to cause the
31
+ direction or management of such entity, whether by contract or
32
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
33
+ outstanding shares, or (iii) beneficial ownership of such entity.
34
+
35
+ "You" (or "Your") shall mean an individual or Legal Entity
36
+ exercising permissions granted by this License.
37
+
38
+ "Source" form shall mean the preferred form for making modifications,
39
+ including but not limited to software source code, documentation
40
+ source, and configuration files.
41
+
42
+ "Object" form shall mean any form resulting from mechanical
43
+ transformation or translation of a Source form, including but
44
+ not limited to compiled object code, generated documentation,
45
+ and conversions to other media types.
46
+
47
+ "Work" shall mean the work of authorship, whether in Source or
48
+ Object form, made available under the License, as indicated by a
49
+ copyright notice that is included in or attached to the work
50
+ (an example is provided in the Appendix below).
51
+
52
+ "Derivative Works" shall mean any work, whether in Source or Object
53
+ form, that is based on (or derived from) the Work and for which the
54
+ editorial revisions, annotations, elaborations, or other modifications
55
+ represent, as a whole, an original work of authorship. For the purposes
56
+ of this License, Derivative Works shall not include works that remain
57
+ separable from, or merely link (or bind by name) to the interfaces of,
58
+ the Work and Derivative Works thereof.
59
+
60
+ "Contribution" shall mean any work of authorship, including
61
+ the original version of the Work and any modifications or additions
62
+ to that Work or Derivative Works thereof, that is intentionally
63
+ submitted to Licensor for inclusion in the Work by the copyright owner
64
+ or by an individual or Legal Entity authorized to submit on behalf of
65
+ the copyright owner. For the purposes of this definition, "submitted"
66
+ means any form of electronic, verbal, or written communication sent
67
+ to the Licensor or its representatives, including but not limited to
68
+ communication on electronic mailing lists, source code control systems,
69
+ and issue tracking systems that are managed by, or on behalf of, the
70
+ Licensor for the purpose of discussing and improving the Work, but
71
+ excluding communication that is conspicuously marked or otherwise
72
+ designated in writing by the copyright owner as "Not a Contribution."
73
+
74
+ "Contributor" shall mean Licensor and any individual or Legal Entity
75
+ on behalf of whom a Contribution has been received by Licensor and
76
+ subsequently incorporated within the Work.
77
+
78
+ 2. Grant of Copyright License. Subject to the terms and conditions of
79
+ this License, each Contributor hereby grants to You a perpetual,
80
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
81
+ copyright license to reproduce, prepare Derivative Works of,
82
+ publicly display, publicly perform, sublicense, and distribute the
83
+ Work and such Derivative Works in Source or Object form.
84
+
85
+ 3. Grant of Patent License. Subject to the terms and conditions of
86
+ this License, each Contributor hereby grants to You a perpetual,
87
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
88
+ (except as stated in this section) patent license to make, have made,
89
+ use, offer to sell, sell, import, and otherwise transfer the Work,
90
+ where such license applies only to those patent claims licensable
91
+ by such Contributor that are necessarily infringed by their
92
+ Contribution(s) alone or by combination of their Contribution(s)
93
+ with the Work to which such Contribution(s) was submitted. If You
94
+ institute patent litigation against any entity (including a
95
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
96
+ or a Contribution incorporated within the Work constitutes direct
97
+ or contributory patent infringement, then any patent licenses
98
+ granted to You under this License for that Work shall terminate
99
+ as of the date such litigation is filed.
100
+
101
+ 4. Redistribution. You may reproduce and distribute copies of the
102
+ Work or Derivative Works thereof in any medium, with or without
103
+ modifications, and in Source or Object form, provided that You
104
+ meet the following conditions:
105
+
106
+ (a) You must give any other recipients of the Work or
107
+ Derivative Works a copy of this License; and
108
+
109
+ (b) You must cause any modified files to carry prominent notices
110
+ stating that You changed the files; and
111
+
112
+ (c) You must retain, in the Source form of any Derivative Works
113
+ that You distribute, all copyright, patent, trademark, and
114
+ attribution notices from the Source form of the Work,
115
+ excluding those notices that do not pertain to any part of
116
+ the Derivative Works; and
117
+
118
+ (d) If the Work includes a "NOTICE" text file as part of its
119
+ distribution, then any Derivative Works that You distribute must
120
+ include a readable copy of the attribution notices contained
121
+ within such NOTICE file, excluding those notices that do not
122
+ pertain to any part of the Derivative Works, in at least one
123
+ of the following places: within a NOTICE text file distributed
124
+ as part of the Derivative Works; within the Source form or
125
+ documentation, if provided along with the Derivative Works; or,
126
+ within a display generated by the Derivative Works, if and
127
+ wherever such third-party notices normally appear. The contents
128
+ of the NOTICE file are for informational purposes only and
129
+ do not modify the License. You may add Your own attribution
130
+ notices within Derivative Works that You distribute, alongside
131
+ or as an addendum to the NOTICE text from the Work, provided
132
+ that such additional attribution notices cannot be construed
133
+ as modifying the License.
134
+
135
+ You may add Your own copyright statement to Your modifications and
136
+ may provide additional or different license terms and conditions
137
+ for use, reproduction, or distribution of Your modifications, or
138
+ for any such Derivative Works as a whole, provided Your use,
139
+ reproduction, and distribution of the Work otherwise complies with
140
+ the conditions stated in this License.
141
+
142
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
143
+ any Contribution intentionally submitted for inclusion in the Work
144
+ by You to the Licensor shall be under the terms and conditions of
145
+ this License, without any additional terms or conditions.
146
+ Notwithstanding the above, nothing herein shall supersede or modify
147
+ the terms of any separate license agreement you may have executed
148
+ with Licensor regarding such Contributions.
149
+
150
+ 6. Trademarks. This License does not grant permission to use the trade
151
+ names, trademarks, service marks, or product names of the Licensor,
152
+ except as required for reasonable and customary use in describing the
153
+ origin of the Work and reproducing the content of the NOTICE file.
154
+
155
+ 7. Disclaimer of Warranty. Unless required by applicable law or
156
+ agreed to in writing, Licensor provides the Work (and each
157
+ Contributor provides its Contributions) on an "AS IS" BASIS,
158
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
159
+ implied, including, without limitation, any warranties or conditions
160
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
161
+ PARTICULAR PURPOSE. You are solely responsible for determining the
162
+ appropriateness of using or redistributing the Work and assume any
163
+ risks associated with Your exercise of permissions under this License.
164
+
165
+ 8. Limitation of Liability. In no event and under no legal theory,
166
+ whether in tort (including negligence), contract, or otherwise,
167
+ unless required by applicable law (such as deliberate and grossly
168
+ negligent acts) or agreed to in writing, shall any Contributor be
169
+ liable to You for damages, including any direct, indirect, special,
170
+ incidental, or consequential damages of any character arising as a
171
+ result of this License or out of the use or inability to use the
172
+ Work (including but not limited to damages for loss of goodwill,
173
+ work stoppage, computer failure or malfunction, or any and all
174
+ other commercial damages or losses), even if such Contributor
175
+ has been advised of the possibility of such damages.
176
+
177
+ 9. Accepting Warranty or Additional Liability. While redistributing
178
+ the Work or Derivative Works thereof, You may choose to offer,
179
+ and charge a fee for, acceptance of support, warranty, indemnity,
180
+ or other liability obligations and/or rights consistent with this
181
+ License. However, in accepting such obligations, You may act only
182
+ on Your own behalf and on Your sole responsibility, not on behalf
183
+ of any other Contributor, and only if You agree to indemnify,
184
+ defend, and hold each Contributor harmless for any liability
185
+ incurred by, or claims asserted against, such Contributor by reason
186
+ of your accepting any such warranty or additional liability.
187
+
188
+ END OF TERMS AND CONDITIONS
189
+
190
+ ================================================================================
191
+ zod 4.6.7
192
+ Licencia: MIT
193
+ https://zod.dev
194
+ ================================================================================
195
+
196
+ --- LICENSE ---
197
+ MIT License
198
+
199
+ Copyright (c) 2025 Colin McDonnell
200
+
201
+ Permission is hereby granted, free of charge, to any person obtaining a copy
202
+ of this software and associated documentation files (the "Software"), to deal
203
+ in the Software without restriction, including without limitation the rights
204
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
205
+ copies of the Software, and to permit persons to whom the Software is
206
+ furnished to do so, subject to the following conditions:
207
+
208
+ The above copyright notice and this permission notice shall be included in all
209
+ copies or substantial portions of the Software.
210
+
211
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
212
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
213
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
214
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
215
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
216
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
217
+ SOFTWARE.