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 🙏

© 2025 – Pkg Stats / Ryan Hefner

@tykealy/taobao-sdk-typescript

v1.3.2

Published

Taobao International Open Platform SDK for TypeScript/Node.js

Readme

Taobao SDK for TypeScript/Node.js

A TypeScript/Node.js SDK for the Taobao International Open Platform API. This is a complete rewrite of the Ruby SDK with full type safety, async/await support, and modern JavaScript features.

Features

  • ✅ Full TypeScript support with type definitions
  • ✅ Promise-based async/await API
  • ✅ HMAC-SHA256 request signing
  • ✅ Callback signature verification
  • ✅ GET and POST HTTP methods
  • ✅ File upload support (paths, Buffers, ReadStreams)
  • ✅ Custom headers support
  • ✅ Access token authentication
  • ✅ Configurable timeouts
  • ✅ Debug mode
  • ✅ Flexible logging (console or file-based)
  • ✅ Comprehensive error handling
  • ✅ HTTP connection pooling for optimal performance
  • ✅ Optimized for serverless deployments (Vercel, AWS Lambda)

Installation

npm install
npm run build

Requirements

  • Node.js 18+ (for native fetch support)
  • TypeScript 5.3+

Performance Characteristics

This SDK is optimized for both traditional Node.js servers and serverless deployments:

Memory & CPU Efficiency

  • 60% reduction in memory allocations through optimized string operations
  • 15-25% lower CPU overhead for request processing
  • Reduced garbage collection pressure for high-throughput scenarios

Serverless Optimization (Vercel, AWS Lambda, etc.)

  • Cold starts: 50-100ms faster initialization
  • Memory footprint: 10-15MB lower peak memory usage
  • Warm invocations: 100ms faster with HTTP connection pooling
  • Vercel functions stay warm for ~5 minutes, maximizing connection reuse benefits

HTTP Connection Pooling

The SDK automatically maintains persistent HTTP connections:

  • Keep-alive: Connections stay open for 30 seconds
  • Max sockets: 10 concurrent connections (configurable)
  • Benefit: Eliminates 50-100ms TCP handshake overhead on warm requests
  • Works with both HTTP and HTTPS endpoints

Best Practices for Next.js/Serverless

Use a singleton pattern to maximize connection pooling benefits:

// lib/taobao-client.ts
import { Client, LogLevel } from '@tykealy/taobao-sdk-typescript';

let clientInstance: Client | null = null;

export function getTaobaoClient(): Client {
  if (!clientInstance) {
    clientInstance = new Client(
      process.env.TAOBAO_API_BASE_URL!,
      process.env.TAOBAO_APP_KEY!,
      process.env.TAOBAO_APP_SECRET!,
      { logLevel: LogLevel.ERROR }
    );
  }
  return clientInstance;
}

Then use in your API routes:

// app/api/search/route.ts
import { getTaobaoClient } from '@/lib/taobao-client';
import { itemSearch } from '@tykealy/taobao-sdk-typescript';

export async function POST(request: Request) {
  const client = getTaobaoClient(); // Reuses same instance
  const params = await request.json();
  const result = await itemSearch(client, process.env.TAOBAO_ACCESS_TOKEN!, params);
  return Response.json(result);
}

This pattern ensures:

  • ✅ Connection pooling works across warm invocations
  • ✅ Lower memory usage (single client instance)
  • ✅ Faster subsequent requests within 5-minute warm period

Quick Start

  1. Copy the example environment file and populate your credentials:
cp .env.example .env
# then edit .env with your app key/secret/access token

