npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

truewallet-angpao

v1.1.8

Published

Redeem TrueMoney Angpao programmatically with TypeScript

Readme

🧧 TrueWallet Angpao Redemption

npm version License: MIT TypeScript Node.js Downloads

🎁 A lightweight TypeScript library for redeeming TrueMoney Angpao (red envelope) voucher codes with full CORS support

✨ Features

  • 🚀 TypeScript Support - Full type safety with IntelliSense
  • 🌐 CORS Handling - Both client-side and server-side implementations
  • Zero Dependencies - Minimal footprint (client version)
  • 🔧 Easy Integration - React hooks and Express middleware included
  • 📱 Mobile Ready - Works on all platforms
  • 🛡️ Error Handling - Comprehensive error messages in Thai/English

🚀 Quick Start

Installation

# npm
npm install truemoney-angpao

# yarn
yarn add truemoney-angpao

# pnpm
pnpm add truemoney-angpao

# bun
bun add truemoney-angpao

Basic Usage (Server-side)

import { redeemAngpao } from 'truemoney-angpao';

async function example() {
  const result = await redeemAngpao('0891234567', 'ABC123DEF456');
  
  if (result.status === 'SUCCESS') {
    console.log(`💰 Redeemed ${result.amount} Baht!`);
  } else {
    console.error('❌', result.message);
  }
}

Client-side Usage (Browser)

import { clientRedeemAngpao } from 'truemoney-angpao';

async function redeemInBrowser() {
  const result = await clientRedeemAngpao('0891234567', 'ABC123DEF456');
  
  switch (result.status) {
    case 'SUCCESS':
      console.log(`✅ Success: ${result.amount} Baht`);
      break;
    case 'CORS_ERROR':
      console.log('🚫 CORS Error - Use proxy server');
      break;
    case 'FAIL':
      console.error('❌', result.message);
      break;
  }
}

📚 Complete Examples

🖥️ Express Server Setup

import express from 'express';
import cors from 'cors';
import { redeemAngpao } from 'truemoney-angpao';

const app = express();

// Enable CORS for all routes
app.use(cors());
app.use(express.json());

// Redemption endpoint
app.post('/api/redeem', async (req, res) => {
  const { phone, voucherCode } = req.body;

  // Validation
  if (!phone || !voucherCode) {
    return res.status(400).json({ 
      error: 'Phone and voucherCode are required' 
    });
  }

  try {
    const result = await redeemAngpao(phone, voucherCode);
    res.json(result);
  } catch (error) {
    console.error('Redemption error:', error);
    res.status(500).json({ 
      status: 'FAIL', 
      message: (error as Error).message 
    });
  }
});

// Health check
app.get('/', (req, res) => {
  res.json({ message: '🧧 TrueMoney Angpao API Ready!' });
});

const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
  console.log(`🚀 Server running on http://localhost:${PORT}`);
});

⚛️ React Hook Implementation

// hooks/useAngpaoRedemption.ts
import { useState, useCallback } from 'react';
import { clientRedeemAngpao, ClientRedeemResult } from 'truemoney-angpao';

interface UseAngpaoRedemption {
  redeem: (phone: string, voucherCode: string) => Promise<ClientRedeemResult>;
  loading: boolean;
  error: string | null;
  result: ClientRedeemResult | null;
  reset: () => void;
}

export function useAngpaoRedemption(): UseAngpaoRedemption {
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const [result, setResult] = useState<ClientRedeemResult | null>(null);

  const redeem = useCallback(async (phone: string, voucherCode: string) => {
    setLoading(true);
    setError(null);
    setResult(null);

    try {
      const response = await clientRedeemAngpao(phone, voucherCode);
      setResult(response);
      
      if (response.status === 'FAIL') {
        setError(response.message || 'Redemption failed');
      }
      
      return response;
    } catch (err) {
      const message = (err as Error).message;
      setError(message);
      return { status: 'FAIL' as const, message };
    } finally {
      setLoading(false);
    }
  }, []);

  const reset = useCallback(() => {
    setLoading(false);
    setError(null);
    setResult(null);
  }, []);

  return { redeem, loading, error, result, reset };
}

🎨 React Component Example

// components/AngpaoRedeemer.tsx
import React, { useState } from 'react';
import { useAngpaoRedemption } from '../hooks/useAngpaoRedemption';

