npm package: @hr-platform/sdk
Description: TypeScript SDK for HR Platform API
Author: Vollers Group IT
Latest version: 0.2.0

# @hr-platform/sdk

Type-safe TypeScript SDK for the HR Platform API with built-in retry logic, rate limit handling, and comprehensive error classes.

## Installation

```bash
npm install @hr-platform/sdk
```

## Quick Start

### API Key Authentication (Service-to-Service)

For integrations with external systems like Microsoft D365 F&O:

```typescript
import { HRPlatformClient } from '@hr-platform/sdk'

const client = HRPlatformClient.withApiKey('hrp_live_xxx...', {
  baseUrl: 'https://hr-platform.vercel.app'
})

// List all records
const records = await client.records.list()

// Get analytics summary
const summary = await client.analytics.getSummary({ entity: 'BVD' })
```

### Cookie Authentication (Browser Apps)

For browser-based applications using session cookies:

```typescript
import { HRPlatformClient } from '@hr-platform/sdk'

const client = HRPlatformClient.withCookieAuth({
  baseUrl: window.location.origin
})

// Get current user profile
const profile = await client.users.getProfile()
```

## Features

- **Type-Safe** - Full TypeScript types generated from OpenAPI specification
- **Retry Logic** - Automatic retries with exponential backoff for transient failures
- **Rate Limit Handling** - Respects `Retry-After` headers from rate limit responses
- **Error Classes** - Typed error classes for different HTTP status codes
- **Minimal Bundle** - ~20KB minified, uses native `fetch`

## Configuration

### Full Configuration Options

```typescript
import { HRPlatformClient } from '@hr-platform/sdk'

const client = new HRPlatformClient({
  baseUrl: 'https://hr-platform.vercel.app',
  apiVersion: 'v1', // default: 'v1'
  auth: { type: 'apiKey', apiKey: 'hrp_live_xxx...' },
  timeout: 30000, // default: 30000ms
  retry: {
    maxRetries: 3, // default: 3
    initialDelay: 1000, // default: 1000ms
    maxDelay: 30000, // default: 30000ms
    backoffMultiplier: 2, // default: 2
    retryableStatuses: [408, 429, 500, 502, 503, 504], // default
    respectRetryAfter: true // default: true
  },
  headers: {
    'X-Custom-Header': 'value'
  }
})
```

## API Reference

### Records

```typescript
// List all records (respects entity scoping)
const records = await client.records.list()

// List with filters
const filtered = await client.records.list({
  entity: 'BVD',
  year: '2025',
  month: '10',
  status: 'APPROVED'
})

// Get single record
const record = await client.records.get('record-uuid')

// Create record
const { id } = await client.records.create({
  entity: 'BVD',
  year: 2025,
  month: 11,
  working_days: 21,
  workforce: {
    bc_male: 20,
    bc_female: 5,
    // ... other fields
  },
  // ... capacity, absences, turnover, performance, financials
})

// Update record (only DRAFT status)
await client.records.update('record-uuid', {
  working_days: 22,
  // ... updated fields
})

// Delete record (requires appropriate permissions)
await client.records.delete('record-uuid')

// Workflow actions
await client.records.submit('record-uuid')
await client.records.approve('record-uuid')
await client.records.reject('record-uuid', 'Please correct the sick days')
```

### Analytics

```typescript
// Get summary metrics
const summary = await client.analytics.getSummary({
  entity: 'BVD', // or 'All'
  year: '2025',
  month: '10'
})

// Get trend data for charts
const trends = await client.analytics.getTrends({
  entity: 'BVD'
})

// Get entity breakdown
const breakdown = await client.analytics.getByEntity()
```

### Users

```typescript
// Get current user profile
const profile = await client.users.getProfile()

// Update profile
await client.users.updateProfile({
  name: 'New Name'
})

// Change password
await client.users.changePassword({
  currentPassword: 'old-password',
  newPassword: 'new-secure-password'
})

// Get password policy
const policy = await client.users.getPasswordPolicy()

// User management (requires system_admin role)
const users = await client.users.list()
const user = await client.users.get('user-uuid')
await client.users.create({
  name: 'New User',
  email: 'user@example.com',
  password: 'SecurePass123!',
  role: 'local_partner',
  entity: 'BVD'
})
await client.users.update('user-uuid', { role: 'group_head' })
await client.users.delete('user-uuid')
```

### Admin (requires system_admin role)

