{"id":43270536,"url":"https://github.com/treeder/flaregun","last_synced_at":"2026-02-01T15:41:24.098Z","repository":{"id":225819277,"uuid":"766934011","full_name":"treeder/flaregun","owner":"treeder","description":"JavaScript utils for Cloudflare dev services. ","archived":false,"fork":false,"pushed_at":"2026-01-23T19:10:17.000Z","size":701,"stargazers_count":5,"open_issues_count":1,"forks_count":2,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-01-24T09:08:48.981Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/treeder.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2024-03-04T12:04:21.000Z","updated_at":"2026-01-23T19:10:21.000Z","dependencies_parsed_at":"2024-04-19T16:30:36.007Z","dependency_job_id":"c42b498d-2901-4917-8662-72d94cb2db39","html_url":"https://github.com/treeder/flaregun","commit_stats":null,"previous_names":["treeder/cloudflare","treeder/cloudflare-funcs","treeder/flaregun"],"tags_count":127,"template":false,"template_full_name":null,"purl":"pkg:github/treeder/flaregun","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/treeder%2Fflaregun","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/treeder%2Fflaregun/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/treeder%2Fflaregun/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/treeder%2Fflaregun/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/treeder","download_url":"https://codeload.github.com/treeder/flaregun/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/treeder%2Fflaregun/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28981453,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-01T15:35:50.179Z","status":"ssl_error","status_checked_at":"2026-02-01T15:35:38.075Z","response_time":56,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-02-01T15:41:23.955Z","updated_at":"2026-02-01T15:41:24.091Z","avatar_url":"https://github.com/treeder.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Flaregun\n\nJavaScript helpers for Cloudflare dev services.\n\n\u003cimg width=\"609\" height=\"298\" alt=\"flaregun3\" src=\"https://github.com/user-attachments/assets/95b8eb01-fa37-4378-b209-5811b0362498\" /\u003e\n\n## Starter kit\n\nCheck out [the starter kit](https://github.com/treeder/flaregun-starter) for a quick start. This will setup everything you need to run a full-stack cloudflare app.\n\n## Install\n\n```sh\nnpm install treeder/flaregun\n```\n\n## D1 Sqlite Database\n\nFlaregun offers a great wrapper around the default D1 interface handles inserting and updating objects, assigning IDs,\nquerying nested JSON objects, merge updates, etc.\n\n```js\nimport { D1 } from 'flaregun'\n\n// D1\nlet 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.\n\n// then you can use the new functions\n// insert new data\nlet user = { name: 'Jimbo', email: 'x@y.com' }\nawait d1.insert('users', user)\n\nuser.name = 'Jim Bean'\n// update a row\nawait d1.update('users', user.id, user)\n\n// get object\nuser = d1.get('users', user.id)\n\n// querying\n// simple equality queries\nlet users = await d1.query('users', {\n  where: { email: 'x@y.com' },\n})\n\n// more complex queries\nlet users = await d1.query('users', {\n  where: [\n    ['orgId', '=', orgId],\n    ['createdAt', '\u003e', new Date(Date.now() - 48 * 60 * 60 * 1000)],\n  ],\n  order: ['createdAt', 'asc'],\n  limit: 100,\n})\n\n// querying JSON data using path notation\nlet users = await d1.query('users', {\n  where: [['data.awesome', '=', true]],\n})\n\n// counts\nlet userCount = await d1.count('users', {\n  where: { orgId },\n})\n```\n\n### Using models for field parsing\n\nRecommended: D1 supports using [models](https://github.com/treeder/models) to parse fields into the proper object types. This is the same format as for [Lit](https://lit.dev) properties AND you can use the\nsame models for automatic [migrations](https://github.com/treeder/migrations), JSON parsing, etc.\n\nFirst, define your models with JavaScript types or custom parsers (see [models](https://github.com/treeder/models) for more info).\n\n```js\nexport class User {\n  static table = 'users'\n  static properties = {\n    id: {\n      type: String,\n      primaryKey: true,\n    },\n    createdAt: {\n      type: Date,\n    },\n    updatedAt: {\n      type: Date,\n    },\n    name: {\n      type: String,\n    },\n    email: {\n      type: String,\n    },\n    data: {\n      type: Object, // this is stored as a JSON object so you can stuff anything in here and still query on it.\n    },\n  }\n}\n```\n\nThen use it like this:\n\n```js\nlet users = await d1.get(User, userId)\n```\n\nThis will parse the dates, booleans, JSON, etc into the proper types.\n\n## KV\n\nThis is a simple wrapper that adds a few nice things like:\n\n```\nlet kv = new KV(env.KV)\nawait kv.putJSON('foo', { bar: 'baz' })\nlet foo = await kv.getJSON('foo')\n```\n\n## Error Handler\n\nThis is a special error handler that will format your error nicely formatted for Cloudflare logging and\nthe ability to send notifications, etc.\n\nIn your global request handler (if you're using cloudflare workers file based routing, in your root `_middleware.js`).\n\n```js\n// define your ErrorHandler with options\nconst errorHandler = new ErrorHandler()\n\n// then in your global wrapper:\ntry {\n  await c.next()\n} catch (err) {\n  return errorHandler.handle(c, err)\n}\n```\n\n### Error Alerts\n\nYou can have the errors sent to a webhook:\n\n```js\nconst errorHandler = new ErrorHandler({\n  postTo: {\n    url: 'https://x.y/webhook',\n    options: {\n      method: 'POST',\n      body: (message) =\u003e {\n        return { text: message }\n      },\n    },\n  },\n})\n```\n\nChange the body function to change the format expected by the webhook service you are using.\n\nTo prevent duplicate errors, ensure you have a key/value store binding at `env.KV`.\n\n## Scheduler\n\nThis makes it easy to handle events on a schedule.\n\n```js\nconst scheduler = new Scheduler()\nscheduler.addEventListener('hour', myFunction)\n```\n\nThat will call `myFunction(c)` every hour. You can use minute, hour, day, week, month, 5minutes, 15minutes.\n\nSetup a cron trigger in your worker settings to run every minute: `*/1 * * * *`\n\nAnd add this scheduled function to your worker:\n\n```js\nasync scheduled(event, env, ctx) {\n  // let scheduledTime = new Date(event.scheduledTime)\n  console.log(`Scheduled event fired. cron: ${event.cron}`)\n  try {\n    await scheduler.run(event)\n  } catch(e){\n    console.error(e)\n  }\n}\n```\n\n## Logging\n\nYou can use CloudflareLogger to get nicely formatted messages for cloudflare logging while\nusing it just like console.log. Setup in `_middleware.js` like this:\n\n```js\nlet rid = nanoid()\nlet url = new URL(req.url)\nc.data.logger = new CloudflareLogger({ data: { requestId: rid, path: url.pathname } })\n```\n\nThe extra data added above will be logged in all messages for easy filtering.\n\nThen use it:\n\n```js\nc.data.logger.log('This is a message')\n// with more data\nc.data.logger.log('This is a message', { foo: 'bar' })\n// errors\nc.data.logger.log(new Error('This is an error'))\n```\n\nIf you want to add some data along the way, in middleware or during function chains:\n\n```js\nlet logger = c.data.logger.with('foo', 'bar')\nlogger.log('This is a message')\n```\n\n## Middleware\n\nIf you're using Wrangler file based routing, you can add our middleware.\n\nAdd this to your root `_middleware.js`:\n\n```js\nimport { timer } from 'flaregun/middleware/timer.js'\nimport { cors } from 'flaregun/middleware/cors.js'\n\nexport async function wrap(c) {\n  // your own things can go here\n}\n\nexport const onRequest = [timer, cors, wrap]\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftreeder%2Fflaregun","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftreeder%2Fflaregun","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftreeder%2Fflaregun/lists"}