@albertomarturelo/sii-core 0.3.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.
Files changed (200) hide show
  1. package/CHANGELOG.md +114 -0
  2. package/LICENSE +21 -0
  3. package/README.md +108 -0
  4. package/dist/adapters/fake/index.d.ts +98 -0
  5. package/dist/adapters/fake/index.d.ts.map +1 -0
  6. package/dist/adapters/fake/index.js +131 -0
  7. package/dist/adapters/fake/index.js.map +1 -0
  8. package/dist/adapters/node/index.d.ts +22 -0
  9. package/dist/adapters/node/index.d.ts.map +1 -0
  10. package/dist/adapters/node/index.js +65 -0
  11. package/dist/adapters/node/index.js.map +1 -0
  12. package/dist/adapters/node/portal.d.ts +8 -0
  13. package/dist/adapters/node/portal.d.ts.map +1 -0
  14. package/dist/adapters/node/portal.js +222 -0
  15. package/dist/adapters/node/portal.js.map +1 -0
  16. package/dist/adapters/node/response.d.ts +21 -0
  17. package/dist/adapters/node/response.d.ts.map +1 -0
  18. package/dist/adapters/node/response.js +48 -0
  19. package/dist/adapters/node/response.js.map +1 -0
  20. package/dist/audit/audit.d.ts +8 -0
  21. package/dist/audit/audit.d.ts.map +1 -0
  22. package/dist/audit/audit.js +15 -0
  23. package/dist/audit/audit.js.map +1 -0
  24. package/dist/audit/index.d.ts +2 -0
  25. package/dist/audit/index.d.ts.map +1 -0
  26. package/dist/audit/index.js +2 -0
  27. package/dist/audit/index.js.map +1 -0
  28. package/dist/auth/auth.d.ts +43 -0
  29. package/dist/auth/auth.d.ts.map +1 -0
  30. package/dist/auth/auth.js +219 -0
  31. package/dist/auth/auth.js.map +1 -0
  32. package/dist/auth/index.d.ts +3 -0
  33. package/dist/auth/index.d.ts.map +1 -0
  34. package/dist/auth/index.js +3 -0
  35. package/dist/auth/index.js.map +1 -0
  36. package/dist/auth/login-error.d.ts +8 -0
  37. package/dist/auth/login-error.d.ts.map +1 -0
  38. package/dist/auth/login-error.js +18 -0
  39. package/dist/auth/login-error.js.map +1 -0
  40. package/dist/auth/session.d.ts +31 -0
  41. package/dist/auth/session.d.ts.map +1 -0
  42. package/dist/auth/session.js +52 -0
  43. package/dist/auth/session.js.map +1 -0
  44. package/dist/cli.d.ts +3 -0
  45. package/dist/cli.d.ts.map +1 -0
  46. package/dist/cli.js +6 -0
  47. package/dist/cli.js.map +1 -0
  48. package/dist/config/config.d.ts +38 -0
  49. package/dist/config/config.d.ts.map +1 -0
  50. package/dist/config/config.js +40 -0
  51. package/dist/config/config.js.map +1 -0
  52. package/dist/config/index.d.ts +2 -0
  53. package/dist/config/index.d.ts.map +1 -0
  54. package/dist/config/index.js +2 -0
  55. package/dist/config/index.js.map +1 -0
  56. package/dist/errors/errors.d.ts +56 -0
  57. package/dist/errors/errors.d.ts.map +1 -0
  58. package/dist/errors/errors.js +62 -0
  59. package/dist/errors/errors.js.map +1 -0
  60. package/dist/errors/index.d.ts +2 -0
  61. package/dist/errors/index.d.ts.map +1 -0
  62. package/dist/errors/index.js +2 -0
  63. package/dist/errors/index.js.map +1 -0
  64. package/dist/format/format.d.ts +5 -0
  65. package/dist/format/format.d.ts.map +1 -0
  66. package/dist/format/format.js +14 -0
  67. package/dist/format/format.js.map +1 -0
  68. package/dist/format/index.d.ts +2 -0
  69. package/dist/format/index.d.ts.map +1 -0
  70. package/dist/format/index.js +2 -0
  71. package/dist/format/index.js.map +1 -0
  72. package/dist/identity/identity.d.ts +56 -0
  73. package/dist/identity/identity.d.ts.map +1 -0
  74. package/dist/identity/identity.js +93 -0
  75. package/dist/identity/identity.js.map +1 -0
  76. package/dist/identity/index.d.ts +2 -0
  77. package/dist/identity/index.d.ts.map +1 -0
  78. package/dist/identity/index.js +2 -0
  79. package/dist/identity/index.js.map +1 -0
  80. package/dist/index.d.ts +24 -0
  81. package/dist/index.d.ts.map +1 -0
  82. package/dist/index.js +24 -0
  83. package/dist/index.js.map +1 -0
  84. package/dist/node.d.ts +9 -0
  85. package/dist/node.d.ts.map +1 -0
  86. package/dist/node.js +22 -0
  87. package/dist/node.js.map +1 -0
  88. package/dist/periodo/anio.d.ts +15 -0
  89. package/dist/periodo/anio.d.ts.map +1 -0
  90. package/dist/periodo/anio.js +42 -0
  91. package/dist/periodo/anio.js.map +1 -0
  92. package/dist/periodo/index.d.ts +3 -0
  93. package/dist/periodo/index.d.ts.map +1 -0
  94. package/dist/periodo/index.js +3 -0
  95. package/dist/periodo/index.js.map +1 -0
  96. package/dist/periodo/periodo.d.ts +19 -0
  97. package/dist/periodo/periodo.d.ts.map +1 -0
  98. package/dist/periodo/periodo.js +55 -0
  99. package/dist/periodo/periodo.js.map +1 -0
  100. package/dist/portal/bte-comunas.d.ts +9 -0
  101. package/dist/portal/bte-comunas.d.ts.map +1 -0
  102. package/dist/portal/bte-comunas.js +400 -0
  103. package/dist/portal/bte-comunas.js.map +1 -0
  104. package/dist/portal/bte-emit.d.ts +70 -0
  105. package/dist/portal/bte-emit.d.ts.map +1 -0
  106. package/dist/portal/bte-emit.js +266 -0
  107. package/dist/portal/bte-emit.js.map +1 -0
  108. package/dist/portal/bte.d.ts +55 -0
  109. package/dist/portal/bte.d.ts.map +1 -0
  110. package/dist/portal/bte.js +215 -0
  111. package/dist/portal/bte.js.map +1 -0
  112. package/dist/portal/dte-public.d.ts +36 -0
  113. package/dist/portal/dte-public.d.ts.map +1 -0
  114. package/dist/portal/dte-public.js +192 -0
  115. package/dist/portal/dte-public.js.map +1 -0
  116. package/dist/portal/f22/declaraciones.d.ts +37 -0
  117. package/dist/portal/f22/declaraciones.d.ts.map +1 -0
  118. package/dist/portal/f22/declaraciones.js +86 -0
  119. package/dist/portal/f22/declaraciones.js.map +1 -0
  120. package/dist/portal/f22/grid.d.ts +14 -0
  121. package/dist/portal/f22/grid.d.ts.map +1 -0
  122. package/dist/portal/f22/grid.js +51 -0
  123. package/dist/portal/f22/grid.js.map +1 -0
  124. package/dist/portal/f22/historial.d.ts +34 -0
  125. package/dist/portal/f22/historial.d.ts.map +1 -0
  126. package/dist/portal/f22/historial.js +66 -0
  127. package/dist/portal/f22/historial.js.map +1 -0
  128. package/dist/portal/f22/index.d.ts +7 -0
  129. package/dist/portal/f22/index.d.ts.map +1 -0
  130. package/dist/portal/f22/index.js +11 -0
  131. package/dist/portal/f22/index.js.map +1 -0
  132. package/dist/portal/f22/observaciones.d.ts +20 -0
  133. package/dist/portal/f22/observaciones.d.ts.map +1 -0
  134. package/dist/portal/f22/observaciones.js +38 -0
  135. package/dist/portal/f22/observaciones.js.map +1 -0
  136. package/dist/portal/f22/shared.d.ts +32 -0
  137. package/dist/portal/f22/shared.d.ts.map +1 -0
  138. package/dist/portal/f22/shared.js +130 -0
  139. package/dist/portal/f22/shared.js.map +1 -0
  140. package/dist/portal/f22-codigos.d.ts +28 -0
  141. package/dist/portal/f22-codigos.d.ts.map +1 -0
  142. package/dist/portal/f22-codigos.js +141 -0
  143. package/dist/portal/f22-codigos.js.map +1 -0
  144. package/dist/portal/f29-codigos.d.ts +15 -0
  145. package/dist/portal/f29-codigos.d.ts.map +1 -0
  146. package/dist/portal/f29-codigos.js +552 -0
  147. package/dist/portal/f29-codigos.js.map +1 -0
  148. package/dist/portal/f29.d.ts +62 -0
  149. package/dist/portal/f29.d.ts.map +1 -0
  150. package/dist/portal/f29.js +244 -0
  151. package/dist/portal/f29.js.map +1 -0
  152. package/dist/portal/rcv.d.ts +62 -0
  153. package/dist/portal/rcv.d.ts.map +1 -0
  154. package/dist/portal/rcv.js +252 -0
  155. package/dist/portal/rcv.js.map +1 -0
  156. package/dist/portal/representacion.d.ts +24 -0
  157. package/dist/portal/representacion.d.ts.map +1 -0
  158. package/dist/portal/representacion.js +153 -0
  159. package/dist/portal/representacion.js.map +1 -0
  160. package/dist/rut/index.d.ts +2 -0
  161. package/dist/rut/index.d.ts.map +1 -0
  162. package/dist/rut/index.js +2 -0
  163. package/dist/rut/index.js.map +1 -0
  164. package/dist/rut/rut.d.ts +16 -0
  165. package/dist/rut/rut.d.ts.map +1 -0
  166. package/dist/rut/rut.js +70 -0
  167. package/dist/rut/rut.js.map +1 -0
  168. package/dist/seams/index.d.ts +126 -0
  169. package/dist/seams/index.d.ts.map +1 -0
  170. package/dist/seams/index.js +6 -0
  171. package/dist/seams/index.js.map +1 -0
  172. package/dist/tasks/auth.d.ts +16 -0
  173. package/dist/tasks/auth.d.ts.map +1 -0
  174. package/dist/tasks/auth.js +22 -0
  175. package/dist/tasks/auth.js.map +1 -0
  176. package/dist/tasks/bte.d.ts +52 -0
  177. package/dist/tasks/bte.d.ts.map +1 -0
  178. package/dist/tasks/bte.js +169 -0
  179. package/dist/tasks/bte.js.map +1 -0
  180. package/dist/tasks/dte.d.ts +9 -0
  181. package/dist/tasks/dte.d.ts.map +1 -0
  182. package/dist/tasks/dte.js +30 -0
  183. package/dist/tasks/dte.js.map +1 -0
  184. package/dist/tasks/f22.d.ts +69 -0
  185. package/dist/tasks/f22.d.ts.map +1 -0
  186. package/dist/tasks/f22.js +189 -0
  187. package/dist/tasks/f22.js.map +1 -0
  188. package/dist/tasks/f29.d.ts +67 -0
  189. package/dist/tasks/f29.d.ts.map +1 -0
  190. package/dist/tasks/f29.js +213 -0
  191. package/dist/tasks/f29.js.map +1 -0
  192. package/dist/tasks/operate.d.ts +22 -0
  193. package/dist/tasks/operate.d.ts.map +1 -0
  194. package/dist/tasks/operate.js +34 -0
  195. package/dist/tasks/operate.js.map +1 -0
  196. package/dist/tasks/rcv.d.ts +17 -0
  197. package/dist/tasks/rcv.d.ts.map +1 -0
  198. package/dist/tasks/rcv.js +76 -0
  199. package/dist/tasks/rcv.js.map +1 -0
  200. package/package.json +54 -0
