├── 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 |
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 |
8 |
9 |
Create Next App
10 |
11 |
12 |
13 |
14 |
15 |
16 | Welcome to Next.js!
17 |
18 |
19 |
20 | Get started by editing{" "}
21 | pages/index.js
22 |
23 |
24 |
53 |
54 |
55 |
67 |
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 |
8 |
9 |
Create Next App
10 |
11 |
12 |
13 |
14 |
15 |
16 | Welcome to Next.js!
17 |
18 |
19 |
20 | Get started by editing{' '}
21 | pages/index.tsx
22 |
23 |
24 |
55 |
56 |
57 |
69 |
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 | {
115 | if (x.state === "") {
116 | setToast({
117 | text: "x is empty"
118 | , type: "error"
119 | })
120 | return
121 | }
122 | if (y.state === "") {
123 | setToast({
124 | text: "y is empty"
125 | , type: "error"
126 | })
127 | return
128 | }
129 | let xValue = 0
130 | let yValue = 0
131 | try {
132 |
133 | xValue = parseFloat(x.state)
134 | if (Number.isNaN(xValue)) {
135 | setToast({
136 | text: `Unable to parse "${x.state}"`
137 | , type: "error"
138 | })
139 | return
140 | }
141 | yValue = parseFloat(y.state)
142 | if (Number.isNaN(yValue)) {
143 | setToast({
144 | text: `Unable to parse "${y.state}"`
145 | , type: "error"
146 | })
147 | return
148 | }
149 | } catch (err) {
150 | setToast({
151 | text: (err as Error).message,
152 | type: "error"
153 | })
154 | return
155 | }
156 | await createTask({ userId, x: xValue, y: yValue })
157 |
158 | setLoading(false)
159 |
160 |
161 |
162 |
163 | }}>Add
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 |
--------------------------------------------------------------------------------