Skip to content
victrexfxPublic
forked from Dorisio/sdk

About

Typed TypeScript client + React hooks for Dorisio embed wallet-to-wallet USDC tipping into any platform.

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Β 
Β 

Latest commit

Β 

History

117 Commits

Folders and files

Repository files navigation

Dorisio SDK

Type-safe client library for Dorisio payment infrastructure. Send tips, verify wallets, and manage creator payouts on Stellar.

npm version TypeScript License: MIT

Features

✨ Production-Ready

  • Type-safe with full TypeScript support
  • Domain-specific error handling (PaymentError, WalletVerificationError, AuthError)
  • Idempotency support prevents double-charging on retries
  • Webhook signature verification for async events
  • Comprehensive examples (vanilla JS + React)

πŸš€ Developer Experience

  • Exported Zod schemas for consumer validation
  • Full JSDoc documentation with examples
  • TypeDoc API reference auto-generated
  • React hooks for seamless integration
  • 86 unit tests (100% passing)

πŸ’° Payment Features

  • Create tips with optional messages
  • Build and submit Stellar transactions
  • Check transaction confirmation status
  • Transaction history with pagination
  • Creator earnings tracking

πŸ” Security

  • Challenge-response wallet verification
  • Wallet linking with Stellar integration
  • Safe retry logic with exponential backoff
  • Constant-time signature verification

Installation

npm install dorisio-sdk

Quick Start

Vanilla JavaScript

import { DorisioClient, PaymentError, Schemas } from 'dorisio-sdk';
import { v4 as uuidv4 } from 'uuid';

const client = new DorisioClient({
  baseURL: 'https://api.dorisio.com',
  timeout: 30000,
});

// Validate input with exported schemas
const tipInput = Schemas.Payment.createTip.parse({
  amount: 50,
  currency: 'USD',
  creatorId: '550e8400-e29b-41d4-a716-446655440000',
  message: 'Great content!',
  idempotencyKey: uuidv4(), // Safe to retry with same key
});

try {
  const tip = await client.payments.createTip(tipInput);
  console.log('Tip created:', tip.id);
} catch (error) {
  if (error instanceof PaymentError) {
    console.error('Payment failed:', error.message);
  }
}

React

import { DorisioProvider, useCreateTip, useWallet } from 'dorisio-sdk/react';
import { Schemas } from 'dorisio-sdk';

function TipButton() {
  const { createTip, loading, error } = useCreateTip();

  const handleTip = async () => {
    const input = Schemas.Payment.createTip.parse({
      amount: 50,
      currency: 'USD',
      creatorId: 'xxx',
      idempotencyKey: uuidv4(),
    });

    await createTip(input);
  };

  return (
    <button onClick={handleTip} disabled={loading}>
      {loading ? 'Processing...' : 'Send Tip'}
    </button>
  );
}

export function App() {
  return (
    <DorisioProvider config={{ baseURL: 'https://api.dorisio.com' }}>
      <TipButton />
    </DorisioProvider>
  );
}

Sandbox / Mock Mode

Test the SDK offline without hitting testnet or the Dorisio API. When mode: "sandbox" is set, HttpClient bypasses fetch and returns deterministic mock responses for every client method.

import { DorisioClient } from 'dorisio-sdk';

const client = new DorisioClient({
  baseUrl: 'https://api.dorisio.com',
  token: 'test-token',
  mode: 'sandbox', // no network calls
  sandboxSeed: 42, // optional β€” same seed => same mocks
});

const tip = await client.createTip({
  creatorId: 'mock-creator-123',
  amount: 50,
  message: 'Test tip',
});

// Inspect what the sandbox handled
console.log(client.getSandboxHistory());

// Toggle to live without recreating the client
client.setMode('live');

Or use the dedicated helper:

import { createSandboxClient } from 'dorisio-sdk';

const client = createSandboxClient({ seed: 42, latency: 0 });
await client.getCurrentUser();

