From ea1ea8bb5df1a82627e3466efc9cb27c720a0538 Mon Sep 17 00:00:00 2001 From: Riccardo Date: Fri, 20 Sep 2024 11:39:50 +0200 Subject: [PATCH] fix: handle summary links and sanitization --- .env.example | 3 +- app/api/confirmation/route.ts | 2 +- app/api/mailing/route.ts | 6 +- components/email/Newsletter.tsx | 13 +- package.json | 1 + utils/summarize.ts | 4 +- yarn.lock | 288 +++++++++++++++++++++++++++++++- 7 files changed, 303 insertions(+), 14 deletions(-) diff --git a/.env.example b/.env.example index cc0f59f..dff7edf 100644 --- a/.env.example +++ b/.env.example @@ -37,4 +37,5 @@ VERCEL_GIT_REPO_OWNER="" VERCEL_GIT_REPO_SLUG="" VERCEL_URL="" ANALYZE="false" -ANTHROPIC_API_KEY="" \ No newline at end of file +ANTHROPIC_API_KEY="" +NEWS_TO_USE=10 \ No newline at end of file diff --git a/app/api/confirmation/route.ts b/app/api/confirmation/route.ts index a8e1aed..e7dab55 100644 --- a/app/api/confirmation/route.ts +++ b/app/api/confirmation/route.ts @@ -16,7 +16,7 @@ export const dynamic = 'force-dynamic'; // defaults to force-static export async function POST(request: NextRequest) { try { if (!process.env.RESEND_KEY || !process.env.RESEND_AUDIENCE) { - throw new Error('RESEND_AUDIENCE is not set'); + throw new Error('Resend variables not set'); } const body = await request.json(); const validation = ConfirmationSchema.safeParse(body); diff --git a/app/api/mailing/route.ts b/app/api/mailing/route.ts index 4a75413..19a292d 100644 --- a/app/api/mailing/route.ts +++ b/app/api/mailing/route.ts @@ -21,6 +21,10 @@ export async function GET(request: NextRequest) { return ApiResponse(STATUS_UNAUTHORIZED, 'Unauthorized'); } + if (!process.env.NEWS_TO_USE) { + throw new Error('NEWS_TO_USE is not set'); + } + try { // send newsletter to users who didn't get it in the last 23h 50m, assuming a cron job every 10 minutes // this is to avoid sending the newsletter to the same users multiple times @@ -61,7 +65,7 @@ export async function GET(request: NextRequest) { orderBy: { score: 'desc' }, - take: 25 + take: Number(process.env.NEWS_TO_USE) }); console.info(`Found ${news.length} news to include in the newsletter.`); diff --git a/components/email/Newsletter.tsx b/components/email/Newsletter.tsx index 931fbcd..2b6d2cc 100644 --- a/components/email/Newsletter.tsx +++ b/components/email/Newsletter.tsx @@ -2,10 +2,14 @@ import { getSayings } from '@utils/getSayings'; import { summirize } from '@utils/summarize'; import { textTruncate } from '@utils/textTruncate'; import { NewsType } from '@utils/validationSchemas'; +import createDOMPurify from 'isomorphic-dompurify'; import Template from './Template'; export default async function NewsletterTemplate(stories: NewsType[]) { const summary = await summirize(stories); + const sanitizedSummary = createDOMPurify.sanitize(summary, { + USE_PROFILES: { html: true } + }); return { subject: `What's new from the Hackernews forum?`, @@ -15,21 +19,20 @@ export default async function NewsletterTemplate(stories: NewsType[]) { ${getSayings[Math.floor(Math.random() * getSayings.length)]}!`} body={ <> - {summary && ( + {sanitizedSummary && (
- {summary} -
+ dangerouslySetInnerHTML={{ __html: sanitizedSummary }} + /> )}
{stories.map(story => { diff --git a/package.json b/package.json index 8822677..15f829b 100644 --- a/package.json +++ b/package.json @@ -30,6 +30,7 @@ "@vercel/analytics": "^1.1.1", "class-variance-authority": "^0.7.0", "clsx": "^2.0.0", + "isomorphic-dompurify": "^2.15.0", "next": "^14.1.0", "postcss-nesting": "^12.0.2", "react": "^18", diff --git a/utils/summarize.ts b/utils/summarize.ts index 6120d4e..58ca2db 100644 --- a/utils/summarize.ts +++ b/utils/summarize.ts @@ -7,7 +7,7 @@ export async function summirize(news: NewsType[]) { .join('\n\n'); const promptSetup = - "You are a tech journalist with a technology degree and background. Summarize the following list of posts from an online forum as a TL;DR (Too Long; Didn't Read) summary. Your summary should:\n\n1. Be 200-500 words long.\n\n2. Consist multiple phrases in one single paragraph, combining related news items where possible.\n\n3. Highlight the 2-3 most significant or impactful news items.\n\n4. Provide context within broader tech trends or developments.\n\n5. Use a tone that is informative and slightly enthusiastic, aimed at tech-savvy general readers.\n\n6. Group news items by themes or technology areas if applicable.\n\n7. Be formatted for HTML use, with links incorporated as follows: [linked text]\n\nFocus on conveying the key points and their potential impact on the tech landscape. Your response should consist of the summary only.\n\nThe news items are structured as follows:\n\nTITLE: \n\nCONTENT: <content>\n\nLINK: <link>\n\nPlease summarize the following news:"; + "You are a tech journalist with a technology degree and background. Summarize the following list of posts from an online forum as a TL;DR (Too Long; Didn't Read) summary. Your summary should:\n\n1. Be 150-300 words long (not counting the urls).\n\n2. Consist multiple phrases in one single paragraph, combining related news items where possible.\n\n3. Highlight the 2-3 most significant or impactful news items.\n\n4. Provide context within broader tech trends or developments.\n\n5. Use a tone that is informative and slightly enthusiastic, aimed at tech-savvy general readers.\n\n6. Group news items by themes or technology areas if applicable.\n\n7. Be formatted for HTML use, with links incorporated as follows and including at most 3-4 words: <a href='[LINK]'>[linked text]</a>\n\nFocus on conveying the key points and their potential impact on the tech landscape. Your response should consist of the summary only.\n\nThe news items are structured as follows:\n\nTITLE: <title>\n\nCONTENT: <content>\n\nLINK: <link>\n\nPlease summarize the following news:"; try { const response = await message(promptSetup + newsInput); @@ -16,6 +16,6 @@ export async function summirize(news: NewsType[]) { return summary.text; } catch (error) { console.error(error); - return; + return ''; } } diff --git a/yarn.lock b/yarn.lock index 82085c4..78b0e37 100644 --- a/yarn.lock +++ b/yarn.lock @@ -736,6 +736,15 @@ __metadata: languageName: node linkType: hard +"@types/dompurify@npm:^3.0.5": + version: 3.0.5 + resolution: "@types/dompurify@npm:3.0.5" + dependencies: + "@types/trusted-types": "npm:*" + checksum: e544b3ce53c41215cabff3d89256ff707c7ee8e0c9a1b5034b22014725d288b16e6942cdcdeeb4221c578c3421a6a4721aa0676431f55d7abd18c07368855c5e + languageName: node + linkType: hard + "@types/json-schema@npm:^7.0.12": version: 7.0.15 resolution: "@types/json-schema@npm:7.0.15" @@ -834,6 +843,13 @@ __metadata: languageName: node linkType: hard +"@types/trusted-types@npm:*": + version: 2.0.7 + resolution: "@types/trusted-types@npm:2.0.7" + checksum: 8e4202766a65877efcf5d5a41b7dd458480b36195e580a3b1085ad21e948bc417d55d6f8af1fd2a7ad008015d4117d5fdfe432731157da3c68678487174e4ba3 + languageName: node + linkType: hard + "@typescript-eslint/eslint-plugin@npm:^6.12.0": version: 6.21.0 resolution: "@typescript-eslint/eslint-plugin@npm:6.21.0" @@ -1818,6 +1834,15 @@ __metadata: languageName: node linkType: hard +"cssstyle@npm:^4.0.1": + version: 4.1.0 + resolution: "cssstyle@npm:4.1.0" + dependencies: + rrweb-cssom: "npm:^0.7.1" + checksum: 8ca9e2d1f1b24f93bb5f3f20a7a1e271e58060957880e985ee55614e196a798ffab309ec6bac105af8a439a6764546761813835ebb7f929d60823637ee838a8f + languageName: node + linkType: hard + "csstype@npm:^3.0.2": version: 3.1.3 resolution: "csstype@npm:3.1.3" @@ -1839,6 +1864,16 @@ __metadata: languageName: node linkType: hard +"data-urls@npm:^5.0.0": + version: 5.0.0 + resolution: "data-urls@npm:5.0.0" + dependencies: + whatwg-mimetype: "npm:^4.0.0" + whatwg-url: "npm:^14.0.0" + checksum: 5c40568c31b02641a70204ff233bc4e42d33717485d074244a98661e5f2a1e80e38fe05a5755dfaf2ee549f2ab509d6a3af2a85f4b2ad2c984e5d176695eaf46 + languageName: node + linkType: hard + "data-view-buffer@npm:^1.0.1": version: 1.0.1 resolution: "data-view-buffer@npm:1.0.1" @@ -1917,6 +1952,13 @@ __metadata: languageName: node linkType: hard +"decimal.js@npm:^10.4.3": + version: 10.4.3 + resolution: "decimal.js@npm:10.4.3" + checksum: de663a7bc4d368e3877db95fcd5c87b965569b58d16cdc4258c063d231ca7118748738df17cd638f7e9dd0be8e34cec08d7234b20f1f2a756a52fc5a38b188d0 + languageName: node + linkType: hard + "deep-equal@npm:^2.0.5": version: 2.2.3 resolution: "deep-equal@npm:2.2.3" @@ -2054,6 +2096,13 @@ __metadata: languageName: node linkType: hard +"dompurify@npm:^3.1.6": + version: 3.1.6 + resolution: "dompurify@npm:3.1.6" + checksum: 036844bc9b717b172ba27f5863b56f950289a05d8eebfb702d6953bbf80bd021e480ce4217bd084567186f2d0ada13358ce5556963492cfe402d774e8667f120 + languageName: node + linkType: hard + "domutils@npm:^3.0.1": version: 3.1.0 resolution: "domutils@npm:3.1.0" @@ -3233,6 +3282,15 @@ __metadata: languageName: node linkType: hard +"html-encoding-sniffer@npm:^4.0.0": + version: 4.0.0 + resolution: "html-encoding-sniffer@npm:4.0.0" + dependencies: + whatwg-encoding: "npm:^3.1.1" + checksum: e86efd493293a5671b8239bd099d42128433bb3c7b0fdc7819282ef8e118a21f5dead0ad6f358e024a4e5c84f17ebb7a9b36075220fac0a6222b207248bede6f + languageName: node + linkType: hard + "html-escaper@npm:^2.0.2": version: 2.0.2 resolution: "html-escaper@npm:2.0.2" @@ -3272,7 +3330,7 @@ __metadata: languageName: node linkType: hard -"http-proxy-agent@npm:^7.0.0": +"http-proxy-agent@npm:^7.0.0, http-proxy-agent@npm:^7.0.2": version: 7.0.2 resolution: "http-proxy-agent@npm:7.0.2" dependencies: @@ -3282,7 +3340,7 @@ __metadata: languageName: node linkType: hard -"https-proxy-agent@npm:^7.0.1": +"https-proxy-agent@npm:^7.0.1, https-proxy-agent@npm:^7.0.5": version: 7.0.5 resolution: "https-proxy-agent@npm:7.0.5" dependencies: @@ -3324,7 +3382,7 @@ __metadata: languageName: node linkType: hard -"iconv-lite@npm:^0.6.2": +"iconv-lite@npm:0.6.3, iconv-lite@npm:^0.6.2": version: 0.6.3 resolution: "iconv-lite@npm:0.6.3" dependencies: @@ -3629,6 +3687,13 @@ __metadata: languageName: node linkType: hard +"is-potential-custom-element-name@npm:^1.0.1": + version: 1.0.1 + resolution: "is-potential-custom-element-name@npm:1.0.1" + checksum: ced7bbbb6433a5b684af581872afe0e1767e2d1146b2207ca0068a648fb5cab9d898495d1ac0583524faaf24ca98176a7d9876363097c2d14fee6dd324f3a1ab + languageName: node + linkType: hard + "is-regex@npm:^1.1.4": version: 1.1.4 resolution: "is-regex@npm:1.1.4" @@ -3752,6 +3817,17 @@ __metadata: languageName: node linkType: hard +"isomorphic-dompurify@npm:^2.15.0": + version: 2.15.0 + resolution: "isomorphic-dompurify@npm:2.15.0" + dependencies: + "@types/dompurify": "npm:^3.0.5" + dompurify: "npm:^3.1.6" + jsdom: "npm:^25.0.0" + checksum: a8cbf6e7680be9d8c795d4fca427d673c6fc78bacec736331897795566a6bde9d61f9cbee0d22f89cab0be0ba4f62a8d61484e0639a115e4aed0501e80c583f9 + languageName: node + linkType: hard + "iterator.prototype@npm:^1.1.2": version: 1.1.2 resolution: "iterator.prototype@npm:1.1.2" @@ -3843,6 +3919,40 @@ __metadata: languageName: node linkType: hard +"jsdom@npm:^25.0.0": + version: 25.0.0 + resolution: "jsdom@npm:25.0.0" + dependencies: + cssstyle: "npm:^4.0.1" + data-urls: "npm:^5.0.0" + decimal.js: "npm:^10.4.3" + form-data: "npm:^4.0.0" + html-encoding-sniffer: "npm:^4.0.0" + http-proxy-agent: "npm:^7.0.2" + https-proxy-agent: "npm:^7.0.5" + is-potential-custom-element-name: "npm:^1.0.1" + nwsapi: "npm:^2.2.12" + parse5: "npm:^7.1.2" + rrweb-cssom: "npm:^0.7.1" + saxes: "npm:^6.0.0" + symbol-tree: "npm:^3.2.4" + tough-cookie: "npm:^4.1.4" + w3c-xmlserializer: "npm:^5.0.0" + webidl-conversions: "npm:^7.0.0" + whatwg-encoding: "npm:^3.1.1" + whatwg-mimetype: "npm:^4.0.0" + whatwg-url: "npm:^14.0.0" + ws: "npm:^8.18.0" + xml-name-validator: "npm:^5.0.0" + peerDependencies: + canvas: ^2.11.2 + peerDependenciesMeta: + canvas: + optional: true + checksum: f07271fe3922458885540b4dd9fb6170a11059f3128ec3cec2688c5c10fde5ca2e8ddcc207fff540e21dfaf592fae6a791c3359038ba4d116250dd3258fbd8cb + languageName: node + linkType: hard + "json-buffer@npm:3.0.1": version: 3.0.1 resolution: "json-buffer@npm:3.0.1" @@ -4561,6 +4671,7 @@ __metadata: eslint-config-next: "npm:14.0.3" eslint-config-prettier: "npm:^9.0.0" husky: "npm:^8.0.3" + isomorphic-dompurify: "npm:^2.15.0" lint-staged: "npm:^15.1.0" next: "npm:^14.1.0" postcss: "npm:^8" @@ -4695,6 +4806,13 @@ __metadata: languageName: node linkType: hard +"nwsapi@npm:^2.2.12": + version: 2.2.12 + resolution: "nwsapi@npm:2.2.12" + checksum: 172119e9ef492467ebfb337f9b5fd12a94d2b519377cde3f6ec2f74a86f6d5c00ef3873539bed7142f908ffca4e35383179be2319d04a563071d146bfa3f1673 + languageName: node + linkType: hard + "object-assign@npm:^4.0.1, object-assign@npm:^4.1.1": version: 4.1.1 resolution: "object-assign@npm:4.1.1" @@ -4920,6 +5038,15 @@ __metadata: languageName: node linkType: hard +"parse5@npm:^7.1.2": + version: 7.1.2 + resolution: "parse5@npm:7.1.2" + dependencies: + entities: "npm:^4.4.0" + checksum: 3c86806bb0fb1e9a999ff3a4c883b1ca243d99f45a619a0898dbf021a95a0189ed955c31b07fe49d342b54e814f33f2c9d7489198e8630dacd5477d413ec5782 + languageName: node + linkType: hard + "parseley@npm:^0.12.0": version: 0.12.1 resolution: "parseley@npm:0.12.1" @@ -5264,13 +5391,27 @@ __metadata: languageName: node linkType: hard -"punycode@npm:^2.1.0": +"psl@npm:^1.1.33": + version: 1.9.0 + resolution: "psl@npm:1.9.0" + checksum: d07879d4bfd0ac74796306a8e5a36a93cfb9c4f4e8ee8e63fbb909066c192fe1008cd8f12abd8ba2f62ca28247949a20c8fb32e1d18831d9e71285a1569720f9 + languageName: node + linkType: hard + +"punycode@npm:^2.1.0, punycode@npm:^2.1.1, punycode@npm:^2.3.1": version: 2.3.1 resolution: "punycode@npm:2.3.1" checksum: febdc4362bead22f9e2608ff0171713230b57aff9dddc1c273aa2a651fbd366f94b7d6a71d78342a7c0819906750351ca7f2edd26ea41b626d87d6a13d1bd059 languageName: node linkType: hard +"querystringify@npm:^2.1.1": + version: 2.2.0 + resolution: "querystringify@npm:2.2.0" + checksum: 46ab16f252fd892fc29d6af60966d338cdfeea68a231e9457631ffd22d67cec1e00141e0a5236a2eb16c0d7d74175d9ec1d6f963660c6f2b1c2fc85b194c5680 + languageName: node + linkType: hard + "queue-microtask@npm:^1.2.2": version: 1.2.3 resolution: "queue-microtask@npm:1.2.3" @@ -5441,6 +5582,13 @@ __metadata: languageName: node linkType: hard +"requires-port@npm:^1.0.0": + version: 1.0.0 + resolution: "requires-port@npm:1.0.0" + checksum: 878880ee78ccdce372784f62f52a272048e2d0827c29ae31e7f99da18b62a2b9463ea03a75f277352f4697c100183debb0532371ad515a2d49d4bfe596dd4c20 + languageName: node + linkType: hard + "resend@npm:^3.1.0": version: 3.4.0 resolution: "resend@npm:3.4.0" @@ -5574,6 +5722,13 @@ __metadata: languageName: node linkType: hard +"rrweb-cssom@npm:^0.7.1": + version: 0.7.1 + resolution: "rrweb-cssom@npm:0.7.1" + checksum: e80cf25c223a823921d7ab57c0ce78f5b7ebceab857b400cce99dd4913420ce679834bc5707e8ada47d062e21ad368108a9534c314dc8d72c20aa4a4fa0ed16a + languageName: node + linkType: hard + "run-parallel@npm:^1.1.9": version: 1.2.0 resolution: "run-parallel@npm:1.2.0" @@ -5620,6 +5775,15 @@ __metadata: languageName: node linkType: hard +"saxes@npm:^6.0.0": + version: 6.0.0 + resolution: "saxes@npm:6.0.0" + dependencies: + xmlchars: "npm:^2.2.0" + checksum: 97b50daf6ca3a153e89842efa18a862e446248296622b7473c169c84c823ee8a16e4a43bac2f73f11fc8cb9168c73fbb0d73340f26552bac17970e9052367aa9 + languageName: node + linkType: hard + "scheduler@npm:^0.23.2": version: 0.23.2 resolution: "scheduler@npm:0.23.2" @@ -6162,6 +6326,13 @@ __metadata: languageName: node linkType: hard +"symbol-tree@npm:^3.2.4": + version: 3.2.4 + resolution: "symbol-tree@npm:3.2.4" + checksum: c09a00aadf279d47d0c5c46ca3b6b2fbaeb45f0a184976d599637d412d3a70bbdc043ff33effe1206dea0e36e0ad226cb957112e7ce9a4bf2daedf7fa4f85c53 + languageName: node + linkType: hard + "tailwind-merge@npm:^2.1.0": version: 2.4.0 resolution: "tailwind-merge@npm:2.4.0" @@ -6296,6 +6467,27 @@ __metadata: languageName: node linkType: hard +"tough-cookie@npm:^4.1.4": + version: 4.1.4 + resolution: "tough-cookie@npm:4.1.4" + dependencies: + psl: "npm:^1.1.33" + punycode: "npm:^2.1.1" + universalify: "npm:^0.2.0" + url-parse: "npm:^1.5.3" + checksum: 75663f4e2cd085f16af0b217e4218772adf0617fb3227171102618a54ce0187a164e505d61f773ed7d65988f8ff8a8f935d381f87da981752c1171b076b4afac + languageName: node + linkType: hard + +"tr46@npm:^5.0.0": + version: 5.0.0 + resolution: "tr46@npm:5.0.0" + dependencies: + punycode: "npm:^2.3.1" + checksum: 29155adb167d048d3c95d181f7cb5ac71948b4e8f3070ec455986e1f34634acae50ae02a3c8d448121c3afe35b76951cd46ed4c128fd80264280ca9502237a3e + languageName: node + linkType: hard + "tr46@npm:~0.0.3": version: 0.0.3 resolution: "tr46@npm:0.0.3" @@ -6498,6 +6690,13 @@ __metadata: languageName: node linkType: hard +"universalify@npm:^0.2.0": + version: 0.2.0 + resolution: "universalify@npm:0.2.0" + checksum: e86134cb12919d177c2353196a4cc09981524ee87abf621f7bc8d249dbbbebaec5e7d1314b96061497981350df786e4c5128dbf442eba104d6e765bc260678b5 + languageName: node + linkType: hard + "update-browserslist-db@npm:^1.1.0": version: 1.1.0 resolution: "update-browserslist-db@npm:1.1.0" @@ -6521,6 +6720,16 @@ __metadata: languageName: node linkType: hard +"url-parse@npm:^1.5.3": + version: 1.5.10 + resolution: "url-parse@npm:1.5.10" + dependencies: + querystringify: "npm:^2.1.1" + requires-port: "npm:^1.0.0" + checksum: c9e96bc8c5b34e9f05ddfeffc12f6aadecbb0d971b3cc26015b58d5b44676a99f50d5aeb1e5c9e61fa4d49961ae3ab1ae997369ed44da51b2f5ac010d188e6ad + languageName: node + linkType: hard + "util-deprecate@npm:^1.0.1, util-deprecate@npm:^1.0.2": version: 1.0.2 resolution: "util-deprecate@npm:1.0.2" @@ -6538,6 +6747,15 @@ __metadata: languageName: node linkType: hard +"w3c-xmlserializer@npm:^5.0.0": + version: 5.0.0 + resolution: "w3c-xmlserializer@npm:5.0.0" + dependencies: + xml-name-validator: "npm:^5.0.0" + checksum: d78f59e6b4f924aa53b6dfc56949959229cae7fe05ea9374eb38d11edcec01398b7f5d7a12576bd5acc57ff446abb5c9115cd83b9d882555015437cf858d42f0 + languageName: node + linkType: hard + "web-streams-polyfill@npm:4.0.0-beta.3": version: 4.0.0-beta.3 resolution: "web-streams-polyfill@npm:4.0.0-beta.3" @@ -6552,6 +6770,13 @@ __metadata: languageName: node linkType: hard +"webidl-conversions@npm:^7.0.0": + version: 7.0.0 + resolution: "webidl-conversions@npm:7.0.0" + checksum: 4c4f65472c010eddbe648c11b977d048dd96956a625f7f8b9d64e1b30c3c1f23ea1acfd654648426ce5c743c2108a5a757c0592f02902cf7367adb7d14e67721 + languageName: node + linkType: hard + "webpack-bundle-analyzer@npm:4.10.1": version: 4.10.1 resolution: "webpack-bundle-analyzer@npm:4.10.1" @@ -6575,6 +6800,32 @@ __metadata: languageName: node linkType: hard +"whatwg-encoding@npm:^3.1.1": + version: 3.1.1 + resolution: "whatwg-encoding@npm:3.1.1" + dependencies: + iconv-lite: "npm:0.6.3" + checksum: bbef815eb67f91487c7f2ef96329743f5fd8357d7d62b1119237d25d41c7e452dff8197235b2d3c031365a17f61d3bb73ca49d0ed1582475aa4a670815e79534 + languageName: node + linkType: hard + +"whatwg-mimetype@npm:^4.0.0": + version: 4.0.0 + resolution: "whatwg-mimetype@npm:4.0.0" + checksum: 894a618e2d90bf444b6f309f3ceb6e58cf21b2beaa00c8b333696958c4076f0c7b30b9d33413c9ffff7c5832a0a0c8569e5bb347ef44beded72aeefd0acd62e8 + languageName: node + linkType: hard + +"whatwg-url@npm:^14.0.0": + version: 14.0.0 + resolution: "whatwg-url@npm:14.0.0" + dependencies: + tr46: "npm:^5.0.0" + webidl-conversions: "npm:^7.0.0" + checksum: 67ea7a359a90663b28c816d76379b4be62d13446e9a4c0ae0b5ae0294b1c22577750fcdceb40827bb35a61777b7093056953c856604a28b37d6a209ba59ad062 + languageName: node + linkType: hard + "whatwg-url@npm:^5.0.0": version: 5.0.0 resolution: "whatwg-url@npm:5.0.0" @@ -6727,6 +6978,35 @@ __metadata: languageName: node linkType: hard +"ws@npm:^8.18.0": + version: 8.18.0 + resolution: "ws@npm:8.18.0" + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: ">=5.0.2" + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + checksum: 70dfe53f23ff4368d46e4c0b1d4ca734db2c4149c6f68bc62cb16fc21f753c47b35fcc6e582f3bdfba0eaeb1c488cddab3c2255755a5c3eecb251431e42b3ff6 + languageName: node + linkType: hard + +"xml-name-validator@npm:^5.0.0": + version: 5.0.0 + resolution: "xml-name-validator@npm:5.0.0" + checksum: 43f30f3f6786e406dd665acf08cd742d5f8a46486bd72517edb04b27d1bcd1599664c2a4a99fc3f1e56a3194bff588b12f178b7972bc45c8047bdc4c3ac8d4a1 + languageName: node + linkType: hard + +"xmlchars@npm:^2.2.0": + version: 2.2.0 + resolution: "xmlchars@npm:2.2.0" + checksum: 4ad5924974efd004a47cce6acf5c0269aee0e62f9a805a426db3337af7bcbd331099df174b024ace4fb18971b8a56de386d2e73a1c4b020e3abd63a4a9b917f1 + languageName: node + linkType: hard + "y18n@npm:^5.0.5": version: 5.0.8 resolution: "y18n@npm:5.0.8"