├── .env.sample ├── .github ├── FUNDING.yml └── workflows │ ├── deploy-pages.yml │ └── deploy-worker.yml ├── .gitignore ├── LICENSE ├── README.md ├── app ├── .env.sample ├── .eslint.js ├── .gitignore ├── .prettierrc ├── .vscode │ └── extensions.json ├── README.md ├── index.html ├── package-lock.json ├── package.json ├── public │ └── favicon.ico ├── src │ ├── App.vue │ ├── assets │ │ └── logo.png │ ├── env.d.ts │ ├── main.ts │ ├── router │ │ └── index.ts │ ├── utils │ │ └── api.ts │ └── views │ │ ├── Article.vue │ │ ├── Articles.vue │ │ ├── Home.vue │ │ ├── NotFound.vue │ │ ├── People.vue │ │ └── Projects.vue ├── tsconfig.json ├── tsconfig.node.json └── vite.config.ts ├── package-lock.json ├── package.json ├── patches └── cfw+0.3.0.patch ├── tsconfig.json └── workers ├── .eslint.js ├── .prettierrc └── directus-cf-cache-worker ├── api.ts ├── assetStore.ts ├── cfw.js ├── index.ts ├── itemStore.ts └── webhook.ts /.env.sample: -------------------------------------------------------------------------------- 1 | CLOUDFLARE_ACCOUNTID=abcd1234abcd1234abcd1234abcd1234 2 | CLOUDFLARE_TOKEN=abcd1234abcd1234abcd1234abcd1234 3 | CLOUDFLARE_ZONEID=abcd1234abcd1234abcd1234abcd1234 4 | # Sample ENV for GitHub Actions 5 | # CLOUDFLARE_PAGES_WEBHOOK_URL=https://api.cloudflare.com/client/v4/pages/webhooks/deploy_hooks/abcd1234-abcd-1234-abcd-1234abcd1234 6 | 7 | DIRECTUS_ACCESS_TOKEN=JustAnotherSecretToken 8 | DIRECTUS_CF_CACHE_KV=abcd1234abcd1234abcd1234abcd1234 9 | DIRECTUS_SERVER_URL=https://directus.example.com 10 | DIRECTUS_WEBHOOK_SECRET=SomeSecret123 11 | 12 | WORKER_ROUTES=a.com/*,b.com/* -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [licitdev] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] -------------------------------------------------------------------------------- /.github/workflows/deploy-pages.yml: -------------------------------------------------------------------------------- 1 | name: Deploy to Cloudflare Pages 2 | 3 | on: 4 | workflow_dispatch: 5 | push: 6 | branches: 7 | - master 8 | - deploy 9 | paths: 10 | - app/** 11 | 12 | defaults: 13 | run: 14 | working-directory: app 15 | 16 | jobs: 17 | deploy: 18 | if: | 19 | github.ref_name == 'deploy' 20 | || (github.ref_name == 'master' && github.repository == 'licitdev/directus-cf-cache') 21 | runs-on: ubuntu-latest 22 | name: Deploy Page 23 | steps: 24 | - name: Invoke Deploy Master Hook 25 | uses: distributhor/workflow-webhook@v2 26 | env: 27 | webhook_url: ${{ secrets.CLOUDFLARE_PAGES_WEBHOOK_URL }} 28 | webhook_secret: "no_secret_required" -------------------------------------------------------------------------------- /.github/workflows/deploy-worker.yml: -------------------------------------------------------------------------------- 1 | name: Deploy to Cloudflare Workers 2 | 3 | on: 4 | workflow_dispatch: 5 | push: 6 | branches: 7 | - master 8 | paths: 9 | - workers/** 10 | 11 | jobs: 12 | deploy: 13 | runs-on: ubuntu-latest 14 | name: Deploy Worker 15 | steps: 16 | - uses: actions/checkout@v2 17 | - name: Set Up Node.js 18 | uses: actions/setup-node@v1 19 | with: 20 | node-version: "16.x" 21 | - run: npm install 22 | - run: npm run build 23 | env: 24 | CLOUDFLARE_ACCOUNTID: ${{ secrets.CLOUDFLARE_ACCOUNTID }} 25 | CLOUDFLARE_TOKEN: ${{ secrets.CLOUDFLARE_TOKEN }} 26 | CLOUDFLARE_ZONEID: ${{ secrets.CLOUDFLARE_ZONEID }} 27 | DIRECTUS_ACCESS_TOKEN: ${{ secrets.DIRECTUS_ACCESS_TOKEN }} 28 | DIRECTUS_CF_CACHE_KV: ${{ secrets.DIRECTUS_CF_CACHE_KV }} 29 | DIRECTUS_SERVER_URL: ${{ secrets.DIRECTUS_SERVER_URL }} 30 | DIRECTUS_WEBHOOK_SECRET: ${{ secrets.DIRECTUS_WEBHOOK_SECRET }} 31 | WORKER_ROUTES: ${{ secrets.WORKER_ROUTES }} 32 | - run: npm run deploy -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_Store 3 | *.log 4 | 5 | /build 6 | .env -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 ian (licitdev) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # directus-cf-cache 2 | 3 | [![GitHub license](https://img.shields.io/github/license/licitdev/directus-cf-cache.svg)](https://github.com/licitdev/directus-cf-cache/blob/master/LICENSE) 4 | ![Deploy to Cloudflare Pages](https://github.com/licitdev/directus-cf-cache/workflows/Deploy%20to%20Cloudflare%20Pages/badge.svg) 5 | ![Deploy to Cloudflare Workers](https://github.com/licitdev/directus-cf-cache/workflows/Deploy%20to%20Cloudflare%20Workers/badge.svg) 6 | 7 | ## About 8 | 9 | Cache and limit direct access to the data managed on your [Directus](https://directus.io) instance, powered by [Cloudflare Workers](https://workers.cloudflare.com), [Workers KV](https://developers.cloudflare.com/workers/runtime-apis/kv) and [Cloudflare Pages](https://pages.cloudflare.com). 10 | 11 | ## Features 12 | 13 | - Always available API with live updates[^1]. 14 | - Origin Priority mode to serve content from your Directus instance, with fallback to the KV cache when unavailable. 15 | - Cache Priority mode to serve content from the KV cache, with fallback to your Directus instance when unavailable. 16 | - Origin Only mode to only serve content from your Directus instance. 17 | - Cache Only mode to only serve content from the KV cache. 18 | - Caching of image assets. 19 | - Automatic updating of cache upon webhook trigger. 20 | - Preset requests to prevent user from the tampering of query parameters. 21 | - Full support of Directus [Global Query Parameters](https://docs.directus.io/reference/query/). 22 | - Demo [Vue](https://vuejs.org/) web application to showcase functionality. 23 | 24 | ## Demo 25 | 26 | 1. Head over to the Directus instance at [https://cztkclnq.directus.app](https://cztkclnq.directus.app/). 27 | 2. Login with the following credentials. 28 | 29 | - Email: `visitor@example.com` 30 | - Password: `abcd1234` 31 | 32 | 3. Create > update > delete your content. 33 | 34 | > Permissions have been set to prevent changes to certain items. 35 | 36 | 4. Check out your updates at [https://directus-cf-cache.pages.dev](https://directus-cf-cache.pages.dev/). 37 | 38 | https://user-images.githubusercontent.com/26413686/172551155-2adc79e7-fcef-43c0-b46a-2f69667cfa80.mov 39 | 40 | ## Cloudflare Features Used 41 | 42 | ### Cloudflare Workers 43 | 44 | Fetching and storing content into Workers KV. 45 | 46 | Serve requests either from the origin or the KV cache. 47 | 48 | ### Workers KV 49 | 50 | Store cached content retrieved from Directus. 51 | 52 | ### Cloudflare Pages 53 | 54 | Host the demo [Vue 3](https://v3.vuejs.org) web application. 55 | 56 | ## Installation Guide 57 | 58 | ### Fork directus-cf-cache 59 | 60 | Create a [Fork](https://github.com/licitdev/directus-cf-cache/fork) of this GitHub repository as the deployments are pushed via GitHub Actions. 61 | 62 | ### Set up Cloudflare Workers 63 | 64 | 1. [Sign up](https://dash.cloudflare.com/sign-up/workers) for a Cloudflare Workers account. 65 | 2. Copy the **Account ID** shown in the Workers page somewhere. 66 | 3. Copy the **Subdomain** shown in the Workers page somewhere. 67 | 4. Head over to KV tab, add a new namespace and copy the **Namespace ID** somewhere. 68 | 5. Head over to [API Tokens](https://dash.cloudflare.com/profile/api-tokens) and create a new Custom API Token with Permission of "Account/Worker Scripts/Edit". 69 | 6. Copy the **API Key** somewhere, you will require it later. 70 | 71 | ### Set up Directus 72 | 73 | 1. If you already have a Directus instance, self-hosted or cloud, skip to point 5. 74 | 2. [Sign up](https://directus.cloud) for a Directus Cloud account. 75 | 3. Create a new Project. 76 | 4. Check your email for the login credentials. 77 | 5. Login to your Directus instance. 78 | 6. Head over to Settings > Data Model. 79 | 7. Set up all your required collections, in the demo there are `articles`, `projects` and `people`. 80 | 8. Create a new collection with the following settings: 81 | 1. Set name as `cf_cache_options` 82 | 2. Check the singleton checkbox 83 | 3. Skip the configuration of other parameters and save. 84 | 9. Click on Data Model. 85 | 10. Create a new collection with the following settings 86 | 1. Set name as `global_query_params` 87 | 2. Skip the configuration of other parameters and save. 88 | 11. Create the following fields in `global_query_params`: 89 | 1. `description` with `string` type 90 | 2. `operation` with `string` type (either `list` or `get`) 91 | 3. `collection` with `string` type (collection names that you want to cache) 92 | 4. `key` with `string` type (cache key to differentiate between presets) 93 | 5. `enabled` with `boolean` 94 | 6. `query_params` with `json` (the query that will be sent with the request) 95 | 7. `file_paths` with `csv` (the paths containing files from the result) 96 | 8. `sort` with `integer` to be used for sorting 97 | 12. Create the following fields in `cf_cache_options`: 98 | 1. `cache_mode` with `string` (`origin_priority`,`cache_priority`,`origin_only`,`cache_only`) 99 | 2. `preset_requests` with `One to Many Relationship` on `global_query_params` with a foreign key of `cf_cache_option`. 100 | 3. Continue in advanced field creation mode. 101 | 4. Click on `Relationship` and set the sort field as `sort` to enable sorting. 102 | 5. Skip the configuration of other parameters and save. 103 | 13. Head over to Settings > Data Model 104 | 1. Click on the kebab menu of `global_query_params`. 105 | 2. Select Make Collection Hidden. 106 | 14. Head over to Settings > Webhooks 107 | 1. Create a new webhook and give it a name. 108 | 2. Set the URL as your Cloudflare Worker webhook endpoint. 109 | 3. Add a new request header `Secret` with your **secret** and copy this value somewhere. 110 | 4. Toggle all actions to be turned on (create, update, delete). 111 | 5. Select the collections that you wish to cache including `Cf Cache Options` 112 | 15. Head over to Settings > Roles & Permissions 113 | 1. Create a new role and uncheck `App Access`. 114 | 2. Allow `All Access` for `Read` column of the tables you wish to cache including `cf_cache_options` 115 | 3. Create a new user, enter a secure **token** and copy this value somewhere. 116 | 4. Save all changes. 117 | 16. Head over to Content > Cf Cache Options and configure your required caching settings. 118 | > **Demo `cf_cache_options` configuration** 119 | > 120 | > ![image](https://user-images.githubusercontent.com/26413686/172445743-18156d31-54c7-4b79-8d71-9cf91c8253e0.png) 121 | > 122 | > **Demo `preset_requests` configuration** 123 | > 124 | > ![image](https://user-images.githubusercontent.com/26413686/172446025-98593f2c-367a-4229-babb-c2ea0a25475e.png) 125 | 126 | ### Set up Cloudflare Pages 127 | 128 | 1. [Sign up](https://dash.cloudflare.com/sign-up/pages) for a Cloudflare Pages account. 129 | 2. Create a new project, selecting the fork of `directus-cf-cache` in your GitHub account. 130 | 3. Set the build output directory as `dist`. 131 | 4. Set the root directory path as `app`. 132 | 5. Create the following environment variables: 133 | 6. `VITE_DIRECTUS_CF_CACHE_URL` with your Cloudflare Worker URL such as `https://directus-cf-cache..workers.dev`. 134 | 7. After the first build is completed, pause the Automatic git deployments. 135 | 8. Add a new deploy hook, copy the **Deploy hook URL** somewhere. 136 | 137 | ### Configure GitHub Actions 138 | 139 | 1. Open the forked GitHub project > Settings > Secrets. 140 | 2. Create the following repository secrets: 141 | 142 | > You may refer to [.env.sample](https://github.com/licitdev/directus-cf-cache/blob/master/.env.sample) for sample values. 143 | 144 | 1. `CLOUDFLARE_ACCOUNTID` with the **Account ID**. 145 | 2. `CLOUDFLARE_PAGES_WEBHOOK_URL` with the **Deploy hook URL**. 146 | 3. `CLOUDFLARE_TOKEN` with the **API Key**. 147 | 4. `CLOUDFLARE_ZONEID` with the **Zone ID**, empty string unless you are using a custom domain. 148 | 5. `DIRECTUS_ACCESS_TOKEN` with the **token**. 149 | 6. `DIRECTUS_CF_CACHE_KV` with the **Namespace ID**. 150 | 7. `DIRECTUS_SERVER_URL` with the root URL of your Directus instance. 151 | 8. `DIRECTUS_WEBHOOK_SECRET` with the **secret**. 152 | 9. `WORKER_ROUTES` with your custom domain or the workers.dev route. 153 | 154 | 3. Click on the Actions tab, manually run the workflows. 155 | 156 | ## Upcoming Features 157 | 158 | - Paging of `list` results to handle bigger datasets 159 | - Integration with Cloudflare R2 for assets storage 160 | - Utilize Directus Flows instead of Webhooks for a "push" approach 161 | - Cache management API to manage content stored in the KV cache 162 | - Have an idea? [Open a discussion](https://github.com/licitdev/directus-cf-cache/discussions/new?category=ideas)! 163 | 164 | ## 165 | 166 | Developed by [licitdev](https://github.com/licitdev) 167 | 168 | [^1]: Changes may take up to 60 seconds to propagate globally when the request is served from the KV cache instead of the origin [https://developers.cloudflare.com/workers/learning/how-kv-works](https://developers.cloudflare.com/workers/learning/how-kv-works) 169 | -------------------------------------------------------------------------------- /app/.env.sample: -------------------------------------------------------------------------------- 1 | VITE_DIRECTUS_CF_CACHE_URL=https://a.com -------------------------------------------------------------------------------- /app/.eslint.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | node: true, 4 | es2020: true, 5 | }, 6 | extends: ['prettier'], 7 | rules: {}, 8 | }; 9 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /app/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "useTabs": true, 4 | "printWidth": 120, 5 | "proseWrap": "always", 6 | "semi": true 7 | } -------------------------------------------------------------------------------- /app/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": ["Vue.volar"] 3 | } 4 | -------------------------------------------------------------------------------- /app/README.md: -------------------------------------------------------------------------------- 1 | # directus-cf-cache-app -------------------------------------------------------------------------------- /app/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Demo Vue App 8 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /app/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "directus-cf-cache-app", 3 | "version": "0.0.0", 4 | "lockfileVersion": 2, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "directus-cf-cache-app", 9 | "version": "0.0.0", 10 | "dependencies": { 11 | "vue": "^3.2.25", 12 | "vue-router": "^4.0.15", 13 | "vue-safe-html": "^2.0.0", 14 | "vue3-carousel": "^0.1.40" 15 | }, 16 | "devDependencies": { 17 | "@vitejs/plugin-vue": "^2.3.3", 18 | "typescript": "^4.5.4", 19 | "vite": "^2.9.16", 20 | "vue-tsc": "^0.34.7" 21 | } 22 | }, 23 | "node_modules/@babel/parser": { 24 | "version": "7.18.4", 25 | "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.18.4.tgz", 26 | "integrity": "sha512-FDge0dFazETFcxGw/EXzOkN8uJp0PC7Qbm+Pe9T+av2zlBpOgunFHkQPPn+eRuClU73JF+98D531UgayY89tow==", 27 | "bin": { 28 | "parser": "bin/babel-parser.js" 29 | }, 30 | "engines": { 31 | "node": ">=6.0.0" 32 | } 33 | }, 34 | "node_modules/@vitejs/plugin-vue": { 35 | "version": "2.3.3", 36 | "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-2.3.3.tgz", 37 | "integrity": "sha512-SmQLDyhz+6lGJhPELsBdzXGc+AcaT8stgkbiTFGpXPe8Tl1tJaBw1A6pxDqDuRsVkD8uscrkx3hA7QDOoKYtyw==", 38 | "dev": true, 39 | "engines": { 40 | "node": ">=12.0.0" 41 | }, 42 | "peerDependencies": { 43 | "vite": "^2.5.10", 44 | "vue": "^3.2.25" 45 | } 46 | }, 47 | "node_modules/@volar/code-gen": { 48 | "version": "0.34.17", 49 | "resolved": "https://registry.npmjs.org/@volar/code-gen/-/code-gen-0.34.17.tgz", 50 | "integrity": "sha512-rHR7BA71BJ/4S7xUOPMPiB7uk6iU9oTWpEMZxFi5VGC9iJmDncE82WzU5iYpcbOBCVHsOjMh0+5CGMgdO6SaPA==", 51 | "dev": true, 52 | "dependencies": { 53 | "@volar/source-map": "0.34.17" 54 | } 55 | }, 56 | "node_modules/@volar/source-map": { 57 | "version": "0.34.17", 58 | "resolved": "https://registry.npmjs.org/@volar/source-map/-/source-map-0.34.17.tgz", 59 | "integrity": "sha512-3yn1IMXJGGWB/G817/VFlFMi8oh5pmE7VzUqvgMZMrppaZpKj6/juvJIEiXNxRsgWc0RxIO8OSp4htdPUg1Raw==", 60 | "dev": true 61 | }, 62 | "node_modules/@volar/vue-code-gen": { 63 | "version": "0.34.17", 64 | "resolved": "https://registry.npmjs.org/@volar/vue-code-gen/-/vue-code-gen-0.34.17.tgz", 65 | "integrity": "sha512-17pzcK29fyFWUc+C82J3JYSnA+jy3QNrIldb9kPaP9Itbik05ZjEIyEue9FjhgIAuHeYSn4LDM5s6nGjxyfhsQ==", 66 | "dev": true, 67 | "dependencies": { 68 | "@volar/code-gen": "0.34.17", 69 | "@volar/source-map": "0.34.17", 70 | "@vue/compiler-core": "^3.2.36", 71 | "@vue/compiler-dom": "^3.2.36", 72 | "@vue/shared": "^3.2.36" 73 | } 74 | }, 75 | "node_modules/@volar/vue-typescript": { 76 | "version": "0.34.17", 77 | "resolved": "https://registry.npmjs.org/@volar/vue-typescript/-/vue-typescript-0.34.17.tgz", 78 | "integrity": "sha512-U0YSVIBPRWVPmgJHNa4nrfq88+oS+tmyZNxmnfajIw9A/GOGZQiKXHC0k09SVvbYXlsjgJ6NIjhm9NuAhGRQjg==", 79 | "dev": true, 80 | "dependencies": { 81 | "@volar/code-gen": "0.34.17", 82 | "@volar/source-map": "0.34.17", 83 | "@volar/vue-code-gen": "0.34.17", 84 | "@vue/compiler-sfc": "^3.2.36", 85 | "@vue/reactivity": "^3.2.36" 86 | } 87 | }, 88 | "node_modules/@vue/compiler-core": { 89 | "version": "3.2.37", 90 | "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.2.37.tgz", 91 | "integrity": "sha512-81KhEjo7YAOh0vQJoSmAD68wLfYqJvoiD4ulyedzF+OEk/bk6/hx3fTNVfuzugIIaTrOx4PGx6pAiBRe5e9Zmg==", 92 | "dependencies": { 93 | "@babel/parser": "^7.16.4", 94 | "@vue/shared": "3.2.37", 95 | "estree-walker": "^2.0.2", 96 | "source-map": "^0.6.1" 97 | } 98 | }, 99 | "node_modules/@vue/compiler-dom": { 100 | "version": "3.2.37", 101 | "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.2.37.tgz", 102 | "integrity": "sha512-yxJLH167fucHKxaqXpYk7x8z7mMEnXOw3G2q62FTkmsvNxu4FQSu5+3UMb+L7fjKa26DEzhrmCxAgFLLIzVfqQ==", 103 | "dependencies": { 104 | "@vue/compiler-core": "3.2.37", 105 | "@vue/shared": "3.2.37" 106 | } 107 | }, 108 | "node_modules/@vue/compiler-sfc": { 109 | "version": "3.2.37", 110 | "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.2.37.tgz", 111 | "integrity": "sha512-+7i/2+9LYlpqDv+KTtWhOZH+pa8/HnX/905MdVmAcI/mPQOBwkHHIzrsEsucyOIZQYMkXUiTkmZq5am/NyXKkg==", 112 | "dependencies": { 113 | "@babel/parser": "^7.16.4", 114 | "@vue/compiler-core": "3.2.37", 115 | "@vue/compiler-dom": "3.2.37", 116 | "@vue/compiler-ssr": "3.2.37", 117 | "@vue/reactivity-transform": "3.2.37", 118 | "@vue/shared": "3.2.37", 119 | "estree-walker": "^2.0.2", 120 | "magic-string": "^0.25.7", 121 | "postcss": "^8.1.10", 122 | "source-map": "^0.6.1" 123 | } 124 | }, 125 | "node_modules/@vue/compiler-ssr": { 126 | "version": "3.2.37", 127 | "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.2.37.tgz", 128 | "integrity": "sha512-7mQJD7HdXxQjktmsWp/J67lThEIcxLemz1Vb5I6rYJHR5vI+lON3nPGOH3ubmbvYGt8xEUaAr1j7/tIFWiEOqw==", 129 | "dependencies": { 130 | "@vue/compiler-dom": "3.2.37", 131 | "@vue/shared": "3.2.37" 132 | } 133 | }, 134 | "node_modules/@vue/devtools-api": { 135 | "version": "6.1.4", 136 | "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.1.4.tgz", 137 | "integrity": "sha512-IiA0SvDrJEgXvVxjNkHPFfDx6SXw0b/TUkqMcDZWNg9fnCAHbTpoo59YfJ9QLFkwa3raau5vSlRVzMSLDnfdtQ==" 138 | }, 139 | "node_modules/@vue/reactivity": { 140 | "version": "3.2.37", 141 | "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.2.37.tgz", 142 | "integrity": "sha512-/7WRafBOshOc6m3F7plwzPeCu/RCVv9uMpOwa/5PiY1Zz+WLVRWiy0MYKwmg19KBdGtFWsmZ4cD+LOdVPcs52A==", 143 | "dependencies": { 144 | "@vue/shared": "3.2.37" 145 | } 146 | }, 147 | "node_modules/@vue/reactivity-transform": { 148 | "version": "3.2.37", 149 | "resolved": "https://registry.npmjs.org/@vue/reactivity-transform/-/reactivity-transform-3.2.37.tgz", 150 | "integrity": "sha512-IWopkKEb+8qpu/1eMKVeXrK0NLw9HicGviJzhJDEyfxTR9e1WtpnnbYkJWurX6WwoFP0sz10xQg8yL8lgskAZg==", 151 | "dependencies": { 152 | "@babel/parser": "^7.16.4", 153 | "@vue/compiler-core": "3.2.37", 154 | "@vue/shared": "3.2.37", 155 | "estree-walker": "^2.0.2", 156 | "magic-string": "^0.25.7" 157 | } 158 | }, 159 | "node_modules/@vue/runtime-core": { 160 | "version": "3.2.37", 161 | "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.2.37.tgz", 162 | "integrity": "sha512-JPcd9kFyEdXLl/i0ClS7lwgcs0QpUAWj+SKX2ZC3ANKi1U4DOtiEr6cRqFXsPwY5u1L9fAjkinIdB8Rz3FoYNQ==", 163 | "dependencies": { 164 | "@vue/reactivity": "3.2.37", 165 | "@vue/shared": "3.2.37" 166 | } 167 | }, 168 | "node_modules/@vue/runtime-dom": { 169 | "version": "3.2.37", 170 | "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.2.37.tgz", 171 | "integrity": "sha512-HimKdh9BepShW6YozwRKAYjYQWg9mQn63RGEiSswMbW+ssIht1MILYlVGkAGGQbkhSh31PCdoUcfiu4apXJoPw==", 172 | "dependencies": { 173 | "@vue/runtime-core": "3.2.37", 174 | "@vue/shared": "3.2.37", 175 | "csstype": "^2.6.8" 176 | } 177 | }, 178 | "node_modules/@vue/server-renderer": { 179 | "version": "3.2.37", 180 | "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.2.37.tgz", 181 | "integrity": "sha512-kLITEJvaYgZQ2h47hIzPh2K3jG8c1zCVbp/o/bzQOyvzaKiCquKS7AaioPI28GNxIsE/zSx+EwWYsNxDCX95MA==", 182 | "dependencies": { 183 | "@vue/compiler-ssr": "3.2.37", 184 | "@vue/shared": "3.2.37" 185 | }, 186 | "peerDependencies": { 187 | "vue": "3.2.37" 188 | } 189 | }, 190 | "node_modules/@vue/shared": { 191 | "version": "3.2.37", 192 | "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.2.37.tgz", 193 | "integrity": "sha512-4rSJemR2NQIo9Klm1vabqWjD8rs/ZaJSzMxkMNeJS6lHiUjjUeYFbooN19NgFjztubEKh3WlZUeOLVdbbUWHsw==" 194 | }, 195 | "node_modules/csstype": { 196 | "version": "2.6.20", 197 | "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.20.tgz", 198 | "integrity": "sha512-/WwNkdXfckNgw6S5R125rrW8ez139lBHWouiBvX8dfMFtcn6V81REDqnH7+CRpRipfYlyU1CmOnOxrmGcFOjeA==" 199 | }, 200 | "node_modules/esbuild": { 201 | "version": "0.14.42", 202 | "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.42.tgz", 203 | "integrity": "sha512-V0uPZotCEHokJdNqyozH6qsaQXqmZEOiZWrXnds/zaH/0SyrIayRXWRB98CENO73MIZ9T3HBIOsmds5twWtmgw==", 204 | "dev": true, 205 | "hasInstallScript": true, 206 | "bin": { 207 | "esbuild": "bin/esbuild" 208 | }, 209 | "engines": { 210 | "node": ">=12" 211 | }, 212 | "optionalDependencies": { 213 | "esbuild-android-64": "0.14.42", 214 | "esbuild-android-arm64": "0.14.42", 215 | "esbuild-darwin-64": "0.14.42", 216 | "esbuild-darwin-arm64": "0.14.42", 217 | "esbuild-freebsd-64": "0.14.42", 218 | "esbuild-freebsd-arm64": "0.14.42", 219 | "esbuild-linux-32": "0.14.42", 220 | "esbuild-linux-64": "0.14.42", 221 | "esbuild-linux-arm": "0.14.42", 222 | "esbuild-linux-arm64": "0.14.42", 223 | "esbuild-linux-mips64le": "0.14.42", 224 | "esbuild-linux-ppc64le": "0.14.42", 225 | "esbuild-linux-riscv64": "0.14.42", 226 | "esbuild-linux-s390x": "0.14.42", 227 | "esbuild-netbsd-64": "0.14.42", 228 | "esbuild-openbsd-64": "0.14.42", 229 | "esbuild-sunos-64": "0.14.42", 230 | "esbuild-windows-32": "0.14.42", 231 | "esbuild-windows-64": "0.14.42", 232 | "esbuild-windows-arm64": "0.14.42" 233 | } 234 | }, 235 | "node_modules/esbuild-android-64": { 236 | "version": "0.14.42", 237 | "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.14.42.tgz", 238 | "integrity": "sha512-P4Y36VUtRhK/zivqGVMqhptSrFILAGlYp0Z8r9UQqHJ3iWztRCNWnlBzD9HRx0DbueXikzOiwyOri+ojAFfW6A==", 239 | "cpu": [ 240 | "x64" 241 | ], 242 | "dev": true, 243 | "optional": true, 244 | "os": [ 245 | "android" 246 | ], 247 | "engines": { 248 | "node": ">=12" 249 | } 250 | }, 251 | "node_modules/esbuild-android-arm64": { 252 | "version": "0.14.42", 253 | "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.42.tgz", 254 | "integrity": "sha512-0cOqCubq+RWScPqvtQdjXG3Czb3AWI2CaKw3HeXry2eoA2rrPr85HF7IpdU26UWdBXgPYtlTN1LUiuXbboROhg==", 255 | "cpu": [ 256 | "arm64" 257 | ], 258 | "dev": true, 259 | "optional": true, 260 | "os": [ 261 | "android" 262 | ], 263 | "engines": { 264 | "node": ">=12" 265 | } 266 | }, 267 | "node_modules/esbuild-darwin-64": { 268 | "version": "0.14.42", 269 | "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.42.tgz", 270 | "integrity": "sha512-ipiBdCA3ZjYgRfRLdQwP82rTiv/YVMtW36hTvAN5ZKAIfxBOyPXY7Cejp3bMXWgzKD8B6O+zoMzh01GZsCuEIA==", 271 | "cpu": [ 272 | "x64" 273 | ], 274 | "dev": true, 275 | "optional": true, 276 | "os": [ 277 | "darwin" 278 | ], 279 | "engines": { 280 | "node": ">=12" 281 | } 282 | }, 283 | "node_modules/esbuild-darwin-arm64": { 284 | "version": "0.14.42", 285 | "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.42.tgz", 286 | "integrity": "sha512-bU2tHRqTPOaoH/4m0zYHbFWpiYDmaA0gt90/3BMEFaM0PqVK/a6MA2V/ypV5PO0v8QxN6gH5hBPY4YJ2lopXgA==", 287 | "cpu": [ 288 | "arm64" 289 | ], 290 | "dev": true, 291 | "optional": true, 292 | "os": [ 293 | "darwin" 294 | ], 295 | "engines": { 296 | "node": ">=12" 297 | } 298 | }, 299 | "node_modules/esbuild-freebsd-64": { 300 | "version": "0.14.42", 301 | "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.42.tgz", 302 | "integrity": "sha512-75h1+22Ivy07+QvxHyhVqOdekupiTZVLN1PMwCDonAqyXd8TVNJfIRFrdL8QmSJrOJJ5h8H1I9ETyl2L8LQDaw==", 303 | "cpu": [ 304 | "x64" 305 | ], 306 | "dev": true, 307 | "optional": true, 308 | "os": [ 309 | "freebsd" 310 | ], 311 | "engines": { 312 | "node": ">=12" 313 | } 314 | }, 315 | "node_modules/esbuild-freebsd-arm64": { 316 | "version": "0.14.42", 317 | "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.42.tgz", 318 | "integrity": "sha512-W6Jebeu5TTDQMJUJVarEzRU9LlKpNkPBbjqSu+GUPTHDCly5zZEQq9uHkmHHl7OKm+mQ2zFySN83nmfCeZCyNA==", 319 | "cpu": [ 320 | "arm64" 321 | ], 322 | "dev": true, 323 | "optional": true, 324 | "os": [ 325 | "freebsd" 326 | ], 327 | "engines": { 328 | "node": ">=12" 329 | } 330 | }, 331 | "node_modules/esbuild-linux-32": { 332 | "version": "0.14.42", 333 | "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.42.tgz", 334 | "integrity": "sha512-Ooy/Bj+mJ1z4jlWcK5Dl6SlPlCgQB9zg1UrTCeY8XagvuWZ4qGPyYEWGkT94HUsRi2hKsXvcs6ThTOjBaJSMfg==", 335 | "cpu": [ 336 | "ia32" 337 | ], 338 | "dev": true, 339 | "optional": true, 340 | "os": [ 341 | "linux" 342 | ], 343 | "engines": { 344 | "node": ">=12" 345 | } 346 | }, 347 | "node_modules/esbuild-linux-64": { 348 | "version": "0.14.42", 349 | "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.42.tgz", 350 | "integrity": "sha512-2L0HbzQfbTuemUWfVqNIjOfaTRt9zsvjnme6lnr7/MO9toz/MJ5tZhjqrG6uDWDxhsaHI2/nsDgrv8uEEN2eoA==", 351 | "cpu": [ 352 | "x64" 353 | ], 354 | "dev": true, 355 | "optional": true, 356 | "os": [ 357 | "linux" 358 | ], 359 | "engines": { 360 | "node": ">=12" 361 | } 362 | }, 363 | "node_modules/esbuild-linux-arm": { 364 | "version": "0.14.42", 365 | "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.42.tgz", 366 | "integrity": "sha512-STq69yzCMhdRaWnh29UYrLSr/qaWMm/KqwaRF1pMEK7kDiagaXhSL1zQGXbYv94GuGY/zAwzK98+6idCMUOOCg==", 367 | "cpu": [ 368 | "arm" 369 | ], 370 | "dev": true, 371 | "optional": true, 372 | "os": [ 373 | "linux" 374 | ], 375 | "engines": { 376 | "node": ">=12" 377 | } 378 | }, 379 | "node_modules/esbuild-linux-arm64": { 380 | "version": "0.14.42", 381 | "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.42.tgz", 382 | "integrity": "sha512-c3Ug3e9JpVr8jAcfbhirtpBauLxzYPpycjWulD71CF6ZSY26tvzmXMJYooQ2YKqDY4e/fPu5K8bm7MiXMnyxuA==", 383 | "cpu": [ 384 | "arm64" 385 | ], 386 | "dev": true, 387 | "optional": true, 388 | "os": [ 389 | "linux" 390 | ], 391 | "engines": { 392 | "node": ">=12" 393 | } 394 | }, 395 | "node_modules/esbuild-linux-mips64le": { 396 | "version": "0.14.42", 397 | "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.42.tgz", 398 | "integrity": "sha512-QuvpHGbYlkyXWf2cGm51LBCHx6eUakjaSrRpUqhPwjh/uvNUYvLmz2LgPTTPwCqaKt0iwL+OGVL0tXA5aDbAbg==", 399 | "cpu": [ 400 | "mips64el" 401 | ], 402 | "dev": true, 403 | "optional": true, 404 | "os": [ 405 | "linux" 406 | ], 407 | "engines": { 408 | "node": ">=12" 409 | } 410 | }, 411 | "node_modules/esbuild-linux-ppc64le": { 412 | "version": "0.14.42", 413 | "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.42.tgz", 414 | "integrity": "sha512-8ohIVIWDbDT+i7lCx44YCyIRrOW1MYlks9fxTo0ME2LS/fxxdoJBwHWzaDYhjvf8kNpA+MInZvyOEAGoVDrMHg==", 415 | "cpu": [ 416 | "ppc64" 417 | ], 418 | "dev": true, 419 | "optional": true, 420 | "os": [ 421 | "linux" 422 | ], 423 | "engines": { 424 | "node": ">=12" 425 | } 426 | }, 427 | "node_modules/esbuild-linux-riscv64": { 428 | "version": "0.14.42", 429 | "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.42.tgz", 430 | "integrity": "sha512-DzDqK3TuoXktPyG1Lwx7vhaF49Onv3eR61KwQyxYo4y5UKTpL3NmuarHSIaSVlTFDDpcIajCDwz5/uwKLLgKiQ==", 431 | "cpu": [ 432 | "riscv64" 433 | ], 434 | "dev": true, 435 | "optional": true, 436 | "os": [ 437 | "linux" 438 | ], 439 | "engines": { 440 | "node": ">=12" 441 | } 442 | }, 443 | "node_modules/esbuild-linux-s390x": { 444 | "version": "0.14.42", 445 | "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.42.tgz", 446 | "integrity": "sha512-YFRhPCxl8nb//Wn6SiS5pmtplBi4z9yC2gLrYoYI/tvwuB1jldir9r7JwAGy1Ck4D7sE7wBN9GFtUUX/DLdcEQ==", 447 | "cpu": [ 448 | "s390x" 449 | ], 450 | "dev": true, 451 | "optional": true, 452 | "os": [ 453 | "linux" 454 | ], 455 | "engines": { 456 | "node": ">=12" 457 | } 458 | }, 459 | "node_modules/esbuild-netbsd-64": { 460 | "version": "0.14.42", 461 | "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.42.tgz", 462 | "integrity": "sha512-QYSD2k+oT9dqB/4eEM9c+7KyNYsIPgzYOSrmfNGDIyJrbT1d+CFVKvnKahDKNJLfOYj8N4MgyFaU9/Ytc6w5Vw==", 463 | "cpu": [ 464 | "x64" 465 | ], 466 | "dev": true, 467 | "optional": true, 468 | "os": [ 469 | "netbsd" 470 | ], 471 | "engines": { 472 | "node": ">=12" 473 | } 474 | }, 475 | "node_modules/esbuild-openbsd-64": { 476 | "version": "0.14.42", 477 | "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.42.tgz", 478 | "integrity": "sha512-M2meNVIKWsm2HMY7+TU9AxM7ZVwI9havdsw6m/6EzdXysyCFFSoaTQ/Jg03izjCsK17FsVRHqRe26Llj6x0MNA==", 479 | "cpu": [ 480 | "x64" 481 | ], 482 | "dev": true, 483 | "optional": true, 484 | "os": [ 485 | "openbsd" 486 | ], 487 | "engines": { 488 | "node": ">=12" 489 | } 490 | }, 491 | "node_modules/esbuild-sunos-64": { 492 | "version": "0.14.42", 493 | "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.42.tgz", 494 | "integrity": "sha512-uXV8TAZEw36DkgW8Ak3MpSJs1ofBb3Smkc/6pZ29sCAN1KzCAQzsje4sUwugf+FVicrHvlamCOlFZIXgct+iqQ==", 495 | "cpu": [ 496 | "x64" 497 | ], 498 | "dev": true, 499 | "optional": true, 500 | "os": [ 501 | "sunos" 502 | ], 503 | "engines": { 504 | "node": ">=12" 505 | } 506 | }, 507 | "node_modules/esbuild-windows-32": { 508 | "version": "0.14.42", 509 | "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.42.tgz", 510 | "integrity": "sha512-4iw/8qWmRICWi9ZOnJJf9sYt6wmtp3hsN4TdI5NqgjfOkBVMxNdM9Vt3626G1Rda9ya2Q0hjQRD9W1o+m6Lz6g==", 511 | "cpu": [ 512 | "ia32" 513 | ], 514 | "dev": true, 515 | "optional": true, 516 | "os": [ 517 | "win32" 518 | ], 519 | "engines": { 520 | "node": ">=12" 521 | } 522 | }, 523 | "node_modules/esbuild-windows-64": { 524 | "version": "0.14.42", 525 | "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.42.tgz", 526 | "integrity": "sha512-j3cdK+Y3+a5H0wHKmLGTJcq0+/2mMBHPWkItR3vytp/aUGD/ua/t2BLdfBIzbNN9nLCRL9sywCRpOpFMx3CxzA==", 527 | "cpu": [ 528 | "x64" 529 | ], 530 | "dev": true, 531 | "optional": true, 532 | "os": [ 533 | "win32" 534 | ], 535 | "engines": { 536 | "node": ">=12" 537 | } 538 | }, 539 | "node_modules/esbuild-windows-arm64": { 540 | "version": "0.14.42", 541 | "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.42.tgz", 542 | "integrity": "sha512-+lRAARnF+hf8J0mN27ujO+VbhPbDqJ8rCcJKye4y7YZLV6C4n3pTRThAb388k/zqF5uM0lS5O201u0OqoWSicw==", 543 | "cpu": [ 544 | "arm64" 545 | ], 546 | "dev": true, 547 | "optional": true, 548 | "os": [ 549 | "win32" 550 | ], 551 | "engines": { 552 | "node": ">=12" 553 | } 554 | }, 555 | "node_modules/estree-walker": { 556 | "version": "2.0.2", 557 | "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", 558 | "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==" 559 | }, 560 | "node_modules/fsevents": { 561 | "version": "2.3.2", 562 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", 563 | "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", 564 | "dev": true, 565 | "hasInstallScript": true, 566 | "optional": true, 567 | "os": [ 568 | "darwin" 569 | ], 570 | "engines": { 571 | "node": "^8.16.0 || ^10.6.0 || >=11.0.0" 572 | } 573 | }, 574 | "node_modules/function-bind": { 575 | "version": "1.1.1", 576 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", 577 | "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", 578 | "dev": true 579 | }, 580 | "node_modules/has": { 581 | "version": "1.0.3", 582 | "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", 583 | "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", 584 | "dev": true, 585 | "dependencies": { 586 | "function-bind": "^1.1.1" 587 | }, 588 | "engines": { 589 | "node": ">= 0.4.0" 590 | } 591 | }, 592 | "node_modules/is-core-module": { 593 | "version": "2.9.0", 594 | "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.9.0.tgz", 595 | "integrity": "sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A==", 596 | "dev": true, 597 | "dependencies": { 598 | "has": "^1.0.3" 599 | }, 600 | "funding": { 601 | "url": "https://github.com/sponsors/ljharb" 602 | } 603 | }, 604 | "node_modules/magic-string": { 605 | "version": "0.25.9", 606 | "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", 607 | "integrity": "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==", 608 | "dependencies": { 609 | "sourcemap-codec": "^1.4.8" 610 | } 611 | }, 612 | "node_modules/nanoid": { 613 | "version": "3.3.4", 614 | "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", 615 | "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", 616 | "bin": { 617 | "nanoid": "bin/nanoid.cjs" 618 | }, 619 | "engines": { 620 | "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" 621 | } 622 | }, 623 | "node_modules/path-parse": { 624 | "version": "1.0.7", 625 | "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", 626 | "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", 627 | "dev": true 628 | }, 629 | "node_modules/picocolors": { 630 | "version": "1.0.0", 631 | "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", 632 | "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" 633 | }, 634 | "node_modules/postcss": { 635 | "version": "8.4.14", 636 | "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.14.tgz", 637 | "integrity": "sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==", 638 | "funding": [ 639 | { 640 | "type": "opencollective", 641 | "url": "https://opencollective.com/postcss/" 642 | }, 643 | { 644 | "type": "tidelift", 645 | "url": "https://tidelift.com/funding/github/npm/postcss" 646 | } 647 | ], 648 | "dependencies": { 649 | "nanoid": "^3.3.4", 650 | "picocolors": "^1.0.0", 651 | "source-map-js": "^1.0.2" 652 | }, 653 | "engines": { 654 | "node": "^10 || ^12 || >=14" 655 | } 656 | }, 657 | "node_modules/resolve": { 658 | "version": "1.22.0", 659 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", 660 | "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", 661 | "dev": true, 662 | "dependencies": { 663 | "is-core-module": "^2.8.1", 664 | "path-parse": "^1.0.7", 665 | "supports-preserve-symlinks-flag": "^1.0.0" 666 | }, 667 | "bin": { 668 | "resolve": "bin/resolve" 669 | }, 670 | "funding": { 671 | "url": "https://github.com/sponsors/ljharb" 672 | } 673 | }, 674 | "node_modules/rollup": { 675 | "version": "2.75.5", 676 | "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.75.5.tgz", 677 | "integrity": "sha512-JzNlJZDison3o2mOxVmb44Oz7t74EfSd1SQrplQk0wSaXV7uLQXtVdHbxlcT3w+8tZ1TL4r/eLfc7nAbz38BBA==", 678 | "dev": true, 679 | "bin": { 680 | "rollup": "dist/bin/rollup" 681 | }, 682 | "engines": { 683 | "node": ">=10.0.0" 684 | }, 685 | "optionalDependencies": { 686 | "fsevents": "~2.3.2" 687 | } 688 | }, 689 | "node_modules/source-map": { 690 | "version": "0.6.1", 691 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", 692 | "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", 693 | "engines": { 694 | "node": ">=0.10.0" 695 | } 696 | }, 697 | "node_modules/source-map-js": { 698 | "version": "1.0.2", 699 | "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", 700 | "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", 701 | "engines": { 702 | "node": ">=0.10.0" 703 | } 704 | }, 705 | "node_modules/sourcemap-codec": { 706 | "version": "1.4.8", 707 | "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", 708 | "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==" 709 | }, 710 | "node_modules/supports-preserve-symlinks-flag": { 711 | "version": "1.0.0", 712 | "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", 713 | "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", 714 | "dev": true, 715 | "engines": { 716 | "node": ">= 0.4" 717 | }, 718 | "funding": { 719 | "url": "https://github.com/sponsors/ljharb" 720 | } 721 | }, 722 | "node_modules/typescript": { 723 | "version": "4.7.3", 724 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.3.tgz", 725 | "integrity": "sha512-WOkT3XYvrpXx4vMMqlD+8R8R37fZkjyLGlxavMc4iB8lrl8L0DeTcHbYgw/v0N/z9wAFsgBhcsF0ruoySS22mA==", 726 | "dev": true, 727 | "bin": { 728 | "tsc": "bin/tsc", 729 | "tsserver": "bin/tsserver" 730 | }, 731 | "engines": { 732 | "node": ">=4.2.0" 733 | } 734 | }, 735 | "node_modules/vite": { 736 | "version": "2.9.16", 737 | "resolved": "https://registry.npmjs.org/vite/-/vite-2.9.16.tgz", 738 | "integrity": "sha512-X+6q8KPyeuBvTQV8AVSnKDvXoBMnTx8zxh54sOwmmuOdxkjMmEJXH2UEchA+vTMps1xw9vL64uwJOWryULg7nA==", 739 | "dev": true, 740 | "dependencies": { 741 | "esbuild": "^0.14.27", 742 | "postcss": "^8.4.13", 743 | "resolve": "^1.22.0", 744 | "rollup": ">=2.59.0 <2.78.0" 745 | }, 746 | "bin": { 747 | "vite": "bin/vite.js" 748 | }, 749 | "engines": { 750 | "node": ">=12.2.0" 751 | }, 752 | "optionalDependencies": { 753 | "fsevents": "~2.3.2" 754 | }, 755 | "peerDependencies": { 756 | "less": "*", 757 | "sass": "*", 758 | "stylus": "*" 759 | }, 760 | "peerDependenciesMeta": { 761 | "less": { 762 | "optional": true 763 | }, 764 | "sass": { 765 | "optional": true 766 | }, 767 | "stylus": { 768 | "optional": true 769 | } 770 | } 771 | }, 772 | "node_modules/vue": { 773 | "version": "3.2.37", 774 | "resolved": "https://registry.npmjs.org/vue/-/vue-3.2.37.tgz", 775 | "integrity": "sha512-bOKEZxrm8Eh+fveCqS1/NkG/n6aMidsI6hahas7pa0w/l7jkbssJVsRhVDs07IdDq7h9KHswZOgItnwJAgtVtQ==", 776 | "dependencies": { 777 | "@vue/compiler-dom": "3.2.37", 778 | "@vue/compiler-sfc": "3.2.37", 779 | "@vue/runtime-dom": "3.2.37", 780 | "@vue/server-renderer": "3.2.37", 781 | "@vue/shared": "3.2.37" 782 | } 783 | }, 784 | "node_modules/vue-router": { 785 | "version": "4.0.15", 786 | "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.0.15.tgz", 787 | "integrity": "sha512-xa+pIN9ZqORdIW1MkN2+d9Ui2pCM1b/UMgwYUCZOiFYHAvz/slKKBDha8DLrh5aCG/RibtrpyhKjKOZ85tYyWg==", 788 | "dependencies": { 789 | "@vue/devtools-api": "^6.0.0" 790 | }, 791 | "funding": { 792 | "url": "https://github.com/sponsors/posva" 793 | }, 794 | "peerDependencies": { 795 | "vue": "^3.2.0" 796 | } 797 | }, 798 | "node_modules/vue-safe-html": { 799 | "version": "2.0.0", 800 | "resolved": "https://registry.npmjs.org/vue-safe-html/-/vue-safe-html-2.0.0.tgz", 801 | "integrity": "sha512-gj8G466BnKCrlnWaYbCdQ9MYg8Qjixvr0MTH48ce9mYE/jLFxkVXDsdQRqm9NOQ1huql1XHiUyji8zmrNf2Prw==" 802 | }, 803 | "node_modules/vue-tsc": { 804 | "version": "0.34.17", 805 | "resolved": "https://registry.npmjs.org/vue-tsc/-/vue-tsc-0.34.17.tgz", 806 | "integrity": "sha512-jzUXky44ZLHC4daaJag7FQr3idlPYN719/K1eObGljz5KaS2UnVGTU/XSYCd7d6ampYYg4OsyalbHyJIxV0aEQ==", 807 | "dev": true, 808 | "dependencies": { 809 | "@volar/vue-typescript": "0.34.17" 810 | }, 811 | "bin": { 812 | "vue-tsc": "bin/vue-tsc.js" 813 | }, 814 | "peerDependencies": { 815 | "typescript": "*" 816 | } 817 | }, 818 | "node_modules/vue3-carousel": { 819 | "version": "0.1.40", 820 | "resolved": "https://registry.npmjs.org/vue3-carousel/-/vue3-carousel-0.1.40.tgz", 821 | "integrity": "sha512-rPIfBxFhsY6W6qKNGsjgzPJdngt07ov06/Ql1lKsTr8gBx73gUxCIIQo/7M3QCx3KU94CDGBbLugF5YGdEPefg==", 822 | "peerDependencies": { 823 | "vue": "^3.2.0" 824 | } 825 | } 826 | }, 827 | "dependencies": { 828 | "@babel/parser": { 829 | "version": "7.18.4", 830 | "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.18.4.tgz", 831 | "integrity": "sha512-FDge0dFazETFcxGw/EXzOkN8uJp0PC7Qbm+Pe9T+av2zlBpOgunFHkQPPn+eRuClU73JF+98D531UgayY89tow==" 832 | }, 833 | "@vitejs/plugin-vue": { 834 | "version": "2.3.3", 835 | "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-2.3.3.tgz", 836 | "integrity": "sha512-SmQLDyhz+6lGJhPELsBdzXGc+AcaT8stgkbiTFGpXPe8Tl1tJaBw1A6pxDqDuRsVkD8uscrkx3hA7QDOoKYtyw==", 837 | "dev": true, 838 | "requires": {} 839 | }, 840 | "@volar/code-gen": { 841 | "version": "0.34.17", 842 | "resolved": "https://registry.npmjs.org/@volar/code-gen/-/code-gen-0.34.17.tgz", 843 | "integrity": "sha512-rHR7BA71BJ/4S7xUOPMPiB7uk6iU9oTWpEMZxFi5VGC9iJmDncE82WzU5iYpcbOBCVHsOjMh0+5CGMgdO6SaPA==", 844 | "dev": true, 845 | "requires": { 846 | "@volar/source-map": "0.34.17" 847 | } 848 | }, 849 | "@volar/source-map": { 850 | "version": "0.34.17", 851 | "resolved": "https://registry.npmjs.org/@volar/source-map/-/source-map-0.34.17.tgz", 852 | "integrity": "sha512-3yn1IMXJGGWB/G817/VFlFMi8oh5pmE7VzUqvgMZMrppaZpKj6/juvJIEiXNxRsgWc0RxIO8OSp4htdPUg1Raw==", 853 | "dev": true 854 | }, 855 | "@volar/vue-code-gen": { 856 | "version": "0.34.17", 857 | "resolved": "https://registry.npmjs.org/@volar/vue-code-gen/-/vue-code-gen-0.34.17.tgz", 858 | "integrity": "sha512-17pzcK29fyFWUc+C82J3JYSnA+jy3QNrIldb9kPaP9Itbik05ZjEIyEue9FjhgIAuHeYSn4LDM5s6nGjxyfhsQ==", 859 | "dev": true, 860 | "requires": { 861 | "@volar/code-gen": "0.34.17", 862 | "@volar/source-map": "0.34.17", 863 | "@vue/compiler-core": "^3.2.36", 864 | "@vue/compiler-dom": "^3.2.36", 865 | "@vue/shared": "^3.2.36" 866 | } 867 | }, 868 | "@volar/vue-typescript": { 869 | "version": "0.34.17", 870 | "resolved": "https://registry.npmjs.org/@volar/vue-typescript/-/vue-typescript-0.34.17.tgz", 871 | "integrity": "sha512-U0YSVIBPRWVPmgJHNa4nrfq88+oS+tmyZNxmnfajIw9A/GOGZQiKXHC0k09SVvbYXlsjgJ6NIjhm9NuAhGRQjg==", 872 | "dev": true, 873 | "requires": { 874 | "@volar/code-gen": "0.34.17", 875 | "@volar/source-map": "0.34.17", 876 | "@volar/vue-code-gen": "0.34.17", 877 | "@vue/compiler-sfc": "^3.2.36", 878 | "@vue/reactivity": "^3.2.36" 879 | } 880 | }, 881 | "@vue/compiler-core": { 882 | "version": "3.2.37", 883 | "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.2.37.tgz", 884 | "integrity": "sha512-81KhEjo7YAOh0vQJoSmAD68wLfYqJvoiD4ulyedzF+OEk/bk6/hx3fTNVfuzugIIaTrOx4PGx6pAiBRe5e9Zmg==", 885 | "requires": { 886 | "@babel/parser": "^7.16.4", 887 | "@vue/shared": "3.2.37", 888 | "estree-walker": "^2.0.2", 889 | "source-map": "^0.6.1" 890 | } 891 | }, 892 | "@vue/compiler-dom": { 893 | "version": "3.2.37", 894 | "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.2.37.tgz", 895 | "integrity": "sha512-yxJLH167fucHKxaqXpYk7x8z7mMEnXOw3G2q62FTkmsvNxu4FQSu5+3UMb+L7fjKa26DEzhrmCxAgFLLIzVfqQ==", 896 | "requires": { 897 | "@vue/compiler-core": "3.2.37", 898 | "@vue/shared": "3.2.37" 899 | } 900 | }, 901 | "@vue/compiler-sfc": { 902 | "version": "3.2.37", 903 | "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.2.37.tgz", 904 | "integrity": "sha512-+7i/2+9LYlpqDv+KTtWhOZH+pa8/HnX/905MdVmAcI/mPQOBwkHHIzrsEsucyOIZQYMkXUiTkmZq5am/NyXKkg==", 905 | "requires": { 906 | "@babel/parser": "^7.16.4", 907 | "@vue/compiler-core": "3.2.37", 908 | "@vue/compiler-dom": "3.2.37", 909 | "@vue/compiler-ssr": "3.2.37", 910 | "@vue/reactivity-transform": "3.2.37", 911 | "@vue/shared": "3.2.37", 912 | "estree-walker": "^2.0.2", 913 | "magic-string": "^0.25.7", 914 | "postcss": "^8.1.10", 915 | "source-map": "^0.6.1" 916 | } 917 | }, 918 | "@vue/compiler-ssr": { 919 | "version": "3.2.37", 920 | "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.2.37.tgz", 921 | "integrity": "sha512-7mQJD7HdXxQjktmsWp/J67lThEIcxLemz1Vb5I6rYJHR5vI+lON3nPGOH3ubmbvYGt8xEUaAr1j7/tIFWiEOqw==", 922 | "requires": { 923 | "@vue/compiler-dom": "3.2.37", 924 | "@vue/shared": "3.2.37" 925 | } 926 | }, 927 | "@vue/devtools-api": { 928 | "version": "6.1.4", 929 | "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.1.4.tgz", 930 | "integrity": "sha512-IiA0SvDrJEgXvVxjNkHPFfDx6SXw0b/TUkqMcDZWNg9fnCAHbTpoo59YfJ9QLFkwa3raau5vSlRVzMSLDnfdtQ==" 931 | }, 932 | "@vue/reactivity": { 933 | "version": "3.2.37", 934 | "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.2.37.tgz", 935 | "integrity": "sha512-/7WRafBOshOc6m3F7plwzPeCu/RCVv9uMpOwa/5PiY1Zz+WLVRWiy0MYKwmg19KBdGtFWsmZ4cD+LOdVPcs52A==", 936 | "requires": { 937 | "@vue/shared": "3.2.37" 938 | } 939 | }, 940 | "@vue/reactivity-transform": { 941 | "version": "3.2.37", 942 | "resolved": "https://registry.npmjs.org/@vue/reactivity-transform/-/reactivity-transform-3.2.37.tgz", 943 | "integrity": "sha512-IWopkKEb+8qpu/1eMKVeXrK0NLw9HicGviJzhJDEyfxTR9e1WtpnnbYkJWurX6WwoFP0sz10xQg8yL8lgskAZg==", 944 | "requires": { 945 | "@babel/parser": "^7.16.4", 946 | "@vue/compiler-core": "3.2.37", 947 | "@vue/shared": "3.2.37", 948 | "estree-walker": "^2.0.2", 949 | "magic-string": "^0.25.7" 950 | } 951 | }, 952 | "@vue/runtime-core": { 953 | "version": "3.2.37", 954 | "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.2.37.tgz", 955 | "integrity": "sha512-JPcd9kFyEdXLl/i0ClS7lwgcs0QpUAWj+SKX2ZC3ANKi1U4DOtiEr6cRqFXsPwY5u1L9fAjkinIdB8Rz3FoYNQ==", 956 | "requires": { 957 | "@vue/reactivity": "3.2.37", 958 | "@vue/shared": "3.2.37" 959 | } 960 | }, 961 | "@vue/runtime-dom": { 962 | "version": "3.2.37", 963 | "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.2.37.tgz", 964 | "integrity": "sha512-HimKdh9BepShW6YozwRKAYjYQWg9mQn63RGEiSswMbW+ssIht1MILYlVGkAGGQbkhSh31PCdoUcfiu4apXJoPw==", 965 | "requires": { 966 | "@vue/runtime-core": "3.2.37", 967 | "@vue/shared": "3.2.37", 968 | "csstype": "^2.6.8" 969 | } 970 | }, 971 | "@vue/server-renderer": { 972 | "version": "3.2.37", 973 | "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.2.37.tgz", 974 | "integrity": "sha512-kLITEJvaYgZQ2h47hIzPh2K3jG8c1zCVbp/o/bzQOyvzaKiCquKS7AaioPI28GNxIsE/zSx+EwWYsNxDCX95MA==", 975 | "requires": { 976 | "@vue/compiler-ssr": "3.2.37", 977 | "@vue/shared": "3.2.37" 978 | } 979 | }, 980 | "@vue/shared": { 981 | "version": "3.2.37", 982 | "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.2.37.tgz", 983 | "integrity": "sha512-4rSJemR2NQIo9Klm1vabqWjD8rs/ZaJSzMxkMNeJS6lHiUjjUeYFbooN19NgFjztubEKh3WlZUeOLVdbbUWHsw==" 984 | }, 985 | "csstype": { 986 | "version": "2.6.20", 987 | "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.20.tgz", 988 | "integrity": "sha512-/WwNkdXfckNgw6S5R125rrW8ez139lBHWouiBvX8dfMFtcn6V81REDqnH7+CRpRipfYlyU1CmOnOxrmGcFOjeA==" 989 | }, 990 | "esbuild": { 991 | "version": "0.14.42", 992 | "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.42.tgz", 993 | "integrity": "sha512-V0uPZotCEHokJdNqyozH6qsaQXqmZEOiZWrXnds/zaH/0SyrIayRXWRB98CENO73MIZ9T3HBIOsmds5twWtmgw==", 994 | "dev": true, 995 | "requires": { 996 | "esbuild-android-64": "0.14.42", 997 | "esbuild-android-arm64": "0.14.42", 998 | "esbuild-darwin-64": "0.14.42", 999 | "esbuild-darwin-arm64": "0.14.42", 1000 | "esbuild-freebsd-64": "0.14.42", 1001 | "esbuild-freebsd-arm64": "0.14.42", 1002 | "esbuild-linux-32": "0.14.42", 1003 | "esbuild-linux-64": "0.14.42", 1004 | "esbuild-linux-arm": "0.14.42", 1005 | "esbuild-linux-arm64": "0.14.42", 1006 | "esbuild-linux-mips64le": "0.14.42", 1007 | "esbuild-linux-ppc64le": "0.14.42", 1008 | "esbuild-linux-riscv64": "0.14.42", 1009 | "esbuild-linux-s390x": "0.14.42", 1010 | "esbuild-netbsd-64": "0.14.42", 1011 | "esbuild-openbsd-64": "0.14.42", 1012 | "esbuild-sunos-64": "0.14.42", 1013 | "esbuild-windows-32": "0.14.42", 1014 | "esbuild-windows-64": "0.14.42", 1015 | "esbuild-windows-arm64": "0.14.42" 1016 | } 1017 | }, 1018 | "esbuild-android-64": { 1019 | "version": "0.14.42", 1020 | "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.14.42.tgz", 1021 | "integrity": "sha512-P4Y36VUtRhK/zivqGVMqhptSrFILAGlYp0Z8r9UQqHJ3iWztRCNWnlBzD9HRx0DbueXikzOiwyOri+ojAFfW6A==", 1022 | "dev": true, 1023 | "optional": true 1024 | }, 1025 | "esbuild-android-arm64": { 1026 | "version": "0.14.42", 1027 | "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.42.tgz", 1028 | "integrity": "sha512-0cOqCubq+RWScPqvtQdjXG3Czb3AWI2CaKw3HeXry2eoA2rrPr85HF7IpdU26UWdBXgPYtlTN1LUiuXbboROhg==", 1029 | "dev": true, 1030 | "optional": true 1031 | }, 1032 | "esbuild-darwin-64": { 1033 | "version": "0.14.42", 1034 | "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.42.tgz", 1035 | "integrity": "sha512-ipiBdCA3ZjYgRfRLdQwP82rTiv/YVMtW36hTvAN5ZKAIfxBOyPXY7Cejp3bMXWgzKD8B6O+zoMzh01GZsCuEIA==", 1036 | "dev": true, 1037 | "optional": true 1038 | }, 1039 | "esbuild-darwin-arm64": { 1040 | "version": "0.14.42", 1041 | "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.42.tgz", 1042 | "integrity": "sha512-bU2tHRqTPOaoH/4m0zYHbFWpiYDmaA0gt90/3BMEFaM0PqVK/a6MA2V/ypV5PO0v8QxN6gH5hBPY4YJ2lopXgA==", 1043 | "dev": true, 1044 | "optional": true 1045 | }, 1046 | "esbuild-freebsd-64": { 1047 | "version": "0.14.42", 1048 | "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.42.tgz", 1049 | "integrity": "sha512-75h1+22Ivy07+QvxHyhVqOdekupiTZVLN1PMwCDonAqyXd8TVNJfIRFrdL8QmSJrOJJ5h8H1I9ETyl2L8LQDaw==", 1050 | "dev": true, 1051 | "optional": true 1052 | }, 1053 | "esbuild-freebsd-arm64": { 1054 | "version": "0.14.42", 1055 | "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.42.tgz", 1056 | "integrity": "sha512-W6Jebeu5TTDQMJUJVarEzRU9LlKpNkPBbjqSu+GUPTHDCly5zZEQq9uHkmHHl7OKm+mQ2zFySN83nmfCeZCyNA==", 1057 | "dev": true, 1058 | "optional": true 1059 | }, 1060 | "esbuild-linux-32": { 1061 | "version": "0.14.42", 1062 | "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.42.tgz", 1063 | "integrity": "sha512-Ooy/Bj+mJ1z4jlWcK5Dl6SlPlCgQB9zg1UrTCeY8XagvuWZ4qGPyYEWGkT94HUsRi2hKsXvcs6ThTOjBaJSMfg==", 1064 | "dev": true, 1065 | "optional": true 1066 | }, 1067 | "esbuild-linux-64": { 1068 | "version": "0.14.42", 1069 | "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.42.tgz", 1070 | "integrity": "sha512-2L0HbzQfbTuemUWfVqNIjOfaTRt9zsvjnme6lnr7/MO9toz/MJ5tZhjqrG6uDWDxhsaHI2/nsDgrv8uEEN2eoA==", 1071 | "dev": true, 1072 | "optional": true 1073 | }, 1074 | "esbuild-linux-arm": { 1075 | "version": "0.14.42", 1076 | "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.42.tgz", 1077 | "integrity": "sha512-STq69yzCMhdRaWnh29UYrLSr/qaWMm/KqwaRF1pMEK7kDiagaXhSL1zQGXbYv94GuGY/zAwzK98+6idCMUOOCg==", 1078 | "dev": true, 1079 | "optional": true 1080 | }, 1081 | "esbuild-linux-arm64": { 1082 | "version": "0.14.42", 1083 | "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.42.tgz", 1084 | "integrity": "sha512-c3Ug3e9JpVr8jAcfbhirtpBauLxzYPpycjWulD71CF6ZSY26tvzmXMJYooQ2YKqDY4e/fPu5K8bm7MiXMnyxuA==", 1085 | "dev": true, 1086 | "optional": true 1087 | }, 1088 | "esbuild-linux-mips64le": { 1089 | "version": "0.14.42", 1090 | "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.42.tgz", 1091 | "integrity": "sha512-QuvpHGbYlkyXWf2cGm51LBCHx6eUakjaSrRpUqhPwjh/uvNUYvLmz2LgPTTPwCqaKt0iwL+OGVL0tXA5aDbAbg==", 1092 | "dev": true, 1093 | "optional": true 1094 | }, 1095 | "esbuild-linux-ppc64le": { 1096 | "version": "0.14.42", 1097 | "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.42.tgz", 1098 | "integrity": "sha512-8ohIVIWDbDT+i7lCx44YCyIRrOW1MYlks9fxTo0ME2LS/fxxdoJBwHWzaDYhjvf8kNpA+MInZvyOEAGoVDrMHg==", 1099 | "dev": true, 1100 | "optional": true 1101 | }, 1102 | "esbuild-linux-riscv64": { 1103 | "version": "0.14.42", 1104 | "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.42.tgz", 1105 | "integrity": "sha512-DzDqK3TuoXktPyG1Lwx7vhaF49Onv3eR61KwQyxYo4y5UKTpL3NmuarHSIaSVlTFDDpcIajCDwz5/uwKLLgKiQ==", 1106 | "dev": true, 1107 | "optional": true 1108 | }, 1109 | "esbuild-linux-s390x": { 1110 | "version": "0.14.42", 1111 | "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.42.tgz", 1112 | "integrity": "sha512-YFRhPCxl8nb//Wn6SiS5pmtplBi4z9yC2gLrYoYI/tvwuB1jldir9r7JwAGy1Ck4D7sE7wBN9GFtUUX/DLdcEQ==", 1113 | "dev": true, 1114 | "optional": true 1115 | }, 1116 | "esbuild-netbsd-64": { 1117 | "version": "0.14.42", 1118 | "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.42.tgz", 1119 | "integrity": "sha512-QYSD2k+oT9dqB/4eEM9c+7KyNYsIPgzYOSrmfNGDIyJrbT1d+CFVKvnKahDKNJLfOYj8N4MgyFaU9/Ytc6w5Vw==", 1120 | "dev": true, 1121 | "optional": true 1122 | }, 1123 | "esbuild-openbsd-64": { 1124 | "version": "0.14.42", 1125 | "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.42.tgz", 1126 | "integrity": "sha512-M2meNVIKWsm2HMY7+TU9AxM7ZVwI9havdsw6m/6EzdXysyCFFSoaTQ/Jg03izjCsK17FsVRHqRe26Llj6x0MNA==", 1127 | "dev": true, 1128 | "optional": true 1129 | }, 1130 | "esbuild-sunos-64": { 1131 | "version": "0.14.42", 1132 | "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.42.tgz", 1133 | "integrity": "sha512-uXV8TAZEw36DkgW8Ak3MpSJs1ofBb3Smkc/6pZ29sCAN1KzCAQzsje4sUwugf+FVicrHvlamCOlFZIXgct+iqQ==", 1134 | "dev": true, 1135 | "optional": true 1136 | }, 1137 | "esbuild-windows-32": { 1138 | "version": "0.14.42", 1139 | "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.42.tgz", 1140 | "integrity": "sha512-4iw/8qWmRICWi9ZOnJJf9sYt6wmtp3hsN4TdI5NqgjfOkBVMxNdM9Vt3626G1Rda9ya2Q0hjQRD9W1o+m6Lz6g==", 1141 | "dev": true, 1142 | "optional": true 1143 | }, 1144 | "esbuild-windows-64": { 1145 | "version": "0.14.42", 1146 | "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.42.tgz", 1147 | "integrity": "sha512-j3cdK+Y3+a5H0wHKmLGTJcq0+/2mMBHPWkItR3vytp/aUGD/ua/t2BLdfBIzbNN9nLCRL9sywCRpOpFMx3CxzA==", 1148 | "dev": true, 1149 | "optional": true 1150 | }, 1151 | "esbuild-windows-arm64": { 1152 | "version": "0.14.42", 1153 | "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.42.tgz", 1154 | "integrity": "sha512-+lRAARnF+hf8J0mN27ujO+VbhPbDqJ8rCcJKye4y7YZLV6C4n3pTRThAb388k/zqF5uM0lS5O201u0OqoWSicw==", 1155 | "dev": true, 1156 | "optional": true 1157 | }, 1158 | "estree-walker": { 1159 | "version": "2.0.2", 1160 | "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", 1161 | "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==" 1162 | }, 1163 | "fsevents": { 1164 | "version": "2.3.2", 1165 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", 1166 | "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", 1167 | "dev": true, 1168 | "optional": true 1169 | }, 1170 | "function-bind": { 1171 | "version": "1.1.1", 1172 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", 1173 | "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", 1174 | "dev": true 1175 | }, 1176 | "has": { 1177 | "version": "1.0.3", 1178 | "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", 1179 | "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", 1180 | "dev": true, 1181 | "requires": { 1182 | "function-bind": "^1.1.1" 1183 | } 1184 | }, 1185 | "is-core-module": { 1186 | "version": "2.9.0", 1187 | "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.9.0.tgz", 1188 | "integrity": "sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A==", 1189 | "dev": true, 1190 | "requires": { 1191 | "has": "^1.0.3" 1192 | } 1193 | }, 1194 | "magic-string": { 1195 | "version": "0.25.9", 1196 | "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", 1197 | "integrity": "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==", 1198 | "requires": { 1199 | "sourcemap-codec": "^1.4.8" 1200 | } 1201 | }, 1202 | "nanoid": { 1203 | "version": "3.3.4", 1204 | "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", 1205 | "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==" 1206 | }, 1207 | "path-parse": { 1208 | "version": "1.0.7", 1209 | "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", 1210 | "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", 1211 | "dev": true 1212 | }, 1213 | "picocolors": { 1214 | "version": "1.0.0", 1215 | "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", 1216 | "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" 1217 | }, 1218 | "postcss": { 1219 | "version": "8.4.14", 1220 | "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.14.tgz", 1221 | "integrity": "sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==", 1222 | "requires": { 1223 | "nanoid": "^3.3.4", 1224 | "picocolors": "^1.0.0", 1225 | "source-map-js": "^1.0.2" 1226 | } 1227 | }, 1228 | "resolve": { 1229 | "version": "1.22.0", 1230 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", 1231 | "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", 1232 | "dev": true, 1233 | "requires": { 1234 | "is-core-module": "^2.8.1", 1235 | "path-parse": "^1.0.7", 1236 | "supports-preserve-symlinks-flag": "^1.0.0" 1237 | } 1238 | }, 1239 | "rollup": { 1240 | "version": "2.75.5", 1241 | "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.75.5.tgz", 1242 | "integrity": "sha512-JzNlJZDison3o2mOxVmb44Oz7t74EfSd1SQrplQk0wSaXV7uLQXtVdHbxlcT3w+8tZ1TL4r/eLfc7nAbz38BBA==", 1243 | "dev": true, 1244 | "requires": { 1245 | "fsevents": "~2.3.2" 1246 | } 1247 | }, 1248 | "source-map": { 1249 | "version": "0.6.1", 1250 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", 1251 | "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" 1252 | }, 1253 | "source-map-js": { 1254 | "version": "1.0.2", 1255 | "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", 1256 | "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==" 1257 | }, 1258 | "sourcemap-codec": { 1259 | "version": "1.4.8", 1260 | "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", 1261 | "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==" 1262 | }, 1263 | "supports-preserve-symlinks-flag": { 1264 | "version": "1.0.0", 1265 | "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", 1266 | "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", 1267 | "dev": true 1268 | }, 1269 | "typescript": { 1270 | "version": "4.7.3", 1271 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.3.tgz", 1272 | "integrity": "sha512-WOkT3XYvrpXx4vMMqlD+8R8R37fZkjyLGlxavMc4iB8lrl8L0DeTcHbYgw/v0N/z9wAFsgBhcsF0ruoySS22mA==", 1273 | "dev": true 1274 | }, 1275 | "vite": { 1276 | "version": "2.9.16", 1277 | "resolved": "https://registry.npmjs.org/vite/-/vite-2.9.16.tgz", 1278 | "integrity": "sha512-X+6q8KPyeuBvTQV8AVSnKDvXoBMnTx8zxh54sOwmmuOdxkjMmEJXH2UEchA+vTMps1xw9vL64uwJOWryULg7nA==", 1279 | "dev": true, 1280 | "requires": { 1281 | "esbuild": "^0.14.27", 1282 | "fsevents": "~2.3.2", 1283 | "postcss": "^8.4.13", 1284 | "resolve": "^1.22.0", 1285 | "rollup": ">=2.59.0 <2.78.0" 1286 | } 1287 | }, 1288 | "vue": { 1289 | "version": "3.2.37", 1290 | "resolved": "https://registry.npmjs.org/vue/-/vue-3.2.37.tgz", 1291 | "integrity": "sha512-bOKEZxrm8Eh+fveCqS1/NkG/n6aMidsI6hahas7pa0w/l7jkbssJVsRhVDs07IdDq7h9KHswZOgItnwJAgtVtQ==", 1292 | "requires": { 1293 | "@vue/compiler-dom": "3.2.37", 1294 | "@vue/compiler-sfc": "3.2.37", 1295 | "@vue/runtime-dom": "3.2.37", 1296 | "@vue/server-renderer": "3.2.37", 1297 | "@vue/shared": "3.2.37" 1298 | } 1299 | }, 1300 | "vue-router": { 1301 | "version": "4.0.15", 1302 | "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.0.15.tgz", 1303 | "integrity": "sha512-xa+pIN9ZqORdIW1MkN2+d9Ui2pCM1b/UMgwYUCZOiFYHAvz/slKKBDha8DLrh5aCG/RibtrpyhKjKOZ85tYyWg==", 1304 | "requires": { 1305 | "@vue/devtools-api": "^6.0.0" 1306 | } 1307 | }, 1308 | "vue-safe-html": { 1309 | "version": "2.0.0", 1310 | "resolved": "https://registry.npmjs.org/vue-safe-html/-/vue-safe-html-2.0.0.tgz", 1311 | "integrity": "sha512-gj8G466BnKCrlnWaYbCdQ9MYg8Qjixvr0MTH48ce9mYE/jLFxkVXDsdQRqm9NOQ1huql1XHiUyji8zmrNf2Prw==" 1312 | }, 1313 | "vue-tsc": { 1314 | "version": "0.34.17", 1315 | "resolved": "https://registry.npmjs.org/vue-tsc/-/vue-tsc-0.34.17.tgz", 1316 | "integrity": "sha512-jzUXky44ZLHC4daaJag7FQr3idlPYN719/K1eObGljz5KaS2UnVGTU/XSYCd7d6ampYYg4OsyalbHyJIxV0aEQ==", 1317 | "dev": true, 1318 | "requires": { 1319 | "@volar/vue-typescript": "0.34.17" 1320 | } 1321 | }, 1322 | "vue3-carousel": { 1323 | "version": "0.1.40", 1324 | "resolved": "https://registry.npmjs.org/vue3-carousel/-/vue3-carousel-0.1.40.tgz", 1325 | "integrity": "sha512-rPIfBxFhsY6W6qKNGsjgzPJdngt07ov06/Ql1lKsTr8gBx73gUxCIIQo/7M3QCx3KU94CDGBbLugF5YGdEPefg==", 1326 | "requires": {} 1327 | } 1328 | } 1329 | } 1330 | -------------------------------------------------------------------------------- /app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "directus-cf-cache-app", 3 | "private": true, 4 | "version": "0.0.0", 5 | "scripts": { 6 | "dev": "vite", 7 | "build": "vue-tsc --noEmit && vite build", 8 | "preview": "vite preview" 9 | }, 10 | "dependencies": { 11 | "vue": "^3.2.25", 12 | "vue-router": "^4.0.15", 13 | "vue-safe-html": "^2.0.0", 14 | "vue3-carousel": "^0.1.40" 15 | }, 16 | "devDependencies": { 17 | "@vitejs/plugin-vue": "^2.3.3", 18 | "typescript": "^4.5.4", 19 | "vite": "^2.9.16", 20 | "vue-tsc": "^0.34.7" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /app/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/licitdev/directus-cf-cache/23f6612d087f871541651dbc5dcefc5869cfaf1c/app/public/favicon.ico -------------------------------------------------------------------------------- /app/src/App.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 30 | -------------------------------------------------------------------------------- /app/src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/licitdev/directus-cf-cache/23f6612d087f871541651dbc5dcefc5869cfaf1c/app/src/assets/logo.png -------------------------------------------------------------------------------- /app/src/env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | declare module '*.vue' { 4 | import type { DefineComponent } from 'vue'; 5 | // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types 6 | const component: DefineComponent<{}, {}, any>; 7 | export default component; 8 | } 9 | 10 | declare module 'vue-safe-html'; 11 | declare module 'vue3-carousel'; 12 | -------------------------------------------------------------------------------- /app/src/main.ts: -------------------------------------------------------------------------------- 1 | import { createApp } from 'vue'; 2 | import App from './App.vue'; 3 | import router from './router'; 4 | import VueSafeHTML, { allowedTags } from 'vue-safe-html'; 5 | 6 | const sanitizeConfig = { 7 | allowedTags: [ 8 | ...allowedTags, 9 | 'blockquote', 10 | 'img', 11 | 'ol', 12 | 'ul', 13 | 'li', 14 | 'a', 15 | 'p', 16 | 'h1', 17 | 'h2', 18 | 'h3', 19 | 'h4', 20 | 'h5', 21 | 'h6', 22 | 'strong', 23 | 'em', 24 | 'code', 25 | 'pre', 26 | 'table', 27 | 'thead', 28 | 'tbody', 29 | 'tr', 30 | 'th', 31 | 'td', 32 | 'br', 33 | 'hr', 34 | 'div', 35 | 'span', 36 | ], 37 | }; 38 | 39 | createApp(App).use(VueSafeHTML, sanitizeConfig).use(router).mount('#app'); 40 | -------------------------------------------------------------------------------- /app/src/router/index.ts: -------------------------------------------------------------------------------- 1 | import { createWebHistory, createRouter } from 'vue-router'; 2 | import Home from '../views/Home.vue'; 3 | import Article from '../views/Article.vue'; 4 | import Articles from '../views/Articles.vue'; 5 | import Projects from '../views/Projects.vue'; 6 | import People from '../views/People.vue'; 7 | import NotFound from '../views/NotFound.vue'; 8 | 9 | const routes = [ 10 | { 11 | path: '/', 12 | component: Home, 13 | }, 14 | { 15 | path: '/articles', 16 | component: Articles, 17 | }, 18 | { 19 | path: '/articles/:key', 20 | component: Articles, 21 | }, 22 | { 23 | path: '/article/:pk', 24 | component: Article, 25 | }, 26 | { 27 | path: '/projects', 28 | component: Projects, 29 | }, 30 | { 31 | path: '/people', 32 | component: People, 33 | }, 34 | { 35 | path: '/:catchAll(.*)', 36 | component: NotFound, 37 | }, 38 | ]; 39 | 40 | const router = createRouter({ 41 | history: createWebHistory(), 42 | routes, 43 | }); 44 | 45 | export default router; 46 | -------------------------------------------------------------------------------- /app/src/utils/api.ts: -------------------------------------------------------------------------------- 1 | const SERVER_URL = import.meta.env.VITE_DIRECTUS_CF_CACHE_URL; 2 | 3 | export const listItems = async (collection: string, key?: string) => { 4 | const url = `${SERVER_URL}/list/${collection}/${key ?? ''}`; 5 | const response = await fetch(url); 6 | if (response.status >= 400) { 7 | return []; 8 | } 9 | const data = await response.json(); 10 | return data; 11 | }; 12 | 13 | export const getItem = async (collection: string, pk: string, key?: string) => { 14 | const url = `${SERVER_URL}/get/${collection}/${pk}/${key ?? ''}`; 15 | const response = await fetch(url); 16 | if (response.status >= 400) { 17 | return {}; 18 | } 19 | const data = await response.json(); 20 | return data; 21 | }; 22 | 23 | export const getAssetUrl = (pk: string) => { 24 | return `${SERVER_URL}/assets/${pk}`; 25 | }; 26 | -------------------------------------------------------------------------------- /app/src/views/Article.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 31 | 32 | 42 | -------------------------------------------------------------------------------- /app/src/views/Articles.vue: -------------------------------------------------------------------------------- 1 | 21 | 22 | 43 | 44 | 51 | -------------------------------------------------------------------------------- /app/src/views/Home.vue: -------------------------------------------------------------------------------- 1 | 31 | 32 | 37 | -------------------------------------------------------------------------------- /app/src/views/NotFound.vue: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /app/src/views/People.vue: -------------------------------------------------------------------------------- 1 | 23 | 24 | 39 | 40 | 56 | -------------------------------------------------------------------------------- /app/src/views/Projects.vue: -------------------------------------------------------------------------------- 1 | 32 | 33 | 49 | 50 | 57 | -------------------------------------------------------------------------------- /app/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "esnext", 4 | "useDefineForClassFields": true, 5 | "module": "esnext", 6 | "moduleResolution": "node", 7 | "strict": true, 8 | "jsx": "preserve", 9 | "sourceMap": true, 10 | "resolveJsonModule": true, 11 | "isolatedModules": true, 12 | "esModuleInterop": true, 13 | "lib": ["esnext", "dom"], 14 | "skipLibCheck": true 15 | }, 16 | "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"], 17 | "references": [{ "path": "./tsconfig.node.json" }] 18 | } 19 | -------------------------------------------------------------------------------- /app/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "module": "esnext", 5 | "moduleResolution": "node" 6 | }, 7 | "include": ["vite.config.ts"] 8 | } 9 | -------------------------------------------------------------------------------- /app/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import vue from '@vitejs/plugin-vue' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [vue()] 7 | }) 8 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "directus-cf-cache", 3 | "version": "0.0.1", 4 | "lockfileVersion": 2, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "directus-cf-cache", 9 | "version": "0.0.1", 10 | "hasInstallScript": true, 11 | "license": "MIT", 12 | "devDependencies": { 13 | "@types/lodash": "^4.14.182", 14 | "cfw": "0.3.0", 15 | "dotenv": "^16.0.1", 16 | "lodash": "^4.17.21", 17 | "patch-package": "^6.4.7", 18 | "worktop": "^0.7.3" 19 | } 20 | }, 21 | "node_modules/@types/lodash": { 22 | "version": "4.14.182", 23 | "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.182.tgz", 24 | "integrity": "sha512-/THyiqyQAP9AfARo4pF+aCGcyiQ94tX/Is2I7HofNRqoYLgN1PBoOWu2/zTA5zMxzP5EFutMtWtGAFRKUe961Q==", 25 | "dev": true 26 | }, 27 | "node_modules/@yarnpkg/lockfile": { 28 | "version": "1.1.0", 29 | "resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz", 30 | "integrity": "sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==", 31 | "dev": true 32 | }, 33 | "node_modules/ansi-styles": { 34 | "version": "3.2.1", 35 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", 36 | "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", 37 | "dev": true, 38 | "dependencies": { 39 | "color-convert": "^1.9.0" 40 | }, 41 | "engines": { 42 | "node": ">=4" 43 | } 44 | }, 45 | "node_modules/balanced-match": { 46 | "version": "1.0.2", 47 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", 48 | "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", 49 | "dev": true 50 | }, 51 | "node_modules/brace-expansion": { 52 | "version": "1.1.11", 53 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 54 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 55 | "dev": true, 56 | "dependencies": { 57 | "balanced-match": "^1.0.0", 58 | "concat-map": "0.0.1" 59 | } 60 | }, 61 | "node_modules/braces": { 62 | "version": "3.0.2", 63 | "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", 64 | "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", 65 | "dev": true, 66 | "dependencies": { 67 | "fill-range": "^7.0.1" 68 | }, 69 | "engines": { 70 | "node": ">=8" 71 | } 72 | }, 73 | "node_modules/cfw": { 74 | "version": "0.3.0", 75 | "resolved": "https://registry.npmjs.org/cfw/-/cfw-0.3.0.tgz", 76 | "integrity": "sha512-KiN54HqdDiw2+nfCjPALoujKXn/N/e1yeCzcpctuWK4cgBbCWbxg966SITKZszXezk8K1E/8kRCfUXKyzluanQ==", 77 | "dev": true, 78 | "dependencies": { 79 | "esbuild": "^0.12.20", 80 | "httpie": "^1.1.2", 81 | "kleur": "^4.0.0", 82 | "klona": "^2.0.0", 83 | "sade": "^1.7.4" 84 | }, 85 | "bin": { 86 | "cfw": "cfw.js" 87 | }, 88 | "engines": { 89 | "node": ">=12.10" 90 | } 91 | }, 92 | "node_modules/chalk": { 93 | "version": "2.4.2", 94 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", 95 | "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", 96 | "dev": true, 97 | "dependencies": { 98 | "ansi-styles": "^3.2.1", 99 | "escape-string-regexp": "^1.0.5", 100 | "supports-color": "^5.3.0" 101 | }, 102 | "engines": { 103 | "node": ">=4" 104 | } 105 | }, 106 | "node_modules/ci-info": { 107 | "version": "2.0.0", 108 | "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", 109 | "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", 110 | "dev": true 111 | }, 112 | "node_modules/color-convert": { 113 | "version": "1.9.3", 114 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", 115 | "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", 116 | "dev": true, 117 | "dependencies": { 118 | "color-name": "1.1.3" 119 | } 120 | }, 121 | "node_modules/color-name": { 122 | "version": "1.1.3", 123 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", 124 | "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", 125 | "dev": true 126 | }, 127 | "node_modules/concat-map": { 128 | "version": "0.0.1", 129 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 130 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", 131 | "dev": true 132 | }, 133 | "node_modules/cross-spawn": { 134 | "version": "6.0.5", 135 | "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", 136 | "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", 137 | "dev": true, 138 | "dependencies": { 139 | "nice-try": "^1.0.4", 140 | "path-key": "^2.0.1", 141 | "semver": "^5.5.0", 142 | "shebang-command": "^1.2.0", 143 | "which": "^1.2.9" 144 | }, 145 | "engines": { 146 | "node": ">=4.8" 147 | } 148 | }, 149 | "node_modules/dotenv": { 150 | "version": "16.0.1", 151 | "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.1.tgz", 152 | "integrity": "sha512-1K6hR6wtk2FviQ4kEiSjFiH5rpzEVi8WW0x96aztHVMhEspNpc4DVOUTEHtEva5VThQ8IaBX1Pe4gSzpVVUsKQ==", 153 | "dev": true, 154 | "engines": { 155 | "node": ">=12" 156 | } 157 | }, 158 | "node_modules/esbuild": { 159 | "version": "0.12.29", 160 | "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.12.29.tgz", 161 | "integrity": "sha512-w/XuoBCSwepyiZtIRsKsetiLDUVGPVw1E/R3VTFSecIy8UR7Cq3SOtwKHJMFoVqqVG36aGkzh4e8BvpO1Fdc7g==", 162 | "dev": true, 163 | "hasInstallScript": true, 164 | "bin": { 165 | "esbuild": "bin/esbuild" 166 | } 167 | }, 168 | "node_modules/escape-string-regexp": { 169 | "version": "1.0.5", 170 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", 171 | "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", 172 | "dev": true, 173 | "engines": { 174 | "node": ">=0.8.0" 175 | } 176 | }, 177 | "node_modules/fill-range": { 178 | "version": "7.0.1", 179 | "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", 180 | "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", 181 | "dev": true, 182 | "dependencies": { 183 | "to-regex-range": "^5.0.1" 184 | }, 185 | "engines": { 186 | "node": ">=8" 187 | } 188 | }, 189 | "node_modules/find-yarn-workspace-root": { 190 | "version": "2.0.0", 191 | "resolved": "https://registry.npmjs.org/find-yarn-workspace-root/-/find-yarn-workspace-root-2.0.0.tgz", 192 | "integrity": "sha512-1IMnbjt4KzsQfnhnzNd8wUEgXZ44IzZaZmnLYx7D5FZlaHt2gW20Cri8Q+E/t5tIj4+epTBub+2Zxu/vNILzqQ==", 193 | "dev": true, 194 | "dependencies": { 195 | "micromatch": "^4.0.2" 196 | } 197 | }, 198 | "node_modules/fs-extra": { 199 | "version": "7.0.1", 200 | "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", 201 | "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", 202 | "dev": true, 203 | "dependencies": { 204 | "graceful-fs": "^4.1.2", 205 | "jsonfile": "^4.0.0", 206 | "universalify": "^0.1.0" 207 | }, 208 | "engines": { 209 | "node": ">=6 <7 || >=8" 210 | } 211 | }, 212 | "node_modules/fs.realpath": { 213 | "version": "1.0.0", 214 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 215 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", 216 | "dev": true 217 | }, 218 | "node_modules/glob": { 219 | "version": "7.2.3", 220 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", 221 | "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", 222 | "dev": true, 223 | "dependencies": { 224 | "fs.realpath": "^1.0.0", 225 | "inflight": "^1.0.4", 226 | "inherits": "2", 227 | "minimatch": "^3.1.1", 228 | "once": "^1.3.0", 229 | "path-is-absolute": "^1.0.0" 230 | }, 231 | "engines": { 232 | "node": "*" 233 | }, 234 | "funding": { 235 | "url": "https://github.com/sponsors/isaacs" 236 | } 237 | }, 238 | "node_modules/graceful-fs": { 239 | "version": "4.2.10", 240 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", 241 | "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", 242 | "dev": true 243 | }, 244 | "node_modules/has-flag": { 245 | "version": "3.0.0", 246 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", 247 | "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", 248 | "dev": true, 249 | "engines": { 250 | "node": ">=4" 251 | } 252 | }, 253 | "node_modules/httpie": { 254 | "version": "1.1.2", 255 | "resolved": "https://registry.npmjs.org/httpie/-/httpie-1.1.2.tgz", 256 | "integrity": "sha512-VQ82oXG95oY1fQw/XecHuvcFBA+lZQ9Vwj1RfLcO8a7HpDd4cc2ukwpJt+TUlFaLUAzZErylxWu6wclJ1rUhUQ==", 257 | "dev": true, 258 | "engines": { 259 | "node": ">=8" 260 | } 261 | }, 262 | "node_modules/inflight": { 263 | "version": "1.0.6", 264 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 265 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", 266 | "dev": true, 267 | "dependencies": { 268 | "once": "^1.3.0", 269 | "wrappy": "1" 270 | } 271 | }, 272 | "node_modules/inherits": { 273 | "version": "2.0.4", 274 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 275 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", 276 | "dev": true 277 | }, 278 | "node_modules/is-ci": { 279 | "version": "2.0.0", 280 | "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", 281 | "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", 282 | "dev": true, 283 | "dependencies": { 284 | "ci-info": "^2.0.0" 285 | }, 286 | "bin": { 287 | "is-ci": "bin.js" 288 | } 289 | }, 290 | "node_modules/is-docker": { 291 | "version": "2.2.1", 292 | "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", 293 | "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", 294 | "dev": true, 295 | "bin": { 296 | "is-docker": "cli.js" 297 | }, 298 | "engines": { 299 | "node": ">=8" 300 | }, 301 | "funding": { 302 | "url": "https://github.com/sponsors/sindresorhus" 303 | } 304 | }, 305 | "node_modules/is-number": { 306 | "version": "7.0.0", 307 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", 308 | "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", 309 | "dev": true, 310 | "engines": { 311 | "node": ">=0.12.0" 312 | } 313 | }, 314 | "node_modules/is-wsl": { 315 | "version": "2.2.0", 316 | "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", 317 | "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", 318 | "dev": true, 319 | "dependencies": { 320 | "is-docker": "^2.0.0" 321 | }, 322 | "engines": { 323 | "node": ">=8" 324 | } 325 | }, 326 | "node_modules/isexe": { 327 | "version": "2.0.0", 328 | "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", 329 | "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", 330 | "dev": true 331 | }, 332 | "node_modules/jsonfile": { 333 | "version": "4.0.0", 334 | "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", 335 | "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", 336 | "dev": true, 337 | "optionalDependencies": { 338 | "graceful-fs": "^4.1.6" 339 | } 340 | }, 341 | "node_modules/klaw-sync": { 342 | "version": "6.0.0", 343 | "resolved": "https://registry.npmjs.org/klaw-sync/-/klaw-sync-6.0.0.tgz", 344 | "integrity": "sha512-nIeuVSzdCCs6TDPTqI8w1Yre34sSq7AkZ4B3sfOBbI2CgVSB4Du4aLQijFU2+lhAFCwt9+42Hel6lQNIv6AntQ==", 345 | "dev": true, 346 | "dependencies": { 347 | "graceful-fs": "^4.1.11" 348 | } 349 | }, 350 | "node_modules/kleur": { 351 | "version": "4.1.4", 352 | "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.4.tgz", 353 | "integrity": "sha512-8QADVssbrFjivHWQU7KkMgptGTl6WAcSdlbBPY4uNF+mWr6DGcKrvY2w4FQJoXch7+fKMjj0dRrL75vk3k23OA==", 354 | "dev": true, 355 | "engines": { 356 | "node": ">=6" 357 | } 358 | }, 359 | "node_modules/klona": { 360 | "version": "2.0.5", 361 | "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.5.tgz", 362 | "integrity": "sha512-pJiBpiXMbt7dkzXe8Ghj/u4FfXOOa98fPW+bihOJ4SjnoijweJrNThJfd3ifXpXhREjpoF2mZVH1GfS9LV3kHQ==", 363 | "dev": true, 364 | "engines": { 365 | "node": ">= 8" 366 | } 367 | }, 368 | "node_modules/lodash": { 369 | "version": "4.17.21", 370 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", 371 | "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", 372 | "dev": true 373 | }, 374 | "node_modules/micromatch": { 375 | "version": "4.0.5", 376 | "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", 377 | "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", 378 | "dev": true, 379 | "dependencies": { 380 | "braces": "^3.0.2", 381 | "picomatch": "^2.3.1" 382 | }, 383 | "engines": { 384 | "node": ">=8.6" 385 | } 386 | }, 387 | "node_modules/minimatch": { 388 | "version": "3.1.2", 389 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", 390 | "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", 391 | "dev": true, 392 | "dependencies": { 393 | "brace-expansion": "^1.1.7" 394 | }, 395 | "engines": { 396 | "node": "*" 397 | } 398 | }, 399 | "node_modules/minimist": { 400 | "version": "1.2.6", 401 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", 402 | "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", 403 | "dev": true 404 | }, 405 | "node_modules/mri": { 406 | "version": "1.2.0", 407 | "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", 408 | "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==", 409 | "dev": true, 410 | "engines": { 411 | "node": ">=4" 412 | } 413 | }, 414 | "node_modules/nice-try": { 415 | "version": "1.0.5", 416 | "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", 417 | "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", 418 | "dev": true 419 | }, 420 | "node_modules/once": { 421 | "version": "1.4.0", 422 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 423 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 424 | "dev": true, 425 | "dependencies": { 426 | "wrappy": "1" 427 | } 428 | }, 429 | "node_modules/open": { 430 | "version": "7.4.2", 431 | "resolved": "https://registry.npmjs.org/open/-/open-7.4.2.tgz", 432 | "integrity": "sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==", 433 | "dev": true, 434 | "dependencies": { 435 | "is-docker": "^2.0.0", 436 | "is-wsl": "^2.1.1" 437 | }, 438 | "engines": { 439 | "node": ">=8" 440 | }, 441 | "funding": { 442 | "url": "https://github.com/sponsors/sindresorhus" 443 | } 444 | }, 445 | "node_modules/os-tmpdir": { 446 | "version": "1.0.2", 447 | "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", 448 | "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", 449 | "dev": true, 450 | "engines": { 451 | "node": ">=0.10.0" 452 | } 453 | }, 454 | "node_modules/patch-package": { 455 | "version": "6.4.7", 456 | "resolved": "https://registry.npmjs.org/patch-package/-/patch-package-6.4.7.tgz", 457 | "integrity": "sha512-S0vh/ZEafZ17hbhgqdnpunKDfzHQibQizx9g8yEf5dcVk3KOflOfdufRXQX8CSEkyOQwuM/bNz1GwKvFj54kaQ==", 458 | "dev": true, 459 | "dependencies": { 460 | "@yarnpkg/lockfile": "^1.1.0", 461 | "chalk": "^2.4.2", 462 | "cross-spawn": "^6.0.5", 463 | "find-yarn-workspace-root": "^2.0.0", 464 | "fs-extra": "^7.0.1", 465 | "is-ci": "^2.0.0", 466 | "klaw-sync": "^6.0.0", 467 | "minimist": "^1.2.0", 468 | "open": "^7.4.2", 469 | "rimraf": "^2.6.3", 470 | "semver": "^5.6.0", 471 | "slash": "^2.0.0", 472 | "tmp": "^0.0.33" 473 | }, 474 | "bin": { 475 | "patch-package": "index.js" 476 | }, 477 | "engines": { 478 | "npm": ">5" 479 | } 480 | }, 481 | "node_modules/path-is-absolute": { 482 | "version": "1.0.1", 483 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 484 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", 485 | "dev": true, 486 | "engines": { 487 | "node": ">=0.10.0" 488 | } 489 | }, 490 | "node_modules/path-key": { 491 | "version": "2.0.1", 492 | "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", 493 | "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", 494 | "dev": true, 495 | "engines": { 496 | "node": ">=4" 497 | } 498 | }, 499 | "node_modules/picomatch": { 500 | "version": "2.3.1", 501 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", 502 | "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", 503 | "dev": true, 504 | "engines": { 505 | "node": ">=8.6" 506 | }, 507 | "funding": { 508 | "url": "https://github.com/sponsors/jonschlinkert" 509 | } 510 | }, 511 | "node_modules/regexparam": { 512 | "version": "2.0.0", 513 | "resolved": "https://registry.npmjs.org/regexparam/-/regexparam-2.0.0.tgz", 514 | "integrity": "sha512-gJKwd2MVPWHAIFLsaYDZfyKzHNS4o7E/v8YmNf44vmeV2e4YfVoDToTOKTvE7ab68cRJ++kLuEXJBaEeJVt5ow==", 515 | "dev": true, 516 | "engines": { 517 | "node": ">=8" 518 | } 519 | }, 520 | "node_modules/rimraf": { 521 | "version": "2.7.1", 522 | "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", 523 | "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", 524 | "dev": true, 525 | "dependencies": { 526 | "glob": "^7.1.3" 527 | }, 528 | "bin": { 529 | "rimraf": "bin.js" 530 | } 531 | }, 532 | "node_modules/sade": { 533 | "version": "1.8.1", 534 | "resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz", 535 | "integrity": "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==", 536 | "dev": true, 537 | "dependencies": { 538 | "mri": "^1.1.0" 539 | }, 540 | "engines": { 541 | "node": ">=6" 542 | } 543 | }, 544 | "node_modules/semver": { 545 | "version": "5.7.1", 546 | "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", 547 | "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", 548 | "dev": true, 549 | "bin": { 550 | "semver": "bin/semver" 551 | } 552 | }, 553 | "node_modules/shebang-command": { 554 | "version": "1.2.0", 555 | "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", 556 | "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", 557 | "dev": true, 558 | "dependencies": { 559 | "shebang-regex": "^1.0.0" 560 | }, 561 | "engines": { 562 | "node": ">=0.10.0" 563 | } 564 | }, 565 | "node_modules/shebang-regex": { 566 | "version": "1.0.0", 567 | "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", 568 | "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", 569 | "dev": true, 570 | "engines": { 571 | "node": ">=0.10.0" 572 | } 573 | }, 574 | "node_modules/slash": { 575 | "version": "2.0.0", 576 | "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", 577 | "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", 578 | "dev": true, 579 | "engines": { 580 | "node": ">=6" 581 | } 582 | }, 583 | "node_modules/supports-color": { 584 | "version": "5.5.0", 585 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", 586 | "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", 587 | "dev": true, 588 | "dependencies": { 589 | "has-flag": "^3.0.0" 590 | }, 591 | "engines": { 592 | "node": ">=4" 593 | } 594 | }, 595 | "node_modules/tmp": { 596 | "version": "0.0.33", 597 | "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", 598 | "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", 599 | "dev": true, 600 | "dependencies": { 601 | "os-tmpdir": "~1.0.2" 602 | }, 603 | "engines": { 604 | "node": ">=0.6.0" 605 | } 606 | }, 607 | "node_modules/to-regex-range": { 608 | "version": "5.0.1", 609 | "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", 610 | "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", 611 | "dev": true, 612 | "dependencies": { 613 | "is-number": "^7.0.0" 614 | }, 615 | "engines": { 616 | "node": ">=8.0" 617 | } 618 | }, 619 | "node_modules/universalify": { 620 | "version": "0.1.2", 621 | "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", 622 | "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", 623 | "dev": true, 624 | "engines": { 625 | "node": ">= 4.0.0" 626 | } 627 | }, 628 | "node_modules/which": { 629 | "version": "1.3.1", 630 | "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", 631 | "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", 632 | "dev": true, 633 | "dependencies": { 634 | "isexe": "^2.0.0" 635 | }, 636 | "bin": { 637 | "which": "bin/which" 638 | } 639 | }, 640 | "node_modules/worktop": { 641 | "version": "0.7.3", 642 | "resolved": "https://registry.npmjs.org/worktop/-/worktop-0.7.3.tgz", 643 | "integrity": "sha512-WBHP1hk8pLP7ahAw13fugDWcO0SUAOiCD6DHT/bfLWoCIA/PL9u7GKdudT2nGZ8EGR1APbGCAI6ZzKG1+X+PnQ==", 644 | "dev": true, 645 | "dependencies": { 646 | "regexparam": "^2.0.0" 647 | }, 648 | "engines": { 649 | "node": ">=12" 650 | } 651 | }, 652 | "node_modules/wrappy": { 653 | "version": "1.0.2", 654 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 655 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", 656 | "dev": true 657 | } 658 | }, 659 | "dependencies": { 660 | "@types/lodash": { 661 | "version": "4.14.182", 662 | "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.182.tgz", 663 | "integrity": "sha512-/THyiqyQAP9AfARo4pF+aCGcyiQ94tX/Is2I7HofNRqoYLgN1PBoOWu2/zTA5zMxzP5EFutMtWtGAFRKUe961Q==", 664 | "dev": true 665 | }, 666 | "@yarnpkg/lockfile": { 667 | "version": "1.1.0", 668 | "resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz", 669 | "integrity": "sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==", 670 | "dev": true 671 | }, 672 | "ansi-styles": { 673 | "version": "3.2.1", 674 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", 675 | "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", 676 | "dev": true, 677 | "requires": { 678 | "color-convert": "^1.9.0" 679 | } 680 | }, 681 | "balanced-match": { 682 | "version": "1.0.2", 683 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", 684 | "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", 685 | "dev": true 686 | }, 687 | "brace-expansion": { 688 | "version": "1.1.11", 689 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 690 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 691 | "dev": true, 692 | "requires": { 693 | "balanced-match": "^1.0.0", 694 | "concat-map": "0.0.1" 695 | } 696 | }, 697 | "braces": { 698 | "version": "3.0.2", 699 | "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", 700 | "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", 701 | "dev": true, 702 | "requires": { 703 | "fill-range": "^7.0.1" 704 | } 705 | }, 706 | "cfw": { 707 | "version": "0.3.0", 708 | "resolved": "https://registry.npmjs.org/cfw/-/cfw-0.3.0.tgz", 709 | "integrity": "sha512-KiN54HqdDiw2+nfCjPALoujKXn/N/e1yeCzcpctuWK4cgBbCWbxg966SITKZszXezk8K1E/8kRCfUXKyzluanQ==", 710 | "dev": true, 711 | "requires": { 712 | "esbuild": "^0.12.20", 713 | "httpie": "^1.1.2", 714 | "kleur": "^4.0.0", 715 | "klona": "^2.0.0", 716 | "sade": "^1.7.4" 717 | } 718 | }, 719 | "chalk": { 720 | "version": "2.4.2", 721 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", 722 | "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", 723 | "dev": true, 724 | "requires": { 725 | "ansi-styles": "^3.2.1", 726 | "escape-string-regexp": "^1.0.5", 727 | "supports-color": "^5.3.0" 728 | } 729 | }, 730 | "ci-info": { 731 | "version": "2.0.0", 732 | "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", 733 | "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", 734 | "dev": true 735 | }, 736 | "color-convert": { 737 | "version": "1.9.3", 738 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", 739 | "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", 740 | "dev": true, 741 | "requires": { 742 | "color-name": "1.1.3" 743 | } 744 | }, 745 | "color-name": { 746 | "version": "1.1.3", 747 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", 748 | "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", 749 | "dev": true 750 | }, 751 | "concat-map": { 752 | "version": "0.0.1", 753 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 754 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", 755 | "dev": true 756 | }, 757 | "cross-spawn": { 758 | "version": "6.0.5", 759 | "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", 760 | "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", 761 | "dev": true, 762 | "requires": { 763 | "nice-try": "^1.0.4", 764 | "path-key": "^2.0.1", 765 | "semver": "^5.5.0", 766 | "shebang-command": "^1.2.0", 767 | "which": "^1.2.9" 768 | } 769 | }, 770 | "dotenv": { 771 | "version": "16.0.1", 772 | "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.1.tgz", 773 | "integrity": "sha512-1K6hR6wtk2FviQ4kEiSjFiH5rpzEVi8WW0x96aztHVMhEspNpc4DVOUTEHtEva5VThQ8IaBX1Pe4gSzpVVUsKQ==", 774 | "dev": true 775 | }, 776 | "esbuild": { 777 | "version": "0.12.29", 778 | "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.12.29.tgz", 779 | "integrity": "sha512-w/XuoBCSwepyiZtIRsKsetiLDUVGPVw1E/R3VTFSecIy8UR7Cq3SOtwKHJMFoVqqVG36aGkzh4e8BvpO1Fdc7g==", 780 | "dev": true 781 | }, 782 | "escape-string-regexp": { 783 | "version": "1.0.5", 784 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", 785 | "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", 786 | "dev": true 787 | }, 788 | "fill-range": { 789 | "version": "7.0.1", 790 | "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", 791 | "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", 792 | "dev": true, 793 | "requires": { 794 | "to-regex-range": "^5.0.1" 795 | } 796 | }, 797 | "find-yarn-workspace-root": { 798 | "version": "2.0.0", 799 | "resolved": "https://registry.npmjs.org/find-yarn-workspace-root/-/find-yarn-workspace-root-2.0.0.tgz", 800 | "integrity": "sha512-1IMnbjt4KzsQfnhnzNd8wUEgXZ44IzZaZmnLYx7D5FZlaHt2gW20Cri8Q+E/t5tIj4+epTBub+2Zxu/vNILzqQ==", 801 | "dev": true, 802 | "requires": { 803 | "micromatch": "^4.0.2" 804 | } 805 | }, 806 | "fs-extra": { 807 | "version": "7.0.1", 808 | "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", 809 | "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", 810 | "dev": true, 811 | "requires": { 812 | "graceful-fs": "^4.1.2", 813 | "jsonfile": "^4.0.0", 814 | "universalify": "^0.1.0" 815 | } 816 | }, 817 | "fs.realpath": { 818 | "version": "1.0.0", 819 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 820 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", 821 | "dev": true 822 | }, 823 | "glob": { 824 | "version": "7.2.3", 825 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", 826 | "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", 827 | "dev": true, 828 | "requires": { 829 | "fs.realpath": "^1.0.0", 830 | "inflight": "^1.0.4", 831 | "inherits": "2", 832 | "minimatch": "^3.1.1", 833 | "once": "^1.3.0", 834 | "path-is-absolute": "^1.0.0" 835 | } 836 | }, 837 | "graceful-fs": { 838 | "version": "4.2.10", 839 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", 840 | "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", 841 | "dev": true 842 | }, 843 | "has-flag": { 844 | "version": "3.0.0", 845 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", 846 | "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", 847 | "dev": true 848 | }, 849 | "httpie": { 850 | "version": "1.1.2", 851 | "resolved": "https://registry.npmjs.org/httpie/-/httpie-1.1.2.tgz", 852 | "integrity": "sha512-VQ82oXG95oY1fQw/XecHuvcFBA+lZQ9Vwj1RfLcO8a7HpDd4cc2ukwpJt+TUlFaLUAzZErylxWu6wclJ1rUhUQ==", 853 | "dev": true 854 | }, 855 | "inflight": { 856 | "version": "1.0.6", 857 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 858 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", 859 | "dev": true, 860 | "requires": { 861 | "once": "^1.3.0", 862 | "wrappy": "1" 863 | } 864 | }, 865 | "inherits": { 866 | "version": "2.0.4", 867 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 868 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", 869 | "dev": true 870 | }, 871 | "is-ci": { 872 | "version": "2.0.0", 873 | "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", 874 | "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", 875 | "dev": true, 876 | "requires": { 877 | "ci-info": "^2.0.0" 878 | } 879 | }, 880 | "is-docker": { 881 | "version": "2.2.1", 882 | "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", 883 | "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", 884 | "dev": true 885 | }, 886 | "is-number": { 887 | "version": "7.0.0", 888 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", 889 | "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", 890 | "dev": true 891 | }, 892 | "is-wsl": { 893 | "version": "2.2.0", 894 | "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", 895 | "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", 896 | "dev": true, 897 | "requires": { 898 | "is-docker": "^2.0.0" 899 | } 900 | }, 901 | "isexe": { 902 | "version": "2.0.0", 903 | "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", 904 | "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", 905 | "dev": true 906 | }, 907 | "jsonfile": { 908 | "version": "4.0.0", 909 | "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", 910 | "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", 911 | "dev": true, 912 | "requires": { 913 | "graceful-fs": "^4.1.6" 914 | } 915 | }, 916 | "klaw-sync": { 917 | "version": "6.0.0", 918 | "resolved": "https://registry.npmjs.org/klaw-sync/-/klaw-sync-6.0.0.tgz", 919 | "integrity": "sha512-nIeuVSzdCCs6TDPTqI8w1Yre34sSq7AkZ4B3sfOBbI2CgVSB4Du4aLQijFU2+lhAFCwt9+42Hel6lQNIv6AntQ==", 920 | "dev": true, 921 | "requires": { 922 | "graceful-fs": "^4.1.11" 923 | } 924 | }, 925 | "kleur": { 926 | "version": "4.1.4", 927 | "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.4.tgz", 928 | "integrity": "sha512-8QADVssbrFjivHWQU7KkMgptGTl6WAcSdlbBPY4uNF+mWr6DGcKrvY2w4FQJoXch7+fKMjj0dRrL75vk3k23OA==", 929 | "dev": true 930 | }, 931 | "klona": { 932 | "version": "2.0.5", 933 | "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.5.tgz", 934 | "integrity": "sha512-pJiBpiXMbt7dkzXe8Ghj/u4FfXOOa98fPW+bihOJ4SjnoijweJrNThJfd3ifXpXhREjpoF2mZVH1GfS9LV3kHQ==", 935 | "dev": true 936 | }, 937 | "lodash": { 938 | "version": "4.17.21", 939 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", 940 | "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", 941 | "dev": true 942 | }, 943 | "micromatch": { 944 | "version": "4.0.5", 945 | "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", 946 | "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", 947 | "dev": true, 948 | "requires": { 949 | "braces": "^3.0.2", 950 | "picomatch": "^2.3.1" 951 | } 952 | }, 953 | "minimatch": { 954 | "version": "3.1.2", 955 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", 956 | "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", 957 | "dev": true, 958 | "requires": { 959 | "brace-expansion": "^1.1.7" 960 | } 961 | }, 962 | "minimist": { 963 | "version": "1.2.6", 964 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", 965 | "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", 966 | "dev": true 967 | }, 968 | "mri": { 969 | "version": "1.2.0", 970 | "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", 971 | "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==", 972 | "dev": true 973 | }, 974 | "nice-try": { 975 | "version": "1.0.5", 976 | "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", 977 | "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", 978 | "dev": true 979 | }, 980 | "once": { 981 | "version": "1.4.0", 982 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 983 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 984 | "dev": true, 985 | "requires": { 986 | "wrappy": "1" 987 | } 988 | }, 989 | "open": { 990 | "version": "7.4.2", 991 | "resolved": "https://registry.npmjs.org/open/-/open-7.4.2.tgz", 992 | "integrity": "sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==", 993 | "dev": true, 994 | "requires": { 995 | "is-docker": "^2.0.0", 996 | "is-wsl": "^2.1.1" 997 | } 998 | }, 999 | "os-tmpdir": { 1000 | "version": "1.0.2", 1001 | "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", 1002 | "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", 1003 | "dev": true 1004 | }, 1005 | "patch-package": { 1006 | "version": "6.4.7", 1007 | "resolved": "https://registry.npmjs.org/patch-package/-/patch-package-6.4.7.tgz", 1008 | "integrity": "sha512-S0vh/ZEafZ17hbhgqdnpunKDfzHQibQizx9g8yEf5dcVk3KOflOfdufRXQX8CSEkyOQwuM/bNz1GwKvFj54kaQ==", 1009 | "dev": true, 1010 | "requires": { 1011 | "@yarnpkg/lockfile": "^1.1.0", 1012 | "chalk": "^2.4.2", 1013 | "cross-spawn": "^6.0.5", 1014 | "find-yarn-workspace-root": "^2.0.0", 1015 | "fs-extra": "^7.0.1", 1016 | "is-ci": "^2.0.0", 1017 | "klaw-sync": "^6.0.0", 1018 | "minimist": "^1.2.0", 1019 | "open": "^7.4.2", 1020 | "rimraf": "^2.6.3", 1021 | "semver": "^5.6.0", 1022 | "slash": "^2.0.0", 1023 | "tmp": "^0.0.33" 1024 | } 1025 | }, 1026 | "path-is-absolute": { 1027 | "version": "1.0.1", 1028 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 1029 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", 1030 | "dev": true 1031 | }, 1032 | "path-key": { 1033 | "version": "2.0.1", 1034 | "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", 1035 | "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", 1036 | "dev": true 1037 | }, 1038 | "picomatch": { 1039 | "version": "2.3.1", 1040 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", 1041 | "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", 1042 | "dev": true 1043 | }, 1044 | "regexparam": { 1045 | "version": "2.0.0", 1046 | "resolved": "https://registry.npmjs.org/regexparam/-/regexparam-2.0.0.tgz", 1047 | "integrity": "sha512-gJKwd2MVPWHAIFLsaYDZfyKzHNS4o7E/v8YmNf44vmeV2e4YfVoDToTOKTvE7ab68cRJ++kLuEXJBaEeJVt5ow==", 1048 | "dev": true 1049 | }, 1050 | "rimraf": { 1051 | "version": "2.7.1", 1052 | "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", 1053 | "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", 1054 | "dev": true, 1055 | "requires": { 1056 | "glob": "^7.1.3" 1057 | } 1058 | }, 1059 | "sade": { 1060 | "version": "1.8.1", 1061 | "resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz", 1062 | "integrity": "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==", 1063 | "dev": true, 1064 | "requires": { 1065 | "mri": "^1.1.0" 1066 | } 1067 | }, 1068 | "semver": { 1069 | "version": "5.7.1", 1070 | "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", 1071 | "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", 1072 | "dev": true 1073 | }, 1074 | "shebang-command": { 1075 | "version": "1.2.0", 1076 | "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", 1077 | "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", 1078 | "dev": true, 1079 | "requires": { 1080 | "shebang-regex": "^1.0.0" 1081 | } 1082 | }, 1083 | "shebang-regex": { 1084 | "version": "1.0.0", 1085 | "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", 1086 | "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", 1087 | "dev": true 1088 | }, 1089 | "slash": { 1090 | "version": "2.0.0", 1091 | "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", 1092 | "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", 1093 | "dev": true 1094 | }, 1095 | "supports-color": { 1096 | "version": "5.5.0", 1097 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", 1098 | "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", 1099 | "dev": true, 1100 | "requires": { 1101 | "has-flag": "^3.0.0" 1102 | } 1103 | }, 1104 | "tmp": { 1105 | "version": "0.0.33", 1106 | "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", 1107 | "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", 1108 | "dev": true, 1109 | "requires": { 1110 | "os-tmpdir": "~1.0.2" 1111 | } 1112 | }, 1113 | "to-regex-range": { 1114 | "version": "5.0.1", 1115 | "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", 1116 | "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", 1117 | "dev": true, 1118 | "requires": { 1119 | "is-number": "^7.0.0" 1120 | } 1121 | }, 1122 | "universalify": { 1123 | "version": "0.1.2", 1124 | "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", 1125 | "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", 1126 | "dev": true 1127 | }, 1128 | "which": { 1129 | "version": "1.3.1", 1130 | "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", 1131 | "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", 1132 | "dev": true, 1133 | "requires": { 1134 | "isexe": "^2.0.0" 1135 | } 1136 | }, 1137 | "worktop": { 1138 | "version": "0.7.3", 1139 | "resolved": "https://registry.npmjs.org/worktop/-/worktop-0.7.3.tgz", 1140 | "integrity": "sha512-WBHP1hk8pLP7ahAw13fugDWcO0SUAOiCD6DHT/bfLWoCIA/PL9u7GKdudT2nGZ8EGR1APbGCAI6ZzKG1+X+PnQ==", 1141 | "dev": true, 1142 | "requires": { 1143 | "regexparam": "^2.0.0" 1144 | } 1145 | }, 1146 | "wrappy": { 1147 | "version": "1.0.2", 1148 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 1149 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", 1150 | "dev": true 1151 | } 1152 | } 1153 | } 1154 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "directus-cf-cache", 3 | "version": "0.0.1", 4 | "description": "", 5 | "private": true, 6 | "scripts": { 7 | "build": "cfw build", 8 | "deploy": "cfw deploy", 9 | "postinstall": "patch-package" 10 | }, 11 | "repository": { 12 | "type": "git", 13 | "url": "git+https://github.com/licitdev/directus-cf-cache.git" 14 | }, 15 | "author": "ian ", 16 | "license": "MIT", 17 | "bugs": { 18 | "url": "https://github.com/licitdev/directus-cf-cache/issues" 19 | }, 20 | "homepage": "https://github.com/licitdev/directus-cf-cache#readme", 21 | "devDependencies": { 22 | "@types/lodash": "^4.14.182", 23 | "cfw": "0.3.0", 24 | "dotenv": "^16.0.1", 25 | "lodash": "^4.17.21", 26 | "patch-package": "^6.4.7", 27 | "worktop": "^0.7.3" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /patches/cfw+0.3.0.patch: -------------------------------------------------------------------------------- 1 | diff --git a/node_modules/cfw/cfw.js b/node_modules/cfw/cfw.js 2 | index 0741f69..2306ae7 100755 3 | --- a/node_modules/cfw/cfw.js 4 | +++ b/node_modules/cfw/cfw.js 5 | @@ -1,2 +1,2 @@ 6 | #!/usr/bin/env node 7 | -import e from"sade";import t from"kleur";import{send as n}from"httpie";import{homedir as r}from"os";import{promises as o,existsSync as i}from"fs";import{createRequire as s}from"module";import{resolve as a,parse as l,join as c}from"path";import{klona as u}from"klona/json";function d(e,t={}){return e.token?t.Authorization=`Bearer ${e.token}`:(t["X-Auth-Key"]=e.authkey,t["X-Auth-Email"]=e.email),t}function m(e,t,r={}){return n(e,"https://api.cloudflare.com/client/v4"+t,r).then((e=>e.data))}const f=" ~> ",p=" ".repeat(6),g=t.bold("[CFW]");function w(e,n){console.log(t[e](g),n.includes("\n")?n.replace(/(\r?\n)/g,"$1"+p):n)}const h=e=>w("white",e),y=e=>w("green",e),k=e=>w("yellow",e);function $(e,t=1){w("red",e),process.exit(t)}const b=t.dim().bold;function v(e,t){return(t.only||t.ignore)&&(e+=`\nPerhaps the ${b("--only")} or ${b("--ignore")} flag needs adjusting`),k(e)}function T(e){return t.italic().dim(` (${e}ms)`)}function E(e,n,r){let o="•",i=t.dim,s=null!=n?T(n):"";r?(o="+",i=t.green().dim):null!=r&&(o="-",i=t.red().dim),console.log(i(p+o+` "${e}"`)+s)}async function D(e,n){let r=0,o=e.length;if(o===r)return;const i=await import("esbuild");let s=await i.formatMessages(e,{terminalWidth:process.stdout.columns,kind:n?"error":"warning",color:t.enabled}),a=/\x1b\[32m/g,l=n?"":"",c=n?t.red:t.yellow,u=`Build ${n?"failed":"finished"} with`;for(u+=" "+t.underline(o)+" ",u+=n?"error":"warning",u+=1===o?":":"s:",u+="\n\n";r{$(`Error fetching "${t}" secrets!\n${JSON.stringify(e.data||e.message,null,2)}`)}))}function C(e,t,n,r){return m("PUT",`/accounts/${e.accountid}/workers/scripts/${t}/secrets`,{headers:d(e),body:{type:"secret_text",text:r,name:n}}).catch((e=>{$(`Error creating new "${t}" secret!\n${JSON.stringify(e.data||e.message,null,2)}`)}))}function W(e,t,n,r){return m("DELETE",`/accounts/${e.accountid}/workers/scripts/${t}/secrets/${n}`,{headers:d(e)}).catch((e=>{let{data:o,message:i}=e;if(r&&o&&o.errors&&10056===o.errors[0].code)return o;$(`Error deleting "${t}/${n}" secret!\n${JSON.stringify(o||i,null,2)}`)}))}const L=o.rm||o.rmdir,_=o.writeFile,A=o.readFile,N=o.readdir;function j(e,t,n){n&&i(e)||e||$(t)}function x(e){return new Set(Array.isArray(e)?e:e.split(","))}const U=s(import.meta.url);async function R(e,t="."){if(!i(e=a(t,e)))return!1;try{var n=U(e)}catch{n=await import(e).catch((()=>!1))}finally{return n||$(`Error loading "${e}" file`)}}async function S(e){let t;return(t=await R("cfw.js",e))||(t=await R("cfw.mjs",e))||(t=await R("cfw.cjs",e))||(t=await R("cfw.json",e))?t:(t=await R("package.json",e))?t.cfw:void 0}async function F(e,t,n){let r=n?e:c(e,t),o=await S(r)||{};return{cfw:o,name:o.name||t,input:c(r,o.entry||"index.js"),abs:r}}async function P(e,t){t.cwd=a(t.cwd);let n,r,o=a(t.cwd,e);j(o,`Workers directory does not exist: "${o}"`,!0);let{cwd:i,single:s,only:c,ignore:u}=t;if(s){let e=t.dir;"."===e&&(e=l(i).base);let n=await F(o,e,!0);return(r=await S(i))&&(Object.assign(n.cfw,r),r.name&&(n.name=r.name),t.profile&&(n.cfw.profile=t.profile)),[n]}let d=await N(o,{withFileTypes:!0}).then((e=>Promise.all(e.filter((e=>e.isDirectory())).map((e=>F(o,e.name))))));return c?(n=x(c),d.filter((e=>n.has(e.name)))):u?(n=x(u),d.filter((e=>!n.has(e.name)))):d}async function K(e,t){let{CLOUDFLARE_ZONEID:n,CLOUDFLARE_ACCOUNTID:o,CLOUDFLARE_AUTH_EMAIL:i,CLOUDFLARE_AUTH_KEY:s,CLOUDFLARE_TOKEN:a}=process.env,l=i||e.email,u=s||e.authkey,d=o||e.accountid,m=n||e.zoneid,f=a||e.token;if((f||u&&l)&&d&&m)return{authkey:u,accountid:d,email:l,token:f,zoneid:m};if(e.profile){let t,n=await async function(e="default"){let t=c(r(),".cfw","config");j(t,`Missing "${t}" config file`,!0);let n,o,i={},s=0,a=/^\[(.*)\]$/,l=(await A(t,"utf8")).split(/(\r?\n)+/g);for(;sMath.random().toString(36).slice(2);function I(e,t,n){return m("POST",`/zones/${e.zoneid}/workers/routes`,{headers:d(e,{"Content-Type":"application/javascript"}),body:{pattern:t,script:n}}).catch((e=>{let{data:n,message:r}=e;n&&n.errors&&10020===n.errors[0].code||$(`Error setting "${t}" route pattern!\n${JSON.stringify(n||r,null,2)}`)}))}async function M(e,t,n,r,o){const i="----"+J()+J();let s="entry",a={type:"application/javascript",value:n};o?(a.type+="+module",s=a.filename="./index.mjs",r.main_module="./index.mjs"):r.body_part=s;const l=function(e,t){let n,r,o="",i="\r\n",s="--"+e;for(n in t)r=t[n],o+=s+i,o+=`Content-Disposition: form-data; name="${n}"`,r.filename&&(o+=`; filename="${r.filename}"`),r.type&&(o+=`\r\nContent-Type: ${r.type}`),o+=i+i+r.value+i;return o+s+"--"}(i,{[s]:a,metadata:{type:"application/json",value:JSON.stringify(r),filename:"metadata.json"}});return m("PUT",`/accounts/${e.accountid}/workers/scripts/${t}`,{headers:d(e,{"Content-Type":`multipart/form-data; boundary=${i}`}),body:l}).catch((e=>{$(`Error uploading "${t}" script!\n${JSON.stringify(e.data||e.message,null,2)}`)}))}function q(e,t,n){return m("PUT",`/accounts/${e.accountid}/workers/scripts/${t}/schedules`,{headers:d(e,{"Content-Type":"application/javascript"}),body:n}).catch((e=>{$(`Error updating "${t}" CRON triggers!\n${JSON.stringify(e.data||e.message,null,2)}`)}))}function z(e){return m("GET",`/accounts/${e.accountid}/workers/subdomain`,{headers:d(e)}).then((e=>{let t=e.success&&e.result.subdomain;return t?`${t}.workers.dev`:$("You must register a subdomain!")})).catch((e=>{$(`Error fetching your workers.dev subdomain!\n${JSON.stringify(e.data||e.message,null,2)}`)}))}function V(e,t,n){return m("POST",`/accounts/${e.accountid}/workers/scripts/${t}/subdomain`,{headers:d(e),body:{enabled:n}}).catch((e=>{$(`Error publishing "${t}" to workers.dev subdomain!\n${JSON.stringify(e.data||e.message,null,2)}`)}))}const B={env:"plain_text",wasm:"wasm_module",secret:"secret_text",kv:"kv_namespace"};function H(e,t){let n=t.indexOf(":"),r=t.substring(0,n),o=t.substring(n+1),i=B[r.toLowerCase()];return i||$(`Unknown binding hint: "${r}"`),"wasm_module"===i?{type:i,name:e,part:"wasm"}:"kv_namespace"===i?{type:i,name:e,namespace_id:o}:{type:i,name:e,text:o}}function Y(e){let t,n=[];for(t in e)n.push(H(t,e[t]));return{bindings:n}}const G={bundle:!0,format:"esm",charset:"utf8",sourcemap:!1,outfile:"",entryPoints:[""],minify:!0,logLevel:"silent",resolveExtensions:[".tsx",".ts",".jsx",".mjs",".js",".json"],mainFields:["worker","browser","module","jsnext","main"],conditions:["worker","browser","import","production"]};e("cfw").version("0.2.0").option("-C, --cwd","The relative working directory",".").option("-P, --profile","The CFW account profile to load").command("build [dir] [output]").describe("Compile the Worker(s) within a directory.").option("-d, --dir","The directory containing Worker scripts","workers").option("-o, --only","The list of Worker names to build; overrides `--ignore` list!").option("-i, --ignore","The list of Worker names to skip").option("-s, --single","The target is a single Worker").action((async function(e,n,r){r.dir=e||r.dir;let o=await P(r.dir,r);if(!o.length)return v("Nothing to build!",r);let s=n||"build";n=a(r.cwd,s),e=a(r.cwd,r.dir),i(n)&&(k(`Removing existing "${s}" directory`),await L(n,{recursive:!0}));const l=await import("esbuild");let d="false"!==String(r.minify),m=t.cyan(f),p=t.bold(o.length),g=1===o.length?"":"s";h(`Building ${p} worker${g}:`);for(let e of o){let o=u(G),{name:i,input:s,cfw:a}=e;if(o.entryPoints=[s],o.minify=d,"function"==typeof a.build){a.build(o);let e=[];if(o.splitting&&e.push("splitting"),(o.external||[]).length&&e.push("external"),"esm"!==o.format&&e.push("format"),o.sourcemap&&e.push("sourcemap"),e.length){let n="\n "+t.dim().red("- "),r="Invalid configuration customization!\nPlease revert or remove the following keys:";return e.forEach((e=>r+=n+e)),$(r)}}let f=c(n,r.single?"":i);o.outfile=c(f,"index.js");try{var w=Date.now(),b=await l.build(o)}catch(e){let{errors:t}=e;return await D(t,!0)}delete a.entry,await _(c(f,"cfw.json"),JSON.stringify({name:i,...a},null,2)),console.log(m+i+T(Date.now()-w)),await D(b.warnings)}y(`Build complete!\nYour worker${g} ${1===o.length?"is":"are"} ready for deployment 🎉`)})).command("deploy [output]").describe("Deploy the built Worker(s) – requires you `build` first.").option("-d, --dir","The directory containing Worker scripts","workers").option("-o, --only","The list of Worker names to build; overrides `--ignore` list!").option("-i, --ignore","The list of Worker names to skip").option("-s, --single","The target is a single Worker").action((async function(e,n){let r,o=e||"build",i=await P(o,n);if(!i.length)return v("Nothing to deploy!",n);let s=t.cyan(f),a=t.bold(i.length),l=1===i.length?"":"s";h(`Deploying ${a} worker${l}:`);for(let e of i){let{name:t,input:o,cfw:i}=e;i.profile=i.profile||n.profile,j(o,`Worker input does not exist: "${o}"`,!0);let a=await K(i),l=Y(i.globals||{}),c=await A(o);if(i.usage){let e=(i.usage||"").toLowerCase().trim();j(/^(bundled|unbound)$/.test(e),`Invalid "usage" value: "${e}"`),l.usage_model=e}let u=Date.now();if(await M(a,t,c,l,!!i.module),console.log(s+t+T(Date.now()-u)),null==i.subdomain||r||(r=await z(a)),i.subdomain){let e=Date.now();await V(a,t,!0),E(`https://${t}.${r}/*`,Date.now()-e,!0)}else if(i.routes&&(await Promise.all(i.routes.map((e=>{let n=Date.now(),r=e.startsWith("!"),o=e.substring(+r);return I(a,o,r?null:t).then((()=>{E(o,Date.now()-n,!r)}))}))),null!=i.subdomain)){let e=Date.now();await V(a,t,!1),E(`https://${t}.${r}/*`,Date.now()-e,!1)}if(i.cron&&i.cron.length){let e=0,n=[],r=/([^\s]+\s+){4}/;for(;e ").alias("secrets new","secrets add","secrets put").describe("Create a new secret for the Worker(s) within a directory.").option("-d, --dir","The directory containing Worker scripts","workers").option("-o, --only","The list of Worker names to query; overrides `--ignore` list!").option("-i, --ignore","The list of Worker names to skip").option("-s, --single","The target is a single Worker").action((async function(e,n,r){let o=await P(r.dir,r);if(!o.length)return v("No workers found!",r);let i=t.cyan(f),s=t.bold(o.length),a=1===o.length?"":"s",l=[];h(`Adding secret "${e}" value to ${s} worker${a}:`);for(let t of o){let{name:o,cfw:s}=t;s.profile=s.profile||r.profile;let a=await K(s);l.push((()=>{let t=Date.now();return C(a,o,e,n).then((e=>{e.success&&console.log(i+o+T(Date.now()-t))}))}))}await Promise.all(l.map((e=>e()))),y(`Added secret to worker${a}`)})).command("secrets destroy ").alias("secrets delete","secrets rm").describe("Remove a secret from the Worker(s) within a directory.").option("-d, --dir","The directory containing Worker scripts","workers").option("-o, --only","The list of Worker names to query; overrides `--ignore` list!").option("-q, --quiet","Do not throw error if Worker is missing secret").option("-i, --ignore","The list of Worker names to skip").option("-s, --single","The target is a single Worker").action((async function(e,n){let r=await P(n.dir,n);if(!r.length)return v("No workers found!",n);let o=t.bold(r.length),i=1===r.length?"":"s",s=[];h(`Removing "${e}" secret from ${o} worker${i}:`);for(let o of r){let{name:r,cfw:i}=o;i.profile=i.profile||n.profile;let a=await K(i);s.push((()=>{let o=Date.now();return W(a,r,e,!!n.quiet).then((e=>{let n=(e.success?t.cyan:t.red)(f);console.log(n+r+T(Date.now()-o))}))}))}await Promise.all(s.map((e=>e()))),y(`Removed secret from worker${i}`)})).command("kv namespaces list").describe("List all KV namespaces").alias("kv ns list","kv ns ls").action((async function(e){const n=await K(e,!0);h("Retrieving KV namespaces:");const r=await function(e){return m("GET",`/accounts/${e.accountid}/storage/kv/namespaces?per_page=100&order=title`,{headers:d(e)})}(n),o=" ",i=t.dim().bold().italic;y(i("ID")+" ".repeat(30)+o+i("Title"));let s=0,a=r.result,l="";for(;s").describe("Create a new KV namespace").alias("kv ns create","kv ns new").action((async function(e,n){const r=await K(n,!0);h("Creating new KV namespace:");const o=await function(e,t){return m("POST",`/accounts/${e.accountid}/storage/kv/namespaces`,{headers:d(e),body:{title:t}}).catch((e=>{$(`Error creating "${t}" namespace!\n${JSON.stringify(e.data||e.message,null,2)}`)}))}(r,e);if(!o)return $("Error creating namespace");console.log(t.cyan(f)+`"${o.result.title}" `+t.italic().dim(`(ID: ${o.result.id})`)),y("KV namespace created!")})).command("kv namespaces destroy ").describe("Destroy a KV namespace").alias("kv ns delete","kv ns rm").action((async function(e,t){const n=await K(t,!0);k("Deleting KV namespace");const r=await function(e,t){return m("DELETE",`/accounts/${e.accountid}/storage/kv/namespaces/${t}`,{headers:d(e)}).catch((e=>{$(`Error removing "${t}" namespace!\n${JSON.stringify(e.data||e.message,null,2)}`)}))}(n,e);if(!r||!r.success)return $("Error deleting namespace");y("KV namespace deleted!")})).parse(process.argv,{boolean:["single","quiet"],string:["only","ignore","profile"]}); 8 | +import"dotenv/config";import e from"sade";import t from"kleur";import{send as n}from"httpie";import{homedir as r}from"os";import{promises as o,existsSync as i}from"fs";import{createRequire as s}from"module";import{resolve as a,parse as l,join as c}from"path";import{klona as u}from"klona/json";function d(e,t={}){return e.token?t.Authorization=`Bearer ${e.token}`:(t["X-Auth-Key"]=e.authkey,t["X-Auth-Email"]=e.email),t}function m(e,t,r={}){return n(e,"https://api.cloudflare.com/client/v4"+t,r).then((e=>e.data))}const f=" ~> ",p=" ".repeat(6),g=t.bold("[CFW]");function w(e,n){console.log(t[e](g),n.includes("\n")?n.replace(/(\r?\n)/g,"$1"+p):n)}const h=e=>w("white",e),y=e=>w("green",e),k=e=>w("yellow",e);function $(e,t=1){w("red",e),process.exit(t)}const b=t.dim().bold;function v(e,t){return(t.only||t.ignore)&&(e+=`\nPerhaps the ${b("--only")} or ${b("--ignore")} flag needs adjusting`),k(e)}function T(e){return t.italic().dim(` (${e}ms)`)}function E(e,n,r){let o="•",i=t.dim,s=null!=n?T(n):"";r?(o="+",i=t.green().dim):null!=r&&(o="-",i=t.red().dim),console.log(i(p+o+` "${e}"`)+s)}async function D(e,n){let r=0,o=e.length;if(o===r)return;const i=await import("esbuild");let s=await i.formatMessages(e,{terminalWidth:process.stdout.columns,kind:n?"error":"warning",color:t.enabled}),a=/\x1b\[32m/g,l=n?"":"",c=n?t.red:t.yellow,u=`Build ${n?"failed":"finished"} with`;for(u+=" "+t.underline(o)+" ",u+=n?"error":"warning",u+=1===o?":":"s:",u+="\n\n";r{$(`Error fetching "${t}" secrets!\n${JSON.stringify(e.data||e.message,null,2)}`)}))}function C(e,t,n,r){return m("PUT",`/accounts/${e.accountid}/workers/scripts/${t}/secrets`,{headers:d(e),body:{type:"secret_text",text:r,name:n}}).catch((e=>{$(`Error creating new "${t}" secret!\n${JSON.stringify(e.data||e.message,null,2)}`)}))}function W(e,t,n,r){return m("DELETE",`/accounts/${e.accountid}/workers/scripts/${t}/secrets/${n}`,{headers:d(e)}).catch((e=>{let{data:o,message:i}=e;if(r&&o&&o.errors&&10056===o.errors[0].code)return o;$(`Error deleting "${t}/${n}" secret!\n${JSON.stringify(o||i,null,2)}`)}))}const L=o.rm||o.rmdir,_=o.writeFile,A=o.readFile,N=o.readdir;function j(e,t,n){n&&i(e)||e||$(t)}function x(e){return new Set(Array.isArray(e)?e:e.split(","))}const U=s(import.meta.url);async function R(e,t="."){if(!i(e=a(t,e)))return!1;try{var n=U(e)}catch{n=await import(e).catch((()=>!1))}finally{return n||$(`Error loading "${e}" file`)}}async function S(e){let t;return(t=await R("cfw.js",e))||(t=await R("cfw.mjs",e))||(t=await R("cfw.cjs",e))||(t=await R("cfw.json",e))?t:(t=await R("package.json",e))?t.cfw:void 0}async function F(e,t,n){let r=n?e:c(e,t),o=await S(r)||{};return{cfw:o,name:o.name||t,input:c(r,o.entry||"index.js"),abs:r}}async function P(e,t){t.cwd=a(t.cwd);let n,r,o=a(t.cwd,e);j(o,`Workers directory does not exist: "${o}"`,!0);let{cwd:i,single:s,only:c,ignore:u}=t;if(s){let e=t.dir;"."===e&&(e=l(i).base);let n=await F(o,e,!0);return(r=await S(i))&&(Object.assign(n.cfw,r),r.name&&(n.name=r.name),t.profile&&(n.cfw.profile=t.profile)),[n]}let d=await N(o,{withFileTypes:!0}).then((e=>Promise.all(e.filter((e=>e.isDirectory())).map((e=>F(o,e.name))))));return c?(n=x(c),d.filter((e=>n.has(e.name)))):u?(n=x(u),d.filter((e=>!n.has(e.name)))):d}async function K(e,t){let{CLOUDFLARE_ZONEID:n,CLOUDFLARE_ACCOUNTID:o,CLOUDFLARE_AUTH_EMAIL:i,CLOUDFLARE_AUTH_KEY:s,CLOUDFLARE_TOKEN:a}=process.env,l=i||e.email,u=s||e.authkey,d=o||e.accountid,m=n||e.zoneid,f=a||e.token;if((f||u&&l)&&d&&m)return{authkey:u,accountid:d,email:l,token:f,zoneid:m};if(e.profile){let t,n=await async function(e="default"){let t=c(r(),".cfw","config");j(t,`Missing "${t}" config file`,!0);let n,o,i={},s=0,a=/^\[(.*)\]$/,l=(await A(t,"utf8")).split(/(\r?\n)+/g);for(;sMath.random().toString(36).slice(2);function I(e,t,n){return m("POST",`/zones/${e.zoneid}/workers/routes`,{headers:d(e,{"Content-Type":"application/javascript"}),body:{pattern:t,script:n}}).catch((e=>{let{data:n,message:r}=e;n&&n.errors&&10020===n.errors[0].code||$(`Error setting "${t}" route pattern!\n${JSON.stringify(n||r,null,2)}`)}))}async function M(e,t,n,r,o){const i="----"+J()+J();let s="entry",a={type:"application/javascript",value:n};o?(a.type+="+module",s=a.filename="./index.mjs",r.main_module="./index.mjs"):r.body_part=s;const l=function(e,t){let n,r,o="",i="\r\n",s="--"+e;for(n in t)r=t[n],o+=s+i,o+=`Content-Disposition: form-data; name="${n}"`,r.filename&&(o+=`; filename="${r.filename}"`),r.type&&(o+=`\r\nContent-Type: ${r.type}`),o+=i+i+r.value+i;return o+s+"--"}(i,{[s]:a,metadata:{type:"application/json",value:JSON.stringify(r),filename:"metadata.json"}});return m("PUT",`/accounts/${e.accountid}/workers/scripts/${t}`,{headers:d(e,{"Content-Type":`multipart/form-data; boundary=${i}`}),body:l}).catch((e=>{$(`Error uploading "${t}" script!\n${JSON.stringify(e.data||e.message,null,2)}`)}))}function q(e,t,n){return m("PUT",`/accounts/${e.accountid}/workers/scripts/${t}/schedules`,{headers:d(e,{"Content-Type":"application/javascript"}),body:n}).catch((e=>{$(`Error updating "${t}" CRON triggers!\n${JSON.stringify(e.data||e.message,null,2)}`)}))}function z(e){return m("GET",`/accounts/${e.accountid}/workers/subdomain`,{headers:d(e)}).then((e=>{let t=e.success&&e.result.subdomain;return t?`${t}.workers.dev`:$("You must register a subdomain!")})).catch((e=>{$(`Error fetching your workers.dev subdomain!\n${JSON.stringify(e.data||e.message,null,2)}`)}))}function V(e,t,n){return m("POST",`/accounts/${e.accountid}/workers/scripts/${t}/subdomain`,{headers:d(e),body:{enabled:n}}).catch((e=>{$(`Error publishing "${t}" to workers.dev subdomain!\n${JSON.stringify(e.data||e.message,null,2)}`)}))}const B={env:"plain_text",wasm:"wasm_module",secret:"secret_text",kv:"kv_namespace"};function H(e,t){let n=t.indexOf(":"),r=t.substring(0,n),o=t.substring(n+1),i=B[r.toLowerCase()];return i||$(`Unknown binding hint: "${r}"`),"wasm_module"===i?{type:i,name:e,part:"wasm"}:"kv_namespace"===i?{type:i,name:e,namespace_id:o}:{type:i,name:e,text:o}}function Y(e){let t,n=[];for(t in e)n.push(H(t,e[t]));return{bindings:n}}const G={bundle:!0,format:"esm",charset:"utf8",sourcemap:!1,outfile:"",entryPoints:[""],minify:!0,logLevel:"silent",resolveExtensions:[".tsx",".ts",".jsx",".mjs",".js",".json"],mainFields:["worker","browser","module","jsnext","main"],conditions:["worker","browser","import","production"]};e("cfw").version("0.3.0").option("-C, --cwd","The relative working directory",".").option("-P, --profile","The CFW account profile to load").command("build [dir] [output]").describe("Compile the Worker(s) within a directory.").option("-d, --dir","The directory containing Worker scripts","workers").option("-o, --only","The list of Worker names to build; overrides `--ignore` list!").option("-i, --ignore","The list of Worker names to skip").option("-s, --single","The target is a single Worker").action((async function(e,n,r){r.dir=e||r.dir;let o=await P(r.dir,r);if(!o.length)return v("Nothing to build!",r);let s=n||"build";n=a(r.cwd,s),e=a(r.cwd,r.dir),i(n)&&(k(`Removing existing "${s}" directory`),await L(n,{recursive:!0}));const l=await import("esbuild");let d="false"!==String(r.minify),m=t.cyan(f),p=t.bold(o.length),g=1===o.length?"":"s";h(`Building ${p} worker${g}:`);for(let e of o){let o=u(G),{name:i,input:s,cfw:a}=e;if(o.entryPoints=[s],o.minify=d,"function"==typeof a.build){a.build(o);let e=[];if(o.splitting&&e.push("splitting"),(o.external||[]).length&&e.push("external"),"esm"!==o.format&&e.push("format"),o.sourcemap&&e.push("sourcemap"),e.length){let n="\n "+t.dim().red("- "),r="Invalid configuration customization!\nPlease revert or remove the following keys:";return e.forEach((e=>r+=n+e)),$(r)}}let f=c(n,r.single?"":i);o.outfile=c(f,"index.js");try{var w=Date.now(),b=await l.build(o)}catch(e){let{errors:t}=e;return await D(t,!0)}delete a.entry,await _(c(f,"cfw.json"),JSON.stringify({name:i,...a},null,2)),console.log(m+i+T(Date.now()-w)),await D(b.warnings)}y(`Build complete!\nYour worker${g} ${1===o.length?"is":"are"} ready for deployment 🎉`)})).command("deploy [output]").describe("Deploy the built Worker(s) – requires you `build` first.").option("-d, --dir","The directory containing Worker scripts","workers").option("-o, --only","The list of Worker names to build; overrides `--ignore` list!").option("-i, --ignore","The list of Worker names to skip").option("-s, --single","The target is a single Worker").action((async function(e,n){let r,o=e||"build",i=await P(o,n);if(!i.length)return v("Nothing to deploy!",n);let s=t.cyan(f),a=t.bold(i.length),l=1===i.length?"":"s";h(`Deploying ${a} worker${l}:`);for(let e of i){let{name:t,input:o,cfw:i}=e;i.profile=i.profile||n.profile,j(o,`Worker input does not exist: "${o}"`,!0);let a=await K(i),l=Y(i.globals||{}),c=await A(o);if(i.usage){let e=(i.usage||"").toLowerCase().trim();j(/^(bundled|unbound)$/.test(e),`Invalid "usage" value: "${e}"`),l.usage_model=e}let u=Date.now();if(await M(a,t,c,l,!!i.module),console.log(s+t+T(Date.now()-u)),null==i.subdomain||r||(r=await z(a)),i.subdomain){let e=Date.now();await V(a,t,!0),E(`https://${t}.${r}/*`,Date.now()-e,!0)}else if(i.routes&&(await Promise.all(i.routes.map((e=>{let n=Date.now(),r=e.startsWith("!"),o=e.substring(+r);return I(a,o,r?null:t).then((()=>{E(o,Date.now()-n,!r)}))}))),null!=i.subdomain)){let e=Date.now();await V(a,t,!1),E(`https://${t}.${r}/*`,Date.now()-e,!1)}if(i.cron&&i.cron.length){let e=0,n=[],r=/([^\s]+\s+){4}/;for(;e ").alias("secrets new","secrets add","secrets put").describe("Create a new secret for the Worker(s) within a directory.").option("-d, --dir","The directory containing Worker scripts","workers").option("-o, --only","The list of Worker names to query; overrides `--ignore` list!").option("-i, --ignore","The list of Worker names to skip").option("-s, --single","The target is a single Worker").action((async function(e,n,r){let o=await P(r.dir,r);if(!o.length)return v("No workers found!",r);let i=t.cyan(f),s=t.bold(o.length),a=1===o.length?"":"s",l=[];h(`Adding secret "${e}" value to ${s} worker${a}:`);for(let t of o){let{name:o,cfw:s}=t;s.profile=s.profile||r.profile;let a=await K(s);l.push((()=>{let t=Date.now();return C(a,o,e,n).then((e=>{e.success&&console.log(i+o+T(Date.now()-t))}))}))}await Promise.all(l.map((e=>e()))),y(`Added secret to worker${a}`)})).command("secrets destroy ").alias("secrets delete","secrets rm").describe("Remove a secret from the Worker(s) within a directory.").option("-d, --dir","The directory containing Worker scripts","workers").option("-o, --only","The list of Worker names to query; overrides `--ignore` list!").option("-q, --quiet","Do not throw error if Worker is missing secret").option("-i, --ignore","The list of Worker names to skip").option("-s, --single","The target is a single Worker").action((async function(e,n){let r=await P(n.dir,n);if(!r.length)return v("No workers found!",n);let o=t.bold(r.length),i=1===r.length?"":"s",s=[];h(`Removing "${e}" secret from ${o} worker${i}:`);for(let o of r){let{name:r,cfw:i}=o;i.profile=i.profile||n.profile;let a=await K(i);s.push((()=>{let o=Date.now();return W(a,r,e,!!n.quiet).then((e=>{let n=(e.success?t.cyan:t.red)(f);console.log(n+r+T(Date.now()-o))}))}))}await Promise.all(s.map((e=>e()))),y(`Removed secret from worker${i}`)})).command("kv namespaces list").describe("List all KV namespaces").alias("kv ns list","kv ns ls").action((async function(e){const n=await K(e,!0);h("Retrieving KV namespaces:");const r=await function(e){return m("GET",`/accounts/${e.accountid}/storage/kv/namespaces?per_page=100&order=title`,{headers:d(e)})}(n),o=" ",i=t.dim().bold().italic;y(i("ID")+" ".repeat(30)+o+i("Title"));let s=0,a=r.result,l="";for(;s").describe("Create a new KV namespace").alias("kv ns create","kv ns new").action((async function(e,n){const r=await K(n,!0);h("Creating new KV namespace:");const o=await function(e,t){return m("POST",`/accounts/${e.accountid}/storage/kv/namespaces`,{headers:d(e),body:{title:t}}).catch((e=>{$(`Error creating "${t}" namespace!\n${JSON.stringify(e.data||e.message,null,2)}`)}))}(r,e);if(!o)return $("Error creating namespace");console.log(t.cyan(f)+`"${o.result.title}" `+t.italic().dim(`(ID: ${o.result.id})`)),y("KV namespace created!")})).command("kv namespaces destroy ").describe("Destroy a KV namespace").alias("kv ns delete","kv ns rm").action((async function(e,t){const n=await K(t,!0);k("Deleting KV namespace");const r=await function(e,t){return m("DELETE",`/accounts/${e.accountid}/storage/kv/namespaces/${t}`,{headers:d(e)}).catch((e=>{$(`Error removing "${t}" namespace!\n${JSON.stringify(e.data||e.message,null,2)}`)}))}(n,e);if(!r||!r.success)return $("Error deleting namespace");y("KV namespace deleted!")})).parse(process.argv,{boolean:["single","quiet"],string:["only","ignore","profile"]}); 9 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strict": true, 4 | "target": "esnext", 5 | "moduleResolution": "node", 6 | "forceConsistentCasingInFileNames": true, 7 | "lib": ["esnext", "dom.iterable", "webworker"], 8 | "strictFunctionTypes": true, 9 | "strictNullChecks": true, 10 | "noImplicitThis": true, 11 | "noImplicitAny": true 12 | }, 13 | "include": ["workers/**/*"], 14 | "exclude": ["node_modules"] 15 | } 16 | -------------------------------------------------------------------------------- /workers/.eslint.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | node: true, 4 | es2020: true, 5 | }, 6 | extends: ['prettier'], 7 | rules: { 8 | }, 9 | }; -------------------------------------------------------------------------------- /workers/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "useTabs": true, 4 | "printWidth": 120, 5 | "proseWrap": "always", 6 | "semi": true 7 | } -------------------------------------------------------------------------------- /workers/directus-cf-cache-worker/api.ts: -------------------------------------------------------------------------------- 1 | import * as Items from './itemStore'; 2 | import * as Assets from './assetStore'; 3 | import type { CFCacheOptions, PresetRequest } from './itemStore'; 4 | import type { Webhook } from './webhook'; 5 | import type { Handler } from 'worktop'; 6 | import { get } from 'lodash'; 7 | 8 | const TABLE_CF_CACHE_OPTIONS = 'cf_cache_options'; 9 | 10 | /** 11 | * GET /list/:collection 12 | * GET /list/:collection/:key 13 | */ 14 | export const listItems: Handler = async function (req, res) { 15 | const cfCacheOptions = await getCFCacheOptions(); 16 | 17 | if (!cfCacheOptions) { 18 | return res.send(400, { message: 'Unable to retrieve cache options.' }); 19 | } 20 | 21 | const { collection, key } = req.params; 22 | 23 | const preset = cfCacheOptions.preset_requests.find( 24 | (p: PresetRequest) => p.collection === collection && p.key === (key ?? null) && p.operation === 'list' 25 | ); 26 | 27 | if (!preset) { 28 | return res.send(400, { message: 'Unable to find preset.' }); 29 | } else if (!preset.enabled) { 30 | return res.send(400, { message: 'Preset is disabled.' }); 31 | } 32 | 33 | const readKV = async () => { 34 | const { collection, key } = req.params; 35 | const data = await Items.read(collection, key ?? '', ''); 36 | 37 | return data; 38 | }; 39 | 40 | const fetchOrigin = async () => { 41 | if (preset.query_params['filter']) { 42 | preset.query_params['filter'] = JSON.stringify(preset.query_params['filter']); 43 | } 44 | 45 | const url = new URL(`${DIRECTUS_SERVER_URL}/items/${collection}`); 46 | 47 | url.search = new URLSearchParams({ 48 | ...preset.query_params, 49 | access_token: DIRECTUS_ACCESS_TOKEN, 50 | }).toString(); 51 | 52 | const response = await fetch(url); 53 | 54 | if (response.status === 200) { 55 | const item = await response.json(); 56 | 57 | if (item.data) { 58 | return item.data; 59 | } 60 | } 61 | 62 | return null; 63 | }; 64 | 65 | let data; 66 | const headers = {} as Record; 67 | 68 | switch (cfCacheOptions.cache_mode) { 69 | case 'origin_priority': 70 | data = await fetchOrigin(); 71 | headers['Cache-Source'] = 'origin'; 72 | 73 | if (!data) { 74 | data = await readKV(); 75 | headers['Cache-Source'] = 'cache'; 76 | } 77 | break; 78 | case 'cache_priority': 79 | data = await readKV(); 80 | headers['Cache-Source'] = 'cache'; 81 | 82 | if (!data) { 83 | data = await fetchOrigin(); 84 | headers['Cache-Source'] = 'origin'; 85 | } 86 | break; 87 | case 'origin_only': 88 | data = await fetchOrigin(); 89 | headers['Cache-Source'] = 'origin'; 90 | break; 91 | case 'cache_only': 92 | data = await readKV(); 93 | headers['Cache-Source'] = 'cache'; 94 | break; 95 | default: 96 | return res.send(500, { message: 'Unsupported cache mode.' }); 97 | } 98 | 99 | if (!data) { 100 | return res.send(404); 101 | } 102 | 103 | res.send(200, data, headers); 104 | }; 105 | 106 | /** 107 | * GET /get/:collection/:pk 108 | * GET /get/:collection/:pk/:key 109 | */ 110 | export const getItem: Handler = async function (req, res) { 111 | const cfCacheOptions = await getCFCacheOptions(); 112 | 113 | if (!cfCacheOptions) { 114 | return res.send(400, { message: 'Unable to retrieve cache options.' }); 115 | } 116 | 117 | const { collection, key, pk } = req.params; 118 | 119 | const preset = cfCacheOptions.preset_requests.find( 120 | (p: PresetRequest) => p.collection === collection && p.key === (key ?? null) && p.operation === 'get' 121 | ); 122 | 123 | if (!preset) { 124 | return res.send(400, { message: 'Unable to find preset.' }); 125 | } else if (!preset.enabled) { 126 | return res.send(400, { message: 'Preset is disabled.' }); 127 | } 128 | 129 | const readKV = async () => { 130 | const { collection, key } = req.params; 131 | const data = await Items.read(collection, key ?? '', pk); 132 | 133 | return data; 134 | }; 135 | 136 | const fetchOrigin = async () => { 137 | if (preset.query_params['filter']) { 138 | preset.query_params['filter'] = JSON.stringify(preset.query_params['filter']); 139 | } 140 | 141 | const url = new URL(`${DIRECTUS_SERVER_URL}/items/${collection}/${pk}`); 142 | 143 | url.search = new URLSearchParams({ 144 | ...preset.query_params, 145 | access_token: DIRECTUS_ACCESS_TOKEN, 146 | }).toString(); 147 | 148 | const response = await fetch(url); 149 | 150 | if (response.status === 200) { 151 | const item = await response.json(); 152 | 153 | if (item.data) { 154 | return item.data; 155 | } 156 | } 157 | 158 | return null; 159 | }; 160 | 161 | let data; 162 | const headers = {} as Record; 163 | 164 | switch (cfCacheOptions.cache_mode) { 165 | case 'origin_priority': 166 | data = await fetchOrigin(); 167 | headers['Cache-Source'] = 'origin'; 168 | 169 | if (!data) { 170 | data = await readKV(); 171 | headers['Cache-Source'] = 'cache'; 172 | } 173 | break; 174 | case 'cache_priority': 175 | data = await readKV(); 176 | headers['Cache-Source'] = 'cache'; 177 | 178 | if (!data) { 179 | data = await fetchOrigin(); 180 | headers['Cache-Source'] = 'origin'; 181 | } 182 | break; 183 | case 'origin_only': 184 | data = await fetchOrigin(); 185 | headers['Cache-Source'] = 'origin'; 186 | break; 187 | case 'cache_only': 188 | data = await readKV(); 189 | headers['Cache-Source'] = 'cache'; 190 | break; 191 | default: 192 | return res.send(500, { message: 'Unsupported cache mode.' }); 193 | } 194 | 195 | if (!data) { 196 | return res.send(404); 197 | } 198 | 199 | res.send(200, data, headers); 200 | }; 201 | 202 | /** 203 | * GET /assets/:pk 204 | */ 205 | export const getAsset: Handler = async function (req, res) { 206 | const cfCacheOptions = await getCFCacheOptions(); 207 | 208 | if (!cfCacheOptions) { 209 | return res.send(400, { message: 'Unable to retrieve cache options.' }); 210 | } 211 | 212 | const { pk } = req.params; 213 | 214 | const readKV = async () => { 215 | const asset = await Assets.read(pk); 216 | 217 | return asset; 218 | }; 219 | 220 | const fetchOrigin = async () => { 221 | const url = new URL(`${DIRECTUS_SERVER_URL}/assets/${pk}`); 222 | 223 | url.search = new URLSearchParams({ 224 | access_token: DIRECTUS_ACCESS_TOKEN, 225 | }).toString(); 226 | 227 | const response = await fetch(url); 228 | 229 | if (response.status === 200) { 230 | return response.body; 231 | } 232 | 233 | return null; 234 | }; 235 | 236 | let asset; 237 | const headers = {} as Record; 238 | 239 | switch (cfCacheOptions.cache_mode) { 240 | case 'origin_priority': 241 | asset = await fetchOrigin(); 242 | headers['Cache-Source'] = 'origin'; 243 | 244 | if (!asset) { 245 | asset = await readKV(); 246 | headers['Cache-Source'] = 'cache'; 247 | } 248 | break; 249 | case 'cache_priority': 250 | asset = await readKV(); 251 | headers['Cache-Source'] = 'cache'; 252 | 253 | if (!asset) { 254 | asset = await fetchOrigin(); 255 | headers['Cache-Source'] = 'origin'; 256 | } 257 | break; 258 | case 'origin_only': 259 | asset = await fetchOrigin(); 260 | headers['Cache-Source'] = 'origin'; 261 | break; 262 | case 'cache_only': 263 | asset = await readKV(); 264 | headers['Cache-Source'] = 'cache'; 265 | break; 266 | default: 267 | return res.send(500, { message: 'Unsupported cache mode.' }); 268 | } 269 | 270 | if (!asset) { 271 | return res.send(404); 272 | } 273 | 274 | res.writeHead(200, headers); 275 | res.end(asset); 276 | }; 277 | 278 | /** 279 | * POST /webhook 280 | */ 281 | export const webhook: Handler = async function (req, res) { 282 | if (!req.headers.get('Secret') || req.headers.get('Secret') !== DIRECTUS_WEBHOOK_SECRET) { 283 | return res.send(403, { message: 'Unauthorized.' }); 284 | } 285 | 286 | if (!req.body || !req.headers.has('Content-Type') || req.headers.get('Content-Type') !== 'application/json') { 287 | return res.send(400, { message: 'Invalid webhook request.' }); 288 | } 289 | 290 | const body = await req.body.json(); 291 | 292 | if (!body || !body.event || !body.collection || !(body.key || body.keys) || !body.payload) 293 | return res.send(400, { message: 'Invalid webhook request.' }); 294 | 295 | const cfCacheOptions = await getCFCacheOptions(); 296 | 297 | if (!cfCacheOptions) { 298 | return res.send(400, { message: 'Unable to retrieve cache options.' }); 299 | } 300 | 301 | switch (body.event) { 302 | case 'items.create': 303 | if (!body.key) return res.send(400, { message: 'Invalid webhook request.' }); 304 | 305 | if (body.collection === TABLE_CF_CACHE_OPTIONS) { 306 | await saveCFCacheOptions(); 307 | } else { 308 | for (const preset of cfCacheOptions.preset_requests) { 309 | if (preset.collection === body.collection) { 310 | if (preset.operation === 'get') { 311 | await saveItem(preset, body.collection, preset.key, body.key); 312 | } else if (preset.operation === 'list') { 313 | await saveList(preset, body.collection, preset.key); 314 | } 315 | } 316 | } 317 | } 318 | break; 319 | case 'items.update': 320 | if (!body.keys) return res.send(400, { message: 'Invalid webhook request.' }); 321 | 322 | if (body.collection === TABLE_CF_CACHE_OPTIONS) { 323 | await saveCFCacheOptions(); 324 | } else { 325 | for (const preset of cfCacheOptions.preset_requests) { 326 | if (preset.collection === body.collection) { 327 | if (preset.operation === 'get') { 328 | await saveItem(preset, body.collection, preset.key, body.keys); 329 | } else if (preset.operation === 'list') { 330 | await saveList(preset, body.collection, preset.key); 331 | } 332 | } 333 | } 334 | } 335 | break; 336 | case 'items.delete': 337 | if (!body.keys) return res.send(400, { message: 'Invalid webhook request.' }); 338 | 339 | for (const preset of cfCacheOptions.preset_requests) { 340 | if (preset.collection === body.collection) { 341 | if (preset.operation === 'get') { 342 | await deleteItem(body.collection, preset.key, body.keys); 343 | } else if (preset.operation === 'list') { 344 | await saveList(preset, body.collection, preset.key); 345 | } 346 | } 347 | } 348 | break; 349 | default: 350 | return res.send(400, { message: 'Invalid webhook request.' }); 351 | } 352 | 353 | return res.send(200, { message: 'OK' }); 354 | }; 355 | 356 | async function getCFCacheOptions() { 357 | const cfCacheOptions = await Items.read(TABLE_CF_CACHE_OPTIONS, '', ''); 358 | 359 | if (cfCacheOptions) { 360 | return cfCacheOptions as CFCacheOptions; 361 | } 362 | 363 | const url = new URL(`${DIRECTUS_SERVER_URL}/items/${TABLE_CF_CACHE_OPTIONS}`); 364 | 365 | url.search = new URLSearchParams({ 366 | fields: '*.*', 367 | access_token: DIRECTUS_ACCESS_TOKEN, 368 | }).toString(); 369 | 370 | const response = await fetch(url); 371 | 372 | if (response.status === 200) { 373 | const responseData = await response.json(); 374 | if (responseData.data) { 375 | await Items.write(TABLE_CF_CACHE_OPTIONS, '', '', responseData.data); 376 | 377 | return responseData.data as CFCacheOptions; 378 | } 379 | } 380 | 381 | throw new Error(`Unable to load "${TABLE_CF_CACHE_OPTIONS}".`); 382 | } 383 | 384 | async function saveCFCacheOptions() { 385 | const url = new URL(`${DIRECTUS_SERVER_URL}/items/${TABLE_CF_CACHE_OPTIONS}`); 386 | 387 | url.search = new URLSearchParams({ 388 | fields: '*.*', 389 | access_token: DIRECTUS_ACCESS_TOKEN, 390 | }).toString(); 391 | 392 | const response = await fetch(url); 393 | 394 | if (response.status === 200) { 395 | const responseData = await response.json(); 396 | if (responseData.data) { 397 | await Items.write(TABLE_CF_CACHE_OPTIONS, '', '', responseData.data); 398 | } 399 | } 400 | } 401 | 402 | async function saveList(preset: PresetRequest, collection: string, key: string) { 403 | if (!key) key = ''; 404 | 405 | const url = new URL(`${DIRECTUS_SERVER_URL}/items/${collection}`); 406 | 407 | if (preset.query_params['filter']) { 408 | preset.query_params['filter'] = JSON.stringify(preset.query_params['filter']); 409 | } 410 | 411 | url.search = new URLSearchParams({ 412 | ...preset.query_params, 413 | access_token: DIRECTUS_ACCESS_TOKEN, 414 | }).toString(); 415 | 416 | const response = await fetch(url); 417 | 418 | if (response.status !== 200) { 419 | throw new Error(`Unable to load list for collection "${collection}" and key "${key}".`); 420 | } 421 | 422 | const item = await response.json(); 423 | 424 | if (!item.data) { 425 | throw new Error(`Missing list data for collection "${collection}" and key "${key}".`); 426 | } 427 | 428 | const result = await Items.write(collection, key, '', item.data); 429 | 430 | if (!result) { 431 | throw new Error(`Unable to save list for collection "${collection}" and key "${key}".`); 432 | } 433 | } 434 | 435 | async function saveItem( 436 | preset: PresetRequest, 437 | collection: string, 438 | key: string, 439 | pk: (string | number) | (string | number)[] 440 | ) { 441 | if (Array.isArray(pk)) { 442 | for (const primaryKey of pk) { 443 | await saveItem(preset, collection, key, primaryKey); 444 | } 445 | return; 446 | } 447 | 448 | if (!key) key = ''; 449 | 450 | const url = new URL(`${DIRECTUS_SERVER_URL}/items/${collection}/${pk}`); 451 | 452 | url.search = new URLSearchParams({ 453 | ...preset.query_params, 454 | access_token: DIRECTUS_ACCESS_TOKEN, 455 | }).toString(); 456 | 457 | const response = await fetch(url); 458 | 459 | if (response.status !== 200) { 460 | throw new Error(`Unable to load item for collection "${collection}", key "${key}" and pk "${pk}".`); 461 | } 462 | 463 | const item = await response.json(); 464 | 465 | if (!item.data) { 466 | throw new Error(`Missing item data for collection "${collection}", key "${key}" and pk "${pk}"`); 467 | } 468 | 469 | const result = await Items.write(collection, key, String(pk), item.data); 470 | 471 | if (!result) { 472 | throw new Error(`Unable to save item for collection "${collection}", key "${key}" and pk "${pk}"`); 473 | } 474 | 475 | if (preset.file_paths) { 476 | const checkAssetRecursive = async (items: any, filePath: string) => { 477 | const splits = filePath.split('.'); 478 | if (Array.isArray(items[splits[0]])) { 479 | const currentPath = splits[0]; 480 | splits.shift(); 481 | const newPath = splits.join('.'); 482 | for (const item of items[currentPath]) { 483 | await checkAssetRecursive(item, newPath); 484 | } 485 | } else if (typeof splits[0] === 'object') { 486 | const currentPath = splits[0]; 487 | splits.shift(); 488 | await checkAssetRecursive(items[currentPath], splits.join('.')); 489 | } else if (typeof splits[0] === 'string') { 490 | const assetId = get(items, splits[0]); 491 | if (assetId) { 492 | const assetUrl = new URL(`${DIRECTUS_SERVER_URL}/assets/${assetId}`); 493 | assetUrl.search = new URLSearchParams({ 494 | access_token: DIRECTUS_ACCESS_TOKEN, 495 | }).toString(); 496 | const assetResponse = await fetch(assetUrl); 497 | if (assetResponse.status === 200) { 498 | await Assets.write(assetId, await assetResponse.body); 499 | } 500 | } 501 | } 502 | }; 503 | 504 | for (const path of preset.file_paths) { 505 | await checkAssetRecursive(result, path); 506 | } 507 | } 508 | } 509 | 510 | async function deleteItem(collection: string, key: string, pk: (string | number) | (string | number)[]) { 511 | if (Array.isArray(pk)) { 512 | for (const primaryKey of pk) { 513 | await deleteItem(collection, key, primaryKey); 514 | } 515 | return; 516 | } 517 | 518 | if (!key) key = ''; 519 | 520 | const result = await Items.destroy(collection, key, String(pk)); 521 | 522 | if (!result) { 523 | throw new Error(`Unable to delete item for collection "${collection}" and key "${key}" and pk "${pk}"`); 524 | } 525 | } 526 | -------------------------------------------------------------------------------- /workers/directus-cf-cache-worker/assetStore.ts: -------------------------------------------------------------------------------- 1 | import * as DB from 'worktop/kv'; 2 | 3 | const toPrefix = (pk: string) => `assets::${pk}`; 4 | 5 | export async function write(pk: string, asset: any) { 6 | const kvKey = toPrefix(pk); 7 | try { 8 | await DB.write(DIRECTUS_CF_CACHE_KV, kvKey, asset); 9 | return asset; 10 | } catch (err) {} 11 | } 12 | 13 | export async function read(pk: string) { 14 | const kvKey = toPrefix(pk); 15 | try { 16 | return await DB.read(DIRECTUS_CF_CACHE_KV, kvKey, 'stream'); 17 | } catch (err) {} 18 | } 19 | 20 | export function destroy(pk: string) { 21 | const kvKey = toPrefix(pk); 22 | return DB.remove(DIRECTUS_CF_CACHE_KV, kvKey); 23 | } 24 | -------------------------------------------------------------------------------- /workers/directus-cf-cache-worker/cfw.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | name: 'directus-cf-cache-worker', 3 | zoneid: process.env.CLOUDFLARE_ZONEID, 4 | accountid: process.env.CLOUDFLARE_ACCOUNTID, 5 | token: process.env.CLOUDFLARE_TOKEN, 6 | entry: 'index.ts', 7 | routes: process.env.WORKER_ROUTES.split(',').filter((route) => route), 8 | globals: { 9 | DIRECTUS_CF_CACHE_KV: `KV:${process.env.DIRECTUS_CF_CACHE_KV}`, 10 | DIRECTUS_ACCESS_TOKEN: `ENV:${process.env.DIRECTUS_ACCESS_TOKEN}`, 11 | DIRECTUS_SERVER_URL: `ENV:${process.env.DIRECTUS_SERVER_URL}`, 12 | DIRECTUS_WEBHOOK_SECRET: `ENV:${process.env.DIRECTUS_WEBHOOK_SECRET}`, 13 | }, 14 | }; 15 | -------------------------------------------------------------------------------- /workers/directus-cf-cache-worker/index.ts: -------------------------------------------------------------------------------- 1 | import { Router, listen } from 'worktop'; 2 | import type { KV } from 'worktop/kv'; 3 | import * as CORS from 'worktop/cors'; 4 | import * as api from './api'; 5 | 6 | declare global { 7 | const DIRECTUS_SERVER_URL: string; 8 | const DIRECTUS_ACCESS_TOKEN: string; 9 | const DIRECTUS_CF_CACHE_KV: KV.Namespace; 10 | const DIRECTUS_WEBHOOK_SECRET: string; 11 | } 12 | 13 | const API = new Router(); 14 | 15 | API.prepare = CORS.preflight({ 16 | origin: '*', 17 | headers: ['Cache-Control', 'Content-Type', 'Secret'], 18 | methods: ['HEAD', 'GET', 'POST'], 19 | maxage: 600, 20 | }); 21 | 22 | API.add('GET', '/list/:collection', api.listItems); 23 | API.add('GET', '/list/:collection/:key', api.listItems); 24 | API.add('GET', '/get/:collection/:pk', api.getItem); 25 | API.add('GET', '/get/:collection/:pk/:key', api.getItem); 26 | API.add('GET', '/assets/:pk', api.getAsset); 27 | API.add('POST', '/webhook', api.webhook); 28 | 29 | listen(API.run); 30 | -------------------------------------------------------------------------------- /workers/directus-cf-cache-worker/itemStore.ts: -------------------------------------------------------------------------------- 1 | import * as DB from 'worktop/kv'; 2 | 3 | export interface Item { 4 | [field: string]: any; 5 | } 6 | 7 | export interface CFCacheOptions { 8 | cache_mode: 'origin_priority' | 'cache_priority' | 'origin_only' | 'cache_only'; 9 | preset_requests: PresetRequest[]; 10 | } 11 | 12 | export interface PresetRequest { 13 | operation: 'list' | 'get'; 14 | collection: string; 15 | key: string; 16 | enabled: boolean; 17 | file_paths: string[] | null; 18 | query_params: any; 19 | } 20 | 21 | const toPrefix = (collection: string, key: string) => `collection::${collection}::key::${key}::pk::`; 22 | const toKeyname = (collection: string, key: string, pk: string) => toPrefix(collection, key) + pk; 23 | 24 | export async function write(collection: string, key: string, pk: string, item: Item) { 25 | const kvKey = toKeyname(collection, key, pk); 26 | try { 27 | await DB.write(DIRECTUS_CF_CACHE_KV, kvKey, item); 28 | return item; 29 | } catch (err) {} 30 | } 31 | 32 | export async function read(collection: string, key: string, pk: string) { 33 | const kvKey = toKeyname(collection, key, pk); 34 | try { 35 | return await DB.read(DIRECTUS_CF_CACHE_KV, kvKey, 'json'); 36 | } catch (err) {} 37 | } 38 | 39 | export function destroy(collection: string, key: string, pk: string) { 40 | const kvKey = toKeyname(collection, key, pk); 41 | return DB.remove(DIRECTUS_CF_CACHE_KV, kvKey); 42 | } 43 | -------------------------------------------------------------------------------- /workers/directus-cf-cache-worker/webhook.ts: -------------------------------------------------------------------------------- 1 | export interface Webhook { 2 | collection: string; 3 | event: 'items.create' | 'items.update' | 'items.delete'; 4 | payload: any; 5 | keys?: (string | number)[]; 6 | key?: string | number; 7 | } 8 | --------------------------------------------------------------------------------