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 🙏

© 2025 – Pkg Stats / Ryan Hefner

moviedb-effect

v0.0.3

Published

A library for interacting with themoviedb.org API using Effect

Readme

moviedb-effect

npm

A modern, type-safe TypeScript client for The Movie Database (TMDb) API, built with Effect.

Why moviedb-effect?

✨ Built for modern TypeScript applications

  • 🎯 Fully type-safe - End-to-end type safety with Effect Schema
  • 🔄 Automatic retry - Resilient API calls with smart retry logic
  • 🚦 Built-in rate limiting - Stay within API limits automatically
  • 📊 Streaming pagination - Memory-efficient data processing with backpressure
  • 🔍 Observability - Built-in logging, tracing, and metrics
  • 🧪 Easy to test - Dependency injection makes testing simple
  • 🛡️ Structured error handling - Type-safe error channels
  • 🐪 CamelCase transforms - Automatic snake_case → camelCase conversion

Quick Start

Installation

npm install moviedb-effect effect @effect/platform @effect/platform-node

Requires effect@^3.19 and @effect/platform@^0.93.

With Effect

import { NodeHttpClient } from '@effect/platform-node'
import { Effect, Layer } from 'effect'
import { Movie, MovieDbClient, MovieDbConfig, RateLimiterLive } from 'moviedb-effect'

const ConfigLive = Layer.succeed(MovieDbConfig, {
  apiKey: 'your-api-key',
  baseUrl: 'https://api.themoviedb.org/3',
})

const program = Effect.gen(function* () {
  const movie = yield* Movie
  const details = yield* movie.getDetails({ id: 550 })

  yield* Effect.log(`${details.title} (${details.releaseDate})`)
  // => Fight Club (1999-10-15)
})

const main = program.pipe(
  Effect.provide(Movie.Default),
  Effect.provide(MovieDbClient.Default),
  Effect.provide(RateLimiterLive),
  Effect.provide(NodeHttpClient.layerUndici),
  Effect.provide(ConfigLive),
  Effect.scoped,
)

await Effect.runPromise(main)

Without Effect (Promise API)

Not using Effect? Use the MovieDbCompat class for a simple Promise-based API:

import { MovieDbCompat } from 'moviedb-effect'

const client = new MovieDbCompat({ apiKey: 'your-api-key' })

const movie = await client.movieInfo(550)
console.log(movie.title) // "Fight Club"

const results = await client.searchMovie({ query: 'inception' })

Services

Four services cover the TMDb API: Movie, Tv, Search, and Person.

const program = Effect.gen(function* () {
  const movie = yield* Movie
  const tv = yield* Tv
  const search = yield* Search
  const person = yield* Person

  // Movies: details, credits, videos, images
  const fightClub = yield* movie.getDetails({ id: 550 })
  const credits = yield* movie.getCredits({ id: 550 })

  // TV: same pattern
  const breakingBad = yield* tv.getDetails({ id: 1396 })

  // Search: movies, TV, people, or everything
  const results = yield* search.searchMovie({ query: 'inception' })
  const all = yield* search.searchMulti({ query: 'nolan' })

  // People: details and filmography
  const bradPitt = yield* person.getDetails({ id: 287 })
  const filmography = yield* person.getCombinedCredits({ id: 287 })
})

All methods are fully typed - explore available methods via autocomplete.

Advanced Features

Streaming Pagination

Efficiently process large datasets with automatic pagination and backpressure:

const program = Effect.gen(function* () {
  const movie = yield* Movie

  // Get first 100 popular movies
  const movies = yield* movie.streamPopular({}, { maxResults: 100 }).pipe(Stream.runCollect)

  // Process with controlled concurrency
  yield* movie.streamNowPlaying({}, { maxPages: 5 }).pipe(
    Stream.mapEffect((m) => processMovie(m), { concurrency: 10 }),
    Stream.runDrain,
  )

  // Lazy evaluation - stops fetching when found
  const found = yield* movie.streamTopRated().pipe(
    Stream.filter((m) => m.voteAverage > 9.0),
    Stream.take(1),
    Stream.runCollect,
  )
})

See streaming-basic.ts and streaming-advanced.ts for more examples.

Error Handling

All errors are typed and can be handled exhaustively:

const program = movie.getDetails({ id: 999999 }).pipe(
  Effect.catchTags({
    NotFoundError: () => Effect.succeed(null),
    AuthenticationError: () => Effect.fail('Invalid API key'),
    RateLimitError: () => Effect.fail('Rate limited'),
    NetworkError: () => Effect.fail('Network issue'),
  }),
)

Error types: NotFoundError, AuthenticationError, RateLimitError, ValidationError, ServerError, NetworkError.

Built-in Resilience

  • Automatic retry - Retries on network errors, rate limits (429), and server errors (5xx) with exponential backoff
  • Rate limiting - Stays within TMDb's ~50 req/s soft limit automatically
  • Observability - Structured logs, distributed tracing spans, and metrics on every request

Configuration

import { Layer } from 'effect'
import { MovieDbConfig } from 'moviedb-effect'

const ConfigLive = Layer.succeed(MovieDbConfig, {
  apiKey: process.env.TMDB_API_KEY!,
  baseUrl: 'https://api.themoviedb.org/3',
})

Rate limiting is automatic with sensible defaults (50 req/s). You can customize requestsPerSecond in your config.

Contributing

pnpm test        # Run tests
pnpm format      # Format code

License

MIT


Get your free TMDb API key at https://www.themoviedb.org/settings/api