├── .dev.vars.example ├── .gitattributes ├── .gitignore ├── LICENSE ├── README.md ├── package-lock.json ├── package.json ├── public ├── favicon.ico ├── index.html ├── login.html ├── script.js └── styles.css ├── src └── index.ts ├── tsconfig.json ├── worker-configuration.d.ts └── wrangler.toml /.dev.vars.example: -------------------------------------------------------------------------------- 1 | OPENAI_API_KEY="sk-proj-go-get-your-own" 2 | JWT_SECRET="do-not-tell-anybody-what-your-secret-is-its-yours-and-can-be-used-to-sign-jwts" -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | .pnpm-debug.log* 9 | 10 | # Diagnostic reports (https://nodejs.org/api/report.html) 11 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 12 | 13 | # Runtime data 14 | pids 15 | *.pid 16 | *.seed 17 | *.pid.lock 18 | 19 | # Directory for instrumented libs generated by jscoverage/JSCover 20 | lib-cov 21 | 22 | # Coverage directory used by tools like istanbul 23 | coverage 24 | *.lcov 25 | 26 | # nyc test coverage 27 | .nyc_output 28 | 29 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 30 | .grunt 31 | 32 | # Bower dependency directory (https://bower.io/) 33 | bower_components 34 | 35 | # node-waf configuration 36 | .lock-wscript 37 | 38 | # Compiled binary addons (https://nodejs.org/api/addons.html) 39 | build/Release 40 | 41 | # Dependency directories 42 | node_modules/ 43 | jspm_packages/ 44 | 45 | # Snowpack dependency directory (https://snowpack.dev/) 46 | web_modules/ 47 | 48 | # TypeScript cache 49 | *.tsbuildinfo 50 | 51 | # Optional npm cache directory 52 | .npm 53 | 54 | # Optional eslint cache 55 | .eslintcache 56 | 57 | # Optional stylelint cache 58 | .stylelintcache 59 | 60 | # Microbundle cache 61 | .rpt2_cache/ 62 | .rts2_cache_cjs/ 63 | .rts2_cache_es/ 64 | .rts2_cache_umd/ 65 | 66 | # Optional REPL history 67 | .node_repl_history 68 | 69 | # Output of 'npm pack' 70 | *.tgz 71 | 72 | # Yarn Integrity file 73 | .yarn-integrity 74 | 75 | # dotenv environment variable files 76 | .env 77 | .env.development.local 78 | .env.test.local 79 | .env.production.local 80 | .env.local 81 | 82 | # parcel-bundler cache (https://parceljs.org/) 83 | .cache 84 | .parcel-cache 85 | 86 | # Next.js build output 87 | .next 88 | out 89 | 90 | # Nuxt.js build / generate output 91 | .nuxt 92 | dist 93 | 94 | # Gatsby files 95 | .cache/ 96 | # Comment in the public line in if your project uses Gatsby and not Next.js 97 | # https://nextjs.org/blog/next-9-1#public-directory-support 98 | # public 99 | 100 | # vuepress build output 101 | .vuepress/dist 102 | 103 | # vuepress v2.x temp and cache directory 104 | .temp 105 | .cache 106 | 107 | # Docusaurus cache and generated files 108 | .docusaurus 109 | 110 | # Serverless directories 111 | .serverless/ 112 | 113 | # FuseBox cache 114 | .fusebox/ 115 | 116 | # DynamoDB Local files 117 | .dynamodb/ 118 | 119 | # TernJS port file 120 | .tern-port 121 | 122 | # Stores VSCode versions used for testing VSCode extensions 123 | .vscode-test 124 | 125 | # yarn v2 126 | .yarn/cache 127 | .yarn/unplugged 128 | .yarn/build-state.yml 129 | .yarn/install-state.gz 130 | .pnp.* 131 | 132 | 133 | .wrangler 134 | .dev.vars 135 | .DS_Store 136 | 137 | # Copied from node modules 138 | public/wavtools.min.js 139 | public/wavtools.js -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License Copyright (c) 2024 Cloudflare, Inc. 2 | 3 | Permission is hereby granted, free of 4 | charge, to any person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the Software without 6 | restriction, including without limitation the rights to use, copy, modify, merge, 7 | publish, distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to the 9 | following conditions: 10 | 11 | The above copyright notice and this permission notice 12 | (including the next paragraph) shall be included in all copies or substantial 13 | portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 16 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO 18 | EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 19 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Say It Again 2 | 3 | [](https://youtu.be/D5mIer4qmdE "Authenticate your OpenAI Realtime API 4 | ") 5 | 6 | 7 | This is an authenticated example based on the [Cloudflare OpenAI Realtime Relay on Workers starter template](https://github.com/cloudflare/openai-workers-relay). 8 | 9 | This makes use of the [OpenAI Realtime API](https://platform.openai.com/docs/api-reference/realtime) to "parrot" back what you said but in character. 10 | 11 | This uses [WavTools](https://www.npmjs.com/package/wavtools) for most of the clientside browser heavy lifting which was introduced in the [OpenAI Realtime Console](https://github.com/openai/openai-realtime-console) but split out for reuse. 12 | 13 | ## Installation 14 | 15 | ```bash 16 | npm install 17 | ``` 18 | 19 | ## Development 20 | 21 | Copy [.dev.vars.example](./.dev.vars.example) to `.dev.vars` and add your keys and secrets. 22 | 23 | ```bash 24 | npm run dev 25 | ``` 26 | 27 | ## Deploy to Region Earth 28 | 29 | Set up your secrets 30 | 31 | ```bash 32 | npx wrangler secret put OPENAI_API_KEY 33 | ``` 34 | 35 | ```bash 36 | npx wrangler secret put JWT_SECRET 37 | ``` 38 | 39 | ```bash 40 | npm run deploy 41 | ``` -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "openai-workers-relay", 3 | "version": "0.0.1", 4 | "lockfileVersion": 3, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "openai-workers-relay", 9 | "version": "0.0.1", 10 | "license": "MIT", 11 | "dependencies": { 12 | "@openai/realtime-api-beta": "github:openai/openai-realtime-api-beta", 13 | "hono": "^4.6.10", 14 | "wavtools": "^0.1.5" 15 | }, 16 | "devDependencies": { 17 | "@cloudflare/workers-types": "^4.20241112.0", 18 | "typescript": "^5.6.3", 19 | "wrangler": "^3.90.0" 20 | } 21 | }, 22 | "node_modules/@cloudflare/kv-asset-handler": { 23 | "version": "0.3.4", 24 | "resolved": "https://registry.npmjs.org/@cloudflare/kv-asset-handler/-/kv-asset-handler-0.3.4.tgz", 25 | "integrity": "sha512-YLPHc8yASwjNkmcDMQMY35yiWjoKAKnhUbPRszBRS0YgH+IXtsMp61j+yTcnCE3oO2DgP0U3iejLC8FTtKDC8Q==", 26 | "dev": true, 27 | "license": "MIT OR Apache-2.0", 28 | "dependencies": { 29 | "mime": "^3.0.0" 30 | }, 31 | "engines": { 32 | "node": ">=16.13" 33 | } 34 | }, 35 | "node_modules/@cloudflare/workerd-darwin-64": { 36 | "version": "1.20241106.1", 37 | "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-64/-/workerd-darwin-64-1.20241106.1.tgz", 38 | "integrity": "sha512-zxvaToi1m0qzAScrxFt7UvFVqU8DxrCO2CinM1yQkv5no7pA1HolpIrwZ0xOhR3ny64Is2s/J6BrRjpO5dM9Zw==", 39 | "cpu": [ 40 | "x64" 41 | ], 42 | "dev": true, 43 | "optional": true, 44 | "os": [ 45 | "darwin" 46 | ], 47 | "engines": { 48 | "node": ">=16" 49 | } 50 | }, 51 | "node_modules/@cloudflare/workerd-darwin-arm64": { 52 | "version": "1.20241106.1", 53 | "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-arm64/-/workerd-darwin-arm64-1.20241106.1.tgz", 54 | "integrity": "sha512-j3dg/42D/bPgfNP3cRUBxF+4waCKO/5YKwXNj+lnVOwHxDu+ne5pFw9TIkKYcWTcwn0ZUkbNZNM5rhJqRn4xbg==", 55 | "cpu": [ 56 | "arm64" 57 | ], 58 | "dev": true, 59 | "optional": true, 60 | "os": [ 61 | "darwin" 62 | ], 63 | "engines": { 64 | "node": ">=16" 65 | } 66 | }, 67 | "node_modules/@cloudflare/workerd-linux-64": { 68 | "version": "1.20241106.1", 69 | "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-64/-/workerd-linux-64-1.20241106.1.tgz", 70 | "integrity": "sha512-Ih+Ye8E1DMBXcKrJktGfGztFqHKaX1CeByqshmTbODnWKHt6O65ax3oTecUwyC0+abuyraOpAtdhHNpFMhUkmw==", 71 | "cpu": [ 72 | "x64" 73 | ], 74 | "dev": true, 75 | "optional": true, 76 | "os": [ 77 | "linux" 78 | ], 79 | "engines": { 80 | "node": ">=16" 81 | } 82 | }, 83 | "node_modules/@cloudflare/workerd-linux-arm64": { 84 | "version": "1.20241106.1", 85 | "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-arm64/-/workerd-linux-arm64-1.20241106.1.tgz", 86 | "integrity": "sha512-mdQFPk4+14Yywn7n1xIzI+6olWM8Ybz10R7H3h+rk0XulMumCWUCy1CzIDauOx6GyIcSgKIibYMssVHZR30ObA==", 87 | "cpu": [ 88 | "arm64" 89 | ], 90 | "dev": true, 91 | "optional": true, 92 | "os": [ 93 | "linux" 94 | ], 95 | "engines": { 96 | "node": ">=16" 97 | } 98 | }, 99 | "node_modules/@cloudflare/workerd-windows-64": { 100 | "version": "1.20241106.1", 101 | "resolved": "https://registry.npmjs.org/@cloudflare/workerd-windows-64/-/workerd-windows-64-1.20241106.1.tgz", 102 | "integrity": "sha512-4rtcss31E/Rb/PeFocZfr+B9i1MdrkhsTBWizh8siNR4KMmkslU2xs2wPaH1z8+ErxkOsHrKRa5EPLh5rIiFeg==", 103 | "cpu": [ 104 | "x64" 105 | ], 106 | "dev": true, 107 | "optional": true, 108 | "os": [ 109 | "win32" 110 | ], 111 | "engines": { 112 | "node": ">=16" 113 | } 114 | }, 115 | "node_modules/@cloudflare/workers-shared": { 116 | "version": "0.8.0", 117 | "resolved": "https://registry.npmjs.org/@cloudflare/workers-shared/-/workers-shared-0.8.0.tgz", 118 | "integrity": "sha512-1OvFkNtslaMZAJsaocTmbACApgmWv55uLpNj50Pn2MGcxdAjpqykXJFQw5tKc+lGV9TDZh9oO3Rsk17IEQDzIg==", 119 | "dev": true, 120 | "dependencies": { 121 | "mime": "^3.0.0", 122 | "zod": "^3.22.3" 123 | }, 124 | "engines": { 125 | "node": ">=16.7.0" 126 | } 127 | }, 128 | "node_modules/@cloudflare/workers-types": { 129 | "version": "4.20241112.0", 130 | "resolved": "https://registry.npmjs.org/@cloudflare/workers-types/-/workers-types-4.20241112.0.tgz", 131 | "integrity": "sha512-Q4p9bAWZrX14bSCKY9to19xl0KMU7nsO5sJ2cTVspHoypsjPUMeQCsjHjmsO2C4Myo8/LPeDvmqFmkyNAPPYZw==", 132 | "dev": true, 133 | "license": "MIT OR Apache-2.0" 134 | }, 135 | "node_modules/@cspotcode/source-map-support": { 136 | "version": "0.8.1", 137 | "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", 138 | "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", 139 | "dev": true, 140 | "dependencies": { 141 | "@jridgewell/trace-mapping": "0.3.9" 142 | }, 143 | "engines": { 144 | "node": ">=12" 145 | } 146 | }, 147 | "node_modules/@esbuild-plugins/node-globals-polyfill": { 148 | "version": "0.2.3", 149 | "resolved": "https://registry.npmjs.org/@esbuild-plugins/node-globals-polyfill/-/node-globals-polyfill-0.2.3.tgz", 150 | "integrity": "sha512-r3MIryXDeXDOZh7ih1l/yE9ZLORCd5e8vWg02azWRGj5SPTuoh69A2AIyn0Z31V/kHBfZ4HgWJ+OK3GTTwLmnw==", 151 | "dev": true, 152 | "license": "ISC", 153 | "peerDependencies": { 154 | "esbuild": "*" 155 | } 156 | }, 157 | "node_modules/@esbuild-plugins/node-modules-polyfill": { 158 | "version": "0.2.2", 159 | "resolved": "https://registry.npmjs.org/@esbuild-plugins/node-modules-polyfill/-/node-modules-polyfill-0.2.2.tgz", 160 | "integrity": "sha512-LXV7QsWJxRuMYvKbiznh+U1ilIop3g2TeKRzUxOG5X3YITc8JyyTa90BmLwqqv0YnX4v32CSlG+vsziZp9dMvA==", 161 | "dev": true, 162 | "license": "ISC", 163 | "dependencies": { 164 | "escape-string-regexp": "^4.0.0", 165 | "rollup-plugin-node-polyfills": "^0.2.1" 166 | }, 167 | "peerDependencies": { 168 | "esbuild": "*" 169 | } 170 | }, 171 | "node_modules/@esbuild/android-arm": { 172 | "version": "0.17.19", 173 | "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.19.tgz", 174 | "integrity": "sha512-rIKddzqhmav7MSmoFCmDIb6e2W57geRsM94gV2l38fzhXMwq7hZoClug9USI2pFRGL06f4IOPHHpFNOkWieR8A==", 175 | "cpu": [ 176 | "arm" 177 | ], 178 | "dev": true, 179 | "license": "MIT", 180 | "optional": true, 181 | "os": [ 182 | "android" 183 | ], 184 | "engines": { 185 | "node": ">=12" 186 | } 187 | }, 188 | "node_modules/@esbuild/android-arm64": { 189 | "version": "0.17.19", 190 | "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.19.tgz", 191 | "integrity": "sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA==", 192 | "cpu": [ 193 | "arm64" 194 | ], 195 | "dev": true, 196 | "license": "MIT", 197 | "optional": true, 198 | "os": [ 199 | "android" 200 | ], 201 | "engines": { 202 | "node": ">=12" 203 | } 204 | }, 205 | "node_modules/@esbuild/android-x64": { 206 | "version": "0.17.19", 207 | "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.19.tgz", 208 | "integrity": "sha512-uUTTc4xGNDT7YSArp/zbtmbhO0uEEK9/ETW29Wk1thYUJBz3IVnvgEiEwEa9IeLyvnpKrWK64Utw2bgUmDveww==", 209 | "cpu": [ 210 | "x64" 211 | ], 212 | "dev": true, 213 | "license": "MIT", 214 | "optional": true, 215 | "os": [ 216 | "android" 217 | ], 218 | "engines": { 219 | "node": ">=12" 220 | } 221 | }, 222 | "node_modules/@esbuild/darwin-arm64": { 223 | "version": "0.17.19", 224 | "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.19.tgz", 225 | "integrity": "sha512-80wEoCfF/hFKM6WE1FyBHc9SfUblloAWx6FJkFWTWiCoht9Mc0ARGEM47e67W9rI09YoUxJL68WHfDRYEAvOhg==", 226 | "cpu": [ 227 | "arm64" 228 | ], 229 | "dev": true, 230 | "license": "MIT", 231 | "optional": true, 232 | "os": [ 233 | "darwin" 234 | ], 235 | "engines": { 236 | "node": ">=12" 237 | } 238 | }, 239 | "node_modules/@esbuild/darwin-x64": { 240 | "version": "0.17.19", 241 | "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.19.tgz", 242 | "integrity": "sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw==", 243 | "cpu": [ 244 | "x64" 245 | ], 246 | "dev": true, 247 | "license": "MIT", 248 | "optional": true, 249 | "os": [ 250 | "darwin" 251 | ], 252 | "engines": { 253 | "node": ">=12" 254 | } 255 | }, 256 | "node_modules/@esbuild/freebsd-arm64": { 257 | "version": "0.17.19", 258 | "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.19.tgz", 259 | "integrity": "sha512-pBwbc7DufluUeGdjSU5Si+P3SoMF5DQ/F/UmTSb8HXO80ZEAJmrykPyzo1IfNbAoaqw48YRpv8shwd1NoI0jcQ==", 260 | "cpu": [ 261 | "arm64" 262 | ], 263 | "dev": true, 264 | "license": "MIT", 265 | "optional": true, 266 | "os": [ 267 | "freebsd" 268 | ], 269 | "engines": { 270 | "node": ">=12" 271 | } 272 | }, 273 | "node_modules/@esbuild/freebsd-x64": { 274 | "version": "0.17.19", 275 | "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.19.tgz", 276 | "integrity": "sha512-4lu+n8Wk0XlajEhbEffdy2xy53dpR06SlzvhGByyg36qJw6Kpfk7cp45DR/62aPH9mtJRmIyrXAS5UWBrJT6TQ==", 277 | "cpu": [ 278 | "x64" 279 | ], 280 | "dev": true, 281 | "license": "MIT", 282 | "optional": true, 283 | "os": [ 284 | "freebsd" 285 | ], 286 | "engines": { 287 | "node": ">=12" 288 | } 289 | }, 290 | "node_modules/@esbuild/linux-arm": { 291 | "version": "0.17.19", 292 | "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.19.tgz", 293 | "integrity": "sha512-cdmT3KxjlOQ/gZ2cjfrQOtmhG4HJs6hhvm3mWSRDPtZ/lP5oe8FWceS10JaSJC13GBd4eH/haHnqf7hhGNLerA==", 294 | "cpu": [ 295 | "arm" 296 | ], 297 | "dev": true, 298 | "license": "MIT", 299 | "optional": true, 300 | "os": [ 301 | "linux" 302 | ], 303 | "engines": { 304 | "node": ">=12" 305 | } 306 | }, 307 | "node_modules/@esbuild/linux-arm64": { 308 | "version": "0.17.19", 309 | "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.19.tgz", 310 | "integrity": "sha512-ct1Tg3WGwd3P+oZYqic+YZF4snNl2bsnMKRkb3ozHmnM0dGWuxcPTTntAF6bOP0Sp4x0PjSF+4uHQ1xvxfRKqg==", 311 | "cpu": [ 312 | "arm64" 313 | ], 314 | "dev": true, 315 | "license": "MIT", 316 | "optional": true, 317 | "os": [ 318 | "linux" 319 | ], 320 | "engines": { 321 | "node": ">=12" 322 | } 323 | }, 324 | "node_modules/@esbuild/linux-ia32": { 325 | "version": "0.17.19", 326 | "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.19.tgz", 327 | "integrity": "sha512-w4IRhSy1VbsNxHRQpeGCHEmibqdTUx61Vc38APcsRbuVgK0OPEnQ0YD39Brymn96mOx48Y2laBQGqgZ0j9w6SQ==", 328 | "cpu": [ 329 | "ia32" 330 | ], 331 | "dev": true, 332 | "license": "MIT", 333 | "optional": true, 334 | "os": [ 335 | "linux" 336 | ], 337 | "engines": { 338 | "node": ">=12" 339 | } 340 | }, 341 | "node_modules/@esbuild/linux-loong64": { 342 | "version": "0.17.19", 343 | "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.19.tgz", 344 | "integrity": "sha512-2iAngUbBPMq439a+z//gE+9WBldoMp1s5GWsUSgqHLzLJ9WoZLZhpwWuym0u0u/4XmZ3gpHmzV84PonE+9IIdQ==", 345 | "cpu": [ 346 | "loong64" 347 | ], 348 | "dev": true, 349 | "license": "MIT", 350 | "optional": true, 351 | "os": [ 352 | "linux" 353 | ], 354 | "engines": { 355 | "node": ">=12" 356 | } 357 | }, 358 | "node_modules/@esbuild/linux-mips64el": { 359 | "version": "0.17.19", 360 | "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.19.tgz", 361 | "integrity": "sha512-LKJltc4LVdMKHsrFe4MGNPp0hqDFA1Wpt3jE1gEyM3nKUvOiO//9PheZZHfYRfYl6AwdTH4aTcXSqBerX0ml4A==", 362 | "cpu": [ 363 | "mips64el" 364 | ], 365 | "dev": true, 366 | "license": "MIT", 367 | "optional": true, 368 | "os": [ 369 | "linux" 370 | ], 371 | "engines": { 372 | "node": ">=12" 373 | } 374 | }, 375 | "node_modules/@esbuild/linux-ppc64": { 376 | "version": "0.17.19", 377 | "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.19.tgz", 378 | "integrity": "sha512-/c/DGybs95WXNS8y3Ti/ytqETiW7EU44MEKuCAcpPto3YjQbyK3IQVKfF6nbghD7EcLUGl0NbiL5Rt5DMhn5tg==", 379 | "cpu": [ 380 | "ppc64" 381 | ], 382 | "dev": true, 383 | "license": "MIT", 384 | "optional": true, 385 | "os": [ 386 | "linux" 387 | ], 388 | "engines": { 389 | "node": ">=12" 390 | } 391 | }, 392 | "node_modules/@esbuild/linux-riscv64": { 393 | "version": "0.17.19", 394 | "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.19.tgz", 395 | "integrity": "sha512-FC3nUAWhvFoutlhAkgHf8f5HwFWUL6bYdvLc/TTuxKlvLi3+pPzdZiFKSWz/PF30TB1K19SuCxDTI5KcqASJqA==", 396 | "cpu": [ 397 | "riscv64" 398 | ], 399 | "dev": true, 400 | "license": "MIT", 401 | "optional": true, 402 | "os": [ 403 | "linux" 404 | ], 405 | "engines": { 406 | "node": ">=12" 407 | } 408 | }, 409 | "node_modules/@esbuild/linux-s390x": { 410 | "version": "0.17.19", 411 | "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.19.tgz", 412 | "integrity": "sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q==", 413 | "cpu": [ 414 | "s390x" 415 | ], 416 | "dev": true, 417 | "license": "MIT", 418 | "optional": true, 419 | "os": [ 420 | "linux" 421 | ], 422 | "engines": { 423 | "node": ">=12" 424 | } 425 | }, 426 | "node_modules/@esbuild/linux-x64": { 427 | "version": "0.17.19", 428 | "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.19.tgz", 429 | "integrity": "sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw==", 430 | "cpu": [ 431 | "x64" 432 | ], 433 | "dev": true, 434 | "license": "MIT", 435 | "optional": true, 436 | "os": [ 437 | "linux" 438 | ], 439 | "engines": { 440 | "node": ">=12" 441 | } 442 | }, 443 | "node_modules/@esbuild/netbsd-x64": { 444 | "version": "0.17.19", 445 | "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.19.tgz", 446 | "integrity": "sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q==", 447 | "cpu": [ 448 | "x64" 449 | ], 450 | "dev": true, 451 | "license": "MIT", 452 | "optional": true, 453 | "os": [ 454 | "netbsd" 455 | ], 456 | "engines": { 457 | "node": ">=12" 458 | } 459 | }, 460 | "node_modules/@esbuild/openbsd-x64": { 461 | "version": "0.17.19", 462 | "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.19.tgz", 463 | "integrity": "sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g==", 464 | "cpu": [ 465 | "x64" 466 | ], 467 | "dev": true, 468 | "license": "MIT", 469 | "optional": true, 470 | "os": [ 471 | "openbsd" 472 | ], 473 | "engines": { 474 | "node": ">=12" 475 | } 476 | }, 477 | "node_modules/@esbuild/sunos-x64": { 478 | "version": "0.17.19", 479 | "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.19.tgz", 480 | "integrity": "sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg==", 481 | "cpu": [ 482 | "x64" 483 | ], 484 | "dev": true, 485 | "license": "MIT", 486 | "optional": true, 487 | "os": [ 488 | "sunos" 489 | ], 490 | "engines": { 491 | "node": ">=12" 492 | } 493 | }, 494 | "node_modules/@esbuild/win32-arm64": { 495 | "version": "0.17.19", 496 | "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.19.tgz", 497 | "integrity": "sha512-yYx+8jwowUstVdorcMdNlzklLYhPxjniHWFKgRqH7IFlUEa0Umu3KuYplf1HUZZ422e3NU9F4LGb+4O0Kdcaag==", 498 | "cpu": [ 499 | "arm64" 500 | ], 501 | "dev": true, 502 | "license": "MIT", 503 | "optional": true, 504 | "os": [ 505 | "win32" 506 | ], 507 | "engines": { 508 | "node": ">=12" 509 | } 510 | }, 511 | "node_modules/@esbuild/win32-ia32": { 512 | "version": "0.17.19", 513 | "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.19.tgz", 514 | "integrity": "sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw==", 515 | "cpu": [ 516 | "ia32" 517 | ], 518 | "dev": true, 519 | "license": "MIT", 520 | "optional": true, 521 | "os": [ 522 | "win32" 523 | ], 524 | "engines": { 525 | "node": ">=12" 526 | } 527 | }, 528 | "node_modules/@esbuild/win32-x64": { 529 | "version": "0.17.19", 530 | "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.19.tgz", 531 | "integrity": "sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA==", 532 | "cpu": [ 533 | "x64" 534 | ], 535 | "dev": true, 536 | "license": "MIT", 537 | "optional": true, 538 | "os": [ 539 | "win32" 540 | ], 541 | "engines": { 542 | "node": ">=12" 543 | } 544 | }, 545 | "node_modules/@fastify/busboy": { 546 | "version": "2.1.1", 547 | "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.1.tgz", 548 | "integrity": "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==", 549 | "dev": true, 550 | "engines": { 551 | "node": ">=14" 552 | } 553 | }, 554 | "node_modules/@jridgewell/resolve-uri": { 555 | "version": "3.1.2", 556 | "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", 557 | "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", 558 | "dev": true, 559 | "engines": { 560 | "node": ">=6.0.0" 561 | } 562 | }, 563 | "node_modules/@jridgewell/sourcemap-codec": { 564 | "version": "1.5.0", 565 | "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", 566 | "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", 567 | "dev": true 568 | }, 569 | "node_modules/@jridgewell/trace-mapping": { 570 | "version": "0.3.9", 571 | "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", 572 | "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", 573 | "dev": true, 574 | "dependencies": { 575 | "@jridgewell/resolve-uri": "^3.0.3", 576 | "@jridgewell/sourcemap-codec": "^1.4.10" 577 | } 578 | }, 579 | "node_modules/@openai/realtime-api-beta": { 580 | "version": "0.0.0", 581 | "resolved": "git+ssh://git@github.com/openai/openai-realtime-api-beta.git#de01e1083834c4c3bc495d190e2f6f5b5785e264", 582 | "license": "MIT", 583 | "dependencies": { 584 | "ws": "^8.18.0" 585 | } 586 | }, 587 | "node_modules/@types/node": { 588 | "version": "22.8.7", 589 | "resolved": "https://registry.npmjs.org/@types/node/-/node-22.8.7.tgz", 590 | "integrity": "sha512-LidcG+2UeYIWcMuMUpBKOnryBWG/rnmOHQR5apjn8myTQcx3rinFRn7DcIFhMnS0PPFSC6OafdIKEad0lj6U0Q==", 591 | "dev": true, 592 | "license": "MIT", 593 | "dependencies": { 594 | "undici-types": "~6.19.8" 595 | } 596 | }, 597 | "node_modules/@types/node-forge": { 598 | "version": "1.3.11", 599 | "resolved": "https://registry.npmjs.org/@types/node-forge/-/node-forge-1.3.11.tgz", 600 | "integrity": "sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ==", 601 | "dev": true, 602 | "license": "MIT", 603 | "dependencies": { 604 | "@types/node": "*" 605 | } 606 | }, 607 | "node_modules/acorn": { 608 | "version": "8.14.0", 609 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", 610 | "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", 611 | "dev": true, 612 | "bin": { 613 | "acorn": "bin/acorn" 614 | }, 615 | "engines": { 616 | "node": ">=0.4.0" 617 | } 618 | }, 619 | "node_modules/acorn-walk": { 620 | "version": "8.3.4", 621 | "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", 622 | "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", 623 | "dev": true, 624 | "dependencies": { 625 | "acorn": "^8.11.0" 626 | }, 627 | "engines": { 628 | "node": ">=0.4.0" 629 | } 630 | }, 631 | "node_modules/as-table": { 632 | "version": "1.0.55", 633 | "resolved": "https://registry.npmjs.org/as-table/-/as-table-1.0.55.tgz", 634 | "integrity": "sha512-xvsWESUJn0JN421Xb9MQw6AsMHRCUknCe0Wjlxvjud80mU4E6hQf1A6NzQKcYNmYw62MfzEtXc+badstZP3JpQ==", 635 | "dev": true, 636 | "dependencies": { 637 | "printable-characters": "^1.0.42" 638 | } 639 | }, 640 | "node_modules/blake3-wasm": { 641 | "version": "2.1.5", 642 | "resolved": "https://registry.npmjs.org/blake3-wasm/-/blake3-wasm-2.1.5.tgz", 643 | "integrity": "sha512-F1+K8EbfOZE49dtoPtmxUQrpXaBIl3ICvasLh+nJta0xkz+9kF/7uet9fLnwKqhDrmj6g+6K3Tw9yQPUg2ka5g==", 644 | "dev": true, 645 | "license": "MIT" 646 | }, 647 | "node_modules/capnp-ts": { 648 | "version": "0.7.0", 649 | "resolved": "https://registry.npmjs.org/capnp-ts/-/capnp-ts-0.7.0.tgz", 650 | "integrity": "sha512-XKxXAC3HVPv7r674zP0VC3RTXz+/JKhfyw94ljvF80yynK6VkTnqE3jMuN8b3dUVmmc43TjyxjW4KTsmB3c86g==", 651 | "dev": true, 652 | "dependencies": { 653 | "debug": "^4.3.1", 654 | "tslib": "^2.2.0" 655 | } 656 | }, 657 | "node_modules/chokidar": { 658 | "version": "4.0.1", 659 | "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.1.tgz", 660 | "integrity": "sha512-n8enUVCED/KVRQlab1hr3MVpcVMvxtZjmEa956u+4YijlmQED223XMSYj2tLuKvr4jcCTzNNMpQDUer72MMmzA==", 661 | "dev": true, 662 | "dependencies": { 663 | "readdirp": "^4.0.1" 664 | }, 665 | "engines": { 666 | "node": ">= 14.16.0" 667 | }, 668 | "funding": { 669 | "url": "https://paulmillr.com/funding/" 670 | } 671 | }, 672 | "node_modules/cookie": { 673 | "version": "0.7.2", 674 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", 675 | "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", 676 | "dev": true, 677 | "engines": { 678 | "node": ">= 0.6" 679 | } 680 | }, 681 | "node_modules/data-uri-to-buffer": { 682 | "version": "2.0.2", 683 | "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-2.0.2.tgz", 684 | "integrity": "sha512-ND9qDTLc6diwj+Xe5cdAgVTbLVdXbtxTJRXRhli8Mowuaan+0EJOtdqJ0QCHNSSPyoXGx9HX2/VMnKeC34AChA==", 685 | "dev": true 686 | }, 687 | "node_modules/date-fns": { 688 | "version": "4.1.0", 689 | "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-4.1.0.tgz", 690 | "integrity": "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==", 691 | "dev": true, 692 | "license": "MIT", 693 | "funding": { 694 | "type": "github", 695 | "url": "https://github.com/sponsors/kossnocorp" 696 | } 697 | }, 698 | "node_modules/debug": { 699 | "version": "4.3.7", 700 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", 701 | "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", 702 | "dev": true, 703 | "dependencies": { 704 | "ms": "^2.1.3" 705 | }, 706 | "engines": { 707 | "node": ">=6.0" 708 | }, 709 | "peerDependenciesMeta": { 710 | "supports-color": { 711 | "optional": true 712 | } 713 | } 714 | }, 715 | "node_modules/defu": { 716 | "version": "6.1.4", 717 | "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.4.tgz", 718 | "integrity": "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==", 719 | "dev": true 720 | }, 721 | "node_modules/esbuild": { 722 | "version": "0.17.19", 723 | "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.19.tgz", 724 | "integrity": "sha512-XQ0jAPFkK/u3LcVRcvVHQcTIqD6E2H1fvZMA5dQPSOWb3suUbWbfbRf94pjc0bNzRYLfIrDRQXr7X+LHIm5oHw==", 725 | "dev": true, 726 | "hasInstallScript": true, 727 | "license": "MIT", 728 | "bin": { 729 | "esbuild": "bin/esbuild" 730 | }, 731 | "engines": { 732 | "node": ">=12" 733 | }, 734 | "optionalDependencies": { 735 | "@esbuild/android-arm": "0.17.19", 736 | "@esbuild/android-arm64": "0.17.19", 737 | "@esbuild/android-x64": "0.17.19", 738 | "@esbuild/darwin-arm64": "0.17.19", 739 | "@esbuild/darwin-x64": "0.17.19", 740 | "@esbuild/freebsd-arm64": "0.17.19", 741 | "@esbuild/freebsd-x64": "0.17.19", 742 | "@esbuild/linux-arm": "0.17.19", 743 | "@esbuild/linux-arm64": "0.17.19", 744 | "@esbuild/linux-ia32": "0.17.19", 745 | "@esbuild/linux-loong64": "0.17.19", 746 | "@esbuild/linux-mips64el": "0.17.19", 747 | "@esbuild/linux-ppc64": "0.17.19", 748 | "@esbuild/linux-riscv64": "0.17.19", 749 | "@esbuild/linux-s390x": "0.17.19", 750 | "@esbuild/linux-x64": "0.17.19", 751 | "@esbuild/netbsd-x64": "0.17.19", 752 | "@esbuild/openbsd-x64": "0.17.19", 753 | "@esbuild/sunos-x64": "0.17.19", 754 | "@esbuild/win32-arm64": "0.17.19", 755 | "@esbuild/win32-ia32": "0.17.19", 756 | "@esbuild/win32-x64": "0.17.19" 757 | } 758 | }, 759 | "node_modules/escape-string-regexp": { 760 | "version": "4.0.0", 761 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", 762 | "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", 763 | "dev": true, 764 | "license": "MIT", 765 | "engines": { 766 | "node": ">=10" 767 | }, 768 | "funding": { 769 | "url": "https://github.com/sponsors/sindresorhus" 770 | } 771 | }, 772 | "node_modules/estree-walker": { 773 | "version": "0.6.1", 774 | "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz", 775 | "integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==", 776 | "dev": true, 777 | "license": "MIT" 778 | }, 779 | "node_modules/exit-hook": { 780 | "version": "2.2.1", 781 | "resolved": "https://registry.npmjs.org/exit-hook/-/exit-hook-2.2.1.tgz", 782 | "integrity": "sha512-eNTPlAD67BmP31LDINZ3U7HSF8l57TxOY2PmBJ1shpCvpnxBF93mWCE8YHBnXs8qiUZJc9WDcWIeC3a2HIAMfw==", 783 | "dev": true, 784 | "engines": { 785 | "node": ">=6" 786 | }, 787 | "funding": { 788 | "url": "https://github.com/sponsors/sindresorhus" 789 | } 790 | }, 791 | "node_modules/fsevents": { 792 | "version": "2.3.3", 793 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", 794 | "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", 795 | "dev": true, 796 | "hasInstallScript": true, 797 | "optional": true, 798 | "os": [ 799 | "darwin" 800 | ], 801 | "engines": { 802 | "node": "^8.16.0 || ^10.6.0 || >=11.0.0" 803 | } 804 | }, 805 | "node_modules/function-bind": { 806 | "version": "1.1.2", 807 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", 808 | "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", 809 | "dev": true, 810 | "license": "MIT", 811 | "funding": { 812 | "url": "https://github.com/sponsors/ljharb" 813 | } 814 | }, 815 | "node_modules/get-source": { 816 | "version": "2.0.12", 817 | "resolved": "https://registry.npmjs.org/get-source/-/get-source-2.0.12.tgz", 818 | "integrity": "sha512-X5+4+iD+HoSeEED+uwrQ07BOQr0kEDFMVqqpBuI+RaZBpBpHCuXxo70bjar6f0b0u/DQJsJ7ssurpP0V60Az+w==", 819 | "dev": true, 820 | "dependencies": { 821 | "data-uri-to-buffer": "^2.0.0", 822 | "source-map": "^0.6.1" 823 | } 824 | }, 825 | "node_modules/glob-to-regexp": { 826 | "version": "0.4.1", 827 | "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", 828 | "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", 829 | "dev": true 830 | }, 831 | "node_modules/hasown": { 832 | "version": "2.0.2", 833 | "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", 834 | "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", 835 | "dev": true, 836 | "license": "MIT", 837 | "dependencies": { 838 | "function-bind": "^1.1.2" 839 | }, 840 | "engines": { 841 | "node": ">= 0.4" 842 | } 843 | }, 844 | "node_modules/hono": { 845 | "version": "4.6.10", 846 | "resolved": "https://registry.npmjs.org/hono/-/hono-4.6.10.tgz", 847 | "integrity": "sha512-IXXNfRAZEahFnWBhUUlqKEGF9upeE6hZoRZszvNkyAz/CYp+iVbxm3viMvStlagRJohjlBRGOQ7f4jfcV0XMGg==", 848 | "engines": { 849 | "node": ">=16.9.0" 850 | } 851 | }, 852 | "node_modules/is-core-module": { 853 | "version": "2.15.1", 854 | "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.1.tgz", 855 | "integrity": "sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==", 856 | "dev": true, 857 | "license": "MIT", 858 | "dependencies": { 859 | "hasown": "^2.0.2" 860 | }, 861 | "engines": { 862 | "node": ">= 0.4" 863 | }, 864 | "funding": { 865 | "url": "https://github.com/sponsors/ljharb" 866 | } 867 | }, 868 | "node_modules/itty-time": { 869 | "version": "1.0.6", 870 | "resolved": "https://registry.npmjs.org/itty-time/-/itty-time-1.0.6.tgz", 871 | "integrity": "sha512-+P8IZaLLBtFv8hCkIjcymZOp4UJ+xW6bSlQsXGqrkmJh7vSiMFSlNne0mCYagEE0N7HDNR5jJBRxwN0oYv61Rw==", 872 | "dev": true, 873 | "license": "MIT" 874 | }, 875 | "node_modules/magic-string": { 876 | "version": "0.25.9", 877 | "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", 878 | "integrity": "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==", 879 | "dev": true, 880 | "license": "MIT", 881 | "dependencies": { 882 | "sourcemap-codec": "^1.4.8" 883 | } 884 | }, 885 | "node_modules/mime": { 886 | "version": "3.0.0", 887 | "resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz", 888 | "integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==", 889 | "dev": true, 890 | "license": "MIT", 891 | "bin": { 892 | "mime": "cli.js" 893 | }, 894 | "engines": { 895 | "node": ">=10.0.0" 896 | } 897 | }, 898 | "node_modules/miniflare": { 899 | "version": "3.20241106.1", 900 | "resolved": "https://registry.npmjs.org/miniflare/-/miniflare-3.20241106.1.tgz", 901 | "integrity": "sha512-dM3RBlJE8rUFxnqlPCaFCq0E7qQqEQvKbYX7W/APGCK+rLcyLmEBzC4GQR/niXdNM/oV6gdg9AA50ghnn2ALuw==", 902 | "dev": true, 903 | "dependencies": { 904 | "@cspotcode/source-map-support": "0.8.1", 905 | "acorn": "^8.8.0", 906 | "acorn-walk": "^8.2.0", 907 | "capnp-ts": "^0.7.0", 908 | "exit-hook": "^2.2.1", 909 | "glob-to-regexp": "^0.4.1", 910 | "stoppable": "^1.1.0", 911 | "undici": "^5.28.4", 912 | "workerd": "1.20241106.1", 913 | "ws": "^8.18.0", 914 | "youch": "^3.2.2", 915 | "zod": "^3.22.3" 916 | }, 917 | "bin": { 918 | "miniflare": "bootstrap.js" 919 | }, 920 | "engines": { 921 | "node": ">=16.13" 922 | } 923 | }, 924 | "node_modules/ms": { 925 | "version": "2.1.3", 926 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", 927 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", 928 | "dev": true 929 | }, 930 | "node_modules/mustache": { 931 | "version": "4.2.0", 932 | "resolved": "https://registry.npmjs.org/mustache/-/mustache-4.2.0.tgz", 933 | "integrity": "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==", 934 | "dev": true, 935 | "bin": { 936 | "mustache": "bin/mustache" 937 | } 938 | }, 939 | "node_modules/nanoid": { 940 | "version": "3.3.7", 941 | "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", 942 | "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", 943 | "dev": true, 944 | "funding": [ 945 | { 946 | "type": "github", 947 | "url": "https://github.com/sponsors/ai" 948 | } 949 | ], 950 | "license": "MIT", 951 | "bin": { 952 | "nanoid": "bin/nanoid.cjs" 953 | }, 954 | "engines": { 955 | "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" 956 | } 957 | }, 958 | "node_modules/node-forge": { 959 | "version": "1.3.1", 960 | "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", 961 | "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", 962 | "dev": true, 963 | "license": "(BSD-3-Clause OR GPL-2.0)", 964 | "engines": { 965 | "node": ">= 6.13.0" 966 | } 967 | }, 968 | "node_modules/ohash": { 969 | "version": "1.1.4", 970 | "resolved": "https://registry.npmjs.org/ohash/-/ohash-1.1.4.tgz", 971 | "integrity": "sha512-FlDryZAahJmEF3VR3w1KogSEdWX3WhA5GPakFx4J81kEAiHyLMpdLLElS8n8dfNadMgAne/MywcvmogzscVt4g==", 972 | "dev": true 973 | }, 974 | "node_modules/path-parse": { 975 | "version": "1.0.7", 976 | "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", 977 | "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", 978 | "dev": true, 979 | "license": "MIT" 980 | }, 981 | "node_modules/path-to-regexp": { 982 | "version": "6.3.0", 983 | "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.3.0.tgz", 984 | "integrity": "sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==", 985 | "dev": true, 986 | "license": "MIT" 987 | }, 988 | "node_modules/pathe": { 989 | "version": "1.1.2", 990 | "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz", 991 | "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==", 992 | "dev": true 993 | }, 994 | "node_modules/printable-characters": { 995 | "version": "1.0.42", 996 | "resolved": "https://registry.npmjs.org/printable-characters/-/printable-characters-1.0.42.tgz", 997 | "integrity": "sha512-dKp+C4iXWK4vVYZmYSd0KBH5F/h1HoZRsbJ82AVKRO3PEo8L4lBS/vLwhVtpwwuYcoIsVY+1JYKR268yn480uQ==", 998 | "dev": true 999 | }, 1000 | "node_modules/readdirp": { 1001 | "version": "4.0.2", 1002 | "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.0.2.tgz", 1003 | "integrity": "sha512-yDMz9g+VaZkqBYS/ozoBJwaBhTbZo3UNYQHNRw1D3UFQB8oHB4uS/tAODO+ZLjGWmUbKnIlOWO+aaIiAxrUWHA==", 1004 | "dev": true, 1005 | "engines": { 1006 | "node": ">= 14.16.0" 1007 | }, 1008 | "funding": { 1009 | "type": "individual", 1010 | "url": "https://paulmillr.com/funding/" 1011 | } 1012 | }, 1013 | "node_modules/resolve": { 1014 | "version": "1.22.8", 1015 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", 1016 | "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", 1017 | "dev": true, 1018 | "license": "MIT", 1019 | "dependencies": { 1020 | "is-core-module": "^2.13.0", 1021 | "path-parse": "^1.0.7", 1022 | "supports-preserve-symlinks-flag": "^1.0.0" 1023 | }, 1024 | "bin": { 1025 | "resolve": "bin/resolve" 1026 | }, 1027 | "funding": { 1028 | "url": "https://github.com/sponsors/ljharb" 1029 | } 1030 | }, 1031 | "node_modules/resolve.exports": { 1032 | "version": "2.0.2", 1033 | "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.2.tgz", 1034 | "integrity": "sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==", 1035 | "dev": true, 1036 | "license": "MIT", 1037 | "engines": { 1038 | "node": ">=10" 1039 | } 1040 | }, 1041 | "node_modules/rollup-plugin-inject": { 1042 | "version": "3.0.2", 1043 | "resolved": "https://registry.npmjs.org/rollup-plugin-inject/-/rollup-plugin-inject-3.0.2.tgz", 1044 | "integrity": "sha512-ptg9PQwzs3orn4jkgXJ74bfs5vYz1NCZlSQMBUA0wKcGp5i5pA1AO3fOUEte8enhGUC+iapTCzEWw2jEFFUO/w==", 1045 | "deprecated": "This package has been deprecated and is no longer maintained. Please use @rollup/plugin-inject.", 1046 | "dev": true, 1047 | "license": "MIT", 1048 | "dependencies": { 1049 | "estree-walker": "^0.6.1", 1050 | "magic-string": "^0.25.3", 1051 | "rollup-pluginutils": "^2.8.1" 1052 | } 1053 | }, 1054 | "node_modules/rollup-plugin-node-polyfills": { 1055 | "version": "0.2.1", 1056 | "resolved": "https://registry.npmjs.org/rollup-plugin-node-polyfills/-/rollup-plugin-node-polyfills-0.2.1.tgz", 1057 | "integrity": "sha512-4kCrKPTJ6sK4/gLL/U5QzVT8cxJcofO0OU74tnB19F40cmuAKSzH5/siithxlofFEjwvw1YAhPmbvGNA6jEroA==", 1058 | "dev": true, 1059 | "license": "MIT", 1060 | "dependencies": { 1061 | "rollup-plugin-inject": "^3.0.0" 1062 | } 1063 | }, 1064 | "node_modules/rollup-pluginutils": { 1065 | "version": "2.8.2", 1066 | "resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz", 1067 | "integrity": "sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==", 1068 | "dev": true, 1069 | "license": "MIT", 1070 | "dependencies": { 1071 | "estree-walker": "^0.6.1" 1072 | } 1073 | }, 1074 | "node_modules/selfsigned": { 1075 | "version": "2.4.1", 1076 | "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.4.1.tgz", 1077 | "integrity": "sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q==", 1078 | "dev": true, 1079 | "license": "MIT", 1080 | "dependencies": { 1081 | "@types/node-forge": "^1.3.0", 1082 | "node-forge": "^1" 1083 | }, 1084 | "engines": { 1085 | "node": ">=10" 1086 | } 1087 | }, 1088 | "node_modules/source-map": { 1089 | "version": "0.6.1", 1090 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", 1091 | "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", 1092 | "dev": true, 1093 | "engines": { 1094 | "node": ">=0.10.0" 1095 | } 1096 | }, 1097 | "node_modules/sourcemap-codec": { 1098 | "version": "1.4.8", 1099 | "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", 1100 | "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", 1101 | "deprecated": "Please use @jridgewell/sourcemap-codec instead", 1102 | "dev": true, 1103 | "license": "MIT" 1104 | }, 1105 | "node_modules/stacktracey": { 1106 | "version": "2.1.8", 1107 | "resolved": "https://registry.npmjs.org/stacktracey/-/stacktracey-2.1.8.tgz", 1108 | "integrity": "sha512-Kpij9riA+UNg7TnphqjH7/CzctQ/owJGNbFkfEeve4Z4uxT5+JapVLFXcsurIfN34gnTWZNJ/f7NMG0E8JDzTw==", 1109 | "dev": true, 1110 | "dependencies": { 1111 | "as-table": "^1.0.36", 1112 | "get-source": "^2.0.12" 1113 | } 1114 | }, 1115 | "node_modules/stoppable": { 1116 | "version": "1.1.0", 1117 | "resolved": "https://registry.npmjs.org/stoppable/-/stoppable-1.1.0.tgz", 1118 | "integrity": "sha512-KXDYZ9dszj6bzvnEMRYvxgeTHU74QBFL54XKtP3nyMuJ81CFYtABZ3bAzL2EdFUaEwJOBOgENyFj3R7oTzDyyw==", 1119 | "dev": true, 1120 | "engines": { 1121 | "node": ">=4", 1122 | "npm": ">=6" 1123 | } 1124 | }, 1125 | "node_modules/supports-preserve-symlinks-flag": { 1126 | "version": "1.0.0", 1127 | "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", 1128 | "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", 1129 | "dev": true, 1130 | "license": "MIT", 1131 | "engines": { 1132 | "node": ">= 0.4" 1133 | }, 1134 | "funding": { 1135 | "url": "https://github.com/sponsors/ljharb" 1136 | } 1137 | }, 1138 | "node_modules/tslib": { 1139 | "version": "2.8.1", 1140 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", 1141 | "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", 1142 | "dev": true 1143 | }, 1144 | "node_modules/typescript": { 1145 | "version": "5.6.3", 1146 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz", 1147 | "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==", 1148 | "dev": true, 1149 | "license": "Apache-2.0", 1150 | "bin": { 1151 | "tsc": "bin/tsc", 1152 | "tsserver": "bin/tsserver" 1153 | }, 1154 | "engines": { 1155 | "node": ">=14.17" 1156 | } 1157 | }, 1158 | "node_modules/ufo": { 1159 | "version": "1.5.4", 1160 | "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.5.4.tgz", 1161 | "integrity": "sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ==", 1162 | "dev": true 1163 | }, 1164 | "node_modules/undici": { 1165 | "version": "5.28.4", 1166 | "resolved": "https://registry.npmjs.org/undici/-/undici-5.28.4.tgz", 1167 | "integrity": "sha512-72RFADWFqKmUb2hmmvNODKL3p9hcB6Gt2DOQMis1SEBaV6a4MH8soBvzg+95CYhCKPFedut2JY9bMfrDl9D23g==", 1168 | "dev": true, 1169 | "dependencies": { 1170 | "@fastify/busboy": "^2.0.0" 1171 | }, 1172 | "engines": { 1173 | "node": ">=14.0" 1174 | } 1175 | }, 1176 | "node_modules/undici-types": { 1177 | "version": "6.19.8", 1178 | "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", 1179 | "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", 1180 | "dev": true, 1181 | "license": "MIT" 1182 | }, 1183 | "node_modules/unenv": { 1184 | "name": "unenv-nightly", 1185 | "version": "2.0.0-20241111-080453-894aa31", 1186 | "resolved": "https://registry.npmjs.org/unenv-nightly/-/unenv-nightly-2.0.0-20241111-080453-894aa31.tgz", 1187 | "integrity": "sha512-0W39QQOQ9VE8kVVUpGwEG+pZcsCXk5wqNG6rDPE6Gr+fiA69LR0qERM61hW5KCOkC1/ArCFrfCGjwHyyv/bI0Q==", 1188 | "dev": true, 1189 | "dependencies": { 1190 | "defu": "^6.1.4", 1191 | "ohash": "^1.1.4", 1192 | "pathe": "^1.1.2", 1193 | "ufo": "^1.5.4" 1194 | } 1195 | }, 1196 | "node_modules/wavtools": { 1197 | "version": "0.1.5", 1198 | "resolved": "https://registry.npmjs.org/wavtools/-/wavtools-0.1.5.tgz", 1199 | "integrity": "sha512-npKxMSOKMLItDk5jTZ2W/sfXOIVbv0/UId1C96Zhtm7UgmKBS4WjliK7qWpKniQvNIMH2URoRANDBMWHAyGAlg==" 1200 | }, 1201 | "node_modules/workerd": { 1202 | "version": "1.20241106.1", 1203 | "resolved": "https://registry.npmjs.org/workerd/-/workerd-1.20241106.1.tgz", 1204 | "integrity": "sha512-1GdKl0kDw8rrirr/ThcK66Kbl4/jd4h8uHx5g7YHBrnenY5SX1UPuop2cnCzYUxlg55kPjzIqqYslz1muRFgFw==", 1205 | "dev": true, 1206 | "hasInstallScript": true, 1207 | "bin": { 1208 | "workerd": "bin/workerd" 1209 | }, 1210 | "engines": { 1211 | "node": ">=16" 1212 | }, 1213 | "optionalDependencies": { 1214 | "@cloudflare/workerd-darwin-64": "1.20241106.1", 1215 | "@cloudflare/workerd-darwin-arm64": "1.20241106.1", 1216 | "@cloudflare/workerd-linux-64": "1.20241106.1", 1217 | "@cloudflare/workerd-linux-arm64": "1.20241106.1", 1218 | "@cloudflare/workerd-windows-64": "1.20241106.1" 1219 | } 1220 | }, 1221 | "node_modules/wrangler": { 1222 | "version": "3.90.0", 1223 | "resolved": "https://registry.npmjs.org/wrangler/-/wrangler-3.90.0.tgz", 1224 | "integrity": "sha512-E/6E9ORAl987+3kP8wDiE3L1lj9r4vQ32/dl5toIxIkSMssmPRQVdxqwgMxbxJrytbFNo8Eo6swgjd4y4nUaLg==", 1225 | "dev": true, 1226 | "dependencies": { 1227 | "@cloudflare/kv-asset-handler": "0.3.4", 1228 | "@cloudflare/workers-shared": "0.8.0", 1229 | "@esbuild-plugins/node-globals-polyfill": "^0.2.3", 1230 | "@esbuild-plugins/node-modules-polyfill": "^0.2.2", 1231 | "blake3-wasm": "^2.1.5", 1232 | "chokidar": "^4.0.1", 1233 | "date-fns": "^4.1.0", 1234 | "esbuild": "0.17.19", 1235 | "itty-time": "^1.0.6", 1236 | "miniflare": "3.20241106.1", 1237 | "nanoid": "^3.3.3", 1238 | "path-to-regexp": "^6.3.0", 1239 | "resolve": "^1.22.8", 1240 | "resolve.exports": "^2.0.2", 1241 | "selfsigned": "^2.0.1", 1242 | "source-map": "^0.6.1", 1243 | "unenv": "npm:unenv-nightly@2.0.0-20241111-080453-894aa31", 1244 | "workerd": "1.20241106.1", 1245 | "xxhash-wasm": "^1.0.1" 1246 | }, 1247 | "bin": { 1248 | "wrangler": "bin/wrangler.js", 1249 | "wrangler2": "bin/wrangler.js" 1250 | }, 1251 | "engines": { 1252 | "node": ">=16.17.0" 1253 | }, 1254 | "optionalDependencies": { 1255 | "fsevents": "~2.3.2" 1256 | }, 1257 | "peerDependencies": { 1258 | "@cloudflare/workers-types": "^4.20241106.0" 1259 | }, 1260 | "peerDependenciesMeta": { 1261 | "@cloudflare/workers-types": { 1262 | "optional": true 1263 | } 1264 | } 1265 | }, 1266 | "node_modules/ws": { 1267 | "version": "8.18.0", 1268 | "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", 1269 | "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", 1270 | "license": "MIT", 1271 | "engines": { 1272 | "node": ">=10.0.0" 1273 | }, 1274 | "peerDependencies": { 1275 | "bufferutil": "^4.0.1", 1276 | "utf-8-validate": ">=5.0.2" 1277 | }, 1278 | "peerDependenciesMeta": { 1279 | "bufferutil": { 1280 | "optional": true 1281 | }, 1282 | "utf-8-validate": { 1283 | "optional": true 1284 | } 1285 | } 1286 | }, 1287 | "node_modules/xxhash-wasm": { 1288 | "version": "1.0.2", 1289 | "resolved": "https://registry.npmjs.org/xxhash-wasm/-/xxhash-wasm-1.0.2.tgz", 1290 | "integrity": "sha512-ibF0Or+FivM9lNrg+HGJfVX8WJqgo+kCLDc4vx6xMeTce7Aj+DLttKbxxRR/gNLSAelRc1omAPlJ77N/Jem07A==", 1291 | "dev": true, 1292 | "license": "MIT" 1293 | }, 1294 | "node_modules/youch": { 1295 | "version": "3.3.4", 1296 | "resolved": "https://registry.npmjs.org/youch/-/youch-3.3.4.tgz", 1297 | "integrity": "sha512-UeVBXie8cA35DS6+nBkls68xaBBXCye0CNznrhszZjTbRVnJKQuNsyLKBTTL4ln1o1rh2PKtv35twV7irj5SEg==", 1298 | "dev": true, 1299 | "dependencies": { 1300 | "cookie": "^0.7.1", 1301 | "mustache": "^4.2.0", 1302 | "stacktracey": "^2.1.8" 1303 | } 1304 | }, 1305 | "node_modules/zod": { 1306 | "version": "3.23.8", 1307 | "resolved": "https://registry.npmjs.org/zod/-/zod-3.23.8.tgz", 1308 | "integrity": "sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==", 1309 | "dev": true, 1310 | "license": "MIT", 1311 | "funding": { 1312 | "url": "https://github.com/sponsors/colinhacks" 1313 | } 1314 | } 1315 | } 1316 | } 1317 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "openai-workers-relay", 3 | "version": "0.0.1", 4 | "private": true, 5 | "scripts": { 6 | "start": "npm run dev", 7 | "build": "cp ./node_modules/wavtools/script/wavtools.min.js ./public/", 8 | "dev": "npm run build && wrangler dev", 9 | "deploy": "npm run build && wrangler deploy" 10 | }, 11 | "keywords": [], 12 | "author": "", 13 | "license": "MIT", 14 | "description": "", 15 | "dependencies": { 16 | "@openai/realtime-api-beta": "github:openai/openai-realtime-api-beta", 17 | "hono": "^4.6.10", 18 | "wavtools": "^0.1.5" 19 | }, 20 | "devDependencies": { 21 | "@cloudflare/workers-types": "^4.20241112.0", 22 | "typescript": "^5.6.3", 23 | "wrangler": "^3.90.0" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/craigsdennis/say-it-again-openai-workers/f1a7aea63c4eed20b4737097acb0f450cc740452/public/favicon.ico -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Say it again - Cloudflare Workers Authenticated OpenAI Relay Demo 7 | 8 | 9 | 10 | 11 | 12 |
13 |
14 |

