npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@musallam/storage-and-collaboration-client

v2.2.0

Published

TypeScript client library for Adobe Cloud Storage and Collaboration API

Downloads

122

Readme

@musallam/storage-and-collaboration-client

TypeScript client library for the Adobe Cloud Storage and Collaboration API.

Features

  • 🚀 Full TypeScript support with auto-generated types from OpenAPI spec
  • 📦 Complete API coverage for all Storage and Collaboration endpoints
  • 🔄 Job polling utilities for async operations
  • 🔐 Built-in authentication via IMS client
  • 📝 Comprehensive documentation and examples

Installation

npm install @musallam/storage-and-collaboration-client

Quick Start

import {
  StorageAndCollaborationClient,
  STORAGE_AXIOS_INSTANCE,
  TokenIMSClient,
} from '@musallam/storage-and-collaboration-client';

// 1. Setup authentication
const imsClient = new TokenIMSClient({
  clientId: 'YOUR_CLIENT_ID',
  clientSecret: 'YOUR_CLIENT_SECRET',
  scopes: ['openid', 'creative_sdk', 'AdobeID'],
});

// 2. Configure axios instance
STORAGE_AXIOS_INSTANCE.interceptors.request.use(async (config) => {
  const token = await imsClient.getAccessToken();
  config.headers.Authorization = `Bearer ${token}`;
  config.headers['x-api-key'] = 'YOUR_CLIENT_ID';
  return config;
});

// 3. Use the client
const projects = await StorageAndCollaborationClient.getProjects({
  limit: 10,
});
console.log(projects);

API Coverage

Projects

  • getProjects() - List all projects
  • createProject() - Create a new project
  • getProject() - Get project details
  • discardProject() - Soft delete a project
  • getProjectChildren() - List project contents
  • getProjectEffectivePermission() - Get user's permission
  • getProjectPermissions() - List all permissions
  • patchProjectPermissions() - Modify permissions

Folders

  • createFolder() - Create a folder
  • getFolder() - Get folder details
  • getFolderChildren() - List folder contents
  • getFolderEffectivePermission() - Get user's permission
  • getFolderPermissions() - List all permissions

Files

  • getFile() - Get file metadata
  • downloadFile() - Get download URL
  • getFileImageRendition() - Get image rendition
  • getFileEffectivePermission() - Get user's permission
  • initBlockBasedFileUpload() - Initialize file upload
  • finalizeBlockBasedFileUpload() - Complete file upload

Jobs

  • getJobStatus() - Check async job status
  • pollStorageJob() - Poll until completion (utility)

Usage Examples

Creating a Project

const project = await StorageAndCollaborationClient.createProject({
  name: 'My New Project',
});
console.log(`Created: ${project.assetId}`);

Creating Folders

// Single folder
const folder = await StorageAndCollaborationClient.createFolder({
  parentId: 'urn:aaid:sc:US:project-id',
  name: 'Documents',
});

// Nested folders (creates entire hierarchy)
const nestedFolder = await StorageAndCollaborationClient.createFolder({
  parentId: 'urn:aaid:sc:US:project-id',
  path: 'Marketing/2024/Q4',
});

Uploading a File

import { pollStorageJob } from '@musallam/storage-and-collaboration-client';

// 1. Initialize upload
const uploadInit = await StorageAndCollaborationClient.initBlockBasedFileUpload({
  parentId: 'urn:aaid:sc:US:folder-id',
  name: 'document.pdf',
  mediaType: 'application/pdf',
  size: fileSize,
  blockSize: 10485760, // 10MB blocks (optional)
});

// 2. Upload blocks to transfer URLs
for (let i = 0; i < uploadInit.transferLinks.length; i++) {
  const link = uploadInit.transferLinks[i];
  const blockData = getBlockData(i); // Your logic to get block data

  await axios.put(link.url, blockData, {
    headers: { 'Content-Type': 'application/octet-stream' },
  });
}

// 3. Finalize upload
const finalizeResponse = await StorageAndCollaborationClient.finalizeBlockBasedFileUpload({
  uploadId: uploadInit.uploadId,
  usedTransferLinks: [1, 2, 3], // Part numbers you uploaded
});

// 4. Poll for completion
const result = await pollStorageJob(finalizeResponse.jobId, {
  intervalMs: 2000,
  maxAttempts: 60,
  onProgress: (status) => {
    console.log(`Upload status: ${status.status}`);
  },
});

console.log('Upload complete!', result);

Managing Permissions

// Get effective permission for current user
const permission = await StorageAndCollaborationClient.getProjectEffectivePermission({
  assetId: 'urn:aaid:sc:US:project-id',
});
console.log(`Your role: ${permission.role}`); // 'edit' or 'comment'

// List all permissions
const permissions = await StorageAndCollaborationClient.getProjectPermissions({
  assetId: 'urn:aaid:sc:US:project-id',
});
console.log(`Direct: ${permissions.direct.length}`);
console.log(`Pending: ${permissions.pending.length}`);

