├── .prettierrc
├── .gitignore
├── .doc
├── marquee.png
└── chrome-web-store-badge.png
├── assets
├── icon16.png
├── icon32.png
├── icon48.png
└── icon128.png
├── .vscode
├── cspell.json
└── settings.json
├── tsconfig.json
├── package.json
├── manifest.json
├── README.md
├── src
└── worker.ts
└── pnpm-lock.yaml
/.prettierrc:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 |
3 | _metadata/
4 |
5 | dist/*
6 |
--------------------------------------------------------------------------------
/.doc/marquee.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ni554n/redium/HEAD/.doc/marquee.png
--------------------------------------------------------------------------------
/assets/icon16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ni554n/redium/HEAD/assets/icon16.png
--------------------------------------------------------------------------------
/assets/icon32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ni554n/redium/HEAD/assets/icon32.png
--------------------------------------------------------------------------------
/assets/icon48.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ni554n/redium/HEAD/assets/icon48.png
--------------------------------------------------------------------------------
/assets/icon128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ni554n/redium/HEAD/assets/icon128.png
--------------------------------------------------------------------------------
/.doc/chrome-web-store-badge.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ni554n/redium/HEAD/.doc/chrome-web-store-badge.png
--------------------------------------------------------------------------------
/.vscode/cspell.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://raw.githubusercontent.com/streetsidesoftware/cspell/main/cspell.schema.json",
3 | "words": ["Freedium", "outdir", "readmedium", "Redium"]
4 | }
5 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ESNext",
4 | "module": "ESNext",
5 | "noEmit": true,
6 | "strict": true,
7 | "types": ["chrome-types"]
8 | },
9 | "include": ["src/**/*"]
10 | }
11 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "editor.defaultFormatter": "esbenp.prettier-vscode",
3 | "json.schemas": [
4 | {
5 | "fileMatch": ["manifest.json"],
6 | "url": "https://json.schemastore.org/chrome-manifest"
7 | }
8 | ]
9 | }
10 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "scripts": {
3 | "dev": "esbuild --minify src/*.ts --outdir=dist --watch",
4 | "build": "esbuild --minify src/*.ts --outdir=dist",
5 | "zip": "powershell Compress-Archive -Path assets,dist,manifest.json -DestinationPath chrome-web-store.zip"
6 | },
7 | "devDependencies": {
8 | "chrome-types": "0.1.297",
9 | "esbuild": "0.23.0",
10 | "prettier": "3.3.3"
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "manifest_version": 3,
3 | "name": "Redium",
4 | "version": "3.0",
5 | "description": "Redirect medium articles to proxies.",
6 | "icons": {
7 | "16": "assets/icon16.png",
8 | "32": "assets/icon32.png",
9 | "48": "assets/icon48.png",
10 | "128": "assets/icon128.png"
11 | },
12 | "action": {},
13 | "commands": {
14 | "_execute_action": {
15 | "suggested_key": {
16 | "default": "Alt+R"
17 | }
18 | }
19 | },
20 | "host_permissions": ["*://*.medium.com/*"],
21 | "permissions": [
22 | "activeTab",
23 | "contentSettings",
24 | "contextMenus",
25 | "management",
26 | "storage"
27 | ],
28 | "background": {
29 | "service_worker": "dist/worker.js"
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |

Redium
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | Automatically unblock medium articles through proxies such as ReadMedium, Freedium, and Archive.today.
10 |
11 | > [!TIP]
12 | > Click the extension icon or press `Alt + R` to redirect manually.
13 |
14 | ## Build
15 |
16 |
17 |
18 | 1. [Download this repo](https://github.com/ni554n/redium/archive/refs/heads/main.zip) and extract it somewhere permanent
19 | 2. `cd` into the extracted **_redium-main_** folder and run `npm install` and `npm run build`
20 | 3. Go to [Chrome Extensions](chrome://extensions/) page and enable `Developer Mode` from the top right corner
21 | 4. Click `Load Unpacked` button and select the folder
22 |
23 | ## Changelog
24 |
25 | ### v3.0
26 |
27 | - Remove proxy services that no longer works
28 | - Added ReadMedium, Freedium, and Archive.today
29 |
30 | ### v2.0
31 |
32 | - Added a keyboard shortcut: `Alt + R` to manually redirect any website to the proxy.
33 | - Added Google Web Cache as the new default proxy. Other proxy services are currently failing to unblock premium articles due to the recent changes made to Medium. However, we can still read the cached version of a premium article through Google Web Cache. But it has some limitations:
34 | - Recent articles may take a few days before Google caches them.
35 | - Dynamic iframes inside articles won't be loaded, so we are limited to only texts and images.
36 |
37 | ### v1.0
38 |
39 | - Initial release.
40 |
41 | ## Information
42 |
43 | **Author:** [Nissan Ahmed](https://anissan.com) ([@ni554n](https://twitter.com/ni554n))
44 |
45 | **Donate:** [PayPal](https://paypal.me/ni554n)
46 |
47 |
--------------------------------------------------------------------------------
/src/worker.ts:
--------------------------------------------------------------------------------
1 | type ProxyService = "ReadMedium" | "Freedium" | "Archive.today";
2 |
3 | const domain: Readonly> = {
4 | ReadMedium: "readmedium.com",
5 | Freedium: "freedium.cfd",
6 | "Archive.today": "archive.today",
7 | };
8 |
9 | const AUTO_REDIRECTION_MENU_ID = "auto_redirection_toggle";
10 |
11 | chrome.runtime.onInstalled.addListener(async ({ reason }) => {
12 | let {
13 | selected_proxy: selectedService,
14 | should_redirect: isAutoRedirectionEnabled,
15 | } = await readStorage();
16 |
17 | if (reason === "update") {
18 | await chrome.storage.local.remove("selected_proxy");
19 | selectedService = defaultValue.selected_proxy;
20 |
21 | // TODO: Remove the contentSettings permission on the next update
22 | await chrome.contentSettings.javascript.clear({});
23 | }
24 |
25 | chrome.contextMenus.removeAll();
26 |
27 | /* Up to 6 menu items can be added. */
28 |
29 | chrome.contextMenus.create({
30 | id: AUTO_REDIRECTION_MENU_ID,
31 | title: "Auto-redirect medium articles on new tab",
32 | contexts: ["action"],
33 | type: "checkbox",
34 | checked: isAutoRedirectionEnabled,
35 | });
36 |
37 | for (const service of Object.keys(domain)) {
38 | chrome.contextMenus.create({
39 | id: service,
40 | title: service,
41 | contexts: ["action"],
42 | type: "radio",
43 | checked: selectedService === service,
44 | });
45 | }
46 |
47 | chrome.contextMenus.create({
48 | id: "tip",
49 | title: "Tip: Press Alt + R or the extension icon to redirect manually",
50 | contexts: ["action"],
51 | type: "normal",
52 | });
53 |
54 | init();
55 | });
56 |
57 | /**
58 | * Handles the click event on the context menu items.
59 | */
60 | chrome.contextMenus.onClicked.addListener(
61 | async (menuItem: chrome.contextMenus.OnClickData) => {
62 | if (menuItem.menuItemId === AUTO_REDIRECTION_MENU_ID) {
63 | await writeStorage("should_redirect", menuItem.checked ?? true);
64 | } else if (menuItem.menuItemId in domain) {
65 | await writeStorage("selected_proxy", menuItem.menuItemId as ProxyService);
66 | }
67 |
68 | init();
69 | },
70 | );
71 |
72 | chrome.runtime.onStartup.addListener(init);
73 | chrome.management.onEnabled.addListener(init);
74 |
75 | async function init() {
76 | const {
77 | selected_proxy: selectedService,
78 | should_redirect: isAutoRedirectionEnabled,
79 | } = await readStorage();
80 |
81 | chrome.action.setTitle({
82 | title: `Redirect to ${selectedService} (Alt + R)`,
83 | });
84 |
85 | if (isAutoRedirectionEnabled) chrome.tabs.onUpdated.addListener(autoRedirect);
86 | else chrome.tabs.onUpdated.removeListener(autoRedirect);
87 | }
88 |
89 | /**
90 | * Auto redirects to proxy service if enabled.
91 | */
92 | async function autoRedirect(
93 | tabId: number,
94 | changeInfo: { status?: chrome.tabs.TabStatus },
95 | tab: chrome.tabs.Tab,
96 | ) {
97 | if (!tab.url || !changeInfo.status) return;
98 | if (changeInfo.status !== "loading") return;
99 | if (!(await readStorage("should_redirect"))) return;
100 |
101 | // Assumes only medium.com urls will be here as set by host_permissions in manifest.json
102 | const tabUrl = new URL(tab.url);
103 |
104 | if (!tabUrl.hostname.includes("medium.com")) return;
105 | if (
106 | tabUrl.pathname.startsWith("/m/") || // Used for 3xx redirection
107 | !/^.+-[0-9a-f]{8,}.*$/.test(tabUrl.pathname) // Matches medium post slug hash
108 | ) {
109 | return;
110 | }
111 |
112 | await chrome.tabs.update(tabId, { url: await selectRedirectUrl(tabUrl) });
113 | }
114 |
115 | /**
116 | * Handles the click event on the extension icon.
117 | */
118 | chrome.action.onClicked.addListener(async (tab: chrome.tabs.Tab) => {
119 | if (!tab.url?.startsWith("http")) return;
120 |
121 | const redirectUrl = await selectRedirectUrl(new URL(tab.url));
122 | await chrome.tabs.create({ index: tab.index + 1, url: redirectUrl });
123 | });
124 |
125 | async function selectRedirectUrl(tabUrl: URL): Promise {
126 | const selectedService: ProxyService = await readStorage("selected_proxy");
127 | const serviceDomain: string = domain[selectedService];
128 |
129 | if (tabUrl.hostname.includes(serviceDomain)) return tabUrl.href;
130 |
131 | switch (selectedService) {
132 | case "ReadMedium":
133 | return `https://${serviceDomain}/en/${tabUrl.href}`;
134 |
135 | case "Archive.today": {
136 | return `https://${serviceDomain}?url=${tabUrl.href}&run=1`;
137 | }
138 |
139 | default:
140 | return `https://${serviceDomain}${tabUrl.pathname}`;
141 | }
142 | }
143 |
144 | /* Storage Helpers */
145 |
146 | type LocalKv = {
147 | selected_proxy: ProxyService;
148 | should_redirect: boolean;
149 | };
150 |
151 | const defaultValue: Readonly = {
152 | selected_proxy: "ReadMedium",
153 | should_redirect: true,
154 | };
155 |
156 | function readStorage(key: "selected_proxy"): Promise;
157 | function readStorage(key: "should_redirect"): Promise;
158 | function readStorage(): Promise;
159 |
160 | async function readStorage(key?: keyof LocalKv) {
161 | const kVs = await chrome.storage.local.get(key);
162 |
163 | if (key !== undefined) return kVs[key] ?? defaultValue[key];
164 |
165 | return kVs;
166 | }
167 |
168 | async function writeStorage(
169 | key: K,
170 | value: LocalKv[K],
171 | ) {
172 | await chrome.storage.local.set({ [key]: value });
173 | }
174 |
--------------------------------------------------------------------------------
/pnpm-lock.yaml:
--------------------------------------------------------------------------------
1 | lockfileVersion: '9.0'
2 |
3 | settings:
4 | autoInstallPeers: true
5 | excludeLinksFromLockfile: false
6 |
7 | importers:
8 |
9 | .:
10 | devDependencies:
11 | chrome-types:
12 | specifier: 0.1.297
13 | version: 0.1.297
14 | esbuild:
15 | specifier: 0.23.0
16 | version: 0.23.0
17 | prettier:
18 | specifier: 3.3.3
19 | version: 3.3.3
20 |
21 | packages:
22 |
23 | '@esbuild/aix-ppc64@0.23.0':
24 | resolution: {integrity: sha512-3sG8Zwa5fMcA9bgqB8AfWPQ+HFke6uD3h1s3RIwUNK8EG7a4buxvuFTs3j1IMs2NXAk9F30C/FF4vxRgQCcmoQ==}
25 | engines: {node: '>=18'}
26 | cpu: [ppc64]
27 | os: [aix]
28 |
29 | '@esbuild/android-arm64@0.23.0':
30 | resolution: {integrity: sha512-EuHFUYkAVfU4qBdyivULuu03FhJO4IJN9PGuABGrFy4vUuzk91P2d+npxHcFdpUnfYKy0PuV+n6bKIpHOB3prQ==}
31 | engines: {node: '>=18'}
32 | cpu: [arm64]
33 | os: [android]
34 |
35 | '@esbuild/android-arm@0.23.0':
36 | resolution: {integrity: sha512-+KuOHTKKyIKgEEqKbGTK8W7mPp+hKinbMBeEnNzjJGyFcWsfrXjSTNluJHCY1RqhxFurdD8uNXQDei7qDlR6+g==}
37 | engines: {node: '>=18'}
38 | cpu: [arm]
39 | os: [android]
40 |
41 | '@esbuild/android-x64@0.23.0':
42 | resolution: {integrity: sha512-WRrmKidLoKDl56LsbBMhzTTBxrsVwTKdNbKDalbEZr0tcsBgCLbEtoNthOW6PX942YiYq8HzEnb4yWQMLQuipQ==}
43 | engines: {node: '>=18'}
44 | cpu: [x64]
45 | os: [android]
46 |
47 | '@esbuild/darwin-arm64@0.23.0':
48 | resolution: {integrity: sha512-YLntie/IdS31H54Ogdn+v50NuoWF5BDkEUFpiOChVa9UnKpftgwzZRrI4J132ETIi+D8n6xh9IviFV3eXdxfow==}
49 | engines: {node: '>=18'}
50 | cpu: [arm64]
51 | os: [darwin]
52 |
53 | '@esbuild/darwin-x64@0.23.0':
54 | resolution: {integrity: sha512-IMQ6eme4AfznElesHUPDZ+teuGwoRmVuuixu7sv92ZkdQcPbsNHzutd+rAfaBKo8YK3IrBEi9SLLKWJdEvJniQ==}
55 | engines: {node: '>=18'}
56 | cpu: [x64]
57 | os: [darwin]
58 |
59 | '@esbuild/freebsd-arm64@0.23.0':
60 | resolution: {integrity: sha512-0muYWCng5vqaxobq6LB3YNtevDFSAZGlgtLoAc81PjUfiFz36n4KMpwhtAd4he8ToSI3TGyuhyx5xmiWNYZFyw==}
61 | engines: {node: '>=18'}
62 | cpu: [arm64]
63 | os: [freebsd]
64 |
65 | '@esbuild/freebsd-x64@0.23.0':
66 | resolution: {integrity: sha512-XKDVu8IsD0/q3foBzsXGt/KjD/yTKBCIwOHE1XwiXmrRwrX6Hbnd5Eqn/WvDekddK21tfszBSrE/WMaZh+1buQ==}
67 | engines: {node: '>=18'}
68 | cpu: [x64]
69 | os: [freebsd]
70 |
71 | '@esbuild/linux-arm64@0.23.0':
72 | resolution: {integrity: sha512-j1t5iG8jE7BhonbsEg5d9qOYcVZv/Rv6tghaXM/Ug9xahM0nX/H2gfu6X6z11QRTMT6+aywOMA8TDkhPo8aCGw==}
73 | engines: {node: '>=18'}
74 | cpu: [arm64]
75 | os: [linux]
76 |
77 | '@esbuild/linux-arm@0.23.0':
78 | resolution: {integrity: sha512-SEELSTEtOFu5LPykzA395Mc+54RMg1EUgXP+iw2SJ72+ooMwVsgfuwXo5Fn0wXNgWZsTVHwY2cg4Vi/bOD88qw==}
79 | engines: {node: '>=18'}
80 | cpu: [arm]
81 | os: [linux]
82 |
83 | '@esbuild/linux-ia32@0.23.0':
84 | resolution: {integrity: sha512-P7O5Tkh2NbgIm2R6x1zGJJsnacDzTFcRWZyTTMgFdVit6E98LTxO+v8LCCLWRvPrjdzXHx9FEOA8oAZPyApWUA==}
85 | engines: {node: '>=18'}
86 | cpu: [ia32]
87 | os: [linux]
88 |
89 | '@esbuild/linux-loong64@0.23.0':
90 | resolution: {integrity: sha512-InQwepswq6urikQiIC/kkx412fqUZudBO4SYKu0N+tGhXRWUqAx+Q+341tFV6QdBifpjYgUndV1hhMq3WeJi7A==}
91 | engines: {node: '>=18'}
92 | cpu: [loong64]
93 | os: [linux]
94 |
95 | '@esbuild/linux-mips64el@0.23.0':
96 | resolution: {integrity: sha512-J9rflLtqdYrxHv2FqXE2i1ELgNjT+JFURt/uDMoPQLcjWQA5wDKgQA4t/dTqGa88ZVECKaD0TctwsUfHbVoi4w==}
97 | engines: {node: '>=18'}
98 | cpu: [mips64el]
99 | os: [linux]
100 |
101 | '@esbuild/linux-ppc64@0.23.0':
102 | resolution: {integrity: sha512-cShCXtEOVc5GxU0fM+dsFD10qZ5UpcQ8AM22bYj0u/yaAykWnqXJDpd77ublcX6vdDsWLuweeuSNZk4yUxZwtw==}
103 | engines: {node: '>=18'}
104 | cpu: [ppc64]
105 | os: [linux]
106 |
107 | '@esbuild/linux-riscv64@0.23.0':
108 | resolution: {integrity: sha512-HEtaN7Y5UB4tZPeQmgz/UhzoEyYftbMXrBCUjINGjh3uil+rB/QzzpMshz3cNUxqXN7Vr93zzVtpIDL99t9aRw==}
109 | engines: {node: '>=18'}
110 | cpu: [riscv64]
111 | os: [linux]
112 |
113 | '@esbuild/linux-s390x@0.23.0':
114 | resolution: {integrity: sha512-WDi3+NVAuyjg/Wxi+o5KPqRbZY0QhI9TjrEEm+8dmpY9Xir8+HE/HNx2JoLckhKbFopW0RdO2D72w8trZOV+Wg==}
115 | engines: {node: '>=18'}
116 | cpu: [s390x]
117 | os: [linux]
118 |
119 | '@esbuild/linux-x64@0.23.0':
120 | resolution: {integrity: sha512-a3pMQhUEJkITgAw6e0bWA+F+vFtCciMjW/LPtoj99MhVt+Mfb6bbL9hu2wmTZgNd994qTAEw+U/r6k3qHWWaOQ==}
121 | engines: {node: '>=18'}
122 | cpu: [x64]
123 | os: [linux]
124 |
125 | '@esbuild/netbsd-x64@0.23.0':
126 | resolution: {integrity: sha512-cRK+YDem7lFTs2Q5nEv/HHc4LnrfBCbH5+JHu6wm2eP+d8OZNoSMYgPZJq78vqQ9g+9+nMuIsAO7skzphRXHyw==}
127 | engines: {node: '>=18'}
128 | cpu: [x64]
129 | os: [netbsd]
130 |
131 | '@esbuild/openbsd-arm64@0.23.0':
132 | resolution: {integrity: sha512-suXjq53gERueVWu0OKxzWqk7NxiUWSUlrxoZK7usiF50C6ipColGR5qie2496iKGYNLhDZkPxBI3erbnYkU0rQ==}
133 | engines: {node: '>=18'}
134 | cpu: [arm64]
135 | os: [openbsd]
136 |
137 | '@esbuild/openbsd-x64@0.23.0':
138 | resolution: {integrity: sha512-6p3nHpby0DM/v15IFKMjAaayFhqnXV52aEmv1whZHX56pdkK+MEaLoQWj+H42ssFarP1PcomVhbsR4pkz09qBg==}
139 | engines: {node: '>=18'}
140 | cpu: [x64]
141 | os: [openbsd]
142 |
143 | '@esbuild/sunos-x64@0.23.0':
144 | resolution: {integrity: sha512-BFelBGfrBwk6LVrmFzCq1u1dZbG4zy/Kp93w2+y83Q5UGYF1d8sCzeLI9NXjKyujjBBniQa8R8PzLFAUrSM9OA==}
145 | engines: {node: '>=18'}
146 | cpu: [x64]
147 | os: [sunos]
148 |
149 | '@esbuild/win32-arm64@0.23.0':
150 | resolution: {integrity: sha512-lY6AC8p4Cnb7xYHuIxQ6iYPe6MfO2CC43XXKo9nBXDb35krYt7KGhQnOkRGar5psxYkircpCqfbNDB4uJbS2jQ==}
151 | engines: {node: '>=18'}
152 | cpu: [arm64]
153 | os: [win32]
154 |
155 | '@esbuild/win32-ia32@0.23.0':
156 | resolution: {integrity: sha512-7L1bHlOTcO4ByvI7OXVI5pNN6HSu6pUQq9yodga8izeuB1KcT2UkHaH6118QJwopExPn0rMHIseCTx1CRo/uNA==}
157 | engines: {node: '>=18'}
158 | cpu: [ia32]
159 | os: [win32]
160 |
161 | '@esbuild/win32-x64@0.23.0':
162 | resolution: {integrity: sha512-Arm+WgUFLUATuoxCJcahGuk6Yj9Pzxd6l11Zb/2aAuv5kWWvvfhLFo2fni4uSK5vzlUdCGZ/BdV5tH8klj8p8g==}
163 | engines: {node: '>=18'}
164 | cpu: [x64]
165 | os: [win32]
166 |
167 | chrome-types@0.1.297:
168 | resolution: {integrity: sha512-pVvyKx+JBZ5jh08bU6qL2IepJItfVOyGeMJtxfi9T5/LBXGbRlbCm7wMUvW51VqqGniPwJjtU20/M0oxH/wsFg==}
169 |
170 | esbuild@0.23.0:
171 | resolution: {integrity: sha512-1lvV17H2bMYda/WaFb2jLPeHU3zml2k4/yagNMG8Q/YtfMjCwEUZa2eXXMgZTVSL5q1n4H7sQ0X6CdJDqqeCFA==}
172 | engines: {node: '>=18'}
173 | hasBin: true
174 |
175 | prettier@3.3.3:
176 | resolution: {integrity: sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==}
177 | engines: {node: '>=14'}
178 | hasBin: true
179 |
180 | snapshots:
181 |
182 | '@esbuild/aix-ppc64@0.23.0':
183 | optional: true
184 |
185 | '@esbuild/android-arm64@0.23.0':
186 | optional: true
187 |
188 | '@esbuild/android-arm@0.23.0':
189 | optional: true
190 |
191 | '@esbuild/android-x64@0.23.0':
192 | optional: true
193 |
194 | '@esbuild/darwin-arm64@0.23.0':
195 | optional: true
196 |
197 | '@esbuild/darwin-x64@0.23.0':
198 | optional: true
199 |
200 | '@esbuild/freebsd-arm64@0.23.0':
201 | optional: true
202 |
203 | '@esbuild/freebsd-x64@0.23.0':
204 | optional: true
205 |
206 | '@esbuild/linux-arm64@0.23.0':
207 | optional: true
208 |
209 | '@esbuild/linux-arm@0.23.0':
210 | optional: true
211 |
212 | '@esbuild/linux-ia32@0.23.0':
213 | optional: true
214 |
215 | '@esbuild/linux-loong64@0.23.0':
216 | optional: true
217 |
218 | '@esbuild/linux-mips64el@0.23.0':
219 | optional: true
220 |
221 | '@esbuild/linux-ppc64@0.23.0':
222 | optional: true
223 |
224 | '@esbuild/linux-riscv64@0.23.0':
225 | optional: true
226 |
227 | '@esbuild/linux-s390x@0.23.0':
228 | optional: true
229 |
230 | '@esbuild/linux-x64@0.23.0':
231 | optional: true
232 |
233 | '@esbuild/netbsd-x64@0.23.0':
234 | optional: true
235 |
236 | '@esbuild/openbsd-arm64@0.23.0':
237 | optional: true
238 |
239 | '@esbuild/openbsd-x64@0.23.0':
240 | optional: true
241 |
242 | '@esbuild/sunos-x64@0.23.0':
243 | optional: true
244 |
245 | '@esbuild/win32-arm64@0.23.0':
246 | optional: true
247 |
248 | '@esbuild/win32-ia32@0.23.0':
249 | optional: true
250 |
251 | '@esbuild/win32-x64@0.23.0':
252 | optional: true
253 |
254 | chrome-types@0.1.297: {}
255 |
256 | esbuild@0.23.0:
257 | optionalDependencies:
258 | '@esbuild/aix-ppc64': 0.23.0
259 | '@esbuild/android-arm': 0.23.0
260 | '@esbuild/android-arm64': 0.23.0
261 | '@esbuild/android-x64': 0.23.0
262 | '@esbuild/darwin-arm64': 0.23.0
263 | '@esbuild/darwin-x64': 0.23.0
264 | '@esbuild/freebsd-arm64': 0.23.0
265 | '@esbuild/freebsd-x64': 0.23.0
266 | '@esbuild/linux-arm': 0.23.0
267 | '@esbuild/linux-arm64': 0.23.0
268 | '@esbuild/linux-ia32': 0.23.0
269 | '@esbuild/linux-loong64': 0.23.0
270 | '@esbuild/linux-mips64el': 0.23.0
271 | '@esbuild/linux-ppc64': 0.23.0
272 | '@esbuild/linux-riscv64': 0.23.0
273 | '@esbuild/linux-s390x': 0.23.0
274 | '@esbuild/linux-x64': 0.23.0
275 | '@esbuild/netbsd-x64': 0.23.0
276 | '@esbuild/openbsd-arm64': 0.23.0
277 | '@esbuild/openbsd-x64': 0.23.0
278 | '@esbuild/sunos-x64': 0.23.0
279 | '@esbuild/win32-arm64': 0.23.0
280 | '@esbuild/win32-ia32': 0.23.0
281 | '@esbuild/win32-x64': 0.23.0
282 |
283 | prettier@3.3.3: {}
284 |
--------------------------------------------------------------------------------