Skip to content

Latest commit

 

History

History
277 lines (221 loc) · 8.16 KB

File metadata and controls

277 lines (221 loc) · 8.16 KB

AGENTS.md - Box Node SDK v10+ Quick Start

Purpose

This guide helps AI coding agents assist developers in quickly building applications with Box Node SDK v10 or above. Focus on getting developers productive fast with best practices and common pitfalls highlighted.

SDK Version

Use Box Node SDK v10 or above - Auto-generated, TypeScript-first SDK.

npm install box-node-sdk  # Installs latest (v10+)

Why v10+?

  • Auto-generated from Box API OpenAPI specs (always up-to-date)
  • Full TypeScript support with complete type definitions
  • Breaking changes from v3 - NOT backwards compatible
  • Built-in retry logic and error handling

Core Commands

npm install
npm run build
npm start

Run in one go: Use tsc + node (no tsx). This avoids platform-specific native binaries (esbuild) so npm install && npm start works on any platform. If you use tsx, run npm install on the same machine where you run the app—do not copy node_modules across platforms.

Quick Start (4 Steps)

Step 1: Install

npm init -y
npm install box-node-sdk dotenv
npm install --save-dev typescript @types/node

Use tsc + node to run (see Step 4). Do not rely on tsx for "one-command" setups—it pulls in esbuild and can fail with wrong-platform binaries if node_modules was copied or installed elsewhere.

Step 2: Get Developer Token (for testing)

  1. Visit Box Developer Console
  2. Create Custom App → "OAuth 2.0 with JWT" → Generate Developer Token
  3. Copy token (⚠️ expires in 60 min)

Step 3: First Script

// index.ts
import { BoxClient, BoxDeveloperTokenAuth } from 'box-node-sdk';

const auth = new BoxDeveloperTokenAuth({
  token: process.env.BOX_DEVELOPER_TOKEN!
});
const client = new BoxClient({ auth });

const items = await client.folders.getFolderItems('0');
items.entries.forEach(item => console.log(`${item.type}: ${item.name}`));

Step 4: Run

BOX_DEVELOPER_TOKEN=your_token npm start

Or build once then run: npm run build && node dist/index.js. With a .env containing BOX_DEVELOPER_TOKEN, npm start is enough.

Authentication Quick Reference

Developer Token (testing only, 60 min expiry)

const auth = new BoxDeveloperTokenAuth({ token: process.env.BOX_DEVELOPER_TOKEN! });

JWT - Service Account (production, server-to-server)

const auth = new BoxJwtAuth({
  clientId: process.env.BOX_CLIENT_ID!,
  clientSecret: process.env.BOX_CLIENT_SECRET!,
  enterpriseId: process.env.BOX_ENTERPRISE_ID!,
  jwtKeyId: process.env.BOX_JWT_KEY_ID!,
  privateKey: process.env.BOX_PRIVATE_KEY!.replace(/\\n/g, '\n'),
  privateKeyPassphrase: process.env.BOX_PRIVATE_KEY_PASSPHRASE!
});
const client = auth.getClient(); // Service Account client

CCG - Client Credentials (production, application-level)

const auth = new BoxCcgAuth({
  clientId: process.env.BOX_CLIENT_ID!,
  clientSecret: process.env.BOX_CLIENT_SECRET!,
  enterpriseId: process.env.BOX_ENTERPRISE_ID!
});

Service Account & Collaboration

Critical: JWT authentication uses a Service Account - a special Box account that owns uploaded files.

⚠️ Common Issue: "Item not found" or 404 errors often mean:

  • File exists but Service Account doesn't have access
  • Solution: Collaborate the Service Account with the folder/file
// Add Service Account as collaborator to existing folder
await client.collaborations.createCollaboration({
  item: { type: 'folder', id: folderId },
  accessible_by: { type: 'user', id: serviceAccountId },
  role: 'editor' // or 'viewer', 'previewer', 'uploader', 'co-owner'
});

// Get Service Account ID
const currentUser = await client.users.getUserMe();
console.log('Service Account ID:', currentUser.id);

