JavaScript helpers for Cloudflare dev services.
Check out the starter kit for a quick start. This will setup everything you need to run a full-stack cloudflare app.
npm install treeder/flaregun
This handles inserting and updating objects, assigning IDs, nested JSON objects, etc.
import { D1 } from 'flaregun'
// D1
let d1 = new D1(env.D1) // just adds some extra functionality to the built in d1 interface, you can still use it just as you normally would too.
// then you can use the new functions
// insert new data
let user = {name: 'Jimbo', email: '[email protected]'}
await d1.insert('users', user)
user.name = 'Jim Bean'
// update a row
await d1.update('users', user.id, user)
// get object
user = d1.get('users', user.id)
// querying
// simple equality queries
let users = await d1.query('users', {
where: { email: '[email protected]' },
})
// more complex queries
let users = await d1.query('users', {
where: [['orgId', '=', orgId], ['createdAt', '>', new Date(Date.now() - 48 * 60 * 60 * 1000)]],
order: ['createdAt', 'asc'],
limit: 100,
})
// querying JSON data using path notation
let users = await d1.query('users', {
where: [['data.awesome', '=', true]],
})
// counts
let userCount = await d1.count('users', {
where: { orgId }
})
Recommended: D1 supports using models to parse fields into the proper object types. This is the same format as for Lit properties AND you can use the same models for automatic migrations, JSON parsing, etc.
First, define your models with JavaScript types or custom parsers (see models for more info).
export class User {
static table = 'users'
static properties = {
id: {
type: String,
primaryKey: true,
},
createdAt: {
type: Date,
},
updatedAt: {
type: Date,
},
name: {
type: String,
},
email: {
type: String,
},
data: {
type: Object, // this is stored as a JSON object so you can stuff anything in here and still query on it.
},
}
}
Then use it like this:
let users = await d1.get(User, userId)
This will parse the dates, booleans, JSON, etc into the proper types.
This is a special error handler that will format your error nicely formatted for Cloudflare logging and the ability to send notifications, etc.
In your global request handler (if you're using cloudflare workers file based routing, in your root _middleware.js
).
// define your ErrorHandler with options
const errorHandler = new ErrorHandler()
// then in your global wrapper:
try {
await c.next()
} catch (err) {
return errorHandler.handle(c, err)
}
You can have the errors sent to a webhook:
const errorHandler = new ErrorHandler({
postTo: {
url: 'https://chat.googleapis.com/v1/spaces/AAQAsw9EPWU/messages?key=X&token=Y',
options: {
method: 'POST',
body: (message) => {
return { text: message }
},
},
},
})
Change the body function to change the format expected by the webhook service you are using.
To prevent duplicate errors, ensure you have a key/value store binding at env.KV
.
This makes it easy to handle events on a schedule.
const scheduler = new Scheduler()
scheduler.addEventListener('hour', myFunction)
That will call myFunction(c)
every hour. You can use minute, hour, day, week, month too.
Setup a cron trigger in your worker settings to run every minute: */1 * * * *
And add this scheduled function to your worker:
async scheduled(event, env, ctx) {
// let scheduledTime = new Date(event.scheduledTime)
console.log(`Scheduled event fired. cron: ${event.cron}`)
try {
await scheduler.run(event)
} catch(e){
console.error(e)
}
}
You can use CloudflareLogger to get nicely formatted messages for cloudflare logging while
using it just like console.log. Setup in _middleware.js
like this:
let rid = nanoid()
let url = new URL(req.url)
c.data.logger = new CloudflareLogger({ data: { requestId: rid, path: url.pathname } })
The extra data added above will be logged in all messages for easy filtering.
Then use it:
c.data.logger.log('This is a message')
// with more data
c.data.logger.log('This is a message', { foo: 'bar' })
// errors
c.data.logger.log(new Error('This is an error'))
If you want to add some data along the way, in middleware or during function chains:
let logger = c.data.logger.with('foo', 'bar')
logger.log('This is a message')
If you're using Wrangler file based routing, you can add our middleware.
Add this to your root _middleware.js
:
import { timer } from 'flaregun/middleware/timer.js'
import { cors } from 'flaregun/middleware/cors.js'
export async function wrap(c) {
// your own things can go here
}
export const onRequest = [timer, cors, wrap]