Cannot find module '@netlify/functions' error in on-demand builder

I’ve submitted a support email about this, but just in case someone else knows I’m copying it over here.

I’m trying to use an on-demand builder and I can get it to work locally with netlify dev, but it appears to be failing while deployed.

The deploy preview is here: https://deploy-preview-262--leereamsnyder.netlify.app/

A sample URL that invokes the builder is https://deploy-preview-262--leereamsnyder.netlify.app/og-image-generator/og-image.jpg

What should happen is it should return a screenshot of the home page. Instead, I get a 502 and this error (prettified):

{
  "errorType": "Runtime.ImportModuleError",
  "errorMessage": "Error: Cannot find module '@netlify/functions'\nRequire stack:\n- /var/task/src/og-image-generator.cjs\n- /var/task/og-image-generator.js\n- /var/runtime/UserFunction.js\n- /var/runtime/index.js",
  "trace": [
    "Runtime.ImportModuleError: Error: Cannot find module '@netlify/functions'",
    "Require stack:",
    "- /var/task/src/og-image-generator.cjs",
    "- /var/task/og-image-generator.js",
    "- /var/runtime/UserFunction.js",
    "- /var/runtime/index.js",
    "    at _loadUserApp (/var/runtime/UserFunction.js:100:13)",
    "    at Object.module.exports.load (/var/runtime/UserFunction.js:140:17)",
    "    at Object.<anonymous> (/var/runtime/index.js:43:30)",
    "    at Module._compile (internal/modules/cjs/loader.js:999:30)",
    "    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1027:10)",
    "    at Module.load (internal/modules/cjs/loader.js:863:32)",
    "    at Function.Module._load (internal/modules/cjs/loader.js:708:14)",
    "    at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:60:12)",
    "    at internal/main/run_main_module.js:17:47"
  ]
}

Here’s my _redirects that forwards that url to the function along:

/og-image-generator/*  /.netlify/functions/og-image-generator  200!

and the plugin/builder file netlify/functions/og-image-generator.cjs:

const { builder } = require('@netlify/functions')
const puppeteer = require('puppeteer')

// https://blog.hootsuite.com/social-media-image-sizes-guide/#Quick_social_media_image_sizes
const captureWidth = 1200
const captureHeight = 630
const clipY = 60

async function handler (event, context) {
  console.log(`enter og-image generator`, event)
  let path = event.path
    .replace('/og-image-generator', '')
    .replace('/og-image.jpg', '')

  console.log('calculated URL', {
    path,
    URL: process.env.URL,
    DEPLOY_URL: process.env.DEPLOY_URL,
    url: `${process.env.DEPLOY_URL}${path}`
  })

  const browser = await puppeteer.launch({
    defaultViewport: {
      width: 1200,
      height: captureHeight + clipY
    }
  })
  const page = await browser.newPage()

  await page.emulateMediaFeatures([
    // { name: 'prefers-color-scheme', value: 'dark' },

    // no need for any animations to be going
    { name: 'prefers-reduced-motion', value: 'reduce' }
  ])

  await page.goto(`${process.env.DEPLOY_URL}${path}`)
  const screenshot = await page.screenshot({
    type: 'jpeg',
    // netlify functions can only return strings, so base64 it is
    encoding: 'base64',
    quality: 70,
    clip: {
      x: 0,
      y: clipY,
      width: captureWidth,
      height: captureHeight
    }
  })

  await browser.close()

  return {
    statusCode: 200,
    headers: {
      'Content-Type': 'image/jpg'
    },
    body: screenshot,
    isBase64Encoded: true
  }
}

exports.handler = builder(handler)

The 2 dependencies for the function are in the top-level package.json:

  "devDependencies": {
    "@netlify/functions": "0.7.2",
    // other dependencies
    "puppeteer": "8.0.0",
    // other dependencies
  }

It appears to build in the build logs:

12:21:03 AM: ────────────────────────────────────────────────────────────────
12:21:03 AM:   2. Functions bundling                                         
12:21:03 AM: ────────────────────────────────────────────────────────────────
12:21:03 AM: ​
12:21:03 AM: Packaging Functions from netlify/functions directory:
12:21:03 AM:  - og-image-generator.cjs
12:21:03 AM: ​
12:21:03 AM: ​
12:21:03 AM: (Functions bundling completed in 101ms)

and I see the function in my Functions on the dashboard.

Am I missing something? I have the dependencies listed in the top-level package.json as the docs recommend. I’ve tried shuffling them from devDependencies to dependencies but that results in the same error. And, again, it works flawlessly running it locally with netlify dev. And I do understand that the on-demand builders are in beta, but the docs seem pretty clear that you gain access by deploying a builder per the instructions.

Am I missing something fundamental to get it actually working on Netlify?

Thanks in advance.