```typescript
// System status
const status = await client.admin.getStatus()
const security = await client.admin.getSecurityDashboard()

// User administration
await client.admin.blockUser('user-uuid')
await client.admin.unblockUser('user-uuid')
await client.admin.resetPassword('user-uuid')
await client.admin.resetRateLimit('user@example.com')

// Session management
const sessions = await client.admin.listSessions()
await client.admin.forceLogout('user-uuid')
await client.admin.invalidateAllSessions()

// Audit logs
const logs = await client.admin.getAuditLogs({
  page: 1,
  limit: 25,
  category: 'auth',
  severity: 'warning'
})

// API key management
const keys = await client.admin.listApiKeys()
const { plainTextKey } = await client.admin.createApiKey({
  name: 'Integration Key',
  userId: 'user-uuid',
  scopes: ['records:read', 'analytics:read'],
  expiresInDays: 365
})
await client.admin.revokeApiKey('key-uuid')
await client.admin.rotateApiKey('key-uuid')
```

### Compliance

```typescript
// Get compliance status
const status = await client.compliance.getStatus()

// Get compliance documents
const { documents } = await client.compliance.getDocuments()
const doc = await client.compliance.getDocument('privacy_notice')

// Acknowledge document
await client.compliance.acknowledge({
  documentType: 'privacy_notice',
  documentVersion: '1.0.0',
  documentContentHash: doc.contentHash
})

// Complete compliance flow
await client.compliance.complete()

// Admin: compliance overview (requires system_admin)
const overview = await client.compliance.getAdminOverview()
await client.compliance.resetUser('user-uuid')
```

### Webhooks

```typescript
// List subscriptions
const subscriptions = await client.webhooks.list()

// Create subscription
const webhook = await client.webhooks.create({
  name: 'My Webhook',
  url: 'https://example.com/webhook',
  events: ['record.created', 'record.approved']
})

// Update subscription
await client.webhooks.update('subscription-uuid', {
  enabled: false
})

// Delete subscription
await client.webhooks.delete('subscription-uuid')

// Test webhook
const result = await client.webhooks.test('subscription-uuid')

// Get delivery history
const history = await client.webhooks.getDeliveryHistory('subscription-uuid', {
  page: 1,
  limit: 50
})

// Get available event types
const { events } = await client.webhooks.getEventTypes()
```

## Error Handling

The SDK provides typed error classes for different failure scenarios:

```typescript
import {
  HRPlatformClient,
  NotFoundError,
  ValidationError,
  RateLimitError,
  AuthenticationError,
  AuthorizationError,
  ConflictError,
  ServerError,
  NetworkError,
  TimeoutError
} from '@hr-platform/sdk'

try {
  const record = await client.records.get('invalid-id')
} catch (error) {
  if (error instanceof NotFoundError) {
    console.log('Record not found')
  } else if (error instanceof ValidationError) {
    console.log('Validation errors:', error.details)
  } else if (error instanceof RateLimitError) {
    console.log(`Rate limited. Retry after ${error.retryAfter} seconds`)
  } else if (error instanceof AuthenticationError) {
    console.log('Invalid or expired credentials')
  } else if (error instanceof AuthorizationError) {
    console.log('Insufficient permissions')
  } else if (error instanceof ConflictError) {
    console.log('Resource conflict (e.g., duplicate record)')
  } else if (error instanceof ServerError) {
    console.log('Server error:', error.message)
  } else if (error instanceof NetworkError) {
    console.log('Network error:', error.message)
  } else if (error instanceof TimeoutError) {
    console.log('Request timed out')
  }
}
```

### Error Properties

All errors extend `HRPlatformError` and include:

| Property | Type | Description |
|----------|------|-------------|
| `message` | string | Error message |
| `status` | number | HTTP status code |
| `code` | string | Error code (if provided by API) |
| `details` | unknown | Additional error details |

Special properties:

- `ValidationError.details` - Array of field-level validation errors
- `RateLimitError.retryAfter` - Seconds until rate limit resets

## TypeScript Types

The SDK exports all types from the OpenAPI specification:

```typescript
import type {
  // Records
  FullHRRecord,
  CreateRecordRequest,
  Entity,
  RecordStatus,

  // Analytics
  AnalyticsSummary,
  AnalyticsTrend,
  EntityBreakdown,

  // Users
  User,
  UserRole,

  // Admin
  SystemStatus,
  AuditLog,
  ApiKey,

  // Compliance
  ComplianceDocument,
  UserComplianceStatus,

  // Webhooks
  WebhookSubscription,
  WebhookEvent,

  // Configuration
  HRPlatformConfig,
  AuthConfig,
  RetryConfig
} from '@hr-platform/sdk'
```

For advanced usage, access the raw OpenAPI types:

```typescript
import type { paths, components, operations } from '@hr-platform/sdk'
```

## Browser Compatibility

The SDK uses native `fetch` and works in:
- Modern browsers (Chrome, Firefox, Safari, Edge)
- Node.js 18+ (native fetch)
- Bun, Deno

For older Node.js versions, install a fetch polyfill:

```bash
npm install node-fetch
```

## License

MIT