@otskit/client 0.4.0 → 0.6.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
  */
@@ -133,12 +139,13 @@ declare const DEFAULT_RESILIENCE: ResilienceOptions;
133
139
  * ```
134
140
  */
135
141
  declare class OpenTimestampsClient {
136
- private calendars;
137
- private networkLayer;
138
- private logger?;
139
- private globalSignal?;
140
- private minimumSuccessfulSubmissions;
141
- private allowPrivateCalendars;
142
+ private readonly calendars;
143
+ private readonly networkLayer;
144
+ private readonly logger?;
145
+ private readonly globalSignal?;
146
+ private readonly minimumSuccessfulSubmissions;
147
+ private readonly allowPrivateCalendars;
148
+ private readonly esploraUrl;
142
149
  /**
143
150
  * Create a new OpenTimestamps client
144
151
  *
@@ -181,7 +188,7 @@ declare class OpenTimestampsClient {
181
188
  * const upgradedProof = await client.upgrade(incompleteProof)
182
189
  *
183
190
  * // If upgrade throws UpgradeError, Bitcoin hasn't confirmed yet
184
- * // Retry later (typically 10-60 minutes after stamp)
191
+ * // Retry later (typically ~60 minutes after stamp)
185
192
  * ```
186
193
  */
187
194
  upgrade(incompleteProof: Buffer, options?: OperationOptions): Promise<Buffer>;