Acceptance checklist

  • DorisioClient({ mode: 'sandbox' }) works with zero network calls
  • Client methods return deterministic mocks (seeded)
  • client.getSandboxHistory() / clearSandboxHistory() for test assertions
  • client.setMode('sandbox' | 'live') toggles without recreating the client

Documentation

API Reference

Interceptors

Hook into the request/response lifecycle for cross-cutting concerns (logging, metrics, retry policy, header injection). See INTERCEPTORS.md for the full guide.

import { DorisioClient } from 'dorisio-sdk';

const client = new DorisioClient({ baseUrl: 'https://api.dorisio.com', token: 'token' });
const interceptors = client.getHttpClient().getInterceptors();

interceptors.addRequestInterceptor((options) => {
  options.headers = { ...options.headers, 'X-Request-Id': crypto.randomUUID() };
  return options;
});

InterceptorManager, RequestInterceptor, ResponseInterceptor, ErrorInterceptor, and RequestOptions are exported from the package root. Interceptors run sequentially in registration order and may be async; error interceptors observe failures but do not swallow them.

Core Concepts

Type-Safe Errors

Catch specific errors and handle them appropriately:

import { PaymentError, WalletVerificationError, AuthError } from 'dorisio-sdk';

try {
  await client.payments.createTip({/* ... */});
} catch (error) {
  if (error instanceof PaymentError) {
    console.error('Payment failed:', error.message);
    console.error('Transaction:', error.transactionHash);
  } else if (error instanceof WalletVerificationError) {
    console.error('Wallet error:', error.message);
  } else if (error instanceof AuthError) {
    console.error('Auth failed:', error.message);
  }
}

Input Validation with Zod & Inferred Types

Dorisio SDK exports both Zod schemas for runtime validation and their corresponding inferred TypeScript types for compile-time safety:

  • When to use TypeScript types: Use inferred types (CreateTipInput, LoginInput, WalletInfo, etc.) across your application code, component props, and API boundaries for compile-time type checking without runtime overhead.
  • When to use Zod schemas / Normalizers: Use schemas (PaymentSchemas, AuthSchemas, CreatorSchemas, WalletSchemas) or SDK normalizers (normalizeCreateTip, normalizeCreatorProfile) at I/O boundariesβ€”such as processing user forms, untrusted API responses, webhooks, or query parametersβ€”to validate data shapes and prevent invalid requests.
import {
  PaymentSchemas,
  type CreateTipInput,
  normalizeCreateTip,
} from 'dorisio-sdk';
import { v4 as uuidv4 } from 'uuid';

// 1. Static typing with inferred types
const tipData: CreateTipInput = {
  amount: 50,
  currency: 'USD',
  creatorId: '550e8400-e29b-41d4-a716-446655440000',
  message: 'Great work!',
  idempotencyKey: uuidv4(),
};

// 2. Runtime validation via Zod schemas
const validatedTip = PaymentSchemas.createTip.parse(tipData);

// Or safe parsing with error handling
const result = PaymentSchemas.createTip.safeParse(untrustedInput);
if (!result.success) {
  console.error('Validation errors:', result.error.flatten());
}

// 3. Normalizer helper for runtime validation & transformation
const normalized = normalizeCreateTip(untrustedInput);

Idempotent Payments

Safe retries with unique keys:

const idempotencyKey = uuidv4(); // Generate once

try {
  const tip = await client.payments.createTip({
    creatorId: 'xxx',
    amount: 50,
    idempotencyKey, // Prevents double-charging on retry
  });
} catch (error) {
  // Safe to retry with same key - returns same tip
  const tip = await client.payments.createTip({
    creatorId: 'xxx',
    amount: 50,
    idempotencyKey, // Same key = same result
  });
}

Webhook Verification

Verify incoming webhooks are authentic:

import { verifyWebhookSignature, parseWebhookPayload } from 'dorisio-sdk';

