aboutsummaryrefslogtreecommitdiff
path: root/projects
diff options
context:
space:
mode:
Diffstat (limited to 'projects')
-rw-r--r--projects/api/.gitignore33
-rw-r--r--projects/api/README.md7
-rw-r--r--projects/api/source/main.js363
-rw-r--r--projects/api/wrangler.jsonc30
-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.js379
-rw-r--r--projects/www/wrangler.jsonc19
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"
+ }
]
}