TinyShip
TinyShip
  • Docs
  • Updates
    ← Back to Updates
    Nov 1, 2026Release

    TinyShip 2.9.0 - AI billing & video tasks, pending orders, multi-channel refunds

    TinyShip 2.9.0 Released

    This release matches GitHub v2.9.0: AI credit billing, video task persistence, pending order resumption, and multi-channel admin refunds. The Cloudflare edition tinyship-cf is synchronized at 1.2.0 (aligning pending orders and refund flows, without #50 AI credit billing / video task tables).

    Highlights

    • AI credit billing: Chat charges per reply without exceeding balance; image/video generation holds credits upfront, confirming on success and idempotently refunding on failure (#50)
    • Video task persistence: Added ai_video_task (migration 0008); credits refund at most once on failure or service restart; supports listing tasks for the current user (#50)
    • Pending orders: Users can "Pay now / Cancel"; admins can mark as paid or cancel; lazy expiration on listing (default 2h, ORDER_PENDING_TTL) (#52)
    • Pending order resumption: "Pay now" calls POST /api/payment/resume to reuse the existing order instead of redirecting back to the pricing page (#54)
    • WeChat Pay: Integrated better-wechatpay with native refund support, revoking entitlements only after receiving REFUND.SUCCESS (#53)
    • Multi-channel admin refunds: One-click full refunds for WeChat, Stripe, Alipay, PayPal, and Dodo; Creem records transactionId only (no refund button); Waffo managed via dashboard (#53 #54)

    Fixes

    • Added missing baseline PostgreSQL migration 0000_optimal_mad_thinker.sql so fresh databases can run db:migrate (#51)
    • Aligned outdated unit tests to restore all green test suites for pnpm test (#51)

    Testing

    • AI credits & video: SQLite / D1 / PostgreSQL integration tests + 3-framework E2E (with local mock AI)
    • Pending orders, resumption, and multi-channel admin refunds: unit tests + E2E (including Stripe admin refund)

    Upgrade

    Run migrations after upgrading:

    pnpm db:migrate          # PostgreSQL
    pnpm db:migrate:sqlite   # SQLite / D1

    Note: Environments initialized with db:push that have an empty migration history table should not switch directly to running a full migrate, as this will attempt to recreate tables starting from 0000.