@@ -244,7 +251,7 @@ declare class ValidationError extends OpenTimestampsClientError {
244
251
  declare class StampError extends OpenTimestampsClientError {
245
252
  readonly successfulSubmissions: Array<{
246
253
  calendar: string;
247
- proof?: Buffer;
254
+ proof?: Uint8Array;
248
255
  }>;
249
256
  readonly failedSubmissions: Array<{
250
257
  calendar: string;
@@ -252,7 +259,7 @@ declare class StampError extends OpenTimestampsClientError {
252
259
  }>;
253
260
  constructor(message: string, successful: Array<{
254
261
  calendar: string;
255
- proof?: Buffer;
262
+ proof?: Uint8Array;
256
263
  }>, failed: Array<{
257
264
  calendar: string;
258
265
  error: Error;
@@ -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;
@@ -324,9 +330,9 @@ interface FetchResponse {
324
330
  }
325
331
 
326
332
  declare class ResilientNetworkLayer {
327
- private options;
328
- private logger?;
329
- private circuitBreaker;
333
+ private readonly options;
334
+ private readonly logger?;
335
+ private readonly circuitBreaker;
330
336
  constructor(options: ResilienceOptions, logger?: Logger | undefined);
331
337
  /**
332
338
  * Execute a request with full resilience pipeline
@@ -341,30 +347,33 @@ 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
  }
@@ -379,32 +388,38 @@ declare const DEFAULT_CALENDAR_WHITELIST: UrlWhitelist;
379
388
  */
380
389
  declare const DEFAULT_AGGREGATORS: readonly string[];
381
390
 
382
- /** Explorador Esplora público por defecto (Bitcoin mainnet). */
391
+ /** Default public Esplora explorer (Bitcoin mainnet). */
383
392
  declare const PUBLIC_ESPLORA_URL = "https://blockstream.info/api";
384
- /** 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. */
385
394
  declare const MAX_ESPLORA_RESPONSE_SIZE = 100000;
386
395
  interface EsploraClientOptions {
387
- /** 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. */
388
397
  url?: string;
389
398
  logger?: Logger;
390
399
  }
391
- /** Cliente de un explorador Esplora remoto. */
400
+ /** Client for a remote Esplora explorer. */
392
401
  declare class EsploraClient {
393
402
  #private;
394
403
  constructor(networkLayer: ResilientNetworkLayer, options?: EsploraClientOptions);
395
- /** 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. */
396
405
  blockHash(height: number, signal?: AbortSignal): Promise<string>;
397
- /** Devuelve la cabecera del bloque (merkleroot + time) dado su hash. */
406
+ /** Returns the block header (merkle root + timestamp) for the given hash. */
398
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>;
399
414
  }
400
415
  /**
401
- * Verifica una atestación Bitcoin/Litecoin contra la cabecera del bloque correspondiente.
416
+ * Verifies a Bitcoin/Litecoin attestation against the corresponding block header.
402
417
  *
403
- * `digest` es el commitment final del árbol del timestamp en el punto de la atestación
404
- * (32 bytes, debe ser el merkleroot del bloque). `explorer` debe apuntar a la cadena de la
405
- * atestación (Blockstream para Bitcoin; un Esplora de Litecoin para Litecoin). Devuelve el
406
- * tiempo del bloque (epoch s) en éxito; lanza `VerificationError` si no coincide o si la
407
- * 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.
408
423
  */
409
424
  declare function verifyTimestampAttestation(digest: Uint8Array, attestation: Attestation, explorer: EsploraClient, signal?: AbortSignal): Promise<number>;
410
425
 
@@ -412,21 +427,21 @@ declare function hashBuffer(data: Buffer | Uint8Array): Buffer;
412
427
  declare function hashFile(path: string): Promise<Buffer>;
413
428
 
414
429
  /**
415
- * SSRF protection para calendarios configurables por el usuario.
430
+ * SSRF protection for user-configurable calendar URLs.
416
431
  *
417
- * LIMITACIONES (documentadas intencionalmente):
418
- * - TOCTOU/DNS rebinding: la validación DNS ocurre ANTES de la conexión.
419
- * Un servidor con TTL=0 puede cambiar la IP entre la validación y el fetch.
420
- * Mitigación real requiere egress filtering a nivel de red.
421
- * - IPv4-mapped IPv6 (::ffff:x.x.x.x): se bloquea el prefijo ::ffff:
422
- * 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.
423
438
  */
424
439
  /**
425
- * Valida que una URL de calendario es segura para hacer outbound HTTP.
426
- * 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.
427
442
  *
428
- * @param allowPrivate Si true, omite la comprobación de rangos IP.
429
- * Ú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.
430
445
  */
431
446
  declare function assertSafeCalendarUrl(url: string, options: {
432
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
  */
@@ -133,12 +139,13 @@ declare const DEFAULT_RESILIENCE: ResilienceOptions;
133
139
  * ```
134
140
  */
135
141
  declare class OpenTimestampsClient {
136
- private calendars;
137
- private networkLayer;
138
- private logger?;
139
- private globalSignal?;
140
- private minimumSuccessfulSubmissions;
141
- private allowPrivateCalendars;
142
+ private readonly calendars;
143
+ private readonly networkLayer;
144
+ private readonly logger?;
145
+ private readonly globalSignal?;
146
+ private readonly minimumSuccessfulSubmissions;
147
+ private readonly allowPrivateCalendars;
148
+ private readonly esploraUrl;
142
149
  /**
143
150
  * Create a new OpenTimestamps client
144
151
  *
@@ -181,7 +188,7 @@ declare class OpenTimestampsClient {
181
188
  * const upgradedProof = await client.upgrade(incompleteProof)
182
189
  *
183
190
  * // If upgrade throws UpgradeError, Bitcoin hasn't confirmed yet
184
- * // Retry later (typically 10-60 minutes after stamp)
191
+ * // Retry later (typically ~60 minutes after stamp)
185
192
  * ```
186
193
  */
187
194
  upgrade(incompleteProof: Buffer, options?: OperationOptions): Promise<Buffer>;
@@ -244,7 +251,7 @@ declare class ValidationError extends OpenTimestampsClientError {
244
251
  declare class StampError extends OpenTimestampsClientError {
245
252
  readonly successfulSubmissions: Array<{
246
253
  calendar: string;
247
- proof?: Buffer;
254
+ proof?: Uint8Array;
248
255
  }>;
249
256
  readonly failedSubmissions: Array<{
250
257
  calendar: string;
@@ -252,7 +259,7 @@ declare class StampError extends OpenTimestampsClientError {
252
259
  }>;
253
260
  constructor(message: string, successful: Array<{
254
261
  calendar: string;
255
- proof?: Buffer;
262
+ proof?: Uint8Array;
256
263
  }>, failed: Array<{
257
264
  calendar: string;
258
265
  error: Error;
@@ -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;
@@ -324,9 +330,9 @@ interface FetchResponse {
324
330
  }
325
331
 
326
332
  declare class ResilientNetworkLayer {
327
- private options;
328
- private logger?;
329
- private circuitBreaker;
333
+ private readonly options;
334
+ private readonly logger?;
335
+ private readonly circuitBreaker;
330
336
  constructor(options: ResilienceOptions, logger?: Logger | undefined);
331
337
  /**
332
338
  * Execute a request with full resilience pipeline
@@ -341,30 +347,33 @@ 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
  }
@@ -379,32 +388,38 @@ declare const DEFAULT_CALENDAR_WHITELIST: UrlWhitelist;
379
388
  */
380
389
  declare const DEFAULT_AGGREGATORS: readonly string[];
381
390
 
382
- /** Explorador Esplora público por defecto (Bitcoin mainnet). */
391
+ /** Default public Esplora explorer (Bitcoin mainnet). */
383
392
  declare const PUBLIC_ESPLORA_URL = "https://blockstream.info/api";
384
- /** 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. */
385
394
  declare const MAX_ESPLORA_RESPONSE_SIZE = 100000;
386
395
  interface EsploraClientOptions {
387
- /** 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. */
388
397
  url?: string;
389
398
  logger?: Logger;
390
399
  }
391
- /** Cliente de un explorador Esplora remoto. */
400
+ /** Client for a remote Esplora explorer. */
392
401
  declare class EsploraClient {
393
402
  #private;
394
403
  constructor(networkLayer: ResilientNetworkLayer, options?: EsploraClientOptions);
395
- /** 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. */
396
405
  blockHash(height: number, signal?: AbortSignal): Promise<string>;
397
- /** Devuelve la cabecera del bloque (merkleroot + time) dado su hash. */
406
+ /** Returns the block header (merkle root + timestamp) for the given hash. */
398
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>;
399
414
  }
400
415
  /**
401
- * Verifica una atestación Bitcoin/Litecoin contra la cabecera del bloque correspondiente.
416
+ * Verifies a Bitcoin/Litecoin attestation against the corresponding block header.
402
417
  *
403
- * `digest` es el commitment final del árbol del timestamp en el punto de la atestación
404
- * (32 bytes, debe ser el merkleroot del bloque). `explorer` debe apuntar a la cadena de la
405
- * atestación (Blockstream para Bitcoin; un Esplora de Litecoin para Litecoin). Devuelve el
406
- * tiempo del bloque (epoch s) en éxito; lanza `VerificationError` si no coincide o si la
407
- * 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.
408
423
  */
409
424
  declare function verifyTimestampAttestation(digest: Uint8Array, attestation: Attestation, explorer: EsploraClient, signal?: AbortSignal): Promise<number>;
410
425
 
@@ -412,21 +427,21 @@ declare function hashBuffer(data: Buffer | Uint8Array): Buffer;
412
427
  declare function hashFile(path: string): Promise<Buffer>;
413
428
 
414
429
  /**
415
- * SSRF protection para calendarios configurables por el usuario.
430
+ * SSRF protection for user-configurable calendar URLs.
416
431
  *
417
- * LIMITACIONES (documentadas intencionalmente):
418
- * - TOCTOU/DNS rebinding: la validación DNS ocurre ANTES de la conexión.
419
- * Un servidor con TTL=0 puede cambiar la IP entre la validación y el fetch.
420
- * Mitigación real requiere egress filtering a nivel de red.
421
- * - IPv4-mapped IPv6 (::ffff:x.x.x.x): se bloquea el prefijo ::ffff:
422
- * 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.
423
438
  */
424
439
  /**
425
- * Valida que una URL de calendario es segura para hacer outbound HTTP.
426
- * 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.
427
442
  *
428
- * @param allowPrivate Si true, omite la comprobación de rangos IP.
429
- * Ú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.
430
445
  */
431
446
  declare function assertSafeCalendarUrl(url: string, options: {
432
447
  allowPrivate: boolean;