├── .github
├── buttcoin.png
├── qr.svg
├── style-after.png
└── style-before.png
├── .gitignore
├── README.md
├── archive
├── index.js
├── package.json
└── wrangler.toml.example
├── buttcoin
├── index.js
├── package.json
└── wrangler.toml.example
├── cors
├── index.js
├── package.json
└── wrangler.toml.example
├── eruda
├── index.js
├── package.json
└── wrangler.toml.example
├── hash
├── index.js
├── package.json
└── wrangler.toml.example
├── instagram
├── index.js
├── package.json
└── wrangler.toml.example
├── ip
├── index.js
├── package.json
└── wrangler.toml.example
├── package-lock.json
├── package.json
├── proxy
├── index.js
├── package.json
└── wrangler.toml.example
├── pwned
├── index.js
├── package.json
└── wrangler.toml.example
├── qr
├── index.js
├── package.json
└── wrangler.toml.example
├── style
├── index.js
├── package.json
└── wrangler.toml.example
├── unroll
├── index.js
├── package.json
└── wrangler.toml.example
└── uuid
├── index.js
├── package.json
└── wrangler.toml.example
/.github/buttcoin.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ardislu/cloudflare-workers/4c71f7e633c14d73efbaee6341456a10597104e4/.github/buttcoin.png
--------------------------------------------------------------------------------
/.github/qr.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/.github/style-after.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ardislu/cloudflare-workers/4c71f7e633c14d73efbaee6341456a10597104e4/.github/style-after.png
--------------------------------------------------------------------------------
/.github/style-before.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ardislu/cloudflare-workers/4c71f7e633c14d73efbaee6341456a10597104e4/.github/style-before.png
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | wrangler.toml
3 | dist
4 | worker
5 | .install.lock
6 | */package-lock.json
7 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # cloudflare-workers
2 |
3 | Monorepo for my personal [Cloudflare Workers](https://workers.cloudflare.com/).
4 |
5 | Uses [npm workspaces](https://docs.npmjs.com/cli/v7/using-npm/workspaces) (npm
6 | version 7+) to manage multiple `package.json` files (a separate package is
7 | required for each Cloudflare Worker).
8 |
9 | # Quickstart
10 |
11 | 1. Clone this repo
12 |
13 | ```
14 | git clone https://github.com/ardislu/cloudflare-workers.git
15 | ```
16 |
17 | 2. Install dependencies
18 |
19 | ```
20 | npm i
21 | ```
22 |
23 | 3. For each Cloudflare Worker, make a copy of `wrangler.toml.example` and rename
24 | it to `wrangler.toml`.
25 | [Customize the fields](https://developers.cloudflare.com/workers/wrangler/configuration/)
26 | as required.
27 |
28 | You can use this bash script to quickly make a `wrangler.toml` file from the
29 | `wrangler.toml.example` file in each folder:
30 |
31 | ```bash
32 | find -name '*.example' | xargs -I {} sh -c 'cp -u "$1" "${1%.*}"' -- {}
33 | ```
34 |
35 | Or using PowerShell:
36 |
37 | ```PowerShell
38 | Get-ChildItem -Recurse -Filter '*.example' | Where-Object { -Not (Test-Path "$($_.DirectoryName)\$($_.BaseName)" -PathType Leaf) } | ForEach-Object { Copy-Item -LiteralPath "$($_.FullName)" -Destination "$($_.DirectoryName)\$($_.BaseName)" }
39 | ```
40 |
41 | 4. Test that each Cloudflare Worker works:
42 |
43 | ```
44 | npm run dev --workspace=[Cloudflare Worker name]
45 | ```
46 |
47 | 5. Deploy all the Workers to Cloudflare:
48 |
49 | ```
50 | npm run deploy --workspaces
51 | ```
52 |
53 | Or deploy an individual Worker:
54 |
55 | ```
56 | npm run deploy --workspace=[Cloudflare Worker name]
57 | ```
58 |
59 | # Limitations
60 |
61 | There are
62 | [some permission issues](https://github.com/cloudflare/wrangler/issues/240) when
63 | installing `wrangler` as a dependency in an npm workspace. As a workaround, I've
64 | made `wrangler` a dependency in the top-level `package.json` for the overall
65 | monorepo, and omitted `wrangler` from the dependencies for each workspace. That
66 | means that **the npm scripts in each workspace depend on `wrangler` being
67 | installed outside of the workspace**. So if you wanted to pull a workspace out
68 | of the monorepo and run the workspace on its own, you must re-add `wrangler` to
69 | the workspace dependencies first.
70 |
71 | # Workers
72 |
73 | All examples assume that the worker has been deployed at
74 | **`https://x.y.workers.dev`**.
75 |
76 |
Reverse Proxies
77 |
78 | ## proxy
79 |
80 | This is a minimal, basic reverse proxy. Proxy any request through the Cloudflare
81 | Worker by passing the **entire** URL as a query string to the Cloudflare Worker.
82 |
83 | For example, if the request you want to proxy is:
84 |
85 | ```
86 | https://api.example.com?param1=test1¶m2=test2
87 | ```
88 |
89 | then the final request URL should be:
90 |
91 | ```
92 | https://x.y.workers.dev?https://api.example.com?param1=test1¶m2=test2
93 | ```
94 |
95 | For simplicity, this worker does not configure the `cf` headers on the `fetch`
96 | request that is sent to the Cloudflare proxy. Set the `cf` request headers to
97 | configure the Cloudflare Worker's behavior on caching. See:
98 | [Cache using fetch](https://developers.cloudflare.com/workers/examples/cache-using-fetch).
99 |
100 | ## cors
101 |
102 | This reverse proxy injects permissive
103 | [CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) response headers
104 | to a response. Useful for using APIs that have not enabled CORS.
105 |
106 | ```
107 | https://x.y.workers.dev?https://api-with-unconfigured-cors.example.com?param1=test1¶m2=test2
108 | ```
109 |
110 | ## style
111 |
112 | This reverse proxy injects a basic CSS style sheet to a page's `` and
113 | returns the result. Good for quickly "upgrading" old/minimalist web pages with
114 | no styling.
115 |
116 | ```
117 | https://x.y.workers.dev?https://site-with-no-styles.example.com
118 | ```
119 |
120 | Before (https://www.cs.virginia.edu/~robins/YouAndYourResearch.html):
121 |
122 |
123 | After
124 | (https://x.y.workers.dev?https://www.cs.virginia.edu/~robins/YouAndYourResearch.html):
125 |
126 |
127 | ## buttcoin
128 |
129 | Returns a page where all instances of the word "bitcoin" are replaced with
130 | "buttcoin".
131 |
132 | ```
133 | https://x.y.workers.dev?https://en.wikipedia.org/wiki/Bitcoin
134 | > (See image below)
135 | ```
136 |
137 |
138 |
139 | ## eruda
140 |
141 | This reverse proxy injects [eruda](https://github.com/liriliri/eruda) into a
142 | webpage. Good for quickly injecting DevTools into a webpage.
143 |
144 | ```
145 | https://x.y.workers.dev?https://example.com
146 | ```
147 |
148 | Web Utilities
149 |
150 | ## qr
151 |
152 | Generates a SVG file representing a QR code for the value passed to the
153 | endpoint.
154 |
155 | ```
156 | https://x.y.workers.dev?https://example.com
157 | > (The SVG file rendered below)
158 | ```
159 |
160 |
161 |
162 | ## unroll
163 |
164 | Redirects a Twitter thread to the corresponding Threadreader thread.
165 |
166 | ```
167 | https://x.y.workers.dev?https://twitter.com/{username}/status/{id}
168 | > (HTTP redirect to https://threadreaderapp.com/thread/{id})
169 | ```
170 |
171 | ## instagram
172 |
173 | Returns a page with an Instagram post embedded in it so the post can be viewed
174 | without logging in.
175 |
176 | ```
177 | https://x.y.workers.dev?https://www.instagram.com/p/{POST_ID}/
178 | > (Page with the Instagram post's embedded view in it)
179 | ```
180 |
181 | ## archive
182 |
183 | Redirects a webpage to the corresponding [archive.ph](https://archive.ph)
184 | capture. Useful to bypass news article paywalls.
185 |
186 | ```
187 | https://x.y.workers.dev?https://example.com
188 | > (HTTP redirect to https://archive.ph/https://example.com)
189 | ```
190 |
191 | Command Line Utilities
192 |
193 | ## pwned
194 |
195 | > [!CAUTION] The underlying Pwned Passwords API used in this worker uses a
196 | > [_k_-anonymity model](https://en.wikipedia.org/wiki/K-anonymity) to preserve
197 | > your privacy. This worker negates that benefit. This worker should only be
198 | > referenced for education, not actually used in a production backend.
199 | > [Click here to read more.](https://www.troyhunt.com/ive-just-launched-pwned-passwords-version-2/#cloudflareprivacyandkanonymity)
200 |
201 | Checks a password against the [have i been pwned?](https://haveibeenpwned.com/)
202 | API and returns a boolean indicating if the password has been pwned or not. This
203 | is a simplified implementation of the
204 | [Pwned Passwords Cloudflare Worker](https://github.com/HaveIBeenPwned/PwnedPasswordsCloudflareWorker).
205 |
206 | In bash:
207 |
208 | ```bash
209 | $ curl https://x.y.workers.dev?hunter2
210 | true
211 | ```
212 |
213 | In PowerShell:
214 |
215 | ```powershell
216 | PS> irm https://x.y.workers.dev?hunter2
217 | True
218 | ```
219 |
220 | ## ip
221 |
222 | Returns the requester's IP address. Uses the
223 | [Cloudflare header](https://developers.cloudflare.com/workers/runtime-apis/headers#cloudflare-headers)
224 | `CF-Connecting-IP` to get this value. Inspired by and works like
225 | [ifconfig.me](https://ifconfig.me) and [ifconfig.co](https://ifconfig.co).
226 |
227 | In bash:
228 |
229 | ```bash
230 | $ curl https://x.y.workers.dev
231 |
232 | ```
233 |
234 | In PowerShell:
235 |
236 | ```powershell
237 | PS> irm https://x.y.workers.dev
238 |
239 | ```
240 |
241 | ## uuid
242 |
243 | Returns a random version 4 UUID.
244 |
245 | In bash:
246 |
247 | ```bash
248 | $ curl https://x.y.workers.dev
249 |
250 | ```
251 |
252 | In PowerShell:
253 |
254 | ```powershell
255 | PS> irm https://x.y.workers.dev
256 |
257 | ```
258 |
259 | ## hash
260 |
261 | Returns the hash of a string or a hexadecimal byte array using the
262 | [Web Crypto API](https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/digest).
263 |
264 | In bash:
265 |
266 | ```bash
267 | # SHA-256 hash of the string "Hello, world!"
268 | $ curl "https://x.y.workers.dev?algorithm=SHA-256&query=Hello%2C%20world%21"
269 | 315F5BDB76D078C43B8AC0064E4A0164612B1FCE77C869345BFC94C75894EDD3
270 |
271 | # MD5 hash of the literal byte array [00, AA, BB, CC]
272 | $ curl "https://x.y.workers.dev?algorithm=MD5&hex=00AABBCC"
273 | CD7409B51FDE80807E2E1532B7432A00
274 | ```
275 |
276 | In PowerShell:
277 |
278 | ```powershell
279 | # SHA-256 hash of the string "Hello, world!"
280 | PS> irm "https://x.y.workers.dev?algorithm=SHA-256&query=Hello%2C%20world%21"
281 | 315F5BDB76D078C43B8AC0064E4A0164612B1FCE77C869345BFC94C75894EDD3
282 |
283 | # MD5 hash of the literal byte array [00, AA, BB, CC]
284 | PS> irm "https://x.y.workers.dev?algorithm=MD5&hex=00AABBCC"
285 | CD7409B51FDE80807E2E1532B7432A00
286 | ```
287 |
288 | ### `algorithm` (alias `a`)
289 |
290 | Supported values are:
291 |
292 | - `MD5` (not part of the Web Crypto API but supported by Cloudflare Workers)
293 | - `SHA-1`
294 | - `SHA-256`
295 | - `SHA-384`
296 | - `SHA-512`
297 |
298 | ### `query` (alias `q`)
299 |
300 | The string you want to get the hash of.
301 |
302 | ### `hex` (alias `h`)
303 |
304 | The hexadecimal byte array you want to get the hash of. An optional "0x" prefix
305 | may be given, the prefix is ignored.
306 |
307 | If both `query` and `hex` are provided, `query` will be used.
308 |
--------------------------------------------------------------------------------
/archive/index.js:
--------------------------------------------------------------------------------
1 | export default {
2 | async fetch(request) {
3 | const url = new URL(request.url);
4 | const queryString = decodeURIComponent(url.search.substring(1));
5 |
6 | return Response.redirect(`https://archive.ph/${queryString}`);
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/archive/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "archive",
3 | "version": "0.3.0",
4 | "description": "Web utility that automatically sends a webpage to archive.ph.",
5 | "license": "ISC",
6 | "author": "Ardis Lu",
7 | "private": true,
8 | "scripts": {
9 | "dev": "wrangler dev",
10 | "deploy": "wrangler deploy"
11 | },
12 | "repository": {
13 | "type": "git",
14 | "url": "https://github.com/ardislu/cloudflare-workers.git"
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/archive/wrangler.toml.example:
--------------------------------------------------------------------------------
1 | name = 'archive'
2 | main = 'index.js'
3 | compatibility_date = '2025-05-23'
4 | route = { pattern = 'archive.example.com', custom_domain = true }
5 |
--------------------------------------------------------------------------------
/buttcoin/index.js:
--------------------------------------------------------------------------------
1 | import { decode } from 'html-entities';
2 | import { SetBase, UpdateLink } from '../proxy';
3 |
4 | class ReplaceBitcoin {
5 | #buffer = '';
6 |
7 | text(text) {
8 | this.#buffer += text.text;
9 |
10 | if (text.lastInTextNode) {
11 | const buttText = this.#buffer
12 | .replaceAll('bitcoin', 'buttcoin')
13 | .replaceAll('Bitcoin', 'Buttcoin')
14 | .replaceAll('BITCOIN', 'BUTTCOIN')
15 | .replaceAll(/bitcoin/gi, 'buttcoin'); // Any other mixed case just become buttcoin
16 | text.replace(decode(buttText));
17 | this.#buffer = '';
18 | }
19 | else {
20 | text.remove();
21 | }
22 | }
23 | }
24 |
25 | export default {
26 | async fetch(request) {
27 | const url = /^http(s)?:\/\//i.test(request.url) ? new URL(request.url) : new URL(`https://${request.url}`);
28 |
29 | const queryString = decodeURIComponent(url.search.substring(1));
30 | let remoteUrl;
31 | try {
32 | remoteUrl = new URL(queryString);
33 | }
34 | catch {
35 | return new Response('Invalid URL provided in query string.', { status: 400 });
36 | }
37 |
38 | const response = await fetch(remoteUrl);
39 |
40 | return new HTMLRewriter()
41 | .on('head', new SetBase(remoteUrl.origin))
42 | .on('link, script', new UpdateLink())
43 | .on('html', new ReplaceBitcoin())
44 | .transform(response);
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/buttcoin/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "buttcoin",
3 | "version": "0.3.0",
4 | "description": "Reverse proxy which replaces all instances of the word \"bitcoin\" to \"buttcoin\".",
5 | "license": "ISC",
6 | "author": "Ardis Lu",
7 | "private": true,
8 | "scripts": {
9 | "dev": "wrangler dev",
10 | "deploy": "wrangler deploy"
11 | },
12 | "dependencies": {
13 | "html-entities": "^2.5.2"
14 | },
15 | "repository": {
16 | "type": "git",
17 | "url": "https://github.com/ardislu/cloudflare-workers.git"
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/buttcoin/wrangler.toml.example:
--------------------------------------------------------------------------------
1 | name = 'buttcoin'
2 | main = 'index.js'
3 | compatibility_date = '2025-05-23'
4 | route = { pattern = 'buttcoin.example.com', custom_domain = true }
5 |
--------------------------------------------------------------------------------
/cors/index.js:
--------------------------------------------------------------------------------
1 | export default {
2 | async fetch(request) {
3 | const url = /^http(s)?:\/\//i.test(request.url) ? new URL(request.url) : new URL(`https://${request.url}`);
4 | const queryString = decodeURIComponent(url.search.substring(1));
5 |
6 | let response;
7 | if (request.method === 'OPTIONS') {
8 | response = new Response();
9 | response.headers.set('Access-Control-Allow-Origin', request.headers.get('Origin'));
10 | response.headers.set('Access-Control-Allow-Methods', request.headers.get('Access-Control-Request-Method'));
11 | response.headers.set('Access-Control-Allow-Headers', request.headers.get('Access-Control-Request-Headers'));
12 | response.headers.set('Access-Control-Allow-Credentials', 'true');
13 | response.headers.set('Access-Control-Max-Age', '86400');
14 | response.headers.append('Vary', 'Origin');
15 | }
16 | else {
17 | response = await fetch(queryString);
18 | response = new Response(response.body, response);
19 | response.headers.set('Access-Control-Allow-Origin', request.headers.get('Origin'));
20 | response.headers.set('Access-Control-Allow-Credentials', 'true');
21 | response.headers.set('Access-Control-Expose-Headers', '*, Authorization');
22 | response.headers.append('Vary', 'Origin');
23 | }
24 |
25 | return response;
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/cors/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "cors",
3 | "version": "0.3.0",
4 | "description": "This reverse proxy injects permissive CORS response headers to a response.",
5 | "license": "ISC",
6 | "author": "Ardis Lu",
7 | "private": true,
8 | "scripts": {
9 | "dev": "wrangler dev",
10 | "deploy": "wrangler deploy"
11 | },
12 | "repository": {
13 | "type": "git",
14 | "url": "https://github.com/ardislu/cloudflare-workers.git"
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/cors/wrangler.toml.example:
--------------------------------------------------------------------------------
1 | name = 'cors'
2 | main = 'index.js'
3 | compatibility_date = '2025-05-23'
4 | route = { pattern = 'cors.example.com', custom_domain = true }
5 |
--------------------------------------------------------------------------------
/eruda/index.js:
--------------------------------------------------------------------------------
1 | import { SetBase, UpdateLink } from '../proxy';
2 |
3 | class InjectEruda {
4 | element(element) {
5 | element.prepend('', { html: true });
6 | }
7 | }
8 |
9 | export default {
10 | async fetch(request) {
11 | const url = /^http(s)?:\/\//i.test(request.url) ? new URL(request.url) : new URL(`https://${request.url}`);
12 | const remoteUrl = new URL(decodeURIComponent(url.search.substring(1)));
13 |
14 | const response = await fetch(remoteUrl);
15 | return new HTMLRewriter()
16 | .on('head', new SetBase(remoteUrl.origin))
17 | .on('link, script', new UpdateLink())
18 | .on('body', new InjectEruda())
19 | .transform(response);
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/eruda/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "eruda",
3 | "version": "0.3.0",
4 | "description": "Reverse proxy which injects eruda into a webpage.",
5 | "license": "ISC",
6 | "author": "Ardis Lu",
7 | "private": true,
8 | "scripts": {
9 | "dev": "wrangler dev",
10 | "deploy": "wrangler deploy"
11 | },
12 | "repository": {
13 | "type": "git",
14 | "url": "https://github.com/ardislu/cloudflare-workers.git"
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/eruda/wrangler.toml.example:
--------------------------------------------------------------------------------
1 | name = 'eruda'
2 | main = 'index.js'
3 | compatibility_date = '2025-05-23'
4 | route = { pattern = 'eruda.example.com', custom_domain = true }
5 |
--------------------------------------------------------------------------------
/hash/index.js:
--------------------------------------------------------------------------------
1 | export default {
2 | async fetch(request) {
3 | const url = new URL(request.url);
4 | let algorithm;
5 | let query;
6 | let hex;
7 |
8 | // Parse URLSearchParams
9 | for (const [key, value] of url.searchParams) {
10 | const normalizedKey = key.toLowerCase();
11 | if ((normalizedKey === 'a' || normalizedKey === 'algorithm')) {
12 | if (/^SHA-?(1|256|384|512)$/i.test(value)) {
13 | algorithm = value.includes('-') ? value : `SHA-${value.slice(3)}`; // Insert a '-' character if it's not present; crypto.subtle.digest() requires it.
14 | }
15 | else if (value.toUpperCase() === 'MD5') {
16 | algorithm = 'MD5';
17 | }
18 | }
19 | else if ((normalizedKey === 'q' || normalizedKey === 'query') && value) { // Intentionally fail for falsy values because a null or empty string is also invalid
20 | query = value;
21 | }
22 | else if ((normalizedKey === 'h' || normalizedKey === 'hex') && value) {
23 | hex = value;
24 | }
25 | }
26 |
27 | // Handling bad params
28 | if (algorithm === undefined) {
29 | return new Response('Invalid algorithm provided. Provide one of the following values for the parameter "a" or "algorithm": MD5, SHA-1, SHA-256, SHA-384, or SHA-512.', { status: 400 });
30 | }
31 | if (query === undefined && hex === undefined) {
32 | return new Response('No input provided. Provide a string value for the parameter "q" or "query", or a hex value for the parameter "h" or "hex".', { status: 400 });
33 | }
34 | if (hex !== undefined) {
35 | if (hex.length % 2 === 1 || !/^(0x)?[a-fA-F0-9]+$/.test(hex)) {
36 | return new Response('Invalid hexadecimal input provided.', { status: 400 });
37 | }
38 | }
39 |
40 | let inputArray;
41 | if (query) {
42 | inputArray = new TextEncoder().encode(query);
43 | }
44 | else {
45 | inputArray = Uint8Array.from(hex.replace('0x', '').match(/.{2}/g), v => parseInt(v, 16));
46 | }
47 | const digest = await crypto.subtle.digest(algorithm, inputArray);
48 | const outputArray = [...new Uint8Array(digest)]; // Need to spread typed array into a non-typed array to allow .map() to output strings
49 | const hash = outputArray.map(v => v.toString(16).padStart(2, '0')).join('').toUpperCase();
50 |
51 | return new Response(hash);
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/hash/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "hash",
3 | "version": "0.3.0",
4 | "description": "Return the hash of the input query.",
5 | "license": "ISC",
6 | "author": "Ardis Lu",
7 | "private": true,
8 | "scripts": {
9 | "dev": "wrangler dev",
10 | "deploy": "wrangler deploy"
11 | },
12 | "repository": {
13 | "type": "git",
14 | "url": "https://github.com/ardislu/cloudflare-workers.git"
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/hash/wrangler.toml.example:
--------------------------------------------------------------------------------
1 | name = 'hash'
2 | main = 'index.js'
3 | compatibility_date = '2025-05-23'
4 | route = { pattern = 'hash.example.com', custom_domain = true }
5 |
--------------------------------------------------------------------------------
/instagram/index.js:
--------------------------------------------------------------------------------
1 | export default {
2 | async fetch(request) {
3 | const url = new URL(request.url);
4 | const queryString = decodeURIComponent(url.search.substring(1));
5 |
6 | const segments = queryString.split('/');
7 | const id = segments.pop() || segments.pop(); // If there's a trailing '/' character, need to pop() twice
8 |
9 | const responseBody = `
10 |
11 |
12 |
13 | `;
14 |
15 | return new Response(responseBody, {
16 | headers: {
17 | "content-type": "text/html;charset=UTF-8",
18 | },
19 | });
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/instagram/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "instagram",
3 | "version": "0.3.0",
4 | "description": "This reverse proxy embeds Instagram posts so they can be viewed without logging in.",
5 | "license": "ISC",
6 | "author": "Ardis Lu",
7 | "private": true,
8 | "scripts": {
9 | "dev": "wrangler dev",
10 | "deploy": "wrangler deploy"
11 | },
12 | "repository": {
13 | "type": "git",
14 | "url": "https://github.com/ardislu/cloudflare-workers.git"
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/instagram/wrangler.toml.example:
--------------------------------------------------------------------------------
1 | name = 'instagram'
2 | main = 'index.js'
3 | compatibility_date = '2025-05-23'
4 | route = { pattern = 'instagram.example.com', custom_domain = true }
5 |
--------------------------------------------------------------------------------
/ip/index.js:
--------------------------------------------------------------------------------
1 | export default {
2 | async fetch(request) {
3 | return new Response(request.headers.get('CF-Connecting-IP'));
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/ip/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ip",
3 | "version": "0.3.0",
4 | "description": "Cloudflare Worker which returns the requester's IP address.",
5 | "license": "ISC",
6 | "author": "Ardis Lu",
7 | "private": true,
8 | "scripts": {
9 | "dev": "wrangler dev",
10 | "deploy": "wrangler deploy"
11 | },
12 | "repository": {
13 | "type": "git",
14 | "url": "https://github.com/ardislu/cloudflare-workers.git"
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/ip/wrangler.toml.example:
--------------------------------------------------------------------------------
1 | name = 'ip'
2 | main = 'index.js'
3 | compatibility_date = '2025-05-23'
4 | route = { pattern = 'ip.example.com', custom_domain = true }
5 |
--------------------------------------------------------------------------------
/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "cloudflare-workers",
3 | "version": "0.3.0",
4 | "lockfileVersion": 3,
5 | "requires": true,
6 | "packages": {
7 | "": {
8 | "name": "cloudflare-workers",
9 | "version": "0.3.0",
10 | "license": "ISC",
11 | "workspaces": [
12 | "proxy",
13 | "instagram",
14 | "cors",
15 | "pwned",
16 | "qr",
17 | "ip",
18 | "uuid",
19 | "hash",
20 | "style",
21 | "unroll",
22 | "buttcoin",
23 | "archive",
24 | "eruda"
25 | ],
26 | "devDependencies": {
27 | "wrangler": "^4.18.0"
28 | }
29 | },
30 | "archive": {
31 | "version": "0.3.0",
32 | "license": "ISC"
33 | },
34 | "buttcoin": {
35 | "version": "0.3.0",
36 | "license": "ISC",
37 | "dependencies": {
38 | "html-entities": "^2.5.2"
39 | }
40 | },
41 | "cors": {
42 | "version": "0.3.0",
43 | "license": "ISC"
44 | },
45 | "eruda": {
46 | "version": "0.3.0",
47 | "license": "ISC"
48 | },
49 | "hash": {
50 | "version": "0.3.0",
51 | "license": "ISC"
52 | },
53 | "instagram": {
54 | "version": "0.3.0",
55 | "license": "ISC"
56 | },
57 | "ip": {
58 | "version": "0.3.0",
59 | "license": "ISC"
60 | },
61 | "node_modules/@cloudflare/kv-asset-handler": {
62 | "version": "0.4.0",
63 | "resolved": "https://registry.npmjs.org/@cloudflare/kv-asset-handler/-/kv-asset-handler-0.4.0.tgz",
64 | "integrity": "sha512-+tv3z+SPp+gqTIcImN9o0hqE9xyfQjI1XD9pL6NuKjua9B1y7mNYv0S9cP+QEbA4ppVgGZEmKOvHX5G5Ei1CVA==",
65 | "dev": true,
66 | "license": "MIT OR Apache-2.0",
67 | "dependencies": {
68 | "mime": "^3.0.0"
69 | },
70 | "engines": {
71 | "node": ">=18.0.0"
72 | }
73 | },
74 | "node_modules/@cloudflare/unenv-preset": {
75 | "version": "2.3.2",
76 | "resolved": "https://registry.npmjs.org/@cloudflare/unenv-preset/-/unenv-preset-2.3.2.tgz",
77 | "integrity": "sha512-MtUgNl+QkQyhQvv5bbWP+BpBC1N0me4CHHuP2H4ktmOMKdB/6kkz/lo+zqiA4mEazb4y+1cwyNjVrQ2DWeE4mg==",
78 | "dev": true,
79 | "license": "MIT OR Apache-2.0",
80 | "peerDependencies": {
81 | "unenv": "2.0.0-rc.17",
82 | "workerd": "^1.20250508.0"
83 | },
84 | "peerDependenciesMeta": {
85 | "workerd": {
86 | "optional": true
87 | }
88 | }
89 | },
90 | "node_modules/@cloudflare/workerd-darwin-64": {
91 | "version": "1.20250525.0",
92 | "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-64/-/workerd-darwin-64-1.20250525.0.tgz",
93 | "integrity": "sha512-L5l+7sSJJT2+riR5rS3Q3PKNNySPjWfRIeaNGMVRi1dPO6QPi4lwuxfRUFNoeUdilZJUVPfSZvTtj9RedsKznQ==",
94 | "cpu": [
95 | "x64"
96 | ],
97 | "dev": true,
98 | "license": "Apache-2.0",
99 | "optional": true,
100 | "os": [
101 | "darwin"
102 | ],
103 | "engines": {
104 | "node": ">=16"
105 | }
106 | },
107 | "node_modules/@cloudflare/workerd-darwin-arm64": {
108 | "version": "1.20250525.0",
109 | "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-arm64/-/workerd-darwin-arm64-1.20250525.0.tgz",
110 | "integrity": "sha512-Y3IbIdrF/vJWh/WBvshwcSyUh175VAiLRW7963S1dXChrZ1N5wuKGQm9xY69cIGVtitpMJWWW3jLq7J/Xxwm0Q==",
111 | "cpu": [
112 | "arm64"
113 | ],
114 | "dev": true,
115 | "license": "Apache-2.0",
116 | "optional": true,
117 | "os": [
118 | "darwin"
119 | ],
120 | "engines": {
121 | "node": ">=16"
122 | }
123 | },
124 | "node_modules/@cloudflare/workerd-linux-64": {
125 | "version": "1.20250525.0",
126 | "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-64/-/workerd-linux-64-1.20250525.0.tgz",
127 | "integrity": "sha512-KSyQPAby+c6cpENoO0ayCQlY6QIh28l/+QID7VC1SLXfiNHy+hPNsH1vVBTST6CilHVAQSsy9tCZ9O9XECB8yg==",
128 | "cpu": [
129 | "x64"
130 | ],
131 | "dev": true,
132 | "license": "Apache-2.0",
133 | "optional": true,
134 | "os": [
135 | "linux"
136 | ],
137 | "engines": {
138 | "node": ">=16"
139 | }
140 | },
141 | "node_modules/@cloudflare/workerd-linux-arm64": {
142 | "version": "1.20250525.0",
143 | "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-arm64/-/workerd-linux-arm64-1.20250525.0.tgz",
144 | "integrity": "sha512-Nt0FUxS2kQhJUea4hMCNPaetkrAFDhPnNX/ntwcqVlGgnGt75iaAhupWJbU0GB+gIWlKeuClUUnDZqKbicoKyg==",
145 | "cpu": [
146 | "arm64"
147 | ],
148 | "dev": true,
149 | "license": "Apache-2.0",
150 | "optional": true,
151 | "os": [
152 | "linux"
153 | ],
154 | "engines": {
155 | "node": ">=16"
156 | }
157 | },
158 | "node_modules/@cloudflare/workerd-windows-64": {
159 | "version": "1.20250525.0",
160 | "resolved": "https://registry.npmjs.org/@cloudflare/workerd-windows-64/-/workerd-windows-64-1.20250525.0.tgz",
161 | "integrity": "sha512-mwTj+9f3uIa4NEXR1cOa82PjLa6dbrb3J+KCVJFYIaq7e63VxEzOchCXS4tublT2pmOhmFqkgBMXrxozxNkR2Q==",
162 | "cpu": [
163 | "x64"
164 | ],
165 | "dev": true,
166 | "license": "Apache-2.0",
167 | "optional": true,
168 | "os": [
169 | "win32"
170 | ],
171 | "engines": {
172 | "node": ">=16"
173 | }
174 | },
175 | "node_modules/@cspotcode/source-map-support": {
176 | "version": "0.8.1",
177 | "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz",
178 | "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==",
179 | "dev": true,
180 | "license": "MIT",
181 | "dependencies": {
182 | "@jridgewell/trace-mapping": "0.3.9"
183 | },
184 | "engines": {
185 | "node": ">=12"
186 | }
187 | },
188 | "node_modules/@emnapi/runtime": {
189 | "version": "1.4.3",
190 | "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.4.3.tgz",
191 | "integrity": "sha512-pBPWdu6MLKROBX05wSNKcNb++m5Er+KQ9QkB+WVM+pW2Kx9hoSrVTnu3BdkI5eBLZoKu/J6mW/B6i6bJB2ytXQ==",
192 | "dev": true,
193 | "license": "MIT",
194 | "optional": true,
195 | "dependencies": {
196 | "tslib": "^2.4.0"
197 | }
198 | },
199 | "node_modules/@esbuild/aix-ppc64": {
200 | "version": "0.25.4",
201 | "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.4.tgz",
202 | "integrity": "sha512-1VCICWypeQKhVbE9oW/sJaAmjLxhVqacdkvPLEjwlttjfwENRSClS8EjBz0KzRyFSCPDIkuXW34Je/vk7zdB7Q==",
203 | "cpu": [
204 | "ppc64"
205 | ],
206 | "dev": true,
207 | "license": "MIT",
208 | "optional": true,
209 | "os": [
210 | "aix"
211 | ],
212 | "engines": {
213 | "node": ">=18"
214 | }
215 | },
216 | "node_modules/@esbuild/android-arm": {
217 | "version": "0.25.4",
218 | "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.4.tgz",
219 | "integrity": "sha512-QNdQEps7DfFwE3hXiU4BZeOV68HHzYwGd0Nthhd3uCkkEKK7/R6MTgM0P7H7FAs5pU/DIWsviMmEGxEoxIZ+ZQ==",
220 | "cpu": [
221 | "arm"
222 | ],
223 | "dev": true,
224 | "license": "MIT",
225 | "optional": true,
226 | "os": [
227 | "android"
228 | ],
229 | "engines": {
230 | "node": ">=18"
231 | }
232 | },
233 | "node_modules/@esbuild/android-arm64": {
234 | "version": "0.25.4",
235 | "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.4.tgz",
236 | "integrity": "sha512-bBy69pgfhMGtCnwpC/x5QhfxAz/cBgQ9enbtwjf6V9lnPI/hMyT9iWpR1arm0l3kttTr4L0KSLpKmLp/ilKS9A==",
237 | "cpu": [
238 | "arm64"
239 | ],
240 | "dev": true,
241 | "license": "MIT",
242 | "optional": true,
243 | "os": [
244 | "android"
245 | ],
246 | "engines": {
247 | "node": ">=18"
248 | }
249 | },
250 | "node_modules/@esbuild/android-x64": {
251 | "version": "0.25.4",
252 | "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.4.tgz",
253 | "integrity": "sha512-TVhdVtQIFuVpIIR282btcGC2oGQoSfZfmBdTip2anCaVYcqWlZXGcdcKIUklfX2wj0JklNYgz39OBqh2cqXvcQ==",
254 | "cpu": [
255 | "x64"
256 | ],
257 | "dev": true,
258 | "license": "MIT",
259 | "optional": true,
260 | "os": [
261 | "android"
262 | ],
263 | "engines": {
264 | "node": ">=18"
265 | }
266 | },
267 | "node_modules/@esbuild/darwin-arm64": {
268 | "version": "0.25.4",
269 | "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.4.tgz",
270 | "integrity": "sha512-Y1giCfM4nlHDWEfSckMzeWNdQS31BQGs9/rouw6Ub91tkK79aIMTH3q9xHvzH8d0wDru5Ci0kWB8b3up/nl16g==",
271 | "cpu": [
272 | "arm64"
273 | ],
274 | "dev": true,
275 | "license": "MIT",
276 | "optional": true,
277 | "os": [
278 | "darwin"
279 | ],
280 | "engines": {
281 | "node": ">=18"
282 | }
283 | },
284 | "node_modules/@esbuild/darwin-x64": {
285 | "version": "0.25.4",
286 | "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.4.tgz",
287 | "integrity": "sha512-CJsry8ZGM5VFVeyUYB3cdKpd/H69PYez4eJh1W/t38vzutdjEjtP7hB6eLKBoOdxcAlCtEYHzQ/PJ/oU9I4u0A==",
288 | "cpu": [
289 | "x64"
290 | ],
291 | "dev": true,
292 | "license": "MIT",
293 | "optional": true,
294 | "os": [
295 | "darwin"
296 | ],
297 | "engines": {
298 | "node": ">=18"
299 | }
300 | },
301 | "node_modules/@esbuild/freebsd-arm64": {
302 | "version": "0.25.4",
303 | "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.4.tgz",
304 | "integrity": "sha512-yYq+39NlTRzU2XmoPW4l5Ifpl9fqSk0nAJYM/V/WUGPEFfek1epLHJIkTQM6bBs1swApjO5nWgvr843g6TjxuQ==",
305 | "cpu": [
306 | "arm64"
307 | ],
308 | "dev": true,
309 | "license": "MIT",
310 | "optional": true,
311 | "os": [
312 | "freebsd"
313 | ],
314 | "engines": {
315 | "node": ">=18"
316 | }
317 | },
318 | "node_modules/@esbuild/freebsd-x64": {
319 | "version": "0.25.4",
320 | "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.4.tgz",
321 | "integrity": "sha512-0FgvOJ6UUMflsHSPLzdfDnnBBVoCDtBTVyn/MrWloUNvq/5SFmh13l3dvgRPkDihRxb77Y17MbqbCAa2strMQQ==",
322 | "cpu": [
323 | "x64"
324 | ],
325 | "dev": true,
326 | "license": "MIT",
327 | "optional": true,
328 | "os": [
329 | "freebsd"
330 | ],
331 | "engines": {
332 | "node": ">=18"
333 | }
334 | },
335 | "node_modules/@esbuild/linux-arm": {
336 | "version": "0.25.4",
337 | "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.4.tgz",
338 | "integrity": "sha512-kro4c0P85GMfFYqW4TWOpvmF8rFShbWGnrLqlzp4X1TNWjRY3JMYUfDCtOxPKOIY8B0WC8HN51hGP4I4hz4AaQ==",
339 | "cpu": [
340 | "arm"
341 | ],
342 | "dev": true,
343 | "license": "MIT",
344 | "optional": true,
345 | "os": [
346 | "linux"
347 | ],
348 | "engines": {
349 | "node": ">=18"
350 | }
351 | },
352 | "node_modules/@esbuild/linux-arm64": {
353 | "version": "0.25.4",
354 | "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.4.tgz",
355 | "integrity": "sha512-+89UsQTfXdmjIvZS6nUnOOLoXnkUTB9hR5QAeLrQdzOSWZvNSAXAtcRDHWtqAUtAmv7ZM1WPOOeSxDzzzMogiQ==",
356 | "cpu": [
357 | "arm64"
358 | ],
359 | "dev": true,
360 | "license": "MIT",
361 | "optional": true,
362 | "os": [
363 | "linux"
364 | ],
365 | "engines": {
366 | "node": ">=18"
367 | }
368 | },
369 | "node_modules/@esbuild/linux-ia32": {
370 | "version": "0.25.4",
371 | "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.4.tgz",
372 | "integrity": "sha512-yTEjoapy8UP3rv8dB0ip3AfMpRbyhSN3+hY8mo/i4QXFeDxmiYbEKp3ZRjBKcOP862Ua4b1PDfwlvbuwY7hIGQ==",
373 | "cpu": [
374 | "ia32"
375 | ],
376 | "dev": true,
377 | "license": "MIT",
378 | "optional": true,
379 | "os": [
380 | "linux"
381 | ],
382 | "engines": {
383 | "node": ">=18"
384 | }
385 | },
386 | "node_modules/@esbuild/linux-loong64": {
387 | "version": "0.25.4",
388 | "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.4.tgz",
389 | "integrity": "sha512-NeqqYkrcGzFwi6CGRGNMOjWGGSYOpqwCjS9fvaUlX5s3zwOtn1qwg1s2iE2svBe4Q/YOG1q6875lcAoQK/F4VA==",
390 | "cpu": [
391 | "loong64"
392 | ],
393 | "dev": true,
394 | "license": "MIT",
395 | "optional": true,
396 | "os": [
397 | "linux"
398 | ],
399 | "engines": {
400 | "node": ">=18"
401 | }
402 | },
403 | "node_modules/@esbuild/linux-mips64el": {
404 | "version": "0.25.4",
405 | "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.4.tgz",
406 | "integrity": "sha512-IcvTlF9dtLrfL/M8WgNI/qJYBENP3ekgsHbYUIzEzq5XJzzVEV/fXY9WFPfEEXmu3ck2qJP8LG/p3Q8f7Zc2Xg==",
407 | "cpu": [
408 | "mips64el"
409 | ],
410 | "dev": true,
411 | "license": "MIT",
412 | "optional": true,
413 | "os": [
414 | "linux"
415 | ],
416 | "engines": {
417 | "node": ">=18"
418 | }
419 | },
420 | "node_modules/@esbuild/linux-ppc64": {
421 | "version": "0.25.4",
422 | "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.4.tgz",
423 | "integrity": "sha512-HOy0aLTJTVtoTeGZh4HSXaO6M95qu4k5lJcH4gxv56iaycfz1S8GO/5Jh6X4Y1YiI0h7cRyLi+HixMR+88swag==",
424 | "cpu": [
425 | "ppc64"
426 | ],
427 | "dev": true,
428 | "license": "MIT",
429 | "optional": true,
430 | "os": [
431 | "linux"
432 | ],
433 | "engines": {
434 | "node": ">=18"
435 | }
436 | },
437 | "node_modules/@esbuild/linux-riscv64": {
438 | "version": "0.25.4",
439 | "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.4.tgz",
440 | "integrity": "sha512-i8JUDAufpz9jOzo4yIShCTcXzS07vEgWzyX3NH2G7LEFVgrLEhjwL3ajFE4fZI3I4ZgiM7JH3GQ7ReObROvSUA==",
441 | "cpu": [
442 | "riscv64"
443 | ],
444 | "dev": true,
445 | "license": "MIT",
446 | "optional": true,
447 | "os": [
448 | "linux"
449 | ],
450 | "engines": {
451 | "node": ">=18"
452 | }
453 | },
454 | "node_modules/@esbuild/linux-s390x": {
455 | "version": "0.25.4",
456 | "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.4.tgz",
457 | "integrity": "sha512-jFnu+6UbLlzIjPQpWCNh5QtrcNfMLjgIavnwPQAfoGx4q17ocOU9MsQ2QVvFxwQoWpZT8DvTLooTvmOQXkO51g==",
458 | "cpu": [
459 | "s390x"
460 | ],
461 | "dev": true,
462 | "license": "MIT",
463 | "optional": true,
464 | "os": [
465 | "linux"
466 | ],
467 | "engines": {
468 | "node": ">=18"
469 | }
470 | },
471 | "node_modules/@esbuild/linux-x64": {
472 | "version": "0.25.4",
473 | "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.4.tgz",
474 | "integrity": "sha512-6e0cvXwzOnVWJHq+mskP8DNSrKBr1bULBvnFLpc1KY+d+irZSgZ02TGse5FsafKS5jg2e4pbvK6TPXaF/A6+CA==",
475 | "cpu": [
476 | "x64"
477 | ],
478 | "dev": true,
479 | "license": "MIT",
480 | "optional": true,
481 | "os": [
482 | "linux"
483 | ],
484 | "engines": {
485 | "node": ">=18"
486 | }
487 | },
488 | "node_modules/@esbuild/netbsd-arm64": {
489 | "version": "0.25.4",
490 | "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.4.tgz",
491 | "integrity": "sha512-vUnkBYxZW4hL/ie91hSqaSNjulOnYXE1VSLusnvHg2u3jewJBz3YzB9+oCw8DABeVqZGg94t9tyZFoHma8gWZQ==",
492 | "cpu": [
493 | "arm64"
494 | ],
495 | "dev": true,
496 | "license": "MIT",
497 | "optional": true,
498 | "os": [
499 | "netbsd"
500 | ],
501 | "engines": {
502 | "node": ">=18"
503 | }
504 | },
505 | "node_modules/@esbuild/netbsd-x64": {
506 | "version": "0.25.4",
507 | "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.4.tgz",
508 | "integrity": "sha512-XAg8pIQn5CzhOB8odIcAm42QsOfa98SBeKUdo4xa8OvX8LbMZqEtgeWE9P/Wxt7MlG2QqvjGths+nq48TrUiKw==",
509 | "cpu": [
510 | "x64"
511 | ],
512 | "dev": true,
513 | "license": "MIT",
514 | "optional": true,
515 | "os": [
516 | "netbsd"
517 | ],
518 | "engines": {
519 | "node": ">=18"
520 | }
521 | },
522 | "node_modules/@esbuild/openbsd-arm64": {
523 | "version": "0.25.4",
524 | "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.4.tgz",
525 | "integrity": "sha512-Ct2WcFEANlFDtp1nVAXSNBPDxyU+j7+tId//iHXU2f/lN5AmO4zLyhDcpR5Cz1r08mVxzt3Jpyt4PmXQ1O6+7A==",
526 | "cpu": [
527 | "arm64"
528 | ],
529 | "dev": true,
530 | "license": "MIT",
531 | "optional": true,
532 | "os": [
533 | "openbsd"
534 | ],
535 | "engines": {
536 | "node": ">=18"
537 | }
538 | },
539 | "node_modules/@esbuild/openbsd-x64": {
540 | "version": "0.25.4",
541 | "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.4.tgz",
542 | "integrity": "sha512-xAGGhyOQ9Otm1Xu8NT1ifGLnA6M3sJxZ6ixylb+vIUVzvvd6GOALpwQrYrtlPouMqd/vSbgehz6HaVk4+7Afhw==",
543 | "cpu": [
544 | "x64"
545 | ],
546 | "dev": true,
547 | "license": "MIT",
548 | "optional": true,
549 | "os": [
550 | "openbsd"
551 | ],
552 | "engines": {
553 | "node": ">=18"
554 | }
555 | },
556 | "node_modules/@esbuild/sunos-x64": {
557 | "version": "0.25.4",
558 | "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.4.tgz",
559 | "integrity": "sha512-Mw+tzy4pp6wZEK0+Lwr76pWLjrtjmJyUB23tHKqEDP74R3q95luY/bXqXZeYl4NYlvwOqoRKlInQialgCKy67Q==",
560 | "cpu": [
561 | "x64"
562 | ],
563 | "dev": true,
564 | "license": "MIT",
565 | "optional": true,
566 | "os": [
567 | "sunos"
568 | ],
569 | "engines": {
570 | "node": ">=18"
571 | }
572 | },
573 | "node_modules/@esbuild/win32-arm64": {
574 | "version": "0.25.4",
575 | "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.4.tgz",
576 | "integrity": "sha512-AVUP428VQTSddguz9dO9ngb+E5aScyg7nOeJDrF1HPYu555gmza3bDGMPhmVXL8svDSoqPCsCPjb265yG/kLKQ==",
577 | "cpu": [
578 | "arm64"
579 | ],
580 | "dev": true,
581 | "license": "MIT",
582 | "optional": true,
583 | "os": [
584 | "win32"
585 | ],
586 | "engines": {
587 | "node": ">=18"
588 | }
589 | },
590 | "node_modules/@esbuild/win32-ia32": {
591 | "version": "0.25.4",
592 | "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.4.tgz",
593 | "integrity": "sha512-i1sW+1i+oWvQzSgfRcxxG2k4I9n3O9NRqy8U+uugaT2Dy7kLO9Y7wI72haOahxceMX8hZAzgGou1FhndRldxRg==",
594 | "cpu": [
595 | "ia32"
596 | ],
597 | "dev": true,
598 | "license": "MIT",
599 | "optional": true,
600 | "os": [
601 | "win32"
602 | ],
603 | "engines": {
604 | "node": ">=18"
605 | }
606 | },
607 | "node_modules/@esbuild/win32-x64": {
608 | "version": "0.25.4",
609 | "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.4.tgz",
610 | "integrity": "sha512-nOT2vZNw6hJ+z43oP1SPea/G/6AbN6X+bGNhNuq8NtRHy4wsMhw765IKLNmnjek7GvjWBYQ8Q5VBoYTFg9y1UQ==",
611 | "cpu": [
612 | "x64"
613 | ],
614 | "dev": true,
615 | "license": "MIT",
616 | "optional": true,
617 | "os": [
618 | "win32"
619 | ],
620 | "engines": {
621 | "node": ">=18"
622 | }
623 | },
624 | "node_modules/@fastify/busboy": {
625 | "version": "2.1.1",
626 | "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.1.tgz",
627 | "integrity": "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==",
628 | "dev": true,
629 | "license": "MIT",
630 | "engines": {
631 | "node": ">=14"
632 | }
633 | },
634 | "node_modules/@img/sharp-darwin-arm64": {
635 | "version": "0.33.5",
636 | "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.5.tgz",
637 | "integrity": "sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==",
638 | "cpu": [
639 | "arm64"
640 | ],
641 | "dev": true,
642 | "license": "Apache-2.0",
643 | "optional": true,
644 | "os": [
645 | "darwin"
646 | ],
647 | "engines": {
648 | "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
649 | },
650 | "funding": {
651 | "url": "https://opencollective.com/libvips"
652 | },
653 | "optionalDependencies": {
654 | "@img/sharp-libvips-darwin-arm64": "1.0.4"
655 | }
656 | },
657 | "node_modules/@img/sharp-darwin-x64": {
658 | "version": "0.33.5",
659 | "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.33.5.tgz",
660 | "integrity": "sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q==",
661 | "cpu": [
662 | "x64"
663 | ],
664 | "dev": true,
665 | "license": "Apache-2.0",
666 | "optional": true,
667 | "os": [
668 | "darwin"
669 | ],
670 | "engines": {
671 | "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
672 | },
673 | "funding": {
674 | "url": "https://opencollective.com/libvips"
675 | },
676 | "optionalDependencies": {
677 | "@img/sharp-libvips-darwin-x64": "1.0.4"
678 | }
679 | },
680 | "node_modules/@img/sharp-libvips-darwin-arm64": {
681 | "version": "1.0.4",
682 | "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.0.4.tgz",
683 | "integrity": "sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg==",
684 | "cpu": [
685 | "arm64"
686 | ],
687 | "dev": true,
688 | "license": "LGPL-3.0-or-later",
689 | "optional": true,
690 | "os": [
691 | "darwin"
692 | ],
693 | "funding": {
694 | "url": "https://opencollective.com/libvips"
695 | }
696 | },
697 | "node_modules/@img/sharp-libvips-darwin-x64": {
698 | "version": "1.0.4",
699 | "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.0.4.tgz",
700 | "integrity": "sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ==",
701 | "cpu": [
702 | "x64"
703 | ],
704 | "dev": true,
705 | "license": "LGPL-3.0-or-later",
706 | "optional": true,
707 | "os": [
708 | "darwin"
709 | ],
710 | "funding": {
711 | "url": "https://opencollective.com/libvips"
712 | }
713 | },
714 | "node_modules/@img/sharp-libvips-linux-arm": {
715 | "version": "1.0.5",
716 | "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.0.5.tgz",
717 | "integrity": "sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==",
718 | "cpu": [
719 | "arm"
720 | ],
721 | "dev": true,
722 | "license": "LGPL-3.0-or-later",
723 | "optional": true,
724 | "os": [
725 | "linux"
726 | ],
727 | "funding": {
728 | "url": "https://opencollective.com/libvips"
729 | }
730 | },
731 | "node_modules/@img/sharp-libvips-linux-arm64": {
732 | "version": "1.0.4",
733 | "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.0.4.tgz",
734 | "integrity": "sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==",
735 | "cpu": [
736 | "arm64"
737 | ],
738 | "dev": true,
739 | "license": "LGPL-3.0-or-later",
740 | "optional": true,
741 | "os": [
742 | "linux"
743 | ],
744 | "funding": {
745 | "url": "https://opencollective.com/libvips"
746 | }
747 | },
748 | "node_modules/@img/sharp-libvips-linux-s390x": {
749 | "version": "1.0.4",
750 | "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.0.4.tgz",
751 | "integrity": "sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==",
752 | "cpu": [
753 | "s390x"
754 | ],
755 | "dev": true,
756 | "license": "LGPL-3.0-or-later",
757 | "optional": true,
758 | "os": [
759 | "linux"
760 | ],
761 | "funding": {
762 | "url": "https://opencollective.com/libvips"
763 | }
764 | },
765 | "node_modules/@img/sharp-libvips-linux-x64": {
766 | "version": "1.0.4",
767 | "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.0.4.tgz",
768 | "integrity": "sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==",
769 | "cpu": [
770 | "x64"
771 | ],
772 | "dev": true,
773 | "license": "LGPL-3.0-or-later",
774 | "optional": true,
775 | "os": [
776 | "linux"
777 | ],
778 | "funding": {
779 | "url": "https://opencollective.com/libvips"
780 | }
781 | },
782 | "node_modules/@img/sharp-libvips-linuxmusl-arm64": {
783 | "version": "1.0.4",
784 | "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.0.4.tgz",
785 | "integrity": "sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==",
786 | "cpu": [
787 | "arm64"
788 | ],
789 | "dev": true,
790 | "license": "LGPL-3.0-or-later",
791 | "optional": true,
792 | "os": [
793 | "linux"
794 | ],
795 | "funding": {
796 | "url": "https://opencollective.com/libvips"
797 | }
798 | },
799 | "node_modules/@img/sharp-libvips-linuxmusl-x64": {
800 | "version": "1.0.4",
801 | "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.0.4.tgz",
802 | "integrity": "sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==",
803 | "cpu": [
804 | "x64"
805 | ],
806 | "dev": true,
807 | "license": "LGPL-3.0-or-later",
808 | "optional": true,
809 | "os": [
810 | "linux"
811 | ],
812 | "funding": {
813 | "url": "https://opencollective.com/libvips"
814 | }
815 | },
816 | "node_modules/@img/sharp-linux-arm": {
817 | "version": "0.33.5",
818 | "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.33.5.tgz",
819 | "integrity": "sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==",
820 | "cpu": [
821 | "arm"
822 | ],
823 | "dev": true,
824 | "license": "Apache-2.0",
825 | "optional": true,
826 | "os": [
827 | "linux"
828 | ],
829 | "engines": {
830 | "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
831 | },
832 | "funding": {
833 | "url": "https://opencollective.com/libvips"
834 | },
835 | "optionalDependencies": {
836 | "@img/sharp-libvips-linux-arm": "1.0.5"
837 | }
838 | },
839 | "node_modules/@img/sharp-linux-arm64": {
840 | "version": "0.33.5",
841 | "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.33.5.tgz",
842 | "integrity": "sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==",
843 | "cpu": [
844 | "arm64"
845 | ],
846 | "dev": true,
847 | "license": "Apache-2.0",
848 | "optional": true,
849 | "os": [
850 | "linux"
851 | ],
852 | "engines": {
853 | "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
854 | },
855 | "funding": {
856 | "url": "https://opencollective.com/libvips"
857 | },
858 | "optionalDependencies": {
859 | "@img/sharp-libvips-linux-arm64": "1.0.4"
860 | }
861 | },
862 | "node_modules/@img/sharp-linux-s390x": {
863 | "version": "0.33.5",
864 | "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.33.5.tgz",
865 | "integrity": "sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==",
866 | "cpu": [
867 | "s390x"
868 | ],
869 | "dev": true,
870 | "license": "Apache-2.0",
871 | "optional": true,
872 | "os": [
873 | "linux"
874 | ],
875 | "engines": {
876 | "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
877 | },
878 | "funding": {
879 | "url": "https://opencollective.com/libvips"
880 | },
881 | "optionalDependencies": {
882 | "@img/sharp-libvips-linux-s390x": "1.0.4"
883 | }
884 | },
885 | "node_modules/@img/sharp-linux-x64": {
886 | "version": "0.33.5",
887 | "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.33.5.tgz",
888 | "integrity": "sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==",
889 | "cpu": [
890 | "x64"
891 | ],
892 | "dev": true,
893 | "license": "Apache-2.0",
894 | "optional": true,
895 | "os": [
896 | "linux"
897 | ],
898 | "engines": {
899 | "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
900 | },
901 | "funding": {
902 | "url": "https://opencollective.com/libvips"
903 | },
904 | "optionalDependencies": {
905 | "@img/sharp-libvips-linux-x64": "1.0.4"
906 | }
907 | },
908 | "node_modules/@img/sharp-linuxmusl-arm64": {
909 | "version": "0.33.5",
910 | "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.33.5.tgz",
911 | "integrity": "sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==",
912 | "cpu": [
913 | "arm64"
914 | ],
915 | "dev": true,
916 | "license": "Apache-2.0",
917 | "optional": true,
918 | "os": [
919 | "linux"
920 | ],
921 | "engines": {
922 | "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
923 | },
924 | "funding": {
925 | "url": "https://opencollective.com/libvips"
926 | },
927 | "optionalDependencies": {
928 | "@img/sharp-libvips-linuxmusl-arm64": "1.0.4"
929 | }
930 | },
931 | "node_modules/@img/sharp-linuxmusl-x64": {
932 | "version": "0.33.5",
933 | "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.33.5.tgz",
934 | "integrity": "sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==",
935 | "cpu": [
936 | "x64"
937 | ],
938 | "dev": true,
939 | "license": "Apache-2.0",
940 | "optional": true,
941 | "os": [
942 | "linux"
943 | ],
944 | "engines": {
945 | "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
946 | },
947 | "funding": {
948 | "url": "https://opencollective.com/libvips"
949 | },
950 | "optionalDependencies": {
951 | "@img/sharp-libvips-linuxmusl-x64": "1.0.4"
952 | }
953 | },
954 | "node_modules/@img/sharp-wasm32": {
955 | "version": "0.33.5",
956 | "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.33.5.tgz",
957 | "integrity": "sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==",
958 | "cpu": [
959 | "wasm32"
960 | ],
961 | "dev": true,
962 | "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT",
963 | "optional": true,
964 | "dependencies": {
965 | "@emnapi/runtime": "^1.2.0"
966 | },
967 | "engines": {
968 | "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
969 | },
970 | "funding": {
971 | "url": "https://opencollective.com/libvips"
972 | }
973 | },
974 | "node_modules/@img/sharp-win32-ia32": {
975 | "version": "0.33.5",
976 | "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.33.5.tgz",
977 | "integrity": "sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ==",
978 | "cpu": [
979 | "ia32"
980 | ],
981 | "dev": true,
982 | "license": "Apache-2.0 AND LGPL-3.0-or-later",
983 | "optional": true,
984 | "os": [
985 | "win32"
986 | ],
987 | "engines": {
988 | "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
989 | },
990 | "funding": {
991 | "url": "https://opencollective.com/libvips"
992 | }
993 | },
994 | "node_modules/@img/sharp-win32-x64": {
995 | "version": "0.33.5",
996 | "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.33.5.tgz",
997 | "integrity": "sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg==",
998 | "cpu": [
999 | "x64"
1000 | ],
1001 | "dev": true,
1002 | "license": "Apache-2.0 AND LGPL-3.0-or-later",
1003 | "optional": true,
1004 | "os": [
1005 | "win32"
1006 | ],
1007 | "engines": {
1008 | "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
1009 | },
1010 | "funding": {
1011 | "url": "https://opencollective.com/libvips"
1012 | }
1013 | },
1014 | "node_modules/@jridgewell/resolve-uri": {
1015 | "version": "3.1.2",
1016 | "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
1017 | "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
1018 | "dev": true,
1019 | "license": "MIT",
1020 | "engines": {
1021 | "node": ">=6.0.0"
1022 | }
1023 | },
1024 | "node_modules/@jridgewell/sourcemap-codec": {
1025 | "version": "1.5.0",
1026 | "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz",
1027 | "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==",
1028 | "dev": true,
1029 | "license": "MIT"
1030 | },
1031 | "node_modules/@jridgewell/trace-mapping": {
1032 | "version": "0.3.9",
1033 | "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz",
1034 | "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==",
1035 | "dev": true,
1036 | "license": "MIT",
1037 | "dependencies": {
1038 | "@jridgewell/resolve-uri": "^3.0.3",
1039 | "@jridgewell/sourcemap-codec": "^1.4.10"
1040 | }
1041 | },
1042 | "node_modules/@paulmillr/qr": {
1043 | "version": "0.3.0",
1044 | "resolved": "https://registry.npmjs.org/@paulmillr/qr/-/qr-0.3.0.tgz",
1045 | "integrity": "sha512-3s/cagXuoXTA2gWSfSfJNanNgm2ifmqgoX8WLOs5//3qrIJ3WWHFjqFqCxvYGf46Afwv6PctT9eAOXLDGwp96Q==",
1046 | "license": "(MIT OR Apache-2.0)",
1047 | "funding": {
1048 | "url": "https://paulmillr.com/funding/"
1049 | }
1050 | },
1051 | "node_modules/acorn": {
1052 | "version": "8.14.0",
1053 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz",
1054 | "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==",
1055 | "dev": true,
1056 | "license": "MIT",
1057 | "bin": {
1058 | "acorn": "bin/acorn"
1059 | },
1060 | "engines": {
1061 | "node": ">=0.4.0"
1062 | }
1063 | },
1064 | "node_modules/acorn-walk": {
1065 | "version": "8.3.2",
1066 | "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.2.tgz",
1067 | "integrity": "sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==",
1068 | "dev": true,
1069 | "license": "MIT",
1070 | "engines": {
1071 | "node": ">=0.4.0"
1072 | }
1073 | },
1074 | "node_modules/archive": {
1075 | "resolved": "archive",
1076 | "link": true
1077 | },
1078 | "node_modules/as-table": {
1079 | "version": "1.0.55",
1080 | "resolved": "https://registry.npmjs.org/as-table/-/as-table-1.0.55.tgz",
1081 | "integrity": "sha512-xvsWESUJn0JN421Xb9MQw6AsMHRCUknCe0Wjlxvjud80mU4E6hQf1A6NzQKcYNmYw62MfzEtXc+badstZP3JpQ==",
1082 | "dev": true,
1083 | "license": "MIT",
1084 | "dependencies": {
1085 | "printable-characters": "^1.0.42"
1086 | }
1087 | },
1088 | "node_modules/blake3-wasm": {
1089 | "version": "2.1.5",
1090 | "resolved": "https://registry.npmjs.org/blake3-wasm/-/blake3-wasm-2.1.5.tgz",
1091 | "integrity": "sha512-F1+K8EbfOZE49dtoPtmxUQrpXaBIl3ICvasLh+nJta0xkz+9kF/7uet9fLnwKqhDrmj6g+6K3Tw9yQPUg2ka5g==",
1092 | "dev": true
1093 | },
1094 | "node_modules/buttcoin": {
1095 | "resolved": "buttcoin",
1096 | "link": true
1097 | },
1098 | "node_modules/color": {
1099 | "version": "4.2.3",
1100 | "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz",
1101 | "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==",
1102 | "dev": true,
1103 | "license": "MIT",
1104 | "dependencies": {
1105 | "color-convert": "^2.0.1",
1106 | "color-string": "^1.9.0"
1107 | },
1108 | "engines": {
1109 | "node": ">=12.5.0"
1110 | }
1111 | },
1112 | "node_modules/color-convert": {
1113 | "version": "2.0.1",
1114 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
1115 | "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
1116 | "dev": true,
1117 | "license": "MIT",
1118 | "dependencies": {
1119 | "color-name": "~1.1.4"
1120 | },
1121 | "engines": {
1122 | "node": ">=7.0.0"
1123 | }
1124 | },
1125 | "node_modules/color-name": {
1126 | "version": "1.1.4",
1127 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
1128 | "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
1129 | "dev": true,
1130 | "license": "MIT"
1131 | },
1132 | "node_modules/color-string": {
1133 | "version": "1.9.1",
1134 | "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz",
1135 | "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==",
1136 | "dev": true,
1137 | "license": "MIT",
1138 | "dependencies": {
1139 | "color-name": "^1.0.0",
1140 | "simple-swizzle": "^0.2.2"
1141 | }
1142 | },
1143 | "node_modules/cookie": {
1144 | "version": "0.7.2",
1145 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz",
1146 | "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==",
1147 | "dev": true,
1148 | "license": "MIT",
1149 | "engines": {
1150 | "node": ">= 0.6"
1151 | }
1152 | },
1153 | "node_modules/cors": {
1154 | "resolved": "cors",
1155 | "link": true
1156 | },
1157 | "node_modules/data-uri-to-buffer": {
1158 | "version": "2.0.2",
1159 | "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-2.0.2.tgz",
1160 | "integrity": "sha512-ND9qDTLc6diwj+Xe5cdAgVTbLVdXbtxTJRXRhli8Mowuaan+0EJOtdqJ0QCHNSSPyoXGx9HX2/VMnKeC34AChA==",
1161 | "dev": true,
1162 | "license": "MIT"
1163 | },
1164 | "node_modules/defu": {
1165 | "version": "6.1.4",
1166 | "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.4.tgz",
1167 | "integrity": "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==",
1168 | "dev": true,
1169 | "license": "MIT"
1170 | },
1171 | "node_modules/detect-libc": {
1172 | "version": "2.0.4",
1173 | "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.4.tgz",
1174 | "integrity": "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==",
1175 | "dev": true,
1176 | "license": "Apache-2.0",
1177 | "engines": {
1178 | "node": ">=8"
1179 | }
1180 | },
1181 | "node_modules/eruda": {
1182 | "resolved": "eruda",
1183 | "link": true
1184 | },
1185 | "node_modules/esbuild": {
1186 | "version": "0.25.4",
1187 | "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.4.tgz",
1188 | "integrity": "sha512-8pgjLUcUjcgDg+2Q4NYXnPbo/vncAY4UmyaCm0jZevERqCHZIaWwdJHkf8XQtu4AxSKCdvrUbT0XUr1IdZzI8Q==",
1189 | "dev": true,
1190 | "hasInstallScript": true,
1191 | "license": "MIT",
1192 | "bin": {
1193 | "esbuild": "bin/esbuild"
1194 | },
1195 | "engines": {
1196 | "node": ">=18"
1197 | },
1198 | "optionalDependencies": {
1199 | "@esbuild/aix-ppc64": "0.25.4",
1200 | "@esbuild/android-arm": "0.25.4",
1201 | "@esbuild/android-arm64": "0.25.4",
1202 | "@esbuild/android-x64": "0.25.4",
1203 | "@esbuild/darwin-arm64": "0.25.4",
1204 | "@esbuild/darwin-x64": "0.25.4",
1205 | "@esbuild/freebsd-arm64": "0.25.4",
1206 | "@esbuild/freebsd-x64": "0.25.4",
1207 | "@esbuild/linux-arm": "0.25.4",
1208 | "@esbuild/linux-arm64": "0.25.4",
1209 | "@esbuild/linux-ia32": "0.25.4",
1210 | "@esbuild/linux-loong64": "0.25.4",
1211 | "@esbuild/linux-mips64el": "0.25.4",
1212 | "@esbuild/linux-ppc64": "0.25.4",
1213 | "@esbuild/linux-riscv64": "0.25.4",
1214 | "@esbuild/linux-s390x": "0.25.4",
1215 | "@esbuild/linux-x64": "0.25.4",
1216 | "@esbuild/netbsd-arm64": "0.25.4",
1217 | "@esbuild/netbsd-x64": "0.25.4",
1218 | "@esbuild/openbsd-arm64": "0.25.4",
1219 | "@esbuild/openbsd-x64": "0.25.4",
1220 | "@esbuild/sunos-x64": "0.25.4",
1221 | "@esbuild/win32-arm64": "0.25.4",
1222 | "@esbuild/win32-ia32": "0.25.4",
1223 | "@esbuild/win32-x64": "0.25.4"
1224 | }
1225 | },
1226 | "node_modules/exit-hook": {
1227 | "version": "2.2.1",
1228 | "resolved": "https://registry.npmjs.org/exit-hook/-/exit-hook-2.2.1.tgz",
1229 | "integrity": "sha512-eNTPlAD67BmP31LDINZ3U7HSF8l57TxOY2PmBJ1shpCvpnxBF93mWCE8YHBnXs8qiUZJc9WDcWIeC3a2HIAMfw==",
1230 | "dev": true,
1231 | "license": "MIT",
1232 | "engines": {
1233 | "node": ">=6"
1234 | },
1235 | "funding": {
1236 | "url": "https://github.com/sponsors/sindresorhus"
1237 | }
1238 | },
1239 | "node_modules/exsolve": {
1240 | "version": "1.0.5",
1241 | "resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.0.5.tgz",
1242 | "integrity": "sha512-pz5dvkYYKQ1AHVrgOzBKWeP4u4FRb3a6DNK2ucr0OoNwYIU4QWsJ+NM36LLzORT+z845MzKHHhpXiUF5nvQoJg==",
1243 | "dev": true,
1244 | "license": "MIT"
1245 | },
1246 | "node_modules/fsevents": {
1247 | "version": "2.3.3",
1248 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
1249 | "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
1250 | "dev": true,
1251 | "hasInstallScript": true,
1252 | "license": "MIT",
1253 | "optional": true,
1254 | "os": [
1255 | "darwin"
1256 | ],
1257 | "engines": {
1258 | "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
1259 | }
1260 | },
1261 | "node_modules/get-source": {
1262 | "version": "2.0.12",
1263 | "resolved": "https://registry.npmjs.org/get-source/-/get-source-2.0.12.tgz",
1264 | "integrity": "sha512-X5+4+iD+HoSeEED+uwrQ07BOQr0kEDFMVqqpBuI+RaZBpBpHCuXxo70bjar6f0b0u/DQJsJ7ssurpP0V60Az+w==",
1265 | "dev": true,
1266 | "license": "Unlicense",
1267 | "dependencies": {
1268 | "data-uri-to-buffer": "^2.0.0",
1269 | "source-map": "^0.6.1"
1270 | }
1271 | },
1272 | "node_modules/glob-to-regexp": {
1273 | "version": "0.4.1",
1274 | "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz",
1275 | "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==",
1276 | "dev": true,
1277 | "license": "BSD-2-Clause"
1278 | },
1279 | "node_modules/hash": {
1280 | "resolved": "hash",
1281 | "link": true
1282 | },
1283 | "node_modules/html-entities": {
1284 | "version": "2.5.2",
1285 | "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.5.2.tgz",
1286 | "integrity": "sha512-K//PSRMQk4FZ78Kyau+mZurHn3FH0Vwr+H36eE0rPbeYkRRi9YxceYPhuN60UwWorxyKHhqoAJl2OFKa4BVtaA==",
1287 | "funding": [
1288 | {
1289 | "type": "github",
1290 | "url": "https://github.com/sponsors/mdevils"
1291 | },
1292 | {
1293 | "type": "patreon",
1294 | "url": "https://patreon.com/mdevils"
1295 | }
1296 | ],
1297 | "license": "MIT"
1298 | },
1299 | "node_modules/instagram": {
1300 | "resolved": "instagram",
1301 | "link": true
1302 | },
1303 | "node_modules/ip": {
1304 | "resolved": "ip",
1305 | "link": true
1306 | },
1307 | "node_modules/is-arrayish": {
1308 | "version": "0.3.2",
1309 | "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz",
1310 | "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==",
1311 | "dev": true,
1312 | "license": "MIT"
1313 | },
1314 | "node_modules/mime": {
1315 | "version": "3.0.0",
1316 | "resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz",
1317 | "integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==",
1318 | "dev": true,
1319 | "license": "MIT",
1320 | "bin": {
1321 | "mime": "cli.js"
1322 | },
1323 | "engines": {
1324 | "node": ">=10.0.0"
1325 | }
1326 | },
1327 | "node_modules/miniflare": {
1328 | "version": "4.20250525.0",
1329 | "resolved": "https://registry.npmjs.org/miniflare/-/miniflare-4.20250525.0.tgz",
1330 | "integrity": "sha512-F5XRDn9WqxUaHphUT8qwy5WXC/3UwbBRJTdjjP5uwHX82vypxIlHNyHziZnplPLhQa1kbSdIY7wfuP1XJyyYZw==",
1331 | "dev": true,
1332 | "license": "MIT",
1333 | "dependencies": {
1334 | "@cspotcode/source-map-support": "0.8.1",
1335 | "acorn": "8.14.0",
1336 | "acorn-walk": "8.3.2",
1337 | "exit-hook": "2.2.1",
1338 | "glob-to-regexp": "0.4.1",
1339 | "sharp": "^0.33.5",
1340 | "stoppable": "1.1.0",
1341 | "undici": "^5.28.5",
1342 | "workerd": "1.20250525.0",
1343 | "ws": "8.18.0",
1344 | "youch": "3.3.4",
1345 | "zod": "3.22.3"
1346 | },
1347 | "bin": {
1348 | "miniflare": "bootstrap.js"
1349 | },
1350 | "engines": {
1351 | "node": ">=18.0.0"
1352 | }
1353 | },
1354 | "node_modules/mustache": {
1355 | "version": "4.2.0",
1356 | "resolved": "https://registry.npmjs.org/mustache/-/mustache-4.2.0.tgz",
1357 | "integrity": "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==",
1358 | "dev": true,
1359 | "license": "MIT",
1360 | "bin": {
1361 | "mustache": "bin/mustache"
1362 | }
1363 | },
1364 | "node_modules/ohash": {
1365 | "version": "2.0.11",
1366 | "resolved": "https://registry.npmjs.org/ohash/-/ohash-2.0.11.tgz",
1367 | "integrity": "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==",
1368 | "dev": true,
1369 | "license": "MIT"
1370 | },
1371 | "node_modules/path-to-regexp": {
1372 | "version": "6.3.0",
1373 | "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.3.0.tgz",
1374 | "integrity": "sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==",
1375 | "dev": true,
1376 | "license": "MIT"
1377 | },
1378 | "node_modules/pathe": {
1379 | "version": "2.0.3",
1380 | "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz",
1381 | "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==",
1382 | "dev": true,
1383 | "license": "MIT"
1384 | },
1385 | "node_modules/printable-characters": {
1386 | "version": "1.0.42",
1387 | "resolved": "https://registry.npmjs.org/printable-characters/-/printable-characters-1.0.42.tgz",
1388 | "integrity": "sha512-dKp+C4iXWK4vVYZmYSd0KBH5F/h1HoZRsbJ82AVKRO3PEo8L4lBS/vLwhVtpwwuYcoIsVY+1JYKR268yn480uQ==",
1389 | "dev": true,
1390 | "license": "Unlicense"
1391 | },
1392 | "node_modules/proxy": {
1393 | "resolved": "proxy",
1394 | "link": true
1395 | },
1396 | "node_modules/pwned": {
1397 | "resolved": "pwned",
1398 | "link": true
1399 | },
1400 | "node_modules/qr": {
1401 | "resolved": "qr",
1402 | "link": true
1403 | },
1404 | "node_modules/semver": {
1405 | "version": "7.7.2",
1406 | "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz",
1407 | "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==",
1408 | "dev": true,
1409 | "license": "ISC",
1410 | "bin": {
1411 | "semver": "bin/semver.js"
1412 | },
1413 | "engines": {
1414 | "node": ">=10"
1415 | }
1416 | },
1417 | "node_modules/sharp": {
1418 | "version": "0.33.5",
1419 | "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.33.5.tgz",
1420 | "integrity": "sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw==",
1421 | "dev": true,
1422 | "hasInstallScript": true,
1423 | "license": "Apache-2.0",
1424 | "dependencies": {
1425 | "color": "^4.2.3",
1426 | "detect-libc": "^2.0.3",
1427 | "semver": "^7.6.3"
1428 | },
1429 | "engines": {
1430 | "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
1431 | },
1432 | "funding": {
1433 | "url": "https://opencollective.com/libvips"
1434 | },
1435 | "optionalDependencies": {
1436 | "@img/sharp-darwin-arm64": "0.33.5",
1437 | "@img/sharp-darwin-x64": "0.33.5",
1438 | "@img/sharp-libvips-darwin-arm64": "1.0.4",
1439 | "@img/sharp-libvips-darwin-x64": "1.0.4",
1440 | "@img/sharp-libvips-linux-arm": "1.0.5",
1441 | "@img/sharp-libvips-linux-arm64": "1.0.4",
1442 | "@img/sharp-libvips-linux-s390x": "1.0.4",
1443 | "@img/sharp-libvips-linux-x64": "1.0.4",
1444 | "@img/sharp-libvips-linuxmusl-arm64": "1.0.4",
1445 | "@img/sharp-libvips-linuxmusl-x64": "1.0.4",
1446 | "@img/sharp-linux-arm": "0.33.5",
1447 | "@img/sharp-linux-arm64": "0.33.5",
1448 | "@img/sharp-linux-s390x": "0.33.5",
1449 | "@img/sharp-linux-x64": "0.33.5",
1450 | "@img/sharp-linuxmusl-arm64": "0.33.5",
1451 | "@img/sharp-linuxmusl-x64": "0.33.5",
1452 | "@img/sharp-wasm32": "0.33.5",
1453 | "@img/sharp-win32-ia32": "0.33.5",
1454 | "@img/sharp-win32-x64": "0.33.5"
1455 | }
1456 | },
1457 | "node_modules/simple-swizzle": {
1458 | "version": "0.2.2",
1459 | "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz",
1460 | "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==",
1461 | "dev": true,
1462 | "license": "MIT",
1463 | "dependencies": {
1464 | "is-arrayish": "^0.3.1"
1465 | }
1466 | },
1467 | "node_modules/source-map": {
1468 | "version": "0.6.1",
1469 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
1470 | "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
1471 | "dev": true,
1472 | "license": "BSD-3-Clause",
1473 | "engines": {
1474 | "node": ">=0.10.0"
1475 | }
1476 | },
1477 | "node_modules/stacktracey": {
1478 | "version": "2.1.8",
1479 | "resolved": "https://registry.npmjs.org/stacktracey/-/stacktracey-2.1.8.tgz",
1480 | "integrity": "sha512-Kpij9riA+UNg7TnphqjH7/CzctQ/owJGNbFkfEeve4Z4uxT5+JapVLFXcsurIfN34gnTWZNJ/f7NMG0E8JDzTw==",
1481 | "dev": true,
1482 | "license": "Unlicense",
1483 | "dependencies": {
1484 | "as-table": "^1.0.36",
1485 | "get-source": "^2.0.12"
1486 | }
1487 | },
1488 | "node_modules/stoppable": {
1489 | "version": "1.1.0",
1490 | "resolved": "https://registry.npmjs.org/stoppable/-/stoppable-1.1.0.tgz",
1491 | "integrity": "sha512-KXDYZ9dszj6bzvnEMRYvxgeTHU74QBFL54XKtP3nyMuJ81CFYtABZ3bAzL2EdFUaEwJOBOgENyFj3R7oTzDyyw==",
1492 | "dev": true,
1493 | "license": "MIT",
1494 | "engines": {
1495 | "node": ">=4",
1496 | "npm": ">=6"
1497 | }
1498 | },
1499 | "node_modules/style": {
1500 | "resolved": "style",
1501 | "link": true
1502 | },
1503 | "node_modules/tslib": {
1504 | "version": "2.8.1",
1505 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
1506 | "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
1507 | "dev": true,
1508 | "license": "0BSD",
1509 | "optional": true
1510 | },
1511 | "node_modules/ufo": {
1512 | "version": "1.6.1",
1513 | "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.1.tgz",
1514 | "integrity": "sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==",
1515 | "dev": true,
1516 | "license": "MIT"
1517 | },
1518 | "node_modules/undici": {
1519 | "version": "5.29.0",
1520 | "resolved": "https://registry.npmjs.org/undici/-/undici-5.29.0.tgz",
1521 | "integrity": "sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg==",
1522 | "dev": true,
1523 | "license": "MIT",
1524 | "dependencies": {
1525 | "@fastify/busboy": "^2.0.0"
1526 | },
1527 | "engines": {
1528 | "node": ">=14.0"
1529 | }
1530 | },
1531 | "node_modules/unenv": {
1532 | "version": "2.0.0-rc.17",
1533 | "resolved": "https://registry.npmjs.org/unenv/-/unenv-2.0.0-rc.17.tgz",
1534 | "integrity": "sha512-B06u0wXkEd+o5gOCMl/ZHl5cfpYbDZKAT+HWTL+Hws6jWu7dCiqBBXXXzMFcFVJb8D4ytAnYmxJA83uwOQRSsg==",
1535 | "dev": true,
1536 | "license": "MIT",
1537 | "dependencies": {
1538 | "defu": "^6.1.4",
1539 | "exsolve": "^1.0.4",
1540 | "ohash": "^2.0.11",
1541 | "pathe": "^2.0.3",
1542 | "ufo": "^1.6.1"
1543 | }
1544 | },
1545 | "node_modules/unroll": {
1546 | "resolved": "unroll",
1547 | "link": true
1548 | },
1549 | "node_modules/uuid": {
1550 | "resolved": "uuid",
1551 | "link": true
1552 | },
1553 | "node_modules/workerd": {
1554 | "version": "1.20250525.0",
1555 | "resolved": "https://registry.npmjs.org/workerd/-/workerd-1.20250525.0.tgz",
1556 | "integrity": "sha512-SXJgLREy/Aqw2J71Oah0Pbu+SShbqbTExjVQyRBTM1r7MG7fS5NUlknhnt6sikjA/t4cO09Bi8OJqHdTkrcnYQ==",
1557 | "dev": true,
1558 | "hasInstallScript": true,
1559 | "license": "Apache-2.0",
1560 | "bin": {
1561 | "workerd": "bin/workerd"
1562 | },
1563 | "engines": {
1564 | "node": ">=16"
1565 | },
1566 | "optionalDependencies": {
1567 | "@cloudflare/workerd-darwin-64": "1.20250525.0",
1568 | "@cloudflare/workerd-darwin-arm64": "1.20250525.0",
1569 | "@cloudflare/workerd-linux-64": "1.20250525.0",
1570 | "@cloudflare/workerd-linux-arm64": "1.20250525.0",
1571 | "@cloudflare/workerd-windows-64": "1.20250525.0"
1572 | }
1573 | },
1574 | "node_modules/wrangler": {
1575 | "version": "4.18.0",
1576 | "resolved": "https://registry.npmjs.org/wrangler/-/wrangler-4.18.0.tgz",
1577 | "integrity": "sha512-/ng0KI9io97SNsBU1rheADBLLTE5Djybgsi4gXuvH1RBKJGpyj1xWvZ2fuWu8vAonit3EiZkwtERTm6kESHP3A==",
1578 | "dev": true,
1579 | "license": "MIT OR Apache-2.0",
1580 | "dependencies": {
1581 | "@cloudflare/kv-asset-handler": "0.4.0",
1582 | "@cloudflare/unenv-preset": "2.3.2",
1583 | "blake3-wasm": "2.1.5",
1584 | "esbuild": "0.25.4",
1585 | "miniflare": "4.20250525.0",
1586 | "path-to-regexp": "6.3.0",
1587 | "unenv": "2.0.0-rc.17",
1588 | "workerd": "1.20250525.0"
1589 | },
1590 | "bin": {
1591 | "wrangler": "bin/wrangler.js",
1592 | "wrangler2": "bin/wrangler.js"
1593 | },
1594 | "engines": {
1595 | "node": ">=18.0.0"
1596 | },
1597 | "optionalDependencies": {
1598 | "fsevents": "~2.3.2"
1599 | },
1600 | "peerDependencies": {
1601 | "@cloudflare/workers-types": "^4.20250525.0"
1602 | },
1603 | "peerDependenciesMeta": {
1604 | "@cloudflare/workers-types": {
1605 | "optional": true
1606 | }
1607 | }
1608 | },
1609 | "node_modules/ws": {
1610 | "version": "8.18.0",
1611 | "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz",
1612 | "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==",
1613 | "dev": true,
1614 | "license": "MIT",
1615 | "engines": {
1616 | "node": ">=10.0.0"
1617 | },
1618 | "peerDependencies": {
1619 | "bufferutil": "^4.0.1",
1620 | "utf-8-validate": ">=5.0.2"
1621 | },
1622 | "peerDependenciesMeta": {
1623 | "bufferutil": {
1624 | "optional": true
1625 | },
1626 | "utf-8-validate": {
1627 | "optional": true
1628 | }
1629 | }
1630 | },
1631 | "node_modules/youch": {
1632 | "version": "3.3.4",
1633 | "resolved": "https://registry.npmjs.org/youch/-/youch-3.3.4.tgz",
1634 | "integrity": "sha512-UeVBXie8cA35DS6+nBkls68xaBBXCye0CNznrhszZjTbRVnJKQuNsyLKBTTL4ln1o1rh2PKtv35twV7irj5SEg==",
1635 | "dev": true,
1636 | "license": "MIT",
1637 | "dependencies": {
1638 | "cookie": "^0.7.1",
1639 | "mustache": "^4.2.0",
1640 | "stacktracey": "^2.1.8"
1641 | }
1642 | },
1643 | "node_modules/zod": {
1644 | "version": "3.22.3",
1645 | "resolved": "https://registry.npmjs.org/zod/-/zod-3.22.3.tgz",
1646 | "integrity": "sha512-EjIevzuJRiRPbVH4mGc8nApb/lVLKVpmUhAaR5R5doKGfAnGJ6Gr3CViAVjP+4FWSxCsybeWQdcgCtbX+7oZug==",
1647 | "dev": true,
1648 | "license": "MIT",
1649 | "funding": {
1650 | "url": "https://github.com/sponsors/colinhacks"
1651 | }
1652 | },
1653 | "proxy": {
1654 | "version": "0.3.0",
1655 | "license": "ISC"
1656 | },
1657 | "pwned": {
1658 | "version": "0.3.0",
1659 | "license": "ISC"
1660 | },
1661 | "qr": {
1662 | "version": "0.3.0",
1663 | "license": "ISC",
1664 | "dependencies": {
1665 | "@paulmillr/qr": "^0.3.0"
1666 | }
1667 | },
1668 | "style": {
1669 | "version": "0.3.0",
1670 | "license": "ISC"
1671 | },
1672 | "unroll": {
1673 | "version": "0.3.0",
1674 | "license": "ISC"
1675 | },
1676 | "uuid": {
1677 | "version": "0.3.0",
1678 | "license": "ISC"
1679 | }
1680 | }
1681 | }
1682 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "cloudflare-workers",
3 | "version": "0.3.0",
4 | "description": "Monorepo for my personal Cloudflare Workers.",
5 | "license": "ISC",
6 | "author": "Ardis Lu",
7 | "private": true,
8 | "scripts": {
9 | "dev": "wrangler dev",
10 | "deploy": "wrangler deploy"
11 | },
12 | "devDependencies": {
13 | "wrangler": "^4.18.0"
14 | },
15 | "repository": {
16 | "type": "git",
17 | "url": "https://github.com/ardislu/cloudflare-workers.git"
18 | },
19 | "workspaces": [
20 | "proxy",
21 | "instagram",
22 | "cors",
23 | "pwned",
24 | "qr",
25 | "ip",
26 | "uuid",
27 | "hash",
28 | "style",
29 | "unroll",
30 | "buttcoin",
31 | "archive",
32 | "eruda"
33 | ]
34 | }
35 |
--------------------------------------------------------------------------------
/proxy/index.js:
--------------------------------------------------------------------------------
1 | export class SetBase {
2 | constructor(origin) {
3 | this.origin = origin;
4 | }
5 |
6 | element(element) {
7 | element.prepend(` `, { html: true });
8 | }
9 | }
10 |
11 | export class UpdateLink {
12 | element(element) {
13 | for (const attrName of ['href', 'src']) {
14 | const attrValue = element.getAttribute(attrName);
15 | if (attrValue !== null && attrValue[0] === '/') {
16 | element.setAttribute(attrName, attrValue.substring(1));
17 | }
18 | }
19 | }
20 | }
21 |
22 | export default {
23 | async fetch(request) {
24 | const url = /^http(s)?:\/\//i.test(request.url) ? new URL(request.url) : new URL(`https://${request.url}`);
25 | const remoteUrl = new URL(decodeURIComponent(url.search.substring(1)));
26 | const response = await fetch(remoteUrl);
27 | return new HTMLRewriter()
28 | .on('head', new SetBase(remoteUrl.origin))
29 | .on('link, script', new UpdateLink())
30 | .transform(response);
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/proxy/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "proxy",
3 | "version": "0.3.0",
4 | "description": "This is a minimal, basic reverse proxy.",
5 | "license": "ISC",
6 | "author": "Ardis Lu",
7 | "private": true,
8 | "scripts": {
9 | "dev": "wrangler dev",
10 | "deploy": "wrangler deploy"
11 | },
12 | "repository": {
13 | "type": "git",
14 | "url": "https://github.com/ardislu/cloudflare-workers.git"
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/proxy/wrangler.toml.example:
--------------------------------------------------------------------------------
1 | name = 'proxy'
2 | main = 'index.js'
3 | compatibility_date = '2025-05-23'
4 | route = { pattern = 'proxy.example.com', custom_domain = true }
5 |
--------------------------------------------------------------------------------
/pwned/index.js:
--------------------------------------------------------------------------------
1 | export default {
2 | async fetch(request) {
3 | const url = new URL(request.url);
4 | const queryString = decodeURIComponent(url.search.substring(1));
5 |
6 | // Convert password string to byte array and hash it, then convert hashed byte array to hex string
7 | const inputArray = new TextEncoder().encode(queryString);
8 | const digest = await crypto.subtle.digest('SHA-1', inputArray);
9 | const outputArray = [...new Uint8Array(digest)]; // Need to spread typed array into a non-typed array to allow .map() to output strings
10 | const hash = outputArray.map(v => v.toString(16).padStart(2, '0')).join('').toUpperCase();
11 |
12 | // Split the hash as required by the HIBP API (k-Anonymity model)
13 | const range = hash.substring(0, 5);
14 | const index = hash.substring(5);
15 |
16 | const result = fetch(`https://api.pwnedpasswords.com/range/${range}`)
17 | .then(response => response.text())
18 | .then(body => body.includes(index))
19 | .then(bool => new Response(bool));
20 |
21 | return result;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/pwned/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "pwned",
3 | "version": "0.3.0",
4 | "description": "This is a re-implementation of the Pwned Passwords Cloudflare Worker.",
5 | "license": "ISC",
6 | "author": "Ardis Lu",
7 | "private": true,
8 | "scripts": {
9 | "dev": "wrangler dev",
10 | "deploy": "wrangler deploy"
11 | },
12 | "repository": {
13 | "type": "git",
14 | "url": "https://github.com/ardislu/cloudflare-workers.git"
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/pwned/wrangler.toml.example:
--------------------------------------------------------------------------------
1 | name = 'pwned'
2 | main = 'index.js'
3 | compatibility_date = '2025-05-23'
4 | route = { pattern = 'pwned.example.com', custom_domain = true }
5 |
--------------------------------------------------------------------------------
/qr/index.js:
--------------------------------------------------------------------------------
1 | import writeQR from '@paulmillr/qr';
2 |
3 | export default {
4 | async fetch(request) {
5 | const url = new URL(request.url);
6 | const queryString = decodeURIComponent(url.search.substring(1));
7 | const qrImage = writeQR(queryString || 'https://example.com', 'svg');
8 |
9 | return new Response(qrImage, {
10 | headers: {
11 | 'Content-Type': 'image/svg+xml'
12 | }
13 | })
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/qr/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "qr",
3 | "version": "0.3.0",
4 | "description": "QR code generator on a Cloudflare Worker.",
5 | "license": "ISC",
6 | "author": "Ardis Lu",
7 | "private": true,
8 | "scripts": {
9 | "dev": "wrangler dev",
10 | "deploy": "wrangler deploy"
11 | },
12 | "dependencies": {
13 | "@paulmillr/qr": "^0.3.0"
14 | },
15 | "repository": {
16 | "type": "git",
17 | "url": "https://github.com/ardislu/cloudflare-workers.git"
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/qr/wrangler.toml.example:
--------------------------------------------------------------------------------
1 | name = 'qr'
2 | main = 'index.js'
3 | compatibility_date = '2025-05-23'
4 | route = { pattern = 'qr.example.com', custom_domain = true }
5 |
--------------------------------------------------------------------------------
/style/index.js:
--------------------------------------------------------------------------------
1 | import { SetBase, UpdateLink } from '../proxy';
2 |
3 | class InjectStyle {
4 | element(element) {
5 | element.prepend(` `, { html: true });
6 | }
7 | }
8 |
9 | export default {
10 | async fetch(request) {
11 | const url = /^http(s)?:\/\//i.test(request.url) ? new URL(request.url) : new URL(`https://${request.url}`);
12 | const remoteUrl = new URL(decodeURIComponent(url.search.substring(1)));
13 |
14 | const response = await fetch(remoteUrl);
15 | return new HTMLRewriter()
16 | .on('head', new SetBase(remoteUrl.origin))
17 | .on('link, script', new UpdateLink())
18 | .on('html', new InjectStyle())
19 | .transform(response);
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/style/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "style",
3 | "version": "0.3.0",
4 | "description": "Reverse proxy which injects a basic CSS style sheet.",
5 | "license": "ISC",
6 | "author": "Ardis Lu",
7 | "private": true,
8 | "scripts": {
9 | "dev": "wrangler dev",
10 | "deploy": "wrangler deploy"
11 | },
12 | "repository": {
13 | "type": "git",
14 | "url": "https://github.com/ardislu/cloudflare-workers.git"
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/style/wrangler.toml.example:
--------------------------------------------------------------------------------
1 | name = 'style'
2 | main = 'index.js'
3 | compatibility_date = '2025-05-23'
4 | route = { pattern = 'style.example.com', custom_domain = true }
5 |
--------------------------------------------------------------------------------
/unroll/index.js:
--------------------------------------------------------------------------------
1 | export default {
2 | async fetch(request) {
3 | const url = new URL(request.url);
4 | const queryString = decodeURIComponent(url.search.substring(1));
5 | const tweet = queryString.split('/').pop();
6 |
7 | return Response.redirect(`https://threadreaderapp.com/thread/${tweet}`);
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/unroll/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "unroll",
3 | "version": "0.3.0",
4 | "description": "Redirects a tweet thread to the corresponding Threadreader thread.",
5 | "license": "ISC",
6 | "author": "Ardis Lu",
7 | "private": true,
8 | "scripts": {
9 | "dev": "wrangler dev",
10 | "deploy": "wrangler deploy"
11 | },
12 | "repository": {
13 | "type": "git",
14 | "url": "https://github.com/ardislu/cloudflare-workers.git"
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/unroll/wrangler.toml.example:
--------------------------------------------------------------------------------
1 | name = 'unroll'
2 | main = 'index.js'
3 | compatibility_date = '2025-05-23'
4 | route = { pattern = 'unroll.example.com', custom_domain = true }
5 |
--------------------------------------------------------------------------------
/uuid/index.js:
--------------------------------------------------------------------------------
1 | export default {
2 | async fetch(request) {
3 | return new Response(crypto.randomUUID());
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/uuid/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "uuid",
3 | "version": "0.3.0",
4 | "description": "Cloudflare Worker which returns a random version 4 UUID.",
5 | "license": "ISC",
6 | "author": "Ardis Lu",
7 | "private": true,
8 | "scripts": {
9 | "dev": "wrangler dev",
10 | "deploy": "wrangler deploy"
11 | },
12 | "repository": {
13 | "type": "git",
14 | "url": "https://github.com/ardislu/cloudflare-workers.git"
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/uuid/wrangler.toml.example:
--------------------------------------------------------------------------------
1 | name = 'uuid'
2 | main = 'index.js'
3 | compatibility_date = '2025-05-23'
4 | route = { pattern = 'uuid.example.com', custom_domain = true }
5 |
--------------------------------------------------------------------------------