What are cloudflare KV preview_ids and how to get one?
Asked Answered
I

2

10

I have a following wrangler.toml. When I would like to use dev or preview (e.g. npx wrangler dev or npx wrangler preview) wrangler asks to add a preview_id to the KV namespaces. Is this an identifier to an existing KV namespace?

I see there is a ticket in Cloudflare Workers GH at https://github.com/cloudflare/wrangler/issues/1458 that tells this ought to be clarified but the ticket is closed with adding an error message

In order to preview a worker with KV namespaces, you must designate a preview_id in your configuration file for each KV namespace you'd like to preview."

which is the reason I'm here. :)

As for larger context I would be really glad if someone could clarify: I see that if I give a value of an existing namespace, I can preview and I see a KV namespace of type __some-worker-dev-1234-workers_sites_assets_preview is generated in Cloudflare. This has a different identifier than the KV namespace pointed by the identifier used in the preview_id and the KV namespace pointed by the identifier I used in preview_id is empty. Why does giving an identifier of an existing KV namespace remove the error message, deploys the assets and allow for previwing but the actual KV namespace is empty and a new one is created?

How do does kv-asset-handler know to look into this generated namespace to retrieve the assets?

I'm currently testing with the default generated Cloudare Worker to my site and I wonder if I have misunderstood something or if there is some mechanics that bundles during preview/publish the site namespace to the scipt.

If there is some random mechanics with automatic mapping, can this be then so that every developer can have their own private preview KV namespace?

type = "javascript"
name = "some-worker-dev-1234"
account_id = "<id>"
workers_dev = true

kv_namespaces = [
  { binding = "site_data", id = "<test-site-id>" }
]

[site]
# The location for the site.
bucket = "./dist"

# The entry directory for the package.json that contains 
# main field for the file name of the compiled worker file in "main" field.
entry-point = ""

[env.production]
name = "some-worker-1234"
zone_id = "<zone-id>"
routes = [
  "http://<site>/*",
  "https://www.<site>/*"
]

# kv_namespaces = [
#  { binding = "site_data", id = "<production-site-id>" }
# ]

import { getAssetFromKV, mapRequestToAsset } from '@cloudflare/kv-asset-handler'

/**
 * The DEBUG flag will do two things that help during development:
 * 1. we will skip caching on the edge, which makes it easier to
 *    debug.
 * 2. we will return an error message on exception in your Response rather
 *    than the default 404.html page.
 */
const DEBUG = false

addEventListener('fetch', event => {
  try {
    event.respondWith(handleEvent(event))
  } catch (e) {
    if (DEBUG) {
      return event.respondWith(
        new Response(e.message || e.toString(), {
          status: 500,
        }),
      )
    }
    event.respondWith(new Response('Internal Error', { status: 500 }))
  }
})

async function handleEvent(event) {
  const url = new URL(event.request.url)
  let options = {}

  /**
   * You can add custom logic to how we fetch your assets
   * by configuring the function `mapRequestToAsset`
   */
  // options.mapRequestToAsset = handlePrefix(/^\/docs/)

  try {
    if (DEBUG) {
      // customize caching
      options.cacheControl = {
        bypassCache: true,
      }
    }

    const page = await getAssetFromKV(event, options)

    // allow headers to be altered
    const response = new Response(page.body, page)

    response.headers.set('X-XSS-Protection', '1; mode=block')
    response.headers.set('X-Content-Type-Options', 'nosniff')
    response.headers.set('X-Frame-Options', 'DENY')
    response.headers.set('Referrer-Policy', 'unsafe-url')
    response.headers.set('Feature-Policy', 'none')

    return response

  } catch (e) {
    // if an error is thrown try to serve the asset at 404.html
    if (!DEBUG) {
      try {
        let notFoundResponse = await getAssetFromKV(event, {
          mapRequestToAsset: req => new Request(`${new URL(req.url).origin}/404.html`, req),
        })

        return new Response(notFoundResponse.body, { ...notFoundResponse, status: 404 })
      } catch (e) {}
    }

    return new Response(e.message || e.toString(), { status: 500 })
  }
}

/**
 * Here's one example of how to modify a request to
 * remove a specific prefix, in this case `/docs` from
 * the url. This can be useful if you are deploying to a
 * route on a zone, or if you only want your static content
 * to exist at a specific path.
 */
function handlePrefix(prefix) {
  return request => {
    // compute the default (e.g. / -> index.html)
    let defaultAssetKey = mapRequestToAsset(request)
    let url = new URL(defaultAssetKey.url)

    // strip the prefix from the path for lookup
    url.pathname = url.pathname.replace(prefix, '/')

    // inherit all other props from the default request
    return new Request(url.toString(), defaultAssetKey)
  }
}