// In your webhook handler
const isValid = verifyWebhookSignature(
  JSON.stringify(req.body),
  req.headers['x-dorisio-signature'],
  process.env.DORISIO_WEBHOOK_SECRET!
);

if (!isValid) {
  return res.status(401).json({ error: 'Invalid signature' });
}

const event = parseWebhookPayload(req.body);
console.log(`Event: ${event.event}`, event.data);

React Hooks

useCreateTip

const { createTip, loading, error, data } = useCreateTip();

const tip = await createTip({
  amount: 50,
  currency: 'USD',
  creatorId: 'xxx',
  idempotencyKey: uuidv4(),
});

useWallet

const { wallet, loading, error, refetch } = useWallet();

console.log(wallet?.balance, wallet?.network);
refetch(); // Manual refresh

useCreatorBalance

const { balance, loading, error } = useCreatorBalance(creatorId);

console.log('Total earnings:', balance?.totalEarnings);
console.log('Pending:', balance?.pendingBalance);

useTransactionHistory

const { transactions, total, page, goToPage, loading } = useTransactionHistory({
  limit: 20,
});

transactions.forEach((tx) => {
  console.log(`$${tx.amount} to ${tx.creatorId}`);
});

Configuration

const client = new DorisioClient({
  baseURL: 'https://api.dorisio.com',
  timeout: 30000,
  retryAttempts: 3,
  retryDelay: 1000,
});

Environment Variables

DORISIO_API_URL=https://api.dorisio.com
DORISIO_WEBHOOK_SECRET=your-secret-key

Development

# Install
npm install

# Run tests (86 tests, 100% passing)
npm run test

# Type check
npm run type-check

# Lint
npm run lint

# Generate docs (output: docs/, deployed to GitHub Pages by .github/workflows/docs.yml)
npm run docs

# Build
npm run build

# Watch mode
npm run dev

Examples

See examples/ for complete working examples:

API Overview

Payments

// Create tip (with idempotency)
await client.payments.createTip({
  creatorId: string;
  amount: number;
  message?: string;
  idempotencyKey?: string;
});

// Get transaction
await client.payments.getTransaction(transactionId);

// Get history
await client.payments.getTransactionHistory({ limit: 20, offset: 0 });

Authentication

// Register
await client.auth.register({
  email: string;
  password: string;
  name: string;
});

// Login
await client.auth.login({
  email: string;
  password: string;
});

// Validate session
await client.auth.validateSession();

// Logout
await client.auth.logout();

Wallets

// Request challenge
const challenge = await client.auth.requestWalletChallenge();

// Verify and link
await client.auth.verifyAndLinkWallet({
  challenge: string;
  signature: string;
  publicKey: string;
});

// Get balance
await client.wallet.getBalance();

Error Handling

The SDK provides domain-specific error classes:

  • DorisioError - Base error class
  • AuthError - Authentication failures
  • PaymentError - Payment processing failures (includes transactionHash)
  • WalletVerificationError - Wallet linking issues (includes challenge)
  • ValidationError - Input validation errors (includes details)
  • RateLimitError - Rate limiting (includes retryAfter)
  • TimeoutError - Network timeouts

Browser Support

  • Modern browsers with ES2020+ support
  • Node.js >=20.0.0
  • React >=18.0.0 (optional, for React hooks)

Performance

  • Automatic retry with exponential backoff
  • Request timeout: 30s (configurable)
  • Concurrent request limit: 10
  • Response compression enabled

Security

  • HTTPS only in production
  • Bearer token authentication
  • HMAC-SHA256 webhook verification
  • Constant-time signature comparison
  • No secrets in logs
  • Input validation with Zod

Changelog

See CHANGELOG.md for version history and breaking changes.

Contributing

See CONTRIBUTING.md for development guidelines.

License

MIT - See LICENSE for details

Support

About

Typed TypeScript client + React hooks for Dorisio embed wallet-to-wallet USDC tipping into any platform.

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages