diff options
| author | Alex Pooley (@zuedev) <zuedev@gmail.com> | 2025-10-31 00:01:55 +0000 |
|---|---|---|
| committer | Alex Pooley (@zuedev) <zuedev@gmail.com> | 2025-10-31 00:01:55 +0000 |
| commit | 0f4cb710dacd43eac6874e1deb0084c234f76c94 (patch) | |
| tree | 411b124f6a2e3f201a06fe54546ac0fb70100560 /projects | |
| parent | cba7362d2a7a888aae0bd203f89745bc6ba559b0 (diff) | |
| download | zue.dev-0f4cb710dacd43eac6874e1deb0084c234f76c94.tar zue.dev-0f4cb710dacd43eac6874e1deb0084c234f76c94.tar.gz zue.dev-0f4cb710dacd43eac6874e1deb0084c234f76c94.tar.bz2 zue.dev-0f4cb710dacd43eac6874e1deb0084c234f76c94.tar.xz zue.dev-0f4cb710dacd43eac6874e1deb0084c234f76c94.zip | |
merge api with root
Diffstat (limited to 'projects')
| -rw-r--r-- | projects/api/.gitignore | 33 | ||||
| -rw-r--r-- | projects/api/README.md | 7 | ||||
| -rw-r--r-- | projects/api/source/main.js | 363 | ||||
| -rw-r--r-- | projects/api/wrangler.jsonc | 30 | ||||
| -rw-r--r-- | projects/www/package-lock.json (renamed from projects/api/package-lock.json) | 467 | ||||
| -rw-r--r-- | projects/www/package.json (renamed from projects/api/package.json) | 0 | ||||
| -rw-r--r-- | projects/www/server/index.js | 379 | ||||
| -rw-r--r-- | projects/www/wrangler.jsonc | 19 |
8 files changed, 613 insertions, 685 deletions
diff --git a/projects/api/.gitignore b/projects/api/.gitignore deleted file mode 100644 index e319e06..0000000 --- a/projects/api/.gitignore +++ /dev/null @@ -1,33 +0,0 @@ -# prod -dist/ - -# dev -.yarn/ -!.yarn/releases -.vscode/* -!.vscode/launch.json -!.vscode/*.code-snippets -.idea/workspace.xml -.idea/usage.statistics.xml -.idea/shelf - -# deps -node_modules/ -.wrangler - -# env -.env -.env.production -.dev.vars - -# logs -logs/ -*.log -npm-debug.log* -yarn-debug.log* -yarn-error.log* -pnpm-debug.log* -lerna-debug.log* - -# misc -.DS_Store diff --git a/projects/api/README.md b/projects/api/README.md deleted file mode 100644 index d6c2606..0000000 --- a/projects/api/README.md +++ /dev/null @@ -1,7 +0,0 @@ -# [api.zue.dev](https://api.zue.dev/) - -> [@zuedev](https://github.com/zuedev)'s public API to support personal projects - -## Development - -This project uses [Wrangler](https://github.com/cloudflare/workers-sdk) to test and deploy versions. Use `wrangler dev` to test and `wrangler deploy` to deploy new versions. diff --git a/projects/api/source/main.js b/projects/api/source/main.js deleted file mode 100644 index e1053f8..0000000 --- a/projects/api/source/main.js +++ /dev/null @@ -1,363 +0,0 @@ -import puppeteer from "@cloudflare/puppeteer"; - -export default { - /* - Fetch event handler, this function will be called whenever a request is made to the worker. - The function will parse the request and return a response based on the request path. - - @param {Request} request - the incoming request object - @param {Environment} environment - the environment object - @param {Context} context - the context object - - @returns {Response} a new Response object - */ - async fetch(request, environment, context) { - const { pathname } = new URL(request.url); - - // modify Response to handle CORS defaults - class Response extends globalThis.Response { - constructor(body, init) { - super(body, init); - this.headers.set("Access-Control-Allow-Origin", "*"); - this.headers.set("Access-Control-Allow-Methods", "*"); - this.headers.set("Access-Control-Allow-Headers", "*"); - } - } - - switch (pathname) { - case "/": - return (() => { - return new Response( - JSON.stringify({ - message: "Hello, World! :3", - random: `${Math.random()}`, - }), - { - headers: { - "Access-Control-Allow-Origin": "*", - "Content-Type": "application/json", - }, - } - ); - })(); - case "/status": - return (() => { - const url = new URL(request.url); - const service = url.searchParams.get("service"); - - const acceptedServices = [ - "dns", - "load-balancer", - "cdn", - "functions", - "mysql-cluster", - "mongodb-cluster", - "redis-cluster", - "elasticsearch-cluster", - "git-connector", - "job-runners", - "container-registry", - "kubernetes-cluster", - "bare-metal-servers", - "game-server-api", - "anti-ddos-protection", - "anti-cheat-api", - ]; - - if (acceptedServices.includes(service)) - return new Response( - JSON.stringify({ - status: "ok", - service, - }), - { - headers: { - "Access-Control-Allow-Origin": "*", - "Content-Type": "application/json", - }, - } - ); - - return new Response( - JSON.stringify({ - error: `service not found`, - }), - { - headers: { - "Access-Control-Allow-Origin": "*", - "Content-Type": "application/json", - }, - } - ); - })(); - case "/96/twitch/streaming": - return (async () => { - /* - Checks if a twitch channel is live by fetching the "live" preview image of the channel, - if the image is fetched successfully, then the channel is live, otherwise it's offline. - - @param {string} channel - the twitch channel name - @returns {boolean} true if the channel is live, false otherwise - */ - async function isTwitchChannelLive(channel) { - // construct preview image url with channel name - const livePreviewUrl = `https://static-cdn.jtvnw.net/previews-ttv/live_user_${channel}-320x180.jpg`; - - // fetch the preview image, don't follow redirects - const response = await fetch(livePreviewUrl, { - redirect: "manual", - }); - - // check if the image was fetched successfully - return response.ok; - } - - const url = new URL(request.url); - const channel = url.searchParams.get("channel"); - - if (!channel) - return new Response( - JSON.stringify({ - error: `channel not provided`, - }), - { - headers: { - "Access-Control-Allow-Origin": "*", - "Content-Type": "application/json", - }, - } - ); - - const whitelist = [ - "zuedev", - ...["vtsweets", "bunnibana", "yayjaybae", "justawoney", "tygiwygi"], - ]; - - if (!whitelist.includes(channel)) - return new Response( - JSON.stringify({ - error: `channel not whitelisted`, - }), - { - headers: { - "Access-Control-Allow-Origin": "*", - "Content-Type": "application/json", - }, - } - ); - - const channelLive = await isTwitchChannelLive(channel); - - if (channelLive) - return new Response( - JSON.stringify({ - status: "live", - channel, - }), - { - headers: { - "Access-Control-Allow-Origin": "*", - "Content-Type": "application/json", - }, - } - ); - - return new Response( - JSON.stringify({ - status: "offline", - }), - { - headers: { - "Access-Control-Allow-Origin": "*", - "Content-Type": "application/json", - }, - } - ); - })(); - case "/96/youtube/latest-video": - return (async () => { - const url = new URL(request.url); - const channelHandle = url.searchParams.get("channelHandle"); - - if (!channelHandle) - return new Response( - JSON.stringify({ - error: `channel not provided`, - }), - { - headers: { - "Access-Control-Allow-Origin": "*", - "Content-Type": "application/json", - }, - } - ); - - const channelHandleWhitelist = ["@vtsweets"]; - - if (!channelHandleWhitelist.includes(channelHandle)) - return new Response( - JSON.stringify({ - error: `channel not allowed`, - }), - { - headers: { - "Access-Control-Allow-Origin": "*", - "Content-Type": "application/json", - }, - } - ); - - let API_Key; - - try { - API_Key = await environment.GOOGLE_API_KEY_UNRESTRICTED.get(); - } catch (error) { - API_Key = environment.GOOGLE_API_KEY_UNRESTRICTED; - } - - if (!API_Key) - return new Response( - JSON.stringify({ - error: `API Key not found`, - }), - { - headers: { - "Access-Control-Allow-Origin": "*", - "Content-Type": "application/json", - }, - } - ); - - const youtubeChannelsListResponse = await fetch( - `https://www.googleapis.com/youtube/v3/channels?part=contentDetails&forHandle=${channelHandle}&key=${API_Key}` - ); - - const youtubeChannelsList = await youtubeChannelsListResponse.json(); - - if (youtubeChannelsList.items.length === 0) { - return new Response( - JSON.stringify({ - error: `channel not found`, - }), - { - headers: { - "Access-Control-Allow-Origin": "*", - "Content-Type": "application/json", - }, - } - ); - } - - const uploadsPlaylistId = - youtubeChannelsList.items[0].contentDetails.relatedPlaylists - .uploads; - - const youtubePlaylistItemsList = await fetch( - `https://www.googleapis.com/youtube/v3/playlistItems?part=snippet&playlistId=${uploadsPlaylistId}&maxResults=1&key=${API_Key}` - ); - - const youtubePlaylistItemsListData = - await youtubePlaylistItemsList.json(); - - if (youtubePlaylistItemsListData.items.length === 0) { - return new Response( - JSON.stringify({ - error: `no videos found in the channel`, - }), - { - headers: { - "Access-Control-Allow-Origin": "*", - "Content-Type": "application/json", - }, - } - ); - } - - return new Response( - youtubePlaylistItemsListData.items[0].snippet.resourceId.videoId - ); - })(); - case "/browser-rendering/screenshot": - return (async () => { - const { searchParams } = new URL(request.url); - const url = searchParams.get("url"); - const type = searchParams.get("type") || "webp"; - const fullPage = searchParams.get("fullPage") !== null; - const width = parseInt(searchParams.get("width"), 10) || 1920; - const height = parseInt(searchParams.get("height"), 10) || 1080; - const delay = parseInt(searchParams.get("delay"), 10) || 0; - - if (!url) - return router.respond({ - error: "URL parameter is required", - }); - - if (!/^https?:\/\//.test(url)) - return router.respond({ - error: "Invalid URL format", - }); - - const browser = await puppeteer.launch(environment.MYBROWSER); - const page = await browser.newPage(); - await page.setViewport({ width, height }); - await page.goto(url, { - waitUntil: "networkidle2", - }); - if (delay > 0) { - await new Promise((resolve) => setTimeout(resolve, delay)); - } - const screenshot = await page.screenshot({ - type, - fullPage, - }); - await browser.close(); - - return new Response(screenshot, { - headers: { - "content-type": `image/${type}`, - }, - }); - })(); - default: - return new Response( - JSON.stringify({ - error: `path not found`, - }), - { - headers: { - "Access-Control-Allow-Origin": "*", - "Content-Type": "application/json", - }, - } - ); - } - }, - - /* - Email event handler, this function will be called whenever an email is sent to the worker. - The function will parse the email message and forward it to a specified email address. - - @param {Message} message - the incoming email message object - @param {Environment} environment - the environment object - @param {Context} context - the context object - - @returns {void} - */ - async email(message, environment, context) { - message.forward("alex@zue.dev"); - }, - - /* - Scheduled event handler, this function will be called whenever a scheduled event is triggered. - The function will perform a task and return a response based on the task outcome. - - @param {Event} event - the incoming event object - @param {Environment} environment - the environment object - @param {Context} context - the context object - - @returns {void} - */ - async scheduled(event, environment, context) { - console.log("Scheduled event triggered!"); - }, -}; diff --git a/projects/api/wrangler.jsonc b/projects/api/wrangler.jsonc deleted file mode 100644 index b87f2e2..0000000 --- a/projects/api/wrangler.jsonc +++ /dev/null @@ -1,30 +0,0 @@ -{ - "$schema": "node_modules/wrangler/config-schema.json", - "compatibility_flags": ["nodejs_compat"], - "compatibility_date": "2025-02-05", - "name": "api-zue-dev", - "main": "source/main.js", - "routes": [ - { - "pattern": "api.zue.dev", - "custom_domain": true - } - ], - "observability": { - "enabled": true, - "head_sampling_rate": 1 - }, - "browser": { - "binding": "MYBROWSER" - }, - "ai": { - "binding": "AI" - }, - "secrets_store_secrets": [ - { - "binding": "GOOGLE_API_KEY_UNRESTRICTED", - "store_id": "df48b01a29a44fe59118b31da3abacbd", - "secret_name": "google-api-key-unrestricted" - } - ] -} diff --git a/projects/api/package-lock.json b/projects/www/package-lock.json index 918933a..aaa087d 100644 --- a/projects/api/package-lock.json +++ b/projects/www/package-lock.json @@ -1,5 +1,5 @@ { - "name": "api.zue.dev", + "name": "www", "lockfileVersion": 3, "requires": true, "packages": { @@ -23,43 +23,21 @@ } }, "node_modules/@cloudflare/puppeteer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@cloudflare/puppeteer/-/puppeteer-1.0.2.tgz", - "integrity": "sha512-I4UmeOg/9lmdrDqcXp1ZZALjCpk6ysygMZifVoI75YNuVHmvOjfkaXWRE1p/WgAs9phDeZrY7AqoK1YLGHwwww==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@cloudflare/puppeteer/-/puppeteer-1.0.4.tgz", + "integrity": "sha512-I7vh9Er1hQ/7OnOL/NEPaiR0alRQ62wEWstyizilmr69AcRqvu+ufNlTc3A2uXREEvFBZ6TFajdcrBbh78/mtA==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@puppeteer/browsers": "2.2.3", - "debug": "4.3.4", - "devtools-protocol": "0.0.1273771", - "ws": "8.17.0" + "@puppeteer/browsers": "2.2.4", + "debug": "^4.3.5", + "devtools-protocol": "0.0.1299070", + "ws": "^8.18.0" }, "engines": { "node": ">=18" } }, - "node_modules/@cloudflare/puppeteer/node_modules/ws": { - "version": "8.17.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.0.tgz", - "integrity": "sha512-uJq6108EgZMAl20KagGkzCKfMEjxmKvZHG7Tlq0Z6nOky7YF7aq4mOx6xK8TJ/i1LeK4Qus7INktacctDgY8Ow==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, "node_modules/@cloudflare/unenv-preset": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/@cloudflare/unenv-preset/-/unenv-preset-2.0.2.tgz", @@ -77,9 +55,9 @@ } }, "node_modules/@cloudflare/workerd-darwin-64": { - "version": "1.20250408.0", - "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-64/-/workerd-darwin-64-1.20250408.0.tgz", - "integrity": "sha512-bxhIwBWxaNItZLXDNOKY2dCv0FHjDiDkfJFpwv4HvtvU5MKcrivZHVmmfDzLW85rqzfcDOmKbZeMPVfiKxdBZw==", + "version": "1.20250718.0", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-64/-/workerd-darwin-64-1.20250718.0.tgz", + "integrity": "sha512-FHf4t7zbVN8yyXgQ/r/GqLPaYZSGUVzeR7RnL28Mwj2djyw2ZergvytVc7fdGcczl6PQh+VKGfZCfUqpJlbi9g==", "cpu": [ "x64" ], @@ -94,9 +72,9 @@ } }, "node_modules/@cloudflare/workerd-darwin-arm64": { - "version": "1.20250408.0", - "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-arm64/-/workerd-darwin-arm64-1.20250408.0.tgz", - "integrity": "sha512-5XZ2Oykr8bSo7zBmERtHh18h5BZYC/6H1YFWVxEj3PtalF3+6SHsO4KZsbGvDml9Pu7sHV277jiZE5eny8Hlyw==", + "version": "1.20250718.0", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-arm64/-/workerd-darwin-arm64-1.20250718.0.tgz", + "integrity": "sha512-fUiyUJYyqqp4NqJ0YgGtp4WJh/II/YZsUnEb6vVy5Oeas8lUOxnN+ZOJ8N/6/5LQCVAtYCChRiIrBbfhTn5Z8Q==", "cpu": [ "arm64" ], @@ -111,9 +89,9 @@ } }, "node_modules/@cloudflare/workerd-linux-64": { - "version": "1.20250408.0", - "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-64/-/workerd-linux-64-1.20250408.0.tgz", - "integrity": "sha512-WbgItXWln6G5d7GvYLWcuOzAVwafysZaWunH3UEfsm95wPuRofpYnlDD861gdWJX10IHSVgMStGESUcs7FLerQ==", + "version": "1.20250718.0", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-64/-/workerd-linux-64-1.20250718.0.tgz", + "integrity": "sha512-5+eb3rtJMiEwp08Kryqzzu8d1rUcK+gdE442auo5eniMpT170Dz0QxBrqkg2Z48SFUPYbj+6uknuA5tzdRSUSg==", "cpu": [ "x64" ], @@ -128,9 +106,9 @@ } }, "node_modules/@cloudflare/workerd-linux-arm64": { - "version": "1.20250408.0", - "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-arm64/-/workerd-linux-arm64-1.20250408.0.tgz", - "integrity": "sha512-pAhEywPPvr92SLylnQfZEPgXz+9pOG9G9haAPLpEatncZwYiYd9yiR6HYWhKp2erzCoNrOqKg9IlQwU3z1IDiw==", + "version": "1.20250718.0", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-arm64/-/workerd-linux-arm64-1.20250718.0.tgz", + "integrity": "sha512-Aa2M/DVBEBQDdATMbn217zCSFKE+ud/teS+fFS+OQqKABLn0azO2qq6ANAHYOIE6Q3Sq4CxDIQr8lGdaJHwUog==", "cpu": [ "arm64" ], @@ -145,9 +123,9 @@ } }, "node_modules/@cloudflare/workerd-windows-64": { - "version": "1.20250408.0", - "resolved": "https://registry.npmjs.org/@cloudflare/workerd-windows-64/-/workerd-windows-64-1.20250408.0.tgz", - "integrity": "sha512-nJ3RjMKGae2aF2rZ/CNeBvQPM+W5V1SUK0FYWG/uomyr7uQ2l4IayHna1ODg/OHHTEgIjwom0Mbn58iXb0WOcQ==", + "version": "1.20250718.0", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-windows-64/-/workerd-windows-64-1.20250718.0.tgz", + "integrity": "sha512-dY16RXKffmugnc67LTbyjdDHZn5NoTF1yHEf2fN4+OaOnoGSp3N1x77QubTDwqZ9zECWxgQfDLjddcH8dWeFhg==", "cpu": [ "x64" ], @@ -175,9 +153,9 @@ } }, "node_modules/@emnapi/runtime": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.4.3.tgz", - "integrity": "sha512-pBPWdu6MLKROBX05wSNKcNb++m5Er+KQ9QkB+WVM+pW2Kx9hoSrVTnu3BdkI5eBLZoKu/J6mW/B6i6bJB2ytXQ==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.6.0.tgz", + "integrity": "sha512-obtUmAHTMjll499P+D9A3axeJFlhdjOWdKUNs/U6QIGT7V5RjcUW1xToAzjvmgTSQhDbYn/NwfTRoJcQ2rNBxA==", "dev": true, "license": "MIT", "optional": true, @@ -984,9 +962,9 @@ } }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.4.tgz", - "integrity": "sha512-VT2+G1VQs/9oz078bLrYbecdZKs912zQlkelYpuf+SXF+QvZDYJlbx/LSx+meSAwdDFnF8FVXW92AVjjkVmgFw==", + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", "dev": true, "license": "MIT" }, @@ -1002,20 +980,20 @@ } }, "node_modules/@puppeteer/browsers": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-2.2.3.tgz", - "integrity": "sha512-bJ0UBsk0ESOs6RFcLXOt99a3yTDcOKlzfjad+rhFwdaG1Lu/Wzq58GHYCDTlZ9z6mldf4g+NTb+TXEfe0PpnsQ==", + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-2.2.4.tgz", + "integrity": "sha512-BdG2qiI1dn89OTUUsx2GZSpUzW+DRffR1wlMJyKxVHYrhnKoELSDxDd+2XImUkuWPEKk76H5FcM/gPFrEK1Tfw==", "dev": true, "license": "Apache-2.0", "dependencies": { - "debug": "4.3.4", - "extract-zip": "2.0.1", - "progress": "2.0.3", - "proxy-agent": "6.4.0", - "semver": "7.6.0", - "tar-fs": "3.0.5", - "unbzip2-stream": "1.4.3", - "yargs": "17.7.2" + "debug": "^4.3.5", + "extract-zip": "^2.0.1", + "progress": "^2.0.3", + "proxy-agent": "^6.4.0", + "semver": "^7.6.2", + "tar-fs": "^3.0.6", + "unbzip2-stream": "^1.4.3", + "yargs": "^17.7.2" }, "bin": { "browsers": "lib/cjs/main-cli.js" @@ -1024,35 +1002,6 @@ "node": ">=18" } }, - "node_modules/@puppeteer/browsers/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@puppeteer/browsers/node_modules/semver": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", - "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", - "dev": true, - "license": "ISC", - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/@tootallnate/quickjs-emscripten": { "version": "0.23.0", "resolved": "https://registry.npmjs.org/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz", @@ -1061,14 +1010,14 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "24.0.3", - "resolved": "https://registry.npmjs.org/@types/node/-/node-24.0.3.tgz", - "integrity": "sha512-R4I/kzCYAdRLzfiCabn9hxWfbuHS573x+r0dJMkkzThEa7pbrcDWK+9zu3e7aBOouf+rQAciqPFMnxwr0aWgKg==", + "version": "24.9.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.9.2.tgz", + "integrity": "sha512-uWN8YqxXxqFMX2RqGOrumsKeti4LlmIMIyV0lgut4jx7KQBcBiW6vkDtIBvHnHIquwNfJhk8v2OtmO8zXWHfPA==", "dev": true, "license": "MIT", "optional": true, "dependencies": { - "undici-types": "~7.8.0" + "undici-types": "~7.16.0" } }, "node_modules/@types/yauzl": { @@ -1106,9 +1055,9 @@ } }, "node_modules/agent-base": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz", - "integrity": "sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==", + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", "dev": true, "license": "MIT", "engines": { @@ -1165,56 +1114,87 @@ } }, "node_modules/b4a": { - "version": "1.6.7", - "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.7.tgz", - "integrity": "sha512-OnAYlL5b7LEkALw87fUVafQw5rVR9RjwGd4KUwNQ6DrrNmaVaUCgLipfVlzrPQ4tWOR9P0IXGNOx50jYCCdSJg==", + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.7.3.tgz", + "integrity": "sha512-5Q2mfq2WfGuFp3uS//0s6baOJLMoVduPYVeNmDYxu5OUA1/cBfvr2RIS7vi62LdNj/urk1hfmj867I3qt6uZ7Q==", "dev": true, - "license": "Apache-2.0" + "license": "Apache-2.0", + "peerDependencies": { + "react-native-b4a": "*" + }, + "peerDependenciesMeta": { + "react-native-b4a": { + "optional": true + } + } }, "node_modules/bare-events": { - "version": "2.5.4", - "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.5.4.tgz", - "integrity": "sha512-+gFfDkR8pj4/TrWCGUGWmJIkBwuxPS5F+a5yWjOHQt2hHvNZd5YLzadjmDUtFmMM4y429bnKLa8bYBMHcYdnQA==", + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.8.1.tgz", + "integrity": "sha512-oxSAxTS1hRfnyit2CL5QpAOS5ixfBjj6ex3yTNvXyY/kE719jQ/IjuESJBK2w5v4wwQRAHGseVJXx9QBYOtFGQ==", "dev": true, "license": "Apache-2.0", - "optional": true + "peerDependencies": { + "bare-abort-controller": "*" + }, + "peerDependenciesMeta": { + "bare-abort-controller": { + "optional": true + } + } }, "node_modules/bare-fs": { - "version": "2.3.5", - "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-2.3.5.tgz", - "integrity": "sha512-SlE9eTxifPDJrT6YgemQ1WGFleevzwY+XAP1Xqgl56HtcrisC2CHCZ2tq6dBpcH2TnNxwUEUGhweo+lrQtYuiw==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-4.5.0.tgz", + "integrity": "sha512-GljgCjeupKZJNetTqxKaQArLK10vpmK28or0+RwWjEl5Rk+/xG3wkpmkv+WrcBm3q1BwHKlnhXzR8O37kcvkXQ==", "dev": true, "license": "Apache-2.0", "optional": true, "dependencies": { - "bare-events": "^2.0.0", - "bare-path": "^2.0.0", - "bare-stream": "^2.0.0" + "bare-events": "^2.5.4", + "bare-path": "^3.0.0", + "bare-stream": "^2.6.4", + "bare-url": "^2.2.2", + "fast-fifo": "^1.3.2" + }, + "engines": { + "bare": ">=1.16.0" + }, + "peerDependencies": { + "bare-buffer": "*" + }, + "peerDependenciesMeta": { + "bare-buffer": { + "optional": true + } } }, "node_modules/bare-os": { - "version": "2.4.4", - "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-2.4.4.tgz", - "integrity": "sha512-z3UiI2yi1mK0sXeRdc4O1Kk8aOa/e+FNWZcTiPB/dfTWyLypuE99LibgRaQki914Jq//yAWylcAt+mknKdixRQ==", + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-3.6.2.tgz", + "integrity": "sha512-T+V1+1srU2qYNBmJCXZkUY5vQ0B4FSlL3QDROnKQYOqeiQR8UbjNHlPa+TIbM4cuidiN9GaTaOZgSEgsvPbh5A==", "dev": true, "license": "Apache-2.0", - "optional": true + "optional": true, + "engines": { + "bare": ">=1.14.0" + } }, "node_modules/bare-path": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/bare-path/-/bare-path-2.1.3.tgz", - "integrity": "sha512-lh/eITfU8hrj9Ru5quUp0Io1kJWIk1bTjzo7JH1P5dWmQ2EL4hFUlfI8FonAhSlgIfhn63p84CDY/x+PisgcXA==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bare-path/-/bare-path-3.0.0.tgz", + "integrity": "sha512-tyfW2cQcB5NN8Saijrhqn0Zh7AnFNsnczRcuWODH0eYAXBsJ5gVxAUuNr7tsHSC6IZ77cA0SitzT+s47kot8Mw==", "dev": true, "license": "Apache-2.0", "optional": true, "dependencies": { - "bare-os": "^2.1.0" + "bare-os": "^3.0.1" } }, "node_modules/bare-stream": { - "version": "2.6.5", - "resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.6.5.tgz", - "integrity": "sha512-jSmxKJNJmHySi6hC42zlZnq00rga4jjxcgNZjY9N5WlOe/iOoGRtdwGsHzQv2RlH2KOYMwGUXhf2zXd32BA9RA==", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.7.0.tgz", + "integrity": "sha512-oyXQNicV1y8nc2aKffH+BUHFRXmx6VrPzlnaEvMhram0nPBrKcEdcyBg5r08D0i8VxngHFAiVyn1QKXpSG0B8A==", "dev": true, "license": "Apache-2.0", "optional": true, @@ -1234,6 +1214,17 @@ } } }, + "node_modules/bare-url": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/bare-url/-/bare-url-2.3.1.tgz", + "integrity": "sha512-v2yl0TnaZTdEnelkKtXZGnotiV6qATBlnNuUMrHl6v9Lmmrh9mw9RYyImPU7/4RahumSwQS1k2oKXcRfXcbjJw==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "bare-path": "^3.0.0" + } + }, "node_modules/base64-js": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", @@ -1380,20 +1371,23 @@ } }, "node_modules/data-uri-to-buffer": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-2.0.2.tgz", - "integrity": "sha512-ND9qDTLc6diwj+Xe5cdAgVTbLVdXbtxTJRXRhli8Mowuaan+0EJOtdqJ0QCHNSSPyoXGx9HX2/VMnKeC34AChA==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-6.0.2.tgz", + "integrity": "sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==", "dev": true, - "license": "MIT" + "license": "MIT", + "engines": { + "node": ">= 14" + } }, "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", "dev": true, "license": "MIT", "dependencies": { - "ms": "2.1.2" + "ms": "^2.1.3" }, "engines": { "node": ">=6.0" @@ -1427,9 +1421,9 @@ } }, "node_modules/detect-libc": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.4.tgz", - "integrity": "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", "dev": true, "license": "Apache-2.0", "optional": true, @@ -1438,9 +1432,9 @@ } }, "node_modules/devtools-protocol": { - "version": "0.0.1273771", - "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1273771.tgz", - "integrity": "sha512-QDbb27xcTVReQQW/GHJsdQqGKwYBE7re7gxehj467kKP2DKuYBUj6i2k5LRiAC66J1yZG/9gsxooz/s9pcm0Og==", + "version": "0.0.1299070", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1299070.tgz", + "integrity": "sha512-+qtL3eX50qsJ7c+qVyagqi7AWMoQCBGNfoyJZMwm/NSXVqLYbuitrWEEIzxfUmTNy7//Xe8yhMmQ+elj3uAqSg==", "dev": true, "license": "BSD-3-Clause" }, @@ -1585,6 +1579,16 @@ "node": ">=0.10.0" } }, + "node_modules/events-universal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/events-universal/-/events-universal-1.0.1.tgz", + "integrity": "sha512-LUd5euvbMLpwOF8m6ivPCbhQeSiYVNb8Vs0fQ8QjXo0JTkEHpz8pxdQf0gStltaPpw0Cca8b39KxvK9cfKRiAw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "bare-events": "^2.7.0" + } + }, "node_modules/exit-hook": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/exit-hook/-/exit-hook-2.2.1.tgz", @@ -1679,6 +1683,13 @@ "source-map": "^0.6.1" } }, + "node_modules/get-source/node_modules/data-uri-to-buffer": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-2.0.2.tgz", + "integrity": "sha512-ND9qDTLc6diwj+Xe5cdAgVTbLVdXbtxTJRXRhli8Mowuaan+0EJOtdqJ0QCHNSSPyoXGx9HX2/VMnKeC34AChA==", + "dev": true, + "license": "MIT" + }, "node_modules/get-stream": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", @@ -1696,9 +1707,9 @@ } }, "node_modules/get-uri": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-6.0.4.tgz", - "integrity": "sha512-E1b1lFFLvLgak2whF2xDBcOy6NLVGZBqqjJjsIhvopKfWWEi64pLVTWWehV8KlLerZkfNTA95sTe2OdJKm1OzQ==", + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-6.0.5.tgz", + "integrity": "sha512-b1O07XYq8eRuVzBNgJLstU6FYc1tS6wnMtF1I1D9lE8LxZSOGZ7LhxN54yPP6mGw5f2CkXY2BQUL9Fx41qvcIg==", "dev": true, "license": "MIT", "dependencies": { @@ -1710,16 +1721,6 @@ "node": ">= 14" } }, - "node_modules/get-uri/node_modules/data-uri-to-buffer": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-6.0.2.tgz", - "integrity": "sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 14" - } - }, "node_modules/glob-to-regexp": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", @@ -1777,23 +1778,19 @@ "license": "BSD-3-Clause" }, "node_modules/ip-address": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz", - "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==", + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.0.1.tgz", + "integrity": "sha512-NWv9YLW4PoW2B7xtzaS3NCot75m6nK7Icdv0o3lfMceJVRfSoQwqD4wEH5rLwoKJwUiZ/rfpiVBhnaF0FK4HoA==", "dev": true, "license": "MIT", - "dependencies": { - "jsbn": "1.1.0", - "sprintf-js": "^1.1.3" - }, "engines": { "node": ">= 12" } }, "node_modules/is-arrayish": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", - "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==", + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.4.tgz", + "integrity": "sha512-m6UrgzFVUYawGBh1dUsWR5M2Clqic9RVXC/9f8ceNlv2IcO9j9J/z8UoCLPqtsPBFNzEpfR3xftohbfqDx8EQA==", "dev": true, "license": "MIT", "optional": true @@ -1808,13 +1805,6 @@ "node": ">=8" } }, - "node_modules/jsbn": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", - "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==", - "dev": true, - "license": "MIT" - }, "node_modules/lru-cache": { "version": "7.18.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", @@ -1849,9 +1839,9 @@ } }, "node_modules/miniflare": { - "version": "3.20250408.2", - "resolved": "https://registry.npmjs.org/miniflare/-/miniflare-3.20250408.2.tgz", - "integrity": "sha512-uTs7cGWFErgJTKtBdmtctwhuoxniuCQqDT8+xaEiJdEC8d+HsaZVYfZwIX2NuSmdAiHMe7NtbdZYjFMbIXtJsQ==", + "version": "3.20250718.2", + "resolved": "https://registry.npmjs.org/miniflare/-/miniflare-3.20250718.2.tgz", + "integrity": "sha512-cW/NQPBKc+fb0FwcEu+z/v93DZd+/6q/AF0iR0VFELtNPOsCvLalq6ndO743A7wfZtFxMxvuDQUXNx3aKQhOwA==", "dev": true, "license": "MIT", "dependencies": { @@ -1862,7 +1852,7 @@ "glob-to-regexp": "0.4.1", "stoppable": "1.1.0", "undici": "^5.28.5", - "workerd": "1.20250408.0", + "workerd": "1.20250718.0", "ws": "8.18.0", "youch": "3.3.4", "zod": "3.22.3" @@ -1874,10 +1864,32 @@ "node": ">=16.13" } }, + "node_modules/miniflare/node_modules/ws": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true, "license": "MIT" }, @@ -1991,20 +2003,20 @@ } }, "node_modules/proxy-agent": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.4.0.tgz", - "integrity": "sha512-u0piLU+nCOHMgGjRbimiXmA9kM/L9EHh3zL81xCdp7m+Y2pHIsnmbdDoEDoAz5geaonNR6q6+yOPQs6n4T6sBQ==", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.5.0.tgz", + "integrity": "sha512-TmatMXdr2KlRiA2CyDu8GqR8EjahTG3aY3nXjdzFyoZbmB8hrBsTyMezhULIXKnC0jpfjlmiZ3+EaCzoInSu/A==", "dev": true, "license": "MIT", "dependencies": { - "agent-base": "^7.0.2", + "agent-base": "^7.1.2", "debug": "^4.3.4", "http-proxy-agent": "^7.0.1", - "https-proxy-agent": "^7.0.3", + "https-proxy-agent": "^7.0.6", "lru-cache": "^7.14.1", - "pac-proxy-agent": "^7.0.1", + "pac-proxy-agent": "^7.1.0", "proxy-from-env": "^1.1.0", - "socks-proxy-agent": "^8.0.2" + "socks-proxy-agent": "^8.0.5" }, "engines": { "node": ">= 14" @@ -2072,12 +2084,11 @@ } }, "node_modules/semver": { - "version": "7.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", - "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", "dev": true, "license": "ISC", - "optional": true, "bin": { "semver": "bin/semver.js" }, @@ -2127,9 +2138,9 @@ } }, "node_modules/simple-swizzle": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", - "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.4.tgz", + "integrity": "sha512-nAu1WFPQSMNr2Zn9PGSZK9AGn4t/y97lEm+MXTtUDwfP0ksAIX4nO+6ruD9Jwut4C49SB1Ws+fbXsm/yScWOHw==", "dev": true, "license": "MIT", "optional": true, @@ -2149,13 +2160,13 @@ } }, "node_modules/socks": { - "version": "2.8.5", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.5.tgz", - "integrity": "sha512-iF+tNDQla22geJdTyJB1wM/qrX9DMRwWrciEPwWLPRWAUEM8sQiyxgckLxWT1f7+9VabJS0jTGGr4QgBuvi6Ww==", + "version": "2.8.7", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.7.tgz", + "integrity": "sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A==", "dev": true, "license": "MIT", "dependencies": { - "ip-address": "^9.0.5", + "ip-address": "^10.0.1", "smart-buffer": "^4.2.0" }, "engines": { @@ -2196,13 +2207,6 @@ "dev": true, "license": "MIT" }, - "node_modules/sprintf-js": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", - "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", - "dev": true, - "license": "BSD-3-Clause" - }, "node_modules/stacktracey": { "version": "2.1.8", "resolved": "https://registry.npmjs.org/stacktracey/-/stacktracey-2.1.8.tgz", @@ -2226,17 +2230,15 @@ } }, "node_modules/streamx": { - "version": "2.22.1", - "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.22.1.tgz", - "integrity": "sha512-znKXEBxfatz2GBNK02kRnCXjV+AA4kjZIUxeWSr3UGirZMJfTE9uiwKHobnbgxWyL/JWro8tTq+vOqAK1/qbSA==", + "version": "2.23.0", + "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.23.0.tgz", + "integrity": "sha512-kn+e44esVfn2Fa/O0CPFcex27fjIL6MkVae0Mm6q+E6f0hWv578YCERbv+4m02cjxvDsPKLnmxral/rR6lBMAg==", "dev": true, "license": "MIT", "dependencies": { + "events-universal": "^1.0.0", "fast-fifo": "^1.3.2", "text-decoder": "^1.1.0" - }, - "optionalDependencies": { - "bare-events": "^2.2.0" } }, "node_modules/string-width": { @@ -2268,9 +2270,9 @@ } }, "node_modules/tar-fs": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.0.5.tgz", - "integrity": "sha512-JOgGAmZyMgbqpLwct7ZV8VzkEB6pxXFBVErLtb+XCOqzc6w1xiWKI9GVd6bwk68EX7eJ4DWmfXVmq8K2ziZTGg==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.1.1.tgz", + "integrity": "sha512-LZA0oaPOc2fVo82Txf3gw+AkEd38szODlptMYejQUhndHMLQ9M059uXR+AfS7DNo0NpINvSqDsvyaCrBVkptWg==", "dev": true, "license": "MIT", "dependencies": { @@ -2278,8 +2280,8 @@ "tar-stream": "^3.1.5" }, "optionalDependencies": { - "bare-fs": "^2.1.1", - "bare-path": "^2.1.0" + "bare-fs": "^4.0.1", + "bare-path": "^3.0.0" } }, "node_modules/tar-stream": { @@ -2350,9 +2352,9 @@ } }, "node_modules/undici-types": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.8.0.tgz", - "integrity": "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw==", + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", "dev": true, "license": "MIT", "optional": true @@ -2372,9 +2374,9 @@ } }, "node_modules/workerd": { - "version": "1.20250408.0", - "resolved": "https://registry.npmjs.org/workerd/-/workerd-1.20250408.0.tgz", - "integrity": "sha512-bBUX+UsvpzAqiWFNeZrlZmDGddiGZdBBbftZJz2wE6iUg/cIAJeVQYTtS/3ahaicguoLBz4nJiDo8luqM9fx1A==", + "version": "1.20250718.0", + "resolved": "https://registry.npmjs.org/workerd/-/workerd-1.20250718.0.tgz", + "integrity": "sha512-kqkIJP/eOfDlUyBzU7joBg+tl8aB25gEAGqDap+nFWb+WHhnooxjGHgxPBy3ipw2hnShPFNOQt5lFRxbwALirg==", "dev": true, "hasInstallScript": true, "license": "Apache-2.0", @@ -2385,17 +2387,17 @@ "node": ">=16" }, "optionalDependencies": { - "@cloudflare/workerd-darwin-64": "1.20250408.0", - "@cloudflare/workerd-darwin-arm64": "1.20250408.0", - "@cloudflare/workerd-linux-64": "1.20250408.0", - "@cloudflare/workerd-linux-arm64": "1.20250408.0", - "@cloudflare/workerd-windows-64": "1.20250408.0" + "@cloudflare/workerd-darwin-64": "1.20250718.0", + "@cloudflare/workerd-darwin-arm64": "1.20250718.0", + "@cloudflare/workerd-linux-64": "1.20250718.0", + "@cloudflare/workerd-linux-arm64": "1.20250718.0", + "@cloudflare/workerd-windows-64": "1.20250718.0" } }, "node_modules/wrangler": { - "version": "3.114.10", - "resolved": "https://registry.npmjs.org/wrangler/-/wrangler-3.114.10.tgz", - "integrity": "sha512-UMs4bSH+P47oXvXqgziRqD8UOT8KBF6D/4O0bB9Kyh9QrT1FGpG2p4rV4FtbKFOchDrXQozbthScND+vLc8gqw==", + "version": "3.114.15", + "resolved": "https://registry.npmjs.org/wrangler/-/wrangler-3.114.15.tgz", + "integrity": "sha512-OpGikaV6t7AGXZImtGnVXI8WUnqBMFBCQcZzqKmQi0T/pZ5h8iSKhEZf7ItVB8bAG56yswHnWWYyANWF/Jj/JA==", "dev": true, "license": "MIT OR Apache-2.0", "dependencies": { @@ -2405,10 +2407,10 @@ "@esbuild-plugins/node-modules-polyfill": "0.2.2", "blake3-wasm": "2.1.5", "esbuild": "0.17.19", - "miniflare": "3.20250408.2", + "miniflare": "3.20250718.2", "path-to-regexp": "6.3.0", "unenv": "2.0.0-rc.14", - "workerd": "1.20250408.0" + "workerd": "1.20250718.0" }, "bin": { "wrangler": "bin/wrangler.js", @@ -2456,9 +2458,9 @@ "license": "ISC" }, "node_modules/ws": { - "version": "8.18.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", - "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", + "version": "8.18.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", + "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", "dev": true, "license": "MIT", "engines": { @@ -2487,13 +2489,6 @@ "node": ">=10" } }, - "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true, - "license": "ISC" - }, "node_modules/yargs": { "version": "17.7.2", "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", diff --git a/projects/api/package.json b/projects/www/package.json index 19fadf7..19fadf7 100644 --- a/projects/api/package.json +++ b/projects/www/package.json diff --git a/projects/www/server/index.js b/projects/www/server/index.js index 10151ea..c8230ec 100644 --- a/projects/www/server/index.js +++ b/projects/www/server/index.js @@ -1,25 +1,376 @@ +import puppeteer from "@cloudflare/puppeteer"; + export default { - async fetch(request, env) { + /* + Fetch event handler, this function will be called whenever a request is made to the worker. + The function will parse the request and return a response based on the request path. + + @param {Request} request - the incoming request object + @param {Environment} environment - the environment object + @param {Context} context - the context object + + @returns {Response} a new Response object + */ + async fetch(request, environment, context) { const url = new URL(request.url); if (url.pathname.startsWith("/api")) { - const apiPath = url.pathname.split("/").filter(Boolean); + const pathname = url.pathname.replace("/api", ""); + + // modify Response to handle CORS defaults + class Response extends globalThis.Response { + constructor(body, init) { + super(body, init); + this.headers.set("Access-Control-Allow-Origin", "*"); + this.headers.set("Access-Control-Allow-Methods", "*"); + this.headers.set("Access-Control-Allow-Headers", "*"); + } + } + + switch (pathname) { + case "/": + return (() => { + return new Response( + JSON.stringify({ + message: "Hello, World! :3", + random: `${Math.random()}`, + }), + { + headers: { + "Access-Control-Allow-Origin": "*", + "Content-Type": "application/json", + }, + } + ); + })(); + case "/status": + return (() => { + const url = new URL(request.url); + const service = url.searchParams.get("service"); + + const acceptedServices = [ + "dns", + "load-balancer", + "cdn", + "functions", + "mysql-cluster", + "mongodb-cluster", + "redis-cluster", + "elasticsearch-cluster", + "git-connector", + "job-runners", + "container-registry", + "kubernetes-cluster", + "bare-metal-servers", + "game-server-api", + "anti-ddos-protection", + "anti-cheat-api", + ]; + + if (acceptedServices.includes(service)) + return new Response( + JSON.stringify({ + status: "ok", + service, + }), + { + headers: { + "Access-Control-Allow-Origin": "*", + "Content-Type": "application/json", + }, + } + ); + + return new Response( + JSON.stringify({ + error: `service not found`, + }), + { + headers: { + "Access-Control-Allow-Origin": "*", + "Content-Type": "application/json", + }, + } + ); + })(); + case "/96/twitch/streaming": + return (async () => { + /* + Checks if a twitch channel is live by fetching the "live" preview image of the channel, + if the image is fetched successfully, then the channel is live, otherwise it's offline. + + @param {string} channel - the twitch channel name + @returns {boolean} true if the channel is live, false otherwise + */ + async function isTwitchChannelLive(channel) { + // construct preview image url with channel name + const livePreviewUrl = `https://static-cdn.jtvnw.net/previews-ttv/live_user_${channel}-320x180.jpg`; + + // fetch the preview image, don't follow redirects + const response = await fetch(livePreviewUrl, { + redirect: "manual", + }); + + // check if the image was fetched successfully + return response.ok; + } + + const url = new URL(request.url); + const channel = url.searchParams.get("channel"); + + if (!channel) + return new Response( + JSON.stringify({ + error: `channel not provided`, + }), + { + headers: { + "Access-Control-Allow-Origin": "*", + "Content-Type": "application/json", + }, + } + ); + + const whitelist = [ + "zuedev", + ...[ + "vtsweets", + "bunnibana", + "yayjaybae", + "justawoney", + "tygiwygi", + ], + ]; + + if (!whitelist.includes(channel)) + return new Response( + JSON.stringify({ + error: `channel not whitelisted`, + }), + { + headers: { + "Access-Control-Allow-Origin": "*", + "Content-Type": "application/json", + }, + } + ); + + const channelLive = await isTwitchChannelLive(channel); + + if (channelLive) + return new Response( + JSON.stringify({ + status: "live", + channel, + }), + { + headers: { + "Access-Control-Allow-Origin": "*", + "Content-Type": "application/json", + }, + } + ); + + return new Response( + JSON.stringify({ + status: "offline", + }), + { + headers: { + "Access-Control-Allow-Origin": "*", + "Content-Type": "application/json", + }, + } + ); + })(); + case "/96/youtube/latest-video": + return (async () => { + const url = new URL(request.url); + const channelHandle = url.searchParams.get("channelHandle"); + + if (!channelHandle) + return new Response( + JSON.stringify({ + error: `channel not provided`, + }), + { + headers: { + "Access-Control-Allow-Origin": "*", + "Content-Type": "application/json", + }, + } + ); + + const channelHandleWhitelist = ["@vtsweets"]; + + if (!channelHandleWhitelist.includes(channelHandle)) + return new Response( + JSON.stringify({ + error: `channel not allowed`, + }), + { + headers: { + "Access-Control-Allow-Origin": "*", + "Content-Type": "application/json", + }, + } + ); - if (!apiPath[1]) apiPath[1] = "index"; + let API_Key; - switch (apiPath[1]) { - case "index": - return new Response(JSON.stringify({ message: "Hello, World! :3" }), { - headers: { "Content-Type": "application/json" }, - }); + try { + API_Key = await environment.GOOGLE_API_KEY_UNRESTRICTED.get(); + } catch (error) { + API_Key = environment.GOOGLE_API_KEY_UNRESTRICTED; + } + + if (!API_Key) + return new Response( + JSON.stringify({ + error: `API Key not found`, + }), + { + headers: { + "Access-Control-Allow-Origin": "*", + "Content-Type": "application/json", + }, + } + ); + + const youtubeChannelsListResponse = await fetch( + `https://www.googleapis.com/youtube/v3/channels?part=contentDetails&forHandle=${channelHandle}&key=${API_Key}` + ); + + const youtubeChannelsList = + await youtubeChannelsListResponse.json(); + + if (youtubeChannelsList.items.length === 0) { + return new Response( + JSON.stringify({ + error: `channel not found`, + }), + { + headers: { + "Access-Control-Allow-Origin": "*", + "Content-Type": "application/json", + }, + } + ); + } + + const uploadsPlaylistId = + youtubeChannelsList.items[0].contentDetails.relatedPlaylists + .uploads; + + const youtubePlaylistItemsList = await fetch( + `https://www.googleapis.com/youtube/v3/playlistItems?part=snippet&playlistId=${uploadsPlaylistId}&maxResults=1&key=${API_Key}` + ); + + const youtubePlaylistItemsListData = + await youtubePlaylistItemsList.json(); + + if (youtubePlaylistItemsListData.items.length === 0) { + return new Response( + JSON.stringify({ + error: `no videos found in the channel`, + }), + { + headers: { + "Access-Control-Allow-Origin": "*", + "Content-Type": "application/json", + }, + } + ); + } + + return new Response( + youtubePlaylistItemsListData.items[0].snippet.resourceId.videoId + ); + })(); + case "/browser-rendering/screenshot": + return (async () => { + const { searchParams } = new URL(request.url); + const url = searchParams.get("url"); + const type = searchParams.get("type") || "webp"; + const fullPage = searchParams.get("fullPage") !== null; + const width = parseInt(searchParams.get("width"), 10) || 1920; + const height = parseInt(searchParams.get("height"), 10) || 1080; + const delay = parseInt(searchParams.get("delay"), 10) || 0; + + if (!url) + return router.respond({ + error: "URL parameter is required", + }); + + if (!/^https?:\/\//.test(url)) + return router.respond({ + error: "Invalid URL format", + }); + + const browser = await puppeteer.launch(environment.MYBROWSER); + const page = await browser.newPage(); + await page.setViewport({ width, height }); + await page.goto(url, { + waitUntil: "networkidle2", + }); + if (delay > 0) { + await new Promise((resolve) => setTimeout(resolve, delay)); + } + const screenshot = await page.screenshot({ + type, + fullPage, + }); + await browser.close(); + + return new Response(screenshot, { + headers: { + "content-type": `image/${type}`, + }, + }); + })(); default: - return new Response(JSON.stringify({ message: "Not Found" }), { - status: 404, - headers: { "Content-Type": "application/json" }, - }); + return new Response( + JSON.stringify({ + error: `path not found`, + }), + { + headers: { + "Access-Control-Allow-Origin": "*", + "Content-Type": "application/json", + }, + } + ); } } - return env.ASSETS.fetch(request); + return environment.ASSETS.fetch(request); + }, + + /* + Email event handler, this function will be called whenever an email is sent to the worker. + The function will parse the email message and forward it to a specified email address. + + @param {Message} message - the incoming email message object + @param {Environment} environment - the environment object + @param {Context} context - the context object + + @returns {void} + */ + async email(message, environment, context) { + message.forward("alex@zue.dev"); + }, + + /* + Scheduled event handler, this function will be called whenever a scheduled event is triggered. + The function will perform a task and return a response based on the task outcome. + + @param {Event} event - the incoming event object + @param {Environment} environment - the environment object + @param {Context} context - the context object + + @returns {void} + */ + async scheduled(event, environment, context) { + console.log("Scheduled event triggered!"); }, -};
\ No newline at end of file +}; diff --git a/projects/www/wrangler.jsonc b/projects/www/wrangler.jsonc index af0687f..7cf70c1 100644 --- a/projects/www/wrangler.jsonc +++ b/projects/www/wrangler.jsonc @@ -1,7 +1,9 @@ { + "$schema": "node_modules/wrangler/config-schema.json", + "compatibility_flags": ["nodejs_compat"], + "compatibility_date": "2025-02-05", "name": "zue-dev", - "compatibility_date": "2025-03-01", - "main" : "./server/index.js", + "main": "./server/index.js", "assets": { "directory": "./public/", "not_found_handling": "single-page-application", @@ -15,5 +17,18 @@ "pattern": "zue.dev", "custom_domain": true } + ], + "browser": { + "binding": "MYBROWSER" + }, + "ai": { + "binding": "AI" + }, + "secrets_store_secrets": [ + { + "binding": "GOOGLE_API_KEY_UNRESTRICTED", + "store_id": "df48b01a29a44fe59118b31da3abacbd", + "secret_name": "google-api-key-unrestricted" + } ] } |
