├── .circleci └── config.yml ├── .github └── workflows │ └── git.yml ├── .gitignore ├── LICENSE ├── README.md ├── demo ├── .gitignore ├── README.md ├── jest.config.js ├── package-lock.json ├── package.json ├── src │ ├── helloworker.ts │ └── helloworkerclass.ts ├── test │ ├── helloworker.test.ts │ └── setupJest.ts ├── tsconfig.json └── webpack.config.js ├── jest.config.js ├── package-lock.json ├── package.json ├── packages ├── @udacity │ └── types-service-worker-mock │ │ ├── .gitignore │ │ ├── LICENSE │ │ ├── README.md │ │ ├── index.d.ts │ │ ├── package-lock.json │ │ ├── package.json │ │ ├── src │ │ └── global.ts │ │ └── tsconfig.json ├── cloudflare-worker-mock │ ├── .gitignore │ ├── LICENSE │ ├── README.md │ ├── package-lock.json │ ├── package.json │ ├── src │ │ └── index.ts │ └── tsconfig.json └── types-cloudflare-worker │ ├── .gitignore │ ├── LICENSE │ ├── README.md │ ├── package-lock.json │ ├── package.json │ ├── src │ └── global.ts │ └── tsconfig.json ├── scripts └── publish.sh ├── src ├── helloworker.ts └── helloworkerclass.ts ├── test ├── helloworker.test.ts └── setupJest.ts ├── tsconfig.json ├── tsconfig.tslint.json ├── tslint.json └── webpack.config.js /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | 3 | build-defaults: &build-defaults 4 | docker: 5 | - image: circleci/node:12.20.0 6 | 7 | jobs: 8 | test: 9 | <<: *build-defaults 10 | steps: 11 | - checkout 12 | - restore_cache: 13 | key: &cache_key dependency-cache-{{ checksum "package.json" }} 14 | - run: 15 | name: Setup 16 | command: | 17 | npm i 18 | cd demo 19 | npm i 20 | - run: 21 | name: Run Linter 22 | command: ./node_modules/tslint/bin/tslint --project tsconfig.tslint.json --force | tee /tmp/test && ! grep -q WARNING /tmp/test 23 | - run: 24 | name: Run Tests 25 | command: npm run test-all 26 | - run: 27 | name: Test Building development 28 | command: npm run build 29 | - run: 30 | name: Test Building demo 31 | command: npm run build-demo 32 | - save_cache: 33 | key: *cache_key 34 | paths: 35 | - ./node_modules 36 | 37 | workflows: 38 | version: 2 39 | test: 40 | jobs: 41 | - test 42 | -------------------------------------------------------------------------------- /.github/workflows/git.yml: -------------------------------------------------------------------------------- 1 | name: Git Checks 2 | 3 | on: [push] 4 | 5 | jobs: 6 | block-fixup: 7 | runs-on: ubuntu-18.04 8 | 9 | steps: 10 | - uses: actions/checkout@v2.0.0 11 | - name: Block Fixup Commit Merge 12 | uses: 13rac1/block-fixup-merge-action@v1.1.1 13 | 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | /dist 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Cloudflare Workers with TypeScript and Webpack 2 | 3 | _**Retired: as of 2022, Cloudflare's official types package 4 | [`@cloudflare/workers-types`](https://github.com/cloudflare/workers-types) 5 | is more up-to-date and better supported.**_ 6 | 7 | [Cloudflare Workers][about-workers] allow you to run JavaScript on Cloudflare's 8 | edge servers around the world. You can modify your site’s HTTP requests and 9 | responses, make parallel requests, or generate responses from the edge. This 10 | project develops, tests, and deploys NPM packages supporting the development of 11 | Cloudflare Workers using TypeScript. 12 | 13 | [Get started on your own TypeScript Cloudflare Worker using the 14 | Template.][starter-template] 15 | 16 | * [`types-cloudflare-worker`][types-cloudflare-worker] - Complete types for all 17 | public features provided by Cloudflare Workers. Supports the `Request.cf` 18 | object, the Cache API and KV API. 19 | * [`cloudflare-worker-mock`][cloudflare-worker-mock] - Wraps 20 | `service-worker-mock` for name consistency, developer experience and to 21 | provide a simple mockable Cache API and KV API implementation. 22 | * [`@udacity/types-service-worker-mock`][types-service-worker-mock] - Incomplete 23 | types for the `pinterest/service-worker-mock` to support Cloudflare Worker 24 | Testing. May be pushed to the NPM `@types` project in the future, but needs 25 | additional work before that is reasonable. 26 | 27 | The [Cloudflare Worker API implements a subset][worker-api-reference] of the 28 | [Service Worker API][service-worker-api] specification, therefore Service Worker 29 | TypeScript types are a useful starting point. 30 | 31 | [about-workers]:https://developers.cloudflare.com/workers/about/ 32 | [starter-template]:https://github.com/udacity/cloudflare-typescript-worker-template 33 | [types-service-worker-mock]:https://www.npmjs.com/package/@udacity/types-service-worker-mock 34 | [types-cloudflare-worker]:https://www.npmjs.com/package/types-cloudflare-worker 35 | [cloudflare-worker-mock]:https://www.npmjs.com/package/cloudflare-worker-mock 36 | [worker-api-reference]:https://developers.cloudflare.com/workers/reference/ 37 | [service-worker-api]:https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API 38 | 39 | ## Example 40 | 41 | A small example of a strictly typed worker: 42 | 43 | ```typescript 44 | import CloudflareWorkerGlobalScope from 'types-cloudflare-worker'; 45 | declare var self: CloudflareWorkerGlobalScope; 46 | 47 | export class Worker { 48 | public async handle(event: FetchEvent) { 49 | const originResponse = fetch(event.request, { 50 | cf: { 51 | minify: { 52 | html: true, 53 | }, 54 | }, 55 | }); 56 | 57 | return originResponse; 58 | } 59 | } 60 | 61 | self.addEventListener('fetch', (event: FetchEvent) => { 62 | const worker = new Worker(); 63 | event.respondWith(worker.handle(event)); 64 | }); 65 | ``` 66 | 67 | ## Getting started 68 | 69 | Start with the [Starter Template][starter-template] or run the following 70 | commands: 71 | 72 | ```bash 73 | npm init 74 | # Add TypeScript 75 | npm i -D \ 76 | typescript \ 77 | @types/node 78 | # Setup the Cloudflare Worker Types and Mock 79 | npm i -D \ 80 | @udacity/types-service-worker-mock \ 81 | types-cloudflare-worker \ 82 | cloudflare-worker-mock 83 | 84 | # Init TypeScript 85 | tsc --init 86 | ``` 87 | 88 | Set the TypeScript compiler options in `tsconfig.json`: 89 | 90 | ```js 91 | "compilerOptions": { 92 | /* https://developers.cloudflare.com/workers/reference/ */ 93 | /* Cloudflare Workers use the V8 JavaScript engine from Google Chrome. The 94 | * Workers runtime is updated at least once a week, to at least the version 95 | * that is currently used by Chrome’s stable release. This means you can 96 | * safely use latest JavaScript features, with no need for "transpilers". 97 | */ 98 | "target": "ESNext", 99 | /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */ 100 | "module": "commonjs", 101 | /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */ 102 | "lib": ["esnext", "webworker"], 103 | /* Specify library files to be included in the compilation. */ 104 | 105 | /* Recommend enabling all Strict Type-Checking Options and Additional Checks */ 106 | } 107 | ``` 108 | 109 | ## Building the Worker(s) 110 | 111 | There are two implementations of the same test worker in this repository. 112 | 113 | ### demo/src/helloworker.ts 114 | 115 | This is the demo worker. It uses the published packages. Reference it as an 116 | example implementation and starting point for your project. 117 | 118 | ```bash 119 | cd demo 120 | npm i 121 | jest 122 | npm run build 123 | ``` 124 | 125 | ### src/helloworker.ts 126 | 127 | This is the development worker. It uses the local packages. 128 | 129 | ```bash 130 | npm i 131 | jest 132 | npm run build 133 | ``` 134 | 135 | ## Testing and deploying the packages 136 | 137 | ```bash 138 | npm i 139 | npm run test-all 140 | scripts/publish.sh $VERSION $OTP # New version and 2FA 141 | ``` 142 | 143 | ## Author 144 | 145 | Brad Erickson ([@13rac1](https://github.com/13rac1)) 146 | 147 | ## License 148 | 149 | Licensed under the Apache License, Version 2.0. 150 | 151 | © 2019 Udacity, Inc. 152 | 153 | Content derived from Cloudflare Developer Documentation. © 2019 Cloudflare, Inc. 154 | -------------------------------------------------------------------------------- /demo/.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | /dist 3 | -------------------------------------------------------------------------------- /demo/README.md: -------------------------------------------------------------------------------- 1 | # Cloudflare Typescript Worker Demo 2 | 3 | This is the same as the development environment in the parent directory, but 4 | uses the published packages to confirm installation. Use this as an example 5 | configuration. 6 | 7 | ## License 8 | 9 | Licensed under the Apache License, Version 2.0. 10 | 11 | © 2019 Udacity, Inc. 12 | 13 | Content derived from Cloudflare Developer Documentation. © 2019 Cloudflare, Inc. 14 | -------------------------------------------------------------------------------- /demo/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | preset: 'ts-jest', 3 | testEnvironment: 'node', 4 | automock: false, 5 | setupFiles: [ 6 | "./test/setupJest.ts" 7 | ] 8 | }; 9 | -------------------------------------------------------------------------------- /demo/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "demo", 3 | "version": "1.0.0", 4 | "description": "Demo of using the npmjs.com packages", 5 | "main": "index.js", 6 | "scripts": { 7 | "build": "webpack --progress --mode production # Create minified output, runs in Cloudflare", 8 | "build-dev": "webpack --progress --mode none # Creates readable output, runs in Cloudflare", 9 | "lint": "tslint --project tsconfig.json", 10 | "test": "jest" 11 | }, 12 | "repository": { 13 | "type": "git", 14 | "url": "git+https://github.com/udacity/cloudflare-typescript-workers.git" 15 | }, 16 | "author": "", 17 | "license": "Apache-2.0", 18 | "bugs": { 19 | "url": "https://github.com/udacity/cloudflare-typescript-workers/issues" 20 | }, 21 | "homepage": "https://github.com/udacity/cloudflare-typescript-workers#readme", 22 | "devDependencies": { 23 | "@types/jest": "^26.0.23", 24 | "@types/node": "^15.12.1", 25 | "@udacity/types-service-worker-mock": "^1.2.0", 26 | "cloudflare-worker-mock": "^1.2.0", 27 | "jest": "^27.0.4", 28 | "jest-fetch-mock": "^3.0.3", 29 | "service-worker-mock": "^2.0.5", 30 | "ts-jest": "^27.0.2", 31 | "ts-loader": "^9.2.2", 32 | "tslint": "^6.1.3", 33 | "tslint-eslint-rules": "^5.4.0", 34 | "types-cloudflare-worker": "^1.2.0", 35 | "typescript": "^4.3.2", 36 | "webpack": "^5.38.1", 37 | "webpack-cli": "^4.7.0" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /demo/src/helloworker.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 Udacity, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | import CloudflareWorkerGlobalScope from 'types-cloudflare-worker'; 18 | declare var self: CloudflareWorkerGlobalScope; 19 | 20 | import HelloWorkerClass from './helloworkerclass'; 21 | 22 | self.addEventListener('fetch', (event: FetchEvent) => { 23 | const worker = new HelloWorkerClass(); 24 | event.respondWith(worker.handle(event)); 25 | }); 26 | -------------------------------------------------------------------------------- /demo/src/helloworkerclass.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 Udacity, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // The class is separate file simply to show imports working 18 | import { CloudflareWorkerKV } from 'types-cloudflare-worker'; 19 | 20 | // Declare a Named KV in the global scope. ref: 21 | // https://developers.cloudflare.com/workers/kv/api/ 22 | 23 | // The name the KV is used to help you identify the namespace and must be unique 24 | // within your account for this demo, we use countryCodeKV to represent the KV 25 | // to store country code info. 26 | declare global { 27 | const countryCodeKV: CloudflareWorkerKV; 28 | } 29 | 30 | export class HelloWorkerClass { 31 | private responseInit = { 32 | headers: { 'Content-Type': 'application/json' }, 33 | status: 200, 34 | }; 35 | 36 | public async handle(event: FetchEvent) { 37 | if (typeof event.passThroughOnException === 'function') { 38 | event.passThroughOnException(); 39 | } 40 | const cache = caches.default; 41 | const request = event.request; 42 | 43 | let response = await cache.match(request); 44 | 45 | if (!response) { 46 | const originResponse = await fetch(request, { 47 | cf: { 48 | cacheKey: 'hello-world', 49 | minify: { 50 | html: true, 51 | }, 52 | }, 53 | }); 54 | let body = 'Hello '; 55 | 56 | if (originResponse.status === 200) { 57 | event.waitUntil(cache.put(request, originResponse)); 58 | body = await originResponse.text(); 59 | } 60 | const country = request.cf.country; 61 | countryCodeKV.put(country, '!', { expiration: 100 }); 62 | const countryCode = await countryCodeKV.get(country); 63 | 64 | response = new Response( 65 | `${body} ${request.cf.country} ${countryCode}!`, 66 | this.responseInit, 67 | ); 68 | } 69 | 70 | return response; 71 | } 72 | } 73 | export default HelloWorkerClass; 74 | -------------------------------------------------------------------------------- /demo/test/helloworker.test.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 Udacity, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | /* 18 | * There are two options for using ServiceWorker types, both with hassles. We 19 | * are using the webworker library method instead of the types-serviceworker 20 | * package. 21 | * 22 | * Option 1: WebWorker library included with TypeScript 23 | * tsc --lib es5,webworker # or anything es5+ 24 | * 25 | * But it requires: 26 | * export default null; 27 | * declare var self: ServiceWorkerGlobalScope; 28 | * 29 | * ref: 30 | * https://github.com/Microsoft/TypeScript/issues/14877#issuecomment-340279293 31 | * 32 | * Option 2: types-serviceworker package 33 | * 34 | * src: 35 | * https://github.com/Microsoft/TypeScript/issues/11781#issuecomment-449617791 36 | * 37 | * types-serviceworker could be referenced in tsconfig.json, but that may lead 38 | * to confusion because: "If types is specified, only packages listed will be 39 | * included." 40 | * ref: 41 | * https://www.typescriptlang.org/docs/handbook/tsconfig-json.html 42 | */ 43 | 44 | import { 45 | CloudflareWorkerGlobalScope, 46 | CloudflareWorkerKVOptions, 47 | } from 'types-cloudflare-worker'; 48 | declare var self: CloudflareWorkerGlobalScope; 49 | 50 | import makeCloudflareWorkerEnv, { 51 | makeCloudflareWorkerKVEnv, 52 | makeCloudflareWorkerRequest, 53 | } from 'cloudflare-worker-mock'; 54 | 55 | describe('helloworker', () => { 56 | beforeEach(() => { 57 | // Merge the Cloudflare Worker Environment into the global scope. 58 | Object.assign(global, makeCloudflareWorkerEnv()); 59 | // Merge the named KV into the global scope 60 | Object.assign(global, makeCloudflareWorkerKVEnv('countryCodeKV')); 61 | // Clear all module imports. 62 | jest.resetModules(); 63 | // Import and init the Worker. 64 | jest.requireActual('../src/helloworker'); 65 | }); 66 | 67 | it('should add listeners', async () => { 68 | expect(self.listeners.get('fetch')).toBeDefined(); 69 | }); 70 | 71 | it('should return Hello US +1!', async () => { 72 | fetchMock.mockResponseOnce('Hello'); 73 | 74 | let putCacheCalled = false; 75 | // Mock the default put() implementation. 76 | // TODO: Make this cleaner. 77 | caches.default.put = ( 78 | _request: Request, 79 | _response: Response, 80 | ): Promise => { 81 | putCacheCalled = true; 82 | return Promise.resolve(undefined); 83 | }; 84 | 85 | // Setup mock responses for the KV put() and get(). 86 | let putKVCalled = false; 87 | countryCodeKV.put = ( 88 | _key: string, 89 | _value: string | ReadableStream | ArrayBuffer | FormData, 90 | _options?: CloudflareWorkerKVOptions, 91 | ): Promise => { 92 | putKVCalled = true; 93 | return Promise.resolve(); 94 | }; 95 | 96 | let getKVCalled = false; 97 | countryCodeKV.get = ( 98 | _key: string, 99 | _type?: 'text' | 'json' | 'arrayBuffer' | 'stream', 100 | ): Promise => { 101 | getKVCalled = true; 102 | return Promise.resolve('+1'); 103 | }; 104 | 105 | const request = makeCloudflareWorkerRequest('/path', { 106 | cf: { 107 | colo: 'SFO', 108 | country: 'US', 109 | tlsClientAuth: { 110 | certIssuerDN: 'Example', 111 | }, 112 | }, 113 | }); 114 | const response = await self.trigger('fetch', request); 115 | 116 | expect(fetchMock).toBeCalledTimes(1); 117 | expect(response.status).toBe(200); 118 | expect(await response.text()).toBe('Hello US +1!'); 119 | expect(putCacheCalled).toBe(true); 120 | expect(putKVCalled).toBe(true); 121 | expect(getKVCalled).toBe(true); 122 | }); 123 | }); 124 | -------------------------------------------------------------------------------- /demo/test/setupJest.ts: -------------------------------------------------------------------------------- 1 | import { GlobalWithFetchMock } from 'jest-fetch-mock'; 2 | 3 | const customGlobal: GlobalWithFetchMock = global as unknown as GlobalWithFetchMock; 4 | /* tslint:disable-next-line:no-var-requires */ 5 | customGlobal.fetch = require('jest-fetch-mock'); 6 | customGlobal.fetchMock = customGlobal.fetch; 7 | -------------------------------------------------------------------------------- /demo/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Basic Options */ 4 | /* https://developers.cloudflare.com/workers/reference/ */ 5 | /* Cloudflare Workers use the V8 JavaScript engine from Google Chrome. The 6 | * Workers runtime is updated at least once a week, to at least the version 7 | * that is currently used by Chrome’s stable release. This means you can 8 | * safely use latest JavaScript features, with no need for “transpilers”. 9 | */ 10 | "target": "ESNext", 11 | /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */ 12 | "module": "commonjs", 13 | /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */ 14 | "lib": ["esnext", "webworker"], 15 | /* Specify library files to be included in the compilation. */ 16 | // "allowJs": true, /* Allow javascript files to be compiled. */ 17 | // "checkJs": true, /* Report errors in .js files. */ 18 | // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ 19 | // "declaration": true, /* Generates corresponding '.d.ts' file. */ 20 | // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ 21 | // "sourceMap": true, /* Generates corresponding '.map' file. */ 22 | // "outFile": "./", /* Concatenate and emit output to single file. */ 23 | "outDir": "./dist", 24 | /* Redirect output structure to the directory. */ 25 | // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ 26 | // "composite": true, /* Enable project compilation */ 27 | // "removeComments": true, /* Do not emit comments to output. */ 28 | // "noEmit": true, /* Do not emit outputs. */ 29 | // "importHelpers": true, /* Import emit helpers from 'tslib'. */ 30 | // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ 31 | // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ 32 | 33 | /* Strict Type-Checking Options */ 34 | "strict": true, 35 | /* Enable all strict type-checking options. */ 36 | "noImplicitAny": true, 37 | /* Raise error on expressions and declarations with an implied 'any' type. */ 38 | "strictNullChecks": true, 39 | /* Enable strict null checks. */ 40 | "strictFunctionTypes": true, 41 | /* Enable strict checking of function types. */ 42 | "strictBindCallApply": true, 43 | /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ 44 | "strictPropertyInitialization": true, 45 | /* Enable strict checking of property initialization in classes. */ 46 | "noImplicitThis": true, 47 | /* Raise error on 'this' expressions with an implied 'any' type. */ 48 | "alwaysStrict": true, 49 | /* Parse in strict mode and emit "use strict" for each source file. */ 50 | 51 | /* Additional Checks */ 52 | "noUnusedLocals": true, 53 | /* Report errors on unused locals. */ 54 | "noUnusedParameters": true, 55 | /* Report errors on unused parameters. */ 56 | "noImplicitReturns": true, 57 | /* Report error when not all code paths in function return a value. */ 58 | "noFallthroughCasesInSwitch": true, 59 | /* Report errors for fallthrough cases in switch statement. */ 60 | 61 | /* Module Resolution Options */ 62 | // "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ 63 | // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ 64 | // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ 65 | // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ 66 | // "typeRoots": ["node_modules/@types"], 67 | /* List of folders to include type definitions from. */ 68 | // "types": [], /* Type declaration files to be included in compilation. */ 69 | // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ 70 | "esModuleInterop": true, 71 | /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ 72 | // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ 73 | 74 | /* Source Map Options */ 75 | // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ 76 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ 77 | // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ 78 | // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ 79 | 80 | /* Experimental Options */ 81 | // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ 82 | // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ 83 | }, 84 | "include": [ 85 | "src/**/*", 86 | "test/**/*" 87 | ] 88 | } 89 | -------------------------------------------------------------------------------- /demo/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | 3 | module.exports = { 4 | entry: { 5 | 'helloworker': './src/helloworker.ts', 6 | }, 7 | /*devtool: 'inline-source-map',*/ 8 | module: { 9 | rules: [{ 10 | test: /\.tsx?$/, 11 | use: 'ts-loader', 12 | exclude: /node_modules/ 13 | }] 14 | }, 15 | resolve: { 16 | extensions: ['.ts', '.js'] 17 | }, 18 | output: { 19 | filename: '[name].js', 20 | path: path.resolve(__dirname, 'dist') 21 | } 22 | }; 23 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | preset: 'ts-jest', 3 | testEnvironment: 'node', 4 | automock: false, 5 | setupFiles: [ 6 | "./test/setupJest.ts" 7 | ], 8 | modulePathIgnorePatterns: ["node_modules", "packages", "demo"] 9 | }; 10 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cloudflare-typescript-workers", 3 | "version": "1.0.0", 4 | "description": "A tested Hello World Cloudflare Worker written in TypeScript", 5 | "main": "src/helloworker.ts", 6 | "scripts": { 7 | "package-types-cloudflare-worker": "cd packages/types-cloudflare-worker; npm run prepublish", 8 | "package-types-service-worker-mock": "cd packages/@udacity/types-service-worker-mock;npm run prepublish", 9 | "package-cloudflare-worker-mock": "cd packages/cloudflare-worker-mock && rm -rf node_modules/@udacity && mkdir -p node_modules/@udacity && cp -R ../types-cloudflare-worker node_modules && cp -R ../@udacity/types-service-worker-mock node_modules/@udacity && npm run prepublish", 10 | "packages": "npm run package-types-cloudflare-worker && npm run package-types-service-worker-mock; npm run package-cloudflare-worker-mock", 11 | "build": "webpack --progress --mode production # Create minified output, runs in Cloudflare", 12 | "build-dev": "webpack --progress --mode none # Creates readable output, runs in Cloudflare", 13 | "build-demo": "cd demo; npm run build", 14 | "test": "jest", 15 | "update-demo": "cp src/* demo/src/; cp test/* demo/test/; # Demo updated on version releases", 16 | "test-demo": "cd demo; jest", 17 | "test-all": "npm run packages && npm run lint && jest && npm run test-demo", 18 | "lint": "tslint --project tsconfig.tslint.json --force", 19 | "lint-fix": "tslint --project tsconfig.tslint.json --fix", 20 | "clean": "git clean -xdf" 21 | }, 22 | "repository": { 23 | "type": "git", 24 | "url": "git+https://github.com/udacity/cloudflare-typescript-workers.git" 25 | }, 26 | "author": "Brad Erickson ", 27 | "license": "Apache-2.0", 28 | "bugs": { 29 | "url": "https://github.com/udacity/cloudflare-typescript-workers/issues" 30 | }, 31 | "homepage": "https://github.com/udacity/cloudflare-typescript-workers#readme", 32 | "devDependencies": { 33 | "@types/jest": "^26.0.23", 34 | "@types/node": "^15.12.1", 35 | "@udacity/types-service-worker-mock": "file:./packages/@udacity/types-service-worker-mock", 36 | "cloudflare-worker-mock": "file:./packages/cloudflare-worker-mock", 37 | "jest": "^27.0.4", 38 | "jest-fetch-mock": "^3.0.3", 39 | "prettier": "^2.3.0", 40 | "service-worker-mock": "^2.0.5", 41 | "ts-jest": "^27.0.2", 42 | "ts-loader": "^9.2.2", 43 | "tslint": "^6.1.3", 44 | "tslint-config-prettier": "^1.18.0", 45 | "tslint-eslint-rules": "^5.4.0", 46 | "tslint-plugin-prettier": "^2.3.0", 47 | "types-cloudflare-worker": "file:./packages/types-cloudflare-worker", 48 | "typescript": "^4.3.2", 49 | "webpack": "^5.38.1", 50 | "webpack-cli": "^4.7.0" 51 | }, 52 | "dependencies": {} 53 | } 54 | -------------------------------------------------------------------------------- /packages/@udacity/types-service-worker-mock/.gitignore: -------------------------------------------------------------------------------- 1 | /global.js 2 | /global.d.ts 3 | /node_modules/ 4 | 5 | -------------------------------------------------------------------------------- /packages/@udacity/types-service-worker-mock/LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /packages/@udacity/types-service-worker-mock/README.md: -------------------------------------------------------------------------------- 1 | # TypeScript types for Service Worker Mock 2 | 3 | Adds types to the `service-worker-mock` project: 4 | https://github.com/pinterest/service-workers/tree/master/packages/service-worker-mock 5 | 6 | See additional details and a demo in: 7 | https://github.com/udacity/cloudflare-typescript-workers 8 | 9 | ## Warning 10 | 11 | These types are incomplete as they were created in service of extending the 12 | `service-worker-mock` project for use with Cloudflare Workers. The types should 13 | be pushed to the `@types` project or directly in `service-worker-mock` when 14 | complete. 15 | 16 | ## License 17 | 18 | Licensed under the Apache License, Version 2.0. 19 | 20 | © 2019 Udacity, Inc. 21 | -------------------------------------------------------------------------------- /packages/@udacity/types-service-worker-mock/index.d.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 Udacity, Inc 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | declare module 'service-worker-mock' { 18 | export interface EnvOptions { 19 | [key: string]: string; 20 | } 21 | 22 | function makeServiceWorkerEnv( 23 | envOptions?: EnvOptions, 24 | ): ServiceWorkerGlobalScope; 25 | export default makeServiceWorkerEnv; 26 | } 27 | -------------------------------------------------------------------------------- /packages/@udacity/types-service-worker-mock/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@udacity/types-service-worker-mock", 3 | "version": "1.2.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "browser-process-hrtime": { 8 | "version": "1.0.0", 9 | "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", 10 | "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==" 11 | }, 12 | "dom-urls": { 13 | "version": "1.1.0", 14 | "resolved": "https://registry.npmjs.org/dom-urls/-/dom-urls-1.1.0.tgz", 15 | "integrity": "sha1-AB3fgWKM0ecGElxxdvU8zsVdkY4=", 16 | "requires": { 17 | "urijs": "^1.16.1" 18 | } 19 | }, 20 | "lodash._basefor": { 21 | "version": "3.0.3", 22 | "resolved": "https://registry.npmjs.org/lodash._basefor/-/lodash._basefor-3.0.3.tgz", 23 | "integrity": "sha1-dVC06SGO8J+tJDQ7YSAhx5tMIMI=" 24 | }, 25 | "lodash.isarguments": { 26 | "version": "3.1.0", 27 | "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", 28 | "integrity": "sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo=" 29 | }, 30 | "lodash.isarray": { 31 | "version": "3.0.4", 32 | "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz", 33 | "integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U=" 34 | }, 35 | "lodash.isplainobject": { 36 | "version": "3.2.0", 37 | "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-3.2.0.tgz", 38 | "integrity": "sha1-moI4rhayAEMpYM1zRlEtASP79MU=", 39 | "requires": { 40 | "lodash._basefor": "^3.0.0", 41 | "lodash.isarguments": "^3.0.0", 42 | "lodash.keysin": "^3.0.0" 43 | } 44 | }, 45 | "lodash.keysin": { 46 | "version": "3.0.8", 47 | "resolved": "https://registry.npmjs.org/lodash.keysin/-/lodash.keysin-3.0.8.tgz", 48 | "integrity": "sha1-IsRJPrvtsUJ5YqVLRFssinZ/tH8=", 49 | "requires": { 50 | "lodash.isarguments": "^3.0.0", 51 | "lodash.isarray": "^3.0.0" 52 | } 53 | }, 54 | "realistic-structured-clone": { 55 | "version": "1.0.1", 56 | "resolved": "https://registry.npmjs.org/realistic-structured-clone/-/realistic-structured-clone-1.0.1.tgz", 57 | "integrity": "sha1-Gr6CrwuAzXsQn9r10pMIAyhS1F0=", 58 | "requires": { 59 | "lodash.isplainobject": "^3.0.2" 60 | } 61 | }, 62 | "service-worker-mock": { 63 | "version": "2.0.5", 64 | "resolved": "https://registry.npmjs.org/service-worker-mock/-/service-worker-mock-2.0.5.tgz", 65 | "integrity": "sha512-yk6NCFnRWGfbOlP+IS4hEbJnGU8dVgtodAAKLxhkTPsOmaES44XVSWTNozK6KwI+p/0PDRrFsb2RjTMhvXiNkA==", 66 | "requires": { 67 | "dom-urls": "^1.1.0", 68 | "shelving-mock-indexeddb": "^1.1.0", 69 | "url-search-params": "^0.10.0", 70 | "w3c-hr-time": "^1.0.1" 71 | } 72 | }, 73 | "shelving-mock-event": { 74 | "version": "1.0.12", 75 | "resolved": "https://registry.npmjs.org/shelving-mock-event/-/shelving-mock-event-1.0.12.tgz", 76 | "integrity": "sha512-2F+IZ010rwV3sA/Kd2hnC1vGNycsxeBJmjkXR8+4IOlv5e+Wvj+xH+A8Cv8/Z0lUyCut/HcxSpeDccYTVtnuaQ==" 77 | }, 78 | "shelving-mock-indexeddb": { 79 | "version": "1.1.0", 80 | "resolved": "https://registry.npmjs.org/shelving-mock-indexeddb/-/shelving-mock-indexeddb-1.1.0.tgz", 81 | "integrity": "sha512-akHJAmGL/dplJ4FZNxPxVbOxMw8Ey6wAnB9+3+GCUNqPUcJaskS55GijxZtarTfAYB4XQyu+FLtjcq2Oa3e2Lg==", 82 | "requires": { 83 | "realistic-structured-clone": "^1.0.1", 84 | "shelving-mock-event": "^1.0.12" 85 | } 86 | }, 87 | "urijs": { 88 | "version": "1.19.2", 89 | "resolved": "https://registry.npmjs.org/urijs/-/urijs-1.19.2.tgz", 90 | "integrity": "sha512-s/UIq9ap4JPZ7H1EB5ULo/aOUbWqfDi7FKzMC2Nz+0Si8GiT1rIEaprt8hy3Vy2Ex2aJPpOQv4P4DuOZ+K1c6w==" 91 | }, 92 | "url-search-params": { 93 | "version": "0.10.2", 94 | "resolved": "https://registry.npmjs.org/url-search-params/-/url-search-params-0.10.2.tgz", 95 | "integrity": "sha512-d6GYsr992Bo9rzTZFc9BUw3UFAAg3prE9JGVBgW2TLTbI3rSvg4VDa0BFXHMzKkWbAuhrmaFWpucpRJl+3W7Jg==" 96 | }, 97 | "w3c-hr-time": { 98 | "version": "1.0.2", 99 | "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", 100 | "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==", 101 | "requires": { 102 | "browser-process-hrtime": "^1.0.0" 103 | } 104 | } 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /packages/@udacity/types-service-worker-mock/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@udacity/types-service-worker-mock", 3 | "version": "1.2.0", 4 | "description": "TypeScript types for service-worker-mock", 5 | "main": "global.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "prepublish": "tsc" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "git+https://github.com/udacity/cloudflare-typescript-workers.git" 13 | }, 14 | "keywords": [ 15 | "service", 16 | "workers", 17 | "typescript", 18 | "types" 19 | ], 20 | "author": "Brad Erickson ", 21 | "license": "Apache-2.0", 22 | "bugs": { 23 | "url": "https://github.com/udacity/cloudflare-typescript-workers/issues" 24 | }, 25 | "homepage": "https://github.com/udacity/cloudflare-typescript-workers#readme", 26 | "types": "index.d.ts", 27 | "files": [ 28 | "global.js", 29 | "global.d.ts", 30 | "index.d.ts", 31 | "LICENSE" 32 | ], 33 | "dependencies": { 34 | "service-worker-mock": "^2.0.5" 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /packages/@udacity/types-service-worker-mock/src/global.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 Udacity, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Why is this a global augmentation? 18 | // 19 | // Because service-worker-mock uses the ServiceWorkerGlobalScope class name 20 | // instead of ServiceWorkerGlobalScopeMock. 21 | // ref: https://github.com/pinterest/service-workers/issues/110 22 | 23 | export {}; 24 | declare global { 25 | type ServiceWorkerGlobalScopeEventListener = < 26 | K extends keyof ServiceWorkerGlobalScopeEventMap, 27 | >( 28 | this: ServiceWorkerGlobalScope, 29 | ev: K, 30 | ) => any; 31 | 32 | interface ServiceWorkerListener { 33 | [key: string]: ServiceWorkerGlobalScopeEventListener; 34 | /** 35 | * Gets a listener object. 36 | * 37 | * @param key string of the name of a listener 38 | */ 39 | get(key: string): ServiceWorkerGlobalScopeEventListener; 40 | } 41 | 42 | // Overriding the original ServiceWorkerGlobalScope to add mock features. 43 | interface ServiceWorkerGlobalScope { 44 | listeners: ServiceWorkerListener; 45 | 46 | trigger(name: string, args: Request): Promise; 47 | // Final overload for void. 48 | trigger(name: string, args: any): Promise; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /packages/@udacity/types-service-worker-mock/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Basic Options */ 4 | "target": "ESNext", 5 | /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */ 6 | "module": "commonjs", 7 | /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */ 8 | "lib": [ 9 | "es5", 10 | "webworker" 11 | ], 12 | /* Specify library files to be included in the compilation. */ 13 | // "allowJs": true, /* Allow javascript files to be compiled. */ 14 | // "checkJs": true, /* Report errors in .js files. */ 15 | // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ 16 | "declaration": true, 17 | /* Generates corresponding '.d.ts' file. */ 18 | // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ 19 | // "sourceMap": true, /* Generates corresponding '.map' file. */ 20 | // "outFile": "./", /* Concatenate and emit output to single file. */ 21 | "outDir": ".", 22 | /* Redirect output structure to the directory. */ 23 | // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ 24 | // "composite": true, /* Enable project compilation */ 25 | // "removeComments": true, /* Do not emit comments to output. */ 26 | // "noEmit": true, /* Do not emit outputs. */ 27 | // "importHelpers": true, /* Import emit helpers from 'tslib'. */ 28 | // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ 29 | // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ 30 | /* Strict Type-Checking Options */ 31 | "strict": true, 32 | /* Enable all strict type-checking options. */ 33 | "noImplicitAny": true, 34 | /* Raise error on expressions and declarations with an implied 'any' type. */ 35 | "strictNullChecks": true, 36 | /* Enable strict null checks. */ 37 | "strictFunctionTypes": true, 38 | /* Enable strict checking of function types. */ 39 | "strictBindCallApply": true, 40 | /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ 41 | "strictPropertyInitialization": true, 42 | /* Enable strict checking of property initialization in classes. */ 43 | "noImplicitThis": true, 44 | /* Raise error on 'this' expressions with an implied 'any' type. */ 45 | "alwaysStrict": true, 46 | /* Parse in strict mode and emit "use strict" for each source file. */ 47 | /* Additional Checks */ 48 | "noUnusedLocals": true, 49 | /* Report errors on unused locals. */ 50 | "noUnusedParameters": true, 51 | /* Report errors on unused parameters. */ 52 | "noImplicitReturns": true, 53 | /* Report error when not all code paths in function return a value. */ 54 | "noFallthroughCasesInSwitch": true, 55 | /* Report errors for fallthrough cases in switch statement. */ 56 | /* Module Resolution Options */ 57 | // "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ 58 | // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ 59 | // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ 60 | // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ 61 | // "typeRoots": ["node_modules/@types"], 62 | /* List of folders to include type definitions from. */ 63 | // "types": [], /* Type declaration files to be included in compilation. */ 64 | // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ 65 | "esModuleInterop": true, 66 | /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ 67 | // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ 68 | /* Source Map Options */ 69 | // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ 70 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ 71 | // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ 72 | // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ 73 | /* Experimental Options */ 74 | // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ 75 | // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ 76 | }, 77 | "include": [ 78 | "src" 79 | ], 80 | "exclude": [ 81 | "dist" 82 | ] 83 | } 84 | -------------------------------------------------------------------------------- /packages/cloudflare-worker-mock/.gitignore: -------------------------------------------------------------------------------- 1 | /index.js 2 | /index.d.ts 3 | /node_modules 4 | -------------------------------------------------------------------------------- /packages/cloudflare-worker-mock/LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /packages/cloudflare-worker-mock/README.md: -------------------------------------------------------------------------------- 1 | # Cloudflare Worker Mock 2 | 3 | Creates a mock Cloudflare Worker environment extending a Service Worker 4 | environment created by `service-worker-mock`. 5 | 6 | See additional details and a demo in: 7 | https://github.com/udacity/cloudflare-typescript-workers 8 | 9 | ## License 10 | 11 | Licensed under the Apache License, Version 2.0. 12 | 13 | © 2019 Udacity, Inc. 14 | 15 | Content derived from Cloudflare Developer Documentation. © 2019 Cloudflare, Inc. 16 | -------------------------------------------------------------------------------- /packages/cloudflare-worker-mock/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cloudflare-worker-mock", 3 | "version": "1.2.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "browser-process-hrtime": { 8 | "version": "1.0.0", 9 | "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", 10 | "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==" 11 | }, 12 | "dom-urls": { 13 | "version": "1.1.0", 14 | "resolved": "https://registry.npmjs.org/dom-urls/-/dom-urls-1.1.0.tgz", 15 | "integrity": "sha1-AB3fgWKM0ecGElxxdvU8zsVdkY4=", 16 | "requires": { 17 | "urijs": "^1.16.1" 18 | } 19 | }, 20 | "lodash._basefor": { 21 | "version": "3.0.3", 22 | "resolved": "https://registry.npmjs.org/lodash._basefor/-/lodash._basefor-3.0.3.tgz", 23 | "integrity": "sha1-dVC06SGO8J+tJDQ7YSAhx5tMIMI=" 24 | }, 25 | "lodash.isarguments": { 26 | "version": "3.1.0", 27 | "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", 28 | "integrity": "sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo=" 29 | }, 30 | "lodash.isarray": { 31 | "version": "3.0.4", 32 | "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz", 33 | "integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U=" 34 | }, 35 | "lodash.isplainobject": { 36 | "version": "3.2.0", 37 | "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-3.2.0.tgz", 38 | "integrity": "sha1-moI4rhayAEMpYM1zRlEtASP79MU=", 39 | "requires": { 40 | "lodash._basefor": "^3.0.0", 41 | "lodash.isarguments": "^3.0.0", 42 | "lodash.keysin": "^3.0.0" 43 | } 44 | }, 45 | "lodash.keysin": { 46 | "version": "3.0.8", 47 | "resolved": "https://registry.npmjs.org/lodash.keysin/-/lodash.keysin-3.0.8.tgz", 48 | "integrity": "sha1-IsRJPrvtsUJ5YqVLRFssinZ/tH8=", 49 | "requires": { 50 | "lodash.isarguments": "^3.0.0", 51 | "lodash.isarray": "^3.0.0" 52 | } 53 | }, 54 | "realistic-structured-clone": { 55 | "version": "1.0.1", 56 | "resolved": "https://registry.npmjs.org/realistic-structured-clone/-/realistic-structured-clone-1.0.1.tgz", 57 | "integrity": "sha1-Gr6CrwuAzXsQn9r10pMIAyhS1F0=", 58 | "requires": { 59 | "lodash.isplainobject": "^3.0.2" 60 | } 61 | }, 62 | "service-worker-mock": { 63 | "version": "2.0.5", 64 | "resolved": "https://registry.npmjs.org/service-worker-mock/-/service-worker-mock-2.0.5.tgz", 65 | "integrity": "sha512-yk6NCFnRWGfbOlP+IS4hEbJnGU8dVgtodAAKLxhkTPsOmaES44XVSWTNozK6KwI+p/0PDRrFsb2RjTMhvXiNkA==", 66 | "requires": { 67 | "dom-urls": "^1.1.0", 68 | "shelving-mock-indexeddb": "^1.1.0", 69 | "url-search-params": "^0.10.0", 70 | "w3c-hr-time": "^1.0.1" 71 | } 72 | }, 73 | "shelving-mock-event": { 74 | "version": "1.0.12", 75 | "resolved": "https://registry.npmjs.org/shelving-mock-event/-/shelving-mock-event-1.0.12.tgz", 76 | "integrity": "sha512-2F+IZ010rwV3sA/Kd2hnC1vGNycsxeBJmjkXR8+4IOlv5e+Wvj+xH+A8Cv8/Z0lUyCut/HcxSpeDccYTVtnuaQ==" 77 | }, 78 | "shelving-mock-indexeddb": { 79 | "version": "1.1.0", 80 | "resolved": "https://registry.npmjs.org/shelving-mock-indexeddb/-/shelving-mock-indexeddb-1.1.0.tgz", 81 | "integrity": "sha512-akHJAmGL/dplJ4FZNxPxVbOxMw8Ey6wAnB9+3+GCUNqPUcJaskS55GijxZtarTfAYB4XQyu+FLtjcq2Oa3e2Lg==", 82 | "requires": { 83 | "realistic-structured-clone": "^1.0.1", 84 | "shelving-mock-event": "^1.0.12" 85 | } 86 | }, 87 | "urijs": { 88 | "version": "1.19.2", 89 | "resolved": "https://registry.npmjs.org/urijs/-/urijs-1.19.2.tgz", 90 | "integrity": "sha512-s/UIq9ap4JPZ7H1EB5ULo/aOUbWqfDi7FKzMC2Nz+0Si8GiT1rIEaprt8hy3Vy2Ex2aJPpOQv4P4DuOZ+K1c6w==" 91 | }, 92 | "url-search-params": { 93 | "version": "0.10.2", 94 | "resolved": "https://registry.npmjs.org/url-search-params/-/url-search-params-0.10.2.tgz", 95 | "integrity": "sha512-d6GYsr992Bo9rzTZFc9BUw3UFAAg3prE9JGVBgW2TLTbI3rSvg4VDa0BFXHMzKkWbAuhrmaFWpucpRJl+3W7Jg==" 96 | }, 97 | "w3c-hr-time": { 98 | "version": "1.0.2", 99 | "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", 100 | "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==", 101 | "requires": { 102 | "browser-process-hrtime": "^1.0.0" 103 | } 104 | } 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /packages/cloudflare-worker-mock/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cloudflare-worker-mock", 3 | "version": "1.2.0", 4 | "description": "Mocks for the Cloudflare Worker API", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "prepublish": "tsc" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "git+https://github.com/udacity/cloudflare-typescript-workers.git" 13 | }, 14 | "keywords": [ 15 | "cloudflare", 16 | "workers", 17 | "typescript", 18 | "mock", 19 | "testing" 20 | ], 21 | "author": "Brad Erickson ", 22 | "license": "Apache-2.0", 23 | "bugs": { 24 | "url": "https://github.com/udacity/cloudflare-typescript-workers/issues" 25 | }, 26 | "homepage": "https://github.com/udacity/cloudflare-typescript-workers#readme", 27 | "types": "index.d.ts", 28 | "files": [ 29 | "index.j", 30 | "index.d.ts", 31 | "LICENSE" 32 | ], 33 | "peerDependencies": { 34 | "types-cloudflare-worker": "^1.0.0-rc8", 35 | "@udacity/types-service-worker-mock": "^1.0.0-rc8" 36 | }, 37 | "dependencies": { 38 | "service-worker-mock": "^2.0.5" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /packages/cloudflare-worker-mock/src/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 Udacity, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Primarily exists to implement the Cache API: 18 | // https://developers.cloudflare.com/workers/reference/cache-api/ 19 | 20 | // Import the service-worker-mock types. 21 | /// 22 | // Import the service-worker-mock global augmentations. 23 | import '@udacity/types-service-worker-mock/global'; 24 | 25 | import makeServiceWorkerEnv from 'service-worker-mock'; 26 | import { EnvOptions } from 'service-worker-mock'; 27 | import { 28 | CloudflareCacheQueryOptions, 29 | CloudflareRequestAttributes, 30 | CloudflareWorkerGlobalKVPatch, 31 | CloudflareWorkerGlobalScopePatch, 32 | CloudflareWorkerKV, 33 | CloudflareWorkerKVList, 34 | MockCloudflareRequestInit, 35 | } from 'types-cloudflare-worker'; 36 | 37 | /** 38 | * Create a mock environment for a Cloudflare Worker with a mockable cache layer. 39 | */ 40 | export function makeCloudflareWorkerEnv( 41 | envOptions?: EnvOptions, 42 | ): CloudflareWorkerGlobalScopePatch { 43 | const serviceWorkerEnv = makeServiceWorkerEnv(envOptions); 44 | const cloudflareWorkerEnv = 45 | serviceWorkerEnv as CloudflareWorkerGlobalScopePatch; 46 | 47 | cloudflareWorkerEnv.caches = { 48 | default: { 49 | put(_request: Request, _response: Response): Promise { 50 | return new Promise((resolve, _reject) => { 51 | resolve(undefined); 52 | }); 53 | }, 54 | match( 55 | _request: Request, 56 | _options?: CloudflareCacheQueryOptions, 57 | ): Promise { 58 | return new Promise((resolve, _reject) => { 59 | resolve(undefined); 60 | }); 61 | }, 62 | delete( 63 | _request: Request, 64 | _options?: CloudflareCacheQueryOptions, 65 | ): Promise { 66 | return new Promise((resolve, _reject) => { 67 | resolve(false); 68 | }); 69 | }, 70 | }, 71 | }; 72 | 73 | return cloudflareWorkerEnv; 74 | } 75 | 76 | /** 77 | * Create a mock KV for a Cloudflare Worker 78 | */ 79 | export function makeCloudflareWorkerKVEnv( 80 | name: string, 81 | ): CloudflareWorkerGlobalKVPatch { 82 | const cloudflareWorkerKV: CloudflareWorkerKV = { 83 | get( 84 | _key: string, 85 | _type?: 'text' | 'json' | 'arrayBuffer' | 'stream', 86 | ): Promise { 87 | return Promise.resolve(undefined); 88 | }, 89 | put( 90 | _key: string, 91 | _value: string | ReadableStream | ArrayBuffer | FormData, 92 | ): Promise { 93 | return Promise.resolve(undefined); 94 | }, 95 | delete(_key: string): Promise { 96 | return Promise.resolve(undefined); 97 | }, 98 | list( 99 | _prefix: string, 100 | _limit: number, 101 | _cursor: string, 102 | ): Promise { 103 | return Promise.resolve({ 104 | cursor: '1234567890', 105 | keys: [{ name: 'foo', expiration: 1234 }], 106 | list_complete: true, 107 | }); 108 | }, 109 | }; 110 | 111 | const cloudflareWorkerKVEnv = { 112 | [name]: cloudflareWorkerKV, 113 | }; 114 | return cloudflareWorkerKVEnv; 115 | } 116 | 117 | /** 118 | * Create a mock Request for a Cloudflare Worker 119 | * 120 | * A CloudflareRequestAttributes object can be created manually, but it requires 121 | * the developer to specify every field. This helper function allows the 122 | * developer to specify only fields required by tests. 123 | */ 124 | export function makeCloudflareWorkerRequest( 125 | input: RequestInfo, 126 | init?: MockCloudflareRequestInit, 127 | ): Request { 128 | if (init == null) { 129 | return new Request(input); 130 | } 131 | 132 | const attr = init.cf; 133 | const tlsAttr: Partial = 134 | attr.tlsClientAuth || {}; 135 | const cf: CloudflareRequestAttributes = { 136 | asn: attr.asn || '395747', 137 | city: attr.city || 'Austin', 138 | colo: attr.colo || 'AUS', 139 | continent: attr.continent || 'NA', 140 | country: attr.country || 'US', 141 | exclusive: attr.exclusive || '0', 142 | group: attr.exclusive || '0', 143 | 'group-weight': attr['group-weight'] || '0', 144 | httpProtocol: attr.httpProtocol || 'HTTP/2', 145 | latitude: attr.latitude || 30.2713, 146 | longitude: attr.longitude || -97.7426, 147 | postalCode: attr.postalCode || '78701', 148 | region: attr.region || 'Texas', 149 | regionCode: attr.regionCode || 'TX', 150 | requestPriority: 151 | attr.requestPriority || 'weight=192;exclusive=0;group=3;group-weight=127', 152 | timezone: attr.timezone || 'America/Chicago', 153 | tlsCipher: attr.tlsCipher || 'AEAD-AES128-GCM-SHA256', 154 | tlsClientAuth: { 155 | certFingerprintSHA1: tlsAttr.certFingerprintSHA1 || '', 156 | certIssuerDN: tlsAttr.certIssuerDN || '', 157 | certIssuerDNLegacy: tlsAttr.certIssuerDNLegacy || '', 158 | certIssuerDNRFC2253: tlsAttr.certIssuerDNRFC2253 || '', 159 | certNotAfter: tlsAttr.certNotAfter || 'Dec 22 19:39:00 2018 GMT', 160 | certNotBefore: tlsAttr.certNotBefore || 'Dec 22 19:39:00 2018 GMT', 161 | certPresented: tlsAttr.certPresented || '1', 162 | certSerial: tlsAttr.certSerial || '', 163 | certSubjectDN: tlsAttr.certSubjectDN || '', 164 | certSubjectDNLegacy: tlsAttr.certSubjectDNLegacy || '', 165 | certVerified: tlsAttr.certVerified || 'SUCCESS', 166 | }, 167 | tlsVersion: attr.weight || 'TLSv1.3', 168 | weight: attr.weight || '0', 169 | }; 170 | 171 | const request = new Request(input, init); 172 | // Manually add CloudflareRequestAttributes since new Request() drops them. 173 | request.cf = cf; 174 | 175 | return request; 176 | } 177 | 178 | export default makeCloudflareWorkerEnv; 179 | -------------------------------------------------------------------------------- /packages/cloudflare-worker-mock/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Basic Options */ 4 | "target": "ESNext", 5 | /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */ 6 | "module": "commonjs", 7 | /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */ 8 | "lib": [ 9 | "es5", 10 | "webworker" 11 | ], 12 | /* Specify library files to be included in the compilation. */ 13 | // "allowJs": true, /* Allow javascript files to be compiled. */ 14 | // "checkJs": true, /* Report errors in .js files. */ 15 | // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ 16 | "declaration": true, 17 | /* Generates corresponding '.d.ts' file. */ 18 | // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ 19 | // "sourceMap": true, /* Generates corresponding '.map' file. */ 20 | // "outFile": "./", /* Concatenate and emit output to single file. */ 21 | "outDir": ".", 22 | /* Redirect output structure to the directory. */ 23 | // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ 24 | // "composite": true, /* Enable project compilation */ 25 | // "removeComments": true, /* Do not emit comments to output. */ 26 | // "noEmit": true, /* Do not emit outputs. */ 27 | // "importHelpers": true, /* Import emit helpers from 'tslib'. */ 28 | // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ 29 | // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ 30 | /* Strict Type-Checking Options */ 31 | "strict": true, 32 | /* Enable all strict type-checking options. */ 33 | "noImplicitAny": true, 34 | /* Raise error on expressions and declarations with an implied 'any' type. */ 35 | "strictNullChecks": true, 36 | /* Enable strict null checks. */ 37 | "strictFunctionTypes": true, 38 | /* Enable strict checking of function types. */ 39 | "strictBindCallApply": true, 40 | /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ 41 | "strictPropertyInitialization": true, 42 | /* Enable strict checking of property initialization in classes. */ 43 | "noImplicitThis": true, 44 | /* Raise error on 'this' expressions with an implied 'any' type. */ 45 | "alwaysStrict": true, 46 | /* Parse in strict mode and emit "use strict" for each source file. */ 47 | /* Additional Checks */ 48 | "noUnusedLocals": true, 49 | /* Report errors on unused locals. */ 50 | "noUnusedParameters": true, 51 | /* Report errors on unused parameters. */ 52 | "noImplicitReturns": true, 53 | /* Report error when not all code paths in function return a value. */ 54 | "noFallthroughCasesInSwitch": true, 55 | /* Report errors for fallthrough cases in switch statement. */ 56 | /* Module Resolution Options */ 57 | // "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ 58 | // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ 59 | // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ 60 | // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ 61 | // "typeRoots": ["node_modules/@types"], 62 | /* List of folders to include type definitions from. */ 63 | // "types": [], /* Type declaration files to be included in compilation. */ 64 | // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ 65 | "esModuleInterop": true, 66 | /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ 67 | // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ 68 | /* Source Map Options */ 69 | // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ 70 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ 71 | // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ 72 | // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ 73 | /* Experimental Options */ 74 | // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ 75 | // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ 76 | }, 77 | "include": [ 78 | "src" 79 | ], 80 | "exclude": [ 81 | "dist" 82 | ] 83 | } 84 | -------------------------------------------------------------------------------- /packages/types-cloudflare-worker/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | /global.js 3 | /global.d.ts 4 | -------------------------------------------------------------------------------- /packages/types-cloudflare-worker/LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /packages/types-cloudflare-worker/README.md: -------------------------------------------------------------------------------- 1 | # TypeScript types for Cloudflare Workers 2 | 3 | Types for [Cloudflare 4 | Workers](https://www.cloudflare.com/products/cloudflare-workers/) extending 5 | Service Worker types. Follows documentation available in: 6 | https://developers.cloudflare.com/workers/about/ 7 | 8 | ## Use 9 | 10 | Requires `tsconfig.json` to contain: 11 | 12 | ```json 13 | "lib": ["webworker"], 14 | ``` 15 | 16 | See additional details and a demo in: 17 | https://github.com/udacity/cloudflare-typescript-workers 18 | 19 | ## License 20 | 21 | Licensed under the Apache License, Version 2.0. 22 | 23 | © 2019 Udacity, Inc. 24 | 25 | Content derived from Cloudflare Developer Documentation. © 2019 Cloudflare, Inc. 26 | -------------------------------------------------------------------------------- /packages/types-cloudflare-worker/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "types-cloudflare-worker", 3 | "version": "1.2.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "@types/node": { 8 | "version": "12.12.26", 9 | "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.26.tgz", 10 | "integrity": "sha512-UmUm94/QZvU5xLcUlNR8hA7Ac+fGpO1EG/a8bcWVz0P0LqtxFmun9Y2bbtuckwGboWJIT70DoWq1r3hb56n3DA==", 11 | "dev": true 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /packages/types-cloudflare-worker/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "types-cloudflare-worker", 3 | "version": "1.2.0", 4 | "description": "TypeScript types for the Cloudflare Worker API", 5 | "main": "global.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "prepublish": "tsc" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "git+https://github.com/udacity/cloudflare-typescript-workers.git" 13 | }, 14 | "keywords": [ 15 | "cloudflare", 16 | "workers", 17 | "typescript", 18 | "types" 19 | ], 20 | "author": "Brad Erickson ", 21 | "license": "Apache-2.0", 22 | "bugs": { 23 | "url": "https://github.com/udacity/cloudflare-typescript-workers/issues" 24 | }, 25 | "homepage": "https://github.com/udacity/cloudflare-typescript-workers#readme", 26 | "types": "global.d.ts", 27 | "files": [ 28 | "global.js", 29 | "global.d.ts", 30 | "LICENSE" 31 | ], 32 | "devDependencies": { 33 | "@types/node": "^12.12.26" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /packages/types-cloudflare-worker/src/global.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 Udacity, Inc 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | 16 | Content derived from Cloudflare Developer Documentation. © 2019 Cloudflare, Inc. 17 | */ 18 | 19 | // Why is this a global augmentation? 20 | // 21 | // Because Cloudflare extends the Request object with additional attributes. 22 | // ref: https://developers.cloudflare.com/workers/reference/request-attributes/ 23 | 24 | declare global { 25 | interface Request { 26 | cf: CloudflareRequestAttributes; // extends, therefore includes CloudflareRequestFeatures 27 | } 28 | 29 | // Global augmentation of FetchEvent to provide additional lifecycle APIs. 30 | // https://developers.cloudflare.com/workers/about/tips/fetch-event-lifecycle 31 | interface FetchEvent { 32 | /** 33 | * Causes the script to “fail open” (meaning the execution of code is not halted) 34 | * on unhandled exceptions. Instead of returning a runtime error response, the runtime 35 | * proxies the request to its destination. To prevent JavaScript errors from causing 36 | * entire requests to fail on uncaught exceptions, passThroughOnException() causes the 37 | * Workers runtime to yield control to the origin server. 38 | */ 39 | passThroughOnException(): void; // extends FetchEvent 40 | } 41 | 42 | /** 43 | * Cloudflare Cache Storage 44 | * 45 | * The Cache API gives you fine grained control of reading and writing from 46 | * cache, and deciding exactly when to fetch data from your origin. 47 | * 48 | * ref: https://developers.cloudflare.com/workers/reference/cache-api/ 49 | * 50 | * This global augmentation adds the Cloudflare Cache storage object to the 51 | * regular CacheStorage interface. 52 | */ 53 | interface CacheStorage { 54 | /** 55 | * The Cloudflare Workers runtime exposes a single global Cache object, 56 | * caches.default. This differs from web browsers’ Cache API in that they do 57 | * not expose any default cache object. 58 | */ 59 | default: CloudflareDefaultCacheStorage; 60 | } 61 | 62 | // Overload fetch to accept the CloudflareRequestInit interface 63 | interface GlobalFetch { 64 | fetch(input: RequestInfo, init?: CloudflareRequestInit): Promise; 65 | } 66 | interface WindowOrWorkerGlobalScope { 67 | fetch(input: RequestInfo, init?: CloudflareRequestInit): Promise; 68 | } 69 | function fetch( 70 | input: RequestInfo, 71 | init?: CloudflareRequestInit, 72 | ): Promise; 73 | 74 | // Overload Headers interface to manually add entries() 75 | // https://github.com/udacity/cloudflare-typescript-workers/issues/4 76 | interface Headers { 77 | /** 78 | * The Headers.entries() method returns an iterator allowing to go through 79 | * all key/value pairs contained in this object. The both the key and value 80 | * of each pairs are ByteString objects. 81 | * 82 | * Note: This override will exist until 83 | * https://github.com/microsoft/TSJS-lib-generator/issues/729 is fixed. 84 | */ 85 | entries(): IterableIterator<[string, string]>; 86 | } 87 | } 88 | 89 | /** 90 | * CloudflareWorkerGlobalScope extends the ServiceWorkerGlobalScope to include 91 | * CloudflareWorkerGlobalScopePatch when created with makeCloudflareWorkerEnv(). 92 | * 93 | * ServiceWorkerGlobalScope could be used instead of this empty extends, but 94 | * this makes the developer experience more consistent and allows for easier 95 | * upgrades if/when changes are implemented. 96 | */ 97 | // tslint:disable-next-line:no-empty-interface 98 | export interface CloudflareWorkerGlobalScope extends ServiceWorkerGlobalScope {} 99 | export default CloudflareWorkerGlobalScope; 100 | 101 | export interface CloudflareCacheQueryOptions { 102 | /** 103 | * Consider the request method to be GET, regardless of its actual value. 104 | */ 105 | ignoreMethod: boolean; 106 | } 107 | 108 | /** 109 | * A Cache object exposes three methods. Each method accepts a Request object or 110 | * string value as its first parameter. If a string is passed, it will be 111 | * interpreted as the URL for a new Request object. 112 | */ 113 | export interface CloudflareDefaultCacheStorage { 114 | put(request: Request | string, response: Response): Promise; 115 | match( 116 | request: Request | string, 117 | options?: CloudflareCacheQueryOptions, 118 | ): Promise; 119 | delete( 120 | request: Request | string, 121 | options?: CloudflareCacheQueryOptions, 122 | ): Promise; 123 | } 124 | 125 | export interface CloudflareCacheStorage { 126 | default: CloudflareDefaultCacheStorage; 127 | } 128 | 129 | // Does not extend ServiceWorkerGlobalScope because we are entirely replacing to 130 | // match the Cloudflare implementation. 131 | export interface CloudflareWorkerGlobalScopePatch { 132 | caches: CloudflareCacheStorage; 133 | } 134 | 135 | // CloudflareWorkerGlobalKVPatch adds a KV name to the global scope 136 | export interface CloudflareWorkerGlobalKVPatch { 137 | [kv: string]: CloudflareWorkerKV; 138 | } 139 | 140 | /** 141 | * Cloudflare Request Attributes 142 | * 143 | * Workers allows you to run custom logic based for any incoming request. In 144 | * addition to the information available on the Request object, such as headers, 145 | * Cloudflare provides additional attributes of the request using the request.cf 146 | * object. 147 | * 148 | * Attributes available on request.cf: 149 | * * tlsVersion: the TLS version used on the connection to Cloudflare. 150 | * * tlsCipher: the cipher used on the connection to Cloudflare. 151 | * * country: the two letter country code on the request (this is the same value 152 | * as the one provided by the CF-IPCountry header) 153 | * * colo: the three letter airport code of the colo the request hit. 154 | * 155 | * Attributes available through headers: 156 | * * Client IP: the client IP is available via the CF-Connecting-IP header. 157 | * 158 | * WARNING: Request Attributes do not currently work in the Worker Editor 159 | * Preview, resulting in an error: "Uncaught (in response) TypeError: Cannot 160 | * read property 'country' of undefined." See: 161 | * https://developers.cloudflare.com/workers/recipes/tls-version-blocking/ 162 | * 163 | */ 164 | export interface CloudflareRequestAttributes extends CloudflareRequestFeatures { 165 | /** 166 | * ASN of the incoming request. (e.g. 395747) 167 | */ 168 | readonly asn: string; 169 | 170 | /** 171 | * The three letter airport code of the colo the request hit. 172 | */ 173 | readonly colo: string; 174 | 175 | /** 176 | * The browser-requested weight for the HTTP/2 prioritization. 177 | */ 178 | readonly weight: string; 179 | 180 | /** 181 | * The browser-requested HTTP/2 exclusive flag (1 for Chromium-based browsers, 182 | * 0 for others). 183 | */ 184 | readonly exclusive: '0' | '1'; 185 | 186 | /** 187 | * HTTP/2 stream ID for the request group (only non-zero for Firefox). 188 | */ 189 | readonly group: string; 190 | 191 | /** 192 | * HTTP/2 weight for the request group (only non-zero for Firefox). 193 | */ 194 | readonly 'group-weight': string; 195 | 196 | /** 197 | * The cipher for the connection to Cloudflare. (e.g. "AEAD-AES128-GCM-SHA256") 198 | */ 199 | readonly tlsCipher: string; 200 | 201 | /** 202 | * The two letter country code on the request (this is the same value as 203 | * the one provided by the CF-IPCountry header.) 204 | */ 205 | readonly country: string; 206 | 207 | /** 208 | * Only set when using Cloudflare Access. 209 | */ 210 | readonly tlsClientAuth: { 211 | certIssuerDNLegacy: string; 212 | certIssuerDN: string; 213 | certIssuerDNRFC2253: string; 214 | certPresented: '0' | '1'; 215 | certSubjectDNLegacy: string; 216 | certSubjectDN: string; 217 | certNotBefore: string; // Format "Dec 22 19:39:00 2018 GMT" 218 | certNotAfter: string; // Format "Dec 22 19:39:00 2018 GMT" 219 | certSerial: string; 220 | certFingerprintSHA1: string; 221 | certVerified: string; // "SUCCESS", "FAILED:reason", "NONE" 222 | }; 223 | 224 | /** 225 | * The TLS version of the connection to Cloudflare (e.g. TLSv1.3) 226 | */ 227 | readonly tlsVersion: string; 228 | 229 | // Business and Enterprise only: 230 | 231 | /** 232 | * The browser-requested prioritization information in the request object. 233 | * (e.g. “weight=192;exclusive=0;group=3;group-weight=127”) 234 | * 235 | * Business and Enterprise ONLY. 236 | */ 237 | readonly requestPriority: string; 238 | 239 | /** 240 | * City of the incoming request. (e.g. "Austin") 241 | * 242 | * Business and Enterprise ONLY. 243 | */ 244 | readonly city: string; 245 | 246 | /** 247 | * Continent of the incoming request. (e.g. "NA") 248 | * 249 | * Business and Enterprise ONLY. 250 | */ 251 | readonly continent: string; 252 | 253 | /** 254 | * HTTP Protocol (e.g. "HTTP/2") 255 | * 256 | * Business and Enterprise ONLY. 257 | */ 258 | readonly httpProtocol: string; 259 | 260 | /** 261 | * Latitude of the incoming request. (e.g. "30.27130") 262 | * 263 | * Business and Enterprise ONLY. 264 | */ 265 | readonly latitude: number; 266 | 267 | /** 268 | * Longitude of the incoming request. (e.g. "-97.74260") 269 | * 270 | * Business and Enterprise ONLY. 271 | */ 272 | readonly longitude: number; 273 | 274 | /** 275 | * PostalCode of the incoming request. (e.g. "78701") 276 | * 277 | * Business and Enterprise ONLY. 278 | */ 279 | readonly postalCode: string; 280 | 281 | /** 282 | * If known, the ISO 3166-2 name for the first level region associated with 283 | * the IP address of the incoming request. If not known, this is an empty 284 | * string. (e.g. "Texas") 285 | * 286 | * Business and Enterprise ONLY. 287 | */ 288 | readonly region: string; 289 | 290 | /** 291 | * If known, the ISO 3166-2 code for the first level region associated with 292 | * the IP address of the incoming request. 1 If not known, this is an empty 293 | * string. (e.g. "TX") 294 | * 295 | * Business and Enterprise ONLY. 296 | */ 297 | readonly regionCode: string; 298 | 299 | /** 300 | * Timezone of the incoming request. (e.g. "America/Chicago") 301 | * 302 | * Business and Enterprise ONLY. 303 | */ 304 | readonly timezone: string; 305 | } 306 | 307 | // An interface for controlling Cloudflare Features on Requests. Reference: 308 | // https://developers.cloudflare.com/workers/reference/cloudflare-features/ 309 | export interface CloudflareRequestFeatures { 310 | /** 311 | * This option forces Cloudflare to cache the response for this request, 312 | * regardless of what headers are seen on the response. This is equivalent to 313 | * setting the page rule “Cache Level” (to “Cache Everything”). (e.g. true) 314 | */ 315 | cacheEverything?: boolean; 316 | 317 | /** 318 | * Disables ScrapeShield for this request. When you specify this option, the 319 | * value should always be false. 320 | */ 321 | scrapeShield?: boolean; 322 | 323 | /** 324 | * Sets Polish mode. The possible values are "lossy", "lossless", or "off". 325 | */ 326 | polish?: string; 327 | 328 | /** 329 | * Resize images fetched from the origin server on the fly. The value is an 330 | * object specifying the desired image properties. 331 | */ 332 | image?: { 333 | /* Maximum width in pixels. Must be an integer. */ 334 | width?: number; 335 | 336 | /* Maximum height in pixels. Must be an integer. */ 337 | height?: number; 338 | 339 | /* Device Pixel Ratio. Default 1. Multiplier for width/height that makes it 340 | * easier to specify higher-DPI sizes in */ 341 | dpr?: number; 342 | 343 | /* Resizing mode. Options are: "scale-down", "contain", "cover", or "pad". */ 344 | fit?: string; 345 | 346 | /* Gravity when cropping with `fit: "cover"`. The value is either a string 347 | * "left", "right", "top", "bottom" or "center" (the default), or an object 348 | * {x, y} containing focal point coordinates in the original image 349 | * expressed as fractions ranging from 0.0 (top or left) to 1.0 (bottom or 350 | * right), 0.5 being the center. */ 351 | gravity?: string; 352 | 353 | /* Quality setting from 1-100 (useful values are in 60-90 range). Default 85. */ 354 | quality?: number; 355 | 356 | /* By default, the image format is retained from the source. Optionally 357 | * images can be converted to "webp", or metadata returned as "json". 358 | * Other format conversion, e.g. gif to jpeg, is not supported. */ 359 | format?: string; 360 | 361 | /* What EXIF data should be preserved in the output image. Note that EXIF 362 | * rotation and embedded color profiles are always "baked into" the image. 363 | * Options are: 364 | * "keep" - Preserve most EXIF metadata, including GPS location. 365 | * "copyright" - Only keep the copyright tag, discard everything else. 366 | * This is the default behavior for JPEG files. 367 | * "none" - Discard all invisible EXIF metadata. Currently WebP and 368 | * PNG output formats always discard metadata. 369 | */ 370 | metadata?: string; 371 | 372 | /* Number of degrees (90, 180, 270) to rotate the image by. width and 373 | * height options refer to axes after rotation. */ 374 | rotate?: number; 375 | }; 376 | 377 | /** 378 | * Enables or disables AutoMinify for various file types. The value is an 379 | * object containing Boolean fields for javascript, css, and html. (e.g. { 380 | * javascript: true, css: true, html: false }) 381 | */ 382 | minify?: { 383 | javascript?: boolean; 384 | css?: boolean; 385 | html?: boolean; 386 | }; 387 | 388 | /** 389 | * Disables Mirage for this request. When you specify this option, the value 390 | * should always be false. 391 | */ 392 | mirage?: boolean; 393 | 394 | /** 395 | * Disables Cloudflare Apps for this request. When you specify this option, 396 | * the value should always be false. 397 | */ 398 | apps?: boolean; 399 | 400 | /** 401 | * This option forces Cloudflare to cache the response for this request, 402 | * regardless of what headers are seen on the response. This is equivalent to 403 | * setting two page rules: "Edge Cache TTL" and "Cache Level" (to "Cache 404 | * Everything"). 405 | */ 406 | cacheTtl?: number; 407 | 408 | // Enterprise only: 409 | 410 | /** 411 | * Set cache key for this request. Enterprise only. 412 | * 413 | * A request’s cache key is what determines if two requests are "the same" for 414 | * caching purposes. If a request has the same cache key as some previous 415 | * request, then we can serve the same cached response for both. 416 | * 417 | * Normally, Cloudflare computes the cache key for a request based on the 418 | * request’s URL. Sometimes, though, you’d like different URLs to be treated 419 | * as if they were the same for caching purposes. For example, say your web 420 | * site content is hosted from both Amazon S3 and Google Cloud Storage – you 421 | * have the same content in both places, and you use a Worker to randomly 422 | * balance between the two. However, you don’t want to end up caching two 423 | * copies of your content! You could utilize custom cache keys to cache based 424 | * on the original request URL rather than the subrequest URL: 425 | * 426 | * addEventListener('fetch', event => { 427 | * let url = new URL(event.request.url); 428 | * if (Math.random() < 0.5) { 429 | * url.hostname = 'example.s3.amazonaws.com' 430 | * } else { 431 | * url.hostname = 'example.storage.googleapis.com' 432 | * } 433 | * 434 | * let request = new Request(url, event.request) 435 | * event.respondWith(fetch(request, { 436 | * cf: { cacheKey: event.request.url } 437 | * })) 438 | * }) 439 | * 440 | * Notes: 441 | * * Each zone has its own private cache key namespace. That means that two 442 | * workers operating within the same zone (even on different hostnames) may 443 | * share cache using custom cache keys, but workers operating on behalf of 444 | * different zones cannot affect each other’s cache. 445 | * * You can only override cache keys when making requests within your own 446 | * zone, or requests to hosts that are not on Cloudflare. When making a 447 | * request to another Cloudflare zone (e.g. belonging to a different 448 | * Cloudflare customer), that zone fully controls how its own content is 449 | * cached within Cloudflare; you cannot override it. 450 | * * URLs that are fetch()ed with a custom cache key cannot be purged using a 451 | * URL purge. However you can use the Cache API and set a Cache Tag on the 452 | * response object if you need to purge the URL. 453 | */ 454 | cacheKey?: string; 455 | 456 | /** 457 | * This option is a version of the cacheTtl feature which chooses a TTL based 458 | * on the response’s status code. If the response to this request has a status 459 | * code that matches, Cloudflare will cache for the instructed time, and 460 | * override cache instructives sent by the origin. 461 | * 462 | * This gives you control over how long assets will stay in the Cloudflare 463 | * cache based on the response code. For example, you could cache successful 464 | * fetches for longer, but continue to fetch assets from the origin in the 465 | * event of failures. You may also use this feature to cache redirects. 466 | * 467 | * You may still choose to have different rules based on request settings by 468 | * checking the URI or headers. 469 | * 470 | * TTL values: 471 | * * Positive TTL values indicate in seconds how long Cloudflare should cache 472 | * the asset for 473 | * * 0 TTL will cause assets to get cached, but expire immediately (revalidate 474 | * from origin every time) 475 | * * -1, or any negative value will instruct Cloudflare not to cache at all 476 | * 477 | * Please note, that Cloudflare will still adhere to standard cache levels, 478 | * so by default this will override cache behavior for static files. If you 479 | * wish to cache non-static 480 | */ 481 | cacheTtlByStatus?: { [key: string]: number }; 482 | 483 | /** 484 | * Redirects the request to an alternate origin server. You can use this, for 485 | * example, to implement load balancing across several origins. Enterprise 486 | * only. 487 | * 488 | * You can achieve a similar effect by simply changing the request URL. For 489 | * example: 490 | * 491 | * let url = new URL(event.request.url) url.hostname = 'us-east.example.com' 492 | * fetch(url, event.request) 493 | * 494 | * However, there is an important difference: If you use resolveOverride to 495 | * change the origin, then the request will be sent with a Host header 496 | * matching the original URL. Often, your origin servers will all expect the 497 | * Host header to specify your web site’s main hostname, not the hostname of 498 | * the specific replica. This is where resolveOverride is needed. 499 | * 500 | * For security reasons, resolveOverride is only honored when both the URL 501 | * hostname and the resolveOverride hostname are orange-cloud hosts within 502 | * your own zone. Otherwise, the setting is ignored. Note that CNAME hosts are 503 | * allowed. So, if you want to resolve to a hostname that is under a different 504 | * domain, first declare a CNAME record within your own zone’s DNS mapping to 505 | * the external hostname, then set resolveOverride to point to that CNAME 506 | * record. 507 | */ 508 | resolveOverride?: string; 509 | } 510 | 511 | export interface CloudflareRequestInit extends RequestInit { 512 | /** 513 | * Controlling Cloudflare Features 514 | * You can use a Worker to control how other Cloudflare features affect the 515 | * request. Your Worker runs after security features, but before everything 516 | * else. Therefore, a Worker cannot affect the operation of security features 517 | * (since they already finished), but it can affect other features, like 518 | * Polish or ScrapeShield, or how Cloudflare caches the response. 519 | * 520 | * Cloudflare features are controlled through the cf property of a request. 521 | * Setting cf is kind of like setting headers. You can add cf to a request 522 | * object by making a copy: 523 | * 524 | * // Disable ScrapeShield for this request. 525 | * let request = new Request(event.request, { cf: { scrapeShield: false } }) 526 | * 527 | * Alternatively, you can set cf directly on fetch(): 528 | * // Disable ScrapeShield for this request. 529 | * fetch(event.request, { cf: { scrapeShield: false } }) 530 | * 531 | * Note: Invalid or incorrectly-named settings in the cf object will be 532 | * silently ignored. Be careful to test that you are getting the behavior you 533 | * want. Currently, settings in the cf object cannot be tested in the live 534 | * preview. 535 | */ 536 | cf: CloudflareRequestFeatures; // Features, not Attributes, because Attributes are readonly. 537 | } 538 | 539 | // Conditional Types in 2.8, we can now declare a recursive partial type as follows 540 | // src: https://stackoverflow.com/a/51365037 541 | type RecursivePartial = { 542 | [P in keyof T]?: T[P] extends (infer U)[] 543 | ? RecursivePartial[] 544 | : T[P] extends object 545 | ? RecursivePartial 546 | : T[P]; 547 | }; 548 | 549 | export interface MockCloudflareRequestInit extends RequestInit { 550 | cf: RecursivePartial; // Attributes can only be set in a mock. 551 | } 552 | 553 | /** 554 | * Cloudflare Worker KV 555 | * 556 | * Workers KV is a global, low-latency, key-value data store. It supports exceptionally 557 | * high read volumes with low-latency, making it possible to build highly dynamic APIs 558 | * and websites which respond as quickly as a cached static file would. 559 | * 560 | * Workers KV is generally good for use-cases where you need to write relatively infrequently, 561 | * but read quickly and frequently. It is optimized for these high-read applications, only 562 | * reaching its full performance when data is being frequently read. Very infrequently read 563 | * values are stored centrally, while more popular values are maintained in all of our data 564 | * centers around the world. 565 | * 566 | * KV achieves this performance by being eventually-consistent. New key-value pairs are 567 | * immediately available everywhere, but value changes may take up to ten seconds to propagate. 568 | * Workers KV isn’t ideal for situations where you need support for atomic operations or where 569 | * values must be read and written in a single transaction. 570 | * 571 | * ref: https://developers.cloudflare.com/workers/kv 572 | * 573 | * Prerequisite 574 | * The first step is to bind one of your Namespaces to your Worker. This will make 575 | * that Namespace accessible from within the Worker at the variable name you specify. 576 | * ref: https://developers.cloudflare.com/workers/api/resource-bindings/ 577 | */ 578 | export interface CloudflareWorkerKV { 579 | /** 580 | * Read Value 581 | * 582 | * NAMESPACE.get(key, [type]) 583 | * 584 | * The method returns a promise you can await to get the value. 585 | * If the key is not found, the promise will resolve with the literal value null. 586 | * 587 | * Type can be any of: 588 | * "text" (default) 589 | * "json" 590 | * "arrayBuffer" 591 | * "stream" 592 | * 593 | * The most performant way to read a KV value is directly from a Worker. 594 | * Read performance will generally get better the higher your read volume. 595 | * 596 | * For simple values it often makes sense to use the default "text" type which 597 | * provides you with your value as a string. For convenience a "json" type is also 598 | * specified which will convert your value into an object before returning it to you. 599 | * For large values you can request a ReadableStream, and for binary values an ArrayBuffer. 600 | */ 601 | get(key: string, type?: 'text'): Promise; 602 | get(key: string, type: 'json'): Promise; 603 | get(key: string, type: 'arrayBuffer'): Promise; 604 | get(key: string, type: 'stream'): Promise; 605 | 606 | /** 607 | * Write Value 608 | * 609 | * You can write and delete values from a Worker, but you should note that it is an 610 | * eventually consistent data store. In practice, this means it is not uncommon for 611 | * an edge location to continue returning an old value for a key that has recently been 612 | * written in some other edge location. If, after considering that, it does make sense 613 | * to write values from your Worker, the API is: 614 | * 615 | * NAMESPACE.put(key, value, options?) 616 | * 617 | * The type is automatically inferred from value, and can be any of: 618 | * string 619 | * ReadableStream 620 | * ArrayBuffer 621 | * FormData 622 | * 623 | * All values are encrypted at rest with 256-bit AES-GCM, and only decrypted by the 624 | * process executing your Worker scripts. 625 | * 626 | * If you want the keys you write to be automatically deleted at some time in the future, 627 | * use the optional third parameter. It accepts an object with optional fields that allow 628 | * you to customize the behavior of the put. In particular, you can set either expiration 629 | * or expirationTtl, depending on how you would like to specify the key’s expiration time. 630 | * In other words, you’d run one of the two commands below to set an expiration when writing 631 | * a key from within a Worker: 632 | * 633 | * NAMESPACE.put(key, value, {expiration: secondsSinceEpoch}) 634 | * 635 | * NAMESPACE.put(key, value, {expirationTtl: secondsFromNow}) 636 | * 637 | * These assume that secondsSinceEpoch and secondsFromNow are variables defined elsewhere in 638 | * your Worker code. 639 | */ 640 | put( 641 | key: string, 642 | value: string | ReadableStream | ArrayBuffer | FormData, 643 | options?: CloudflareWorkerKVOptions, 644 | ): Promise; 645 | 646 | /** 647 | * Delete Value 648 | * 649 | * NAMESPACE.delete(key) 650 | * 651 | * As with all updates, deletes can take up to ten seconds to propagate globally. 652 | */ 653 | delete(key: string): Promise; 654 | 655 | /** 656 | * Listing Keys 657 | * 658 | * NAMESPACE.list({prefix?: string, limit?: number, cursor?: string}) 659 | * 660 | * The .list method returns a promise which resolves with a CloudflareWorkerKVList object: 661 | * 662 | * { 663 | * keys: [{ name: "foo", expiration: 1234}], 664 | * list_complete: false, 665 | * cursor: "6Ck1la0VxJ0djhidm1MdX2FyD" 666 | * } 667 | */ 668 | list( 669 | prefix?: string, 670 | limit?: number, 671 | cursor?: string, 672 | ): Promise; 673 | } 674 | 675 | /** 676 | * Cloudflare Worker KV Options 677 | * Worker KV accepts a third parameters to control the lifetime of the key 678 | * ref: https://developers.cloudflare.com/workers/kv/expiring-keys/ 679 | * 680 | * Many common uses of Workers KV involve writing keys that are only meant to be valid 681 | * for a certain amount of time. Rather than requiring applications to remember to delete 682 | * such data at the appropriate time, Workers KV offers the ability to create keys that 683 | * automatically expire, either at a particular point in time or after a certain amount of 684 | * time has passed since the key was last modified. 685 | */ 686 | export interface CloudflareWorkerKVOptions { 687 | /** 688 | * Set its “expiration”, using an absolute time specified in a number of seconds since the 689 | * UNIX epoch. For example, if you wanted a key to expire at 12:00AM UTC on April 1, 2019, 690 | * you would set the key’s expiration to 1554076800. 691 | */ 692 | expiration?: number; 693 | /** 694 | * Set its “expiration TTL” (time to live), using a relative number of seconds from the 695 | * current time. For example, if you wanted a key to expire 10 minutes after creating it, 696 | * you would set its expiration TTL to 600. 697 | */ 698 | expirationTtl?: number; 699 | } 700 | 701 | /** 702 | * Cloudflare Worker KV key list 703 | */ 704 | export interface CloudflareWorkerKVList { 705 | keys: { 706 | name: string; 707 | expiration?: number; 708 | }[]; 709 | list_complete: boolean; 710 | cursor: string; 711 | } 712 | -------------------------------------------------------------------------------- /packages/types-cloudflare-worker/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Basic Options */ 4 | "target": "ESNext", 5 | /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */ 6 | "module": "commonjs", 7 | /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */ 8 | "lib": [ 9 | "es5", 10 | "webworker" 11 | ], 12 | /* Specify library files to be included in the compilation. */ 13 | // "allowJs": true, /* Allow javascript files to be compiled. */ 14 | // "checkJs": true, /* Report errors in .js files. */ 15 | // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ 16 | "declaration": true, 17 | /* Generates corresponding '.d.ts' file. */ 18 | // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ 19 | // "sourceMap": true, /* Generates corresponding '.map' file. */ 20 | // "outFile": "./", /* Concatenate and emit output to single file. */ 21 | "outDir": ".", 22 | /* Redirect output structure to the directory. */ 23 | // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ 24 | // "composite": true, /* Enable project compilation */ 25 | // "removeComments": true, /* Do not emit comments to output. */ 26 | // "noEmit": true, /* Do not emit outputs. */ 27 | // "importHelpers": true, /* Import emit helpers from 'tslib'. */ 28 | // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ 29 | // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ 30 | /* Strict Type-Checking Options */ 31 | "strict": true, 32 | /* Enable all strict type-checking options. */ 33 | "noImplicitAny": true, 34 | /* Raise error on expressions and declarations with an implied 'any' type. */ 35 | "strictNullChecks": true, 36 | /* Enable strict null checks. */ 37 | "strictFunctionTypes": true, 38 | /* Enable strict checking of function types. */ 39 | "strictBindCallApply": true, 40 | /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ 41 | "strictPropertyInitialization": true, 42 | /* Enable strict checking of property initialization in classes. */ 43 | "noImplicitThis": true, 44 | /* Raise error on 'this' expressions with an implied 'any' type. */ 45 | "alwaysStrict": true, 46 | /* Parse in strict mode and emit "use strict" for each source file. */ 47 | /* Additional Checks */ 48 | "noUnusedLocals": true, 49 | /* Report errors on unused locals. */ 50 | "noUnusedParameters": true, 51 | /* Report errors on unused parameters. */ 52 | "noImplicitReturns": true, 53 | /* Report error when not all code paths in function return a value. */ 54 | "noFallthroughCasesInSwitch": true, 55 | /* Report errors for fallthrough cases in switch statement. */ 56 | /* Module Resolution Options */ 57 | // "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ 58 | // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ 59 | // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ 60 | // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ 61 | // "typeRoots": ["node_modules/@types"], 62 | /* List of folders to include type definitions from. */ 63 | // "types": [], /* Type declaration files to be included in compilation. */ 64 | // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ 65 | "esModuleInterop": true, 66 | /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ 67 | // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ 68 | /* Source Map Options */ 69 | // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ 70 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ 71 | // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ 72 | // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ 73 | /* Experimental Options */ 74 | // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ 75 | // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ 76 | }, 77 | "include": [ 78 | "src" 79 | ], 80 | "exclude": [ 81 | "dist" 82 | ] 83 | } 84 | -------------------------------------------------------------------------------- /scripts/publish.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | VERSION=$1 5 | OTP=$2 6 | 7 | pushd packages/cloudflare-worker-mock 8 | npm version $VERSION 9 | npm publish --otp=$OTP 10 | popd 11 | 12 | pushd packages/types-cloudflare-worker 13 | npm version $VERSION 14 | npm publish --otp=$OTP 15 | popd 16 | 17 | pushd packages/@udacity/types-service-worker-mock 18 | npm version $VERSION 19 | npm publish --otp=$OTP 20 | popd 21 | -------------------------------------------------------------------------------- /src/helloworker.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 Udacity, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | import CloudflareWorkerGlobalScope from 'types-cloudflare-worker'; 18 | declare var self: CloudflareWorkerGlobalScope; 19 | 20 | import HelloWorkerClass from './helloworkerclass'; 21 | 22 | self.addEventListener('fetch', (event: FetchEvent) => { 23 | const worker = new HelloWorkerClass(); 24 | event.respondWith(worker.handle(event)); 25 | }); 26 | -------------------------------------------------------------------------------- /src/helloworkerclass.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 Udacity, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // The class is separate file simply to show imports working 18 | import { CloudflareWorkerKV } from 'types-cloudflare-worker'; 19 | 20 | // Declare a Named KV in the global scope. ref: 21 | // https://developers.cloudflare.com/workers/kv/api/ 22 | 23 | // The name the KV is used to help you identify the namespace and must be unique 24 | // within your account for this demo, we use countryCodeKV to represent the KV 25 | // to store country code info. 26 | declare global { 27 | const countryCodeKV: CloudflareWorkerKV; 28 | } 29 | 30 | export class HelloWorkerClass { 31 | private responseInit = { 32 | headers: { 'Content-Type': 'application/json' }, 33 | status: 200, 34 | }; 35 | 36 | public async handle(event: FetchEvent) { 37 | if (typeof event.passThroughOnException === 'function') { 38 | event.passThroughOnException(); 39 | } 40 | const cache = caches.default; 41 | const request = event.request; 42 | 43 | let response = await cache.match(request); 44 | 45 | if (!response) { 46 | const originResponse = await fetch(request, { 47 | cf: { 48 | cacheKey: 'hello-world', 49 | minify: { 50 | html: true, 51 | }, 52 | }, 53 | }); 54 | let body = 'Hello '; 55 | 56 | if (originResponse.status === 200) { 57 | event.waitUntil(cache.put(request, originResponse)); 58 | body = await originResponse.text(); 59 | } 60 | const country = request.cf.country; 61 | countryCodeKV.put(country, '!', { expiration: 100 }); 62 | const countryCode = await countryCodeKV.get(country); 63 | 64 | response = new Response( 65 | `${body} ${request.cf.country} ${countryCode}!`, 66 | this.responseInit, 67 | ); 68 | } 69 | 70 | return response; 71 | } 72 | } 73 | export default HelloWorkerClass; 74 | -------------------------------------------------------------------------------- /test/helloworker.test.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 Udacity, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | /* 18 | * There are two options for using ServiceWorker types, both with hassles. We 19 | * are using the webworker library method instead of the types-serviceworker 20 | * package. 21 | * 22 | * Option 1: WebWorker library included with TypeScript 23 | * tsc --lib es5,webworker # or anything es5+ 24 | * 25 | * But it requires: 26 | * export default null; 27 | * declare var self: ServiceWorkerGlobalScope; 28 | * 29 | * ref: 30 | * https://github.com/Microsoft/TypeScript/issues/14877#issuecomment-340279293 31 | * 32 | * Option 2: types-serviceworker package 33 | * 34 | * src: 35 | * https://github.com/Microsoft/TypeScript/issues/11781#issuecomment-449617791 36 | * 37 | * types-serviceworker could be referenced in tsconfig.json, but that may lead 38 | * to confusion because: "If types is specified, only packages listed will be 39 | * included." 40 | * ref: 41 | * https://www.typescriptlang.org/docs/handbook/tsconfig-json.html 42 | */ 43 | 44 | import { 45 | CloudflareWorkerGlobalScope, 46 | CloudflareWorkerKVOptions, 47 | } from 'types-cloudflare-worker'; 48 | declare var self: CloudflareWorkerGlobalScope; 49 | 50 | import makeCloudflareWorkerEnv, { 51 | makeCloudflareWorkerKVEnv, 52 | makeCloudflareWorkerRequest, 53 | } from 'cloudflare-worker-mock'; 54 | 55 | describe('helloworker', () => { 56 | beforeEach(() => { 57 | // Merge the Cloudflare Worker Environment into the global scope. 58 | Object.assign(global, makeCloudflareWorkerEnv()); 59 | // Merge the named KV into the global scope 60 | Object.assign(global, makeCloudflareWorkerKVEnv('countryCodeKV')); 61 | // Clear all module imports. 62 | jest.resetModules(); 63 | // Import and init the Worker. 64 | jest.requireActual('../src/helloworker'); 65 | }); 66 | 67 | it('should add listeners', async () => { 68 | expect(self.listeners.get('fetch')).toBeDefined(); 69 | }); 70 | 71 | it('should return Hello US +1!', async () => { 72 | fetchMock.mockResponseOnce('Hello'); 73 | 74 | let putCacheCalled = false; 75 | // Mock the default put() implementation. 76 | // TODO: Make this cleaner. 77 | caches.default.put = ( 78 | _request: Request, 79 | _response: Response, 80 | ): Promise => { 81 | putCacheCalled = true; 82 | return Promise.resolve(undefined); 83 | }; 84 | 85 | // Setup mock responses for the KV put() and get(). 86 | let putKVCalled = false; 87 | countryCodeKV.put = ( 88 | _key: string, 89 | _value: string | ReadableStream | ArrayBuffer | FormData, 90 | _options?: CloudflareWorkerKVOptions, 91 | ): Promise => { 92 | putKVCalled = true; 93 | return Promise.resolve(); 94 | }; 95 | 96 | let getKVCalled = false; 97 | countryCodeKV.get = ( 98 | _key: string, 99 | _type?: 'text' | 'json' | 'arrayBuffer' | 'stream', 100 | ): Promise => { 101 | getKVCalled = true; 102 | return Promise.resolve('+1'); 103 | }; 104 | 105 | const request = makeCloudflareWorkerRequest('/path', { 106 | cf: { 107 | colo: 'SFO', 108 | country: 'US', 109 | tlsClientAuth: { 110 | certIssuerDN: 'Example', 111 | }, 112 | }, 113 | }); 114 | const response = await self.trigger('fetch', request); 115 | 116 | expect(fetchMock).toBeCalledTimes(1); 117 | expect(response.status).toBe(200); 118 | expect(await response.text()).toBe('Hello US +1!'); 119 | expect(putCacheCalled).toBe(true); 120 | expect(putKVCalled).toBe(true); 121 | expect(getKVCalled).toBe(true); 122 | }); 123 | }); 124 | -------------------------------------------------------------------------------- /test/setupJest.ts: -------------------------------------------------------------------------------- 1 | import { GlobalWithFetchMock } from 'jest-fetch-mock'; 2 | 3 | const customGlobal: GlobalWithFetchMock = 4 | global as unknown as GlobalWithFetchMock; 5 | /* tslint:disable-next-line:no-var-requires */ 6 | customGlobal.fetch = require('jest-fetch-mock'); 7 | customGlobal.fetchMock = customGlobal.fetch; 8 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Basic Options */ 4 | /* https://developers.cloudflare.com/workers/reference/ */ 5 | /* Cloudflare Workers use the V8 JavaScript engine from Google Chrome. The 6 | * Workers runtime is updated at least once a week, to at least the version 7 | * that is currently used by Chrome’s stable release. This means you can 8 | * safely use latest JavaScript features, with no need for “transpilers”. 9 | */ 10 | "target": "ESNext", 11 | /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */ 12 | "module": "commonjs", 13 | /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */ 14 | "lib": ["esnext", "webworker"], 15 | /* Specify library files to be included in the compilation. */ 16 | // "allowJs": true, /* Allow javascript files to be compiled. */ 17 | // "checkJs": true, /* Report errors in .js files. */ 18 | // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ 19 | // "declaration": true, /* Generates corresponding '.d.ts' file. */ 20 | // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ 21 | // "sourceMap": true, /* Generates corresponding '.map' file. */ 22 | // "outFile": "./", /* Concatenate and emit output to single file. */ 23 | "outDir": "./dist", 24 | /* Redirect output structure to the directory. */ 25 | // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ 26 | // "composite": true, /* Enable project compilation */ 27 | // "removeComments": true, /* Do not emit comments to output. */ 28 | // "noEmit": true, /* Do not emit outputs. */ 29 | // "importHelpers": true, /* Import emit helpers from 'tslib'. */ 30 | // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ 31 | // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ 32 | 33 | /* Strict Type-Checking Options */ 34 | "strict": true, 35 | /* Enable all strict type-checking options. */ 36 | "noImplicitAny": true, 37 | /* Raise error on expressions and declarations with an implied 'any' type. */ 38 | "strictNullChecks": true, 39 | /* Enable strict null checks. */ 40 | "strictFunctionTypes": true, 41 | /* Enable strict checking of function types. */ 42 | "strictBindCallApply": true, 43 | /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ 44 | "strictPropertyInitialization": true, 45 | /* Enable strict checking of property initialization in classes. */ 46 | "noImplicitThis": true, 47 | /* Raise error on 'this' expressions with an implied 'any' type. */ 48 | "alwaysStrict": true, 49 | /* Parse in strict mode and emit "use strict" for each source file. */ 50 | 51 | /* Additional Checks */ 52 | "noUnusedLocals": true, 53 | /* Report errors on unused locals. */ 54 | "noUnusedParameters": true, 55 | /* Report errors on unused parameters. */ 56 | "noImplicitReturns": true, 57 | /* Report error when not all code paths in function return a value. */ 58 | "noFallthroughCasesInSwitch": true, 59 | /* Report errors for fallthrough cases in switch statement. */ 60 | 61 | /* Module Resolution Options */ 62 | // "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ 63 | // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ 64 | // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ 65 | // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ 66 | // "typeRoots": ["node_modules/@types"], 67 | /* List of folders to include type definitions from. */ 68 | // "types": [], /* Type declaration files to be included in compilation. */ 69 | // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ 70 | "esModuleInterop": true, 71 | /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ 72 | // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ 73 | 74 | /* Source Map Options */ 75 | // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ 76 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ 77 | // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ 78 | // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ 79 | 80 | /* Experimental Options */ 81 | // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ 82 | // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ 83 | }, 84 | "include": [ 85 | "src/**/*", 86 | "test/**/*" 87 | ], 88 | "exclude": [ 89 | "demo" 90 | ] 91 | } 92 | -------------------------------------------------------------------------------- /tsconfig.tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Basic Options */ 4 | /* https://developers.cloudflare.com/workers/reference/ */ 5 | /* Cloudflare Workers use the V8 JavaScript engine from Google Chrome. The 6 | * Workers runtime is updated at least once a week, to at least the version 7 | * that is currently used by Chrome’s stable release. This means you can 8 | * safely use latest JavaScript features, with no need for “transpilers”. 9 | */ 10 | "target": "ESNext", 11 | /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */ 12 | "module": "commonjs", 13 | /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */ 14 | "lib": ["esnext", "webworker"], 15 | /* Specify library files to be included in the compilation. */ 16 | // "allowJs": true, /* Allow javascript files to be compiled. */ 17 | // "checkJs": true, /* Report errors in .js files. */ 18 | // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ 19 | // "declaration": true, /* Generates corresponding '.d.ts' file. */ 20 | // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ 21 | // "sourceMap": true, /* Generates corresponding '.map' file. */ 22 | // "outFile": "./", /* Concatenate and emit output to single file. */ 23 | "outDir": "./dist", 24 | /* Redirect output structure to the directory. */ 25 | // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ 26 | // "composite": true, /* Enable project compilation */ 27 | // "removeComments": true, /* Do not emit comments to output. */ 28 | // "noEmit": true, /* Do not emit outputs. */ 29 | // "importHelpers": true, /* Import emit helpers from 'tslib'. */ 30 | // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ 31 | // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ 32 | 33 | /* Strict Type-Checking Options */ 34 | "strict": true, 35 | /* Enable all strict type-checking options. */ 36 | "noImplicitAny": true, 37 | /* Raise error on expressions and declarations with an implied 'any' type. */ 38 | "strictNullChecks": true, 39 | /* Enable strict null checks. */ 40 | "strictFunctionTypes": true, 41 | /* Enable strict checking of function types. */ 42 | "strictBindCallApply": true, 43 | /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ 44 | "strictPropertyInitialization": true, 45 | /* Enable strict checking of property initialization in classes. */ 46 | "noImplicitThis": true, 47 | /* Raise error on 'this' expressions with an implied 'any' type. */ 48 | "alwaysStrict": true, 49 | /* Parse in strict mode and emit "use strict" for each source file. */ 50 | 51 | /* Additional Checks */ 52 | "noUnusedLocals": true, 53 | /* Report errors on unused locals. */ 54 | "noUnusedParameters": true, 55 | /* Report errors on unused parameters. */ 56 | "noImplicitReturns": true, 57 | /* Report error when not all code paths in function return a value. */ 58 | "noFallthroughCasesInSwitch": true, 59 | /* Report errors for fallthrough cases in switch statement. */ 60 | 61 | /* Module Resolution Options */ 62 | // "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ 63 | // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ 64 | // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ 65 | // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ 66 | // "typeRoots": ["node_modules/@types"], 67 | /* List of folders to include type definitions from. */ 68 | // "types": [], /* Type declaration files to be included in compilation. */ 69 | // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ 70 | "esModuleInterop": true, 71 | /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ 72 | // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ 73 | 74 | /* Source Map Options */ 75 | // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ 76 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ 77 | // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ 78 | // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ 79 | 80 | /* Experimental Options */ 81 | // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ 82 | // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ 83 | }, 84 | "include": [ 85 | "src/**/*", 86 | "packages/**/*", // THE ONLY DIFFERENCE VERSES tsconfig.json 87 | "test/**/*" 88 | ], 89 | "exclude": [ 90 | "demo" 91 | ] 92 | } 93 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "defaultSeverity": "warning", 3 | "extends": [ 4 | "tslint:recommended", 5 | "tslint-eslint-rules", 6 | "tslint-plugin-prettier", 7 | "tslint-config-prettier" 8 | ], 9 | "jsRules": {}, 10 | "rules": { 11 | "prettier": [true, { 12 | "singleQuote": true, 13 | "trailingComma": "all" 14 | }], 15 | "quotemark": [true, "single"], 16 | "interface-name": false, 17 | "variable-name": [true, "ban-keywords", "check-format", "allow-leading-underscore"] 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | 3 | module.exports = { 4 | entry: { 5 | 'helloworker': './src/helloworker.ts', 6 | }, 7 | /*devtool: 'inline-source-map',*/ 8 | module: { 9 | rules: [{ 10 | test: /\.tsx?$/, 11 | use: 'ts-loader', 12 | exclude: /node_modules/ 13 | }] 14 | }, 15 | resolve: { 16 | extensions: ['.ts', '.js'] 17 | }, 18 | output: { 19 | filename: '[name].js', 20 | path: path.resolve(__dirname, 'dist') 21 | } 22 | }; 23 | --------------------------------------------------------------------------------