diff --git a/.env.example b/.env.example index 2b5ae71..c37f8d5 100644 --- a/.env.example +++ b/.env.example @@ -5,6 +5,7 @@ TEXT_ONLY_DOMAINS = "t.fxtwitter.com,t.twittpr.com,t.fixupx.com" INSTANT_VIEW_DOMAINS = "i.fxtwitter.com,i.twittpr.com,i.fixupx.com" INSTANT_VIEW_THREADS_DOMAINS = "u.fxtwitter.com,u.twittpr.com,u.fixupx.com" GALLERY_DOMAINS = "g.fxtwitter.com,g.twittpr.com,g.fixupx.com" +NATIVE_MULTI_IMAGE_DOMAINS = "m.fxtwitter.com,m.twittpr.com,m.fixupx.com" MOSAIC_DOMAIN_LIST = "mosaic.fxtwitter.com" API_HOST_LIST = "api.fxtwitter.com,api-canary.fxtwitter.com" HOST_URL = "https://fxtwitter.com" @@ -13,4 +14,5 @@ EMBED_URL = "https://github.com/FixTweet/FxTwitter" SENTRY_DSN = "" SENTRY_AUTH_TOKEN = "" SENTRY_ORG = "" -SENTRY_PROJECT = "" \ No newline at end of file +SENTRY_PROJECT = "" +GIF_TRANSCODE_DOMAIN = "gif.fxtwitter.com" \ No newline at end of file diff --git a/.github/readme/directmedia.png b/.github/readme/directmedia.png new file mode 100644 index 0000000..1dabccb Binary files /dev/null and b/.github/readme/directmedia.png differ diff --git a/.github/readme/fixtweet.webp b/.github/readme/fixtweet.webp new file mode 100644 index 0000000..605aa64 Binary files /dev/null and b/.github/readme/fixtweet.webp differ diff --git a/.github/readme/gallery.png b/.github/readme/gallery.png new file mode 100644 index 0000000..e255447 Binary files /dev/null and b/.github/readme/gallery.png differ diff --git a/.github/readme/poll.png b/.github/readme/poll.png new file mode 100644 index 0000000..429db1f Binary files /dev/null and b/.github/readme/poll.png differ diff --git a/.github/readme/quote.png b/.github/readme/quote.png new file mode 100644 index 0000000..8ee5a0f Binary files /dev/null and b/.github/readme/quote.png differ diff --git a/.github/readme/tco.png b/.github/readme/tco.png new file mode 100644 index 0000000..1fe31f1 Binary files /dev/null and b/.github/readme/tco.png differ diff --git a/.github/readme/textonly.png b/.github/readme/textonly.png new file mode 100644 index 0000000..9813e23 Binary files /dev/null and b/.github/readme/textonly.png differ diff --git a/.github/readme/translate.png b/.github/readme/translate.png new file mode 100644 index 0000000..59bd00f Binary files /dev/null and b/.github/readme/translate.png differ diff --git a/.github/readme/videos.png b/.github/readme/videos.png new file mode 100644 index 0000000..631a694 Binary files /dev/null and b/.github/readme/videos.png differ diff --git a/README.md b/README.md index cc0bfa0..aa11bb8 100644 --- a/README.md +++ b/README.md @@ -29,13 +29,13 @@ ### For `twitter.com` links on Discord, send a link and type `s/e/p` to make `twittpr.com`. - + ## Embed Videos We all have videos of memes and other things from Twitter we want to quickly share with friends. With normal Twitter links, embedding videos is often broken on Discord and impossible on Telegram. But using FxTwitter, we embed the raw mp4 file so it's compatible with just about anything supporting video embeds. -![](https://cdn.discordapp.com/attachments/165560751363325952/1184627562811494461/video.png) +![](https://raw.githubusercontent.com/FixTweet/FxTwitter/main/.github/readme/videos.png) On Discord, we'll also automatically embed videos linked from other platforms, such as YouTube, so they can play without having to open a browser. @@ -43,13 +43,13 @@ On Discord, we'll also automatically embed videos linked from other platforms, s If you want to share the results of a Twitter poll, you can do so by just linking the post using FxTwitter. -![](https://cdn.discordapp.com/attachments/165560751363325952/1006331192372629544/FixTweet.png) +![](https://raw.githubusercontent.com/FixTweet/FxTwitter/main/.github/readme/poll.png) ## Embed Quotes & Media Quotes and their media can provide important context to a post. So we'll automatically add said context, and even media if there isn't already media embedded in the quote. -![](https://cdn.discordapp.com/attachments/165560751363325952/1184630052797816863/quote.png) +![](https://raw.githubusercontent.com/FixTweet/FxTwitter/main/.github/readme/quote.png) ## Translate Posts @@ -57,19 +57,25 @@ You can translate a post into any other supported language, with the original an Just append a post with its 2-letter ISO language code. So for English, add `/en` at the end. -![](https://cdn.discordapp.com/attachments/165560751363325952/1184625715522572298/translation.png) +![](https://raw.githubusercontent.com/FixTweet/FxTwitter/main/.github/readme/translate.png) ## Gallery view Use `g.fxtwitter.com` or `g.fixupx.com` to generate minimal embeds with just the post's media and author information without other distractions. This can be particularly useful for read-only channels dedicated to sharing media. -![](https://cdn.discordapp.com/attachments/165560751363325952/1182788212482117662/gallery.png) +![](https://raw.githubusercontent.com/FixTweet/FxTwitter/main/.github/readme/gallery.png?a) + +## Text-only view + +Basically the opposite of gallery view, use `t.fxtwitter.com` / `t.fixupx.com` to exclude photos/videos and only display text. + +![](https://raw.githubusercontent.com/FixTweet/FxTwitter/main/.github/readme/textonly.png) ## Direct media links Want to link directly to a post's media without the embed? You can easily do that using FxTwitter. -![Image demonstrating the feature](https://cdn.discordapp.com/attachments/165560751363325952/1006338772192989194/FixTweet.png) +![Image demonstrating the feature](https://raw.githubusercontent.com/FixTweet/FxTwitter/main/.github/readme/directmedia.png) There are a few supported ways to do this: @@ -87,12 +93,12 @@ In the future we plan to do even more with Instant View such as embedding entire Examples from above: -- `https://d.fxtwitter.com/dangeredwolf/status/1548119328498728960` -- `https://fxtwitter.com/dangeredwolf/status/1548117889437208581.jpg` +- `https://d.fxtwitter.com/example/status/1548119328498728960` +- `https://fxtwitter.com/example/status/1548117889437208581.jpg` Posts with multiple images are supported, so you can do something like this and it will pick the correct one: -`https://d.fxtwitter.com/dangeredwolf/status/1547514042146865153/photo/3` +`https://d.fxtwitter.com/example/status/1547514042146865153/photo/3` Otherwise, it will default to the first image. @@ -100,7 +106,7 @@ Otherwise, it will default to the first image. The default Twitter embeds include t.co link shorteners, which make it difficult to know where the link is heading. We automatically replace t.co links with their original links to make things clearer. -![](https://cdn.discordapp.com/attachments/165560751363325952/1006348698659344464/FixTweet.png) +![](https://github.com/FixTweet/FxTwitter/blob/main/.github/readme/tco.png) ## Redirect to Nitter or other custom instances @@ -124,26 +130,26 @@ On a different note, if the person who posted a FxTwitter link forgot to strip t In many ways, FxTwitter has richer embeds and does more. Here's a table comparing some of FxTwitter's features compared to Twitter default embeds as well as other embedding services -| | FxTwitter | Twitter default | vxTwitter (BetterTwitFix) | -| -------------------------------------- | :------------------------------------------------: | :------------------------------: | :-------------------------------------------------: | -| Embed Posts / Images | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | -| Embed profile pictures on text posts | :heavy_check_mark: | :x: | :heavy_check_mark: | -| Embed Twitter Videos | :heavy_check_mark: | :heavy_minus_sign: Discord Only¹ | :heavy_check_mark: | -| Embed External Videos (YouTube, etc.) | :heavy_check_mark:⁴ | :x: | :x:³ | -| Embed Poll results | :heavy_check_mark: | :x: | [:heavy_check_mark:][polladd] | -| Embed Quotes | :heavy_check_mark: | :x: | :ballot_box_with_check: Without Media | -| Embed Multiple Images | :heavy_check_mark: | :heavy_minus_sign: Discord Only² | :heavy_check_mark: | -| Translate Posts | :heavy_check_mark: | :x: | :x: | -| Replace t.co with original links | :heavy_check_mark: | :x: | :heavy_check_mark: | -| Redirect to media file (without embed) | :heavy_check_mark: | :x: | :ballot_box_with_check: Subdomain broken, no images | -| Gallery view | :heavy_check_mark: | :x: | :x: | -| Strip tracking info on redirect | :heavy_check_mark: | :x: | :heavy_check_mark: | -| Show retweet, like, reply, view counts | :heavy_minus_sign: Discord / Telegram Instant View | :heavy_minus_sign: Discord Only² | :ballot_box_with_check: No replies / views | -| Discord sed replace (`s/`) friendly | :ballot_box_with_check: twittpr.com | N/A | :x: | -| Domain for X.com links | :ballot_box_with_check: fixupx.com | N/A | :ballot_box_with_check: fixvx.com | -| Telegram Instant View | :heavy_check_mark: | :x: | :x: | -| Status fetch API for Developers | :heavy_check_mark: | N/A | :heavy_check_mark: | -| Last commit | [![][flc]][fc] | N/A | [![][vlc]][vc] | +| | FxTwitter | Twitter default | vxTwitter (BetterTwitFix) | +| -------------------------------------- | :------------------------------------------------: | :----------------: | :-------------------------------------------------: | +| Embed Posts / Images | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | +| Embed profile pictures on text posts | :heavy_check_mark: | :x: | :heavy_check_mark: | +| Embed Twitter Videos | :heavy_check_mark: | :x: | :heavy_check_mark: | +| Embed External Videos (YouTube, etc.) | :heavy_check_mark:⁴ | :x: | :x:³ | +| Embed Poll results | :heavy_check_mark: | :x: | [:heavy_check_mark:][polladd] | +| Embed Quotes | :heavy_check_mark: | :x: | :ballot_box_with_check: Without Media | +| Embed Multiple Images | :heavy_check_mark: | :x: | :heavy_check_mark: | +| Translate Posts | :heavy_check_mark: | :x: | :x: | +| Replace t.co with original links | :heavy_check_mark: | :x: | :heavy_check_mark: | +| Redirect to media file (without embed) | :heavy_check_mark: | :x: | :ballot_box_with_check: Subdomain broken, no images | +| Gallery view | :heavy_check_mark: | :x: | :x: | +| Strip tracking info on redirect | :heavy_check_mark: | :x: | :heavy_check_mark: | +| Show retweet, like, reply, view counts | :heavy_minus_sign: Discord / Telegram Instant View | :x: | :ballot_box_with_check: No replies / views | +| Discord sed replace (`s/`) friendly | :ballot_box_with_check: twittpr.com | N/A | :x: | +| Domain for X.com links | :ballot_box_with_check: fixupx.com | N/A | :ballot_box_with_check: fixvx.com | +| Telegram Instant View | :heavy_check_mark: | :x: | :x: | +| Status fetch API for Developers | :heavy_check_mark: | N/A | :heavy_check_mark: | +| Last commit | [![][flc]][fc] | N/A | [![][vlc]][vc] | [flc]: https://img.shields.io/github/last-commit/FixTweet/FxTwitter?label [vlc]: https://img.shields.io/github/last-commit/dylanpdx/BetterTwitFix?label @@ -228,3 +234,7 @@ Feel free to [open an issue](https://github.com/FixTweet/FxTwitter/issues) [Mosaic](https://github.com/FixTweet/mosaic) Multi-image combiner by [Antonio32A](https://github.com/Antonio32A) & other contributions by [Antonio32A](https://github.com/Antonio32A), [Burner](https://github.com/YaBoiBurner), [Deer-Spangle](https://github.com/Deer-Spangle), [Eramdam](https://github.com/Eramdam), [SirStendec](https://github.com/SirStendec), [SpeedyFolf](https://github.com/SpeedyFolf), [Wazbat](https://github.com/Wazbat) + +## Disclaimer + +Twitter, Tweet, and X are trademarks of X Corp. This project is not affiliated in any way with X Corp or Twitter. diff --git a/esbuild.config.mjs b/esbuild.config.mjs index 41c4c35..959ca2c 100644 --- a/esbuild.config.mjs +++ b/esbuild.config.mjs @@ -39,12 +39,14 @@ let envVariables = [ 'INSTANT_VIEW_DOMAINS', 'INSTANT_VIEW_THREADS_DOMAINS', 'GALLERY_DOMAINS', + 'NATIVE_MULTI_IMAGE_DOMAINS', 'HOST_URL', 'REDIRECT_URL', 'EMBED_URL', 'MOSAIC_DOMAIN_LIST', 'API_HOST_LIST', - 'SENTRY_DSN' + 'SENTRY_DSN', + 'GIF_TRANSCODE_DOMAIN' ]; // Create defines for all environment variables diff --git a/jestconfig.json b/jestconfig.json index 8a4d5eb..9132585 100644 --- a/jestconfig.json +++ b/jestconfig.json @@ -9,6 +9,7 @@ "INSTANT_VIEW_DOMAINS": "i.fxtwitter.com,i.twittpr.com,i.fixupx.com", "INSTANT_VIEW_THREADS_DOMAINS": "u.fxtwitter.com,u.twittpr.com,u.fixupx.com", "GALLERY_DOMAINS": "g.fxtwitter.com,g.twittpr.com,g.fixupx.com", + "NATIVE_MULTI_IMAGE_DOMAINS": "m.fxtwitter.com,m.twittpr.com,m.fixupx.com", "STANDARD_DOMAIN_LIST": "fxtwitter.com,fixupx.com,twittpr.com", "DIRECT_MEDIA_DOMAINS": "d.fxtwitter.com,dl.fxtwitter.com,d.fixupx.com,dl.fixupx.com", "MOSAIC_DOMAIN_LIST": "mosaic.fxtwitter.com", diff --git a/package-lock.json b/package-lock.json index 237339b..2b0115d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,30 +9,30 @@ "version": "1.0.0", "license": "MIT", "dependencies": { - "@hono/sentry": "^1.0.0", - "hono": "^3.12.3" + "@hono/sentry": "^1.0.1", + "hono": "^3.12.12" }, "devDependencies": { - "@cloudflare/workers-types": "^4.20231218.0", - "@microsoft/eslint-formatter-sarif": "^3.0.0", - "@sentry/esbuild-plugin": "^2.10.2", - "@sentry/integrations": "^7.93.0", - "@types/jest": "^29.5.11", - "@typescript-eslint/eslint-plugin": "^6.18.1", - "@typescript-eslint/parser": "^6.18.1", - "dotenv": "^16.3.1", - "eslint": "^8.56.0", + "@cloudflare/workers-types": "^4.20240423.0", + "@microsoft/eslint-formatter-sarif": "^3.1.0", + "@sentry/esbuild-plugin": "^2.16.1", + "@sentry/integrations": "^7.112.2", + "@types/jest": "^29.5.12", + "@typescript-eslint/eslint-plugin": "^7.7.1", + "@typescript-eslint/parser": "^7.7.1", + "dotenv": "^16.4.5", + "eslint": "^8.57.0", "eslint-config-prettier": "^9.1.0", "eslint-config-typescript": "^3.0.0", "eslint-plugin-optimize-regex": "^1.2.1", - "eslint-plugin-sonarjs": "^0.23.0", + "eslint-plugin-sonarjs": "^0.25.1", "jest": "^29.7.0", - "jest-environment-miniflare": "^2.14.1", - "prettier": "^3.2.2", - "ts-jest": "^29.1.1", + "jest-environment-miniflare": "^2.14.2", + "prettier": "^3.2.5", + "ts-jest": "^29.1.2", "ts-loader": "^9.5.1", - "typescript": "^5.3.3", - "wrangler": "^3.22.4" + "typescript": "^5.4.5", + "wrangler": "^3.51.2" } }, "node_modules/@aashutoshrathi/word-wrap": { @@ -45,61 +45,61 @@ } }, "node_modules/@ampproject/remapping": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", - "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", "dev": true, "dependencies": { - "@jridgewell/gen-mapping": "^0.3.0", - "@jridgewell/trace-mapping": "^0.3.9" + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" }, "engines": { "node": ">=6.0.0" } }, "node_modules/@babel/code-frame": { - "version": "7.23.5", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz", - "integrity": "sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==", + "version": "7.24.2", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.2.tgz", + "integrity": "sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==", "dev": true, "dependencies": { - "@babel/highlight": "^7.23.4", - "chalk": "^2.4.2" + "@babel/highlight": "^7.24.2", + "picocolors": "^1.0.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/compat-data": { - "version": "7.23.5", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.5.tgz", - "integrity": "sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw==", + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.4.tgz", + "integrity": "sha512-vg8Gih2MLK+kOkHJp4gBEIkyaIi00jgWot2D9QOmmfLC8jINSOzmCLta6Bvz/JSBCqnegV0L80jhxkol5GWNfQ==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.18.5", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.18.5.tgz", - "integrity": "sha512-MGY8vg3DxMnctw0LdvSEojOsumc70g0t18gNyUdAZqB1Rpd1Bqo/svHGvt+UJ6JcGX+DIekGFDxxIWofBxLCnQ==", + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.4.tgz", + "integrity": "sha512-MBVlMXP+kkl5394RBLSxxk/iLTeVGuXTV3cIDXavPpMMqnSnt6apKgan/U8O3USWZCWZT/TbgfEpKa4uMgN4Dg==", "dev": true, "dependencies": { - "@ampproject/remapping": "^2.1.0", - "@babel/code-frame": "^7.16.7", - "@babel/generator": "^7.18.2", - "@babel/helper-compilation-targets": "^7.18.2", - "@babel/helper-module-transforms": "^7.18.0", - "@babel/helpers": "^7.18.2", - "@babel/parser": "^7.18.5", - "@babel/template": "^7.16.7", - "@babel/traverse": "^7.18.5", - "@babel/types": "^7.18.4", - "convert-source-map": "^1.7.0", + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.24.2", + "@babel/generator": "^7.24.4", + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helpers": "^7.24.4", + "@babel/parser": "^7.24.4", + "@babel/template": "^7.24.0", + "@babel/traverse": "^7.24.1", + "@babel/types": "^7.24.0", + "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", - "json5": "^2.2.1", - "semver": "^6.3.0" + "json5": "^2.2.3", + "semver": "^6.3.1" }, "engines": { "node": ">=6.9.0" @@ -110,14 +110,14 @@ } }, "node_modules/@babel/generator": { - "version": "7.23.6", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.6.tgz", - "integrity": "sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw==", + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.4.tgz", + "integrity": "sha512-Xd6+v6SnjWVx/nus+y0l1sxMOTOMBkyL4+BIdbALyatQnAe/SRVjANeDPSCYaX+i1iJmuGSKf3Z+E+V/va1Hvw==", "dev": true, "dependencies": { - "@babel/types": "^7.23.6", - "@jridgewell/gen-mapping": "^0.3.2", - "@jridgewell/trace-mapping": "^0.3.17", + "@babel/types": "^7.24.0", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", "jsesc": "^2.5.1" }, "engines": { @@ -175,12 +175,12 @@ } }, "node_modules/@babel/helper-module-imports": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz", - "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==", + "version": "7.24.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.3.tgz", + "integrity": "sha512-viKb0F9f2s0BCS22QSF308z/+1YWKV/76mwt61NBzS5izMzDPwdq1pTrzf+Li3npBWX9KdQbkeCt1jSAM7lZqg==", "dev": true, "dependencies": { - "@babel/types": "^7.22.15" + "@babel/types": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -239,9 +239,9 @@ } }, "node_modules/@babel/helper-string-parser": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz", - "integrity": "sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.1.tgz", + "integrity": "sha512-2ofRCjnnA9y+wk8b9IAREroeUP02KHp431N2mhKniy2yKIDKpbrHv9eXwm8cBeWQYcJmzv5qKCu65P47eCF7CQ==", "dev": true, "engines": { "node": ">=6.9.0" @@ -266,13 +266,13 @@ } }, "node_modules/@babel/helpers": { - "version": "7.24.0", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.0.tgz", - "integrity": "sha512-ulDZdc0Aj5uLc5nETsa7EPx2L7rM0YJM8r7ck7U73AXi7qOV44IHHRAYZHY6iU1rr3C5N4NtTmMRUJP6kwCWeA==", + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.4.tgz", + "integrity": "sha512-FewdlZbSiwaVGlgT1DPANDuCHaDMiOo+D/IDYRFYjHOuv66xMSJ7fQwwODwRNAPkADIO/z1EoF/l2BCWlWABDw==", "dev": true, "dependencies": { "@babel/template": "^7.24.0", - "@babel/traverse": "^7.24.0", + "@babel/traverse": "^7.24.1", "@babel/types": "^7.24.0" }, "engines": { @@ -280,23 +280,24 @@ } }, "node_modules/@babel/highlight": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz", - "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==", + "version": "7.24.2", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.2.tgz", + "integrity": "sha512-Yac1ao4flkTxTteCDZLEvdxg2fZfz1v8M4QpaGypq/WPDqg3ijHYbDfs+LG5hvzSoqaSZ9/Z9lKSP3CjZjv+pA==", "dev": true, "dependencies": { "@babel/helper-validator-identifier": "^7.22.20", "chalk": "^2.4.2", - "js-tokens": "^4.0.0" + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/parser": { - "version": "7.24.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.0.tgz", - "integrity": "sha512-QuP/FxEAzMSjXygs8v4N9dvdXzEHN4W1oF3PxuWAtPo08UdM17u89RDMgjLn/mlc56iM0HlLmVkO/wgR+rDgHg==", + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.4.tgz", + "integrity": "sha512-zTvEBcghmeBma9QIGunWevvBAp4/Qu9Bdq+2k0Ot4fVMD6v3dsC9WOcRSKk7tRRyBM/53yKMJko9xOatGQAwSg==", "dev": true, "bin": { "parser": "bin/babel-parser.js" @@ -366,12 +367,12 @@ } }, "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.23.3.tgz", - "integrity": "sha512-EB2MELswq55OHUoRZLGg/zC7QWUKfNLpE57m/S2yr1uEneIgsTgrSzXP3NXEsMkVn76OlaVVnzN+ugObuYGwhg==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.1.tgz", + "integrity": "sha512-2eCtxZXf+kbkMIsXS4poTvT4Yu5rXiRa+9xGVT56raghjmBTKMpFNc9R4IDiB4emao9eO22Ox7CxuJG7BgExqA==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -468,12 +469,12 @@ } }, "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.23.3.tgz", - "integrity": "sha512-9EiNjVJOMwCO+43TqoTrgQ8jMwcAd0sWyXi9RPfIsLTj4R2MADDDQXELhffaUx/uJv2AYcxBgPwH6j4TIA4ytQ==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.24.1.tgz", + "integrity": "sha512-Yhnmvy5HZEnHUty6i++gcfH1/l68AHnItFHnaCv6hn9dNh0hQvvQJsxpi4BMBFN5DLeHBuucT/0DgzXif/OyRw==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -497,18 +498,18 @@ } }, "node_modules/@babel/traverse": { - "version": "7.24.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.0.tgz", - "integrity": "sha512-HfuJlI8qq3dEDmNU5ChzzpZRWq+oxCZQyMzIMEqLho+AQnhMnKQUzH6ydo3RBl/YjPCuk68Y6s0Gx0AeyULiWw==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.1.tgz", + "integrity": "sha512-xuU6o9m68KeqZbQuDt2TcKSxUw/mrsvavlEqQ1leZ/B+C9tk6E4sRWy97WaXgvq5E+nU3cXMxv3WKOCanVMCmQ==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.23.5", - "@babel/generator": "^7.23.6", + "@babel/code-frame": "^7.24.1", + "@babel/generator": "^7.24.1", "@babel/helper-environment-visitor": "^7.22.20", "@babel/helper-function-name": "^7.23.0", "@babel/helper-hoist-variables": "^7.22.5", "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/parser": "^7.24.0", + "@babel/parser": "^7.24.1", "@babel/types": "^7.24.0", "debug": "^4.3.1", "globals": "^11.1.0" @@ -547,9 +548,9 @@ } }, "node_modules/@cloudflare/workerd-darwin-64": { - "version": "1.20240223.1", - "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-64/-/workerd-darwin-64-1.20240223.1.tgz", - "integrity": "sha512-GgHnvkazLFZ7bmR96+dTX0+WS13a+5CHOOP3qNUSR9oEnR4hHzpNIO75MuZsm9RPAXrvtT7nSJmYwiGCZXh6og==", + "version": "1.20240405.0", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-64/-/workerd-darwin-64-1.20240405.0.tgz", + "integrity": "sha512-ut8kwpHmlz9dNSjoov6v1b6jS50J46Mj9QcMA0t1Hne36InaQk/qqPSd12fN5p2GesZ9OOBJvBdDsTblVdyJ1w==", "cpu": [ "x64" ], @@ -563,9 +564,9 @@ } }, "node_modules/@cloudflare/workerd-darwin-arm64": { - "version": "1.20240223.1", - "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-arm64/-/workerd-darwin-arm64-1.20240223.1.tgz", - "integrity": "sha512-ZF98vUmVlC0EVEd3RRuhMq4HYWFcqmPtMIMPUN2+ivEHR92TE+6E/AvdeE6wcE7fKHQ+fk3dH+ZgB0GcfptfnA==", + "version": "1.20240405.0", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-arm64/-/workerd-darwin-arm64-1.20240405.0.tgz", + "integrity": "sha512-x3A3Ym+J2DH1uYnw0aedeKOTnUebEo312+Aladv7bFri97pjRJcqVbYhMtOHLkHjwYn7bpKSY2eL5iM+0XT29A==", "cpu": [ "arm64" ], @@ -579,9 +580,9 @@ } }, "node_modules/@cloudflare/workerd-linux-64": { - "version": "1.20240223.1", - "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-64/-/workerd-linux-64-1.20240223.1.tgz", - "integrity": "sha512-1kH41ewNTGMmAk2zUX0Xj9VSfidl26GQ0ZrWMdi5kwf6gAHd3oVWNigJN078Jx56SgQxNcqVGX1LunqF949asw==", + "version": "1.20240405.0", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-64/-/workerd-linux-64-1.20240405.0.tgz", + "integrity": "sha512-3tYpfjtxEQ0R30Pna7OF3Bz0CTx30hc0QNtH61KnkvXtaeYMkWutSKQKXIuVlPa/7v1MHp+8ViBXMflmS7HquA==", "cpu": [ "x64" ], @@ -595,9 +596,9 @@ } }, "node_modules/@cloudflare/workerd-linux-arm64": { - "version": "1.20240223.1", - "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-arm64/-/workerd-linux-arm64-1.20240223.1.tgz", - "integrity": "sha512-Ro8Og5C4evh890JrRm0B8sHyumRtgL+mUqPeNcEsyG45jAQy5xHpapHnmJAMJV6ah+zDc1cZtQq+en39SojXvQ==", + "version": "1.20240405.0", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-arm64/-/workerd-linux-arm64-1.20240405.0.tgz", + "integrity": "sha512-NpKZlvmdgcX/m4tP5zM91AfJpZrue2/GRA+Sl3szxAivu2uE5jDVf5SS9dzqzCVfPrdhylqH7yeL4U/cafFNOg==", "cpu": [ "arm64" ], @@ -611,9 +612,9 @@ } }, "node_modules/@cloudflare/workerd-windows-64": { - "version": "1.20240223.1", - "resolved": "https://registry.npmjs.org/@cloudflare/workerd-windows-64/-/workerd-windows-64-1.20240223.1.tgz", - "integrity": "sha512-eNP5sfaP6WL07DaoigYou5ASPF7jHsFiNzzD2vGOI7yFd5sPlb7sJ4SpIy+BCX0LdqFnjmlUo5Xr+/I6qJ2Nww==", + "version": "1.20240405.0", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-windows-64/-/workerd-windows-64-1.20240405.0.tgz", + "integrity": "sha512-REBeJMxvUCjwuEVzSSIBtzAyM69QjToab8qBst0S9vdih+9DObym4dw8CevdBQhDbFrHiyL9E6pAZpLPNHVgCw==", "cpu": [ "x64" ], @@ -627,9 +628,9 @@ } }, "node_modules/@cloudflare/workers-types": { - "version": "4.20240222.0", - "resolved": "https://registry.npmjs.org/@cloudflare/workers-types/-/workers-types-4.20240222.0.tgz", - "integrity": "sha512-luO0BdK3rLlCv3B240+cTrfqm+XSbHtpk+88aJtGwzyVK9QF/Xz8lBgE/oZZLN8nCTmOvxAZnszyxUuZ8GP8Cg==", + "version": "4.20240423.0", + "resolved": "https://registry.npmjs.org/@cloudflare/workers-types/-/workers-types-4.20240423.0.tgz", + "integrity": "sha512-ssuccb3j+URp6mP2p0PcQE9vmS3YeKBQnALHF9P3yQfUAFozuhTsDTbqmL+zPrJvUcG7SL2xVQkNDF9QJeKDZw==", "dev": true }, "node_modules/@cspotcode/source-map-support": { @@ -1215,9 +1216,9 @@ } }, "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz", - "integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", + "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", "dev": true }, "node_modules/@iarna/toml": { @@ -1896,12 +1897,6 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "node_modules/@jest/transform/node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true - }, "node_modules/@jest/transform/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -2011,14 +2006,14 @@ } }, "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.4", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.4.tgz", - "integrity": "sha512-Oud2QPM5dHviZNn4y/WhhYKSXksv+1xLEIsNrAbGcFzUN3ubqWRFT5gwPchNc5NuzILOU4tPBDTZ4VwhL8Y7cw==", + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", "dev": true, "dependencies": { - "@jridgewell/set-array": "^1.0.1", + "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" + "@jridgewell/trace-mapping": "^0.3.24" }, "engines": { "node": ">=6.0.0" @@ -2043,14 +2038,14 @@ } }, "node_modules/@jridgewell/source-map": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.5.tgz", - "integrity": "sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==", + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", + "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", "dev": true, "peer": true, "dependencies": { - "@jridgewell/gen-mapping": "^0.3.0", - "@jridgewell/trace-mapping": "^0.3.9" + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" } }, "node_modules/@jridgewell/sourcemap-codec": { @@ -2060,9 +2055,9 @@ "dev": true }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.23", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.23.tgz", - "integrity": "sha512-9/4foRoUKp8s96tSkh8DlAAc5A0Ty8vLXld+l9gjKKY6ckwI8G15f0hskGmuLZu78ZlGa1vtsfOa+lnB4vG6Jg==", + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", "dev": true, "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", @@ -2070,9 +2065,9 @@ } }, "node_modules/@microsoft/eslint-formatter-sarif": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@microsoft/eslint-formatter-sarif/-/eslint-formatter-sarif-3.0.0.tgz", - "integrity": "sha512-KIKkT44hEqCzqxODYwFMUvYEK0CrdHx/Ll9xiOWgFbBSRuzbxmVy4d/tzfgoucGz72HJZNOMjuyzFTBKntRK5Q==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@microsoft/eslint-formatter-sarif/-/eslint-formatter-sarif-3.1.0.tgz", + "integrity": "sha512-/mn4UXziHzGXnKCg+r8HGgPy+w4RzpgdoqFuqaKOqUVBT5x2CygGefIrO4SusaY7t0C4gyIWMNu6YQT6Jw64Cw==", "dev": true, "dependencies": { "eslint": "^8.9.0", @@ -2363,27 +2358,27 @@ } }, "node_modules/@sentry/babel-plugin-component-annotate": { - "version": "2.14.2", - "resolved": "https://registry.npmjs.org/@sentry/babel-plugin-component-annotate/-/babel-plugin-component-annotate-2.14.2.tgz", - "integrity": "sha512-mFBVnIZmdMrpxo61rG5yf0WFt5VrRpy8cpIpJtT3mYkX9vDmcUZaZaD1ctv73iZF3QwaieVdn05Na5mWzZ8h/A==", + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/@sentry/babel-plugin-component-annotate/-/babel-plugin-component-annotate-2.16.1.tgz", + "integrity": "sha512-pJka66URsqQbk6hTs9H1XFpUeI0xxuqLYf9Dy5pRGNHSJMtfv91U+CaYSWt03aRRMGDXMduh62zAAY7Wf0HO+A==", "dev": true, "engines": { "node": ">= 14" } }, "node_modules/@sentry/bundler-plugin-core": { - "version": "2.14.2", - "resolved": "https://registry.npmjs.org/@sentry/bundler-plugin-core/-/bundler-plugin-core-2.14.2.tgz", - "integrity": "sha512-HgOFWYdq87lSmeVW1w8K2Vf2DGzRPvKzHTajZYLTPlrZ1jbajq9vwuqhrJ9AnDkjl0mjyzSPEy3ZTeG1Z7uRNA==", + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/@sentry/bundler-plugin-core/-/bundler-plugin-core-2.16.1.tgz", + "integrity": "sha512-n6z8Ts3T9HROLuY7tVEYpBKvS+P7+b8NdqxP7QBcwp2nuPUlN5Ola1ivFjk1p5a7wRYeN9zM8orGe4l2HeNfYA==", "dev": true, "dependencies": { - "@babel/core": "7.18.5", - "@sentry/babel-plugin-component-annotate": "2.14.2", + "@babel/core": "^7.18.5", + "@sentry/babel-plugin-component-annotate": "2.16.1", "@sentry/cli": "^2.22.3", "dotenv": "^16.3.1", - "find-up": "5.0.0", - "glob": "9.3.2", - "magic-string": "0.27.0", + "find-up": "^5.0.0", + "glob": "^9.3.2", + "magic-string": "0.30.8", "unplugin": "1.0.1" }, "engines": { @@ -2391,9 +2386,9 @@ } }, "node_modules/@sentry/cli": { - "version": "2.28.6", - "resolved": "https://registry.npmjs.org/@sentry/cli/-/cli-2.28.6.tgz", - "integrity": "sha512-o2Ngz7xXuhwHxMi+4BFgZ4qjkX0tdZeOSIZkFAGnTbRhQe5T8bxq6CcQRLdPhqMgqvDn7XuJ3YlFtD3ZjHvD7g==", + "version": "2.31.0", + "resolved": "https://registry.npmjs.org/@sentry/cli/-/cli-2.31.0.tgz", + "integrity": "sha512-nCESoXAG3kRUO5n3QbDYAqX6RU3z1ORjnd7a3sqijYsCGHfOpcjGdS7JYLVg5if+tXMEF5529BPXFe5Kg/J9tw==", "dev": true, "hasInstallScript": true, "dependencies": { @@ -2410,19 +2405,19 @@ "node": ">= 10" }, "optionalDependencies": { - "@sentry/cli-darwin": "2.28.6", - "@sentry/cli-linux-arm": "2.28.6", - "@sentry/cli-linux-arm64": "2.28.6", - "@sentry/cli-linux-i686": "2.28.6", - "@sentry/cli-linux-x64": "2.28.6", - "@sentry/cli-win32-i686": "2.28.6", - "@sentry/cli-win32-x64": "2.28.6" + "@sentry/cli-darwin": "2.31.0", + "@sentry/cli-linux-arm": "2.31.0", + "@sentry/cli-linux-arm64": "2.31.0", + "@sentry/cli-linux-i686": "2.31.0", + "@sentry/cli-linux-x64": "2.31.0", + "@sentry/cli-win32-i686": "2.31.0", + "@sentry/cli-win32-x64": "2.31.0" } }, "node_modules/@sentry/cli-darwin": { - "version": "2.28.6", - "resolved": "https://registry.npmjs.org/@sentry/cli-darwin/-/cli-darwin-2.28.6.tgz", - "integrity": "sha512-KRf0VvTltHQ5gA7CdbUkaIp222LAk/f1+KqpDzO6nB/jC/tL4sfiy6YyM4uiH6IbVEudB8WpHCECiatmyAqMBA==", + "version": "2.31.0", + "resolved": "https://registry.npmjs.org/@sentry/cli-darwin/-/cli-darwin-2.31.0.tgz", + "integrity": "sha512-VM5liyxMnm4K2g0WsrRPXRCMLhaT09C7gK5Fz/CxKYh9sbMZB7KA4hV/3klkyuyw1+ECF1J66cefhNkFZepUig==", "dev": true, "optional": true, "os": [ @@ -2433,9 +2428,9 @@ } }, "node_modules/@sentry/cli-linux-arm": { - "version": "2.28.6", - "resolved": "https://registry.npmjs.org/@sentry/cli-linux-arm/-/cli-linux-arm-2.28.6.tgz", - "integrity": "sha512-ANG7U47yEHD1g3JrfhpT4/MclEvmDZhctWgSP5gVw5X4AlcI87E6dTqccnLgvZjiIAQTaJJAZuSHVVF3Jk403w==", + "version": "2.31.0", + "resolved": "https://registry.npmjs.org/@sentry/cli-linux-arm/-/cli-linux-arm-2.31.0.tgz", + "integrity": "sha512-AZoCN3waXEfXGCd3YSrikcX/y63oQe0Tiyapkeoifq/0QhI+2MOOrAQb60gthsXwb0UDK/XeFi3PaxyUCphzxA==", "cpu": [ "arm" ], @@ -2450,9 +2445,9 @@ } }, "node_modules/@sentry/cli-linux-arm64": { - "version": "2.28.6", - "resolved": "https://registry.npmjs.org/@sentry/cli-linux-arm64/-/cli-linux-arm64-2.28.6.tgz", - "integrity": "sha512-caMDt37FI752n4/3pVltDjlrRlPFCOxK4PHvoZGQ3KFMsai0ZhE/0CLBUMQqfZf0M0r8KB2x7wqLm7xSELjefQ==", + "version": "2.31.0", + "resolved": "https://registry.npmjs.org/@sentry/cli-linux-arm64/-/cli-linux-arm64-2.31.0.tgz", + "integrity": "sha512-eENJTmXoFX3uNr8xRW7Bua2Sw3V1tylQfdtS85pNjZPdbm3U8wYQSWu2VoZkK2ASOoC+17YC8jTQxq62KWnSeQ==", "cpu": [ "arm64" ], @@ -2467,9 +2462,9 @@ } }, "node_modules/@sentry/cli-linux-i686": { - "version": "2.28.6", - "resolved": "https://registry.npmjs.org/@sentry/cli-linux-i686/-/cli-linux-i686-2.28.6.tgz", - "integrity": "sha512-Tj1+GMc6lFsDRquOqaGKXFpW9QbmNK4TSfynkWKiJxdTEn5jSMlXXfr0r9OQrxu3dCCqEHkhEyU63NYVpgxIPw==", + "version": "2.31.0", + "resolved": "https://registry.npmjs.org/@sentry/cli-linux-i686/-/cli-linux-i686-2.31.0.tgz", + "integrity": "sha512-cQUFb3brhLaNSIoNzjU/YASnTM1I3TDJP9XXzH0eLK9sSopCcDcc6OrYEYvdjJXZKzFv5sbc9UNMsIDbh4+rYg==", "cpu": [ "x86", "ia32" @@ -2485,9 +2480,9 @@ } }, "node_modules/@sentry/cli-linux-x64": { - "version": "2.28.6", - "resolved": "https://registry.npmjs.org/@sentry/cli-linux-x64/-/cli-linux-x64-2.28.6.tgz", - "integrity": "sha512-Dt/Xz784w/z3tEObfyJEMmRIzn0D5qoK53H9kZ6e0yNvJOSKNCSOq5cQk4n1/qeG0K/6SU9dirmvHwFUiVNyYg==", + "version": "2.31.0", + "resolved": "https://registry.npmjs.org/@sentry/cli-linux-x64/-/cli-linux-x64-2.31.0.tgz", + "integrity": "sha512-z1zTNg91nZJRdcGHC/bCU1KwIaifV0MLJteip9KrFDprzhJk1HtMxFOS0+OZ5/UH21CjAFmg9Pj6IAGqm3BYjA==", "cpu": [ "x64" ], @@ -2502,9 +2497,9 @@ } }, "node_modules/@sentry/cli-win32-i686": { - "version": "2.28.6", - "resolved": "https://registry.npmjs.org/@sentry/cli-win32-i686/-/cli-win32-i686-2.28.6.tgz", - "integrity": "sha512-zkpWtvY3kt+ogVaAbfFr2MEkgMMHJNJUnNMO8Ixce9gh38sybIkDkZNFnVPBXMClJV0APa4QH0EwumYBFZUMuQ==", + "version": "2.31.0", + "resolved": "https://registry.npmjs.org/@sentry/cli-win32-i686/-/cli-win32-i686-2.31.0.tgz", + "integrity": "sha512-+K7fdk57aUd4CmYrQfDGYPzVyxsTnVro6IPb5QSSLpP03dL7ko5208epu4m2SyN/MkFvscy9Di3n3DTvIfDU2w==", "cpu": [ "x86", "ia32" @@ -2519,9 +2514,9 @@ } }, "node_modules/@sentry/cli-win32-x64": { - "version": "2.28.6", - "resolved": "https://registry.npmjs.org/@sentry/cli-win32-x64/-/cli-win32-x64-2.28.6.tgz", - "integrity": "sha512-TG2YzZ9JMeNFzbicdr5fbtsusVGACbrEfHmPgzWGDeLUP90mZxiMTjkXsE1X/5jQEQjB2+fyfXloba/Ugo51hA==", + "version": "2.31.0", + "resolved": "https://registry.npmjs.org/@sentry/cli-win32-x64/-/cli-win32-x64-2.31.0.tgz", + "integrity": "sha512-w5cvpZ6VVlhlyleY8TYHmrP7g48vKHnoVt5xFccfxT+HqQI/AxodvzgVvBTM2kB/sh/kHwexp6bJGWCdkGftww==", "cpu": [ "x64" ], @@ -2535,25 +2530,25 @@ } }, "node_modules/@sentry/core": { - "version": "7.103.0", - "resolved": "https://registry.npmjs.org/@sentry/core/-/core-7.103.0.tgz", - "integrity": "sha512-LCI+PIDoF/RLqN41fNXum3ilmS6ukni6L7t38vSdibbe2G0804EbPLtOIpv2PkS8E6CFuRW5zOb+8OwEAAtZWw==", + "version": "7.112.2", + "resolved": "https://registry.npmjs.org/@sentry/core/-/core-7.112.2.tgz", + "integrity": "sha512-gHPCcJobbMkk0VR18J65WYQTt3ED4qC6X9lHKp27Ddt63E+MDGkG6lvYBU1LS8cV7CdyBGC1XXDCfor61GvLsA==", "dev": true, "dependencies": { - "@sentry/types": "7.103.0", - "@sentry/utils": "7.103.0" + "@sentry/types": "7.112.2", + "@sentry/utils": "7.112.2" }, "engines": { "node": ">=8" } }, "node_modules/@sentry/esbuild-plugin": { - "version": "2.14.2", - "resolved": "https://registry.npmjs.org/@sentry/esbuild-plugin/-/esbuild-plugin-2.14.2.tgz", - "integrity": "sha512-ciumtibhxguf47xLwQmhzotdQiHFqiifcROnjU2VACub/GD+2cpz6rnKU5BAPTo13UIR0+Nask/xYmZkpMbGog==", + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/@sentry/esbuild-plugin/-/esbuild-plugin-2.16.1.tgz", + "integrity": "sha512-xwkuDKxNfEL8hMjlD/ByjmTeC1QiLULTsmdiYFjlz9HcYUtjU175V+cmOKqWrXAg/j3DmPZM9zNS9sdg3E7oVg==", "dev": true, "dependencies": { - "@sentry/bundler-plugin-core": "2.14.2", + "@sentry/bundler-plugin-core": "2.16.1", "unplugin": "1.0.1", "uuid": "^9.0.0" }, @@ -2562,14 +2557,14 @@ } }, "node_modules/@sentry/integrations": { - "version": "7.103.0", - "resolved": "https://registry.npmjs.org/@sentry/integrations/-/integrations-7.103.0.tgz", - "integrity": "sha512-jS1vQqBBF776xFpht4xS5cJRztbpskFELeZX57pELzy/J7PNjbO0/oypP1qK7budMxxkazJhkcNwJw9eUFT0pg==", + "version": "7.112.2", + "resolved": "https://registry.npmjs.org/@sentry/integrations/-/integrations-7.112.2.tgz", + "integrity": "sha512-ioC2yyU6DqtLkdmWnm87oNvdn2+9oKctJeA4t+jkS6JaJ10DcezjCwiLscX4rhB9aWJV3IWF7Op0O6K3w0t2Hg==", "dev": true, "dependencies": { - "@sentry/core": "7.103.0", - "@sentry/types": "7.103.0", - "@sentry/utils": "7.103.0", + "@sentry/core": "7.112.2", + "@sentry/types": "7.112.2", + "@sentry/utils": "7.112.2", "localforage": "^1.8.1" }, "engines": { @@ -2577,21 +2572,21 @@ } }, "node_modules/@sentry/types": { - "version": "7.103.0", - "resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.103.0.tgz", - "integrity": "sha512-NCvKyx8d2AGBQKPARrJemZmZ16DiMo688OEikZg4BbvFNDUzK5Egm2BH0vfLDhbNkU19o3maJowrYo42m8r9Zw==", + "version": "7.112.2", + "resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.112.2.tgz", + "integrity": "sha512-kCMLt7yhY5OkWE9MeowlTNmox9pqDxcpvqguMo4BDNZM5+v9SEb1AauAdR78E1a1V8TyCzjBD7JDfXWhvpYBcQ==", "dev": true, "engines": { "node": ">=8" } }, "node_modules/@sentry/utils": { - "version": "7.103.0", - "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-7.103.0.tgz", - "integrity": "sha512-phkUJt3F0UOkVq+M4GfdAh2ewI3ASrNiJddx9aO7GnT0aDwwVBHZltnqt95qgAB8W+BipTSt1dAh8yUbbq1Ceg==", + "version": "7.112.2", + "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-7.112.2.tgz", + "integrity": "sha512-OjLh0hx0t1EcL4ZIjf+4svlmmP+tHUDGcr5qpFWH78tjmkPW4+cqPuZCZfHSuWcDdeiaXi8TnYoVRqDcJKK/eQ==", "dev": true, "dependencies": { - "@sentry/types": "7.103.0" + "@sentry/types": "7.112.2" }, "engines": { "node": ">=8" @@ -2663,18 +2658,18 @@ } }, "node_modules/@types/better-sqlite3": { - "version": "7.6.9", - "resolved": "https://registry.npmjs.org/@types/better-sqlite3/-/better-sqlite3-7.6.9.tgz", - "integrity": "sha512-FvktcujPDj9XKMJQWFcl2vVl7OdRIqsSRX9b0acWwTmwLK9CF2eqo/FRcmMLNpugKoX/avA6pb7TorDLmpgTnQ==", + "version": "7.6.10", + "resolved": "https://registry.npmjs.org/@types/better-sqlite3/-/better-sqlite3-7.6.10.tgz", + "integrity": "sha512-TZBjD+yOsyrUJGmcUj6OS3JADk3+UZcNv3NOBqGkM09bZdi28fNZw8ODqbMOLfKCu7RYCO62/ldq1iHbzxqoPw==", "dev": true, "dependencies": { "@types/node": "*" } }, "node_modules/@types/eslint": { - "version": "8.56.5", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.5.tgz", - "integrity": "sha512-u5/YPJHo1tvkSF2CE0USEkxon82Z5DBy2xR+qfyYNszpX9qcs4sT6uq2kBbj4BXY1+DBGDPnrhMZV3pKWGNukw==", + "version": "8.56.10", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.10.tgz", + "integrity": "sha512-Shavhk87gCtY2fhXDctcfS3e6FdxWkCx1iUZ9eEUbh7rTqlZT0/IzOkCOVt0fCjcFuZ9FPYfuezTBImfHCDBGQ==", "dev": true, "peer": true, "dependencies": { @@ -2750,9 +2745,9 @@ "dev": true }, "node_modules/@types/node": { - "version": "20.11.24", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.24.tgz", - "integrity": "sha512-Kza43ewS3xoLgCEpQrsT+xRo/EJej1y0kVYGiLFE1NEODXGzTfwiC6tXTLMQskn1X4/Rjlh0MQUvx9W+L9long==", + "version": "20.12.7", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.7.tgz", + "integrity": "sha512-wq0cICSkRLVaf3UGLMGItu/PtdY7oaXaI/RVU+xliKVOtRna3PRY57ZDfztpDL0n11vfymMUnXv8QwYCO7L1wg==", "dev": true, "dependencies": { "undici-types": "~5.26.4" @@ -2795,33 +2790,33 @@ "dev": true }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.21.0.tgz", - "integrity": "sha512-oy9+hTPCUFpngkEZUSzbf9MxI65wbKFoQYsgPdILTfbUldp5ovUuphZVe4i30emU9M/kP+T64Di0mxl7dSw3MA==", + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.7.1.tgz", + "integrity": "sha512-KwfdWXJBOviaBVhxO3p5TJiLpNuh2iyXyjmWN0f1nU87pwyvfS0EmjC6ukQVYVFJd/K1+0NWGPDXiyEyQorn0Q==", "dev": true, "dependencies": { - "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "6.21.0", - "@typescript-eslint/type-utils": "6.21.0", - "@typescript-eslint/utils": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0", + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "7.7.1", + "@typescript-eslint/type-utils": "7.7.1", + "@typescript-eslint/utils": "7.7.1", + "@typescript-eslint/visitor-keys": "7.7.1", "debug": "^4.3.4", "graphemer": "^1.4.0", - "ignore": "^5.2.4", + "ignore": "^5.3.1", "natural-compare": "^1.4.0", - "semver": "^7.5.4", - "ts-api-utils": "^1.0.1" + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^6.0.0 || ^6.0.0-alpha", - "eslint": "^7.0.0 || ^8.0.0" + "@typescript-eslint/parser": "^7.0.0", + "eslint": "^8.56.0" }, "peerDependenciesMeta": { "typescript": { @@ -2863,26 +2858,26 @@ "dev": true }, "node_modules/@typescript-eslint/parser": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.21.0.tgz", - "integrity": "sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==", + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.7.1.tgz", + "integrity": "sha512-vmPzBOOtz48F6JAGVS/kZYk4EkXao6iGrD838sp1w3NQQC0W8ry/q641KU4PrG7AKNAf56NOcR8GOpH8l9FPCw==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "6.21.0", - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/typescript-estree": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0", + "@typescript-eslint/scope-manager": "7.7.1", + "@typescript-eslint/types": "7.7.1", + "@typescript-eslint/typescript-estree": "7.7.1", + "@typescript-eslint/visitor-keys": "7.7.1", "debug": "^4.3.4" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" + "eslint": "^8.56.0" }, "peerDependenciesMeta": { "typescript": { @@ -2891,16 +2886,16 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.21.0.tgz", - "integrity": "sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg==", + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.7.1.tgz", + "integrity": "sha512-PytBif2SF+9SpEUKynYn5g1RHFddJUcyynGpztX3l/ik7KmZEv19WCMhUBkHXPU9es/VWGD3/zg3wg90+Dh2rA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0" + "@typescript-eslint/types": "7.7.1", + "@typescript-eslint/visitor-keys": "7.7.1" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", @@ -2908,25 +2903,25 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.21.0.tgz", - "integrity": "sha512-rZQI7wHfao8qMX3Rd3xqeYSMCL3SoiSQLBATSiVKARdFGCYSRvmViieZjqc58jKgs8Y8i9YvVVhRbHSTA4VBag==", + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.7.1.tgz", + "integrity": "sha512-ZksJLW3WF7o75zaBPScdW1Gbkwhd/lyeXGf1kQCxJaOeITscoSl0MjynVvCzuV5boUz/3fOI06Lz8La55mu29Q==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "6.21.0", - "@typescript-eslint/utils": "6.21.0", + "@typescript-eslint/typescript-estree": "7.7.1", + "@typescript-eslint/utils": "7.7.1", "debug": "^4.3.4", - "ts-api-utils": "^1.0.1" + "ts-api-utils": "^1.3.0" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" + "eslint": "^8.56.0" }, "peerDependenciesMeta": { "typescript": { @@ -2935,12 +2930,12 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.21.0.tgz", - "integrity": "sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg==", + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.7.1.tgz", + "integrity": "sha512-AmPmnGW1ZLTpWa+/2omPrPfR7BcbUU4oha5VIbSbS1a1Tv966bklvLNXxp3mrbc+P2j4MNOTfDffNsk4o0c6/w==", "dev": true, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", @@ -2948,22 +2943,22 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.21.0.tgz", - "integrity": "sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==", + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.7.1.tgz", + "integrity": "sha512-CXe0JHCXru8Fa36dteXqmH2YxngKJjkQLjxzoj6LYwzZ7qZvgsLSc+eqItCrqIop8Vl2UKoAi0StVWu97FQZIQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0", + "@typescript-eslint/types": "7.7.1", + "@typescript-eslint/visitor-keys": "7.7.1", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", - "minimatch": "9.0.3", - "semver": "^7.5.4", - "ts-api-utils": "^1.0.1" + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", @@ -3009,28 +3004,28 @@ "dev": true }, "node_modules/@typescript-eslint/utils": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.21.0.tgz", - "integrity": "sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ==", + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.7.1.tgz", + "integrity": "sha512-QUvBxPEaBXf41ZBbaidKICgVL8Hin0p6prQDu6bbetWo39BKbWJxRsErOzMNT1rXvTll+J7ChrbmMCXM9rsvOQ==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@types/json-schema": "^7.0.12", - "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "6.21.0", - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/typescript-estree": "6.21.0", - "semver": "^7.5.4" + "@types/json-schema": "^7.0.15", + "@types/semver": "^7.5.8", + "@typescript-eslint/scope-manager": "7.7.1", + "@typescript-eslint/types": "7.7.1", + "@typescript-eslint/typescript-estree": "7.7.1", + "semver": "^7.6.0" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" + "eslint": "^8.56.0" } }, "node_modules/@typescript-eslint/utils/node_modules/lru-cache": { @@ -3067,16 +3062,16 @@ "dev": true }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.21.0.tgz", - "integrity": "sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A==", + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.7.1.tgz", + "integrity": "sha512-gBL3Eq25uADw1LQ9kVpf3hRM+DWzs0uZknHYK3hq4jcTPqVCClHGDnB6UUUV2SFeBeA4KWHWbbLqmbGcZ4FYbw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.21.0", - "eslint-visitor-keys": "^3.4.1" + "@typescript-eslint/types": "7.7.1", + "eslint-visitor-keys": "^3.4.3" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", @@ -3090,9 +3085,9 @@ "dev": true }, "node_modules/@webassemblyjs/ast": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.6.tgz", - "integrity": "sha512-IN1xI7PwOvLPgjcf180gC1bqn3q/QaOCwYUahIOhbYUu8KA/3tw2RT/T0Gidi1l7Hhj5D/INhJxiICObqpMu4Q==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.12.1.tgz", + "integrity": "sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg==", "dev": true, "peer": true, "dependencies": { @@ -3115,9 +3110,9 @@ "peer": true }, "node_modules/@webassemblyjs/helper-buffer": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.6.tgz", - "integrity": "sha512-z3nFzdcp1mb8nEOFFk8DrYLpHvhKC3grJD2ardfKOzmbmJvEf/tPIqCY+sNcwZIY8ZD7IkB2l7/pqhUhqm7hLA==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.12.1.tgz", + "integrity": "sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw==", "dev": true, "peer": true }, @@ -3141,16 +3136,16 @@ "peer": true }, "node_modules/@webassemblyjs/helper-wasm-section": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.6.tgz", - "integrity": "sha512-LPpZbSOwTpEC2cgn4hTydySy1Ke+XEu+ETXuoyvuyezHO3Kjdu90KK95Sh9xTbmjrCsUwvWwCOQQNta37VrS9g==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.12.1.tgz", + "integrity": "sha512-Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g==", "dev": true, "peer": true, "dependencies": { - "@webassemblyjs/ast": "1.11.6", - "@webassemblyjs/helper-buffer": "1.11.6", + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/wasm-gen": "1.11.6" + "@webassemblyjs/wasm-gen": "1.12.1" } }, "node_modules/@webassemblyjs/ieee754": { @@ -3181,30 +3176,30 @@ "peer": true }, "node_modules/@webassemblyjs/wasm-edit": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.6.tgz", - "integrity": "sha512-Ybn2I6fnfIGuCR+Faaz7YcvtBKxvoLV3Lebn1tM4o/IAJzmi9AWYIPWpyBfU8cC+JxAO57bk4+zdsTjJR+VTOw==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.12.1.tgz", + "integrity": "sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g==", "dev": true, "peer": true, "dependencies": { - "@webassemblyjs/ast": "1.11.6", - "@webassemblyjs/helper-buffer": "1.11.6", + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/helper-wasm-section": "1.11.6", - "@webassemblyjs/wasm-gen": "1.11.6", - "@webassemblyjs/wasm-opt": "1.11.6", - "@webassemblyjs/wasm-parser": "1.11.6", - "@webassemblyjs/wast-printer": "1.11.6" + "@webassemblyjs/helper-wasm-section": "1.12.1", + "@webassemblyjs/wasm-gen": "1.12.1", + "@webassemblyjs/wasm-opt": "1.12.1", + "@webassemblyjs/wasm-parser": "1.12.1", + "@webassemblyjs/wast-printer": "1.12.1" } }, "node_modules/@webassemblyjs/wasm-gen": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.6.tgz", - "integrity": "sha512-3XOqkZP/y6B4F0PBAXvI1/bky7GryoogUtfwExeP/v7Nzwo1QLcq5oQmpKlftZLbT+ERUOAZVQjuNVak6UXjPA==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.12.1.tgz", + "integrity": "sha512-TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w==", "dev": true, "peer": true, "dependencies": { - "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/ast": "1.12.1", "@webassemblyjs/helper-wasm-bytecode": "1.11.6", "@webassemblyjs/ieee754": "1.11.6", "@webassemblyjs/leb128": "1.11.6", @@ -3212,26 +3207,26 @@ } }, "node_modules/@webassemblyjs/wasm-opt": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.6.tgz", - "integrity": "sha512-cOrKuLRE7PCe6AsOVl7WasYf3wbSo4CeOk6PkrjS7g57MFfVUF9u6ysQBBODX0LdgSvQqRiGz3CXvIDKcPNy4g==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.12.1.tgz", + "integrity": "sha512-Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg==", "dev": true, "peer": true, "dependencies": { - "@webassemblyjs/ast": "1.11.6", - "@webassemblyjs/helper-buffer": "1.11.6", - "@webassemblyjs/wasm-gen": "1.11.6", - "@webassemblyjs/wasm-parser": "1.11.6" + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/wasm-gen": "1.12.1", + "@webassemblyjs/wasm-parser": "1.12.1" } }, "node_modules/@webassemblyjs/wasm-parser": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.6.tgz", - "integrity": "sha512-6ZwPeGzMJM3Dqp3hCsLgESxBGtT/OeCvCZ4TA1JUPYgmhAx38tTPR9JaKy0S5H3evQpO/h2uWs2j6Yc/fjkpTQ==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.12.1.tgz", + "integrity": "sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ==", "dev": true, "peer": true, "dependencies": { - "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/ast": "1.12.1", "@webassemblyjs/helper-api-error": "1.11.6", "@webassemblyjs/helper-wasm-bytecode": "1.11.6", "@webassemblyjs/ieee754": "1.11.6", @@ -3240,13 +3235,13 @@ } }, "node_modules/@webassemblyjs/wast-printer": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.6.tgz", - "integrity": "sha512-JM7AhRcE+yW2GWYaKeHL5vt4xqee5N2WcezptmgyhNS+ScggqcT1OtXykhAb13Sn5Yas0j2uv9tHgrjwvzAP4A==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.12.1.tgz", + "integrity": "sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA==", "dev": true, "peer": true, "dependencies": { - "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/ast": "1.12.1", "@xtuc/long": "4.2.2" } }, @@ -3599,12 +3594,15 @@ "dev": true }, "node_modules/binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", "dev": true, "engines": { "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/blake3-wasm": { @@ -3694,9 +3692,9 @@ "dev": true }, "node_modules/builtins": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.0.1.tgz", - "integrity": "sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.1.0.tgz", + "integrity": "sha512-SW9lzGTLvWTP1AY8xeAMZimqDrIaSdLQUcVr9DMef51niJ022Ri87SwRRKYm4A6iHfkPaiVUu/Duw2Wc4J7kKg==", "dev": true, "dependencies": { "semver": "^7.0.0" @@ -3766,9 +3764,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001591", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001591.tgz", - "integrity": "sha512-PCzRMei/vXjJyL5mJtzNiUCKP59dm8Apqc3PH8gJkMnMXZGox93RbE76jHsmLwmIo6/3nsYIpJtx0O7u5PqFuQ==", + "version": "1.0.30001612", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001612.tgz", + "integrity": "sha512-lFgnZ07UhaCcsSZgWW0K5j4e69dK1u/ltrL9lTUiFOwNHs12S3UMIEYgBV0Z6C6hRDev7iRnMzzYmKabYdXF9g==", "dev": true, "funding": [ { @@ -3944,9 +3942,9 @@ "dev": true }, "node_modules/convert-source-map": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", - "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", "dev": true }, "node_modules/cookie": { @@ -4087,9 +4085,9 @@ } }, "node_modules/dedent": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.1.tgz", - "integrity": "sha512-+LxW+KLWxu3HW3M2w2ympwtqPrqYRzU8fqi6Fhd18fBALe15blJPI/I4+UHveMVG6lJqB4JNd4UG0S5cnVHwIg==", + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.3.tgz", + "integrity": "sha512-NHQtfOOW68WD8lgypbLA5oT+Bt0xXJhiYvoR6SmmNXZfpzOGXwdKWmcwG8N7PwVVWV3eF/68nmD9BaJSsTBhyQ==", "dev": true, "peerDependencies": { "babel-plugin-macros": "^3.1.0" @@ -4170,9 +4168,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.4.688", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.688.tgz", - "integrity": "sha512-3/tHg2ChPF00eukURIB8cSVt3/9oeS1oTUIEt3ivngBInUaEcBhG2VdyEDejhwQdR6SLqaiEAEc0dHS0V52pOw==", + "version": "1.4.746", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.746.tgz", + "integrity": "sha512-jeWaIta2rIG2FzHaYIhSuVWqC6KJYo7oSBX4Jv7g+aVujKztfvdpf+n6MGwZdC5hQXbax4nntykLH2juIQrfPg==", "dev": true }, "node_modules/emittery": { @@ -4194,9 +4192,9 @@ "dev": true }, "node_modules/enhanced-resolve": { - "version": "5.15.1", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.15.1.tgz", - "integrity": "sha512-3d3JRbwsCLJsYgvb6NuWEG44jjPSOMuS73L/6+7BZuoKm3W+qXnSoIYVHi8dG7Qcg4inAY4jbzkZ7MnskePeDg==", + "version": "5.16.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.16.0.tgz", + "integrity": "sha512-O+QWCviPNSSLAD9Ucn8Awv+poAkqn3T1XY5/N7kR7rQO9yfSGWkYZDwpJ+iKF7B8rxaQKWngSqACpgzeapSyoA==", "dev": true, "dependencies": { "graceful-fs": "^4.2.4", @@ -4216,9 +4214,9 @@ } }, "node_modules/es-module-lexer": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.4.1.tgz", - "integrity": "sha512-cXLGjP0c4T3flZJKQSuziYoq7MlT+rnvfZjfp7h+I7K9BNX54kP9nyWvdbwjQ4u1iWbOL4u96fgeZLToQlZC7w==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.0.tgz", + "integrity": "sha512-pqrTKmwEIgafsYZAGw9kszYzmagcE/n4dbgwGWLEXg7J4QFJVQRBld8j3Q3GNez79jzxZshq0bcT962QHOghjw==", "dev": true, "peer": true }, @@ -4369,12 +4367,12 @@ } }, "node_modules/eslint-plugin-sonarjs": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-sonarjs/-/eslint-plugin-sonarjs-0.23.0.tgz", - "integrity": "sha512-z44T3PBf9W7qQ/aR+NmofOTyg6HLhSEZOPD4zhStqBpLoMp8GYhFksuUBnCxbnf1nfISpKBVkQhiBLFI/F4Wlg==", + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-sonarjs/-/eslint-plugin-sonarjs-0.25.1.tgz", + "integrity": "sha512-5IOKvj/GMBNqjxBdItfotfRHo7w48496GOu1hxdeXuD0mB1JBlDCViiLHETDTfA8pDAVSBimBEQoetRXYceQEw==", "dev": true, "engines": { - "node": ">=14" + "node": ">=16" }, "peerDependencies": { "eslint": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0" @@ -4890,13 +4888,13 @@ } }, "node_modules/glob": { - "version": "9.3.2", - "resolved": "https://registry.npmjs.org/glob/-/glob-9.3.2.tgz", - "integrity": "sha512-BTv/JhKXFEHsErMte/AnfiSv8yYOLLiyH2lTg8vn02O21zWFgHPTfxtgn1QRe7NRgggUhC8hacR2Re94svHqeA==", + "version": "9.3.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-9.3.5.tgz", + "integrity": "sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q==", "dev": true, "dependencies": { "fs.realpath": "^1.0.0", - "minimatch": "^7.4.1", + "minimatch": "^8.0.2", "minipass": "^4.2.4", "path-scurry": "^1.6.1" }, @@ -4926,15 +4924,15 @@ "dev": true }, "node_modules/glob/node_modules/minimatch": { - "version": "7.4.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-7.4.6.tgz", - "integrity": "sha512-sBz8G/YjVniEz6lKPNpKxXwazJe4c19fEfV2GDMX6AjFz+MX9uDWIZW8XreVhkFW3fkIdTv/gxWr/Kks5FFAVw==", + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-8.0.4.tgz", + "integrity": "sha512-W0Wvr9HyFXZRGIDgCicunpQ299OKXs9RgZfaukz4qAW/pJhcpUfupc9c+OObPOFueNy8VSrZgEmDtk6Kh4WzDA==", "dev": true, "dependencies": { "brace-expansion": "^2.0.1" }, "engines": { - "node": ">=10" + "node": ">=16 || 14 >=14.17" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -4991,9 +4989,9 @@ } }, "node_modules/hasown": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.1.tgz", - "integrity": "sha512-1/th4MHjnwncwXsIW6QMzlvYL9kG5e/CpVvLRZe4XPa8TOUNbCELqmvhDmnkNsAjwaG4+I8gJJL0JBvTTLO9qA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", "dev": true, "dependencies": { "function-bind": "^1.1.2" @@ -5254,51 +5252,6 @@ "node": ">=10" } }, - "node_modules/istanbul-lib-instrument/node_modules/@babel/core": { - "version": "7.24.0", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.0.tgz", - "integrity": "sha512-fQfkg0Gjkza3nf0c7/w6Xf34BW4YvzNfACRLmmb7XRLa6XHdR+K9AlJlxneFfWYf6uhOzuzZVTjF/8KfndZANw==", - "dev": true, - "dependencies": { - "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.23.5", - "@babel/generator": "^7.23.6", - "@babel/helper-compilation-targets": "^7.23.6", - "@babel/helper-module-transforms": "^7.23.3", - "@babel/helpers": "^7.24.0", - "@babel/parser": "^7.24.0", - "@babel/template": "^7.24.0", - "@babel/traverse": "^7.24.0", - "@babel/types": "^7.24.0", - "convert-source-map": "^2.0.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.3", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/istanbul-lib-instrument/node_modules/@babel/core/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/istanbul-lib-instrument/node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true - }, "node_modules/istanbul-lib-instrument/node_modules/lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -7097,9 +7050,9 @@ } }, "node_modules/jschardet": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/jschardet/-/jschardet-3.0.0.tgz", - "integrity": "sha512-lJH6tJ77V8Nzd5QWRkFYCLc13a3vADkh3r/Fi8HupZGWk2OVVDfnZP8V/VgQgZ+lzW0kG2UGb5hFgt3V3ndotQ==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/jschardet/-/jschardet-3.1.2.tgz", + "integrity": "sha512-mw3CBZGzW8nUBPYhFU2ztZ/kJ6NClQUQVpyzvFMfznZsoC///ZQ30J2RCUanNsr5yF22LqhgYr/lj807/ZleWA==", "dev": true, "engines": { "node": ">=0.1.90" @@ -7268,12 +7221,12 @@ } }, "node_modules/magic-string": { - "version": "0.27.0", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.27.0.tgz", - "integrity": "sha512-8UnnX2PeRAPZuN12svgR9j7M1uWMovg/CEnIwIG0LFkXSJJe4PdfUGiTGl8V9bsBHFUtfVINcSyYxd7q+kx9fA==", + "version": "0.30.8", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.8.tgz", + "integrity": "sha512-ISQTe55T2ao7XtlAStud6qwYPZjE4GK1S/BeVPus4jrq6JuOnQ00YKQC581RWhR122W7msZV263KzVeLoqidyQ==", "dev": true, "dependencies": { - "@jridgewell/sourcemap-codec": "^1.4.13" + "@jridgewell/sourcemap-codec": "^1.4.15" }, "engines": { "node": ">=12" @@ -7415,9 +7368,9 @@ } }, "node_modules/miniflare": { - "version": "3.20240223.0", - "resolved": "https://registry.npmjs.org/miniflare/-/miniflare-3.20240223.0.tgz", - "integrity": "sha512-8T/36FEfvsL4aMF7SLZ28v+PQL0jsUlVw/u114GYcdobkyPax9E6Ahn0XePOHEqLxQSndwPee+eS1phHANFePA==", + "version": "3.20240405.2", + "resolved": "https://registry.npmjs.org/miniflare/-/miniflare-3.20240405.2.tgz", + "integrity": "sha512-n/V5m9GVMN37U5gWdrNXKx2d1icLXtcIKcxWtLslH4RTaebZJdSRmp12UHyuQsKlaSpTkNqyzLVtCEgt2bhRSA==", "dev": true, "dependencies": { "@cspotcode/source-map-support": "0.8.1", @@ -7428,7 +7381,7 @@ "glob-to-regexp": "^0.4.1", "stoppable": "^1.1.0", "undici": "^5.28.2", - "workerd": "1.20240223.1", + "workerd": "1.20240405.0", "ws": "^8.11.0", "youch": "^3.2.2", "zod": "^3.20.6" @@ -7441,9 +7394,9 @@ } }, "node_modules/minimatch": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", - "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", + "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", "dev": true, "dependencies": { "brace-expansion": "^2.0.1" @@ -7877,12 +7830,12 @@ "dev": true }, "node_modules/path-scurry": { - "version": "1.10.1", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.1.tgz", - "integrity": "sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==", + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.2.tgz", + "integrity": "sha512-7xTavNy5RQXnsjANvVvMkEjvloOinkAjv/Z6Ildz9v2RinZ4SBKTWFOVRbaF8p0vpHnyjV/UwNDdKuUv6M5qcA==", "dev": true, "dependencies": { - "lru-cache": "^9.1.1 || ^10.0.0", + "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" }, "engines": { @@ -7911,9 +7864,9 @@ } }, "node_modules/path-to-regexp": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.2.1.tgz", - "integrity": "sha512-JLyh7xT1kizaEvcaXOQwOc2/Yhw6KZOvPf1S8401UyLk86CU79LN3vl7ztXGm/pZ+YjoyAJ4rxmHwbkBXJX+yw==", + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.2.2.tgz", + "integrity": "sha512-GQX3SSMokngb36+whdpRXE+3f9V8UzyAorlYvOGx87ufGHehNTn5lCxrKtLyZ4Yl/wEKnNnr98ZzOwwDZV5ogw==", "dev": true }, "node_modules/path-type": { @@ -8119,9 +8072,9 @@ } }, "node_modules/pure-rand": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.0.4.tgz", - "integrity": "sha512-LA0Y9kxMYv47GIPJy6MI84fqTd2HmYZI83W/kM/SkKfDlajnZYfmXFTxkbY+xSBPkLJxltMa9hIkmdc29eguMA==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz", + "integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==", "dev": true, "funding": [ { @@ -8406,6 +8359,15 @@ ], "peer": true }, + "node_modules/safe-stable-stringify": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz", + "integrity": "sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g==", + "dev": true, + "engines": { + "node": ">=10" + } + }, "node_modules/schema-utils": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", @@ -8690,9 +8652,9 @@ } }, "node_modules/terser": { - "version": "5.28.1", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.28.1.tgz", - "integrity": "sha512-wM+bZp54v/E9eRRGXb5ZFDvinrJIOaTapx3WUokyVGZu5ucVCK55zEgGd5Dl2fSr3jUo5sDiERErUWLY6QPFyA==", + "version": "5.30.4", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.30.4.tgz", + "integrity": "sha512-xRdd0v64a8mFK9bnsKVdoNP9GQIKUAaJPTaqEQDL4w/J8WaW4sWXXoMZ+6SimPkfT5bElreXf8m9HnmPc3E1BQ==", "dev": true, "peer": true, "dependencies": { @@ -8947,9 +8909,9 @@ "dev": true }, "node_modules/ts-api-utils": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.2.1.tgz", - "integrity": "sha512-RIYA36cJn2WiH9Hy77hdF9r7oEwxAtB/TS9/S4Qd90Ap4z5FSiin5zEiTL44OII1Y3IIlEvxwxFUVgrHSZ/UpA==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", + "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", "dev": true, "engines": { "node": ">=16" @@ -9034,6 +8996,67 @@ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true }, + "node_modules/ts-json-schema-generator": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/ts-json-schema-generator/-/ts-json-schema-generator-1.5.1.tgz", + "integrity": "sha512-apX5qG2+NA66j7b4AJm8q/DpdTeOsjfh7A3LpKsUiil0FepkNwtN28zYgjrsiiya2/OPhsr/PSjX5FUYg79rCg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.15", + "commander": "^12.0.0", + "glob": "^8.0.3", + "json5": "^2.2.3", + "normalize-path": "^3.0.0", + "safe-stable-stringify": "^2.4.3", + "typescript": "~5.4.2" + }, + "bin": { + "ts-json-schema-generator": "bin/ts-json-schema-generator" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/ts-json-schema-generator/node_modules/commander": { + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-12.0.0.tgz", + "integrity": "sha512-MwVNWlYjDTtOjX5PiD7o5pK0UrFU/OYgcJfjjK4RaHZETNtjJqrZa9Y9ds88+A+f+d5lv+561eZ+yCKoS3gbAA==", + "dev": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/ts-json-schema-generator/node_modules/glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/ts-json-schema-generator/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/ts-loader": { "version": "9.5.1", "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.5.1.tgz", @@ -9206,9 +9229,9 @@ } }, "node_modules/typescript": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", - "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", + "version": "5.4.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", + "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", "dev": true, "bin": { "tsc": "bin/tsc", @@ -9326,12 +9349,6 @@ "node": ">=10.12.0" } }, - "node_modules/v8-to-istanbul/node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true - }, "node_modules/validate-npm-package-name": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-4.0.0.tgz", @@ -9354,9 +9371,9 @@ } }, "node_modules/watchpack": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", - "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.1.tgz", + "integrity": "sha512-8wrBCMtVhqcXP2Sup1ctSkga6uc2Bx0IIvKyT7yTFier5AXHooSI+QyQQAtTb7+E0IUCCKyTFmXqdqgum2XWGg==", "dev": true, "peer": true, "dependencies": { @@ -9374,27 +9391,27 @@ "dev": true }, "node_modules/webpack": { - "version": "5.90.3", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.90.3.tgz", - "integrity": "sha512-h6uDYlWCctQRuXBs1oYpVe6sFcWedl0dpcVaTf/YF67J9bKvwJajFulMVSYKHrksMB3I/pIagRzDxwxkebuzKA==", + "version": "5.91.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.91.0.tgz", + "integrity": "sha512-rzVwlLeBWHJbmgTC/8TvAcu5vpJNII+MelQpylD4jNERPwpBJOE2lEcko1zJX3QJeLjTTAnQxn/OJ8bjDzVQaw==", "dev": true, "peer": true, "dependencies": { "@types/eslint-scope": "^3.7.3", "@types/estree": "^1.0.5", - "@webassemblyjs/ast": "^1.11.5", - "@webassemblyjs/wasm-edit": "^1.11.5", - "@webassemblyjs/wasm-parser": "^1.11.5", + "@webassemblyjs/ast": "^1.12.1", + "@webassemblyjs/wasm-edit": "^1.12.1", + "@webassemblyjs/wasm-parser": "^1.12.1", "acorn": "^8.7.1", "acorn-import-assertions": "^1.9.0", "browserslist": "^4.21.10", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.15.0", + "enhanced-resolve": "^5.16.0", "es-module-lexer": "^1.2.1", "eslint-scope": "5.1.1", "events": "^3.2.0", "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.2.9", + "graceful-fs": "^4.2.11", "json-parse-even-better-errors": "^2.3.1", "loader-runner": "^4.2.0", "mime-types": "^2.1.27", @@ -9402,7 +9419,7 @@ "schema-utils": "^3.2.0", "tapable": "^2.1.1", "terser-webpack-plugin": "^5.3.10", - "watchpack": "^2.4.0", + "watchpack": "^2.4.1", "webpack-sources": "^3.2.3" }, "bin": { @@ -9486,9 +9503,9 @@ } }, "node_modules/workerd": { - "version": "1.20240223.1", - "resolved": "https://registry.npmjs.org/workerd/-/workerd-1.20240223.1.tgz", - "integrity": "sha512-Mo1fwdp6DLva4/fWdL09ZdYllkO45I4YpWG5PbF/YUGFlu2aMk24fmU6Pd6fo5/cWek4F+n3LmYEKKHfqjiJIA==", + "version": "1.20240405.0", + "resolved": "https://registry.npmjs.org/workerd/-/workerd-1.20240405.0.tgz", + "integrity": "sha512-AWrOSBh4Ll7sBWHuh0aywm8hDkKqsZmcwnDB0PVGszWZM5mndNBI5iJ/8haXVpdoyqkJQEVdhET9JDi4yU8tRg==", "dev": true, "hasInstallScript": true, "bin": { @@ -9498,17 +9515,17 @@ "node": ">=16" }, "optionalDependencies": { - "@cloudflare/workerd-darwin-64": "1.20240223.1", - "@cloudflare/workerd-darwin-arm64": "1.20240223.1", - "@cloudflare/workerd-linux-64": "1.20240223.1", - "@cloudflare/workerd-linux-arm64": "1.20240223.1", - "@cloudflare/workerd-windows-64": "1.20240223.1" + "@cloudflare/workerd-darwin-64": "1.20240405.0", + "@cloudflare/workerd-darwin-arm64": "1.20240405.0", + "@cloudflare/workerd-linux-64": "1.20240405.0", + "@cloudflare/workerd-linux-arm64": "1.20240405.0", + "@cloudflare/workerd-windows-64": "1.20240405.0" } }, "node_modules/wrangler": { - "version": "3.30.1", - "resolved": "https://registry.npmjs.org/wrangler/-/wrangler-3.30.1.tgz", - "integrity": "sha512-cT6Ezx8h2v5QiI0HWhnHVy32ng4omdMVdhaMQLuMnyMIHmyDoRg7pmrbhtZfj0663gExLdVtE4ucK//yncVTwg==", + "version": "3.51.2", + "resolved": "https://registry.npmjs.org/wrangler/-/wrangler-3.51.2.tgz", + "integrity": "sha512-8TRUwzPHj6+uPDzY0hBJ9/YwniEF9pqMGe5qbqLP/XsHTCWxIFib5go374zyCkmuVh23AwV7NuTA6gUtSqZ8pQ==", "dev": true, "dependencies": { "@cloudflare/kv-asset-handler": "0.3.1", @@ -9517,13 +9534,14 @@ "blake3-wasm": "^2.1.5", "chokidar": "^3.5.3", "esbuild": "0.17.19", - "miniflare": "3.20240223.0", + "miniflare": "3.20240405.2", "nanoid": "^3.3.3", "path-to-regexp": "^6.2.0", "resolve": "^1.22.8", "resolve.exports": "^2.0.2", "selfsigned": "^2.0.1", "source-map": "0.6.1", + "ts-json-schema-generator": "^1.5.0", "xxhash-wasm": "^1.0.1" }, "bin": { @@ -9537,7 +9555,7 @@ "fsevents": "~2.3.2" }, "peerDependencies": { - "@cloudflare/workers-types": "^4.20230914.0" + "@cloudflare/workers-types": "^4.20240405.0" }, "peerDependenciesMeta": { "@cloudflare/workers-types": { @@ -9707,9 +9725,9 @@ } }, "node_modules/zod": { - "version": "3.22.4", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.22.4.tgz", - "integrity": "sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==", + "version": "3.23.3", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.23.3.tgz", + "integrity": "sha512-tPvq1B/2Yu/dh2uAIH2/BhUlUeLIUvAjr6dpL/75I0pCYefHgjhXk1o1Kob3kTU8C7yU1j396jFHlsVWFi9ogg==", "dev": true, "funding": { "url": "https://github.com/sponsors/colinhacks" diff --git a/package.json b/package.json index f5bc423..2004b33 100644 --- a/package.json +++ b/package.json @@ -16,29 +16,29 @@ "author": "dangered wolf", "license": "MIT", "devDependencies": { - "@cloudflare/workers-types": "^4.20231218.0", - "@microsoft/eslint-formatter-sarif": "^3.0.0", - "@sentry/esbuild-plugin": "^2.10.2", - "@sentry/integrations": "^7.93.0", - "@types/jest": "^29.5.11", - "@typescript-eslint/eslint-plugin": "^6.18.1", - "@typescript-eslint/parser": "^6.18.1", - "dotenv": "^16.3.1", - "eslint": "^8.56.0", + "@cloudflare/workers-types": "^4.20240423.0", + "@microsoft/eslint-formatter-sarif": "^3.1.0", + "@sentry/esbuild-plugin": "^2.16.1", + "@sentry/integrations": "^7.112.2", + "@types/jest": "^29.5.12", + "@typescript-eslint/eslint-plugin": "^7.7.1", + "@typescript-eslint/parser": "^7.7.1", + "dotenv": "^16.4.5", + "eslint": "^8.57.0", "eslint-config-prettier": "^9.1.0", "eslint-config-typescript": "^3.0.0", "eslint-plugin-optimize-regex": "^1.2.1", - "eslint-plugin-sonarjs": "^0.23.0", + "eslint-plugin-sonarjs": "^0.25.1", "jest": "^29.7.0", - "jest-environment-miniflare": "^2.14.1", - "prettier": "^3.2.2", - "ts-jest": "^29.1.1", + "jest-environment-miniflare": "^2.14.2", + "prettier": "^3.2.5", + "ts-jest": "^29.1.2", "ts-loader": "^9.5.1", - "typescript": "^5.3.3", - "wrangler": "^3.22.4" + "typescript": "^5.4.5", + "wrangler": "^3.51.2" }, "dependencies": { - "@hono/sentry": "^1.0.0", - "hono": "^3.12.3" + "@hono/sentry": "^1.0.1", + "hono": "^3.12.12" } } diff --git a/src/caches.ts b/src/caches.ts index 6b94213..a9c1229 100644 --- a/src/caches.ts +++ b/src/caches.ts @@ -20,6 +20,13 @@ export const cacheMiddleware = (): MiddlewareHandler => async (c, next) => { console.log('cacheUrl', cacheUrl); let cacheKey: Request; + const returnAsJson = Constants.API_HOST_LIST.includes(cacheUrl.hostname); + + /* If caching unavailable, ignore the rest of the cache middleware */ + if (typeof caches === 'undefined') { + await next(); + return c.res.clone(); + } try { cacheKey = new Request(cacheUrl.toString(), request); @@ -74,17 +81,20 @@ export const cacheMiddleware = (): MiddlewareHandler => async (c, next) => { case 'DELETE': console.log('Purging cache as requested'); await cache.delete(cacheKey); - return c.text(''); + if (returnAsJson) return c.json(''); + return c.html(''); /* yes, we do give HEAD */ case 'HEAD': - return c.text(''); + if (returnAsJson) return c.json(''); + return c.html(''); /* We properly state our OPTIONS when asked */ case 'OPTIONS': c.header('allow', Constants.RESPONSE_HEADERS.allow); c.status(204); - return c.text(''); + return; default: c.status(405); - return c.text(''); + if (returnAsJson) return c.json(''); + return c.html(''); } }; diff --git a/src/constants.ts b/src/constants.ts index 84447c6..2426cab 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -7,18 +7,21 @@ export const Constants = { INSTANT_VIEW_DOMAINS: INSTANT_VIEW_DOMAINS.split(','), INSTANT_VIEW_THREADS_DOMAINS: INSTANT_VIEW_THREADS_DOMAINS.split(','), GALLERY_DOMAINS: GALLERY_DOMAINS.split(','), + NATIVE_MULTI_IMAGE_DOMAINS: NATIVE_MULTI_IMAGE_DOMAINS.split(','), MOSAIC_DOMAIN_LIST: MOSAIC_DOMAIN_LIST.split(','), API_HOST_LIST: API_HOST_LIST.split(','), HOST_URL: HOST_URL, EMBED_URL: EMBED_URL, REDIRECT_URL: REDIRECT_URL, RELEASE_NAME: RELEASE_NAME, + GIF_TRANSCODE_DOMAIN: GIF_TRANSCODE_DOMAIN, API_DOCS_URL: `https://github.com/dangeredwolf/FixTweet/wiki/API-Home`, TWITTER_ROOT: 'https://twitter.com', TWITTER_GLOBAL_NAME_ROOT: 'twitter.com', TWITTER_API_ROOT: 'https://api.twitter.com', + TWITTER_VIDEO_BASE: 'https://video.twimg.com', BOT_UA_REGEX: - /bot|facebook|embed|got|firefox\/92|firefox\/38|curl|wget|go-http|yahoo|generator|whatsapp|revoltchat|preview|link|proxy|vkshare|images|analyzer|index|crawl|spider|python|cfnetwork|node|mastodon|http\.rb|ruby|bun\/|fiddler/gi, + /bot|facebook|embed|got|firefox\/92|firefox\/38|curl|wget|go-http|yahoo|generator|whatsapp|revoltchat|preview|link|proxy|vkshare|images|analyzer|index|crawl|spider|python|cfnetwork|node|mastodon|http\.rb|ruby|bun\/|fiddler|iframely/gi, /* 3 hours */ GUEST_TOKEN_MAX_AGE: 3 * 60 * 60, GUEST_BEARER_TOKEN: `Bearer AAAAAAAAAAAAAAAAAAAAANRILgAAAAAAnNwIzUejRCOuH5E6I8xnZz4puTs%3D1Zv7ttfk8LF81IUq16cHjhLTvJu4FA33AGWWjCpTnA`, diff --git a/src/embed/status.ts b/src/embed/status.ts index 883df3b..6f2a793 100644 --- a/src/embed/status.ts +++ b/src/embed/status.ts @@ -8,6 +8,7 @@ import { renderPhoto } from '../render/photo'; import { renderVideo } from '../render/video'; import { renderInstantView } from '../render/instantview'; import { constructTwitterThread } from '../providers/twitter/conversation'; +import { Experiment, experimentCheck } from '../experiments'; export const returnError = (c: Context, error: string): Response => { return c.html( @@ -97,6 +98,7 @@ export const handleStatus = async ( } const isTelegram = (userAgent || '').indexOf('Telegram') > -1; + const isDiscord = (userAgent || '').indexOf('Discord') > -1; /* Should sensitive statuses be allowed Instant View? */ let useIV = isTelegram /*&& !status.possibly_sensitive*/ && @@ -277,7 +279,7 @@ export const handleStatus = async ( /* This status has a video to render. */ break; } - } else if (media?.videos) { + } else if (media?.videos && !flags.nativeMultiImage) { const instructions = renderVideo( { status: status, userAgent: userAgent, text: newText }, media.videos[0] @@ -290,16 +292,40 @@ export const handleStatus = async ( siteName = instructions.siteName; } } else if (media?.mosaic) { - const instructions = renderPhoto( - { - status: status, - authorText: authorText, - engagementText: engagementText, - userAgent: userAgent - }, - media.mosaic - ); - headers.push(...instructions.addHeaders); + if ( + experimentCheck(Experiment.DISCORD_NATIVE_MULTI_IMAGE, isDiscord) && + flags.nativeMultiImage + ) { + const photos = status.media?.photos || []; + + photos.forEach(photo => { + /* Override the card type */ + status.embed_card = 'summary_large_image'; + console.log('set embed_card to summary_large_image'); + + const instructions = renderPhoto( + { + status: status, + authorText: authorText, + engagementText: engagementText, + userAgent: userAgent + }, + photo + ); + headers.push(...instructions.addHeaders); + }); + } else { + const instructions = renderPhoto( + { + status: status, + authorText: authorText, + engagementText: engagementText, + userAgent: userAgent + }, + media.mosaic + ); + headers.push(...instructions.addHeaders); + } } else if (media?.photos) { const instructions = renderPhoto( { @@ -312,7 +338,7 @@ export const handleStatus = async ( ); headers.push(...instructions.addHeaders); } - if (status.media?.external && !status.media.videos?.length) { + if (status.media?.external && !status.media.videos?.length && !flags.nativeMultiImage) { const { external } = status.media; authorText = newText || ''; headers.push( @@ -444,6 +470,20 @@ export const handleStatus = async ( providerEngagementText = Strings.DEFAULT_AUTHOR_TEXT; } + let provider = ''; + const mediaType = overrideMedia ?? status.media.videos?.[0]?.type; + + if (mediaType === 'gif') { + provider = `GIF - ${Constants.BRANDING_NAME}`; + } else if ( + status.embed_card === 'player' && + providerEngagementText !== Strings.DEFAULT_AUTHOR_TEXT + ) { + provider = providerEngagementText; + } + + // Now you can use the 'provider' variable + headers.push( ``.format( { @@ -454,10 +494,7 @@ export const handleStatus = async ( status: encodeURIComponent(statusId), author: encodeURIComponent(status.author.screen_name || ''), name: status.author.name || '', - provider: - status.embed_card === 'player' && providerEngagementText !== Strings.DEFAULT_AUTHOR_TEXT - ? `&provider=${encodeURIComponent(providerEngagementText)}` - : '' + provider: provider ? `&provider=${encodeURIComponent(provider)}` : '' } ) ); diff --git a/src/experiments.ts b/src/experiments.ts index 83127c1..0b16983 100644 --- a/src/experiments.ts +++ b/src/experiments.ts @@ -2,7 +2,9 @@ export enum Experiment { IV_FORCE_THREAD_UNROLL = 'IV_FORCE_THREAD_UNROLL', ELONGATOR_BY_DEFAULT = 'ELONGATOR_BY_DEFAULT', ELONGATOR_PROFILE_API = 'ELONGATOR_PROFILE_API', - TWEET_DETAIL_API = 'TWEET_DETAIL_API' + TWEET_DETAIL_API = 'TWEET_DETAIL_API', + DISCORD_NATIVE_MULTI_IMAGE = 'DISCORD_NATIVE_MULTI_IMAGE', + TRANSCODE_GIFS = 'TRANSCODE_GIFS' } type ExperimentConfig = { @@ -31,6 +33,16 @@ const Experiments: { [key in Experiment]: ExperimentConfig } = { name: 'Tweet detail API', description: 'Use Tweet Detail API (where available with elongator)', percentage: 0.75 + }, + [Experiment.DISCORD_NATIVE_MULTI_IMAGE]: { + name: 'Discord native multi-image', + description: 'Use Discord native multi-image', + percentage: 1 + }, + [Experiment.TRANSCODE_GIFS]: { + name: 'Transcode GIFs', + description: 'Transcode GIFs for Discord, etc.', + percentage: 1 } }; diff --git a/src/fetch.ts b/src/fetch.ts index 0581362..26462ac 100644 --- a/src/fetch.ts +++ b/src/fetch.ts @@ -59,11 +59,11 @@ export const twitterFetch = async ( } ); - const cache = caches.default; + const cache = typeof caches !== 'undefined' ? caches.default : null; while (apiAttempts < API_ATTEMPTS) { /* Generate a random CSRF token, Twitter just cares that header and cookie match, - REST can use shorter csrf tokens (32 bytes) but graphql prefers 160 bytes */ + REST can use shorter csrf tokens (32 bytes) but graphql uses a 160 byte one. */ const csrfToken = crypto.randomUUID().replace(/-/g, ''); const headers: Record = { @@ -75,7 +75,12 @@ export const twitterFetch = async ( let activate: Response | null = null; - if (!newTokenGenerated && !useElongator) { + if (cache === null) { + console.log('Caching unavailable, requesting new token'); + newTokenGenerated = true; + } + + if (!newTokenGenerated && !useElongator && cache) { const timeBefore = performance.now(); const cachedResponse = await cache.match(guestTokenRequestCacheDummy.clone()); const timeAfter = performance.now(); @@ -138,13 +143,12 @@ export const twitterFetch = async ( if (useElongator && typeof c.env?.TwitterProxy !== 'undefined') { console.log('Fetching using elongator'); const performanceStart = performance.now(); - apiRequest = await withTimeout( - (signal: AbortSignal) => - c.env?.TwitterProxy.fetch(url, { - method: 'GET', - headers: headers, - signal: signal - }) + apiRequest = await withTimeout((signal: AbortSignal) => + c.env?.TwitterProxy.fetch(url, { + method: 'GET', + headers: headers, + signal: signal + }) ); const performanceEnd = performance.now(); console.log(`Elongator request successful after ${performanceEnd - performanceStart}ms`); @@ -173,6 +177,7 @@ export const twitterFetch = async ( } try { !useElongator && + cache && c.executionCtx && c.executionCtx.waitUntil( cache.delete(guestTokenRequestCacheDummy.clone(), { ignoreMethod: true }) @@ -208,6 +213,7 @@ export const twitterFetch = async ( console.log(`Purging token on this edge due to low rate limit remaining`); try { c.executionCtx && + cache && c.executionCtx.waitUntil( cache.delete(guestTokenRequestCacheDummy.clone(), { ignoreMethod: true }) ); @@ -232,7 +238,7 @@ export const twitterFetch = async ( } try { /* If we've generated a new token, we'll cache it */ - if (c.executionCtx && newTokenGenerated && activate) { + if (c.executionCtx && newTokenGenerated && activate && cache) { const cachingResponse = new Response(await activate.clone().text(), { headers: { ...tokenHeaders, diff --git a/src/helpers/card.ts b/src/helpers/card.ts index 8df5c89..973ae58 100644 --- a/src/helpers/card.ts +++ b/src/helpers/card.ts @@ -3,7 +3,11 @@ import { calculateTimeLeftString } from './pollTime'; /* Renders card for polls and non-Twitter video embeds (i.e. YouTube) */ export const renderCard = ( card: GraphQLTwitterStatus['card'] -): { poll?: APIPoll; external_media?: APIExternalMedia } => { +): { + poll?: APIPoll; + external_media?: APIExternalMedia; + media?: { videos: TweetMedia[]; photos: TweetMedia[] }; +} => { if (!Array.isArray(card.legacy?.binding_values)) { return {}; } @@ -58,5 +62,37 @@ export const renderCard = ( }; } + if (binding_values.unified_card?.string_value) { + try { + const card = JSON.parse(binding_values.unified_card.string_value); + const mediaEntities = card?.media_entities as Record; + + if (mediaEntities) { + const media = { + videos: [] as TweetMedia[], + photos: [] as TweetMedia[] + }; + Object.keys(mediaEntities).forEach(key => { + const mediaItem = mediaEntities[key]; + switch (mediaItem.type) { + case 'photo': + media.photos.push(mediaItem); + break; + case 'animated_gif': + case 'video': + media.videos.push(mediaItem); + break; + } + }); + + console.log('media', media); + + return { media: media }; + } + } catch (e) { + console.error('Failed to parse unified card JSON', e); + } + } + return {}; }; diff --git a/src/helpers/media.ts b/src/helpers/media.ts index b1e4b84..8dd78c7 100644 --- a/src/helpers/media.ts +++ b/src/helpers/media.ts @@ -1,5 +1,7 @@ +import { Context } from 'hono'; + /* Help populate API response for media */ -export const processMedia = (media: TweetMedia): APIPhoto | APIVideo | null => { +export const processMedia = (c: Context, media: TweetMedia): APIPhoto | APIVideo | null => { if (media.type === 'photo') { return { type: 'photo', @@ -10,9 +12,27 @@ export const processMedia = (media: TweetMedia): APIPhoto | APIVideo | null => { }; } else if (media.type === 'video' || media.type === 'animated_gif') { /* Find the variant with the highest bitrate */ - const bestVariant = media.video_info?.variants?.reduce?.((a, b) => - (a.bitrate ?? 0) > (b.bitrate ?? 0) ? a : b - ); + const bestVariant = media.video_info?.variants + ?.filter?.(format => { + if (c.req.header('user-agent')?.includes('Telegram') && format.bitrate) { + /* Telegram doesn't support videos over 20 MB, so we need to filter them out */ + const bitrate = format.bitrate || 0; + const length = (media.video_info?.duration_millis || 0) / 1000; + /* Calculate file size in bytes */ + const fileSizeBytes: number = (bitrate * length) / 8; + /* Convert file size to megabytes (MB) */ + const fileSizeMB: number = fileSizeBytes / (1024 * 1024); + + console.log( + `Estimated file size: ${fileSizeMB.toFixed(2)} MB for bitrate ${bitrate / 1000} kbps` + ); + return ( + fileSizeMB < 30 + ); /* Currently this calculation is off, so we'll just do it if it's way over */ + } + return !format.url.includes('hevc'); + }) + .reduce?.((a, b) => ((a.bitrate ?? 0) > (b.bitrate ?? 0) ? a : b)); return { url: bestVariant?.url || '', thumbnail_url: media.media_url_https, @@ -20,7 +40,8 @@ export const processMedia = (media: TweetMedia): APIPhoto | APIVideo | null => { width: media.original_info?.width, height: media.original_info?.height, format: bestVariant?.content_type || '', - type: media.type === 'animated_gif' ? 'gif' : 'video' + type: media.type === 'animated_gif' ? 'gif' : 'video', + variants: media.video_info?.variants ?? [] }; } return null; diff --git a/src/helpers/translate.ts b/src/helpers/translate.ts index 687bf83..38110fc 100644 --- a/src/helpers/translate.ts +++ b/src/helpers/translate.ts @@ -64,13 +64,12 @@ export const translateStatus = async ( tweet.rest_id ?? tweet.legacy?.id_str },destinationLanguage=None,translationSource=Some(Google),feature=None,timeout=None,onlyCached=None/translation/service/translateTweet`; console.log(url, headers); - translationApiResponse = (await withTimeout( - (signal: AbortSignal) => - c.env?.TwitterProxy.fetch(url, { - method: 'GET', - headers: headers, - signal: signal - }) + translationApiResponse = (await withTimeout((signal: AbortSignal) => + c.env?.TwitterProxy.fetch(url, { + method: 'GET', + headers: headers, + signal: signal + }) )) as Response; translationResults = (await translationApiResponse.json()) as TranslationPartial; diff --git a/src/helpers/useragent.ts b/src/helpers/useragent.ts index 2315d7e..78619ed 100644 --- a/src/helpers/useragent.ts +++ b/src/helpers/useragent.ts @@ -1,6 +1,6 @@ /* We keep this value up-to-date for making our requests to Twitter as indistinguishable from normal user traffic as possible. */ -const fakeChromeVersion = 120; +const fakeChromeVersion = 124; const platformWindows = 'Windows NT 10.0; Win64; x64'; const platformMac = 'Macintosh; Intel Mac OS X 10_15_7'; const platformLinux = 'X11; Linux x86_64'; diff --git a/src/helpers/utils.ts b/src/helpers/utils.ts index 7827bbf..1505cbe 100644 --- a/src/helpers/utils.ts +++ b/src/helpers/utils.ts @@ -58,11 +58,11 @@ export async function withTimeout( } export const formatNumber = (num: number) => { - if (num >= 1e6) { - return (num / 1e6).toFixed(2) + 'M'; - } else if (num >= 1e3) { - return (num / 1e3).toFixed(1) + 'K'; - } else { - return num.toString(); - } -}; \ No newline at end of file + if (num >= 1e6) { + return (num / 1e6).toFixed(2) + 'M'; + } else if (num >= 1e3) { + return (num / 1e3).toFixed(1) + 'K'; + } else { + return num.toString(); + } +}; diff --git a/src/providers/twitter/conversation.ts b/src/providers/twitter/conversation.ts index c7bfe43..3119b44 100644 --- a/src/providers/twitter/conversation.ts +++ b/src/providers/twitter/conversation.ts @@ -5,6 +5,36 @@ import { Experiment, experimentCheck } from '../../experiments'; import { isGraphQLTwitterStatus } from '../../helpers/graphql'; import { Context } from 'hono'; +const writeDataPoint = ( + c: Context, + language: string | undefined, + nsfw: boolean | null, + returnCode: string, + flags?: InputFlags +) => { + console.log('Writing data point...'); + if (typeof c.env?.AnalyticsEngine !== 'undefined') { + const flagString = + Object.keys(flags || {}) + // @ts-expect-error - TypeScript doesn't like iterating over the keys, but that's OK + .filter(flag => flags?.[flag])[0] || 'standard'; + + console.log(flagString); + + c.env?.AnalyticsEngine.writeDataPoint({ + blobs: [ + c.req.raw.cf?.colo as string /* Datacenter location */, + c.req.raw.cf?.country as string /* Country code */, + c.req.header('user-agent') ?? '' /* User agent (for aggregating bots calling) */, + returnCode /* Return code */, + flagString /* Type of request */, + language ?? '' /* For translate feature */ + ], + doubles: [nsfw ? 1 : 0 /* NSFW media = 1, No NSFW Media = 0 */] + }); + } +}; + export const fetchTweetDetail = async ( c: Context, status: string, @@ -304,6 +334,7 @@ export const constructTwitterThread = async ( console.log('response', response); if (!response?.data) { + writeDataPoint(c, language, null, '404'); return { status: null, thread: null, author: null, code: 404 }; } } @@ -316,19 +347,23 @@ export const constructTwitterThread = async ( const result = response?.data?.tweetResult?.result as GraphQLTwitterStatus; if (typeof result === 'undefined') { + writeDataPoint(c, language, null, '404'); return { status: null, thread: null, author: null, code: 404 }; } const buildStatus = await buildAPITwitterStatus(c, result, language, null, legacyAPI); if ((buildStatus as FetchResults)?.status === 401) { + writeDataPoint(c, language, null, '401'); return { status: null, thread: null, author: null, code: 401 }; } else if (buildStatus === null || (buildStatus as FetchResults)?.status === 404) { + writeDataPoint(c, language, null, '404'); return { status: null, thread: null, author: null, code: 404 }; } status = buildStatus as APITwitterStatus; + writeDataPoint(c, language, status.possibly_sensitive, '200'); return { status: status, thread: null, author: status.author, code: 200 }; } @@ -339,6 +374,7 @@ export const constructTwitterThread = async ( /* Don't bother processing thread on a null tweet */ if (originalStatus === null) { + writeDataPoint(c, language, null, '404'); return { status: null, thread: null, author: null, code: 404 }; } @@ -351,6 +387,7 @@ export const constructTwitterThread = async ( )) as APITwitterStatus; if (status === null) { + writeDataPoint(c, language, null, '404'); return { status: null, thread: null, author: null, code: 404 }; } @@ -358,6 +395,7 @@ export const constructTwitterThread = async ( /* If we're not processing threads, let's be done here */ if (!processThread) { + writeDataPoint(c, language, status.possibly_sensitive, '200'); return { status: status, thread: null, author: author, code: 200 }; } diff --git a/src/providers/twitter/processor.ts b/src/providers/twitter/processor.ts index 20bfb88..fefe4f7 100644 --- a/src/providers/twitter/processor.ts +++ b/src/providers/twitter/processor.ts @@ -183,7 +183,7 @@ export const buildAPITwitterStatus = async ( /* Populate status media */ mediaList.forEach(media => { - const mediaObject = processMedia(media); + const mediaObject = processMedia(c, media); if (mediaObject) { apiStatus.media.all = apiStatus.media?.all ?? []; apiStatus.media?.all?.push(mediaObject); @@ -242,6 +242,31 @@ export const buildAPITwitterStatus = async ( if (card.poll) { apiStatus.poll = card.poll; } + /* TODO: Right now, we push them after native photos and videos but should we prepend them instead? */ + if (card.media) { + if (card.media.videos) { + card.media.videos.forEach(video => { + const mediaObject = processMedia(c, video) as APIVideo; + if (mediaObject) { + apiStatus.media.all = apiStatus.media?.all ?? []; + apiStatus.media?.all?.push(mediaObject); + apiStatus.media.videos = apiStatus.media?.videos ?? []; + apiStatus.media.videos?.push(mediaObject); + } + }); + } + if (card.media.photos) { + card.media.photos.forEach(photo => { + const mediaObject = processMedia(c, photo) as APIPhoto; + if (mediaObject) { + apiStatus.media.all = apiStatus.media?.all ?? []; + apiStatus.media?.all?.push(mediaObject); + apiStatus.media.photos = apiStatus.media?.photos ?? []; + apiStatus.media.photos?.push(mediaObject); + } + }); + } + } } else { /* Determine if the status contains a YouTube link (either youtube.com or youtu.be) so we can include it */ const youtubeIdRegex = /(https?:\/\/)?(www\.)?(youtube\.com\/watch\?v=|youtu\.be\/)([^\s&]+)/; diff --git a/src/realms/api/hit.ts b/src/realms/api/hit.ts new file mode 100644 index 0000000..4d8db8e --- /dev/null +++ b/src/realms/api/hit.ts @@ -0,0 +1,15 @@ +import { Context } from 'hono'; + +export const linkHitRequest = async (c: Context) => { + // eslint-disable-next-line sonarjs/no-duplicate-string + const userAgent = c.req.header('User-Agent') || ''; + + if (userAgent.includes('Telegram')) { + c.status(403); + } + // If param `url` exists, 302 redirect to it + if (typeof c.req.query('url') === 'string') { + const url = new URL(c.req.query('url') as string); + return c.redirect(url.href, 302); + } +}; diff --git a/src/realms/api/router.ts b/src/realms/api/router.ts index 6816dc5..da08d56 100644 --- a/src/realms/api/router.ts +++ b/src/realms/api/router.ts @@ -3,6 +3,7 @@ import { statusRequest } from '../twitter/routes/status'; import { profileRequest } from '../twitter/routes/profile'; import { Strings } from '../../strings'; import { Constants } from '../../constants'; +import { linkHitRequest } from './hit'; export const api = new Hono(); @@ -16,6 +17,9 @@ api.use('*', async (c, next) => { } await next(); }); + +api.get('/2/hit', linkHitRequest); + /* Current v1 API endpoints. Currently, these still go through the Twitter embed requests. API v2+ won't do this. */ api.get('/status/:id', statusRequest); api.get('/status/:id/', statusRequest); diff --git a/src/realms/twitter/router.ts b/src/realms/twitter/router.ts index 3f79666..0d50a59 100644 --- a/src/realms/twitter/router.ts +++ b/src/realms/twitter/router.ts @@ -98,9 +98,13 @@ twitter.get('/owoembed', oembed); twitter.get('/robots.txt', async c => c.text(Strings.ROBOTS_TXT)); twitter.get('/i/events/:id', genericTwitterRedirect); +twitter.get('/i/trending/:id', genericTwitterRedirect); twitter.get('/hashtag/:hashtag', genericTwitterRedirect); twitter.get('/:handle/', _profileRequest); twitter.get('/:handle', _profileRequest); +/* Redirect profile subpages in case someone links them for some reason (https://github.com/FixTweet/FxTwitter/issues/603) */ +twitter.get('/:handle/:subpage', genericTwitterRedirect); +twitter.get('/:handle/:subpage/', genericTwitterRedirect); twitter.all('*', async c => c.redirect(Constants.REDIRECT_URL, 302)); diff --git a/src/realms/twitter/routes/status.ts b/src/realms/twitter/routes/status.ts index 4138e70..e70b32f 100644 --- a/src/realms/twitter/routes/status.ts +++ b/src/realms/twitter/routes/status.ts @@ -44,7 +44,7 @@ export const statusRequest = async (c: Context) => { Also note that all we're doing here is setting the direct flag. If someone links a video and ends it with .jpg, it will still redirect to a .mp4! */ - if (url.pathname.match(/\/status(es)?\/\d{2,20}\.(mp4|png|jpe?g)/g)) { + if (url.pathname.match(/\/status(es)?\/\d{2,20}\.(mp4|png|jpe?g|gifv?)/g)) { console.log('Direct media request by extension'); flags.direct = true; } else if (Constants.DIRECT_MEDIA_DOMAINS.includes(url.hostname)) { @@ -63,6 +63,9 @@ export const statusRequest = async (c: Context) => { } else if (Constants.GALLERY_DOMAINS.includes(url.hostname)) { console.log('Gallery embed request'); flags.gallery = true; + } else if (Constants.NATIVE_MULTI_IMAGE_DOMAINS.includes(url.hostname)) { + console.log('Force native multi-image'); + flags.nativeMultiImage = true; } else if (prefix === 'dl' || prefix === 'dir') { console.log('Direct media request by path prefix'); flags.direct = true; diff --git a/src/render/instantview.ts b/src/render/instantview.ts index 5725519..d11b8be 100644 --- a/src/render/instantview.ts +++ b/src/render/instantview.ts @@ -64,9 +64,9 @@ const formatDate = (date: Date): string => { }; const htmlifyLinks = (input: string): string => { - const urlPattern = /\bhttps?:\/\/\S+/g; + const urlPattern = /\bhttps?:\/\/[\w.-]+\.\w+[/\w.-]*\w/g; return input.replace(urlPattern, url => { - return `${url}`; + return `${url}`; }); }; @@ -129,6 +129,23 @@ const generateInlineAuthorHeader = (status: APIStatus, author: APIUser, authorAc }); } +const wrapForeignLinks = (url: string) => { + let unwrap = false; + const whitelistedDomains = ['twitter.com', 'x.com', 't.me', 'telegram.me']; + try { + const urlObj = new URL(url); + + if (!whitelistedDomains.includes(urlObj.hostname)) { + unwrap = true; + } + } catch (error) { + unwrap = true; + } + + return unwrap + ? `https://${Constants.API_HOST_LIST[0]}/2/hit?url=${encodeURIComponent(url)}` + : url; +}; const generateStatusFooter = (status: APIStatus, isQuote = false, author: APIUser): string => { let description = author.description; @@ -164,7 +181,7 @@ const generateStatusFooter = (status: APIStatus, isQuote = false, author: APIUse }'s profile picture" />`, location: author.location ? `📌 ${author.location}` : '', website: author.website - ? `🔗 ${author.website.display_url}` + ? `🔗 ${author.website.display_url}` : '', joined: author.joined ? `📆 ${formatDate(new Date(author.joined))}` : '', following: truncateSocialCount(author.following), diff --git a/src/render/video.ts b/src/render/video.ts index 065cc87..a07a867 100644 --- a/src/render/video.ts +++ b/src/render/video.ts @@ -1,4 +1,5 @@ import { Constants } from '../constants'; +import { Experiment, experimentCheck } from '../experiments'; import { handleQuote } from '../helpers/quote'; import { Strings } from '../strings'; @@ -47,14 +48,28 @@ export const renderVideo = ( instructions.authorText += `\n${handleQuote(status.quote)}`; } + let url = video.url; + + if ( + experimentCheck(Experiment.TRANSCODE_GIFS, !!Constants.GIF_TRANSCODE_DOMAIN) && + !userAgent?.includes('Telegram') && + video.type === 'gif' + ) { + url = video.url.replace( + Constants.TWITTER_VIDEO_BASE, + `https://${Constants.GIF_TRANSCODE_DOMAIN}` + ); + console.log('We passed checks for transcoding GIFs, feeding embed url', url); + } + /* Push the raw video-related headers */ instructions.addHeaders = [ ``, ``, - ``, + ``, ``, - ``, - ``, + ``, + ``, ``, ``, ``, diff --git a/src/types/env.d.ts b/src/types/env.d.ts index 111de5f..7a02d4a 100644 --- a/src/types/env.d.ts +++ b/src/types/env.d.ts @@ -5,11 +5,13 @@ declare const TEXT_ONLY_DOMAINS: string; declare const INSTANT_VIEW_DOMAINS: string; declare const INSTANT_VIEW_THREADS_DOMAINS: string; declare const GALLERY_DOMAINS: string; +declare const NATIVE_MULTI_IMAGE_DOMAINS: string; declare const HOST_URL: string; declare const EMBED_URL: string; declare const REDIRECT_URL: string; declare const MOSAIC_DOMAIN_LIST: string; declare const API_HOST_LIST: string; +declare const GIF_TRANSCODE_DOMAIN: string; declare const SENTRY_DSN: string; declare const RELEASE_NAME: string; diff --git a/src/types/types.d.ts b/src/types/types.d.ts index 6a9c2d4..cc1e635 100644 --- a/src/types/types.d.ts +++ b/src/types/types.d.ts @@ -11,6 +11,7 @@ type InputFlags = { instantViewUnrollThreads?: boolean; archive?: boolean; gallery?: boolean; + nativeMultiImage?: boolean; }; interface StatusResponse { @@ -102,6 +103,7 @@ interface APIVideo extends APIMedia { thumbnail_url: string; format: string; duration: number; + variants: TweetMediaFormat[]; } interface APIMosaicPhoto extends APIMedia { diff --git a/src/types/vendor/twitter.d.ts b/src/types/vendor/twitter.d.ts index 6d3cbee..3a589f5 100644 --- a/src/types/vendor/twitter.d.ts +++ b/src/types/vendor/twitter.d.ts @@ -440,7 +440,8 @@ type GraphQLTwitterStatus = { | 'last_updated_datetime_utc' | 'duration_minutes' | 'api' - | 'card_url'; + | 'card_url' + | 'unified_card'; value: | { string_value: string; // "Option text" diff --git a/src/worker.ts b/src/worker.ts index e20dbf4..3d5ab74 100644 --- a/src/worker.ts +++ b/src/worker.ts @@ -10,7 +10,8 @@ import { twitter } from './realms/twitter/router'; import { cacheMiddleware } from './caches'; const noCache = 'max-age=0, no-cache, no-store, must-revalidate'; -const embeddingClientRegex = /(discordbot|telegrambot|facebook|whatsapp|firefox\/92|vkshare|revoltchat|preview)/gi; +const embeddingClientRegex = + /(discordbot|telegrambot|facebook|whatsapp|firefox\/92|vkshare|revoltchat|preview|iframely)/gi; /* This is the root app which contains route trees for multiple "realms".