Inscrutable answered 9/8, 2020 at 23:24 Comment(0)
B
4

This answer applies to versions of Wrangler >= 1.10.0

wrangler asks to add a preview_id to the KV namespaces. Is this an identifier to an existing KV namespace?

Yes! The reason there is a different identifier for preview namespaces is so that when developing with wrangler dev or wrangler preview you don't accidentally write changes to your existing production data with possibly buggy or incompatible code. You can add a --preview flag to most wrangler kv commands to interact with your preview namespaces.


For your situation here there are actually a few things going on.

  1. You are using Workers Sites
  2. You have a KV namespace defined in wrangler.toml

Workers Sites will automatically configure a production namespace for each environment you run wrangler publish on, and a preview namespace for each environment you run wrangler dev or wrangler preview on. If all you need is Workers Sites, then there is no need at all to specify a kv-namepsaces table in your manifest. That table is for additional KV namespaces that you may want to read data from or write data to. If that is what you need, you'll need to configure your own namespace and add id to wrangler.toml if you want to use wrangler publish, and preview_id (which should be different) if you want to use wrangler dev or wrangler preview.

Billy answered 10/8, 2020 at 16:45 Comment(2)
This makes sense. Do you know how the (currently) auto-generated Worker script know how to fetch data from the preview namespace? I see getAssetFromKV etc. Or would this be a case for separate question, I wonder too... The reason I wonder about this separete question is because this is a bit confusing due to this reason (and in the docs the namespace ID being something that isn't told where it comes from).Inscrutable
Isn't this what the --env flag is for? Establishing different resources per environment?Bonehead
C
19

In case the format is not obvious (it wasn't to me) here is a sample config block from the docs with the preview_id specified for a couple of KV Namespaces:

kv_namespaces = [  
  { binding = "FOO", id = "0f2ac74b498b48028cb68387c421e279", preview_id = "6a1ddb03f3ec250963f0a1e46820076f" },
  { binding = "BAR", id = "068c101e168d03c65bddf4ba75150fb0", preview_id = "fb69528dbc7336525313f2e8c3b17db0" }
]

You can generate a new namespace ID in the Workers KV section of the dashboard or with the Wrangler CLI: wrangler kv:namespace create "SOME_NAMESPACE" --preview

Clack answered 19/9, 2020 at 18:57 Comment(3)
Good points. I think the docs don't make it very clear what is the differences between 'dev' and 'preview' modes and how it relates to KV namespaces. This is what caused my initial confusion with the example pieces that seemedto have unrelated IDs. I think the docs should still be clearer and also note that one needs to have main in package.json in case Rollup (=JavaScript) is used and so on.Inscrutable
I realized that the wrangler command I gave worked, but was not really way the utility is intended to be used. Fixed it.Clack
Worth noting: the namespace in that command needs to be the same as the one that already exists. That is, the "binding" value on the line in the wrangler.toml file.Wistful
B
4

This answer applies to versions of Wrangler >= 1.10.0

wrangler asks to add a preview_id to the KV namespaces. Is this an identifier to an existing KV namespace?

Yes! The reason there is a different identifier for preview namespaces is so that when developing with wrangler dev or wrangler preview you don't accidentally write changes to your existing production data with possibly buggy or incompatible code. You can add a --preview flag to most wrangler kv commands to interact with your preview namespaces.


For your situation here there are actually a few things going on.

  1. You are using Workers Sites
  2. You have a KV namespace defined in wrangler.toml

Workers Sites will automatically configure a production namespace for each environment you run wrangler publish on, and a preview namespace for each environment you run wrangler dev or wrangler preview on. If all you need is Workers Sites, then there is no need at all to specify a kv-namepsaces table in your manifest. That table is for additional KV namespaces that you may want to read data from or write data to. If that is what you need, you'll need to configure your own namespace and add id to wrangler.toml if you want to use wrangler publish, and preview_id (which should be different) if you want to use wrangler dev or wrangler preview.

Billy answered 10/8, 2020 at 16:45 Comment(2)
This makes sense. Do you know how the (currently) auto-generated Worker script know how to fetch data from the preview namespace? I see getAssetFromKV etc. Or would this be a case for separate question, I wonder too... The reason I wonder about this separete question is because this is a bit confusing due to this reason (and in the docs the namespace ID being something that isn't told where it comes from).Inscrutable
Isn't this what the --env flag is for? Establishing different resources per environment?Bonehead

© 2022 - 2024 — McMap. All rights reserved.