export function AngpaoRedeemer() {
  const [phone, setPhone] = useState('');
  const [voucherCode, setVoucherCode] = useState('');
  const { redeem, loading, error, result, reset } = useAngpaoRedemption();

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    
    if (!phone || !voucherCode) {
      alert('กรุณากรอกเบอร์โทรและรหัสอั่งเปา');
      return;
    }

    const response = await redeem(phone, voucherCode);
    
    if (response.status === 'SUCCESS') {
      alert(`🎉 แลกสำเร็จ! ได้รับ ${response.amount} บาท`);
    } else if (response.status === 'CORS_ERROR') {
      alert('❌ ข้อผิดพลาด CORS - กรุณาใช้ Proxy Server');
    }
  };

  return (
    <div className="max-w-md mx-auto p-6 bg-white rounded-lg shadow-lg">
      <h2 className="text-2xl font-bold text-center mb-6 text-red-600">
        🧧 แลกอั่งเปา TrueMoney
      </h2>
      
      <form onSubmit={handleSubmit} className="space-y-4">
        <div>
          <label className="block text-sm font-medium text-gray-700 mb-1">
            เบอร์โทรศัพท์
          </label>
          <input
            type="tel"
            value={phone}
            onChange={(e) => setPhone(e.target.value)}
            placeholder="089xxxxxxx"
            className="w-full p-3 border border-gray-300 rounded-md focus:ring-2 focus:ring-red-500 focus:border-transparent"
            maxLength={10}
          />
        </div>

        <div>
          <label className="block text-sm font-medium text-gray-700 mb-1">
            รหัสอั่งเปา
          </label>
          <input
            type="text"
            value={voucherCode}
            onChange={(e) => setVoucherCode(e.target.value.toUpperCase())}
            placeholder="ABC123DEF456"
            className="w-full p-3 border border-gray-300 rounded-md focus:ring-2 focus:ring-red-500 focus:border-transparent"
          />
        </div>

        <button
          type="submit"
          disabled={loading}
          className="w-full bg-red-600 text-white py-3 px-4 rounded-md hover:bg-red-700 disabled:opacity-50 disabled:cursor-not-allowed transition-colors"
        >
          {loading ? '⏳ กำลังแลก...' : '🎁 แลกอั่งเปา'}
        </button>
      </form>

      {error && (
        <div className="mt-4 p-3 bg-red-50 border border-red-200 rounded-md">
          <p className="text-red-700 text-sm">❌ {error}</p>
        </div>
      )}

      {result && result.status === 'SUCCESS' && (
        <div className="mt-4 p-3 bg-green-50 border border-green-200 rounded-md">
          <p className="text-green-700 text-sm">
            ✅ แลกสำเร็จ! ได้รับ <strong>{result.amount} บาท</strong>
          </p>
        </div>
      )}

      {result && result.status === 'CORS_ERROR' && (
        <div className="mt-4 p-3 bg-yellow-50 border border-yellow-200 rounded-md">
          <p className="text-yellow-700 text-sm">
            ⚠️ CORS Error: กรุณาใช้ Proxy Server สำหรับการใช้งานจริง
          </p>
        </div>
      )}

      {(error || result) && (
        <button
          onClick={reset}
          className="mt-2 text-sm text-gray-500 hover:text-gray-700 underline"
        >
          ล้างข้อมูล
        </button>
      )}
    </div>
  );
}

📋 API Reference

Server-side Functions

redeemAngpao(phone: string, voucherCode: string): Promise<RedeemResult>

Redeems an Angpao voucher using Node.js (no CORS issues).

Parameters:

  • phone: Thai mobile number (e.g., '0891234567')
  • voucherCode: Angpao voucher code (e.g., 'ABC123DEF456')

Returns:

type RedeemResult = 
  | { status: 'SUCCESS'; amount: number }
  | { status: 'FAIL'; message: string };

Client-side Functions

clientRedeemAngpao(phone: string, voucherCode: string): Promise<ClientRedeemResult>

Redeems an Angpao voucher in the browser (may have CORS issues).

Returns:

type ClientRedeemResult = 
  | { status: 'SUCCESS'; amount: number }
  | { status: 'FAIL'; message: string }
  | { status: 'CORS_ERROR'; message: string };

🔧 Configuration

Environment Variables

# Optional: Set custom API endpoint
TRUEMONEY_API_URL=https://gift.truemoney.com

# Server port
PORT=3000

TypeScript Configuration

{
  "compilerOptions": {
    "target": "ES2020",
    "module": "commonjs",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true
  }
}

🛡️ Error Handling

The library provides detailed error messages for common scenarios:

| Error Type | Description | Solution | |------------|-------------|----------| | CORS_ERROR | Cross-origin request blocked | Use server-side proxy | | INVALID_VOUCHER | Invalid voucher code format | Check code format | | EXPIRED_VOUCHER | Voucher has expired | Use valid voucher | | ALREADY_REDEEMED | Voucher already used | Use new voucher | | NETWORK_ERROR | Connection failed | Check internet connection |

🚀 Deployment

Vercel

{
  "functions": {
    "api/**/*.ts": {
      "runtime": "@vercel/node"
    }
  }
}

Netlify

[build]
  functions = "netlify/functions"

[[redirects]]
  from = "/api/*"
  to = "/.netlify/functions/:splat"
  status = 200

Railway

FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
EXPOSE 3000
CMD ["npm", "start"]

🧪 Testing

# Install dev dependencies
npm install -D jest @types/jest ts-jest

# Run tests
npm test

# Run with coverage
npm run test:coverage

Example test:

import { redeemAngpao } from '../src/redeemAngpao';

describe('redeemAngpao', () => {
  it('should handle successful redemption', async () => {
    const result = await redeemAngpao('0891234567', 'VALID_CODE');
    expect(result.status).toBe('SUCCESS');
    expect(result.amount).toBeGreaterThan(0);
  });

  it('should handle invalid voucher', async () => {
    const result = await redeemAngpao('0891234567', 'INVALID_CODE');
    expect(result.status).toBe('FAIL');
    expect(result.message).toContain('invalid');
  });
});

🤝 Contributing

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

Development Setup

# Clone the repo
git clone https://github.com/CrypticDay/truemoney-angpao.git
cd truemoney-angpao

# Install dependencies
npm install

# Start development
npm run dev

# Build
npm run build

# Test
npm test

📈 Roadmap

  • [x] ✅ TypeScript support
  • [x] ✅ CORS handling
  • [x] ✅ React hooks
  • [x] ✅ Express middleware
  • [ ] 🔄 CLI tool
  • [ ] 🔄 Batch redemption
  • [ ] 🔄 Rate limiting
  • [ ] 🔄 Webhook support
  • [ ] 🔄 Mobile app SDK

📄 License

MIT © 2025 - See LICENSE file for details.

🙏 Acknowledgments

  • TrueMoney team for providing the API
  • Thai developer community for feedback and suggestions
  • Contributors who helped improve this library

Made with ❤️ for the Thai developer community

📖 Documentation🐛 Report Bug✨ Request Feature