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

@playdeck/provider-vimeo

v1.0.0

Published

Vimeo player SDK provider for Playdeck.

Readme

@playdeck/provider-vimeo

The Vimeo provider for Playdeck, over the @vimeo/player SDK.

pnpm add @playdeck/provider-vimeo

@playdeck/react loads this for you when the source resolves to vimeo. The SDK is bundled as a dependency and imported dynamically — nothing is fetched from a Vimeo CDN. Provider setup lists the URL forms that resolve to it, the ones that do not, and the options reachable through Player.Root.

import { PlayerController } from '@playdeck/core';
import {
  createVimeoProvider,
  loadVimeoSdk,
  PLAYER_READY_TIMEOUT_MS,
  resetVimeoSdkLoader
} from '@playdeck/provider-vimeo';
import type { VimeoMountElement } from '@playdeck/provider-vimeo';

declare const mount: VimeoMountElement;

const controller = new PlayerController();

// `hash` is the privacy hash of an unlisted video, which `detectSource` keeps
// when it recognises one in the URL. `dnt` asks Vimeo not to track the session.
controller.setProvider(
  createVimeoProvider(
    mount,
    { type: 'vimeo', videoId: '76979871', hash: '8272103f6e' },
    { controls: false, dnt: true }
  )
);

// The SDK is loaded on demand and cached across players. Pass your own importer
// to serve it from somewhere other than the default module.
export const warm = (): Promise<unknown> => loadVimeoSdk();

// Drops the cached SDK — for tests that need a clean load, not for app code.
export const reset = (): void => resetVimeoSdkLoader();

// How long `player.ready()` is given before the attach reports a recoverable
// error. Command readiness is declared earlier, at player construction, because
// the SDK queues calls it receives before its own ready resolves — but that is
// not a bound, and without this a frame blocked by the page CSP, an extension
// or the network leaves the player loading for ever with no error to render
// (#327).
export const playerReadyTimeout = PLAYER_READY_TIMEOUT_MS; // 15000

The embed is chromeless by default (controls: false) so Playdeck's own controls are the only ones on screen, and dnt is on unless you turn it off. See Third-party requests and CSP for the full origins list and what a page's CSP has to allow.

Exports

| Export | What it is | | ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | createVimeoProvider | Builds the adapter over a mount element and a VimeoSource. | | VimeoProviderOptions | controls, dnt, loop, startTime, endTime, customControls, suppressSeoMetadata. Through Player.Root, controls, loop, startTime and endTime are its own props (ADR-0004), not bag keys. | | VimeoSdkLoadOptions | What loadVimeoSdk takes beyond its importer: suppressSeoMetadata, honoured only by the call that actually imports the SDK. | | VimeoMountElement | What the adapter can mount into. | | VimeoProviderAdapter | The adapter's own type. | | VimeoSdkConstructor | What loadVimeoSdk resolves to: the @vimeo/player class, constructed over an iframe. | | VimeoSdkPlayer | An instance of that class, as the SDK members this adapter uses. | | VimeoSdkEventListener | The listener VimeoSdkPlayer's on and off take. Its payload is unknown — the SDK decides the shape per event. | | VimeoSdkModule | The imported SDK module, whose default is the constructor. What an importer handed to loadVimeoSdk has to resolve. | | VimeoSdkQuality | An entry as getQualities() reports it, auto among them, with active marking the one the player is honouring rather than the rung being rendered. Distinct from core's published PlayerQuality. | | VimeoSdkChapter | A chapter as getChapters() reports it — a start, a title and a 1-based index, with no end. Distinct from core's published Chapter. | | VimeoSdkTextTrack | A track as getTextTracks() reports it, including the SDK's own mode. Distinct from core's published TextTrack. |

The VimeoSdk* names above describe @vimeo/player rather than Playdeck. They are declared here, in src/loader.ts, as the SDK members this adapter uses, so the loader and the adapter can be typed without binding to the SDK's own typings — these name only what the adapter calls. Their contents belong to Vimeo: what a member does, what it reports, whether it exists at all is settled in an SDK release rather than here, and nothing this project can do makes those shapes stable for you. They are exported so that a caller holding what loadVimeoSdk returns has names for it; read them as a description of the SDK you have installed, not as a contract Playdeck controls.

