@utilia-os/sdk-js 1.10.0 → 2.1.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/README.md CHANGED
@@ -208,6 +208,116 @@ legacy (emailSupport, emailHr, etc.) no se exponen en esta respuesta; los
208
208
  emails legacy se transforman automáticamente a `contactChannels` por
209
209
  retrocompatibilidad.
210
210
 
211
+ > **Breaking change en v2.0.0**: se ha eliminado el campo `businessActivity`
212
+ > de `OrganizationPublicSettings`. La actividad económica ya no forma parte
213
+ > de la configuración general de la organización; se ha migrado al modelo
214
+ > `FiscalConfig.activityDesc`, disponible vía el endpoint
215
+ > `finance/fiscal-config` (se añadirá un método dedicado al SDK en próximas
216
+ > versiones). Si tu integración leía `settings.businessActivity`, debes
217
+ > migrar a la nueva ubicación.
218
+
219
+ ## Comentarios y firmas de presupuestos
220
+
221
+ Desde la versión 2.1.0, el SDK cubre los dos dominios centrales del flujo de
222
+ aprobación de presupuestos: la conversación entre equipo y cliente y la firma
223
+ electrónica con magic link.
224
+
225
+ ### Comentarios (`sdk.budgetComments`)
226
+
227
+ Dos visibilidades: `INTERNAL` (solo equipo) y `CLIENT` (visible también en el
228
+ portal del cliente). Las menciones con `mentionedUserIds` solo tienen efecto
229
+ cuando la visibilidad es `INTERNAL`.
230
+
231
+ ```typescript
232
+ import { UtiliaSDK } from '@utilia-os/sdk-js';
233
+
234
+ const sdk = new UtiliaSDK({ baseURL: 'https://os.utilia.ai/api', apiKey: '...' });
235
+
236
+ // Listar comentarios dirigidos al cliente
237
+ const page = await sdk.budgetComments.list(budgetId, {
238
+ visibility: 'CLIENT',
239
+ page: 1,
240
+ limit: 20,
241
+ });
242
+
243
+ // Crear un comentario interno con menciones
244
+ const comment = await sdk.budgetComments.create(budgetId, {
245
+ body: 'Revisar el descuento del item 2 antes de enviar al cliente.',
246
+ visibility: 'INTERNAL',
247
+ mentionedUserIds: ['6d1a4c6b-3f8b-4a0e-a0d1-b29f1f1c21cb'],
248
+ });
249
+
250
+ // Editar el propio comentario
251
+ await sdk.budgetComments.update(budgetId, comment.id, {
252
+ body: 'Revisar descuento y condiciones de pago.',
253
+ });
254
+
255
+ // Crear varios comentarios en lote, tolerante a fallos
256
+ const result = await sdk.budgetComments.bulkCreate(
257
+ budgetId,
258
+ [
259
+ { body: 'Primer comentario' },
260
+ { body: 'Segundo comentario', clientOperationId: 'op-2' },
261
+ ],
262
+ { idempotencyKey: 'migration-2026-04-17' },
263
+ );
264
+ console.log(result.summary); // { total: 2, ok: 2, failed: 0 }
265
+ ```
266
+
267
+ ### Firmas y magic link (`sdk.budgetSignatures`)
268
+
269
+ El flujo completo cubre la emisión del magic link, el listado y revocación, la
270
+ verificación de integridad de una firma ya registrada y la descarga del
271
+ certificado legal.
272
+
273
+ ```typescript
274
+ // Emitir un magic link (idempotente por email)
275
+ const link = await sdk.budgetSignatures.generateSigningLink(budgetId, {
276
+ signerEmail: 'cliente@empresa.com',
277
+ signerName: 'María García',
278
+ expiresInHours: 72,
279
+ sendEmail: true,
280
+ });
281
+
282
+ if (!link.reused && link.signingUrl) {
283
+ console.log('Enviar al cliente:', link.signingUrl);
284
+ }
285
+
286
+ // Listar los magic links vivos
287
+ const activeLinks = await sdk.budgetSignatures.listSigningLinks(budgetId);
288
+
289
+ // Revocar un link
290
+ await sdk.budgetSignatures.revokeSigningLink(budgetId, link.tokenId);
291
+
292
+ // Verificar la integridad de una firma ya registrada
293
+ const signatures = await sdk.budgetSignatures.list(budgetId);
294
+ const verification = await sdk.budgetSignatures.verify(
295
+ budgetId,
296
+ signatures[0].id,
297
+ );
298
+ if (!verification.valid) {
299
+ console.warn('El documento ha cambiado después de la firma.');
300
+ }
301
+
302
+ // Descargar el certificado legal
303
+ const pdf = await sdk.budgetSignatures.downloadCertificate(
304
+ budgetId,
305
+ signatures[0].id,
306
+ );
307
+ ```
308
+
309
+ ### Audit trail
310
+
311
+ Historial paginado de eventos del proceso de firma (emisión, visualización,
312
+ descarga del PDF, aprobación, rechazo, expiración, revocación y fallos):
313
+
314
+ ```typescript
315
+ const events = await sdk.budgetSignatures.getAuditTrail(budgetId, {
316
+ tokenId: link.tokenId,
317
+ limit: 100,
318
+ });
319
+ ```
320
+
211
321
  ## OAuth y Sign In
