├── .codeclimate.yml ├── .env ├── .github └── workflows │ ├── deploy.yml │ └── test.yml ├── .gitignore ├── .nvmrc ├── .prettierignore ├── LICENSE ├── README.md ├── codecov.yml ├── index.js ├── lerna.json ├── package-lock.json ├── package.json ├── packages ├── client │ ├── .env │ ├── .gitignore │ ├── README.md │ ├── package-lock.json │ ├── package.json │ ├── public │ │ ├── favicon.ico │ │ ├── index.html │ │ ├── logo192.png │ │ ├── logo512.png │ │ ├── manifest.json │ │ └── robots.txt │ ├── src │ │ ├── App.css │ │ ├── App.test.tsx │ │ ├── App.tsx │ │ ├── index.css │ │ ├── index.tsx │ │ ├── logo.svg │ │ ├── react-app-env.d.ts │ │ ├── serviceWorker.ts │ │ └── setupTests.ts │ └── tsconfig.json ├── e2e │ ├── README.md │ ├── __tests__ │ │ └── index.test.ts │ ├── jest-playwright.config.js │ ├── jest.config.js │ ├── package-lock.json │ ├── package.json │ └── tsconfig.json ├── server │ ├── README.md │ ├── jest.config.js │ ├── jest.setup.js │ ├── package-lock.json │ ├── package.json │ ├── src │ │ ├── hello.test.ts │ │ ├── hello.ts │ │ ├── index.test.ts │ │ ├── index.ts │ │ └── types.d.ts │ └── tsconfig.json └── worker │ ├── .gitignore │ ├── README.md │ ├── null.js │ ├── package-lock.json │ ├── package.json │ ├── src │ ├── handleError.ts │ ├── index.ts │ └── pages.ts │ ├── tsconfig.json │ └── webpack.config.js ├── updatePackages.js └── wrangler.toml /.codeclimate.yml: -------------------------------------------------------------------------------- 1 | version: "2" 2 | plugins: 3 | eslint: 4 | enabled: true 5 | fixme: 6 | enabled: true 7 | git-legal: 8 | enabled: true 9 | markdownlint: 10 | enabled: true 11 | checks: 12 | MD033: 13 | enabled: false 14 | MD013: 15 | enabled: false 16 | nodesecurity: 17 | enabled: true 18 | exclude_patterns: 19 | - "" 20 | -------------------------------------------------------------------------------- /.env: -------------------------------------------------------------------------------- 1 | SKIP_PREFLIGHT_CHECK=true -------------------------------------------------------------------------------- /.github/workflows/deploy.yml: -------------------------------------------------------------------------------- 1 | name: Deploy 2 | on: 3 | repository_dispatch: 4 | push: 5 | branches: 6 | - master 7 | 8 | jobs: 9 | deploy: 10 | runs-on: ubuntu-latest 11 | name: Deploy 12 | steps: 13 | - name: Checkout 14 | uses: actions/checkout@v2 15 | - name: Setup Node 16 | uses: actions/setup-node@v1 17 | - name: Install 18 | run: npm ci 19 | - name: Deploy 20 | run: npm run deploy 21 | env: 22 | CF_API_TOKEN: ${{ secrets.CF_API_TOKEN }} 23 | CF_ACCOUNT_ID: ${{ secrets.CF_ACCOUNT_ID }} 24 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Test 2 | on: [push] 3 | 4 | jobs: 5 | deploy: 6 | runs-on: ubuntu-latest 7 | name: Test 8 | steps: 9 | - name: Checkout 10 | uses: actions/checkout@v2 11 | - name: Setup Node 12 | uses: actions/setup-node@v1 13 | - name: Setup Playwright 14 | uses: microsoft/playwright-github-action@v1 15 | - name: Install 16 | run: npm ci 17 | - name: Lint 18 | run: npm run lint 19 | - name: Test 20 | run: npm run test 21 | env: 22 | CF_API_TOKEN: ${{ secrets.CF_API_TOKEN }} 23 | CF_ACCOUNT_ID: ${{ secrets.CF_ACCOUNT_ID }} 24 | - name: Upload Coverage Report 25 | uses: codecov/codecov-action@v1.0.6 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.gitignore.io/api/git,node,react,visualstudiocode 3 | # Edit at https://www.gitignore.io/?templates=git,node,react,visualstudiocode 4 | 5 | ### Git ### 6 | # Created by git for backups. To disable backups in Git: 7 | # $ git config --global mergetool.keepBackup false 8 | *.orig 9 | 10 | # Created by git when using merge tools for conflicts 11 | *.BACKUP.* 12 | *.BASE.* 13 | *.LOCAL.* 14 | *.REMOTE.* 15 | *_BACKUP_*.txt 16 | *_BASE_*.txt 17 | *_LOCAL_*.txt 18 | *_REMOTE_*.txt 19 | 20 | ### Node ### 21 | # Logs 22 | logs 23 | *.log 24 | npm-debug.log* 25 | yarn-debug.log* 26 | yarn-error.log* 27 | lerna-debug.log* 28 | 29 | # Diagnostic reports (https://nodejs.org/api/report.html) 30 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 31 | 32 | # Runtime data 33 | pids 34 | *.pid 35 | *.seed 36 | *.pid.lock 37 | 38 | # Directory for instrumented libs generated by jscoverage/JSCover 39 | lib-cov 40 | 41 | # Coverage directory used by tools like istanbul 42 | coverage 43 | *.lcov 44 | 45 | # nyc test coverage 46 | .nyc_output 47 | 48 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 49 | .grunt 50 | 51 | # Bower dependency directory (https://bower.io/) 52 | bower_components 53 | 54 | # node-waf configuration 55 | .lock-wscript 56 | 57 | # Compiled binary addons (https://nodejs.org/api/addons.html) 58 | build/Release 59 | 60 | # Dependency directories 61 | node_modules/ 62 | jspm_packages/ 63 | 64 | # TypeScript v1 declaration files 65 | typings/ 66 | 67 | # TypeScript cache 68 | *.tsbuildinfo 69 | 70 | # Optional npm cache directory 71 | .npm 72 | 73 | # Optional eslint cache 74 | .eslintcache 75 | 76 | # Optional REPL history 77 | .node_repl_history 78 | 79 | # Output of 'npm pack' 80 | *.tgz 81 | 82 | # Yarn Integrity file 83 | .yarn-integrity 84 | 85 | # dotenv environment variables file 86 | # .env 87 | .env.test 88 | 89 | # parcel-bundler cache (https://parceljs.org/) 90 | .cache 91 | 92 | # next.js build output 93 | .next 94 | 95 | # nuxt.js build output 96 | .nuxt 97 | 98 | # rollup.js default build output 99 | dist/ 100 | 101 | # Uncomment the public line if your project uses Gatsby 102 | # https://nextjs.org/blog/next-9-1#public-directory-support 103 | # https://create-react-app.dev/docs/using-the-public-folder/#docsNav 104 | # public 105 | 106 | # Storybook build outputs 107 | .out 108 | .storybook-out 109 | 110 | # vuepress build output 111 | .vuepress/dist 112 | 113 | # Serverless directories 114 | .serverless/ 115 | 116 | # FuseBox cache 117 | .fusebox/ 118 | 119 | # DynamoDB Local files 120 | .dynamodb/ 121 | 122 | # Temporary folders 123 | tmp/ 124 | temp/ 125 | 126 | ### react ### 127 | .DS_* 128 | **/*.backup.* 129 | **/*.back.* 130 | 131 | node_modules 132 | 133 | *.sublime* 134 | 135 | psd 136 | thumb 137 | sketch 138 | 139 | ### VisualStudioCode ### 140 | .vscode/* 141 | !.vscode/settings.json 142 | !.vscode/tasks.json 143 | !.vscode/launch.json 144 | !.vscode/extensions.json 145 | 146 | ### VisualStudioCode Patch ### 147 | # Ignore all local history of files 148 | .history 149 | 150 | # End of https://www.gitignore.io/api/git,node,react,visualstudiocode -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | v13.14.0 2 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | /packages/client/coverage 2 | /packages/client/build 3 | /packages/server/coverage 4 | /packages/worker/build 5 | /packages/worker/worker 6 | /**/package-lock.json -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Greg Brimble 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Cloudflare Workers Typescript Server & Client Template 2 | 3 | [![GitHub Actions Test](https://github.com/GregBrimble/cf-workers-typescript-template/workflows/Test/badge.svg)](https://github.com/GregBrimble/cf-workers-typescript-template/actions?query=workflow%3ATest) 4 | [![GitHub Actions Deploy](https://github.com/GregBrimble/cf-workers-typescript-template/workflows/Deploy/badge.svg)](https://github.com/GregBrimble/cf-workers-typescript-template/actions?query=workflow%3ADeploy) 5 | [![LGTM Alerts](https://img.shields.io/lgtm/alerts/g/GregBrimble/cf-workers-typescript-template.svg?logo=lgtm&style=plastic)](https://lgtm.com/projects/g/GregBrimble/cf-workers-typescript-template/alerts/) 6 | [![LGTM Code Quality](https://img.shields.io/lgtm/grade/javascript/g/GregBrimble/cf-workers-typescript-template.svg?logo=lgtm&style=plastic)](https://lgtm.com/projects/g/GregBrimble/cf-workers-typescript-template/context:javascript) 7 | [![Code Climate Maintainability](https://img.shields.io/codeclimate/maintainability/GregBrimble/cf-workers-typescript-template.svg?style=plastic)](https://codeclimate.com/github/GregBrimble/cf-workers-typescript-template/maintainability) 8 | [![Codecov](https://img.shields.io/codecov/c/github/GregBrimble/cf-workers-typescript-template?logo=codecov&style=plastic)](https://codecov.io/gh/GregBrimble/cf-workers-typescript-template) 9 | [![License](https://img.shields.io/github/license/GregBrimble/cf-workers-typescript-template?style=plastic)](https://github.com/GregBrimble/cf-workers-typescript-template/blob/master/LICENSE) 10 | [![GitHub Last Commit](https://img.shields.io/github/last-commit/GregBrimble/cf-workers-typescript-template.svg?logo=github&style=plastic)](https://github.com/GregBrimble/cf-workers-typescript-template) 11 | [![Lerna](https://img.shields.io/badge/maintained%20with-lerna-cc00ff.svg?style=plastic)](https://lerna.js.org/) 12 | 13 | A perfect\* template for a [Cloudflare Workers](https://workers.cloudflare.com/) project, using [Workers Sites](https://workers.cloudflare.com/sites) ([React](https://reactjs.org/) although can be easily swapped for [Gatsby](https://www.gatsbyjs.org/) or another static builder), [TypeScript](https://www.typescriptlang.org/), [Jest](https://jestjs.io/) and [Prettier](https://prettier.io/). 14 | 15 | **And now, with end-to-end tests thanks to the new [`wrangler dev`](https://github.com/cloudflare/wrangler#-dev) command and [Playwright](https://playwright.dev/)! ✨** 16 | 17 | ## Prerequisites 18 | 19 | - [Node.js](https://nodejs.org/en/) 20 | 21 | - [`cloudflared`](https://developers.cloudflare.com/argo-tunnel/downloads/) 22 | 23 | (On MacOS with Homebrew: `brew install cloudflare/cloudflare/cloudflared`) 24 | 25 | ## Getting Started 26 | 27 | ### Automatic 28 | 29 | Click [the button below](<(https://deploy.workers.cloudflare.com/?url=https://github.com/GregBrimble/cf-workers-typescript-template&paid=true)>) and follow the setup instructions. 30 | 31 | [![Deploy to Cloudflare Workers](https://deploy.workers.cloudflare.com/button?paid=true)](https://deploy.workers.cloudflare.com/?url=https://github.com/GregBrimble/cf-workers-typescript-template&paid=true) 32 | 33 | ### Manual 34 | 35 | 1. Fork repository: 36 | 37 | 1. Click the [`Use this template`](https://github.com/GregBrimble/cf-workers-typescript-template/generate) button. 38 | 39 | 1. Add GitHub Actions secret for [`CF_ACCOUNT_ID`](https://dash.cloudflare.com/?to=/:account/workers) and [`CF_API_TOKEN`](https://dash.cloudflare.com/profile/api-tokens) using `Edit Cloudflare Workers` template permissions. 40 | 41 | 1. Enable the [CodeClimate](https://github.com/settings/installations/205740), [Codecov](https://github.com/settings/installations/655980), [LGTM](https://github.com/settings/installations/2030503), and [Synk](https://snyk.io/) apps. 42 | 43 | 1. (Optionally) Update `.nvmrc`: 44 | 45 | - Find available versions with `nvm ls-remote` 46 | - Use the current Node.js version with `node -v > .nvmrc` 47 | 48 | 1. Update `wrangler.toml`: 49 | 50 | 1. Replace `script-name` and `script-name-dev` with `new-script-name` and `new-script-name-dev` respectively. 51 | 52 | 1. Add KV Namespaces. For example: 53 | 54 | ```toml 55 | kv-namespaces = [ 56 | { binding = "NAMESPACENAME", id = "86bbce2f10524d33a5f26517e8dee123" } 57 | ] 58 | ``` 59 | 60 | - Find existing namespaces with `wrangler kv:namespace list` 61 | - Create a new namespace with `wrangler kv:namespace create NAMESPACENAME` 62 | 63 | 1. Update `account_id`. 64 | 65 | 1. Update `package.json`: 66 | 67 | 1. Replace `script-name` with `new-script-name`. 68 | 69 | 1. Replace `repositoryname` with `newrepositoryname`. 70 | 71 | 1. Update GitHub account name in the following locations: 72 | 73 | 1. `repository.url` 74 | 75 | 1. `bugs.url` 76 | 77 | 1. `homepage` 78 | 79 | 1. Update `homepage` and `author`. 80 | 81 | 1. `npm i` 82 | 83 | 1. (Optionally) Update npm packages: `npm run updatePackages` 84 | 85 | 1. Update `README.md`, (don't forget the badges!). 86 | 87 | 1. Follow additional instructions in `/packages/*/README.md` 88 | 89 | ## Scripts 90 | 91 | These should all be self-explanatory: 92 | 93 | - `npm run lint` 94 | 95 | - `npm run lint:fix` 96 | 97 | - `npm run test` 98 | 99 | - `npm run test:client` 100 | - `npm run test:server` 101 | - `npm run test:e2e` 102 | 103 | - `npm run deploy` 104 | 105 | To start a local version: 106 | 107 | 1. In one terminal window, run `npm run start:client`. 108 | 109 | 1. In another, run `npm run start` and navigate to [http://localhost:8787](http://localhost:8787). 110 | 111 | ## About 112 | 113 | - `/packages/client` is simply a CRA created with `npx create-react-app . --template typescript --use-npm`. 114 | 115 | - `/packages/server` an function which intercepts a request to the client. If it returns a 404, the request is passed through to the client. 116 | 117 | - `/packages/worker` attempts to fetch from the server first, falling back on the client. 118 | 119 | - `/packages/e2e` runs end-to-end tests on the full-stack Worker. 120 | 121 | --- 122 | 123 | \* May not be perfect 124 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | coverage: 2 | status: 3 | project: 4 | default: off 5 | client: 6 | flags: client 7 | server: 8 | flags: server 9 | 10 | flags: 11 | client: 12 | paths: 13 | - packages/client/ 14 | server: 15 | paths: 16 | - packages/server/ 17 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | require("cross-fetch/polyfill"); 2 | const { spawn } = require("child_process"); 3 | const cwd = process.cwd(); 4 | 5 | const SLEEP_DURATION = 2000; 6 | const hostNameRegex = /userHostname=\"(.*)\"/g; 7 | 8 | const startServer = (hostName) => { 9 | process.env.CLOUDFLARED_TUNNEL = "true"; 10 | spawn("npm", ["run", "start:worker", "--", "--host", hostName], { 11 | cwd, 12 | stdio: "inherit", 13 | }); 14 | }; 15 | 16 | const findTunnelHostname = async () => { 17 | console.log("Waiting for tunnel to initiate..."); 18 | try { 19 | const resp = await fetch("http://localhost:8081/metrics"); 20 | const data = await resp.text(); 21 | const matches = Array.from(data.matchAll(hostNameRegex)); 22 | const hostName = matches[0][1]; 23 | console.log(`Tunnel initiated: ${hostName}`); 24 | startServer(hostName); 25 | } catch { 26 | setTimeout(findTunnelHostname, SLEEP_DURATION); 27 | } 28 | }; 29 | 30 | const startTunnel = () => { 31 | console.log("Starting tunnel..."); 32 | spawn("npm", ["run", "start:tunnel"], { 33 | cwd, 34 | }); 35 | }; 36 | 37 | startTunnel(); 38 | findTunnelHostname(); 39 | -------------------------------------------------------------------------------- /lerna.json: -------------------------------------------------------------------------------- 1 | { 2 | "packages": ["packages/*"], 3 | "version": "1.0.0" 4 | } 5 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "script-name", 3 | "version": "1.0.0", 4 | "private": true, 5 | "scripts": { 6 | "postinstall": "lerna bootstrap", 7 | "prebuild": "lerna run --scope client build", 8 | "build": "wrangler build", 9 | "clean:node": "rimraf node_modules package-lock.json", 10 | "test:client": "CI=true lerna run --scope client test", 11 | "test:server": "CI=true lerna run --scope server test", 12 | "test:e2e": "CI=true lerna run --scope e2e test:ci", 13 | "test": "CI=true lerna run test:ci", 14 | "lint": "prettier -c .", 15 | "lint:fix": "npm run lint -- --write", 16 | "start": "node index.js", 17 | "start:client": "CI=true lerna run --scope client --stream start", 18 | "start:worker": "wrangler dev", 19 | "start:tunnel": "cloudflared tunnel --url localhost:3000 --metrics localhost:8081", 20 | "predeploy": "npm run prebuild", 21 | "deploy": "wrangler publish --env production", 22 | "updatePackages": "node updatePackages.js && npm i" 23 | }, 24 | "repository": { 25 | "type": "git", 26 | "url": "git@github.com:GregBrimble/repositoryname.git" 27 | }, 28 | "author": { 29 | "name": "Greg Brimble", 30 | "email": "developer@gregbrimble.com", 31 | "url": "https://gregbrimble.com" 32 | }, 33 | "license": "MIT", 34 | "bugs": { 35 | "url": "https://github.com/GregBrimble/repositoryname/issues" 36 | }, 37 | "homepage": "https://github.com/GregBrimble/repositoryname#readme", 38 | "devDependencies": { 39 | "@cloudflare/wrangler": "1.12.3", 40 | "cross-fetch": "3.0.6", 41 | "husky": "4.3.7", 42 | "lerna": "3.22.1", 43 | "npm-check-updates": "10.2.5", 44 | "prettier": "2.2.1", 45 | "rimraf": "3.0.2", 46 | "ts-loader": "8.0.14", 47 | "typescript": "4.1.3", 48 | "webpack": "5.12.2" 49 | }, 50 | "husky": { 51 | "hooks": { 52 | "pre-commit": "npm run lint || (npm run lint:fix && npm run lint)", 53 | "pre-push": "npm test" 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /packages/client/.env: -------------------------------------------------------------------------------- 1 | SKIP_PREFLIGHT_CHECK=true -------------------------------------------------------------------------------- /packages/client/.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 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | -------------------------------------------------------------------------------- /packages/client/README.md: -------------------------------------------------------------------------------- 1 | This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). 2 | 3 | ## Available Scripts 4 | 5 | In the project directory, you can run: 6 | 7 | ### `npm start` 8 | 9 | Runs the app in the development mode.
10 | Open [http://localhost:3000](http://localhost:3000) to view it in the browser. 11 | 12 | The page will reload if you make edits.
13 | You will also see any lint errors in the console. 14 | 15 | ### `npm test` 16 | 17 | Launches the test runner in the interactive watch mode.
18 | See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information. 19 | 20 | ### `npm run build` 21 | 22 | Builds the app for production to the `build` folder.
23 | It correctly bundles React in production mode and optimizes the build for the best performance. 24 | 25 | The build is minified and the filenames include the hashes.
26 | Your app is ready to be deployed! 27 | 28 | See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information. 29 | 30 | ### `npm run eject` 31 | 32 | **Note: this is a one-way operation. Once you `eject`, you can’t go back!** 33 | 34 | If you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project. 35 | 36 | Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own. 37 | 38 | You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it. 39 | 40 | ## Learn More 41 | 42 | You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started). 43 | 44 | To learn React, check out the [React documentation](https://reactjs.org/). 45 | -------------------------------------------------------------------------------- /packages/client/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "client", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@testing-library/jest-dom": "5.11.8", 7 | "@testing-library/react": "11.2.3", 8 | "@testing-library/user-event": "12.6.0", 9 | "@types/jest": "26.0.20", 10 | "@types/node": "14.14.20", 11 | "@types/react": "17.0.0", 12 | "@types/react-dom": "17.0.0", 13 | "react": "17.0.1", 14 | "react-dom": "17.0.1", 15 | "react-scripts": "4.0.1", 16 | "typescript": "4.1.3" 17 | }, 18 | "scripts": { 19 | "start": "react-scripts start", 20 | "build": "react-scripts build", 21 | "test": "react-scripts test", 22 | "test:ci": "npm run test -- --coverage", 23 | "eject": "react-scripts eject", 24 | "lint": "prettier -c .", 25 | "lint:fix": "npm run lint -- --write" 26 | }, 27 | "eslintConfig": { 28 | "extends": "react-app" 29 | }, 30 | "browserslist": { 31 | "production": [ 32 | ">0.2%", 33 | "not dead", 34 | "not op_mini all" 35 | ], 36 | "development": [ 37 | "last 1 chrome version", 38 | "last 1 firefox version", 39 | "last 1 safari version" 40 | ] 41 | }, 42 | "devDependencies": { 43 | "prettier": "2.2.1" 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /packages/client/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GregBrimble/cf-workers-typescript-template/d8d102e5bb158e72da17316d4be9f5f5443c468d/packages/client/public/favicon.ico -------------------------------------------------------------------------------- /packages/client/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 17 | 18 | 27 | React App 28 | 29 | 30 | 31 |
32 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /packages/client/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GregBrimble/cf-workers-typescript-template/d8d102e5bb158e72da17316d4be9f5f5443c468d/packages/client/public/logo192.png -------------------------------------------------------------------------------- /packages/client/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GregBrimble/cf-workers-typescript-template/d8d102e5bb158e72da17316d4be9f5f5443c468d/packages/client/public/logo512.png -------------------------------------------------------------------------------- /packages/client/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /packages/client/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /packages/client/src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | text-align: center; 3 | } 4 | 5 | .App-logo { 6 | height: 40vmin; 7 | pointer-events: none; 8 | } 9 | 10 | @media (prefers-reduced-motion: no-preference) { 11 | .App-logo { 12 | animation: App-logo-spin infinite 20s linear; 13 | } 14 | } 15 | 16 | .App-header { 17 | background-color: #282c34; 18 | min-height: 100vh; 19 | display: flex; 20 | flex-direction: column; 21 | align-items: center; 22 | justify-content: center; 23 | font-size: calc(10px + 2vmin); 24 | color: white; 25 | } 26 | 27 | .App-link { 28 | color: #61dafb; 29 | } 30 | 31 | @keyframes App-logo-spin { 32 | from { 33 | transform: rotate(0deg); 34 | } 35 | to { 36 | transform: rotate(360deg); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /packages/client/src/App.test.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { render } from "@testing-library/react"; 3 | import App from "./App"; 4 | 5 | test("renders learn react link", () => { 6 | const { getByText } = render(); 7 | const linkElement = getByText(/learn react/i); 8 | expect(linkElement).toBeInTheDocument(); 9 | }); 10 | -------------------------------------------------------------------------------- /packages/client/src/App.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import logo from "./logo.svg"; 3 | import "./App.css"; 4 | 5 | function App() { 6 | return ( 7 |
8 |
9 | logo 10 |

11 | Edit src/App.tsx and save to reload. 12 |

13 | 19 | Learn React 20 | 21 |
22 |
23 | ); 24 | } 25 | 26 | export default App; 27 | -------------------------------------------------------------------------------- /packages/client/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", 4 | "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", 5 | sans-serif; 6 | -webkit-font-smoothing: antialiased; 7 | -moz-osx-font-smoothing: grayscale; 8 | } 9 | 10 | code { 11 | font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", 12 | monospace; 13 | } 14 | -------------------------------------------------------------------------------- /packages/client/src/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom"; 3 | import "./index.css"; 4 | import App from "./App"; 5 | import * as serviceWorker from "./serviceWorker"; 6 | 7 | ReactDOM.render( 8 | 9 | 10 | , 11 | document.getElementById("root") 12 | ); 13 | 14 | // If you want your app to work offline and load faster, you can change 15 | // unregister() to register() below. Note this comes with some pitfalls. 16 | // Learn more about service workers: https://bit.ly/CRA-PWA 17 | serviceWorker.unregister(); 18 | -------------------------------------------------------------------------------- /packages/client/src/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /packages/client/src/react-app-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /packages/client/src/serviceWorker.ts: -------------------------------------------------------------------------------- 1 | // This optional code is used to register a service worker. 2 | // register() is not called by default. 3 | 4 | // This lets the app load faster on subsequent visits in production, and gives 5 | // it offline capabilities. However, it also means that developers (and users) 6 | // will only see deployed updates on subsequent visits to a page, after all the 7 | // existing tabs open on the page have been closed, since previously cached 8 | // resources are updated in the background. 9 | 10 | // To learn more about the benefits of this model and instructions on how to 11 | // opt-in, read https://bit.ly/CRA-PWA 12 | 13 | const isLocalhost = Boolean( 14 | window.location.hostname === "localhost" || 15 | // [::1] is the IPv6 localhost address. 16 | window.location.hostname === "[::1]" || 17 | // 127.0.0.0/8 are considered localhost for IPv4. 18 | window.location.hostname.match( 19 | /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/ 20 | ) 21 | ); 22 | 23 | type Config = { 24 | onSuccess?: (registration: ServiceWorkerRegistration) => void; 25 | onUpdate?: (registration: ServiceWorkerRegistration) => void; 26 | }; 27 | 28 | export function register(config?: Config) { 29 | if (process.env.NODE_ENV === "production" && "serviceWorker" in navigator) { 30 | // The URL constructor is available in all browsers that support SW. 31 | const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href); 32 | if (publicUrl.origin !== window.location.origin) { 33 | // Our service worker won't work if PUBLIC_URL is on a different origin 34 | // from what our page is served on. This might happen if a CDN is used to 35 | // serve assets; see https://github.com/facebook/create-react-app/issues/2374 36 | return; 37 | } 38 | 39 | window.addEventListener("load", () => { 40 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`; 41 | 42 | if (isLocalhost) { 43 | // This is running on localhost. Let's check if a service worker still exists or not. 44 | checkValidServiceWorker(swUrl, config); 45 | 46 | // Add some additional logging to localhost, pointing developers to the 47 | // service worker/PWA documentation. 48 | navigator.serviceWorker.ready.then(() => { 49 | console.log( 50 | "This web app is being served cache-first by a service " + 51 | "worker. To learn more, visit https://bit.ly/CRA-PWA" 52 | ); 53 | }); 54 | } else { 55 | // Is not localhost. Just register service worker 56 | registerValidSW(swUrl, config); 57 | } 58 | }); 59 | } 60 | } 61 | 62 | function registerValidSW(swUrl: string, config?: Config) { 63 | navigator.serviceWorker 64 | .register(swUrl) 65 | .then((registration) => { 66 | registration.onupdatefound = () => { 67 | const installingWorker = registration.installing; 68 | if (installingWorker == null) { 69 | return; 70 | } 71 | installingWorker.onstatechange = () => { 72 | if (installingWorker.state === "installed") { 73 | if (navigator.serviceWorker.controller) { 74 | // At this point, the updated precached content has been fetched, 75 | // but the previous service worker will still serve the older 76 | // content until all client tabs are closed. 77 | console.log( 78 | "New content is available and will be used when all " + 79 | "tabs for this page are closed. See https://bit.ly/CRA-PWA." 80 | ); 81 | 82 | // Execute callback 83 | if (config && config.onUpdate) { 84 | config.onUpdate(registration); 85 | } 86 | } else { 87 | // At this point, everything has been precached. 88 | // It's the perfect time to display a 89 | // "Content is cached for offline use." message. 90 | console.log("Content is cached for offline use."); 91 | 92 | // Execute callback 93 | if (config && config.onSuccess) { 94 | config.onSuccess(registration); 95 | } 96 | } 97 | } 98 | }; 99 | }; 100 | }) 101 | .catch((error) => { 102 | console.error("Error during service worker registration:", error); 103 | }); 104 | } 105 | 106 | function checkValidServiceWorker(swUrl: string, config?: Config) { 107 | // Check if the service worker can be found. If it can't reload the page. 108 | fetch(swUrl, { 109 | headers: { "Service-Worker": "script" }, 110 | }) 111 | .then((response) => { 112 | // Ensure service worker exists, and that we really are getting a JS file. 113 | const contentType = response.headers.get("content-type"); 114 | if ( 115 | response.status === 404 || 116 | (contentType != null && contentType.indexOf("javascript") === -1) 117 | ) { 118 | // No service worker found. Probably a different app. Reload the page. 119 | navigator.serviceWorker.ready.then((registration) => { 120 | registration.unregister().then(() => { 121 | window.location.reload(); 122 | }); 123 | }); 124 | } else { 125 | // Service worker found. Proceed as normal. 126 | registerValidSW(swUrl, config); 127 | } 128 | }) 129 | .catch(() => { 130 | console.log( 131 | "No internet connection found. App is running in offline mode." 132 | ); 133 | }); 134 | } 135 | 136 | export function unregister() { 137 | if ("serviceWorker" in navigator) { 138 | navigator.serviceWorker.ready 139 | .then((registration) => { 140 | registration.unregister(); 141 | }) 142 | .catch((error) => { 143 | console.error(error.message); 144 | }); 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /packages/client/src/setupTests.ts: -------------------------------------------------------------------------------- 1 | // jest-dom adds custom jest matchers for asserting on DOM nodes. 2 | // allows you to do things like: 3 | // expect(element).toHaveTextContent(/react/i) 4 | // learn more: https://github.com/testing-library/jest-dom 5 | import "@testing-library/jest-dom/extend-expect"; 6 | -------------------------------------------------------------------------------- /packages/client/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "esModuleInterop": true, 8 | "allowSyntheticDefaultImports": true, 9 | "strict": true, 10 | "forceConsistentCasingInFileNames": true, 11 | "module": "esnext", 12 | "moduleResolution": "node", 13 | "resolveJsonModule": true, 14 | "isolatedModules": true, 15 | "noEmit": true, 16 | "jsx": "react-jsx", 17 | "noFallthroughCasesInSwitch": false 18 | }, 19 | "include": ["src"] 20 | } 21 | -------------------------------------------------------------------------------- /packages/e2e/README.md: -------------------------------------------------------------------------------- 1 | # `e2e` 2 | 3 | Runs end-to-end tests on the full-stack Worker with [Jest](https://jestjs.io/) and [Playwright](https://playwright.dev/). 4 | 5 | ## Getting Started 6 | 7 | 1. `npm t` or `npm run test:ci` 8 | -------------------------------------------------------------------------------- /packages/e2e/__tests__/index.test.ts: -------------------------------------------------------------------------------- 1 | describe("the universe", () => { 2 | it("can do math", () => { 3 | expect(2 + 2).toBe(4); 4 | }); 5 | }); 6 | 7 | describe("the front-end", () => { 8 | beforeAll(async () => { 9 | await page.goto("http://localhost:8787/"); 10 | }); 11 | 12 | test("should load", async () => { 13 | await expect(page).toHaveText("Learn React"); 14 | }); 15 | }); 16 | 17 | describe("the back-end", () => { 18 | beforeAll(async () => { 19 | await page.goto("http://localhost:8787/hello"); 20 | }); 21 | 22 | test("should load", async () => { 23 | await expect(page).toEqualText("Hello, world!"); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /packages/e2e/jest-playwright.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | serverOptions: { 3 | command: "cd ../.. && npx wrangler dev --port 8787", 4 | port: 8787, 5 | launchTimeout: 30000, 6 | }, 7 | }; 8 | -------------------------------------------------------------------------------- /packages/e2e/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | preset: "jest-playwright-preset", 3 | transform: { 4 | "^.+\\.ts$": "ts-jest", 5 | }, 6 | setupFilesAfterEnv: ["expect-playwright"], 7 | // testEnvironment: "node", 8 | // collectCoverage: true, 9 | // collectCoverageFrom: [ 10 | // "src/**/*.{js,jsx,ts,tsx}", 11 | // "!**/coverage/**", 12 | // "!**/node_modules/**", 13 | // "!**/babel.config.js", 14 | // "!**/jest.setup.js", 15 | // ], 16 | }; 17 | -------------------------------------------------------------------------------- /packages/e2e/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "e2e", 3 | "private": true, 4 | "scripts": { 5 | "clean:node": "rimraf node_modules package-lock.json", 6 | "pretest": "cd ../.. && npm run prebuild", 7 | "test": "jest --watch --coverage=false", 8 | "pretest:ci": "npm run pretest", 9 | "test:ci": "jest --ci" 10 | }, 11 | "devDependencies": { 12 | "@cloudflare/workers-types": "2.1.0", 13 | "@types/jest": "26.0.20", 14 | "expect-playwright": "0.3.0", 15 | "jest": "26.6.3", 16 | "jest-playwright-preset": "1.4.3", 17 | "playwright": "1.7.1", 18 | "rimraf": "3.0.2", 19 | "ts-jest": "26.4.4" 20 | }, 21 | "dependencies": {} 22 | } 23 | -------------------------------------------------------------------------------- /packages/e2e/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "esnext", 4 | "module": "commonjs", 5 | "experimentalDecorators": true, 6 | "lib": ["esnext", "webworker"], 7 | "types": ["jest", "jest-playwright-preset", "expect-playwright"] 8 | }, 9 | "include": ["./__tests__/**/*.ts"], 10 | "exclude": ["node_modules/"] 11 | } 12 | -------------------------------------------------------------------------------- /packages/server/README.md: -------------------------------------------------------------------------------- 1 | # `server` 2 | 3 | ## Getting Started 4 | 5 | 8 | 9 | 1. Update `/src/types.d.ts`: 10 | 11 | 1. Add KV Namespaces. For example: 12 | 13 | ```typescript 14 | declare global { 15 | const NAMESPACENAME: KVNamespace; 16 | } 17 | ``` 18 | -------------------------------------------------------------------------------- /packages/server/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | preset: "ts-jest", 3 | testEnvironment: "node", 4 | setupFiles: ["./jest.setup.js"], 5 | collectCoverage: true, 6 | collectCoverageFrom: [ 7 | "src/**/*.{js,jsx,ts,tsx}", 8 | "!**/coverage/**", 9 | "!**/node_modules/**", 10 | "!**/babel.config.js", 11 | "!**/jest.setup.js", 12 | ], 13 | }; 14 | -------------------------------------------------------------------------------- /packages/server/jest.setup.js: -------------------------------------------------------------------------------- 1 | require("cross-fetch/polyfill"); 2 | -------------------------------------------------------------------------------- /packages/server/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "server", 3 | "private": true, 4 | "main": "src/index.ts", 5 | "scripts": { 6 | "clean:node": "rimraf node_modules package-lock.json", 7 | "test": "jest --watch --coverage=false --changedSince=origin/master", 8 | "test:ci": "jest --ci" 9 | }, 10 | "devDependencies": { 11 | "@cloudflare/workers-types": "2.1.0", 12 | "@types/jest": "26.0.20", 13 | "jest": "26.6.3", 14 | "rimraf": "3.0.2", 15 | "ts-jest": "26.4.4" 16 | }, 17 | "dependencies": { 18 | "@glenstack/cf-workers-router": "1.0.1" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /packages/server/src/hello.test.ts: -------------------------------------------------------------------------------- 1 | import { handleHello } from "./hello"; 2 | 3 | describe("hello", () => { 4 | it("returns a response", async () => { 5 | const response = await handleHello(undefined); 6 | const text = await response.text(); 7 | expect(text).toEqual("Hello, world!"); 8 | }); 9 | }); 10 | -------------------------------------------------------------------------------- /packages/server/src/hello.ts: -------------------------------------------------------------------------------- 1 | export const handleHello = async (request: Request): Promise => 2 | new Response("Hello, world!", { headers: { "Content-Type": "text/plain" } }); 3 | -------------------------------------------------------------------------------- /packages/server/src/index.test.ts: -------------------------------------------------------------------------------- 1 | describe("the universe", () => { 2 | it("can do math", () => { 3 | expect(2 + 2).toBe(4); 4 | }); 5 | }); 6 | -------------------------------------------------------------------------------- /packages/server/src/index.ts: -------------------------------------------------------------------------------- 1 | import { Router } from "@glenstack/cf-workers-router"; 2 | import { handleHello } from "./hello"; 3 | 4 | const router = new Router(); 5 | 6 | router.get("/hello", (request) => handleHello(request)); 7 | 8 | export const handleRequest = async (request: Request): Promise => { 9 | console.log("Hello from a worker!"); 10 | return router.route(request); 11 | }; 12 | -------------------------------------------------------------------------------- /packages/server/src/types.d.ts: -------------------------------------------------------------------------------- 1 | import { KVNamespace } from "@cloudflare/workers-types"; 2 | 3 | declare global {} 4 | -------------------------------------------------------------------------------- /packages/server/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "esnext", 4 | "module": "commonjs", 5 | "experimentalDecorators": true, 6 | "lib": ["esnext", "webworker"] 7 | }, 8 | "include": [ 9 | "./src/**/*.ts", 10 | "./node_modules/@cloudflare/workers-types/index.d.ts" 11 | ], 12 | "typeAcquisition": { 13 | "include": ["jest"] 14 | }, 15 | "exclude": ["node_modules/"] 16 | } 17 | -------------------------------------------------------------------------------- /packages/worker/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | /worker -------------------------------------------------------------------------------- /packages/worker/README.md: -------------------------------------------------------------------------------- 1 | # `worker` 2 | 3 | ## Getting Started 4 | 5 | 1. Update `src/handleError.ts` to log to error reporting service or similar. 6 | 7 | 1. Update `src/pages.ts` with pretty pages. 8 | -------------------------------------------------------------------------------- /packages/worker/null.js: -------------------------------------------------------------------------------- 1 | module.exports = {}; 2 | -------------------------------------------------------------------------------- /packages/worker/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "worker", 3 | "requires": true, 4 | "lockfileVersion": 1, 5 | "dependencies": { 6 | "@cloudflare/kv-asset-handler": { 7 | "version": "0.1.0", 8 | "resolved": "https://registry.npmjs.org/@cloudflare/kv-asset-handler/-/kv-asset-handler-0.1.0.tgz", 9 | "integrity": "sha512-sXZRw/Z5JJfi/nGh66SECSm5L2zomyf6f9O3nc5QOI11/R3W/4N+BPOecp/Dc8eL/q/Rwgb7lwhhjnqy8O5CYA==", 10 | "requires": { 11 | "@cloudflare/workers-types": "^2.0.0", 12 | "@types/mime": "^2.0.2", 13 | "mime": "^2.4.6" 14 | } 15 | }, 16 | "@cloudflare/workers-types": { 17 | "version": "2.1.0", 18 | "resolved": "https://registry.npmjs.org/@cloudflare/workers-types/-/workers-types-2.1.0.tgz", 19 | "integrity": "sha512-VmXaHTq0lt6Xre4aK1hUK25hjZjuEUkHtdUEt0FJamv+NzQO54Gwp6Zr5Cfu6SP5EQ/tTmTMP/tK9npA8zhcCg==" 20 | }, 21 | "@discoveryjs/json-ext": { 22 | "version": "0.5.2", 23 | "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.2.tgz", 24 | "integrity": "sha512-HyYEUDeIj5rRQU2Hk5HTB2uHsbRQpF70nvMhVzi+VJR0X+xNEhjPui4/kBf3VeH/wqD28PT4sVOm8qqLjBrSZg==", 25 | "dev": true 26 | }, 27 | "@types/eslint": { 28 | "version": "7.2.6", 29 | "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-7.2.6.tgz", 30 | "integrity": "sha512-I+1sYH+NPQ3/tVqCeUSBwTE/0heyvtXqpIopUUArlBm0Kpocb8FbMa3AZ/ASKIFpN3rnEx932TTXDbt9OXsNDw==", 31 | "dev": true, 32 | "requires": { 33 | "@types/estree": "*", 34 | "@types/json-schema": "*" 35 | } 36 | }, 37 | "@types/eslint-scope": { 38 | "version": "3.7.0", 39 | "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.0.tgz", 40 | "integrity": "sha512-O/ql2+rrCUe2W2rs7wMR+GqPRcgB6UiqN5RhrR5xruFlY7l9YLMn0ZkDzjoHLeiFkR8MCQZVudUuuvQ2BLC9Qw==", 41 | "dev": true, 42 | "requires": { 43 | "@types/eslint": "*", 44 | "@types/estree": "*" 45 | } 46 | }, 47 | "@types/estree": { 48 | "version": "0.0.45", 49 | "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.45.tgz", 50 | "integrity": "sha512-jnqIUKDUqJbDIUxm0Uj7bnlMnRm1T/eZ9N+AVMqhPgzrba2GhGG5o/jCTwmdPK709nEZsGoMzXEDUjcXHa3W0g==", 51 | "dev": true 52 | }, 53 | "@types/json-schema": { 54 | "version": "7.0.6", 55 | "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.6.tgz", 56 | "integrity": "sha512-3c+yGKvVP5Y9TYBEibGNR+kLtijnj7mYrXRg+WpFb2X9xm04g/DXYkfg4hmzJQosc9snFNUPkbYIhu+KAm6jJw==", 57 | "dev": true 58 | }, 59 | "@types/mime": { 60 | "version": "2.0.3", 61 | "resolved": "https://registry.npmjs.org/@types/mime/-/mime-2.0.3.tgz", 62 | "integrity": "sha512-Jus9s4CDbqwocc5pOAnh8ShfrnMcPHuJYzVcSUU7lrh8Ni5HuIqX3oilL86p3dlTrk0LzHRCgA/GQ7uNCw6l2Q==" 63 | }, 64 | "@types/node": { 65 | "version": "14.14.20", 66 | "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.20.tgz", 67 | "integrity": "sha512-Y93R97Ouif9JEOWPIUyU+eyIdyRqQR0I8Ez1dzku4hDx34NWh4HbtIc3WNzwB1Y9ULvNGeu5B8h8bVL5cAk4/A==", 68 | "dev": true 69 | }, 70 | "@webassemblyjs/ast": { 71 | "version": "1.9.1", 72 | "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.9.1.tgz", 73 | "integrity": "sha512-uMu1nCWn2Wxyy126LlGqRVlhdTOsO/bsBRI4dNq3+6SiSuRKRQX6ejjKgh82LoGAPSq72lDUiQ4FWVaf0PecYw==", 74 | "dev": true, 75 | "requires": { 76 | "@webassemblyjs/helper-module-context": "1.9.1", 77 | "@webassemblyjs/helper-wasm-bytecode": "1.9.1", 78 | "@webassemblyjs/wast-parser": "1.9.1" 79 | } 80 | }, 81 | "@webassemblyjs/floating-point-hex-parser": { 82 | "version": "1.9.1", 83 | "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.9.1.tgz", 84 | "integrity": "sha512-5VEKu024RySmLKTTBl9q1eO/2K5jk9ZS+2HXDBLA9s9p5IjkaXxWiDb/+b7wSQp6FRdLaH1IVGIfOex58Na2pg==", 85 | "dev": true 86 | }, 87 | "@webassemblyjs/helper-api-error": { 88 | "version": "1.9.1", 89 | "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.9.1.tgz", 90 | "integrity": "sha512-y1lGmfm38djrScwpeL37rRR9f1D6sM8RhMpvM7CYLzOlHVboouZokXK/G88BpzW0NQBSvCCOnW5BFhten4FPfA==", 91 | "dev": true 92 | }, 93 | "@webassemblyjs/helper-buffer": { 94 | "version": "1.9.1", 95 | "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.9.1.tgz", 96 | "integrity": "sha512-uS6VSgieHbk/m4GSkMU5cqe/5TekdCzQso4revCIEQ3vpGZgqSSExi4jWpTWwDpAHOIAb1Jfrs0gUB9AA4n71w==", 97 | "dev": true 98 | }, 99 | "@webassemblyjs/helper-code-frame": { 100 | "version": "1.9.1", 101 | "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.9.1.tgz", 102 | "integrity": "sha512-ZQ2ZT6Evk4DPIfD+92AraGYaFIqGm4U20e7FpXwl7WUo2Pn1mZ1v8VGH8i+Y++IQpxPbQo/UyG0Khs7eInskzA==", 103 | "dev": true, 104 | "requires": { 105 | "@webassemblyjs/wast-printer": "1.9.1" 106 | } 107 | }, 108 | "@webassemblyjs/helper-fsm": { 109 | "version": "1.9.1", 110 | "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-fsm/-/helper-fsm-1.9.1.tgz", 111 | "integrity": "sha512-J32HGpveEqqcKFS0YbgicB0zAlpfIxJa5MjxDxhu3i5ltPcVfY5EPvKQ1suRguFPehxiUs+/hfkwPEXom/l0lw==", 112 | "dev": true 113 | }, 114 | "@webassemblyjs/helper-module-context": { 115 | "version": "1.9.1", 116 | "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-module-context/-/helper-module-context-1.9.1.tgz", 117 | "integrity": "sha512-IEH2cMmEQKt7fqelLWB5e/cMdZXf2rST1JIrzWmf4XBt3QTxGdnnLvV4DYoN8pJjOx0VYXsWg+yF16MmJtolZg==", 118 | "dev": true, 119 | "requires": { 120 | "@webassemblyjs/ast": "1.9.1" 121 | } 122 | }, 123 | "@webassemblyjs/helper-wasm-bytecode": { 124 | "version": "1.9.1", 125 | "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.9.1.tgz", 126 | "integrity": "sha512-i2rGTBqFUcSXxyjt2K4vm/3kkHwyzG6o427iCjcIKjOqpWH8SEem+xe82jUk1iydJO250/CvE5o7hzNAMZf0dQ==", 127 | "dev": true 128 | }, 129 | "@webassemblyjs/helper-wasm-section": { 130 | "version": "1.9.1", 131 | "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.9.1.tgz", 132 | "integrity": "sha512-FetqzjtXZr2d57IECK+aId3D0IcGweeM0CbAnJHkYJkcRTHP+YcMb7Wmc0j21h5UWBpwYGb9dSkK/93SRCTrGg==", 133 | "dev": true, 134 | "requires": { 135 | "@webassemblyjs/ast": "1.9.1", 136 | "@webassemblyjs/helper-buffer": "1.9.1", 137 | "@webassemblyjs/helper-wasm-bytecode": "1.9.1", 138 | "@webassemblyjs/wasm-gen": "1.9.1" 139 | } 140 | }, 141 | "@webassemblyjs/ieee754": { 142 | "version": "1.9.1", 143 | "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.9.1.tgz", 144 | "integrity": "sha512-EvTG9M78zP1MmkBpUjGQHZc26DzPGZSLIPxYHCjQsBMo60Qy2W34qf8z0exRDtxBbRIoiKa5dFyWer/7r1aaSQ==", 145 | "dev": true, 146 | "requires": { 147 | "@xtuc/ieee754": "^1.2.0" 148 | } 149 | }, 150 | "@webassemblyjs/leb128": { 151 | "version": "1.9.1", 152 | "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.9.1.tgz", 153 | "integrity": "sha512-Oc04ub0vFfLnF+2/+ki3AE+anmW4sv9uNBqb+79fgTaPv6xJsOT0dhphNfL3FrME84CbX/D1T9XT8tjFo0IIiw==", 154 | "dev": true, 155 | "requires": { 156 | "@xtuc/long": "4.2.2" 157 | } 158 | }, 159 | "@webassemblyjs/utf8": { 160 | "version": "1.9.1", 161 | "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.9.1.tgz", 162 | "integrity": "sha512-llkYtppagjCodFjo0alWOUhAkfOiQPQDIc5oA6C9sFAXz7vC9QhZf/f8ijQIX+A9ToM3c9Pq85X0EX7nx9gVhg==", 163 | "dev": true 164 | }, 165 | "@webassemblyjs/wasm-edit": { 166 | "version": "1.9.1", 167 | "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.9.1.tgz", 168 | "integrity": "sha512-S2IaD6+x9B2Xi8BCT0eGsrXXd8UxAh2LVJpg1ZMtHXnrDcsTtIX2bDjHi40Hio6Lc62dWHmKdvksI+MClCYbbw==", 169 | "dev": true, 170 | "requires": { 171 | "@webassemblyjs/ast": "1.9.1", 172 | "@webassemblyjs/helper-buffer": "1.9.1", 173 | "@webassemblyjs/helper-wasm-bytecode": "1.9.1", 174 | "@webassemblyjs/helper-wasm-section": "1.9.1", 175 | "@webassemblyjs/wasm-gen": "1.9.1", 176 | "@webassemblyjs/wasm-opt": "1.9.1", 177 | "@webassemblyjs/wasm-parser": "1.9.1", 178 | "@webassemblyjs/wast-printer": "1.9.1" 179 | } 180 | }, 181 | "@webassemblyjs/wasm-gen": { 182 | "version": "1.9.1", 183 | "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.9.1.tgz", 184 | "integrity": "sha512-bqWI0S4lBQsEN5FTZ35vYzfKUJvtjNnBobB1agCALH30xNk1LToZ7Z8eiaR/Z5iVECTlBndoRQV3F6mbEqE/fg==", 185 | "dev": true, 186 | "requires": { 187 | "@webassemblyjs/ast": "1.9.1", 188 | "@webassemblyjs/helper-wasm-bytecode": "1.9.1", 189 | "@webassemblyjs/ieee754": "1.9.1", 190 | "@webassemblyjs/leb128": "1.9.1", 191 | "@webassemblyjs/utf8": "1.9.1" 192 | } 193 | }, 194 | "@webassemblyjs/wasm-opt": { 195 | "version": "1.9.1", 196 | "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.9.1.tgz", 197 | "integrity": "sha512-gSf7I7YWVXZ5c6XqTEqkZjVs8K1kc1k57vsB6KBQscSagDNbAdxt6MwuJoMjsE1yWY1tsuL+pga268A6u+Fdkg==", 198 | "dev": true, 199 | "requires": { 200 | "@webassemblyjs/ast": "1.9.1", 201 | "@webassemblyjs/helper-buffer": "1.9.1", 202 | "@webassemblyjs/wasm-gen": "1.9.1", 203 | "@webassemblyjs/wasm-parser": "1.9.1" 204 | } 205 | }, 206 | "@webassemblyjs/wasm-parser": { 207 | "version": "1.9.1", 208 | "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.9.1.tgz", 209 | "integrity": "sha512-ImM4N2T1MEIond0MyE3rXvStVxEmivQrDKf/ggfh5pP6EHu3lL/YTAoSrR7shrbKNPpeKpGesW1LIK/L4kqduw==", 210 | "dev": true, 211 | "requires": { 212 | "@webassemblyjs/ast": "1.9.1", 213 | "@webassemblyjs/helper-api-error": "1.9.1", 214 | "@webassemblyjs/helper-wasm-bytecode": "1.9.1", 215 | "@webassemblyjs/ieee754": "1.9.1", 216 | "@webassemblyjs/leb128": "1.9.1", 217 | "@webassemblyjs/utf8": "1.9.1" 218 | } 219 | }, 220 | "@webassemblyjs/wast-parser": { 221 | "version": "1.9.1", 222 | "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-parser/-/wast-parser-1.9.1.tgz", 223 | "integrity": "sha512-2xVxejXSvj3ls/o2TR/zI6p28qsGupjHhnHL6URULQRcXmryn3w7G83jQMcT7PHqUfyle65fZtWLukfdLdE7qw==", 224 | "dev": true, 225 | "requires": { 226 | "@webassemblyjs/ast": "1.9.1", 227 | "@webassemblyjs/floating-point-hex-parser": "1.9.1", 228 | "@webassemblyjs/helper-api-error": "1.9.1", 229 | "@webassemblyjs/helper-code-frame": "1.9.1", 230 | "@webassemblyjs/helper-fsm": "1.9.1", 231 | "@xtuc/long": "4.2.2" 232 | } 233 | }, 234 | "@webassemblyjs/wast-printer": { 235 | "version": "1.9.1", 236 | "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.9.1.tgz", 237 | "integrity": "sha512-tDV8V15wm7mmbAH6XvQRU1X+oPGmeOzYsd6h7hlRLz6QpV4Ec/KKxM8OpLtFmQPLCreGxTp+HuxtH4pRIZyL9w==", 238 | "dev": true, 239 | "requires": { 240 | "@webassemblyjs/ast": "1.9.1", 241 | "@webassemblyjs/wast-parser": "1.9.1", 242 | "@xtuc/long": "4.2.2" 243 | } 244 | }, 245 | "@webpack-cli/info": { 246 | "version": "1.2.1", 247 | "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.2.1.tgz", 248 | "integrity": "sha512-fLnDML5HZ5AEKzHul8xLAksoKN2cibu6MgonkUj8R9V7bbeVRkd1XbGEGWrAUNYHbX1jcqCsDEpBviE5StPMzQ==", 249 | "dev": true, 250 | "requires": { 251 | "envinfo": "^7.7.3" 252 | } 253 | }, 254 | "@webpack-cli/serve": { 255 | "version": "1.2.1", 256 | "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.2.1.tgz", 257 | "integrity": "sha512-Zj1z6AyS+vqV6Hfi7ngCjFGdHV5EwZNIHo6QfFTNe9PyW+zBU1zJ9BiOW1pmUEq950RC4+Dym6flyA/61/vhyw==", 258 | "dev": true 259 | }, 260 | "@xtuc/ieee754": { 261 | "version": "1.2.0", 262 | "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", 263 | "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", 264 | "dev": true 265 | }, 266 | "@xtuc/long": { 267 | "version": "4.2.2", 268 | "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", 269 | "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", 270 | "dev": true 271 | }, 272 | "acorn": { 273 | "version": "8.0.4", 274 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.0.4.tgz", 275 | "integrity": "sha512-XNP0PqF1XD19ZlLKvB7cMmnZswW4C/03pRHgirB30uSJTaS3A3V1/P4sS3HPvFmjoriPCJQs+JDSbm4bL1TxGQ==", 276 | "dev": true 277 | }, 278 | "ajv": { 279 | "version": "6.12.6", 280 | "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", 281 | "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", 282 | "dev": true, 283 | "requires": { 284 | "fast-deep-equal": "^3.1.1", 285 | "fast-json-stable-stringify": "^2.0.0", 286 | "json-schema-traverse": "^0.4.1", 287 | "uri-js": "^4.2.2" 288 | } 289 | }, 290 | "ajv-keywords": { 291 | "version": "3.5.2", 292 | "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", 293 | "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", 294 | "dev": true 295 | }, 296 | "ansi-colors": { 297 | "version": "4.1.1", 298 | "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", 299 | "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", 300 | "dev": true 301 | }, 302 | "balanced-match": { 303 | "version": "1.0.0", 304 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", 305 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", 306 | "dev": true 307 | }, 308 | "brace-expansion": { 309 | "version": "1.1.11", 310 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 311 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 312 | "dev": true, 313 | "requires": { 314 | "balanced-match": "^1.0.0", 315 | "concat-map": "0.0.1" 316 | } 317 | }, 318 | "browserslist": { 319 | "version": "4.16.1", 320 | "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.1.tgz", 321 | "integrity": "sha512-UXhDrwqsNcpTYJBTZsbGATDxZbiVDsx6UjpmRUmtnP10pr8wAYr5LgFoEFw9ixriQH2mv/NX2SfGzE/o8GndLA==", 322 | "dev": true, 323 | "requires": { 324 | "caniuse-lite": "^1.0.30001173", 325 | "colorette": "^1.2.1", 326 | "electron-to-chromium": "^1.3.634", 327 | "escalade": "^3.1.1", 328 | "node-releases": "^1.1.69" 329 | } 330 | }, 331 | "buffer-from": { 332 | "version": "1.1.1", 333 | "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", 334 | "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", 335 | "dev": true 336 | }, 337 | "caniuse-lite": { 338 | "version": "1.0.30001173", 339 | "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001173.tgz", 340 | "integrity": "sha512-R3aqmjrICdGCTAnSXtNyvWYMK3YtV5jwudbq0T7nN9k4kmE4CBuwPqyJ+KBzepSTh0huivV2gLbSMEzTTmfeYw==", 341 | "dev": true 342 | }, 343 | "chrome-trace-event": { 344 | "version": "1.0.2", 345 | "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.2.tgz", 346 | "integrity": "sha512-9e/zx1jw7B4CO+c/RXoCsfg/x1AfUBioy4owYH0bJprEYAx5hRFLRhWBqHAG57D0ZM4H7vxbP7bPe0VwhQRYDQ==", 347 | "dev": true, 348 | "requires": { 349 | "tslib": "^1.9.0" 350 | } 351 | }, 352 | "colorette": { 353 | "version": "1.2.1", 354 | "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.1.tgz", 355 | "integrity": "sha512-puCDz0CzydiSYOrnXpz/PKd69zRrribezjtE9yd4zvytoRc8+RY/KJPvtPFKZS3E3wP6neGyMe0vOTlHO5L3Pw==", 356 | "dev": true 357 | }, 358 | "commander": { 359 | "version": "2.20.3", 360 | "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", 361 | "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", 362 | "dev": true 363 | }, 364 | "concat-map": { 365 | "version": "0.0.1", 366 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 367 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", 368 | "dev": true 369 | }, 370 | "cross-spawn": { 371 | "version": "7.0.3", 372 | "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", 373 | "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", 374 | "dev": true, 375 | "requires": { 376 | "path-key": "^3.1.0", 377 | "shebang-command": "^2.0.0", 378 | "which": "^2.0.1" 379 | } 380 | }, 381 | "electron-to-chromium": { 382 | "version": "1.3.635", 383 | "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.635.tgz", 384 | "integrity": "sha512-RRriZOLs9CpW6KTLmgBqyUdnY0QNqqWs0HOtuQGGEMizOTNNn1P7sGRBxARnUeLejOsgwjDyRqT3E/CSst02ZQ==", 385 | "dev": true 386 | }, 387 | "enhanced-resolve": { 388 | "version": "5.4.1", 389 | "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.4.1.tgz", 390 | "integrity": "sha512-4GbyIMzYktTFoRSmkbgZ1LU+RXwf4AQ8Z+rSuuh1dC8plp0PPeaWvx6+G4hh4KnUJ48VoxKbNyA1QQQIUpXjYA==", 391 | "dev": true, 392 | "requires": { 393 | "graceful-fs": "^4.2.4", 394 | "tapable": "^2.2.0" 395 | } 396 | }, 397 | "enquirer": { 398 | "version": "2.3.6", 399 | "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", 400 | "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", 401 | "dev": true, 402 | "requires": { 403 | "ansi-colors": "^4.1.1" 404 | } 405 | }, 406 | "envinfo": { 407 | "version": "7.7.3", 408 | "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.7.3.tgz", 409 | "integrity": "sha512-46+j5QxbPWza0PB1i15nZx0xQ4I/EfQxg9J8Had3b408SV63nEtor2e+oiY63amTo9KTuh2a3XLObNwduxYwwA==", 410 | "dev": true 411 | }, 412 | "escalade": { 413 | "version": "3.1.1", 414 | "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", 415 | "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", 416 | "dev": true 417 | }, 418 | "eslint-scope": { 419 | "version": "5.1.1", 420 | "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", 421 | "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", 422 | "dev": true, 423 | "requires": { 424 | "esrecurse": "^4.3.0", 425 | "estraverse": "^4.1.1" 426 | } 427 | }, 428 | "esrecurse": { 429 | "version": "4.3.0", 430 | "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", 431 | "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", 432 | "dev": true, 433 | "requires": { 434 | "estraverse": "^5.2.0" 435 | }, 436 | "dependencies": { 437 | "estraverse": { 438 | "version": "5.2.0", 439 | "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", 440 | "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", 441 | "dev": true 442 | } 443 | } 444 | }, 445 | "estraverse": { 446 | "version": "4.3.0", 447 | "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", 448 | "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", 449 | "dev": true 450 | }, 451 | "events": { 452 | "version": "3.2.0", 453 | "resolved": "https://registry.npmjs.org/events/-/events-3.2.0.tgz", 454 | "integrity": "sha512-/46HWwbfCX2xTawVfkKLGxMifJYQBWMwY1mjywRtb4c9x8l5NP3KoJtnIOiL1hfdRkIuYhETxQlo62IF8tcnlg==", 455 | "dev": true 456 | }, 457 | "execa": { 458 | "version": "5.0.0", 459 | "resolved": "https://registry.npmjs.org/execa/-/execa-5.0.0.tgz", 460 | "integrity": "sha512-ov6w/2LCiuyO4RLYGdpFGjkcs0wMTgGE8PrkTHikeUy5iJekXyPIKUjifk5CsE0pt7sMCrMZ3YNqoCj6idQOnQ==", 461 | "dev": true, 462 | "requires": { 463 | "cross-spawn": "^7.0.3", 464 | "get-stream": "^6.0.0", 465 | "human-signals": "^2.1.0", 466 | "is-stream": "^2.0.0", 467 | "merge-stream": "^2.0.0", 468 | "npm-run-path": "^4.0.1", 469 | "onetime": "^5.1.2", 470 | "signal-exit": "^3.0.3", 471 | "strip-final-newline": "^2.0.0" 472 | } 473 | }, 474 | "fast-deep-equal": { 475 | "version": "3.1.3", 476 | "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", 477 | "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", 478 | "dev": true 479 | }, 480 | "fast-json-stable-stringify": { 481 | "version": "2.1.0", 482 | "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", 483 | "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", 484 | "dev": true 485 | }, 486 | "fastest-levenshtein": { 487 | "version": "1.0.12", 488 | "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.12.tgz", 489 | "integrity": "sha512-On2N+BpYJ15xIC974QNVuYGMOlEVt4s0EOI3wwMqOmK1fdDY+FN/zltPV8vosq4ad4c/gJ1KHScUn/6AWIgiow==", 490 | "dev": true 491 | }, 492 | "find-up": { 493 | "version": "5.0.0", 494 | "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", 495 | "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", 496 | "dev": true, 497 | "requires": { 498 | "locate-path": "^6.0.0", 499 | "path-exists": "^4.0.0" 500 | } 501 | }, 502 | "fs.realpath": { 503 | "version": "1.0.0", 504 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 505 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", 506 | "dev": true 507 | }, 508 | "function-bind": { 509 | "version": "1.1.1", 510 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", 511 | "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", 512 | "dev": true 513 | }, 514 | "get-stream": { 515 | "version": "6.0.0", 516 | "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.0.tgz", 517 | "integrity": "sha512-A1B3Bh1UmL0bidM/YX2NsCOTnGJePL9rO/M+Mw3m9f2gUpfokS0hi5Eah0WSUEWZdZhIZtMjkIYS7mDfOqNHbg==", 518 | "dev": true 519 | }, 520 | "glob": { 521 | "version": "7.1.6", 522 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", 523 | "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", 524 | "dev": true, 525 | "requires": { 526 | "fs.realpath": "^1.0.0", 527 | "inflight": "^1.0.4", 528 | "inherits": "2", 529 | "minimatch": "^3.0.4", 530 | "once": "^1.3.0", 531 | "path-is-absolute": "^1.0.0" 532 | } 533 | }, 534 | "glob-to-regexp": { 535 | "version": "0.4.1", 536 | "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", 537 | "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", 538 | "dev": true 539 | }, 540 | "graceful-fs": { 541 | "version": "4.2.4", 542 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", 543 | "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==", 544 | "dev": true 545 | }, 546 | "has": { 547 | "version": "1.0.3", 548 | "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", 549 | "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", 550 | "dev": true, 551 | "requires": { 552 | "function-bind": "^1.1.1" 553 | } 554 | }, 555 | "has-flag": { 556 | "version": "4.0.0", 557 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", 558 | "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", 559 | "dev": true 560 | }, 561 | "human-signals": { 562 | "version": "2.1.0", 563 | "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", 564 | "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", 565 | "dev": true 566 | }, 567 | "import-local": { 568 | "version": "3.0.2", 569 | "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.0.2.tgz", 570 | "integrity": "sha512-vjL3+w0oulAVZ0hBHnxa/Nm5TAurf9YLQJDhqRZyqb+VKGOB6LU8t9H1Nr5CIo16vh9XfJTOoHwU0B71S557gA==", 571 | "dev": true, 572 | "requires": { 573 | "pkg-dir": "^4.2.0", 574 | "resolve-cwd": "^3.0.0" 575 | }, 576 | "dependencies": { 577 | "find-up": { 578 | "version": "4.1.0", 579 | "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", 580 | "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", 581 | "dev": true, 582 | "requires": { 583 | "locate-path": "^5.0.0", 584 | "path-exists": "^4.0.0" 585 | } 586 | }, 587 | "locate-path": { 588 | "version": "5.0.0", 589 | "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", 590 | "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", 591 | "dev": true, 592 | "requires": { 593 | "p-locate": "^4.1.0" 594 | } 595 | }, 596 | "p-limit": { 597 | "version": "2.3.0", 598 | "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", 599 | "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", 600 | "dev": true, 601 | "requires": { 602 | "p-try": "^2.0.0" 603 | } 604 | }, 605 | "p-locate": { 606 | "version": "4.1.0", 607 | "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", 608 | "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", 609 | "dev": true, 610 | "requires": { 611 | "p-limit": "^2.2.0" 612 | } 613 | }, 614 | "pkg-dir": { 615 | "version": "4.2.0", 616 | "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", 617 | "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", 618 | "dev": true, 619 | "requires": { 620 | "find-up": "^4.0.0" 621 | } 622 | } 623 | } 624 | }, 625 | "inflight": { 626 | "version": "1.0.6", 627 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 628 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", 629 | "dev": true, 630 | "requires": { 631 | "once": "^1.3.0", 632 | "wrappy": "1" 633 | } 634 | }, 635 | "inherits": { 636 | "version": "2.0.4", 637 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 638 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", 639 | "dev": true 640 | }, 641 | "interpret": { 642 | "version": "2.2.0", 643 | "resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz", 644 | "integrity": "sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==", 645 | "dev": true 646 | }, 647 | "is-core-module": { 648 | "version": "2.2.0", 649 | "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.2.0.tgz", 650 | "integrity": "sha512-XRAfAdyyY5F5cOXn7hYQDqh2Xmii+DEfIcQGxK/uNwMHhIkPWO0g8msXcbzLe+MpGoR951MlqM/2iIlU4vKDdQ==", 651 | "dev": true, 652 | "requires": { 653 | "has": "^1.0.3" 654 | } 655 | }, 656 | "is-stream": { 657 | "version": "2.0.0", 658 | "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", 659 | "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==", 660 | "dev": true 661 | }, 662 | "isexe": { 663 | "version": "2.0.0", 664 | "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", 665 | "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", 666 | "dev": true 667 | }, 668 | "jest-worker": { 669 | "version": "26.6.2", 670 | "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz", 671 | "integrity": "sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==", 672 | "dev": true, 673 | "requires": { 674 | "@types/node": "*", 675 | "merge-stream": "^2.0.0", 676 | "supports-color": "^7.0.0" 677 | } 678 | }, 679 | "json-parse-better-errors": { 680 | "version": "1.0.2", 681 | "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", 682 | "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", 683 | "dev": true 684 | }, 685 | "json-schema-traverse": { 686 | "version": "0.4.1", 687 | "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", 688 | "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", 689 | "dev": true 690 | }, 691 | "loader-runner": { 692 | "version": "4.2.0", 693 | "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.2.0.tgz", 694 | "integrity": "sha512-92+huvxMvYlMzMt0iIOukcwYBFpkYJdpl2xsZ7LrlayO7E8SOv+JJUEK17B/dJIHAOLMfh2dZZ/Y18WgmGtYNw==", 695 | "dev": true 696 | }, 697 | "locate-path": { 698 | "version": "6.0.0", 699 | "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", 700 | "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", 701 | "dev": true, 702 | "requires": { 703 | "p-locate": "^5.0.0" 704 | } 705 | }, 706 | "lodash": { 707 | "version": "4.17.20", 708 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", 709 | "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==", 710 | "dev": true 711 | }, 712 | "merge-stream": { 713 | "version": "2.0.0", 714 | "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", 715 | "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", 716 | "dev": true 717 | }, 718 | "mime": { 719 | "version": "2.4.7", 720 | "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.7.tgz", 721 | "integrity": "sha512-dhNd1uA2u397uQk3Nv5LM4lm93WYDUXFn3Fu291FJerns4jyTudqhIWe4W04YLy7Uk1tm1Ore04NpjRvQp/NPA==" 722 | }, 723 | "mime-db": { 724 | "version": "1.45.0", 725 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.45.0.tgz", 726 | "integrity": "sha512-CkqLUxUk15hofLoLyljJSrukZi8mAtgd+yE5uO4tqRZsdsAJKv0O+rFMhVDRJgozy+yG6md5KwuXhD4ocIoP+w==", 727 | "dev": true 728 | }, 729 | "mime-types": { 730 | "version": "2.1.28", 731 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.28.tgz", 732 | "integrity": "sha512-0TO2yJ5YHYr7M2zzT7gDU1tbwHxEUWBCLt0lscSNpcdAfFyJOVEpRYNS7EXVcTLNj/25QO8gulHC5JtTzSE2UQ==", 733 | "dev": true, 734 | "requires": { 735 | "mime-db": "1.45.0" 736 | } 737 | }, 738 | "mimic-fn": { 739 | "version": "2.1.0", 740 | "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", 741 | "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", 742 | "dev": true 743 | }, 744 | "minimatch": { 745 | "version": "3.0.4", 746 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", 747 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", 748 | "dev": true, 749 | "requires": { 750 | "brace-expansion": "^1.1.7" 751 | } 752 | }, 753 | "neo-async": { 754 | "version": "2.6.2", 755 | "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", 756 | "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", 757 | "dev": true 758 | }, 759 | "node-releases": { 760 | "version": "1.1.69", 761 | "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.69.tgz", 762 | "integrity": "sha512-DGIjo79VDEyAnRlfSqYTsy+yoHd2IOjJiKUozD2MV2D85Vso6Bug56mb9tT/fY5Urt0iqk01H7x+llAruDR2zA==", 763 | "dev": true 764 | }, 765 | "npm-run-path": { 766 | "version": "4.0.1", 767 | "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", 768 | "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", 769 | "dev": true, 770 | "requires": { 771 | "path-key": "^3.0.0" 772 | } 773 | }, 774 | "once": { 775 | "version": "1.4.0", 776 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 777 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 778 | "dev": true, 779 | "requires": { 780 | "wrappy": "1" 781 | } 782 | }, 783 | "onetime": { 784 | "version": "5.1.2", 785 | "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", 786 | "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", 787 | "dev": true, 788 | "requires": { 789 | "mimic-fn": "^2.1.0" 790 | } 791 | }, 792 | "p-limit": { 793 | "version": "3.1.0", 794 | "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", 795 | "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", 796 | "dev": true, 797 | "requires": { 798 | "yocto-queue": "^0.1.0" 799 | } 800 | }, 801 | "p-locate": { 802 | "version": "5.0.0", 803 | "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", 804 | "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", 805 | "dev": true, 806 | "requires": { 807 | "p-limit": "^3.0.2" 808 | } 809 | }, 810 | "p-try": { 811 | "version": "2.2.0", 812 | "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", 813 | "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", 814 | "dev": true 815 | }, 816 | "path-exists": { 817 | "version": "4.0.0", 818 | "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", 819 | "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", 820 | "dev": true 821 | }, 822 | "path-is-absolute": { 823 | "version": "1.0.1", 824 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 825 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", 826 | "dev": true 827 | }, 828 | "path-key": { 829 | "version": "3.1.1", 830 | "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", 831 | "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", 832 | "dev": true 833 | }, 834 | "path-parse": { 835 | "version": "1.0.6", 836 | "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", 837 | "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", 838 | "dev": true 839 | }, 840 | "pkg-dir": { 841 | "version": "5.0.0", 842 | "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-5.0.0.tgz", 843 | "integrity": "sha512-NPE8TDbzl/3YQYY7CSS228s3g2ollTFnc+Qi3tqmqJp9Vg2ovUpixcJEo2HJScN2Ez+kEaal6y70c0ehqJBJeA==", 844 | "dev": true, 845 | "requires": { 846 | "find-up": "^5.0.0" 847 | } 848 | }, 849 | "punycode": { 850 | "version": "2.1.1", 851 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", 852 | "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", 853 | "dev": true 854 | }, 855 | "randombytes": { 856 | "version": "2.1.0", 857 | "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", 858 | "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", 859 | "dev": true, 860 | "requires": { 861 | "safe-buffer": "^5.1.0" 862 | } 863 | }, 864 | "rechoir": { 865 | "version": "0.7.0", 866 | "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.7.0.tgz", 867 | "integrity": "sha512-ADsDEH2bvbjltXEP+hTIAmeFekTFK0V2BTxMkok6qILyAJEXV0AFfoWcAq4yfll5VdIMd/RVXq0lR+wQi5ZU3Q==", 868 | "dev": true, 869 | "requires": { 870 | "resolve": "^1.9.0" 871 | } 872 | }, 873 | "resolve": { 874 | "version": "1.19.0", 875 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.19.0.tgz", 876 | "integrity": "sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==", 877 | "dev": true, 878 | "requires": { 879 | "is-core-module": "^2.1.0", 880 | "path-parse": "^1.0.6" 881 | } 882 | }, 883 | "resolve-cwd": { 884 | "version": "3.0.0", 885 | "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", 886 | "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", 887 | "dev": true, 888 | "requires": { 889 | "resolve-from": "^5.0.0" 890 | } 891 | }, 892 | "resolve-from": { 893 | "version": "5.0.0", 894 | "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", 895 | "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", 896 | "dev": true 897 | }, 898 | "rimraf": { 899 | "version": "3.0.2", 900 | "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", 901 | "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", 902 | "dev": true, 903 | "requires": { 904 | "glob": "^7.1.3" 905 | } 906 | }, 907 | "safe-buffer": { 908 | "version": "5.2.1", 909 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", 910 | "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", 911 | "dev": true 912 | }, 913 | "schema-utils": { 914 | "version": "3.0.0", 915 | "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.0.0.tgz", 916 | "integrity": "sha512-6D82/xSzO094ajanoOSbe4YvXWMfn2A//8Y1+MUqFAJul5Bs+yn36xbK9OtNDcRVSBJ9jjeoXftM6CfztsjOAA==", 917 | "dev": true, 918 | "requires": { 919 | "@types/json-schema": "^7.0.6", 920 | "ajv": "^6.12.5", 921 | "ajv-keywords": "^3.5.2" 922 | } 923 | }, 924 | "serialize-javascript": { 925 | "version": "5.0.1", 926 | "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-5.0.1.tgz", 927 | "integrity": "sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA==", 928 | "dev": true, 929 | "requires": { 930 | "randombytes": "^2.1.0" 931 | } 932 | }, 933 | "shebang-command": { 934 | "version": "2.0.0", 935 | "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", 936 | "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", 937 | "dev": true, 938 | "requires": { 939 | "shebang-regex": "^3.0.0" 940 | } 941 | }, 942 | "shebang-regex": { 943 | "version": "3.0.0", 944 | "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", 945 | "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", 946 | "dev": true 947 | }, 948 | "signal-exit": { 949 | "version": "3.0.3", 950 | "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", 951 | "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", 952 | "dev": true 953 | }, 954 | "source-list-map": { 955 | "version": "2.0.1", 956 | "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz", 957 | "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==", 958 | "dev": true 959 | }, 960 | "source-map": { 961 | "version": "0.6.1", 962 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", 963 | "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", 964 | "dev": true 965 | }, 966 | "source-map-support": { 967 | "version": "0.5.19", 968 | "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", 969 | "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", 970 | "dev": true, 971 | "requires": { 972 | "buffer-from": "^1.0.0", 973 | "source-map": "^0.6.0" 974 | } 975 | }, 976 | "strip-final-newline": { 977 | "version": "2.0.0", 978 | "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", 979 | "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", 980 | "dev": true 981 | }, 982 | "supports-color": { 983 | "version": "7.2.0", 984 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", 985 | "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", 986 | "dev": true, 987 | "requires": { 988 | "has-flag": "^4.0.0" 989 | } 990 | }, 991 | "tapable": { 992 | "version": "2.2.0", 993 | "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.0.tgz", 994 | "integrity": "sha512-FBk4IesMV1rBxX2tfiK8RAmogtWn53puLOQlvO8XuwlgxcYbP4mVPS9Ph4aeamSyyVjOl24aYWAuc8U5kCVwMw==", 995 | "dev": true 996 | }, 997 | "terser": { 998 | "version": "5.5.1", 999 | "resolved": "https://registry.npmjs.org/terser/-/terser-5.5.1.tgz", 1000 | "integrity": "sha512-6VGWZNVP2KTUcltUQJ25TtNjx/XgdDsBDKGt8nN0MpydU36LmbPPcMBd2kmtZNNGVVDLg44k7GKeHHj+4zPIBQ==", 1001 | "dev": true, 1002 | "requires": { 1003 | "commander": "^2.20.0", 1004 | "source-map": "~0.7.2", 1005 | "source-map-support": "~0.5.19" 1006 | }, 1007 | "dependencies": { 1008 | "source-map": { 1009 | "version": "0.7.3", 1010 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", 1011 | "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", 1012 | "dev": true 1013 | } 1014 | } 1015 | }, 1016 | "terser-webpack-plugin": { 1017 | "version": "5.1.1", 1018 | "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.1.1.tgz", 1019 | "integrity": "sha512-5XNNXZiR8YO6X6KhSGXfY0QrGrCRlSwAEjIIrlRQR4W8nP69TaJUlh3bkuac6zzgspiGPfKEHcY295MMVExl5Q==", 1020 | "dev": true, 1021 | "requires": { 1022 | "jest-worker": "^26.6.2", 1023 | "p-limit": "^3.1.0", 1024 | "schema-utils": "^3.0.0", 1025 | "serialize-javascript": "^5.0.1", 1026 | "source-map": "^0.6.1", 1027 | "terser": "^5.5.1" 1028 | } 1029 | }, 1030 | "tslib": { 1031 | "version": "1.14.1", 1032 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", 1033 | "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", 1034 | "dev": true 1035 | }, 1036 | "typescript": { 1037 | "version": "4.1.3", 1038 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.1.3.tgz", 1039 | "integrity": "sha512-B3ZIOf1IKeH2ixgHhj6la6xdwR9QrLC5d1VKeCSY4tvkqhF2eqd9O7txNlS0PO3GrBAFIdr3L1ndNwteUbZLYg==", 1040 | "dev": true 1041 | }, 1042 | "uri-js": { 1043 | "version": "4.4.0", 1044 | "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.0.tgz", 1045 | "integrity": "sha512-B0yRTzYdUCCn9n+F4+Gh4yIDtMQcaJsmYBDsTSG8g/OejKBodLQ2IHfN3bM7jUsRXndopT7OIXWdYqc1fjmV6g==", 1046 | "dev": true, 1047 | "requires": { 1048 | "punycode": "^2.1.0" 1049 | } 1050 | }, 1051 | "v8-compile-cache": { 1052 | "version": "2.2.0", 1053 | "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.2.0.tgz", 1054 | "integrity": "sha512-gTpR5XQNKFwOd4clxfnhaqvfqMpqEwr4tOtCyz4MtYZX2JYhfr1JvBFKdS+7K/9rfpZR3VLX+YWBbKoxCgS43Q==", 1055 | "dev": true 1056 | }, 1057 | "watchpack": { 1058 | "version": "2.1.0", 1059 | "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.1.0.tgz", 1060 | "integrity": "sha512-UjgD1mqjkG99+3lgG36at4wPnUXNvis2v1utwTgQ43C22c4LD71LsYMExdWXh4HZ+RmW+B0t1Vrg2GpXAkTOQw==", 1061 | "dev": true, 1062 | "requires": { 1063 | "glob-to-regexp": "^0.4.1", 1064 | "graceful-fs": "^4.1.2" 1065 | } 1066 | }, 1067 | "webpack": { 1068 | "version": "5.12.2", 1069 | "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.12.2.tgz", 1070 | "integrity": "sha512-HiTXBGLFQiRecP5Fwrh21aaxlEUqQdDeUaninKVKX0Dtqaf+WjKCsNcv+UVftfYXrY0bnRQHnouw1x+CPqQKFQ==", 1071 | "dev": true, 1072 | "requires": { 1073 | "@types/eslint-scope": "^3.7.0", 1074 | "@types/estree": "^0.0.45", 1075 | "@webassemblyjs/ast": "1.9.1", 1076 | "@webassemblyjs/helper-module-context": "1.9.1", 1077 | "@webassemblyjs/wasm-edit": "1.9.1", 1078 | "@webassemblyjs/wasm-parser": "1.9.1", 1079 | "acorn": "^8.0.4", 1080 | "browserslist": "^4.14.5", 1081 | "chrome-trace-event": "^1.0.2", 1082 | "enhanced-resolve": "^5.3.1", 1083 | "eslint-scope": "^5.1.1", 1084 | "events": "^3.2.0", 1085 | "glob-to-regexp": "^0.4.1", 1086 | "graceful-fs": "^4.2.4", 1087 | "json-parse-better-errors": "^1.0.2", 1088 | "loader-runner": "^4.2.0", 1089 | "mime-types": "^2.1.27", 1090 | "neo-async": "^2.6.2", 1091 | "pkg-dir": "^5.0.0", 1092 | "schema-utils": "^3.0.0", 1093 | "tapable": "^2.1.1", 1094 | "terser-webpack-plugin": "^5.0.3", 1095 | "watchpack": "^2.0.0", 1096 | "webpack-sources": "^2.1.1" 1097 | } 1098 | }, 1099 | "webpack-cli": { 1100 | "version": "4.3.1", 1101 | "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.3.1.tgz", 1102 | "integrity": "sha512-/F4+9QNZM/qKzzL9/06Am8NXIkGV+/NqQ62Dx7DSqudxxpAgBqYn6V7+zp+0Y7JuWksKUbczRY3wMTd+7Uj6OA==", 1103 | "dev": true, 1104 | "requires": { 1105 | "@discoveryjs/json-ext": "^0.5.0", 1106 | "@webpack-cli/info": "^1.2.1", 1107 | "@webpack-cli/serve": "^1.2.1", 1108 | "colorette": "^1.2.1", 1109 | "commander": "^6.2.0", 1110 | "enquirer": "^2.3.6", 1111 | "execa": "^5.0.0", 1112 | "fastest-levenshtein": "^1.0.12", 1113 | "import-local": "^3.0.2", 1114 | "interpret": "^2.2.0", 1115 | "rechoir": "^0.7.0", 1116 | "v8-compile-cache": "^2.2.0", 1117 | "webpack-merge": "^4.2.2" 1118 | }, 1119 | "dependencies": { 1120 | "commander": { 1121 | "version": "6.2.1", 1122 | "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", 1123 | "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==", 1124 | "dev": true 1125 | } 1126 | } 1127 | }, 1128 | "webpack-merge": { 1129 | "version": "4.2.2", 1130 | "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-4.2.2.tgz", 1131 | "integrity": "sha512-TUE1UGoTX2Cd42j3krGYqObZbOD+xF7u28WB7tfUordytSjbWTIjK/8V0amkBfTYN4/pB/GIDlJZZ657BGG19g==", 1132 | "dev": true, 1133 | "requires": { 1134 | "lodash": "^4.17.15" 1135 | } 1136 | }, 1137 | "webpack-sources": { 1138 | "version": "2.2.0", 1139 | "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-2.2.0.tgz", 1140 | "integrity": "sha512-bQsA24JLwcnWGArOKUxYKhX3Mz/nK1Xf6hxullKERyktjNMC4x8koOeaDNTA2fEJ09BdWLbM/iTW0ithREUP0w==", 1141 | "dev": true, 1142 | "requires": { 1143 | "source-list-map": "^2.0.1", 1144 | "source-map": "^0.6.1" 1145 | } 1146 | }, 1147 | "which": { 1148 | "version": "2.0.2", 1149 | "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", 1150 | "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", 1151 | "dev": true, 1152 | "requires": { 1153 | "isexe": "^2.0.0" 1154 | } 1155 | }, 1156 | "wrappy": { 1157 | "version": "1.0.2", 1158 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 1159 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", 1160 | "dev": true 1161 | }, 1162 | "yocto-queue": { 1163 | "version": "0.1.0", 1164 | "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", 1165 | "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", 1166 | "dev": true 1167 | } 1168 | } 1169 | } 1170 | -------------------------------------------------------------------------------- /packages/worker/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "worker", 3 | "private": true, 4 | "main": "src/index.ts", 5 | "scripts": { 6 | "clean": "rimraf build", 7 | "clean:node": "rimraf node_modules package-lock.json", 8 | "build": "webpack" 9 | }, 10 | "devDependencies": { 11 | "@cloudflare/workers-types": "2.1.0", 12 | "rimraf": "3.0.2", 13 | "typescript": "4.1.3", 14 | "webpack": "5.12.2", 15 | "webpack-cli": "4.3.1" 16 | }, 17 | "dependencies": { 18 | "@cloudflare/kv-asset-handler": "0.1.0" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /packages/worker/src/handleError.ts: -------------------------------------------------------------------------------- 1 | export const handleError = async ( 2 | event: FetchEvent, 3 | error: Error 4 | ): Promise => { 5 | console.info(event.request); 6 | console.error(error); 7 | }; 8 | -------------------------------------------------------------------------------- /packages/worker/src/index.ts: -------------------------------------------------------------------------------- 1 | import {} from "@cloudflare/workers-types"; 2 | import { 3 | getAssetFromKV, 4 | serveSinglePageApp, 5 | } from "@cloudflare/kv-asset-handler"; 6 | import { handleRequest as server } from "../../server/src"; 7 | import { handleError } from "./handleError"; 8 | import { internalServerError, notFound } from "./pages"; 9 | 10 | const assetOptions = { 11 | mapRequestToAsset: serveSinglePageApp, 12 | }; 13 | 14 | const handleProductionAssetRequest = async ( 15 | event: FetchEvent 16 | ): Promise => { 17 | try { 18 | return await getAssetFromKV(event, assetOptions); 19 | } catch (e) { 20 | // TODO: Could also be an error thrown by the getAssetFromKV function: https://github.com/cloudflare/kv-asset-handler#return 21 | return notFound(event); 22 | } 23 | }; 24 | 25 | const handleAssetRequest = async (event: any): Promise => { 26 | if (process.env.CLOUDFLARED_TUNNEL) return await fetch(event.request); 27 | 28 | return await handleProductionAssetRequest(event); 29 | }; 30 | 31 | const handleRequest = async (event: any): Promise => { 32 | try { 33 | const { request } = event; 34 | const response = await server(request); 35 | if (response.status !== 404) return response; 36 | 37 | return handleAssetRequest(event); 38 | } catch (error) { 39 | event.waitUntil(handleError(event, error)); 40 | 41 | return internalServerError(event, error); 42 | } 43 | }; 44 | 45 | addEventListener(`fetch`, (event: any) => { 46 | event.respondWith(handleRequest(event)); 47 | }); 48 | -------------------------------------------------------------------------------- /packages/worker/src/pages.ts: -------------------------------------------------------------------------------- 1 | export const notFound = (event: any) => 2 | // TODO: Pretty 404 page 3 | new Response(`Not Found`, { 4 | status: 404, 5 | headers: { "Content-Type": `text/plain` }, 6 | }); 7 | 8 | export const internalServerError = (event: any, error: Error) => 9 | // TODO: Pretty 500 page 10 | new Response(`Internal Server Error`, { 11 | status: 500, 12 | headers: { "Content-Type": `text/plain` }, 13 | }); 14 | -------------------------------------------------------------------------------- /packages/worker/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "outDir": "./build", 4 | "module": "commonjs", 5 | "target": "esnext", 6 | "lib": ["esnext", "webworker"], 7 | "alwaysStrict": true, 8 | "strict": true, 9 | "preserveConstEnums": true, 10 | "moduleResolution": "node", 11 | "sourceMap": true, 12 | "esModuleInterop": true 13 | }, 14 | "include": [ 15 | "./src/**/*.ts", 16 | "./node_modules/@cloudflare/workers-types/index.d.ts", 17 | "src/index.ts" 18 | ], 19 | "exclude": ["build/"] 20 | } 21 | -------------------------------------------------------------------------------- /packages/worker/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | const webpack = require("webpack"); 3 | 4 | module.exports = { 5 | entry: path.join(__dirname, "src", "index.ts"), 6 | output: { 7 | filename: `worker.js`, 8 | path: path.join(__dirname, "build"), 9 | }, 10 | target: "webworker", 11 | resolve: { 12 | extensions: [".ts", ".tsx", ".js"], 13 | alias: { 14 | fs: path.resolve(__dirname, "./null.js"), 15 | }, 16 | }, 17 | mode: "production", 18 | optimization: { 19 | usedExports: true, 20 | }, 21 | module: { 22 | rules: [ 23 | { 24 | test: /\.tsx?$/, 25 | loader: "ts-loader", 26 | options: { 27 | transpileOnly: true, 28 | }, 29 | }, 30 | ], 31 | }, 32 | plugins: [new webpack.EnvironmentPlugin({ CLOUDFLARED_TUNNEL: "" })], 33 | }; 34 | -------------------------------------------------------------------------------- /updatePackages.js: -------------------------------------------------------------------------------- 1 | const ncu = require("npm-check-updates"); 2 | 3 | const packageFiles = [ 4 | "package.json", 5 | "packages/client/package.json", 6 | "packages/server/package.json", 7 | "packages/worker/package.json", 8 | ]; 9 | 10 | packageFiles.map((packageFile) => { 11 | ncu 12 | .run({ upgrade: true, packageFile }) 13 | .then(() => console.log(`Updated ${packageFile}`)); 14 | }); 15 | -------------------------------------------------------------------------------- /wrangler.toml: -------------------------------------------------------------------------------- 1 | name = "script-name-dev" 2 | type = "webpack" 3 | webpack_config = "./packages/worker/webpack.config.js" 4 | account_id = "5a883b414d4090a1442b20361f3c43a9" 5 | workers_dev = true 6 | 7 | kv-namespaces = [] 8 | 9 | [site] 10 | bucket = "./packages/client/build" 11 | entry-point = "./packages/worker" 12 | 13 | [env.production] 14 | name = "script-name" --------------------------------------------------------------------------------