Xeonr Developer Docs
SDK

API Client

Low-level API access using authenticated Connect RPC clients.

For operations beyond the high-level upload() and download() methods, you can create authenticated API clients that call the upl.im services directly. The SDK handles token management and authentication retry automatically.

Creating an API client

From an Upl instance

import { Upl } from '@xeonr/uploads-sdk';
import { BucketUploadsService } from '@xeonr/uploads-protocol/uplim/api/v1/uploads_pb';

const upl = new Upl({ clientId: 'your-client-id' });

// Option 1: Get a typed client directly
const uploads = upl.getApiClient(BucketUploadsService, {
  interactive: true, // Allow popup login if token is missing
});

// Option 2: Get an adapter and create clients manually
const adapter = upl.getApiAdapter({ interactive: true });

Using getUploadClientWithEnv

For use outside of the Upl class (e.g. in renderers or services), create clients from an adapter directly:

import { getUploadClientWithEnv } from '@xeonr/uploads-sdk/api/base';
import { BucketUploadsService } from '@xeonr/uploads-protocol/uplim/api/v1/uploads_pb';

const client = getUploadClientWithEnv(BucketUploadsService, adapter);

The adapter can come from upl.getApiAdapter(), a renderer's apiAdapter, or a manually constructed IUploadAdapterEnv.

Adapter interface

interface IUploadAdapterEnv {
  hostname?: string;
  tokenHelper?: () => Promise<string | null>;
  onAuthenticationExpired?: (retryCount: number) => Promise<boolean>;
  onAuthenticationFailed?: () => Promise<any>;
  extraHeaders?: () => Record<string, string>;
}
FieldDescription
hostnameAPI base URL
tokenHelperReturns the current access token (called on every request)
onAuthenticationExpiredCalled when a request returns Unauthenticated — return true to retry
onAuthenticationFailedCalled when retry also fails
extraHeadersAdditional headers to include on every request

The SDK's auth interceptor:

  1. Adds Authorization: Bearer {token} via tokenHelper
  2. Adds any extraHeaders
  3. On Unauthenticated error: calls onAuthenticationExpired, retries if it returns true
  4. On second failure: calls onAuthenticationFailed

Available services

BucketUploadsService

File upload and management operations.

import { BucketUploadsService } from '@xeonr/uploads-protocol/uplim/api/v1/uploads_pb';

const uploads = getUploadClientWithEnv(BucketUploadsService, adapter);

// List uploads
const result = await uploads.listUploads({
  bucketRef: { type: { case: 'bucketId', value: 'bkt_123' } },
  path: '/',
  pagination: { case: 'limit', value: 20 },
});

// Get a single upload
const { upload } = await uploads.getUpload({
  bucketRef: { type: { case: 'bucketId', value: 'bkt_123' } },
  uploadRef: { type: { case: 'uploadId', value: 'upl_456' } },
});

// Delete an upload
await uploads.deleteUpload({
  bucketRef: { type: { case: 'bucketId', value: 'bkt_123' } },
  uploadRef: { type: { case: 'uploadId', value: 'upl_456' } },
});

// Get download URL
const { url } = await uploads.getUploadDownloadUrl({
  bucketRef: { type: { case: 'bucketId', value: 'bkt_123' } },
  uploadRef: { type: { case: 'uploadId', value: 'upl_456' } },
});

// Get/set text content
const { content } = await uploads.getTextContent({
  bucketRef: { type: { case: 'bucketId', value: 'bkt_123' } },
  uploadRef: { type: { case: 'uploadId', value: 'upl_456' } },
});

// Copy/move uploads
await uploads.copyUpload({ /* ... */ });
await uploads.moveUpload({ /* ... */ });

// Upload history
const history = await uploads.listUploadHistory({ /* ... */ });
await uploads.restoreUploadFromHistory({ /* ... */ });

BucketFoldersService

Folder and directory management.

import { BucketFoldersService } from '@xeonr/uploads-protocol/uplim/api/v1/uploads_pb';

const folders = getUploadClientWithEnv(BucketFoldersService, adapter);

// List folders
const result = await folders.listFolders({
  bucketRef: { type: { case: 'bucketId', value: 'bkt_123' } },
  path: '/',
});

// Create a folder
const { folder } = await folders.createFolder({
  bucketRef: { type: { case: 'bucketId', value: 'bkt_123' } },
  name: 'New Folder',
  path: '/',
});

// Get folder tree
const tree = await folders.listFolderTree({
  bucketRef: { type: { case: 'bucketId', value: 'bkt_123' } },
});

BucketsService

Bucket-level operations, permissions, and bulk actions.

import { BucketsService } from '@xeonr/uploads-protocol/uplim/api/v1/uploads_pb';

const buckets = getUploadClientWithEnv(BucketsService, adapter);

// List buckets
const result = await buckets.listBuckets({});

// Get bucket details
const { bucket } = await buckets.getBucket({
  bucketRef: { type: { case: 'bucketId', value: 'bkt_123' } },
});

// Bucket permissions
await buckets.grantBucketPermission({ /* ... */ });
await buckets.revokeBucketPermission({ /* ... */ });

// Bulk operations
await buckets.bulkMoveContent({ /* ... */ });
await buckets.bulkDeleteContent({ /* ... */ });
await buckets.bulkCopyContent({ /* ... */ });

IntegrationsService

Integration and renderer resolution.

import { IntegrationsService } from '@xeonr/uploads-protocol/uplim/api/v1/uploads_pb';

const integrations = getUploadClientWithEnv(IntegrationsService, adapter);

// List available integrations
const result = await integrations.listIntegrations({});

// Resolve integrations for a resource
const resolved = await integrations.resolveResourceIntegrations({
  bucketRef: { type: { case: 'bucketId', value: 'bkt_123' } },
  target: { type: { case: 'uploadRef', value: { /* ... */ } } },
});

AuthService

Token refresh (typically handled automatically by the SDK).

import { AuthService } from '@xeonr/uploads-protocol/uplim/api/v1/uploads_pb';

const auth = getUploadClientWithEnv(AuthService, adapter);
const { token } = await auth.refreshToken({ refreshToken: '...' });

Reference patterns

Bucket references

Most API calls require a BucketRef to identify the bucket:

// By bucket ID
{ type: { case: 'bucketId', value: 'bkt_123' } }

// By hostname/alias
{ type: { case: 'hostname', value: 'my-bucket.upl.im' } }

Upload references

// By upload ID
{ type: { case: 'uploadId', value: 'upl_456' } }

// By path
{ type: { case: 'path', value: '/images/photo.jpg' } }

Folder references

// By folder ID
{ type: { case: 'folderId', value: 'fld_789' } }

// By path
{ type: { case: 'path', value: '/documents' } }

Pagination

List endpoints support cursor-based or limit-based pagination:

// Limit-based (first page)
const page1 = await uploads.listUploads({
  bucketRef: { type: { case: 'bucketId', value: 'bkt_123' } },
  pagination: { case: 'limit', value: 20 },
});

// Cursor-based (subsequent pages)
const page2 = await uploads.listUploads({
  bucketRef: { type: { case: 'bucketId', value: 'bkt_123' } },
  pagination: { case: 'cursor', value: page1.nextCursor },
});

On this page