212
322
 
213
323
  Desde la versión 1.6.0, el SDK incluye soporte nativo para OAuth 2.1 con PKCE. Esto permite implementar "Iniciar sesión con UTILIA" en tu aplicación:
package/dist/index.d.mts CHANGED
@@ -1337,6 +1337,284 @@ interface ApplyTemplateInput {
1337
1337
  title?: string;
1338
1338
  }
1339
1339
 
1340
+ /**
1341
+ * Tipos del servicio de comentarios de presupuesto.
1342
+ *
1343
+ * Los comentarios soportan dos visibilidades:
1344
+ * - `INTERNAL`: solo visible para el equipo.
1345
+ * - `CLIENT`: visible también en el portal del cliente.
1346
+ *
1347
+ * Un comentario puede provenir de un usuario interno (`authorKind = 'INTERNAL'`)
1348
+ * o de un usuario del portal cliente (`authorKind = 'PORTAL'`). La autoría es
1349
+ * exclusiva: exactamente uno de `authorId` / `portalAuthorId` está presente.
1350
+ */
1351
+ /** Visibilidades admitidas para un comentario. */
1352
+ type BudgetCommentVisibility = 'INTERNAL' | 'CLIENT';
1353
+ /** Origen de la autoría del comentario. */
1354
+ type BudgetCommentAuthorKind = 'INTERNAL' | 'PORTAL';
1355
+ /** Datos del autor interno cuando el comentario lo escribe un usuario del equipo. */
1356
+ interface BudgetCommentAuthor {
1357
+ id: string;
1358
+ firstName?: string | null;
1359
+ lastName?: string | null;
1360
+ avatar?: string | null;
1361
+ }
1362
+ /** Datos del autor desde el portal cliente. */
1363
+ interface BudgetCommentPortalAuthor {
1364
+ id: string;
1365
+ firstName?: string | null;
1366
+ lastName?: string | null;
1367
+ avatarUrl?: string | null;
1368
+ }
1369
+ /**
1370
+ * Comentario de presupuesto. El `body` puede venir como string plano o como
1371
+ * objeto con versión Markdown y plain text (según cómo lo serialice el
1372
+ * backend).
1373
+ */
1374
+ interface BudgetComment {
1375
+ id: string;
1376
+ budgetId: string;
1377
+ authorId?: string | null;
1378
+ author?: BudgetCommentAuthor | null;
1379
+ portalAuthorId?: string | null;
1380
+ portalAuthor?: BudgetCommentPortalAuthor | null;
1381
+ authorKind?: BudgetCommentAuthorKind;
1382
+ visibility: BudgetCommentVisibility;
1383
+ body: string | {
1384
+ markdown: string;
1385
+ plainText: string;
1386
+ };
1387
+ mentionedUserIds?: string[];
1388
+ createdAt: string;
1389
+ editedAt?: string | null;
1390
+ updatedAt?: string;
1391
+ }
1392
+ /**
1393
+ * Entrada para crear un comentario.
1394
+ *
1395
+ * Si se envía `clientOperationId`, el backend puede deduplicar la operación
1396
+ * en batch (ver `bulkCreate`).
1397
+ */
1398
+ interface CreateBudgetCommentInput {
1399
+ body: string;
1400
+ visibility?: BudgetCommentVisibility;
1401
+ mentionedUserIds?: string[];
1402
+ clientOperationId?: string;
1403
+ }
1404
+ /** Entrada para editar un comentario existente. */
1405
+ interface UpdateBudgetCommentInput {
1406
+ body: string;
1407
+ }
1408
+ /**
1409
+ * Filtros para listar comentarios. `ALL` es azúcar local del SDK: se mapea a
1410
+ * "sin filtro de visibilidad" en el query.
1411
+ */
1412
+ interface ListBudgetCommentsFilter {
1413
+ visibility?: BudgetCommentVisibility | 'ALL';
1414
+ authorId?: string;
1415
+ mentionedUserId?: string;
1416
+ cursor?: string;
1417
+ limit?: number;
1418
+ since?: string;
1419
+ until?: string;
1420
+ /** Número de página (1-indexado) cuando el endpoint usa paginación offset. */
1421
+ page?: number;
1422
+ }
1423
+ /**
1424
+ * Información de paginación del listado de comentarios.
1425
+ *
1426
+ * El backend actual devuelve paginación offset (`page`, `limit`, `total`,
1427
+ * `totalPages`). Se conservan también los campos por cursor para compatibilidad
1428
+ * futura si el servicio migrara a paginación por cursor.
1429
+ */
1430
+ interface BudgetCommentPageInfo {
1431
+ page?: number;
1432
+ limit?: number;
1433
+ total?: number;
1434
+ totalPages?: number;
1435
+ nextCursor?: string | null;
1436
+ hasMore?: boolean;
1437
+ pageSize?: number;
1438
+ }
1439
+ /** Respuesta paginada del listado de comentarios. */
1440
+ interface BudgetCommentListResponse {
1441
+ data: BudgetComment[];
1442
+ pageInfo: BudgetCommentPageInfo;
1443
+ }
1444
+ /** Detalle de un fallo individual en una operación batch. */
1445
+ interface BudgetCommentBulkFailure {
1446
+ index: number;
1447
+ clientOperationId?: string;
1448
+ code: string;
1449
+ message: string;
1450
+ }
1451
+ /** Resultado de `bulkCreate` en modo saga (tolerante a fallos parciales). */
1452
+ interface BudgetCommentBulkResult {
1453
+ succeeded: BudgetComment[];
1454
+ failed: BudgetCommentBulkFailure[];
1455
+ summary: {
1456
+ total: number;
1457
+ ok: number;
1458
+ failed: number;
1459
+ };
1460
+ }
1461
+ /** Elemento del timeline: comentario o evento de historial. */
1462
+ type BudgetTimelineItem = {
1463
+ kind: 'COMMENT';
1464
+ at: string;
1465
+ comment: BudgetComment;
1466
+ } | {
1467
+ kind: 'EVENT';
1468
+ at: string;
1469
+ event: Record<string, unknown>;
1470
+ };
1471
+ /** Filtros para `getTimeline`. */
1472
+ interface BudgetTimelineFilter {
1473
+ cursor?: string;
1474
+ limit?: number;
1475
+ since?: string;
1476
+ until?: string;
1477
+ }
1478
+ /** Respuesta del timeline unificado. */
1479
+ interface BudgetTimelineResponse {
1480
+ items: BudgetTimelineItem[];
1481
+ pageInfo: {
1482
+ nextCursor?: string | null;
1483
+ hasMore: boolean;
1484
+ pageSize?: number;
1485
+ };
1486
+ }
1487
+
1488
+ /**
1489
+ * Tipos del servicio de firmas electrónicas de presupuesto.
1490
+ *
1491
+ * El flujo de firma usa magic links (tokens de un solo uso, SHA-256 en BD,
1492
+ * snapshot del hash del documento al emitir). Un token vivo evoluciona por los
1493
+ * estados ACTIVE → CONSUMED | REVOKED | EXPIRED.
1494
+ */
1495
+ /**
1496
+ * Estado agregado del proceso de firma para un presupuesto.
1497
+ * Pensado para representar el estado en la UI, no un enum de la BD.
1498
+ */
1499
+ type SignatureStatus = 'NOT_SENT' | 'PENDING_SIGNATURE' | 'SIGNED' | 'REJECTED' | 'EXPIRED';
1500
+ /** Estado de un magic link concreto. */
1501
+ type SigningLinkStatus = 'ACTIVE' | 'CONSUMED' | 'REVOKED' | 'EXPIRED';
1502
+ /**
1503
+ * Firma electrónica registrada. `hashVersion` indica qué algoritmo de
1504
+ * serialización canónica se usó (1 = legado, 2 = extendido con descuentos,
1505
+ * impuestos, secciones, notas, términos).
1506
+ */
1507
+ interface BudgetSignature {
1508
+ id: string;
1509
+ budgetId: string;
1510
+ budgetApprovalId?: string;
1511
+ signerName: string;
1512
+ signerEmail: string;
1513
+ signedAt: string;
1514
+ documentHash: string;
1515
+ hashVersion: number;
1516
+ /**
1517
+ * IP del firmante enmascarada (por ejemplo `***.***.x.xx`). Nunca se
1518
+ * devuelve la IP en claro por el endpoint público.
1519
+ */
1520
+ ipAddressMasked?: string | null;
1521
+ userAgent?: string | null;
1522
+ signatureFileId?: string;
1523
+ signingTokenId?: string | null;
1524
+ }
1525
+ /**
1526
+ * Resultado de verificar la integridad de una firma. Si `valid === false`,
1527
+ * el documento ha cambiado después de la firma y la UI debe avisar al usuario.
1528
+ */
1529
+ interface BudgetSignatureVerification {
1530
+ valid: boolean;
1531
+ expectedHash: string;
1532
+ actualHash: string;
1533
+ hashVersion: number;
1534
+ signedAt: string;
1535
+ signerName: string;
1536
+ signerEmail: string;
1537
+ ipAddressMasked?: string | null;
1538
+ userAgent?: string | null;
1539
+ signingTokenId?: string | null;
1540
+ }
1541
+ /** Entrada para generar un magic link de firma. */
1542
+ interface SigningLinkRequest {
1543
+ signerEmail: string;
1544
+ signerName?: string;
1545
+ /** Rango admitido: 1 a 168 horas (7 días). Por defecto 72 h. */
1546
+ expiresInHours?: number;
1547
+ /** Si es `true`, el backend envía el correo con el enlace al firmante. */
1548
+ sendEmail?: boolean;
1549
+ }
1550
+ /**
1551
+ * Respuesta de `generateSigningLink`. `signingUrl` puede ser `null` cuando se
1552
+ * reutiliza un token vivo existente (idempotencia por email) ya que el raw
1553
+ * token original no es recuperable.
1554
+ */
1555
+ interface SigningLinkResponse {
1556
+ tokenId: string;
1557
+ signingUrl: string | null;
1558
+ expiresAt: string;
1559
+ /** `true` si el backend devolvió un token preexistente sin crear uno nuevo. */
1560
+ reused?: boolean;
1561
+ }
1562
+ /** Proyección segura de un token activo devuelta al listar. */
1563
+ interface SigningLinkSummary {
1564
+ tokenId: string;
1565
+ status?: SigningLinkStatus;
1566
+ signerEmail: string;
1567
+ signerName?: string | null;
1568
+ createdAt: string;
1569
+ expiresAt: string;
1570
+ consumedAt?: string | null;
1571
+ revokedAt?: string | null;
1572
+ sentTo?: string | null;
1573
+ createdBy?: {
1574
+ id: string;
1575
+ firstName?: string | null;
1576
+ lastName?: string | null;
1577
+ } | null;
1578
+ }
1579
+ /** Filtros para `listSigningLinks`. */
1580
+ interface ListSigningLinksFilter {
1581
+ includeRevoked?: boolean;
1582
+ includeExpired?: boolean;
1583
+ cursor?: string;
1584
+ limit?: number;
1585
+ }
1586
+ /** Respuesta al revocar un magic link. */
1587
+ interface RevokeSigningLinkResponse {
1588
+ tokenId: string;
1589
+ revokedAt: string;
1590
+ /** `true` si el token ya había sido revocado previamente. */
1591
+ alreadyRevoked?: boolean;
1592
+ }
1593
+ /** Tipos de eventos registrados en el audit trail legal. */
1594
+ type SignerAuditEventKind = 'ISSUED' | 'VIEWED' | 'PDF_DOWNLOADED' | 'APPROVED' | 'REJECTED' | 'EXPIRED' | 'REVOKED' | 'FAILED';
1595
+ /** Evento individual del audit trail. */
1596
+ interface SignerAuditEvent {
1597
+ id: string;
1598
+ event: SignerAuditEventKind;
1599
+ at: string;
1600
+ tokenId?: string | null;
1601
+ actorUserId?: string | null;
1602
+ ipAddress?: string | null;
1603
+ userAgent?: string | null;
1604
+ meta?: Record<string, unknown> | null;
1605
+ }
1606
+ /** Filtros para `getAuditTrail`. */
1607
+ interface AuditTrailFilter {
1608
+ tokenId?: string;
1609
+ cursor?: string;
1610
+ limit?: number;
1611
+ }
1612
+ /** Respuesta paginada del audit trail. */
1613
+ interface AuditTrailResponse {
1614
+ items: SignerAuditEvent[];
1615
+ nextCursor?: string | null;
1616
+ }
1617
+
1340
1618
  /**
1341
1619
  * Tipos relacionados con la configuración de la organización.
1342
1620
  *
@@ -1372,7 +1650,6 @@ interface OrganizationPublicSettings {
1372
1650
  taxRegime: string | null;
1373
1651
  companyRegistryNumber: string | null;
1374
1652
  legalRepresentative: string | null;
1375
- businessActivity: string | null;
1376
1653
  legalAddressStreet: string | null;
1377
1654
  legalAddressCity: string | null;
1378
1655
  legalAddressPostalCode: string | null;
@@ -2378,6 +2655,149 @@ declare class BudgetTemplatesService {
2378
2655
  applyTemplate(templateId: string, data: ApplyTemplateInput): Promise<Budget>;
2379
2656
  }
2380
2657
 
2658
+ /**
2659
+ * Servicio de comentarios de presupuesto.
2660
+ *
2661
+ * Cubre el CRUD completo, la creación masiva tolerante a fallos y el timeline
2662
+ * unificado (comentarios + eventos del historial). La capa de permisos es
2663
+ * responsabilidad del backend: el SDK se limita a enviar la petición con la
2664
+ * visibilidad solicitada.
2665
+ */
2666
+
2667
+ declare class BudgetCommentsService {
2668
+ private readonly client;
2669
+ private readonly basePath;
2670
+ constructor(client: UtiliaClient);
2671
+ /**
2672
+ * Listar comentarios del presupuesto.
2673
+ *
2674
+ * @param budgetId - UUID del presupuesto.
2675
+ * @param filter - Filtros de visibilidad, paginación y rango de fechas.
2676
+ *
2677
+ * @example
2678
+ * ```typescript
2679
+ * const page = await sdk.budgetComments.list(budgetId, { visibility: 'CLIENT', page: 1, limit: 20 });
2680
+ * page.data.forEach(c => console.log(c.body));
2681
+ * ```
2682
+ */
2683
+ list(budgetId: string, filter?: ListBudgetCommentsFilter): Promise<BudgetCommentListResponse>;
2684
+ /**
2685
+ * Obtener un comentario por su ID.
2686
+ *
2687
+ * Nota: el backend actual no expone `GET /comments/:commentId` a nivel de
2688
+ * REST. El SDK lo emula filtrando localmente el resultado del listado. Si
2689
+ * en el futuro se añade un endpoint dedicado, este método se puede migrar
2690
+ * sin romper la firma.
2691
+ */
2692
+ get(budgetId: string, commentId: string): Promise<BudgetComment>;
2693
+ /**
2694
+ * Crear un comentario en el presupuesto.
2695
+ *
2696
+ * La visibilidad (INTERNAL / CLIENT) debe ser compatible con los permisos
2697
+ * del usuario autenticado. Las menciones solo tienen efecto en comentarios
2698
+ * internos.
2699
+ */
2700
+ create(budgetId: string, input: CreateBudgetCommentInput): Promise<BudgetComment>;
2701
+ /** Actualizar el cuerpo de un comentario. Solo autor o SUPER_ADMIN. */
2702
+ update(budgetId: string, commentId: string, input: UpdateBudgetCommentInput): Promise<BudgetComment>;
2703
+ /** Eliminar un comentario. Solo autor o SUPER_ADMIN. */
2704
+ remove(budgetId: string, commentId: string): Promise<{
2705
+ message: string;
2706
+ }>;
2707
+ /**
2708
+ * Creación masiva tolerante a fallos (saga).
2709
+ *
2710
+ * Nota: a día de hoy, el backend expone el bulk únicamente a través de la
2711
+ * herramienta MCP `crm_budget_comments.bulk_create`. Para consumirlo desde
2712
+ * REST, el SDK llama secuencialmente a `create` y agrega el resultado,
2713
+ * respetando el contrato del método. Sustituir cuando exista un endpoint
2714
+ * REST dedicado.
2715
+ */
2716
+ bulkCreate(budgetId: string, items: CreateBudgetCommentInput[], options?: {
2717
+ idempotencyKey?: string;
2718
+ }): Promise<BudgetCommentBulkResult>;
2719
+ /**
2720
+ * Devuelve el timeline unificado: comentarios + eventos de historial del
2721
+ * presupuesto ordenados cronológicamente descendente.
2722
+ *
2723
+ * Nota: el backend expone esta vista agregada a través de la herramienta MCP
2724
+ * `crm_budget_comments.get_timeline`. Hasta que se habilite un endpoint REST
2725
+ * dedicado, el SDK devuelve los comentarios paginados y un `items` sólo con
2726
+ * kind `COMMENT`. Se marca como follow-up.
2727
+ */
2728
+ getTimeline(budgetId: string, filter?: BudgetTimelineFilter): Promise<BudgetTimelineResponse>;
2729
+ private serializeListFilter;
2730
+ private serializeTimelineFilter;
2731
+ private normalizeBulkResult;
2732
+ private mapErrorCode;
2733
+ }
2734
+
2735
+ /**
2736
+ * Servicio de firmas electrónicas de presupuesto.
2737
+ *
2738
+ * Gestiona:
2739
+ * - Magic links de firma (generar, listar, revocar).
2740
+ * - Consulta y verificación de firmas registradas.
2741
+ * - Descarga del certificado legal en PDF.
2742
+ * - Audit trail de eventos.
2743
+ *
2744
+ * El SDK no consume el flujo público del firmante (`/public/budgets/sign/:token`),
2745
+ * ya que ese flujo no usa autenticación y se accede desde el frontend público
2746
+ * `/sign/[token]`.
2747
+ */
2748
+
2749
+ declare class BudgetSignaturesService {
2750
+ private readonly client;
2751
+ private readonly basePath;
2752
+ constructor(client: UtiliaClient);
2753
+ /** Listar todas las firmas asociadas al presupuesto. */
2754
+ list(budgetId: string): Promise<BudgetSignature[]>;
2755
+ /** Obtener el detalle de una firma concreta. */
2756
+ get(budgetId: string, signatureId: string): Promise<BudgetSignature>;
2757
+ /**
2758
+ * Verificar la integridad de una firma. Recalcula el hash del documento con
2759
+ * la versión (`hashVersion`) con la que se firmó originalmente y lo compara.
2760
+ *
2761
+ * Si `valid === false`, el documento ha sido modificado después de firmar.
2762
+ */
2763
+ verify(budgetId: string, signatureId: string): Promise<BudgetSignatureVerification>;
2764
+ /**
2765
+ * Descargar el certificado legal de una firma como Blob.
2766
+ *
2767
+ * Ideal para consumidores que necesiten guardar el PDF localmente o abrirlo
2768
+ * con `URL.createObjectURL`.
2769
+ */
2770
+ downloadCertificate(budgetId: string, signatureId: string): Promise<Blob>;
2771
+ /**
2772
+ * Construir la URL del certificado (útil para `<iframe>` o enlaces directos).
2773
+ * Incluye las credenciales en query string cuando el SDK usa API key.
2774
+ */
2775
+ getCertificateUrl(budgetId: string, signatureId: string): string;
2776
+ /**
2777
+ * Generar un magic link de firma. El endpoint es idempotente para la tupla
2778
+ * (budgetId, signerEmail): si ya existe un token vivo se devuelve con
2779
+ * `reused: true` y `signingUrl: null` (el raw token original no se
2780
+ * recupera).
2781
+ */
2782
+ generateSigningLink(budgetId: string, input: SigningLinkRequest): Promise<SigningLinkResponse>;
2783
+ /**
2784
+ * Listar los magic links vivos del presupuesto (no usados, no revocados y no
2785
+ * expirados). Los filtros `includeRevoked`/`includeExpired` se reservan para
2786
+ * cuando el backend exponga la vista extendida.
2787
+ */
2788
+ listSigningLinks(budgetId: string, filter?: ListSigningLinksFilter): Promise<SigningLinkSummary[]>;
2789
+ /** Revocar un magic link. Idempotente: llamarla dos veces no falla. */
2790
+ revokeSigningLink(budgetId: string, tokenId: string): Promise<RevokeSigningLinkResponse>;
2791
+ /**
2792
+ * Audit trail paginado por cursor de los eventos de firma del presupuesto
2793
+ * (emisión, visualización, descarga de PDF, aprobación, rechazo,
2794
+ * expiración, revocación, fallos).
2795
+ */
2796
+ getAuditTrail(budgetId: string, filter?: AuditTrailFilter): Promise<SignerAuditEvent[]>;
2797
+ private serializeSigningLinksFilter;
2798
+ private serializeAuditFilter;
2799
+ }
2800
+
2381
2801
  /**
2382
2802
  * Servicio de configuración de organización.
2383
2803
  *
@@ -2597,6 +3017,8 @@ declare const SDK_LIMITS: {
2597
3017
  * - `ai`: Funcionalidades de IA (transcripción, sugerencias)
2598
3018
  * - `budgets`: Presupuestos CRM (CRUD, items, secciones, flujo, IA, PDF)
2599
3019
  * - `budgetTemplates`: Plantillas de presupuesto reutilizables
3020
+ * - `budgetComments`: Comentarios internos y dirigidos al cliente de presupuestos
3021
+ * - `budgetSignatures`: Firma electrónica con magic link, verificación y certificado
2600
3022
  * - `organizationSettings`: Datos públicos de la organización (branding, fiscal, contacto)
2601
3023
  */
