Tcat
A Ruby gem for tracking T-Cat (Taiwan Pelican Express) shipment status. Provides a simple and easy-to-use API interface.
โจ Two Ways to Use Tcat
1. Ruby Gem (This Repository)
Perfect for Ruby/Rails applications with direct integration.
2. Cloudflare Worker API
Looking for a serverless solution? Check out worker/README.md
Benefits of the Worker version:
- ๐ Global edge deployment for faster queries worldwide
- ๐ Secure secret storage in environment variables
- ๐ HTTP API accessible from any platform (JavaScript, Python, cURL, etc.)
- ๐ฐ Cost-effective: 100K free requests/day
- ๐ฑ Perfect for frontend apps, mobile apps, or microservices
Features
- ๐ฆ Track shipment status
- ๐ Secure encrypted requests
- ๐ Simple API interface
- โก Non-blocking HTTP requests
- ๐ก๏ธ Comprehensive error handling
Installation
Add this line to your application's Gemfile:
gem 'tcat'
And then execute:
$ bundle install
Or install it yourself as:
$ gem install tcat
Usage
There are two ways to use this gem:
- Direct API Access - Query T-Cat API directly from your Ruby application
- Cloudflare Worker - Query through a Cloudflare Worker proxy (recommended for production)
Option 1: Direct API Access
Configure the gem with your T-Cat API credentials:
Tcat.configure do |config|
config.secret_string = 'your_secret_string'
config.secret_key = 'your_secret_key'
end
# Create a query instance
query = Tcat::Query.new('your_tracking_number')
# Get shipment status
status = query.status_code
# Returns one of the following:
# :done - Successfully delivered
# :delivering - Out for delivery
# :collected - Package collected
# :in_transit - In transit
# :returned - Return completed
# :held - Held at post office
# :rescheduled - Delivery time rescheduled
# :forwarding - Being forwarded
# :investigation - Under investigation
# :rejected - Delivery rejected
# :returning - In return process
# :store_delivery - At convenience store for pickup
# :unknown - Unknown status
# Get latest status details
latest = query.latest_status
if latest
puts "Status: #{latest.status}" # e.g. "Successfully delivered"
puts "Status code: #{latest.status_code}" # e.g. :done
puts "Time: #{latest.time}" # Time object
puts "Office: #{latest.office}" # e.g. "Tainan office"
puts "Last update: #{latest.last_update}" # Time object
end
# Get full shipment history
history = query.history
history.each do |item|
puts "Status: #{item.status}"
puts "Time: #{item.time}"
puts "Office: #{item.office}"
puts "---"
end
Option 2: Via Cloudflare Worker (Recommended)
The Worker approach is recommended for production because:
- โ Secrets are stored securely in Cloudflare, not in your application
- โ Faster response times via Cloudflare's edge network
- โ No need to manage encryption in your Ruby app
- โ Can be used by any language/platform (not just Ruby)
First, deploy the Cloudflare Worker (see worker/README.md for deployment instructions).
Then use the WorkerClient in your Ruby application. You can pass the Worker
URL (and optional Bearer token) directly, or configure them globally via
Tcat.configure:
# Option A: explicit per-instance arguments
client = Tcat::WorkerClient.new(
'https://your-worker.workers.dev',
token: ENV['TCAT_WORKER_TOKEN'] # only needed when AUTH_TOKEN is set on the Worker
)
# Option B: global configuration, then construct without arguments
Tcat.configure do |config|
config.worker_url = 'https://your-worker.workers.dev'
config.worker_token = ENV['TCAT_WORKER_TOKEN']
end
client = Tcat::WorkerClient.new
# Explicit args always override configuration:
override = Tcat::WorkerClient.new('https://other.workers.dev', token: 'other-token')
# Get shipment status (same API as Query)
status = client.status_code('your_tracking_number')
# => :delivering
# Get latest status details
latest = client.latest_status('your_tracking_number')
if latest
puts "Status: #{latest.status}" # e.g. "้
้ไธญ"
puts "Status code: #{latest.status_code}" # e.g. :delivering
puts "Time: #{latest.time}" # Time object
puts "Office: #{latest.office}" # e.g. "ๅฐๅ็ๆฅญๆ"
end
# Get full shipment history
history = client.history('your_tracking_number')
history.each do |item|
puts "Status: #{item.status}"
puts "Time: #{item.time}"
puts "Office: #{item.office}"
puts "---"
end
# Check if Worker is healthy
if client.healthy?
puts "Worker is operational"
end
Custom timeout:
# Default timeout is 30 seconds
client = Tcat::WorkerClient.new('https://your-worker.workers.dev', timeout: 60)
Error handling:
begin
status = client.status_code('tracking_number')
rescue Tcat::WorkerClient::NetworkError => e
puts "Network error: #{e.}"
rescue Tcat::WorkerClient::APIError => e
puts "API error: #{e.}"
end
Status Code Explanation
:done- Successfully delivered:delivering- Out for delivery:collected- Package collected:in_transit- In transit:returned- Return completed:held- Package is being held at post office:rescheduled- Delivery time rescheduled:forwarding- Package is being forwarded:investigation- Package is under investigation (e.g., address change, rejection):rejected- Delivery was rejected:returning- Package is in return process:store_delivery- Handed over to a convenience store, awaiting recipient pickup:unknown- Unknown status
Cloudflare Worker
This repository includes a Cloudflare Worker implementation that provides an HTTP API for T-Cat tracking.
Features
- ๐ Deploy globally on Cloudflare's edge network
- ๐ Securely store API credentials as Worker secrets
- ๐ Fast response times from edge locations
- ๐ CORS enabled for frontend applications
- ๐ฑ Works with any programming language
Quick Start
cd worker
npm install
npm run dev # Start local development server
For full deployment instructions, see worker/README.md and worker/DEPLOYMENT.md.
Comparison: Direct API vs Worker
| Feature | Direct API (Query) |
Cloudflare Worker (WorkerClient) |
|---|---|---|
| Setup complexity | Low (just gem install) | Medium (requires Worker deployment) |
| Security | Secrets in your app | Secrets in Cloudflare |
| Performance | Direct to T-Cat API | Via Cloudflare edge |
| Multi-platform | Ruby only | Any language/platform |
| Cost | Free | Free tier available |
| Best for | Simple scripts, internal tools | Production apps, public APIs |
Development
Running Tests
# Run all tests
$ bundle exec rake spec
# Run specific test file
$ bundle exec rspec spec/tcat/worker_client_spec.rb
Local Installation
$ bundle exec rake install
Contributing
Bug reports and pull requests are welcome.
- Fork the project
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -am 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Create a Pull Request
License
This gem is available as open source under the terms of the MIT License.
Changelog
0.3.5
- Added optional
worker_urlandworker_tokentoTcat.configure; explicitTcat::WorkerClient.new(url, token:)arguments still take precedence Tcat::WorkerClient.newnow accepts no arguments whenworker_urlis set in configuration
0.3.4
- Bundled the 0.3.3 fixes for release on RubyGems
0.3.3
- Worker now subtracts the Taiwan UTC+8 offset when emitting ISO timestamps (previously every event was reported 8 hours later than reality)
- Worker forwards only the
name=valueportion ofSet-Cookieto the upstreamCookie:header (RFC 6265) - Worker rejects
/querywith HTTP 401 whenAUTH_TOKENis not configured (fail-closed) - 5xx responses no longer leak
error.message; details are written toconsole.error(visible viawrangler tail)
0.3.2
- Added optional Bearer token auth to the Cloudflare Worker (
AUTH_TOKENsecret) Tcat::WorkerClientaccepts atoken:keyword arg that is sent asAuthorization: Bearer <token>- Worker compares tokens in constant time; CORS allow-headers gain
Authorization
0.3.1
- Tightened
tcat.gemspecso the published gem no longer bundles theworker/subproject or dev-only configs
0.3.0
- Added
Tcat::WorkerClientto query a Cloudflare Worker proxy instead of T-Cat directly - Added new status mapping:
:store_deliveryfor่ฝไบค่ถ ๅ้ ้(handed over to convenience store) - Added the
worker/Cloudflare Worker subproject (separate from the gem release)
0.2.2
- Fixed status parsing to handle HTML tags in API responses
0.2.1
- Updated base64 gem dependency to ~> 0.3
- Code formatting improvements
0.2.0
- Fixed SSL certificate verification issues with T-Cat API
- Added session initialization to obtain cookies before queries
- Added cookie management for maintaining session state
- Added new status code mappings:
:rescheduled(ๅฆ็ดๆ้) and:held(ๆซ็ฝฎ็ๆฅญๆ) - Removed Rails.logger dependency for better standalone gem compatibility
- Added base64 gem dependency for Ruby 3.4+ compatibility
- Updated HTTP headers to match latest BlackCat iOS app (version 3)
- Improved error handling with better debug output
0.1.9
- Updated User-Agent and API version
0.1.7
- Improved method naming, removed get_ prefix
- Added
latest_statusmethod to get latest status details - Added
historymethod to get full shipment history - Used
DeliveryItemstruct to provide more complete shipment information - Improved error handling and logging
- Supported UTF-8 encoding
0.1.6
- Refactored query parsing method
- Improved error handling
- Added test coverage
0.1.5
- Refactored HTTP request handling with new HttpClient class
- Refactored encryption logic with new EncryptionService class
- Improved error handling
- Updated documentation