npm package: @odecloud/sdk
Description: Official Node.js SDK for the OdeCloud API
Author: OdeCloud
Latest version: 0.2.0

# @odecloud/sdk

Official Node.js/TypeScript SDK for the OdeCloud API.

## Installation

```bash
npm install @odecloud/sdk
```

## Quick Start

```typescript
import { OdeCloud } from '@odecloud/sdk';

const client = new OdeCloud({
  apiKey: 'ode_live_...',
});

// Get your profile
const profile = await client.profile.get();
console.log(`Hello, ${profile.firstName}!`);

// List projects
const projects = await client.projects.list();
for (const project of projects.data) {
  console.log(project.title);
}

// Find tasks for a project
const tasks = await client.projects.listTasks(projects.data[0]._id);
const task = tasks.data[0];

// Log time against a task
const now = Date.now();
const entry = await client.timeEntries.create({
  taskId: task._id,
  times: [{ startedAt: now - 3600000, endedAt: now }],
  billable: true,
  notes: 'Worked on feature implementation',
});
```

## Configuration

```typescript
const client = new OdeCloud({
  apiKey: 'ode_live_...',                                        // Required
  baseUrl: 'https://server.odecloud.app/api/v1/public',         // Optional (default shown)
  timeout: 30000,                                                 // Optional (ms, default: 30000)
  maxRetries: 3,                                                  // Optional (default: 3)
});
```

## Time Entries

```typescript
// List time entries with filters
const entries = await client.timeEntries.list({
  projectId: 'project-id',
  taskId: 'task-id',
  startDate: '2026-01-01',
  endDate: '2026-01-31',
  billable: true,
  page: 1,
  pageSize: 50,
});

// Get a single entry
const entry = await client.timeEntries.get('entry-id');

// Create a time entry
const newEntry = await client.timeEntries.create({
  taskId: 'task-id',
  times: [
    { startedAt: 1706360400000, endedAt: 1706364000000 },
  ],
  billable: true,
  notes: 'Implemented new feature',
});

// Update a time entry
const updated = await client.timeEntries.update('entry-id', {
  notes: 'Updated notes',
  billable: false,
});

// Delete a time entry
await client.timeEntries.delete('entry-id');

// Get summary for a date range
const summary = await client.timeEntries.summary({
  startDate: '2026-01-01',
  endDate: '2026-01-31',
  projectId: 'project-id', // optional
});

console.log(`Total: ${summary.totalTimeHours}h`);
console.log(`Billable: ${summary.billableTimeHours}h`);
console.log(`Entries: ${summary.entryCount}`);
```

## Projects

```typescript
// List projects
const projects = await client.projects.list({
  search: 'JVCKenwood',
  page: 1,
  pageSize: 50,
});

// Get project details (includes members)
const project = await client.projects.get('project-id');
console.log(`${project.title} — ${project.members.length} members`);

// List tasks for a project
const tasks = await client.projects.listTasks('project-id', {
  status: 'active',
});

for (const task of tasks.data) {
  const hours = (task.currentTime / 3600000).toFixed(1);
  console.log(`${task.title}: ${hours}h tracked`);
}
```

## Profile

```typescript
// Get your profile
const profile = await client.profile.get();
console.log(profile.firstName, profile.lastName);
console.log(profile.email);

// Update your profile
await client.profile.update({
  tagline: 'Senior Developer',
  location: 'New York, NY',
  socialLinks: {
    linkedin: 'https://linkedin.com/in/johndoe',
    github: 'https://github.com/johndoe',
  },
});
```

## Pagination

```typescript
// Manual pagination
const page1 = await client.timeEntries.list({ page: 1, pageSize: 100 });
console.log(`Page 1: ${page1.data.length} entries, hasNext: ${page1.hasNextPage}`);

// Auto-pagination (recommended)
for await (const entry of client.timeEntries.listAutoPaginate()) {
  console.log(entry.notes);
}

// Collect all items into an array
import { collectAll } from '@odecloud/sdk';

const allEntries = await collectAll(client.timeEntries.listAutoPaginate());
console.log(`Total entries: ${allEntries.length}`);
```

## Error Handling

```typescript
import {
  OdeCloud,
  OdeCloudError,
  AuthenticationError,
  NotFoundError,
  RateLimitError,
} from '@odecloud/sdk';

try {
  await client.timeEntries.get('invalid-id');
} catch (error) {
  if (error instanceof AuthenticationError) {
    console.error('Invalid API key');
  } else if (error instanceof NotFoundError) {
    console.error('Entry not found');
  } else if (error instanceof RateLimitError) {
    console.error(`Rate limited. Retry after ${error.retryAfter}s`);
  } else if (error instanceof OdeCloudError) {
    console.error(`API error [${error.statusCode}]: ${error.message}`);
  }
}
```

## API Scopes

| Scope | Description |
|-------|-------------|
| `time:read` | Read time entries and summaries |
| `time:write` | Create, update, delete time entries |
| `projects:read` | Read projects and tasks |
| `clients:read` | Read organizations/clients |
| `profile:read` | Read your profile |
| `profile:write` | Update your profile |

## Requirements

- Node.js 18+
- TypeScript 4.7+ (if using TypeScript)

## License

MIT