2602
3024
  declare class UtiliaSDK {
@@ -2615,6 +3037,10 @@ declare class UtiliaSDK {
2615
3037
  readonly budgets: BudgetsService;
2616
3038
  /** Servicio de plantillas de presupuesto CRM */
2617
3039
  readonly budgetTemplates: BudgetTemplatesService;
3040
+ /** Servicio de comentarios de presupuesto (INTERNAL / CLIENT) */
3041
+ readonly budgetComments: BudgetCommentsService;
3042
+ /** Servicio de firmas electrónicas y magic links de presupuesto */
3043
+ readonly budgetSignatures: BudgetSignaturesService;
2618
3044
  /** Servicio de configuración pública de la organización */
2619
3045
  readonly organizationSettings: OrganizationSettingsService;
2620
3046
  /**
@@ -2654,4 +3080,4 @@ declare class UtiliaSDK {
2654
3080
  get oauth(): OAuthService;
2655
3081
  }
2656
3082
 
2657
- export { type AddMessageInput, type AiGeneratedItem, type AiGeneratedSection, type AiJobStatus, type AiSuggestInput, type AiSuggestions, type AiUserAction, type ApplyTemplateInput, type ApproveBudgetInput, type ApproverType, type AuthorizedApp, BUDGET_WEBHOOK_EVENTS, type Budget, type BudgetApproval, type BudgetAttachment, type BudgetClientRef, type BudgetExportFormat, type BudgetFilters, type BudgetHistoryEntry, type BudgetItem, type BudgetItemOrder, type BudgetItemType, type BudgetListItem, type BudgetListResponse, type BudgetOpportunityRef, type BudgetPdfUrlResponse, type BudgetProjectRef, type BudgetSection, type BudgetSectionPosition, type BudgetSectionType, type BudgetStatus, type BudgetTemplate, type BudgetTemplateItemJson, type BudgetTemplateSectionJson, type BudgetUserRef, type BudgetWebhookEvent, type BulkBudgetInput, type BulkBudgetOperation, type BulkBudgetOptions, type BulkBudgetResult, type BulkBudgetResultItem, type ChangeStatusInput, type CheckCodeResponse, type ConvertToInvoiceInput, type ConvertToProjectInput, type CreateBudgetInput, type CreateBudgetItemInput, type CreateBudgetSectionInput, type CreateBudgetTemplateInput, type CreateTemplateFromBudgetInput, type CreateTicketInput, type CreateTicketUser, type CreatedMessage, type CreatedTicket, type DuplicateBudgetInput, ErrorCode, type ErrorFilters, type ErrorHttpMethod, type ErrorSeverity, type ErrorStats, type ExternalUser, type FileQuota, FileTokenStorage, type GenerateCompleteAiResult, type GenerateItemsAiInput, type GenerateItemsAiJob, type GenerateSectionsAiResult, type GetSuggestionsOptions, type IdentifyUserInput, type IntrospectResponse, type LoginUrlResult, MemoryTokenStorage, type MessageAuthor, type NextCodeResponse, type OAuthConfig, OAuthService, type OAuthTokens, type OAuthUserInfo, type OidcAuthorizationOptions, type OrganizationContactChannel, type OrganizationPublicSettings, type PKCEChallenge, type PaginatedResponse, type PaginationMeta, type PaymentMethod, type PendingOAuthState, type PopupLoginOptions, type RejectBudgetInput, type ReorderItemsInput, type ReorderSectionsInput, type ReportErrorInput, type ReportedError, type RequestConfig, SDK_LIMITS, type SendBudgetInput, type SortOrder, type SseEvent, type StreamSuggestionsHandle, type StreamSuggestionsOptions, type StreamTranscriptionOptions, type SystemError, type TicketAttachment, type TicketCategory, type TicketContext, type TicketDetail, type TicketFilters, type TicketListItem, type TicketMessage, type TicketPriority, type TicketReporter, type TicketStatus, type TokenStorage, type TrackAiActionInput, type TranscriptionJobStatus, type UnreadCount, type UpdateBudgetInput, type UpdateBudgetItemInput, type UpdateBudgetSectionInput, type UpdateBudgetTemplateInput, type UploadFileOptions, type UploadedBudgetImage, type UploadedFile, UtiliaSDK, type UtiliaSDKConfig, UtiliaSDKError, base64UrlEncode, generateCodeChallenge, generateCodeVerifier };
3083
+ export { type AddMessageInput, type AiGeneratedItem, type AiGeneratedSection, type AiJobStatus, type AiSuggestInput, type AiSuggestions, type AiUserAction, type ApplyTemplateInput, type ApproveBudgetInput, type ApproverType, type AuditTrailFilter, type AuditTrailResponse, type AuthorizedApp, BUDGET_WEBHOOK_EVENTS, type Budget, type BudgetApproval, type BudgetAttachment, type BudgetClientRef, type BudgetComment, type BudgetCommentAuthor, type BudgetCommentAuthorKind, type BudgetCommentBulkFailure, type BudgetCommentBulkResult, type BudgetCommentListResponse, type BudgetCommentPageInfo, type BudgetCommentPortalAuthor, type BudgetCommentVisibility, type BudgetExportFormat, type BudgetFilters, type BudgetHistoryEntry, type BudgetItem, type BudgetItemOrder, type BudgetItemType, type BudgetListItem, type BudgetListResponse, type BudgetOpportunityRef, type BudgetPdfUrlResponse, type BudgetProjectRef, type BudgetSection, type BudgetSectionPosition, type BudgetSectionType, type BudgetSignature, type BudgetSignatureVerification, type BudgetStatus, type BudgetTemplate, type BudgetTemplateItemJson, type BudgetTemplateSectionJson, type BudgetTimelineFilter, type BudgetTimelineItem, type BudgetTimelineResponse, type BudgetUserRef, type BudgetWebhookEvent, type BulkBudgetInput, type BulkBudgetOperation, type BulkBudgetOptions, type BulkBudgetResult, type BulkBudgetResultItem, type ChangeStatusInput, type CheckCodeResponse, type ConvertToInvoiceInput, type ConvertToProjectInput, type CreateBudgetCommentInput, type CreateBudgetInput, type CreateBudgetItemInput, type CreateBudgetSectionInput, type CreateBudgetTemplateInput, type CreateTemplateFromBudgetInput, type CreateTicketInput, type CreateTicketUser, type CreatedMessage, type CreatedTicket, type DuplicateBudgetInput, ErrorCode, type ErrorFilters, type ErrorHttpMethod, type ErrorSeverity, type ErrorStats, type ExternalUser, type FileQuota, FileTokenStorage, type GenerateCompleteAiResult, type GenerateItemsAiInput, type GenerateItemsAiJob, type GenerateSectionsAiResult, type GetSuggestionsOptions, type IdentifyUserInput, type IntrospectResponse, type ListBudgetCommentsFilter, type ListSigningLinksFilter, type LoginUrlResult, MemoryTokenStorage, type MessageAuthor, type NextCodeResponse, type OAuthConfig, OAuthService, type OAuthTokens, type OAuthUserInfo, type OidcAuthorizationOptions, type OrganizationContactChannel, type OrganizationPublicSettings, type PKCEChallenge, type PaginatedResponse, type PaginationMeta, type PaymentMethod, type PendingOAuthState, type PopupLoginOptions, type RejectBudgetInput, type ReorderItemsInput, type ReorderSectionsInput, type ReportErrorInput, type ReportedError, type RequestConfig, type RevokeSigningLinkResponse, SDK_LIMITS, type SendBudgetInput, type SignatureStatus, type SignerAuditEvent, type SignerAuditEventKind, type SigningLinkRequest, type SigningLinkResponse, type SigningLinkStatus, type SigningLinkSummary, type SortOrder, type SseEvent, type StreamSuggestionsHandle, type StreamSuggestionsOptions, type StreamTranscriptionOptions, type SystemError, type TicketAttachment, type TicketCategory, type TicketContext, type TicketDetail, type TicketFilters, type TicketListItem, type TicketMessage, type TicketPriority, type TicketReporter, type TicketStatus, type TokenStorage, type TrackAiActionInput, type TranscriptionJobStatus, type UnreadCount, type UpdateBudgetCommentInput, type UpdateBudgetInput, type UpdateBudgetItemInput, type UpdateBudgetSectionInput, type UpdateBudgetTemplateInput, type UploadFileOptions, type UploadedBudgetImage, type UploadedFile, UtiliaSDK, type UtiliaSDKConfig, UtiliaSDKError, base64UrlEncode, generateCodeChallenge, generateCodeVerifier };