OTSkit.ts
← Paquetes·v0.5.0

@otskit/client

SDK TypeScript para sellar hashes, actualizar pruebas pendientes y verificar attestations Bitcoin. Usa @otskit/core por debajo y añade calendarios, red, resiliencia y helpers para producción.

Production-readystamp / upgrade / verifyCircuit breakerRetry + backoffAbortControllerNode ≥ 20MIT

Cuándo usarlo

Cuándo usarlo

Si eres developer y quieres usar OTSkit en una aplicación real, empieza aquí.

Sellar un archivo real contra calendarios OpenTimestamps
Hacer stamp → upgrade → verify
Integrarlo en un backend o CLI
Controlar retries, timeouts y calendarios
Manipular .ots a bajo nivelMejor → core
Sin dependencias externas salvo @otskit/core. No es "zero deps" como core, pero tampoco añade nada que no necesites.

El ciclo

El ciclo completo

hashFile()stamp().ots pendingupgrade().ots confirmedverify()
hashFile()
SHA-256 en streaming, localmente. El archivo no sale de tu máquina.
stamp()
Envía el hash a los calendarios. Devuelve una prueba pending en milisegundos.
.ots pending
Estado normal. Bitcoin aún no ha incluido el hash en un bloque.
upgrade()
Consulta los calendarios más tarde. Fusiona la attestation Bitcoin en la prueba.
.ots confirmed
La prueba es completa. Tiene una attestation Bitcoin verificable offline.
verify()
Comprueba la prueba contra Bitcoin. Devuelve { valid, blockHeight, timestamp }.

Instalación

Instalación

$ npm install @otskit/client
$ pnpm add @otskit/client
$ yarn add @otskit/client

Incluye @otskit/core automáticamente.

Quick start

Quick start

Flujo completo: stamp → upgrade → verify

El flujo habitual en producción. hashFile calcula el SHA-256 localmente, stamp sella contra calendarios, upgrade recoge la confirmación Bitcoin y verify comprueba la prueba.

workflow.tsnode
import { OpenTimestampsClient, hashFile } from '@otskit/client'
import { writeFileSync } from 'fs'

const client = new OpenTimestampsClient()

const hash = await hashFile('contract.pdf')       // streaming SHA-256

const pending = await client.stamp(hash)           // milisegundos
writeFileSync('contract.pdf.ots', pending)

const upgraded = await client.upgrade(pending)     // ~60 min después
writeFileSync('contract.pdf.ots', upgraded)

const result = await client.verify(upgraded, hash)
if (result.valid) {
  console.log('Block:', result.blockHeight)
  console.log('Time: ', new Date(result.timestamp! * 1000).toISOString())
}
user@host:~/project$ node workflow.ts
Block: 848201
Time: 2024-06-14T02:13:20.000Z

Manejo de errores tipado

Cada tipo de fallo tiene su clase. verify() nunca lanza por una prueba inválida — devuelve {valid: false}.

errors.tstypescript
import { StampError, ValidationError, CircuitBreakerError } from '@otskit/client'

try {
  await client.stamp(hash)
} catch (err) {
  if (err instanceof ValidationError)     { /* hash inválido */ }
  if (err instanceof StampError)          { console.log(err.successfulSubmissions) }
  if (err instanceof CircuitBreakerError) { /* calendario aislado */ }
}

Pending no es error

Pending no es error

Después de stamp(), la prueba queda pending: los calendarios ya conocen tu hash, pero Bitcoin aún no lo ha incluido en un bloque. Eso es normal. Reintenta upgrade() más tarde — típicamente después de ~60 minutos.
check-pending.tstypescript
import { DetachedTimestampFile } from '@otskit/core'

const proof = new Uint8Array(readFileSync('contract.pdf.ots'))
const dtf = DetachedTimestampFile.deserialize(proof)

if (!dtf.timestamp.isTimestampComplete()) {
  console.log('Pendiente — reintenta upgrade() en ~60 min')
} else {
  console.log('Confirmado en Bitcoin')
}

Resiliencia

Resiliencia

El diferencial de client sobre core: red con comportamiento de producción. Cada operación puede sobrevivir a fallos de calendarios individuales sin afectar al resultado.