Best Practice: When working with existing Box content:

  1. Get Service Account ID first
  2. Add it as collaborator to target folders
  3. Then perform operations

Common Operations

// Upload file
const upload = await client.uploads.uploadFile({
  attributes: { name: 'doc.pdf', parent: { id: '0' } },
  file: createReadStream('./doc.pdf')
});

// Create folder
const folder = await client.folders.createFolder({
  name: 'My Folder', parent: { id: '0' }
});

// Download file
const stream = await client.downloads.downloadFile(fileId);
await pipeline(stream, createWriteStream('./output.pdf'));

// Search
const results = await client.search.searchForContent({
  query: 'contract', queryParams: { type: 'file' }
});

// List with pagination
const items = await client.folders.getFolderItems(folderId, {
  queryParams: { limit: 100, offset: 0 }
});

Common Box API Errors

Status codes to handle:

  • 401 - Token expired (auto-refreshed with JWT/CCG, manual for DevToken)
  • 403 - Permission denied → Check if Service Account has collaboration access
  • 404 - Not found → File exists but Service Account not collaborated
  • 409 - Conflict (e.g., folder name exists)
  • 429 - Rate limited (implement exponential backoff)
  • 500/503 - Box service error (retry)
import { BoxSdkError } from 'box-node-sdk';

try {
  const file = await client.files.getFileById(fileId);
} catch (error) {
  if (error instanceof BoxSdkError) {
    if (error.response?.status === 404) {
      console.log('File not found - Service Account may need collaboration access');
    } else if (error.response?.status === 403) {
      console.log('Access denied - Ensure Service Account is collaborated on this item');
    }
  }
  throw error;
}

Project Structure Hints

Quick navigation:

  • Authentication → *auth*.ts, box-client.ts
  • File operations → services/file*.ts, *upload*.ts
  • Environment config → .env, config/
  • Tests → *.test.ts, /tests

Recommended structure:

src/
├── box-client.ts       # Client initialization
├── services/
│   ├── file-service.ts
│   └── folder-service.ts
└── index.ts

Security Critical

🔒 Never commit:

  • Developer tokens
  • JWT private keys
  • Client secrets
  • Box config JSON files

🔒 Token lifecycle:

  • Developer tokens: 60 min, NO auto-refresh
  • JWT/CCG access tokens: 60 min, auto-refreshed by SDK
  • Always use environment variables

🔒 Service Account security:

  • Service Account has admin privileges in enterprise
  • Use app users for customer-scoped data
  • Apply least privilege principle

Safety & Permissions

Agent can do without asking:

  • client.files.getFileById() - Read files
  • client.folders.getFolderItems() - List contents
  • npm test -- <specific-test> - Run single test
  • tsc --noEmit - Type checking

Agent must ask first:

  • npm install <package> - Installing dependencies
  • client.files.deleteFileById() - Deleting content
  • client.folders.deleteFolderById() - Deleting folders
  • Full test suite in CI
  • Revoking tokens or collaborations

Common Mistakes

Using v3 syntax (callbacks)

// Wrong
client.files.get(fileId, null, callback);
// Right
await client.files.getFileById(fileId);

Forgetting Service Account collaboration

// Wrong - assuming Service Account has access
await client.files.getFileById(existingFileId); // 404 error!

// Right - check and add collaboration first
const user = await client.users.getUserMe();
await client.collaborations.createCollaboration({
  item: { type: 'folder', id: folderId },
  accessible_by: { type: 'user', id: user.id },
  role: 'editor'
});

Hardcoding IDs

// Wrong
const folderId = '123456789';
// Right
const folderId = process.env.BOX_FOLDER_ID!;

When to Ask Developer

Agent should escalate when:

  • Choosing JWT vs CCG vs OAuth (business requirement)
  • Setting up Box app in Developer Console
  • Requesting admin authorization for JWT app
  • Deciding on Service Account vs app users architecture
  • Implementing webhook handlers
  • Custom retry/rate limit strategies beyond exponential backoff

Resources


Version: 1.0 | SDK: v10+ | Last Updated: Feb 2026