@ltorresu82/firmagob-client 0.1.2 → 0.1.3

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/README.md CHANGED
@@ -53,7 +53,7 @@ const response = await client.signHashes([
53
53
  ]);
54
54
  ```
55
55
 
56
- El JWT incluye los claims `entity`, `run`, `purpose`, `expiration` e `iat`. Por defecto el token expira en 5 minutos, alineado con los ejemplos oficiales. `expiration` se serializa como `yyyy-MM-dd'T'HH:mm:ss`. Se puede ajustar con `tokenTtlSeconds` si el ambiente lo requiere.
56
+ El JWT incluye los claims `entity`, `run`, `purpose`, `expiration` e `iat`. Por defecto el token expira en 5 minutos, alineado con los ejemplos oficiales. `expiration` se serializa como `yyyy-MM-dd'T'HH:mm:ss` en zona horaria `America/Santiago`, porque FirmaGob interpreta ese valor como fecha local sin zona. Se puede ajustar con `tokenTtlSeconds` y `tokenTimeZone` si el ambiente lo requiere.
57
57
 
58
58
  ## PDF con firma externa
59
59
 
@@ -107,7 +107,7 @@ Para solicitar credenciales a la institucion o al equipo FirmaGob, ver [docs/cre
107
107
 
108
108
  ## Ejemplos de integracion
109
109
 
110
- Ejemplos completos con CLI Node.js, API Hono y app Astro:
110
+ Ejemplos completos con CLI Node.js, API Hono y app Angular:
111
111
 
112
112
  ```text
113
113
  https://github.com/ltorresu82/firmagob-client-examples
