@utilia-os/sdk-js 1.7.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/dist/index.d.mts CHANGED
@@ -102,10 +102,25 @@ interface LoginUrlResult {
102
102
  /** Valor de state para protección CSRF */
103
103
  state: string;
104
104
  }
105
+ /**
106
+ * Opciones OIDC extendidas aceptadas por getLoginUrl() y loginWithPopup().
107
+ */
108
+ interface OidcAuthorizationOptions {
109
+ /** Parámetro `prompt` de OIDC Core 1.0 §3.1.2.1. */
110
+ prompt?: 'none' | 'login' | 'consent' | 'select_account';
111
+ /** Sugerencia de email o identificador de usuario para el login. */
112
+ loginHint?: string;
113
+ /** Nonce para prevenir replay attacks en el ID token. */
114
+ nonce?: string;
115
+ /** Resource Indicator (RFC 8707) del token resultante. */
116
+ resource?: string;
117
+ /** Tiempo máximo en segundos desde la última autenticación activa. */
118
+ maxAge?: number;
119
+ }
105
120
  /**
106
121
  * Opciones para inicio de sesión OAuth mediante ventana emergente
107
122
  */
108
- interface PopupLoginOptions {
123
+ interface PopupLoginOptions extends OidcAuthorizationOptions {
109
124
  /** Parámetro state personalizado para protección CSRF */
110
125
  state?: string;
111
126
  /** Scopes a solicitar */
@@ -116,6 +131,35 @@ interface PopupLoginOptions {
116
131
  height?: number;
117
132
  /** Tiempo límite en milisegundos antes de rechazar (por defecto: 300000 = 5 min) */
118
133
  timeout?: number;
134
+ /** Tema de la pantalla de consentimiento: 'light' o 'dark'. Si no se indica, usa la preferencia del usuario. */
135
+ theme?: 'light' | 'dark';
136
+ }
137
+ /**
138
+ * Respuesta de introspección de token (RFC 7662 §2.2).
139
+ */
140
+ interface IntrospectResponse {
141
+ active: boolean;
142
+ scope?: string;
143
+ client_id?: string;
144
+ username?: string;
145
+ token_type?: string;
146
+ exp?: number;
147
+ iat?: number;
148
+ sub?: string;
149
+ aud?: string;
150
+ iss?: string;
151
+ }
152
+ /**
153
+ * Datos de una aplicación OAuth autorizada por el usuario.
154
+ */
155
+ interface AuthorizedApp {
156
+ clientId: string;
157
+ clientName: string;
158
+ clientUri: string | null;
159
+ logoUri: string | null;
160
+ scope: string;
161
+ authorizedAt: string;
162
+ lastUsedAt: string | null;
119
163
  }
120
164
 
121
165
  /**
@@ -139,12 +183,26 @@ interface UtiliaSDKConfig {
139
183
  interface RequestConfig {
140
184
  headers?: Record<string, string>;
141
185
  params?: Record<string, unknown>;
186
+ /**
187
+ * Tipo esperado de la respuesta. Util para descargas binarias (PDF, CSV).
188
+ * Internamente mapea al `responseType` de Axios.
189
+ */
190
+ responseType?: 'json' | 'arraybuffer' | 'blob' | 'text';
142
191
  }
143
192
 
144
193
  /**
145
194
  * Servicio OAuth 2.1 con PKCE para el SDK de UTILIA OS
146
195
  */
147
196
 
197
+ /**
198
+ * Opciones comunes para construir la URL de autorización.
199
+ */
200
+ interface AuthorizationUrlOptions extends OidcAuthorizationOptions {
201
+ state?: string;
202
+ scopes?: string[];
203
+ /** Tema de la pantalla de consentimiento: 'light' o 'dark'. */
204
+ theme?: 'light' | 'dark';
205
+ }
148
206
  /**
149
207
  * Servicio que gestiona el flujo OAuth 2.1 con PKCE
150
208
  */
@@ -155,6 +213,8 @@ declare class OAuthService {
155
213
  private readonly http;
156
214
  /** Estado PKCE en memoria como fallback cuando el storage no soporta pendingState */
157
215
  private _pendingState;
216
+ /** Promesa de refresco en curso para deduplicar llamadas concurrentes. */
217
+ private _refreshInFlight;
158
218
  constructor(baseURL: string, config: OAuthConfig);
159
219
  /**
160
220
  * Genera la URL de autorización OAuth con PKCE y almacena el estado
@@ -162,26 +222,20 @@ declare class OAuthService {
162
222
  *
163
223
  * Este es el método recomendado para la mayoría de los casos.
164
224
  *
165
- * @param options - Opciones adicionales (state personalizado, scopes)
225
+ * @param options - Opciones adicionales (state personalizado, scopes, parámetros OIDC)
166
226
  * @returns URL de autorización lista para redirigir al usuario
167
227
  */
168
- getAuthorizationUrl(options?: {
169
- state?: string;
170
- scopes?: string[];
171
- }): Promise<string>;
228
+ getAuthorizationUrl(options?: AuthorizationUrlOptions): Promise<string>;
172
229
  /**
173
230
  * Genera la URL de inicio de sesión OAuth con PKCE.
174
231
  *
175
232
  * Método de control manual: devuelve codeVerifier y state que el desarrollador
176
233
  * debe gestionar. Para un flujo automático, usar getAuthorizationUrl() en su lugar.
177
234
  *
178
- * @param options - Opciones adicionales (state personalizado, scopes)
179
- * @returns URL de autorización, code_verifier y state
235
+ * Soporta los parámetros OIDC Core 1.0 §3.1.2.1: prompt, loginHint, nonce,
236
+ * maxAge y el Resource Indicator (RFC 8707) mediante el campo resource.
180
237
  */
181
- getLoginUrl(options?: {
182
- state?: string;
183
- scopes?: string[];
184
- }): Promise<LoginUrlResult>;
238
+ getLoginUrl(options?: AuthorizationUrlOptions): Promise<LoginUrlResult>;
185
239
  /**
186
240
  * Abre una ventana emergente para inicio de sesión OAuth y devuelve tokens al completarse.
187
241
  *
@@ -203,7 +257,13 @@ declare class OAuthService {
203
257
  */
204
258
  handleCallback(code: string, codeVerifier?: string, callbackState?: string): Promise<OAuthTokens>;
205
259
  /**
206
- * Refresca el token de acceso usando el refresh_token
260
+ * Refresca el token de acceso usando el refresh_token.
261
+ *
262
+ * Deduplica peticiones concurrentes mediante una promesa cacheada: si dos
263
+ * llamadas entran a la vez, comparten la misma petición HTTP. Esto es
264
+ * imprescindible porque el backend implementa rotación de refresh tokens con
265
+ * detección de reuso; dos refresh concurrentes con el mismo token producirían
266
+ * una invalidación inmediata de toda la cadena.
207
267
  *
208
268
  * @returns Nuevos tokens OAuth
209
269
  * @throws Error si no hay refresh_token disponible
@@ -216,12 +276,39 @@ declare class OAuthService {
216
276
  */
217
277
  getUserInfo(): Promise<OAuthUserInfo>;
218
278
  /**
219
- * Revoca el token actual
279
+ * Revoca el token actual almacenado y limpia el storage.
220
280
  *
221
- * @param tokenType - Tipo de token a revocar ('access_token' | 'refresh_token').
281
+ * @param tokenType - Tipo de token a revocar (`access_token` o `refresh_token`).
222
282
  * Por defecto revoca el access_token.
223
283
  */
224
284
  revokeToken(tokenType?: 'access_token' | 'refresh_token'): Promise<void>;
285
+ /**
286
+ * Revoca un token arbitrario contra el endpoint `/oauth/revoke` (RFC 7009).
287
+ * A diferencia de `revokeToken()`, no toca el almacenamiento local.
288
+ *
289
+ * @param token - Token a revocar (access token o refresh token).
290
+ * @param tokenTypeHint - Pista opcional sobre el tipo de token.
291
+ */
292
+ revoke(token: string, tokenTypeHint?: 'access_token' | 'refresh_token'): Promise<void>;
293
+ /**
294
+ * Introspecciona un token contra `/oauth/introspect` (RFC 7662).
295
+ * Requiere que el cliente esté autenticado (client_secret o public con PKCE).
296
+ *
297
+ * @param token - Token a introspeccionar.
298
+ * @param tokenTypeHint - Pista opcional sobre el tipo de token.
299
+ * @returns Estado y metadatos del token.
300
+ */
301
+ introspect(token: string, tokenTypeHint?: 'access_token' | 'refresh_token'): Promise<IntrospectResponse>;
302
+ /**
303
+ * Lista las aplicaciones OAuth autorizadas por el usuario actual.
304
+ * Requiere un access token válido.
305
+ */
306
+ getAuthorizedApps(): Promise<AuthorizedApp[]>;
307
+ /**
308
+ * Revoca el acceso de una aplicación OAuth concreta del usuario actual.
309
+ * Todos los tokens emitidos para esa aplicación quedan invalidados.
310
+ */
311
+ revokeApp(clientId: string): Promise<void>;
225
312
  /**
226
313
  * Obtiene un access token válido, refrescándolo automáticamente si ha expirado
227
314
  *
@@ -731,6 +818,877 @@ interface ErrorStats {
731
818
  }>;
732
819
  }
733
820
 
821
+ /**
822
+ * Tipos relacionados con presupuestos (CRM Budgets)
823
+ *
824
+ * Expuestos por la API REST bajo `/api/crm/budgets` y `/api/crm/budget-templates`.
825
+ */
826
+
827
+ /** Estado del presupuesto. */
828
+ type BudgetStatus = 'DRAFT' | 'SENT' | 'APPROVED' | 'REJECTED' | 'EXPIRED' | 'CANCELLED';
829
+ /** Tipo de linea en el presupuesto. */
830
+ type BudgetItemType = 'ITEM' | 'SERVICE' | 'SECTION_HEADER';
831
+ /** Tipo semantico de seccion. */
832
+ type BudgetSectionType = 'INTRO' | 'INFO' | 'SCOPE' | 'TIMELINE' | 'COSTS' | 'PAYMENT' | 'CUSTOM' | 'RICH_HTML';
833
+ /** Posicion de la seccion respecto a la tabla de items. */
834
+ type BudgetSectionPosition = 'BEFORE_ITEMS' | 'AFTER_ITEMS';
835
+ /** Metodo de pago propuesto. */
836
+ type PaymentMethod = 'TRANSFER' | 'CASH' | 'CARD' | 'CHECK' | 'OTHER';
837
+ /** Quien aprueba o rechaza un presupuesto. */
838
+ type ApproverType = 'INTERNAL' | 'CLIENT';
839
+ /** Operaciones soportadas por el endpoint de masivos. */
840
+ type BulkBudgetOperation = 'delete' | 'cancel' | 'change-status';
841
+ /** Orden ascendente o descendente. */
842
+ type SortOrder = 'asc' | 'desc';
843
+ /** DTO para anyadir un item al presupuesto. */
844
+ interface CreateBudgetItemInput {
845
+ /** UUID opcional. Se genera si no se indica. */
846
+ id?: string;
847
+ /** Tipo de linea. Por defecto ITEM. */
848
+ type?: BudgetItemType;
849
+ /** Nombre visible en el PDF. */
850
+ name: string;
851
+ /** Descripcion detallada (acepta texto plano). */
852
+ description?: string;
853
+ /** Codigo interno del item. */
854
+ code?: string;
855
+ /** Cantidad (por defecto 1). */
856
+ quantity: number;
857
+ /** Precio unitario sin impuestos. */
858
+ unitPrice: number;
859
+ /** Descuento aplicado al item en porcentaje (0-100). */
860
+ discount?: number;
861
+ /** Tasa impositiva del item en porcentaje (IVA/IGIC). */
862
+ taxRate?: number;
863
+ /** Coste interno (no visible para el cliente). */
864
+ internalCost?: number;
865
+ /** Orden de aparicion. */
866
+ order?: number;
867
+ /** Metadatos adicionales. */
868
+ metadata?: Record<string, unknown>;
869
+ }
870
+ /** DTO parcial para actualizar un item existente. */
871
+ type UpdateBudgetItemInput = Partial<Omit<CreateBudgetItemInput, 'id'>>;
872
+ /** Item de presupuesto devuelto por la API. */
873
+ interface BudgetItem {
874
+ id: string;
875
+ budgetId: string;
876
+ type: BudgetItemType;
877
+ name: string;
878
+ description?: string | null;
879
+ code?: string | null;
880
+ quantity: number;
881
+ unitPrice: number;
882
+ discount: number;
883
+ taxRate: number;
884
+ /** Subtotal calculado: quantity * unitPrice - descuento. */
885
+ subtotal: number;
886
+ /** Coste interno; solo presente si el usuario tiene permiso. */
887
+ internalCost?: number | null;
888
+ order: number;
889
+ metadata?: Record<string, unknown> | null;
890
+ createdAt: string;
891
+ updatedAt: string;
892
+ }
893
+ /** Pareja id + order para reordenar items. */
894
+ interface BudgetItemOrder {
895
+ id: string;
896
+ order: number;
897
+ }
898
+ interface ReorderItemsInput {
899
+ items: BudgetItemOrder[];
900
+ }
901
+ /** DTO para anyadir una seccion al presupuesto. */
902
+ interface CreateBudgetSectionInput {
903
+ id?: string;
904
+ /** Tipo semantico. Por defecto CUSTOM. */
905
+ type?: BudgetSectionType;
906
+ /** Posicion respecto a los items. Por defecto BEFORE_ITEMS. */
907
+ position?: BudgetSectionPosition;
908
+ /** Titulo visible de la seccion. */
909
+ title: string;
910
+ /** Contenido HTML/Markdown. En RICH_HTML se renderiza como imagen en el PDF. */
911
+ content?: string;
912
+ order?: number;
913
+ metadata?: Record<string, unknown>;
914
+ }
915
+ type UpdateBudgetSectionInput = Partial<Omit<CreateBudgetSectionInput, 'id'>>;
916
+ interface BudgetSection {
917
+ id: string;
918
+ budgetId: string;
919
+ type: BudgetSectionType;
920
+ position: BudgetSectionPosition;
921
+ title: string;
922
+ content?: string | null;
923
+ order: number;
924
+ metadata?: Record<string, unknown> | null;
925
+ createdAt: string;
926
+ updatedAt: string;
927
+ }
928
+ interface ReorderSectionsInput {
929
+ /** UUIDs de las secciones en el nuevo orden deseado. */
930
+ sectionIds: string[];
931
+ }
932
+ interface BudgetApproval {
933
+ id: string;
934
+ budgetId: string;
935
+ action: 'APPROVED' | 'REJECTED';
936
+ approverType: ApproverType;
937
+ approverId?: string | null;
938
+ approverName?: string | null;
939
+ approverEmail?: string | null;
940
+ reason?: string | null;
941
+ comments?: string | null;
942
+ createdAt: string;
943
+ }
944
+ interface BudgetAttachment {
945
+ id: string;
946
+ budgetId: string;
947
+ fileId: string;
948
+ name: string;
949
+ description?: string | null;
950
+ mimeType: string;
951
+ size: number;
952
+ url?: string;
953
+ uploadedById: string;
954
+ createdAt: string;
955
+ }
956
+ /** Cliente relacionado (subconjunto expuesto en presupuestos). */
957
+ interface BudgetClientRef {
958
+ id: string;
959
+ name: string;
960
+ email?: string | null;
961
+ taxId?: string | null;
962
+ }
963
+ interface BudgetProjectRef {
964
+ id: string;
965
+ name: string;
966
+ }
967
+ interface BudgetOpportunityRef {
968
+ id: string;
969
+ title: string;
970
+ }
971
+ interface BudgetUserRef {
972
+ id: string;
973
+ name: string;
974
+ email?: string | null;
975
+ }
976
+ /** Listado de presupuesto (version resumida). */
977
+ interface BudgetListItem {
978
+ id: string;
979
+ code: string;
980
+ title: string;
981
+ status: BudgetStatus;
982
+ currency: string;
983
+ issueDate: string;
984
+ validUntil: string;
985
+ total: number;
986
+ version: number;
987
+ tags: string[];
988
+ client?: BudgetClientRef | null;
989
+ project?: BudgetProjectRef | null;
990
+ opportunity?: BudgetOpportunityRef | null;
991
+ createdBy?: BudgetUserRef | null;
992
+ createdAt: string;
993
+ updatedAt: string;
994
+ }
995
+ /** Presupuesto completo con items, secciones y aprobaciones. */
996
+ interface Budget extends BudgetListItem {
997
+ description?: string | null;
998
+ taxRate: number;
999
+ discount: number;
1000
+ discountPercent: number;
1001
+ subtotal: number;
1002
+ taxAmount: number;
1003
+ internalCost?: number | null;
1004
+ profit?: number | null;
1005
+ profitMargin?: number | null;
1006
+ paymentMethod?: PaymentMethod | null;
1007
+ paymentTerms?: string | null;
1008
+ termsAndConditions?: string | null;
1009
+ notes?: string | null;
1010
+ includeAcceptanceSection: boolean;
1011
+ metadata?: Record<string, unknown> | null;
1012
+ items: BudgetItem[];
1013
+ sections: BudgetSection[];
1014
+ approvals?: BudgetApproval[];
1015
+ attachments?: BudgetAttachment[];
1016
+ previousVersionId?: string | null;
1017
+ nextVersionId?: string | null;
1018
+ }
1019
+ interface CreateBudgetInput {
1020
+ /** Codigo. Si se omite, se autogenera segun la configuracion. */
1021
+ code?: string;
1022
+ /** Codigo ISO 4217 de la moneda (3 letras mayus). */
1023
+ currency?: string;
1024
+ /** Titulo visible para el cliente. */
1025
+ title: string;
1026
+ /** Descripcion general. */
1027
+ description?: string;
1028
+ /** UUID del cliente destinatario. */
1029
+ clientId: string;
1030
+ /** UUID del proyecto CRM asociado. */
1031
+ projectId?: string;
1032
+ /** UUID de la oportunidad comercial asociada. */
1033
+ opportunityId?: string;
1034
+ /** Fecha de emision (ISO 8601). Por defecto hoy. */
1035
+ issueDate?: string;
1036
+ /** Fecha de validez (ISO 8601). Obligatoria. */
1037
+ validUntil: string;
1038
+ /** Tasa impositiva global (0-100). */
1039
+ taxRate?: number;
1040
+ /** Descuento absoluto. */
1041
+ discount?: number;
1042
+ /** Descuento porcentual (0-100). */
1043
+ discountPercent?: number;
1044
+ /** Coste interno global (no visible al cliente). */
1045
+ internalCost?: number;
1046
+ /** Metodo de pago propuesto. */
1047
+ paymentMethod?: PaymentMethod;
1048
+ /** Condiciones de pago en texto libre. */
1049
+ paymentTerms?: string;
1050
+ /** Terminos y condiciones. Acepta Markdown. */
1051
+ termsAndConditions?: string;
1052
+ /** Notas internas. */
1053
+ notes?: string;
1054
+ /** Incluir seccion de aceptacion en el PDF generado. */
1055
+ includeAcceptanceSection?: boolean;
1056
+ /** Etiquetas para categorizar. */
1057
+ tags?: string[];
1058
+ /** Metadatos adicionales. */
1059
+ metadata?: Record<string, unknown>;
1060
+ /** Estado inicial. Por defecto DRAFT. */
1061
+ status?: BudgetStatus;
1062
+ /** Lista de items a crear junto al presupuesto. */
1063
+ items?: CreateBudgetItemInput[];
1064
+ /** Lista de secciones a crear junto al presupuesto. */
1065
+ sections?: CreateBudgetSectionInput[];
1066
+ }
1067
+ type UpdateBudgetInput = Partial<Omit<CreateBudgetInput, 'clientId'>> & {
1068
+ clientId?: string;
1069
+ };
1070
+ /** Filtros para listar presupuestos. */
1071
+ interface BudgetFilters {
1072
+ page?: number;
1073
+ limit?: number;
1074
+ /** Busqueda libre por codigo, titulo o descripcion. */
1075
+ search?: string;
1076
+ /** Uno o varios estados. */
1077
+ status?: BudgetStatus | BudgetStatus[];
1078
+ clientId?: string;
1079
+ projectId?: string;
1080
+ opportunityId?: string;
1081
+ createdById?: string;
1082
+ version?: number;
1083
+ /** Rango de fechas de emision. */
1084
+ fromDate?: string;
1085
+ toDate?: string;
1086
+ /** Rango de fechas de validez. */
1087
+ validFromDate?: string;
1088
+ validToDate?: string;
1089
+ /** Rango de importes. */
1090
+ minAmount?: number;
1091
+ maxAmount?: number;
1092
+ tags?: string[];
1093
+ sortBy?: string;
1094
+ sortOrder?: SortOrder;
1095
+ }
1096
+ interface BudgetListResponse {
1097
+ data: BudgetListItem[];
1098
+ pagination: PaginationMeta;
1099
+ }
1100
+ interface SendBudgetInput {
1101
+ /** Destinatarios principales (To). */
1102
+ emails: string[];
1103
+ /** Asunto del correo. */
1104
+ subject?: string;
1105
+ /** Mensaje personalizado en el cuerpo. */
1106
+ message?: string;
1107
+ /** Direcciones CC. */
1108
+ cc?: string[];
1109
+ /** Direcciones BCC. */
1110
+ bcc?: string[];
1111
+ /** Incluir adjuntos del presupuesto ademas del PDF. */
1112
+ includeAttachments?: boolean;
1113
+ }
1114
+ interface ApproveBudgetInput {
1115
+ /** Comentarios adicionales. */
1116
+ comments?: string;
1117
+ /** Crear automaticamente un proyecto. */
1118
+ createProject?: boolean;
1119
+ /** Quien aprueba. */
1120
+ approverType?: ApproverType;
1121
+ /** Nombre del contacto del cliente que aprueba (si approverType es CLIENT). */
1122
+ clientApproverName?: string;
1123
+ /** Correo del contacto del cliente que aprueba. */
1124
+ clientApproverEmail?: string;
1125
+ }
1126
+ interface RejectBudgetInput {
1127
+ /** Motivo del rechazo. Obligatorio. */
1128
+ reason: string;
1129
+ /** Comentarios adicionales. */
1130
+ comments?: string;
1131
+ approverType?: ApproverType;
1132
+ clientApproverName?: string;
1133
+ clientApproverEmail?: string;
1134
+ }
1135
+ interface ChangeStatusInput {
1136
+ status: BudgetStatus;
1137
+ reason?: string;
1138
+ }
1139
+ interface ConvertToProjectInput {
1140
+ name: string;
1141
+ startDate: string;
1142
+ estimatedEndDate?: string;
1143
+ description?: string;
1144
+ /** Convertir items en tareas (por defecto true). */
1145
+ copyItemsAsTasks?: boolean;
1146
+ }
1147
+ interface ConvertToInvoiceInput {
1148
+ /** Emitir la factura directamente (ISSUED) en lugar de DRAFT. */
1149
+ issueDirectly?: boolean;
1150
+ /** Metodo de pago (hereda si se omite). */
1151
+ paymentMethod?: PaymentMethod;
1152
+ /** Condiciones de pago (hereda si se omite). */
1153
+ paymentTerms?: string;
1154
+ /** Fecha de vencimiento. */
1155
+ dueDate?: string;
1156
+ /** Notas visibles. */
1157
+ notes?: string;
1158
+ /** Notas internas no visibles para el cliente. */
1159
+ internalNotes?: string;
1160
+ }
1161
+ interface DuplicateBudgetInput {
1162
+ /** Cliente destino. Si se omite, conserva el del original. */
1163
+ targetClientId?: string;
1164
+ /** Titulo del duplicado. */
1165
+ title?: string;
1166
+ /** Resetear a DRAFT (por defecto true). */
1167
+ resetStatus?: boolean;
1168
+ /** Copiar registros de adjuntos. */
1169
+ includeAttachments?: boolean;
1170
+ }
1171
+ interface BulkBudgetOptions {
1172
+ /** Nuevo estado (obligatorio cuando la operacion es change-status). */
1173
+ newStatus?: BudgetStatus;
1174
+ }
1175
+ interface BulkBudgetInput {
1176
+ operation: BulkBudgetOperation;
1177
+ ids: string[];
1178
+ options?: BulkBudgetOptions;
1179
+ }
1180
+ interface BulkBudgetResultItem {
1181
+ id: string;
1182
+ success: boolean;
1183
+ error?: string;
1184
+ }
1185
+ interface BulkBudgetResult {
1186
+ success: number;
1187
+ failed: number;
1188
+ results: BulkBudgetResultItem[];
1189
+ }
1190
+ interface BudgetHistoryEntry {
1191
+ id: string;
1192
+ budgetId: string;
1193
+ version: number;
1194
+ action: string;
1195
+ actorId?: string | null;
1196
+ actorName?: string | null;
1197
+ changes?: Record<string, unknown> | null;
1198
+ createdAt: string;
1199
+ }
1200
+ interface NextCodeResponse {
1201
+ code: string;
1202
+ }
1203
+ interface CheckCodeResponse {
1204
+ exists: boolean;
1205
+ }
1206
+ interface BudgetPdfUrlResponse {
1207
+ url: string;
1208
+ }
1209
+ interface UploadedBudgetImage {
1210
+ url: string;
1211
+ }
1212
+ interface GenerateItemsAiInput {
1213
+ /** Texto en lenguaje natural (minimo 10 caracteres). */
1214
+ text: string;
1215
+ }
1216
+ interface AiGeneratedItem {
1217
+ name: string;
1218
+ description?: string;
1219
+ quantity: number;
1220
+ unitPrice: number;
1221
+ taxRate?: number;
1222
+ type?: BudgetItemType;
1223
+ }
1224
+ interface AiGeneratedSection {
1225
+ type: BudgetSectionType;
1226
+ position: BudgetSectionPosition;
1227
+ title: string;
1228
+ content: string;
1229
+ }
1230
+ interface GenerateItemsAiJob {
1231
+ jobId: string;
1232
+ }
1233
+ interface GenerateCompleteAiResult {
1234
+ sections: AiGeneratedSection[];
1235
+ items: AiGeneratedItem[];
1236
+ suggestedTitle?: string;
1237
+ suggestedPaymentTerms?: string;
1238
+ suggestedTermsAndConditions?: string;
1239
+ }
1240
+ interface GenerateSectionsAiResult {
1241
+ sections: AiGeneratedSection[];
1242
+ }
1243
+ type BudgetExportFormat = 'csv';
1244
+ /**
1245
+ * Eventos de webhook emitidos por el modulo de presupuestos.
1246
+ * Formato UPPER_SNAKE coherente con el resto de eventos de la plataforma.
1247
+ */
1248
+ type BudgetWebhookEvent = 'BUDGET_CREATED' | 'BUDGET_UPDATED' | 'BUDGET_SENT' | 'BUDGET_APPROVED' | 'BUDGET_REJECTED' | 'BUDGET_CANCELLED' | 'BUDGET_EXPIRED' | 'BUDGET_DUPLICATED' | 'BUDGET_CONVERTED_TO_PROJECT' | 'BUDGET_CONVERTED_TO_INVOICE';
1249
+ /**
1250
+ * Lista completa de eventos de webhook de presupuestos.
1251
+ * Util para registrar todos los eventos al configurar una app externa.
1252
+ */
1253
+ declare const BUDGET_WEBHOOK_EVENTS: readonly BudgetWebhookEvent[];
1254
+
1255
+ /**
1256
+ * Tipos relacionados con plantillas de presupuesto.
1257
+ *
1258
+ * Expuestos por la API REST bajo `/api/crm/budget-templates`.
1259
+ */
1260
+
1261
+ /**
1262
+ * Estructura sugerida de una seccion dentro de `sectionsJson` de la plantilla.
1263
+ * El backend acepta `unknown[]` pero esta es la estructura recomendada.
1264
+ */
1265
+ interface BudgetTemplateSectionJson {
1266
+ type: BudgetSectionType;
1267
+ position: BudgetSectionPosition;
1268
+ title: string;
1269
+ content?: string;
1270
+ order?: number;
1271
+ }
1272
+ /**
1273
+ * Estructura sugerida de un item dentro de `itemsJson` de la plantilla.
1274
+ */
1275
+ interface BudgetTemplateItemJson {
1276
+ type?: BudgetItemType;
1277
+ name: string;
1278
+ description?: string;
1279
+ code?: string;
1280
+ quantity: number;
1281
+ unitPrice: number;
1282
+ taxRate?: number;
1283
+ discount?: number;
1284
+ order?: number;
1285
+ }
1286
+ /** Plantilla de presupuesto. */
1287
+ interface BudgetTemplate {
1288
+ id: string;
1289
+ name: string;
1290
+ description?: string | null;
1291
+ icon?: string | null;
1292
+ defaultTitle?: string | null;
1293
+ defaultValidDays?: number | null;
1294
+ defaultTaxRate?: number | null;
1295
+ defaultPaymentTerms?: string | null;
1296
+ defaultTermsAndConditions?: string | null;
1297
+ includeAcceptanceSection: boolean;
1298
+ /** Secciones de la plantilla. */
1299
+ sectionsJson: BudgetTemplateSectionJson[];
1300
+ /** Items de la plantilla. */
1301
+ itemsJson: BudgetTemplateItemJson[];
1302
+ /** Plantilla del sistema (inmutable). */
1303
+ isSystemDefault: boolean;
1304
+ /** Activa / archivada. */
1305
+ isActive: boolean;
1306
+ createdById?: string | null;
1307
+ createdAt: string;
1308
+ updatedAt: string;
1309
+ }
1310
+ /** DTO para crear una plantilla personalizada. */
1311
+ interface CreateBudgetTemplateInput {
1312
+ name: string;
1313
+ description?: string;
1314
+ icon?: string;
1315
+ defaultTitle?: string;
1316
+ defaultValidDays?: number;
1317
+ defaultTaxRate?: number;
1318
+ defaultPaymentTerms?: string;
1319
+ defaultTermsAndConditions?: string;
1320
+ includeAcceptanceSection?: boolean;
1321
+ sectionsJson?: BudgetTemplateSectionJson[];
1322
+ itemsJson?: BudgetTemplateItemJson[];
1323
+ }
1324
+ /** DTO parcial para actualizar una plantilla. */
1325
+ type UpdateBudgetTemplateInput = Partial<CreateBudgetTemplateInput>;
1326
+ /** DTO para guardar un presupuesto existente como plantilla. */
1327
+ interface CreateTemplateFromBudgetInput {
1328
+ name: string;
1329
+ description?: string;
1330
+ icon?: string;
1331
+ }
1332
+ /** DTO para crear un presupuesto aplicando una plantilla. */
1333
+ interface ApplyTemplateInput {
1334
+ clientId: string;
1335
+ opportunityId?: string;
1336
+ /** Titulo personalizado. Si se omite, se usa `defaultTitle` de la plantilla. */
1337
+ title?: string;
1338
+ }
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
+
1618
+ /**
1619
+ * Tipos relacionados con la configuración de la organización.
1620
+ *
1621
+ * Reflejan el DTO `OrganizationPublicSettingsResponseDto` del backend
1622
+ * (`apps/backend/src/modules/organization-settings/dto/organization-public-settings-response.dto.ts`).
1623
+ */
1624
+ /**
1625
+ * Canal de contacto dinámico (email, teléfono, URL, etc.) configurado por la
1626
+ * organización.
1627
+ */
1628
+ interface OrganizationContactChannel {
1629
+ /** Etiqueta legible (ej: "Soporte", "RRHH", "Comercial"). */
1630
+ label: string;
1631
+ /** Valor del canal (email, teléfono, URL). */
1632
+ value: string;
1633
+ /** Tipo de canal. Valores habituales: "email", "phone", "url". */
1634
+ type: string;
1635
+ }
1636
+ /**
1637
+ * Datos públicos de la organización devueltos por
1638
+ * `GET /organization-settings/public`.
1639
+ *
1640
+ * Son los campos que cualquier usuario autenticado puede leer para renderizar
1641
+ * branding, contacto y valores por defecto de facturación. No incluye
1642
+ * metadatos internos (id, createdAt, updatedAt, updatedById) ni los emails
1643
+ * legacy (ya transformados a `contactChannels`).
1644
+ */
1645
+ interface OrganizationPublicSettings {
1646
+ companyName: string | null;
1647
+ companyLegalName: string | null;
1648
+ companyType: string | null;
1649
+ taxId: string | null;
1650
+ taxRegime: string | null;
1651
+ companyRegistryNumber: string | null;
1652
+ legalRepresentative: string | null;
1653
+ legalAddressStreet: string | null;
1654
+ legalAddressCity: string | null;
1655
+ legalAddressPostalCode: string | null;
1656
+ legalAddressCountry: string | null;
1657
+ operationalAddressName: string | null;
1658
+ operationalAddressStreet: string | null;
1659
+ operationalAddressCity: string | null;
1660
+ operationalAddressPostalCode: string | null;
1661
+ operationalAddressCountry: string | null;
1662
+ emailGeneral: string | null;
1663
+ phone: string | null;
1664
+ website: string | null;
1665
+ contactChannels: OrganizationContactChannel[] | null;
1666
+ bankName: string | null;
1667
+ bankIban: string | null;
1668
+ bankSwift: string | null;
1669
+ bankPaymentMethod: string | null;
1670
+ bankAccountHolder: string | null;
1671
+ defaultCurrency: string | null;
1672
+ defaultPaymentTermsDays: number | null;
1673
+ /** Nombre del impuesto por defecto (IVA, IGIC, VAT, TVA, MwSt, etc.). */
1674
+ defaultTaxName: string | null;
1675
+ /** Tasa por defecto en porcentaje (21 = 21 %). */
1676
+ defaultTaxRate: number | null;
1677
+ /** Código ISO 3166-1 alfa-2 del país principal (ES, FR, US, etc.). */
1678
+ country: string | null;
1679
+ invoicePrefix: string | null;
1680
+ invoiceLegalFooter: string | null;
1681
+ timezone: string | null;
1682
+ brandPrimaryColor: string | null;
1683
+ brandSecondaryColor: string | null;
1684
+ signatureImageUrl: string | null;
1685
+ documentSignerRole: string | null;
1686
+ logoUrl: string | null;
1687
+ logoDarkBgUrl: string | null;
1688
+ logoWidth: number | null;
1689
+ budgetBrandConfig: Record<string, unknown> | null;
1690
+ }
1691
+
734
1692
  /**
735
1693
  * Servicio de errores del sistema
736
1694
  * Maneja todas las operaciones relacionadas con el reporte y consulta de errores
@@ -1451,6 +2409,429 @@ declare class AiService {
1451
2409
  private sleep;
1452
2410
  }
1453
2411
 
2412
+ /**
2413
+ * Servicio de presupuestos (CRM Budgets).
2414
+ *
2415
+ * Cubre el CRUD completo, items, secciones, acciones (send/approve/reject/
2416
+ * cancel/duplicate/convert), adjuntos, historial, exportacion, operaciones
2417
+ * masivas y generacion asistida por IA.
2418
+ */
2419
+
2420
+ /**
2421
+ * Opciones para la suscripcion SSE al job de generacion de items con IA.
2422
+ */
2423
+ interface StreamAiJobOptions {
2424
+ /** Callback para cada evento de progreso. */
2425
+ onProgress?: (data: {
2426
+ status: string;
2427
+ progress: number;
2428
+ }) => void;
2429
+ /** Callback cuando el job se completa con exito. */
2430
+ onComplete?: (data: {
2431
+ items: AiGeneratedItem[];
2432
+ }) => void;
2433
+ /** Callback en caso de error. */
2434
+ onError?: (error: Error) => void;
2435
+ }
2436
+ /** Handle devuelto por streamGenerateItemsStatus para cerrar la conexion. */
2437
+ interface StreamAiJobHandle {
2438
+ close: () => void;
2439
+ }
2440
+ declare class BudgetsService {
2441
+ private readonly client;
2442
+ private readonly basePath;
2443
+ constructor(client: UtiliaClient);
2444
+ /**
2445
+ * Listar presupuestos aplicando filtros.
2446
+ *
2447
+ * @example
2448
+ * ```typescript
2449
+ * const page = await sdk.budgets.list({ status: 'SENT', page: 1, limit: 20 });
2450
+ * console.log(page.data, page.pagination.total);
2451
+ * ```
2452
+ */
2453
+ list(filters?: BudgetFilters): Promise<BudgetListResponse>;
2454
+ /** Obtener el detalle completo de un presupuesto por UUID. */
2455
+ get(id: string): Promise<Budget>;
2456
+ /**
2457
+ * Crear un nuevo presupuesto.
2458
+ * Puede incluir items y secciones en la misma peticion.
2459
+ */
2460
+ create(data: CreateBudgetInput): Promise<Budget>;
2461
+ /** Actualizar un presupuesto (solo en estado DRAFT salvo excepciones). */
2462
+ update(id: string, data: UpdateBudgetInput): Promise<Budget>;
2463
+ /** Soft delete (puede recuperarse). */
2464
+ delete(id: string): Promise<{
2465
+ message: string;
2466
+ }>;
2467
+ /**
2468
+ * Eliminar de forma permanente.
2469
+ * Solo disponible para SUPER_ADMIN en la organizacion origen.
2470
+ */
2471
+ deletePermanent(id: string): Promise<{
2472
+ message: string;
2473
+ }>;
2474
+ /** Duplicar un presupuesto sin encadenarlo como nueva version. */
2475
+ duplicate(id: string, options?: DuplicateBudgetInput): Promise<Budget>;
2476
+ /** Crear una nueva version DRAFT del presupuesto, incrementando el contador. */
2477
+ createVersion(id: string): Promise<Budget>;
2478
+ /** Historial de versiones y cambios. */
2479
+ getHistory(id: string): Promise<BudgetHistoryEntry[]>;
2480
+ /** Presupuestos de un cliente. */
2481
+ listByClient(clientId: string): Promise<BudgetListItem[]>;
2482
+ /** Presupuestos de un proyecto. */
2483
+ listByProject(projectId: string): Promise<BudgetListItem[]>;
2484
+ /** Presupuestos de una oportunidad. */
2485
+ listByOpportunity(opportunityId: string): Promise<BudgetListItem[]>;
2486
+ /** Anyadir un item al presupuesto. */
2487
+ addItem(budgetId: string, data: CreateBudgetItemInput): Promise<BudgetItem>;
2488
+ /** Actualizar un item. */
2489
+ updateItem(budgetId: string, itemId: string, data: UpdateBudgetItemInput): Promise<BudgetItem>;
2490
+ /** Eliminar un item. */
2491
+ removeItem(budgetId: string, itemId: string): Promise<{
2492
+ message: string;
2493
+ }>;
2494
+ /** Aplicar un nuevo orden a los items del presupuesto. */
2495
+ reorderItems(budgetId: string, data: ReorderItemsInput): Promise<{
2496
+ message: string;
2497
+ }>;
2498
+ /** Listar secciones del presupuesto ordenadas por posicion y orden. */
2499
+ listSections(budgetId: string): Promise<BudgetSection[]>;
2500
+ /** Anyadir una seccion al presupuesto. */
2501
+ addSection(budgetId: string, data: CreateBudgetSectionInput): Promise<BudgetSection>;
2502
+ /** Actualizar una seccion existente. */
2503
+ updateSection(budgetId: string, sectionId: string, data: UpdateBudgetSectionInput): Promise<BudgetSection>;
2504
+ /** Eliminar una seccion. */
2505
+ removeSection(budgetId: string, sectionId: string): Promise<{
2506
+ message: string;
2507
+ }>;
2508
+ /** Reordenar secciones. */
2509
+ reorderSections(budgetId: string, data: ReorderSectionsInput): Promise<{
2510
+ message: string;
2511
+ }>;
2512
+ /** Enviar el presupuesto por correo al cliente. */
2513
+ send(id: string, data: SendBudgetInput): Promise<Budget>;
2514
+ /** Aprobar el presupuesto. */
2515
+ approve(id: string, data?: ApproveBudgetInput): Promise<Budget>;
2516
+ /** Rechazar el presupuesto. El motivo (reason) es obligatorio. */
2517
+ reject(id: string, data: RejectBudgetInput): Promise<Budget>;
2518
+ /** Cancelar el presupuesto. */
2519
+ cancel(id: string): Promise<Budget>;
2520
+ /**
2521
+ * Cambiar el estado del presupuesto directamente (uso administrativo).
2522
+ * Restringido a SUPER_ADMIN en el backend.
2523
+ */
2524
+ changeStatus(id: string, status: BudgetStatus, reason?: string): Promise<Budget>;
2525
+ /** Convertir un presupuesto aprobado en un proyecto CRM. */
2526
+ convertToProject(id: string, options: ConvertToProjectInput): Promise<{
2527
+ projectId: string;
2528
+ }>;
2529
+ /** Convertir un presupuesto aprobado en factura. */
2530
+ convertToInvoice(id: string, options?: ConvertToInvoiceInput): Promise<{
2531
+ invoiceId: string;
2532
+ }>;
2533
+ /**
2534
+ * Generar el PDF del presupuesto para descarga.
2535
+ * Devuelve un Blob. Si el consumidor necesita una URL, usa `URL.createObjectURL`.
2536
+ */
2537
+ generatePdf(id: string): Promise<Blob>;
2538
+ /**
2539
+ * Visualizar el PDF del presupuesto (Content-Disposition inline).
2540
+ * Devuelve un Blob.
2541
+ */
2542
+ viewPdf(id: string): Promise<Blob>;
2543
+ /**
2544
+ * Construir la URL del PDF del presupuesto (util para <iframe>, <embed>, etc.).
2545
+ * Incluye las credenciales en query string para funcionar en etiquetas HTML
2546
+ * que no pueden anyadir headers personalizados.
2547
+ */
2548
+ getPdfUrl(id: string): string;
2549
+ /** Listar adjuntos del presupuesto. */
2550
+ getAttachments(budgetId: string): Promise<BudgetAttachment[]>;
2551
+ /**
2552
+ * Subir un adjunto al presupuesto.
2553
+ *
2554
+ * @param budgetId - UUID del presupuesto
2555
+ * @param file - Archivo a subir (File o Blob)
2556
+ * @param meta - Nombre visible y descripcion opcionales
2557
+ */
2558
+ uploadAttachment(budgetId: string, file: File | Blob, meta?: {
2559
+ name?: string;
2560
+ description?: string;
2561
+ }): Promise<BudgetAttachment>;
2562
+ /** Eliminar un adjunto del presupuesto. */
2563
+ deleteAttachment(budgetId: string, attachmentId: string): Promise<{
2564
+ message: string;
2565
+ }>;
2566
+ /**
2567
+ * Subir una imagen para el editor WYSIWYG.
2568
+ * La imagen no aparece como adjunto en el File Manager: solo devuelve la URL
2569
+ * para incrustarla en el contenido del presupuesto.
2570
+ */
2571
+ uploadEditorImage(budgetId: string, file: File | Blob): Promise<UploadedBudgetImage>;
2572
+ /** Proximo codigo sugerido segun la configuracion de numeracion. */
2573
+ getNextCode(): Promise<NextCodeResponse>;
2574
+ /** Comprobar si un codigo ya esta en uso. */
2575
+ checkCode(code: string, excludeId?: string): Promise<CheckCodeResponse>;
2576
+ /** Estadisticas agregadas (totales, tasa aprobacion, etc.). */
2577
+ getStats(filters?: BudgetFilters): Promise<Record<string, unknown>>;
2578
+ /** Ejecutar una operacion masiva (delete / cancel / change-status). */
2579
+ bulk(operation: BulkBudgetOperation, ids: string[], options?: BulkBudgetOptions): Promise<BulkBudgetResult>;
2580
+ /**
2581
+ * Exportar el listado filtrado en el formato indicado.
2582
+ * De momento solo se soporta `csv`. Devuelve un Blob.
2583
+ */
2584
+ export(filters?: BudgetFilters, format?: BudgetExportFormat): Promise<Blob>;
2585
+ /**
2586
+ * Encolar un job asincrono para generar items del presupuesto a partir
2587
+ * de un texto en lenguaje natural. Devuelve el `jobId` para seguir el
2588
+ * progreso vía `streamGenerateItemsStatus`.
2589
+ */
2590
+ generateItemsWithAi(data: GenerateItemsAiInput): Promise<GenerateItemsAiJob>;
2591
+ /**
2592
+ * Suscribirse al progreso (SSE) del job de generacion de items con IA.
2593
+ * Requiere EventSource en el entorno.
2594
+ */
2595
+ streamGenerateItemsStatus(jobId: string, options?: StreamAiJobOptions): StreamAiJobHandle;
2596
+ /**
2597
+ * Generar un presupuesto completo (secciones + items) a partir de un texto.
2598
+ * Devuelve la estructura sugerida sin crear el presupuesto.
2599
+ */
2600
+ generateCompleteWithAi(data: GenerateItemsAiInput): Promise<GenerateCompleteAiResult>;
2601
+ /** Generar unicamente secciones sugeridas para un presupuesto existente. */
2602
+ generateSectionsWithAi(data: GenerateItemsAiInput): Promise<GenerateSectionsAiResult>;
2603
+ /**
2604
+ * Convierte los filtros a un objeto plano apto para query string.
2605
+ * Aplana arrays en formato coma-separado (patron del backend).
2606
+ */
2607
+ private serializeFilters;
2608
+ /**
2609
+ * Descargar una respuesta binaria (PDF, CSV) respetando el auth del cliente.
2610
+ * Usa `buildSseUrl` para añadir las credenciales en la URL cuando la ruta
2611
+ * no pueda llevarlas en headers (p. ej. etiquetas `<a href>`).
2612
+ */
2613
+ private fetchBinary;
2614
+ }
2615
+
2616
+ /**
2617
+ * Servicio de plantillas de presupuesto (CRM Budget Templates).
2618
+ *
2619
+ * Las plantillas aceleran la creacion de presupuestos reutilizando
2620
+ * secciones e items predefinidos. Se distinguen:
2621
+ * - Plantillas del sistema (`isSystemDefault: true`), inmutables.
2622
+ * - Plantillas personalizadas del usuario.
2623
+ */
2624
+
2625
+ declare class BudgetTemplatesService {
2626
+ private readonly client;
2627
+ private readonly basePath;
2628
+ private readonly budgetsPath;
2629
+ constructor(client: UtiliaClient);
2630
+ /**
2631
+ * Listar plantillas activas.
2632
+ * Las plantillas del sistema aparecen primero, seguidas de las
2633
+ * personalizadas ordenadas por fecha de creacion descendente.
2634
+ */
2635
+ list(): Promise<BudgetTemplate[]>;
2636
+ /** Obtener el detalle de una plantilla por UUID. */
2637
+ get(id: string): Promise<BudgetTemplate>;
2638
+ /** Crear una plantilla personalizada. */
2639
+ create(data: CreateBudgetTemplateInput): Promise<BudgetTemplate>;
2640
+ /** Actualizar una plantilla personalizada (las del sistema son inmutables). */
2641
+ update(id: string, data: UpdateBudgetTemplateInput): Promise<BudgetTemplate>;
2642
+ /** Archivar (soft delete) una plantilla personalizada. */
2643
+ delete(id: string): Promise<{
2644
+ message: string;
2645
+ }>;
2646
+ /**
2647
+ * Crear una plantilla personalizada copiando items y secciones de un
2648
+ * presupuesto existente.
2649
+ */
2650
+ createFromBudget(budgetId: string, data: CreateTemplateFromBudgetInput): Promise<BudgetTemplate>;
2651
+ /**
2652
+ * Crear un presupuesto DRAFT aplicando una plantilla.
2653
+ * Copia los items/secciones de la plantilla y asigna cliente/oportunidad.
2654
+ */
2655
+ applyTemplate(templateId: string, data: ApplyTemplateInput): Promise<Budget>;
2656
+ }
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
+
2801
+ /**
2802
+ * Servicio de configuración de organización.
2803
+ *
2804
+ * Expone los datos públicos de la organización a consumidores externos
2805
+ * (portal de cliente, integraciones, agentes IA) sin exponer metadatos
2806
+ * internos. Los datos devueltos incluyen branding, valores fiscales por
2807
+ * defecto y preferencias regionales que son útiles durante el onboarding
2808
+ * o para auto-rellenar formularios.
2809
+ */
2810
+
2811
+ declare class OrganizationSettingsService {
2812
+ private readonly client;
2813
+ private readonly basePath;
2814
+ constructor(client: UtiliaClient);
2815
+ /**
2816
+ * Obtener los datos públicos de la organización.
2817
+ *
2818
+ * Incluye identidad corporativa, branding, configuración de facturación
2819
+ * (moneda, impuesto por defecto, país) y canales de contacto.
2820
+ *
2821
+ * @returns Configuración pública de la organización.
2822
+ *
2823
+ * @example
2824
+ * ```typescript
2825
+ * const settings = await sdk.organizationSettings.getPublicSettings();
2826
+ * console.log(settings.defaultCurrency); // "EUR"
2827
+ * console.log(settings.defaultTaxName); // "IVA"
2828
+ * console.log(settings.defaultTaxRate); // 21
2829
+ * console.log(settings.country); // "ES"
2830
+ * ```
2831
+ */
2832
+ getPublicSettings(): Promise<OrganizationPublicSettings>;
2833
+ }
2834
+
1454
2835
  /**
1455
2836
  * Codigos de error del SDK
1456
2837
  */
@@ -1634,6 +3015,11 @@ declare const SDK_LIMITS: {
1634
3015
  * - `tickets`: Operaciones con tickets de soporte
1635
3016
  * - `users`: Operaciones con usuarios externos
1636
3017
  * - `ai`: Funcionalidades de IA (transcripción, sugerencias)
3018
+ * - `budgets`: Presupuestos CRM (CRUD, items, secciones, flujo, IA, PDF)
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
3022
+ * - `organizationSettings`: Datos públicos de la organización (branding, fiscal, contacto)
1637
3023
  */
1638
3024
  declare class UtiliaSDK {
1639
3025
  private readonly _client;
@@ -1647,6 +3033,16 @@ declare class UtiliaSDK {
1647
3033
  readonly users: UsersService;
1648
3034
  /** Servicio de IA para transcripción y sugerencias */
1649
3035
  readonly ai: AiService;
3036
+ /** Servicio de presupuestos CRM */
3037
+ readonly budgets: BudgetsService;
3038
+ /** Servicio de plantillas de presupuesto CRM */
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;
3044
+ /** Servicio de configuración pública de la organización */
3045
+ readonly organizationSettings: OrganizationSettingsService;
1650
3046
  /**
1651
3047
  * Crea una nueva instancia del SDK
1652
3048
  *
@@ -1684,4 +3080,4 @@ declare class UtiliaSDK {
1684
3080
  get oauth(): OAuthService;
1685
3081
  }
1686
3082
 
1687
- export { type AddMessageInput, type AiJobStatus, type AiSuggestInput, type AiSuggestions, type AiUserAction, type CreateTicketInput, type CreateTicketUser, type CreatedMessage, type CreatedTicket, ErrorCode, type ErrorFilters, type ErrorHttpMethod, type ErrorSeverity, type ErrorStats, type ExternalUser, type FileQuota, FileTokenStorage, type GetSuggestionsOptions, type IdentifyUserInput, type LoginUrlResult, MemoryTokenStorage, type MessageAuthor, type OAuthConfig, OAuthService, type OAuthTokens, type OAuthUserInfo, type PKCEChallenge, type PaginatedResponse, type PaginationMeta, type PendingOAuthState, type PopupLoginOptions, type ReportErrorInput, type ReportedError, type RequestConfig, SDK_LIMITS, 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 UploadFileOptions, 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 };