// Add collaborators
await StorageAndCollaborationClient.patchProjectPermissions(
  { assetId: 'urn:aaid:sc:US:project-id' },
  {
    direct: {
      additions: [
        {
          recipient: 'mailto:[email protected]',
          type: 'user',
          role: 'comment',
        },
        {
          recipient: 'name:Marketing Team',
          type: 'group',
          role: 'edit',
        },
      ],
    },
  }
);

// Update or remove permissions
await StorageAndCollaborationClient.patchProjectPermissions(
  { assetId: 'urn:aaid:sc:US:project-id' },
  {
    direct: {
      updates: [
        {
          id: 'user-id@AdobeID',
          type: 'user',
          role: 'edit', // Changed from 'comment' to 'edit'
        },
      ],
      deletions: [
        {
          id: 'another-user-id@AdobeID',
          type: 'user',
        },
      ],
    },
  }
);

Downloading Files

// Get download URL
const downloadInfo = await StorageAndCollaborationClient.downloadFile({
  assetId: 'urn:aaid:sc:US:file-id',
  urlTTL: 3600, // URL valid for 1 hour
});

console.log(`Download from: ${downloadInfo.url}`);
console.log(`Expires: ${downloadInfo.urlExpirationDate}`);
console.log(`Size: ${downloadInfo.size} bytes`);

// For large files, the API might return 202 with a job ID
// Poll the job to get the download URL when ready

Pagination

let cursor: string | undefined;
let allProjects: typeof projects.items = [];

do {
  const projects = await StorageAndCollaborationClient.getProjects({
    limit: 100,
    cursor,
  });

  allProjects.push(...(projects.items || []));

  // Extract cursor from nextUrl if present
  if (projects.paging?.nextUrl) {
    const url = new URL(projects.paging.nextUrl);
    cursor = url.searchParams.get('cursor') || undefined;
  } else {
    cursor = undefined;
  }
} while (cursor);

console.log(`Total projects: ${allProjects.length}`);

Filtering and Sorting

// Filter projects by view
const myProjects = await StorageAndCollaborationClient.getProjects({
  filter: 'view==yours',
  sortBy: '-created', // Sort by creation date descending
});

// Filter children by asset type
const onlyFolders = await StorageAndCollaborationClient.getProjectChildren({
  assetId: 'urn:aaid:sc:US:project-id',
  filter: 'assetType==folder',
});

// Filter children by media type
const pdfFiles = await StorageAndCollaborationClient.getProjectChildren({
  assetId: 'urn:aaid:sc:US:project-id',
  filter: 'assetType==file;mediaType==application/pdf',
});

Job Polling

For async operations, use the polling utility:

import { pollStorageJob, PollingTimeoutError } from '@musallam/storage-and-collaboration-client';

try {
  const result = await pollStorageJob(jobId, {
    intervalMs: 2000, // Poll every 2 seconds
    maxAttempts: 60, // Try up to 60 times
    timeoutMs: 300000, // Or timeout after 5 minutes
    onProgress: (status) => {
      console.log(`Status: ${status.status}`);
    },
  });

  console.log('Job completed:', result);
} catch (error) {
  if (error instanceof PollingTimeoutError) {
    console.error('Job timed out');
  } else {
    console.error('Job failed:', error);
  }
}

Error Handling

try {
  const project = await StorageAndCollaborationClient.getProject({
    assetId: 'invalid-id',
  });
} catch (error) {
  if (axios.isAxiosError(error)) {
    console.error(`HTTP ${error.response?.status}: ${error.response?.data?.message}`);
    console.error(`Error code: ${error.response?.data?.error_code}`);
  }
}

Advanced Configuration

Custom Axios Instance

import axios from 'axios';
import { STORAGE_AXIOS_INSTANCE } from '@musallam/storage-and-collaboration-client';

// Add custom headers
STORAGE_AXIOS_INSTANCE.defaults.headers.common['X-Custom-Header'] = 'value';

// Add request interceptor
STORAGE_AXIOS_INSTANCE.interceptors.request.use((config) => {
  console.log(`Making request to ${config.url}`);
  return config;
});

// Add response interceptor
STORAGE_AXIOS_INSTANCE.interceptors.response.use(
  (response) => response,
  (error) => {
    console.error('Request failed:', error.message);
    return Promise.reject(error);
  }
);

Timeout Configuration

STORAGE_AXIOS_INSTANCE.defaults.timeout = 30000; // 30 seconds

TypeScript Support

All types are automatically generated from the OpenAPI spec:

import type {
  ProjectAsset,
  FolderAsset,
  FileAsset,
  JobStatus,
  PaginatedProjectsResponseResponse,
} from '@musallam/storage-and-collaboration-client';

const project: ProjectAsset = await StorageAndCollaborationClient.createProject({
  name: 'Typed Project',
});

const status: JobStatus = await StorageAndCollaborationClient.getJobStatus({
  jobId: 'job-id',
});

License

MIT

Related Packages

Resources