JSPM

  • Created
  • Published
  • Downloads 13
  • Score
    100M100P100Q77096F
  • License MIT

TypeScript SDK for the Arke API - auto-generated from OpenAPI spec

Package Exports

  • @arke-institute/sdk
  • @arke-institute/sdk/generated
  • @arke-institute/sdk/operations
  • @arke-institute/sdk/spec

Readme

@arke-institute/sdk

TypeScript SDK for the Arke API - auto-generated from OpenAPI spec.

Installation

npm install @arke-institute/sdk

Quick Start

import { ArkeClient } from '@arke-institute/sdk';

const arke = new ArkeClient({
  authToken: 'your-jwt-token',
});

// Create an entity
const { data, error } = await arke.api.POST('/entities', {
  body: {
    collection_id: '01ABC...',
    type: 'document',
    properties: { title: 'My Document' },
  },
});

if (error) {
  console.error('Failed:', error);
} else {
  console.log('Created:', data.id);
}

Configuration

const arke = new ArkeClient({
  // Base URL (default: 'https://api.arke.institute')
  baseUrl: 'https://api.arke.institute',

  // JWT or API key
  authToken: 'your-token',

  // Network: 'main' or 'test' (default: 'main')
  network: 'test',

  // Custom headers
  headers: {
    'X-Custom-Header': 'value',
  },
});

API Access

All API calls are made through the arke.api property, which provides full type safety:

// GET request
const { data } = await arke.api.GET('/entities/{id}', {
  params: { path: { id: '01XYZ...' } },
});

// POST request
const { data } = await arke.api.POST('/entities', {
  body: { collection_id: '...', type: 'document', properties: {} },
});

// PUT request (update)
const { data } = await arke.api.PUT('/entities/{id}', {
  params: { path: { id: '01XYZ...' } },
  body: { expect_tip: 'bafyrei...', properties_merge: { status: 'active' } },
});

// DELETE request
await arke.api.DELETE('/relationships', {
  body: { source_id: '...', target_id: '...', predicate: 'contains' },
});

Available Endpoints

The SDK provides typed access to all Arke API endpoints:

Endpoint Group Description
/auth/* Authentication and registration
/users/* User profile and API keys
/collections/* Collection CRUD, roles, members
/entities/* Entity CRUD
/relationships Relationship management
/files/* File storage and downloads
/folders/* Folder hierarchy
/versions/* Version history
/agents/* Agent management
/permissions/* Permission introspection

Error Handling

import {
  ArkeError,
  CASConflictError,
  NotFoundError,
  parseApiError
} from '@arke-institute/sdk';

const { data, error, response } = await arke.api.GET('/entities/{id}', {
  params: { path: { id: 'invalid-id' } },
});

if (error) {
  // Parse into typed error
  const arkeError = parseApiError(response.status, error);

  if (arkeError instanceof CASConflictError) {
    console.log('Concurrent modification - expected:', arkeError.expectedTip);
  } else if (arkeError instanceof NotFoundError) {
    console.log('Entity not found');
  }
}

CAS Retry for Concurrent Updates

When multiple clients update the same entity simultaneously, use withCasRetry for automatic retry with backoff:

import { ArkeClient, withCasRetry } from '@arke-institute/sdk';

const client = new ArkeClient({ authToken: 'xxx' });

const { data, attempts } = await withCasRetry({
  getTip: async () => {
    // Lightweight endpoint - single DO lookup, no manifest fetch
    const { data } = await client.api.GET('/entities/{id}/tip', {
      params: { path: { id: entityId } }
    });
    return data!.cid;
  },
  update: async (tip) => {
    return client.api.PUT('/entities/{id}', {
      params: { path: { id: entityId } },
      body: {
        expect_tip: tip,
        relationships_add: [{ predicate: 'contains', peer: childId }]
      }
    });
  }
}, { concurrency: 100 }); // Expected number of concurrent writers

console.log(`Updated in ${attempts} attempt(s)`);

Set concurrency based on expected parallel updates. The utility automatically:

  • Staggers initial requests to reduce collisions
  • Applies exponential backoff with jitter on conflicts
  • Scales retry attempts based on concurrency level

See docs/cas-retry.md for best practices.

Authentication Management

const arke = new ArkeClient();

// Set token after login
arke.setAuthToken('new-token');

// Check auth status
if (arke.isAuthenticated) {
  // Make authenticated requests
}

// Clear token on logout
arke.clearAuthToken();

Test Network

Use the test network for development (uses 'II' prefixed IDs):

const arke = new ArkeClient({
  authToken: 'your-token',
  network: 'test',
});

Folder Upload

Upload entire folder structures with automatic CID computation and relationship linking:

Node.js

import { ArkeClient } from '@arke-institute/sdk';
import { uploadTree, scanDirectory } from '@arke-institute/sdk/operations';

const arke = new ArkeClient({ authToken: 'your-token' });

// Scan a local directory
const tree = await scanDirectory('/path/to/my-folder');

// Upload to a new collection
const result = await uploadTree(arke, tree, {
  target: {
    createCollection: {
      label: 'My Upload',
      description: 'Uploaded folder contents',
    },
  },
  onProgress: (p) => {
    console.log(`${p.phase}: ${p.completedFiles}/${p.totalFiles} files`);
  },
});

console.log('Collection:', result.collection.id);
console.log('Files:', result.files.length);
console.log('Folders:', result.folders.length);

Browser (Drag & Drop)

import { uploadTree, scanFileSystemEntries } from '@arke-institute/sdk/operations';

dropzone.ondrop = async (e) => {
  e.preventDefault();
  const entries = Array.from(e.dataTransfer.items)
    .map(item => item.webkitGetAsEntry())
    .filter(Boolean);

  const tree = await scanFileSystemEntries(entries);
  const result = await uploadTree(client, tree, {
    target: { collectionId: 'existing-collection-id' },
  });
};

Browser (File Input)

import { uploadTree, scanFileList } from '@arke-institute/sdk/operations';

// <input type="file" webkitdirectory multiple />
input.onchange = async (e) => {
  const tree = await scanFileList(e.target.files);
  const result = await uploadTree(client, tree, {
    target: { parentId: 'existing-folder-id', collectionId: 'collection-id' },
  });
};

Upload Options

const result = await uploadTree(client, tree, {
  target: {
    // Option 1: Create new collection
    createCollection: { label: 'New Collection' },

    // Option 2: Upload to existing collection root
    collectionId: '01ABC...',

    // Option 3: Upload to existing folder
    collectionId: '01ABC...',
    parentId: '01XYZ...',
  },

  // Progress tracking
  onProgress: (p) => console.log(p.phase, p.completedFiles),

  // Parallel uploads (default: 5)
  concurrency: 10,

  // Continue if some files fail
  continueOnError: true,
});

CID Utilities

import { computeCid, verifyCid } from '@arke-institute/sdk/operations';

// Compute CIDv1 for any content
const cid = await computeCid(new TextEncoder().encode('hello'));
// => "bafkreifzjut3te2nhyekklss27nh3k72ysco7y32koao5eei66wof36n5e"

// Verify content matches CID
const isValid = await verifyCid(content, expectedCid);

Development

Regenerate Types

When the API changes, regenerate the types:

# From production API
npm run generate

# From local dev server
npm run generate:local

Build

npm run build

Test

npm test

Publish

# Dry run
npm run publish-all:dry

# Actual publish
npm run publish-all

High-Level Operations

The SDK includes modules for common workflows:

  • CAS Retry: Concurrent update handling with automatic retry (docs)
  • Folder Upload: Upload entire directory structures with CID computation
  • BatchOperations: Bulk entity/relationship creation (planned)
  • CryptoOperations: Ed25519 key generation (planned)

License

MIT