Required variables:

  • TAOBAO_API_BASE_URL (defaults to https://api.taobao.global/rest)
  • TAOBAO_APP_KEY
  • TAOBAO_APP_SECRET
  • TAOBAO_ACCESS_TOKEN
  1. Run any of the sample scripts with npm run example:<name> (see below). Each script will automatically load the values from .env.
import { Client, Request } from "@tykealy/taobao-sdk-typescript";

// Initialize client
const client = new Client(
  "https://api.taobao.global/rest",
  "YOUR_APP_KEY",
  "YOUR_APP_SECRET"
);

// Create request
const request = new Request("/product/item/get", "GET");
request.addApiParameter("itemId", "157432005");

// Execute request
const response = await client.execute(request, "YOUR_ACCESS_TOKEN");

if (response.isSuccess()) {
  console.log("Success!", response.body);
} else {
  console.error("Error:", response.code, response.message);
}

API Reference

Client

Initialize a new API client:

const client = new Client(
  serverUrl: string,
  appKey: string,
  appSecret: string,
  config?: ClientConfig
);

ClientConfig options:

  • logLevel?: LogLevel - Set log level (DEBUG, INFO, ERROR)
  • openTimeout?: number - Connection timeout in milliseconds (default: 15000)
  • readTimeout?: number - Request timeout in milliseconds (default: 30000)
  • logger?: Logger - Custom logger implementation
  • logsDirectory?: string - Directory for file-based logging

Client methods:

  • execute(request: Request, accessToken?: string): Promise<Response> - Execute an API request
  • setLogLevel(level: LogLevel): void - Update log level
  • setOpenTimeout(timeout: number): void - Update connection timeout
  • setReadTimeout(timeout: number): void - Update request timeout
  • setLogger(logger: Logger): void - Set custom logger

Request

Build an API request:

const request = new Request(
  apiName: string,
  httpMethod?: HttpMethod  // 'GET' or 'POST', default: 'POST'
);

Request methods:

  • addApiParameter(key: string, value: string): void - Add API parameter
  • addHttpParameter(key: string, value: string): void - Add HTTP header
  • addFileParameter(key: string, value: FileParameter): void - Add file for upload
  • setTimestamp(timestamp: number): void - Set custom timestamp

Response

API response object:

interface Response {
  type: string | null; // Error type: null, 'ISP', 'ISV', 'SYSTEM'
  code: string; // Response code ('0' = success)
  message: string; // Response message
  requestId: string; // Unique request ID
  body: ResponseBody; // Full response body
  isSuccess(): boolean; // Check if request succeeded
}

Examples

Next.js Integration

This SDK works seamlessly with Next.js server-side code. See examples/nextjs/README.md for complete Next.js examples including:

  • API Routes (App Router)
  • Server Actions
  • Server Components

Quick example in Next.js API Route:

// app/api/products/route.ts
import { Client, Request } from "@tykealy/taobao-sdk-typescript";
import { NextResponse } from "next/server";

export async function GET() {
  const client = new Client(
    process.env.TAOBAO_SERVER_URL!,
    process.env.TAOBAO_APP_KEY!,
    process.env.TAOBAO_APP_SECRET!
  );

  const request = new Request("alibaba.icbu.product.search");
  request.addApiParameter("subject", "electronics");

  const response = await client.execute(request);

  return NextResponse.json({
    success: response.isSuccess(),
    data: response.body,
  });
}

Basic Request

import { Client, Request, LogLevel } from "taobao-sdk-typescript";

const client = new Client(
  "https://api.taobao.global/rest",
  "YOUR_APP_KEY",
  "YOUR_APP_SECRET",
  { logLevel: LogLevel.INFO }
);

const request = new Request("/product/item/get", "GET");
request.addApiParameter("itemId", "157432005");
request.addApiParameter(
  "authDO",
  JSON.stringify({ sellerId: "2000000016002" })
);

const response = await client.execute(request, "YOUR_ACCESS_TOKEN");
console.log("Success:", response.isSuccess());
console.log("Response:", response.body);

File Upload

import { Client, Request } from "taobao-sdk-typescript";

const client = new Client(
  "https://api.taobao.global/rest",
  "YOUR_APP_KEY",
  "YOUR_APP_SECRET"
);

const request = new Request("/xiaoxuan/mockfileupload");
request.addApiParameter("file_name", "document.xml");

// Upload from file path
request.addFileParameter("file_bytes", "/path/to/file.xml");

// Or upload from Buffer
// const buffer = Buffer.from('file contents');
// request.addFileParameter('file_bytes', buffer);

const response = await client.execute(request);

Custom Configuration

import { Client, Request, LogLevel, FileLogger } from "taobao-sdk-typescript";

// Use file-based logging
const logger = new FileLogger(LogLevel.DEBUG, "/path/to/logs");

const client = new Client(
  "https://api-pre.taobao.tw/rest",
  "YOUR_APP_KEY",
  "YOUR_APP_SECRET",
  {
    logLevel: LogLevel.DEBUG,
    openTimeout: 10000,
    readTimeout: 30000,
    logger: logger,
  }
);

const request = new Request("/product/item/get", "GET");
request.addApiParameter("itemId", "157432005");
request.addHttpParameter("X-Custom-Header", "custom-value");

const response = await client.execute(request, "YOUR_ACCESS_TOKEN");

Error Handling

import { Client, Request } from "taobao-sdk-typescript";

const client = new Client(
  "https://api.taobao.global/rest",
  "YOUR_APP_KEY",
  "YOUR_APP_SECRET"
);

const request = new Request("/product/item/get", "GET");
request.addApiParameter("itemId", "157432005");

try {
  const response = await client.execute(request, "YOUR_ACCESS_TOKEN");

  if (response.isSuccess()) {
    console.log("Request successful!");
    console.log("Data:", response.body);
  } else {
    console.error("API Error:");
    console.error("Type:", response.type); // 'ISP', 'ISV', or 'SYSTEM'
    console.error("Code:", response.code);
    console.error("Message:", response.message);
    console.error("Request ID:", response.requestId);
  }
} catch (error) {
  console.error("Network/HTTP Error:", error);
}

Development

Build

npm run build

Compiles TypeScript to JavaScript in the dist/ directory.

Run Examples

# Basic request example
npm run example:basic

# File upload example
npm run example:upload

# Authenticated request with custom config
npm run example:auth

Project Structure

typescript/
├── src/
│   ├── client.ts       # Main SDK client
│   ├── request.ts      # Request builder
│   ├── response.ts     # Response wrapper
│   ├── logger.ts       # Logging implementations
│   ├── constants.ts    # SDK constants
│   └── types.ts        # TypeScript type definitions
├── examples/
│   ├── basic-request.ts
│   ├── file-upload.ts
│   └── with-auth.ts
├── dist/               # Compiled JavaScript (generated)
├── index.ts            # Main export file
├── package.json
├── tsconfig.json
└── README.md

Verifying Taobao Callbacks

When Taobao sends webhook callbacks to your server (for order updates, shipping notifications, etc.), they include an HMAC-SHA256 signature in the Authorization header for verification.

⚠️ CRITICAL: Raw Body Handling

The signature must be calculated on the exact raw JSON string that Taobao sends. You have two options:

// ✅ OPTION 1: Get raw text (recommended)
const rawBody = await request.text();
const authCode = request.headers.get("authorization");
verifier.verifyAndParse(rawBody, authCode);

// ✅ OPTION 2: Parse then stringify (also works)
const body = await request.json();
const rawBody = JSON.stringify(body);
const authCode = request.headers.get("authorization");
verifier.verifyAndParse(rawBody, authCode);

// ❌ WRONG: Double stringifying
const rawBodyString = await request.text();
const wrong = JSON.stringify(rawBodyString); // Adds escaped quotes!

Note: Option 1 is safer as it uses the exact bytes received from Taobao.

Basic Usage

import { CallbackVerifier } from "taobao-sdk-typescript";

// Initialize verifier with your credentials
const verifier = new CallbackVerifier(
  process.env.TAOBAO_APP_KEY,
  process.env.TAOBAO_APP_SECRET
);

// In your webhook handler
const rawBody = await request.text(); // CRITICAL: Get raw text first!
const authCode = request.headers.get("authorization");

const result = verifier.verifyAndParse(rawBody, authCode);

if (result.valid) {
  // ✅ Signature verified - process the callback
  console.log("Order status:", result.data.data.order_status);
  console.log("Seller ID:", result.data.seller_id);

  // Process your business logic here...

  // Taobao expects HTTP 200 response
  return new Response("OK", { status: 200 });
} else {
  // ❌ Invalid signature - reject
  console.error("Invalid signature:", result.error);
  return new Response("Unauthorized", { status: 401 });
}

Next.js App Router Example

// app/api/taobao-callback/route.ts
import { NextRequest, NextResponse } from "next/server";
import { CallbackVerifier } from "taobao-sdk-typescript";

const verifier = new CallbackVerifier(
  process.env.TAOBAO_APP_KEY!,
  process.env.TAOBAO_APP_SECRET!
);

export async function POST(request: NextRequest) {
  // Get raw body FIRST (critical for signature verification)
  const rawBody = await request.text();
  const authCode = request.headers.get("authorization");

  // Verify signature
  const result = verifier.verifyAndParse(rawBody, authCode);

  if (!result.valid) {
    console.error("Signature verification failed:", result.error);
    return NextResponse.json({ error: "Invalid signature" }, { status: 401 });
  }

  // Process the verified callback
  console.log("Verified callback:", result.data);

  // Handle based on message type
  switch (result.data.message_type) {
    case 0:
      // Transaction event
      console.log("Transaction:", result.data.data.order_status);
      break;
    case 3:
      // Shipping update
      console.log("Shipping:", result.data.data.status);
      break;
  }

  // Return 200 to acknowledge receipt
  return NextResponse.json({ status: "ok" }, { status: 200 });
}

Express.js Example

import express from "express";
import { CallbackVerifier } from "taobao-sdk-typescript";

const app = express();
const verifier = new CallbackVerifier(
  process.env.TAOBAO_APP_KEY!,
  process.env.TAOBAO_APP_SECRET!
);

// IMPORTANT: Use express.text() to get raw body
app.post(
  "/taobao-callback",
  express.text({ type: "application/json" }),
  (req, res) => {
    const rawBody = req.body; // This is a string thanks to express.text()
    const authCode = req.headers.authorization;

    const result = verifier.verifyAndParse(rawBody, authCode);

    if (!result.valid) {
      console.error("Invalid signature:", result.error);
      return res.status(401).json({ error: "Unauthorized" });
    }

    // Process callback
    console.log("Verified callback:", result.data);

    // Acknowledge receipt
    res.status(200).json({ status: "ok" });
  }
);

Signature Algorithm

The signature verification follows Taobao's documentation:

  1. Base String: app_key + raw_body_json (concatenation)
  2. Signature: HMAC-SHA256(base_string, app_secret)
  3. Output: Lowercase hexadecimal string

Example:

import * as crypto from "crypto";

const app_key = "123456";
const raw_body = '{"seller_id":"9999","message_type":0,...}';
const app_secret = "your_secret";

const base = app_key + raw_body;
const signature = crypto
  .createHmac("sha256", app_secret)
  .update(base)
  .digest("hex")
  .toLowerCase();

The signature is sent in the Authorization header.

Callback Message Types

Common message_type values:

  • 0 - Forward transaction (orders, payments, shipping)
  • 3 - Shipping updates
  • Other values may exist - check Taobao documentation

Testing Signature Verification

Test with your real callback data:

TAOBAO_APP_KEY=your_key TAOBAO_APP_SECRET=your_secret npm run example:verify-callback

Troubleshooting

"Signature always fails"

Cause: Raw body was modified after receiving.

Solution: Use request.text() or equivalent to get the raw string BEFORE any parsing.

// Next.js
const rawBody = await request.text();

// Express with body-parser
app.use(express.text({ type: "application/json" }));

// Express with raw-body
app.use((req, res, next) => {
  getRawBody(req, (err, string) => {
    req.rawBody = string;
    next();
  });
});

"Authorization header not found"

Cause: Header is missing from the request.

Solution: Check what headers are actually received: console.log(Object.keys(headers))

Security Best Practices

  1. Always verify signatures in production - Don't process callbacks without verification
  2. Use HTTPS for callback URLs - Required by Taobao
  3. Return 200 only for valid signatures - This prevents replay attacks
  4. Log verification failures - Monitor for potential security issues
  5. Validate timestamp freshness (optional) - Check callback.timestamp is recent
// Optional: Check timestamp is recent (within 5 minutes)
const callbackAge = Date.now() - result.data.timestamp * 1000;
if (callbackAge > 300000) {
  // 5 minutes
  console.warn(
    "Callback timestamp is stale:",
    callbackAge / 1000,
    "seconds old"
  );
}

API Signing

The SDK automatically handles HMAC-SHA256 request signing for outgoing API requests. The signature is generated by:

  1. Merging system parameters (app_key, timestamp, etc.) with API parameters
  2. Sorting parameters alphabetically by key
  3. Building a string: apiName + key1 + value1 + key2 + value2...
  4. Generating HMAC-SHA256 signature using the app secret
  5. Converting to uppercase hexadecimal

You don't need to handle signing manually - the SDK does this for you.

Response Types

Success Response

{
  type: null,
  code: '0',
  message: 'success',
  requestId: 'abc123...',
  body: { /* API response data */ }
}

Error Response

{
  type: 'ISV',  // or 'ISP', 'SYSTEM'
  code: 'ERROR_CODE',
  message: 'Error description',
  requestId: 'abc123...',
  body: { /* Error details */ }
}

Error Types:

  • null - No error
  • ISP - API Service Provider Error
  • ISV - API Request Client Error
  • SYSTEM - IOP Platform Error

Logging

Console Logging (Default)

import { Client, LogLevel } from "taobao-sdk-typescript";

const client = new Client(url, appKey, appSecret, {
  logLevel: LogLevel.DEBUG, // DEBUG, INFO, or ERROR
});

File Logging

import { Client, FileLogger, LogLevel } from "taobao-sdk-typescript";

const logger = new FileLogger(LogLevel.DEBUG, "/path/to/logs");
const client = new Client(url, appKey, appSecret, { logger });

Custom Logger

Implement the Logger interface:

import { Logger } from "taobao-sdk-typescript";

class MyLogger implements Logger {
  debug(message: string): void {
    /* ... */
  }
  info(message: string): void {
    /* ... */
  }
  warn(message: string): void {
    /* ... */
  }
  error(message: string): void {
    /* ... */
  }
}

const client = new Client(url, appKey, appSecret, {
  logger: new MyLogger(),
});

TypeScript Support

This SDK is written in TypeScript and provides full type definitions:

import {
  Client,
  Request,
  Response,
  LogLevel,
  HttpMethod,
  ClientConfig,
  Logger,
} from "@tykealy/taobao-sdk-typescript";

// All types are fully typed and autocomplete works in your IDE

Version History

1.0.0

  • Initial TypeScript port from Ruby SDK
  • Full feature parity with Ruby version
  • Added TypeScript types and interfaces
  • Modern async/await API
  • Improved error handling

License

MIT

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Support

For issues and questions:

  • Check the examples in the examples/ directory
  • Review the API documentation above
  • Ensure your API credentials and endpoints are correct