You must log in to continue

15 |
16 | 87 |
88 | 107 | 108 | 109 | 110 | -------------------------------------------------------------------------------- /public/login.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Login 7 | 8 | 9 | 10 |
11 |

Login

12 |
13 |
14 | 15 | 16 |
17 |
18 | 19 | 20 |
21 | 22 |
23 |
24 | 25 | 26 | -------------------------------------------------------------------------------- /public/script.js: -------------------------------------------------------------------------------- 1 | // The mono output from WavRecorder 2 | function monoArrayBufferToBase64(arrayBuffer) { 3 | let binary = ""; 4 | let bytes = new Uint8Array(arrayBuffer); 5 | const chunkSize = 0x8000; // 32KB chunk size 6 | for (let i = 0; i < bytes.length; i += chunkSize) { 7 | let chunk = bytes.subarray(i, i + chunkSize); 8 | binary += String.fromCharCode.apply(null, chunk); 9 | } 10 | return btoa(binary); 11 | } 12 | 13 | function base64ToInt16Array(base64) { 14 | const raw = atob(base64); 15 | const bytes = Uint8Array.from(raw, (m) => m.codePointAt(0)); 16 | return new Int16Array(bytes.buffer); 17 | } 18 | 19 | document.addEventListener("DOMContentLoaded", () => { 20 | const parrot = document.getElementById("parrot"); 21 | const notAuthenticated = document.getElementById("not-authenticated"); 22 | const authenticationRequired = document.getElementById( 23 | "authentication-required" 24 | ); 25 | const recordingStatus = document.getElementById("recording-status"); 26 | const characterChooser = document.getElementById("character-chooser"); 27 | const parrotTranscript = document.getElementById("parrot-transcript"); 28 | let isRecording = false; 29 | 30 | notAuthenticated.style.display = "none"; 31 | // Hackers might try to set this... 32 | if (!document.cookie.includes("jwtPayload")) { 33 | notAuthenticated.style.display = "block"; 34 | authenticationRequired.display = "none"; 35 | } else { 36 | try { 37 | const url = new URL(window.location.href); 38 | const protocol = url.protocol === "http:" ? "ws" : "wss"; 39 | // ...But hackers will not get past this as it is behind /auth and jwt middleware will catch it 40 | const webSocketURL = `${protocol}://${url.hostname}${ 41 | url.port ? ":" + url.port : "" 42 | }/auth/ws`; 43 | console.log("Attempting to connect", webSocketURL); 44 | const ws = new WebSocket(webSocketURL); 45 | // Intialize 46 | ws.onopen = () => { 47 | refreshParrotSetup(); 48 | }; 49 | authenticationRequired.style.display = "block"; 50 | // This is a global JS include 51 | const wavRecorder = new WavRecorder({ sampleRate: 24000 }); 52 | const wavStreamPlayer = new WavStreamPlayer({ sampleRate: 24000 }); 53 | ws.onmessage = (evt) => { 54 | const data = JSON.parse(evt.data); 55 | switch (data.type) { 56 | case "response.audio.delta": 57 | const bytes = base64ToInt16Array(data.delta); 58 | wavStreamPlayer.add16BitPCM(bytes, data.item_id); 59 | break; 60 | case "response.audio_transcript.delta": 61 | parrotTranscript.innerText += data.delta; 62 | break; 63 | default: 64 | console.log(data.type, data); 65 | break; 66 | } 67 | }; 68 | function refreshParrotSetup(evt) { 69 | const prompt = characterChooser.value; 70 | const sessionUpdateEvent = { 71 | type: "session.update", 72 | session: { 73 | voice: "verse", 74 | instructions: `Your task is repeat back what the user said but in your own tone. You are ${prompt}. Only restate what the user said and nothing else.`, 75 | }, 76 | }; 77 | ws.send(JSON.stringify(sessionUpdateEvent)); 78 | } 79 | characterChooser.addEventListener("change", (evt) => { 80 | parrotTranscript.style.display = "none"; 81 | }); 82 | parrot.addEventListener("click", async () => { 83 | await wavStreamPlayer.connect(); 84 | isRecording = !isRecording; 85 | if (isRecording) { 86 | parrotTranscript.innerText = ""; 87 | refreshParrotSetup(); 88 | recordingStatus.style.display = "block"; 89 | // https://platform.openai.com/docs/api-reference/realtime 90 | await wavRecorder.begin(); 91 | // This outputs chunks 92 | await wavRecorder.record((data) => { 93 | const base64AudioData = monoArrayBufferToBase64(data.mono); 94 | console.log("Appending", base64AudioData.length, "base64"); 95 | const appendEvent = { 96 | type: "input_audio_buffer.append", 97 | audio: base64AudioData, 98 | }; 99 | ws.send(JSON.stringify(appendEvent)); 100 | }); 101 | } else { 102 | parrotTranscript.style.display = "block"; 103 | recordingStatus.style.display = "none"; 104 | await wavRecorder.end(); 105 | const commitEvent = { 106 | type: "input_audio_buffer.commit", 107 | }; 108 | ws.send(JSON.stringify(commitEvent)); 109 | // Request a response 110 | ws.send(JSON.stringify({ type: "response.create" })); 111 | } 112 | }); 113 | } catch (err) { 114 | // Hide the parrot 115 | authenticationRequired.style.display = "none"; 116 | console.error(err); 117 | } 118 | } 119 | }); 120 | -------------------------------------------------------------------------------- /public/styles.css: -------------------------------------------------------------------------------- 1 | /* Shared CSS for the Login and Main Page */ 2 | 3 | body { 4 | font-family: Arial, sans-serif; 5 | background-color: #f0f0f0; 6 | display: flex; 7 | justify-content: center; 8 | align-items: center; 9 | height: 100vh; 10 | margin: 0; 11 | } 12 | 13 | .login-container { 14 | background-color: #ffffff; 15 | padding: 2rem; 16 | border-radius: 8px; 17 | box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); 18 | width: 300px; 19 | } 20 | 21 | h1 { 22 | font-size: 1.5rem; 23 | text-align: center; 24 | margin-bottom: 1.5rem; 25 | } 26 | 27 | .input-group { 28 | margin-bottom: 1rem; 29 | } 30 | 31 | label { 32 | display: block; 33 | margin-bottom: 0.5rem; 34 | font-weight: bold; 35 | } 36 | 37 | input[type="text"], 38 | input[type="password"] { 39 | width: 100%; 40 | padding: 0.5rem; 41 | border: 1px solid #ccc; 42 | border-radius: 4px; 43 | } 44 | 45 | button[type="submit"] { 46 | width: 100%; 47 | padding: 0.75rem; 48 | background-color: #007bff; 49 | color: #ffffff; 50 | border: none; 51 | border-radius: 4px; 52 | cursor: pointer; 53 | font-size: 1rem; 54 | } 55 | 56 | button[type="submit"]:hover { 57 | background-color: #0056b3; 58 | } 59 | 60 | /* Styles for the Main Page */ 61 | .parrot-container { 62 | display: flex; 63 | flex-direction: column; 64 | align-items: center; 65 | } 66 | 67 | #not-authenticated, #authentication-required { 68 | display: flex; 69 | flex-direction: column; 70 | justify-content: center; 71 | text-align: center; 72 | align-items: center; 73 | } 74 | 75 | .parrot-emoji { 76 | font-size: 10rem; 77 | cursor: pointer; 78 | transition: transform 0.3s ease; 79 | } 80 | 81 | .parrot-emoji:hover { 82 | transform: scale(1.1); 83 | } 84 | 85 | .recording { 86 | color: red; 87 | font-size: 1.25rem; 88 | margin-top: 1rem; 89 | } 90 | 91 | /* Styles for the Parrot Transcript */ 92 | #parrot-transcript { 93 | background-color: rgba(0, 0, 0, 0.8); 94 | color: #ffffff; 95 | padding: 1rem; 96 | border-radius: 8px; 97 | margin-top: 1rem; 98 | max-width: 600px; 99 | line-height: 1.5; 100 | font-size: 1rem; 101 | text-align: left; 102 | box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); 103 | overflow-y: auto; 104 | max-height: 200px; 105 | } 106 | 107 | /* Footer Styles */ 108 | footer { 109 | position: fixed; 110 | bottom: 0; 111 | left: 0; 112 | width: 100%; 113 | background-color: #ffffff; 114 | text-align: center; 115 | padding: 1rem; 116 | box-shadow: 0 -2px 5px rgba(0, 0, 0, 0.1); 117 | font-size: 0.9rem; 118 | color: #333; 119 | } 120 | 121 | footer p { 122 | margin: 0.2rem; 123 | } -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2024 Cloudflare, Inc. 2 | // Licensed under the MIT license found in the LICENSE file or at https://opensource.org/licenses/MIT 3 | 4 | import { Hono } from "hono"; 5 | import { jwt, JwtVariables, sign } from "hono/jwt"; 6 | import { RealtimeClient } from "@openai/realtime-api-beta"; 7 | import { HTTPException } from "hono/http-exception"; 8 | import { setCookie } from "hono/cookie"; 9 | 10 | type Variables = JwtVariables; 11 | 12 | const app = new Hono<{ Bindings: Env; Variables: Variables }>(); 13 | 14 | const DEBUG = false; // set as true to see debug logs 15 | const MODEL = "gpt-4o-realtime-preview-2024-10-01"; 16 | const OPENAI_URL = "wss://api.openai.com/v1/realtime"; 17 | 18 | function owrLog(...args: unknown[]) { 19 | if (DEBUG) { 20 | console.log("[owr]", ...args); 21 | } 22 | } 23 | 24 | function owrError(...args: unknown[]) { 25 | console.error("[owr error]", ...args); 26 | } 27 | 28 | async function createRealtimeClient( 29 | request: Request, 30 | env: Env, 31 | ctx: ExecutionContext 32 | ) { 33 | const webSocketPair = new WebSocketPair(); 34 | const [clientSocket, serverSocket] = Object.values(webSocketPair); 35 | 36 | serverSocket.accept(); 37 | 38 | // Copy protocol headers 39 | const responseHeaders = new Headers(); 40 | const protocolHeader = request.headers.get("Sec-WebSocket-Protocol"); 41 | let apiKey = env.OPENAI_API_KEY; 42 | if (protocolHeader) { 43 | const requestedProtocols = protocolHeader.split(",").map((p) => p.trim()); 44 | if (requestedProtocols.includes("realtime")) { 45 | // Not exactly sure why this protocol needs to be accepted 46 | responseHeaders.set("Sec-WebSocket-Protocol", "realtime"); 47 | } 48 | } 49 | 50 | if (!apiKey) { 51 | owrError( 52 | "Missing OpenAI API key. Did you forget to set OPENAI_API_KEY in .dev.vars (for local dev) or with wrangler secret put OPENAI_API_KEY (for production)?" 53 | ); 54 | return new Response("Missing API key", { status: 401 }); 55 | } 56 | 57 | let realtimeClient: RealtimeClient | null = null; 58 | 59 | // Create RealtimeClient 60 | try { 61 | owrLog("Creating OpenAIRealtimeClient"); 62 | realtimeClient = new RealtimeClient({ 63 | apiKey, 64 | debug: DEBUG, 65 | url: OPENAI_URL, 66 | }); 67 | } catch (e) { 68 | owrError("Error creating OpenAI RealtimeClient", e); 69 | serverSocket.close(); 70 | return new Response("Error creating OpenAI RealtimeClient", { 71 | status: 500, 72 | }); 73 | } 74 | 75 | // Relay: OpenAI Realtime API Event -> Client 76 | realtimeClient.realtime.on("server.*", (event: { type: string }) => { 77 | serverSocket.send(JSON.stringify(event)); 78 | }); 79 | 80 | realtimeClient.realtime.on("close", (metadata: { error: boolean }) => { 81 | owrLog( 82 | `Closing server-side because I received a close event: (error: ${metadata.error})` 83 | ); 84 | serverSocket.close(); 85 | }); 86 | 87 | // Relay: Client -> OpenAI Realtime API Event 88 | const messageQueue: string[] = []; 89 | 90 | serverSocket.addEventListener("message", (event: MessageEvent) => { 91 | const messageHandler = (data: string) => { 92 | try { 93 | const parsedEvent = JSON.parse(data); 94 | realtimeClient.realtime.send(parsedEvent.type, parsedEvent); 95 | } catch (e) { 96 | owrError("Error parsing event from client", data); 97 | } 98 | }; 99 | 100 | const data = 101 | typeof event.data === "string" ? event.data : event.data.toString(); 102 | if (!realtimeClient.isConnected()) { 103 | messageQueue.push(data); 104 | } else { 105 | messageHandler(data); 106 | } 107 | }); 108 | 109 | serverSocket.addEventListener("close", ({ code, reason }) => { 110 | owrLog( 111 | `Closing server-side because the client closed the connection: ${code} ${reason}` 112 | ); 113 | realtimeClient.disconnect(); 114 | messageQueue.length = 0; 115 | }); 116 | 117 | let model: string | undefined = MODEL; 118 | 119 | // uncomment this to use a model from specified by the client 120 | 121 | // const modelParam = new URL(request.url).searchParams.get("model"); 122 | // if (modelParam) { 123 | // model = modelParam; 124 | // } 125 | 126 | // Connect to OpenAI Realtime API 127 | try { 128 | owrLog(`Connecting to OpenAI...`); 129 | // @ts-expect-error Waiting on https://github.com/openai/openai-realtime-api-beta/pull/52 130 | await realtimeClient.connect({ model }); 131 | owrLog(`Connected to OpenAI successfully!`); 132 | while (messageQueue.length) { 133 | const message = messageQueue.shift(); 134 | if (message) { 135 | serverSocket.send(message); 136 | } 137 | } 138 | } catch (e) { 139 | owrError("Error connecting to OpenAI", e); 140 | return new Response("Error connecting to OpenAI", { status: 500 }); 141 | } 142 | 143 | return new Response(null, { 144 | status: 101, 145 | headers: responseHeaders, 146 | webSocket: clientSocket, 147 | }); 148 | } 149 | 150 | app.use("/auth/*", (c, next) => { 151 | const jwtMiddleware = jwt({ 152 | secret: c.env.JWT_SECRET, 153 | cookie: "jwtPayload", 154 | }); 155 | return jwtMiddleware(c, next); 156 | }); 157 | 158 | app.onError(async (err, c) => { 159 | console.error(err); 160 | if (err instanceof HTTPException) { 161 | const res = err.getResponse(); 162 | if (res.status === 401) { 163 | return c.redirect(`/login`); 164 | } 165 | } 166 | return new Response(err.message); 167 | }); 168 | 169 | app.post("/authenticate", async (c) => { 170 | const body = await c.req.parseBody(); 171 | // TODO: Use D1 to store users and passwords 172 | if (body.username === "cloud" && body.password === "flare") { 173 | const expires = Math.floor(Date.now() / 1000) + 60 * 60 * 24 * 30; // 30 days 174 | const expiresDate = new Date(); 175 | expiresDate.setTime(expiresDate.getTime() + expires); 176 | const payload = { 177 | sub: body.username, 178 | role: "user", 179 | exp: expires, 180 | }; 181 | const jwt = await sign(payload, c.env.JWT_SECRET); 182 | setCookie(c, "jwtPayload", jwt, { expires: expiresDate }); 183 | return c.redirect("/"); 184 | } 185 | const message = "Invalid login, try again"; 186 | // TODO: Show the message if it exists 187 | return c.redirect(`/login?message=${encodeURIComponent(message)}`); 188 | }); 189 | 190 | app.get("/auth/check", async (c) => { 191 | console.log("This will be blocked unless user is authenticated"); 192 | const jwt = c.get("jwtPayload"); 193 | return c.json({ success: true, loggedInAs: jwt.sub }); 194 | }); 195 | 196 | app.get("/auth/ws", async (c) => { 197 | // This would be a good place to add logic for rate limiting, etc. 198 | const jwt = c.get("jwtPayload"); 199 | console.log("jwt", jwt); 200 | const upgradeHeader = c.req.header("Upgrade"); 201 | if (upgradeHeader === "websocket") { 202 | return createRealtimeClient(c.req.raw, c.env, c.executionCtx); 203 | } 204 | return new Response("Expected Upgrade: websocket", { status: 426 }); 205 | }); 206 | 207 | export default app; 208 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Visit https://aka.ms/tsconfig to read more about this file */ 4 | 5 | /* Projects */ 6 | // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ 7 | // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ 8 | // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ 9 | // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ 10 | // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ 11 | // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ 12 | 13 | /* Language and Environment */ 14 | "target": "ESNext" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */, 15 | // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ 16 | // "jsx": "preserve", /* Specify what JSX code is generated. */ 17 | // "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */ 18 | // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ 19 | // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ 20 | // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ 21 | // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ 22 | // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ 23 | // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ 24 | // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ 25 | // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ 26 | 27 | /* Modules */ 28 | "module": "ESNext" /* Specify what module code is generated. */, 29 | // "rootDir": "./", /* Specify the root folder within your source files. */ 30 | "moduleResolution": "Bundler" /* Specify how TypeScript looks up a file from a given module specifier. */, 31 | // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ 32 | // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ 33 | // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ 34 | // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ 35 | "types": [ 36 | "@cloudflare/workers-types" 37 | ] /* Specify type package names to be included without being referenced in a source file. */, 38 | // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ 39 | // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ 40 | // "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */ 41 | // "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */ 42 | // "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */ 43 | // "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */ 44 | // "noUncheckedSideEffectImports": true, /* Check side effect imports. */ 45 | // "resolveJsonModule": true, /* Enable importing .json files. */ 46 | // "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */ 47 | // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ 48 | 49 | /* JavaScript Support */ 50 | // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ 51 | // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ 52 | // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ 53 | 54 | /* Emit */ 55 | // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ 56 | // "declarationMap": true, /* Create sourcemaps for d.ts files. */ 57 | // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ 58 | // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ 59 | // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ 60 | "noEmit": true /* Disable emitting files from a compilation. */, 61 | // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ 62 | // "outDir": "./", /* Specify an output folder for all emitted files. */ 63 | // "removeComments": true, /* Disable emitting comments. */ 64 | // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ 65 | // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ 66 | // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ 67 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ 68 | // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ 69 | // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ 70 | // "newLine": "crlf", /* Set the newline character for emitting files. */ 71 | // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ 72 | // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ 73 | // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ 74 | // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ 75 | // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ 76 | 77 | /* Interop Constraints */ 78 | // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ 79 | // "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */ 80 | // "isolatedDeclarations": true, /* Require sufficient annotation on exports so other tools can trivially generate declaration files. */ 81 | // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ 82 | "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */, 83 | // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ 84 | "forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */, 85 | 86 | /* Type Checking */ 87 | "strict": true /* Enable all strict type-checking options. */, 88 | // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ 89 | // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ 90 | // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ 91 | // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ 92 | // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ 93 | // "strictBuiltinIteratorReturn": true, /* Built-in iterators are instantiated with a 'TReturn' type of 'undefined' instead of 'any'. */ 94 | // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ 95 | // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ 96 | // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ 97 | // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */ 98 | // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */ 99 | // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ 100 | // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ 101 | // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ 102 | // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ 103 | // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ 104 | // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ 105 | // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ 106 | // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ 107 | 108 | /* Completeness */ 109 | // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ 110 | "skipLibCheck": true /* Skip type checking all .d.ts files. */ 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /worker-configuration.d.ts: -------------------------------------------------------------------------------- 1 | // Generated by Wrangler by running `wrangler types` 2 | 3 | interface Env { 4 | OPENAI_API_KEY: string; 5 | JWT_SECRET: string; 6 | ASSETS: Fetcher; 7 | } 8 | -------------------------------------------------------------------------------- /wrangler.toml: -------------------------------------------------------------------------------- 1 | name = "say-it-again" 2 | main = "src/index.ts" 3 | compatibility_date = "2024-11-11" 4 | 5 | # This will deploy the project by default to openai-workers-relay..workers.dev. 6 | # You can modify this by changing the name of the project in wrangler.toml, 7 | # and/or setting the `routes` param in this file. Learn more at 8 | # https://developers.cloudflare.com/workers/configuration/routing/routes/#set-up-a-route-in-wranglertoml 9 | 10 | [assets] 11 | directory = "./public" 12 | binding = "ASSETS" --------------------------------------------------------------------------------