@@ -12,6 +12,7 @@ export type FirmaGobClientConfig = {
12
12
  purpose?: Purpose;
13
13
  environment?: Environment;
14
14
  tokenTtlSeconds?: number;
15
+ tokenTimeZone?: string;
15
16
  fetch?: typeof fetch;
16
17
  testUrl?: string;
17
18
  productionUrl?: string;
@@ -16,6 +16,7 @@ export class FirmaGobClientError extends Error {
16
16
  const TEST_URL = "https://api.firma.cert.digital.gob.cl/firma/v2/files/tickets";
17
17
  const PRODUCTION_URL = "https://api.firma.digital.gob.cl/firma/v2/files/tickets";
18
18
  const DEFAULT_TOKEN_TTL_SECONDS = 5 * 60;
19
+ const DEFAULT_TOKEN_TIME_ZONE = "America/Santiago";
19
20
  export class FirmaGobClient {
20
21
  config;
21
22
  fetchImpl;
@@ -63,7 +64,7 @@ export class FirmaGobClient {
63
64
  entity: this.config.entity,
64
65
  run: this.config.run,
65
66
  purpose: this.config.purpose ?? Purpose.Unattended,
66
- expiration: formatFirmaGobDateTime(expiration),
67
+ expiration: formatFirmaGobDateTime(expiration, this.config.tokenTimeZone ?? DEFAULT_TOKEN_TIME_ZONE),
67
68
  iat: Math.floor(now.getTime() / 1000),
68
69
  });
69
70
  const unsignedToken = `${header}.${payload}`;
@@ -110,8 +111,25 @@ function assertRequired(name, value) {
110
111
  function base64UrlEncodeJson(value) {
111
112
  return Buffer.from(JSON.stringify(value)).toString("base64url");
112
113
  }
113
- function formatFirmaGobDateTime(date) {
114
- return date.toISOString().slice(0, 19);
114
+ function formatFirmaGobDateTime(date, timeZone) {
115
+ const parts = new Intl.DateTimeFormat("sv-SE", {
116
+ timeZone,
117
+ year: "numeric",
118
+ month: "2-digit",
119
+ day: "2-digit",
120
+ hour: "2-digit",
121
+ minute: "2-digit",
122
+ second: "2-digit",
123
+ hour12: false,
124
+ }).formatToParts(date);
125
+ const get = (type) => {
126
+ const value = parts.find((part) => part.type === type)?.value;
127
+ if (!value) {
128
+ throw new FirmaGobClientError(`Could not format FirmaGob expiration date for time zone: ${timeZone}`);
129
+ }
130
+ return value;
131
+ };
132
+ return `${get("year")}-${get("month")}-${get("day")}T${get("hour")}:${get("minute")}:${get("second")}`;
115
133
  }
116
134
  function parseJsonResponse(body) {
117
135
  try {
@@ -0,0 +1,23 @@
1
+ # ADR-0001: Mantener firmagob-client como paquete público y genérico
2
+
3
+ ## Status
4
+
5
+ Accepted
6
+
7
+ ## Context
8
+
9
+ `firmagob-client` es un repositorio público orientado a integrar FirmaGob Chile desde TypeScript. `AGENTS.md` define que debe mantenerse genérico, sin referencias a clientes, proyectos internos, instituciones específicas, conversaciones privadas ni documentos no públicos.
10
+
11
+ El README presenta el paquete como cliente TypeScript para FirmaGob Chile y aclara que no es un SDK oficial.
12
+
13
+ ## Decision
14
+
15
+ Mantener el repositorio público, genérico y reutilizable por cualquier institución pública habilitada.
16
+
17
+ Los ejemplos, tests y documentación deben usar nombres genéricos como `Institución de Prueba`. Las fuentes normativas o técnicas deben ser públicas y oficiales cuando existan.
18
+
19
+ ## Consequences
20
+
21
+ - No introducir referencias a clientes, instituciones específicas, proyectos internos ni evidencia institucional.
22
+ - Si aparece una referencia institucional específica, limpiarla antes de publicar o distribuir.
23
+ - Revisar documentación, ejemplos y tests como superficie pública, no como material interno.
@@ -0,0 +1,23 @@
1
+ # ADR-0002: Las fuentes oficiales FirmaGob prevalecen sobre el cliente
2
+
3
+ ## Status
4
+
5
+ Accepted
6
+
7
+ ## Context
8
+
9
+ El README lista como fuentes oficiales el manual de integración API FirmaGob y repositorios `digital-gob-cl`. También declara que, si existe diferencia entre este paquete y una fuente oficial vigente, debe prevalecer la fuente oficial.
10
+
11
+ El código modela endpoints de certificación y producción de FirmaGob v2.
12
+
13
+ ## Decision
14
+
15
+ El contrato funcional del cliente debe seguir la documentación y ejemplos oficiales vigentes de FirmaGob.
16
+
17
+ Cuando exista una discrepancia, se debe actualizar este paquete o documentar la incompatibilidad. No se debe inventar un contrato propio ni mantener comportamiento divergente como default.
18
+
19
+ ## Consequences
20
+
21
+ - Cambios de API, claims JWT, endpoints, formatos de payload o reglas de firma deben contrastarse con fuentes oficiales.
22
+ - El README puede citar fuentes oficiales; no debe basarse en conocimiento privado.
23
+ - Las decisiones futuras de compatibilidad deben dejar explícita la versión o fuente pública usada.
@@ -0,0 +1,21 @@
1
+ # ADR-0003: Mantener cero dependencias runtime salvo justificación técnica clara
2
+
3
+ ## Status
4
+
5
+ Accepted
6
+
7
+ ## Context
8
+
9
+ `AGENTS.md` exige mantener el paquete sin dependencias runtime salvo razón técnica clara. El README lista `sin dependencias runtime` como parte del estado inicial, y `package.json` actualmente solo declara `devDependencies`.
10
+
11
+ ## Decision
12
+
13
+ Mantener el paquete liviano y sin dependencias runtime por defecto.
14
+
15
+ Las dependencias de desarrollo para TypeScript, tipos, tests o tooling son aceptables. Cualquier dependencia runtime debe justificarse por una necesidad técnica clara y quedar documentada.
16
+
17
+ ## Consequences
18
+
19
+ - No agregar librerías PDF, JWT, HTTP o criptográficas runtime si Node.js ya cubre el caso de uso.
20
+ - Evaluar cualquier dependencia runtime nueva por seguridad, mantenimiento, tamaño de paquete y compatibilidad ESM/Node.
21
+ - Mantener la validación del contenido empacado antes de publicar.
@@ -0,0 +1,23 @@
1
+ # ADR-0004: Configuración y secretos deben fallar de forma explícita
2
+
3
+ ## Status
4
+
5
+ Accepted
6
+
7
+ ## Context
8
+
9
+ `src/firmagob-client.ts` valida `apiTokenKey`, `secret`, `entity` y `run` en el constructor. El ejemplo `examples/sign-hash-sandbox.js` falla cuando faltan variables de entorno requeridas. `docs/credentials.md` documenta variables requeridas y manejo seguro.
10
+
11
+ `AGENTS.md` prohíbe commitear credenciales, RUN reales, tokens y evidencia con datos institucionales.
12
+
13
+ ## Decision
14
+
15
+ Credenciales, RUN, entidad, propósito y endpoint deben venir de configuración externa.
16
+
17
+ El runtime y los ejemplos deben fallar con errores claros cuando falte configuración requerida. No se deben agregar credenciales dummy, usuarios de prueba, endpoints locales o fallbacks silenciosos como comportamiento productivo.
18
+
19
+ ## Consequences
20
+
21
+ - Los ejemplos pueden usar dry-run explícito, pero no deben simular credenciales reales.
22
+ - Las respuestas o evidencias reales de FirmaGob no deben quedar versionadas.
23
+ - Cualquier bypass de desarrollo debe estar nombrado como tal y no ser el camino por defecto.
@@ -0,0 +1,23 @@
1
+ # ADR-0005: La firma PDF se modela como preparación ByteRange más PKCS#7 externo
2
+
3
+ ## Status
4
+
5
+ Accepted
6
+
7
+ ## Context
8
+
9
+ El README describe el flujo de preparar el PDF, calcular hash, enviar a FirmaGob y recibir PKCS#7 base64. `src/pdf-external-signature.ts` implementa preparación de `ByteRange`, exclusión de `/Contents` y embebido de firma PKCS#7.
10
+
11
+ Los tests validan placeholder, bytes de hash y rechazo de firmas mayores al espacio reservado.
12
+
13
+ ## Decision
14
+
15
+ El paquete se encarga de preparar PDFs para firma externa y de insertar una firma PKCS#7 emitida fuera del paquete.
16
+
17
+ No administra certificados, llaves privadas ni firma criptográfica local.
18
+
19
+ ## Consequences
20
+
21
+ - El límite del paquete es preparación, hashing e inyección de firma externa.
22
+ - No introducir llaves privadas, certificados reales o almacenamiento de secretos en este repositorio.
23
+ - Cambios al helper PDF deben conservar el contrato de `ByteRange`, placeholder y validaciones de tamaño de firma.
@@ -0,0 +1,23 @@
1
+ # Architecture Decision Records
2
+
3
+ Este directorio contiene decisiones técnicas durables del repositorio `firmagob-client`.
4
+
5
+ Los ADRs se usan para preservar decisiones que futuros mantenedores o agentes necesitan conocer antes de cambiar contratos, límites del paquete, seguridad, dependencias o comportamiento público.
6
+
7
+ ## Índice
8
+
9
+ | ADR | Estado | Decisión |
10
+ | --- | --- | --- |
11
+ | [ADR-0001](./ADR-0001-public-generic-package.md) | Accepted | Mantener `firmagob-client` como paquete público y genérico |
12
+ | [ADR-0002](./ADR-0002-official-firmagob-sources.md) | Accepted | Las fuentes oficiales FirmaGob prevalecen sobre el cliente |
13
+ | [ADR-0003](./ADR-0003-zero-runtime-dependencies.md) | Accepted | Mantener cero dependencias runtime salvo justificación técnica clara |
14
+ | [ADR-0004](./ADR-0004-explicit-configuration-failures.md) | Accepted | Configuración y secretos deben fallar de forma explícita |
15
+ | [ADR-0005](./ADR-0005-external-pdf-signature-boundary.md) | Accepted | La firma PDF se modela como preparación ByteRange más PKCS#7 externo |
16
+
17
+ ## Candidatos pendientes
18
+
19
+ No hay candidatos pendientes al momento de crear este índice.
20
+
21
+ ## Origen
22
+
23
+ Estos ADRs se originan desde la auditoría de memoria durable en [`docs/decision-memory-audit.md`](../decision-memory-audit.md).
@@ -13,6 +13,8 @@ Este paquete no incluye credenciales de prueba ni productivas. Para ejecutar una
13
13
  | `FIRMAGOB_PURPOSE` | Proposito del certificado: `Desatendido` o `Propósito General`. |
14
14
  | `FIRMAGOB_ENDPOINT_API` | Endpoint API del ambiente correspondiente. |
15
15
 
16
+ El token JWT usa `expiration` como fecha local sin zona horaria. Por defecto este paquete usa `America/Santiago`, que replica el comportamiento esperado por los ejemplos oficiales Java cuando se ejecutan en Chile.
17
+
16
18
  Endpoint de certificacion usado por los ejemplos oficiales:
17
19
 
18
20
  ```text
@@ -0,0 +1,136 @@
1
+ # Auditoría de memoria durable de decisiones
2
+
3
+ Fecha: 2026-05-30
4
+
5
+ ## Alcance
6
+
7
+ Auditoría del repositorio `firmagob-client` para identificar decisiones que conviene preservar como memoria durable del repositorio. No se crean ADRs en este reporte; se proponen candidatos y estados.
8
+
9
+ ## Hallazgos
10
+
11
+ No existe una carpeta ADR o decision-record vigente. Si se decide formalizar estas decisiones, la ubicación recomendada es `docs/adr/`.
12
+
13
+ El repositorio ya contiene varias decisiones implícitas distribuidas entre `AGENTS.md`, `README.md`, `docs/credentials.md`, `package.json`, CI y código fuente. Las decisiones siguientes cumplen el criterio de memoria durable: si otro agente cambia estas áreas en dos meses, necesita conocerlas para no romper el contrato público del paquete.
14
+
15
+ ## Propuestas de memoria durable
16
+
17
+ ### ADR-0001: Mantener firmagob-client como paquete público y genérico
18
+
19
+ Estado sugerido: Accepted
20
+
21
+ Evidencia:
22
+
23
+ - `AGENTS.md`: declara que el repositorio es público y debe mantenerse genérico.
24
+ - `AGENTS.md`: prohíbe referencias a clientes, proyectos internos, instituciones específicas, conversaciones privadas y documentos no públicos.
25
+ - `README.md`: define el paquete como cliente TypeScript para integrar FirmaGob Chile y declara que no es un SDK oficial.
26
+
27
+ Decisión:
28
+
29
+ El repositorio debe mantenerse público, genérico y reutilizable por cualquier institución pública habilitada. Los ejemplos, tests y documentación deben usar nombres genéricos como `Institución de Prueba`. Las fuentes normativas o técnicas deben ser públicas y oficiales cuando existan.
30
+
31
+ Consecuencias:
32
+
33
+ - No se deben introducir referencias a clientes, instituciones específicas, proyectos internos ni evidencia institucional.
34
+ - Si aparece una referencia institucional específica, debe limpiarse antes de publicar o distribuir.
35
+ - Los cambios de documentación y ejemplos deben revisarse como superficie pública, no como material interno.
36
+
37
+ ### ADR-0002: Las fuentes oficiales FirmaGob prevalecen sobre el cliente
38
+
39
+ Estado sugerido: Accepted
40
+
41
+ Evidencia:
42
+
43
+ - `README.md`: lista como fuentes oficiales el manual de integración API FirmaGob y repositorios `digital-gob-cl`.
44
+ - `README.md`: indica que, si existe diferencia entre el paquete y una fuente oficial vigente, debe prevalecer la fuente oficial.
45
+ - `src/firmagob-client.ts`: modela endpoints de certificación y producción de FirmaGob v2.
46
+
47
+ Decisión:
48
+
49
+ El contrato funcional del cliente debe seguir la documentación y ejemplos oficiales vigentes de FirmaGob. Cuando exista una discrepancia, se debe actualizar este paquete o documentar la incompatibilidad; no se debe inventar un contrato propio ni mantener comportamiento divergente como default.
50
+
51
+ Consecuencias:
52
+
53
+ - Cambios de API, claims JWT, endpoints, formatos de payload o reglas de firma deben contrastarse con fuentes oficiales.
54
+ - El README puede citar fuentes oficiales; no debe basarse en conocimiento privado.
55
+ - Las decisiones futuras de compatibilidad deben dejar explícita la versión o fuente pública usada.
56
+
57
+ ### ADR-0003: Cero dependencias runtime salvo justificación técnica clara
58
+
59
+ Estado sugerido: Accepted
60
+
61
+ Evidencia:
62
+
63
+ - `AGENTS.md`: exige mantener el paquete sin dependencias runtime salvo razón técnica clara.
64
+ - `README.md`: lista `sin dependencias runtime` como parte del estado inicial.
65
+ - `package.json`: actualmente solo declara `devDependencies`.
66
+
67
+ Decisión:
68
+
69
+ El paquete debe conservarse liviano y sin dependencias runtime por defecto. Las dependencias de desarrollo para TypeScript, tipos, tests o tooling son aceptables; cualquier dependencia runtime debe justificarse por una necesidad técnica clara y quedar documentada.
70
+
71
+ Consecuencias:
72
+
73
+ - No agregar librerías PDF, JWT, HTTP o criptográficas runtime si Node.js ya cubre el caso de uso.
74
+ - Una dependencia runtime nueva debe evaluarse por superficie de seguridad, mantenimiento, tamaño de paquete y compatibilidad ESM/Node.
75
+ - La validación de publicación debe seguir revisando el contenido empacado.
76
+
77
+ ### ADR-0004: Configuración y secretos fallan de forma explícita
78
+
79
+ Estado sugerido: Accepted
80
+
81
+ Evidencia:
82
+
83
+ - `src/firmagob-client.ts`: valida `apiTokenKey`, `secret`, `entity` y `run` en el constructor.
84
+ - `examples/sign-hash-sandbox.js`: falla si faltan variables de entorno requeridas.
85
+ - `docs/credentials.md`: documenta variables requeridas y manejo seguro.
86
+ - `AGENTS.md`: prohíbe commitear credenciales, RUN reales, tokens y evidencia con datos institucionales.
87
+
88
+ Decisión:
89
+
90
+ Credenciales, RUN, entidad, propósito y endpoint deben venir de configuración externa. El runtime y los ejemplos deben fallar con errores claros cuando falte configuración requerida. No se deben agregar credenciales dummy, usuarios de prueba, endpoints locales o fallbacks silenciosos como comportamiento productivo.
91
+
92
+ Consecuencias:
93
+
94
+ - Los ejemplos pueden usar dry-run explícito, pero no deben simular credenciales reales.
95
+ - Las respuestas o evidencias reales de FirmaGob no deben quedar versionadas.
96
+ - Cualquier bypass de desarrollo debe estar nombrado como tal y no ser el camino por defecto.
97
+
98
+ ### ADR-0005: La firma PDF se modela como preparación ByteRange más PKCS#7 externo
99
+
100
+ Estado sugerido: Accepted
101
+
102
+ Evidencia:
103
+
104
+ - `README.md`: describe preparar el PDF, calcular hash, enviar a FirmaGob y recibir PKCS#7 base64.
105
+ - `src/pdf-external-signature.ts`: implementa preparación de `ByteRange`, exclusión de `/Contents` y embebido de firma PKCS#7.
106
+ - `src/pdf-external-signature.test.ts`: valida placeholder, bytes de hash y rechazo de firmas mayores al espacio reservado.
107
+
108
+ Decisión:
109
+
110
+ El paquete debe encargarse de preparar PDFs para firma externa y de insertar una firma PKCS#7 emitida fuera del paquete. No administra certificados, llaves privadas ni firma criptográfica local.
111
+
112
+ Consecuencias:
113
+
114
+ - El límite del paquete es preparación, hashing e inyección de firma externa.
115
+ - No se deben introducir llaves privadas, certificados reales o almacenamiento de secretos en este repositorio.
116
+ - Cambios al helper PDF deben conservar el contrato de `ByteRange`, placeholder y validaciones de tamaño de firma.
117
+
118
+ ## Validación realizada
119
+
120
+ Comandos ejecutados:
121
+
122
+ ```bash
123
+ npm test
124
+ npm audit
125
+ git status --short --ignored
126
+ ```
127
+
128
+ Resultados:
129
+
130
+ - `npm test`: pasó con 7 tests.
131
+ - `npm audit`: `found 0 vulnerabilities`.
132
+ - `git status --short --ignored`: solo mostró `dist/` y `node_modules/` como ignorados luego de la validación.
133
+
134
+ ## Resultado posterior
135
+
136
+ Esta propuesta fue aceptada y materializada como ADRs en `docs/adr/`, con un índice en `docs/adr/README.md`.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ltorresu82/firmagob-client",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "description": "Cliente TypeScript para integrar FirmaGob Chile con firma por hash y PDFs firmados externamente",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",