├── with-novu ├── .eslintrc.json ├── next.config.js ├── .gitignore ├── pages │ ├── _app.tsx │ ├── api │ │ └── task │ │ │ ├── add.ts │ │ │ └── process.ts │ └── index.tsx ├── tsconfig.json ├── package.json ├── lib │ └── useUserId.tsx └── README.md ├── cron-api-nyt ├── .eslintrc.json ├── .env.example ├── public │ ├── favicon.ico │ └── vercel.svg ├── next.config.js ├── pages │ ├── _app.tsx │ ├── api │ │ ├── hello.ts │ │ └── callback.ts │ └── index.tsx ├── styles │ ├── globals.css │ └── Home.module.css ├── .gitignore ├── tsconfig.json ├── package.json └── README.md ├── vercel-nextjs ├── .eslintrc.json ├── public │ ├── favicon.ico │ └── vercel.svg ├── next.config.js ├── pages │ ├── _app.js │ ├── api │ │ ├── hello.js │ │ └── qstash.js │ └── index.js ├── styles │ ├── globals.css │ └── Home.module.css ├── package.json └── README.md ├── periodic-data-updates ├── .eslintrc.json ├── public │ ├── favicon.ico │ └── vercel.svg ├── postcss.config.js ├── next.config.js ├── next-env.d.ts ├── components │ ├── ReadBlogPost.tsx │ ├── Header.tsx │ ├── StarButton.tsx │ └── Breadcrumb.tsx ├── .gitignore ├── tailwind.config.js ├── tsconfig.json ├── package.json ├── pages │ ├── _app.tsx │ ├── api │ │ └── cron.ts │ └── index.tsx ├── styles │ ├── globals.css │ └── Home.module.css └── README.md ├── cloudflare-workers ├── wrangler.toml ├── package.json ├── src │ └── index.ts ├── tsconfig.json └── package-lock.json ├── fly.io └── go │ ├── go.mod │ ├── go.sum │ ├── Dockerfile │ ├── fly.toml │ ├── fly.original.toml │ └── main.go ├── aws-lambda ├── python-example │ ├── Makefile │ └── lambda_function.py └── typescript-example │ ├── package.json │ └── index.ts ├── .gitignore ├── deno-deploy └── index.ts └── README.md /with-novu/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals" 3 | } 4 | -------------------------------------------------------------------------------- /cron-api-nyt/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals" 3 | } 4 | -------------------------------------------------------------------------------- /vercel-nextjs/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals" 3 | } 4 | -------------------------------------------------------------------------------- /periodic-data-updates/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals" 3 | } 4 | -------------------------------------------------------------------------------- /cron-api-nyt/.env.example: -------------------------------------------------------------------------------- 1 | QSTASH_CURRENT_SIGNING_KEY= 2 | QSTASH_NEXT_SIGNING_KEY= 3 | 4 | DISCORD_WEBHOOK= -------------------------------------------------------------------------------- /cron-api-nyt/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/upstash/qstash-examples/main/cron-api-nyt/public/favicon.ico -------------------------------------------------------------------------------- /vercel-nextjs/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/upstash/qstash-examples/main/vercel-nextjs/public/favicon.ico -------------------------------------------------------------------------------- /cloudflare-workers/wrangler.toml: -------------------------------------------------------------------------------- 1 | name = "cloudflare-workers" 2 | main = "src/index.ts" 3 | compatibility_date = "2022-07-11" 4 | -------------------------------------------------------------------------------- /fly.io/go/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/upstash/qstash-examples/fly.io/go 2 | 3 | go 1.18 4 | 5 | require github.com/golang-jwt/jwt/v4 v4.4.2 6 | -------------------------------------------------------------------------------- /periodic-data-updates/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/upstash/qstash-examples/main/periodic-data-updates/public/favicon.ico -------------------------------------------------------------------------------- /periodic-data-updates/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | }; 7 | -------------------------------------------------------------------------------- /cron-api-nyt/next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | reactStrictMode: true, 4 | swcMinify: true, 5 | } 6 | 7 | module.exports = nextConfig 8 | -------------------------------------------------------------------------------- /with-novu/next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | reactStrictMode: true, 4 | swcMinify: true, 5 | } 6 | 7 | module.exports = nextConfig 8 | -------------------------------------------------------------------------------- /vercel-nextjs/next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | reactStrictMode: true, 4 | swcMinify: true, 5 | }; 6 | 7 | module.exports = nextConfig; 8 | -------------------------------------------------------------------------------- /vercel-nextjs/pages/_app.js: -------------------------------------------------------------------------------- 1 | import "../styles/globals.css"; 2 | 3 | function MyApp({ Component, pageProps }) { 4 | return ; 5 | } 6 | 7 | export default MyApp; 8 | -------------------------------------------------------------------------------- /fly.io/go/go.sum: -------------------------------------------------------------------------------- 1 | github.com/golang-jwt/jwt/v4 v4.4.2 h1:rcc4lwaZgFMCZ5jxF9ABolDcIHdBytAFgqFPbSJQAYs= 2 | github.com/golang-jwt/jwt/v4 v4.4.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= 3 | -------------------------------------------------------------------------------- /periodic-data-updates/next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | reactStrictMode: true, 4 | swcMinify: true, 5 | }; 6 | 7 | module.exports = nextConfig; 8 | -------------------------------------------------------------------------------- /vercel-nextjs/pages/api/hello.js: -------------------------------------------------------------------------------- 1 | // Next.js API route support: https://nextjs.org/docs/api-routes/introduction 2 | 3 | export default function handler(_req, res) { 4 | res.status(200).json({ name: "John Doe" }); 5 | } 6 | -------------------------------------------------------------------------------- /cron-api-nyt/pages/_app.tsx: -------------------------------------------------------------------------------- 1 | import '../styles/globals.css' 2 | import type { AppProps } from 'next/app' 3 | 4 | export default function App({ Component, pageProps }: AppProps) { 5 | return 6 | } 7 | -------------------------------------------------------------------------------- /fly.io/go/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:1.18 2 | 3 | WORKDIR /flyio-qstash 4 | 5 | COPY go.sum go.mod ./ 6 | RUN go mod download 7 | 8 | 9 | 10 | COPY . . 11 | 12 | 13 | RUN go build -o bin/app ./main.go 14 | 15 | 16 | 17 | CMD ["bin/app"] -------------------------------------------------------------------------------- /periodic-data-updates/next-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | // NOTE: This file should not be edited 5 | // see https://nextjs.org/docs/basic-features/typescript for more information. 6 | -------------------------------------------------------------------------------- /periodic-data-updates/components/ReadBlogPost.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | export default function ReadBlogPost({ 4 | children, 5 | }: { 6 | children: React.ReactNode; 7 | }) { 8 | return
{children}
; 9 | } 10 | -------------------------------------------------------------------------------- /aws-lambda/python-example/Makefile: -------------------------------------------------------------------------------- 1 | zip: 2 | rm -rf dist 3 | pip3 install --target ./dist pyjwt 4 | cp lambda_function.py ./dist/lambda_function.py 5 | cd dist && zip -r lambda.zip . 6 | mv ./dist/lambda.zip ./ 7 | 8 | 9 | deploy: zip 10 | aws lambda update-function-code --function-name sdks-qstash-quickstart-python --zip-file fileb://./lambda.zip -------------------------------------------------------------------------------- /vercel-nextjs/styles/globals.css: -------------------------------------------------------------------------------- 1 | html, 2 | body { 3 | padding: 0; 4 | margin: 0; 5 | font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, 6 | Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif; 7 | } 8 | 9 | a { 10 | color: inherit; 11 | text-decoration: none; 12 | } 13 | 14 | * { 15 | box-sizing: border-box; 16 | } 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | **/node_modules 2 | 3 | /.next/ 4 | /out/ 5 | dist/ 6 | 7 | # production 8 | /build 9 | 10 | # misc 11 | .DS_Store 12 | *.pem 13 | 14 | # debug 15 | npm-debug.log* 16 | yarn-debug.log* 17 | yarn-error.log* 18 | .pnpm-debug.log* 19 | 20 | # local env files 21 | .env 22 | 23 | # vercel 24 | .vercel 25 | 26 | 27 | package-lock.json 28 | yarn.lock 29 | pnpm-lock.yaml 30 | 31 | -------------------------------------------------------------------------------- /cron-api-nyt/pages/api/hello.ts: -------------------------------------------------------------------------------- 1 | // Next.js API route support: https://nextjs.org/docs/api-routes/introduction 2 | import type { NextApiRequest, NextApiResponse } from 'next' 3 | 4 | type Data = { 5 | name: string 6 | } 7 | 8 | export default function handler( 9 | req: NextApiRequest, 10 | res: NextApiResponse 11 | ) { 12 | res.status(200).json({ name: 'John Doe' }) 13 | } 14 | -------------------------------------------------------------------------------- /cloudflare-workers/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cloudflare-workers", 3 | "version": "0.0.0", 4 | "devDependencies": { 5 | "@cloudflare/workers-types": "^3.14.1", 6 | "typescript": "^4.7.4", 7 | "wrangler": "2.0.17" 8 | }, 9 | "private": true, 10 | "scripts": { 11 | "start": "wrangler dev", 12 | "deploy": "wrangler publish" 13 | }, 14 | "dependencies": { 15 | "@upstash/qstash": "^0.1.2" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /vercel-nextjs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vercel-nextjs", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build": "next build", 8 | "start": "next start", 9 | "lint": "next lint" 10 | }, 11 | "dependencies": { 12 | "@upstash/qstash": "^0.1.1", 13 | "next": "12.2.2", 14 | "react": "18.2.0", 15 | "react-dom": "18.2.0" 16 | }, 17 | "devDependencies": { 18 | "eslint": "8.19.0", 19 | "eslint-config-next": "12.2.2" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /cron-api-nyt/styles/globals.css: -------------------------------------------------------------------------------- 1 | html, 2 | body { 3 | padding: 0; 4 | margin: 0; 5 | font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, 6 | Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif; 7 | } 8 | 9 | a { 10 | color: inherit; 11 | text-decoration: none; 12 | } 13 | 14 | * { 15 | box-sizing: border-box; 16 | } 17 | 18 | @media (prefers-color-scheme: dark) { 19 | html { 20 | color-scheme: dark; 21 | } 22 | body { 23 | color: white; 24 | background: black; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /vercel-nextjs/pages/api/qstash.js: -------------------------------------------------------------------------------- 1 | import { verifySignature } from "@upstash/qstash/nextjs"; 2 | 3 | function handler(_req, res) { 4 | console.log("If this is printed, the signature has already been verified"); 5 | 6 | // do stuff 7 | 8 | res.status(200).end(); 9 | } 10 | 11 | /** 12 | * verifySignature will try to load `QSTASH_CURRENT_SIGNING_KEY` and `QSTASH_NEXT_SIGNING_KEY` from the environment. 13 | */ 14 | export default verifySignature(handler); 15 | 16 | export const config = { 17 | api: { 18 | bodyParser: false, 19 | }, 20 | }; 21 | -------------------------------------------------------------------------------- /periodic-data-updates/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # next.js 12 | /.next/ 13 | /out/ 14 | 15 | # production 16 | /build 17 | 18 | # misc 19 | .DS_Store 20 | *.pem 21 | 22 | # debug 23 | npm-debug.log* 24 | yarn-debug.log* 25 | yarn-error.log* 26 | .pnpm-debug.log* 27 | 28 | # local env files 29 | .env*.local 30 | 31 | # vercel 32 | .vercel 33 | 34 | # typescript 35 | *.tsbuildinfo 36 | -------------------------------------------------------------------------------- /with-novu/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # next.js 12 | /.next/ 13 | /out/ 14 | 15 | # production 16 | /build 17 | 18 | # misc 19 | .DS_Store 20 | *.pem 21 | 22 | # debug 23 | npm-debug.log* 24 | yarn-debug.log* 25 | yarn-error.log* 26 | .pnpm-debug.log* 27 | 28 | # local env files 29 | .env*.local 30 | 31 | # vercel 32 | .vercel 33 | 34 | # typescript 35 | *.tsbuildinfo 36 | next-env.d.ts 37 | -------------------------------------------------------------------------------- /cron-api-nyt/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # next.js 12 | /.next/ 13 | /out/ 14 | 15 | # production 16 | /build 17 | 18 | # misc 19 | .DS_Store 20 | *.pem 21 | 22 | # debug 23 | npm-debug.log* 24 | yarn-debug.log* 25 | yarn-error.log* 26 | .pnpm-debug.log* 27 | 28 | # local env files 29 | .env*.local 30 | 31 | # vercel 32 | .vercel 33 | 34 | # typescript 35 | *.tsbuildinfo 36 | next-env.d.ts 37 | -------------------------------------------------------------------------------- /with-novu/pages/_app.tsx: -------------------------------------------------------------------------------- 1 | import type { AppProps } from 'next/app' 2 | import { 3 | NovuProvider, 4 | PopoverNotificationCenter, 5 | NotificationBell, 6 | IMessage, 7 | } from '@novu/notification-center'; 8 | import { useRouter } from 'next/router'; 9 | import { GeistProvider, CssBaseline } from '@geist-ui/core' 10 | 11 | 12 | function MyApp({ Component, pageProps }: AppProps) { 13 | 14 | return ( 15 | 16 | 17 | 18 | 19 | 20 | ) 21 | } 22 | 23 | export default MyApp 24 | -------------------------------------------------------------------------------- /periodic-data-updates/tailwind.config.js: -------------------------------------------------------------------------------- 1 | const colors = require("tailwindcss/colors"); 2 | 3 | module.exports = { 4 | content: [ 5 | "./pages/**/*.{js,ts,jsx,tsx}", 6 | "./components/**/*.{js,ts,jsx,tsx}", 7 | ], 8 | theme: { 9 | extend: { 10 | colors: { 11 | gray: colors.zinc, 12 | primary: colors.emerald, 13 | }, 14 | }, 15 | }, 16 | plugins: [ 17 | require("@tailwindcss/forms")({ 18 | strategy: "base", // only generate global styles 19 | // strategy: "class", // only generate classes 20 | }), 21 | ], 22 | }; 23 | -------------------------------------------------------------------------------- /with-novu/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "strict": true, 8 | "forceConsistentCasingInFileNames": true, 9 | "noEmit": true, 10 | "esModuleInterop": true, 11 | "module": "esnext", 12 | "moduleResolution": "node", 13 | "resolveJsonModule": true, 14 | "isolatedModules": true, 15 | "jsx": "preserve", 16 | "incremental": true 17 | }, 18 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"], 19 | "exclude": ["node_modules"] 20 | } 21 | -------------------------------------------------------------------------------- /cron-api-nyt/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "strict": true, 8 | "forceConsistentCasingInFileNames": true, 9 | "noEmit": true, 10 | "esModuleInterop": true, 11 | "module": "esnext", 12 | "moduleResolution": "node", 13 | "resolveJsonModule": true, 14 | "isolatedModules": true, 15 | "jsx": "preserve", 16 | "incremental": true 17 | }, 18 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"], 19 | "exclude": ["node_modules"] 20 | } 21 | -------------------------------------------------------------------------------- /cron-api-nyt/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cron-api-nyt", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build": "next build", 8 | "start": "next start", 9 | "lint": "next lint" 10 | }, 11 | "dependencies": { 12 | "@types/node": "18.11.9", 13 | "@types/react": "18.0.25", 14 | "@types/react-dom": "18.0.8", 15 | "@upstash/qstash": "^0.3.0", 16 | "eslint": "8.27.0", 17 | "eslint-config-next": "13.0.3", 18 | "next": "13.0.3", 19 | "react": "18.2.0", 20 | "react-dom": "18.2.0", 21 | "typescript": "4.8.4" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /periodic-data-updates/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "strict": true, 8 | "forceConsistentCasingInFileNames": true, 9 | "noEmit": true, 10 | "esModuleInterop": true, 11 | "module": "esnext", 12 | "moduleResolution": "node", 13 | "resolveJsonModule": true, 14 | "isolatedModules": true, 15 | "jsx": "preserve", 16 | "incremental": true, 17 | "baseUrl": "." 18 | }, 19 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"], 20 | "exclude": ["node_modules"] 21 | } 22 | -------------------------------------------------------------------------------- /periodic-data-updates/components/Header.tsx: -------------------------------------------------------------------------------- 1 | import { Breadcrumb, BreadcrumbProps } from "./Breadcrumb"; 2 | import StarButton from "./StarButton"; 3 | import React from "react"; 4 | 5 | export type HeaderProps = { 6 | breadcrumbOptions: BreadcrumbProps; 7 | }; 8 | 9 | export default function Header({ breadcrumbOptions }: HeaderProps) { 10 | return ( 11 |
12 | 13 |
14 | 15 |
16 |
17 | ); 18 | } 19 | -------------------------------------------------------------------------------- /aws-lambda/typescript-example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "aws-lambda-container", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "build": "rm -rf dist && esbuild index.ts --bundle --minify --sourcemap --platform=node --target=es2020 --outfile=dist/index.js", 8 | "push": "cd dist && zip -r index.zip index.js* && aws lambda update-function-code --function-name sdks-qstash-quickstart-typescript --zip-file fileb://index.zip" 9 | }, 10 | "keywords": [], 11 | "author": "Andreas Thomas", 12 | "license": "ISC", 13 | "devDependencies": { 14 | "@types/aws-lambda": "^8.10.101", 15 | "@types/node": "^18.0.4", 16 | "esbuild": "^0.14.49" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /with-novu/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "my-app", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build": "next build", 8 | "start": "next start", 9 | "lint": "next lint" 10 | }, 11 | "dependencies": { 12 | "@geist-ui/core": "^2.3.8", 13 | "@geist-ui/icons": "^1.0.2", 14 | "@novu/node": "^0.7.2", 15 | "@novu/notification-center": "^0.7.3", 16 | "@upstash/qstash": "^0.1.7", 17 | "next": "12.2.5", 18 | "react": "18.2.0", 19 | "react-dom": "18.2.0" 20 | }, 21 | "devDependencies": { 22 | "@types/node": "18.7.15", 23 | "@types/react": "18.0.18", 24 | "@types/react-dom": "18.0.6", 25 | "eslint": "8.23.0", 26 | "eslint-config-next": "12.2.5", 27 | "typescript": "4.8.2" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /with-novu/lib/useUserId.tsx: -------------------------------------------------------------------------------- 1 | import { useState } from "react" 2 | 3 | export const useUserId: () => [string, (s: string) => void] = () => { 4 | const key = "qstash+novuhq:userId" 5 | 6 | const [userId, setUserId] = useState(() => { 7 | if (typeof window === "undefined") { 8 | return "" 9 | } 10 | return window.localStorage.getItem(key) ?? Math.random().toFixed(10) 11 | 12 | }) 13 | 14 | const setValue = (value: string) => { 15 | if (typeof window === "undefined") { 16 | return 17 | } 18 | setUserId(value) 19 | try { 20 | 21 | window.localStorage.setItem(key, value) 22 | } catch (err) { 23 | console.error(err) 24 | } 25 | } 26 | 27 | 28 | return [userId, setValue] 29 | 30 | 31 | } -------------------------------------------------------------------------------- /deno-deploy/index.ts: -------------------------------------------------------------------------------- 1 | import { serve } from "https://deno.land/std@0.142.0/http/server.ts"; 2 | import { Receiver } from "https://deno.land/x/upstash_qstash@v0.1.4/mod.ts"; 3 | 4 | serve(async (req: Request) => { 5 | const r = new Receiver({ 6 | currentSigningKey: Deno.env.get("QSTASH_CURRENT_SIGNING_KEY")!, 7 | nextSigningKey: Deno.env.get("QSTASH_NEXT_SIGNING_KEY")!, 8 | }); 9 | 10 | const isValid = await r.verify({ 11 | signature: req.headers.get("Upstash-Signature")!, 12 | body: await req.text(), 13 | }).catch((err: Error) => { 14 | console.error(err); 15 | return false; 16 | }); 17 | 18 | if (!isValid) { 19 | return new Response("Invalid signature", { status: 401 }); 20 | } 21 | 22 | console.log("The signature was valid"); 23 | 24 | // do work 25 | 26 | return new Response("OK", { status: 200 }); 27 | }); 28 | -------------------------------------------------------------------------------- /periodic-data-updates/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "scheduled-fetch", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build": "next build", 8 | "start": "next start", 9 | "lint": "next lint" 10 | }, 11 | "dependencies": { 12 | "@ant-design/plots": "^1.2.0", 13 | "@upstash/qstash": "^0.1.6", 14 | "@upstash/redis": "^1.10.2", 15 | "next": "12.2.3", 16 | "react": "18.2.0", 17 | "react-dom": "18.2.0" 18 | }, 19 | "devDependencies": { 20 | "@tailwindcss/forms": "^0.5.2", 21 | "@types/node": "18.6.1", 22 | "@types/react": "18.0.15", 23 | "@types/react-dom": "18.0.6", 24 | "autoprefixer": "^10.4.7", 25 | "eslint": "8.20.0", 26 | "eslint-config-next": "12.2.3", 27 | "postcss": "^8.4.14", 28 | "tailwindcss": "^3.1.6", 29 | "typescript": "4.7.4" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /fly.io/go/fly.toml: -------------------------------------------------------------------------------- 1 | # fly.toml file generated for winter-cherry-9545 on 2022-07-15T15:03:47+02:00 2 | 3 | app = "winter-cherry-9545" 4 | kill_signal = "SIGINT" 5 | kill_timeout = 5 6 | processes = [] 7 | 8 | [env] 9 | 10 | [experimental] 11 | allowed_public_ports = [] 12 | auto_rollback = true 13 | 14 | [[services]] 15 | http_checks = [] 16 | internal_port = 8080 17 | processes = ["app"] 18 | protocol = "tcp" 19 | script_checks = [] 20 | [services.concurrency] 21 | hard_limit = 25 22 | soft_limit = 20 23 | type = "connections" 24 | 25 | [[services.ports]] 26 | force_https = true 27 | handlers = ["http"] 28 | port = 80 29 | 30 | [[services.ports]] 31 | handlers = ["tls", "http"] 32 | port = 443 33 | 34 | [[services.tcp_checks]] 35 | grace_period = "1s" 36 | interval = "15s" 37 | restart_limit = 0 38 | timeout = "2s" 39 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # qStash examples 2 | 3 | This repo is depracated, see https://github.com/upstash/examples/tree/main/examples 4 | 5 | ## aws-lambda 6 | 7 | [Documentation](https://docs.upstash.com/qstash/quickstarts/aws-lambda/qstash/quickstarts/aws-lambda/nodejs) 8 | 9 | ## cloudflare-workers 10 | 11 | [Documentation](https://docs.upstash.com/qstash/quickstarts/cloudflare-workers) 12 | 13 | ## deno-deploy 14 | 15 | [Documentation](https://docs.upstash.com/qstash/quickstarts/deno-deploy) 16 | 17 | ## vercel-nextjs 18 | 19 | [Documentation](https://docs.upstash.com/qstash/quickstarts/vercel-nextjs) 20 | 21 | ## fly.io-go 22 | 23 | [Documentation](https://docs.upstash.com/qstash/quickstarts/fly-io/go) 24 | 25 | 26 | ## Periodic Data Updates with Next.js and Vercel Serverless Functions 27 | 28 | [Recipe](https://docs.upstash.com/qstash/recipes/periodic-data-updates) 29 | 30 | ### For internal use, please ignore: 31 | 32 | team id: 4516a528-415d-4263-bc11-1fe509d03e68 33 | -------------------------------------------------------------------------------- /periodic-data-updates/components/StarButton.tsx: -------------------------------------------------------------------------------- 1 | export type StarButtonProps = { 2 | url?: string; 3 | }; 4 | 5 | export default function StarButton({ url }: StarButtonProps) { 6 | if (!url) { 7 | return null; 8 | } 9 | 10 | return ( 11 | 17 | 18 | 23 | 24 | 25 | Star on GitHub 26 | 27 | ); 28 | } 29 | -------------------------------------------------------------------------------- /cloudflare-workers/src/index.ts: -------------------------------------------------------------------------------- 1 | import { Receiver } from "@upstash/qstash/cloudflare"; 2 | export interface Env { 3 | QSTASH_CURRENT_SIGNING_KEY: string; 4 | QSTASH_NEXT_SIGNING_KEY: string; 5 | } 6 | 7 | export default { 8 | async fetch( 9 | request: Request, 10 | env: Env, 11 | _ctx: ExecutionContext, 12 | ): Promise { 13 | const c = new Receiver({ 14 | currentSigningKey: env.QSTASH_CURRENT_SIGNING_KEY, 15 | nextSigningKey: env.QSTASH_NEXT_SIGNING_KEY, 16 | }); 17 | 18 | const body = await request.text(); 19 | 20 | const isValid = await c.verify({ 21 | signature: request.headers.get("Upstash-Signature")!, 22 | body, 23 | }).catch((err) => { 24 | console.error(err); 25 | return false; 26 | }); 27 | if (!isValid) { 28 | return new Response("Invalid signature", { status: 401 }); 29 | } 30 | console.log("The signature was valid"); 31 | 32 | // do work here 33 | 34 | return new Response("Hello World!"); 35 | }, 36 | }; 37 | -------------------------------------------------------------------------------- /fly.io/go/fly.original.toml: -------------------------------------------------------------------------------- 1 | # fly.toml file generated for divine-wildflower-7402 on 2022-07-15T13:59:38+02:00 2 | 3 | app = "divine-wildflower-7402" 4 | kill_signal = "SIGINT" 5 | kill_timeout = 5 6 | processes = [] 7 | 8 | [build] 9 | builder = "paketobuildpacks/builder:base" 10 | buildpacks = ["gcr.io/paketo-buildpacks/go"] 11 | 12 | [env] 13 | PORT = "8080" 14 | 15 | [experimental] 16 | allowed_public_ports = [] 17 | auto_rollback = true 18 | 19 | [[services]] 20 | http_checks = [] 21 | internal_port = 8080 22 | processes = ["app"] 23 | protocol = "tcp" 24 | script_checks = [] 25 | [services.concurrency] 26 | hard_limit = 25 27 | soft_limit = 20 28 | type = "connections" 29 | 30 | [[services.ports]] 31 | force_https = true 32 | handlers = ["http"] 33 | port = 80 34 | 35 | [[services.ports]] 36 | handlers = ["tls", "http"] 37 | port = 443 38 | 39 | [[services.tcp_checks]] 40 | grace_period = "1s" 41 | interval = "15s" 42 | restart_limit = 0 43 | timeout = "2s" 44 | -------------------------------------------------------------------------------- /cron-api-nyt/public/vercel.svg: -------------------------------------------------------------------------------- 1 | 3 | 4 | -------------------------------------------------------------------------------- /vercel-nextjs/public/vercel.svg: -------------------------------------------------------------------------------- 1 | 3 | 4 | -------------------------------------------------------------------------------- /periodic-data-updates/public/vercel.svg: -------------------------------------------------------------------------------- 1 | 3 | 4 | -------------------------------------------------------------------------------- /cron-api-nyt/pages/api/callback.ts: -------------------------------------------------------------------------------- 1 | import type { NextApiRequest, NextApiResponse } from "next"; 2 | import { verifySignature } from "@upstash/qstash/nextjs"; 3 | 4 | const botConfig = { 5 | name: "Best of NYTimes Bot", 6 | url: "https://picsum.photos/200", // random image 7 | }; 8 | 9 | async function sendMessage(json: any) { 10 | return fetch(process.env.DISCORD_WEBHOOK!, { 11 | method: "POST", 12 | headers: { 13 | "Content-Type": "application/json", 14 | }, 15 | body: JSON.stringify({ 16 | username: botConfig.name, 17 | avatar_url: botConfig.url, 18 | // use only the five most popular articles of the day 19 | embeds: json.results.slice(0, 5).map((article: any) => { 20 | return { 21 | title: article.title, 22 | description: article.abstract, 23 | url: article.url, 24 | }; 25 | }), 26 | }), 27 | }); 28 | } 29 | 30 | async function handler(req: NextApiRequest, res: NextApiResponse) { 31 | try { 32 | const decoded = Buffer.from(req.body.body, "base64"); 33 | const json = JSON.parse(decoded.toString()); 34 | const result = await sendMessage(json); 35 | if (!result.ok) { 36 | return res.status(500).end(); 37 | } 38 | return res.status(201).end(); 39 | } catch (e) { 40 | return res.status(500).end(e); 41 | } 42 | } 43 | 44 | export const config = { 45 | api: { 46 | bodyParser: false, 47 | }, 48 | }; 49 | 50 | export default verifySignature(handler); 51 | -------------------------------------------------------------------------------- /periodic-data-updates/pages/_app.tsx: -------------------------------------------------------------------------------- 1 | import "styles/globals.css"; 2 | 3 | import React from "react"; 4 | import type { AppProps } from "next/app"; 5 | import Header from "components/Header"; 6 | import Head from "next/head"; 7 | 8 | function MyApp({ Component, pageProps }: AppProps) { 9 | return ( 10 | <> 11 | 12 | Create Next App 13 | 14 | 15 | 16 |
31 | 32 | { 33 | /* 34 | This is a sample project for the blogpost{" "} 35 | 41 | Example Post 42 | 43 | */ 44 | } 45 | 46 |
47 | 48 |
49 | 50 | ); 51 | } 52 | 53 | export default MyApp; 54 | -------------------------------------------------------------------------------- /periodic-data-updates/styles/globals.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | @layer base { 6 | body { 7 | @apply antialiased text-gray-900; 8 | } 9 | 10 | a { 11 | @apply transition; 12 | } 13 | 14 | pre { 15 | @apply bg-gray-800 text-gray-50 p-6 rounded-lg text-sm; 16 | } 17 | } 18 | 19 | @layer components { 20 | button { 21 | @apply flex 22 | items-center 23 | px-4 24 | py-2 25 | font-semibold 26 | rounded 27 | bg-emerald-500 28 | text-white 29 | hover:bg-emerald-600 30 | focus:outline-none 31 | focus:ring-2 32 | focus:ring-primary-200 33 | focus:ring-offset-2; 34 | } 35 | 36 | [type="text"], 37 | [type="email"], 38 | [type="url"], 39 | [type="password"], 40 | [type="number"], 41 | [type="date"], 42 | [type="datetime-local"], 43 | [type="month"], 44 | [type="search"], 45 | [type="tel"], 46 | [type="time"], 47 | [type="week"], 48 | textarea, 49 | select { 50 | @apply rounded 51 | shadow-sm 52 | border-gray-300 53 | focus:ring 54 | focus:ring-primary-200 55 | focus:ring-opacity-50 56 | focus:border-primary-300; 57 | } 58 | 59 | [type="checkbox"], 60 | [type="radio"] { 61 | @apply w-5 62 | h-5 63 | text-primary-500 64 | border-gray-300 65 | focus:ring 66 | focus:ring-offset-0 67 | focus:ring-primary-200 68 | focus:ring-opacity-50 69 | focus:border-primary-300; 70 | } 71 | 72 | [type="checkbox"] { 73 | @apply rounded 74 | shadow-sm; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /with-novu/README.md: -------------------------------------------------------------------------------- 1 | This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app). 2 | 3 | ## Getting Started 4 | 5 | First, run the development server: 6 | 7 | ```bash 8 | npm run dev 9 | # or 10 | yarn dev 11 | ``` 12 | 13 | Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. 14 | 15 | You can start editing the page by modifying `pages/index.tsx`. The page auto-updates as you edit the file. 16 | 17 | [API routes](https://nextjs.org/docs/api-routes/introduction) can be accessed on [http://localhost:3000/api/hello](http://localhost:3000/api/hello). This endpoint can be edited in `pages/api/hello.ts`. 18 | 19 | The `pages/api` directory is mapped to `/api/*`. Files in this directory are treated as [API routes](https://nextjs.org/docs/api-routes/introduction) instead of React pages. 20 | 21 | ## Learn More 22 | 23 | To learn more about Next.js, take a look at the following resources: 24 | 25 | - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. 26 | - [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. 27 | 28 | You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome! 29 | 30 | ## Deploy on Vercel 31 | 32 | The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. 33 | 34 | Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details. 35 | -------------------------------------------------------------------------------- /cron-api-nyt/README.md: -------------------------------------------------------------------------------- 1 | This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app). 2 | 3 | ## Getting Started 4 | 5 | First, run the development server: 6 | 7 | ```bash 8 | npm run dev 9 | # or 10 | yarn dev 11 | ``` 12 | 13 | Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. 14 | 15 | You can start editing the page by modifying `pages/index.tsx`. The page auto-updates as you edit the file. 16 | 17 | [API routes](https://nextjs.org/docs/api-routes/introduction) can be accessed on [http://localhost:3000/api/hello](http://localhost:3000/api/hello). This endpoint can be edited in `pages/api/hello.ts`. 18 | 19 | The `pages/api` directory is mapped to `/api/*`. Files in this directory are treated as [API routes](https://nextjs.org/docs/api-routes/introduction) instead of React pages. 20 | 21 | ## Learn More 22 | 23 | To learn more about Next.js, take a look at the following resources: 24 | 25 | - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. 26 | - [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. 27 | 28 | You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome! 29 | 30 | ## Deploy on Vercel 31 | 32 | The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. 33 | 34 | Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details. 35 | -------------------------------------------------------------------------------- /with-novu/pages/api/task/add.ts: -------------------------------------------------------------------------------- 1 | import { NextApiRequest, NextApiResponse } from "next"; 2 | import { Novu } from '@novu/node'; 3 | import { Client } from "@upstash/qstash" 4 | import assert from "assert"; 5 | import { randomUUID } from "crypto"; 6 | 7 | export type AddRequest = { 8 | userId: string 9 | x: number 10 | y: number 11 | } 12 | export type AddResponse = { 13 | taskId: string 14 | } 15 | export type ErrorResponse = { 16 | error: string 17 | } 18 | 19 | 20 | 21 | export default async function (req: NextApiRequest, res: NextApiResponse): Promise { 22 | try { 23 | 24 | const novuApiKey = process.env.NOVU_API_KEY; 25 | assert(novuApiKey, "NOVU_API_KEY is not defined") 26 | const qstashToken = process.env.QSTASH_TOKEN; 27 | assert(qstashToken, "QSTASH_TOKEN is not defined"); 28 | 29 | const novu = new Novu(novuApiKey) 30 | const qstash = new Client({ 31 | token: qstashToken, 32 | }) 33 | 34 | const { userId, x, y } = req.body as AddRequest 35 | const taskId = randomUUID() 36 | 37 | await qstash.publishJSON({ 38 | url: `https://${process.env.VERCEL_URL}/api/task/process`, 39 | retries: 3, 40 | body: { 41 | taskId, 42 | userId, 43 | x, 44 | y, 45 | } 46 | }) 47 | 48 | res.status(201) 49 | res.json({ taskId }) 50 | return 51 | 52 | } catch (error) { 53 | console.error((error as Error).message) 54 | res.status(500).json({ error: (error as Error).message }) 55 | } finally { 56 | res.end() 57 | } 58 | } 59 | 60 | 61 | -------------------------------------------------------------------------------- /vercel-nextjs/README.md: -------------------------------------------------------------------------------- 1 | This is a [Next.js](https://nextjs.org/) project bootstrapped with 2 | [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app). 3 | 4 | ## Getting Started 5 | 6 | First, run the development server: 7 | 8 | ```bash 9 | npm run dev 10 | # or 11 | yarn dev 12 | ``` 13 | 14 | Open [http://localhost:3000](http://localhost:3000) with your browser to see the 15 | result. 16 | 17 | You can start editing the page by modifying `pages/index.js`. The page 18 | auto-updates as you edit the file. 19 | 20 | [API routes](https://nextjs.org/docs/api-routes/introduction) can be accessed on 21 | [http://localhost:3000/api/hello](http://localhost:3000/api/hello). This 22 | endpoint can be edited in `pages/api/hello.js`. 23 | 24 | The `pages/api` directory is mapped to `/api/*`. Files in this directory are 25 | treated as [API routes](https://nextjs.org/docs/api-routes/introduction) instead 26 | of React pages. 27 | 28 | ## Learn More 29 | 30 | To learn more about Next.js, take a look at the following resources: 31 | 32 | - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js 33 | features and API. 34 | - [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. 35 | 36 | You can check out 37 | [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your 38 | feedback and contributions are welcome! 39 | 40 | ## Deploy on Vercel 41 | 42 | The easiest way to deploy your Next.js app is to use the 43 | [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) 44 | from the creators of Next.js. 45 | 46 | Check out our 47 | [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more 48 | details. 49 | -------------------------------------------------------------------------------- /periodic-data-updates/README.md: -------------------------------------------------------------------------------- 1 | This is a [Next.js](https://nextjs.org/) project bootstrapped with 2 | [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app). 3 | 4 | ## Getting Started 5 | 6 | First, run the development server: 7 | 8 | ```bash 9 | npm run dev 10 | # or 11 | yarn dev 12 | ``` 13 | 14 | Open [http://localhost:3000](http://localhost:3000) with your browser to see the 15 | result. 16 | 17 | You can start editing the page by modifying `pages/index.tsx`. The page 18 | auto-updates as you edit the file. 19 | 20 | [API routes](https://nextjs.org/docs/api-routes/introduction) can be accessed on 21 | [http://localhost:3000/api/hello](http://localhost:3000/api/hello). This 22 | endpoint can be edited in `pages/api/hello.ts`. 23 | 24 | The `pages/api` directory is mapped to `/api/*`. Files in this directory are 25 | treated as [API routes](https://nextjs.org/docs/api-routes/introduction) instead 26 | of React pages. 27 | 28 | ## Learn More 29 | 30 | To learn more about Next.js, take a look at the following resources: 31 | 32 | - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js 33 | features and API. 34 | - [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. 35 | 36 | You can check out 37 | [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your 38 | feedback and contributions are welcome! 39 | 40 | ## Deploy on Vercel 41 | 42 | The easiest way to deploy your Next.js app is to use the 43 | [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) 44 | from the creators of Next.js. 45 | 46 | Check out our 47 | [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more 48 | details. 49 | -------------------------------------------------------------------------------- /periodic-data-updates/pages/api/cron.ts: -------------------------------------------------------------------------------- 1 | // @@@SNIPSTART qstash-periodic-data-updates-api 2 | 3 | import { NextApiRequest, NextApiResponse } from "next"; 4 | import { Redis } from "@upstash/redis"; 5 | 6 | import { verifySignature } from "@upstash/qstash/nextjs"; 7 | 8 | /** 9 | * You can use any database you want, in this case we use Redis 10 | */ 11 | const redis = Redis.fromEnv(); 12 | 13 | /** 14 | * Load the current bitcoin price in USD and store it in our database at the 15 | * current timestamp 16 | */ 17 | async function handler(_req: NextApiRequest, res: NextApiResponse) { 18 | try { 19 | /** 20 | * The API returns something like this: 21 | * ```json 22 | * { 23 | * "USD": { 24 | * "last": 123 25 | * }, 26 | * ... 27 | * } 28 | * ``` 29 | */ 30 | const raw = await fetch("https://blockchain.info/ticker"); 31 | const prices = await raw.json(); 32 | const bitcoinPrice = prices["USD"]["last"] as number; 33 | 34 | /** 35 | * After we have loaded the current bitcoin price, we can store it in the 36 | * database together with the current time 37 | */ 38 | await redis.zadd("bitcoin-prices", { 39 | score: Date.now(), 40 | member: bitcoinPrice, 41 | }); 42 | 43 | res.send("OK"); 44 | } catch (err) { 45 | res.status(500).send(err); 46 | } finally { 47 | res.end(); 48 | } 49 | } 50 | 51 | /** 52 | * Wrap your handler with `verifySignature` to automatically reject all 53 | * requests that are not coming from Upstash. 54 | */ 55 | export default verifySignature(handler); 56 | 57 | /** 58 | * To verify the authenticity of the incoming request in the `verifySignature` 59 | * function, we need access to the raw request body. 60 | */ 61 | export const config = { 62 | api: { 63 | bodyParser: false, 64 | }, 65 | }; 66 | 67 | // @@@SNIPEND 68 | -------------------------------------------------------------------------------- /vercel-nextjs/styles/Home.module.css: -------------------------------------------------------------------------------- 1 | .container { 2 | padding: 0 2rem; 3 | } 4 | 5 | .main { 6 | min-height: 100vh; 7 | padding: 4rem 0; 8 | flex: 1; 9 | display: flex; 10 | flex-direction: column; 11 | justify-content: center; 12 | align-items: center; 13 | } 14 | 15 | .footer { 16 | display: flex; 17 | flex: 1; 18 | padding: 2rem 0; 19 | border-top: 1px solid #eaeaea; 20 | justify-content: center; 21 | align-items: center; 22 | } 23 | 24 | .footer a { 25 | display: flex; 26 | justify-content: center; 27 | align-items: center; 28 | flex-grow: 1; 29 | } 30 | 31 | .title a { 32 | color: #0070f3; 33 | text-decoration: none; 34 | } 35 | 36 | .title a:hover, 37 | .title a:focus, 38 | .title a:active { 39 | text-decoration: underline; 40 | } 41 | 42 | .title { 43 | margin: 0; 44 | line-height: 1.15; 45 | font-size: 4rem; 46 | } 47 | 48 | .title, 49 | .description { 50 | text-align: center; 51 | } 52 | 53 | .description { 54 | margin: 4rem 0; 55 | line-height: 1.5; 56 | font-size: 1.5rem; 57 | } 58 | 59 | .code { 60 | background: #fafafa; 61 | border-radius: 5px; 62 | padding: 0.75rem; 63 | font-size: 1.1rem; 64 | font-family: Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono, 65 | Bitstream Vera Sans Mono, Courier New, monospace; 66 | } 67 | 68 | .grid { 69 | display: flex; 70 | align-items: center; 71 | justify-content: center; 72 | flex-wrap: wrap; 73 | max-width: 800px; 74 | } 75 | 76 | .card { 77 | margin: 1rem; 78 | padding: 1.5rem; 79 | text-align: left; 80 | color: inherit; 81 | text-decoration: none; 82 | border: 1px solid #eaeaea; 83 | border-radius: 10px; 84 | transition: color 0.15s ease, border-color 0.15s ease; 85 | max-width: 300px; 86 | } 87 | 88 | .card:hover, 89 | .card:focus, 90 | .card:active { 91 | color: #0070f3; 92 | border-color: #0070f3; 93 | } 94 | 95 | .card h2 { 96 | margin: 0 0 1rem 0; 97 | font-size: 1.5rem; 98 | } 99 | 100 | .card p { 101 | margin: 0; 102 | font-size: 1.25rem; 103 | line-height: 1.5; 104 | } 105 | 106 | .logo { 107 | height: 1em; 108 | margin-left: 0.5rem; 109 | } 110 | 111 | @media (max-width: 600px) { 112 | .grid { 113 | width: 100%; 114 | flex-direction: column; 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /with-novu/pages/api/task/process.ts: -------------------------------------------------------------------------------- 1 | import { Novu } from "@novu/node"; 2 | import { verifySignature } from "@upstash/qstash/nextjs"; 3 | import assert from "assert"; 4 | import { NextApiRequest, NextApiResponse } from "next"; 5 | 6 | 7 | async function handler(req: NextApiRequest, res: NextApiResponse) { 8 | try { 9 | 10 | 11 | const { userId, x, y } = req.body as { userId: string, taskId: string, x: number, y: number } 12 | 13 | const novuApiKey = process.env.NOVU_API_KEY; 14 | assert(novuApiKey, "NOVU_API_KEY is not defined") 15 | const novu = new Novu(novuApiKey) 16 | 17 | const rng = Math.random() 18 | const success = rng > 0.5 19 | 20 | if (success) { 21 | const data = { 22 | to: { 23 | subscriberId: userId 24 | }, 25 | payload: { 26 | x: x.toString(), 27 | y: y.toString(), 28 | result: (x + y).toString() 29 | } 30 | } 31 | console.log({ data }) 32 | const ntr = await novu.trigger('add.success', data).catch(err => { 33 | throw new Error(`Novu error: ${err.message}`) 34 | }) 35 | console.log(JSON.stringify(ntr.data, null, 2)) 36 | 37 | return res.send("ok") 38 | 39 | } 40 | 41 | if (!success) { 42 | const error = "simulated error" 43 | const ntr = await novu.trigger('add.failure', { 44 | to: { 45 | subscriberId: userId 46 | }, 47 | payload: { 48 | x, 49 | y, 50 | error 51 | } 52 | }).catch(err => { 53 | throw new Error(`Novu error: ${err.message}`) 54 | }) 55 | console.log(JSON.stringify(ntr.data, null, 2)) 56 | return res.status(500).send(error) 57 | 58 | } 59 | 60 | } catch (error) { 61 | console.error((error as Error).message) 62 | res.status(500).json({ error: (error as Error).message }) 63 | } finally { 64 | res.end() 65 | } 66 | } 67 | 68 | export default verifySignature(handler); 69 | 70 | export const config = { 71 | api: { 72 | bodyParser: false, 73 | }, 74 | }; -------------------------------------------------------------------------------- /fly.io/go/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "crypto/sha256" 5 | "encoding/base64" 6 | "fmt" 7 | "github.com/golang-jwt/jwt/v4" 8 | "io" 9 | "net/http" 10 | "os" 11 | "time" 12 | ) 13 | 14 | func main() { 15 | port := os.Getenv("PORT") 16 | if port == "" { 17 | port = "8080" 18 | } 19 | 20 | http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { 21 | defer r.Body.Close() 22 | currentSigningKey := os.Getenv("QSTASH_CURRENT_SIGNING_KEY") 23 | nextSigningKey := os.Getenv("QSTASH_NEXT_SIGNING_KEY") 24 | tokenString := r.Header.Get("Upstash-Signature") 25 | body, err := io.ReadAll(r.Body) 26 | if err != nil { 27 | http.Error(w, err.Error(), http.StatusInternalServerError) 28 | return 29 | } 30 | 31 | err = verify(body, tokenString, currentSigningKey) 32 | if err != nil { 33 | fmt.Printf("Unable to verify signature with current signing key: %v", err) 34 | err = verify(body, tokenString, nextSigningKey) 35 | } 36 | 37 | if err != nil { 38 | http.Error(w, err.Error(), http.StatusUnauthorized) 39 | return 40 | } 41 | 42 | // handle your business logic here 43 | 44 | w.WriteHeader(http.StatusOK) 45 | 46 | }) 47 | 48 | fmt.Println("listening on", port) 49 | err := http.ListenAndServe(":"+port, nil) 50 | if err != nil { 51 | panic(err) 52 | } 53 | } 54 | 55 | func verify(body []byte, tokenString, signingKey string) error { 56 | 57 | token, err := jwt.Parse( 58 | tokenString, 59 | func(token *jwt.Token) (interface{}, error) { 60 | if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok { 61 | return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"]) 62 | } 63 | return []byte(signingKey), nil 64 | }) 65 | 66 | if err != nil { 67 | return err 68 | } 69 | 70 | claims, ok := token.Claims.(jwt.MapClaims) 71 | if !ok || !token.Valid { 72 | return fmt.Errorf("Invalid token") 73 | } 74 | 75 | if !claims.VerifyIssuer("Upstash", true) { 76 | return fmt.Errorf("invalid issuer") 77 | } 78 | if !claims.VerifyExpiresAt(time.Now().Unix(), true) { 79 | return fmt.Errorf("token has expired") 80 | } 81 | if !claims.VerifyNotBefore(time.Now().Unix(), true) { 82 | return fmt.Errorf("token is not valid yet") 83 | } 84 | 85 | bodyHash := sha256.Sum256(body) 86 | if claims["body"] != base64.URLEncoding.EncodeToString(bodyHash[:]) { 87 | return fmt.Errorf("body hash does not match") 88 | } 89 | 90 | return nil 91 | } 92 | -------------------------------------------------------------------------------- /periodic-data-updates/components/Breadcrumb.tsx: -------------------------------------------------------------------------------- 1 | import Image from "next/image"; 2 | import React from "react"; 3 | 4 | export type BreadcrumbItemProps = { 5 | name: string; 6 | url: string; 7 | }; 8 | 9 | export type BreadcrumbProps = { 10 | data: BreadcrumbItemProps[]; 11 | showRoot?: boolean; 12 | }; 13 | 14 | export function BreadcrumbDivider() { 15 | return /; 16 | } 17 | 18 | export function BreadcrumbItem({ url, name }: BreadcrumbItemProps) { 19 | return ( 20 | 26 | {name} 27 | 28 | ); 29 | } 30 | 31 | export function Breadcrumb({ data, showRoot = true }: BreadcrumbProps) { 32 | return ( 33 |
34 | 40 | 45 | 46 | 47 | {showRoot && ( 48 | 49 | / 50 | 51 | 57 | upstash 58 | 59 | 60 | )} 61 | 62 | {data.map((item) => { 63 | return ( 64 | 65 | 66 | 67 | 68 | ); 69 | })} 70 |
71 | ); 72 | } 73 | -------------------------------------------------------------------------------- /vercel-nextjs/pages/index.js: -------------------------------------------------------------------------------- 1 | import Head from "next/head"; 2 | import Image from "next/image"; 3 | import styles from "../styles/Home.module.css"; 4 | 5 | export default function Home() { 6 | return ( 7 | 68 | ); 69 | } 70 | -------------------------------------------------------------------------------- /cron-api-nyt/styles/Home.module.css: -------------------------------------------------------------------------------- 1 | .container { 2 | padding: 0 2rem; 3 | } 4 | 5 | .main { 6 | min-height: 100vh; 7 | padding: 4rem 0; 8 | flex: 1; 9 | display: flex; 10 | flex-direction: column; 11 | justify-content: center; 12 | align-items: center; 13 | } 14 | 15 | .footer { 16 | display: flex; 17 | flex: 1; 18 | padding: 2rem 0; 19 | border-top: 1px solid #eaeaea; 20 | justify-content: center; 21 | align-items: center; 22 | } 23 | 24 | .footer a { 25 | display: flex; 26 | justify-content: center; 27 | align-items: center; 28 | flex-grow: 1; 29 | } 30 | 31 | .title a { 32 | color: #0070f3; 33 | text-decoration: none; 34 | } 35 | 36 | .title a:hover, 37 | .title a:focus, 38 | .title a:active { 39 | text-decoration: underline; 40 | } 41 | 42 | .title { 43 | margin: 0; 44 | line-height: 1.15; 45 | font-size: 4rem; 46 | } 47 | 48 | .title, 49 | .description { 50 | text-align: center; 51 | } 52 | 53 | .description { 54 | margin: 4rem 0; 55 | line-height: 1.5; 56 | font-size: 1.5rem; 57 | } 58 | 59 | .code { 60 | background: #fafafa; 61 | border-radius: 5px; 62 | padding: 0.75rem; 63 | font-size: 1.1rem; 64 | font-family: Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono, 65 | Bitstream Vera Sans Mono, Courier New, monospace; 66 | } 67 | 68 | .grid { 69 | display: flex; 70 | align-items: center; 71 | justify-content: center; 72 | flex-wrap: wrap; 73 | max-width: 800px; 74 | } 75 | 76 | .card { 77 | margin: 1rem; 78 | padding: 1.5rem; 79 | text-align: left; 80 | color: inherit; 81 | text-decoration: none; 82 | border: 1px solid #eaeaea; 83 | border-radius: 10px; 84 | transition: color 0.15s ease, border-color 0.15s ease; 85 | max-width: 300px; 86 | } 87 | 88 | .card:hover, 89 | .card:focus, 90 | .card:active { 91 | color: #0070f3; 92 | border-color: #0070f3; 93 | } 94 | 95 | .card h2 { 96 | margin: 0 0 1rem 0; 97 | font-size: 1.5rem; 98 | } 99 | 100 | .card p { 101 | margin: 0; 102 | font-size: 1.25rem; 103 | line-height: 1.5; 104 | } 105 | 106 | .logo { 107 | height: 1em; 108 | margin-left: 0.5rem; 109 | } 110 | 111 | @media (max-width: 600px) { 112 | .grid { 113 | width: 100%; 114 | flex-direction: column; 115 | } 116 | } 117 | 118 | @media (prefers-color-scheme: dark) { 119 | .card, 120 | .footer { 121 | border-color: #222; 122 | } 123 | .code { 124 | background: #111; 125 | } 126 | .logo img { 127 | filter: invert(1); 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /cron-api-nyt/pages/index.tsx: -------------------------------------------------------------------------------- 1 | import Head from 'next/head' 2 | import Image from 'next/image' 3 | import styles from '../styles/Home.module.css' 4 | 5 | export default function Home() { 6 | return ( 7 | 70 | ) 71 | } 72 | -------------------------------------------------------------------------------- /periodic-data-updates/styles/Home.module.css: -------------------------------------------------------------------------------- 1 | .container { 2 | padding: 0 2rem; 3 | } 4 | 5 | .main { 6 | min-height: 100vh; 7 | padding: 4rem 0; 8 | flex: 1; 9 | display: flex; 10 | flex-direction: column; 11 | justify-content: center; 12 | align-items: center; 13 | } 14 | 15 | .footer { 16 | display: flex; 17 | flex: 1; 18 | padding: 2rem 0; 19 | border-top: 1px solid #eaeaea; 20 | justify-content: center; 21 | align-items: center; 22 | } 23 | 24 | .footer a { 25 | display: flex; 26 | justify-content: center; 27 | align-items: center; 28 | flex-grow: 1; 29 | } 30 | 31 | .title a { 32 | color: #0070f3; 33 | text-decoration: none; 34 | } 35 | 36 | .title a:hover, 37 | .title a:focus, 38 | .title a:active { 39 | text-decoration: underline; 40 | } 41 | 42 | .title { 43 | margin: 0; 44 | line-height: 1.15; 45 | font-size: 4rem; 46 | } 47 | 48 | .title, 49 | .description { 50 | text-align: center; 51 | } 52 | 53 | .description { 54 | margin: 4rem 0; 55 | line-height: 1.5; 56 | font-size: 1.5rem; 57 | } 58 | 59 | .code { 60 | background: #fafafa; 61 | border-radius: 5px; 62 | padding: 0.75rem; 63 | font-size: 1.1rem; 64 | font-family: Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono, 65 | Bitstream Vera Sans Mono, Courier New, monospace; 66 | } 67 | 68 | .grid { 69 | display: flex; 70 | align-items: center; 71 | justify-content: center; 72 | flex-wrap: wrap; 73 | max-width: 800px; 74 | } 75 | 76 | .card { 77 | margin: 1rem; 78 | padding: 1.5rem; 79 | text-align: left; 80 | color: inherit; 81 | text-decoration: none; 82 | border: 1px solid #eaeaea; 83 | border-radius: 10px; 84 | transition: color 0.15s ease, border-color 0.15s ease; 85 | max-width: 300px; 86 | } 87 | 88 | .card:hover, 89 | .card:focus, 90 | .card:active { 91 | color: #0070f3; 92 | border-color: #0070f3; 93 | } 94 | 95 | .card h2 { 96 | margin: 0 0 1rem 0; 97 | font-size: 1.5rem; 98 | } 99 | 100 | .card p { 101 | margin: 0; 102 | font-size: 1.25rem; 103 | line-height: 1.5; 104 | } 105 | 106 | .logo { 107 | height: 1em; 108 | margin-left: 0.5rem; 109 | } 110 | 111 | @media (max-width: 600px) { 112 | .grid { 113 | width: 100%; 114 | flex-direction: column; 115 | } 116 | } 117 | 118 | @media (prefers-color-scheme: dark) { 119 | .card, 120 | .footer { 121 | border-color: #222; 122 | } 123 | .code { 124 | background: #111; 125 | } 126 | .logo img { 127 | filter: invert(1); 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /periodic-data-updates/pages/index.tsx: -------------------------------------------------------------------------------- 1 | import type { GetStaticPropsResult, NextPage } from "next"; 2 | import { Line } from "@ant-design/plots"; 3 | import { Redis } from "@upstash/redis"; 4 | import Link from "next/link"; 5 | 6 | const redis = Redis.fromEnv(); 7 | 8 | type Price = { 9 | /** 10 | * Unix timestamp in milliseconds 11 | */ 12 | time: number; 13 | /** 14 | * Price in USD 15 | */ 16 | value: number; 17 | }; 18 | 19 | const Home: NextPage<{ prices: Price[] }> = ({ prices }) => { 20 | return ( 21 | <> 22 |
23 |
24 |

25 | 26 | qStash scheduled-db-updates example 27 | 28 |

29 | 30 |

31 | This is an example of using qStash to trigger Next.js serverless 32 | functions to fetch updates from an external API using CRON schedules 33 |

34 | 35 |

36 | The api route /api/cron{" "} 37 | is triggered every 10 minutes by{" "} 38 | 39 | 40 | qStash 41 | 42 | {" "} 43 | and loads data into our database. On this page you can see the 44 | aggregated data. 45 |

46 |
47 | 48 |

Bitcoin price in USD over time

49 | ({ 51 | time: new Date(time).toLocaleString(), 52 | value, 53 | }))} 54 | padding="auto" 55 | xField="time" 56 | yField="value" 57 | color="#10b981" 58 | xAxis={{ 59 | tickCount: 5, 60 | }} 61 | yAxis={{ 62 | label: { 63 | formatter: (value) => `$${parseFloat(value).toLocaleString()}`, 64 | }, 65 | }} 66 | /> 67 |
68 | 69 | ); 70 | }; 71 | 72 | export async function getStaticProps(): Promise< 73 | GetStaticPropsResult<{ prices: Price[] }> 74 | > { 75 | const raw = await redis.zrange("bitcoin-prices", 0, -1, { 76 | withScores: true, 77 | }); 78 | 79 | const prices: Price[] = []; 80 | while (raw.length >= 2) { 81 | const value = parseFloat(raw.shift()!); 82 | const time = parseFloat(raw.shift()!); 83 | prices.push({ time, value }); 84 | } 85 | 86 | return { 87 | props: { 88 | prices, 89 | }, 90 | revalidate: 60, 91 | }; 92 | } 93 | 94 | export default Home; 95 | -------------------------------------------------------------------------------- /aws-lambda/python-example/lambda_function.py: -------------------------------------------------------------------------------- 1 | import json 2 | import os 3 | import hmac 4 | import hashlib 5 | import base64 6 | import time 7 | import jwt 8 | 9 | 10 | def lambda_handler(event, context): 11 | 12 | # parse the inputs 13 | current_signing_key = os.environ['QSTASH_CURRENT_SIGNING_KEY'] 14 | next_signing_key = os.environ['QSTASH_NEXT_SIGNING_KEY'] 15 | 16 | headers = event['headers'] 17 | signature = headers['upstash-signature'] 18 | url = 'https://{}'.format(event['requestContext']['domainName']) 19 | body = None 20 | if 'body' in event: 21 | body = event['body'] 22 | 23 | 24 | # check verification now 25 | try: 26 | verify(signature, current_signing_key, body, url) 27 | except Exception as e: 28 | print("Failed to verify signature with current signing key:", e) 29 | try: 30 | verify(signature, next_signing_key, body, url) 31 | except Exception as e2: 32 | return { 33 | "statusCode": 400, 34 | "body": json.dumps({ 35 | "error": str(e2), 36 | }), 37 | } 38 | 39 | 40 | # Your logic here... 41 | 42 | return { 43 | "statusCode": 200, 44 | "body": json.dumps({ 45 | "message": "ok", 46 | }), 47 | } 48 | 49 | 50 | def verify(jwt_token, signing_key, body, url): 51 | split = jwt_token.split(".") 52 | if len(split) != 3: 53 | raise Exception("Invalid JWT.") 54 | 55 | header, payload, signature = split 56 | 57 | message = header + '.' + payload 58 | generated_signature = base64.urlsafe_b64encode(hmac.new(bytes(signing_key, 'utf-8'), bytes(message, 'utf-8'), digestmod=hashlib.sha256).digest()).decode() 59 | 60 | if generated_signature != signature and signature + "=" != generated_signature : 61 | raise Exception("Invalid JWT signature.") 62 | 63 | decoded = jwt.decode(jwt_token, options={"verify_signature": False}) 64 | sub = decoded['sub'] 65 | iss = decoded['iss'] 66 | exp = decoded['exp'] 67 | nbf = decoded['nbf'] 68 | decoded_body = decoded['body'] 69 | 70 | if iss != "Upstash": 71 | raise Exception("Invalid issuer: {}".format(iss)) 72 | 73 | if sub != url: 74 | raise Exception("Invalid subject: {}".format(sub)) 75 | 76 | now = time.time() 77 | if now > exp: 78 | raise Exception("Token has expired.") 79 | 80 | if now < nbf: 81 | raise Exception("Token is not yet valid.") 82 | 83 | 84 | if body != None: 85 | while decoded_body[-1] == "=": 86 | decoded_body = decoded_body[:-1] 87 | 88 | m = hashlib.sha256() 89 | m.update(bytes(body, 'utf-8')) 90 | m = m.digest() 91 | generated_hash = base64.urlsafe_b64encode(m).decode() 92 | 93 | if generated_hash != decoded_body and generated_hash != decoded_body + "=" : 94 | raise Exception("Body hash doesn't match.") 95 | 96 | -------------------------------------------------------------------------------- /aws-lambda/typescript-example/index.ts: -------------------------------------------------------------------------------- 1 | import { APIGatewayEvent, APIGatewayProxyResult, Context } from "aws-lambda"; 2 | import { createHash, createHmac } from "node:crypto"; 3 | export const handler = async ( 4 | event: APIGatewayEvent, 5 | _context: Context, 6 | ): Promise => { 7 | console.log("Custom message") 8 | 9 | const signature = event.headers["upstash-signature"]!; 10 | const currentSigningKey = process.env["QSTASH_CURRENT_SIGNING_KEY"]; 11 | const nextSigningKey = process.env["QSTASH_NEXT_SIGNING_KEY"]; 12 | const url = `https://${event.requestContext.domainName}`; 13 | 14 | console.log({ signature, currentSigningKey, nextSigningKey, url }) 15 | try { 16 | // Try to verify the signature with the current signing key and if that fails, try the next signing key 17 | // This allows you to roll your signing keys once without downtime 18 | try { 19 | verify(signature, currentSigningKey, event.body, url) 20 | } catch (err) { 21 | console.error( 22 | `Failed to verify signature with current signing key: ${err}`, 23 | ); 24 | verify(signature, nextSigningKey, event.body, url); 25 | 26 | } 27 | } catch (err) { 28 | return { 29 | statusCode: 500, 30 | body: err instanceof Error ? err.toString() : err, 31 | }; 32 | } 33 | 34 | // Add your business logic here 35 | console.log("Doing work") 36 | return { 37 | statusCode: 200, 38 | body: "OK", 39 | }; 40 | }; 41 | 42 | /** 43 | * @param jwt - The content of the `upstash-signature` header 44 | * @param signingKey - The signing key to use to verify the signature (Get it from Upstash Console) 45 | * @param body - The raw body of the request 46 | * @param url - The public URL of the lambda function 47 | */ 48 | function verify( 49 | jwt: string, 50 | signingKey: string, 51 | body: string | null, 52 | url: string, 53 | ): void { 54 | const split = jwt.split("."); 55 | if (split.length != 3) { 56 | throw new Error("Invalid JWT"); 57 | } 58 | const [header, payload, signature] = split; 59 | 60 | if ( 61 | signature != 62 | createHmac("sha256", signingKey) 63 | .update(`${header}.${payload}`) 64 | .digest("base64url") 65 | ) { 66 | throw new Error("Invalid JWT signature"); 67 | } 68 | // Now the jwt is verified and we can start looking at the claims in the payload 69 | const p: { 70 | sub: string; 71 | iss: string; 72 | exp: number; 73 | nbf: number; 74 | body: string; 75 | } = JSON.parse(Buffer.from(payload, "base64url").toString()); 76 | 77 | if (p.iss !== "Upstash") { 78 | throw new Error(`invalid issuer: ${p.iss}, expected "Upstash"`); 79 | } 80 | if (p.sub !== url) { 81 | throw new Error(`invalid subject: ${p.sub}, expected "${url}"`); 82 | } 83 | 84 | const now = Math.floor(Date.now() / 1000); 85 | if (now > p.exp) { 86 | throw new Error("token has expired"); 87 | } 88 | if (now < p.nbf) { 89 | throw new Error("token is not yet valid"); 90 | } 91 | 92 | if (body != null) { 93 | if ( 94 | p.body.replace(/=+$/, "") != 95 | createHash("sha256").update(body).digest("base64url") 96 | ) { 97 | throw new Error("body hash does not match"); 98 | } 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /with-novu/pages/index.tsx: -------------------------------------------------------------------------------- 1 | import { Button, Display, Fieldset, Grid, Input, Link, Page, Spacer, Tag, Text, useInput, useToasts } from '@geist-ui/core' 2 | import { NovuProvider, useNotifications } from '@novu/notification-center' 3 | import type { NextPage } from 'next' 4 | import React, { useEffect, useState } from 'react' 5 | import type { AddRequest } from './api/task/add' 6 | import { useUserId } from '../lib/useUserId' 7 | 8 | 9 | 10 | const Notifications: React.FC = () => { 11 | const { notifications, markAsSeen, refetch } = useNotifications(); 12 | setInterval(refetch, 2000) 13 | 14 | 15 | const { setToast } = useToasts() 16 | useEffect(() => { 17 | notifications.filter(n => !n.seen).forEach((n) => { 18 | console.log({ n }) 19 | 20 | switch (n.templateIdentifier) { 21 | case "add.success": 22 | setToast({ 23 | text: {`Success: ${n.payload["x"]} + ${n.payload["y"]} = ${n.payload["result"]}`}, 24 | }) 25 | break; 26 | case "add.failure": 27 | setToast({ 28 | text: {`Failed to add: ${n.payload["x"]} + ${n.payload["y"]}: ${n.payload["error"]}`}, 29 | type: "error" 30 | }) 31 | break 32 | 33 | default: 34 | setToast({ 35 | text: {`Unknown template: ${n.templateIdentifier}`}, 36 | type: "warning" 37 | }) 38 | } 39 | 40 | markAsSeen(n._id) 41 | }) 42 | 43 | }, [notifications]) 44 | 45 | return null 46 | } 47 | 48 | const Home: NextPage = () => { 49 | 50 | 51 | 52 | const { setToast } = useToasts({ placement: "topRight" }) 53 | 54 | 55 | const [userId] = useUserId() 56 | console.log("random user id:", userId) 57 | const [loading, setLoading] = useState(false) 58 | 59 | async function createTask(req: AddRequest): Promise { 60 | const res = await fetch("/api/task/add", { 61 | method: "POST", 62 | body: JSON.stringify(req), 63 | headers: { 64 | "Content-Type": "application/json" 65 | } 66 | }) 67 | if (res.status !== 201) { 68 | const err = ((await res.json()) as { error: string }).error 69 | setToast({ 70 | text: err, 71 | type: "error" 72 | }) 73 | 74 | return 75 | } 76 | 77 | } 78 | 79 | 80 | const x = useInput((Math.random() * 100).toFixed(0)) 81 | const y = useInput((Math.random() * 100).toFixed(0)) 82 | 83 | return ( 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | Asynchronous serverless processing with QStash and notifications by novu 92 | 93 | 94 | 95 | 96 | 97 | 98 |
99 | 100 | 101 | Add these numbers asynchronously 102 | 103 | 104 | 105 | 106 | + 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 164 | 165 | 166 |
167 | 168 | 169 |
170 |
171 | 172 |
173 | 174 | ) 175 | } 176 | 177 | export default Home 178 | -------------------------------------------------------------------------------- /cloudflare-workers/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Visit https://aka.ms/tsconfig.json to read more about this file */ 4 | 5 | /* Projects */ 6 | // "incremental": true, /* Enable incremental compilation */ 7 | // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ 8 | // "tsBuildInfoFile": "./", /* Specify the folder for .tsbuildinfo incremental compilation files. */ 9 | // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects */ 10 | // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ 11 | // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ 12 | 13 | /* Language and Environment */ 14 | "target": "es2021", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ 15 | "lib": [ 16 | "es2021" 17 | ], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ 18 | "jsx": "react", /* Specify what JSX code is generated. */ 19 | // "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */ 20 | // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ 21 | // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h' */ 22 | // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ 23 | // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using `jsx: react-jsx*`.` */ 24 | // "reactNamespace": "", /* Specify the object invoked for `createElement`. This only applies when targeting `react` JSX emit. */ 25 | // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ 26 | // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ 27 | 28 | /* Modules */ 29 | "module": "es2022", /* Specify what module code is generated. */ 30 | // "rootDir": "./", /* Specify the root folder within your source files. */ 31 | "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */ 32 | // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ 33 | // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ 34 | // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ 35 | // "typeRoots": [], /* Specify multiple folders that act like `./node_modules/@types`. */ 36 | "types": [ 37 | "@cloudflare/workers-types" 38 | ], /* Specify type package names to be included without being referenced in a source file. */ 39 | // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ 40 | "resolveJsonModule": true, /* Enable importing .json files */ 41 | // "noResolve": true, /* Disallow `import`s, `require`s or ``s from expanding the number of files TypeScript should add to a project. */ 42 | 43 | /* JavaScript Support */ 44 | "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the `checkJS` option to get errors from these files. */ 45 | "checkJs": false, /* Enable error reporting in type-checked JavaScript files. */ 46 | // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from `node_modules`. Only applicable with `allowJs`. */ 47 | 48 | /* Emit */ 49 | // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ 50 | // "declarationMap": true, /* Create sourcemaps for d.ts files. */ 51 | // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ 52 | // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ 53 | // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If `declaration` is true, also designates a file that bundles all .d.ts output. */ 54 | // "outDir": "./", /* Specify an output folder for all emitted files. */ 55 | // "removeComments": true, /* Disable emitting comments. */ 56 | "noEmit": true, /* Disable emitting files from a compilation. */ 57 | // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ 58 | // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types */ 59 | // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ 60 | // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ 61 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ 62 | // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ 63 | // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ 64 | // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ 65 | // "newLine": "crlf", /* Set the newline character for emitting files. */ 66 | // "stripInternal": true, /* Disable emitting declarations that have `@internal` in their JSDoc comments. */ 67 | // "noEmitHelpers": true, /* Disable generating custom helper functions like `__extends` in compiled output. */ 68 | // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ 69 | // "preserveConstEnums": true, /* Disable erasing `const enum` declarations in generated code. */ 70 | // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ 71 | // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ 72 | 73 | /* Interop Constraints */ 74 | "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ 75 | "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ 76 | // "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables `allowSyntheticDefaultImports` for type compatibility. */, 77 | // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ 78 | "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ 79 | 80 | /* Type Checking */ 81 | "strict": true, /* Enable all strict type-checking options. */ 82 | // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied `any` type.. */ 83 | // "strictNullChecks": true, /* When type checking, take into account `null` and `undefined`. */ 84 | // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ 85 | // "strictBindCallApply": true, /* Check that the arguments for `bind`, `call`, and `apply` methods match the original function. */ 86 | // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ 87 | // "noImplicitThis": true, /* Enable error reporting when `this` is given the type `any`. */ 88 | // "useUnknownInCatchVariables": true, /* Type catch clause variables as 'unknown' instead of 'any'. */ 89 | // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ 90 | // "noUnusedLocals": true, /* Enable error reporting when a local variables aren't read. */ 91 | // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read */ 92 | // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ 93 | // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ 94 | // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ 95 | // "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */ 96 | // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ 97 | // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type */ 98 | // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ 99 | // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ 100 | 101 | /* Completeness */ 102 | // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ 103 | "skipLibCheck": true /* Skip type checking all .d.ts files. */ 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /cloudflare-workers/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cloudflare-workers", 3 | "version": "0.0.0", 4 | "lockfileVersion": 2, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "cloudflare-workers", 9 | "version": "0.0.0", 10 | "dependencies": { 11 | "@upstash/qstash": "^0.1.2" 12 | }, 13 | "devDependencies": { 14 | "@cloudflare/workers-types": "^3.14.1", 15 | "typescript": "^4.7.4", 16 | "wrangler": "2.0.17" 17 | } 18 | }, 19 | "node_modules/@cloudflare/kv-asset-handler": { 20 | "version": "0.2.0", 21 | "resolved": "https://registry.npmjs.org/@cloudflare/kv-asset-handler/-/kv-asset-handler-0.2.0.tgz", 22 | "integrity": "sha512-MVbXLbTcAotOPUj0pAMhVtJ+3/kFkwJqc5qNOleOZTv6QkZZABDMS21dSrSlVswEHwrpWC03e4fWytjqKvuE2A==", 23 | "dev": true, 24 | "dependencies": { 25 | "mime": "^3.0.0" 26 | } 27 | }, 28 | "node_modules/@cloudflare/workers-types": { 29 | "version": "3.14.1", 30 | "resolved": "https://registry.npmjs.org/@cloudflare/workers-types/-/workers-types-3.14.1.tgz", 31 | "integrity": "sha512-B1/plF62pt+H2IJHvApK8fdOJAVsvojvacuac8x8s+JIyqbropMyqNqHTKLm3YD8ZFLGwYeFTudU+PQ7vGvBdA==", 32 | "dev": true 33 | }, 34 | "node_modules/@deno/shim-crypto": { 35 | "version": "0.3.1", 36 | "resolved": "https://registry.npmjs.org/@deno/shim-crypto/-/shim-crypto-0.3.1.tgz", 37 | "integrity": "sha512-ed4pNnfur6UbASEgF34gVxR9p7Mc3qF+Ygbmjiil8ws5IhNFhPDFy5vE5hQAUA9JmVsSxXPcVLM5Rf8LOZqQ5Q==" 38 | }, 39 | "node_modules/@esbuild-plugins/node-globals-polyfill": { 40 | "version": "0.1.1", 41 | "resolved": "https://registry.npmjs.org/@esbuild-plugins/node-globals-polyfill/-/node-globals-polyfill-0.1.1.tgz", 42 | "integrity": "sha512-MR0oAA+mlnJWrt1RQVQ+4VYuRJW/P2YmRTv1AsplObyvuBMnPHiizUF95HHYiSsMGLhyGtWufaq2XQg6+iurBg==", 43 | "dev": true, 44 | "peerDependencies": { 45 | "esbuild": "*" 46 | } 47 | }, 48 | "node_modules/@esbuild-plugins/node-modules-polyfill": { 49 | "version": "0.1.4", 50 | "resolved": "https://registry.npmjs.org/@esbuild-plugins/node-modules-polyfill/-/node-modules-polyfill-0.1.4.tgz", 51 | "integrity": "sha512-uZbcXi0zbmKC/050p3gJnne5Qdzw8vkXIv+c2BW0Lsc1ji1SkrxbKPUy5Efr0blbTu1SL8w4eyfpnSdPg3G0Qg==", 52 | "dev": true, 53 | "dependencies": { 54 | "escape-string-regexp": "^4.0.0", 55 | "rollup-plugin-node-polyfills": "^0.2.1" 56 | }, 57 | "peerDependencies": { 58 | "esbuild": "*" 59 | } 60 | }, 61 | "node_modules/@iarna/toml": { 62 | "version": "2.2.5", 63 | "resolved": "https://registry.npmjs.org/@iarna/toml/-/toml-2.2.5.tgz", 64 | "integrity": "sha512-trnsAYxU3xnS1gPHPyU961coFyLkh4gAD/0zQ5mymY4yOZ+CYvsPqUbOFSw0aDM4y0tV7tiFxL/1XfXPNC6IPg==", 65 | "dev": true 66 | }, 67 | "node_modules/@miniflare/cache": { 68 | "version": "2.6.0", 69 | "resolved": "https://registry.npmjs.org/@miniflare/cache/-/cache-2.6.0.tgz", 70 | "integrity": "sha512-4oh8MgpquoxaslI7Z8sMzmEZR0Dc+L3aEh69o9d8ZCs4nUdOENnfKlY50O5nEnL7nhhyAljkMBaXD2wAH2DLeQ==", 71 | "dev": true, 72 | "dependencies": { 73 | "@miniflare/core": "2.6.0", 74 | "@miniflare/shared": "2.6.0", 75 | "http-cache-semantics": "^4.1.0", 76 | "undici": "5.5.1" 77 | }, 78 | "engines": { 79 | "node": ">=16.7" 80 | } 81 | }, 82 | "node_modules/@miniflare/cli-parser": { 83 | "version": "2.6.0", 84 | "resolved": "https://registry.npmjs.org/@miniflare/cli-parser/-/cli-parser-2.6.0.tgz", 85 | "integrity": "sha512-dJDoIPAUqWhzvBHHyqyhobdzDedBYRWZ4yItBi9m4MTU/EneLJ5jryB340SwUnmtBMZxUh/LWdAuUEkKpdVNyA==", 86 | "dev": true, 87 | "dependencies": { 88 | "@miniflare/shared": "2.6.0", 89 | "kleur": "^4.1.4" 90 | }, 91 | "engines": { 92 | "node": ">=16.7" 93 | } 94 | }, 95 | "node_modules/@miniflare/core": { 96 | "version": "2.6.0", 97 | "resolved": "https://registry.npmjs.org/@miniflare/core/-/core-2.6.0.tgz", 98 | "integrity": "sha512-CmofhIRot++GI7NHPMwzNb65+0hWLN186L91BrH/doPVHnT/itmEfzYQpL9bFLD0c/i14dfv+IUNetDdGEBIrw==", 99 | "dev": true, 100 | "dependencies": { 101 | "@iarna/toml": "^2.2.5", 102 | "@miniflare/shared": "2.6.0", 103 | "@miniflare/watcher": "2.6.0", 104 | "busboy": "^1.6.0", 105 | "dotenv": "^10.0.0", 106 | "kleur": "^4.1.4", 107 | "set-cookie-parser": "^2.4.8", 108 | "undici": "5.5.1", 109 | "urlpattern-polyfill": "^4.0.3" 110 | }, 111 | "engines": { 112 | "node": ">=16.7" 113 | } 114 | }, 115 | "node_modules/@miniflare/durable-objects": { 116 | "version": "2.6.0", 117 | "resolved": "https://registry.npmjs.org/@miniflare/durable-objects/-/durable-objects-2.6.0.tgz", 118 | "integrity": "sha512-uzWoGFtkIIh3m3HAzqd5f86nOSC0xFli6dq2q7ilE3UjgouOcLqObxJyE/IzvSwsj4DUWFv6//YDfHihK2fGAA==", 119 | "dev": true, 120 | "dependencies": { 121 | "@miniflare/core": "2.6.0", 122 | "@miniflare/shared": "2.6.0", 123 | "@miniflare/storage-memory": "2.6.0", 124 | "undici": "5.5.1" 125 | }, 126 | "engines": { 127 | "node": ">=16.7" 128 | } 129 | }, 130 | "node_modules/@miniflare/html-rewriter": { 131 | "version": "2.6.0", 132 | "resolved": "https://registry.npmjs.org/@miniflare/html-rewriter/-/html-rewriter-2.6.0.tgz", 133 | "integrity": "sha512-+JqFlIDLzstb/Spj+j/kI6uHzolrqjsMks3Tf24Q4YFo9YYdZguqUFcDz2yr79ZTP/SKXaZH+AYqosnJps4dHQ==", 134 | "dev": true, 135 | "dependencies": { 136 | "@miniflare/core": "2.6.0", 137 | "@miniflare/shared": "2.6.0", 138 | "html-rewriter-wasm": "^0.4.1", 139 | "undici": "5.5.1" 140 | }, 141 | "engines": { 142 | "node": ">=16.7" 143 | } 144 | }, 145 | "node_modules/@miniflare/http-server": { 146 | "version": "2.6.0", 147 | "resolved": "https://registry.npmjs.org/@miniflare/http-server/-/http-server-2.6.0.tgz", 148 | "integrity": "sha512-FhcAVIpipMEzMCsJBc/b0JhNEJ66GPX60vA2NcqjGKHYbwoPCPlwCFQq2giPzW/R95ugrEjPfo4/5Q4UbnpoGA==", 149 | "dev": true, 150 | "dependencies": { 151 | "@miniflare/core": "2.6.0", 152 | "@miniflare/shared": "2.6.0", 153 | "@miniflare/web-sockets": "2.6.0", 154 | "kleur": "^4.1.4", 155 | "selfsigned": "^2.0.0", 156 | "undici": "5.5.1", 157 | "ws": "^8.2.2", 158 | "youch": "^2.2.2" 159 | }, 160 | "engines": { 161 | "node": ">=16.7" 162 | } 163 | }, 164 | "node_modules/@miniflare/kv": { 165 | "version": "2.6.0", 166 | "resolved": "https://registry.npmjs.org/@miniflare/kv/-/kv-2.6.0.tgz", 167 | "integrity": "sha512-7Q+Q0Wwinsz85qpKLlBeXSCLweiVowpMJ5AmQpmELnTya59HQ24cOUHxPd64hXFhdYXVIxOmk6lQaZ21JhdHGQ==", 168 | "dev": true, 169 | "dependencies": { 170 | "@miniflare/shared": "2.6.0" 171 | }, 172 | "engines": { 173 | "node": ">=16.7" 174 | } 175 | }, 176 | "node_modules/@miniflare/r2": { 177 | "version": "2.6.0", 178 | "resolved": "https://registry.npmjs.org/@miniflare/r2/-/r2-2.6.0.tgz", 179 | "integrity": "sha512-Ymbqu17ajtuk9b11txF2h1Ewqqlu3XCCpAwAgCQa6AK1yRidQECCPq9w9oXZxE1p5aaSuLTOUbgSdtveFCsLxQ==", 180 | "dev": true, 181 | "dependencies": { 182 | "@miniflare/shared": "2.6.0", 183 | "undici": "5.5.1" 184 | }, 185 | "engines": { 186 | "node": ">=16.7" 187 | } 188 | }, 189 | "node_modules/@miniflare/runner-vm": { 190 | "version": "2.6.0", 191 | "resolved": "https://registry.npmjs.org/@miniflare/runner-vm/-/runner-vm-2.6.0.tgz", 192 | "integrity": "sha512-ZxsiVMMUcjb01LwrO2t50YbU5PT5s3k7DrmR5185R/n04K5BikqZz8eQf8lKlQQYem0BROqmmQgurZGw0a2HUw==", 193 | "dev": true, 194 | "dependencies": { 195 | "@miniflare/shared": "2.6.0" 196 | }, 197 | "engines": { 198 | "node": ">=16.7" 199 | } 200 | }, 201 | "node_modules/@miniflare/scheduler": { 202 | "version": "2.6.0", 203 | "resolved": "https://registry.npmjs.org/@miniflare/scheduler/-/scheduler-2.6.0.tgz", 204 | "integrity": "sha512-BM+RDF+8twkTCOb7Oz0NIs5phzAVJ/Gx7tFZR23fGsZjWRnE3TBeqfzaNutU9pcoWDZtBQqEJMeTeb0KZTo75Q==", 205 | "dev": true, 206 | "dependencies": { 207 | "@miniflare/core": "2.6.0", 208 | "@miniflare/shared": "2.6.0", 209 | "cron-schedule": "^3.0.4" 210 | }, 211 | "engines": { 212 | "node": ">=16.7" 213 | } 214 | }, 215 | "node_modules/@miniflare/shared": { 216 | "version": "2.6.0", 217 | "resolved": "https://registry.npmjs.org/@miniflare/shared/-/shared-2.6.0.tgz", 218 | "integrity": "sha512-/7k4C37GF0INu99LNFmFhHYL6U9/oRY/nWDa5sr6+lPEKKm2rkmfvDIA+YNAj7Ql61ZWMgEMj0S3NhV0rWkj7Q==", 219 | "dev": true, 220 | "dependencies": { 221 | "ignore": "^5.1.8", 222 | "kleur": "^4.1.4" 223 | }, 224 | "engines": { 225 | "node": ">=16.7" 226 | } 227 | }, 228 | "node_modules/@miniflare/sites": { 229 | "version": "2.6.0", 230 | "resolved": "https://registry.npmjs.org/@miniflare/sites/-/sites-2.6.0.tgz", 231 | "integrity": "sha512-XfWhpREC638LOGNmuHaPn1MAz1sh2mz+VdMsjRCzUo6NwPl4IcUhnorJR62Xr0qmI/RqVMTZbvzrChXio4Bi4A==", 232 | "dev": true, 233 | "dependencies": { 234 | "@miniflare/kv": "2.6.0", 235 | "@miniflare/shared": "2.6.0", 236 | "@miniflare/storage-file": "2.6.0" 237 | }, 238 | "engines": { 239 | "node": ">=16.7" 240 | } 241 | }, 242 | "node_modules/@miniflare/storage-file": { 243 | "version": "2.6.0", 244 | "resolved": "https://registry.npmjs.org/@miniflare/storage-file/-/storage-file-2.6.0.tgz", 245 | "integrity": "sha512-xprDVJClQ2X1vXVPM16WQZz3rS+6fNuCYC8bfEFHABDByQoUNDpk8q+m1IpTaFXYivYxRhE+xr7eK2QQP068tA==", 246 | "dev": true, 247 | "dependencies": { 248 | "@miniflare/shared": "2.6.0", 249 | "@miniflare/storage-memory": "2.6.0" 250 | }, 251 | "engines": { 252 | "node": ">=16.7" 253 | } 254 | }, 255 | "node_modules/@miniflare/storage-memory": { 256 | "version": "2.6.0", 257 | "resolved": "https://registry.npmjs.org/@miniflare/storage-memory/-/storage-memory-2.6.0.tgz", 258 | "integrity": "sha512-0EwELTG2r6IC4AMlQv0YXRZdw9g/lCydceuGKeFkWAVb55pY+yMBxkJO9VV7QOrEx8MLsR8tsfl5SBK3AkfLtA==", 259 | "dev": true, 260 | "dependencies": { 261 | "@miniflare/shared": "2.6.0" 262 | }, 263 | "engines": { 264 | "node": ">=16.7" 265 | } 266 | }, 267 | "node_modules/@miniflare/watcher": { 268 | "version": "2.6.0", 269 | "resolved": "https://registry.npmjs.org/@miniflare/watcher/-/watcher-2.6.0.tgz", 270 | "integrity": "sha512-mttfhNDmEIFo2rWF73JeWj1TLN+3cQC1TFhbtLApz9bXilLywArXMYqDJGA8PUnJCFM/8k2FDjaFNiPy6ggIJw==", 271 | "dev": true, 272 | "dependencies": { 273 | "@miniflare/shared": "2.6.0" 274 | }, 275 | "engines": { 276 | "node": ">=16.7" 277 | } 278 | }, 279 | "node_modules/@miniflare/web-sockets": { 280 | "version": "2.6.0", 281 | "resolved": "https://registry.npmjs.org/@miniflare/web-sockets/-/web-sockets-2.6.0.tgz", 282 | "integrity": "sha512-ePbcuP9LrStVTllZzqx2oNVoOpceyU3jJF3nGDMNW5+bqB+BdeTggSF8rhER7omcSCswCMY2Do6VelIcAXHkXA==", 283 | "dev": true, 284 | "dependencies": { 285 | "@miniflare/core": "2.6.0", 286 | "@miniflare/shared": "2.6.0", 287 | "undici": "5.5.1", 288 | "ws": "^8.2.2" 289 | }, 290 | "engines": { 291 | "node": ">=16.7" 292 | } 293 | }, 294 | "node_modules/@types/stack-trace": { 295 | "version": "0.0.29", 296 | "resolved": "https://registry.npmjs.org/@types/stack-trace/-/stack-trace-0.0.29.tgz", 297 | "integrity": "sha512-TgfOX+mGY/NyNxJLIbDWrO9DjGoVSW9+aB8H2yy1fy32jsvxijhmyJI9fDFgvz3YP4lvJaq9DzdR/M1bOgVc9g==", 298 | "dev": true 299 | }, 300 | "node_modules/@upstash/qstash": { 301 | "version": "0.1.2", 302 | "resolved": "https://registry.npmjs.org/@upstash/qstash/-/qstash-0.1.2.tgz", 303 | "integrity": "sha512-lM/PRfyuc3QPs0Yz4bfl5gT0P0DYMp05RcLbeenziv7DqYx9wMeMiLs5veEJzeMhHcSmjCKDYgL0zzsSW0SP4w==", 304 | "dependencies": { 305 | "@deno/shim-crypto": "~0.3.0" 306 | } 307 | }, 308 | "node_modules/blake3-wasm": { 309 | "version": "2.1.5", 310 | "resolved": "https://registry.npmjs.org/blake3-wasm/-/blake3-wasm-2.1.5.tgz", 311 | "integrity": "sha512-F1+K8EbfOZE49dtoPtmxUQrpXaBIl3ICvasLh+nJta0xkz+9kF/7uet9fLnwKqhDrmj6g+6K3Tw9yQPUg2ka5g==", 312 | "dev": true 313 | }, 314 | "node_modules/buffer-from": { 315 | "version": "1.1.2", 316 | "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", 317 | "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", 318 | "dev": true 319 | }, 320 | "node_modules/busboy": { 321 | "version": "1.6.0", 322 | "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", 323 | "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", 324 | "dev": true, 325 | "dependencies": { 326 | "streamsearch": "^1.1.0" 327 | }, 328 | "engines": { 329 | "node": ">=10.16.0" 330 | } 331 | }, 332 | "node_modules/cookie": { 333 | "version": "0.4.2", 334 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", 335 | "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", 336 | "dev": true, 337 | "engines": { 338 | "node": ">= 0.6" 339 | } 340 | }, 341 | "node_modules/cron-schedule": { 342 | "version": "3.0.6", 343 | "resolved": "https://registry.npmjs.org/cron-schedule/-/cron-schedule-3.0.6.tgz", 344 | "integrity": "sha512-izfGgKyzzIyLaeb1EtZ3KbglkS6AKp9cv7LxmiyoOu+fXfol1tQDC0Cof0enVZGNtudTHW+3lfuW9ZkLQss4Wg==", 345 | "dev": true 346 | }, 347 | "node_modules/dotenv": { 348 | "version": "10.0.0", 349 | "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz", 350 | "integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==", 351 | "dev": true, 352 | "engines": { 353 | "node": ">=10" 354 | } 355 | }, 356 | "node_modules/esbuild": { 357 | "version": "0.14.47", 358 | "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.47.tgz", 359 | "integrity": "sha512-wI4ZiIfFxpkuxB8ju4MHrGwGLyp1+awEHAHVpx6w7a+1pmYIq8T9FGEVVwFo0iFierDoMj++Xq69GXWYn2EiwA==", 360 | "dev": true, 361 | "hasInstallScript": true, 362 | "bin": { 363 | "esbuild": "bin/esbuild" 364 | }, 365 | "engines": { 366 | "node": ">=12" 367 | }, 368 | "optionalDependencies": { 369 | "esbuild-android-64": "0.14.47", 370 | "esbuild-android-arm64": "0.14.47", 371 | "esbuild-darwin-64": "0.14.47", 372 | "esbuild-darwin-arm64": "0.14.47", 373 | "esbuild-freebsd-64": "0.14.47", 374 | "esbuild-freebsd-arm64": "0.14.47", 375 | "esbuild-linux-32": "0.14.47", 376 | "esbuild-linux-64": "0.14.47", 377 | "esbuild-linux-arm": "0.14.47", 378 | "esbuild-linux-arm64": "0.14.47", 379 | "esbuild-linux-mips64le": "0.14.47", 380 | "esbuild-linux-ppc64le": "0.14.47", 381 | "esbuild-linux-riscv64": "0.14.47", 382 | "esbuild-linux-s390x": "0.14.47", 383 | "esbuild-netbsd-64": "0.14.47", 384 | "esbuild-openbsd-64": "0.14.47", 385 | "esbuild-sunos-64": "0.14.47", 386 | "esbuild-windows-32": "0.14.47", 387 | "esbuild-windows-64": "0.14.47", 388 | "esbuild-windows-arm64": "0.14.47" 389 | } 390 | }, 391 | "node_modules/esbuild-android-64": { 392 | "version": "0.14.47", 393 | "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.14.47.tgz", 394 | "integrity": "sha512-R13Bd9+tqLVFndncMHssZrPWe6/0Kpv2/dt4aA69soX4PRxlzsVpCvoJeFE8sOEoeVEiBkI0myjlkDodXlHa0g==", 395 | "cpu": [ 396 | "x64" 397 | ], 398 | "dev": true, 399 | "optional": true, 400 | "os": [ 401 | "android" 402 | ], 403 | "engines": { 404 | "node": ">=12" 405 | } 406 | }, 407 | "node_modules/esbuild-android-arm64": { 408 | "version": "0.14.47", 409 | "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.47.tgz", 410 | "integrity": "sha512-OkwOjj7ts4lBp/TL6hdd8HftIzOy/pdtbrNA4+0oVWgGG64HrdVzAF5gxtJufAPOsEjkyh1oIYvKAUinKKQRSQ==", 411 | "cpu": [ 412 | "arm64" 413 | ], 414 | "dev": true, 415 | "optional": true, 416 | "os": [ 417 | "android" 418 | ], 419 | "engines": { 420 | "node": ">=12" 421 | } 422 | }, 423 | "node_modules/esbuild-darwin-64": { 424 | "version": "0.14.47", 425 | "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.47.tgz", 426 | "integrity": "sha512-R6oaW0y5/u6Eccti/TS6c/2c1xYTb1izwK3gajJwi4vIfNs1s8B1dQzI1UiC9T61YovOQVuePDcfqHLT3mUZJA==", 427 | "cpu": [ 428 | "x64" 429 | ], 430 | "dev": true, 431 | "optional": true, 432 | "os": [ 433 | "darwin" 434 | ], 435 | "engines": { 436 | "node": ">=12" 437 | } 438 | }, 439 | "node_modules/esbuild-darwin-arm64": { 440 | "version": "0.14.47", 441 | "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.47.tgz", 442 | "integrity": "sha512-seCmearlQyvdvM/noz1L9+qblC5vcBrhUaOoLEDDoLInF/VQ9IkobGiLlyTPYP5dW1YD4LXhtBgOyevoIHGGnw==", 443 | "cpu": [ 444 | "arm64" 445 | ], 446 | "dev": true, 447 | "optional": true, 448 | "os": [ 449 | "darwin" 450 | ], 451 | "engines": { 452 | "node": ">=12" 453 | } 454 | }, 455 | "node_modules/esbuild-freebsd-64": { 456 | "version": "0.14.47", 457 | "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.47.tgz", 458 | "integrity": "sha512-ZH8K2Q8/Ux5kXXvQMDsJcxvkIwut69KVrYQhza/ptkW50DC089bCVrJZZ3sKzIoOx+YPTrmsZvqeZERjyYrlvQ==", 459 | "cpu": [ 460 | "x64" 461 | ], 462 | "dev": true, 463 | "optional": true, 464 | "os": [ 465 | "freebsd" 466 | ], 467 | "engines": { 468 | "node": ">=12" 469 | } 470 | }, 471 | "node_modules/esbuild-freebsd-arm64": { 472 | "version": "0.14.47", 473 | "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.47.tgz", 474 | "integrity": "sha512-ZJMQAJQsIOhn3XTm7MPQfCzEu5b9STNC+s90zMWe2afy9EwnHV7Ov7ohEMv2lyWlc2pjqLW8QJnz2r0KZmeAEQ==", 475 | "cpu": [ 476 | "arm64" 477 | ], 478 | "dev": true, 479 | "optional": true, 480 | "os": [ 481 | "freebsd" 482 | ], 483 | "engines": { 484 | "node": ">=12" 485 | } 486 | }, 487 | "node_modules/esbuild-linux-32": { 488 | "version": "0.14.47", 489 | "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.47.tgz", 490 | "integrity": "sha512-FxZOCKoEDPRYvq300lsWCTv1kcHgiiZfNrPtEhFAiqD7QZaXrad8LxyJ8fXGcWzIFzRiYZVtB3ttvITBvAFhKw==", 491 | "cpu": [ 492 | "ia32" 493 | ], 494 | "dev": true, 495 | "optional": true, 496 | "os": [ 497 | "linux" 498 | ], 499 | "engines": { 500 | "node": ">=12" 501 | } 502 | }, 503 | "node_modules/esbuild-linux-64": { 504 | "version": "0.14.47", 505 | "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.47.tgz", 506 | "integrity": "sha512-nFNOk9vWVfvWYF9YNYksZptgQAdstnDCMtR6m42l5Wfugbzu11VpMCY9XrD4yFxvPo9zmzcoUL/88y0lfJZJJw==", 507 | "cpu": [ 508 | "x64" 509 | ], 510 | "dev": true, 511 | "optional": true, 512 | "os": [ 513 | "linux" 514 | ], 515 | "engines": { 516 | "node": ">=12" 517 | } 518 | }, 519 | "node_modules/esbuild-linux-arm": { 520 | "version": "0.14.47", 521 | "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.47.tgz", 522 | "integrity": "sha512-ZGE1Bqg/gPRXrBpgpvH81tQHpiaGxa8c9Rx/XOylkIl2ypLuOcawXEAo8ls+5DFCcRGt/o3sV+PzpAFZobOsmA==", 523 | "cpu": [ 524 | "arm" 525 | ], 526 | "dev": true, 527 | "optional": true, 528 | "os": [ 529 | "linux" 530 | ], 531 | "engines": { 532 | "node": ">=12" 533 | } 534 | }, 535 | "node_modules/esbuild-linux-arm64": { 536 | "version": "0.14.47", 537 | "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.47.tgz", 538 | "integrity": "sha512-ywfme6HVrhWcevzmsufjd4iT3PxTfCX9HOdxA7Hd+/ZM23Y9nXeb+vG6AyA6jgq/JovkcqRHcL9XwRNpWG6XRw==", 539 | "cpu": [ 540 | "arm64" 541 | ], 542 | "dev": true, 543 | "optional": true, 544 | "os": [ 545 | "linux" 546 | ], 547 | "engines": { 548 | "node": ">=12" 549 | } 550 | }, 551 | "node_modules/esbuild-linux-mips64le": { 552 | "version": "0.14.47", 553 | "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.47.tgz", 554 | "integrity": "sha512-mg3D8YndZ1LvUiEdDYR3OsmeyAew4MA/dvaEJxvyygahWmpv1SlEEnhEZlhPokjsUMfRagzsEF/d/2XF+kTQGg==", 555 | "cpu": [ 556 | "mips64el" 557 | ], 558 | "dev": true, 559 | "optional": true, 560 | "os": [ 561 | "linux" 562 | ], 563 | "engines": { 564 | "node": ">=12" 565 | } 566 | }, 567 | "node_modules/esbuild-linux-ppc64le": { 568 | "version": "0.14.47", 569 | "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.47.tgz", 570 | "integrity": "sha512-WER+f3+szmnZiWoK6AsrTKGoJoErG2LlauSmk73LEZFQ/iWC+KhhDsOkn1xBUpzXWsxN9THmQFltLoaFEH8F8w==", 571 | "cpu": [ 572 | "ppc64" 573 | ], 574 | "dev": true, 575 | "optional": true, 576 | "os": [ 577 | "linux" 578 | ], 579 | "engines": { 580 | "node": ">=12" 581 | } 582 | }, 583 | "node_modules/esbuild-linux-riscv64": { 584 | "version": "0.14.47", 585 | "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.47.tgz", 586 | "integrity": "sha512-1fI6bP3A3rvI9BsaaXbMoaOjLE3lVkJtLxsgLHqlBhLlBVY7UqffWBvkrX/9zfPhhVMd9ZRFiaqXnB1T7BsL2g==", 587 | "cpu": [ 588 | "riscv64" 589 | ], 590 | "dev": true, 591 | "optional": true, 592 | "os": [ 593 | "linux" 594 | ], 595 | "engines": { 596 | "node": ">=12" 597 | } 598 | }, 599 | "node_modules/esbuild-linux-s390x": { 600 | "version": "0.14.47", 601 | "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.47.tgz", 602 | "integrity": "sha512-eZrWzy0xFAhki1CWRGnhsHVz7IlSKX6yT2tj2Eg8lhAwlRE5E96Hsb0M1mPSE1dHGpt1QVwwVivXIAacF/G6mw==", 603 | "cpu": [ 604 | "s390x" 605 | ], 606 | "dev": true, 607 | "optional": true, 608 | "os": [ 609 | "linux" 610 | ], 611 | "engines": { 612 | "node": ">=12" 613 | } 614 | }, 615 | "node_modules/esbuild-netbsd-64": { 616 | "version": "0.14.47", 617 | "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.47.tgz", 618 | "integrity": "sha512-Qjdjr+KQQVH5Q2Q1r6HBYswFTToPpss3gqCiSw2Fpq/ua8+eXSQyAMG+UvULPqXceOwpnPo4smyZyHdlkcPppQ==", 619 | "cpu": [ 620 | "x64" 621 | ], 622 | "dev": true, 623 | "optional": true, 624 | "os": [ 625 | "netbsd" 626 | ], 627 | "engines": { 628 | "node": ">=12" 629 | } 630 | }, 631 | "node_modules/esbuild-openbsd-64": { 632 | "version": "0.14.47", 633 | "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.47.tgz", 634 | "integrity": "sha512-QpgN8ofL7B9z8g5zZqJE+eFvD1LehRlxr25PBkjyyasakm4599iroUpaj96rdqRlO2ShuyqwJdr+oNqWwTUmQw==", 635 | "cpu": [ 636 | "x64" 637 | ], 638 | "dev": true, 639 | "optional": true, 640 | "os": [ 641 | "openbsd" 642 | ], 643 | "engines": { 644 | "node": ">=12" 645 | } 646 | }, 647 | "node_modules/esbuild-sunos-64": { 648 | "version": "0.14.47", 649 | "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.47.tgz", 650 | "integrity": "sha512-uOeSgLUwukLioAJOiGYm3kNl+1wJjgJA8R671GYgcPgCx7QR73zfvYqXFFcIO93/nBdIbt5hd8RItqbbf3HtAQ==", 651 | "cpu": [ 652 | "x64" 653 | ], 654 | "dev": true, 655 | "optional": true, 656 | "os": [ 657 | "sunos" 658 | ], 659 | "engines": { 660 | "node": ">=12" 661 | } 662 | }, 663 | "node_modules/esbuild-windows-32": { 664 | "version": "0.14.47", 665 | "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.47.tgz", 666 | "integrity": "sha512-H0fWsLTp2WBfKLBgwYT4OTfFly4Im/8B5f3ojDv1Kx//kiubVY0IQunP2Koc/fr/0wI7hj3IiBDbSrmKlrNgLQ==", 667 | "cpu": [ 668 | "ia32" 669 | ], 670 | "dev": true, 671 | "optional": true, 672 | "os": [ 673 | "win32" 674 | ], 675 | "engines": { 676 | "node": ">=12" 677 | } 678 | }, 679 | "node_modules/esbuild-windows-64": { 680 | "version": "0.14.47", 681 | "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.47.tgz", 682 | "integrity": "sha512-/Pk5jIEH34T68r8PweKRi77W49KwanZ8X6lr3vDAtOlH5EumPE4pBHqkCUdELanvsT14yMXLQ/C/8XPi1pAtkQ==", 683 | "cpu": [ 684 | "x64" 685 | ], 686 | "dev": true, 687 | "optional": true, 688 | "os": [ 689 | "win32" 690 | ], 691 | "engines": { 692 | "node": ">=12" 693 | } 694 | }, 695 | "node_modules/esbuild-windows-arm64": { 696 | "version": "0.14.47", 697 | "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.47.tgz", 698 | "integrity": "sha512-HFSW2lnp62fl86/qPQlqw6asIwCnEsEoNIL1h2uVMgakddf+vUuMcCbtUY1i8sst7KkgHrVKCJQB33YhhOweCQ==", 699 | "cpu": [ 700 | "arm64" 701 | ], 702 | "dev": true, 703 | "optional": true, 704 | "os": [ 705 | "win32" 706 | ], 707 | "engines": { 708 | "node": ">=12" 709 | } 710 | }, 711 | "node_modules/escape-string-regexp": { 712 | "version": "4.0.0", 713 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", 714 | "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", 715 | "dev": true, 716 | "engines": { 717 | "node": ">=10" 718 | }, 719 | "funding": { 720 | "url": "https://github.com/sponsors/sindresorhus" 721 | } 722 | }, 723 | "node_modules/estree-walker": { 724 | "version": "0.6.1", 725 | "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz", 726 | "integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==", 727 | "dev": true 728 | }, 729 | "node_modules/fsevents": { 730 | "version": "2.3.2", 731 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", 732 | "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", 733 | "dev": true, 734 | "hasInstallScript": true, 735 | "optional": true, 736 | "os": [ 737 | "darwin" 738 | ], 739 | "engines": { 740 | "node": "^8.16.0 || ^10.6.0 || >=11.0.0" 741 | } 742 | }, 743 | "node_modules/html-rewriter-wasm": { 744 | "version": "0.4.1", 745 | "resolved": "https://registry.npmjs.org/html-rewriter-wasm/-/html-rewriter-wasm-0.4.1.tgz", 746 | "integrity": "sha512-lNovG8CMCCmcVB1Q7xggMSf7tqPCijZXaH4gL6iE8BFghdQCbaY5Met9i1x2Ex8m/cZHDUtXK9H6/znKamRP8Q==", 747 | "dev": true 748 | }, 749 | "node_modules/http-cache-semantics": { 750 | "version": "4.1.0", 751 | "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", 752 | "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==", 753 | "dev": true 754 | }, 755 | "node_modules/ignore": { 756 | "version": "5.2.0", 757 | "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", 758 | "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", 759 | "dev": true, 760 | "engines": { 761 | "node": ">= 4" 762 | } 763 | }, 764 | "node_modules/kleur": { 765 | "version": "4.1.5", 766 | "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", 767 | "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", 768 | "dev": true, 769 | "engines": { 770 | "node": ">=6" 771 | } 772 | }, 773 | "node_modules/magic-string": { 774 | "version": "0.25.9", 775 | "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", 776 | "integrity": "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==", 777 | "dev": true, 778 | "dependencies": { 779 | "sourcemap-codec": "^1.4.8" 780 | } 781 | }, 782 | "node_modules/mime": { 783 | "version": "3.0.0", 784 | "resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz", 785 | "integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==", 786 | "dev": true, 787 | "bin": { 788 | "mime": "cli.js" 789 | }, 790 | "engines": { 791 | "node": ">=10.0.0" 792 | } 793 | }, 794 | "node_modules/miniflare": { 795 | "version": "2.6.0", 796 | "resolved": "https://registry.npmjs.org/miniflare/-/miniflare-2.6.0.tgz", 797 | "integrity": "sha512-KDAQZV2aDZ044X1ihlCIa6DPdq1w3fUJFW4xZ+r+DPUxj9t1AuehjR9Fc6zCmZQrk12gLXDSZSyNft1ozm1X7Q==", 798 | "dev": true, 799 | "dependencies": { 800 | "@miniflare/cache": "2.6.0", 801 | "@miniflare/cli-parser": "2.6.0", 802 | "@miniflare/core": "2.6.0", 803 | "@miniflare/durable-objects": "2.6.0", 804 | "@miniflare/html-rewriter": "2.6.0", 805 | "@miniflare/http-server": "2.6.0", 806 | "@miniflare/kv": "2.6.0", 807 | "@miniflare/r2": "2.6.0", 808 | "@miniflare/runner-vm": "2.6.0", 809 | "@miniflare/scheduler": "2.6.0", 810 | "@miniflare/shared": "2.6.0", 811 | "@miniflare/sites": "2.6.0", 812 | "@miniflare/storage-file": "2.6.0", 813 | "@miniflare/storage-memory": "2.6.0", 814 | "@miniflare/web-sockets": "2.6.0", 815 | "kleur": "^4.1.4", 816 | "semiver": "^1.1.0", 817 | "source-map-support": "^0.5.20", 818 | "undici": "5.5.1" 819 | }, 820 | "bin": { 821 | "miniflare": "bootstrap.js" 822 | }, 823 | "engines": { 824 | "node": ">=16.7" 825 | }, 826 | "peerDependencies": { 827 | "@miniflare/storage-redis": "2.6.0", 828 | "cron-schedule": "^3.0.4", 829 | "ioredis": "^4.27.9" 830 | }, 831 | "peerDependenciesMeta": { 832 | "@miniflare/storage-redis": { 833 | "optional": true 834 | }, 835 | "cron-schedule": { 836 | "optional": true 837 | }, 838 | "ioredis": { 839 | "optional": true 840 | } 841 | } 842 | }, 843 | "node_modules/mustache": { 844 | "version": "4.2.0", 845 | "resolved": "https://registry.npmjs.org/mustache/-/mustache-4.2.0.tgz", 846 | "integrity": "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==", 847 | "dev": true, 848 | "bin": { 849 | "mustache": "bin/mustache" 850 | } 851 | }, 852 | "node_modules/nanoid": { 853 | "version": "3.3.4", 854 | "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", 855 | "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", 856 | "dev": true, 857 | "bin": { 858 | "nanoid": "bin/nanoid.cjs" 859 | }, 860 | "engines": { 861 | "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" 862 | } 863 | }, 864 | "node_modules/node-forge": { 865 | "version": "1.3.1", 866 | "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", 867 | "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", 868 | "dev": true, 869 | "engines": { 870 | "node": ">= 6.13.0" 871 | } 872 | }, 873 | "node_modules/path-to-regexp": { 874 | "version": "6.2.1", 875 | "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.2.1.tgz", 876 | "integrity": "sha512-JLyh7xT1kizaEvcaXOQwOc2/Yhw6KZOvPf1S8401UyLk86CU79LN3vl7ztXGm/pZ+YjoyAJ4rxmHwbkBXJX+yw==", 877 | "dev": true 878 | }, 879 | "node_modules/rollup-plugin-inject": { 880 | "version": "3.0.2", 881 | "resolved": "https://registry.npmjs.org/rollup-plugin-inject/-/rollup-plugin-inject-3.0.2.tgz", 882 | "integrity": "sha512-ptg9PQwzs3orn4jkgXJ74bfs5vYz1NCZlSQMBUA0wKcGp5i5pA1AO3fOUEte8enhGUC+iapTCzEWw2jEFFUO/w==", 883 | "deprecated": "This package has been deprecated and is no longer maintained. Please use @rollup/plugin-inject.", 884 | "dev": true, 885 | "dependencies": { 886 | "estree-walker": "^0.6.1", 887 | "magic-string": "^0.25.3", 888 | "rollup-pluginutils": "^2.8.1" 889 | } 890 | }, 891 | "node_modules/rollup-plugin-node-polyfills": { 892 | "version": "0.2.1", 893 | "resolved": "https://registry.npmjs.org/rollup-plugin-node-polyfills/-/rollup-plugin-node-polyfills-0.2.1.tgz", 894 | "integrity": "sha512-4kCrKPTJ6sK4/gLL/U5QzVT8cxJcofO0OU74tnB19F40cmuAKSzH5/siithxlofFEjwvw1YAhPmbvGNA6jEroA==", 895 | "dev": true, 896 | "dependencies": { 897 | "rollup-plugin-inject": "^3.0.0" 898 | } 899 | }, 900 | "node_modules/rollup-pluginutils": { 901 | "version": "2.8.2", 902 | "resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz", 903 | "integrity": "sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==", 904 | "dev": true, 905 | "dependencies": { 906 | "estree-walker": "^0.6.1" 907 | } 908 | }, 909 | "node_modules/selfsigned": { 910 | "version": "2.0.1", 911 | "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.0.1.tgz", 912 | "integrity": "sha512-LmME957M1zOsUhG+67rAjKfiWFox3SBxE/yymatMZsAx+oMrJ0YQ8AToOnyCm7xbeg2ep37IHLxdu0o2MavQOQ==", 913 | "dev": true, 914 | "dependencies": { 915 | "node-forge": "^1" 916 | }, 917 | "engines": { 918 | "node": ">=10" 919 | } 920 | }, 921 | "node_modules/semiver": { 922 | "version": "1.1.0", 923 | "resolved": "https://registry.npmjs.org/semiver/-/semiver-1.1.0.tgz", 924 | "integrity": "sha512-QNI2ChmuioGC1/xjyYwyZYADILWyW6AmS1UH6gDj/SFUUUS4MBAWs/7mxnkRPc/F4iHezDP+O8t0dO8WHiEOdg==", 925 | "dev": true, 926 | "engines": { 927 | "node": ">=6" 928 | } 929 | }, 930 | "node_modules/set-cookie-parser": { 931 | "version": "2.5.0", 932 | "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.5.0.tgz", 933 | "integrity": "sha512-cHMAtSXilfyBePduZEBVPTCftTQWz6ehWJD5YNUg4mqvRosrrjKbo4WS8JkB0/RxonMoohHm7cOGH60mDkRQ9w==", 934 | "dev": true 935 | }, 936 | "node_modules/source-map": { 937 | "version": "0.6.1", 938 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", 939 | "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", 940 | "dev": true, 941 | "engines": { 942 | "node": ">=0.10.0" 943 | } 944 | }, 945 | "node_modules/source-map-support": { 946 | "version": "0.5.21", 947 | "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", 948 | "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", 949 | "dev": true, 950 | "dependencies": { 951 | "buffer-from": "^1.0.0", 952 | "source-map": "^0.6.0" 953 | } 954 | }, 955 | "node_modules/sourcemap-codec": { 956 | "version": "1.4.8", 957 | "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", 958 | "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", 959 | "dev": true 960 | }, 961 | "node_modules/stack-trace": { 962 | "version": "0.0.10", 963 | "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", 964 | "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==", 965 | "dev": true, 966 | "engines": { 967 | "node": "*" 968 | } 969 | }, 970 | "node_modules/streamsearch": { 971 | "version": "1.1.0", 972 | "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", 973 | "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", 974 | "dev": true, 975 | "engines": { 976 | "node": ">=10.0.0" 977 | } 978 | }, 979 | "node_modules/typescript": { 980 | "version": "4.7.4", 981 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz", 982 | "integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==", 983 | "dev": true, 984 | "bin": { 985 | "tsc": "bin/tsc", 986 | "tsserver": "bin/tsserver" 987 | }, 988 | "engines": { 989 | "node": ">=4.2.0" 990 | } 991 | }, 992 | "node_modules/undici": { 993 | "version": "5.5.1", 994 | "resolved": "https://registry.npmjs.org/undici/-/undici-5.5.1.tgz", 995 | "integrity": "sha512-MEvryPLf18HvlCbLSzCW0U00IMftKGI5udnjrQbC5D4P0Hodwffhv+iGfWuJwg16Y/TK11ZFK8i+BPVW2z/eAw==", 996 | "dev": true, 997 | "engines": { 998 | "node": ">=12.18" 999 | } 1000 | }, 1001 | "node_modules/urlpattern-polyfill": { 1002 | "version": "4.0.3", 1003 | "resolved": "https://registry.npmjs.org/urlpattern-polyfill/-/urlpattern-polyfill-4.0.3.tgz", 1004 | "integrity": "sha512-DOE84vZT2fEcl9gqCUTcnAw5ZY5Id55ikUcziSUntuEFL3pRvavg5kwDmTEUJkeCHInTlV/HexFomgYnzO5kdQ==", 1005 | "dev": true 1006 | }, 1007 | "node_modules/wrangler": { 1008 | "version": "2.0.17", 1009 | "resolved": "https://registry.npmjs.org/wrangler/-/wrangler-2.0.17.tgz", 1010 | "integrity": "sha512-U4PSx1j0JUPX/fDvQSqeCVZeAww+DLZkm1tWeFovOxgzpvpvZ/2s+2IINR+dhw4FGiSpDUsQgiA4EDm64fV4RA==", 1011 | "dev": true, 1012 | "dependencies": { 1013 | "@cloudflare/kv-asset-handler": "^0.2.0", 1014 | "@esbuild-plugins/node-globals-polyfill": "^0.1.1", 1015 | "@esbuild-plugins/node-modules-polyfill": "^0.1.4", 1016 | "blake3-wasm": "^2.1.5", 1017 | "esbuild": "0.14.47", 1018 | "miniflare": "^2.6.0", 1019 | "nanoid": "^3.3.3", 1020 | "path-to-regexp": "^6.2.0", 1021 | "selfsigned": "^2.0.1", 1022 | "semiver": "^1.1.0", 1023 | "xxhash-wasm": "^1.0.1" 1024 | }, 1025 | "bin": { 1026 | "wrangler": "bin/wrangler.js", 1027 | "wrangler2": "bin/wrangler.js" 1028 | }, 1029 | "engines": { 1030 | "node": ">=16.7.0" 1031 | }, 1032 | "optionalDependencies": { 1033 | "fsevents": "~2.3.2" 1034 | } 1035 | }, 1036 | "node_modules/ws": { 1037 | "version": "8.8.0", 1038 | "resolved": "https://registry.npmjs.org/ws/-/ws-8.8.0.tgz", 1039 | "integrity": "sha512-JDAgSYQ1ksuwqfChJusw1LSJ8BizJ2e/vVu5Lxjq3YvNJNlROv1ui4i+c/kUUrPheBvQl4c5UbERhTwKa6QBJQ==", 1040 | "dev": true, 1041 | "engines": { 1042 | "node": ">=10.0.0" 1043 | }, 1044 | "peerDependencies": { 1045 | "bufferutil": "^4.0.1", 1046 | "utf-8-validate": "^5.0.2" 1047 | }, 1048 | "peerDependenciesMeta": { 1049 | "bufferutil": { 1050 | "optional": true 1051 | }, 1052 | "utf-8-validate": { 1053 | "optional": true 1054 | } 1055 | } 1056 | }, 1057 | "node_modules/xxhash-wasm": { 1058 | "version": "1.0.1", 1059 | "resolved": "https://registry.npmjs.org/xxhash-wasm/-/xxhash-wasm-1.0.1.tgz", 1060 | "integrity": "sha512-Lc9CTvDrH2vRoiaUzz25q7lRaviMhz90pkx6YxR9EPYtF99yOJnv2cB+CQ0hp/TLoqrUsk8z/W2EN31T568Azw==", 1061 | "dev": true 1062 | }, 1063 | "node_modules/youch": { 1064 | "version": "2.2.2", 1065 | "resolved": "https://registry.npmjs.org/youch/-/youch-2.2.2.tgz", 1066 | "integrity": "sha512-/FaCeG3GkuJwaMR34GHVg0l8jCbafZLHiFowSjqLlqhC6OMyf2tPJBu8UirF7/NI9X/R5ai4QfEKUCOxMAGxZQ==", 1067 | "dev": true, 1068 | "dependencies": { 1069 | "@types/stack-trace": "0.0.29", 1070 | "cookie": "^0.4.1", 1071 | "mustache": "^4.2.0", 1072 | "stack-trace": "0.0.10" 1073 | } 1074 | } 1075 | }, 1076 | "dependencies": { 1077 | "@cloudflare/kv-asset-handler": { 1078 | "version": "0.2.0", 1079 | "resolved": "https://registry.npmjs.org/@cloudflare/kv-asset-handler/-/kv-asset-handler-0.2.0.tgz", 1080 | "integrity": "sha512-MVbXLbTcAotOPUj0pAMhVtJ+3/kFkwJqc5qNOleOZTv6QkZZABDMS21dSrSlVswEHwrpWC03e4fWytjqKvuE2A==", 1081 | "dev": true, 1082 | "requires": { 1083 | "mime": "^3.0.0" 1084 | } 1085 | }, 1086 | "@cloudflare/workers-types": { 1087 | "version": "3.14.1", 1088 | "resolved": "https://registry.npmjs.org/@cloudflare/workers-types/-/workers-types-3.14.1.tgz", 1089 | "integrity": "sha512-B1/plF62pt+H2IJHvApK8fdOJAVsvojvacuac8x8s+JIyqbropMyqNqHTKLm3YD8ZFLGwYeFTudU+PQ7vGvBdA==", 1090 | "dev": true 1091 | }, 1092 | "@deno/shim-crypto": { 1093 | "version": "0.3.1", 1094 | "resolved": "https://registry.npmjs.org/@deno/shim-crypto/-/shim-crypto-0.3.1.tgz", 1095 | "integrity": "sha512-ed4pNnfur6UbASEgF34gVxR9p7Mc3qF+Ygbmjiil8ws5IhNFhPDFy5vE5hQAUA9JmVsSxXPcVLM5Rf8LOZqQ5Q==" 1096 | }, 1097 | "@esbuild-plugins/node-globals-polyfill": { 1098 | "version": "0.1.1", 1099 | "resolved": "https://registry.npmjs.org/@esbuild-plugins/node-globals-polyfill/-/node-globals-polyfill-0.1.1.tgz", 1100 | "integrity": "sha512-MR0oAA+mlnJWrt1RQVQ+4VYuRJW/P2YmRTv1AsplObyvuBMnPHiizUF95HHYiSsMGLhyGtWufaq2XQg6+iurBg==", 1101 | "dev": true, 1102 | "requires": {} 1103 | }, 1104 | "@esbuild-plugins/node-modules-polyfill": { 1105 | "version": "0.1.4", 1106 | "resolved": "https://registry.npmjs.org/@esbuild-plugins/node-modules-polyfill/-/node-modules-polyfill-0.1.4.tgz", 1107 | "integrity": "sha512-uZbcXi0zbmKC/050p3gJnne5Qdzw8vkXIv+c2BW0Lsc1ji1SkrxbKPUy5Efr0blbTu1SL8w4eyfpnSdPg3G0Qg==", 1108 | "dev": true, 1109 | "requires": { 1110 | "escape-string-regexp": "^4.0.0", 1111 | "rollup-plugin-node-polyfills": "^0.2.1" 1112 | } 1113 | }, 1114 | "@iarna/toml": { 1115 | "version": "2.2.5", 1116 | "resolved": "https://registry.npmjs.org/@iarna/toml/-/toml-2.2.5.tgz", 1117 | "integrity": "sha512-trnsAYxU3xnS1gPHPyU961coFyLkh4gAD/0zQ5mymY4yOZ+CYvsPqUbOFSw0aDM4y0tV7tiFxL/1XfXPNC6IPg==", 1118 | "dev": true 1119 | }, 1120 | "@miniflare/cache": { 1121 | "version": "2.6.0", 1122 | "resolved": "https://registry.npmjs.org/@miniflare/cache/-/cache-2.6.0.tgz", 1123 | "integrity": "sha512-4oh8MgpquoxaslI7Z8sMzmEZR0Dc+L3aEh69o9d8ZCs4nUdOENnfKlY50O5nEnL7nhhyAljkMBaXD2wAH2DLeQ==", 1124 | "dev": true, 1125 | "requires": { 1126 | "@miniflare/core": "2.6.0", 1127 | "@miniflare/shared": "2.6.0", 1128 | "http-cache-semantics": "^4.1.0", 1129 | "undici": "5.5.1" 1130 | } 1131 | }, 1132 | "@miniflare/cli-parser": { 1133 | "version": "2.6.0", 1134 | "resolved": "https://registry.npmjs.org/@miniflare/cli-parser/-/cli-parser-2.6.0.tgz", 1135 | "integrity": "sha512-dJDoIPAUqWhzvBHHyqyhobdzDedBYRWZ4yItBi9m4MTU/EneLJ5jryB340SwUnmtBMZxUh/LWdAuUEkKpdVNyA==", 1136 | "dev": true, 1137 | "requires": { 1138 | "@miniflare/shared": "2.6.0", 1139 | "kleur": "^4.1.4" 1140 | } 1141 | }, 1142 | "@miniflare/core": { 1143 | "version": "2.6.0", 1144 | "resolved": "https://registry.npmjs.org/@miniflare/core/-/core-2.6.0.tgz", 1145 | "integrity": "sha512-CmofhIRot++GI7NHPMwzNb65+0hWLN186L91BrH/doPVHnT/itmEfzYQpL9bFLD0c/i14dfv+IUNetDdGEBIrw==", 1146 | "dev": true, 1147 | "requires": { 1148 | "@iarna/toml": "^2.2.5", 1149 | "@miniflare/shared": "2.6.0", 1150 | "@miniflare/watcher": "2.6.0", 1151 | "busboy": "^1.6.0", 1152 | "dotenv": "^10.0.0", 1153 | "kleur": "^4.1.4", 1154 | "set-cookie-parser": "^2.4.8", 1155 | "undici": "5.5.1", 1156 | "urlpattern-polyfill": "^4.0.3" 1157 | } 1158 | }, 1159 | "@miniflare/durable-objects": { 1160 | "version": "2.6.0", 1161 | "resolved": "https://registry.npmjs.org/@miniflare/durable-objects/-/durable-objects-2.6.0.tgz", 1162 | "integrity": "sha512-uzWoGFtkIIh3m3HAzqd5f86nOSC0xFli6dq2q7ilE3UjgouOcLqObxJyE/IzvSwsj4DUWFv6//YDfHihK2fGAA==", 1163 | "dev": true, 1164 | "requires": { 1165 | "@miniflare/core": "2.6.0", 1166 | "@miniflare/shared": "2.6.0", 1167 | "@miniflare/storage-memory": "2.6.0", 1168 | "undici": "5.5.1" 1169 | } 1170 | }, 1171 | "@miniflare/html-rewriter": { 1172 | "version": "2.6.0", 1173 | "resolved": "https://registry.npmjs.org/@miniflare/html-rewriter/-/html-rewriter-2.6.0.tgz", 1174 | "integrity": "sha512-+JqFlIDLzstb/Spj+j/kI6uHzolrqjsMks3Tf24Q4YFo9YYdZguqUFcDz2yr79ZTP/SKXaZH+AYqosnJps4dHQ==", 1175 | "dev": true, 1176 | "requires": { 1177 | "@miniflare/core": "2.6.0", 1178 | "@miniflare/shared": "2.6.0", 1179 | "html-rewriter-wasm": "^0.4.1", 1180 | "undici": "5.5.1" 1181 | } 1182 | }, 1183 | "@miniflare/http-server": { 1184 | "version": "2.6.0", 1185 | "resolved": "https://registry.npmjs.org/@miniflare/http-server/-/http-server-2.6.0.tgz", 1186 | "integrity": "sha512-FhcAVIpipMEzMCsJBc/b0JhNEJ66GPX60vA2NcqjGKHYbwoPCPlwCFQq2giPzW/R95ugrEjPfo4/5Q4UbnpoGA==", 1187 | "dev": true, 1188 | "requires": { 1189 | "@miniflare/core": "2.6.0", 1190 | "@miniflare/shared": "2.6.0", 1191 | "@miniflare/web-sockets": "2.6.0", 1192 | "kleur": "^4.1.4", 1193 | "selfsigned": "^2.0.0", 1194 | "undici": "5.5.1", 1195 | "ws": "^8.2.2", 1196 | "youch": "^2.2.2" 1197 | } 1198 | }, 1199 | "@miniflare/kv": { 1200 | "version": "2.6.0", 1201 | "resolved": "https://registry.npmjs.org/@miniflare/kv/-/kv-2.6.0.tgz", 1202 | "integrity": "sha512-7Q+Q0Wwinsz85qpKLlBeXSCLweiVowpMJ5AmQpmELnTya59HQ24cOUHxPd64hXFhdYXVIxOmk6lQaZ21JhdHGQ==", 1203 | "dev": true, 1204 | "requires": { 1205 | "@miniflare/shared": "2.6.0" 1206 | } 1207 | }, 1208 | "@miniflare/r2": { 1209 | "version": "2.6.0", 1210 | "resolved": "https://registry.npmjs.org/@miniflare/r2/-/r2-2.6.0.tgz", 1211 | "integrity": "sha512-Ymbqu17ajtuk9b11txF2h1Ewqqlu3XCCpAwAgCQa6AK1yRidQECCPq9w9oXZxE1p5aaSuLTOUbgSdtveFCsLxQ==", 1212 | "dev": true, 1213 | "requires": { 1214 | "@miniflare/shared": "2.6.0", 1215 | "undici": "5.5.1" 1216 | } 1217 | }, 1218 | "@miniflare/runner-vm": { 1219 | "version": "2.6.0", 1220 | "resolved": "https://registry.npmjs.org/@miniflare/runner-vm/-/runner-vm-2.6.0.tgz", 1221 | "integrity": "sha512-ZxsiVMMUcjb01LwrO2t50YbU5PT5s3k7DrmR5185R/n04K5BikqZz8eQf8lKlQQYem0BROqmmQgurZGw0a2HUw==", 1222 | "dev": true, 1223 | "requires": { 1224 | "@miniflare/shared": "2.6.0" 1225 | } 1226 | }, 1227 | "@miniflare/scheduler": { 1228 | "version": "2.6.0", 1229 | "resolved": "https://registry.npmjs.org/@miniflare/scheduler/-/scheduler-2.6.0.tgz", 1230 | "integrity": "sha512-BM+RDF+8twkTCOb7Oz0NIs5phzAVJ/Gx7tFZR23fGsZjWRnE3TBeqfzaNutU9pcoWDZtBQqEJMeTeb0KZTo75Q==", 1231 | "dev": true, 1232 | "requires": { 1233 | "@miniflare/core": "2.6.0", 1234 | "@miniflare/shared": "2.6.0", 1235 | "cron-schedule": "^3.0.4" 1236 | } 1237 | }, 1238 | "@miniflare/shared": { 1239 | "version": "2.6.0", 1240 | "resolved": "https://registry.npmjs.org/@miniflare/shared/-/shared-2.6.0.tgz", 1241 | "integrity": "sha512-/7k4C37GF0INu99LNFmFhHYL6U9/oRY/nWDa5sr6+lPEKKm2rkmfvDIA+YNAj7Ql61ZWMgEMj0S3NhV0rWkj7Q==", 1242 | "dev": true, 1243 | "requires": { 1244 | "ignore": "^5.1.8", 1245 | "kleur": "^4.1.4" 1246 | } 1247 | }, 1248 | "@miniflare/sites": { 1249 | "version": "2.6.0", 1250 | "resolved": "https://registry.npmjs.org/@miniflare/sites/-/sites-2.6.0.tgz", 1251 | "integrity": "sha512-XfWhpREC638LOGNmuHaPn1MAz1sh2mz+VdMsjRCzUo6NwPl4IcUhnorJR62Xr0qmI/RqVMTZbvzrChXio4Bi4A==", 1252 | "dev": true, 1253 | "requires": { 1254 | "@miniflare/kv": "2.6.0", 1255 | "@miniflare/shared": "2.6.0", 1256 | "@miniflare/storage-file": "2.6.0" 1257 | } 1258 | }, 1259 | "@miniflare/storage-file": { 1260 | "version": "2.6.0", 1261 | "resolved": "https://registry.npmjs.org/@miniflare/storage-file/-/storage-file-2.6.0.tgz", 1262 | "integrity": "sha512-xprDVJClQ2X1vXVPM16WQZz3rS+6fNuCYC8bfEFHABDByQoUNDpk8q+m1IpTaFXYivYxRhE+xr7eK2QQP068tA==", 1263 | "dev": true, 1264 | "requires": { 1265 | "@miniflare/shared": "2.6.0", 1266 | "@miniflare/storage-memory": "2.6.0" 1267 | } 1268 | }, 1269 | "@miniflare/storage-memory": { 1270 | "version": "2.6.0", 1271 | "resolved": "https://registry.npmjs.org/@miniflare/storage-memory/-/storage-memory-2.6.0.tgz", 1272 | "integrity": "sha512-0EwELTG2r6IC4AMlQv0YXRZdw9g/lCydceuGKeFkWAVb55pY+yMBxkJO9VV7QOrEx8MLsR8tsfl5SBK3AkfLtA==", 1273 | "dev": true, 1274 | "requires": { 1275 | "@miniflare/shared": "2.6.0" 1276 | } 1277 | }, 1278 | "@miniflare/watcher": { 1279 | "version": "2.6.0", 1280 | "resolved": "https://registry.npmjs.org/@miniflare/watcher/-/watcher-2.6.0.tgz", 1281 | "integrity": "sha512-mttfhNDmEIFo2rWF73JeWj1TLN+3cQC1TFhbtLApz9bXilLywArXMYqDJGA8PUnJCFM/8k2FDjaFNiPy6ggIJw==", 1282 | "dev": true, 1283 | "requires": { 1284 | "@miniflare/shared": "2.6.0" 1285 | } 1286 | }, 1287 | "@miniflare/web-sockets": { 1288 | "version": "2.6.0", 1289 | "resolved": "https://registry.npmjs.org/@miniflare/web-sockets/-/web-sockets-2.6.0.tgz", 1290 | "integrity": "sha512-ePbcuP9LrStVTllZzqx2oNVoOpceyU3jJF3nGDMNW5+bqB+BdeTggSF8rhER7omcSCswCMY2Do6VelIcAXHkXA==", 1291 | "dev": true, 1292 | "requires": { 1293 | "@miniflare/core": "2.6.0", 1294 | "@miniflare/shared": "2.6.0", 1295 | "undici": "5.5.1", 1296 | "ws": "^8.2.2" 1297 | } 1298 | }, 1299 | "@types/stack-trace": { 1300 | "version": "0.0.29", 1301 | "resolved": "https://registry.npmjs.org/@types/stack-trace/-/stack-trace-0.0.29.tgz", 1302 | "integrity": "sha512-TgfOX+mGY/NyNxJLIbDWrO9DjGoVSW9+aB8H2yy1fy32jsvxijhmyJI9fDFgvz3YP4lvJaq9DzdR/M1bOgVc9g==", 1303 | "dev": true 1304 | }, 1305 | "@upstash/qstash": { 1306 | "version": "0.1.2", 1307 | "resolved": "https://registry.npmjs.org/@upstash/qstash/-/qstash-0.1.2.tgz", 1308 | "integrity": "sha512-lM/PRfyuc3QPs0Yz4bfl5gT0P0DYMp05RcLbeenziv7DqYx9wMeMiLs5veEJzeMhHcSmjCKDYgL0zzsSW0SP4w==", 1309 | "requires": { 1310 | "@deno/shim-crypto": "~0.3.0" 1311 | } 1312 | }, 1313 | "blake3-wasm": { 1314 | "version": "2.1.5", 1315 | "resolved": "https://registry.npmjs.org/blake3-wasm/-/blake3-wasm-2.1.5.tgz", 1316 | "integrity": "sha512-F1+K8EbfOZE49dtoPtmxUQrpXaBIl3ICvasLh+nJta0xkz+9kF/7uet9fLnwKqhDrmj6g+6K3Tw9yQPUg2ka5g==", 1317 | "dev": true 1318 | }, 1319 | "buffer-from": { 1320 | "version": "1.1.2", 1321 | "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", 1322 | "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", 1323 | "dev": true 1324 | }, 1325 | "busboy": { 1326 | "version": "1.6.0", 1327 | "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", 1328 | "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", 1329 | "dev": true, 1330 | "requires": { 1331 | "streamsearch": "^1.1.0" 1332 | } 1333 | }, 1334 | "cookie": { 1335 | "version": "0.4.2", 1336 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", 1337 | "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", 1338 | "dev": true 1339 | }, 1340 | "cron-schedule": { 1341 | "version": "3.0.6", 1342 | "resolved": "https://registry.npmjs.org/cron-schedule/-/cron-schedule-3.0.6.tgz", 1343 | "integrity": "sha512-izfGgKyzzIyLaeb1EtZ3KbglkS6AKp9cv7LxmiyoOu+fXfol1tQDC0Cof0enVZGNtudTHW+3lfuW9ZkLQss4Wg==", 1344 | "dev": true 1345 | }, 1346 | "dotenv": { 1347 | "version": "10.0.0", 1348 | "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz", 1349 | "integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==", 1350 | "dev": true 1351 | }, 1352 | "esbuild": { 1353 | "version": "0.14.47", 1354 | "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.47.tgz", 1355 | "integrity": "sha512-wI4ZiIfFxpkuxB8ju4MHrGwGLyp1+awEHAHVpx6w7a+1pmYIq8T9FGEVVwFo0iFierDoMj++Xq69GXWYn2EiwA==", 1356 | "dev": true, 1357 | "requires": { 1358 | "esbuild-android-64": "0.14.47", 1359 | "esbuild-android-arm64": "0.14.47", 1360 | "esbuild-darwin-64": "0.14.47", 1361 | "esbuild-darwin-arm64": "0.14.47", 1362 | "esbuild-freebsd-64": "0.14.47", 1363 | "esbuild-freebsd-arm64": "0.14.47", 1364 | "esbuild-linux-32": "0.14.47", 1365 | "esbuild-linux-64": "0.14.47", 1366 | "esbuild-linux-arm": "0.14.47", 1367 | "esbuild-linux-arm64": "0.14.47", 1368 | "esbuild-linux-mips64le": "0.14.47", 1369 | "esbuild-linux-ppc64le": "0.14.47", 1370 | "esbuild-linux-riscv64": "0.14.47", 1371 | "esbuild-linux-s390x": "0.14.47", 1372 | "esbuild-netbsd-64": "0.14.47", 1373 | "esbuild-openbsd-64": "0.14.47", 1374 | "esbuild-sunos-64": "0.14.47", 1375 | "esbuild-windows-32": "0.14.47", 1376 | "esbuild-windows-64": "0.14.47", 1377 | "esbuild-windows-arm64": "0.14.47" 1378 | } 1379 | }, 1380 | "esbuild-android-64": { 1381 | "version": "0.14.47", 1382 | "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.14.47.tgz", 1383 | "integrity": "sha512-R13Bd9+tqLVFndncMHssZrPWe6/0Kpv2/dt4aA69soX4PRxlzsVpCvoJeFE8sOEoeVEiBkI0myjlkDodXlHa0g==", 1384 | "dev": true, 1385 | "optional": true 1386 | }, 1387 | "esbuild-android-arm64": { 1388 | "version": "0.14.47", 1389 | "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.47.tgz", 1390 | "integrity": "sha512-OkwOjj7ts4lBp/TL6hdd8HftIzOy/pdtbrNA4+0oVWgGG64HrdVzAF5gxtJufAPOsEjkyh1oIYvKAUinKKQRSQ==", 1391 | "dev": true, 1392 | "optional": true 1393 | }, 1394 | "esbuild-darwin-64": { 1395 | "version": "0.14.47", 1396 | "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.47.tgz", 1397 | "integrity": "sha512-R6oaW0y5/u6Eccti/TS6c/2c1xYTb1izwK3gajJwi4vIfNs1s8B1dQzI1UiC9T61YovOQVuePDcfqHLT3mUZJA==", 1398 | "dev": true, 1399 | "optional": true 1400 | }, 1401 | "esbuild-darwin-arm64": { 1402 | "version": "0.14.47", 1403 | "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.47.tgz", 1404 | "integrity": "sha512-seCmearlQyvdvM/noz1L9+qblC5vcBrhUaOoLEDDoLInF/VQ9IkobGiLlyTPYP5dW1YD4LXhtBgOyevoIHGGnw==", 1405 | "dev": true, 1406 | "optional": true 1407 | }, 1408 | "esbuild-freebsd-64": { 1409 | "version": "0.14.47", 1410 | "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.47.tgz", 1411 | "integrity": "sha512-ZH8K2Q8/Ux5kXXvQMDsJcxvkIwut69KVrYQhza/ptkW50DC089bCVrJZZ3sKzIoOx+YPTrmsZvqeZERjyYrlvQ==", 1412 | "dev": true, 1413 | "optional": true 1414 | }, 1415 | "esbuild-freebsd-arm64": { 1416 | "version": "0.14.47", 1417 | "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.47.tgz", 1418 | "integrity": "sha512-ZJMQAJQsIOhn3XTm7MPQfCzEu5b9STNC+s90zMWe2afy9EwnHV7Ov7ohEMv2lyWlc2pjqLW8QJnz2r0KZmeAEQ==", 1419 | "dev": true, 1420 | "optional": true 1421 | }, 1422 | "esbuild-linux-32": { 1423 | "version": "0.14.47", 1424 | "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.47.tgz", 1425 | "integrity": "sha512-FxZOCKoEDPRYvq300lsWCTv1kcHgiiZfNrPtEhFAiqD7QZaXrad8LxyJ8fXGcWzIFzRiYZVtB3ttvITBvAFhKw==", 1426 | "dev": true, 1427 | "optional": true 1428 | }, 1429 | "esbuild-linux-64": { 1430 | "version": "0.14.47", 1431 | "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.47.tgz", 1432 | "integrity": "sha512-nFNOk9vWVfvWYF9YNYksZptgQAdstnDCMtR6m42l5Wfugbzu11VpMCY9XrD4yFxvPo9zmzcoUL/88y0lfJZJJw==", 1433 | "dev": true, 1434 | "optional": true 1435 | }, 1436 | "esbuild-linux-arm": { 1437 | "version": "0.14.47", 1438 | "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.47.tgz", 1439 | "integrity": "sha512-ZGE1Bqg/gPRXrBpgpvH81tQHpiaGxa8c9Rx/XOylkIl2ypLuOcawXEAo8ls+5DFCcRGt/o3sV+PzpAFZobOsmA==", 1440 | "dev": true, 1441 | "optional": true 1442 | }, 1443 | "esbuild-linux-arm64": { 1444 | "version": "0.14.47", 1445 | "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.47.tgz", 1446 | "integrity": "sha512-ywfme6HVrhWcevzmsufjd4iT3PxTfCX9HOdxA7Hd+/ZM23Y9nXeb+vG6AyA6jgq/JovkcqRHcL9XwRNpWG6XRw==", 1447 | "dev": true, 1448 | "optional": true 1449 | }, 1450 | "esbuild-linux-mips64le": { 1451 | "version": "0.14.47", 1452 | "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.47.tgz", 1453 | "integrity": "sha512-mg3D8YndZ1LvUiEdDYR3OsmeyAew4MA/dvaEJxvyygahWmpv1SlEEnhEZlhPokjsUMfRagzsEF/d/2XF+kTQGg==", 1454 | "dev": true, 1455 | "optional": true 1456 | }, 1457 | "esbuild-linux-ppc64le": { 1458 | "version": "0.14.47", 1459 | "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.47.tgz", 1460 | "integrity": "sha512-WER+f3+szmnZiWoK6AsrTKGoJoErG2LlauSmk73LEZFQ/iWC+KhhDsOkn1xBUpzXWsxN9THmQFltLoaFEH8F8w==", 1461 | "dev": true, 1462 | "optional": true 1463 | }, 1464 | "esbuild-linux-riscv64": { 1465 | "version": "0.14.47", 1466 | "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.47.tgz", 1467 | "integrity": "sha512-1fI6bP3A3rvI9BsaaXbMoaOjLE3lVkJtLxsgLHqlBhLlBVY7UqffWBvkrX/9zfPhhVMd9ZRFiaqXnB1T7BsL2g==", 1468 | "dev": true, 1469 | "optional": true 1470 | }, 1471 | "esbuild-linux-s390x": { 1472 | "version": "0.14.47", 1473 | "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.47.tgz", 1474 | "integrity": "sha512-eZrWzy0xFAhki1CWRGnhsHVz7IlSKX6yT2tj2Eg8lhAwlRE5E96Hsb0M1mPSE1dHGpt1QVwwVivXIAacF/G6mw==", 1475 | "dev": true, 1476 | "optional": true 1477 | }, 1478 | "esbuild-netbsd-64": { 1479 | "version": "0.14.47", 1480 | "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.47.tgz", 1481 | "integrity": "sha512-Qjdjr+KQQVH5Q2Q1r6HBYswFTToPpss3gqCiSw2Fpq/ua8+eXSQyAMG+UvULPqXceOwpnPo4smyZyHdlkcPppQ==", 1482 | "dev": true, 1483 | "optional": true 1484 | }, 1485 | "esbuild-openbsd-64": { 1486 | "version": "0.14.47", 1487 | "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.47.tgz", 1488 | "integrity": "sha512-QpgN8ofL7B9z8g5zZqJE+eFvD1LehRlxr25PBkjyyasakm4599iroUpaj96rdqRlO2ShuyqwJdr+oNqWwTUmQw==", 1489 | "dev": true, 1490 | "optional": true 1491 | }, 1492 | "esbuild-sunos-64": { 1493 | "version": "0.14.47", 1494 | "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.47.tgz", 1495 | "integrity": "sha512-uOeSgLUwukLioAJOiGYm3kNl+1wJjgJA8R671GYgcPgCx7QR73zfvYqXFFcIO93/nBdIbt5hd8RItqbbf3HtAQ==", 1496 | "dev": true, 1497 | "optional": true 1498 | }, 1499 | "esbuild-windows-32": { 1500 | "version": "0.14.47", 1501 | "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.47.tgz", 1502 | "integrity": "sha512-H0fWsLTp2WBfKLBgwYT4OTfFly4Im/8B5f3ojDv1Kx//kiubVY0IQunP2Koc/fr/0wI7hj3IiBDbSrmKlrNgLQ==", 1503 | "dev": true, 1504 | "optional": true 1505 | }, 1506 | "esbuild-windows-64": { 1507 | "version": "0.14.47", 1508 | "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.47.tgz", 1509 | "integrity": "sha512-/Pk5jIEH34T68r8PweKRi77W49KwanZ8X6lr3vDAtOlH5EumPE4pBHqkCUdELanvsT14yMXLQ/C/8XPi1pAtkQ==", 1510 | "dev": true, 1511 | "optional": true 1512 | }, 1513 | "esbuild-windows-arm64": { 1514 | "version": "0.14.47", 1515 | "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.47.tgz", 1516 | "integrity": "sha512-HFSW2lnp62fl86/qPQlqw6asIwCnEsEoNIL1h2uVMgakddf+vUuMcCbtUY1i8sst7KkgHrVKCJQB33YhhOweCQ==", 1517 | "dev": true, 1518 | "optional": true 1519 | }, 1520 | "escape-string-regexp": { 1521 | "version": "4.0.0", 1522 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", 1523 | "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", 1524 | "dev": true 1525 | }, 1526 | "estree-walker": { 1527 | "version": "0.6.1", 1528 | "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz", 1529 | "integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==", 1530 | "dev": true 1531 | }, 1532 | "fsevents": { 1533 | "version": "2.3.2", 1534 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", 1535 | "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", 1536 | "dev": true, 1537 | "optional": true 1538 | }, 1539 | "html-rewriter-wasm": { 1540 | "version": "0.4.1", 1541 | "resolved": "https://registry.npmjs.org/html-rewriter-wasm/-/html-rewriter-wasm-0.4.1.tgz", 1542 | "integrity": "sha512-lNovG8CMCCmcVB1Q7xggMSf7tqPCijZXaH4gL6iE8BFghdQCbaY5Met9i1x2Ex8m/cZHDUtXK9H6/znKamRP8Q==", 1543 | "dev": true 1544 | }, 1545 | "http-cache-semantics": { 1546 | "version": "4.1.0", 1547 | "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", 1548 | "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==", 1549 | "dev": true 1550 | }, 1551 | "ignore": { 1552 | "version": "5.2.0", 1553 | "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", 1554 | "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", 1555 | "dev": true 1556 | }, 1557 | "kleur": { 1558 | "version": "4.1.5", 1559 | "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", 1560 | "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", 1561 | "dev": true 1562 | }, 1563 | "magic-string": { 1564 | "version": "0.25.9", 1565 | "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", 1566 | "integrity": "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==", 1567 | "dev": true, 1568 | "requires": { 1569 | "sourcemap-codec": "^1.4.8" 1570 | } 1571 | }, 1572 | "mime": { 1573 | "version": "3.0.0", 1574 | "resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz", 1575 | "integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==", 1576 | "dev": true 1577 | }, 1578 | "miniflare": { 1579 | "version": "2.6.0", 1580 | "resolved": "https://registry.npmjs.org/miniflare/-/miniflare-2.6.0.tgz", 1581 | "integrity": "sha512-KDAQZV2aDZ044X1ihlCIa6DPdq1w3fUJFW4xZ+r+DPUxj9t1AuehjR9Fc6zCmZQrk12gLXDSZSyNft1ozm1X7Q==", 1582 | "dev": true, 1583 | "requires": { 1584 | "@miniflare/cache": "2.6.0", 1585 | "@miniflare/cli-parser": "2.6.0", 1586 | "@miniflare/core": "2.6.0", 1587 | "@miniflare/durable-objects": "2.6.0", 1588 | "@miniflare/html-rewriter": "2.6.0", 1589 | "@miniflare/http-server": "2.6.0", 1590 | "@miniflare/kv": "2.6.0", 1591 | "@miniflare/r2": "2.6.0", 1592 | "@miniflare/runner-vm": "2.6.0", 1593 | "@miniflare/scheduler": "2.6.0", 1594 | "@miniflare/shared": "2.6.0", 1595 | "@miniflare/sites": "2.6.0", 1596 | "@miniflare/storage-file": "2.6.0", 1597 | "@miniflare/storage-memory": "2.6.0", 1598 | "@miniflare/web-sockets": "2.6.0", 1599 | "kleur": "^4.1.4", 1600 | "semiver": "^1.1.0", 1601 | "source-map-support": "^0.5.20", 1602 | "undici": "5.5.1" 1603 | } 1604 | }, 1605 | "mustache": { 1606 | "version": "4.2.0", 1607 | "resolved": "https://registry.npmjs.org/mustache/-/mustache-4.2.0.tgz", 1608 | "integrity": "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==", 1609 | "dev": true 1610 | }, 1611 | "nanoid": { 1612 | "version": "3.3.4", 1613 | "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", 1614 | "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", 1615 | "dev": true 1616 | }, 1617 | "node-forge": { 1618 | "version": "1.3.1", 1619 | "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", 1620 | "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", 1621 | "dev": true 1622 | }, 1623 | "path-to-regexp": { 1624 | "version": "6.2.1", 1625 | "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.2.1.tgz", 1626 | "integrity": "sha512-JLyh7xT1kizaEvcaXOQwOc2/Yhw6KZOvPf1S8401UyLk86CU79LN3vl7ztXGm/pZ+YjoyAJ4rxmHwbkBXJX+yw==", 1627 | "dev": true 1628 | }, 1629 | "rollup-plugin-inject": { 1630 | "version": "3.0.2", 1631 | "resolved": "https://registry.npmjs.org/rollup-plugin-inject/-/rollup-plugin-inject-3.0.2.tgz", 1632 | "integrity": "sha512-ptg9PQwzs3orn4jkgXJ74bfs5vYz1NCZlSQMBUA0wKcGp5i5pA1AO3fOUEte8enhGUC+iapTCzEWw2jEFFUO/w==", 1633 | "dev": true, 1634 | "requires": { 1635 | "estree-walker": "^0.6.1", 1636 | "magic-string": "^0.25.3", 1637 | "rollup-pluginutils": "^2.8.1" 1638 | } 1639 | }, 1640 | "rollup-plugin-node-polyfills": { 1641 | "version": "0.2.1", 1642 | "resolved": "https://registry.npmjs.org/rollup-plugin-node-polyfills/-/rollup-plugin-node-polyfills-0.2.1.tgz", 1643 | "integrity": "sha512-4kCrKPTJ6sK4/gLL/U5QzVT8cxJcofO0OU74tnB19F40cmuAKSzH5/siithxlofFEjwvw1YAhPmbvGNA6jEroA==", 1644 | "dev": true, 1645 | "requires": { 1646 | "rollup-plugin-inject": "^3.0.0" 1647 | } 1648 | }, 1649 | "rollup-pluginutils": { 1650 | "version": "2.8.2", 1651 | "resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz", 1652 | "integrity": "sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==", 1653 | "dev": true, 1654 | "requires": { 1655 | "estree-walker": "^0.6.1" 1656 | } 1657 | }, 1658 | "selfsigned": { 1659 | "version": "2.0.1", 1660 | "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.0.1.tgz", 1661 | "integrity": "sha512-LmME957M1zOsUhG+67rAjKfiWFox3SBxE/yymatMZsAx+oMrJ0YQ8AToOnyCm7xbeg2ep37IHLxdu0o2MavQOQ==", 1662 | "dev": true, 1663 | "requires": { 1664 | "node-forge": "^1" 1665 | } 1666 | }, 1667 | "semiver": { 1668 | "version": "1.1.0", 1669 | "resolved": "https://registry.npmjs.org/semiver/-/semiver-1.1.0.tgz", 1670 | "integrity": "sha512-QNI2ChmuioGC1/xjyYwyZYADILWyW6AmS1UH6gDj/SFUUUS4MBAWs/7mxnkRPc/F4iHezDP+O8t0dO8WHiEOdg==", 1671 | "dev": true 1672 | }, 1673 | "set-cookie-parser": { 1674 | "version": "2.5.0", 1675 | "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.5.0.tgz", 1676 | "integrity": "sha512-cHMAtSXilfyBePduZEBVPTCftTQWz6ehWJD5YNUg4mqvRosrrjKbo4WS8JkB0/RxonMoohHm7cOGH60mDkRQ9w==", 1677 | "dev": true 1678 | }, 1679 | "source-map": { 1680 | "version": "0.6.1", 1681 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", 1682 | "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", 1683 | "dev": true 1684 | }, 1685 | "source-map-support": { 1686 | "version": "0.5.21", 1687 | "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", 1688 | "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", 1689 | "dev": true, 1690 | "requires": { 1691 | "buffer-from": "^1.0.0", 1692 | "source-map": "^0.6.0" 1693 | } 1694 | }, 1695 | "sourcemap-codec": { 1696 | "version": "1.4.8", 1697 | "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", 1698 | "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", 1699 | "dev": true 1700 | }, 1701 | "stack-trace": { 1702 | "version": "0.0.10", 1703 | "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", 1704 | "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==", 1705 | "dev": true 1706 | }, 1707 | "streamsearch": { 1708 | "version": "1.1.0", 1709 | "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", 1710 | "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", 1711 | "dev": true 1712 | }, 1713 | "typescript": { 1714 | "version": "4.7.4", 1715 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz", 1716 | "integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==", 1717 | "dev": true 1718 | }, 1719 | "undici": { 1720 | "version": "5.5.1", 1721 | "resolved": "https://registry.npmjs.org/undici/-/undici-5.5.1.tgz", 1722 | "integrity": "sha512-MEvryPLf18HvlCbLSzCW0U00IMftKGI5udnjrQbC5D4P0Hodwffhv+iGfWuJwg16Y/TK11ZFK8i+BPVW2z/eAw==", 1723 | "dev": true 1724 | }, 1725 | "urlpattern-polyfill": { 1726 | "version": "4.0.3", 1727 | "resolved": "https://registry.npmjs.org/urlpattern-polyfill/-/urlpattern-polyfill-4.0.3.tgz", 1728 | "integrity": "sha512-DOE84vZT2fEcl9gqCUTcnAw5ZY5Id55ikUcziSUntuEFL3pRvavg5kwDmTEUJkeCHInTlV/HexFomgYnzO5kdQ==", 1729 | "dev": true 1730 | }, 1731 | "wrangler": { 1732 | "version": "2.0.17", 1733 | "resolved": "https://registry.npmjs.org/wrangler/-/wrangler-2.0.17.tgz", 1734 | "integrity": "sha512-U4PSx1j0JUPX/fDvQSqeCVZeAww+DLZkm1tWeFovOxgzpvpvZ/2s+2IINR+dhw4FGiSpDUsQgiA4EDm64fV4RA==", 1735 | "dev": true, 1736 | "requires": { 1737 | "@cloudflare/kv-asset-handler": "^0.2.0", 1738 | "@esbuild-plugins/node-globals-polyfill": "^0.1.1", 1739 | "@esbuild-plugins/node-modules-polyfill": "^0.1.4", 1740 | "blake3-wasm": "^2.1.5", 1741 | "esbuild": "0.14.47", 1742 | "fsevents": "~2.3.2", 1743 | "miniflare": "^2.6.0", 1744 | "nanoid": "^3.3.3", 1745 | "path-to-regexp": "^6.2.0", 1746 | "selfsigned": "^2.0.1", 1747 | "semiver": "^1.1.0", 1748 | "xxhash-wasm": "^1.0.1" 1749 | } 1750 | }, 1751 | "ws": { 1752 | "version": "8.8.0", 1753 | "resolved": "https://registry.npmjs.org/ws/-/ws-8.8.0.tgz", 1754 | "integrity": "sha512-JDAgSYQ1ksuwqfChJusw1LSJ8BizJ2e/vVu5Lxjq3YvNJNlROv1ui4i+c/kUUrPheBvQl4c5UbERhTwKa6QBJQ==", 1755 | "dev": true, 1756 | "requires": {} 1757 | }, 1758 | "xxhash-wasm": { 1759 | "version": "1.0.1", 1760 | "resolved": "https://registry.npmjs.org/xxhash-wasm/-/xxhash-wasm-1.0.1.tgz", 1761 | "integrity": "sha512-Lc9CTvDrH2vRoiaUzz25q7lRaviMhz90pkx6YxR9EPYtF99yOJnv2cB+CQ0hp/TLoqrUsk8z/W2EN31T568Azw==", 1762 | "dev": true 1763 | }, 1764 | "youch": { 1765 | "version": "2.2.2", 1766 | "resolved": "https://registry.npmjs.org/youch/-/youch-2.2.2.tgz", 1767 | "integrity": "sha512-/FaCeG3GkuJwaMR34GHVg0l8jCbafZLHiFowSjqLlqhC6OMyf2tPJBu8UirF7/NI9X/R5ai4QfEKUCOxMAGxZQ==", 1768 | "dev": true, 1769 | "requires": { 1770 | "@types/stack-trace": "0.0.29", 1771 | "cookie": "^0.4.1", 1772 | "mustache": "^4.2.0", 1773 | "stack-trace": "0.0.10" 1774 | } 1775 | } 1776 | } 1777 | } 1778 | --------------------------------------------------------------------------------