diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index 3e06b6773a331b..1a29f35400dfee 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -2,4 +2,4 @@ github: DIYgod patreon: DIYgod open_collective: RSSHub -custom: ['https://afdian.net/a/diygod', 'https://docs.rsshub.app/support'] +custom: ['https://afdian.net/a/diygod', 'https://docs.rsshub.app/sponsor'] diff --git a/.github/ISSUE_TEMPLATE/bug_report_en.yml b/.github/ISSUE_TEMPLATE/bug_report_en.yml index ac686b2dcc909a..de560dad5979cc 100644 --- a/.github/ISSUE_TEMPLATE/bug_report_en.yml +++ b/.github/ISSUE_TEMPLATE/bug_report_en.yml @@ -6,7 +6,7 @@ body: - type: markdown attributes: value: | - Please ensure you have read [documentation](https://docs.rsshub.app/en), and provide all the information required by this template, otherwise the issue will be closed immediately. + Please ensure you have read [documentation](https://docs.rsshub.app/), and provide all the information required by this template, otherwise the issue will be closed immediately. Due to the anti-crawling policy implemented by certain websites, some RSS routes provided by the demo will return status code 403. This is not an issue caused by RSSHub and please do not report it. - type: textarea diff --git a/.github/ISSUE_TEMPLATE/feature_request_en.yml b/.github/ISSUE_TEMPLATE/feature_request_en.yml index ed5db239e07fe0..7aee701cc8e5d9 100644 --- a/.github/ISSUE_TEMPLATE/feature_request_en.yml +++ b/.github/ISSUE_TEMPLATE/feature_request_en.yml @@ -7,7 +7,7 @@ body: - type: markdown attributes: value: | - Please ensure the feature requested is not listed in [documentation](https://docs.rsshub.app/en) or [issue](https://github.com/DIYgod/RSSHub/issues), and is not a [new RSS proposal](https://github.com/DIYgod/RSSHub/issues/new?assignees=&labels=RSS+proposal&template=rss_request_en.yml), and provide all the information required by this template. + Please ensure the feature requested is not listed in [documentation](https://docs.rsshub.app/) or [issue](https://github.com/DIYgod/RSSHub/issues), and is not a [new RSS proposal](https://github.com/DIYgod/RSSHub/issues/new?assignees=&labels=RSS+proposal&template=rss_request_en.yml), and provide all the information required by this template. Otherwise the issue will be closed immediately. - type: textarea diff --git a/.github/ISSUE_TEMPLATE/rss_request_en.yml b/.github/ISSUE_TEMPLATE/rss_request_en.yml index 322b48e143d2ed..0f1efc64b5c915 100644 --- a/.github/ISSUE_TEMPLATE/rss_request_en.yml +++ b/.github/ISSUE_TEMPLATE/rss_request_en.yml @@ -7,7 +7,7 @@ body: - type: markdown attributes: value: | - Please ensure the RSS proposal is not listed in [documentation](https://docs.rsshub.app/en) or [issue](https://github.com/DIYgod/RSSHub/issues), website doesn't provide this kind of RSS feed, and provide all the information required by this template. + Please ensure the RSS proposal is not listed in [documentation](https://docs.rsshub.app/) or [issue](https://github.com/DIYgod/RSSHub/issues), website doesn't provide this kind of RSS feed, and provide all the information required by this template. Otherwise the issue will be closed immediately. We are flooded with feature requests and short-handed, please try to make it yourself, the [guide](https://docs.rsshub.app/joinus) is a good place to start. Submit a pull request when done! diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 12d5111208bd9d..273aa2c8b304c6 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1 +1 @@ -## Please refer to [Join Us](https://docs.rsshub.app/joinus/quick-start) +## Please refer to [Join Us](https://docs.rsshub.app/joinus/) diff --git a/README.md b/README.md index 936fb4887170b3..8eb2654555ec1d 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ RSSHub can be used with browser extension [RSSHub Radar](https://github.com/DIYg        

-[![](https://opencollective.com/static/images/become_sponsor.svg)](https://docs.rsshub.app/support/) +[![](https://opencollective.com/static/images/become_sponsor.svg)](https://docs.rsshub.app/sponsor/) ### Contributors @@ -54,15 +54,15 @@ Logo designer [sheldonrrr](https://dribbble.com/sheldonrrr) We welcome all pull requests. Suggestions and feedback are also welcomed [here](https://github.com/DIYgod/RSSHub/issues). -Refer to [Join Us](https://docs.rsshub.app/joinus/quick-start) +Refer to [Join Us](https://docs.rsshub.app/joinus/) ## Deployment -Refer to [Deployment](https://docs.rsshub.app/install/) +Refer to [Deployment](https://docs.rsshub.app/deploy/) ## Support RSSHub -Refer to [Support RSSHub](https://docs.rsshub.app/support/) +Refer to [Support RSSHub](https://docs.rsshub.app/sponsor/) RSSHub is open source and completely free under the MIT license. However, just like any other open source project, as the project grows, the hosting, development and maintenance requires funding support. diff --git a/api/vercel.ts b/api/vercel.ts index 1f9ac0208e03c1..12a2a910b723a3 100644 --- a/api/vercel.ts +++ b/api/vercel.ts @@ -12,6 +12,6 @@ const app = require('../lib/app'); const logger = require('../lib/utils/logger'); logger.info(`🎉 RSSHub is running! Cheers!`); -logger.info('💖 Can you help keep this open source project alive? Please sponsor 👉 https://docs.rsshub.app/support'); +logger.info('💖 Can you help keep this open source project alive? Please sponsor 👉 https://docs.rsshub.app/sponsor'); module.exports = handle(app); diff --git a/lib/app.tsx b/lib/app.tsx index c3b27ab41f2e17..5615affc107b47 100644 --- a/lib/app.tsx +++ b/lib/app.tsx @@ -1,4 +1,4 @@ -import '@/utils/request-wrapper'; +import '@/utils/request-rewriter'; import { Hono } from 'hono'; diff --git a/lib/config.test.ts b/lib/config.test.ts index 1d59fd0f9261f9..edf38055a6dfcc 100644 --- a/lib/config.test.ts +++ b/lib/config.test.ts @@ -1,5 +1,4 @@ import { describe, expect, it, afterEach, vi } from 'vitest'; -import nock from 'nock'; afterEach(() => { vi.resetModules(); @@ -93,11 +92,6 @@ describe('config', () => { it('remote config', async () => { process.env.REMOTE_CONFIG = 'http://rsshub.test/config'; - nock(/rsshub\.test/) - .get('/config') - .reply(200, { - UA: 'test', - }); const { config } = await import('./config'); await new Promise((resolve) => setTimeout(resolve, 100)); expect(config.ua).toBe('test'); diff --git a/lib/config.ts b/lib/config.ts index d99935c457cc54..2be41d9e52ada0 100644 --- a/lib/config.ts +++ b/lib/config.ts @@ -1,6 +1,6 @@ import 'dotenv/config'; import randUserAgent from '@/utils/rand-user-agent'; -import got from 'got'; +import { ofetch } from 'ofetch'; let envs = process.env; @@ -634,9 +634,8 @@ const calculateValue = () => { calculateValue(); if (envs.REMOTE_CONFIG) { - got.get(envs.REMOTE_CONFIG) - .then(async (response) => { - const data = JSON.parse(response.body); + ofetch(envs.REMOTE_CONFIG) + .then(async (data) => { if (data) { envs = Object.assign(envs, data); calculateValue(); diff --git a/lib/errors/index.test.ts b/lib/errors/index.test.ts index a89a84af62a232..f76af62198a959 100644 --- a/lib/errors/index.test.ts +++ b/lib/errors/index.test.ts @@ -22,7 +22,7 @@ describe('httperror', () => { it(`httperror`, async () => { const response = await request.get('/test/httperror'); expect(response.status).toBe(503); - expect(response.text).toMatch('Response code 404 (Not Found): target website might be blocking our access, you can host your own RSSHub instance for a better usability.'); + expect(response.text).toMatch('404 Not Found: target website might be blocking our access, you can host your own RSSHub instance for a better usability.'); }, 20000); }); diff --git a/lib/errors/index.tsx b/lib/errors/index.tsx index f2ff4bde7ec2aa..913bd3b82c7e2c 100644 --- a/lib/errors/index.tsx +++ b/lib/errors/index.tsx @@ -39,7 +39,7 @@ export const errorHandler: ErrorHandler = (error, ctx) => { } let message = ''; - if (error.name && (error.name === 'HTTPError' || error.name === 'RequestError')) { + if (error.name && (error.name === 'HTTPError' || error.name === 'RequestError' || error.name === 'FetchError')) { ctx.status(503); message = `${error.message}: target website might be blocking our access, you can host your own RSSHub instance for a better usability.`; } else if (error instanceof RequestInProgressError) { diff --git a/lib/index.ts b/lib/index.ts index edef861a134e38..24e7a247c3d3ac 100644 --- a/lib/index.ts +++ b/lib/index.ts @@ -8,7 +8,7 @@ const port = config.connect.port; const hostIPList = getLocalhostAddress(); logger.info(`🎉 RSSHub is running on port ${port}! Cheers!`); -logger.info('💖 Can you help keep this open source project alive? Please sponsor 👉 https://docs.rsshub.app/support'); +logger.info('💖 Can you help keep this open source project alive? Please sponsor 👉 https://docs.rsshub.app/sponsor'); logger.info(`🔗 Local: 👉 http://localhost:${port}`); for (const ip of hostIPList) { logger.info(`🔗 Network: 👉 http://${ip}:${port}`); diff --git a/lib/middleware/cache.test.ts b/lib/middleware/cache.test.ts index 7edce9fc5baf43..393d8153e7d4f1 100644 --- a/lib/middleware/cache.test.ts +++ b/lib/middleware/cache.test.ts @@ -3,7 +3,7 @@ import Parser from 'rss-parser'; import wait from '@/utils/wait'; process.env.CACHE_EXPIRE = '1'; -process.env.CACHE_CONTENT_EXPIRE = '3'; +process.env.CACHE_CONTENT_EXPIRE = '2'; const parser = new Parser(); @@ -38,7 +38,7 @@ describe('cache', () => { expect(response3.headers).not.toHaveProperty('rsshub-cache-status'); const parsed3 = await parser.parseString(await response3.text()); - await wait(3 * 1000 + 100); + await wait(2 * 1000 + 100); const response4 = await app.request('/test/cache'); const parsed4 = await parser.parseString(await response4.text()); @@ -51,7 +51,7 @@ describe('cache', () => { await wait(1 * 1000 + 100); const response5 = await app.request('/test/refreshCache'); const parsed5 = await parser.parseString(await response5.text()); - await wait(2 * 1000 + 100); + await wait(1 * 1000 + 100); const response6 = await app.request('/test/refreshCache'); const parsed6 = await parser.parseString(await response6.text()); @@ -86,7 +86,7 @@ describe('cache', () => { expect(response3.headers).not.toHaveProperty('rsshub-cache-status'); const parsed3 = await parser.parseString(await response3.text()); - await wait(3 * 1000 + 100); + await wait(2 * 1000 + 100); const response4 = await app.request('/test/cache'); const parsed4 = await parser.parseString(await response4.text()); @@ -99,7 +99,7 @@ describe('cache', () => { await wait(1 * 1000 + 100); const response5 = await app.request('/test/refreshCache'); const parsed5 = await parser.parseString(await response5.text()); - await wait(2 * 1000 + 100); + await wait(1 * 1000 + 100); const response6 = await app.request('/test/refreshCache'); const parsed6 = await parser.parseString(await response6.text()); diff --git a/lib/middleware/parameter.test.ts b/lib/middleware/parameter.test.ts index 2a31436d3018ed..6fb8788bbf35b2 100644 --- a/lib/middleware/parameter.test.ts +++ b/lib/middleware/parameter.test.ts @@ -1,8 +1,12 @@ import { describe, expect, it, vi } from 'vitest'; -import app from '@/app'; import Parser from 'rss-parser'; -import { config } from '@/config'; -import nock from 'nock'; + +process.env.OPENAI_API_KEY = 'sk-1234567890'; +process.env.OPENAI_API_ENDPOINT = 'https://api.openai.mock/v1'; + +vi.mock('@/utils/request-rewriter', () => ({ default: null })); +const { config } = await import('@/config'); +const { default: app } = await import('@/app'); const parser = new Parser(); @@ -424,26 +428,6 @@ describe('multi parameter', () => { describe('openai', () => { it(`chatgpt`, async () => { - vi.resetModules(); - - process.env.OPENAI_API_KEY = 'sk-1234567890'; - const app = (await import('@/app')).default; - const { config } = await import('@/config'); - nock(config.openai.endpoint) - .post('/chat/completions') - .reply(() => [ - 200, - { - choices: [ - { - message: { - content: 'Summary of the article.', - }, - }, - ], - }, - ]); - const responseWithGpt = await app.request('/test/gpt?chatgpt=true'); const responseNormal = await app.request('/test/gpt'); diff --git a/lib/middleware/parameter.ts b/lib/middleware/parameter.ts index 1933889128678d..843f9bc1f931b9 100644 --- a/lib/middleware/parameter.ts +++ b/lib/middleware/parameter.ts @@ -1,7 +1,7 @@ import * as entities from 'entities'; import { load, type CheerioAPI, type Element } from 'cheerio'; import { simplecc } from 'simplecc-wasm'; -import got from '@/utils/got'; +import ofetch from '@/utils/ofetch'; import { config } from '@/config'; import { RE2JS } from 're2js'; import markdownit from 'markdown-it'; @@ -34,8 +34,9 @@ const resolveRelativeLink = ($: CheerioAPI, elem: Element, attr: string, baseUrl const summarizeArticle = async (articleText: string) => { const apiUrl = `${config.openai.endpoint}/chat/completions`; - const response = await got.post(apiUrl, { - json: { + const response = await ofetch(apiUrl, { + method: 'POST', + body: { model: config.openai.model, max_tokens: config.openai.maxTokens, messages: [ @@ -49,8 +50,7 @@ const summarizeArticle = async (articleText: string) => { }, }); - // @ts-expect-error custom field - return response.data.choices[0].message.content; + return response.choices[0].message.content; }; const getAuthorString = (item) => { @@ -305,8 +305,7 @@ const middleware: MiddlewareHandler = async (ctx, next) => { if (link) { // if parser failed, return default description and not report error try { - // @ts-expect-error custom field - const { data: res } = await got(link); + const res = await ofetch(link); const $ = load(res); const result = await Parser.parse(link, { html: $.html(), @@ -380,7 +379,7 @@ const middleware: MiddlewareHandler = async (ctx, next) => { } } } else { - throw new Error(`Invalid parameter brief. Please check the doc https://docs.rsshub.app/parameter#shu-chu-jian-xun`); + throw new Error(`Invalid parameter brief. Please check the doc https://docs.rsshub.app/guide/parameters#shu-chu-jian-xun`); } } // some parameters are processed in `anti-hotlink.js` diff --git a/lib/registry.ts b/lib/registry.ts index 74101502df2bd9..7d20172e226406 100644 --- a/lib/registry.ts +++ b/lib/registry.ts @@ -45,7 +45,7 @@ if (Object.keys(modules).length) { | { namespace: Namespace; }; - const namespace = module.split('/')[1]; + const namespace = module.split(/[/\\]/)[1]; if ('namespace' in content) { namespaces[namespace] = Object.assign( { @@ -65,13 +65,13 @@ if (Object.keys(modules).length) { for (const path of content.route.path) { namespaces[namespace].routes[path] = { ...content.route, - location: module.split('/').slice(2).join('/'), + location: module.split(/[/\\]/).slice(2).join('/'), }; } } else { namespaces[namespace].routes[content.route.path] = { ...content.route, - location: module.split('/').slice(2).join('/'), + location: module.split(/[/\\]/).slice(2).join('/'), }; } } diff --git a/lib/routes-deprecated/005tv/zx.js b/lib/routes-deprecated/005tv/zx.js deleted file mode 100644 index 007546baa5cfd6..00000000000000 --- a/lib/routes-deprecated/005tv/zx.js +++ /dev/null @@ -1,24 +0,0 @@ -const got = require('@/utils/got'); -const host = 'http://www.005.tv/zx'; -const cheerio = require('cheerio'); - -module.exports = async (ctx) => { - const response = await got(host); - const data = response.body; - const $ = cheerio.load(data); - const list = $('div.article-list li'); - ctx.state.data = { - title: $('head > title').text(), - link: host, - description: '二次元资讯', - item: list - .map((index, item) => ({ - title: $(item).find('h3 > a').text().trim(), - description: `
- ${$(item).find('div.p-row').text()}`, - link: $(item).find('h3 > a').attr('href'), - pubDate: new Date($(item).find('span.fr.time').text().trim().slice(0, 4), $(item).find('span.fr.time').text().trim().slice(5, 7), $(item).find('span.fr.time').text().trim().slice(8, 12)).toUTCString(), - })) - .get(), - }; -}; diff --git a/lib/routes-deprecated/disqus/posts.js b/lib/routes-deprecated/disqus/posts.js index ab1779e1ea7c9d..28e72e887ced98 100644 --- a/lib/routes-deprecated/disqus/posts.js +++ b/lib/routes-deprecated/disqus/posts.js @@ -3,7 +3,7 @@ const config = require('@/config').value; module.exports = async (ctx) => { if (!config.disqus || !config.disqus.api_key) { - throw new Error('Disqus RSS is disabled due to the lack of relevant config'); + throw new Error('Disqus RSS is disabled due to the lack of relevant config'); } const forum = ctx.params.forum; diff --git a/lib/routes-deprecated/fanfou/favorites.js b/lib/routes-deprecated/fanfou/favorites.js index abeb4bb35e82a3..7131ef49874878 100644 --- a/lib/routes-deprecated/fanfou/favorites.js +++ b/lib/routes-deprecated/fanfou/favorites.js @@ -3,7 +3,7 @@ const utils = require('./utils'); module.exports = async (ctx) => { if (!config.fanfou || !config.fanfou.consumer_key || !config.fanfou.consumer_secret || !config.fanfou.username || !config.fanfou.password) { - throw new Error('Fanfou RSS is disabled due to the lack of relevant config'); + throw new Error('Fanfou RSS is disabled due to the lack of relevant config'); } const uid = ctx.params.uid; diff --git a/lib/routes-deprecated/fanfou/home-timeline.js b/lib/routes-deprecated/fanfou/home-timeline.js index 94af0c2d8d2f5c..4c97e848a6dc39 100644 --- a/lib/routes-deprecated/fanfou/home-timeline.js +++ b/lib/routes-deprecated/fanfou/home-timeline.js @@ -3,7 +3,7 @@ const utils = require('./utils'); module.exports = async (ctx) => { if (!config.fanfou || !config.fanfou.consumer_key || !config.fanfou.consumer_secret || !config.fanfou.username || !config.fanfou.password) { - throw new Error('Fanfou RSS is disabled due to the lack of relevant config'); + throw new Error('Fanfou RSS is disabled due to the lack of relevant config'); } const fanfou = await utils.getFanfou(); diff --git a/lib/routes-deprecated/fanfou/public-timeline.js b/lib/routes-deprecated/fanfou/public-timeline.js index 81d18f28e27231..90e41bf03fb78e 100644 --- a/lib/routes-deprecated/fanfou/public-timeline.js +++ b/lib/routes-deprecated/fanfou/public-timeline.js @@ -3,7 +3,7 @@ const utils = require('./utils'); module.exports = async (ctx) => { if (!config.fanfou || !config.fanfou.consumer_key || !config.fanfou.consumer_secret || !config.fanfou.username || !config.fanfou.password) { - throw new Error('Fanfou RSS is disabled due to the lack of relevant config'); + throw new Error('Fanfou RSS is disabled due to the lack of relevant config'); } const keyword = ctx.params.keyword; diff --git a/lib/routes-deprecated/fanfou/user-timeline.js b/lib/routes-deprecated/fanfou/user-timeline.js index 4f6d9d8611bb2c..3644f7c34b64c2 100644 --- a/lib/routes-deprecated/fanfou/user-timeline.js +++ b/lib/routes-deprecated/fanfou/user-timeline.js @@ -3,7 +3,7 @@ const utils = require('./utils'); module.exports = async (ctx) => { if (!config.fanfou || !config.fanfou.consumer_key || !config.fanfou.consumer_secret || !config.fanfou.username || !config.fanfou.password) { - throw new Error('Fanfou RSS is disabled due to the lack of relevant config'); + throw new Error('Fanfou RSS is disabled due to the lack of relevant config'); } const uid = ctx.params.uid; diff --git a/lib/routes-deprecated/lastfm/loved.js b/lib/routes-deprecated/lastfm/loved.js index 51ca36f9cb68d5..276e2802ba411c 100644 --- a/lib/routes-deprecated/lastfm/loved.js +++ b/lib/routes-deprecated/lastfm/loved.js @@ -3,7 +3,7 @@ const config = require('@/config').value; module.exports = async (ctx) => { if (!config.lastfm || !config.lastfm.api_key) { - throw new Error('Last.fm RSS is disabled due to the lack of relevant config'); + throw new Error('Last.fm RSS is disabled due to the lack of relevant config'); } const user = ctx.params.user; diff --git a/lib/routes-deprecated/lastfm/recent.js b/lib/routes-deprecated/lastfm/recent.js index 02b17668ce2c3b..4915fe7d8729b6 100644 --- a/lib/routes-deprecated/lastfm/recent.js +++ b/lib/routes-deprecated/lastfm/recent.js @@ -3,7 +3,7 @@ const config = require('@/config').value; module.exports = async (ctx) => { if (!config.lastfm || !config.lastfm.api_key) { - throw new Error('Last.fm RSS is disabled due to the lack of relevant config'); + throw new Error('Last.fm RSS is disabled due to the lack of relevant config'); } const user = ctx.params.user; diff --git a/lib/routes-deprecated/lastfm/top.js b/lib/routes-deprecated/lastfm/top.js index 3ee3b7ee25ab21..b58f357399e8c5 100644 --- a/lib/routes-deprecated/lastfm/top.js +++ b/lib/routes-deprecated/lastfm/top.js @@ -3,7 +3,7 @@ const config = require('@/config').value; module.exports = async (ctx) => { if (!config.lastfm || !config.lastfm.api_key) { - throw new Error('Last.fm RSS is disabled due to the lack of relevant config'); + throw new Error('Last.fm RSS is disabled due to the lack of relevant config'); } const country = ctx.params.country; diff --git a/lib/routes/005/index.ts b/lib/routes/005/index.ts new file mode 100644 index 00000000000000..9b8c1ec34a312a --- /dev/null +++ b/lib/routes/005/index.ts @@ -0,0 +1,156 @@ +import { Route } from '@/types'; +import { getCurrentPath } from '@/utils/helpers'; +const __dirname = getCurrentPath(import.meta.url); + +import cache from '@/utils/cache'; +import got from '@/utils/got'; +import { load } from 'cheerio'; +import timezone from '@/utils/timezone'; +import { parseDate } from '@/utils/parse-date'; +import { art } from '@/utils/render'; +import * as path from 'node:path'; + +export const handler = async (ctx) => { + const { category = 'zx' } = ctx.req.param(); + const limit = ctx.req.query('limit') ? Number.parseInt(ctx.req.query('limit'), 10) : 20; + + const rootUrl = 'https://005.tv'; + const currentUrl = new URL(category ? `${category}/` : '', rootUrl).href; + + const { data: response } = await got(currentUrl); + + const $ = load(response); + + const language = $('html').prop('lang'); + + let items = $('div.article-list ul li') + .slice(0, limit) + .toArray() + .map((item) => { + item = $(item); + + const title = item.find('h3').text(); + const image = item.find('img').prop('src'); + + const description = art(path.join(__dirname, 'templates/description.art'), { + intro: item.find('div.p-row').text(), + images: image + ? [ + { + src: image, + alt: title, + }, + ] + : undefined, + }); + + return { + title, + description, + pubDate: parseDate(item.find('span.time').text()), + link: new URL(item.find('h3 a').prop('href'), rootUrl).href, + content: { + html: description, + text: item.find('div.p-row').text(), + }, + image, + banner: image, + language, + }; + }); + + items = await Promise.all( + items.map((item) => + cache.tryGet(item.link, async () => { + const { data: detailResponse } = await got(item.link); + + const $$ = load(detailResponse); + + const title = $$('h1.articleTitle-name').text(); + const description = $$('div.articleContent').html(); + + item.title = title; + item.description = description; + item.pubDate = timezone(parseDate($$('.time').text()), +8); + item.category = $$('meta[name="keywords"]').prop('content').split(/,/); + item.content = { + html: description, + text: $$('div.articleContent').text(), + }; + item.language = language; + + return item; + }) + ) + ); + + const title = $('title').text(); + const image = new URL('templets/muban/style/images/logo.png', rootUrl).href; + + return { + title, + description: title.split(/_/)[0], + link: currentUrl, + item: items, + allowEmpty: true, + image, + author: title.split(/,/).pop(), + language, + }; +}; + +export const route: Route = { + path: '/:category?', + name: '资讯', + url: '005.tv', + maintainers: ['nczitzk'], + handler, + example: '/005/zx', + parameters: { category: '分类,可在对应分类页 URL 中找到,默认为二次元资讯' }, + description: ` + | 二次元资讯 | 慢慢说 | 道听途说 | 展会资讯 | + | ---------- | ------ | -------- | -------- | + | zx | zwh | dtts | zh | + `, + categories: ['anime'], + + features: { + requireConfig: false, + requirePuppeteer: false, + antiCrawler: false, + supportRadar: true, + supportBT: false, + supportPodcast: false, + supportScihub: false, + }, + radar: [ + { + source: ['005.tv/:category'], + target: (params) => { + const category = params.category; + + return `/005${category ? `/${category}` : ''}`; + }, + }, + { + title: '二次元资讯', + source: ['005.tv/zx/'], + target: '/005/zx', + }, + { + title: '慢慢说', + source: ['005.tv/zwh/'], + target: '/005/zwh', + }, + { + title: '道听途说', + source: ['005.tv/dtts/'], + target: '/005/dtts', + }, + { + title: '展会资讯', + source: ['005.tv/zh/'], + target: '/005/zh', + }, + ], +}; diff --git a/lib/routes/005/namespace.ts b/lib/routes/005/namespace.ts new file mode 100644 index 00000000000000..fcf20a8fb0f1bd --- /dev/null +++ b/lib/routes/005/namespace.ts @@ -0,0 +1,8 @@ +import type { Namespace } from '@/types'; + +export const namespace: Namespace = { + name: '幻之羁绊动漫网', + url: '005.tv', + categories: ['anime'], + description: '', +}; diff --git a/lib/routes/005/templates/description.art b/lib/routes/005/templates/description.art new file mode 100644 index 00000000000000..d96cdbc563e13b --- /dev/null +++ b/lib/routes/005/templates/description.art @@ -0,0 +1,27 @@ +{{ if images }} + {{ each images image }} + {{ if !videos?.[0]?.src && image?.src }} +
+ {{ image.alt }} +
+ {{ /if }} + {{ /each }} +{{ /if }} + +{{ if intro }} +
{{ intro }}
+{{ /if }} + +{{ if description }} + {{@ description }} +{{ /if }} \ No newline at end of file diff --git a/lib/routes/163/music/playlist.ts b/lib/routes/163/music/playlist.ts index 5a7861217dbbf0..61da28a6270687 100644 --- a/lib/routes/163/music/playlist.ts +++ b/lib/routes/163/music/playlist.ts @@ -27,7 +27,7 @@ export const route: Route = { async function handler(ctx) { if (!config.ncm || !config.ncm.cookies) { - throw new Error('163 Music RSS is disabled due to the lack of relevant config'); + throw new Error('163 Music RSS is disabled due to the lack of relevant config'); } const id = ctx.req.param('id'); diff --git a/lib/routes/1lou/index.ts b/lib/routes/1lou/index.ts index 9769567760af48..0d3f16267b3c2c 100644 --- a/lib/routes/1lou/index.ts +++ b/lib/routes/1lou/index.ts @@ -1,88 +1,147 @@ import { Route } from '@/types'; + import cache from '@/utils/cache'; import got from '@/utils/got'; import { load } from 'cheerio'; import timezone from '@/utils/timezone'; import { parseDate } from '@/utils/parse-date'; -export const route: Route = { - path: '/:path?', - categories: ['multimedia'], - example: '/1lou/search-繁花.htm', - parameters: { path: '路径信息在URL里找到,主页为 index' }, - features: { - requireConfig: false, - requirePuppeteer: false, - antiCrawler: false, - supportBT: false, - supportPodcast: false, - supportScihub: false, - }, - radar: [ - { - source: ['1lou.me/:path'], - target: '/:path', - }, - ], - name: '搜索', - maintainers: ['falling'], - handler, - description: `:::tip - 将 1lou.me/ 后的内容作为参数传入到 path 即可 +const rootUrl = 'https://www.1lou.me'; - [www.1lou.me/search - 繁花.htm](http://www.1lou.me/search-繁花.htm) --> /1lou/search - 繁花.htm +export const handler = async (ctx) => { + const { params } = ctx.req.param(); + const limit = ctx.req.query('limit') ? Number.parseInt(ctx.req.query('limit'), 10) : 50; - [www.1lou.me/forum-1.htm](http://www.1lou.me/forum-1.htm) --> /1lou/forum-1.htm + const queryString = Object.entries(ctx.req.query()) + .map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`) + .join('&'); - [www.1lou.me/](http://www.1lou.me/) --> /1lou/ - :::`, -}; + const currentUrl = new URL(`${params && params.endsWith('.htm') ? params : `${params}.htm`}${queryString ? `?${queryString}` : ''}`, rootUrl).href; + + const { data: response } = await got(currentUrl); + + const $ = load(response); + + const language = $('html').prop('lang'); -async function handler(ctx) { - const path = ctx.req.param('path') ?? ''; - const rootUrl = `https://www.1lou.me`; - const currentUrl = `${rootUrl}/${path}`; - const response = await got({ - method: 'get', - url: currentUrl, - }); - const $ = load(response.data); - - let items = $('li.media.thread.tap:not(.hidden-sm)') + let items = $('li.media.thread.tap:not(li.hidden-sm)') + .slice(0, limit) .toArray() .map((item) => { - const title = $(item).find('.subject.break-all').children('a').first(); - const author = $(item).find('.username.text-grey.mr-1').text(); - const pubDate = $(item).find('.date.text-grey').text(); + item = $(item); + + const subjectEl = item.find('div.subject').children('a').first(); + return { - title: title.text(), - link: `${rootUrl}/${title.attr('href')}`, - author, - pubDate: timezone(parseDate(pubDate), +8), + title: subjectEl.text(), + pubDate: timezone(parseDate(item.find('span.date').text()), +8), + link: new URL(subjectEl.prop('href'), rootUrl).href, + category: [ + item.find('a.text-secondary').text().replaceAll('[]', ''), + ...item + .find('a.badge') + .toArray() + .map((c) => $(c).text()), + ].filter(Boolean), + author: item.find('a.username').text(), + language, }; }); + items = await Promise.all( items.map((item) => cache.tryGet(item.link, async () => { - const detailResponse = await got({ - method: 'get', - url: item.link, - }); - const content = load(detailResponse.data); - item.description = content('.message.break-all').html(); - const torrents = content('.attachlist').find('a'); - if (torrents.length > 0) { - item.enclosure_type = 'application/x-bittorrent'; - item.enclosure_url = `${rootUrl}/${torrents.first().attr('href')}`; + const { data: detailResponse } = await got(item.link); + + const $$ = load(detailResponse); + + const title = $$('h4.break-all').contents().last().text(); + + if (title) { + const description = $$('div.message.break-all').html(); + const image = new URL($$('img').first().prop('src'), rootUrl).href; + + item.title = title; + item.description = description; + item.pubDate = timezone(parseDate($$('span.date').text()), +8); + item.category = $$('a.badge') + .toArray() + .map((c) => $$(c).text()); + item.content = { + html: description, + text: $$('div.message.break-all').text(), + }; + item.image = image; + item.banner = image; + item.language = language; + + const torrents = $$('ul.attachlist li a'); + + if (torrents.length > 0) { + const torrent = torrents.first(); + + item.enclosure_url = new URL(torrent.prop('href'), rootUrl).href; + item.enclosure_type = 'application/x-bittorrent'; + item.enclosure_title = torrent.text(); + } } return item; }) ) ); + + const author = 'BT 之家 1LOU 站'; + const image = new URL($('img.logo-2').prop('src'), rootUrl).href; + return { - title: '1Lou', + title: `${$('title').text().split(/-/)[0]} - ${author}`, + description: $('meta[name="description"]').prop('content'), link: currentUrl, item: items, + allowEmpty: true, + image, + author, + language, }; -} +}; + +export const route: Route = { + path: '/:params{.+}?', + name: '通用', + url: '1lou.me', + maintainers: ['falling', 'nczitzk'], + handler, + example: '/1lou/forum-2-1', + parameters: { params: '路径参数,可以在对应页面的 URL 中找到' }, + description: `:::tip + \`1lou.me/\` 后的内容填入 params 参数,以下是几个例子: + + 若订阅 [大陆电视剧](https://www.1lou.me/forum-2-1.htm?tagids=0_97_0_0),网址为 \`https://www.1lou.me/forum-2-1.htm?tagids=0_97_0_0\`。截取 \`https://www.1lou.me/\` 到末尾 \`.htm\` 的部分 \`forum-2-1\` 作为参数,并补充 \`tagids\`,此时路由为 [\`/1lou/forum-2-1?tagids=0_97_0_0\`](https://rsshub.app/1lou/forum-2-1?tagids=0_97_0_0)。 + + 若订阅 [最新发帖电视剧](https://www.1lou.me/forum-2-1.htm?orderby=tid&digest=0),网址为 \`https://www.1lou.me/forum-2-1.htm?orderby=tid&digest=0\`。截取 \`https://www.1lou.me/\` 到末尾 \`.htm\` 的部分 \`forum-2-1\` 作为参数,并补充 \`orderby\`,此时路由为 [\`/1lou/forum-2-1?orderby=tid\`](https://rsshub.app/1lou/forum-2-1?orderby=tid)。 + + 若订阅 [搜素繁花主题贴](https://www.1lou.me/search-_E7_B9_81_E8_8A_B1-1.htm),网址为 \`https://www.1lou.me/search-_E7_B9_81_E8_8A_B1-1.htm\`。截取 \`https://www.1lou.me/\` 到末尾 \`.htm\` 的部分 \`search-_E7_B9_81_E8_8A_B1-1\` 作为参数,此时路由为 [\`/1lou/search-_E7_B9_81_E8_8A_B1-1\`](https://rsshub.app/1lou/search-_E7_B9_81_E8_8A_B1-1)。 + :::`, + categories: ['multimedia'], + + features: { + requireConfig: false, + requirePuppeteer: false, + antiCrawler: false, + supportRadar: true, + supportBT: false, + supportPodcast: false, + supportScihub: false, + }, + radar: [ + { + source: ['1lou.me/:params'], + target: (_, url) => { + url = new URL(url); + + return `/1lou${url.href.replace(rootUrl, '')}`; + }, + }, + ], +}; diff --git a/lib/routes/1lou/namespace.ts b/lib/routes/1lou/namespace.ts index 388f617e4fd5c3..03f3b6c0adb5be 100644 --- a/lib/routes/1lou/namespace.ts +++ b/lib/routes/1lou/namespace.ts @@ -3,4 +3,6 @@ import type { Namespace } from '@/types'; export const namespace: Namespace = { name: 'BT 之家 1LOU 站', url: '1lou.me', + categories: ['multimedia'], + description: '', }; diff --git a/lib/routes/bilibili/followers.ts b/lib/routes/bilibili/followers.ts index 36cbd342c0c692..962d860d03df9e 100644 --- a/lib/routes/bilibili/followers.ts +++ b/lib/routes/bilibili/followers.ts @@ -45,7 +45,7 @@ async function handler(ctx) { const cookie = config.bilibili.cookies[loginUid]; if (cookie === undefined) { - throw new Error('缺少对应 loginUid 的 Bilibili 用户登录后的 Cookie 值 bilibili 用户关注动态系列路由'); + throw new Error('缺少对应 loginUid 的 Bilibili 用户登录后的 Cookie 值 bilibili 用户关注动态系列路由'); } const name = await cache.getUsernameFromUID(uid); diff --git a/lib/routes/bilibili/followings.ts b/lib/routes/bilibili/followings.ts index 4f1443896c3a6f..82cce50d205e47 100644 --- a/lib/routes/bilibili/followings.ts +++ b/lib/routes/bilibili/followings.ts @@ -43,7 +43,7 @@ async function handler(ctx) { const loginUid = ctx.req.param('loginUid'); const cookie = config.bilibili.cookies[loginUid]; if (cookie === undefined) { - throw new Error('缺少对应 loginUid 的 Bilibili 用户登录后的 Cookie 值 bilibili 用户关注动态系列路由'); + throw new Error('缺少对应 loginUid 的 Bilibili 用户登录后的 Cookie 值 bilibili 用户关注动态系列路由'); } const uid = ctx.req.param('uid'); diff --git a/lib/routes/bloomberg/utils.ts b/lib/routes/bloomberg/utils.ts index b48da12585c0e7..0bcbbefc761696 100644 --- a/lib/routes/bloomberg/utils.ts +++ b/lib/routes/bloomberg/utils.ts @@ -99,7 +99,7 @@ const parseArticle = (item) => res = await got(apiUrl, { headers }); } catch (error) { // fallback - if (error.name && (error.name === 'HTTPError' || error.name === 'RequestError')) { + if (error.name && (error.name === 'HTTPError' || error.name === 'RequestError' || error.name === 'FetchError')) { try { res = await got(item.link, { headers }); } catch { @@ -214,7 +214,7 @@ const parseReactRendererPage = async (res, api, item) => { return await parseStoryJson(res.data, item); } catch (error) { // fallback - if (error.name && (error.name === 'HTTPError' || error.name === 'RequestError')) { + if (error.name && (error.name === 'HTTPError' || error.name === 'RequestError' || error.name === 'FetchError')) { return { title: item.title, link: item.link, diff --git a/lib/routes/booru/mmda.ts b/lib/routes/booru/mmda.ts index 664cc1bb264d1b..612373541159ad 100644 --- a/lib/routes/booru/mmda.ts +++ b/lib/routes/booru/mmda.ts @@ -1,4 +1,7 @@ import { Route } from '@/types'; +import { getCurrentPath } from '@/utils/helpers'; +const __dirname = getCurrentPath(import.meta.url); + import got from '@/utils/got'; import queryString from 'query-string'; import { load } from 'cheerio'; diff --git a/lib/routes/discord/channel.ts b/lib/routes/discord/channel.ts index d3986c40f64d75..ed2ef1c2166610 100644 --- a/lib/routes/discord/channel.ts +++ b/lib/routes/discord/channel.ts @@ -39,7 +39,7 @@ export const route: Route = { async function handler(ctx) { if (!config.discord || !config.discord.authorization) { - throw new Error('Discord RSS is disabled due to the lack of relevant config'); + throw new Error('Discord RSS is disabled due to the lack of relevant config'); } const { authorization } = config.discord; const channelId = ctx.req.param('channelId'); diff --git a/lib/routes/discourse/utils.ts b/lib/routes/discourse/utils.ts index 1927fd11a36ef4..897738ed72518a 100644 --- a/lib/routes/discourse/utils.ts +++ b/lib/routes/discourse/utils.ts @@ -2,7 +2,7 @@ import { config } from '@/config'; function getConfig(ctx) { if (!config.discourse.config[ctx.req.param('configId')]) { - throw new Error('Discourse RSS is disabled due to the lack of relevant config'); + throw new Error('Discourse RSS is disabled due to the lack of relevant config'); } return config.discourse.config[ctx.req.param('configId')]; } diff --git a/lib/routes/ehentai/favorites.ts b/lib/routes/ehentai/favorites.ts index a5a1d8ad558f4f..2c0dac5a7566f1 100644 --- a/lib/routes/ehentai/favorites.ts +++ b/lib/routes/ehentai/favorites.ts @@ -22,7 +22,7 @@ export const route: Route = { async function handler(ctx) { if (!EhAPI.has_cookie) { - throw new Error('Ehentai favorites RSS is disabled due to the lack of relevant config'); + throw new Error('Ehentai favorites RSS is disabled due to the lack of relevant config'); } const favcat = ctx.req.param('favcat') ? Number.parseInt(ctx.req.param('favcat')) : 0; const page = ctx.req.param('page'); diff --git a/lib/routes/gamer/gnn-index.ts b/lib/routes/gamer/gnn-index.ts index 20d95722643b65..d767ae4fb3b9ef 100644 --- a/lib/routes/gamer/gnn-index.ts +++ b/lib/routes/gamer/gnn-index.ts @@ -13,13 +13,13 @@ export const route: Route = { features: { requireConfig: false, requirePuppeteer: false, - antiCrawler: false, + antiCrawler: true, supportBT: false, supportPodcast: false, supportScihub: false, }, name: 'GNN 新聞', - maintainers: ['Arracc'], + maintainers: ['Arracc', 'ladeng07'], handler, description: `| 首頁 | PC | TV 掌機 | 手機遊戲 | 動漫畫 | 主題報導 | 活動展覽 | 電競 | | ---- | -- | ------- | -------- | ------ | -------- | -------- | ---- | @@ -68,11 +68,13 @@ async function handler(ctx) { url, }); const data = response.data; + const limit = ctx.req.query('limit') ? Number.parseInt(ctx.req.query('limit')) : 50; const $ = load(data); const list = $('div.BH-lbox.GN-lbox2') .children() .not('p,a,img,span') + .slice(0, limit) .map((index, item) => { item = $(item); let aLabelNode; @@ -99,11 +101,11 @@ async function handler(ctx) { item.description = await cache.tryGet(item.link, async () => { const response = await got.get(item.link); let component = ''; - const urlReg = /window.location.replace\('.*'/g; + const urlReg = /window\.lazySizesConfig/g; let pubInfo; let dateStr; - if (response.body.search(urlReg) < 0) { + if (response.body.search(urlReg) >= 0) { const $ = load(response.data); if ($('span.GN-lbox3C').length > 0) { // official publish 1 @@ -119,8 +121,7 @@ async function handler(ctx) { component = $('div.GN-lbox3B').html(); } else { // url redirect - const newUrl = response.body.match(urlReg)[0].split('(')[1].replaceAll("'", ''); - const _response = await got.get(newUrl); + const _response = await got.get(item.link); const _$ = load(_response.data); if (_$('div.MSG-list8C').length > 0) { diff --git a/lib/routes/github/follower.ts b/lib/routes/github/follower.ts index 554de31f358b38..6a6dabb9a8160b 100644 --- a/lib/routes/github/follower.ts +++ b/lib/routes/github/follower.ts @@ -27,7 +27,7 @@ export const route: Route = { async function handler(ctx) { if (!config.github || !config.github.access_token) { - throw new Error('GitHub follower RSS is disabled due to the lack of relevant config'); + throw new Error('GitHub follower RSS is disabled due to the lack of relevant config'); } const user = ctx.req.param('user'); diff --git a/lib/routes/github/notifications.ts b/lib/routes/github/notifications.ts index c12ec85a7cd95d..e0594bd46ff566 100644 --- a/lib/routes/github/notifications.ts +++ b/lib/routes/github/notifications.ts @@ -36,7 +36,7 @@ export const route: Route = { async function handler(ctx) { if (!config.github || !config.github.access_token) { - throw new Error('GitHub trending RSS is disabled due to the lack of relevant config'); + throw new Error('GitHub trending RSS is disabled due to the lack of relevant config'); } const headers = { Accept: 'application/vnd.github.v3+json', diff --git a/lib/routes/github/star.ts b/lib/routes/github/star.ts index 309f513906ac5e..06e2b1b2bac557 100644 --- a/lib/routes/github/star.ts +++ b/lib/routes/github/star.ts @@ -27,7 +27,7 @@ export const route: Route = { async function handler(ctx) { if (!config.github || !config.github.access_token) { - throw new Error('GitHub star RSS is disabled due to the lack of relevant config'); + throw new Error('GitHub star RSS is disabled due to the lack of relevant config'); } const user = ctx.req.param('user'); const repo = ctx.req.param('repo'); diff --git a/lib/routes/github/trending.ts b/lib/routes/github/trending.ts index a8872bfe35815e..fe2ec6cde144ff 100644 --- a/lib/routes/github/trending.ts +++ b/lib/routes/github/trending.ts @@ -44,7 +44,7 @@ export const route: Route = { async function handler(ctx) { if (!config.github || !config.github.access_token) { - throw new Error('GitHub trending RSS is disabled due to the lack of relevant config'); + throw new Error('GitHub trending RSS is disabled due to the lack of relevant config'); } const since = ctx.req.param('since'); const language = ctx.req.param('language') === 'any' ? '' : ctx.req.param('language'); diff --git a/lib/routes/google/fonts.ts b/lib/routes/google/fonts.ts index c21ac8b495a434..2ee8551da8682a 100644 --- a/lib/routes/google/fonts.ts +++ b/lib/routes/google/fonts.ts @@ -42,7 +42,7 @@ export const route: Route = { | date | trending | popularity | alpha | style | :::warning - This route requires API key, therefore it's only available when self-hosting, refer to the [Deploy Guide](https://docs.rsshub.app/install/#configuration-route-specific-configurations) for route-specific configurations. + This route requires API key, therefore it's only available when self-hosting, refer to the [Deploy Guide](https://docs.rsshub.app/deploy/config#route-specific-configurations) for route-specific configurations. :::`, }; diff --git a/lib/routes/gov/chinatax/latest.ts b/lib/routes/gov/chinatax/latest.ts index 6b54a4c734b063..9999b6e496e023 100644 --- a/lib/routes/gov/chinatax/latest.ts +++ b/lib/routes/gov/chinatax/latest.ts @@ -56,7 +56,7 @@ async function handler() { item.description = content('#fontzoom').html(); return item; } catch (error) { - if (error.name === 'HTTPError') { + if (error.name === 'HTTPError' || error.name === 'FetchError') { item.description = error.message; return item; } diff --git a/lib/routes/gov/mot/index.ts b/lib/routes/gov/mot/index.ts index 0eef6b4aa4e783..b273395c57604f 100644 --- a/lib/routes/gov/mot/index.ts +++ b/lib/routes/gov/mot/index.ts @@ -7,8 +7,8 @@ import { parseDate } from '@/utils/parse-date'; export const route: Route = { path: '/mot/:category{.+}?', - name: 'Unknown', - maintainers: [], + name: '中华人民共和国交通运输部', + maintainers: ['ladeng07'], handler, }; @@ -48,7 +48,7 @@ async function handler(ctx) { item.title = content('meta[name="ArticleTitle"]').prop('content') || content('h1#ti').text(); item.description = content('div.TRS_UEDITOR').html(); - item.author = [...new Set([content('meta[name="Author"]').prop('content'), content('meta[name="ContentSource"]').prop('content')])].filter(Boolean); + item.author = [...new Set([content('meta[name="Author"]').prop('content'), content('meta[name="ContentSource"]').prop('content')])].find(Boolean); item.category = [ ...new Set([content('meta[name="ColumnName"]').prop('content'), content('meta[name="ColumnType"]').prop('content'), ...(content('meta[name="Keywords"]').prop('content')?.split(/,|;/) ?? [])]), ].filter(Boolean); diff --git a/lib/routes/hit/namespace.ts b/lib/routes/hit/namespace.ts index 0d2385c40bf8e5..e4eae82546d766 100644 --- a/lib/routes/hit/namespace.ts +++ b/lib/routes/hit/namespace.ts @@ -4,6 +4,6 @@ export const namespace: Namespace = { name: '哈尔滨工业大学', url: 'jwc.hit.edu.cn', description: `:::warning -哈工大网站疑似禁止了\`rsshub.app\`的访问,使用路由需要自行 [部署](https://docs.rsshub.app/install)。 +哈工大网站疑似禁止了\`rsshub.app\`的访问,使用路由需要自行 [部署](https://docs.rsshub.app/deploy/)。 :::`, }; diff --git a/lib/routes/instagram/private-api/index.ts b/lib/routes/instagram/private-api/index.ts index ce6af2cb60cad2..92f1aaedad0354 100644 --- a/lib/routes/instagram/private-api/index.ts +++ b/lib/routes/instagram/private-api/index.ts @@ -78,7 +78,7 @@ export const route: Route = { maintainers: ['oppilate', 'DIYgod'], handler, description: `:::warning -Due to [Instagram Private API](https://github.com/dilame/instagram-private-api) restrictions, you have to setup your credentials on the server. 2FA is not supported. See [deployment guide](https://docs.rsshub.app/install/) for more. +Due to [Instagram Private API](https://github.com/dilame/instagram-private-api) restrictions, you have to setup your credentials on the server. 2FA is not supported. See [deployment guide](https://docs.rsshub.app/deploy/) for more. :::`, }; diff --git a/lib/routes/instagram/private-api/utils.ts b/lib/routes/instagram/private-api/utils.ts index 2ac6fd94802505..f6cdeac65810d6 100644 --- a/lib/routes/instagram/private-api/utils.ts +++ b/lib/routes/instagram/private-api/utils.ts @@ -6,7 +6,7 @@ const ig = new IgApiClient(); async function login(ig, cache) { if (!config.instagram || !config.instagram.username || !config.instagram.password) { - throw new Error('Instagram RSS is disabled due to the lack of relevant config'); + throw new Error('Instagram RSS is disabled due to the lack of relevant config'); } const LOGIN_CACHE_KEY = 'instagram:login'; const { username, password } = config.instagram; diff --git a/lib/routes/instagram/web-api/index.ts b/lib/routes/instagram/web-api/index.ts index 33f916331b1521..f53da7ff0c2750 100644 --- a/lib/routes/instagram/web-api/index.ts +++ b/lib/routes/instagram/web-api/index.ts @@ -33,7 +33,7 @@ You may need to setup cookie for a less restrictive rate limit and private profi async function handler(ctx) { // if (!config.instagram || !config.instagram.cookie) { - // throw Error('Instagram RSS is disabled due to the lack of relevant config'); + // throw Error('Instagram RSS is disabled due to the lack of relevant config'); // } const availableCategories = ['user', 'tags']; const { category, key } = ctx.req.param(); diff --git a/lib/routes/iwara/subscriptions.ts b/lib/routes/iwara/subscriptions.ts index 4bf05913e7c3ac..a845e7dd467024 100644 --- a/lib/routes/iwara/subscriptions.ts +++ b/lib/routes/iwara/subscriptions.ts @@ -45,13 +45,13 @@ export const route: Route = { handler, url: 'ecchi.iwara.tv/', description: `:::warning - This route requires username and password, therefore it's only available when self-hosting, refer to the [Deploy Guide](/install/#route-specific-configurations) for route-specific configurations. + This route requires username and password, therefore it's only available when self-hosting, refer to the [Deploy Guide](https://docs.rsshub.app/deploy/config#route-specific-configurations) for route-specific configurations. :::`, }; async function handler() { if (!config.iwara || !config.iwara.username || !config.iwara.password) { - throw new Error('Iwara subscription RSS is disabled due to the lack of relevant config'); + throw new Error('Iwara subscription RSS is disabled due to the lack of relevant config'); } const rootUrl = `https://www.iwara.tv`; diff --git a/lib/routes/line/utils.ts b/lib/routes/line/utils.ts index e55c00d46b0375..8d9712e4884632 100644 --- a/lib/routes/line/utils.ts +++ b/lib/routes/line/utils.ts @@ -29,7 +29,7 @@ const parseItems = (list, tryGet) => }); data = response.data; } catch (error) { - if (error instanceof got.HTTPError && error.response.statusCode === 404) { + if ((error.name === 'HTTPError' || error.name === 'FetchError') && error.response.statusCode === 404) { logger.error(`Error parsing article ${item.link}: ${error.message}`); return item; } diff --git a/lib/routes/linovelib/volume.ts b/lib/routes/linovelib/volume.ts index 8aa877e3dbfb08..be962f55ebe255 100644 --- a/lib/routes/linovelib/volume.ts +++ b/lib/routes/linovelib/volume.ts @@ -21,7 +21,7 @@ export const route: Route = { async function handler(ctx: Context): Promise { const { id } = ctx.req.param(); const link = `https://www.linovelib.com/novel/${id}/catalog`; - const $ = load(await got(link).text()); + const $ = load((await got(link)).data); return { title: `${$('.book-meta h1').text()} - 哔哩轻小说`, link, diff --git a/lib/routes/mail/imap.ts b/lib/routes/mail/imap.ts index 93ae006466a082..fa9be620c1bc4f 100644 --- a/lib/routes/mail/imap.ts +++ b/lib/routes/mail/imap.ts @@ -23,7 +23,7 @@ async function handler(ctx) { }; if (!mailConfig.username || !mailConfig.password || !mailConfig.host || !mailConfig.port) { - throw new Error('Email Inbox RSS is disabled due to the lack of relevant config'); + throw new Error('Email Inbox RSS is disabled due to the lack of relevant config'); } const client = new ImapFlow({ diff --git a/lib/routes/manhuagui/subscribe.ts b/lib/routes/manhuagui/subscribe.ts index ebc9ae50e8eec9..7e94c6477030af 100644 --- a/lib/routes/manhuagui/subscribe.ts +++ b/lib/routes/manhuagui/subscribe.ts @@ -45,7 +45,7 @@ export const route: Route = { async function handler() { if (!config.manhuagui || !config.manhuagui.cookie) { - throw new Error('manhuagui RSS is disabled due to the lack of relevant config'); + throw new Error('manhuagui RSS is disabled due to the lack of relevant config'); } const cookie = config.manhuagui.cookie; const response = await got({ diff --git a/lib/routes/mastodon/namespace.ts b/lib/routes/mastodon/namespace.ts index f0f3f3dc486db3..0d8b2473cc1822 100644 --- a/lib/routes/mastodon/namespace.ts +++ b/lib/routes/mastodon/namespace.ts @@ -9,6 +9,6 @@ Official user RSS: - RSS: \`https://**:instance**/users/**:username**.rss\` ([Example](https://pawoo.net/users/pawoo_support.rss)) - Atom: ~~\`https://**:instance**/users/**:username**.atom\`~~ (Only for pawoo.net, [example](https://pawoo.net/users/pawoo_support.atom)) -These feed do not include boosts (a.k.a. reblogs). RSSHub provides a feed for user timeline based on the Mastodon API, but to use that, you may need to create application on a Mastodon instance, and configure your RSSHub instance. Check the [Deploy Guide](/install/#route-specific-configurations) for route-specific configurations. +These feed do not include boosts (a.k.a. reblogs). RSSHub provides a feed for user timeline based on the Mastodon API, but to use that, you may need to create application on a Mastodon instance, and configure your RSSHub instance. Check the [Deploy Guide](https://docs.rsshub.app/deploy/config#route-specific-configurations) for route-specific configurations. :::`, }; diff --git a/lib/routes/mastodon/utils.ts b/lib/routes/mastodon/utils.ts index d4492f007ad979..f25cda95e517bb 100644 --- a/lib/routes/mastodon/utils.ts +++ b/lib/routes/mastodon/utils.ts @@ -93,7 +93,7 @@ async function getAccountIdByAcct(acct) { const site = mastodonConfig.apiHost || acctHost; const acctDomain = mastodonConfig.acctDomain || acctHost; if (!(site && acctDomain)) { - throw new Error('Mastodon RSS is disabled due to the lack of relevant config'); + throw new Error('Mastodon RSS is disabled due to the lack of relevant config'); } if (!config.feature.allow_user_supply_unsafe_domain && !allowSiteList.includes(site)) { throw new Error(`RSS for this domain is disabled unless 'ALLOW_USER_SUPPLY_UNSAFE_DOMAIN' is set to 'true' or 'MASTODON_API_HOST' is set.`); diff --git a/lib/routes/mihoyo/bbs/cache.ts b/lib/routes/mihoyo/bbs/cache.ts index 05adf548141c38..9e56eafa7401ff 100644 --- a/lib/routes/mihoyo/bbs/cache.ts +++ b/lib/routes/mihoyo/bbs/cache.ts @@ -4,7 +4,7 @@ import { config } from '@/config'; const getUserFullInfo = (ctx, uid) => { if (!uid && !config.mihoyo.cookie) { - throw new Error('GetUserFullInfo is not available due to the absense of [Miyoushe Cookie]. Check relevant config tutorial'); + throw new Error('GetUserFullInfo is not available due to the absense of [Miyoushe Cookie]. Check relevant config tutorial'); } uid ||= ''; const key = 'mihoyo:user-full-info-uid-' + uid; diff --git a/lib/routes/mihoyo/bbs/timeline.ts b/lib/routes/mihoyo/bbs/timeline.ts index 4a3ce513e0ef7e..04795c48070370 100644 --- a/lib/routes/mihoyo/bbs/timeline.ts +++ b/lib/routes/mihoyo/bbs/timeline.ts @@ -37,7 +37,7 @@ export const route: Route = { async function handler(ctx) { if (!config.mihoyo.cookie) { - throw new Error('Miyoushe Timeline is not available due to the absense of [Miyoushe Cookie]. Check relevant config tutorial'); + throw new Error('Miyoushe Timeline is not available due to the absense of [Miyoushe Cookie]. Check relevant config tutorial'); } const page_size = ctx.req.query('limit') || '20'; diff --git a/lib/routes/minecraft/version.ts b/lib/routes/minecraft/version.ts index c04d8430f2f7e0..f53a6c38c3b346 100644 --- a/lib/routes/minecraft/version.ts +++ b/lib/routes/minecraft/version.ts @@ -1,11 +1,15 @@ import { Route } from '@/types'; import got from '@/utils/got'; +import { Context } from 'hono'; export const route: Route = { - path: '/version', + path: '/version/:versionType?/:linkType?', categories: ['game'], example: '/minecraft/version', - parameters: {}, + parameters: { + versionType: `Game version type, \`all\` by default`, + linkType: `Link added to feed, \`official\` by default`, + }, features: { requireConfig: false, requirePuppeteer: false, @@ -20,39 +24,113 @@ export const route: Route = { }, ], name: 'Java Game Update', - maintainers: ['TheresaQWQ'], + maintainers: ['TheresaQWQ', 'xtexChooser'], handler, url: 'minecraft.net/', + description: ` +| Version | versionType | +| -------------------------- | ----------- | +| 正式版 | release | +| 快照 | snapshot | +| Alpha 及更早的版本 | old_alpha | +| Beta 版 | old_beta | +| Target | linkType | +| -------------------------- | -------- | +| minecraft.net | official | +| 英文 Minecraft Wiki 版本页 | enwiki | +| 中文 Minecraft Wiki 版本页 | zhwiki | +`, + zh: { + name: 'Java版游戏更新', + }, +}; + +interface VersionInManifest { + id: string; + type: string; + releaseTime: string; +} + +const typeName = { + release: '正式版', + snapshot: '快照', + old_alpha: 'Alpha及更早的版本', + old_beta: 'Beta版', }; -async function handler() { - const url = 'https://launchermeta.mojang.com/mc/game/version_manifest.json'; +const linkFormatter: any = { + official: () => `https://www.minecraft.net`, + enwiki: (item: VersionInManifest) => { + let id = item.id; + if (item.type === 'old_beta' && id.startsWith('b')) { + id = `Beta ${id.substring(1)}`; + } + if (item.type === 'old_alpha') { + if (id.startsWith('a')) { + id = `Alpha ${id.substring(1)}`; + } else if (id.startsWith('c')) { + id = `Classic ${id.substring(1)}`; + } else if (id.startsWith('inf-')) { + id = `Infdev`; + } else if (id.startsWith('rd-')) { + id = `pre-Classic ${id}`; + } + } + return `https://minecraft.wiki/w/Java Edition ${id}`; + }, + zhwiki: (item: VersionInManifest) => { + let id = item.id; + if (item.type === 'release') { + id = `Java版${id}`; + } + if (item.type === 'old_beta' && id.startsWith('b')) { + id = `Java版Beta ${id.substring(1)}`; + } + if (item.type === 'old_alpha') { + if (id.startsWith('a')) { + id = `Java版Alpha ${id.substring(1)}`; + } else if (id.startsWith('c')) { + id = `Java版Classic ${id.substring(1)}`; + } else if (id.startsWith('inf-')) { + id = `Java版Infdev`; + } else if (id.startsWith('rd-')) { + id = `Java版pre-Classic ${id}`; + } + } + return `https://zh.minecraft.wiki/w/${id}`; + }, +}; - const response = await got({ +async function handler(ctx?: Context) { + const url = ctx?.req.query('mcmanifest') ?? 'https://piston-meta.mojang.com/mc/game/version_manifest_v2.json'; + + const response: any = await got({ method: 'get', url, + responseType: 'json', }); - const typeMap = { - release: '正式版', - snapshot: '快照', - old_alpha: '过时的预览版', - old_beta: '过时的测试版', - }; + let data: VersionInManifest[] = response.data.versions; + + const versionType = ctx?.req.param('versionType') ?? 'all'; + const linkType = ctx?.req.param('linkType') ?? 'official'; + const linker = linkFormatter[linkType] ?? linkFormatter.official; - const data = response.data.versions; + if (versionType !== 'all') { + data = data.filter((item) => item.type === versionType); + } - const title = `Minecraft Java版游戏更新`; + const title = `Minecraft Java版${versionType === 'all' ? '' : typeName[versionType] ?? versionType}游戏更新`; return { title, link: `https://www.minecraft.net/`, description: title, item: data.map((item) => ({ - title: `${item.id} ${typeMap[item.type] || ''}更新`, - description: `${item.id} ${typeMap[item.type] || ''}更新`, + title: `${item.id} ${typeName[item.type] || ''}更新`, + description: `${item.id} ${typeName[item.type] || ''}更新`, pubDate: new Date(item.releaseTime).toUTCString(), - link: `https://www.minecraft.net`, + link: linker(item), guid: item.id + item.type, })), }; diff --git a/lib/routes/modrinth/versions.ts b/lib/routes/modrinth/versions.ts index e7ba723c16514e..57e5673b5132ac 100644 --- a/lib/routes/modrinth/versions.ts +++ b/lib/routes/modrinth/versions.ts @@ -93,15 +93,19 @@ async function handler(ctx: Context) { }).json(); const authors = await customGot(`https://api.modrinth.com/v2/users`, { searchParams: { - ids: JSON.stringify(versions.map((it) => it.author_id)), + ids: JSON.stringify([...new Set(versions.map((it) => it.author_id))]), }, }).json(); + const groupedAuthors = >{}; + for (const author of authors) { + groupedAuthors[author.id] = author; + } return { title: `${project.title} Modrinth versions`, description: project.description, link: `https://modrinth.com/project/${id}`, - item: versions.map((it, index) => ({ + item: versions.map((it) => ({ title: `${it.name} for ${it.loaders.join('/')} on ${[...new Set([it.game_versions[0], it.game_versions.at(-1)])].join('-')}`, link: `https://modrinth.com/project/${id}/version/${it.version_number}`, pubDate: parseDate(it.date_published), @@ -110,7 +114,7 @@ async function handler(ctx: Context) { changelog: md.render(it.changelog), }), guid: it.id, - author: authors[index].name, + author: groupedAuthors[it.author_id].username, })), }; } catch (error: any) { diff --git a/lib/routes/newrank/douyin.ts b/lib/routes/newrank/douyin.ts index dabdae87d99f3c..4a77715a6acf43 100644 --- a/lib/routes/newrank/douyin.ts +++ b/lib/routes/newrank/douyin.ts @@ -31,7 +31,7 @@ export const route: Route = { async function handler(ctx) { if (!config.newrank || !config.newrank.cookie) { - throw new Error('newrank RSS is disabled due to the lack of relevant config'); + throw new Error('newrank RSS is disabled due to the lack of relevant config'); } const uid = ctx.req.param('dyid'); const nonce = utils.random_nonce(9); diff --git a/lib/routes/newrank/wechat.ts b/lib/routes/newrank/wechat.ts index d84a5c145193ad..592d83a06c327a 100644 --- a/lib/routes/newrank/wechat.ts +++ b/lib/routes/newrank/wechat.ts @@ -30,7 +30,7 @@ export const route: Route = { async function handler(ctx) { if (!config.newrank || !config.newrank.cookie) { - throw new Error('newrank RSS is disabled due to the lack of relevant config'); + throw new Error('newrank RSS is disabled due to the lack of relevant config'); } const uid = ctx.req.param('wxid'); const nonce = utils.random_nonce(9); diff --git a/lib/routes/nhentai/other.ts b/lib/routes/nhentai/other.ts index 027c1661dfaf29..191a140c3cc0c8 100644 --- a/lib/routes/nhentai/other.ts +++ b/lib/routes/nhentai/other.ts @@ -11,7 +11,7 @@ export const route: Route = { parameters: { key: 'Filter term, can be: `parody`, `character`, `tag`, `artist`, `group`, `language` or `category`', keyword: 'Filter value', - mode: 'mode, `simple` to only show cover, `detail` to show all pages, `torrent` to include Magnet URI, need login, refer to [Route-specific Configurations](/install/#configuration-route-specific-configurations), default to `simple`', + mode: 'mode, `simple` to only show cover, `detail` to show all pages, `torrent` to include Magnet URI, need login, refer to [Route-specific Configurations](https://docs.rsshub.app/deploy/config#route-specific-configurations), default to `simple`', }, features: { requireConfig: false, diff --git a/lib/routes/nhentai/search.ts b/lib/routes/nhentai/search.ts index df945511fdd5f9..cb26cf29e63134 100644 --- a/lib/routes/nhentai/search.ts +++ b/lib/routes/nhentai/search.ts @@ -8,7 +8,7 @@ export const route: Route = { example: '/nhentai/search/language%3Ajapanese+-scat+-yaoi+-guro+-"mosaic+censorship"', parameters: { keyword: 'Keywords for search. You can copy the content after `q=` after searching on the original website, or you can enter it directly. See the [official website](https://nhentai.net/info/) for details', - mode: 'mode, `simple` to only show cover, `detail` to show all pages, `torrent` to include Magnet URI, need login, refer to [Route-specific Configurations](/install/#configuration-route-specific-configurations), default to `simple`', + mode: 'mode, `simple` to only show cover, `detail` to show all pages, `torrent` to include Magnet URI, need login, refer to [Route-specific Configurations](https://docs.rsshub.app/deploy/config#route-specific-configurations), default to `simple`', }, features: { requireConfig: false, diff --git a/lib/routes/nhentai/util.ts b/lib/routes/nhentai/util.ts index 9874a684c26e27..b1329a29f158ba 100644 --- a/lib/routes/nhentai/util.ts +++ b/lib/routes/nhentai/util.ts @@ -88,7 +88,7 @@ const getDetails = (cache, simples, limit) => Promise.all(simples.slice(0, limit const getTorrents = async (cache, simples, limit) => { if (!config.nhentai || !config.nhentai.username || !config.nhentai.password) { - throw new Error('nhentai RSS with torrents is disabled due to the lack of relevant config'); + throw new Error('nhentai RSS with torrents is disabled due to the lack of relevant config'); } const cookie = await getCookie(config.nhentai.username, config.nhentai.password, cache); if (!cookie) { diff --git a/lib/routes/notion/database.ts b/lib/routes/notion/database.ts index eda7853547737c..833f4b185514a0 100644 --- a/lib/routes/notion/database.ts +++ b/lib/routes/notion/database.ts @@ -55,7 +55,7 @@ export const route: Route = { async function handler(ctx) { if (!config.notion.key) { - throw new Error('Notion RSS is disabled due to the lack of NOTION_TOKEN(relevant config)'); + throw new Error('Notion RSS is disabled due to the lack of NOTION_TOKEN(relevant config)'); } const databaseId = ctx.req.param('databaseId'); diff --git a/lib/routes/notion/namespace.ts b/lib/routes/notion/namespace.ts index c07c16baf5613f..2910f91ad7956a 100644 --- a/lib/routes/notion/namespace.ts +++ b/lib/routes/notion/namespace.ts @@ -4,7 +4,7 @@ export const namespace: Namespace = { name: 'Notion', url: 'notion.so', description: `:::warning -Need to set up Notion integration, please refer to [Route-specific Configurations](https://docs.rsshub.app/install/#Deployment) for details. +Need to set up Notion integration, please refer to [Route-specific Configurations](https://docs.rsshub.app/deploy/config#route-specific-configurations) for details. ::: :::tip Recommendation diff --git a/lib/routes/ntdm/video.ts b/lib/routes/ntdm/video.ts index 2c0bcdd11feea0..7a320ceb729d05 100644 --- a/lib/routes/ntdm/video.ts +++ b/lib/routes/ntdm/video.ts @@ -6,7 +6,7 @@ import cheerio from 'cheerio'; export const route: Route = { path: '/video/:id', categories: ['anime'], - example: '/ntdm/video/20200035', + example: '/ntdm/video/4309', parameters: { id: '番剧 id,对应详情 URL 中找到' }, features: { requireConfig: false, @@ -22,7 +22,7 @@ export const route: Route = { }, ], name: '番剧详情', - maintainers: ['alexhere'], + maintainers: ['Yamico'], handler, }; diff --git a/lib/routes/phoronix/index.ts b/lib/routes/phoronix/index.ts index d4063906a39813..e4413fd4b96eec 100644 --- a/lib/routes/phoronix/index.ts +++ b/lib/routes/phoronix/index.ts @@ -72,7 +72,7 @@ const webFetch = (url) => try { return webFetchCb(await got(url)); } catch (error) { - if (error.name === 'HTTPError' && error.response.statusCode === 404) { + if ((error.name === 'HTTPError' || error.name === 'FetchError') && error.response.statusCode === 404) { return '404'; } throw error; diff --git a/lib/routes/pianyuan/utils.ts b/lib/routes/pianyuan/utils.ts index 920e953d6a30dd..7948eac5c33c65 100644 --- a/lib/routes/pianyuan/utils.ts +++ b/lib/routes/pianyuan/utils.ts @@ -47,7 +47,7 @@ async function getCookie(cache) { let py_loginauth = await cache.get(loginauth_key); if (!py_loginauth) { if (!config.pianyuan || !config.pianyuan.cookie) { - throw new Error('pianyuan is disabled due to the lack of relevant config'); + throw new Error('pianyuan is disabled due to the lack of relevant config'); } py_loginauth = config.pianyuan.cookie; } diff --git a/lib/routes/pixiv/bookmarks.ts b/lib/routes/pixiv/bookmarks.ts index 862cc2ead9a9c4..ea5fab4bae1618 100644 --- a/lib/routes/pixiv/bookmarks.ts +++ b/lib/routes/pixiv/bookmarks.ts @@ -32,7 +32,7 @@ export const route: Route = { async function handler(ctx) { if (!config.pixiv || !config.pixiv.refreshToken) { - throw new Error('pixiv RSS is disabled due to the lack of relevant config'); + throw new Error('pixiv RSS is disabled due to the lack of relevant config'); } const id = ctx.req.param('id'); diff --git a/lib/routes/pixiv/illustfollow.ts b/lib/routes/pixiv/illustfollow.ts index 33072455f90d48..569499898e086f 100644 --- a/lib/routes/pixiv/illustfollow.ts +++ b/lib/routes/pixiv/illustfollow.ts @@ -40,7 +40,7 @@ export const route: Route = { async function handler() { if (!config.pixiv || !config.pixiv.refreshToken) { - throw new Error('pixiv RSS is disabled due to the lack of relevant config'); + throw new Error('pixiv RSS is disabled due to the lack of relevant config'); } const token = await getToken(cache.tryGet); diff --git a/lib/routes/pixiv/ranking.ts b/lib/routes/pixiv/ranking.ts index 5f6205ce55afee..3f3576941705e2 100644 --- a/lib/routes/pixiv/ranking.ts +++ b/lib/routes/pixiv/ranking.ts @@ -84,7 +84,7 @@ export const route: Route = { async function handler(ctx) { if (!config.pixiv || !config.pixiv.refreshToken) { - throw new Error('pixiv RSS is disabled due to the lack of relevant config'); + throw new Error('pixiv RSS is disabled due to the lack of relevant config'); } const mode = alias[ctx.req.param('mode')] ?? ctx.req.param('mode'); diff --git a/lib/routes/pixiv/search.ts b/lib/routes/pixiv/search.ts index e84b6b9900453f..30c2a04561a74c 100644 --- a/lib/routes/pixiv/search.ts +++ b/lib/routes/pixiv/search.ts @@ -30,7 +30,7 @@ export const route: Route = { async function handler(ctx) { if (!config.pixiv || !config.pixiv.refreshToken) { - throw new Error('pixiv RSS is disabled due to the lack of relevant config'); + throw new Error('pixiv RSS is disabled due to the lack of relevant config'); } const keyword = ctx.req.param('keyword'); diff --git a/lib/routes/pixiv/token.ts b/lib/routes/pixiv/token.ts index ac0d9e542597a6..98356a05799886 100644 --- a/lib/routes/pixiv/token.ts +++ b/lib/routes/pixiv/token.ts @@ -15,34 +15,27 @@ const refreshToken = (tryGet) => tryGet( 'pixiv:accessToken', () => - got - .post('https://oauth.secure.pixiv.net/auth/token', { - form: { - ...authorizationInfo, - get_secure_url: 1, - grant_type: 'refresh_token', - refresh_token: config.pixiv.refreshToken, - }, - headers: { - ...maskHeader, - }, - responseType: 'json', - resolveBodyOnly: true, - }) - .catch((error) => { - logger.error('Pixiv refresh token failed.'); - logger.error(error); - }), + got.post('https://oauth.secure.pixiv.net/auth/token', { + form: { + ...authorizationInfo, + get_secure_url: 1, + grant_type: 'refresh_token', + refresh_token: config.pixiv.refreshToken, + }, + headers: { + ...maskHeader, + }, + }), 3600, false ); async function getToken(tryGet) { - const result = await refreshToken(tryGet); + const { data } = await refreshToken(tryGet); // let expireTime; - if (result && result.access_token) { + if (data && data.access_token) { logger.debug('Pixiv refresh token success.'); - token = result.access_token; + token = data.access_token; // expireTime = result.expires_in; } // } else { diff --git a/lib/routes/pixiv/user.ts b/lib/routes/pixiv/user.ts index bb1a185deaf91e..47a1bc3ccda8bb 100644 --- a/lib/routes/pixiv/user.ts +++ b/lib/routes/pixiv/user.ts @@ -31,7 +31,7 @@ export const route: Route = { async function handler(ctx) { if (!config.pixiv || !config.pixiv.refreshToken) { - throw new Error('pixiv RSS is disabled due to the lack of relevant config'); + throw new Error('pixiv RSS is disabled due to the lack of relevant config'); } const id = ctx.req.param('id'); diff --git a/lib/routes/sdu/data.ts b/lib/routes/sdu/data.ts index 079cd009c6b9e0..8b5f0c6c0dbabc 100644 --- a/lib/routes/sdu/data.ts +++ b/lib/routes/sdu/data.ts @@ -5,7 +5,7 @@ export default { route: '/news', source: ['/*path', '/'], titlePrefix: '(威海)新闻网|', - docs: 'https://docs.rsshub.app/university#shan-dong-da-xue-wei-hai', + docs: 'https://docs.rsshub.app/routes/university#shan-dong-da-xue-wei-hai', getTarget(url) { return this.route + '/' + url.replace(/\.htm$/, ''); }, @@ -62,7 +62,7 @@ export default { route: '/jwc', source: ['/*path', '/'], titlePrefix: '(威海)教务处|', - docs: 'https://docs.rsshub.app/university#shan-dong-da-xue-wei-hai', + docs: 'https://docs.rsshub.app/routes/university#shan-dong-da-xue-wei-hai', getTarget(url) { return this.route + '/' + url.replace(/\.htm$/, ''); }, diff --git a/lib/routes/sehuatang/user.ts b/lib/routes/sehuatang/user.ts index 1d4d076fee48ba..01fbbb4cac65ec 100644 --- a/lib/routes/sehuatang/user.ts +++ b/lib/routes/sehuatang/user.ts @@ -33,7 +33,7 @@ export const route: Route = { async function handler(ctx) { if (!config.sehuatang.cookie) { - throw new Error('Sehuatang RSS is disabled due to the lack of relevant config'); + throw new Error('Sehuatang RSS is disabled due to the lack of relevant config'); } // 从Url参数中获取uid const uid = ctx.req.param('uid'); diff --git a/lib/routes/spotify/utils.ts b/lib/routes/spotify/utils.ts index 919304677b224a..6103efa730e2dc 100644 --- a/lib/routes/spotify/utils.ts +++ b/lib/routes/spotify/utils.ts @@ -4,7 +4,7 @@ import got from '@/utils/got'; // Token used to retrieve public information. async function getPublicToken() { if (!config.spotify || !config.spotify.clientId || !config.spotify.clientSecret) { - throw new Error('Spotify public RSS is disabled due to the lack of relevant config'); + throw new Error('Spotify public RSS is disabled due to the lack of relevant config'); } const { clientId, clientSecret } = config.spotify; @@ -26,7 +26,7 @@ async function getPublicToken() { // Note that we don't use PKCE since the client secret shall be safe on the server. async function getPrivateToken() { if (!config.spotify || !config.spotify.clientId || !config.spotify.clientSecret || !config.spotify.refreshToken) { - throw new Error('Spotify private RSS is disabled due to the lack of relevant config'); + throw new Error('Spotify private RSS is disabled due to the lack of relevant config'); } const { clientId, clientSecret, refreshToken } = config.spotify; diff --git a/lib/routes/stbu/jsjxy.ts b/lib/routes/stbu/jsjxy.ts index 259f037bfba22e..81f739a9ffb11a 100644 --- a/lib/routes/stbu/jsjxy.ts +++ b/lib/routes/stbu/jsjxy.ts @@ -30,7 +30,7 @@ export const route: Route = { handler, url: 'jsjxy.stbu.edu.cn/news', description: `:::warning -计算机学院通知公告疑似禁止了非大陆 IP 访问,使用路由需要自行 [部署](https://docs.rsshub.app/install)。 +计算机学院通知公告疑似禁止了非大陆 IP 访问,使用路由需要自行 [部署](https://docs.rsshub.app/deploy/)。 :::`, }; diff --git a/lib/routes/telegram/stickerpack.ts b/lib/routes/telegram/stickerpack.ts index 4525169b5c6a37..66338509104b07 100644 --- a/lib/routes/telegram/stickerpack.ts +++ b/lib/routes/telegram/stickerpack.ts @@ -22,7 +22,7 @@ export const route: Route = { async function handler(ctx) { if (!config.telegram || !config.telegram.token) { - throw new Error('Telegram Sticker Pack RSS is disabled due to the lack of relevant config'); + throw new Error('Telegram Sticker Pack RSS is disabled due to the lack of relevant config'); } const name = ctx.req.param('name'); diff --git a/lib/routes/twitter/likes.ts b/lib/routes/twitter/likes.ts index 509d0b489db908..1c62479b965026 100644 --- a/lib/routes/twitter/likes.ts +++ b/lib/routes/twitter/likes.ts @@ -22,7 +22,7 @@ export const route: Route = { async function handler(ctx) { if (!config.twitter || !config.twitter.consumer_key || !config.twitter.consumer_secret) { - throw new Error('Twitter RSS is disabled due to the lack of relevant config'); + throw new Error('Twitter RSS is disabled due to the lack of relevant config'); } const id = ctx.req.param('id'); const client = await utils.getAppClient(); diff --git a/lib/routes/twitter/trends.ts b/lib/routes/twitter/trends.ts index 0757fe23c1ff45..19ea43b55ac4f2 100644 --- a/lib/routes/twitter/trends.ts +++ b/lib/routes/twitter/trends.ts @@ -22,7 +22,7 @@ export const route: Route = { async function handler(ctx) { if (!config.twitter || !config.twitter.consumer_key || !config.twitter.consumer_secret) { - throw new Error('Twitter RSS is disabled due to the lack of relevant config'); + throw new Error('Twitter RSS is disabled due to the lack of relevant config'); } const woeid = ctx.req.param('woeid') ?? 1; // Global information is available by using 1 as the WOEID const client = await utils.getAppClient(); diff --git a/lib/routes/twreporter/category.ts b/lib/routes/twreporter/category.ts index c09e8b92dcfec5..5bf0534576d156 100644 --- a/lib/routes/twreporter/category.ts +++ b/lib/routes/twreporter/category.ts @@ -1,6 +1,5 @@ import { Route } from '@/types'; import cache from '@/utils/cache'; -import { load } from 'cheerio'; import got from '@/utils/got'; import fetch from './fetch-article'; @@ -30,34 +29,43 @@ export const route: Route = { }; async function handler(ctx) { - const baseURL = 'https://www.twreporter.org'; - const url = baseURL + `/categories/${ctx.req.param('category')}`; - const res = await got(url); - const $ = load(res.data); + const category = ctx.req.param('category'); + const url = `https://go-api.twreporter.org/v2/index_page`; + const res = await got(url).json(); + const list = res.data[category]; - const regexp = /^window\.__REDUX_STATE__=(.*);$/gm; - const raw = $('script[charset="UTF-8"]').text().replaceAll(regexp, '$1'); - const posts = JSON.parse(raw).entities.posts; + let name = list[0].category_set[0].category.name; + let categoryID = category; + switch (categoryID) { + case 'photos_section': + categoryID = 'photography'; - const list = posts.allIds.map((id) => ({ - link: baseURL + '/a/' + posts.byId[id].slug, - title: posts.byId[id].title, - })); - const category = posts.byId[posts.allIds[0]].category_set[0].category.name; + break; + case 'politics_and_society': + categoryID = categoryID.replaceAll('_', '-'); + name = '政治社會'; + + break; + default: + break; + } + const home = `https://www.twreporter.org/categories/${categoryID}`; const out = await Promise.all( - list.map((item) => - cache.tryGet(item.link, async () => { - const single = await fetch(item.link); - single.title = item.title; + list.map((item) => { + const title = item.title; + // categoryNames = item.category_set[0].category.name; + return cache.tryGet(item.slug, async () => { + const single = await fetch(item.slug); + single.title = title; return single; - }) - ) + }); + }) ); return { - title: `報導者 | ${category}`, - link: url, + title: `報導者 | ${name}`, + link: home, item: out, }; } diff --git a/lib/routes/twreporter/fetch-article.ts b/lib/routes/twreporter/fetch-article.ts index a9bca8d4c0fafc..cf9cfee8c45ba7 100644 --- a/lib/routes/twreporter/fetch-article.ts +++ b/lib/routes/twreporter/fetch-article.ts @@ -1,67 +1,104 @@ -import { load } from 'cheerio'; +import { getCurrentPath } from '@/utils/helpers'; +const __dirname = getCurrentPath(import.meta.url); + import got from '@/utils/got'; import { parseDate } from '@/utils/parse-date'; +import { art } from '@/utils/render'; +import * as path from 'node:path'; -export default async function fetch(address) { - const res = await got(address); - const capture = load(res.data); - capture('.gIMvvS').remove(); +export default async function fetch(slug: string) { + const url = `https://go-api.twreporter.org/v2/posts/${slug}?full=true`; + const res = await got(url); + const post = res.data.data; - let time = capture('.gzaDTq').text(); - // For `photography` - if (!time) { - time = capture('.fEZfRw').text(); + const time = post.published_date; + // For `writers` + let authors = ''; + if (post.writers) { + authors = post.writers.map((writer) => (writer.job_title ? writer.job_title + ' / ' + writer.name : '文字 / ' + writer.name)).join(','); } - let metaInfoBox = capture('.ffAPnj') - .filter((index) => index === 0) - .get(); - - // For photography - if (metaInfoBox.length === 0) { - metaInfoBox = capture('.deNvJY') - .filter((index) => index === 0) - .get(); + // For `photography`, if it exists + let photographers = ''; + if (post.photographers) { + photographers = post.photographers + .map((photographer) => { + let title = '攝影 / '; + if (photographer.job_title) { + title = photographer.job_title + ' / '; + } + return title + photographer.name; + }) + .join(','); + authors += ';' + photographers; } - const acquire = load(metaInfoBox); - // # Author(s) of the article - // - // There exists two formats for this section. - // 1. 文字 /...` with `摄影 / ..` in separate line, or - // 2. just a simple line starts with `文/ ...` - // For the first condition, we use a array - // to record the list of author(s), and use - // `;` to connect two lines. - const authors = []; - - if (acquire('.loxoWO').text() === '') { - for (const item of acquire('.flciyI').get()) { - const $ = load(item); - const job = $('.hGsNtm').text(); - // An article may have multiple authors - const name = []; - for (const item of $('.cidPTd > a').get()) { - const $ = load(item); - name.push($('.fJSaZP').text()); - } + const bannerImage = post.og_image.resized_targets.desktop.url; + const caption = post.leading_image_description; + const bannerDescription = post.og_image.description; + const ogDescription = post.og_description; + const banner = art(path.join(__dirname, 'templates/image.art'), { image: bannerImage, description: bannerDescription, caption }); + + function format(type, content) { + let block = ''; + if (content !== '' && type !== 'embeddedcode') { + switch (type) { + case 'image': + case 'slideshow': + block = content.map((image) => art(path.join(__dirname, 'templates/image.art'), { image: image.desktop.url, description: image.description, caption: image.description })).join('
'); + + break; + + case 'blockquote': + block = `
${content}
`; + + break; - const author = job + '/' + name.join(','); - authors.push(author); + case 'header-one': + block = `

${content}

`; + + break; + + case 'header-two': + block = `

${content}

`; + + break; + + case 'infobox': { + const box = content[0]; + block = `

${box.title}

${box.body}`; + + break; + } + case 'youtube': { + const video = content[0].youtubeId; + const id = video.split('?')[0]; + block = art(path.join(__dirname, 'templates/youtube.art'), { video: id }); + + break; + } + default: + block = `${content}
`; + } } - } else { - authors.push(acquire('.loxoWO').text()); + return block; } - const author = authors.join(';'); - // contents = cover photo + italic intro + text - const contents = '' + capture('.hxFBKc').html() + '
' + capture('.jONJYq').html(); + const text = post.content.api_data + .map((item) => { + const content = item.content; + const type = item.type; + return format(type, content); + }) + .filter(Boolean) + .join('
'); + const contents = [banner, ogDescription, text].filter(Boolean).join('

'); return { - author, + author: authors, description: contents, - link: address, - guid: address, - pubDate: parseDate(time, 'YYYY/M/D'), + link: `https://www.twreporter.org/a/${slug}`, + guid: `https://www.twreporter.org/a/${slug}`, + pubDate: parseDate(time, 'YYYY-MM-DDTHH:mm:ssZ'), }; } diff --git a/lib/routes/twreporter/newest.ts b/lib/routes/twreporter/newest.ts index f8b56e69d674f3..a71354ba8de6fc 100644 --- a/lib/routes/twreporter/newest.ts +++ b/lib/routes/twreporter/newest.ts @@ -1,6 +1,5 @@ import { Route } from '@/types'; import cache from '@/utils/cache'; -import { load } from 'cheerio'; import got from '@/utils/got'; import fetch from './fetch-article'; @@ -30,26 +29,24 @@ export const route: Route = { }; async function handler() { - const url = 'https://www.twreporter.org'; - const res = await got(url); - const $ = load(res.data); - const list = $('.gKMjSz').get(); - + const base = `https://www.twreporter.org`; + const url = `https://go-api.twreporter.org/v2/index_page`; + const res = await got(url).json(); + const list = res.data.latest_section; const out = await Promise.all( list.map((item) => { - const $ = load(item); - const address = url + $('a').attr('href'); - const title = $('.latest-section__Title-hzxpx3-6').text(); - return cache.tryGet(address, async () => { - const single = await fetch(address); + const title = item.title; + return cache.tryGet(item.slug, async () => { + const single = await fetch(item.slug); single.title = title; return single; }); }) ); + return { title: `報導者 | 最新`, - link: url, + link: base, item: out, }; } diff --git a/lib/routes/twreporter/templates/image.art b/lib/routes/twreporter/templates/image.art new file mode 100644 index 00000000000000..74fd8bd73288de --- /dev/null +++ b/lib/routes/twreporter/templates/image.art @@ -0,0 +1,3 @@ + +{{ description }} +
{{ caption }}
\ No newline at end of file diff --git a/lib/routes/twreporter/templates/youtube.art b/lib/routes/twreporter/templates/youtube.art new file mode 100644 index 00000000000000..4388be031268d2 --- /dev/null +++ b/lib/routes/twreporter/templates/youtube.art @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/lib/routes/ucas/rader.ts b/lib/routes/ucas/rader.ts index 77a59e427ba1aa..ccea519da9c032 100644 --- a/lib/routes/ucas/rader.ts +++ b/lib/routes/ucas/rader.ts @@ -4,7 +4,7 @@ export default { zhaopin: [ { title: '招聘信息-博士后', - docs: 'https://docs.rsshub.app/university#zhong-guo-ke-xue-yuan-da-xue-zhao-pin-xin-xi', + docs: 'https://docs.rsshub.app/routes/university#zhong-guo-ke-xue-yuan-da-xue-zhao-pin-xin-xi', source: '/*', target: (params, url) => { if (new URL(url).searchParams.get('c') === '6') { @@ -14,7 +14,7 @@ export default { }, { title: '招聘信息-课题项目聘用', - docs: 'https://docs.rsshub.app/university#zhong-guo-ke-xue-yuan-da-xue-zhao-pin-xin-xi', + docs: 'https://docs.rsshub.app/routes/university#zhong-guo-ke-xue-yuan-da-xue-zhao-pin-xin-xi', source: '/*', target: (params, url) => { if (new URL(url).searchParams.get('c') === '5') { @@ -24,7 +24,7 @@ export default { }, { title: '招聘信息-管理支撑人才', - docs: 'https://docs.rsshub.app/university#zhong-guo-ke-xue-yuan-da-xue-zhao-pin-xin-xi', + docs: 'https://docs.rsshub.app/routes/university#zhong-guo-ke-xue-yuan-da-xue-zhao-pin-xin-xi', source: '/*', target: (params, url) => { if (new URL(url).searchParams.get('c') === '4') { @@ -34,7 +34,7 @@ export default { }, { title: '招聘信息-科学科研人才', - docs: 'https://docs.rsshub.app/university#zhong-guo-ke-xue-yuan-da-xue-zhao-pin-xin-xi', + docs: 'https://docs.rsshub.app/routes/university#zhong-guo-ke-xue-yuan-da-xue-zhao-pin-xin-xi', source: '/*', target: (params, url) => { if (new URL(url).searchParams.get('c') === '3') { diff --git a/lib/routes/wechat/feeddd.ts b/lib/routes/wechat/feeddd.ts index d71c01a4f80fe0..97a4a52c3309fc 100644 --- a/lib/routes/wechat/feeddd.ts +++ b/lib/routes/wechat/feeddd.ts @@ -13,7 +13,7 @@ export default async (ctx) => { try { response = await got(apiUrl); } catch (error) { - if (error.name === 'HTTPError' && error.response.statusCode === 404) { + if ((error.name === 'HTTPError' || error.name === 'FetchError') && error.response.statusCode === 404) { throw new Error('该公众号不存在,有关如何获取公众号 id,详见 https://docs.rsshub.app/routes/new-media#wei-xin-gong-zhong-hao-feeddd-lai-yuan'); } throw error; diff --git a/lib/routes/weibo/friends.ts b/lib/routes/weibo/friends.ts index c6d04e7307f61b..4aeb9d1980022d 100644 --- a/lib/routes/weibo/friends.ts +++ b/lib/routes/weibo/friends.ts @@ -45,7 +45,7 @@ export const route: Route = { async function handler(ctx) { if (!config.weibo.cookies) { - throw new Error('Weibo Friends Timeline is not available due to the absense of [Weibo Cookies]. Check relevant config tutorial'); + throw new Error('Weibo Friends Timeline is not available due to the absense of [Weibo Cookies]. Check relevant config tutorial'); } let displayVideo = '1'; diff --git a/lib/routes/weibo/group.ts b/lib/routes/weibo/group.ts index 884fe116c50ee5..c3850822c5d262 100644 --- a/lib/routes/weibo/group.ts +++ b/lib/routes/weibo/group.ts @@ -38,7 +38,7 @@ export const route: Route = { async function handler(ctx) { if (!config.weibo.cookies) { - throw new Error('Weibo Group Timeline is not available due to the absense of [Weibo Cookies]. Check relevant config tutorial'); + throw new Error('Weibo Group Timeline is not available due to the absense of [Weibo Cookies]. Check relevant config tutorial'); } const gid = ctx.req.param('gid'); diff --git a/lib/routes/wfu/news.ts b/lib/routes/wfu/news.ts index eefca4f5b5f716..b0bf76ff61936f 100644 --- a/lib/routes/wfu/news.ts +++ b/lib/routes/wfu/news.ts @@ -32,7 +32,7 @@ async function loadContent(link) { response = await got.get(link); } catch (error) { // 如果网络问题 直接出错 - if (error.name && (error.name === 'HTTPError' || error.name === 'RequestError')) { + if (error.name && (error.name === 'HTTPError' || error.name === 'RequestError' || error.name === 'FetchError')) { description = 'Page 404 Please Check!'; } return { description }; diff --git a/lib/routes/youtube/channel.ts b/lib/routes/youtube/channel.ts index dbfb5d1bbd3433..d5c557ffcfcedf 100644 --- a/lib/routes/youtube/channel.ts +++ b/lib/routes/youtube/channel.ts @@ -38,7 +38,7 @@ YouTube provides official RSS feeds for channels, for instance [https://www.yout async function handler(ctx) { if (!config.youtube || !config.youtube.key) { - throw new Error('YouTube RSS is disabled due to the lack of relevant config'); + throw new Error('YouTube RSS is disabled due to the lack of relevant config'); } const id = ctx.req.param('id'); const embed = !ctx.req.param('embed'); diff --git a/lib/routes/youtube/custom.ts b/lib/routes/youtube/custom.ts index 9ccda071cff9d5..944548ba8ed3e9 100644 --- a/lib/routes/youtube/custom.ts +++ b/lib/routes/youtube/custom.ts @@ -21,7 +21,7 @@ export const route: Route = { async function handler(ctx) { if (!config.youtube || !config.youtube.key) { - throw new Error('YouTube RSS is disabled due to the lack of relevant config'); + throw new Error('YouTube RSS is disabled due to the lack of relevant config'); } const username = ctx.req.param('username'); const embed = !ctx.req.param('embed'); diff --git a/lib/routes/youtube/live.ts b/lib/routes/youtube/live.ts index e9d1e3ef437982..680c66582ec0ec 100644 --- a/lib/routes/youtube/live.ts +++ b/lib/routes/youtube/live.ts @@ -26,7 +26,7 @@ export const route: Route = { async function handler(ctx) { if (!config.youtube || !config.youtube.key) { - throw new Error('YouTube RSS is disabled due to the lack of relevant config'); + throw new Error('YouTube RSS is disabled due to the lack of relevant config'); } const username = ctx.req.param('username'); const embed = !ctx.req.param('embed'); diff --git a/lib/routes/youtube/playlist.ts b/lib/routes/youtube/playlist.ts index e46f886c814d18..70602d066fb89a 100644 --- a/lib/routes/youtube/playlist.ts +++ b/lib/routes/youtube/playlist.ts @@ -24,7 +24,7 @@ export const route: Route = { async function handler(ctx) { if (!config.youtube || !config.youtube.key) { - throw new Error('YouTube RSS is disabled due to the lack of relevant config'); + throw new Error('YouTube RSS is disabled due to the lack of relevant config'); } const id = ctx.req.param('id'); const embed = !ctx.req.param('embed'); diff --git a/lib/routes/youtube/subscriptions.ts b/lib/routes/youtube/subscriptions.ts index a47f5c0b1471c4..abda50eaf568b6 100644 --- a/lib/routes/youtube/subscriptions.ts +++ b/lib/routes/youtube/subscriptions.ts @@ -49,7 +49,7 @@ export const route: Route = { async function handler(ctx) { if (!config.youtube || !config.youtube.key || !config.youtube.clientId || !config.youtube.clientSecret || !config.youtube.refreshToken) { - throw new Error('YouTube RSS is disabled due to the lack of relevant config'); + throw new Error('YouTube RSS is disabled due to the lack of relevant config'); } const embed = !ctx.req.param('embed'); diff --git a/lib/routes/youtube/user.ts b/lib/routes/youtube/user.ts index 7136643f32d2fd..bc910c34418f7f 100644 --- a/lib/routes/youtube/user.ts +++ b/lib/routes/youtube/user.ts @@ -32,7 +32,7 @@ export const route: Route = { async function handler(ctx) { if (!config.youtube || !config.youtube.key) { - throw new Error('YouTube RSS is disabled due to the lack of relevant config'); + throw new Error('YouTube RSS is disabled due to the lack of relevant config'); } const username = ctx.req.param('username'); const embed = !ctx.req.param('embed'); diff --git a/lib/routes/zhihu/daily.ts b/lib/routes/zhihu/daily.ts index fd57b162d323bd..5125087ea8c19b 100644 --- a/lib/routes/zhihu/daily.ts +++ b/lib/routes/zhihu/daily.ts @@ -60,9 +60,9 @@ async function handler() { headers: { ...utils.header, Referer: `${api}/latest`, - Host: HOST, + Host: address, }, - host: address, + // host: address, }); // 根据api的说明,过滤掉极个别站外链接 const storyList = listRes.data.stories.filter((el) => el.type === 0); @@ -85,9 +85,9 @@ async function handler() { url, headers: { Referer: url, - Host: HOST, + Host: address, }, - host: address, + // host: address, }); return utils.ProcessImage(storyDetail.data.body.replaceAll(/
([\S\s]*?)<\/div>/g, '$1').replaceAll(/<\/?h2.*?>/g, '')); }); diff --git a/lib/routes/zodgame/forum.ts b/lib/routes/zodgame/forum.ts index 04c5a1b30527eb..b219adc3d0c1ba 100644 --- a/lib/routes/zodgame/forum.ts +++ b/lib/routes/zodgame/forum.ts @@ -40,7 +40,7 @@ async function handler(ctx) { const cookie = config.zodgame.cookie; if (cookie === undefined) { - throw new Error('Zodgame RSS is disabled due to the lack of relevant config'); + throw new Error('Zodgame RSS is disabled due to the lack of relevant config'); } const response = await got({ diff --git a/lib/setup.test.ts b/lib/setup.test.ts new file mode 100644 index 00000000000000..192d9fe8275c3f --- /dev/null +++ b/lib/setup.test.ts @@ -0,0 +1,77 @@ +import { afterAll, afterEach } from 'vitest'; +import { setupServer } from 'msw/node'; +import { http, HttpResponse } from 'msw'; + +const server = setupServer( + http.post(`https://api.openai.mock/v1/chat/completions`, () => + HttpResponse.json({ + choices: [ + { + message: { + content: 'Summary of the article.', + }, + }, + ], + }) + ), + http.get(`http://rsshub.test/config`, () => + HttpResponse.json({ + UA: 'test', + }) + ), + http.get(`http://rsshub.test/buildData`, () => + HttpResponse.text(`
+
    +
  • + 1 +
    RSSHub1
    +
  • +
  • + 2 +
    RSSHub2
    +
  • +
+
`) + ), + http.get(`https://mp.weixin.qq.com/rsshub_test/wechatMp_fetchArticle`, () => + HttpResponse.text( + '\n' + + '\n' + + '\n' + + '\n' + + '\n' + + '\n' + + '
mpName
\n' + + '' + ) + ), + http.get(`http://rsshub.test/headers`, ({ request }) => + HttpResponse.json({ + ...Object.fromEntries(request.headers.entries()), + }) + ), + http.post(`http://rsshub.test/form-post`, async ({ request }) => { + const formData = await request.formData(); + return HttpResponse.json({ + test: formData.get('test'), + }); + }), + http.post(`http://rsshub.test/json-post`, async ({ request }) => { + const jsonData = (await request.json()) as { + test: string; + }; + return HttpResponse.json({ + test: jsonData?.test, + }); + }), + http.get(`http://rsshub.test/rss`, () => HttpResponse.text('')) +); +server.listen(); + +afterAll(() => server.close()); +afterEach(() => server.resetHandlers()); + +export default server; diff --git a/lib/utils/common-config.test.ts b/lib/utils/common-config.test.ts index 84b4c15c95d179..57839fd38edfb3 100644 --- a/lib/utils/common-config.test.ts +++ b/lib/utils/common-config.test.ts @@ -1,6 +1,5 @@ import { describe, expect, it } from 'vitest'; import configUtils, { transElemText, replaceParams, getProp } from '@/utils/common-config'; -import nock from 'nock'; describe('index', () => { it('transElemText', () => { @@ -40,23 +39,6 @@ describe('index', () => { }); it('buildData', async () => { - nock('http://rsshub.test') - .get('/buildData') - .reply(() => [ - 200, - `
-
    -
  • - 1 -
    RSSHub1
    -
  • -
  • - 2 -
    RSSHub2
    -
  • -
-
`, - ]); const data = await configUtils({ link: 'http://rsshub.test/buildData', url: 'http://rsshub.test/buildData', diff --git a/lib/utils/common-config.ts b/lib/utils/common-config.ts index 65e84d209490a3..74d1b7c2bf3d5d 100644 --- a/lib/utils/common-config.ts +++ b/lib/utils/common-config.ts @@ -1,5 +1,5 @@ -import cheerio from 'cheerio'; -import got from '@/utils/got'; +import { load } from 'cheerio'; +import ofetch from '@/utils/ofetch'; import iconv from 'iconv-lite'; function transElemText($, prop) { @@ -37,8 +37,8 @@ function getProp(data, prop, $) { } async function buildData(data) { - const response = await got.get(data.url); - const contentType = response.headers['content-type'] || ''; + const response = await ofetch.raw(data.url); + const contentType = response.headers.get('content-type') || ''; // 若没有指定编码,则默认utf-8 let charset = 'utf-8'; for (const attr of contentType.split(';')) { @@ -47,8 +47,8 @@ async function buildData(data) { } } // @ts-expect-error custom property - const responseData = charset === 'utf-8' ? response.data : iconv.decode((await got.get({ url: data.url, responseType: 'buffer' })).data, charset); - const $ = cheerio.load(responseData); + const responseData = charset === 'utf-8' ? response._data : iconv.decode(await ofetch(data.url, { responseType: 'buffer' }), charset); + const $ = load(responseData); const $item = $(data.item.item); // 这里应该是可以通过参数注入一些代码的,不过应该无伤大雅 return { diff --git a/lib/utils/got-deprecated.ts b/lib/utils/got-deprecated.ts new file mode 100644 index 00000000000000..d99ddc3f6d7c34 --- /dev/null +++ b/lib/utils/got-deprecated.ts @@ -0,0 +1,79 @@ +import logger from '@/utils/logger'; +import { config } from '@/config'; +import got, { CancelableRequest, Response as GotResponse, OptionsInit, Options, Got } from 'got'; + +type Response = GotResponse & { + data: T; + status: number; +}; + +type GotRequestFunction = { + (url: string | URL, options?: Options): CancelableRequest>>; + (url: string | URL, options?: Options): CancelableRequest>; + (options: Options): CancelableRequest>>; + (options: Options): CancelableRequest>; +}; + +// @ts-expect-error got instance with custom response type +const custom: { + all?: (list: Array>) => Promise>; + get: GotRequestFunction; + post: GotRequestFunction; + put: GotRequestFunction; + patch: GotRequestFunction; + head: GotRequestFunction; + delete: GotRequestFunction; +} & GotRequestFunction & + Got = got.extend({ + retry: { + limit: config.requestRetry, + statusCodes: [400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 421, 422, 423, 424, 426, 428, 429, 431, 451, 500, 501, 502, 503, 504, 505, 506, 507, 508, 510, 511, 521, 522, 524], + }, + hooks: { + beforeRetry: [ + (err, count) => { + logger.error(`Request ${err.options.url} fail, retry attempt #${count}: ${err}`); + }, + ], + beforeRedirect: [ + (options, response) => { + logger.http(`Redirecting to ${options.url} for ${response.requestUrl}`); + }, + ], + afterResponse: [ + // @ts-expect-error custom response type + (response: Response>) => { + try { + response.data = typeof response.body === 'string' ? JSON.parse(response.body) : response.body; + } catch { + // @ts-expect-error for compatibility + response.data = response.body; + } + response.status = response.statusCode; + return response; + }, + ], + init: [ + ( + options: OptionsInit & { + data?: string; + } + ) => { + // compatible with axios api + if (options && options.data) { + options.body = options.body || options.data; + } + }, + ], + }, + headers: { + 'user-agent': config.ua, + }, + timeout: { + request: config.requestTimeout, + }, +}); +custom.all = (list) => Promise.all(list); + +export default custom; +export type { Response, Options } from 'got'; diff --git a/lib/utils/got.test.ts b/lib/utils/got.test.ts index 59d69c2348cfd3..b09ff977e4d730 100644 --- a/lib/utils/got.test.ts +++ b/lib/utils/got.test.ts @@ -1,88 +1,51 @@ -import { describe, expect, it, afterEach, vi } from 'vitest'; -import nock from 'nock'; - -afterEach(() => { - vi.resetModules(); -}); +import { describe, expect, it, vi } from 'vitest'; +import { http, HttpResponse } from 'msw'; +import got from '@/utils/got'; +import { config } from '@/config'; describe('got', () => { it('headers', async () => { - const { default: got } = await import('@/utils/got'); - const { config } = await import('@/config'); - nock('http://rsshub.test') - .get('/test') - .reply(function () { - expect(this.req.headers['user-agent']).toBe(config.ua); - return [200, '']; - }); - - await got.get('http://rsshub.test/test'); + const { data } = await got('http://rsshub.test/headers'); + expect(data['user-agent']).toBe(config.ua); }); it('retry', async () => { - const { default: got } = await import('@/utils/got'); - const { config } = await import('@/config'); const requestRun = vi.fn(); - nock('http://rsshub.test') - .get('/testRerty') - .times(config.requestRetry + 1) - .reply(() => { + const { default: server } = await import('@/setup.test'); + server.use( + http.get(`http://rsshub.test/retry-test`, () => { requestRun(); - return [503, '0']; - }); + return HttpResponse.error(); + }) + ); try { - await got.get('http://rsshub.test/testRerty'); + await got.get('http://rsshub.test/retry-test'); } catch (error: any) { - expect(error.name).toBe('HTTPError'); + expect(error.name).toBe('FetchError'); } // retries expect(requestRun).toHaveBeenCalledTimes(config.requestRetry + 1); }); - it('axios', async () => { - const { default: got } = await import('@/utils/got'); - nock('http://rsshub.test') - .post('/post') - .reply(() => [200, '{"code": 0}']); - - const response1 = await got.post('http://rsshub.test/post', { + it('form-post', async () => { + const response = await got.post('http://rsshub.test/form-post', { form: { - test: 1, + test: 'rsshub', }, }); - expect(response1.statusCode).toBe(200); - // @ts-expect-error custom property - expect(response1.status).toBe(200); - expect(response1.body).toBe('{"code": 0}'); - // @ts-expect-error custom property - expect(response1.data.code).toBe(0); + expect(response.body).toBe('{"test":"rsshub"}'); + expect(response.data.test).toBe('rsshub'); }); - it('timeout', async () => { - process.env.REQUEST_TIMEOUT = '500'; - - const { default: got } = await import('@/utils/got'); - nock('http://rsshub.test') - .get('/timeout') - .delay(600) - .reply(() => [200, '{"code": 0}']); - - const logger = (await import('@/utils/logger')).default; - // @ts-expect-error unused - const loggerSpy = vi.spyOn(logger, 'error').mockReturnValue({}); - - try { - await got.get('http://rsshub.test/timeout'); - throw new Error('Timeout Invalid'); - } catch (error: any) { - expect(error.name).toBe('RequestError'); - } - expect(loggerSpy).toHaveBeenCalledWith(expect.stringContaining('http://rsshub.test/timeout')); - - loggerSpy.mockRestore(); - - delete process.env.REQUEST_TIMEOUT; + it('json-post', async () => { + const response = await got.post('http://rsshub.test/json-post', { + json: { + test: 'rsshub', + }, + }); + expect(response.body).toBe('{"test":"rsshub"}'); + expect(response.data.test).toBe('rsshub'); }); }); diff --git a/lib/utils/got.ts b/lib/utils/got.ts index d99ddc3f6d7c34..a602fab3a5c1cb 100644 --- a/lib/utils/got.ts +++ b/lib/utils/got.ts @@ -1,79 +1,66 @@ -import logger from '@/utils/logger'; -import { config } from '@/config'; -import got, { CancelableRequest, Response as GotResponse, OptionsInit, Options, Got } from 'got'; +import { destr } from 'destr'; +import ofetch from '@/utils/ofetch'; -type Response = GotResponse & { - data: T; - status: number; -}; +const gotofetch = ofetch.create({ + parseResponse: (responseText) => ({ + data: destr(responseText), + body: responseText, + }), +}); -type GotRequestFunction = { - (url: string | URL, options?: Options): CancelableRequest>>; - (url: string | URL, options?: Options): CancelableRequest>; - (options: Options): CancelableRequest>>; - (options: Options): CancelableRequest>; -}; +const getFakeGot = (defaultOptions?: any) => { + const fakeGot = (request, options?: any) => { + if (!(typeof request === 'string' || request instanceof Request) && request.url) { + options = { + ...request, + ...options, + }; + request = request.url; + } + if (options?.hooks?.beforeRequest) { + for (const hook of options.hooks.beforeRequest) { + hook(options); + } + delete options.hooks; + } -// @ts-expect-error got instance with custom response type -const custom: { - all?: (list: Array>) => Promise>; - get: GotRequestFunction; - post: GotRequestFunction; - put: GotRequestFunction; - patch: GotRequestFunction; - head: GotRequestFunction; - delete: GotRequestFunction; -} & GotRequestFunction & - Got = got.extend({ - retry: { - limit: config.requestRetry, - statusCodes: [400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 421, 422, 423, 424, 426, 428, 429, 431, 451, 500, 501, 502, 503, 504, 505, 506, 507, 508, 510, 511, 521, 522, 524], - }, - hooks: { - beforeRetry: [ - (err, count) => { - logger.error(`Request ${err.options.url} fail, retry attempt #${count}: ${err}`); - }, - ], - beforeRedirect: [ - (options, response) => { - logger.http(`Redirecting to ${options.url} for ${response.requestUrl}`); - }, - ], - afterResponse: [ - // @ts-expect-error custom response type - (response: Response>) => { - try { - response.data = typeof response.body === 'string' ? JSON.parse(response.body) : response.body; - } catch { - // @ts-expect-error for compatibility - response.data = response.body; - } - response.status = response.statusCode; - return response; - }, - ], - init: [ - ( - options: OptionsInit & { - data?: string; - } - ) => { - // compatible with axios api - if (options && options.data) { - options.body = options.body || options.data; - } - }, - ], - }, - headers: { - 'user-agent': config.ua, - }, - timeout: { - request: config.requestTimeout, - }, -}); -custom.all = (list) => Promise.all(list); + options = { + ...defaultOptions, + ...options, + }; + + if (options?.json && !options.body) { + options.body = options.json; + delete options.json; + } + if (options?.form && !options.body) { + const body = new FormData(); + for (const key in options.form) { + body.append(key, options.form[key]); + } + options.body = body; + if (!options.headers) { + options.headers = {}; + } + delete options.form; + } + if (options?.searchParams) { + request += '?' + new URLSearchParams(options.searchParams).toString(); + delete options.searchParams; + } + + return gotofetch(request, options); + }; + + fakeGot.get = (request, options) => fakeGot(request, { ...options, method: 'GET' }); + fakeGot.post = (request, options) => fakeGot(request, { ...options, method: 'POST' }); + fakeGot.put = (request, options) => fakeGot(request, { ...options, method: 'PUT' }); + fakeGot.patch = (request, options) => fakeGot(request, { ...options, method: 'PATCH' }); + fakeGot.head = (request, options) => fakeGot(request, { ...options, method: 'HEAD' }); + fakeGot.delete = (request, options) => fakeGot(request, { ...options, method: 'DELETE' }); + fakeGot.extend = (options) => getFakeGot(options); + + return fakeGot; +}; -export default custom; -export type { Response, Options } from 'got'; +export default getFakeGot(); diff --git a/lib/utils/ofetch.ts b/lib/utils/ofetch.ts new file mode 100644 index 00000000000000..06f77e379232ae --- /dev/null +++ b/lib/utils/ofetch.ts @@ -0,0 +1,17 @@ +import { createFetch } from 'ofetch'; +import { config } from '@/config'; +import logger from '@/utils/logger'; + +const rofetch = createFetch().create({ + retry: config.requestRetry, + retryDelay: 1000, + timeout: config.requestTimeout, + onRequestError({ request, error }) { + logger.error(`Request ${request} fail: ${error}`); + }, + headers: { + 'user-agent': config.ua, + }, +}); + +export default rofetch; diff --git a/lib/utils/proxy/index.ts b/lib/utils/proxy/index.ts index b49730693b605c..aa0c5c9a7a9158 100644 --- a/lib/utils/proxy/index.ts +++ b/lib/utils/proxy/index.ts @@ -2,6 +2,7 @@ import { config } from '@/config'; import { PacProxyAgent } from 'pac-proxy-agent'; import { HttpsProxyAgent } from 'https-proxy-agent'; import { SocksProxyAgent } from 'socks-proxy-agent'; +import { ProxyAgent } from 'undici'; const proxyIsPAC = config.pacUri || config.pacScript; @@ -24,11 +25,23 @@ if (proxyIsPAC) { } let agent: PacProxyAgent | HttpsProxyAgent | SocksProxyAgent | null = null; +let dispatcher: ProxyAgent | null = null; if (proxyIsPAC) { agent = new PacProxyAgent(`pac+${proxyUri}`); } else if (proxyUri) { if (proxyUri.startsWith('http')) { - agent = new HttpsProxyAgent(proxyUri); + agent = new HttpsProxyAgent(proxyUri, { + headers: { + 'proxy-authorization': config.proxy?.auth ? `Basic ${config.proxy?.auth}` : undefined, + }, + }); + dispatcher = new ProxyAgent({ + uri: proxyUri, + token: config.proxy?.auth ? `Basic ${config.proxy?.auth}` : undefined, + requestTls: { + rejectUnauthorized: process.env.NODE_TLS_REJECT_UNAUTHORIZED !== '0', + }, + }); } else if (proxyUri.startsWith('socks')) { agent = new SocksProxyAgent(proxyUri); } @@ -36,6 +49,7 @@ if (proxyIsPAC) { export default { agent, + dispatcher, proxyUri, proxyObj, proxyUrlHandler, diff --git a/lib/utils/rand-user-agent.test.ts b/lib/utils/rand-user-agent.test.ts index 4ccea6ad99919a..c459190dd6f6e5 100644 --- a/lib/utils/rand-user-agent.test.ts +++ b/lib/utils/rand-user-agent.test.ts @@ -1,7 +1,6 @@ import { describe, expect, it } from 'vitest'; -import got from '@/utils/got'; +import ofetch from '@/utils/ofetch'; import { config } from '@/config'; -import nock from 'nock'; import randUserAgent from '@/utils/rand-user-agent'; const mobileUa = randUserAgent({ browser: 'mobile safari', os: 'ios', device: 'mobile' }); @@ -23,30 +22,16 @@ describe('rand-user-agent', () => { }); it('should has default random ua', async () => { - nock('https://rsshub.test') - .get('/test') - .reply(function () { - expect(this.req.headers['user-agent']).toBe(config.ua); - expect(this.req.headers['user-agent']).not.toBe(mobileUa); - expect(this.req.headers['user-agent']).not.toBe('Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36'); - return [200, '']; - }); - await got('https://rsshub.test/test'); + const response = await ofetch('http://rsshub.test/headers'); + expect(response['user-agent']).toBe(config.ua); }); it('should match ua configurated', async () => { - nock('https://rsshub.test') - .get('/test') - .reply(function () { - return [200, { ua: this.req.headers['user-agent'] }]; - }); - - const resonse = await got('https://rsshub.test/test', { + const response = await ofetch('http://rsshub.test/headers', { headers: { 'user-agent': mobileUa, }, }); - // @ts-expect-error custom field - expect(resonse.data.ua).toBe(mobileUa); + expect(response['user-agent']).toBe(mobileUa); }); }); diff --git a/lib/utils/request-rewriter.test.ts b/lib/utils/request-rewriter.test.ts new file mode 100644 index 00000000000000..44b1a37f4cb84f --- /dev/null +++ b/lib/utils/request-rewriter.test.ts @@ -0,0 +1,137 @@ +import { describe, expect, it, vi } from 'vitest'; +import undici from 'undici'; +import got from 'got'; +import http from 'node:http'; + +process.env.PROXY_URI = 'http://rsshub.proxy:2333/'; +process.env.PROXY_AUTH = 'rsshubtest'; +process.env.PROXY_URL_REGEX = 'headers'; + +await import('@/utils/request-rewriter'); +const { config } = await import('@/config'); +const { default: ofetch } = await import('@/utils/ofetch'); + +describe('request-rewriter', () => { + it('fetch', async () => { + const fetchSpy = vi.spyOn(undici, 'fetch'); + + try { + await (await fetch('http://rsshub.test/headers')).json(); + } catch { + // ignore + } + + // headers + const headers: Headers = fetchSpy.mock.lastCall?.[0].headers; + expect(headers.get('user-agent')).toBe(config.ua); + expect(headers.get('accept')).toBe('*/*'); + expect(headers.get('referer')).toBe('http://rsshub.test'); + + // proxy + const options = fetchSpy.mock.lastCall?.[1]; + const agentKey = Object.getOwnPropertySymbols(options?.dispatcher).find((s) => s.description === 'proxy agent options'); + const agentUri = agentKey ? options?.dispatcher?.[agentKey].uri : null; + expect(agentUri).toBe(process.env.PROXY_URI); + + // proxy auth + const headersKey = Object.getOwnPropertySymbols(options?.dispatcher).find((s) => s.description === 'proxy headers'); + const agentHeaders = headersKey ? options?.dispatcher?.[headersKey] : null; + expect(agentHeaders['proxy-authorization']).toBe(`Basic ${process.env.PROXY_AUTH}`); + + // url regex not match + { + try { + await (await fetch('http://rsshub.test/rss')).json(); + } catch { + // ignore + } + const options = fetchSpy.mock.lastCall?.[1]; + expect(options?.dispatcher).toBeUndefined(); + } + }); + + it('ofetch', async () => { + const fetchSpy = vi.spyOn(undici, 'fetch'); + + try { + await ofetch('http://rsshub.test/headers', { + retry: 0, + }); + } catch { + // ignore + } + + // headers + const headers: Headers = fetchSpy.mock.lastCall?.[0].headers; + expect(headers.get('user-agent')).toBe(config.ua); + expect(headers.get('accept')).toBe('*/*'); + expect(headers.get('referer')).toBe('http://rsshub.test'); + + // proxy + const options = fetchSpy.mock.lastCall?.[1]; + const agentKey = Object.getOwnPropertySymbols(options?.dispatcher).find((s) => s.description === 'proxy agent options'); + const agentUri = agentKey ? options?.dispatcher?.[agentKey].uri : null; + expect(agentUri).toBe(process.env.PROXY_URI); + + // proxy auth + const headersKey = Object.getOwnPropertySymbols(options?.dispatcher).find((s) => s.description === 'proxy headers'); + const agentHeaders = headersKey ? options?.dispatcher?.[headersKey] : null; + expect(agentHeaders['proxy-authorization']).toBe(`Basic ${process.env.PROXY_AUTH}`); + + // url regex not match + { + try { + await ofetch('http://rsshub.test/rss', { + retry: 0, + }); + } catch { + // ignore + } + const options = fetchSpy.mock.lastCall?.[1]; + expect(options?.dispatcher).toBeUndefined(); + } + }); + + it('http', async () => { + const httpSpy = vi.spyOn(http, 'request'); + + try { + await got.get('http://rsshub.test/headers', { + headers: { + 'user-agent': undefined, + accept: undefined, + }, + }); + } catch { + // ignore + } + + // headers + const options = httpSpy.mock.lastCall?.[1]; + const headers = options?.headers; + expect(headers?.['user-agent']).toBe(config.ua); + expect(headers?.accept).toBe('*/*'); + expect(headers?.referer).toBe('http://rsshub.test'); + + // proxy + const agentUri = options?.agent?.proxy?.href; + expect(agentUri).toBe(process.env.PROXY_URI); + expect(options?.agent?.proxyHeaders['proxy-authorization']).toBe(`Basic ${process.env.PROXY_AUTH}`); + + // url regex not match + { + try { + await got.get('http://rsshub.test/rss', { + headers: { + 'user-agent': undefined, + accept: undefined, + }, + }); + } catch { + // ignore + } + const options = httpSpy.mock.lastCall?.[1]; + expect(options?.agent).toBeUndefined(); + } + }); +}); diff --git a/lib/utils/request-rewriter/fetch.ts b/lib/utils/request-rewriter/fetch.ts new file mode 100644 index 00000000000000..69861eb0b55491 --- /dev/null +++ b/lib/utils/request-rewriter/fetch.ts @@ -0,0 +1,50 @@ +import logger from '@/utils/logger'; +import { config } from '@/config'; +import undici, { Request, RequestInfo, RequestInit } from 'undici'; +import proxy from '@/utils/proxy'; + +const wrappedFetch: typeof undici.fetch = (input: RequestInfo, init?: RequestInit) => { + const request = new Request(input, init); + const options: RequestInit = {}; + + logger.debug(`Outgoing request: ${request.method} ${request.url}`); + + // ua + if (!request.headers.get('user-agent')) { + request.headers.set('user-agent', config.ua); + } + + // accept + if (!request.headers.get('accept')) { + request.headers.set('accept', '*/*'); + } + + // referer + if (!request.headers.get('referer')) { + try { + const urlHandler = new URL(request.url); + request.headers.set('referer', urlHandler.origin); + } catch { + // ignore + } + } + + // proxy + if (!options.dispatcher && proxy.dispatcher) { + const proxyRegex = new RegExp(proxy.proxyObj.url_regex); + let urlHandler; + try { + urlHandler = new URL(request.url); + } catch { + // ignore + } + + if (proxyRegex.test(request.url) && request.url.startsWith('http') && !(urlHandler && urlHandler.host === proxy.proxyUrlHandler?.host)) { + options.dispatcher = proxy.dispatcher; + } + } + + return undici.fetch(request, options); +}; + +export default wrappedFetch; diff --git a/lib/utils/request-rewriter/get.ts b/lib/utils/request-rewriter/get.ts new file mode 100644 index 00000000000000..7a0b21e6f23f1f --- /dev/null +++ b/lib/utils/request-rewriter/get.ts @@ -0,0 +1,70 @@ +import http from 'node:http'; +import https from 'node:https'; +import logger from '@/utils/logger'; +import { config } from '@/config'; +import proxy from '@/utils/proxy'; + +type Get = typeof http.get | typeof https.get | typeof http.request | typeof https.request; + +const getWrappedGet: (origin: T) => T = (origin) => + function (this: any, ...args: Parameters) { + let url: URL | null; + let options: http.RequestOptions = {}; + let callback: ((res: http.IncomingMessage) => void) | undefined; + if (typeof args[0] === 'string' || args[0] instanceof URL) { + url = new URL(args[0]); + if (typeof args[1] === 'object') { + options = args[1]; + callback = args[2]; + } else if (typeof args[1] === 'function') { + options = {}; + callback = args[1]; + } + } else { + options = args[0]; + try { + url = new URL(options.href || `${options.protocol || 'http:'}//${options.hostname || options.host}${options.path}${options.search || (options.query ? `?${options.query}` : '')}`); + } catch { + url = null; + } + if (typeof args[1] === 'function') { + callback = args[1]; + } + } + if (!url) { + return Reflect.apply(origin, this, args) as ReturnType; + } + + logger.debug(`Outgoing request: ${options.method || 'GET'} ${url}`); + + options.headers = options.headers || {}; + const headersLowerCaseKeys = new Set(Object.keys(options.headers).map((key) => key.toLowerCase())); + + // ua + if (!headersLowerCaseKeys.has('user-agent')) { + options.headers['user-agent'] = config.ua; + } + + // Accept + if (!headersLowerCaseKeys.has('accept')) { + options.headers.accept = '*/*'; + } + + // referer + if (!headersLowerCaseKeys.has('referer')) { + options.headers.referer = url.origin; + } + + // proxy + if (!options.agent && proxy.agent) { + const proxyRegex = new RegExp(proxy.proxyObj.url_regex); + + if (proxyRegex.test(url.toString()) && url.protocol.startsWith('http') && url.host !== proxy.proxyUrlHandler?.host) { + options.agent = proxy.agent; + } + } + + return Reflect.apply(origin, this, [url, options, callback]) as ReturnType; + }; + +export default getWrappedGet; diff --git a/lib/utils/request-rewriter/index.ts b/lib/utils/request-rewriter/index.ts new file mode 100644 index 00000000000000..74e793167f8cdb --- /dev/null +++ b/lib/utils/request-rewriter/index.ts @@ -0,0 +1,19 @@ +import { Headers, FormData, Request, Response } from 'undici'; +import http from 'node:http'; +import https from 'node:https'; + +import fetch from '@/utils/request-rewriter/fetch'; +import getWrappedGet from '@/utils/request-rewriter/get'; + +Object.defineProperties(globalThis, { + fetch: { value: fetch }, + Headers: { value: Headers }, + FormData: { value: FormData }, + Request: { value: Request }, + Response: { value: Response }, +}); + +http.get = getWrappedGet(http.get); +http.request = getWrappedGet(http.request); +https.get = getWrappedGet(https.get); +https.request = getWrappedGet(https.request); diff --git a/lib/utils/request-wrapper.test.ts b/lib/utils/request-wrapper.test.ts deleted file mode 100644 index 1b126d5068ec58..00000000000000 --- a/lib/utils/request-wrapper.test.ts +++ /dev/null @@ -1,365 +0,0 @@ -import { describe, expect, it, beforeEach, afterEach, vi } from 'vitest'; - -import got from '@/utils/got'; -import parser from '@/utils/rss-parser'; -import nock from 'nock'; -import http from 'node:http'; - -let check: ( - request: Request & { - agent: any; - path: string; - } -) => void = () => {}; -const simpleResponse = ''; - -beforeEach(() => { - delete process.env.PAC_URI; - delete process.env.PAC_SCRIPT; -}); - -afterEach(() => { - delete process.env.PROXY_URI; - delete process.env.PROXY_PROTOCOL; - delete process.env.PROXY_HOST; - delete process.env.PROXY_PORT; - delete process.env.PROXY_AUTH; - delete process.env.PROXY_URL_REGEX; - - nock.restore(); - nock.activate(); - check = () => {}; - - const httpWrap = (func) => { - const origin = func; - return function (url, request) { - if (typeof url === 'object') { - if (url instanceof URL) { - check(request); - } else { - check(url); - } - } else { - check(request); - } - // @ts-expect-error any - // eslint-disable-next-line prefer-rest-params - return Reflect.apply(origin, this, arguments); - }; - }; - http.get = httpWrap(http.get); - http.request = httpWrap(http.request); - - vi.resetModules(); -}); - -describe('got', () => { - it('headers', async () => { - await import('@/utils/request-wrapper'); - - nock(/rsshub\.test/) - .get(/.*/) - .times(3) - .reply(function () { - expect(this.req.headers.referer).toBe('http://api.rsshub.test'); - expect(this.req.headers.host).toBe('api.rsshub.test'); - return [200, simpleResponse]; - }); - - await got.get('http://api.rsshub.test/test'); - await got.get('http://api.rsshub.test'); - - await parser.parseURL('http://api.rsshub.test/test'); - }); - - it('proxy-uri socks', async () => { - process.env.PROXY_URI = 'socks5://user:pass@rsshub.proxy:2333'; - - await import('@/utils/request-wrapper'); - check = (request) => { - expect(request.agent.constructor.name).toBe('SocksProxyAgent'); - expect(request.agent.proxy.host).toBe('rsshub.proxy'); - expect(request.agent.proxy.port).toBe(2333); - expect(request.agent.proxy.type).toBe(5); - }; - - nock(/rsshub\.test/) - .get('/proxy') - .times(2) - .reply(200, simpleResponse); - - await got.get('http://rsshub.test/proxy'); - await parser.parseURL('http://rsshub.test/proxy'); - }); - - it('proxy-uri http', async () => { - process.env.PROXY_URI = 'http://user:pass@rsshub.proxy:2333'; - - await import('@/utils/request-wrapper'); - check = (request) => { - expect(request.agent.constructor.name).toBe('HttpsProxyAgent'); - expect(request.agent.proxy.protocol).toBe('http:'); - expect(request.agent.proxy.username).toBe('user'); - expect(request.agent.proxy.password).toBe('pass'); - expect(request.agent.proxy.host).toBe('rsshub.proxy:2333'); - expect(request.agent.proxy.hostname).toBe('rsshub.proxy'); - expect(request.agent.proxy.port).toBe('2333'); - }; - - nock(/rsshub\.test/) - .get('/proxy') - .times(2) - .reply(200, simpleResponse); - - await got.get('http://rsshub.test/proxy'); - await parser.parseURL('http://rsshub.test/proxy'); - }); - - it('proxy-uri https', async () => { - process.env.PROXY_URI = 'https://rsshub.proxy:2333'; - - await import('@/utils/request-wrapper'); - check = (request) => { - expect(request.agent.constructor.name).toBe('HttpsProxyAgent'); - expect(request.agent.proxy.protocol).toBe('https:'); - expect(request.agent.proxy.host).toBe('rsshub.proxy:2333'); - expect(request.agent.proxy.hostname).toBe('rsshub.proxy'); - expect(request.agent.proxy.port).toBe('2333'); - }; - - nock(/rsshub\.test/) - .get('/proxy') - .times(2) - .reply(200, simpleResponse); - - await got.get('http://rsshub.test/proxy'); - await parser.parseURL('http://rsshub.test/proxy'); - }); - - it('proxy socks', async () => { - process.env.PROXY_PROTOCOL = 'socks'; - process.env.PROXY_HOST = 'rsshub.proxy'; - process.env.PROXY_PORT = '2333'; - - await import('@/utils/request-wrapper'); - check = (request) => { - expect(request.agent.constructor.name).toBe('SocksProxyAgent'); - expect(request.agent.proxy.host).toBe('rsshub.proxy'); - expect(request.agent.proxy.port).toBe(2333); - expect(request.agent.proxy.type).toBe(5); - }; - - nock(/rsshub\.test/) - .get('/proxy') - .times(2) - .reply(200, simpleResponse); - - await got.get('http://rsshub.test/proxy'); - await parser.parseURL('http://rsshub.test/proxy'); - }); - - it('proxy http', async () => { - process.env.PROXY_PROTOCOL = 'http'; - process.env.PROXY_HOST = 'rsshub.proxy'; - process.env.PROXY_PORT = '2333'; - - await import('@/utils/request-wrapper'); - check = (request) => { - expect(request.agent.constructor.name).toBe('HttpsProxyAgent'); - expect(request.agent.proxy.protocol).toBe('http:'); - expect(request.agent.proxy.host).toBe('rsshub.proxy:2333'); - expect(request.agent.proxy.hostname).toBe('rsshub.proxy'); - expect(request.agent.proxy.port).toBe('2333'); - }; - - nock(/rsshub\.test/) - .get('/proxy') - .times(2) - .reply(200, simpleResponse); - - await got.get('http://rsshub.test/proxy'); - await parser.parseURL('http://rsshub.test/proxy'); - }); - - it('proxy https', async () => { - process.env.PROXY_PROTOCOL = 'https'; - process.env.PROXY_HOST = 'rsshub.proxy'; - process.env.PROXY_PORT = '2333'; - - await import('@/utils/request-wrapper'); - check = (request) => { - expect(request.agent.constructor.name).toBe('HttpsProxyAgent'); - expect(request.agent.proxy.protocol).toBe('https:'); - expect(request.agent.proxy.host).toBe('rsshub.proxy:2333'); - expect(request.agent.proxy.hostname).toBe('rsshub.proxy'); - expect(request.agent.proxy.port).toBe('2333'); - }; - - nock(/rsshub\.test/) - .get('/proxy') - .times(2) - .reply(200, simpleResponse); - - await got.get('http://rsshub.test/proxy'); - await parser.parseURL('http://rsshub.test/proxy'); - }); - - it('pac-uri http', async () => { - process.env.PAC_URI = 'http://rsshub.proxy:2333'; - - await import('@/utils/request-wrapper'); - - check = (request) => { - expect(request.agent.constructor.name).toBe('PacProxyAgent'); - expect(request.agent.uri.protocol).toBe('http:'); - expect(request.agent.uri.host).toBe('rsshub.proxy:2333'); - expect(request.agent.uri.hostname).toBe('rsshub.proxy'); - expect(request.agent.uri.port).toBe('2333'); - }; - - nock(/rsshub\.test/) - .get('/proxy') - .times(2) - .reply(200, simpleResponse); - - await got.get('http://rsshub.test/proxy'); - await parser.parseURL('http://rsshub.test/proxy'); - }); - - it('pac-uri https', async () => { - process.env.PAC_URI = 'https://rsshub.proxy:2333'; - - await import('@/utils/request-wrapper'); - - check = (request) => { - expect(request.agent.constructor.name).toBe('PacProxyAgent'); - expect(request.agent.uri.protocol).toBe('https:'); - expect(request.agent.uri.host).toBe('rsshub.proxy:2333'); - expect(request.agent.uri.hostname).toBe('rsshub.proxy'); - expect(request.agent.uri.port).toBe('2333'); - }; - - nock(/rsshub\.test/) - .get('/proxy') - .times(2) - .reply(200, simpleResponse); - - await got.get('http://rsshub.test/proxy'); - await parser.parseURL('http://rsshub.test/proxy'); - }); - - it('pac-uri ftp', async () => { - process.env.PAC_URI = 'ftp://rsshub.proxy:2333'; - - await import('@/utils/request-wrapper'); - - check = (request) => { - expect(request.agent.constructor.name).toBe('PacProxyAgent'); - expect(request.agent.uri.protocol).toBe('ftp:'); - expect(request.agent.uri.host).toBe('rsshub.proxy:2333'); - expect(request.agent.uri.hostname).toBe('rsshub.proxy'); - expect(request.agent.uri.port).toBe('2333'); - }; - - nock(/rsshub\.test/) - .get('/proxy') - .times(2) - .reply(200, simpleResponse); - - await got.get('http://rsshub.test/proxy'); - await parser.parseURL('http://rsshub.test/proxy'); - }); - - it('pac-uri file', async () => { - process.env.PAC_URI = 'file:///D:/rsshub/proxy'; - - await import('@/utils/request-wrapper'); - - check = (request) => { - expect(request.agent.constructor.name).toBe('PacProxyAgent'); - expect(request.agent.uri.protocol).toBe('file:'); - expect(request.agent.uri.pathname).toBe('/D:/rsshub/proxy'); - }; - - nock(/rsshub\.test/) - .get('/proxy') - .times(2) - .reply(200, simpleResponse); - - await got.get('http://rsshub.test/proxy'); - await parser.parseURL('http://rsshub.test/proxy'); - }); - - it('pac-script data', async () => { - process.env.PAC_SCRIPT = "function FindProxyForURL(url,host){return 'DIRECT';}"; - - await import('@/utils/request-wrapper'); - - check = (request) => { - expect(request.agent.constructor.name).toBe('PacProxyAgent'); - expect(request.agent.uri.protocol).toBe('data:'); - expect(request.agent.uri.pathname).toBe("text/javascript;charset=utf-8,function%20FindProxyForURL(url%2Chost)%7Breturn%20'DIRECT'%3B%7D"); - }; - - nock(/rsshub\.test/) - .get('/proxy') - .times(2) - .reply(200, simpleResponse); - - await got.get('http://rsshub.test/proxy'); - await parser.parseURL('http://rsshub.test/proxy'); - }); - - it('auth', async () => { - process.env.PROXY_AUTH = 'testtest'; - process.env.PROXY_PROTOCOL = 'http'; // only http(s) proxies extract auth from Headers - process.env.PROXY_HOST = 'rsshub.proxy'; - process.env.PROXY_PORT = '2333'; - - await import('@/utils/request-wrapper'); - - nock(/rsshub\.test/) - .get('/auth') - .times(2) - .reply(function () { - expect(this.req.headers['proxy-authorization']).toBe('Basic testtest'); - return [200, simpleResponse]; - }); - - await got.get('http://rsshub.test/auth'); - await parser.parseURL('http://rsshub.test/auth'); - }); - - it('url_regex', async () => { - process.env.PROXY_URL_REGEX = 'url_regex'; - process.env.PROXY_PROTOCOL = 'socks'; - process.env.PROXY_HOST = 'rsshub.proxy'; - process.env.PROXY_PORT = '2333'; - - await import('@/utils/request-wrapper'); - check = (request) => { - if (request.path === '/url_regex') { - expect(request.agent.constructor.name).toBe('SocksProxyAgent'); - expect(request.agent.proxy.host).toBe('rsshub.proxy'); - expect(request.agent.proxy.port).toBe(2333); - } else if (request.path === '/proxy') { - expect(request.agent).toBe(undefined); - } - }; - - nock(/rsshub\.test/) - .get('/url_regex') - .times(2) - .reply(() => [200, simpleResponse]); - nock(/rsshub\.test/) - .get('/proxy') - .times(2) - .reply(() => [200, simpleResponse]); - - await got.get('http://rsshub.test/url_regex'); - await parser.parseURL('http://rsshub.test/url_regex'); - - await got.get('http://rsshub.test/proxy'); - await parser.parseURL('http://rsshub.test/proxy'); - }); -}); diff --git a/lib/utils/request-wrapper.ts b/lib/utils/request-wrapper.ts deleted file mode 100644 index 352f7d2dba138a..00000000000000 --- a/lib/utils/request-wrapper.ts +++ /dev/null @@ -1,105 +0,0 @@ -import { config } from '@/config'; -import logger from '@/utils/logger'; -import http, { type RequestOptions } from 'node:http'; -import https from 'node:https'; -import proxy from '@/utils/proxy'; - -let proxyWrapper: ( - url: string, - options: RequestOptions & { - headers: Record; - } -) => boolean = () => false; - -if (proxy.agent) { - const proxyRegex = new RegExp(proxy.proxyObj.url_regex); - const protocolMatch = (protocolLike?: string | null) => protocolLike?.toLowerCase().startsWith('http'); - - proxyWrapper = (url, options) => { - let urlHandler; - try { - urlHandler = new URL(url); - } catch { - // ignore - } - if (proxyRegex.test(url) && (protocolMatch(options.protocol) || protocolMatch(url)) && (!urlHandler || urlHandler.host !== proxy.proxyUrlHandler?.host)) { - options.agent = proxy.agent || false; - if (proxy.proxyObj.auth) { - options.headers['Proxy-Authorization'] = `Basic ${proxy.proxyObj.auth}`; - } - return true; - } - return false; - }; -} - -const requestWrapper = (url: string, options: http.RequestOptions = {}) => { - options.headers = options.headers || {}; - - const optionsWithHeaders = options as http.RequestOptions & { - headers: Record; - }; - const headersLowerCaseKeys = new Set(Object.keys(optionsWithHeaders.headers).map((key) => key.toLowerCase())); - - let prxied = false; - if (config.proxyStrategy === 'all') { - prxied = proxyWrapper(url, optionsWithHeaders); - } else if (config.proxyStrategy === 'on_retry' && (optionsWithHeaders as any).retryCount) { - // TODO - prxied = proxyWrapper(url, optionsWithHeaders); - } - if (prxied) { - logger.debug(`Proxy for ${url}`); - } else { - logger.debug(`Requesting ${url}`); - } - - // ua - if (!headersLowerCaseKeys.has('user-agent')) { - options.headers['user-agent'] = config.ua; - } - - // Accept - if (!headersLowerCaseKeys.has('accept')) { - options.headers.Accept = '*/*'; - } - - let urlHandler; - try { - urlHandler = new URL(url); - } catch { - // ignore - } - - if ( - urlHandler && // referer - !headersLowerCaseKeys.has('referer') - ) { - options.headers.referer = urlHandler.origin; - } -}; - -const httpWrap = (func: typeof http.request) => { - const origin = func; - const warpped: typeof http.request = function (...args) { - let url: string; - let options: http.RequestOptions; - if (args[0] instanceof URL || typeof args[0] === 'string') { - url = args[0].toString(); - options = args[1] as http.RequestOptions; - } else { - options = args[0] as http.RequestOptions; - url = `${options.protocol}//${options.hostname || options.host}${options.path}`; - } - requestWrapper(url, options); - - // @ts-expect-error apply - return origin.apply(this, args); - }; - return warpped; -}; - -http.get = httpWrap(http.get); -https.get = httpWrap(https.get); -http.request = httpWrap(http.request); -https.request = httpWrap(https.request); diff --git a/lib/utils/rss-parser.test.ts b/lib/utils/rss-parser.test.ts index 20b6664b56815f..0b09b61ea50092 100644 --- a/lib/utils/rss-parser.test.ts +++ b/lib/utils/rss-parser.test.ts @@ -1,17 +1,9 @@ import { describe, expect, it } from 'vitest'; import parser from '@/utils/rss-parser'; -import { config } from '@/config'; -import nock from 'nock'; -describe('got', () => { - it('headers', async () => { - nock('http://rsshub.test') - .get('/test') - .reply(function () { - expect(this.req.headers['user-agent']).toBe(config.ua); - return [200, '']; - }); - - await parser.parseURL('http://rsshub.test/test'); +describe('rss-parser', () => { + it('rss', async () => { + const result = await parser.parseURL('http://rsshub.test/rss'); + expect(result).toBeTruthy(); }); }); diff --git a/lib/utils/wechat-mp.test.ts b/lib/utils/wechat-mp.test.ts index b4811e84cdeee9..e700a6e425bdc6 100644 --- a/lib/utils/wechat-mp.test.ts +++ b/lib/utils/wechat-mp.test.ts @@ -1,6 +1,5 @@ import { describe, expect, it } from 'vitest'; import { load } from 'cheerio'; -import nock from 'nock'; import { fixArticleContent, fetchArticle, finishArticleItem, normalizeUrl } from '@/utils/wechat-mp'; // date from the cache will be an ISO8601 string, so we need to use this function @@ -91,22 +90,6 @@ describe('wechat-mp', () => { it('fetchArticle_&_finishArticleItem', async () => { const ct = 1_636_626_300; - const exampleMpArticlePage = - '\n' + - '\n' + - '\n' + - '\n' + - '\n' + - '\n' + - '
mpName
\n' + - ''; - - nock('https://mp.weixin.qq.com') - .get('/rsshub_test/wechatMp_fetchArticle') - .reply(() => [200, exampleMpArticlePage]); const httpsUrl = 'https://mp.weixin.qq.com/rsshub_test/wechatMp_fetchArticle'; const httpUrl = httpsUrl.replace(/^https:\/\//, 'http://'); diff --git a/lib/utils/wechat-mp.ts b/lib/utils/wechat-mp.ts index ae03957b8dbe09..0615ab1c944950 100644 --- a/lib/utils/wechat-mp.ts +++ b/lib/utils/wechat-mp.ts @@ -25,7 +25,7 @@ * For more details of these functions, please refer to the jsDoc in the source code. */ -import got from '@/utils/got'; +import ofetch from '@/utils/ofetch'; import { load, type Cheerio, type Element } from 'cheerio'; import { parseDate } from '@/utils/parse-date'; import cache from '@/utils/cache'; @@ -196,9 +196,8 @@ const normalizeUrl = (url, bypassHostCheck = false) => { const fetchArticle = (url, bypassHostCheck = false) => { url = normalizeUrl(url, bypassHostCheck); return cache.tryGet(url, async () => { - const response = await got(url); - // @ts-expect-error custom field - const $ = load(response.data); + const data = await ofetch(url); + const $ = load(data); const title = ($('meta[property="og:title"]').attr('content') || '').replaceAll('\\r', '').replaceAll('\\n', ' '); const author = $('meta[name=author]').attr('content'); @@ -209,9 +208,8 @@ const fetchArticle = (url, bypassHostCheck = false) => { const originalUrl = detectOriginalArticleUrl($); if (originalUrl) { // try to fetch the description from the original article - const originalResponse = await got(normalizeUrl(originalUrl, bypassHostCheck)); - // @ts-expect-error custom field - const original$ = load(originalResponse.data); + const data = await ofetch(normalizeUrl(originalUrl, bypassHostCheck)); + const original$ = load(data); description += fixArticleContent(original$('#js_content')); } @@ -230,7 +228,7 @@ const fetchArticle = (url, bypassHostCheck = false) => { let mpName = $('.profile_nickname').first().text(); mpName = mpName && mpName.trim(); - return { title, author, description, summary, pubDate, mpName, link: response.url }; + return { title, author, description, summary, pubDate, mpName, link: url }; }) as Promise<{ title: string; author: string; diff --git a/lib/views/error.tsx b/lib/views/error.tsx index 9aedf58649d34b..bdab930c16bec9 100644 --- a/lib/views/error.tsx +++ b/lib/views/error.tsx @@ -88,7 +88,7 @@ const Index: FC<{

Please consider{' '} - + sponsoring {' '} to help keep this open source project alive. diff --git a/lib/views/index.tsx b/lib/views/index.tsx index c47564cc79603a..03850b6a8c9c73 100644 --- a/lib/views/index.tsx +++ b/lib/views/index.tsx @@ -171,7 +171,7 @@ const Index: FC<{ debugQuery: string | undefined }> = ({ debugQuery }) => { - +

@@ -204,7 +204,7 @@ const Index: FC<{ debugQuery: string | undefined }> = ({ debugQuery }) => {

Please consider{' '} - + sponsoring {' '} to help keep this open source project alive. diff --git a/package.json b/package.json index 969610d08045b1..7cd349712d1a38 100644 --- a/package.json +++ b/package.json @@ -52,10 +52,10 @@ "dependencies": { "@hono/node-server": "1.9.0", "@hono/swagger-ui": "0.2.1", - "@hono/zod-openapi": "0.9.9", + "@hono/zod-openapi": "0.9.10", "@notionhq/client": "2.2.14", "@postlight/parser": "2.2.3", - "@sentry/node": "7.108.0", + "@sentry/node": "7.109.0", "@tonyrl/rand-user-agent": "2.0.56", "aes-js": "3.1.2", "art-template": "4.13.2", @@ -67,6 +67,7 @@ "crypto-js": "4.2.0", "currency-symbol-map": "5.1.0", "dayjs": "1.11.8", + "destr": "2.0.3", "directory-import": "3.3.1", "dotenv": "16.4.5", "entities": "4.5.0", @@ -75,8 +76,7 @@ "form-data": "4.0.0", "git-rev-sync": "3.0.2", "googleapis": "134.0.0", - "got": "14.2.1", - "hono": "4.1.4", + "hono": "4.1.5", "html-to-text": "9.0.5", "https-proxy-agent": "7.0.4", "iconv-lite": "0.6.3", @@ -94,6 +94,7 @@ "module-alias": "2.2.3", "notion-to-md": "3.1.1", "oauth-1.0a": "2.2.6", + "ofetch": "1.3.4", "otplib": "12.0.1", "pac-proxy-agent": "7.0.1", "proxy-chain": "2.4.0", @@ -113,10 +114,11 @@ "telegram": "2.20.2", "tiny-async-pool": "2.1.0", "title": "3.5.3", - "tldts": "6.1.15", + "tldts": "6.1.16", "tough-cookie": "4.1.3", "tsx": "4.7.1", "twitter-api-v2": "1.16.1", + "undici": "6.10.2", "uuid": "9.0.1", "winston": "3.13.0", "xxhash-wasm": "1.0.2", @@ -160,11 +162,12 @@ "eslint-plugin-unicorn": "51.0.1", "eslint-plugin-yml": "1.13.2", "fs-extra": "11.2.0", + "got": "14.2.1", "husky": "9.0.11", "js-beautify": "1.15.1", "lint-staged": "15.2.2", "mockdate": "3.0.5", - "nock": "13.5.4", + "msw": "2.2.13", "prettier": "3.2.5", "remark-parse": "11.0.0", "supertest": "6.3.4", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9d80c751bf6b9e..55a499b446a458 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -10,10 +10,10 @@ dependencies: version: 1.9.0 '@hono/swagger-ui': specifier: 0.2.1 - version: 0.2.1(hono@4.1.4) + version: 0.2.1(hono@4.1.5) '@hono/zod-openapi': - specifier: 0.9.9 - version: 0.9.9(hono@4.1.4)(zod@3.22.4) + specifier: 0.9.10 + version: 0.9.10(hono@4.1.5)(zod@3.22.4) '@notionhq/client': specifier: 2.2.14 version: 2.2.14 @@ -21,8 +21,8 @@ dependencies: specifier: 2.2.3 version: 2.2.3 '@sentry/node': - specifier: 7.108.0 - version: 7.108.0 + specifier: 7.109.0 + version: 7.109.0 '@tonyrl/rand-user-agent': specifier: 2.0.56 version: 2.0.56 @@ -56,6 +56,9 @@ dependencies: dayjs: specifier: 1.11.8 version: 1.11.8 + destr: + specifier: 2.0.3 + version: 2.0.3 directory-import: specifier: 3.3.1 version: 3.3.1 @@ -80,12 +83,9 @@ dependencies: googleapis: specifier: 134.0.0 version: 134.0.0 - got: - specifier: 14.2.1 - version: 14.2.1 hono: - specifier: 4.1.4 - version: 4.1.4 + specifier: 4.1.5 + version: 4.1.5 html-to-text: specifier: 9.0.5 version: 9.0.5 @@ -137,6 +137,9 @@ dependencies: oauth-1.0a: specifier: 2.2.6 version: 2.2.6 + ofetch: + specifier: 1.3.4 + version: 1.3.4 otplib: specifier: 12.0.1 version: 12.0.1 @@ -195,8 +198,8 @@ dependencies: specifier: 3.5.3 version: 3.5.3 tldts: - specifier: 6.1.15 - version: 6.1.15 + specifier: 6.1.16 + version: 6.1.16 tough-cookie: specifier: 4.1.3 version: 4.1.3 @@ -206,6 +209,9 @@ dependencies: twitter-api-v2: specifier: 1.16.1 version: 1.16.1 + undici: + specifier: 6.10.2 + version: 6.10.2 uuid: specifier: 9.0.1 version: 9.0.1 @@ -331,6 +337,9 @@ devDependencies: fs-extra: specifier: 11.2.0 version: 11.2.0 + got: + specifier: 14.2.1 + version: 14.2.1 husky: specifier: 9.0.11 version: 9.0.11 @@ -343,9 +352,9 @@ devDependencies: mockdate: specifier: 3.0.5 version: 3.0.5 - nock: - specifier: 13.5.4 - version: 13.5.4 + msw: + specifier: 2.2.13 + version: 2.2.13(typescript@5.4.3) prettier: specifier: 3.2.5 version: 3.2.5 @@ -378,14 +387,6 @@ packages: engines: {node: '>=0.10.0'} dev: true - /@ampproject/remapping@2.2.1: - resolution: {integrity: sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==} - engines: {node: '>=6.0.0'} - dependencies: - '@jridgewell/gen-mapping': 0.3.3 - '@jridgewell/trace-mapping': 0.3.22 - dev: true - /@ampproject/remapping@2.3.0: resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} engines: {node: '>=6.0.0'} @@ -551,8 +552,8 @@ packages: '@babel/types': 7.24.0 dev: true - /@babel/helper-module-imports@7.24.1: - resolution: {integrity: sha512-HfEWzysMyOa7xI5uQHc/OcZf67/jc+xe/RZlznWQHhbb8Pg1SkRdbK4yEi61aY8wxQA7PkSfoojtLQP/Kpe3og==} + /@babel/helper-module-imports@7.24.3: + resolution: {integrity: sha512-viKb0F9f2s0BCS22QSF308z/+1YWKV/76mwt61NBzS5izMzDPwdq1pTrzf+Li3npBWX9KdQbkeCt1jSAM7lZqg==} engines: {node: '>=6.9.0'} dependencies: '@babel/types': 7.24.0 @@ -566,7 +567,7 @@ packages: dependencies: '@babel/core': 7.24.3 '@babel/helper-environment-visitor': 7.22.20 - '@babel/helper-module-imports': 7.24.1 + '@babel/helper-module-imports': 7.24.3 '@babel/helper-simple-access': 7.22.5 '@babel/helper-split-export-declaration': 7.22.6 '@babel/helper-validator-identifier': 7.22.20 @@ -629,8 +630,8 @@ packages: '@babel/types': 7.24.0 dev: true - /@babel/helper-string-parser@7.23.4: - resolution: {integrity: sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==} + /@babel/helper-string-parser@7.24.1: + resolution: {integrity: sha512-2ofRCjnnA9y+wk8b9IAREroeUP02KHp431N2mhKniy2yKIDKpbrHv9eXwm8cBeWQYcJmzv5qKCu65P47eCF7CQ==} engines: {node: '>=6.9.0'} dev: true @@ -672,14 +673,6 @@ packages: js-tokens: 4.0.0 picocolors: 1.0.0 - /@babel/parser@7.23.9: - resolution: {integrity: sha512-9tcKgqKbs3xGJ+NtKF2ndOBBLVwPjl1SHxPQkd36r3Dlirw3xWUeGaTbqr7uGZcTaxkVNwc+03SVP7aCdWrTlA==} - engines: {node: '>=6.0.0'} - hasBin: true - dependencies: - '@babel/types': 7.24.0 - dev: true - /@babel/parser@7.24.1: resolution: {integrity: sha512-Zo9c7N3xdOIQrNip7Lc9wvRPzlRtovHVE4lkz8WEDr7uYh/GMQhSiIgFxGIArRHYdJE5kxtZjAf8rT0xhdLCzg==} engines: {node: '>=6.0.0'} @@ -949,7 +942,7 @@ packages: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.24.3 - '@babel/helper-module-imports': 7.24.1 + '@babel/helper-module-imports': 7.24.3 '@babel/helper-plugin-utils': 7.24.0 '@babel/helper-remap-async-to-generator': 7.22.20(@babel/core@7.24.3) dev: true @@ -1583,16 +1576,16 @@ packages: resolution: {integrity: sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==} dev: true - /@babel/runtime-corejs2@7.23.9: - resolution: {integrity: sha512-lwwDy5QfMkO2rmSz9AvLj6j2kWt5a4ulMi1t21vWQEO0kNCFslHoszat8reU/uigIQSUDF31zraZG/qMkcqAlw==} + /@babel/runtime-corejs2@7.24.1: + resolution: {integrity: sha512-De0q0utpUPiXnc7+B7Ku86mJ0eDItC/v3uFa/lQkq63XnHyZiytDHeCIvechlnVwwpU2ChjGF7c3I+mBrTudwg==} engines: {node: '>=6.9.0'} dependencies: core-js: 2.6.12 regenerator-runtime: 0.14.1 dev: false - /@babel/runtime@7.24.0: - resolution: {integrity: sha512-Chk32uHMg6TnQdvw2e9IlqPpFX/6NLuK0Ys2PqLb7/gL5uFn9mXvK715FGLlOLQrcO4qIkNHkvPGktzzXexsFw==} + /@babel/runtime@7.24.1: + resolution: {integrity: sha512-+BIznRzyqBf+2wCTxcKE3wDjfGeCoVE61KSHGpkzqrLi8qxqFwBeUFyId2cxkTmm55fzDGnm0+yCxaxygrLUnQ==} engines: {node: '>=6.9.0'} dependencies: regenerator-runtime: 0.14.1 @@ -1625,20 +1618,11 @@ packages: - supports-color dev: true - /@babel/types@7.23.9: - resolution: {integrity: sha512-dQjSq/7HaSjRM43FFGnv5keM2HsxpmyV1PfaSVm0nzzjwwTmjOe6J4bC8e3+pTEIgHaHj+1ZlLThRJ2auc/w1Q==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/helper-string-parser': 7.23.4 - '@babel/helper-validator-identifier': 7.22.20 - to-fast-properties: 2.0.0 - dev: true - /@babel/types@7.24.0: resolution: {integrity: sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==} engines: {node: '>=6.9.0'} dependencies: - '@babel/helper-string-parser': 7.23.4 + '@babel/helper-string-parser': 7.24.1 '@babel/helper-validator-identifier': 7.22.20 to-fast-properties: 2.0.0 dev: true @@ -1647,6 +1631,18 @@ packages: resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} dev: true + /@bundled-es-modules/cookie@2.0.0: + resolution: {integrity: sha512-Or6YHg/kamKHpxULAdSqhGqnWFneIXu1NKvvfBBzKGwpVsYuFIQ5aBPHDnnoR3ghW1nvSkALd+EF9iMtY7Vjxw==} + dependencies: + cookie: 0.5.0 + dev: true + + /@bundled-es-modules/statuses@1.0.1: + resolution: {integrity: sha512-yn7BklA5acgcBr+7w064fGV+SGIFySjCKpqjcWgBAIfrAkY+4GQTJJHQMeT3V/sgz23VTEVV8TtOmkvJAhFVfg==} + dependencies: + statuses: 2.0.1 + dev: true + /@colors/colors@1.6.0: resolution: {integrity: sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==} engines: {node: '>=0.1.90'} @@ -1670,6 +1666,16 @@ packages: cpu: [ppc64] os: [aix] requiresBuild: true + dev: false + optional: true + + /@esbuild/aix-ppc64@0.20.2: + resolution: {integrity: sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [aix] + requiresBuild: true + dev: true optional: true /@esbuild/android-arm64@0.19.12: @@ -1678,6 +1684,16 @@ packages: cpu: [arm64] os: [android] requiresBuild: true + dev: false + optional: true + + /@esbuild/android-arm64@0.20.2: + resolution: {integrity: sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==} + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + requiresBuild: true + dev: true optional: true /@esbuild/android-arm@0.19.12: @@ -1686,6 +1702,16 @@ packages: cpu: [arm] os: [android] requiresBuild: true + dev: false + optional: true + + /@esbuild/android-arm@0.20.2: + resolution: {integrity: sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==} + engines: {node: '>=12'} + cpu: [arm] + os: [android] + requiresBuild: true + dev: true optional: true /@esbuild/android-x64@0.19.12: @@ -1694,6 +1720,16 @@ packages: cpu: [x64] os: [android] requiresBuild: true + dev: false + optional: true + + /@esbuild/android-x64@0.20.2: + resolution: {integrity: sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==} + engines: {node: '>=12'} + cpu: [x64] + os: [android] + requiresBuild: true + dev: true optional: true /@esbuild/darwin-arm64@0.19.12: @@ -1702,6 +1738,16 @@ packages: cpu: [arm64] os: [darwin] requiresBuild: true + dev: false + optional: true + + /@esbuild/darwin-arm64@0.20.2: + resolution: {integrity: sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==} + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: true optional: true /@esbuild/darwin-x64@0.19.12: @@ -1710,6 +1756,16 @@ packages: cpu: [x64] os: [darwin] requiresBuild: true + dev: false + optional: true + + /@esbuild/darwin-x64@0.20.2: + resolution: {integrity: sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==} + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: true optional: true /@esbuild/freebsd-arm64@0.19.12: @@ -1718,6 +1774,16 @@ packages: cpu: [arm64] os: [freebsd] requiresBuild: true + dev: false + optional: true + + /@esbuild/freebsd-arm64@0.20.2: + resolution: {integrity: sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==} + engines: {node: '>=12'} + cpu: [arm64] + os: [freebsd] + requiresBuild: true + dev: true optional: true /@esbuild/freebsd-x64@0.19.12: @@ -1726,6 +1792,16 @@ packages: cpu: [x64] os: [freebsd] requiresBuild: true + dev: false + optional: true + + /@esbuild/freebsd-x64@0.20.2: + resolution: {integrity: sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==} + engines: {node: '>=12'} + cpu: [x64] + os: [freebsd] + requiresBuild: true + dev: true optional: true /@esbuild/linux-arm64@0.19.12: @@ -1734,6 +1810,16 @@ packages: cpu: [arm64] os: [linux] requiresBuild: true + dev: false + optional: true + + /@esbuild/linux-arm64@0.20.2: + resolution: {integrity: sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true optional: true /@esbuild/linux-arm@0.19.12: @@ -1742,6 +1828,16 @@ packages: cpu: [arm] os: [linux] requiresBuild: true + dev: false + optional: true + + /@esbuild/linux-arm@0.20.2: + resolution: {integrity: sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: true optional: true /@esbuild/linux-ia32@0.19.12: @@ -1750,6 +1846,16 @@ packages: cpu: [ia32] os: [linux] requiresBuild: true + dev: false + optional: true + + /@esbuild/linux-ia32@0.20.2: + resolution: {integrity: sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==} + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + requiresBuild: true + dev: true optional: true /@esbuild/linux-loong64@0.19.12: @@ -1758,6 +1864,16 @@ packages: cpu: [loong64] os: [linux] requiresBuild: true + dev: false + optional: true + + /@esbuild/linux-loong64@0.20.2: + resolution: {integrity: sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==} + engines: {node: '>=12'} + cpu: [loong64] + os: [linux] + requiresBuild: true + dev: true optional: true /@esbuild/linux-mips64el@0.19.12: @@ -1766,6 +1882,16 @@ packages: cpu: [mips64el] os: [linux] requiresBuild: true + dev: false + optional: true + + /@esbuild/linux-mips64el@0.20.2: + resolution: {integrity: sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + requiresBuild: true + dev: true optional: true /@esbuild/linux-ppc64@0.19.12: @@ -1774,6 +1900,16 @@ packages: cpu: [ppc64] os: [linux] requiresBuild: true + dev: false + optional: true + + /@esbuild/linux-ppc64@0.20.2: + resolution: {integrity: sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + requiresBuild: true + dev: true optional: true /@esbuild/linux-riscv64@0.19.12: @@ -1782,6 +1918,16 @@ packages: cpu: [riscv64] os: [linux] requiresBuild: true + dev: false + optional: true + + /@esbuild/linux-riscv64@0.20.2: + resolution: {integrity: sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + requiresBuild: true + dev: true optional: true /@esbuild/linux-s390x@0.19.12: @@ -1790,6 +1936,16 @@ packages: cpu: [s390x] os: [linux] requiresBuild: true + dev: false + optional: true + + /@esbuild/linux-s390x@0.20.2: + resolution: {integrity: sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + requiresBuild: true + dev: true optional: true /@esbuild/linux-x64@0.19.12: @@ -1798,6 +1954,16 @@ packages: cpu: [x64] os: [linux] requiresBuild: true + dev: false + optional: true + + /@esbuild/linux-x64@0.20.2: + resolution: {integrity: sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true optional: true /@esbuild/netbsd-x64@0.19.12: @@ -1806,6 +1972,16 @@ packages: cpu: [x64] os: [netbsd] requiresBuild: true + dev: false + optional: true + + /@esbuild/netbsd-x64@0.20.2: + resolution: {integrity: sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + requiresBuild: true + dev: true optional: true /@esbuild/openbsd-x64@0.19.12: @@ -1814,6 +1990,16 @@ packages: cpu: [x64] os: [openbsd] requiresBuild: true + dev: false + optional: true + + /@esbuild/openbsd-x64@0.20.2: + resolution: {integrity: sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + requiresBuild: true + dev: true optional: true /@esbuild/sunos-x64@0.19.12: @@ -1822,6 +2008,16 @@ packages: cpu: [x64] os: [sunos] requiresBuild: true + dev: false + optional: true + + /@esbuild/sunos-x64@0.20.2: + resolution: {integrity: sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + requiresBuild: true + dev: true optional: true /@esbuild/win32-arm64@0.19.12: @@ -1830,6 +2026,16 @@ packages: cpu: [arm64] os: [win32] requiresBuild: true + dev: false + optional: true + + /@esbuild/win32-arm64@0.20.2: + resolution: {integrity: sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: true optional: true /@esbuild/win32-ia32@0.19.12: @@ -1838,6 +2044,16 @@ packages: cpu: [ia32] os: [win32] requiresBuild: true + dev: false + optional: true + + /@esbuild/win32-ia32@0.20.2: + resolution: {integrity: sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: true optional: true /@esbuild/win32-x64@0.19.12: @@ -1846,6 +2062,16 @@ packages: cpu: [x64] os: [win32] requiresBuild: true + dev: false + optional: true + + /@esbuild/win32-x64@0.20.2: + resolution: {integrity: sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: true optional: true /@eslint-community/eslint-utils@4.4.0(eslint@8.57.0): @@ -1890,34 +2116,34 @@ packages: engines: {node: '>=18.14.1'} dev: false - /@hono/swagger-ui@0.2.1(hono@4.1.4): + /@hono/swagger-ui@0.2.1(hono@4.1.5): resolution: {integrity: sha512-wBxVMRe3/v8xH4o6icmwztiIq0DG0s7+jHVMHVUAoFFCWEQNL2iskMmQtrhSDtsFmBZUeUFQUaaJ6Ir6DOmHLA==} peerDependencies: hono: '*' dependencies: - hono: 4.1.4 + hono: 4.1.5 dev: false - /@hono/zod-openapi@0.9.9(hono@4.1.4)(zod@3.22.4): - resolution: {integrity: sha512-Icak3c8WKNS1gFDWmYs2zJ7ra3js9lDeAXNPf5h3fa0SnJQcjcCrLaG6EZPPAbW92HRwCDeQt8yA/ZVp17HPFg==} + /@hono/zod-openapi@0.9.10(hono@4.1.5)(zod@3.22.4): + resolution: {integrity: sha512-v/b/z0qPxDo952gjRyhJ0n9ifbPoIluR2KmXDL20np0hj99+XvakoIHK5/T/3+hUmXlTj1Kn3TiGsSV6hwZesg==} engines: {node: '>=16.0.0'} peerDependencies: hono: '>=3.11.3' zod: 3.* dependencies: '@asteasolutions/zod-to-openapi': 5.5.0(zod@3.22.4) - '@hono/zod-validator': 0.1.11(hono@4.1.4)(zod@3.22.4) - hono: 4.1.4 + '@hono/zod-validator': 0.2.1(hono@4.1.5)(zod@3.22.4) + hono: 4.1.5 zod: 3.22.4 dev: false - /@hono/zod-validator@0.1.11(hono@4.1.4)(zod@3.22.4): - resolution: {integrity: sha512-PQXeHUP0+36qpRt8yfeD7N2jbK3ETlGvSN6dMof/HwUC/APRokQRjpXZm4rrlG71Ft0aWE01+Bm4XejqPie5Uw==} + /@hono/zod-validator@0.2.1(hono@4.1.5)(zod@3.22.4): + resolution: {integrity: sha512-HFoxln7Q6JsE64qz2WBS28SD33UB2alp3aRKmcWnNLDzEL1BLsWfbdX6e1HIiUprHYTIXf5y7ax8eYidKUwyaA==} peerDependencies: hono: '>=3.9.0' zod: ^3.19.1 dependencies: - hono: 4.1.4 + hono: 4.1.5 zod: 3.22.4 dev: false @@ -1949,6 +2175,39 @@ packages: lodash: 4.17.21 dev: true + /@inquirer/confirm@3.1.0: + resolution: {integrity: sha512-nH5mxoTEoqk6WpoBz80GMpDSm9jH5V9AF8n+JZAZfMzd9gHeEG9w1o3KawPRR72lfzpP+QxBHLkOKLEApwhDiQ==} + engines: {node: '>=18'} + dependencies: + '@inquirer/core': 7.1.0 + '@inquirer/type': 1.2.1 + dev: true + + /@inquirer/core@7.1.0: + resolution: {integrity: sha512-FRCiDiU54XHt5B/D8hX4twwZuzSP244ANHbu3R7CAsJfiv1dUOz24ePBgCZjygEjDUi6BWIJuk4eWLKJ7LATUw==} + engines: {node: '>=18'} + dependencies: + '@inquirer/type': 1.2.1 + '@types/mute-stream': 0.0.4 + '@types/node': 20.11.30 + '@types/wrap-ansi': 3.0.0 + ansi-escapes: 4.3.2 + chalk: 4.1.2 + cli-spinners: 2.9.2 + cli-width: 4.1.0 + figures: 3.2.0 + mute-stream: 1.0.0 + run-async: 3.0.0 + signal-exit: 4.1.0 + strip-ansi: 6.0.1 + wrap-ansi: 6.2.0 + dev: true + + /@inquirer/type@1.2.1: + resolution: {integrity: sha512-xwMfkPAxeo8Ji/IxfUSqzRi0/+F2GIqJmpc5/thelgMGsjNZcjDDRBO9TLXT1s/hdx/mK5QbVIvgoLIFgXhTMQ==} + engines: {node: '>=18'} + dev: true + /@ioredis/commands@1.2.0: resolution: {integrity: sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg==} dev: false @@ -1977,15 +2236,6 @@ packages: '@sinclair/typebox': 0.27.8 dev: true - /@jridgewell/gen-mapping@0.3.3: - resolution: {integrity: sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==} - engines: {node: '>=6.0.0'} - dependencies: - '@jridgewell/set-array': 1.1.2 - '@jridgewell/sourcemap-codec': 1.4.15 - '@jridgewell/trace-mapping': 0.3.22 - dev: true - /@jridgewell/gen-mapping@0.3.5: resolution: {integrity: sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==} engines: {node: '>=6.0.0'} @@ -2000,11 +2250,6 @@ packages: engines: {node: '>=6.0.0'} dev: true - /@jridgewell/set-array@1.1.2: - resolution: {integrity: sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==} - engines: {node: '>=6.0.0'} - dev: true - /@jridgewell/set-array@1.2.1: resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} engines: {node: '>=6.0.0'} @@ -2014,13 +2259,6 @@ packages: resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} dev: true - /@jridgewell/trace-mapping@0.3.22: - resolution: {integrity: sha512-Wf963MzWtA2sjrNt+g18IAln9lKnlRp+K2eH4jjIoF1wYeq3aMREpG09xhlhdzS0EjwU7qmUJYangWa+151vZw==} - dependencies: - '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.4.15 - dev: true - /@jridgewell/trace-mapping@0.3.25: resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} dependencies: @@ -2028,15 +2266,15 @@ packages: '@jridgewell/sourcemap-codec': 1.4.15 dev: true - /@lifeomic/attempt@3.0.3: - resolution: {integrity: sha512-GlM2AbzrErd/TmLL3E8hAHmb5Q7VhDJp35vIbyPVA5Rz55LZuRr8pwL3qrwwkVNo05gMX1J44gURKb4MHQZo7w==} + /@lifeomic/attempt@3.1.0: + resolution: {integrity: sha512-QZqem4QuAnAyzfz+Gj5/+SLxqwCAw2qmt7732ZXodr6VDWGeYLG6w1i/vYLa55JQM9wRuBKLmXmiZ2P0LtE5rw==} dev: false /@mapbox/node-pre-gyp@1.0.11: resolution: {integrity: sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ==} hasBin: true dependencies: - detect-libc: 2.0.2 + detect-libc: 2.0.3 https-proxy-agent: 5.0.1 make-dir: 3.1.0 node-fetch: 2.7.0 @@ -2044,7 +2282,7 @@ packages: npmlog: 5.0.1 rimraf: 3.0.2 semver: 7.6.0 - tar: 6.2.0 + tar: 6.2.1 transitivePeerDependencies: - encoding - supports-color @@ -2062,8 +2300,25 @@ packages: - supports-color dev: true + /@mswjs/cookies@1.1.0: + resolution: {integrity: sha512-0ZcCVQxifZmhwNBoQIrystCb+2sWBY2Zw8lpfJBPCHGCA/HWqehITeCRVIv4VMy8MPlaHo2w2pTHFV2pFfqKPw==} + engines: {node: '>=18'} + dev: true + + /@mswjs/interceptors@0.26.14: + resolution: {integrity: sha512-q4S8RGjOUzv3A3gCawuKkUEcNJXjdPaSqoRHFvuZPWQnc7yOw702iGBRDMJoBK+l0KSv9XN8YP5ek6duRzrpqw==} + engines: {node: '>=18'} + dependencies: + '@open-draft/deferred-promise': 2.2.0 + '@open-draft/logger': 0.3.0 + '@open-draft/until': 2.1.0 + is-node-process: 1.2.0 + outvariant: 1.4.2 + strict-event-emitter: 0.5.1 + dev: true + /@nodelib/fs.scandir@2.1.5: - resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + resolution: {integrity: sha1-dhnC6yGyVIP20WdUi0z9WnSIw9U=, tarball: https://registry.npmmirror.com/@nodelib/fs.scandir/download/@nodelib/fs.scandir-2.1.5.tgz} engines: {node: '>= 8'} dependencies: '@nodelib/fs.stat': 2.0.5 @@ -2097,6 +2352,21 @@ packages: resolution: {integrity: sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw==} dev: true + /@open-draft/deferred-promise@2.2.0: + resolution: {integrity: sha512-CecwLWx3rhxVQF6V4bAgPS5t+So2sTbPgAzafKkVizyi7tlwpcFpdFqq+wqF2OwNBmqFuu6tOyouTuxgpMfzmA==} + dev: true + + /@open-draft/logger@0.3.0: + resolution: {integrity: sha512-X2g45fzhxH238HKO4xbSr7+wBS8Fvw6ixhTDuvLd5mqh6bJJCFAPwU9mPDxbcrRtfxv4u5IHCEH77BmxvXmmxQ==} + dependencies: + is-node-process: 1.2.0 + outvariant: 1.4.2 + dev: true + + /@open-draft/until@2.1.0: + resolution: {integrity: sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg==} + dev: true + /@otplib/core@12.0.1: resolution: {integrity: sha512-4sGntwbA/AC+SbPhbsziRiD+jNDdIzsZ3JUyfZwjtKyc/wufl1pnSIaG4Uqx8ymPagujub0o92kgBnB89cuAMA==} dev: false @@ -2157,7 +2427,7 @@ packages: engines: {node: '>=10'} hasBin: true dependencies: - '@babel/runtime-corejs2': 7.23.9 + '@babel/runtime-corejs2': 7.24.1 '@postlight/ci-failed-test-reporter': 1.0.26 cheerio: 0.22.0 difflib: github.com/postlight/difflib.js/32e8e38c7fcd935241b9baab71bb432fd9b166ed @@ -2167,7 +2437,7 @@ packages: moment-parseformat: 3.0.0 postman-request: 2.88.1-postman.33 string-direction: 0.1.2 - turndown: 7.1.2 + turndown: 7.1.3 valid-url: 1.0.9 wuzzy: 0.1.8 yargs-parser: 15.0.3 @@ -2229,104 +2499,109 @@ packages: picomatch: 2.3.1 dev: true - /@rollup/rollup-android-arm-eabi@4.12.0: - resolution: {integrity: sha512-+ac02NL/2TCKRrJu2wffk1kZ+RyqxVUlbjSagNgPm94frxtr+XDL12E5Ll1enWskLrtrZ2r8L3wED1orIibV/w==} + /@rollup/rollup-android-arm-eabi@4.13.0: + resolution: {integrity: sha512-5ZYPOuaAqEH/W3gYsRkxQATBW3Ii1MfaT4EQstTnLKViLi2gLSQmlmtTpGucNP3sXEpOiI5tdGhjdE111ekyEg==} cpu: [arm] os: [android] requiresBuild: true dev: true optional: true - /@rollup/rollup-android-arm64@4.12.0: - resolution: {integrity: sha512-OBqcX2BMe6nvjQ0Nyp7cC90cnumt8PXmO7Dp3gfAju/6YwG0Tj74z1vKrfRz7qAv23nBcYM8BCbhrsWqO7PzQQ==} + /@rollup/rollup-android-arm64@4.13.0: + resolution: {integrity: sha512-BSbaCmn8ZadK3UAQdlauSvtaJjhlDEjS5hEVVIN3A4bbl3X+otyf/kOJV08bYiRxfejP3DXFzO2jz3G20107+Q==} cpu: [arm64] os: [android] requiresBuild: true dev: true optional: true - /@rollup/rollup-darwin-arm64@4.12.0: - resolution: {integrity: sha512-X64tZd8dRE/QTrBIEs63kaOBG0b5GVEd3ccoLtyf6IdXtHdh8h+I56C2yC3PtC9Ucnv0CpNFJLqKFVgCYe0lOQ==} + /@rollup/rollup-darwin-arm64@4.13.0: + resolution: {integrity: sha512-Ovf2evVaP6sW5Ut0GHyUSOqA6tVKfrTHddtmxGQc1CTQa1Cw3/KMCDEEICZBbyppcwnhMwcDce9ZRxdWRpVd6g==} cpu: [arm64] os: [darwin] requiresBuild: true dev: true optional: true - /@rollup/rollup-darwin-x64@4.12.0: - resolution: {integrity: sha512-cc71KUZoVbUJmGP2cOuiZ9HSOP14AzBAThn3OU+9LcA1+IUqswJyR1cAJj3Mg55HbjZP6OLAIscbQsQLrpgTOg==} + /@rollup/rollup-darwin-x64@4.13.0: + resolution: {integrity: sha512-U+Jcxm89UTK592vZ2J9st9ajRv/hrwHdnvyuJpa5A2ngGSVHypigidkQJP+YiGL6JODiUeMzkqQzbCG3At81Gg==} cpu: [x64] os: [darwin] requiresBuild: true dev: true optional: true - /@rollup/rollup-linux-arm-gnueabihf@4.12.0: - resolution: {integrity: sha512-a6w/Y3hyyO6GlpKL2xJ4IOh/7d+APaqLYdMf86xnczU3nurFTaVN9s9jOXQg97BE4nYm/7Ga51rjec5nfRdrvA==} + /@rollup/rollup-linux-arm-gnueabihf@4.13.0: + resolution: {integrity: sha512-8wZidaUJUTIR5T4vRS22VkSMOVooG0F4N+JSwQXWSRiC6yfEsFMLTYRFHvby5mFFuExHa/yAp9juSphQQJAijQ==} cpu: [arm] os: [linux] requiresBuild: true dev: true optional: true - /@rollup/rollup-linux-arm64-gnu@4.12.0: - resolution: {integrity: sha512-0fZBq27b+D7Ar5CQMofVN8sggOVhEtzFUwOwPppQt0k+VR+7UHMZZY4y+64WJ06XOhBTKXtQB/Sv0NwQMXyNAA==} + /@rollup/rollup-linux-arm64-gnu@4.13.0: + resolution: {integrity: sha512-Iu0Kno1vrD7zHQDxOmvweqLkAzjxEVqNhUIXBsZ8hu8Oak7/5VTPrxOEZXYC1nmrBVJp0ZcL2E7lSuuOVaE3+w==} cpu: [arm64] os: [linux] + libc: [glibc] requiresBuild: true dev: true optional: true - /@rollup/rollup-linux-arm64-musl@4.12.0: - resolution: {integrity: sha512-eTvzUS3hhhlgeAv6bfigekzWZjaEX9xP9HhxB0Dvrdbkk5w/b+1Sxct2ZuDxNJKzsRStSq1EaEkVSEe7A7ipgQ==} + /@rollup/rollup-linux-arm64-musl@4.13.0: + resolution: {integrity: sha512-C31QrW47llgVyrRjIwiOwsHFcaIwmkKi3PCroQY5aVq4H0A5v/vVVAtFsI1nfBngtoRpeREvZOkIhmRwUKkAdw==} cpu: [arm64] os: [linux] + libc: [musl] requiresBuild: true dev: true optional: true - /@rollup/rollup-linux-riscv64-gnu@4.12.0: - resolution: {integrity: sha512-ix+qAB9qmrCRiaO71VFfY8rkiAZJL8zQRXveS27HS+pKdjwUfEhqo2+YF2oI+H/22Xsiski+qqwIBxVewLK7sw==} + /@rollup/rollup-linux-riscv64-gnu@4.13.0: + resolution: {integrity: sha512-Oq90dtMHvthFOPMl7pt7KmxzX7E71AfyIhh+cPhLY9oko97Zf2C9tt/XJD4RgxhaGeAraAXDtqxvKE1y/j35lA==} cpu: [riscv64] os: [linux] + libc: [glibc] requiresBuild: true dev: true optional: true - /@rollup/rollup-linux-x64-gnu@4.12.0: - resolution: {integrity: sha512-TenQhZVOtw/3qKOPa7d+QgkeM6xY0LtwzR8OplmyL5LrgTWIXpTQg2Q2ycBf8jm+SFW2Wt/DTn1gf7nFp3ssVA==} + /@rollup/rollup-linux-x64-gnu@4.13.0: + resolution: {integrity: sha512-yUD/8wMffnTKuiIsl6xU+4IA8UNhQ/f1sAnQebmE/lyQ8abjsVyDkyRkWop0kdMhKMprpNIhPmYlCxgHrPoXoA==} cpu: [x64] os: [linux] + libc: [glibc] requiresBuild: true dev: true optional: true - /@rollup/rollup-linux-x64-musl@4.12.0: - resolution: {integrity: sha512-LfFdRhNnW0zdMvdCb5FNuWlls2WbbSridJvxOvYWgSBOYZtgBfW9UGNJG//rwMqTX1xQE9BAodvMH9tAusKDUw==} + /@rollup/rollup-linux-x64-musl@4.13.0: + resolution: {integrity: sha512-9RyNqoFNdF0vu/qqX63fKotBh43fJQeYC98hCaf89DYQpv+xu0D8QFSOS0biA7cGuqJFOc1bJ+m2rhhsKcw1hw==} cpu: [x64] os: [linux] + libc: [musl] requiresBuild: true dev: true optional: true - /@rollup/rollup-win32-arm64-msvc@4.12.0: - resolution: {integrity: sha512-JPDxovheWNp6d7AHCgsUlkuCKvtu3RB55iNEkaQcf0ttsDU/JZF+iQnYcQJSk/7PtT4mjjVG8N1kpwnI9SLYaw==} + /@rollup/rollup-win32-arm64-msvc@4.13.0: + resolution: {integrity: sha512-46ue8ymtm/5PUU6pCvjlic0z82qWkxv54GTJZgHrQUuZnVH+tvvSP0LsozIDsCBFO4VjJ13N68wqrKSeScUKdA==} cpu: [arm64] os: [win32] requiresBuild: true dev: true optional: true - /@rollup/rollup-win32-ia32-msvc@4.12.0: - resolution: {integrity: sha512-fjtuvMWRGJn1oZacG8IPnzIV6GF2/XG+h71FKn76OYFqySXInJtseAqdprVTDTyqPxQOG9Exak5/E9Z3+EJ8ZA==} + /@rollup/rollup-win32-ia32-msvc@4.13.0: + resolution: {integrity: sha512-P5/MqLdLSlqxbeuJ3YDeX37srC8mCflSyTrUsgbU1c/U9j6l2g2GiIdYaGD9QjdMQPMSgYm7hgg0551wHyIluw==} cpu: [ia32] os: [win32] requiresBuild: true dev: true optional: true - /@rollup/rollup-win32-x64-msvc@4.12.0: - resolution: {integrity: sha512-ZYmr5mS2wd4Dew/JjT0Fqi2NPB/ZhZ2VvPp7SmvPZb4Y1CG/LRcS6tcRo2cYU7zLK5A7cdbhWnnWmUjoI4qapg==} + /@rollup/rollup-win32-x64-msvc@4.13.0: + resolution: {integrity: sha512-UKXUQNbO3DOhzLRwHSpa0HnhhCgNODvfoPWv2FCXme8N/ANFfhIPMGuOT+QuKd16+B5yxZ0HdpNlqPvTMS1qfw==} cpu: [x64] os: [win32] requiresBuild: true @@ -2340,43 +2615,43 @@ packages: selderee: 0.11.0 dev: false - /@sentry-internal/tracing@7.108.0: - resolution: {integrity: sha512-zuK5XsTsb+U+hgn3SPetYDAogrXsM16U/LLoMW7+TlC6UjlHGYQvmX3o+M2vntejoU1QZS8m1bCAZSMWEypAEw==} + /@sentry-internal/tracing@7.109.0: + resolution: {integrity: sha512-PzK/joC5tCuh2R/PRh+7dp+uuZl7pTsBIjPhVZHMTtb9+ls65WkdZJ1/uKXPouyz8NOo9Xok7aEvEo9seongyw==} engines: {node: '>=8'} dependencies: - '@sentry/core': 7.108.0 - '@sentry/types': 7.108.0 - '@sentry/utils': 7.108.0 + '@sentry/core': 7.109.0 + '@sentry/types': 7.109.0 + '@sentry/utils': 7.109.0 dev: false - /@sentry/core@7.108.0: - resolution: {integrity: sha512-I/VNZCFgLASxHZaD0EtxZRM34WG9w2gozqgrKGNMzAymwmQ3K9g/1qmBy4e6iS3YRptb7J5UhQkZQHrcwBbjWQ==} + /@sentry/core@7.109.0: + resolution: {integrity: sha512-xwD4U0IlvvlE/x/g/W1I8b4Cfb16SsCMmiEuBf6XxvAa3OfWBxKoqLifb3GyrbxMC4LbIIZCN/SvLlnGJPgszA==} engines: {node: '>=8'} dependencies: - '@sentry/types': 7.108.0 - '@sentry/utils': 7.108.0 + '@sentry/types': 7.109.0 + '@sentry/utils': 7.109.0 dev: false - /@sentry/node@7.108.0: - resolution: {integrity: sha512-pMxc9txnDDkU4Z8k2Uw/DPSLPehNtWV3mjJ3+my0AMORGYrXLkJI93tddlE5z/7k+GEJdj1HsOLgxUN0OU+HGA==} + /@sentry/node@7.109.0: + resolution: {integrity: sha512-tqMNAES4X/iBl1eZRCmc29p//0id01FBLEiesNo5nk6ECl6/SaGMFAEwu1gsn90h/Bjgr04slwFOS4cR45V2PQ==} engines: {node: '>=8'} dependencies: - '@sentry-internal/tracing': 7.108.0 - '@sentry/core': 7.108.0 - '@sentry/types': 7.108.0 - '@sentry/utils': 7.108.0 + '@sentry-internal/tracing': 7.109.0 + '@sentry/core': 7.109.0 + '@sentry/types': 7.109.0 + '@sentry/utils': 7.109.0 dev: false - /@sentry/types@7.108.0: - resolution: {integrity: sha512-bKtHITmBN3kqtqE5eVvL8mY8znM05vEodENwRpcm6TSrrBjC2RnwNWVwGstYDdHpNfFuKwC8mLY9bgMJcENo8g==} + /@sentry/types@7.109.0: + resolution: {integrity: sha512-egCBnDv3YpVFoNzRLdP0soVrxVLCQ+rovREKJ1sw3rA2/MFH9WJ+DZZexsX89yeAFzy1IFsCp7/dEqudusml6g==} engines: {node: '>=8'} dev: false - /@sentry/utils@7.108.0: - resolution: {integrity: sha512-a45yEFD5qtgZaIFRAcFkG8C8lnDzn6t4LfLXuV4OafGAy/3ZAN3XN8wDnrruHkiUezSSANGsLg3bXaLW/JLvJw==} + /@sentry/utils@7.109.0: + resolution: {integrity: sha512-3RjxMOLMBwZ5VSiH84+o/3NY2An4Zldjz0EbfEQNRY9yffRiCPJSQiCJID8EoylCFOh/PAhPimBhqbtWJxX6iw==} engines: {node: '>=8'} dependencies: - '@sentry/types': 7.108.0 + '@sentry/types': 7.109.0 dev: false /@sinclair/typebox@0.27.8: @@ -2391,7 +2666,7 @@ packages: /@sindresorhus/is@6.2.0: resolution: {integrity: sha512-yM/IGPkVnYGblhDosFBwq0ZGdnVSBkNV4onUtipGMOjZd4kB6GAu3ys91aftSbyMHh6A2GPdt+KDI5NoWP63MQ==} engines: {node: '>=16'} - dev: false + dev: true /@stylistic/eslint-plugin-js@1.7.0(eslint@8.57.0): resolution: {integrity: sha512-PN6On/+or63FGnhhMKSQfYcWutRlzOiYlVdLM6yN7lquoBTqUJHYnl4TA4MHwiAt46X5gRxDr1+xPZ1lOLcL+Q==} @@ -2470,7 +2745,6 @@ packages: engines: {node: '>=14.16'} dependencies: defer-to-connect: 2.0.1 - dev: false /@tonyrl/rand-user-agent@2.0.56: resolution: {integrity: sha512-7C2zOyvJsU2BxYayw+w/KjtP/InxYHzRWOWUuPj3XP3SGfnUTpQjKvEuo5K0LB+0YqF62w65LjHGE7Aw1irtaA==} @@ -2496,6 +2770,10 @@ packages: resolution: {integrity: sha512-V+pm3stv1Mvz8fSKJJod6CglNGVqEQ6OyuqitoDkWywEODM/eJd1eSuIp9xt6DrX8BWZ2eDSIzbw1tPCUTvGbQ==} dev: false + /@types/cookie@0.6.0: + resolution: {integrity: sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==} + dev: true + /@types/cookiejar@2.1.5: resolution: {integrity: sha512-he+DHOWReW0nghN24E1WUqM0efK4kI9oTqDm6XmK8ZPe2djZ90BSNdGnIyCLzCPw7/pogPlGbzI2wHGGmi4O/Q==} dev: true @@ -2547,7 +2825,6 @@ packages: /@types/http-cache-semantics@4.0.4: resolution: {integrity: sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==} - dev: false /@types/imapflow@1.0.18: resolution: {integrity: sha512-BoWZUoMktji2YJmkRY8z0KsjvyDNpBzeC/rLVMFKcHkPxaKp+SHBFfx/kj7ltKh3l010Lc9RZqnJs8KUMNhf6Q==} @@ -2624,6 +2901,12 @@ packages: /@types/ms@0.7.34: resolution: {integrity: sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==} + /@types/mute-stream@0.0.4: + resolution: {integrity: sha512-CPM9nzrCPPJHQNA9keH9CVkVI+WR5kMa+7XEs5jcGQ0VoAGnLv242w8lIVgwAEfmE4oufJRaTc9PNLQl0ioAow==} + dependencies: + '@types/node': 20.11.30 + dev: true + /@types/node-fetch@2.6.11: resolution: {integrity: sha512-24xFj9R5+rfQJLRyM56qh+wnVSYhyXC2tkoBndtY0U+vubqNsYXGjufB2nn8Q6gt0LrARwL6UBtMCSVCwl4B1g==} dependencies: @@ -2671,8 +2954,12 @@ packages: resolution: {integrity: sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==} dev: true - /@types/superagent@8.1.3: - resolution: {integrity: sha512-R/CfN6w2XsixLb1Ii8INfn+BT9sGPvw74OavfkW4SwY+jeUcAwLZv2+bXLJkndnimxjEBm0RPHgcjW9pLCa8cw==} + /@types/statuses@2.0.5: + resolution: {integrity: sha512-jmIUGWrAiwu3dZpxntxieC+1n/5c3mjrImkmOSQ2NC5uP6cYO4aAZDdSmRcI5C1oiTmqlZGHC+/NmJrKogbP5A==} + dev: true + + /@types/superagent@8.1.6: + resolution: {integrity: sha512-yzBOv+6meEHSzV2NThYYOA6RtqvPr3Hbob9ZLp3i07SH27CrYVfm8CrF7ydTmidtelsFiKx2I4gZAiAOamGgvQ==} dependencies: '@types/cookiejar': 2.1.5 '@types/methods': 1.1.4 @@ -2683,7 +2970,7 @@ packages: resolution: {integrity: sha512-137ypx2lk/wTQbW6An6safu9hXmajAifU/s7szAHLN/FeIm5w7yR0Wkl9fdJMRSHwOn4HLAI0DaB2TOORuhPDg==} dependencies: '@types/methods': 1.1.4 - '@types/superagent': 8.1.3 + '@types/superagent': 8.1.6 dev: true /@types/tiny-async-pool@2.0.3: @@ -2701,6 +2988,10 @@ packages: resolution: {integrity: sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==} dev: true + /@types/wrap-ansi@3.0.0: + resolution: {integrity: sha512-ltIpx+kM7g/MLRZfkbL7EsCEjfzCcScLpkg37eXEtx5kmrAKBkTJwd1GIAjDSL8wTpM6Hzn5YO4pSb91BEwu1g==} + dev: true + /@types/yauzl@2.10.3: resolution: {integrity: sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==} requiresBuild: true @@ -2732,7 +3023,7 @@ packages: ignore: 5.3.1 natural-compare: 1.4.0 semver: 7.6.0 - ts-api-utils: 1.2.1(typescript@5.4.3) + ts-api-utils: 1.3.0(typescript@5.4.3) typescript: 5.4.3 transitivePeerDependencies: - supports-color @@ -2789,7 +3080,7 @@ packages: '@typescript-eslint/utils': 7.4.0(eslint@8.57.0)(typescript@5.4.3) debug: 4.3.4 eslint: 8.57.0 - ts-api-utils: 1.2.1(typescript@5.4.3) + ts-api-utils: 1.3.0(typescript@5.4.3) typescript: 5.4.3 transitivePeerDependencies: - supports-color @@ -2821,7 +3112,7 @@ packages: is-glob: 4.0.3 minimatch: 9.0.3 semver: 7.6.0 - ts-api-utils: 1.2.1(typescript@5.4.3) + ts-api-utils: 1.3.0(typescript@5.4.3) typescript: 5.4.3 transitivePeerDependencies: - supports-color @@ -2843,7 +3134,7 @@ packages: is-glob: 4.0.3 minimatch: 9.0.3 semver: 7.6.0 - ts-api-utils: 1.2.1(typescript@5.4.3) + ts-api-utils: 1.3.0(typescript@5.4.3) typescript: 5.4.3 transitivePeerDependencies: - supports-color @@ -2915,7 +3206,7 @@ packages: '@mapbox/node-pre-gyp': 1.0.11 '@rollup/pluginutils': 4.2.1 acorn: 8.11.3 - acorn-import-attributes: 1.9.2(acorn@8.11.3) + acorn-import-attributes: 1.9.4(acorn@8.11.3) async-sema: 3.1.1 bindings: 1.5.0 estree-walker: 2.0.2 @@ -2934,13 +3225,13 @@ packages: peerDependencies: vitest: 1.4.0 dependencies: - '@ampproject/remapping': 2.2.1 + '@ampproject/remapping': 2.3.0 '@bcoe/v8-coverage': 0.2.3 debug: 4.3.4 istanbul-lib-coverage: 3.2.2 istanbul-lib-report: 3.0.1 istanbul-lib-source-maps: 5.0.4 - istanbul-reports: 3.1.6 + istanbul-reports: 3.1.7 magic-string: 0.30.8 magicast: 0.3.3 picocolors: 1.0.0 @@ -3008,8 +3299,8 @@ packages: event-target-shim: 5.0.1 dev: false - /acorn-import-attributes@1.9.2(acorn@8.11.3): - resolution: {integrity: sha512-O+nfJwNolEA771IYJaiLWK1UAwjNsQmZbTRqqwBYxCgVQTmpFEMvBw6LOIQV0Me339L5UMVYFyRohGnGlQDdIQ==} + /acorn-import-attributes@1.9.4(acorn@8.11.3): + resolution: {integrity: sha512-dNIX/5UEnZvVL94dV2scl4VIooK36D8AteP4xiz7cPKhDbhLhSuWkzG580g+Q7TXJklp+Z21SiaK7/HpLO84Qg==} peerDependencies: acorn: ^8 dependencies: @@ -3077,11 +3368,9 @@ packages: type-fest: 0.21.3 dev: true - /ansi-escapes@6.2.0: - resolution: {integrity: sha512-kzRaCqXnpzWs+3z5ABPQiVke+iq0KXkHo8xiWV4RPTi5Yli0l97BEQuhXV1s7+aSU/fu1kUuxgS4MsQ0fRuygw==} + /ansi-escapes@6.2.1: + resolution: {integrity: sha512-4nJ3yixlEthEJ9Rk4vPcdBRkZvQZlYyu8j4/Mqz5sgIkddmEnH2Yj2ZrnP9S3tQOvSNRUIgVNF/1yPpRAGNRig==} engines: {node: '>=14.16'} - dependencies: - type-fest: 3.13.1 dev: true /ansi-regex@2.1.1: @@ -3280,8 +3569,8 @@ packages: /balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - /bare-events@2.2.0: - resolution: {integrity: sha512-Yyyqff4PIFfSuthCZqLlPISTWHmnQxoPuAvkmgzsJEmG3CesdIv6Xweayl0JkCZJSB2yYIdJyEz97tpxNhgjbg==} + /bare-events@2.2.2: + resolution: {integrity: sha512-h7z00dWdG0PYOQEvChhOSWvOfkIKsdZGkWr083FgN/HyoQuebSew/cgirYqh9SCuy/hRvxc5Vy6Fw8xAmYHLkQ==} requiresBuild: true dev: false optional: true @@ -3290,15 +3579,15 @@ packages: resolution: {integrity: sha512-X9IqgvyB0/VA5OZJyb5ZstoN62AzD7YxVGog13kkfYWYqJYcK0kcqLZ6TrmH5qr4/8//ejVcX4x/a0UvaogXmA==} requiresBuild: true dependencies: - bare-events: 2.2.0 - bare-os: 2.2.0 + bare-events: 2.2.2 + bare-os: 2.2.1 bare-path: 2.1.0 - streamx: 2.15.8 + streamx: 2.16.1 dev: false optional: true - /bare-os@2.2.0: - resolution: {integrity: sha512-hD0rOPfYWOMpVirTACt4/nK8mC55La12K5fY1ij8HAdfQakD62M+H4o4tpfKzVGLgRDTuk3vjA4GqGXXCeFbag==} + /bare-os@2.2.1: + resolution: {integrity: sha512-OwPyHgBBMkhC29Hl3O4/YfxW9n7mdTr2+SsO29XBWKKJsbgj3mnorDB80r5TiCQgQstgE5ga1qNYrpes6NvX2w==} requiresBuild: true dev: false optional: true @@ -3307,15 +3596,15 @@ packages: resolution: {integrity: sha512-DIIg7ts8bdRKwJRJrUMy/PICEaQZaPGZ26lsSx9MJSwIhSrcdHn7/C8W+XmnG/rKi6BaRcz+JO00CjZteybDtw==} requiresBuild: true dependencies: - bare-os: 2.2.0 + bare-os: 2.2.1 dev: false optional: true /base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} - /basic-ftp@5.0.4: - resolution: {integrity: sha512-8PzkB0arJFV4jJWSGOYR+OEic6aeKMu/osRhBULN6RY0ykby6LKhbmuQ5ublvaas5BOwboah5D87nrHyuh8PPA==} + /basic-ftp@5.0.5: + resolution: {integrity: sha512-4Bcg1P8xhUuqcii/S0Z9wiHIrQVPMermM1any+MX5GeGD7faD3/msQUDGLol9wOcz4/jbg/WJnGqoJF6LiBdtg==} engines: {node: '>=10.0.0'} dev: false @@ -3394,8 +3683,8 @@ packages: engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true dependencies: - caniuse-lite: 1.0.30001587 - electron-to-chromium: 1.4.669 + caniuse-lite: 1.0.30001600 + electron-to-chromium: 1.4.717 node-releases: 2.0.14 update-browserslist-db: 1.0.13(browserslist@4.23.0) dev: true @@ -3405,7 +3694,7 @@ packages: dev: false /buffer-equal-constant-time@1.0.1: - resolution: {integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==} + resolution: {integrity: sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=, tarball: https://registry.npmmirror.com/buffer-equal-constant-time/download/buffer-equal-constant-time-1.0.1.tgz} dev: false /buffer@5.7.1: @@ -3448,7 +3737,6 @@ packages: /cacheable-lookup@7.0.0: resolution: {integrity: sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w==} engines: {node: '>=14.16'} - dev: false /cacheable-request@10.2.14: resolution: {integrity: sha512-zkDT5WAF4hSSoUgyfg5tFIxz8XQK+25W/TLVojJTMKBaxevLBBtLxgqguAuVQB8PVW79FVjHcU+GJ9tVbDZ9mQ==} @@ -3459,9 +3747,8 @@ packages: http-cache-semantics: 4.1.1 keyv: 4.5.4 mimic-response: 4.0.0 - normalize-url: 8.0.0 + normalize-url: 8.0.1 responselike: 3.0.0 - dev: false /call-bind@1.0.7: resolution: {integrity: sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==} @@ -3471,7 +3758,7 @@ packages: es-errors: 1.3.0 function-bind: 1.1.2 get-intrinsic: 1.2.4 - set-function-length: 1.2.1 + set-function-length: 1.2.2 /callsites@3.1.0: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} @@ -3504,8 +3791,8 @@ packages: engines: {node: '>=10'} dev: false - /caniuse-lite@1.0.30001587: - resolution: {integrity: sha512-HMFNotUmLXn71BQxg8cijvqxnIAofforZOwGsxyXJ0qugTdspUF4sPSJ2vhgprHCB996tIDzEq1ubumPDV8ULA==} + /caniuse-lite@1.0.30001600: + resolution: {integrity: sha512-+2S9/2JFhYmYaDpZvo0lKkfvuKIglrx68MwOBqMGHhQsNkLjB5xtc/TGoEPs+MxjSyN/72qer2g97nzR641mOQ==} dev: true /caseless@0.12.0: @@ -3714,6 +4001,11 @@ packages: engines: {node: '>= 10'} dev: true + /cli-width@4.1.0: + resolution: {integrity: sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==} + engines: {node: '>= 12'} + dev: true + /clipboardy@1.2.2: resolution: {integrity: sha512-16KrBOV7bHmHdxcQiCvfUFYVFyEah4FI8vYT1Fr7CGSA4G+xBWMEfUEQJS1hxeHGtI9ju1Bzs9uXSbj5HZKArw==} engines: {node: '>=4'} @@ -3729,7 +4021,6 @@ packages: string-width: 4.2.3 strip-ansi: 6.0.1 wrap-ansi: 7.0.0 - dev: false /clone-deep@0.2.4: resolution: {integrity: sha512-we+NuQo2DHhSl+DP6jlUiAhyAjBQrYnpOk15rN6c6JSPScjiCLh8IbSU+VTcph6YS3o7mASE8a0+gbZ7ChLpgg==} @@ -3828,7 +4119,7 @@ packages: dev: true /concat-map@0.0.1: - resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + resolution: {integrity: sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=, tarball: https://registry.npmmirror.com/concat-map/download/concat-map-0.0.1.tgz} /config-chain@1.1.13: resolution: {integrity: sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==} @@ -3845,14 +4136,13 @@ packages: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} dev: true - /cookiejar@2.1.4: - resolution: {integrity: sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw==} + /cookie@0.5.0: + resolution: {integrity: sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==} + engines: {node: '>= 0.6'} dev: true - /core-js-compat@3.36.0: - resolution: {integrity: sha512-iV9Pd/PsgjNWBXeq8XRtWVSgz2tKAfhfvBs7qxYty+RlRd+OCksaWmOnc4JKrTc1cToXL1N0s3l/vwlxPtdElw==} - dependencies: - browserslist: 4.23.0 + /cookiejar@2.1.4: + resolution: {integrity: sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw==} dev: true /core-js-compat@3.36.1: @@ -3953,11 +4243,12 @@ packages: resolution: {integrity: sha512-LO/lzYRw134LMDVnLyAf1dHE5tyO6axEFkR3TXjQIOmMkAM9YL6QsiUwuXzZAmFnuDJcs4hayOgyIYtViXFrLw==} dev: false - /d@1.0.1: - resolution: {integrity: sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==} + /d@1.0.2: + resolution: {integrity: sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw==} + engines: {node: '>=0.12'} dependencies: es5-ext: 0.10.64 - type: 1.2.0 + type: 2.7.2 dev: false /dashdash@1.14.1: @@ -4042,7 +4333,6 @@ packages: engines: {node: '>=10'} dependencies: mimic-response: 3.1.0 - dev: false /deep-eql@4.1.3: resolution: {integrity: sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==} @@ -4068,7 +4358,6 @@ packages: /defer-to-connect@2.0.1: resolution: {integrity: sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==} engines: {node: '>=10'} - dev: false /define-data-property@1.1.4: resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} @@ -4105,8 +4394,12 @@ packages: engines: {node: '>=6'} dev: true - /detect-libc@2.0.2: - resolution: {integrity: sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==} + /destr@2.0.3: + resolution: {integrity: sha512-2N3BOUU4gYMpTP24s5rF5iP7BDr7uNTCs4ozw3kf/eKfvWSIu93GEBi5m427YoyJoeOzQ5smuu4nNAPGb8idSQ==} + dev: false + + /detect-libc@2.0.3: + resolution: {integrity: sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==} engines: {node: '>=8'} dev: true @@ -4270,8 +4563,8 @@ packages: semver: 7.6.0 dev: true - /electron-to-chromium@1.4.669: - resolution: {integrity: sha512-E2SmpffFPrZhBSgf8ibqanRS2mpuk3FIRDzLDwt7WFpfgJMKDHJs0hmacyP0PS1cWsq0dVkwIIzlscNaterkPg==} + /electron-to-chromium@1.4.717: + resolution: {integrity: sha512-6Fmg8QkkumNOwuZ/5mIbMU9WI3H2fmn5ajcVya64I5Yr5CcNmO7vcLt0Y7c96DCiMO5/9G+4sI2r6eEvdg1F7A==} dev: true /ellipsize@0.1.0: @@ -4342,7 +4635,7 @@ packages: requiresBuild: true dependencies: es6-iterator: 2.0.3 - es6-symbol: 3.1.3 + es6-symbol: 3.1.4 esniff: 2.0.1 next-tick: 1.1.0 dev: false @@ -4350,15 +4643,16 @@ packages: /es6-iterator@2.0.3: resolution: {integrity: sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==} dependencies: - d: 1.0.1 + d: 1.0.2 es5-ext: 0.10.64 - es6-symbol: 3.1.3 + es6-symbol: 3.1.4 dev: false - /es6-symbol@3.1.3: - resolution: {integrity: sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==} + /es6-symbol@3.1.4: + resolution: {integrity: sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg==} + engines: {node: '>=0.12'} dependencies: - d: 1.0.1 + d: 1.0.2 ext: 1.7.0 dev: false @@ -4391,6 +4685,38 @@ packages: '@esbuild/win32-arm64': 0.19.12 '@esbuild/win32-ia32': 0.19.12 '@esbuild/win32-x64': 0.19.12 + dev: false + + /esbuild@0.20.2: + resolution: {integrity: sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==} + engines: {node: '>=12'} + hasBin: true + requiresBuild: true + optionalDependencies: + '@esbuild/aix-ppc64': 0.20.2 + '@esbuild/android-arm': 0.20.2 + '@esbuild/android-arm64': 0.20.2 + '@esbuild/android-x64': 0.20.2 + '@esbuild/darwin-arm64': 0.20.2 + '@esbuild/darwin-x64': 0.20.2 + '@esbuild/freebsd-arm64': 0.20.2 + '@esbuild/freebsd-x64': 0.20.2 + '@esbuild/linux-arm': 0.20.2 + '@esbuild/linux-arm64': 0.20.2 + '@esbuild/linux-ia32': 0.20.2 + '@esbuild/linux-loong64': 0.20.2 + '@esbuild/linux-mips64el': 0.20.2 + '@esbuild/linux-ppc64': 0.20.2 + '@esbuild/linux-riscv64': 0.20.2 + '@esbuild/linux-s390x': 0.20.2 + '@esbuild/linux-x64': 0.20.2 + '@esbuild/netbsd-x64': 0.20.2 + '@esbuild/openbsd-x64': 0.20.2 + '@esbuild/sunos-x64': 0.20.2 + '@esbuild/win32-arm64': 0.20.2 + '@esbuild/win32-ia32': 0.20.2 + '@esbuild/win32-x64': 0.20.2 + dev: true /escalade@3.1.2: resolution: {integrity: sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==} @@ -4429,15 +4755,6 @@ packages: source-map: 0.6.1 dev: false - /eslint-compat-utils@0.1.2(eslint@8.57.0): - resolution: {integrity: sha512-Jia4JDldWnFNIru1Ehx1H5s9/yxiRHY/TimCuUc0jNexew3cF1gI6CYZil1ociakfWO3rRqFjl1mskBblB3RYg==} - engines: {node: '>=12'} - peerDependencies: - eslint: '>=6.0.0' - dependencies: - eslint: 8.57.0 - dev: true - /eslint-compat-utils@0.5.0(eslint@8.57.0): resolution: {integrity: sha512-dc6Y8tzEcSYZMHa+CMPLi/hyo1FzNeonbhJL7Ol0ccuKQkwopJcJBA9YL/xmMTLU1eKigXo9vj9nALElWYSowg==} engines: {node: '>=12'} @@ -4495,8 +4812,8 @@ packages: optionator: 0.9.3 dev: true - /eslint-plugin-es-x@7.5.0(eslint@8.57.0): - resolution: {integrity: sha512-ODswlDSO0HJDzXU0XvgZ3lF3lS3XAZEossh15Q2UHjwrJggWeBoKqqEsLTZLXl+dh5eOAozG0zRcYtuE35oTuQ==} + /eslint-plugin-es-x@7.6.0(eslint@8.57.0): + resolution: {integrity: sha512-I0AmeNgevgaTR7y2lrVCJmGYF0rjoznpDvqV/kIkZSZbZ8Rw3eu4cGlvBBULScfkSOCzqKbff5LR4CNrV7mZHA==} engines: {node: ^14.18.0 || >=16.0.0} peerDependencies: eslint: '>=8' @@ -4504,7 +4821,7 @@ packages: '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) '@eslint-community/regexpp': 4.10.0 eslint: 8.57.0 - eslint-compat-utils: 0.1.2(eslint@8.57.0) + eslint-compat-utils: 0.5.0(eslint@8.57.0) dev: true /eslint-plugin-n@16.6.2(eslint@8.57.0): @@ -4516,8 +4833,8 @@ packages: '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) builtins: 5.0.1 eslint: 8.57.0 - eslint-plugin-es-x: 7.5.0(eslint@8.57.0) - get-tsconfig: 4.7.2 + eslint-plugin-es-x: 7.6.0(eslint@8.57.0) + get-tsconfig: 4.7.3 globals: 13.24.0 ignore: 5.3.1 is-builtin-module: 3.2.1 @@ -4560,7 +4877,7 @@ packages: '@eslint/eslintrc': 2.1.4 ci-info: 4.0.0 clean-regexp: 1.0.0 - core-js-compat: 3.36.0 + core-js-compat: 3.36.1 eslint: 8.57.0 esquery: 1.5.0 indent-string: 4.0.0 @@ -4664,7 +4981,7 @@ packages: resolution: {integrity: sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==} engines: {node: '>=0.10'} dependencies: - d: 1.0.1 + d: 1.0.2 es5-ext: 0.10.64 event-emitter: 0.3.5 type: 2.7.2 @@ -4730,7 +5047,7 @@ packages: /event-emitter@0.3.5: resolution: {integrity: sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==} dependencies: - d: 1.0.1 + d: 1.0.2 es5-ext: 0.10.64 dev: false @@ -4770,7 +5087,7 @@ packages: human-signals: 5.0.0 is-stream: 3.0.0 merge-stream: 2.0.0 - npm-run-path: 5.2.0 + npm-run-path: 5.3.0 onetime: 6.0.0 signal-exit: 4.1.0 strip-final-newline: 3.0.0 @@ -4855,8 +5172,8 @@ packages: /fast-levenshtein@2.0.6: resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} - /fast-redact@3.3.0: - resolution: {integrity: sha512-6T5V1QK1u4oF+ATxs1lWUmlEk6P2T9HqJG3e2DnHOdVgZy2rFJBoEnrIedcTXlkAHU/zKC+7KETJ+KGGKwxgMQ==} + /fast-redact@3.5.0: + resolution: {integrity: sha512-dwsoQlS7h9hMeYUq1W++23NDcBLV4KqONnITDV9DjfS3q1SgDGVrBdvvTLUotWtPSD7asWDV9/CmsZPy8Hf70A==} engines: {node: '>=6'} dev: false @@ -4935,13 +5252,13 @@ packages: resolution: {integrity: sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==} engines: {node: ^10.12.0 || >=12.0.0} dependencies: - flatted: 3.2.9 + flatted: 3.3.1 keyv: 4.5.4 rimraf: 3.0.2 dev: true - /flatted@3.2.9: - resolution: {integrity: sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==} + /flatted@3.3.1: + resolution: {integrity: sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==} dev: true /fn.name@1.1.0: @@ -4985,7 +5302,7 @@ packages: /form-data-encoder@4.0.2: resolution: {integrity: sha512-KQVhvhK8ZkWzxKxOr56CPulAhH3dobtuQ4+hNQ+HekH/Wp5gSOafqRAeTphQUJAIk0GBvHZgJ2ZGRWd5kphMuw==} engines: {node: '>= 18'} - dev: false + dev: true /form-data@2.3.3: resolution: {integrity: sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==} @@ -5018,7 +5335,7 @@ packages: dezalgo: 1.0.4 hexoid: 1.0.0 once: 1.4.0 - qs: 6.11.2 + qs: 6.12.0 dev: true /fs-extra@10.1.0: @@ -5073,8 +5390,8 @@ packages: wide-align: 1.1.5 dev: true - /gaxios@6.2.0: - resolution: {integrity: sha512-H6+bHeoEAU5D6XNc6mPKeN5dLZqEDs9Gpk6I+SZBEzK5So58JVrHPmevNi35fRl1J9Y5TaeLW0kYx3pCJ1U2mQ==} + /gaxios@6.3.0: + resolution: {integrity: sha512-p+ggrQw3fBwH2F5N/PAI4k/G/y1art5OxKpb2J2chwNNHM4hHuAOtivjPuirMF4KNKwTTUal/lPfL2+7h2mEcg==} engines: {node: '>=14'} dependencies: extend: 3.0.2 @@ -5090,7 +5407,7 @@ packages: resolution: {integrity: sha512-Jh/AIwwgaxan+7ZUUmRLCjtchyDiqh4KjBJ5tW3plBZb5iL/BPcso8A5DlzeD9qlw0duCamnNdpFjxwaT0KyKg==} engines: {node: '>=14'} dependencies: - gaxios: 6.2.0 + gaxios: 6.3.0 json-bigint: 1.0.0 transitivePeerDependencies: - encoding @@ -5105,7 +5422,6 @@ packages: /get-caller-file@2.0.5: resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} engines: {node: 6.* || 8.* || >= 10.*} - dev: false /get-east-asian-width@1.2.0: resolution: {integrity: sha512-2nk+7SIVb14QrgXFHcm84tD4bKQz0RxPuMT8Ag5KPOq7J5fEmAg0UbXdTOSHqNuHSU28k55qnceesxXRZGzKWA==} @@ -5122,9 +5438,9 @@ packages: dependencies: es-errors: 1.3.0 function-bind: 1.1.2 - has-proto: 1.0.1 + has-proto: 1.0.3 has-symbols: 1.0.3 - hasown: 2.0.1 + hasown: 2.0.2 /get-stream@3.0.0: resolution: {integrity: sha512-GlhdIUuVakc8SJ6kK0zAFbiGzRFzNnY4jUuEbV9UROo4Y+0Ny4fjvcZFVTeDA4odpFyOQzaw6hXukJSq/f28sQ==} @@ -5141,14 +5457,14 @@ packages: /get-stream@6.0.1: resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} engines: {node: '>=10'} - dev: false /get-stream@8.0.1: resolution: {integrity: sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==} engines: {node: '>=16'} + dev: true - /get-tsconfig@4.7.2: - resolution: {integrity: sha512-wuMsz4leaj5hbGgg4IvDU0bqJagpftG5l5cXIAvo8uZrqn0NJqwtfupTN00VnkQJPcIRrxYrm1Ue24btpCha2A==} + /get-tsconfig@4.7.3: + resolution: {integrity: sha512-ZvkrzoUA0PQZM6fy6+/Hce561s+faD1rsNwhnO5FelNjyy7EMGJ3Rz1AQ8GYDWjhRs/7dBLOEJvhK8MiEJOAFg==} dependencies: resolve-pkg-maps: 1.0.0 @@ -5156,7 +5472,7 @@ packages: resolution: {integrity: sha512-BzUrJBS9EcUb4cFol8r4W3v1cPsSyajLSthNkz5BxbpDcHN5tIrM10E2eNvfnvBn3DaT3DUgx0OpsBKkaOpanw==} engines: {node: '>= 14'} dependencies: - basic-ftp: 5.0.4 + basic-ftp: 5.0.5 data-uri-to-buffer: 6.0.2 debug: 4.3.4 fs-extra: 11.2.0 @@ -5200,7 +5516,7 @@ packages: foreground-child: 3.1.1 jackspeak: 2.3.6 minimatch: 9.0.3 - minipass: 5.0.0 + minipass: 7.0.4 path-scurry: 1.10.1 dev: true @@ -5242,13 +5558,13 @@ packages: resolution: {integrity: sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==} dev: true - /google-auth-library@9.6.3: - resolution: {integrity: sha512-4CacM29MLC2eT9Cey5GDVK4Q8t+MMp8+OEdOaqD9MG6b0dOyLORaaeJMPQ7EESVgm/+z5EKYyFLxgzBJlJgyHQ==} + /google-auth-library@9.7.0: + resolution: {integrity: sha512-I/AvzBiUXDzLOy4iIZ2W+Zq33W4lcukQv1nl7C8WUA6SQwyQwUwu3waNmWNAvzds//FG8SZ+DnKnW/2k6mQS8A==} engines: {node: '>=14'} dependencies: base64-js: 1.5.1 ecdsa-sig-formatter: 1.0.11 - gaxios: 6.2.0 + gaxios: 6.3.0 gcp-metadata: 6.1.0 gtoken: 7.1.0 jws: 4.0.0 @@ -5257,14 +5573,14 @@ packages: - supports-color dev: false - /googleapis-common@7.0.1: - resolution: {integrity: sha512-mgt5zsd7zj5t5QXvDanjWguMdHAcJmmDrF9RkInCecNsyV7S7YtGqm5v2IWONNID88osb7zmx5FtrAP12JfD0w==} + /googleapis-common@7.1.0: + resolution: {integrity: sha512-p3KHiWDBBWJEXk6SYauBEvxw5+UmRy7k2scxGtsNv9eHsTbpopJ3/7If4OrNnzJ9XMLg3IlyQXpVp8YPQsStiw==} engines: {node: '>=14.0.0'} dependencies: extend: 3.0.2 - gaxios: 6.2.0 - google-auth-library: 9.6.3 - qs: 6.11.2 + gaxios: 6.3.0 + google-auth-library: 9.7.0 + qs: 6.12.0 url-template: 2.0.8 uuid: 9.0.1 transitivePeerDependencies: @@ -5276,8 +5592,8 @@ packages: resolution: {integrity: sha512-o8LhD1754W6MHWtpwAPeP1WUHgNxuMxCnLMDFlMKAA5kCMTNqX9/eaTXnkkAIv6YRfoKMQ6D1vyR6/biXuhE9g==} engines: {node: '>=14.0.0'} dependencies: - google-auth-library: 9.6.3 - googleapis-common: 7.0.1 + google-auth-library: 9.7.0 + googleapis-common: 7.1.0 transitivePeerDependencies: - encoding - supports-color @@ -5320,7 +5636,7 @@ packages: lowercase-keys: 3.0.0 p-cancelable: 4.0.1 responselike: 3.0.0 - dev: false + dev: true /graceful-fs@4.1.15: resolution: {integrity: sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==} @@ -5333,11 +5649,16 @@ packages: resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} dev: true + /graphql@16.8.1: + resolution: {integrity: sha512-59LZHPdGZVh695Ud9lRzPBVTtlX9ZCV150Er2W43ro37wVof0ctenSaskPPjN7lVTIN8mSZt8PHUNKZuNQUuxw==} + engines: {node: ^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0} + dev: true + /gtoken@7.1.0: resolution: {integrity: sha512-pCcEwRi+TKpMlxAQObHDQ56KawURgyAf6jtIY046fJ5tIv3zDe/LEIubckAO8fj6JnAxLdmWkUfNyulQ2iKdEw==} engines: {node: '>=14.0.0'} dependencies: - gaxios: 6.2.0 + gaxios: 6.3.0 jws: 4.0.0 transitivePeerDependencies: - encoding @@ -5384,8 +5705,8 @@ packages: dependencies: es-define-property: 1.0.0 - /has-proto@1.0.1: - resolution: {integrity: sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==} + /has-proto@1.0.3: + resolution: {integrity: sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==} engines: {node: '>= 0.4'} /has-symbols@1.0.3: @@ -5396,8 +5717,8 @@ packages: resolution: {integrity: sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==} dev: true - /hasown@2.0.1: - resolution: {integrity: sha512-1/th4MHjnwncwXsIW6QMzlvYL9kG5e/CpVvLRZe4XPa8TOUNbCELqmvhDmnkNsAjwaG4+I8gJJL0JBvTTLO9qA==} + /hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} engines: {node: '>= 0.4'} dependencies: function-bind: 1.1.2 @@ -5407,6 +5728,10 @@ packages: hasBin: true dev: false + /headers-polyfill@4.0.3: + resolution: {integrity: sha512-IScLbePpkvO846sIwOtOTDjutRMWdXdJmXdMvk6gCBHxFO8d+QKOQedyZSxFTTFYRSmlgSTDtXqqq4pcenBXLQ==} + dev: true + /heap@0.2.7: resolution: {integrity: sha512-2bsegYkkHO+h/9MGbn6KWcE45cHZgPANo5LXF7EvWdT0yT2EguSVO1nDgU5c8+ZOPwp2vMNa7YFsJhVcDR9Sdg==} dev: false @@ -5420,8 +5745,8 @@ packages: resolution: {integrity: sha512-4FP6J0oI8jqb6gLLl9tSwVdosWJ/AKSGJ+HwYf6Ixe4MUcEkst4uWzpVQrNOCin0fzTRQbXV8ePheU8WiiDYBw==} dev: false - /hono@4.1.4: - resolution: {integrity: sha512-JcdAKRBHjWO5OEkEW6Lv5NUr4QLl4InshCIUnHwGY7hymCxmV1Ji/eAAr1hclQixWc3I7ZljMHXwIedNWRAcqA==} + /hono@4.1.5: + resolution: {integrity: sha512-3ChJiIoeCxvkt6vnkxJagplrt1YZg3NyNob7ssVeK2PUqEINp4q1F94HzFnvY9QE8asVmbW5kkTDlyWylfg2vg==} engines: {node: '>=16.0.0'} dev: false @@ -5494,10 +5819,9 @@ packages: /http-cache-semantics@4.1.1: resolution: {integrity: sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==} - dev: false - /http-proxy-agent@7.0.1: - resolution: {integrity: sha512-My1KCEPs6A0hb4qCVzYp8iEvA8j8YqcvXLZZH8C9OFuTYpYjHE7N2dtG3mRl1HMD4+VGXpF3XcDVcxGBT7yDZQ==} + /http-proxy-agent@7.0.2: + resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==} engines: {node: '>= 14'} dependencies: agent-base: 7.1.0 @@ -5529,7 +5853,6 @@ packages: dependencies: quick-lru: 5.1.1 resolve-alpn: 1.2.1 - dev: false /https-proxy-agent@5.0.1: resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} @@ -5668,7 +5991,7 @@ packages: re2: optional: true dependencies: - '@lifeomic/attempt': 3.0.3 + '@lifeomic/attempt': 3.1.0 '@types/chance': 1.1.6 '@types/request-promise': 4.1.51 bluebird: 3.7.2 @@ -5754,7 +6077,7 @@ packages: /is-core-module@2.13.1: resolution: {integrity: sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==} dependencies: - hasown: 2.0.1 + hasown: 2.0.2 /is-extendable@0.1.1: resolution: {integrity: sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==} @@ -5799,6 +6122,10 @@ packages: engines: {node: '>=0.10.0'} dev: false + /is-node-process@1.2.0: + resolution: {integrity: sha512-Vg4o6/fqPxIjtxgUH5QLJhwZ7gW5diGCVlXpuUfELC62CuxM1iHcRe51f2W1FDy04Ai4KJkagKjx3XaqyfRKXw==} + dev: true + /is-number@7.0.0: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} engines: {node: '>=0.12.0'} @@ -5890,8 +6217,8 @@ packages: - supports-color dev: true - /istanbul-reports@3.1.6: - resolution: {integrity: sha512-TLgnMkKg3iTDsQ9PbPTdpfAK2DzjF9mqUG7RMgcQl8oFjad8ob4laGxv5XV5U9MAfx8D6tSJiUyuAwzLicaxlg==} + /istanbul-reports@3.1.7: + resolution: {integrity: sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==} engines: {node: '>=8'} dependencies: html-escaper: 2.0.2 @@ -5968,7 +6295,7 @@ packages: decimal.js: 10.4.3 form-data: 4.0.0 html-encoding-sniffer: 4.0.0 - http-proxy-agent: 7.0.1 + http-proxy-agent: 7.0.2 https-proxy-agent: 7.0.4 is-potential-custom-element-name: 1.0.1 nwsapi: 2.2.7 @@ -6031,6 +6358,7 @@ packages: /json-stringify-safe@5.0.1: resolution: {integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==} + dev: false /json5@2.2.3: resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} @@ -6312,7 +6640,7 @@ packages: resolution: {integrity: sha512-niTvB4gqvtof056rRIrTZvjNYE4rCUzO6X/X+kYjd7WFxXeJ0NwEFnRxX6ehkvv3jTwrXnNdtAak5XYZuIyPFw==} engines: {node: '>=18'} dependencies: - ansi-escapes: 6.2.0 + ansi-escapes: 6.2.1 cli-cursor: 4.0.0 slice-ansi: 7.1.0 strip-ansi: 7.1.0 @@ -6344,7 +6672,6 @@ packages: /lowercase-keys@3.0.0: resolution: {integrity: sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - dev: false /lru-cache@10.2.0: resolution: {integrity: sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==} @@ -6393,9 +6720,9 @@ packages: /magicast@0.3.3: resolution: {integrity: sha512-ZbrP1Qxnpoes8sz47AM0z08U+jW6TyRgZzcWy3Ma3vDhJttwMwAFDMMQFobwdBxByBD46JYmxRzeF7w2+wJEuw==} dependencies: - '@babel/parser': 7.23.9 - '@babel/types': 7.23.9 - source-map-js: 1.0.2 + '@babel/parser': 7.24.1 + '@babel/types': 7.24.0 + source-map-js: 1.2.0 dev: true /mailparser@3.6.9: @@ -6739,12 +7066,10 @@ packages: /mimic-response@3.1.0: resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==} engines: {node: '>=10'} - dev: false /mimic-response@4.0.0: resolution: {integrity: sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - dev: false /min-indent@1.0.1: resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==} @@ -6782,6 +7107,11 @@ packages: engines: {node: '>=8'} dev: true + /minipass@7.0.4: + resolution: {integrity: sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==} + engines: {node: '>=16 || 14 >=14.17'} + dev: true + /minizlib@2.1.2: resolution: {integrity: sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==} engines: {node: '>= 8'} @@ -6814,7 +7144,7 @@ packages: acorn: 8.11.3 pathe: 1.1.2 pkg-types: 1.0.3 - ufo: 1.4.0 + ufo: 1.5.3 dev: true /mockdate@3.0.5: @@ -6844,10 +7174,46 @@ packages: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} dev: false + /msw@2.2.13(typescript@5.4.3): + resolution: {integrity: sha512-ljFf1xZsU0b4zv1l7xzEmC6OZA6yD06hcx0H+dc8V0VypaP3HGYJa1rMLjQbBWl32ptGhcfwcPCWDB1wjmsftw==} + engines: {node: '>=18'} + hasBin: true + requiresBuild: true + peerDependencies: + typescript: '>= 4.7.x' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@bundled-es-modules/cookie': 2.0.0 + '@bundled-es-modules/statuses': 1.0.1 + '@inquirer/confirm': 3.1.0 + '@mswjs/cookies': 1.1.0 + '@mswjs/interceptors': 0.26.14 + '@open-draft/until': 2.1.0 + '@types/cookie': 0.6.0 + '@types/statuses': 2.0.5 + chalk: 4.1.2 + graphql: 16.8.1 + headers-polyfill: 4.0.3 + is-node-process: 1.2.0 + outvariant: 1.4.2 + path-to-regexp: 6.2.1 + strict-event-emitter: 0.5.1 + type-fest: 4.14.0 + typescript: 5.4.3 + yargs: 17.7.2 + dev: true + /mute-stream@0.0.8: resolution: {integrity: sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==} dev: true + /mute-stream@1.0.0: + resolution: {integrity: sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + dev: true + /nanoid@3.3.7: resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} @@ -6872,16 +7238,9 @@ packages: lower-case: 1.1.4 dev: false - /nock@13.5.4: - resolution: {integrity: sha512-yAyTfdeNJGGBFxWdzSKCBYxs5FxLbCg5X5Q4ets974hcQzG1+qCxvIyOo4j2Ry6MUlhWVMX4OoYDefAIIwupjw==} - engines: {node: '>= 10.13'} - dependencies: - debug: 4.3.4 - json-stringify-safe: 5.0.1 - propagate: 2.0.1 - transitivePeerDependencies: - - supports-color - dev: true + /node-fetch-native@1.6.4: + resolution: {integrity: sha512-IhOigYzAKHd244OC0JIMIUrjzctirCmPkaIfhDeGcEETWof5zKYUW7e7MYvChGWh/4CJeXEgsRyGzuF334rOOQ==} + dev: false /node-fetch@2.7.0: resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} @@ -6944,10 +7303,9 @@ packages: validate-npm-package-license: 3.0.4 dev: true - /normalize-url@8.0.0: - resolution: {integrity: sha512-uVFpKhj5MheNBJRTiMZ9pE/7hD1QTeEvugSJW/OmLzAp78PB5O6adfMNTvmfKhXBkvCzC+rqifWcVYpGFwTjnw==} + /normalize-url@8.0.1: + resolution: {integrity: sha512-IO9QvjUMWxPQQhs60oOu10CRkWCiZzSUkzbXGGV9pviYl1fXYcvkzQ5jV9z8Y6un8ARoVRl4EtC6v6jNqbaJ/w==} engines: {node: '>=14.16'} - dev: false /notion-to-md@3.1.1: resolution: {integrity: sha512-Zaa2P1B9Rx99bevFYTGuUMYbbfdHn2G1AZMsytYGDWIJjr6Ie1qp/8CorpwVUh1qrquES/V2PkEREqCuTu1zKA==} @@ -6966,8 +7324,8 @@ packages: path-key: 2.0.1 dev: false - /npm-run-path@5.2.0: - resolution: {integrity: sha512-W4/tgAXFqFA0iL7fk0+uQ3g7wkL8xJmx3XdK0VGb4cHW//eZTtKGvFBBoRKVTpY7n6ze4NL9ly7rgXcHufqXKg==} + /npm-run-path@5.3.0: + resolution: {integrity: sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} dependencies: path-key: 4.0.0 @@ -7013,6 +7371,14 @@ packages: /object-inspect@1.13.1: resolution: {integrity: sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==} + /ofetch@1.3.4: + resolution: {integrity: sha512-KLIET85ik3vhEfS+3fDlc/BAZiAp+43QEC/yCo5zkNoY2YaKvNkOaFr/6wCFgFH1kuYQM5pMNi0Tg8koiIemtw==} + dependencies: + destr: 2.0.3 + node-fetch-native: 1.6.4 + ufo: 1.5.3 + dev: false + /on-exit-leak-free@2.1.2: resolution: {integrity: sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==} engines: {node: '>=14.0.0'} @@ -7046,7 +7412,7 @@ packages: /openapi3-ts@4.2.2: resolution: {integrity: sha512-+9g4actZKeb3czfi9gVQ4Br2Ju3KwhCAQJBNaKgye5KggqcBLIhFHH+nIkcm0BUX00TrAJl6dH4JWgM4G4JWrw==} dependencies: - yaml: 2.3.4 + yaml: 2.4.1 dev: false /optionator@0.8.3: @@ -7101,6 +7467,10 @@ packages: '@otplib/preset-v11': 12.0.1 dev: false + /outvariant@1.4.2: + resolution: {integrity: sha512-Ou3dJ6bA/UJ5GVHxah4LnqDwZRwAmWxrG3wtrHrbGnP4RnLCtA64A4F+ae7Y8ww660JaddSoArUR5HjipWSHAQ==} + dev: true + /p-cancelable@3.0.0: resolution: {integrity: sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw==} engines: {node: '>=12.20'} @@ -7109,7 +7479,7 @@ packages: /p-cancelable@4.0.1: resolution: {integrity: sha512-wBowNApzd45EIKdO1LaU+LrMBwAcjfPaYtVzV3lmfM3gf8Z4CHZsiIqlM8TZZ8okYvh5A1cP6gTfCRQtwUpaUg==} engines: {node: '>=14.16'} - dev: false + dev: true /p-finally@1.0.0: resolution: {integrity: sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==} @@ -7164,7 +7534,7 @@ packages: agent-base: 7.1.0 debug: 4.3.4 get-uri: 6.0.3 - http-proxy-agent: 7.0.1 + http-proxy-agent: 7.0.2 https-proxy-agent: 7.0.4 pac-resolver: 7.0.1 socks-proxy-agent: 8.0.2 @@ -7263,7 +7633,11 @@ packages: engines: {node: '>=16 || 14 >=14.17'} dependencies: lru-cache: 10.2.0 - minipass: 5.0.0 + minipass: 7.0.4 + dev: true + + /path-to-regexp@6.2.1: + resolution: {integrity: sha512-JLyh7xT1kizaEvcaXOQwOc2/Yhw6KZOvPf1S8401UyLk86CU79LN3vl7ztXGm/pZ+YjoyAJ4rxmHwbkBXJX+yw==} dev: true /path-type@4.0.0: @@ -7326,7 +7700,7 @@ packages: hasBin: true dependencies: atomic-sleep: 1.0.0 - fast-redact: 3.3.0 + fast-redact: 3.5.0 on-exit-leak-free: 2.1.2 pino-abstract-transport: 1.1.0 pino-std-serializers: 6.2.2 @@ -7351,13 +7725,13 @@ packages: engines: {node: '>=4'} dev: true - /postcss@8.4.35: - resolution: {integrity: sha512-u5U8qYpBCpN13BsiEB0CbR1Hhh4Gc0zLFuedrHJKMctHCHAGrMdG0PRM/KErzAL3CU6/eckEtmHNB3x6e3c0vA==} + /postcss@8.4.38: + resolution: {integrity: sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==} engines: {node: ^10 || ^12 || >=14} dependencies: nanoid: 3.3.7 picocolors: 1.0.0 - source-map-js: 1.0.2 + source-map-js: 1.2.0 /postman-request@2.88.1-postman.33: resolution: {integrity: sha512-uL9sCML4gPH6Z4hreDWbeinKU0p0Ke261nU7OvII95NU22HN6Dk7T/SaVPaj6T4TsQqGKIFw6/woLZnH7ugFNA==} @@ -7433,11 +7807,6 @@ packages: engines: {node: '>=0.4.0'} dev: false - /propagate@2.0.1: - resolution: {integrity: sha512-vGrhOavPSTz4QVNuBNdcNXePNdNMaO1xj9yBeH1ScQPjk/rhg9sSlCXPhMkFuaNNW/syTvYqsnbIJxMBfRbbag==} - engines: {node: '>= 8'} - dev: true - /proto-list@1.2.4: resolution: {integrity: sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==} dev: true @@ -7448,7 +7817,7 @@ packages: dependencies: agent-base: 7.1.0 debug: 4.3.4 - http-proxy-agent: 7.0.1 + http-proxy-agent: 7.0.2 https-proxy-agent: 7.0.4 lru-cache: 7.18.3 pac-proxy-agent: 7.0.1 @@ -7629,11 +7998,11 @@ packages: - utf-8-validate dev: false - /qs@6.11.2: - resolution: {integrity: sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA==} + /qs@6.12.0: + resolution: {integrity: sha512-trVZiI6RMOkO476zLGaBIzszOdFPnCCXHPG9kn0yuS1uz6xdVxPfZdB3vUig9pxPFDM9BRAgz/YUIVQ1/vuiUg==} engines: {node: '>=0.6'} dependencies: - side-channel: 1.0.5 + side-channel: 1.0.6 /qs@6.5.3: resolution: {integrity: sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==} @@ -7678,7 +8047,6 @@ packages: /quick-lru@5.1.1: resolution: {integrity: sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==} engines: {node: '>=10'} - dev: false /re2js@0.4.1: resolution: {integrity: sha512-Kxb+OKXrEPowP4bXAF07NDXtgYX07S8HeVGgadx5/D/R41LzWg1kgTD2szIv2iHJM3vrAPnDKaBzfUE/7QWX9w==} @@ -7775,7 +8143,7 @@ packages: /regenerator-transform@0.15.2: resolution: {integrity: sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==} dependencies: - '@babel/runtime': 7.24.0 + '@babel/runtime': 7.24.1 dev: true /regexp-tree@0.1.27: @@ -7831,7 +8199,7 @@ packages: dev: false /request-promise-core@1.1.4(request@2.88.2): - resolution: {integrity: sha512-TTbAfBBRdWD7aNNOoVOBH4pN/KigV6LyapYNNlAPA8JwbovRti1E88m3sYAwsLi5ryhPKsE9APwnjFTgdUjTpw==} + resolution: {integrity: sha1-Pu3UIjII1BmGe3jOgVFn0QWToi8=, tarball: https://registry.npmmirror.com/request-promise-core/download/request-promise-core-1.1.4.tgz} engines: {node: '>=0.10.0'} peerDependencies: request: ^2.34 @@ -7884,14 +8252,12 @@ packages: /require-directory@2.1.1: resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} engines: {node: '>=0.10.0'} - dev: false /requires-port@1.0.0: resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==} /resolve-alpn@1.2.1: resolution: {integrity: sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==} - dev: false /resolve-from@4.0.0: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} @@ -7918,7 +8284,6 @@ packages: engines: {node: '>=14.16'} dependencies: lowercase-keys: 3.0.0 - dev: false /restore-cursor@3.1.0: resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==} @@ -7955,26 +8320,26 @@ packages: dependencies: glob: 7.2.3 - /rollup@4.12.0: - resolution: {integrity: sha512-wz66wn4t1OHIJw3+XU7mJJQV/2NAfw5OAk6G6Hoo3zcvz/XOfQ52Vgi+AN4Uxoxi0KBBwk2g8zPrTDA4btSB/Q==} + /rollup@4.13.0: + resolution: {integrity: sha512-3YegKemjoQnYKmsBlOHfMLVPPA5xLkQ8MHLLSw/fBrFaVkEayL51DilPpNNLq1exr98F2B1TzrV0FUlN3gWRPg==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true dependencies: '@types/estree': 1.0.5 optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.12.0 - '@rollup/rollup-android-arm64': 4.12.0 - '@rollup/rollup-darwin-arm64': 4.12.0 - '@rollup/rollup-darwin-x64': 4.12.0 - '@rollup/rollup-linux-arm-gnueabihf': 4.12.0 - '@rollup/rollup-linux-arm64-gnu': 4.12.0 - '@rollup/rollup-linux-arm64-musl': 4.12.0 - '@rollup/rollup-linux-riscv64-gnu': 4.12.0 - '@rollup/rollup-linux-x64-gnu': 4.12.0 - '@rollup/rollup-linux-x64-musl': 4.12.0 - '@rollup/rollup-win32-arm64-msvc': 4.12.0 - '@rollup/rollup-win32-ia32-msvc': 4.12.0 - '@rollup/rollup-win32-x64-msvc': 4.12.0 + '@rollup/rollup-android-arm-eabi': 4.13.0 + '@rollup/rollup-android-arm64': 4.13.0 + '@rollup/rollup-darwin-arm64': 4.13.0 + '@rollup/rollup-darwin-x64': 4.13.0 + '@rollup/rollup-linux-arm-gnueabihf': 4.13.0 + '@rollup/rollup-linux-arm64-gnu': 4.13.0 + '@rollup/rollup-linux-arm64-musl': 4.13.0 + '@rollup/rollup-linux-riscv64-gnu': 4.13.0 + '@rollup/rollup-linux-x64-gnu': 4.13.0 + '@rollup/rollup-linux-x64-musl': 4.13.0 + '@rollup/rollup-win32-arm64-msvc': 4.13.0 + '@rollup/rollup-win32-ia32-msvc': 4.13.0 + '@rollup/rollup-win32-x64-msvc': 4.13.0 fsevents: 2.3.3 dev: true @@ -7993,6 +8358,11 @@ packages: engines: {node: '>=0.12.0'} dev: true + /run-async@3.0.0: + resolution: {integrity: sha512-540WwVDOMxA6dN6We19EcT9sc3hkXPw5mzRNGM3FkdN/vtE9NFvj5lFAPNwUDmJjXidm3v7TC1cTE7t17Ulm1Q==} + engines: {node: '>=0.12.0'} + dev: true + /run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} dependencies: @@ -8031,7 +8401,7 @@ packages: htmlparser2: 8.0.2 is-plain-object: 5.0.0 parse-srcset: 1.0.2 - postcss: 8.4.35 + postcss: 8.4.38 dev: false /sax@1.3.0: @@ -8071,8 +8441,8 @@ packages: resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} dev: true - /set-function-length@1.2.1: - resolution: {integrity: sha512-j4t6ccc+VsKwYHso+kElc5neZpjtq9EnRICFZtWyBsLojhmeF/ZBd/elqm22WJh/BziDe/SBiOeAt0m2mfLD0g==} + /set-function-length@1.2.2: + resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} engines: {node: '>= 0.4'} dependencies: define-data-property: 1.1.4 @@ -8124,8 +8494,8 @@ packages: rechoir: 0.6.2 dev: false - /side-channel@1.0.5: - resolution: {integrity: sha512-QcgiIWV4WV7qWExbN5llt6frQB/lBven9pqliLXfGPB+K9ZYXxDozp0wLkHS24kWCm+6YXH/f0HhnObZnZOBnQ==} + /side-channel@1.0.6: + resolution: {integrity: sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==} engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.7 @@ -8199,20 +8569,11 @@ packages: dependencies: agent-base: 7.1.0 debug: 4.3.4 - socks: 2.7.3 + socks: 2.8.1 transitivePeerDependencies: - supports-color dev: false - /socks@2.7.3: - resolution: {integrity: sha512-vfuYK48HXCTFD03G/1/zkIls3Ebr2YNa4qU9gHDZdblHLiqhJrJGkY3+0Nx0JpN9qBhJbVObc1CNciT1bIZJxw==} - engines: {node: '>= 10.0.0', npm: '>= 3.0.0'} - deprecated: please use 2.7.4 or 2.8.1 to fix package-lock issue - dependencies: - ip-address: 9.0.5 - smart-buffer: 4.2.0 - dev: false - /socks@2.8.1: resolution: {integrity: sha512-B6w7tkwNid7ToxjZ08rQMT8M9BJAf8DKx8Ft4NivzH0zBUfd6jldGcisJn/RLgxcX3FPNDdNQCUEMMT79b+oCQ==} engines: {node: '>= 10.0.0', npm: '>= 3.0.0'} @@ -8227,8 +8588,8 @@ packages: atomic-sleep: 1.0.0 dev: false - /source-map-js@1.0.2: - resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==} + /source-map-js@1.2.0: + resolution: {integrity: sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==} engines: {node: '>=0.10.0'} /source-map@0.5.7: @@ -8253,14 +8614,14 @@ packages: spdx-license-ids: 3.0.17 dev: true - /spdx-exceptions@2.4.0: - resolution: {integrity: sha512-hcjppoJ68fhxA/cjbN4T8N6uCUejN8yFw69ttpqtBeCbF3u13n7mb31NB9jKwGTTWWnt9IbRA/mf1FprYS8wfw==} + /spdx-exceptions@2.5.0: + resolution: {integrity: sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==} dev: true /spdx-expression-parse@3.0.1: resolution: {integrity: sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==} dependencies: - spdx-exceptions: 2.4.0 + spdx-exceptions: 2.5.0 spdx-license-ids: 3.0.17 dev: true @@ -8315,6 +8676,11 @@ packages: resolution: {integrity: sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==} dev: false + /statuses@2.0.1: + resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} + engines: {node: '>= 0.8'} + dev: true + /std-env@3.7.0: resolution: {integrity: sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg==} dev: true @@ -8334,15 +8700,19 @@ packages: bluebird: 2.11.0 dev: false - /streamx@2.15.8: - resolution: {integrity: sha512-6pwMeMY/SuISiRsuS8TeIrAzyFbG5gGPHFQsYjUr/pbBadaL1PCWmzKw+CHZSwainfvcF6Si6cVLq4XTEwswFQ==} + /streamx@2.16.1: + resolution: {integrity: sha512-m9QYj6WygWyWa3H1YY69amr4nVgy61xfjys7xO7kviL5rfIEc2naf+ewFiOA+aEJD7y0JO3h2GoiUv4TDwEGzQ==} dependencies: fast-fifo: 1.3.2 queue-tick: 1.0.1 optionalDependencies: - bare-events: 2.2.0 + bare-events: 2.2.2 dev: false + /strict-event-emitter@0.5.1: + resolution: {integrity: sha512-vMgjE/GGEPEFnhFub6pa4FmJBRBVOLpIII2hvCZ8Kzb7K0hlHo7mQv6xYrBvCL2LtAIBwFUK8wvuJgTVSQ5MFQ==} + dev: true + /strict-uri-encode@2.0.0: resolution: {integrity: sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ==} engines: {node: '>=4'} @@ -8455,7 +8825,7 @@ packages: formidable: 2.1.2 methods: 1.1.2 mime: 2.6.0 - qs: 6.11.2 + qs: 6.12.0 semver: 7.6.0 transitivePeerDependencies: - supports-color @@ -8526,11 +8896,11 @@ packages: dependencies: b4a: 1.6.6 fast-fifo: 1.3.2 - streamx: 2.15.8 + streamx: 2.16.1 dev: false - /tar@6.2.0: - resolution: {integrity: sha512-/Wo7DcT0u5HUV486xg675HtjNd3BXZ6xDbzsCUZPt5iw8bTQ63bP0Raut3mvro9u+CUyq7YQd8Cx55fsZXxqLQ==} + /tar@6.2.1: + resolution: {integrity: sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==} engines: {node: '>=10'} dependencies: chownr: 2.0.0 @@ -8604,8 +8974,8 @@ packages: resolution: {integrity: sha512-N8hW3PG/3aOoZAN5V/NSAEDz0ZixDSSt5b/a05iqtpgfLWMSVuCo7w0k2vVvEjdrIoeGqZzweX2WlyioNIHchA==} dev: true - /tinypool@0.8.2: - resolution: {integrity: sha512-SUszKYe5wgsxnNOVlBYO6IC+8VGWdVGZWAqUxp3UErNBtptZvWbwyUOyzNL59zigz2rCA92QiL3wvG+JDSdJdQ==} + /tinypool@0.8.3: + resolution: {integrity: sha512-Ud7uepAklqRH1bvwy22ynrliC7Dljz7Tm8M/0RBUW+YRa4YHhZ6e4PpgE+fu1zr/WqB1kbeuVrdfeuyIBpy4tw==} engines: {node: '>=14.0.0'} dev: true @@ -8634,15 +9004,20 @@ packages: hasBin: true dev: false - /tldts-core@6.1.15: - resolution: {integrity: sha512-E/gy+y6I53cZcqbHllhS5Aak6DmMZSO9tX6DYw3NXZk+f1yoFKGLiojQ8ww39G5QAupKKZL+vehNVqzSS0SQgQ==} + /tlds@1.251.0: + resolution: {integrity: sha512-yztVk5O1LGKCjPd+7soBQyiKvSBXI5qugc/X0C7pLa0rV5ufBS6xcyX0pdf4NznO8xcZ5fqX248q+jTHd4AQJA==} + hasBin: true + dev: false + + /tldts-core@6.1.16: + resolution: {integrity: sha512-rxnuCux+zn3hMF57nBzr1m1qGZH7Od2ErbDZjVm04fk76cEynTg3zqvHjx5BsBl8lvRTjpzIhsEGMHDH/Hr2Vw==} dev: false - /tldts@6.1.15: - resolution: {integrity: sha512-0/2FOdXnP5ON6PTQfE7B4X1ymqa1Bs6oG/yHKtVMxLSlUPlb/1AdWGzz2Co3P/uM0eUPWOt61L7cayyyNUSh7A==} + /tldts@6.1.16: + resolution: {integrity: sha512-X6VrQzW4RymhI1kBRvrWzYlRLXTftZpi7/s/9ZlDILA04yM2lNX7mBvkzDib9L4uSymHt8mBbeaielZMdsAkfQ==} hasBin: true dependencies: - tldts-core: 6.1.15 + tldts-core: 6.1.16 dev: false /tmp@0.0.33: @@ -8720,8 +9095,8 @@ packages: resolution: {integrity: sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==} dev: true - /ts-api-utils@1.2.1(typescript@5.4.3): - resolution: {integrity: sha512-RIYA36cJn2WiH9Hy77hdF9r7oEwxAtB/TS9/S4Qd90Ap4z5FSiin5zEiTL44OII1Y3IIlEvxwxFUVgrHSZ/UpA==} + /ts-api-utils@1.3.0(typescript@5.4.3): + resolution: {integrity: sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==} engines: {node: '>=16'} peerDependencies: typescript: '>=4.2.0' @@ -8770,7 +9145,7 @@ packages: hasBin: true dependencies: esbuild: 0.19.12 - get-tsconfig: 4.7.2 + get-tsconfig: 4.7.3 optionalDependencies: fsevents: 2.3.3 dev: false @@ -8781,8 +9156,8 @@ packages: safe-buffer: 5.2.1 dev: false - /turndown@7.1.2: - resolution: {integrity: sha512-ntI9R7fcUKjqBP6QU8rBK2Ehyt8LAzt3UBT9JR9tgo6GtuKvyUzpayWmeMKJw1DPdXzktvtIT8m2mVXz+bL/Qg==} + /turndown@7.1.3: + resolution: {integrity: sha512-Z3/iJ6IWh8VBiACWQJaA5ulPQE5E1QwvBHj00uGzdQxdRnd8fh1DPqNOJqzQDu6DkOstORrtXzf/9adB+vMtEA==} dependencies: domino: 2.1.6 dev: false @@ -8839,15 +9214,11 @@ packages: engines: {node: '>=10'} dev: false - /type-fest@3.13.1: - resolution: {integrity: sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g==} - engines: {node: '>=14.16'} + /type-fest@4.14.0: + resolution: {integrity: sha512-on5/Cw89wwqGZQu+yWO0gGMGu8VNxsaW9SB2HE8yJjllEk7IDTwnSN1dUVldYILhYPN5HzD7WAaw2cc/jBfn0Q==} + engines: {node: '>=16'} dev: true - /type@1.2.0: - resolution: {integrity: sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==} - dev: false - /type@2.7.2: resolution: {integrity: sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==} dev: false @@ -8867,9 +9238,8 @@ packages: resolution: {integrity: sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==} dev: false - /ufo@1.4.0: - resolution: {integrity: sha512-Hhy+BhRBleFjpJ2vchUNN40qgkh0366FWJGqVLYBHev0vpHTrXSA0ryT+74UiW6KWsldNurQMKGqCm1M2zBciQ==} - dev: true + /ufo@1.5.3: + resolution: {integrity: sha512-Y7HYmWaFwPUmkoQCUIAYpKqkOf+SbVj/2fJJZ4RJMCfZp0rTGwRbzQD+HghfnhKOjL9E01okqz+ncJskGYfBNw==} /uglify-js@3.4.10: resolution: {integrity: sha512-Y2VsbPVs0FIshJztycsO2SfPk7/KAF/T72qzv9u5EpQ4kB2hQoHlhNQTsNyy6ul7lQtqJN/AoWeS23OzEiEFxw==} @@ -8890,6 +9260,11 @@ packages: /undici-types@5.26.5: resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} + /undici@6.10.2: + resolution: {integrity: sha512-HcVuBy7ACaDejIMdwCzAvO22OsiE6ir6ziTIr9kAE0vB+PheVe29ZvRN8p7FXCO2uZHTjEoUs5bPiFpuc/hwwQ==} + engines: {node: '>=18.0'} + dev: false + /unicode-canonical-property-names-ecmascript@2.0.0: resolution: {integrity: sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==} engines: {node: '>=4'} @@ -8975,7 +9350,7 @@ packages: optional: true dependencies: ip-regex: 4.3.0 - tlds: 1.250.0 + tlds: 1.251.0 dev: false /url-template@2.0.8: @@ -9026,7 +9401,7 @@ packages: resolution: {integrity: sha512-/EH/sDgxU2eGxajKdwLCDmQ4FWq+kpi3uCmBGpw1xJtnAxEjlD8j8PEiGWpCIMIs3ciNAgH0d3TTJiUkYzyZjA==} engines: {node: '>=10.12.0'} dependencies: - '@jridgewell/trace-mapping': 0.3.22 + '@jridgewell/trace-mapping': 0.3.25 '@types/istanbul-lib-coverage': 2.0.6 convert-source-map: 2.0.0 dev: true @@ -9075,7 +9450,7 @@ packages: debug: 4.3.4 pathe: 1.1.2 picocolors: 1.0.0 - vite: 5.1.5(@types/node@20.11.30) + vite: 5.2.6(@types/node@20.11.30) transitivePeerDependencies: - '@types/node' - less @@ -9103,8 +9478,8 @@ packages: - typescript dev: true - /vite@5.1.5(@types/node@20.11.30): - resolution: {integrity: sha512-BdN1xh0Of/oQafhU+FvopafUp6WaYenLU/NFoL5WyJL++GxkNfieKzBhM24H3HVsPQrlAqB7iJYTHabzaRed5Q==} + /vite@5.2.6(@types/node@20.11.30): + resolution: {integrity: sha512-FPtnxFlSIKYjZ2eosBQamz4CbyrTizbZ3hnGJlh/wMtCrlp1Hah6AzBLjGI5I2urTfNnpovpHdrL6YRuBOPnCA==} engines: {node: ^18.0.0 || >=20.0.0} hasBin: true peerDependencies: @@ -9132,9 +9507,9 @@ packages: optional: true dependencies: '@types/node': 20.11.30 - esbuild: 0.19.12 - postcss: 8.4.35 - rollup: 4.12.0 + esbuild: 0.20.2 + postcss: 8.4.38 + rollup: 4.13.0 optionalDependencies: fsevents: 2.3.3 dev: true @@ -9182,8 +9557,8 @@ packages: std-env: 3.7.0 strip-literal: 2.0.0 tinybench: 2.6.0 - tinypool: 0.8.2 - vite: 5.1.5(@types/node@20.11.30) + tinypool: 0.8.3 + vite: 5.2.6(@types/node@20.11.30) vite-node: 1.4.0(@types/node@20.11.30) why-is-node-running: 2.2.2 transitivePeerDependencies: @@ -9403,7 +9778,6 @@ packages: /y18n@5.0.8: resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} engines: {node: '>=10'} - dev: false /yaeti@0.0.6: resolution: {integrity: sha512-MvQa//+KcZCUkBTIC9blM+CU9J2GzuTytsOUwf2lidtvkx/6gnEp1QvJv34t9vdjhFmha/mUiNDbN0D0mJWdug==} @@ -9427,12 +9801,18 @@ packages: dependencies: eslint-visitor-keys: 3.4.3 lodash: 4.17.21 - yaml: 2.3.4 + yaml: 2.4.1 dev: true /yaml@2.3.4: resolution: {integrity: sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA==} engines: {node: '>= 14'} + dev: true + + /yaml@2.4.1: + resolution: {integrity: sha512-pIXzoImaqmfOrL7teGUBt/T7ZDnyeGBWyXQBvOVhLkWLN37GXv8NMLK406UY6dS51JfcQHsmcW5cJ441bHg6Lg==} + engines: {node: '>= 14'} + hasBin: true /yargs-parser@15.0.3: resolution: {integrity: sha512-/MVEVjTXy/cGAjdtQf8dW3V9b97bPN7rNn8ETj6BmAQL7ibC7O1Q9SPJbGjgh3SlwoBNXMzj/ZGIj8mBgl12YA==} @@ -9444,7 +9824,6 @@ packages: /yargs-parser@21.1.1: resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} engines: {node: '>=12'} - dev: false /yargs@17.7.2: resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} @@ -9457,7 +9836,6 @@ packages: string-width: 4.2.3 y18n: 5.0.8 yargs-parser: 21.1.1 - dev: false /yauzl@2.10.0: resolution: {integrity: sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==} diff --git a/tsconfig.json b/tsconfig.json index 20bc583435996f..5ce6ad95848773 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -2,7 +2,7 @@ "compilerOptions": { "target": "ESNext", "module": "ESNext", - "moduleResolution": "node", + "moduleResolution": "bundler", "strict": true, "jsx": "react-jsx", "jsxImportSource": "hono/jsx", diff --git a/vitest.config.ts b/vitest.config.ts index 2a4074bea752d0..fa395d2b2b78ae 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -1,4 +1,4 @@ -import { defineConfig } from 'vitest/config'; +import { defineConfig, configDefaults } from 'vitest/config'; import tsconfigPaths from 'vite-tsconfig-paths'; export default defineConfig({ @@ -10,5 +10,7 @@ export default defineConfig({ exclude: ['lib/routes/**', 'lib/routes-deprecated/**'], }, testTimeout: 10000, + setupFiles: ['./lib/setup.test.ts'], + exclude: [...configDefaults.exclude, './lib/setup.test.ts'], }, });