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 🙏

© 2024 – Pkg Stats / Ryan Hefner

@nora-soderlund/cloudflare-dynamic-bindings

v0.9.4

Published

A package that aims to provide a single solution for managing dynamic binds for Cloudflare Workers.

Downloads

129

Readme

cloudflare-dynamic-bindings

This is a package that aims to provide a single solution for managing dynamic binds for Cloudflare Workers.

How does it work?

  1. (Optional) Worker creates a new D1 database via the Cloudflare API.
  2. Worker triggers a GitHub workflow to add the new binding.
  3. GitHub Actions modifies wrangler.toml and triggers a new deployment.

It's important to highlight that this action will parse and then stringify your wrangler configuration. It will look a bit different than the original because of how dynamic toml is.

For clarification, the new binding will not be available until the next deployment. It is in your control how you want to initiate the next deployment, some scenarios could be for example:

  • Automatically when a commit is pushed to the main branch
  • Automatically open a pull request in the workflow and approve manually
  • Automatically when a deployment workflow has been approved manually

Supported bindings

Right now only D1 databases are supported, feel free to adapt the action script to provide more options.

  • [X] D1 Databases
  • [ ] KV Namespaces
  • [ ] Durable Objects
  • [ ] R2 buckets
  • [ ] Queues

Getting started

Prerequisities

  • A GitHub token with workflow permissions to your worker repository.
  • (Optional) A Cloudflare token with d1:write permissions to create new databases.

Setting up your repository

  1. Create a new workflow in the .github/workflows path, for example called dynamic-bindings.yml
  2. Use the @nora-soderlund/cloudflare-dynamic-bindings action to modify your wrangler.toml file on demand
name: Dynamic bindings

on:
  workflow_dispatch:
    inputs:
      bindings:
        required: true
        description: An JSON array of bindings to add.

permissions:
  contents: write

jobs:
  create-dynamic-bindings:
    name: Create dynamic bindings
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4
      
      - name: Create dynamic bindings
        uses: nora-soderlund/[email protected]
        with:
          file: ./wrangler.toml # change the path to your wrangler.toml file or just omit this line
          bindings: ${{ inputs.bindings }}

      - name: Commit new bindings
        run: |
          git config --global user.name 'GitHub Actions'
          git config --global user.email ''
          git commit -am "Add dynamic bindings"
          git push

Setting up your worker

  1. Install the @nora-soderlund/cloudflare-dynamic-bindings package, e.g.
npm install @nora-soderlund/[email protected]
  1. Create a dynamic binding using the createWranglerBinding function, e.g.
import { createD1Database, createWranglerBinding, getD1DatabaseBinding, getD1DatabaseIdentifier } from "@nora-soderlund/cloudflare-dynamic-bindings";
import type { RepositoryProperties } from "@nora-soderlund/cloudflare-dynamic-bindings";

const repositorySettings: RepositoryProperties = {
  owner: "nora-soderlund",
  repository: "cloudflare-dynamic-bindings",
  workflow: "dynamic-bindings.yml" // use the file name you chose for setting up the repository
};

export default {
  async fetch(request: Request, env: Env, context: ExecutionContext): Promise<Response> {
    if(!request.cf) {
      throw new Error("Request is missing `cf` object.");
    }

    const binding = `DATABASE_${request.cf.colo}`;
    const databaseName = `DATABASE_${request.cf.colo}`;

    let database = env[binding];

    if(!database) {
			// Check if the database already exists but just isn't bound
			let databaseId = await getD1DatabaseIdentifier(env.CLOUDFLARE_TOKEN, env.ACCOUNT_ID, databaseName);

			if(!databaseId) {
				// Create a new database otherwise using the Cloudflare API
				databaseId = await createD1Database(env.CLOUDFLARE_TOKEN, env.ACCOUNT_ID, databaseName);
				
				// Dispatch a binding update but don't block the response
				context.waitUntil(createWranglerBinding(repositorySettings, env.GITHUB_TOKEN, {
					type: "D1",
					binding,
					environments: [
						{
							databaseId,
							databaseName
						}
					]
				}));
			}

			// Create a D1Database polyfill instance that uses the HTTP API as a fallback
			database = getD1DatabaseBinding(env.CLOUDFLARE_TOKEN, env.ACCOUNT_ID, databaseId);
    }

    // Example query on the bound or non-bound database
    const sum = await database.prepare("SELECT ? + ? AS sum").bind(50, 50).first<number>("sum");
    
    // ...
  }
}

Outcome

Now, when you create a wrangler binding via your worker, a commit is pushed to your primary branch with the new binding. It is now expected that you have a workflow that is triggered on new commits and deploys your worker.