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

@bozonx/social-posting-vimeo

v0.8.0

Published

Vimeo platform for @bozonx/social-posting

Downloads

147

Readme

@bozonx/social-posting-vimeo

Vimeo support for @bozonx/social-posting. Zero runtime dependencies, Web APIs only — it runs on Node, Bun, Deno and Cloudflare Workers.

pnpm add @bozonx/social-posting @bozonx/social-posting-vimeo
import { createPostingClient } from '@bozonx/social-posting';
import { vimeo } from '@bozonx/social-posting-vimeo';

const client = createPostingClient({
  platforms: [vimeo],
  accounts: {
    studio: { platform: 'vimeo', auth: { accessToken: process.env.VIMEO_TOKEN } },
  },
});

const result = await client.post({
  platform: 'vimeo',
  account: 'studio',
  type: 'video',
  title: 'Release notes, August',
  body: 'Everything that shipped this month.',
  media: [{ type: 'video', source: { kind: 'stream', open: openFile, sizeBytes: 812_000_000 } }],
});

// result.data.status === 'processing' — see below.

An uploaded video is not a playable video

publish() never returns published. Vimeo stores the file, then transcodes it, and only then can anybody watch it. So post() answers processing with a handle, and the host polls checkStatus() until it says otherwise.

checkStatus() reads transcode.status, not the video's status field: a video reads available while its highest-quality rendition is still being produced.

Budget the wait from capabilities.asyncProcessing (maxWaitSecs, pollIntervalSecs) rather than from a constant of your own.

Two upload approaches

| | tus (default) | pull | | ----------------------- | ---------------------------- | ----------------------------------- | | Who moves the bytes | This process, chunk by chunk | Vimeo, from a URL you give it | | Resumable | Yes | No | | Needs the size up front | Yes | No | | Your bandwidth | Full file | None | | A broken link surfaces | Immediately | Minutes later, as a transcode error |

Choose per request with extra.uploadApproach, or per account with defaultUploadApproach.

If you use pull, the URL must stay alive. The descriptor states urlMustRemainAvailableForSecs: 86400 for exactly this reason: Vimeo fetches the file asynchronously, after the create call has already returned success, and a signed link that expires with the request produces a failure with nothing in the response to explain it.

Storage, not operations

Vimeo's limit is the account's stored bytes plus a weekly upload allowance, both set by the plan. Neither resets on a daily clock.

getQuota() reports it in bytes, and returns whichever of the two is tighter — a plan with room left can still be out of its weekly allowance, and that is what will actually stop the next upload:

const quota = await client.getQuota({ platform: 'vimeo', account: 'studio' });
// { unit: 'bytes', remaining: 4294967296, limit: 5368709120, resetsAt: '2026-09-06T…' }

Exhaustion arrives as QUOTA_EXCEEDED with retryable: false: storage does not free itself, and the right message to the user is "delete something or upgrade", not "try again tomorrow". That is the opposite of YouTube, where the same code means exactly "try again tomorrow" — capabilities.rateLimits.quotaCost.unit (bytes against quotaUnits) is what distinguishes them.

Resumable upload

The tus approach uploads by offset, and a failure carries a resumeHandle:

const result = await client.post(request, { resume: previousError.resumeHandle });

The handle names only the video, never the tus upload link. That link is a bearer URL — anyone holding it can write bytes into the video — and a handle is something the host writes to its database. On resume the adapter re-reads the link from GET /videos/{id} and asks the tus endpoint for its real offset, because the stored offset is only what was true before the process died.

If the session is gone by then (the upload completed, or the video was removed), the adapter raises UNKNOWN_OUTCOME rather than starting a second upload.

What it publishes

| Field | Maps to | | ---------------------- | ------------------------------------------------------- | | title | name (≤ 128) | | body / description | description (≤ 5000) | | tags | tags[] (≤ 20) | | visibility | privacy.view — public→anybody, private→nobody | | extra.privacyView | privacy.view directly, for modes visibility lacks | | extra.folderUri | folder_uri |

Setting both visibility and extra.privacyView is refused: they write the same field, and letting one win silently publishes at a visibility nobody asked for.

Known limits

  • Vimeo publishes videos only. No text posts, no images, no galleries, no stories — and no Shorts equivalent, so a vertical video is an ordinary upload and shortVideo is absent rather than aliased.
  • Upload access depends on the account plan; a plan that forbids it answers 403 as AUTH_ERROR, which no scope change fixes.
  • delete() is not implemented in this iteration, and supportsDeletion says so.