@otskit/client 0.3.0 → 0.5.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.cts CHANGED
@@ -4,7 +4,7 @@ export { Attestation, BitcoinAttestation, DetachedTimestampFile, PendingAttestat
4
4
  /**
5
5
  * Type definitions for the OpenTimestamps Client SDK
6
6
  */
7
- /** Logger interface for observability */
7
+ /** Logger interface for observability. */
8
8
  interface Logger {
9
9
  debug(message: string, ...args: unknown[]): void;
10
10
  info(message: string, ...args: unknown[]): void;
@@ -39,7 +39,7 @@ interface ResilienceOptions {
39
39
  connectTimeoutMs: number;
40
40
  retries: RetryOptions;
41
41
  circuitBreaker: CircuitBreakerOptions;
42
- /** Límite de bytes para el body de la respuesta. Default 100 KB. */
42
+ /** Maximum bytes allowed in the response body. Defaults to 100 KB. */
43
43
  maxResponseBytes?: number;
44
44
  }
45
45
  /** Client configuration options */
@@ -55,12 +55,18 @@ interface ClientOptions {
55
55
  /** Minimum successful calendar submissions required (default: 2) */
56
56
  minimumSuccessfulSubmissions?: number;
57
57
  /**
58
- * Permite URLs de calendario que resuelven a IPs privadas/reservadas.
58
+ * Base URL for the Esplora block explorer used by verify().
59
+ * Defaults to Blockstream (https://blockstream.info/api).
60
+ * Override to use a self-hosted or alternative explorer.
61
+ */
62
+ esploraUrl?: string;
63
+ /**
64
+ * Allows calendar URLs that resolve to private/reserved IPs.
59
65
  *
60
- * **No activar en producción.** Útil para testing local o redes corporativas.
66
+ * **Do not enable in production.** Useful for local testing or corporate networks.
61
67
  *
62
- * Incluso con `false`, la protección es best-effort contra DNS rebinding (TOCTOU).
63
- * Para alta seguridad, complementar con egress filtering a nivel de red.
68
+ * Even when `false`, protection is best-effort against DNS rebinding (TOCTOU).
69
+ * For high-security environments, complement with network-level egress filtering.
64
70
  *
65
71
  * @default false
66
72
  */
@@ -99,7 +105,7 @@ interface VerificationNetworkError {
99
105
  type VerificationResult = VerificationSuccess | VerificationPending | VerificationInvalid | VerificationNetworkError;
100
106
  /** Type guard — verdadero si la verificación fue exitosa. */
101
107
  declare const isVerified: (r: VerificationResult) => r is VerificationSuccess;
102
- /** Default calendar servers */
108
+ /** Default calendar servers. Sourced from @otskit/core (single source of truth). */
103
109
  declare const DEFAULT_CALENDARS: string[];
104
110
  /** Default resilience configuration */
105
111
  declare const DEFAULT_RESILIENCE: ResilienceOptions;
@@ -139,6 +145,7 @@ declare class OpenTimestampsClient {
139
145
  private globalSignal?;
140
146
  private minimumSuccessfulSubmissions;
141
147
  private allowPrivateCalendars;
148
+ private esploraUrl;
142
149
  /**
143
150
  * Create a new OpenTimestamps client
144
151
  *
@@ -265,7 +272,7 @@ declare class UpgradeError extends OpenTimestampsClientError {
265
272
  }
266
273
  /** Network-related error (timeout, all retries failed, etc.) */
267
274
  declare class NetworkError extends OpenTimestampsClientError {
268
- /** HTTP status code, cuando el fallo viene de una respuesta HTTP. */
275
+ /** HTTP status code when the failure originates from an HTTP response. */
269
276
  readonly status?: number;
270
277
  constructor(message: string, options?: {
271
278
  cause?: Error;
@@ -276,16 +283,16 @@ declare class NetworkError extends OpenTimestampsClientError {
276
283
  declare class CircuitBreakerError extends NetworkError {
277
284
  constructor(calendar: string);
278
285
  }
279
- /** El calendario no conoce (todavía) el commitment consultado (HTTP 404). */
286
+ /** The calendar does not yet know the queried commitment (HTTP 404). */
280
287
  declare class CommitmentNotFoundError extends NetworkError {
281
288
  }
282
- /** La respuesta del calendario supera el límite de tamaño permitido (defensa DoS). */
289
+ /** The calendar response exceeds the allowed size limit (DoS defense). */
283
290
  declare class CalendarResponseTooLargeError extends NetworkError {
284
291
  }
285
- /** Respuesta del explorador Esplora inválida: vacía, no-JSON, malformada o demasiado grande (defensa DoS). */
292
+ /** Invalid Esplora response: empty, non-JSON, malformed, or too large (DoS defense). */
286
293
  declare class EsploraResponseError extends NetworkError {
287
294
  }
288
- /** La respuesta supera el límite de bytes permitido (defensa DoS). */
295
+ /** Response exceeds the allowed byte limit (DoS defense). */
289
296
  declare class SizeLimitExceededError extends NetworkError {
290
297
  readonly maxBytes: number;
291
298
  readonly actualBytes?: number;
@@ -306,8 +313,7 @@ declare enum CircuitState {
306
313
  }
307
314
 
308
315
  /**
309
- * Universal fetch adapter para compatibilidad multi-runtime.
310
- * Funciona en Node.js 18+, browsers y edge runtimes.
316
+ * Fetch adapter for Node.js 20+.
311
317
  */
312
318
  interface FetchRequest {
313
319
  url: string;
@@ -341,64 +347,79 @@ declare class ResilientNetworkLayer {
341
347
  }
342
348
 
343
349
  /**
344
- * Cliente de un calendario remoto OpenTimestamps (protocolo OTS real).
350
+ * Remote OpenTimestamps calendar client (real OTS protocol).
345
351
  */
346
352
 
347
- /** Limite de tamano de la respuesta de un calendario (defensa DoS). */
353
+ /** Maximum response size from a calendar server (DoS defense). */
348
354
  declare const MAX_CALENDAR_RESPONSE_SIZE = 10000;
349
- /** Interfaz con un servidor de calendario remoto. */
355
+ /** Interface to a remote calendar server. */
350
356
  declare class CalendarClient {
351
357
  #private;
352
358
  private readonly url;
353
359
  private readonly networkLayer;
354
360
  private readonly logger?;
355
361
  constructor(url: string, networkLayer: ResilientNetworkLayer, logger?: Logger | undefined);
356
- /** Envia un digest al calendario y devuelve el Timestamp que lo commit-ea. */
362
+ /** Submits a digest to the calendar and returns the Timestamp that commits to it. */
357
363
  submit(digest: Uint8Array, signal?: AbortSignal): Promise<Timestamp>;
358
- /** Pregunta al calendario si tiene un Timestamp mas completo para `commitment` (upgrade). */
364
+ /** Asks the calendar for a more complete Timestamp for `commitment` (upgrade). */
359
365
  getTimestamp(commitment: Uint8Array, signal?: AbortSignal): Promise<Timestamp>;
360
366
  }
361
- /** Lista blanca de URLs de calendario de confianza. */
367
+ /** Allowlist of trusted calendar URLs. */
362
368
  declare class UrlWhitelist {
363
369
  #private;
364
370
  constructor(urls?: readonly string[]);
365
- /** Anade un patron; si no trae esquema, se anaden las variantes http y https. */
371
+ /**
372
+ * Adds a pattern. If the URL has no scheme, both http:// and https:// variants are added.
373
+ * Throws TypeError if the pattern is not a valid string or is structurally invalid.
374
+ */
366
375
  add(url: string): void;
367
- /** Verdadero si `url` casa con algun patron de la whitelist. */
376
+ /** Returns true if `url` matches any pattern in the allowlist. */
368
377
  contains(url: string): boolean;
369
378
  toString(): string;
370
379
  }
371
- /** Calendarios de confianza por defecto para verificacion/upgrade. */
380
+ /**
381
+ * Default trusted calendars for verification/upgrade.
382
+ * Patterns sourced from @otskit/core (single source of truth).
383
+ */
372
384
  declare const DEFAULT_CALENDAR_WHITELIST: UrlWhitelist;
373
- /** Agregadores por defecto a los que enviar digests al sellar. */
385
+ /**
386
+ * Default aggregators to submit digests to when stamping.
387
+ * Sourced from @otskit/core (single source of truth).
388
+ */
374
389
  declare const DEFAULT_AGGREGATORS: readonly string[];
375
390
 
376
- /** Explorador Esplora público por defecto (Bitcoin mainnet). */
391
+ /** Default public Esplora explorer (Bitcoin mainnet). */
377
392
  declare const PUBLIC_ESPLORA_URL = "https://blockstream.info/api";
378
- /** Límite de tamaño de una respuesta de Esplora (defensa DoS). Una cabecera JSON ronda los cientos de bytes. */
393
+ /** Maximum size of an Esplora response (DoS defense). A JSON block header is a few hundred bytes. */
379
394
  declare const MAX_ESPLORA_RESPONSE_SIZE = 100000;
380
395
  interface EsploraClientOptions {
381
- /** URL base del explorador (por defecto Blockstream). Útil para apuntar a un Esplora de Litecoin. */
396
+ /** Base URL of the explorer (defaults to Blockstream). Useful for pointing to a Litecoin Esplora. */
382
397
  url?: string;
383
398
  logger?: Logger;
384
399
  }
385
- /** Cliente de un explorador Esplora remoto. */
400
+ /** Client for a remote Esplora explorer. */
386
401
  declare class EsploraClient {
387
402
  #private;
388
403
  constructor(networkLayer: ResilientNetworkLayer, options?: EsploraClientOptions);
389
- /** Devuelve el hash (hex 64, minúsculas) del bloque a la altura dada. */
404
+ /** Returns the block hash (64-char hex, lowercase) at the given height. */
390
405
  blockHash(height: number, signal?: AbortSignal): Promise<string>;
391
- /** Devuelve la cabecera del bloque (merkleroot + time) dado su hash. */
406
+ /** Returns the block header (merkle root + timestamp) for the given hash. */
392
407
  block(hash: string, signal?: AbortSignal): Promise<BlockHeader>;
408
+ /**
409
+ * Fetches the raw 80-byte block header for `hash` and self-authenticates it:
410
+ * sha256d(rawHeader) reversed must equal `hash`. This removes trust in the explorer's
411
+ * JSON layer — the raw header is cryptographically bound to the block hash we requested.
412
+ */
413
+ rawBlockHeader(hash: string, signal?: AbortSignal): Promise<Uint8Array>;
393
414
  }
394
415
  /**
395
- * Verifica una atestación Bitcoin/Litecoin contra la cabecera del bloque correspondiente.
416
+ * Verifies a Bitcoin/Litecoin attestation against the corresponding block header.
396
417
  *
397
- * `digest` es el commitment final del árbol del timestamp en el punto de la atestación
398
- * (32 bytes, debe ser el merkleroot del bloque). `explorer` debe apuntar a la cadena de la
399
- * atestación (Blockstream para Bitcoin; un Esplora de Litecoin para Litecoin). Devuelve el
400
- * tiempo del bloque (epoch s) en éxito; lanza `VerificationError` si no coincide o si la
401
- * atestación no es verificable en cadena (`pending`/`unknown`). Fail-closed.
418
+ * `digest` is the final tree commitment at the attestation point (32 bytes, must equal the
419
+ * block's merkle root). `explorer` must point to the correct chain (Blockstream for Bitcoin;
420
+ * a Litecoin Esplora for Litecoin). Returns the block time (epoch seconds) on success;
421
+ * throws `VerificationError` if the digest does not match or the attestation is not
422
+ * on-chain verifiable (`pending`/`unknown`). Fail-closed.
402
423
  */
403
424
  declare function verifyTimestampAttestation(digest: Uint8Array, attestation: Attestation, explorer: EsploraClient, signal?: AbortSignal): Promise<number>;
404
425
 
@@ -406,21 +427,21 @@ declare function hashBuffer(data: Buffer | Uint8Array): Buffer;
406
427
  declare function hashFile(path: string): Promise<Buffer>;
407
428
 
408
429
  /**
409
- * SSRF protection para calendarios configurables por el usuario.
430
+ * SSRF protection for user-configurable calendar URLs.
410
431
  *
411
- * LIMITACIONES (documentadas intencionalmente):
412
- * - TOCTOU/DNS rebinding: la validación DNS ocurre ANTES de la conexión.
413
- * Un servidor con TTL=0 puede cambiar la IP entre la validación y el fetch.
414
- * Mitigación real requiere egress filtering a nivel de red.
415
- * - IPv4-mapped IPv6 (::ffff:x.x.x.x): se bloquea el prefijo ::ffff:
416
- * pero la validación del componente IPv4 depende del formato que devuelva Node.js.
432
+ * KNOWN LIMITATIONS (documented intentionally):
433
+ * - TOCTOU / DNS rebinding: DNS validation happens BEFORE the connection.
434
+ * A server with TTL=0 can change its IP between validation and the actual fetch.
435
+ * Real mitigation requires network-level egress filtering.
436
+ * - IPv4-mapped IPv6 (::ffff:x.x.x.x): the ::ffff: prefix is blocked but the
437
+ * IPv4 component validation depends on the format Node.js returns.
417
438
  */
418
439
  /**
419
- * Valida que una URL de calendario es segura para hacer outbound HTTP.
420
- * Bloquea IPs privadas/reservadas por defecto.
440
+ * Validates that a calendar URL is safe for outbound HTTP requests.
441
+ * Blocks private/reserved IPs by default.
421
442
  *
422
- * @param allowPrivate Si true, omite la comprobación de rangos IP.
423
- * Útil para testing local o redes corporativas internas.
443
+ * @param allowPrivate When true, skips the IP range check.
444
+ * Useful for local testing or internal corporate networks.
424
445
  */
425
446
  declare function assertSafeCalendarUrl(url: string, options: {
426
447
  allowPrivate: boolean;
package/dist/index.d.ts CHANGED
@@ -4,7 +4,7 @@ export { Attestation, BitcoinAttestation, DetachedTimestampFile, PendingAttestat
4
4
  /**
5
5
  * Type definitions for the OpenTimestamps Client SDK
6
6
  */
7
- /** Logger interface for observability */
7
+ /** Logger interface for observability. */
8
8
  interface Logger {
9
9
  debug(message: string, ...args: unknown[]): void;
10
10
  info(message: string, ...args: unknown[]): void;
@@ -39,7 +39,7 @@ interface ResilienceOptions {
39
39
  connectTimeoutMs: number;
40
40
  retries: RetryOptions;
41
41
  circuitBreaker: CircuitBreakerOptions;
42
- /** Límite de bytes para el body de la respuesta. Default 100 KB. */
42
+ /** Maximum bytes allowed in the response body. Defaults to 100 KB. */
43
43
  maxResponseBytes?: number;
44
44
  }
45
45
  /** Client configuration options */
@@ -55,12 +55,18 @@ interface ClientOptions {
55
55
  /** Minimum successful calendar submissions required (default: 2) */
56
56
  minimumSuccessfulSubmissions?: number;
57
57
  /**
58
- * Permite URLs de calendario que resuelven a IPs privadas/reservadas.
58
+ * Base URL for the Esplora block explorer used by verify().
59
+ * Defaults to Blockstream (https://blockstream.info/api).
60
+ * Override to use a self-hosted or alternative explorer.
61
+ */
62
+ esploraUrl?: string;
63
+ /**
64
+ * Allows calendar URLs that resolve to private/reserved IPs.
59
65
  *
60
- * **No activar en producción.** Útil para testing local o redes corporativas.
66
+ * **Do not enable in production.** Useful for local testing or corporate networks.
61
67
  *
62
- * Incluso con `false`, la protección es best-effort contra DNS rebinding (TOCTOU).
63
- * Para alta seguridad, complementar con egress filtering a nivel de red.
68
+ * Even when `false`, protection is best-effort against DNS rebinding (TOCTOU).
69
+ * For high-security environments, complement with network-level egress filtering.
64
70
  *
65
71
  * @default false
66
72
  */
@@ -99,7 +105,7 @@ interface VerificationNetworkError {
99
105
  type VerificationResult = VerificationSuccess | VerificationPending | VerificationInvalid | VerificationNetworkError;
100
106
  /** Type guard — verdadero si la verificación fue exitosa. */
101
107
  declare const isVerified: (r: VerificationResult) => r is VerificationSuccess;
102
- /** Default calendar servers */
108
+ /** Default calendar servers. Sourced from @otskit/core (single source of truth). */
103
109
  declare const DEFAULT_CALENDARS: string[];
104
110
  /** Default resilience configuration */
105
111
  declare const DEFAULT_RESILIENCE: ResilienceOptions;
@@ -139,6 +145,7 @@ declare class OpenTimestampsClient {
139
145
  private globalSignal?;
140
146
  private minimumSuccessfulSubmissions;
141
147
  private allowPrivateCalendars;
148
+ private esploraUrl;
142
149
  /**
143
150
  * Create a new OpenTimestamps client
144
151
  *
@@ -265,7 +272,7 @@ declare class UpgradeError extends OpenTimestampsClientError {
265
272
  }
266
273
  /** Network-related error (timeout, all retries failed, etc.) */
267
274
  declare class NetworkError extends OpenTimestampsClientError {
268
- /** HTTP status code, cuando el fallo viene de una respuesta HTTP. */
275
+ /** HTTP status code when the failure originates from an HTTP response. */
269
276
  readonly status?: number;
270
277
  constructor(message: string, options?: {
271
278
  cause?: Error;
@@ -276,16 +283,16 @@ declare class NetworkError extends OpenTimestampsClientError {
276
283
  declare class CircuitBreakerError extends NetworkError {
277
284
  constructor(calendar: string);
278
285
  }
279
- /** El calendario no conoce (todavía) el commitment consultado (HTTP 404). */
286
+ /** The calendar does not yet know the queried commitment (HTTP 404). */
280
287
  declare class CommitmentNotFoundError extends NetworkError {
281
288
  }
282
- /** La respuesta del calendario supera el límite de tamaño permitido (defensa DoS). */
289
+ /** The calendar response exceeds the allowed size limit (DoS defense). */
283
290
  declare class CalendarResponseTooLargeError extends NetworkError {
284
291
  }
285
- /** Respuesta del explorador Esplora inválida: vacía, no-JSON, malformada o demasiado grande (defensa DoS). */
292
+ /** Invalid Esplora response: empty, non-JSON, malformed, or too large (DoS defense). */
286
293
  declare class EsploraResponseError extends NetworkError {
287
294
  }
288
- /** La respuesta supera el límite de bytes permitido (defensa DoS). */
295
+ /** Response exceeds the allowed byte limit (DoS defense). */
289
296
  declare class SizeLimitExceededError extends NetworkError {
290
297
  readonly maxBytes: number;
291
298
  readonly actualBytes?: number;
@@ -306,8 +313,7 @@ declare enum CircuitState {
306
313
  }
307
314
 
308
315
  /**
309
- * Universal fetch adapter para compatibilidad multi-runtime.
310
- * Funciona en Node.js 18+, browsers y edge runtimes.
316
+ * Fetch adapter for Node.js 20+.
311
317
  */
312
318
  interface FetchRequest {
313
319
  url: string;
@@ -341,64 +347,79 @@ declare class ResilientNetworkLayer {
341
347
  }
342
348
 
343
349
  /**
344
- * Cliente de un calendario remoto OpenTimestamps (protocolo OTS real).
350
+ * Remote OpenTimestamps calendar client (real OTS protocol).
345
351
  */
346
352
 
347
- /** Limite de tamano de la respuesta de un calendario (defensa DoS). */
353
+ /** Maximum response size from a calendar server (DoS defense). */
348
354
  declare const MAX_CALENDAR_RESPONSE_SIZE = 10000;
349
- /** Interfaz con un servidor de calendario remoto. */
355
+ /** Interface to a remote calendar server. */
350
356
  declare class CalendarClient {
351
357
  #private;
352
358
  private readonly url;
353
359
  private readonly networkLayer;
354
360
  private readonly logger?;
355
361
  constructor(url: string, networkLayer: ResilientNetworkLayer, logger?: Logger | undefined);
356
- /** Envia un digest al calendario y devuelve el Timestamp que lo commit-ea. */
362
+ /** Submits a digest to the calendar and returns the Timestamp that commits to it. */
357
363
  submit(digest: Uint8Array, signal?: AbortSignal): Promise<Timestamp>;
358
- /** Pregunta al calendario si tiene un Timestamp mas completo para `commitment` (upgrade). */
364
+ /** Asks the calendar for a more complete Timestamp for `commitment` (upgrade). */
359
365
  getTimestamp(commitment: Uint8Array, signal?: AbortSignal): Promise<Timestamp>;
360
366
  }
361
- /** Lista blanca de URLs de calendario de confianza. */
367
+ /** Allowlist of trusted calendar URLs. */
362
368
  declare class UrlWhitelist {
363
369
  #private;
364
370
  constructor(urls?: readonly string[]);
365
- /** Anade un patron; si no trae esquema, se anaden las variantes http y https. */
371
+ /**
372
+ * Adds a pattern. If the URL has no scheme, both http:// and https:// variants are added.
373
+ * Throws TypeError if the pattern is not a valid string or is structurally invalid.
374
+ */
366
375
  add(url: string): void;
367
- /** Verdadero si `url` casa con algun patron de la whitelist. */
376
+ /** Returns true if `url` matches any pattern in the allowlist. */
368
377
  contains(url: string): boolean;
369
378
  toString(): string;
370
379
  }
371
- /** Calendarios de confianza por defecto para verificacion/upgrade. */
380
+ /**
381
+ * Default trusted calendars for verification/upgrade.
382
+ * Patterns sourced from @otskit/core (single source of truth).
383
+ */
372
384
  declare const DEFAULT_CALENDAR_WHITELIST: UrlWhitelist;
373
- /** Agregadores por defecto a los que enviar digests al sellar. */
385
+ /**
386
+ * Default aggregators to submit digests to when stamping.
387
+ * Sourced from @otskit/core (single source of truth).
388
+ */
374
389
  declare const DEFAULT_AGGREGATORS: readonly string[];
375
390
 
376
- /** Explorador Esplora público por defecto (Bitcoin mainnet). */
391
+ /** Default public Esplora explorer (Bitcoin mainnet). */
377
392
  declare const PUBLIC_ESPLORA_URL = "https://blockstream.info/api";
378
- /** Límite de tamaño de una respuesta de Esplora (defensa DoS). Una cabecera JSON ronda los cientos de bytes. */
393
+ /** Maximum size of an Esplora response (DoS defense). A JSON block header is a few hundred bytes. */
379
394
  declare const MAX_ESPLORA_RESPONSE_SIZE = 100000;
380
395
  interface EsploraClientOptions {
381
- /** URL base del explorador (por defecto Blockstream). Útil para apuntar a un Esplora de Litecoin. */
396
+ /** Base URL of the explorer (defaults to Blockstream). Useful for pointing to a Litecoin Esplora. */
382
397
  url?: string;
383
398
  logger?: Logger;
384
399
  }
385
- /** Cliente de un explorador Esplora remoto. */
400
+ /** Client for a remote Esplora explorer. */
386
401
  declare class EsploraClient {
387
402
  #private;
388
403
  constructor(networkLayer: ResilientNetworkLayer, options?: EsploraClientOptions);
389
- /** Devuelve el hash (hex 64, minúsculas) del bloque a la altura dada. */
404
+ /** Returns the block hash (64-char hex, lowercase) at the given height. */
390
405
  blockHash(height: number, signal?: AbortSignal): Promise<string>;
391
- /** Devuelve la cabecera del bloque (merkleroot + time) dado su hash. */
406
+ /** Returns the block header (merkle root + timestamp) for the given hash. */
392
407
  block(hash: string, signal?: AbortSignal): Promise<BlockHeader>;
408
+ /**
409
+ * Fetches the raw 80-byte block header for `hash` and self-authenticates it:
410
+ * sha256d(rawHeader) reversed must equal `hash`. This removes trust in the explorer's
411
+ * JSON layer — the raw header is cryptographically bound to the block hash we requested.
412
+ */
413
+ rawBlockHeader(hash: string, signal?: AbortSignal): Promise<Uint8Array>;
393
414
  }
394
415
  /**
395
- * Verifica una atestación Bitcoin/Litecoin contra la cabecera del bloque correspondiente.
416
+ * Verifies a Bitcoin/Litecoin attestation against the corresponding block header.
396
417
  *
397
- * `digest` es el commitment final del árbol del timestamp en el punto de la atestación
398
- * (32 bytes, debe ser el merkleroot del bloque). `explorer` debe apuntar a la cadena de la
399
- * atestación (Blockstream para Bitcoin; un Esplora de Litecoin para Litecoin). Devuelve el
400
- * tiempo del bloque (epoch s) en éxito; lanza `VerificationError` si no coincide o si la
401
- * atestación no es verificable en cadena (`pending`/`unknown`). Fail-closed.
418
+ * `digest` is the final tree commitment at the attestation point (32 bytes, must equal the
419
+ * block's merkle root). `explorer` must point to the correct chain (Blockstream for Bitcoin;
420
+ * a Litecoin Esplora for Litecoin). Returns the block time (epoch seconds) on success;
421
+ * throws `VerificationError` if the digest does not match or the attestation is not
422
+ * on-chain verifiable (`pending`/`unknown`). Fail-closed.
402
423
  */
403
424
  declare function verifyTimestampAttestation(digest: Uint8Array, attestation: Attestation, explorer: EsploraClient, signal?: AbortSignal): Promise<number>;
404
425
 
@@ -406,21 +427,21 @@ declare function hashBuffer(data: Buffer | Uint8Array): Buffer;
406
427
  declare function hashFile(path: string): Promise<Buffer>;
407
428
 
408
429
  /**
409
- * SSRF protection para calendarios configurables por el usuario.
430
+ * SSRF protection for user-configurable calendar URLs.
410
431
  *
411
- * LIMITACIONES (documentadas intencionalmente):
412
- * - TOCTOU/DNS rebinding: la validación DNS ocurre ANTES de la conexión.
413
- * Un servidor con TTL=0 puede cambiar la IP entre la validación y el fetch.
414
- * Mitigación real requiere egress filtering a nivel de red.
415
- * - IPv4-mapped IPv6 (::ffff:x.x.x.x): se bloquea el prefijo ::ffff:
416
- * pero la validación del componente IPv4 depende del formato que devuelva Node.js.
432
+ * KNOWN LIMITATIONS (documented intentionally):
433
+ * - TOCTOU / DNS rebinding: DNS validation happens BEFORE the connection.
434
+ * A server with TTL=0 can change its IP between validation and the actual fetch.
435
+ * Real mitigation requires network-level egress filtering.
436
+ * - IPv4-mapped IPv6 (::ffff:x.x.x.x): the ::ffff: prefix is blocked but the
437
+ * IPv4 component validation depends on the format Node.js returns.
417
438
  */
418
439
  /**
419
- * Valida que una URL de calendario es segura para hacer outbound HTTP.
420
- * Bloquea IPs privadas/reservadas por defecto.
440
+ * Validates that a calendar URL is safe for outbound HTTP requests.
441
+ * Blocks private/reserved IPs by default.
421
442
  *
422
- * @param allowPrivate Si true, omite la comprobación de rangos IP.
423
- * Útil para testing local o redes corporativas internas.
443
+ * @param allowPrivate When true, skips the IP range check.
444
+ * Useful for local testing or internal corporate networks.
424
445
  */
425
446
  declare function assertSafeCalendarUrl(url: string, options: {
426
447
  allowPrivate: boolean;