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

@cassets/cloud

v0.1.1

Published

Signed-upload URL adapters for @cassets/http-client across S3-compatible storage, Azure Blob Storage, and Google Cloud Storage.

Readme

@cassets/cloud

Cloud signed-upload URL adapters for @cassets/http-client.

npm license

The package does not contain AWS, Azure, or Google cloud credentials and does not sign requests in the browser. Instead, it standardizes the browser-to-backend contract used to obtain short-lived signed URLs for chunked uploads.

Supported adapter families in 0.1.x:

  • Amazon S3 and S3-compatible providers such as Wasabi and MinIO
  • Azure Blob Storage
  • Google Cloud Storage (GCS)

Installation

npm install @cassets/cloud @cassets/http-client

You can also use the adapters without @cassets/http-client; they simply return a function matching the documented GetUploadUrlsFn contract.

Architecture

Browser
  |
  | file metadata only
  v
Your signing endpoint
  |
  | server-side cloud credentials / identity
  v
Cloud provider
  |
  | short-lived signed part URLs
  v
Browser -> direct chunk uploads -> cloud storage

Cloud credentials stay on the server. The browser receives only scoped upload URLs.

Quick start: S3

import { UploadManager } from '@cassets/http-client/upload';
import { createS3UploadUrlFetcher } from '@cassets/cloud/s3';

const getUploadUrls = createS3UploadUrlFetcher({
  signEndpoint: '/api/uploads/s3/sign',
  headers: {
    Authorization: `Bearer ${accessToken}`,
  },
});

await UploadManager.getInstance().upload({
  file,
  getUploadUrls,
  chunkSize: 10 * 1024 * 1024,
  parallelParts: 3,
});

The root import is also supported:

import {
  createS3UploadUrlFetcher,
  createAzureUploadUrlFetcher,
  createGCSUploadUrlFetcher,
} from '@cassets/cloud';

Adapter contract

interface UploadUrl {
  partNumber: number;
  url: string;
  uploadId?: string;
}

type GetUploadUrlsFn = (
  file: File,
  chunkSize: number,
  totalParts: number,
) => Promise<UploadUrl[]>;

interface AdapterConfig {
  signEndpoint: string;
  headers?: Record<string, string>;
  fetchFn?: typeof fetch;
}

Every adapter sends the same request body to your signing endpoint:

{
  "fileName": "video.mp4",
  "fileSize": 73400320,
  "chunkSize": 10485760,
  "totalParts": 7,
  "contentType": "video/mp4"
}

Your backend returns:

{
  "urls": [
    {
      "partNumber": 1,
      "url": "https://provider.example/signed-part-1",
      "uploadId": "optional-provider-session-id"
    },
    {
      "partNumber": 2,
      "url": "https://provider.example/signed-part-2",
      "uploadId": "optional-provider-session-id"
    }
  ]
}

partNumber is 1-based and should cover every requested part.

S3 / S3-compatible storage

import { createS3UploadUrlFetcher } from '@cassets/cloud/s3';

const getUploadUrls = createS3UploadUrlFetcher({
  signEndpoint: 'https://api.example.com/uploads/s3/sign',
});

The adapter is provider-neutral on the client. Your backend signer determines whether the target is AWS S3, Wasabi, MinIO, Backblaze B2 S3-compatible API, or another compatible service.

Example signing-endpoint pseudocode

POST /uploads/s3/sign
  authenticate user
  authorize tenant/bucket/object
  validate file metadata
  create multipart upload
  create one signed PUT URL per part
  return { urls }

The backend should persist the multipart uploadId and complete/abort the multipart session after the client reports uploaded part metadata. The browser package does not hold AWS secret keys.

Azure Blob Storage

import { createAzureUploadUrlFetcher } from '@cassets/cloud/azure';

const getUploadUrls = createAzureUploadUrlFetcher({
  signEndpoint: '/api/uploads/azure/sign',
  headers: {
    'X-Tenant-ID': tenantId,
  },
});

