@opentusk/sdk
v0.6.3
Published
TypeScript SDK for the OpenTusk decentralized storage platform
Readme
@opentusk/sdk
TypeScript SDK for the OpenTusk decentralized storage platform. Zero external dependencies — uses native fetch.
Installation
npm install @opentusk/sdkQuick Start
import { OpenTuskClient } from '@opentusk/sdk';
const client = new OpenTuskClient({
apiKey: 'otk_your_api_key',
});Vaults
// Create a vault
const vault = await client.vaults.create({
name: 'My Vault',
description: 'Project files',
visibility: 'public',
});
// List vaults
const vaults = await client.vaults.list();
// Update a vault
await client.vaults.update(vault.id, { name: 'Renamed Vault' });
// Delete (use force: true if vault has files)
await client.vaults.delete(vault.id, { force: true });File Upload
One-liner upload
import { readFile } from 'fs/promises';
const data = await readFile('./photo.jpg');
const file = await client.files.upload({
name: 'photo.jpg',
mimeType: 'image/jpeg',
vaultId: vault.id,
data,
});
console.log(file.id, file.status); // "hot"Manual 3-step upload
// 1. Get presigned URL
const { fileId, uploadUrl } = await client.files.requestUpload({
name: 'doc.pdf',
mimeType: 'application/pdf',
sizeBytes: buffer.byteLength,
vaultId: vault.id,
});
// 2. PUT to presigned URL
await fetch(uploadUrl, {
method: 'PUT',
body: buffer,
headers: { 'Content-Type': 'application/pdf' },
});
// 3. Confirm
const file = await client.files.confirmUpload(fileId);Polling for Walrus Sync
// Wait for file to be synced to Walrus (promise)
const status = await client.files.waitForStatus(file.id, ['synced'], {
interval: 3000, // poll every 3s (default: 2s)
timeout: 120000, // give up after 2min (default: 60s)
});
// Or use async iterator for progress updates
for await (const status of client.files.pollStatus(file.id, ['synced'])) {
console.log(`Status: ${status.status}`);
}Download
const { downloadUrl, encryption } = await client.files.getDownloadUrl(file.id);
if (downloadUrl) {
const response = await fetch(downloadUrl);
// If encrypted, decrypt client-side using encryption.wrappedKey / encryption.iv
}List Files
const { files, nextCursor } = await client.files.list({
vaultId: vault.id,
limit: 25,
sortBy: 'createdAt',
order: 'desc',
});Webhooks
// Create a webhook
const webhook = await client.webhooks.create({
url: 'https://example.com/webhook',
events: ['file.synced', 'file.error'],
});
console.log(webhook.secret); // Save this — only shown once
// Send a test delivery
const delivery = await client.webhooks.test(webhook.id);
// List deliveries
const deliveries = await client.webhooks.listDeliveries(webhook.id, { limit: 10 });
// Update
await client.webhooks.update(webhook.id, { active: false });
// Delete
await client.webhooks.delete(webhook.id);Shared Vaults
Shared vaults use SEAL on-chain access control. Members are managed by Sui address:
// Pre-validate before signing on-chain tx (checks plan limits, duplicates, ownership)
const { onchain } = await client.sharedVaults.prevalidateAddMember(vaultId, {
suiAddress: '0x...',
});
// onchain contains: allowlistObjectId, capObjectId, packageId, memberAddress
// After signing the on-chain transaction with your Sui keypair:
await client.sharedVaults.addMember(vaultId, {
suiAddress: '0x...',
txDigest: 'ABC123...',
});
// List members
const { members } = await client.sharedVaults.listMembers(vaultId);
// Revoke access (after signing on-chain remove transaction)
await client.sharedVaults.removeMember(vaultId, memberId, { txDigest: '...' });
// List shared vaults you're a member of
const { vaults } = await client.sharedVaults.list();
// Link/unlink Sui address
await client.sharedVaults.linkSuiAddress('0x...', 'external', { signature, signedMessage });
await client.sharedVaults.unlinkSuiAddress();Public Access (No Auth)
// Build public URLs (synchronous)
const fileUrl = client.public.getFileUrl(fileId);
const blobUrl = client.public.getBlobUrl(walrusBlobId);
// List files in a public vault
const { vault, files } = await client.public.listVaultFiles(userId, 'my-vault');Account & API Keys
// Get account info
const account = await client.account.get();
console.log(account.planTier, account.storageUsedFormatted);
// Create an API key
const newKey = await client.apiKeys.create({
name: 'CI/CD',
scopes: ['files:write'],
expiresInDays: 90,
});
// List & revoke
const keys = await client.apiKeys.list();
await client.apiKeys.revoke(keys[0].id);Trash
const trash = await client.trash.list();
await client.trash.restore(trash.files[0].id);
await client.trash.delete(trash.vaults[0].id);
await client.trash.empty();Error Handling
import { OpenTuskError, OpenTuskTimeoutError } from '@opentusk/sdk';
try {
await client.vaults.get('non-existent');
} catch (err) {
if (err instanceof OpenTuskError) {
console.error(err.statusCode, err.message);
}
if (err instanceof OpenTuskTimeoutError) {
console.error('Polling timed out');
}
}Configuration
const client = new OpenTuskClient({
apiKey: 'otk_...',
baseUrl: 'http://localhost:8000', // Override for local dev
headers: { 'X-Custom': 'value' }, // Extra headers
fetch: customFetchFn, // Custom fetch implementation
});