Circuit breaker por calendario

Un calendario roto se aísla automáticamente. No afecta a los demás ni bloquea la operación.

Retry con backoff

Reintentos con backoff exponencial, linear o constante. Jitter configurable para evitar tormentas.

Threshold submissions

stamp() puede exigir N de M calendarios exitosos. Tú decides cuánta redundancia necesitas.

Dual timeouts

Timeout total para la operación completa y timeout por intento de red. Ambos configurables.

Fail-fast 4xx

Los errores de cliente (400, 401, 404…) no se reintentan. Solo fallan los 5xx y errores de red.

AbortController

Cualquier operación en curso se puede cancelar limpiamente pasando tu propio signal.

Seguridad

Seguridad

Client no custodia nada ni requiere cuenta. El diseño de seguridad es el mismo que el del protocolo: sin servidores de confianza propios.

El archivo no se sube

hashFile() lee el archivo localmente y calcula SHA-256 en streaming. Solo el hash sale de tu máquina.

stamp() recibe hash

Envía el hash (Uint8Array o hex) a los calendarios, nunca el archivo original.

Calendarios con whitelist

upgrade() solo consulta los calendarios ya presentes en la prueba y valida las URLs contra una whitelist.

verify() sin red propietaria

Valida la prueba contra Esplora / Bitcoin directamente. Sin pasar por servidores de OTSkit.

Config avanzada

Configuración avanzada

Todos los parámetros son opcionales. Los valores por defecto funcionan para producción con los cuatro calendarios públicos.

config.tstypescript
const client = new OpenTimestampsClient({
  minimumSuccessfulSubmissions: 2,   // 2 de 4 calendarios

  resilience: {
    retries: {
      maxAttempts: 3,
      backoff: { type: 'exponential', jitter: 'full', baseMs: 1000, maxMs: 30000 }
    },
    circuitBreaker: {
      failureThreshold: 5,
      recoveryTimeoutMs: 30000,
      halfOpenMaxCalls: 2
    },
    timeout: { totalTimeoutMs: 30000, connectTimeoutMs: 10000 }
  },

  logger: console,          // cualquier objeto { info, warn, error }
  signal: abortController.signal,
})

Errores tipados

Errores tipados

verify() no lanza por una prueba inválida — devuelve {valid: false, error}. Los throws son para fallos inesperados de red o input malformado.

ValidationError

Hash malformado, prueba corrupta u otro input inválido. No tiene sentido reintentar.

StampError

stamp() no alcanzó el mínimo de calendarios exitosos. Incluye successfulSubmissions.

UpgradeError

No se pudo consultar ningún calendario durante el upgrade. Puede reintentarse más tarde.

NetworkError

Fallo de red no recuperable después de agotar los reintentos configurados.

CircuitBreakerError

El calendario está aislado por su circuit breaker. Se recupera solo tras recoveryTimeoutMs.

verify() no lanza

Una prueba inválida devuelve { valid: false, error }. Los throws son para fallos de red o input malformado.

API surface

API surface

OpenTimestampsClient

new OpenTimestampsClient(config?)Crea el cliente con configuración opcional
.stamp(hash)Envía hash a calendarios, devuelve prueba pending (Uint8Array)
.upgrade(proof)Actualiza prueba pendiente con attestation Bitcoin
.verify(proof, originalHash?)Verifica la prueba. Devuelve { valid, blockHeight, timestamp }
.getCircuitState(url)Estado del circuit breaker para un calendario
.resetCircuit(url)Resetea manualmente el circuit breaker de un calendario

Helpers

hashFile(path)SHA-256 en streaming de un archivo local
hashBuffer(data)SHA-256 de un Uint8Array o Buffer ya en memoria

Avanzado

CalendarClientCliente de bajo nivel para un calendario concreto
EsploraClientCliente para consultar Bitcoin via API Esplora
ResilientNetworkLayerCapa de red con retry, circuit breaker y timeouts

Siguiente paso

¿Quieres usarlo desde Claude, Codex u otro agente AI? Sigue con @otskit/mcp.

@otskit/mcp — Servidor MCP para agentes AI →