├── .eslintrc.js ├── .gitignore ├── .npmrc ├── LICENSE.txt ├── README.md ├── config.json ├── package.json ├── packages └── util │ ├── cache.ts │ ├── cors.ts │ ├── index.ts │ ├── package.json │ ├── tsconfig.json │ └── types.d.ts ├── pnpm-lock.yaml ├── pnpm-workspace.yaml ├── scripts └── init_secret.js ├── turbo.json └── worker ├── index-consumer ├── package.json ├── src │ └── index.ts ├── tsconfig.json └── wrangler.toml ├── index ├── package.json ├── src │ └── index.ts ├── tsconfig.json └── wrangler.toml └── search ├── package.json ├── src └── index.ts ├── tsconfig.json └── wrangler.toml /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | // This tells ESLint to load the config from the package `eslint-config-custom` 4 | extends: ["custom"], 5 | settings: { 6 | next: { 7 | rootDir: ["apps/*/"], 8 | }, 9 | }, 10 | }; 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | node_modules 5 | .pnp 6 | .pnp.js 7 | 8 | # testing 9 | coverage 10 | 11 | # next.js 12 | .next/ 13 | out/ 14 | build 15 | 16 | # misc 17 | .DS_Store 18 | *.pem 19 | 20 | # debug 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | 25 | # local env files 26 | .env 27 | .env.local 28 | .env.development.local 29 | .env.test.local 30 | .env.production.local 31 | 32 | # turbo 33 | .turbo 34 | 35 | # vercel 36 | .vercel 37 | 38 | .env 39 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | auto-install-peers = true 2 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Source code in this repository is covered by (i) a dual license under the Server 2 | Side Public License, v 1 and the Elastic License 2.0 or (ii) an Apache License 3 | 2.0 compatible license or (iii) solely under the Elastic License 2.0, in each 4 | case, as noted in the applicable header. The default throughout the repository 5 | is a dual license under the Server Side Public License, v 1 and the Elastic 6 | License 2.0, unless the header specifies another license. Code that is licensed 7 | solely under the Elastic License 2.0 is found only in the x-pack folder. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 |

3 | 4 | 5 | 6 | 7 | 8 |