Your server may generate per-block SAS URLs or another upload URL strategy. Provider-specific block IDs and commit behavior remain a backend/application responsibility.

Google Cloud Storage

import { createGCSUploadUrlFetcher } from '@cassets/cloud/gcs';

const getUploadUrls = createGCSUploadUrlFetcher({
  signEndpoint: '/api/uploads/gcs/sign',
});

Your server chooses the actual GCS signed-upload strategy. The adapter only standardizes the metadata request and returned URL list.

Custom authentication headers

const getUploadUrls = createS3UploadUrlFetcher({
  signEndpoint: '/api/uploads/sign',
  headers: {
    Authorization: `Bearer ${token}`,
    'X-Workspace-ID': workspaceId,
  },
});

Do not put cloud provider secret credentials in these headers. They are browser-visible request headers to your API.

Custom fetch

Useful for tests, tracing, or a wrapper around the browser Fetch API:

const getUploadUrls = createGCSUploadUrlFetcher({
  signEndpoint: '/api/uploads/gcs/sign',
  fetchFn: async (input, init) => {
    console.debug('sign request', input);
    return fetch(input, init);
  },
});

Direct use without @cassets/http-client

const getUrls = createS3UploadUrlFetcher({
  signEndpoint: '/api/uploads/s3/sign',
});

const urls = await getUrls(file, 10 * 1024 * 1024, 4);
console.log(urls);

You can then use the URLs with your own upload engine.

Error handling

A non-2xx signing response throws an error:

try {
  const urls = await getUploadUrls(file, chunkSize, totalParts);
} catch (error) {
  console.error('Could not obtain upload URLs', error);
}

Treat signing failures separately from failures that happen while PUTing chunks to cloud storage.

Security guidance

The safest design is capability-based upload:

  1. Authenticate the user to your backend.
  2. Authorize the exact tenant/workspace/object operation.
  3. Validate file name, expected size, MIME type, number of parts, and allowed storage route.
  4. Generate short-lived, operation-scoped signed URLs.
  5. Return only the minimum capability required to upload the requested parts.
  6. Verify/complete the upload server-side.
  7. Expire or abort abandoned multipart sessions.

Additional recommendations:

  • Never send AWS secret keys, Azure account keys, GCP service-account keys, or long-lived provider tokens to the browser.
  • Keep signing endpoints rate-limited and audited.
  • Do not trust fileName, contentType, or fileSize merely because the browser supplied them.
  • Bind object keys to server-authorized tenant/user context; do not allow arbitrary bucket/key selection from the browser.
  • Configure cloud CORS narrowly.

What this package does not do

@cassets/cloud is deliberately not a full cloud SDK. It does not:

  • authenticate directly to cloud providers with secret credentials;
  • create buckets/containers;
  • finalize provider-specific multipart/block sessions;
  • persist upload state;
  • retry chunks;
  • download or delete objects;
  • proxy file bytes through your API.

Those boundaries keep the client adapter lightweight and reduce credential exposure.

Package exports

import { createS3UploadUrlFetcher } from '@cassets/cloud/s3';
import { createAzureUploadUrlFetcher } from '@cassets/cloud/azure';
import { createGCSUploadUrlFetcher } from '@cassets/cloud/gcs';

All adapters are also exported from @cassets/cloud.

Both ESM and CommonJS builds plus TypeScript declarations are published.

Project links

  • ClusterAssets GitHub: https://github.com/clusterassets
  • ClusterAssets LinkedIn: https://www.linkedin.com/company/clusterassets
  • Creator GitHub: https://github.com/diskhacker
  • Creator LinkedIn: https://www.linkedin.com/in/kp-vivek-rao-bhosale/

Contributing and security

See CONTRIBUTING.md and SECURITY.md.

License

MIT © Vivek Rao Bhosale / ClusterAssets.