npm package: @plankton.mobi/ims-sdk
Description: Plankton IMS SDK - Client library for the Inventory Management System API
Author: Plankton
Latest version: 1.0.0

# @plankton/ims-sdk

Official TypeScript SDK for the Plankton IMS (Inventory Management System) API.

## Installation

```bash
npm install @plankton/ims-sdk
```

## Quick Start

```typescript
import { init } from '@plankton/ims-sdk';

// Initialize the SDK
const ims = init({
  apiUrl: 'https://ims-api-1004574811436.africa-south1.run.app',
  getToken: async () => {
    // Return a valid Firebase/Itsumi token
    const user = auth.currentUser;
    return user ? await user.getIdToken() : '';
  },
});

// Query entities
const { data: characters } = await ims.getEntities({ type: 'character' });
console.log(characters);

// Register a managed object
const object = await ims.register({
  type: 'collectible',
  name: 'Simba Digital Card',
  description: 'A collectible digital card featuring Simba the Lion',
  tags: ['character', 'big5', 'lion'],
  rule_sets: [
    {
      type: 'commerce',
      config: {
        sku: 'CARD-SIMBA-001',
        price_cents: 999,
        currency: 'ZAR',
        channels: ['app', 'web'],
      },
    },
    {
      type: 'entitlement',
      config: {
        access_type: 'unlimited',
        binding: 'user',
        transferable: false,
      },
    },
  ],
});

console.log('Created object:', object.id);
```

## Usage Patterns

### Pattern 1: Singleton (Recommended)

Initialize once, use everywhere:

```typescript
// In your app initialization
import { init } from '@plankton/ims-sdk';

init({
  apiUrl: process.env.IMS_API_URL!,
  getToken: () => getAuthToken(),
});

// Anywhere else in your app
import { getEntities, register, resolve } from '@plankton/ims-sdk';

const entities = await getEntities({ type: 'park' });
```

### Pattern 2: Direct Client Instance

For more control or multiple clients:

```typescript
import { IMSClient } from '@plankton/ims-sdk';

const client = new IMSClient({
  apiUrl: 'https://ims-api.plankton.mobi',
  getToken: () => getAuthToken(),
  timeout: 60000, // 60 second timeout
});

const entities = await client.getEntities({ type: 'park' });
```

## API Reference

### Objects

```typescript
// Register a new object
const obj = await ims.register({
  type: 'collectible',
  name: 'My Object',
  description: 'Description here',
  tags: ['tag1', 'tag2'],
});

// Get an object
const obj = await ims.get('uuid-here');

// Update an object
await ims.update('uuid-here', {
  name: 'New Name',
  description: 'Updated description',
});

// Query objects
const { data, total, has_more } = await ims.query({
  type: 'collectible',
  status: 'published',
  search: 'simba',
  limit: 20,
});

// Publish an object
await ims.publish('uuid-here');

// Add a rule set
await ims.addRuleSet('uuid-here', {
  type: 'commerce',
  config: {
    sku: 'SKU-001',
    price_cents: 1000,
    currency: 'ZAR',
    channels: ['app'],
  },
});
```

### Resolution (QR/Token)

```typescript
// Resolve a QR code
const result = await ims.resolve({
  token_code: 'ABC123',
  location: { lat: -33.9, lng: 18.4 },
  device_id: 'device-uuid',
});

if (result.success) {
  console.log('Content URI:', result.storage_uri);
}

// Convenience method
const result = await ims.resolveToken('ABC123', {
  location: { lat: -33.9, lng: 18.4 },
});
```

### Events

```typescript
// Emit an event
const event = await ims.emit({
  event_type: 'content_accessed',
  target_object_id: 'uuid-here',
  payload: {
    custom_data: 'value',
  },
});
```

### Catalog

```typescript
// Get available products
const { data: products } = await ims.getCatalog({
  channel: 'app',
  territory: 'ZA',
  type: 'collectible',
});
```

### Entitlements

```typescript
// Get current user's entitlements
const { entitlements } = await ims.getMyEntitlements();

// Check if user has access
const { has_entitlement } = await ims.checkEntitlement('user-id', 'object-id');

// Grant entitlement
await ims.grantEntitlement({
  holder_id: 'user-id',
  managed_object_id: 'object-id',
  grant_type: 'purchase',
  access_type: 'unlimited',
});
```

### Entities (Ontology)

```typescript
// Get all characters
const { data: characters } = await ims.getEntities({ type: 'character' });

// Get all parks
const { data: parks } = await ims.getEntities({ type: 'park' });

// Search entities
const { data: results } = await ims.getEntities({
  type: 'character',
  search: 'simba',
});
```

## Types

All types are exported for use in your TypeScript code:

```typescript
import type {
  ManagedObject,
  ManagedObjectType,
  ObjectStatus,
  RuleSet,
  RuleType,
  Entity,
  EntityType,
  Entitlement,
  CatalogItem,
  // Request/Response types
  RegisterObjectRequest,
  QueryObjectsRequest,
  ResolveRequest,
  EmitEventRequest,
  // Rule configs
  CommerceConfig,
  EntitlementConfig,
  GovernanceConfig,
  ResolutionConfig,
} from '@plankton/ims-sdk';
```

## Error Handling

```typescript
import { IMSApiError } from '@plankton/ims-sdk';

try {
  await ims.get('non-existent-id');
} catch (error) {
  if (error instanceof IMSApiError) {
    console.log('Status:', error.status); // 404
    console.log('Code:', error.code); // 'not_found'
    console.log('Message:', error.message);
  }
}
```

## Configuration Options

| Option | Type | Required | Default | Description |
|--------|------|----------|---------|-------------|
| `apiUrl` | `string` | Yes | - | Base URL of the IMS API |
| `getToken` | `() => Promise<string> \| string` | Yes | - | Function that returns auth token |
| `tenantCode` | `string` | No | - | Override tenant code |
| `timeout` | `number` | No | 30000 | Request timeout in ms |

## License

MIT