What it reports honestly

  • Chromeless playback needs a paid plan, and checking for one is opt-in. Pass customControls: true and customControls resolves from the account tier behind the video, via a request to Vimeo's public oEmbed endpoint: free and basic accounts report unavailable / provider-plan, paid tiers report available, and a tier we do not recognise stays unresolved rather than being guessed at. Without customControls: true, no request is made — the capability stays unknown / provider-check — so no viewer is disclosed to Vimeo before anyone has asked for the capability. That holds through Player.Root too: the option is reachable as providerOptions={{ vimeo: { customControls: true } }}, and the probe fires only when it is set.
  • selectQuality is available with a ladder from the SDK's getQualities(). The rung's height is Vimeo's own name for it, not a measurement — the rung it labels 240p renders at 480×270 — and width and bitrate are null because the SDK reports neither. auto arrives as a member of the list but is a mode, not a rung, so it is reported as selectedQualityId: null. A quality id that the player never offered is refused before the SDK sees it: setQuality with an unoffered id never settles at all, so forwarding one would hang the command forever.
  • Chapters come from the SDK's own chapter list, read once the player is ready, and kept current by its chapterchange event rather than by polling. The SDK reports a start and a title per chapter and no end at all, so every endTime is derived: each chapter ends where the next begins, and the last takes the duration, or null where the duration is not known.
  • Captions are Playdeck's to draw (captionRendering: 'custom'): the track is enabled with showing: false, which makes Vimeo emit cuechange without drawing the cues itself. setCaptionRenderer('native') hands drawing back and reports provider. Vimeo's cue payload is markup, not plain text — WebVTT tags survive in it and lines are joined with U+21B5 — so it is parsed into plain text rather than passed through.
  • Cue timings are not reported. The payload carries no start or end, so a cue reports the position it became active at for both bounds.
  • buffered is every range, including the gaps a seek leaves behind.
  • live is never reported. @vimeo/[email protected] publishes no liveness signal at all: its typings (types/player.d.ts, types/events.ts) carry no liveness member on the player and no live entry in PlayerEventMap, and neither does the subset this adapter declares for itself (src/loader.ts). What the SDK does offer — getDuration(), getSeekable(), getBuffered() and the durationchange event — describes a live event and a video on demand identically: a duration that grows as playback runs on is also what a VOD reports while its metadata settles. So the adapter publishes no live key at all rather than a guess — the field is absent from every patch, not present holding null. Pinned by "pins the liveness gap" in test/index.test.ts (#187).
  • The [startTime, endTime] window is this adapter's to enforce. Vimeo carries a start as a #t= fragment on the embed url, which only keeps the embed from loading at zero — the seek this adapter issues when the player is ready is what the start rests on. There is no end mechanism at all, so the adapter watches timeupdate: crossing endTime pauses the embed, seeks the playhead back onto the boundary and publishes ended there, and the pause it caused is not reported as one. loop composes with both — loop=1 stays on the embed and wraps to zero, and the adapter puts the playhead back at startTime afterwards, which also covers the embeds where Vimeo never fires ended. Reaching the boundary while looping restarts instead of ending. Sanitisation matches every other provider: a non-finite or non-positive start is no start, an end that is not finite or not above the start is no end, and an end past the duration is clamped to it.
  • startTime is a floor, not just where playback starts. A reported position below it is pulled back to it, whatever moved the playhead — the SDK's own url-parameter seek, a repeat ready, or the viewer dragging Vimeo's scrub bar. seeked is corrected as well as timeupdate, because a paused embed reports no time update after a seek. A seekTo or seekBy below the start is clamped to the same value, so the two agree rather than correcting one position twice, and a correction never triggers another: the position it seeks to is one the window accepts (#381).
  • A plain looping embed publishes ended on every iteration, where the native provider publishes none. With loop and no startTime, loop=1 restarts the embed at zero, which is where the window already begins, so this adapter has nothing to correct and passes Vimeo's own ended through as it always has. The native provider is the one that differs: it swallows ended for a looping video and just restarts. That is pre-existing embed behaviour, deliberately left alone by #214 — that change fanned startTime and endTime out to the embeds and did not revise how loop fans out. A startTime is what makes this adapter step in.
  • The SDK sends the embedding page's full URL to the embed, and suppressSeoMetadata is how you stop it. When the embed answers the SDK's readiness handshake, @vimeo/player's own module-scope listener replies to it with window.location.href — path and query included — over postMessage. The iframe's referrerpolicy="strict-origin-when-cross-origin" does not prevent this: it narrows the iframe's own request header, and this travels as a message afterwards. Neither does dnt. Pass suppressSeoMetadata: true — reachable from Player.Root as providerOptions={{ vimeo: { suppressSeoMetadata: true } }} — and Playdeck sets the SDK's own guard before the SDK is imported, so the listener is never installed. It is off by default, and with it off nothing about this changes. Two things to know before switching it on. First, the effect is page-wide, not per-embed: the SDK's guard is a window global, so this silences the handshake for every Vimeo embed on the page, including embeds Playdeck did not create, and that blast radius is yours to accept rather than the library's to decide. Second, it takes effect on the first Vimeo attach and holds for the life of the page: the SDK module is imported once and cached, and it reads the guard while it evaluates, so a page that attaches one Vimeo source without the option and a later one with it gets no suppression at all. That is the vendor's design, not something Playdeck works around. A page that has set the guard itself keeps its own value, in either direction; Playdeck only ever writes it when it is not already set. Where that leaves the handshake installed — a later attach, or a guard the page pinned to false — the adapter says so: it publishes a non-fatal configuration notice on PlayerState.error, so a fall back to the SDK's default is detectable at runtime and not only readable here. A guard someone else already set to true is the other direction: suppression is in effect, the request was honoured, and there is nothing to report.

License

MIT.