Skip to content

Latest commit

 

History

History
253 lines (190 loc) · 6.43 KB

File metadata and controls

253 lines (190 loc) · 6.43 KB

@caixuan-cc/sdk

English · 中文 · Français · Español · Deutsch · Русский · 日本語 · 한국어

TypeScript SDK for the Caixuan platform. Integrate with the Caixuan API from Node.js services, scripts, or automation workflows.

Installation

npm install @caixuan-cc/sdk

Requires Node.js >= 18.

Quick start

import { createCaixuan } from '@caixuan-cc/sdk';

const client = createCaixuan({
  token: process.env.CAIXUAN_TOKEN,
  spaceId: process.env.CAIXUAN_SPACE_ID,
});

// Get current session
const session = await client.session.get();

// List spaces
const { rows: spaces } = await client.spaces.list();

// Upload a file and create a document
const file = await client.files.upload('./deck.pptx');
const doc = await client.docs.create({
  spaceId: spaces[0].id,
  fileId: file.id,
  name: file.name,
});

Initialize the client

Create a client instance with createCaixuan():

import { createCaixuan, DEFAULT_ROOT } from '@caixuan-cc/sdk';

const client = createCaixuan({
  root: DEFAULT_ROOT,           // API root URL, default https://app.caixuan.cc/api
  token: 'your-auth-token',     // User token (X-Auth-Token header)
  spaceId: 'space-id',          // Current space ID (optional; resolved automatically if omitted)
  userId: 'user-id',            // User ID (optional)
  lang: 'en',                   // Language: 'zh' | 'en'
  basicAuth: 'user:pass',       // nginx Basic Auth (optional)
  onUnauthorized: async () => { // Refresh token on expiry (optional)
    const newToken = await refreshToken();
    return { token: newToken };
  },
});

You can also update credentials after the client is created:

client.setToken('new-token');
client.setSpaceId('space-id');
client.setUserId('user-id');
client.setBasicAuth('user:pass');

Obtaining a token

  • Complete OAuth login in the Caixuan web app
  • Or use the CLI: run caixuan login, then caixuan config show

Space ID resolution

Most APIs require a spaceId. If none is provided at initialization, the SDK resolves it in this order:

  1. Explicitly set spaceId
  2. defaultSpace.id from /session

API modules

Access resource APIs through namespaces on the client:

Module Description
client.session Session (current user, logout)
client.spaces Space list, details, switch
client.shares Share link CRUD
client.docs Document CRUD
client.members Space member management
client.files File upload

Session

const session = await client.session.get();
// session.id, session.defaultSpace, ...

await client.session.logout();

Spaces

const { rows, count } = await client.spaces.list();
const space = await client.spaces.get();           // Current space
const current = await client.spaces.current();     // From session
await client.spaces.select('space-id');            // Switch and set as default

Shares

const { rows } = await client.shares.list(undefined, { _startIndex: 0, _maxResults: 20 });
const share = await client.shares.get('share-id', ['content']);

const created = await client.shares.create({
  spaceId: 'space-id',
  name: 'My share',
  description: 'Optional description',
  content: [{ _type: 'doc', id: 'doc-id' }],
  needPhone: 'no',
});

await client.shares.update({ id: 'share-id', name: 'New name', password: '1234' });
await client.shares.delete('share-id');

Docs

const { rows } = await client.docs.list(undefined, { name: 'demo', tag: 'pptx' });
const doc = await client.docs.get('doc-id');

const created = await client.docs.create({
  spaceId: 'space-id',
  fileId: 'file-id',
  name: 'demo.pptx',
  folderId: '',
});

await client.docs.rename('doc-id', 'new-name.pptx');
await client.docs.delete('doc-id');
await client.docs.recover('doc-id');

Members

const { rows } = await client.members.list();
const member = await client.members.get(undefined, 'user-id');

await client.members.add({
  spaceId: 'space-id',
  role: 'teammate',   // 'manager' | 'teammate' | 'guest'
  email: 'user@example.com',
  name: 'Jane Doe',
});

await client.members.updateRole(undefined, 'user-id', 'manager');
await client.members.rename(undefined, 'user-id', 'New name');
await client.members.remove(undefined, 'user-id');

Files (upload)

Supports local file paths or binary data, with automatic single-file and multipart upload:

// Upload a local file
const result = await client.files.upload('./presentation.pptx', {
  spaceId: 'space-id',
  onProgress: (pct) => console.log(`${Math.round(pct * 100)}%`),
});
// result: { id, name, bytes, hash }

// Upload binary data (name required)
const buffer = new Uint8Array(await fetch(url).then(r => r.arrayBuffer()));
const result2 = await client.files.upload(buffer, {
  spaceId: 'space-id',
  name: 'remote-file.pptx',
});

Typical workflow: call files.upload() to get fileId, then docs.create() to create the document.

Pagination

List endpoints return ListResult<T>:

interface ListResult<T> {
  rows: T[];
  count: number;
}

Pagination parameters:

await client.shares.list(undefined, { _startIndex: 0, _maxResults: 50 });

Error handling

The SDK wraps API errors as APIError:

import { APIError, isRetriableError } from '@caixuan-cc/sdk';

try {
  await client.docs.get('invalid-id');
} catch (err) {
  if (err instanceof APIError) {
    console.error(err.statusCode);    // HTTP status code
    console.error(err.code);          // Business error code
    console.error(err.requestId);     // Request trace ID
    console.error(err.requestUrl);    // Request URL
    console.error(err.requestPayload);// Request body
  }

  if (isRetriableError(err)) {
    // Network errors or 502/604 — safe to retry
  }
}

The SDK automatically retries retriable errors (network timeouts, 502, 604) with exponential backoff.

On 401 Unauthorized, if onUnauthorized is configured, the SDK refreshes the token and retries the request.

Type exports

import type {
  CaixuanClient,
  CreateCaixuanOptions,
  MySpace,
  SessionInfo,
  ListResult,
  CreateShareParams,
  UpdateShareParams,
  CreateDocParams,
  AddMemberParams,
  FileUploadResult,
} from '@caixuan-cc/sdk';

License

MIT