Packages

On-the-fly audio transcoding proxy: renders variants (transcodes, trimmed previews, waveform peaks) from signed URLs, streams them while they encode, and caches them for range-capable serving.

Current section

Files

Jump to
Raw

mix.exs

defmodule AudioProxy.MixProject do
  use Mix.Project

  @version "0.8.0"
  @source_url "https://github.com/audioproxy/audioproxy"

  def project do
    [
      app: :audio_proxy,
      version: @version,
      elixir: "~> 1.20",
      start_permanent: Mix.env() == :prod,
      elixirc_paths: elixirc_paths(Mix.env()),
      deps: deps(),
      releases: releases(),
      name: "audio_proxy",
      source_url: @source_url,
      description: description(),
      package: package(),
      docs: docs()
    ]
  end

  def application do
    [
      # `:inets` and `:ssl` are OTP's own, and are what
      # `AudioProxy.S3.HttpClient` talks to S3 over — listed so the release
      # bundles them, since a release ships only what it is told about.
      extra_applications: [:logger, :inets, :ssl],
      mod: {AudioProxy.Application, []}
    ]
  end

  # The release is what the Docker image ships: ERTS is bundled (the runtime
  # stage has no Erlang installed), and `rel/env.sh.eex` turns distribution off.
  defp releases do
    [
      audio_proxy: [
        include_executables_for: [:unix],
        applications: [audio_proxy: :permanent]
      ]
    ]
  end

  defp elixirc_paths(:test), do: ["lib", "test/support"]
  defp elixirc_paths(_), do: ["lib"]

  defp description do
    "On-the-fly audio transcoding proxy: renders variants (transcodes, " <>
      "trimmed previews, waveform peaks) from signed URLs, streams them while " <>
      "they encode, and caches them for range-capable serving."
  end

  # A curated allowlist rather than an exclude list: a hex release is
  # permanent, so the question worth answering at publish time is "is this
  # file meant to ship?" rather than "did we remember to exclude it?".
  # `test/`, `openspec/`, `examples/`, `Dockerfile` and `.github/` are absent
  # by construction, and CI asserts that (see the `hex-package` job).
  #
  # `llms.txt` and `llms-full.txt` are why the docs ship at all: an embedder
  # with `{:audio_proxy, "~> 0.x"}` finds the whole URL contract in
  # `deps/audio_proxy/`, at the version they actually depend on, instead of
  # having to work out which tag that is on GitHub.
  defp package do
    [
      licenses: ["Apache-2.0"],
      links: %{
        "GitHub" => @source_url,
        "Changelog" => "#{@source_url}/releases",
        "Container image" => "https://github.com/audioproxy/audioproxy/pkgs/container/audioproxy"
      },
      files: [
        "lib",
        "mix.exs",
        "README.md",
        "LICENSE",
        "VERSIONS.md",
        "llms.txt",
        "llms-full.txt",
        "docs"
      ]
    ]
  end

  # The extras are the package's *documentation*, which is a smaller set than
  # the package's files. Two rules decide what is on the list.
  #
  # `llms.txt` and `llms-full.txt` are here because the README — the front page,
  # via `main: "readme"` — links to them prominently. A relative link from an
  # extra to a file ex_doc was never given resolves to nothing, so leaving them
  # off published a front page whose two most-pointed-at links were dead.
  #
  # `docs/development.md` is deliberately *not* here, though it does ship in
  # the tarball. It is about working on this repository — worktrees,
  # devcontainers, the release procedure — which is not a question a package
  # consumer has, and every one of its links points at a `bin/` script or a
  # dotfile the package does not carry. Links out to repository-only paths are
  # absolute GitHub URLs for that same reason.
  defp docs do
    [
      main: "readme",
      source_ref: "v#{@version}",
      extras: [
        "README.md",
        "docs/audio-proxy-api-v1.md",
        "docs/sources.md",
        "docs/s3-providers.md",
        "docs/rendering.md",
        "docs/ffmpeg-arguments.md",
        "docs/scaling.md",
        "docs/capacity.md",
        "docs/operations.md",
        "llms.txt",
        "llms-full.txt",
        "VERSIONS.md",
        "LICENSE"
      ]
    ]
  end

  defp deps do
    [
      {:plug, "~> 1.16"},
      {:bandit, "~> 1.6"},
      # Not a new dependency — Plug and Bandit already bring it in. Declared
      # because the render path now emits into it directly
      # (`AudioProxy.Telemetry`), and a direct use should be a direct dep.
      {:telemetry, "~> 1.0"},
      # S3 access. `ex_aws_s3` over `ex_aws`, with `sweet_xml` for S3's XML
      # responses. A deliberate exception to the stdlib-first dependency
      # policy, argued in CLAUDE.md: the alternative was ~2000 lines of
      # hand-rolled SigV4, multipart orchestration and a fake S3 to test it
      # against, all owned by us against a request contract AWS changes and
      # we do not control.
      #
      # `hackney` is deliberately absent even though `ex_aws` lists it: its
      # bundled adapter does not handle hackney 4.0's bodyless responses, so
      # an adapter was needed regardless — and `AudioProxy.S3.HttpClient`
      # over OTP's own `:httpc` costs three packages here instead of twelve.
      {:ex_aws, "~> 2.7"},
      {:ex_aws_s3, "~> 2.5"},
      {:sweet_xml, "~> 0.7"},
      {:stream_data, "~> 1.1", only: [:test]},
      # Docs only. `runtime: false` and `only: :dev` keep it out of both the
      # release and a consumer's dependency tree, so the dependency policy is
      # untouched at runtime.
      {:ex_doc, "~> 0.34", only: :dev, runtime: false}
    ]
  end
end