9 | 10 | # 🔍🌩️ Serverless Search on Cloudflare 11 | Using Cloudflare Worker + Queues + R2 Storage + Cache to implement a small scale to zero search system that is reasonably fast and cheap. 12 | Benchmark welcome for performance measure :) 13 | 14 | Endpoints: 15 | - **search** - public 16 | - **index** - access restricted (see config) 17 | 18 | Cached Index saved in R2. Cache read on search request. 19 | Queue -> Writing Index (Batch size and concurrency 0) 20 | 21 | ## Features 22 | - Generic Index support 23 | - Multiple Parallel indices per endpoint (infinite) 24 | - Good performance for smaller Datasets (up to 50k documents (I guess? Feel free to create a better benchmark!)) 25 | 26 | ## Setup 27 | create a .env file in your root with the following parameter: 28 | ``` 29 | CLOUDFLARE_AUTH_KEY= 30 | CLOUDFLARE_AUTH_EMAIL= 31 | ``` 32 | 33 | > - `pnpm install` ➡️ populates your config with a strong secret 34 | > - `pnpm run initialize` ➡️ creates the bucket and queue 35 | > - `npx turbo build` ➡️ publishes your workers to cloudflare 36 | 37 | ## "Benchmark" 38 | This project is meant for smaller datasets (cheap serverless search). 39 | For a movie dataset with **17920 documents** a search takes *800ms first time* (downloading the index from R2), after that we get a worker performance of *50-60ms per search*. 40 | 41 | ## Todo 42 | - Alternative Flexsearch implementation (Problems with export / import and types) 43 | - Investigate Durable Object for faster initial response 44 | - Add serverless setup for AWS deployment 45 | - Add CLI tool 46 | 47 | **Provided by TM9657 GmbH with ❤️** 48 | ### Check out some of our products: 49 | - [Kwirk.io](https://kwirk.io?ref=github) (Text Editor with AI integration, privacy focus and offline support) 50 | -------------------------------------------------------------------------------- /config.json: -------------------------------------------------------------------------------- 1 | { 2 | "cors": [""], 3 | "secret": "", 4 | "minSearch": 3 5 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "scripts": { 4 | "initialize": "wrangler queues create search-indexing-queue && wrangler r2 bucket create serverless-search", 5 | "build": "dotenv -- turbo run build", 6 | "postinstall": "node ./scripts/init_secret.js", 7 | "dev": "turbo run dev", 8 | "lint": "turbo run lint", 9 | "format": "prettier --write \"**/*.{ts,tsx,md}\"" 10 | }, 11 | "devDependencies": { 12 | "dotenv-cli": "^7.2.1", 13 | "eslint": "^7.32.0", 14 | "prettier": "^2.5.1", 15 | "turbo": "^1.9.3", 16 | "wrangler": "2.18.0" 17 | }, 18 | "packageManager": "pnpm@7.15.0", 19 | "name": "serverless-cloudflare-search" 20 | } 21 | -------------------------------------------------------------------------------- /packages/util/cache.ts: -------------------------------------------------------------------------------- 1 | let searchCache: Cache | null = null; 2 | export async function cachePut(index: string, serialized: string) { 3 | if (!searchCache) searchCache = await caches.open("custom:serverless-search"); 4 | if (!searchCache) return undefined; 5 | const key = cacheKey(index); 6 | return await searchCache.put( 7 | key, 8 | new Response(serialized, { 9 | headers: { 10 | "Cache-Control": "public, max-age=2678400", 11 | Expires: new Date(Date.now() + 2678400 * 1000).toUTCString(), 12 | "Last-Modified": new Date().toUTCString(), 13 | }, 14 | }) 15 | ); 16 | } 17 | 18 | export async function cacheGet(index: string) { 19 | if (!searchCache) searchCache = await caches.open("custom:serverless-search"); 20 | if (!searchCache) return undefined; 21 | const key = cacheKey(index); 22 | return await (await searchCache.match(key))?.text(); 23 | } 24 | 25 | function cacheKey(index: string) { 26 | return new Request(new URL(`https://${index}.search`).toString()); 27 | } 28 | -------------------------------------------------------------------------------- /packages/util/cors.ts: -------------------------------------------------------------------------------- 1 | import config from "../../config.json"; 2 | const allowedOrigins = new Set(config.cors); 3 | 4 | export class CorsResponse { 5 | body: BodyInit | null; 6 | status: number; 7 | constructor(body: BodyInit | null, status = 200) { 8 | this.status = status; 9 | this.body = body; 10 | } 11 | 12 | finalize(request: Request): Response { 13 | let origin = ""; 14 | if ( 15 | request.headers.has("Origin") && 16 | allowedOrigins.has(request.headers.get("Origin") || "") 17 | ) 18 | origin = request.headers.get("Origin") || ""; 19 | const headers: HeadersInit = { 20 | "Access-Control-Allow-Origin": origin, 21 | "Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS, PATCH", 22 | "Access-Control-Allow-Headers": 23 | "Content-Type, Authorization, X-Requested-With", 24 | "Content-Type": "application/json", 25 | "X-DNS-Prefetch-Control": "off", 26 | "X-Frame-Options": "DENY", 27 | "Cache-Control": "no-store", 28 | "Content-Security-Policy": "frame-ancestors 'none'", 29 | "x-provided-by": "serverless-cloudflare-search@tm9657.de", 30 | }; 31 | 32 | if (request.method === "OPTIONS") { 33 | return new Response(null, { 34 | status: 204, 35 | headers: headers, 36 | }); 37 | } 38 | 39 | const response = new Response(this.body, { 40 | status: this.status, 41 | headers: headers, 42 | }); 43 | return response; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /packages/util/index.ts: -------------------------------------------------------------------------------- 1 | import MiniSearch, { Options } from "minisearch"; 2 | import { SerializedIndex } from "./types"; 3 | import { gunzipSync, gzipSync, strToU8, strFromU8 } from "fflate"; 4 | 5 | export async function loadIndex(serialized: string | null, config?: Options) { 6 | if (!serialized) { 7 | if (!config) throw new Error("No config provided"); 8 | return new MiniSearch(config); 9 | } 10 | const deserialized: SerializedIndex = JSON.parse(serialized); 11 | console.log("initializing with config: ", deserialized.config); 12 | const index = MiniSearch.loadJSON(deserialized.values, deserialized.config); 13 | return index; 14 | } 15 | 16 | export async function saveIndex( 17 | index: MiniSearch, 18 | config: Options 19 | ): Promise { 20 | const serialized: SerializedIndex = { 21 | config, 22 | values: JSON.stringify(index.toJSON()), 23 | }; 24 | 25 | return JSON.stringify(serialized); 26 | } 27 | -------------------------------------------------------------------------------- /packages/util/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "util", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [], 10 | "author": "", 11 | "license": "ISC", 12 | "devDependencies": { 13 | "@cloudflare/workers-types": "^4.20230419.0", 14 | "@tm9657/tsconfig": "^1.2.0" 15 | }, 16 | "dependencies": { 17 | "fflate": "^0.7.4", 18 | "minisearch": "^6.0.1" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /packages/util/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@tm9657/tsconfig/worker.json", 3 | "include": ["."], 4 | "exclude": ["dist", "build", "node_modules"] 5 | } 6 | -------------------------------------------------------------------------------- /packages/util/types.d.ts: -------------------------------------------------------------------------------- 1 | import { Options } from "minisearch"; 2 | 3 | export interface SearchQueueMessage { 4 | index: string; 5 | config: SearchConfig; 6 | document: any; 7 | } 8 | 9 | export interface SerializedIndex { 10 | config: Options; 11 | values: string; 12 | } 13 | 14 | export { Options, default as MiniSearch } from "minisearch"; 15 | -------------------------------------------------------------------------------- /pnpm-lock.yaml: -------------------------------------------------------------------------------- 1 | lockfileVersion: '6.0' 2 | 3 | importers: 4 | 5 | .: 6 | devDependencies: 7 | dotenv-cli: 8 | specifier: ^7.2.1 9 | version: 7.2.1 10 | eslint: 11 | specifier: ^7.32.0 12 | version: 7.32.0 13 | prettier: 14 | specifier: ^2.5.1 15 | version: 2.8.8 16 | turbo: 17 | specifier: ^1.9.3 18 | version: 1.9.3 19 | wrangler: 20 | specifier: 2.18.0 21 | version: 2.18.0 22 | 23 | packages/util: 24 | dependencies: 25 | fflate: 26 | specifier: ^0.7.4 27 | version: 0.7.4 28 | minisearch: 29 | specifier: ^6.0.1 30 | version: 6.0.1 31 | devDependencies: 32 | '@cloudflare/workers-types': 33 | specifier: ^4.20230419.0 34 | version: 4.20230419.0 35 | '@tm9657/tsconfig': 36 | specifier: ^1.2.0 37 | version: 1.2.0 38 | 39 | worker/batchIndex: 40 | dependencies: 41 | util: 42 | specifier: workspace:* 43 | version: link:../../packages/util 44 | devDependencies: 45 | '@cloudflare/workers-types': 46 | specifier: ^4.20230419.0 47 | version: 4.20230419.0 48 | '@tm9657/tsconfig': 49 | specifier: ^1.2.0 50 | version: 1.2.0 51 | wrangler: 52 | specifier: 2.18.0 53 | version: 2.18.0 54 | 55 | worker/index: 56 | dependencies: 57 | util: 58 | specifier: workspace:* 59 | version: link:../../packages/util 60 | devDependencies: 61 | '@cloudflare/workers-types': 62 | specifier: ^4.20230419.0 63 | version: 4.20230419.0 64 | '@tm9657/tsconfig': 65 | specifier: ^1.2.0 66 | version: 1.2.0 67 | wrangler: 68 | specifier: 2.18.0 69 | version: 2.18.0 70 | 71 | worker/index-consumer: 72 | dependencies: 73 | util: 74 | specifier: workspace:* 75 | version: link:../../packages/util 76 | devDependencies: 77 | '@cloudflare/workers-types': 78 | specifier: ^4.20230419.0 79 | version: 4.20230419.0 80 | '@tm9657/tsconfig': 81 | specifier: ^1.2.0 82 | version: 1.2.0 83 | wrangler: 84 | specifier: 2.18.0 85 | version: 2.18.0 86 | 87 | worker/search: 88 | dependencies: 89 | util: 90 | specifier: workspace:* 91 | version: link:../../packages/util 92 | devDependencies: 93 | '@cloudflare/workers-types': 94 | specifier: ^4.20230419.0 95 | version: 4.20230419.0 96 | '@tm9657/tsconfig': 97 | specifier: ^1.2.0 98 | version: 1.2.0 99 | wrangler: 100 | specifier: 2.18.0 101 | version: 2.18.0 102 | 103 | packages: 104 | 105 | /@babel/code-frame@7.12.11: 106 | resolution: {integrity: sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==} 107 | dependencies: 108 | '@babel/highlight': 7.18.6 109 | dev: true 110 | 111 | /@babel/helper-validator-identifier@7.19.1: 112 | resolution: {integrity: sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==} 113 | engines: {node: '>=6.9.0'} 114 | dev: true 115 | 116 | /@babel/highlight@7.18.6: 117 | resolution: {integrity: sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==} 118 | engines: {node: '>=6.9.0'} 119 | dependencies: 120 | '@babel/helper-validator-identifier': 7.19.1 121 | chalk: 2.4.2 122 | js-tokens: 4.0.0 123 | dev: true 124 | 125 | /@cloudflare/kv-asset-handler@0.2.0: 126 | resolution: {integrity: sha512-MVbXLbTcAotOPUj0pAMhVtJ+3/kFkwJqc5qNOleOZTv6QkZZABDMS21dSrSlVswEHwrpWC03e4fWytjqKvuE2A==} 127 | dependencies: 128 | mime: 3.0.0 129 | dev: true 130 | 131 | /@cloudflare/workers-types@4.20230419.0: 132 | resolution: {integrity: sha512-MfNBlHrI/ekRkbLtdAo23D4hkXF+3QD92OCwuXxCUK73HtMHuBqkMp9T/8KFbKNRCnz7PzUderc7Jr5m3eeW3g==} 133 | dev: true 134 | 135 | /@esbuild-plugins/node-globals-polyfill@0.1.1(esbuild@0.16.3): 136 | resolution: {integrity: sha512-MR0oAA+mlnJWrt1RQVQ+4VYuRJW/P2YmRTv1AsplObyvuBMnPHiizUF95HHYiSsMGLhyGtWufaq2XQg6+iurBg==} 137 | peerDependencies: 138 | esbuild: '*' 139 | dependencies: 140 | esbuild: 0.16.3 141 | dev: true 142 | 143 | /@esbuild-plugins/node-modules-polyfill@0.1.4(esbuild@0.16.3): 144 | resolution: {integrity: sha512-uZbcXi0zbmKC/050p3gJnne5Qdzw8vkXIv+c2BW0Lsc1ji1SkrxbKPUy5Efr0blbTu1SL8w4eyfpnSdPg3G0Qg==} 145 | peerDependencies: 146 | esbuild: '*' 147 | dependencies: 148 | esbuild: 0.16.3 149 | escape-string-regexp: 4.0.0 150 | rollup-plugin-node-polyfills: 0.2.1 151 | dev: true 152 | 153 | /@esbuild/android-arm64@0.16.3: 154 | resolution: {integrity: sha512-RolFVeinkeraDvN/OoRf1F/lP0KUfGNb5jxy/vkIMeRRChkrX/HTYN6TYZosRJs3a1+8wqpxAo5PI5hFmxyPRg==} 155 | engines: {node: '>=12'} 156 | cpu: [arm64] 157 | os: [android] 158 | requiresBuild: true 159 | dev: true 160 | optional: true 161 | 162 | /@esbuild/android-arm@0.16.3: 163 | resolution: {integrity: sha512-mueuEoh+s1eRbSJqq9KNBQwI4QhQV6sRXIfTyLXSHGMpyew61rOK4qY21uKbXl1iBoMb0AdL1deWFCQVlN2qHA==} 164 | engines: {node: '>=12'} 165 | cpu: [arm] 166 | os: [android] 167 | requiresBuild: true 168 | dev: true 169 | optional: true 170 | 171 | /@esbuild/android-x64@0.16.3: 172 | resolution: {integrity: sha512-SFpTUcIT1bIJuCCBMCQWq1bL2gPTjWoLZdjmIhjdcQHaUfV41OQfho6Ici5uvvkMmZRXIUGpM3GxysP/EU7ifQ==} 173 | engines: {node: '>=12'} 174 | cpu: [x64] 175 | os: [android] 176 | requiresBuild: true 177 | dev: true 178 | optional: true 179 | 180 | /@esbuild/darwin-arm64@0.16.3: 181 | resolution: {integrity: sha512-DO8WykMyB+N9mIDfI/Hug70Dk1KipavlGAecxS3jDUwAbTpDXj0Lcwzw9svkhxfpCagDmpaTMgxWK8/C/XcXvw==} 182 | engines: {node: '>=12'} 183 | cpu: [arm64] 184 | os: [darwin] 185 | requiresBuild: true 186 | dev: true 187 | optional: true 188 | 189 | /@esbuild/darwin-x64@0.16.3: 190 | resolution: {integrity: sha512-uEqZQ2omc6BvWqdCiyZ5+XmxuHEi1SPzpVxXCSSV2+Sh7sbXbpeNhHIeFrIpRjAs0lI1FmA1iIOxFozKBhKgRQ==} 191 | engines: {node: '>=12'} 192 | cpu: [x64] 193 | os: [darwin] 194 | requiresBuild: true 195 | dev: true 196 | optional: true 197 | 198 | /@esbuild/freebsd-arm64@0.16.3: 199 | resolution: {integrity: sha512-nJansp3sSXakNkOD5i5mIz2Is/HjzIhFs49b1tjrPrpCmwgBmH9SSzhC/Z1UqlkivqMYkhfPwMw1dGFUuwmXhw==} 200 | engines: {node: '>=12'} 201 | cpu: [arm64] 202 | os: [freebsd] 203 | requiresBuild: true 204 | dev: true 205 | optional: true 206 | 207 | /@esbuild/freebsd-x64@0.16.3: 208 | resolution: {integrity: sha512-TfoDzLw+QHfc4a8aKtGSQ96Wa+6eimljjkq9HKR0rHlU83vw8aldMOUSJTUDxbcUdcgnJzPaX8/vGWm7vyV7ug==} 209 | engines: {node: '>=12'} 210 | cpu: [x64] 211 | os: [freebsd] 212 | requiresBuild: true 213 | dev: true 214 | optional: true 215 | 216 | /@esbuild/linux-arm64@0.16.3: 217 | resolution: {integrity: sha512-7I3RlsnxEFCHVZNBLb2w7unamgZ5sVwO0/ikE2GaYvYuUQs9Qte/w7TqWcXHtCwxvZx/2+F97ndiUQAWs47ZfQ==} 218 | engines: {node: '>=12'} 219 | cpu: [arm64] 220 | os: [linux] 221 | requiresBuild: true 222 | dev: true 223 | optional: true 224 | 225 | /@esbuild/linux-arm@0.16.3: 226 | resolution: {integrity: sha512-VwswmSYwVAAq6LysV59Fyqk3UIjbhuc6wb3vEcJ7HEJUtFuLK9uXWuFoH1lulEbE4+5GjtHi3MHX+w1gNHdOWQ==} 227 | engines: {node: '>=12'} 228 | cpu: [arm] 229 | os: [linux] 230 | requiresBuild: true 231 | dev: true 232 | optional: true 233 | 234 | /@esbuild/linux-ia32@0.16.3: 235 | resolution: {integrity: sha512-X8FDDxM9cqda2rJE+iblQhIMYY49LfvW4kaEjoFbTTQ4Go8G96Smj2w3BRTwA8IHGoi9dPOPGAX63dhuv19UqA==} 236 | engines: {node: '>=12'} 237 | cpu: [ia32] 238 | os: [linux] 239 | requiresBuild: true 240 | dev: true 241 | optional: true 242 | 243 | /@esbuild/linux-loong64@0.16.3: 244 | resolution: {integrity: sha512-hIbeejCOyO0X9ujfIIOKjBjNAs9XD/YdJ9JXAy1lHA+8UXuOqbFe4ErMCqMr8dhlMGBuvcQYGF7+kO7waj2KHw==} 245 | engines: {node: '>=12'} 246 | cpu: [loong64] 247 | os: [linux] 248 | requiresBuild: true 249 | dev: true 250 | optional: true 251 | 252 | /@esbuild/linux-mips64el@0.16.3: 253 | resolution: {integrity: sha512-znFRzICT/V8VZQMt6rjb21MtAVJv/3dmKRMlohlShrbVXdBuOdDrGb+C2cZGQAR8RFyRe7HS6klmHq103WpmVw==} 254 | engines: {node: '>=12'} 255 | cpu: [mips64el] 256 | os: [linux] 257 | requiresBuild: true 258 | dev: true 259 | optional: true 260 | 261 | /@esbuild/linux-ppc64@0.16.3: 262 | resolution: {integrity: sha512-EV7LuEybxhXrVTDpbqWF2yehYRNz5e5p+u3oQUS2+ZFpknyi1NXxr8URk4ykR8Efm7iu04//4sBg249yNOwy5Q==} 263 | engines: {node: '>=12'} 264 | cpu: [ppc64] 265 | os: [linux] 266 | requiresBuild: true 267 | dev: true 268 | optional: true 269 | 270 | /@esbuild/linux-riscv64@0.16.3: 271 | resolution: {integrity: sha512-uDxqFOcLzFIJ+r/pkTTSE9lsCEaV/Y6rMlQjUI9BkzASEChYL/aSQjZjchtEmdnVxDKETnUAmsaZ4pqK1eE5BQ==} 272 | engines: {node: '>=12'} 273 | cpu: [riscv64] 274 | os: [linux] 275 | requiresBuild: true 276 | dev: true 277 | optional: true 278 | 279 | /@esbuild/linux-s390x@0.16.3: 280 | resolution: {integrity: sha512-NbeREhzSxYwFhnCAQOQZmajsPYtX71Ufej3IQ8W2Gxskfz9DK58ENEju4SbpIj48VenktRASC52N5Fhyf/aliQ==} 281 | engines: {node: '>=12'} 282 | cpu: [s390x] 283 | os: [linux] 284 | requiresBuild: true 285 | dev: true 286 | optional: true 287 | 288 | /@esbuild/linux-x64@0.16.3: 289 | resolution: {integrity: sha512-SDiG0nCixYO9JgpehoKgScwic7vXXndfasjnD5DLbp1xltANzqZ425l7LSdHynt19UWOcDjG9wJJzSElsPvk0w==} 290 | engines: {node: '>=12'} 291 | cpu: [x64] 292 | os: [linux] 293 | requiresBuild: true 294 | dev: true 295 | optional: true 296 | 297 | /@esbuild/netbsd-x64@0.16.3: 298 | resolution: {integrity: sha512-AzbsJqiHEq1I/tUvOfAzCY15h4/7Ivp3ff/o1GpP16n48JMNAtbW0qui2WCgoIZArEHD0SUQ95gvR0oSO7ZbdA==} 299 | engines: {node: '>=12'} 300 | cpu: [x64] 301 | os: [netbsd] 302 | requiresBuild: true 303 | dev: true 304 | optional: true 305 | 306 | /@esbuild/openbsd-x64@0.16.3: 307 | resolution: {integrity: sha512-gSABi8qHl8k3Cbi/4toAzHiykuBuWLZs43JomTcXkjMZVkp0gj3gg9mO+9HJW/8GB5H89RX/V0QP4JGL7YEEVg==} 308 | engines: {node: '>=12'} 309 | cpu: [x64] 310 | os: [openbsd] 311 | requiresBuild: true 312 | dev: true 313 | optional: true 314 | 315 | /@esbuild/sunos-x64@0.16.3: 316 | resolution: {integrity: sha512-SF9Kch5Ete4reovvRO6yNjMxrvlfT0F0Flm+NPoUw5Z4Q3r1d23LFTgaLwm3Cp0iGbrU/MoUI+ZqwCv5XJijCw==} 317 | engines: {node: '>=12'} 318 | cpu: [x64] 319 | os: [sunos] 320 | requiresBuild: true 321 | dev: true 322 | optional: true 323 | 324 | /@esbuild/win32-arm64@0.16.3: 325 | resolution: {integrity: sha512-u5aBonZIyGopAZyOnoPAA6fGsDeHByZ9CnEzyML9NqntK6D/xl5jteZUKm/p6nD09+v3pTM6TuUIqSPcChk5gg==} 326 | engines: {node: '>=12'} 327 | cpu: [arm64] 328 | os: [win32] 329 | requiresBuild: true 330 | dev: true 331 | optional: true 332 | 333 | /@esbuild/win32-ia32@0.16.3: 334 | resolution: {integrity: sha512-GlgVq1WpvOEhNioh74TKelwla9KDuAaLZrdxuuUgsP2vayxeLgVc+rbpIv0IYF4+tlIzq2vRhofV+KGLD+37EQ==} 335 | engines: {node: '>=12'} 336 | cpu: [ia32] 337 | os: [win32] 338 | requiresBuild: true 339 | dev: true 340 | optional: true 341 | 342 | /@esbuild/win32-x64@0.16.3: 343 | resolution: {integrity: sha512-5/JuTd8OWW8UzEtyf19fbrtMJENza+C9JoPIkvItgTBQ1FO2ZLvjbPO6Xs54vk0s5JB5QsfieUEshRQfu7ZHow==} 344 | engines: {node: '>=12'} 345 | cpu: [x64] 346 | os: [win32] 347 | requiresBuild: true 348 | dev: true 349 | optional: true 350 | 351 | /@eslint/eslintrc@0.4.3: 352 | resolution: {integrity: sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==} 353 | engines: {node: ^10.12.0 || >=12.0.0} 354 | dependencies: 355 | ajv: 6.12.6 356 | debug: 4.3.4 357 | espree: 7.3.1 358 | globals: 13.20.0 359 | ignore: 4.0.6 360 | import-fresh: 3.3.0 361 | js-yaml: 3.14.1 362 | minimatch: 3.1.2 363 | strip-json-comments: 3.1.1 364 | transitivePeerDependencies: 365 | - supports-color 366 | dev: true 367 | 368 | /@humanwhocodes/config-array@0.5.0: 369 | resolution: {integrity: sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==} 370 | engines: {node: '>=10.10.0'} 371 | dependencies: 372 | '@humanwhocodes/object-schema': 1.2.1 373 | debug: 4.3.4 374 | minimatch: 3.1.2 375 | transitivePeerDependencies: 376 | - supports-color 377 | dev: true 378 | 379 | /@humanwhocodes/object-schema@1.2.1: 380 | resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==} 381 | dev: true 382 | 383 | /@iarna/toml@2.2.5: 384 | resolution: {integrity: sha512-trnsAYxU3xnS1gPHPyU961coFyLkh4gAD/0zQ5mymY4yOZ+CYvsPqUbOFSw0aDM4y0tV7tiFxL/1XfXPNC6IPg==} 385 | dev: true 386 | 387 | /@miniflare/cache@2.13.0: 388 | resolution: {integrity: sha512-y3SdN3SVyPECWmLAEGkkrv0RB+LugEPs/FeXn8QtN9aE1vyj69clOAgmsDzoh1DpFfFsLKRiv05aWs4m79P8Xw==} 389 | engines: {node: '>=16.13'} 390 | dependencies: 391 | '@miniflare/core': 2.13.0 392 | '@miniflare/shared': 2.13.0 393 | http-cache-semantics: 4.1.1 394 | undici: 5.20.0 395 | dev: true 396 | 397 | /@miniflare/cli-parser@2.13.0: 398 | resolution: {integrity: sha512-Nx1PIfuMZ3mK9Dg/JojWZAjHR16h1pcdCFSqYln/ME7y5ifx+P1E5UkShWUQ1cBlibNaltjbJ2n/7stSAsIGPQ==} 399 | engines: {node: '>=16.13'} 400 | dependencies: 401 | '@miniflare/shared': 2.13.0 402 | kleur: 4.1.5 403 | dev: true 404 | 405 | /@miniflare/core@2.13.0: 406 | resolution: {integrity: sha512-YJ/C0J3k+7xn4gvlMpvePnM3xC8nOnkweW96cc0IA8kJ1JSmScOO2tZ7rrU1RyDgp6StkAtQBw4yC0wYeFycBw==} 407 | engines: {node: '>=16.13'} 408 | dependencies: 409 | '@iarna/toml': 2.2.5 410 | '@miniflare/queues': 2.13.0 411 | '@miniflare/shared': 2.13.0 412 | '@miniflare/watcher': 2.13.0 413 | busboy: 1.6.0 414 | dotenv: 10.0.0 415 | kleur: 4.1.5 416 | set-cookie-parser: 2.6.0 417 | undici: 5.20.0 418 | urlpattern-polyfill: 4.0.3 419 | dev: true 420 | 421 | /@miniflare/d1@2.13.0: 422 | resolution: {integrity: sha512-OslqjO8iTcvzyrC0spByftMboRmHJEyHyTHnlKkjWDGdQQztEOjso2Xj+3I4SZIeUYvbzDRhKLS2QXI9a8LS5A==} 423 | engines: {node: '>=16.7'} 424 | dependencies: 425 | '@miniflare/core': 2.13.0 426 | '@miniflare/shared': 2.13.0 427 | dev: true 428 | 429 | /@miniflare/durable-objects@2.13.0: 430 | resolution: {integrity: sha512-CRGVBPO9vY4Fc3aV+pdPRVVeYIt64vQqvw+BJbyW+TQtqVP2CGQeziJGnCfcONNNKyooZxGyUkHewUypyH+Qhg==} 431 | engines: {node: '>=16.13'} 432 | dependencies: 433 | '@miniflare/core': 2.13.0 434 | '@miniflare/shared': 2.13.0 435 | '@miniflare/storage-memory': 2.13.0 436 | undici: 5.20.0 437 | dev: true 438 | 439 | /@miniflare/html-rewriter@2.13.0: 440 | resolution: {integrity: sha512-XhN7Icyzvtvu+o/A0hrnSiSmla78seCaNwQ9M1TDHxt352I/ahPX4wtPXs6GbKqY0/i+V6yoG2KGFRQ/j59cQQ==} 441 | engines: {node: '>=16.13'} 442 | dependencies: 443 | '@miniflare/core': 2.13.0 444 | '@miniflare/shared': 2.13.0 445 | html-rewriter-wasm: 0.4.1 446 | undici: 5.20.0 447 | dev: true 448 | 449 | /@miniflare/http-server@2.13.0: 450 | resolution: {integrity: sha512-aMS/nUMTKP15hKnyZboeuWCiqmNrrCu+XRBY/TxDDl07iXcLpiHGf3oVv+yXxXkWlJHJVCbK7i/nXSNPllRMSw==} 451 | engines: {node: '>=16.13'} 452 | dependencies: 453 | '@miniflare/core': 2.13.0 454 | '@miniflare/shared': 2.13.0 455 | '@miniflare/web-sockets': 2.13.0 456 | kleur: 4.1.5 457 | selfsigned: 2.1.1 458 | undici: 5.20.0 459 | ws: 8.13.0 460 | youch: 2.2.2 461 | transitivePeerDependencies: 462 | - bufferutil 463 | - utf-8-validate 464 | dev: true 465 | 466 | /@miniflare/kv@2.13.0: 467 | resolution: {integrity: sha512-J0AS5x3g/YVOmHMxMAZs07nRXRvSo9jyuC0eikTBf+4AABvBIyvVYmdTjYNjCmr8O5smcfWBX5S27HelD3aAAQ==} 468 | engines: {node: '>=16.13'} 469 | dependencies: 470 | '@miniflare/shared': 2.13.0 471 | dev: true 472 | 473 | /@miniflare/queues@2.13.0: 474 | resolution: {integrity: sha512-Gf/a6M1mJL03iOvNqh3JNahcBfvEMPHnO28n0gkCoyYWGvddIr9lwCdFIa0qwNJsC1fIDRxhPg8PZ5cQLBMwRA==} 475 | engines: {node: '>=16.7'} 476 | dependencies: 477 | '@miniflare/shared': 2.13.0 478 | dev: true 479 | 480 | /@miniflare/r2@2.13.0: 481 | resolution: {integrity: sha512-/5k6GHOYMNV/oBtilV9HDXBkJUrx8oXVigG5vxbnzEGRXyVRmR+Glzu7mFT8JiE94XiEbXHk9Qvu1S5Dej3wBw==} 482 | engines: {node: '>=16.13'} 483 | dependencies: 484 | '@miniflare/shared': 2.13.0 485 | undici: 5.20.0 486 | dev: true 487 | 488 | /@miniflare/runner-vm@2.13.0: 489 | resolution: {integrity: sha512-VmKtF2cA8HmTuLXor1THWY0v+DmaobPct63iLcgWIaUdP3MIvL+9X8HDXFAviCR7bCTe6MKxckHkaOj0IE0aJQ==} 490 | engines: {node: '>=16.13'} 491 | dependencies: 492 | '@miniflare/shared': 2.13.0 493 | dev: true 494 | 495 | /@miniflare/scheduler@2.13.0: 496 | resolution: {integrity: sha512-AOaQanoR4NjVEzVGWHnrL15A7aMx+d9AKLJhSDF7KaP+4NrT2Wo2BQuXCpn5oStx3itOdlQpMfqQ139e/I8WhQ==} 497 | engines: {node: '>=16.13'} 498 | dependencies: 499 | '@miniflare/core': 2.13.0 500 | '@miniflare/shared': 2.13.0 501 | cron-schedule: 3.0.6 502 | dev: true 503 | 504 | /@miniflare/shared@2.13.0: 505 | resolution: {integrity: sha512-m8YFQzKmbjberrV9hPzNcQjNCXxjTjXUpuNrIGjAJO7g+BDztUHaZbdd26H9maBDlkeiWxA3hf0mDyCT/6MCMA==} 506 | engines: {node: '>=16.13'} 507 | dependencies: 508 | '@types/better-sqlite3': 7.6.4 509 | kleur: 4.1.5 510 | npx-import: 1.1.4 511 | picomatch: 2.3.1 512 | dev: true 513 | 514 | /@miniflare/sites@2.13.0: 515 | resolution: {integrity: sha512-/tuzIu00o6CF2tkSv01q02MgEShXBSKx85h9jwWvc+6u7prGacAOer0FA1YNRFbE+t9QIfutAkoPGMA9zYf8+Q==} 516 | engines: {node: '>=16.13'} 517 | dependencies: 518 | '@miniflare/kv': 2.13.0 519 | '@miniflare/shared': 2.13.0 520 | '@miniflare/storage-file': 2.13.0 521 | dev: true 522 | 523 | /@miniflare/storage-file@2.13.0: 524 | resolution: {integrity: sha512-LuAeAAY5046rq5U1eFLVkz+ppiFEWytWacpkQw92DvVKFFquZcXSj6WPxZF4rSs23WDk+rdcwuLekbb52aDR7A==} 525 | engines: {node: '>=16.13'} 526 | dependencies: 527 | '@miniflare/shared': 2.13.0 528 | '@miniflare/storage-memory': 2.13.0 529 | dev: true 530 | 531 | /@miniflare/storage-memory@2.13.0: 532 | resolution: {integrity: sha512-FnkYcBNXa/ym1ksNilNZycg9WYYKo6cWKplVBeSthRon3e8QY6t3n7/XRseBUo7O6mhDybVTy4wNCP1R2nBiEw==} 533 | engines: {node: '>=16.13'} 534 | dependencies: 535 | '@miniflare/shared': 2.13.0 536 | dev: true 537 | 538 | /@miniflare/watcher@2.13.0: 539 | resolution: {integrity: sha512-teAacWcpMStoBLbLae95IUaL5lPzjPlXa9lhK9CbRaio/KRMibTMRGWrYos3IVGQRZvklvLwcms/nTvgcdb6yw==} 540 | engines: {node: '>=16.13'} 541 | dependencies: 542 | '@miniflare/shared': 2.13.0 543 | dev: true 544 | 545 | /@miniflare/web-sockets@2.13.0: 546 | resolution: {integrity: sha512-+U2/HCf+BetRIgjAnNQjkuN6UeAjQmXifhQC+7CCaX834XJhrKXoR6z2xr2xkg1qj0qQs4D2jWG0KzrO5OUpug==} 547 | engines: {node: '>=16.13'} 548 | dependencies: 549 | '@miniflare/core': 2.13.0 550 | '@miniflare/shared': 2.13.0 551 | undici: 5.20.0 552 | ws: 8.13.0 553 | transitivePeerDependencies: 554 | - bufferutil 555 | - utf-8-validate 556 | dev: true 557 | 558 | /@tm9657/tsconfig@1.2.0: 559 | resolution: {integrity: sha512-sBWUy3qTsG3mvbdZ3YD8ntjdX+/bvowBZfTT/9AZts9TdH0ipnqq52lN4U4UA8WufilGDIIdIKj1JfU1wiVMOQ==} 560 | dev: true 561 | 562 | /@types/better-sqlite3@7.6.4: 563 | resolution: {integrity: sha512-dzrRZCYPXIXfSR1/surNbJ/grU3scTaygS0OMzjlGf71i9sc2fGyHPXXiXmEvNIoE0cGwsanEFMVJxPXmco9Eg==} 564 | dependencies: 565 | '@types/node': 17.0.45 566 | dev: true 567 | 568 | /@types/node@17.0.45: 569 | resolution: {integrity: sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==} 570 | dev: true 571 | 572 | /@types/stack-trace@0.0.29: 573 | resolution: {integrity: sha512-TgfOX+mGY/NyNxJLIbDWrO9DjGoVSW9+aB8H2yy1fy32jsvxijhmyJI9fDFgvz3YP4lvJaq9DzdR/M1bOgVc9g==} 574 | dev: true 575 | 576 | /acorn-jsx@5.3.2(acorn@7.4.1): 577 | resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} 578 | peerDependencies: 579 | acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 580 | dependencies: 581 | acorn: 7.4.1 582 | dev: true 583 | 584 | /acorn@7.4.1: 585 | resolution: {integrity: sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==} 586 | engines: {node: '>=0.4.0'} 587 | hasBin: true 588 | dev: true 589 | 590 | /ajv@6.12.6: 591 | resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} 592 | dependencies: 593 | fast-deep-equal: 3.1.3 594 | fast-json-stable-stringify: 2.1.0 595 | json-schema-traverse: 0.4.1 596 | uri-js: 4.4.1 597 | dev: true 598 | 599 | /ajv@8.12.0: 600 | resolution: {integrity: sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==} 601 | dependencies: 602 | fast-deep-equal: 3.1.3 603 | json-schema-traverse: 1.0.0 604 | require-from-string: 2.0.2 605 | uri-js: 4.4.1 606 | dev: true 607 | 608 | /ansi-colors@4.1.3: 609 | resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} 610 | engines: {node: '>=6'} 611 | dev: true 612 | 613 | /ansi-regex@5.0.1: 614 | resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} 615 | engines: {node: '>=8'} 616 | dev: true 617 | 618 | /ansi-styles@3.2.1: 619 | resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} 620 | engines: {node: '>=4'} 621 | dependencies: 622 | color-convert: 1.9.3 623 | dev: true 624 | 625 | /ansi-styles@4.3.0: 626 | resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} 627 | engines: {node: '>=8'} 628 | dependencies: 629 | color-convert: 2.0.1 630 | dev: true 631 | 632 | /anymatch@3.1.3: 633 | resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} 634 | engines: {node: '>= 8'} 635 | dependencies: 636 | normalize-path: 3.0.0 637 | picomatch: 2.3.1 638 | dev: true 639 | 640 | /argparse@1.0.10: 641 | resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} 642 | dependencies: 643 | sprintf-js: 1.0.3 644 | dev: true 645 | 646 | /astral-regex@2.0.0: 647 | resolution: {integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==} 648 | engines: {node: '>=8'} 649 | dev: true 650 | 651 | /balanced-match@1.0.2: 652 | resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} 653 | dev: true 654 | 655 | /binary-extensions@2.2.0: 656 | resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==} 657 | engines: {node: '>=8'} 658 | dev: true 659 | 660 | /blake3-wasm@2.1.5: 661 | resolution: {integrity: sha512-F1+K8EbfOZE49dtoPtmxUQrpXaBIl3ICvasLh+nJta0xkz+9kF/7uet9fLnwKqhDrmj6g+6K3Tw9yQPUg2ka5g==} 662 | dev: true 663 | 664 | /brace-expansion@1.1.11: 665 | resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} 666 | dependencies: 667 | balanced-match: 1.0.2 668 | concat-map: 0.0.1 669 | dev: true 670 | 671 | /braces@3.0.2: 672 | resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} 673 | engines: {node: '>=8'} 674 | dependencies: 675 | fill-range: 7.0.1 676 | dev: true 677 | 678 | /buffer-from@1.1.2: 679 | resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} 680 | dev: true 681 | 682 | /builtins@5.0.1: 683 | resolution: {integrity: sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ==} 684 | dependencies: 685 | semver: 7.5.0 686 | dev: true 687 | 688 | /busboy@1.6.0: 689 | resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==} 690 | engines: {node: '>=10.16.0'} 691 | dependencies: 692 | streamsearch: 1.1.0 693 | dev: true 694 | 695 | /callsites@3.1.0: 696 | resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} 697 | engines: {node: '>=6'} 698 | dev: true 699 | 700 | /chalk@2.4.2: 701 | resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} 702 | engines: {node: '>=4'} 703 | dependencies: 704 | ansi-styles: 3.2.1 705 | escape-string-regexp: 1.0.5 706 | supports-color: 5.5.0 707 | dev: true 708 | 709 | /chalk@4.1.2: 710 | resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} 711 | engines: {node: '>=10'} 712 | dependencies: 713 | ansi-styles: 4.3.0 714 | supports-color: 7.2.0 715 | dev: true 716 | 717 | /chokidar@3.5.3: 718 | resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==} 719 | engines: {node: '>= 8.10.0'} 720 | dependencies: 721 | anymatch: 3.1.3 722 | braces: 3.0.2 723 | glob-parent: 5.1.2 724 | is-binary-path: 2.1.0 725 | is-glob: 4.0.3 726 | normalize-path: 3.0.0 727 | readdirp: 3.6.0 728 | optionalDependencies: 729 | fsevents: 2.3.2 730 | dev: true 731 | 732 | /color-convert@1.9.3: 733 | resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} 734 | dependencies: 735 | color-name: 1.1.3 736 | dev: true 737 | 738 | /color-convert@2.0.1: 739 | resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} 740 | engines: {node: '>=7.0.0'} 741 | dependencies: 742 | color-name: 1.1.4 743 | dev: true 744 | 745 | /color-name@1.1.3: 746 | resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} 747 | dev: true 748 | 749 | /color-name@1.1.4: 750 | resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} 751 | dev: true 752 | 753 | /concat-map@0.0.1: 754 | resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} 755 | dev: true 756 | 757 | /cookie@0.4.2: 758 | resolution: {integrity: sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==} 759 | engines: {node: '>= 0.6'} 760 | dev: true 761 | 762 | /cron-schedule@3.0.6: 763 | resolution: {integrity: sha512-izfGgKyzzIyLaeb1EtZ3KbglkS6AKp9cv7LxmiyoOu+fXfol1tQDC0Cof0enVZGNtudTHW+3lfuW9ZkLQss4Wg==} 764 | dev: true 765 | 766 | /cross-spawn@7.0.3: 767 | resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} 768 | engines: {node: '>= 8'} 769 | dependencies: 770 | path-key: 3.1.1 771 | shebang-command: 2.0.0 772 | which: 2.0.2 773 | dev: true 774 | 775 | /debug@4.3.4: 776 | resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} 777 | engines: {node: '>=6.0'} 778 | peerDependencies: 779 | supports-color: '*' 780 | peerDependenciesMeta: 781 | supports-color: 782 | optional: true 783 | dependencies: 784 | ms: 2.1.2 785 | dev: true 786 | 787 | /deep-is@0.1.4: 788 | resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} 789 | dev: true 790 | 791 | /doctrine@3.0.0: 792 | resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} 793 | engines: {node: '>=6.0.0'} 794 | dependencies: 795 | esutils: 2.0.3 796 | dev: true 797 | 798 | /dotenv-cli@7.2.1: 799 | resolution: {integrity: sha512-ODHbGTskqRtXAzZapDPvgNuDVQApu4oKX8lZW7Y0+9hKA6le1ZJlyRS687oU9FXjOVEDU/VFV6zI125HzhM1UQ==} 800 | hasBin: true 801 | dependencies: 802 | cross-spawn: 7.0.3 803 | dotenv: 16.0.3 804 | dotenv-expand: 10.0.0 805 | minimist: 1.2.8 806 | dev: true 807 | 808 | /dotenv-expand@10.0.0: 809 | resolution: {integrity: sha512-GopVGCpVS1UKH75VKHGuQFqS1Gusej0z4FyQkPdwjil2gNIv+LNsqBlboOzpJFZKVT95GkCyWJbBSdFEFUWI2A==} 810 | engines: {node: '>=12'} 811 | dev: true 812 | 813 | /dotenv@10.0.0: 814 | resolution: {integrity: sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==} 815 | engines: {node: '>=10'} 816 | dev: true 817 | 818 | /dotenv@16.0.3: 819 | resolution: {integrity: sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==} 820 | engines: {node: '>=12'} 821 | dev: true 822 | 823 | /emoji-regex@8.0.0: 824 | resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} 825 | dev: true 826 | 827 | /enquirer@2.3.6: 828 | resolution: {integrity: sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==} 829 | engines: {node: '>=8.6'} 830 | dependencies: 831 | ansi-colors: 4.1.3 832 | dev: true 833 | 834 | /esbuild@0.16.3: 835 | resolution: {integrity: sha512-71f7EjPWTiSguen8X/kxEpkAS7BFHwtQKisCDDV3Y4GLGWBaoSCyD5uXkaUew6JDzA9FEN1W23mdnSwW9kqCeg==} 836 | engines: {node: '>=12'} 837 | hasBin: true 838 | requiresBuild: true 839 | optionalDependencies: 840 | '@esbuild/android-arm': 0.16.3 841 | '@esbuild/android-arm64': 0.16.3 842 | '@esbuild/android-x64': 0.16.3 843 | '@esbuild/darwin-arm64': 0.16.3 844 | '@esbuild/darwin-x64': 0.16.3 845 | '@esbuild/freebsd-arm64': 0.16.3 846 | '@esbuild/freebsd-x64': 0.16.3 847 | '@esbuild/linux-arm': 0.16.3 848 | '@esbuild/linux-arm64': 0.16.3 849 | '@esbuild/linux-ia32': 0.16.3 850 | '@esbuild/linux-loong64': 0.16.3 851 | '@esbuild/linux-mips64el': 0.16.3 852 | '@esbuild/linux-ppc64': 0.16.3 853 | '@esbuild/linux-riscv64': 0.16.3 854 | '@esbuild/linux-s390x': 0.16.3 855 | '@esbuild/linux-x64': 0.16.3 856 | '@esbuild/netbsd-x64': 0.16.3 857 | '@esbuild/openbsd-x64': 0.16.3 858 | '@esbuild/sunos-x64': 0.16.3 859 | '@esbuild/win32-arm64': 0.16.3 860 | '@esbuild/win32-ia32': 0.16.3 861 | '@esbuild/win32-x64': 0.16.3 862 | dev: true 863 | 864 | /escape-string-regexp@1.0.5: 865 | resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} 866 | engines: {node: '>=0.8.0'} 867 | dev: true 868 | 869 | /escape-string-regexp@4.0.0: 870 | resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} 871 | engines: {node: '>=10'} 872 | dev: true 873 | 874 | /eslint-scope@5.1.1: 875 | resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==} 876 | engines: {node: '>=8.0.0'} 877 | dependencies: 878 | esrecurse: 4.3.0 879 | estraverse: 4.3.0 880 | dev: true 881 | 882 | /eslint-utils@2.1.0: 883 | resolution: {integrity: sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==} 884 | engines: {node: '>=6'} 885 | dependencies: 886 | eslint-visitor-keys: 1.3.0 887 | dev: true 888 | 889 | /eslint-visitor-keys@1.3.0: 890 | resolution: {integrity: sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==} 891 | engines: {node: '>=4'} 892 | dev: true 893 | 894 | /eslint-visitor-keys@2.1.0: 895 | resolution: {integrity: sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==} 896 | engines: {node: '>=10'} 897 | dev: true 898 | 899 | /eslint@7.32.0: 900 | resolution: {integrity: sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==} 901 | engines: {node: ^10.12.0 || >=12.0.0} 902 | hasBin: true 903 | dependencies: 904 | '@babel/code-frame': 7.12.11 905 | '@eslint/eslintrc': 0.4.3 906 | '@humanwhocodes/config-array': 0.5.0 907 | ajv: 6.12.6 908 | chalk: 4.1.2 909 | cross-spawn: 7.0.3 910 | debug: 4.3.4 911 | doctrine: 3.0.0 912 | enquirer: 2.3.6 913 | escape-string-regexp: 4.0.0 914 | eslint-scope: 5.1.1 915 | eslint-utils: 2.1.0 916 | eslint-visitor-keys: 2.1.0 917 | espree: 7.3.1 918 | esquery: 1.5.0 919 | esutils: 2.0.3 920 | fast-deep-equal: 3.1.3 921 | file-entry-cache: 6.0.1 922 | functional-red-black-tree: 1.0.1 923 | glob-parent: 5.1.2 924 | globals: 13.20.0 925 | ignore: 4.0.6 926 | import-fresh: 3.3.0 927 | imurmurhash: 0.1.4 928 | is-glob: 4.0.3 929 | js-yaml: 3.14.1 930 | json-stable-stringify-without-jsonify: 1.0.1 931 | levn: 0.4.1 932 | lodash.merge: 4.6.2 933 | minimatch: 3.1.2 934 | natural-compare: 1.4.0 935 | optionator: 0.9.1 936 | progress: 2.0.3 937 | regexpp: 3.2.0 938 | semver: 7.5.0 939 | strip-ansi: 6.0.1 940 | strip-json-comments: 3.1.1 941 | table: 6.8.1 942 | text-table: 0.2.0 943 | v8-compile-cache: 2.3.0 944 | transitivePeerDependencies: 945 | - supports-color 946 | dev: true 947 | 948 | /espree@7.3.1: 949 | resolution: {integrity: sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==} 950 | engines: {node: ^10.12.0 || >=12.0.0} 951 | dependencies: 952 | acorn: 7.4.1 953 | acorn-jsx: 5.3.2(acorn@7.4.1) 954 | eslint-visitor-keys: 1.3.0 955 | dev: true 956 | 957 | /esprima@4.0.1: 958 | resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} 959 | engines: {node: '>=4'} 960 | hasBin: true 961 | dev: true 962 | 963 | /esquery@1.5.0: 964 | resolution: {integrity: sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==} 965 | engines: {node: '>=0.10'} 966 | dependencies: 967 | estraverse: 5.3.0 968 | dev: true 969 | 970 | /esrecurse@4.3.0: 971 | resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} 972 | engines: {node: '>=4.0'} 973 | dependencies: 974 | estraverse: 5.3.0 975 | dev: true 976 | 977 | /estraverse@4.3.0: 978 | resolution: {integrity: sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==} 979 | engines: {node: '>=4.0'} 980 | dev: true 981 | 982 | /estraverse@5.3.0: 983 | resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} 984 | engines: {node: '>=4.0'} 985 | dev: true 986 | 987 | /estree-walker@0.6.1: 988 | resolution: {integrity: sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==} 989 | dev: true 990 | 991 | /esutils@2.0.3: 992 | resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} 993 | engines: {node: '>=0.10.0'} 994 | dev: true 995 | 996 | /execa@6.1.0: 997 | resolution: {integrity: sha512-QVWlX2e50heYJcCPG0iWtf8r0xjEYfz/OYLGDYH+IyjWezzPNxz63qNFOu0l4YftGWuizFVZHHs8PrLU5p2IDA==} 998 | engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} 999 | dependencies: 1000 | cross-spawn: 7.0.3 1001 | get-stream: 6.0.1 1002 | human-signals: 3.0.1 1003 | is-stream: 3.0.0 1004 | merge-stream: 2.0.0 1005 | npm-run-path: 5.1.0 1006 | onetime: 6.0.0 1007 | signal-exit: 3.0.7 1008 | strip-final-newline: 3.0.0 1009 | dev: true 1010 | 1011 | /fast-deep-equal@3.1.3: 1012 | resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} 1013 | dev: true 1014 | 1015 | /fast-json-stable-stringify@2.1.0: 1016 | resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} 1017 | dev: true 1018 | 1019 | /fast-levenshtein@2.0.6: 1020 | resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} 1021 | dev: true 1022 | 1023 | /fflate@0.7.4: 1024 | resolution: {integrity: sha512-5u2V/CDW15QM1XbbgS+0DfPxVB+jUKhWEKuuFuHncbk3tEEqzmoXL+2KyOFuKGqOnmdIy0/davWF1CkuwtibCw==} 1025 | dev: false 1026 | 1027 | /file-entry-cache@6.0.1: 1028 | resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} 1029 | engines: {node: ^10.12.0 || >=12.0.0} 1030 | dependencies: 1031 | flat-cache: 3.0.4 1032 | dev: true 1033 | 1034 | /fill-range@7.0.1: 1035 | resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} 1036 | engines: {node: '>=8'} 1037 | dependencies: 1038 | to-regex-range: 5.0.1 1039 | dev: true 1040 | 1041 | /flat-cache@3.0.4: 1042 | resolution: {integrity: sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==} 1043 | engines: {node: ^10.12.0 || >=12.0.0} 1044 | dependencies: 1045 | flatted: 3.2.7 1046 | rimraf: 3.0.2 1047 | dev: true 1048 | 1049 | /flatted@3.2.7: 1050 | resolution: {integrity: sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==} 1051 | dev: true 1052 | 1053 | /fs.realpath@1.0.0: 1054 | resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} 1055 | dev: true 1056 | 1057 | /fsevents@2.3.2: 1058 | resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} 1059 | engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} 1060 | os: [darwin] 1061 | requiresBuild: true 1062 | dev: true 1063 | optional: true 1064 | 1065 | /functional-red-black-tree@1.0.1: 1066 | resolution: {integrity: sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==} 1067 | dev: true 1068 | 1069 | /get-stream@6.0.1: 1070 | resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} 1071 | engines: {node: '>=10'} 1072 | dev: true 1073 | 1074 | /glob-parent@5.1.2: 1075 | resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} 1076 | engines: {node: '>= 6'} 1077 | dependencies: 1078 | is-glob: 4.0.3 1079 | dev: true 1080 | 1081 | /glob@7.2.3: 1082 | resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} 1083 | dependencies: 1084 | fs.realpath: 1.0.0 1085 | inflight: 1.0.6 1086 | inherits: 2.0.4 1087 | minimatch: 3.1.2 1088 | once: 1.4.0 1089 | path-is-absolute: 1.0.1 1090 | dev: true 1091 | 1092 | /globals@13.20.0: 1093 | resolution: {integrity: sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==} 1094 | engines: {node: '>=8'} 1095 | dependencies: 1096 | type-fest: 0.20.2 1097 | dev: true 1098 | 1099 | /has-flag@3.0.0: 1100 | resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} 1101 | engines: {node: '>=4'} 1102 | dev: true 1103 | 1104 | /has-flag@4.0.0: 1105 | resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} 1106 | engines: {node: '>=8'} 1107 | dev: true 1108 | 1109 | /html-rewriter-wasm@0.4.1: 1110 | resolution: {integrity: sha512-lNovG8CMCCmcVB1Q7xggMSf7tqPCijZXaH4gL6iE8BFghdQCbaY5Met9i1x2Ex8m/cZHDUtXK9H6/znKamRP8Q==} 1111 | dev: true 1112 | 1113 | /http-cache-semantics@4.1.1: 1114 | resolution: {integrity: sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==} 1115 | dev: true 1116 | 1117 | /human-signals@3.0.1: 1118 | resolution: {integrity: sha512-rQLskxnM/5OCldHo+wNXbpVgDn5A17CUoKX+7Sokwaknlq7CdSnphy0W39GU8dw59XiCXmFXDg4fRuckQRKewQ==} 1119 | engines: {node: '>=12.20.0'} 1120 | dev: true 1121 | 1122 | /ignore@4.0.6: 1123 | resolution: {integrity: sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==} 1124 | engines: {node: '>= 4'} 1125 | dev: true 1126 | 1127 | /import-fresh@3.3.0: 1128 | resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} 1129 | engines: {node: '>=6'} 1130 | dependencies: 1131 | parent-module: 1.0.1 1132 | resolve-from: 4.0.0 1133 | dev: true 1134 | 1135 | /imurmurhash@0.1.4: 1136 | resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} 1137 | engines: {node: '>=0.8.19'} 1138 | dev: true 1139 | 1140 | /inflight@1.0.6: 1141 | resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} 1142 | dependencies: 1143 | once: 1.4.0 1144 | wrappy: 1.0.2 1145 | dev: true 1146 | 1147 | /inherits@2.0.4: 1148 | resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} 1149 | dev: true 1150 | 1151 | /is-binary-path@2.1.0: 1152 | resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} 1153 | engines: {node: '>=8'} 1154 | dependencies: 1155 | binary-extensions: 2.2.0 1156 | dev: true 1157 | 1158 | /is-extglob@2.1.1: 1159 | resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} 1160 | engines: {node: '>=0.10.0'} 1161 | dev: true 1162 | 1163 | /is-fullwidth-code-point@3.0.0: 1164 | resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} 1165 | engines: {node: '>=8'} 1166 | dev: true 1167 | 1168 | /is-glob@4.0.3: 1169 | resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} 1170 | engines: {node: '>=0.10.0'} 1171 | dependencies: 1172 | is-extglob: 2.1.1 1173 | dev: true 1174 | 1175 | /is-number@7.0.0: 1176 | resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} 1177 | engines: {node: '>=0.12.0'} 1178 | dev: true 1179 | 1180 | /is-stream@3.0.0: 1181 | resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==} 1182 | engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} 1183 | dev: true 1184 | 1185 | /isexe@2.0.0: 1186 | resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} 1187 | dev: true 1188 | 1189 | /js-tokens@4.0.0: 1190 | resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} 1191 | dev: true 1192 | 1193 | /js-yaml@3.14.1: 1194 | resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==} 1195 | hasBin: true 1196 | dependencies: 1197 | argparse: 1.0.10 1198 | esprima: 4.0.1 1199 | dev: true 1200 | 1201 | /json-schema-traverse@0.4.1: 1202 | resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} 1203 | dev: true 1204 | 1205 | /json-schema-traverse@1.0.0: 1206 | resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} 1207 | dev: true 1208 | 1209 | /json-stable-stringify-without-jsonify@1.0.1: 1210 | resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} 1211 | dev: true 1212 | 1213 | /kleur@4.1.5: 1214 | resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==} 1215 | engines: {node: '>=6'} 1216 | dev: true 1217 | 1218 | /levn@0.4.1: 1219 | resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} 1220 | engines: {node: '>= 0.8.0'} 1221 | dependencies: 1222 | prelude-ls: 1.2.1 1223 | type-check: 0.4.0 1224 | dev: true 1225 | 1226 | /lodash.merge@4.6.2: 1227 | resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} 1228 | dev: true 1229 | 1230 | /lodash.truncate@4.4.2: 1231 | resolution: {integrity: sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==} 1232 | dev: true 1233 | 1234 | /lru-cache@6.0.0: 1235 | resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} 1236 | engines: {node: '>=10'} 1237 | dependencies: 1238 | yallist: 4.0.0 1239 | dev: true 1240 | 1241 | /magic-string@0.25.9: 1242 | resolution: {integrity: sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==} 1243 | dependencies: 1244 | sourcemap-codec: 1.4.8 1245 | dev: true 1246 | 1247 | /merge-stream@2.0.0: 1248 | resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} 1249 | dev: true 1250 | 1251 | /mime@3.0.0: 1252 | resolution: {integrity: sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==} 1253 | engines: {node: '>=10.0.0'} 1254 | hasBin: true 1255 | dev: true 1256 | 1257 | /mimic-fn@4.0.0: 1258 | resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==} 1259 | engines: {node: '>=12'} 1260 | dev: true 1261 | 1262 | /miniflare@2.13.0: 1263 | resolution: {integrity: sha512-ayNhVa4a6bZiOuHtrPmOt4BCYcmW1fBQ/+qGL85smq1m2OBBm3aUs6f4ISf38xH8tk+qewgmAywetyVtn6KHPw==} 1264 | engines: {node: '>=16.13'} 1265 | hasBin: true 1266 | peerDependencies: 1267 | '@miniflare/storage-redis': 2.13.0 1268 | cron-schedule: ^3.0.4 1269 | ioredis: ^4.27.9 1270 | peerDependenciesMeta: 1271 | '@miniflare/storage-redis': 1272 | optional: true 1273 | cron-schedule: 1274 | optional: true 1275 | ioredis: 1276 | optional: true 1277 | dependencies: 1278 | '@miniflare/cache': 2.13.0 1279 | '@miniflare/cli-parser': 2.13.0 1280 | '@miniflare/core': 2.13.0 1281 | '@miniflare/d1': 2.13.0 1282 | '@miniflare/durable-objects': 2.13.0 1283 | '@miniflare/html-rewriter': 2.13.0 1284 | '@miniflare/http-server': 2.13.0 1285 | '@miniflare/kv': 2.13.0 1286 | '@miniflare/queues': 2.13.0 1287 | '@miniflare/r2': 2.13.0 1288 | '@miniflare/runner-vm': 2.13.0 1289 | '@miniflare/scheduler': 2.13.0 1290 | '@miniflare/shared': 2.13.0 1291 | '@miniflare/sites': 2.13.0 1292 | '@miniflare/storage-file': 2.13.0 1293 | '@miniflare/storage-memory': 2.13.0 1294 | '@miniflare/web-sockets': 2.13.0 1295 | kleur: 4.1.5 1296 | semiver: 1.1.0 1297 | source-map-support: 0.5.21 1298 | undici: 5.20.0 1299 | transitivePeerDependencies: 1300 | - bufferutil 1301 | - utf-8-validate 1302 | dev: true 1303 | 1304 | /minimatch@3.1.2: 1305 | resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} 1306 | dependencies: 1307 | brace-expansion: 1.1.11 1308 | dev: true 1309 | 1310 | /minimist@1.2.8: 1311 | resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} 1312 | dev: true 1313 | 1314 | /minisearch@6.0.1: 1315 | resolution: {integrity: sha512-Ly1w0nHKnlhAAh6/BF/+9NgzXfoJxaJ8nhopFhQ3NcvFJrFIL+iCg9gw9e9UMBD+XIsp/RyznJ/o5UIe5Kw+kg==} 1316 | dev: false 1317 | 1318 | /ms@2.1.2: 1319 | resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} 1320 | dev: true 1321 | 1322 | /mustache@4.2.0: 1323 | resolution: {integrity: sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==} 1324 | hasBin: true 1325 | dev: true 1326 | 1327 | /nanoid@3.3.6: 1328 | resolution: {integrity: sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==} 1329 | engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} 1330 | hasBin: true 1331 | dev: true 1332 | 1333 | /natural-compare@1.4.0: 1334 | resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} 1335 | dev: true 1336 | 1337 | /node-forge@1.3.1: 1338 | resolution: {integrity: sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==} 1339 | engines: {node: '>= 6.13.0'} 1340 | dev: true 1341 | 1342 | /normalize-path@3.0.0: 1343 | resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} 1344 | engines: {node: '>=0.10.0'} 1345 | dev: true 1346 | 1347 | /npm-run-path@5.1.0: 1348 | resolution: {integrity: sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==} 1349 | engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} 1350 | dependencies: 1351 | path-key: 4.0.0 1352 | dev: true 1353 | 1354 | /npx-import@1.1.4: 1355 | resolution: {integrity: sha512-3ShymTWOgqGyNlh5lMJAejLuIv3W1K3fbI5Ewc6YErZU3Sp0PqsNs8UIU1O8z5+KVl/Du5ag56Gza9vdorGEoA==} 1356 | dependencies: 1357 | execa: 6.1.0 1358 | parse-package-name: 1.0.0 1359 | semver: 7.5.0 1360 | validate-npm-package-name: 4.0.0 1361 | dev: true 1362 | 1363 | /once@1.4.0: 1364 | resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} 1365 | dependencies: 1366 | wrappy: 1.0.2 1367 | dev: true 1368 | 1369 | /onetime@6.0.0: 1370 | resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==} 1371 | engines: {node: '>=12'} 1372 | dependencies: 1373 | mimic-fn: 4.0.0 1374 | dev: true 1375 | 1376 | /optionator@0.9.1: 1377 | resolution: {integrity: sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==} 1378 | engines: {node: '>= 0.8.0'} 1379 | dependencies: 1380 | deep-is: 0.1.4 1381 | fast-levenshtein: 2.0.6 1382 | levn: 0.4.1 1383 | prelude-ls: 1.2.1 1384 | type-check: 0.4.0 1385 | word-wrap: 1.2.3 1386 | dev: true 1387 | 1388 | /parent-module@1.0.1: 1389 | resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} 1390 | engines: {node: '>=6'} 1391 | dependencies: 1392 | callsites: 3.1.0 1393 | dev: true 1394 | 1395 | /parse-package-name@1.0.0: 1396 | resolution: {integrity: sha512-kBeTUtcj+SkyfaW4+KBe0HtsloBJ/mKTPoxpVdA57GZiPerREsUWJOhVj9anXweFiJkm5y8FG1sxFZkZ0SN6wg==} 1397 | dev: true 1398 | 1399 | /path-is-absolute@1.0.1: 1400 | resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} 1401 | engines: {node: '>=0.10.0'} 1402 | dev: true 1403 | 1404 | /path-key@3.1.1: 1405 | resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} 1406 | engines: {node: '>=8'} 1407 | dev: true 1408 | 1409 | /path-key@4.0.0: 1410 | resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==} 1411 | engines: {node: '>=12'} 1412 | dev: true 1413 | 1414 | /path-to-regexp@6.2.1: 1415 | resolution: {integrity: sha512-JLyh7xT1kizaEvcaXOQwOc2/Yhw6KZOvPf1S8401UyLk86CU79LN3vl7ztXGm/pZ+YjoyAJ4rxmHwbkBXJX+yw==} 1416 | dev: true 1417 | 1418 | /picomatch@2.3.1: 1419 | resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} 1420 | engines: {node: '>=8.6'} 1421 | dev: true 1422 | 1423 | /prelude-ls@1.2.1: 1424 | resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} 1425 | engines: {node: '>= 0.8.0'} 1426 | dev: true 1427 | 1428 | /prettier@2.8.8: 1429 | resolution: {integrity: sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==} 1430 | engines: {node: '>=10.13.0'} 1431 | hasBin: true 1432 | dev: true 1433 | 1434 | /progress@2.0.3: 1435 | resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==} 1436 | engines: {node: '>=0.4.0'} 1437 | dev: true 1438 | 1439 | /punycode@2.3.0: 1440 | resolution: {integrity: sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==} 1441 | engines: {node: '>=6'} 1442 | dev: true 1443 | 1444 | /readdirp@3.6.0: 1445 | resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} 1446 | engines: {node: '>=8.10.0'} 1447 | dependencies: 1448 | picomatch: 2.3.1 1449 | dev: true 1450 | 1451 | /regexpp@3.2.0: 1452 | resolution: {integrity: sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==} 1453 | engines: {node: '>=8'} 1454 | dev: true 1455 | 1456 | /require-from-string@2.0.2: 1457 | resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} 1458 | engines: {node: '>=0.10.0'} 1459 | dev: true 1460 | 1461 | /resolve-from@4.0.0: 1462 | resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} 1463 | engines: {node: '>=4'} 1464 | dev: true 1465 | 1466 | /rimraf@3.0.2: 1467 | resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} 1468 | hasBin: true 1469 | dependencies: 1470 | glob: 7.2.3 1471 | dev: true 1472 | 1473 | /rollup-plugin-inject@3.0.2: 1474 | resolution: {integrity: sha512-ptg9PQwzs3orn4jkgXJ74bfs5vYz1NCZlSQMBUA0wKcGp5i5pA1AO3fOUEte8enhGUC+iapTCzEWw2jEFFUO/w==} 1475 | deprecated: This package has been deprecated and is no longer maintained. Please use @rollup/plugin-inject. 1476 | dependencies: 1477 | estree-walker: 0.6.1 1478 | magic-string: 0.25.9 1479 | rollup-pluginutils: 2.8.2 1480 | dev: true 1481 | 1482 | /rollup-plugin-node-polyfills@0.2.1: 1483 | resolution: {integrity: sha512-4kCrKPTJ6sK4/gLL/U5QzVT8cxJcofO0OU74tnB19F40cmuAKSzH5/siithxlofFEjwvw1YAhPmbvGNA6jEroA==} 1484 | dependencies: 1485 | rollup-plugin-inject: 3.0.2 1486 | dev: true 1487 | 1488 | /rollup-pluginutils@2.8.2: 1489 | resolution: {integrity: sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==} 1490 | dependencies: 1491 | estree-walker: 0.6.1 1492 | dev: true 1493 | 1494 | /selfsigned@2.1.1: 1495 | resolution: {integrity: sha512-GSL3aowiF7wa/WtSFwnUrludWFoNhftq8bUkH9pkzjpN2XSPOAYEgg6e0sS9s0rZwgJzJiQRPU18A6clnoW5wQ==} 1496 | engines: {node: '>=10'} 1497 | dependencies: 1498 | node-forge: 1.3.1 1499 | dev: true 1500 | 1501 | /semiver@1.1.0: 1502 | resolution: {integrity: sha512-QNI2ChmuioGC1/xjyYwyZYADILWyW6AmS1UH6gDj/SFUUUS4MBAWs/7mxnkRPc/F4iHezDP+O8t0dO8WHiEOdg==} 1503 | engines: {node: '>=6'} 1504 | dev: true 1505 | 1506 | /semver@7.5.0: 1507 | resolution: {integrity: sha512-+XC0AD/R7Q2mPSRuy2Id0+CGTZ98+8f+KvwirxOKIEyid+XSx6HbC63p+O4IndTHuX5Z+JxQ0TghCkO5Cg/2HA==} 1508 | engines: {node: '>=10'} 1509 | hasBin: true 1510 | dependencies: 1511 | lru-cache: 6.0.0 1512 | dev: true 1513 | 1514 | /set-cookie-parser@2.6.0: 1515 | resolution: {integrity: sha512-RVnVQxTXuerk653XfuliOxBP81Sf0+qfQE73LIYKcyMYHG94AuH0kgrQpRDuTZnSmjpysHmzxJXKNfa6PjFhyQ==} 1516 | dev: true 1517 | 1518 | /shebang-command@2.0.0: 1519 | resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} 1520 | engines: {node: '>=8'} 1521 | dependencies: 1522 | shebang-regex: 3.0.0 1523 | dev: true 1524 | 1525 | /shebang-regex@3.0.0: 1526 | resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} 1527 | engines: {node: '>=8'} 1528 | dev: true 1529 | 1530 | /signal-exit@3.0.7: 1531 | resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} 1532 | dev: true 1533 | 1534 | /slice-ansi@4.0.0: 1535 | resolution: {integrity: sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==} 1536 | engines: {node: '>=10'} 1537 | dependencies: 1538 | ansi-styles: 4.3.0 1539 | astral-regex: 2.0.0 1540 | is-fullwidth-code-point: 3.0.0 1541 | dev: true 1542 | 1543 | /source-map-support@0.5.21: 1544 | resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} 1545 | dependencies: 1546 | buffer-from: 1.1.2 1547 | source-map: 0.6.1 1548 | dev: true 1549 | 1550 | /source-map@0.6.1: 1551 | resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} 1552 | engines: {node: '>=0.10.0'} 1553 | dev: true 1554 | 1555 | /source-map@0.7.4: 1556 | resolution: {integrity: sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==} 1557 | engines: {node: '>= 8'} 1558 | dev: true 1559 | 1560 | /sourcemap-codec@1.4.8: 1561 | resolution: {integrity: sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==} 1562 | deprecated: Please use @jridgewell/sourcemap-codec instead 1563 | dev: true 1564 | 1565 | /sprintf-js@1.0.3: 1566 | resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} 1567 | dev: true 1568 | 1569 | /stack-trace@0.0.10: 1570 | resolution: {integrity: sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==} 1571 | dev: true 1572 | 1573 | /streamsearch@1.1.0: 1574 | resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==} 1575 | engines: {node: '>=10.0.0'} 1576 | dev: true 1577 | 1578 | /string-width@4.2.3: 1579 | resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} 1580 | engines: {node: '>=8'} 1581 | dependencies: 1582 | emoji-regex: 8.0.0 1583 | is-fullwidth-code-point: 3.0.0 1584 | strip-ansi: 6.0.1 1585 | dev: true 1586 | 1587 | /strip-ansi@6.0.1: 1588 | resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} 1589 | engines: {node: '>=8'} 1590 | dependencies: 1591 | ansi-regex: 5.0.1 1592 | dev: true 1593 | 1594 | /strip-final-newline@3.0.0: 1595 | resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==} 1596 | engines: {node: '>=12'} 1597 | dev: true 1598 | 1599 | /strip-json-comments@3.1.1: 1600 | resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} 1601 | engines: {node: '>=8'} 1602 | dev: true 1603 | 1604 | /supports-color@5.5.0: 1605 | resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} 1606 | engines: {node: '>=4'} 1607 | dependencies: 1608 | has-flag: 3.0.0 1609 | dev: true 1610 | 1611 | /supports-color@7.2.0: 1612 | resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} 1613 | engines: {node: '>=8'} 1614 | dependencies: 1615 | has-flag: 4.0.0 1616 | dev: true 1617 | 1618 | /table@6.8.1: 1619 | resolution: {integrity: sha512-Y4X9zqrCftUhMeH2EptSSERdVKt/nEdijTOacGD/97EKjhQ/Qs8RTlEGABSJNNN8lac9kheH+af7yAkEWlgneA==} 1620 | engines: {node: '>=10.0.0'} 1621 | dependencies: 1622 | ajv: 8.12.0 1623 | lodash.truncate: 4.4.2 1624 | slice-ansi: 4.0.0 1625 | string-width: 4.2.3 1626 | strip-ansi: 6.0.1 1627 | dev: true 1628 | 1629 | /text-table@0.2.0: 1630 | resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} 1631 | dev: true 1632 | 1633 | /to-regex-range@5.0.1: 1634 | resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} 1635 | engines: {node: '>=8.0'} 1636 | dependencies: 1637 | is-number: 7.0.0 1638 | dev: true 1639 | 1640 | /turbo-darwin-64@1.9.3: 1641 | resolution: {integrity: sha512-0dFc2cWXl82kRE4Z+QqPHhbEFEpUZho1msHXHWbz5+PqLxn8FY0lEVOHkq5tgKNNEd5KnGyj33gC/bHhpZOk5g==} 1642 | cpu: [x64] 1643 | os: [darwin] 1644 | requiresBuild: true 1645 | dev: true 1646 | optional: true 1647 | 1648 | /turbo-darwin-arm64@1.9.3: 1649 | resolution: {integrity: sha512-1cYbjqLBA2zYE1nbf/qVnEkrHa4PkJJbLo7hnuMuGM0bPzh4+AnTNe98gELhqI1mkTWBu/XAEeF5u6dgz0jLNA==} 1650 | cpu: [arm64] 1651 | os: [darwin] 1652 | requiresBuild: true 1653 | dev: true 1654 | optional: true 1655 | 1656 | /turbo-linux-64@1.9.3: 1657 | resolution: {integrity: sha512-UuBPFefawEwpuxh5pM9Jqq3q4C8M0vYxVYlB3qea/nHQ80pxYq7ZcaLGEpb10SGnr3oMUUs1zZvkXWDNKCJb8Q==} 1658 | cpu: [x64] 1659 | os: [linux] 1660 | requiresBuild: true 1661 | dev: true 1662 | optional: true 1663 | 1664 | /turbo-linux-arm64@1.9.3: 1665 | resolution: {integrity: sha512-vUrNGa3hyDtRh9W0MkO+l1dzP8Co2gKnOVmlJQW0hdpOlWlIh22nHNGGlICg+xFa2f9j4PbQlWTsc22c019s8Q==} 1666 | cpu: [arm64] 1667 | os: [linux] 1668 | requiresBuild: true 1669 | dev: true 1670 | optional: true 1671 | 1672 | /turbo-windows-64@1.9.3: 1673 | resolution: {integrity: sha512-0BZ7YaHs6r+K4ksqWus1GKK3W45DuDqlmfjm/yuUbTEVc8szmMCs12vugU2Zi5GdrdJSYfoKfEJ/PeegSLIQGQ==} 1674 | cpu: [x64] 1675 | os: [win32] 1676 | requiresBuild: true 1677 | dev: true 1678 | optional: true 1679 | 1680 | /turbo-windows-arm64@1.9.3: 1681 | resolution: {integrity: sha512-QJUYLSsxdXOsR1TquiOmLdAgtYcQ/RuSRpScGvnZb1hY0oLc7JWU0llkYB81wVtWs469y8H9O0cxbKwCZGR4RQ==} 1682 | cpu: [arm64] 1683 | os: [win32] 1684 | requiresBuild: true 1685 | dev: true 1686 | optional: true 1687 | 1688 | /turbo@1.9.3: 1689 | resolution: {integrity: sha512-ID7mxmaLUPKG/hVkp+h0VuucB1U99RPCJD9cEuSEOdIPoSIuomcIClEJtKamUsdPLhLCud+BvapBNnhgh58Nzw==} 1690 | hasBin: true 1691 | requiresBuild: true 1692 | optionalDependencies: 1693 | turbo-darwin-64: 1.9.3 1694 | turbo-darwin-arm64: 1.9.3 1695 | turbo-linux-64: 1.9.3 1696 | turbo-linux-arm64: 1.9.3 1697 | turbo-windows-64: 1.9.3 1698 | turbo-windows-arm64: 1.9.3 1699 | dev: true 1700 | 1701 | /type-check@0.4.0: 1702 | resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} 1703 | engines: {node: '>= 0.8.0'} 1704 | dependencies: 1705 | prelude-ls: 1.2.1 1706 | dev: true 1707 | 1708 | /type-fest@0.20.2: 1709 | resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} 1710 | engines: {node: '>=10'} 1711 | dev: true 1712 | 1713 | /undici@5.20.0: 1714 | resolution: {integrity: sha512-J3j60dYzuo6Eevbawwp1sdg16k5Tf768bxYK4TUJRH7cBM4kFCbf3mOnM/0E3vQYXvpxITbbWmBafaDbxLDz3g==} 1715 | engines: {node: '>=12.18'} 1716 | dependencies: 1717 | busboy: 1.6.0 1718 | dev: true 1719 | 1720 | /uri-js@4.4.1: 1721 | resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} 1722 | dependencies: 1723 | punycode: 2.3.0 1724 | dev: true 1725 | 1726 | /urlpattern-polyfill@4.0.3: 1727 | resolution: {integrity: sha512-DOE84vZT2fEcl9gqCUTcnAw5ZY5Id55ikUcziSUntuEFL3pRvavg5kwDmTEUJkeCHInTlV/HexFomgYnzO5kdQ==} 1728 | dev: true 1729 | 1730 | /v8-compile-cache@2.3.0: 1731 | resolution: {integrity: sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==} 1732 | dev: true 1733 | 1734 | /validate-npm-package-name@4.0.0: 1735 | resolution: {integrity: sha512-mzR0L8ZDktZjpX4OB46KT+56MAhl4EIazWP/+G/HPGuvfdaqg4YsCdtOm6U9+LOFyYDoh4dpnpxZRB9MQQns5Q==} 1736 | engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} 1737 | dependencies: 1738 | builtins: 5.0.1 1739 | dev: true 1740 | 1741 | /which@2.0.2: 1742 | resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} 1743 | engines: {node: '>= 8'} 1744 | hasBin: true 1745 | dependencies: 1746 | isexe: 2.0.0 1747 | dev: true 1748 | 1749 | /word-wrap@1.2.3: 1750 | resolution: {integrity: sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==} 1751 | engines: {node: '>=0.10.0'} 1752 | dev: true 1753 | 1754 | /wrangler@2.18.0: 1755 | resolution: {integrity: sha512-e+WJ019AbioAf9u4YiOxjrfKqzOP8K3kDAM9v+lGQa+WKsae/UVcMb3Hn5iMIlIt2fc622WefZfuSNRpkAzrSA==} 1756 | engines: {node: '>=16.13.0'} 1757 | hasBin: true 1758 | dependencies: 1759 | '@cloudflare/kv-asset-handler': 0.2.0 1760 | '@esbuild-plugins/node-globals-polyfill': 0.1.1(esbuild@0.16.3) 1761 | '@esbuild-plugins/node-modules-polyfill': 0.1.4(esbuild@0.16.3) 1762 | '@miniflare/core': 2.13.0 1763 | '@miniflare/d1': 2.13.0 1764 | '@miniflare/durable-objects': 2.13.0 1765 | blake3-wasm: 2.1.5 1766 | chokidar: 3.5.3 1767 | esbuild: 0.16.3 1768 | miniflare: 2.13.0 1769 | nanoid: 3.3.6 1770 | path-to-regexp: 6.2.1 1771 | selfsigned: 2.1.1 1772 | source-map: 0.7.4 1773 | xxhash-wasm: 1.0.2 1774 | optionalDependencies: 1775 | fsevents: 2.3.2 1776 | transitivePeerDependencies: 1777 | - '@miniflare/storage-redis' 1778 | - bufferutil 1779 | - cron-schedule 1780 | - ioredis 1781 | - utf-8-validate 1782 | dev: true 1783 | 1784 | /wrappy@1.0.2: 1785 | resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} 1786 | dev: true 1787 | 1788 | /ws@8.13.0: 1789 | resolution: {integrity: sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==} 1790 | engines: {node: '>=10.0.0'} 1791 | peerDependencies: 1792 | bufferutil: ^4.0.1 1793 | utf-8-validate: '>=5.0.2' 1794 | peerDependenciesMeta: 1795 | bufferutil: 1796 | optional: true 1797 | utf-8-validate: 1798 | optional: true 1799 | dev: true 1800 | 1801 | /xxhash-wasm@1.0.2: 1802 | resolution: {integrity: sha512-ibF0Or+FivM9lNrg+HGJfVX8WJqgo+kCLDc4vx6xMeTce7Aj+DLttKbxxRR/gNLSAelRc1omAPlJ77N/Jem07A==} 1803 | dev: true 1804 | 1805 | /yallist@4.0.0: 1806 | resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} 1807 | dev: true 1808 | 1809 | /youch@2.2.2: 1810 | resolution: {integrity: sha512-/FaCeG3GkuJwaMR34GHVg0l8jCbafZLHiFowSjqLlqhC6OMyf2tPJBu8UirF7/NI9X/R5ai4QfEKUCOxMAGxZQ==} 1811 | dependencies: 1812 | '@types/stack-trace': 0.0.29 1813 | cookie: 0.4.2 1814 | mustache: 4.2.0 1815 | stack-trace: 0.0.10 1816 | dev: true 1817 | -------------------------------------------------------------------------------- /pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | packages: 2 | - "worker/*" 3 | - "packages/*" 4 | -------------------------------------------------------------------------------- /scripts/init_secret.js: -------------------------------------------------------------------------------- 1 | const crypto = require("crypto"); 2 | const fs = require("fs"); 3 | 4 | const config = fs.readFileSync("config.json"); 5 | const parsedConfig = JSON.parse(config); 6 | 7 | parsedConfig.secret = crypto.randomBytes(64).toString("hex"); 8 | 9 | fs.writeFileSync("config.json", JSON.stringify(parsedConfig, null, 2)); 10 | -------------------------------------------------------------------------------- /turbo.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://turbo.build/schema.json", 3 | "globalDependencies": ["**/.env.*local"], 4 | "pipeline": { 5 | "build": { 6 | "dependsOn": ["^build"], 7 | "outputs": [".next/**", "!.next/cache/**"] 8 | }, 9 | "lint": {}, 10 | "dev": { 11 | "cache": false, 12 | "persistent": true 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /worker/index-consumer/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "search-index-consumer", 3 | "version": "0.0.0", 4 | "devDependencies": { 5 | "@cloudflare/workers-types": "^4.20230419.0", 6 | "@tm9657/tsconfig": "^1.2.0", 7 | "wrangler": "2.18.0" 8 | }, 9 | "private": true, 10 | "scripts": { 11 | "start": "wrangler dev", 12 | "build": "wrangler publish --minify", 13 | "deploy": "wrangler publish" 14 | }, 15 | "dependencies": { 16 | "util": "workspace:*" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /worker/index-consumer/src/index.ts: -------------------------------------------------------------------------------- 1 | import { loadIndex, saveIndex } from "util"; 2 | import { SearchQueueMessage, Options, MiniSearch } from "util/types"; 3 | import { cachePut } from "util/cache"; 4 | export interface Env { 5 | // Example binding to KV. Learn more at https://developers.cloudflare.com/workers/runtime-apis/kv/ 6 | // MY_KV_NAMESPACE: KVNamespace; 7 | // 8 | // Example binding to Durable Object. Learn more at https://developers.cloudflare.com/workers/runtime-apis/durable-objects/ 9 | // MY_DURABLE_OBJECT: DurableObjectNamespace; 10 | // 11 | // Example binding to R2. Learn more at https://developers.cloudflare.com/workers/runtime-apis/r2/ 12 | SEARCH_BUCKET: R2Bucket; 13 | // 14 | // Example binding to a Service. Learn more at https://developers.cloudflare.com/workers/runtime-apis/service-bindings/ 15 | // MY_SERVICE: Fetcher; 16 | } 17 | 18 | // caching the index, concurrency max 1, so no parallel data is missed 19 | let indices = new Map< 20 | string, 21 | { index: MiniSearch; config: Options } 22 | >(); 23 | 24 | export default { 25 | async queue( 26 | batch: MessageBatch, 27 | env: Env, 28 | ctx: ExecutionContext 29 | ) { 30 | const bucket = env.SEARCH_BUCKET; 31 | const changed = new Set(); 32 | 33 | for await (const msg of batch.messages) { 34 | const { config, document, index } = msg.body; 35 | const indexFile = indices.has(index) 36 | ? indices.get(index)?.index 37 | : await loadIndex( 38 | (await (await bucket.get(index))?.text()) || "", 39 | config 40 | ); 41 | if (!indexFile) continue; 42 | changed.add(index); 43 | try { 44 | indexFile.add(document); 45 | } catch (e) { 46 | console.log("replacing existing document"); 47 | indexFile.replace(document); 48 | } 49 | indices.set(index, { index: indexFile, config }); 50 | } 51 | 52 | // saving the index changes 53 | for await (const changedIndex of changed) { 54 | if (!indices.has(changedIndex)) continue; 55 | const { index, config } = indices.get(changedIndex) as { 56 | index: MiniSearch; 57 | config: Options; 58 | }; 59 | 60 | await bucket.put(changedIndex, await saveIndex(index, config)); 61 | await cachePut(changedIndex, await saveIndex(index, config)); 62 | } 63 | 64 | batch.ackAll(); 65 | }, 66 | }; 67 | -------------------------------------------------------------------------------- /worker/index-consumer/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@tm9657/tsconfig/worker.json", 3 | "include": ["."], 4 | "exclude": ["dist", "build", "node_modules"] 5 | } 6 | -------------------------------------------------------------------------------- /worker/index-consumer/wrangler.toml: -------------------------------------------------------------------------------- 1 | name = "search-index-consumer" 2 | main = "src/index.ts" 3 | compatibility_date = "2023-05-02" 4 | # node_compat = true 5 | send_metrics = true 6 | logpush = true 7 | 8 | [[queues.consumers]] 9 | queue = "search-indexing-queue" 10 | max_concurrency = 1 11 | max_batch_size = 100 12 | max_batch_timeout = 30 13 | 14 | [[r2_buckets]] 15 | binding = 'SEARCH_BUCKET' # <~ valid JavaScript variable name 16 | bucket_name = 'serverless-search' 17 | 18 | -------------------------------------------------------------------------------- /worker/index/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "search-index", 3 | "version": "0.0.0", 4 | "devDependencies": { 5 | "@cloudflare/workers-types": "^4.20230419.0", 6 | "@tm9657/tsconfig": "^1.2.0", 7 | "wrangler": "2.18.0" 8 | }, 9 | "private": true, 10 | "scripts": { 11 | "start": "wrangler dev", 12 | "build": "wrangler publish --minify", 13 | "deploy": "wrangler publish" 14 | }, 15 | "dependencies": { 16 | "util": "workspace:*" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /worker/index/src/index.ts: -------------------------------------------------------------------------------- 1 | import { CorsResponse } from "util/cors"; 2 | import { SearchQueueMessage } from "util/types"; 3 | import config from "../../../config.json"; 4 | export interface Env { 5 | // Example binding to KV. Learn more at https://developers.cloudflare.com/workers/runtime-apis/kv/ 6 | // MY_KV_NAMESPACE: KVNamespace; 7 | // 8 | // Example binding to Durable Object. Learn more at https://developers.cloudflare.com/workers/runtime-apis/durable-objects/ 9 | // MY_DURABLE_OBJECT: DurableObjectNamespace; 10 | // 11 | // Example binding to R2. Learn more at https://developers.cloudflare.com/workers/runtime-apis/r2/ 12 | // MY_BUCKET: R2Bucket; 13 | // 14 | // Example binding to a Service. Learn more at https://developers.cloudflare.com/workers/runtime-apis/service-bindings/ 15 | // MY_SERVICE: Fetcher; 16 | 17 | SEARCH_INDEXING_QUEUE: Queue; 18 | } 19 | 20 | type IndexingBody = { 21 | key: string; 22 | content: SearchQueueMessage; 23 | }; 24 | 25 | export default { 26 | async fetch( 27 | request: Request, 28 | env: Env, 29 | ctx: ExecutionContext 30 | ): Promise { 31 | const body: IndexingBody = await request.json(); 32 | // could be replaced with crypto constant time compare (not necessary for our key security) 33 | if (body.key !== config.secret) 34 | return new CorsResponse("Invalid key", 401).finalize(request); 35 | await env.SEARCH_INDEXING_QUEUE.send(body.content); 36 | return new CorsResponse("").finalize(request); 37 | }, 38 | }; 39 | -------------------------------------------------------------------------------- /worker/index/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@tm9657/tsconfig/worker.json", 3 | "include": ["."], 4 | "exclude": ["dist", "build", "node_modules"] 5 | } 6 | -------------------------------------------------------------------------------- /worker/index/wrangler.toml: -------------------------------------------------------------------------------- 1 | name = "search-index" 2 | main = "src/index.ts" 3 | compatibility_date = "2023-05-02" 4 | # node_compat = true 5 | send_metrics = true 6 | logpush = true 7 | 8 | [[queues.producers]] 9 | queue = "search-indexing-queue" 10 | binding = "SEARCH_INDEXING_QUEUE" -------------------------------------------------------------------------------- /worker/search/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "search-search", 3 | "version": "0.0.0", 4 | "devDependencies": { 5 | "@cloudflare/workers-types": "^4.20230419.0", 6 | "@tm9657/tsconfig": "^1.2.0", 7 | "wrangler": "2.18.0" 8 | }, 9 | "private": true, 10 | "scripts": { 11 | "start": "wrangler dev", 12 | "build": "wrangler publish --minify", 13 | "deploy": "wrangler publish" 14 | }, 15 | "dependencies": { 16 | "util": "workspace:*" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /worker/search/src/index.ts: -------------------------------------------------------------------------------- 1 | import { CorsResponse } from "util/cors"; 2 | import { MiniSearch } from "util/types"; 3 | import config from "../../../config.json"; 4 | import { loadIndex } from "util"; 5 | import { cachePut, cacheGet } from "util/cache"; 6 | export interface Env { 7 | // Example binding to KV. Learn more at https://developers.cloudflare.com/workers/runtime-apis/kv/ 8 | // MY_KV_NAMESPACE: KVNamespace; 9 | // 10 | // Example binding to Durable Object. Learn more at https://developers.cloudflare.com/workers/runtime-apis/durable-objects/ 11 | // MY_DURABLE_OBJECT: DurableObjectNamespace; 12 | // 13 | // Example binding to R2. Learn more at https://developers.cloudflare.com/workers/runtime-apis/r2/ 14 | SEARCH_BUCKET: R2Bucket; 15 | // 16 | // Example binding to a Service. Learn more at https://developers.cloudflare.com/workers/runtime-apis/service-bindings/ 17 | // MY_SERVICE: Fetcher; 18 | } 19 | 20 | let indices = new Map>(); 21 | 22 | type SearchBody = { 23 | index: string; 24 | term: string; 25 | }; 26 | 27 | export default { 28 | async fetch( 29 | request: Request, 30 | env: Env, 31 | ctx: ExecutionContext 32 | ): Promise { 33 | const { index, term }: SearchBody = await request.json(); 34 | console.log("index: " + index + " term: ", term); 35 | if (!index || !term) 36 | return new CorsResponse("Invalid request", 400).finalize(request); 37 | if (term.length < config.minSearch) 38 | return new CorsResponse("Term too short", 400).finalize(request); 39 | if (!indices.has(index)) { 40 | let serialized = await cacheGet(index); 41 | if (!serialized) { 42 | console.log("cache miss"); 43 | serialized = await (await env.SEARCH_BUCKET.get(index))?.text(); 44 | if (serialized) await cachePut(index, serialized); 45 | } else { 46 | console.log("cache hit"); 47 | } 48 | if (!serialized) 49 | return new CorsResponse("Index not found", 404).finalize(request); 50 | const deserialized = await loadIndex(serialized); 51 | indices.set(index, deserialized); 52 | } 53 | const result = indices.get(index); 54 | if (!result) 55 | return new CorsResponse("Index not found, internal error", 404).finalize( 56 | request 57 | ); 58 | const search = result.search(term); 59 | return new CorsResponse(JSON.stringify(search)).finalize(request); 60 | }, 61 | }; 62 | -------------------------------------------------------------------------------- /worker/search/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@tm9657/tsconfig/worker.json", 3 | "include": ["."], 4 | "exclude": ["dist", "build", "node_modules"] 5 | } 6 | -------------------------------------------------------------------------------- /worker/search/wrangler.toml: -------------------------------------------------------------------------------- 1 | name = "search-search" 2 | main = "src/index.ts" 3 | compatibility_date = "2023-05-02" 4 | # node_compat = true 5 | send_metrics = true 6 | logpush = true 7 | 8 | [[r2_buckets]] 9 | binding = 'SEARCH_BUCKET' # <~ valid JavaScript variable name 10 | bucket_name = 'serverless-search' --------------------------------------------------------------------------------