@@ -0,0 +1,192 @@
1
+ // DTE — public consulta de empresas autorizadas a emitir DTE. Typed facade over the
2
+ // UNAUTHENTICATED `PortalDriver.requestPublic` seam (ADR-014).
3
+ //
4
+ // The FIRST public/session-less portal surface. Unlike rcv/f22/f29, it does NOT ride
5
+ // `withSession`: it issues a cold form-POST to the public palena CGI
6
+ // (`/cvc_cgi/dte/ee_empresa_rut`), which returns a server-rendered HTML report for ANY
7
+ // RUT — no login, no cookie, no session. Ported from the proven Python sii-cli
8
+ // (portal/dte.py); the wire contract is first-hand-observed there, NOT a third-party
9
+ // library (ADR-004). Full contract: docs/sii-contract/dte-authorized.md.
10
+ //
11
+ // Observed 2026-06-13, prod (palena.sii.cl): the response is `text/html;
12
+ // charset=ISO-8859-1` (the seam decodes it), carrying a header block + a `<table>` of
13
+ // authorized docs. No JSON envelope, no captcha. We parse the table rows in-house with
14
+ // a small tag stripper — stdlib only, no third-party HTML library (ADR-004).
15
+ import { HOSTS } from '../config/index.js';
16
+ import { DteError } from '../errors/index.js';
17
+ // `/cvc/dte/ee_empresas_dte.html` is the public HTML form; its validation JS rewrites
18
+ // the submit target to this `/cvc_cgi/` CGI path (observed 2026-06-13). We POST the CGI
19
+ // path directly — the static `ee_empresa_rut` path returns "NO SE ENCONTRÓ LA PÁGINA".
20
+ const AUTORIZADOS_URL = `${HOSTS.dteWs}/cvc_cgi/dte/ee_empresa_rut`;
21
+ // Origin/Referer mirror the public form page; neither is required (all headers confirmed
22
+ // optional 2026-06-13), but sending them keeps the request indistinguishable from the form.
23
+ const HEADERS = {
24
+ Origin: HOSTS.dteWs,
25
+ Referer: `${HOSTS.dteWs}/cvc/dte/ee_empresas_dte.html`,
26
+ };
27
+ // SII's verbatim "not an authorized emisor" sentence (observed 2026-06-13). Its presence
28
+ // (with no docs table) is a CLEAN NEGATIVE — the RUT exists-or-not but is not a DTE emisor
29
+ // — never an error (ADR-014). Matched as a lowercased substring on the decoded body.
30
+ const NOT_AUTHORIZED_MARKER = 'no corresponde a una empresa autorizada';
31
+ const messageOf = (e) => (e instanceof Error ? e.message : String(e));
32
+ // Decode the handful of HTML entities SII's report can carry. The body is already
33
+ // Latin-1-decoded by the seam, so most accents are real chars; numeric/named refs
34
+ // (e.g. N&deg;, &oacute;) still appear and are normalised here. NAMED accent entities are
35
+ // CASE-SENSITIVE (`&Eacute;` = É, `&eacute;` = é) — keep the cases distinct.
36
+ const NAMED_ENTITIES = {
37
+ aacute: 'á',
38
+ eacute: 'é',
39
+ iacute: 'í',
40
+ oacute: 'ó',
41
+ uacute: 'ú',
42
+ ntilde: 'ñ',
43
+ Aacute: 'Á',
44
+ Eacute: 'É',
45
+ Iacute: 'Í',
46
+ Oacute: 'Ó',
47
+ Uacute: 'Ú',
48
+ Ntilde: 'Ñ',
49
+ deg: '°',
50
+ ordm: 'º',
51
+ };
52
+ function decodeEntities(s) {
53
+ return s
54
+ .replace(/&nbsp;/gi, ' ')
55
+ .replace(/&amp;/gi, '&')
56
+ .replace(/&lt;/gi, '<')
57
+ .replace(/&gt;/gi, '>')
58
+ .replace(/&quot;/gi, '"')
59
+ .replace(/&([A-Za-z]+);/g, (m, name) => NAMED_ENTITIES[name] ?? m)
60
+ .replace(/&#(\d+);/g, (_, d) => String.fromCodePoint(Number(d)))
61
+ .replace(/&#x([0-9a-f]+);/gi, (_, h) => String.fromCodePoint(parseInt(h, 16)));
62
+ }
63
+ /** Collect every `<tr>` as a list of `<td>`/`<th>` cell texts (tags stripped, entities
64
+ * decoded, whitespace collapsed, empty cells preserved). The tables are siblings (not
65
+ * nested), so a flat row collector suffices — rows are classified by content downstream,
66
+ * not by which table they came from (mirrors the Python `_TableRowParser`). */
67
+ function tableRows(html) {
68
+ const rows = [];
69
+ const trRe = /<tr\b[^>]*>([\s\S]*?)<\/tr>/gi;
70
+ for (let tr = trRe.exec(html); tr !== null; tr = trRe.exec(html)) {
71
+ const cells = [];
72
+ const tdRe = /<t[dh]\b[^>]*>([\s\S]*?)<\/t[dh]>/gi;
73
+ const inner = tr[1] ?? '';
74
+ for (let td = tdRe.exec(inner); td !== null; td = tdRe.exec(inner)) {
75
+ const text = (td[1] ?? '').replace(/<[^>]*>/g, ' ');
76
+ cells.push(decodeEntities(text).replace(/\s+/g, ' ').trim());
77
+ }
78
+ if (cells.length > 0)
79
+ rows.push(cells);
80
+ }
81
+ return rows;
82
+ }
83
+ /** Map a header-table label cell to a logical field. Order matters: "Fecha Resolución"
84
+ * also contains "resoluc", so test it before "N° Resolución" (mirrors Python). */
85
+ function classifyHeaderLabel(label) {
86
+ const low = label.toLowerCase();
87
+ if (low.includes('fecha') && low.includes('resoluc'))
88
+ return 'fechaResolucion';
89
+ if (low.includes('resoluc'))
90
+ return 'nResolucion';
91
+ if (low === 'rut')
92
+ return 'rut';
93
+ if (low.includes('raz') && low.includes('social'))
94
+ return 'razonSocial';
95
+ if (low.includes('regional'))
96
+ return 'direccionRegional';
97
+ return null;
98
+ }
99
+ const cell = (cells, i) => {
100
+ const v = cells[i];
101
+ return v === undefined || v === '' ? null : v;
102
+ };
103
+ /** Pull SII's verbatim "no autorizado" sentence out of the HTML (ADR-004); falls back to
104
+ * a fixed phrasing if the surrounding markup defeats cell extraction. */
105
+ function notAuthorizedMessage(html) {
106
+ for (const row of tableRows(html)) {
107
+ for (const c of row) {
108
+ if (c.toLowerCase().includes(NOT_AUTHORIZED_MARKER))
109
+ return c;
110
+ }
111
+ }
112
+ return 'El rut que ha ingresado, no corresponde a una empresa autorizada a emitir Facturas Electronicas.';
113
+ }
114
+ /** Parse the decoded HTML report into a `DteAutorizados`. Throws `DteError` when the body
115
+ * is neither a recognizable authorized report nor the known not-authorized message (the
116
+ * portal HTML changed shape — "scraper roto", ADR-004). */
117
+ function parseReport(html, subjectCanonical) {
118
+ if (html.toLowerCase().includes(NOT_AUTHORIZED_MARKER)) {
119
+ return {
120
+ rut: subjectCanonical,
121
+ autorizado: false,
122
+ razonSocial: null,
123
+ nResolucion: null,
124
+ fechaResolucion: null,
125
+ direccionRegional: null,
126
+ documentos: [],
127
+ mensaje: notAuthorizedMessage(html),
128
+ };
129
+ }
130
+ const header = {};
131
+ const documentos = [];
132
+ for (const cells of tableRows(html)) {
133
+ if (cells.length < 2)
134
+ continue;
135
+ const first = (cells[0] ?? '').trim();
136
+ if (/^\d+$/.test(first)) {
137
+ // A docs-grid row: [codigo, descripcion, autorizado, desautorizado].
138
+ documentos.push({
139
+ codigo: Number(first),
140
+ descripcion: cell(cells, 1),
141
+ fechaAutorizacion: cell(cells, 2),
142
+ fechaDesautorizacion: cell(cells, 3),
143
+ });
144
+ continue;
145
+ }
146
+ const logical = classifyHeaderLabel(first);
147
+ const value = cells[1];
148
+ if (logical && value !== undefined && header[logical] === undefined)
149
+ header[logical] = value;
150
+ }
151
+ if (header.rut === undefined && documentos.length === 0) {
152
+ throw new DteError('scraper roto: la respuesta del SII no trae ni la tabla de documentos autorizados ' +
153
+ 'ni el mensaje de "no autorizado" esperado (la página pudo cambiar). ' +
154
+ `RUT consultado: ${subjectCanonical}.`);
155
+ }
156
+ return {
157
+ rut: subjectCanonical,
158
+ autorizado: true,
159
+ razonSocial: header.razonSocial ?? null,
160
+ nResolucion: header.nResolucion ?? null,
161
+ fechaResolucion: header.fechaResolucion ?? null,
162
+ direccionRegional: header.direccionRegional ?? null,
163
+ documentos,
164
+ mensaje: null,
165
+ };
166
+ }
167
+ /** List the DTE types a contribuyente is authorized to emit (public, login-free).
168
+ * Hits the palena consulta CGI with no session, for ANY RUT incl. counterparties
169
+ * (ADR-014). Returns the resolution header + authorized-document grid, or a clean
170
+ * negative (`autorizado: false` + SII's verbatim `mensaje`) when the RUT is not a
171
+ * registered DTE emisor. Throws `DteError` on a network/CGI failure, a non-200, or an
172
+ * unrecognizable body. `driver` is the seam — NO `PortalSession` (it is session-less). */
173
+ export async function fetchDteAutorizados(driver, rut) {
174
+ let response;
175
+ try {
176
+ response = await driver.requestPublic(AUTORIZADOS_URL, {
177
+ method: 'POST',
178
+ headers: HEADERS,
179
+ form: { RUT_EMP: String(rut.body), DV_EMP: rut.dv },
180
+ });
181
+ }
182
+ catch (e) {
183
+ throw new DteError(`No se pudo consultar el SII (${AUTORIZADOS_URL}): ${messageOf(e)}`);
184
+ }
185
+ // palena answers HTTP 200 for BOTH authorized and not-authorized; a non-200 is an
186
+ // infrastructure failure, not a user condition — fail loud, never retry (ADR-004).
187
+ if (response.status !== 200) {
188
+ throw new DteError(`El SII respondió HTTP ${response.status} a la consulta de DTE autorizados.`);
189
+ }
190
+ return parseReport(response.body, rut.canonical);
191
+ }
192
+ //# sourceMappingURL=dte-public.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dte-public.js","sourceRoot":"","sources":["../../src/portal/dte-public.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,37 @@
1
+ import type { Rut } from '../../rut/index.js';
2
+ import type { Anio } from '../../periodo/index.js';
3
+ import type { PortalSession } from '../../seams/index.js';
4
+ import type { CodigoF22, F22Grupos } from '../f22-codigos.js';
5
+ export interface DeclaracionF22 {
6
+ readonly folio: string | null;
7
+ readonly vigente: boolean | null;
8
+ readonly estado: string | null;
9
+ readonly fecha: string | null;
10
+ readonly tipoImpugnado: string | null;
11
+ }
12
+ /** Step 1 — the año's declaraciones + estado (no código grid). The overview surface. */
13
+ export interface F22Declaraciones {
14
+ readonly rut: string;
15
+ readonly anio: string;
16
+ readonly tieneDeclaracion: boolean;
17
+ readonly declaraciones: readonly DeclaracionF22[];
18
+ }
19
+ /** Full readback for one (RUT, año): the selected declaración + its código grid (always
20
+ * `f22Compacto`, identity/bank PII dropped). On a `--full` read `grupos` adds the contador
21
+ * split over the SAME `codigos`; otherwise `grupos` is absent and the output is the flat grid. */
22
+ export interface F22Estado extends F22Declaraciones {
23
+ readonly folio: string | null;
24
+ readonly estado: string | null;
25
+ readonly codigos: readonly CodigoF22[];
26
+ readonly grupos?: F22Grupos;
27
+ }
28
+ /** The folio to read when none is pinned: the first vigente declaración, else the
29
+ * first with a folio, else null. */
30
+ export declare function pickVigenteFolio(declaraciones: readonly DeclaracionF22[]): string | null;
31
+ /** Step 1: `buscaDeclVgte` — the año's declaraciones + estado. Empty `decls` is a
32
+ * legitimate "no declaración" (tieneDeclaracion=false), NOT an error. */
33
+ export declare function fetchF22Declaraciones(session: PortalSession, params: {
34
+ rut: Rut;
35
+ anio: Anio;
36
+ }): Promise<F22Declaraciones>;
37
+ //# sourceMappingURL=declaraciones.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"declaraciones.d.ts","sourceRoot":"","sources":["../../../src/portal/f22/declaraciones.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,wBAAwB,CAAC;AACnD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAa9D,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,QAAQ,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC;IACjC,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,QAAQ,CAAC,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;CACvC;AAED,wFAAwF;AACxF,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,gBAAgB,EAAE,OAAO,CAAC;IACnC,QAAQ,CAAC,aAAa,EAAE,SAAS,cAAc,EAAE,CAAC;CACnD;AAED;;mGAEmG;AACnG,MAAM,WAAW,SAAU,SAAQ,gBAAgB;IACjD,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,QAAQ,CAAC,OAAO,EAAE,SAAS,SAAS,EAAE,CAAC;IACvC,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,CAAC;CAC7B;AAuDD;qCACqC;AACrC,wBAAgB,gBAAgB,CAAC,aAAa,EAAE,SAAS,cAAc,EAAE,GAAG,MAAM,GAAG,IAAI,CAMxF;AAED;0EAC0E;AAC1E,wBAAsB,qBAAqB,CACzC,OAAO,EAAE,aAAa,EACtB,MAAM,EAAE;IAAE,GAAG,EAAE,GAAG,CAAC;IAAC,IAAI,EAAE,IAAI,CAAA;CAAE,GAC/B,OAAO,CAAC,gBAAgB,CAAC,CAa3B"}
@@ -0,0 +1,86 @@
1
+ import { F22_BASE, aliasGet, asStr, isObj, postSdi, rutDigits } from './shared.js';
2
+ const BUSCA_DECL_URL = `${F22_BASE}/buscaDeclVgte`;
3
+ // Namespace was best-guess from the SDI pattern (área renta / app consultaestadof22);
4
+ // SII ACCEPTED it live 2026-06-27 (returned the real código grid). The URL path routes.
5
+ const BUSCA_DECL_NAMESPACE = 'cl.sii.sdi.lob.renta.consultaestadof22.data.api.interfaces.FacadeService/buscaDeclVgte';
6
+ const DECL_ALIASES = {
7
+ folio: ['folio', 'folioDeclaracion'],
8
+ vgte: ['vgte', 'vigente'],
9
+ codConc: ['codConc', 'codConclusion'],
10
+ fecha: ['fecIng', 'fechaIngreso', 'fecha'],
11
+ tipoImpugnado: ['tipoImpugnado'],
12
+ };
13
+ const GLOSA_ALIASES = {
14
+ codConc: ['codConclusion', 'codConc'],
15
+ descripcion: ['descripcion', 'glosa'],
16
+ };
17
+ /** `vgte` arrives as "S"/"N", a bool, or 1/0 (exact form unconfirmed). Tolerant. */
18
+ function coerceVigente(v) {
19
+ if (v === null || v === undefined)
20
+ return null;
21
+ if (typeof v === 'boolean')
22
+ return v;
23
+ const s = String(v).trim().toUpperCase();
24
+ if (['S', 'SI', 'TRUE', '1', 'VIGENTE'].includes(s))
25
+ return true;
26
+ if (['N', 'NO', 'FALSE', '0'].includes(s))
27
+ return false;
28
+ return null;
29
+ }
30
+ /** Map `glosas[]` (codConclusion → descripción) so a decl's codConc resolves to its
31
+ * human estado label. */
32
+ function glosaMap(data) {
33
+ const out = new Map();
34
+ const glosas = isObj(data) ? data['glosas'] : undefined;
35
+ if (!Array.isArray(glosas))
36
+ return out;
37
+ for (const g of glosas) {
38
+ if (!isObj(g))
39
+ continue;
40
+ const cod = asStr(aliasGet(g, GLOSA_ALIASES.codConc));
41
+ const desc = asStr(aliasGet(g, GLOSA_ALIASES.descripcion));
42
+ if (cod !== null && desc !== null)
43
+ out.set(cod, desc);
44
+ }
45
+ return out;
46
+ }
47
+ function buildDeclaraciones(data) {
48
+ const decls = isObj(data) ? data['decls'] : undefined;
49
+ if (!Array.isArray(decls))
50
+ return [];
51
+ const glosas = glosaMap(data);
52
+ return decls.filter(isObj).map((d) => {
53
+ const codConc = asStr(aliasGet(d, DECL_ALIASES.codConc));
54
+ return {
55
+ folio: asStr(aliasGet(d, DECL_ALIASES.folio)),
56
+ vigente: coerceVigente(aliasGet(d, DECL_ALIASES.vgte)),
57
+ estado: codConc !== null ? (glosas.get(codConc) ?? null) : null,
58
+ fecha: asStr(aliasGet(d, DECL_ALIASES.fecha)),
59
+ tipoImpugnado: asStr(aliasGet(d, DECL_ALIASES.tipoImpugnado)),
60
+ };
61
+ });
62
+ }
63
+ /** The folio to read when none is pinned: the first vigente declaración, else the
64
+ * first with a folio, else null. */
65
+ export function pickVigenteFolio(declaraciones) {
66
+ return (declaraciones.find((d) => d.vigente && d.folio !== null)?.folio ??
67
+ declaraciones.find((d) => d.folio !== null)?.folio ??
68
+ null);
69
+ }
70
+ /** Step 1: `buscaDeclVgte` — the año's declaraciones + estado. Empty `decls` is a
71
+ * legitimate "no declaración" (tieneDeclaracion=false), NOT an error. */
72
+ export async function fetchF22Declaraciones(session, params) {
73
+ const { rut, anio } = params;
74
+ const env = await postSdi(session, BUSCA_DECL_URL, BUSCA_DECL_NAMESPACE, {
75
+ periodo: anio.canonical,
76
+ ...rutDigits(rut),
77
+ });
78
+ const declaraciones = buildDeclaraciones(env.data);
79
+ return {
80
+ rut: rut.canonical,
81
+ anio: anio.canonical,
82
+ tieneDeclaracion: declaraciones.length > 0,
83
+ declaraciones,
84
+ };
85
+ }
86
+ //# sourceMappingURL=declaraciones.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"declaraciones.js","sourceRoot":"","sources":["../../../src/portal/f22/declaraciones.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import type { Rut } from '../../rut/index.js';
2
+ import type { Anio } from '../../periodo/index.js';
3
+ import type { PortalSession } from '../../seams/index.js';
4
+ import type { CodigoF22 } from '../f22-codigos.js';
5
+ /** `f22Compacto` — the código grid for a folio, MINUS identity/bank PII. This IS the form the
6
+ * SII renders (and its PDF); `--full` just adds the contador grouping over the same data via
7
+ * `groupCodigos` (the sibling `f22Completo` only adds internal control códigos — noisier, not
8
+ * richer — so it is not used). */
9
+ export declare function fetchF22Grid(session: PortalSession, params: {
10
+ rut: Rut;
11
+ anio: Anio;
12
+ folio: string;
13
+ }): Promise<CodigoF22[]>;
14
+ //# sourceMappingURL=grid.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"grid.d.ts","sourceRoot":"","sources":["../../../src/portal/f22/grid.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,wBAAwB,CAAC;AACnD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAI1D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAqCnD;;;mCAGmC;AACnC,wBAAsB,YAAY,CAChC,OAAO,EAAE,aAAa,EACtB,MAAM,EAAE;IAAE,GAAG,EAAE,GAAG,CAAC;IAAC,IAAI,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAC9C,OAAO,CAAC,SAAS,EAAE,CAAC,CAQtB"}
@@ -0,0 +1,51 @@
1
+ // The código taxonomy (PII denylist + contador grouping) lives in its own domain module —
2
+ // it changes when we observe a new código, not when the wire changes.
3
+ import { isHeaderCodigo } from '../f22-codigos.js';
4
+ import { F22_BASE, aliasGet, asNumber, asStr, isObj, postSdi, rutDigits } from './shared.js';
5
+ const F22_COMPACTO_URL = `${F22_BASE}/f22Compacto`;
6
+ const F22_COMPACTO_NAMESPACE = 'cl.sii.sdi.lob.renta.consultaestadof22.data.api.interfaces.FacadeService/f22Compacto';
7
+ // NOTE on `f22Completo`: a sibling endpoint exists, but live capture (spike #27, 2026-06-29)
8
+ // showed it returns f22Compacto's códigos PLUS internal control códigos (3056/8891/8865…) and
9
+ // extra PII (9306/9920) — i.e. NOISIER, not richer in tax content. The real "formulario
10
+ // completo" the SII renders (and its PDF) is built from `f22Compacto` + `codigosFormato` (the
11
+ // form skeleton). So `--full` reads `f22Compacto` (same source as the compact view) and adds
12
+ // the contador grouping — it does NOT use f22Completo. (ADR-004: first-hand obs over the port.)
13
+ const CODIGO_ALIASES = {
14
+ codigo: ['codigo', 'cod'],
15
+ valor: ['valor', 'monto'],
16
+ glosa: ['glosa', 'descripcion'],
17
+ };
18
+ /** Project a código grid (`data:[{codigo,valor,glosa}]`) into rows, DROPPING the
19
+ * identity/bank PII códigos (HEADER_CODIGOS). Sign preserved. */
20
+ function parseCodigoGrid(data) {
21
+ if (!Array.isArray(data))
22
+ return [];
23
+ const out = [];
24
+ for (const r of data) {
25
+ if (!isObj(r))
26
+ continue;
27
+ const codigo = asStr(aliasGet(r, CODIGO_ALIASES.codigo));
28
+ if (codigo === null || isHeaderCodigo(codigo))
29
+ continue; // drop identity/bank PII
30
+ out.push({
31
+ codigo,
32
+ valor: asNumber(aliasGet(r, CODIGO_ALIASES.valor)),
33
+ glosa: asStr(aliasGet(r, CODIGO_ALIASES.glosa)),
34
+ });
35
+ }
36
+ return out;
37
+ }
38
+ /** `f22Compacto` — the código grid for a folio, MINUS identity/bank PII. This IS the form the
39
+ * SII renders (and its PDF); `--full` just adds the contador grouping over the same data via
40
+ * `groupCodigos` (the sibling `f22Completo` only adds internal control códigos — noisier, not
41
+ * richer — so it is not used). */
42
+ export async function fetchF22Grid(session, params) {
43
+ const { rut, anio, folio } = params;
44
+ const env = await postSdi(session, F22_COMPACTO_URL, F22_COMPACTO_NAMESPACE, {
45
+ ...rutDigits(rut),
46
+ periodo: anio.canonical,
47
+ folio,
48
+ });
49
+ return parseCodigoGrid(env.data);
50
+ }
51
+ //# sourceMappingURL=grid.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"grid.js","sourceRoot":"","sources":["../../../src/portal/f22/grid.ts"],"names":[],"mappings":"AAMA,0FAA0F;AAC1F,sEAAsE;AACtE,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAEnD,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAE7F,MAAM,gBAAgB,GAAG,GAAG,QAAQ,cAAc,CAAC;AACnD,MAAM,sBAAsB,GAC1B,sFAAsF,CAAC;AACzF,6FAA6F;AAC7F,8FAA8F;AAC9F,wFAAwF;AACxF,8FAA8F;AAC9F,6FAA6F;AAC7F,gGAAgG;AAEhG,MAAM,cAAc,GAAG;IACrB,MAAM,EAAE,CAAC,QAAQ,EAAE,KAAK,CAAC;IACzB,KAAK,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC;IACzB,KAAK,EAAE,CAAC,OAAO,EAAE,aAAa,CAAC;CACvB,CAAC;AAEX;kEACkE;AAClE,SAAS,eAAe,CAAC,IAAa;IACpC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC;QAAE,OAAO,EAAE,CAAC;IACpC,MAAM,GAAG,GAAgB,EAAE,CAAC;IAC5B,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;QACrB,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;YAAE,SAAS;QACxB,MAAM,MAAM,GAAG,KAAK,CAAC,QAAQ,CAAC,CAAC,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC;QACzD,IAAI,MAAM,KAAK,IAAI,IAAI,cAAc,CAAC,MAAM,CAAC;YAAE,SAAS,CAAC,yBAAyB;QAClF,GAAG,CAAC,IAAI,CAAC;YACP,MAAM;YACN,KAAK,EAAE,QAAQ,CAAC,QAAQ,CAAC,CAAC,EAAE,cAAc,CAAC,KAAK,CAAC,CAAC;YAClD,KAAK,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC,EAAE,cAAc,CAAC,KAAK,CAAC,CAAC;SAChD,CAAC,CAAC;IACL,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;mCAGmC;AACnC,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,OAAsB,EACtB,MAA+C;IAE/C,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM,CAAC;IACpC,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,OAAO,EAAE,gBAAgB,EAAE,sBAAsB,EAAE;QAC3E,GAAG,SAAS,CAAC,GAAG,CAAC;QACjB,OAAO,EAAE,IAAI,CAAC,SAAS;QACvB,KAAK;KACN,CAAC,CAAC;IACH,OAAO,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;AACnC,CAAC"}
@@ -0,0 +1,34 @@
1
+ import type { Rut } from '../../rut/index.js';
2
+ import type { Anio } from '../../periodo/index.js';
3
+ import type { PortalSession } from '../../seams/index.js';
4
+ /** One event in a declaración's historial (`buscaEventos`). NOT PII — every field is a
5
+ * tax-process datum: the event code/glosa, dates, and carta/notification references. The
6
+ * monto rides inside `glosa` as verbatim SII text (tax content, not identity/bank), so the
7
+ * row is fully curated — no header exclusion, no `raw`. */
8
+ export interface EventoF22 {
9
+ readonly folio: string | null;
10
+ readonly codigo: string;
11
+ readonly glosa: string | null;
12
+ readonly fecha: string | null;
13
+ readonly tipo: string | null;
14
+ readonly codCarta: string | null;
15
+ readonly idCarta: string | null;
16
+ readonly referencia: string | null;
17
+ readonly fechaCitacion: string | null;
18
+ readonly unidadSii: string | null;
19
+ }
20
+ /** Sort key for an event's `fecha` (DD/MM/YYYY) → numeric YYYYMMDD for most-recent-first
21
+ * ordering. Undated / unparseable events sink to the bottom (−∞). Exported for the task,
22
+ * which sorts the aggregate across folios. */
23
+ export declare function eventoDateKey(fecha: string | null): number;
24
+ /** `buscaEventos` — the historial/eventos timeline for ONE folio (the folio is REQUIRED;
25
+ * omitting it returns a RESTEASY 500). Rows carry NO identity/bank PII (event code + glosa
26
+ * + dates + carta refs), so all are curated, nothing excluded, no `raw`. Wire order is
27
+ * oldest-first; the task aggregates across folios and sorts most-recent-first. Empty/non-array
28
+ * data = sin eventos (NOT an error). All params sent as strings (like buscaDeclVgte). */
29
+ export declare function fetchF22Historial(session: PortalSession, params: {
30
+ rut: Rut;
31
+ anio: Anio;
32
+ folio: string;
33
+ }): Promise<EventoF22[]>;
34
+ //# sourceMappingURL=historial.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"historial.d.ts","sourceRoot":"","sources":["../../../src/portal/f22/historial.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,wBAAwB,CAAC;AACnD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAO1D;;;4DAG4D;AAC5D,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,QAAQ,CAAC,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IACtC,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CACnC;AAiBD;;+CAE+C;AAC/C,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAK1D;AAED;;;;0FAI0F;AAC1F,wBAAsB,iBAAiB,CACrC,OAAO,EAAE,aAAa,EACtB,MAAM,EAAE;IAAE,GAAG,EAAE,GAAG,CAAC;IAAC,IAAI,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAC9C,OAAO,CAAC,SAAS,EAAE,CAAC,CA4BtB"}
@@ -0,0 +1,66 @@
1
+ import { F22_BASE, aliasGet, asStr, postSdi, rutDigits, trimToNull, isObj } from './shared.js';
2
+ const BUSCA_EVENTOS_URL = `${F22_BASE}/buscaEventos`;
3
+ const BUSCA_EVENTOS_NAMESPACE = 'cl.sii.sdi.lob.renta.consultaestadof22.data.api.interfaces.FacadeService/buscaEventos';
4
+ const EVENTO_ALIASES = {
5
+ folio: ['folio'],
6
+ // The event-type code is `codEvento`; the row ALSO carries an unrelated `codigo` (a long
7
+ // internal id), so `codEvento` MUST come first.
8
+ codigo: ['codEvento', 'codigo'],
9
+ glosa: ['nombre', 'glosa', 'descripcion'],
10
+ fecha: ['fechaEvento', 'fecha'],
11
+ tipo: ['tipoEvento', 'tipo'],
12
+ codCarta: ['codCarta'],
13
+ idCarta: ['idCarta'],
14
+ referencia: ['referencia'],
15
+ fechaCitacion: ['fechaCitacion'],
16
+ unidadSii: ['unidadSii'],
17
+ };
18
+ /** Sort key for an event's `fecha` (DD/MM/YYYY) → numeric YYYYMMDD for most-recent-first
19
+ * ordering. Undated / unparseable events sink to the bottom (−∞). Exported for the task,
20
+ * which sorts the aggregate across folios. */
21
+ export function eventoDateKey(fecha) {
22
+ if (fecha === null)
23
+ return Number.NEGATIVE_INFINITY;
24
+ const m = /^(\d{2})\/(\d{2})\/(\d{4})$/.exec(fecha.trim());
25
+ if (!m)
26
+ return Number.NEGATIVE_INFINITY;
27
+ return Number(`${m[3]}${m[2]}${m[1]}`);
28
+ }
29
+ /** `buscaEventos` — the historial/eventos timeline for ONE folio (the folio is REQUIRED;
30
+ * omitting it returns a RESTEASY 500). Rows carry NO identity/bank PII (event code + glosa
31
+ * + dates + carta refs), so all are curated, nothing excluded, no `raw`. Wire order is
32
+ * oldest-first; the task aggregates across folios and sorts most-recent-first. Empty/non-array
33
+ * data = sin eventos (NOT an error). All params sent as strings (like buscaDeclVgte). */
34
+ export async function fetchF22Historial(session, params) {
35
+ const { rut, anio, folio } = params;
36
+ const env = await postSdi(session, BUSCA_EVENTOS_URL, BUSCA_EVENTOS_NAMESPACE, {
37
+ periodo: anio.canonical,
38
+ ...rutDigits(rut),
39
+ folio,
40
+ });
41
+ const rows = env.data;
42
+ if (!Array.isArray(rows))
43
+ return [];
44
+ const out = [];
45
+ for (const r of rows) {
46
+ if (!isObj(r))
47
+ continue;
48
+ const codigo = asStr(aliasGet(r, EVENTO_ALIASES.codigo));
49
+ if (codigo === null)
50
+ continue;
51
+ out.push({
52
+ folio: asStr(aliasGet(r, EVENTO_ALIASES.folio)),
53
+ codigo,
54
+ glosa: asStr(aliasGet(r, EVENTO_ALIASES.glosa)), // verbatim (ADR-004) — may embed the monto
55
+ fecha: asStr(aliasGet(r, EVENTO_ALIASES.fecha)),
56
+ tipo: asStr(aliasGet(r, EVENTO_ALIASES.tipo)),
57
+ codCarta: asStr(aliasGet(r, EVENTO_ALIASES.codCarta)),
58
+ idCarta: asStr(aliasGet(r, EVENTO_ALIASES.idCarta)),
59
+ referencia: trimToNull(aliasGet(r, EVENTO_ALIASES.referencia)),
60
+ fechaCitacion: trimToNull(aliasGet(r, EVENTO_ALIASES.fechaCitacion)),
61
+ unidadSii: trimToNull(aliasGet(r, EVENTO_ALIASES.unidadSii)),
62
+ });
63
+ }
64
+ return out;
65
+ }
66
+ //# sourceMappingURL=historial.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"historial.js","sourceRoot":"","sources":["../../../src/portal/f22/historial.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ export { fetchF22Declaraciones, pickVigenteFolio, type DeclaracionF22, type F22Declaraciones, type F22Estado, } from './declaraciones.js';
2
+ export { fetchF22Grid } from './grid.js';
3
+ export { fetchF22Observaciones, type ObservacionF22 } from './observaciones.js';
4
+ export { eventoDateKey, fetchF22Historial, type EventoF22 } from './historial.js';
5
+ export { groupCodigos, isHeaderCodigo } from '../f22-codigos.js';
6
+ export type { CodigoF22, F22Grupos } from '../f22-codigos.js';
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/portal/f22/index.ts"],"names":[],"mappings":"AAGA,OAAO,EACL,qBAAqB,EACrB,gBAAgB,EAChB,KAAK,cAAc,EACnB,KAAK,gBAAgB,EACrB,KAAK,SAAS,GACf,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,EAAE,qBAAqB,EAAE,KAAK,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAChF,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,KAAK,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAGlF,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACjE,YAAY,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC"}
@@ -0,0 +1,11 @@
1
+ // The F22 facade, split per view (shared wire plumbing in shared.ts). This barrel
2
+ // preserves the public surface the tasks import — same names as the pre-split
3
+ // single-file facade.
4
+ export { fetchF22Declaraciones, pickVigenteFolio, } from './declaraciones.js';
5
+ export { fetchF22Grid } from './grid.js';
6
+ export { fetchF22Observaciones } from './observaciones.js';
7
+ export { eventoDateKey, fetchF22Historial } from './historial.js';
8
+ // The código taxonomy (PII denylist + contador grouping) — re-exported so the public
9
+ // surface is unchanged.
10
+ export { groupCodigos, isHeaderCodigo } from '../f22-codigos.js';
11
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/portal/f22/index.ts"],"names":[],"mappings":"AAAA,kFAAkF;AAClF,8EAA8E;AAC9E,sBAAsB;AACtB,OAAO,EACL,qBAAqB,EACrB,gBAAgB,GAIjB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,EAAE,qBAAqB,EAAuB,MAAM,oBAAoB,CAAC;AAChF,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAkB,MAAM,gBAAgB,CAAC;AAClF,qFAAqF;AACrF,wBAAwB;AACxB,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC"}
@@ -0,0 +1,20 @@
1
+ import type { Rut } from '../../rut/index.js';
2
+ import type { Anio } from '../../periodo/index.js';
3
+ import type { PortalSession } from '../../seams/index.js';
4
+ /** One observación (inconsistencia) on a declaración. NOT PII — observación code + glosa
5
+ * + the SII ayuda URL — so every field is curated (no header-código exclusion, no `raw`). */
6
+ export interface ObservacionF22 {
7
+ readonly codigo: string;
8
+ readonly descripcion: string | null;
9
+ readonly url: string | null;
10
+ }
11
+ /** `situacionObservacion` — the observaciones (inconsistencias) for a folio. Rows carry
12
+ * NO PII (observación code + glosa + ayuda URL), so all are curated and nothing is
13
+ * excluded; empty `data` = sin observaciones (NOT an error). Observed 2026-06-29 (#26):
14
+ * the request sends NUMERIC `periodo`/`folio`. */
15
+ export declare function fetchF22Observaciones(session: PortalSession, params: {
16
+ rut: Rut;
17
+ anio: Anio;
18
+ folio: string;
19
+ }): Promise<ObservacionF22[]>;
20
+ //# sourceMappingURL=observaciones.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"observaciones.d.ts","sourceRoot":"","sources":["../../../src/portal/f22/observaciones.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,wBAAwB,CAAC;AACnD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAO1D;8FAC8F;AAC9F,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B;AAQD;;;mDAGmD;AACnD,wBAAsB,qBAAqB,CACzC,OAAO,EAAE,aAAa,EACtB,MAAM,EAAE;IAAE,GAAG,EAAE,GAAG,CAAC;IAAC,IAAI,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAC9C,OAAO,CAAC,cAAc,EAAE,CAAC,CAqB3B"}
@@ -0,0 +1,38 @@
1
+ import { F22_BASE, aliasGet, asStr, isObj, postSdi, rutDigits } from './shared.js';
2
+ const SITUACION_OBS_URL = `${F22_BASE}/situacionObservacion`;
3
+ const SITUACION_OBS_NAMESPACE = 'cl.sii.sdi.lob.renta.consultaestadof22.data.api.interfaces.FacadeService/situacionObservacion';
4
+ const OBSERVACION_ALIASES = {
5
+ codigo: ['codigo', 'cod'],
6
+ descripcion: ['descripcion', 'glosa'],
7
+ url: ['url', 'link'],
8
+ };
9
+ /** `situacionObservacion` — the observaciones (inconsistencias) for a folio. Rows carry
10
+ * NO PII (observación code + glosa + ayuda URL), so all are curated and nothing is
11
+ * excluded; empty `data` = sin observaciones (NOT an error). Observed 2026-06-29 (#26):
12
+ * the request sends NUMERIC `periodo`/`folio`. */
13
+ export async function fetchF22Observaciones(session, params) {
14
+ const { rut, anio, folio } = params;
15
+ const env = await postSdi(session, SITUACION_OBS_URL, SITUACION_OBS_NAMESPACE, {
16
+ periodo: Number(anio.canonical),
17
+ ...rutDigits(rut),
18
+ folio: Number(folio),
19
+ });
20
+ const rows = env.data;
21
+ if (!Array.isArray(rows))
22
+ return [];
23
+ const out = [];
24
+ for (const r of rows) {
25
+ if (!isObj(r))
26
+ continue;
27
+ const codigo = asStr(aliasGet(r, OBSERVACION_ALIASES.codigo));
28
+ if (codigo === null)
29
+ continue;
30
+ out.push({
31
+ codigo,
32
+ descripcion: asStr(aliasGet(r, OBSERVACION_ALIASES.descripcion)),
33
+ url: asStr(aliasGet(r, OBSERVACION_ALIASES.url)),
34
+ });
35
+ }
36
+ return out;
37
+ }
38
+ //# sourceMappingURL=observaciones.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"observaciones.js","sourceRoot":"","sources":["../../../src/portal/f22/observaciones.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAEnF,MAAM,iBAAiB,GAAG,GAAG,QAAQ,uBAAuB,CAAC;AAC7D,MAAM,uBAAuB,GAC3B,+FAA+F,CAAC;AAUlG,MAAM,mBAAmB,GAAG;IAC1B,MAAM,EAAE,CAAC,QAAQ,EAAE,KAAK,CAAC;IACzB,WAAW,EAAE,CAAC,aAAa,EAAE,OAAO,CAAC;IACrC,GAAG,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC;CACZ,CAAC;AAEX;;;mDAGmD;AACnD,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,OAAsB,EACtB,MAA+C;IAE/C,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM,CAAC;IACpC,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,OAAO,EAAE,iBAAiB,EAAE,uBAAuB,EAAE;QAC7E,OAAO,EAAE,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC;QAC/B,GAAG,SAAS,CAAC,GAAG,CAAC;QACjB,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC;KACrB,CAAC,CAAC;IACH,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,CAAC;IACtB,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC;QAAE,OAAO,EAAE,CAAC;IACpC,MAAM,GAAG,GAAqB,EAAE,CAAC;IACjC,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;QACrB,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;YAAE,SAAS;QACxB,MAAM,MAAM,GAAG,KAAK,CAAC,QAAQ,CAAC,CAAC,EAAE,mBAAmB,CAAC,MAAM,CAAC,CAAC,CAAC;QAC9D,IAAI,MAAM,KAAK,IAAI;YAAE,SAAS;QAC9B,GAAG,CAAC,IAAI,CAAC;YACP,MAAM;YACN,WAAW,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC,EAAE,mBAAmB,CAAC,WAAW,CAAC,CAAC;YAChE,GAAG,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC,EAAE,mBAAmB,CAAC,GAAG,CAAC,CAAC;SACjD,CAAC,CAAC;IACL,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}