{"id":15355252,"url":"https://github.com/gomah/spera","last_synced_at":"2025-04-15T06:28:14.123Z","repository":{"id":111948222,"uuid":"571981753","full_name":"Gomah/spera","owner":"Gomah","description":"Run \u0026 schedule your code in the background with a fully typed client","archived":false,"fork":false,"pushed_at":"2024-05-14T00:28:58.000Z","size":9284,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2024-05-14T01:39:04.597Z","etag":null,"topics":["background","background-jobs","nextjs","qstash","queue","redis","serverless","spera"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","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/Gomah.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}},"created_at":"2022-11-29T10:00:43.000Z","updated_at":"2024-05-30T07:15:34.621Z","dependencies_parsed_at":"2023-10-16T22:37:00.671Z","dependency_job_id":"3d4729ba-ee93-4c88-8e06-08352d9607ec","html_url":"https://github.com/Gomah/spera","commit_stats":null,"previous_names":[],"tags_count":30,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Gomah%2Fspera","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Gomah%2Fspera/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Gomah%2Fspera/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Gomah%2Fspera/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Gomah","download_url":"https://codeload.github.com/Gomah/spera/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":249019904,"owners_count":21199447,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["background","background-jobs","nextjs","qstash","queue","redis","serverless","spera"],"created_at":"2024-10-01T12:23:25.247Z","updated_at":"2025-04-15T06:28:14.107Z","avatar_url":"https://github.com/Gomah.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Spera\n\n\u003e Run \u0026 schedule your code in the background with a fully typed client.\n\n![Preview](https://user-images.githubusercontent.com/2362138/204499245-c2d0451f-b34c-4ea1-bdb2-f0fa7f8121f5.gif)\n\n⚠️ Very early project – I'm currently using a similar version of this code in production but I don't think you should 🤷\n\n## How it works ?\n\nSpera is (for now), just a small typed client for the code you want to schedule in the background, it uses QStash and runs locally when running `NODE_ENV` is set to development.\n\nAll you need is to pass a functions object (key being the name of your event and the function to run as the value), e.g:\n\n```ts\nconst functions = {\n  'app/account.created': accountCreated.Handler\n}\n```\n\n```ts\nimport qStashProvider from '@spera/plugin-qstash';\nimport { Spera } from '@spera/core';\nimport * as accountCreated from './account.created';\n\nexport const functions = {\n  'app/account.created': accountCreated.handler,\n};\n\nexport const spera = new Spera({\n  url: `${getBaseUrl()}/api/spera`,\n  functions,\n  provider: qStashProvider({ token: process.env.QSTASH_TOKEN as string }),\n});\n```\n\nI plan to support different providers, frameworks \u0026 improve the project – there's a fair bit of boilerplate for now.\n\n## Quickstart (With Next.js)\n\n### Install dependencies\n\n```bash\nyarn add @spera/core @spera/nextjs @spera/plugin-qstash\n```\n\nNotes:\n\nThis first version depends on [QStash](https://upstash.com/qstash) as a provider, please make sure you have the following environment variables setup for your project:\n\n- `QSTASH_URL`\n- `QSTASH_TOKEN`\n- `QSTASH_CURRENT_SIGNING_KEY`\n- `QSTASH_NEXT_SIGNING_KEY`\n\n\n### Define your \"functions\" / \"jobs\" you want to run in the background\n\nSee `apps/next/.spera` as an example.\n\n```bash\n.\n├── .spera/                     # Your folder containing your functions to run in the background\n│   ├── account.created.ts\n│   └── index.ts\n├── pages/\n│   ├── api/                    # Next.js API folder\n│   │   ├── spera.ts            # The Spera API handler\n└── ...\n```\n\n```ts\n// .spera/index.ts\nimport * as accountCreated from './account.created';\nimport { Spera } from '@spera/core';\nimport qStashProvider from '@spera/plugin-qstash';\n\nexport const functions = {\n  [accountCreated.name]: accountCreated.handler,\n};\n\nexport const getBaseUrl = () =\u003e {\n  if (typeof window !== 'undefined') return ''; // browser should use relative url\n  if (process.env.VERCEL_URL) return `https://${process.env.VERCEL_URL}`; // SSR should use vercel url\n  return `http://localhost:${process.env.PORT ?? 3000}`; // dev SSR should use localhost\n};\n\nexport const spera = new Spera({\n  url: `${getBaseUrl()}/api/spera`,\n  functions,\n  provider: qStashProvider({ token: process.env.QSTASH_TOKEN as string }),\n});\n```\n\n```ts\n// .spera/account.created.ts\nexport const name = 'app/account.created';\n\nexport interface AccountCreatedPayload {\n  id: string;\n}\n\nexport async function handler(payload: AccountCreatedPayload) {\n  const { id } = payload;\n  console.info(`Account created: ${id}`);\n  return id;\n}\n```\n\n```ts\n// pages/api/spera.ts\nimport { withSpera } from '@spera/nextjs';\nimport { verifySignature } from '@spera/plugin-qstash/nextjs';\nimport type { NextApiRequest, NextApiResponse } from 'next';\nimport { spera } from '../../.spera';\n\nexport const config = {\n  api: {\n    bodyParser: false,\n  },\n};\n\nasync function handler(req: NextApiRequest, res: NextApiResponse) {\n  // This should be displayed after the background function is processed :)\n  console.log('Hey there!');\n  return res.status(200).end();\n}\n\nexport default withSpera(handler, spera, verifySignature);\n\n```\n\n## Project \"roadmap\"\n\n- [x] Abstract QStash as a \"Provider\" plugin.\n- [x] Next.js helpers (Spera to extract \"use\" hooks to verify signatures based on X provider)\n- [x] Dynamic Next.js helpers (based on provider)\n- [ ] Support batch\n- [ ] Add zod\n- [ ] Client API Design\n- [ ] Cloudflare Queues as a \"Provider\" plugin.\n- [ ] Docs\n- [ ] Cleanup code / repo\n- [ ] Framework agnostic\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgomah%2Fspera","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgomah%2Fspera","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgomah%2Fspera/lists"}