@jackwener/opencli 1.3.3 → 1.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/actions/setup-chrome/action.yml +5 -4
- package/.github/pull_request_template.md +3 -1
- package/.github/workflows/build-extension.yml +7 -1
- package/.github/workflows/ci.yml +46 -6
- package/.github/workflows/docs.yml +1 -1
- package/.github/workflows/e2e-headed.yml +36 -3
- package/.github/workflows/release.yml +1 -1
- package/.github/workflows/security.yml +0 -3
- package/CHANGELOG.md +78 -0
- package/CONTRIBUTING.md +6 -3
- package/PRIVACY.md +57 -0
- package/README.md +31 -4
- package/README.zh-CN.md +31 -4
- package/SKILL.md +107 -2
- package/TESTING.md +1 -0
- package/chatwise-opencli.ps1 +82 -0
- package/dist/analysis.d.ts +38 -0
- package/dist/analysis.js +166 -0
- package/dist/browser/cdp.d.ts +0 -4
- package/dist/browser/cdp.js +53 -41
- package/dist/browser/cdp.test.d.ts +1 -0
- package/dist/browser/cdp.test.js +52 -0
- package/dist/browser/dom-snapshot.d.ts +2 -2
- package/dist/browser/dom-snapshot.js +54 -1
- package/dist/browser/dom-snapshot.test.js +36 -0
- package/dist/browser/index.d.ts +2 -2
- package/dist/browser/index.js +1 -1
- package/dist/browser/mcp.d.ts +0 -2
- package/dist/browser/mcp.js +2 -3
- package/dist/browser/page.d.ts +4 -3
- package/dist/browser/page.js +34 -37
- package/dist/browser/stealth.d.ts +0 -2
- package/dist/browser/stealth.js +24 -9
- package/dist/browser.test.js +2 -2
- package/dist/build-manifest.js +15 -9
- package/dist/build-manifest.test.js +12 -0
- package/dist/cascade.js +4 -2
- package/dist/cli-manifest.json +1325 -256
- package/dist/cli.js +57 -29
- package/dist/clis/_shared/desktop-commands.d.ts +22 -0
- package/dist/clis/_shared/desktop-commands.js +108 -0
- package/dist/clis/antigravity/serve.js +5 -2
- package/dist/clis/apple-podcasts/search.js +2 -1
- package/dist/clis/arxiv/search.js +3 -3
- package/dist/clis/bbc/news.js +0 -1
- package/dist/clis/bilibili/dynamic.test.d.ts +1 -0
- package/dist/clis/bilibili/dynamic.test.js +68 -0
- package/dist/clis/bilibili/favorite.js +4 -2
- package/dist/clis/bilibili/following.js +3 -2
- package/dist/clis/bilibili/subtitle.js +8 -7
- package/dist/clis/bilibili/utils.js +2 -2
- package/dist/clis/boss/batchgreet.js +1 -1
- package/dist/clis/boss/chatlist.js +1 -1
- package/dist/clis/boss/chatmsg.js +1 -1
- package/dist/clis/boss/detail.js +1 -1
- package/dist/clis/boss/exchange.js +1 -1
- package/dist/clis/boss/greet.js +1 -1
- package/dist/clis/boss/invite.js +1 -1
- package/dist/clis/boss/joblist.js +1 -1
- package/dist/clis/boss/mark.js +4 -3
- package/dist/clis/boss/recommend.js +1 -1
- package/dist/clis/boss/resume.js +1 -1
- package/dist/clis/boss/search.js +1 -1
- package/dist/clis/boss/send.js +5 -4
- package/dist/clis/boss/stats.js +1 -1
- package/dist/clis/chatgpt/ask.js +4 -0
- package/dist/clis/chatgpt/new.js +5 -1
- package/dist/clis/chatgpt/read.js +5 -1
- package/dist/clis/chatgpt/send.js +2 -1
- package/dist/clis/chatgpt/status.js +5 -1
- package/dist/clis/chatwise/ask.js +8 -2
- package/dist/clis/chatwise/export.js +2 -0
- package/dist/clis/chatwise/history.js +2 -0
- package/dist/clis/chatwise/model.js +8 -3
- package/dist/clis/chatwise/new.js +3 -18
- package/dist/clis/chatwise/read.js +2 -0
- package/dist/clis/chatwise/screenshot.js +3 -27
- package/dist/clis/chatwise/send.js +8 -2
- package/dist/clis/chatwise/shared.d.ts +2 -0
- package/dist/clis/chatwise/shared.js +6 -0
- package/dist/clis/chatwise/status.js +3 -22
- package/dist/clis/codex/ask.js +6 -2
- package/dist/clis/codex/dump.js +2 -25
- package/dist/clis/codex/new.js +2 -25
- package/dist/clis/codex/screenshot.js +2 -27
- package/dist/clis/codex/send.js +6 -4
- package/dist/clis/codex/status.js +2 -22
- package/dist/clis/ctrip/search.js +0 -1
- package/dist/clis/cursor/ask.js +2 -1
- package/dist/clis/cursor/composer.js +2 -1
- package/dist/clis/cursor/dump.js +2 -25
- package/dist/clis/cursor/new.js +2 -18
- package/dist/clis/cursor/read.js +2 -1
- package/dist/clis/cursor/screenshot.js +1 -30
- package/dist/clis/cursor/send.js +2 -1
- package/dist/clis/cursor/status.js +2 -21
- package/dist/clis/dictionary/examples.yaml +25 -0
- package/dist/clis/dictionary/search.yaml +27 -0
- package/dist/clis/dictionary/synonyms.yaml +25 -0
- package/dist/clis/douban/book-hot.js +1 -1
- package/dist/clis/douban/movie-hot.js +1 -1
- package/dist/clis/douban/search.js +1 -1
- package/dist/clis/douban/utils.d.ts +4 -1
- package/dist/clis/douban/utils.js +156 -1
- package/dist/clis/doubao/ask.js +1 -1
- package/dist/clis/doubao/new.js +1 -1
- package/dist/clis/doubao/read.js +1 -1
- package/dist/clis/doubao/send.js +1 -1
- package/dist/clis/doubao/status.js +1 -1
- package/dist/clis/doubao-app/ask.js +1 -1
- package/dist/clis/doubao-app/new.js +1 -1
- package/dist/clis/doubao-app/read.js +1 -1
- package/dist/clis/doubao-app/send.js +1 -1
- package/dist/clis/douyin/_shared/browser-fetch.d.ts +10 -0
- package/dist/clis/douyin/_shared/browser-fetch.js +30 -0
- package/dist/clis/douyin/_shared/browser-fetch.test.d.ts +1 -0
- package/dist/clis/douyin/_shared/browser-fetch.test.js +31 -0
- package/dist/clis/douyin/_shared/creation-id.d.ts +1 -0
- package/dist/clis/douyin/_shared/creation-id.js +5 -0
- package/dist/clis/douyin/_shared/creation-id.test.d.ts +1 -0
- package/dist/clis/douyin/_shared/creation-id.test.js +22 -0
- package/dist/clis/douyin/_shared/imagex-upload.d.ts +20 -0
- package/dist/clis/douyin/_shared/imagex-upload.js +53 -0
- package/dist/clis/douyin/_shared/imagex-upload.test.d.ts +1 -0
- package/dist/clis/douyin/_shared/imagex-upload.test.js +87 -0
- package/dist/clis/douyin/_shared/sts2.d.ts +8 -0
- package/dist/clis/douyin/_shared/sts2.js +15 -0
- package/dist/clis/douyin/_shared/text-extra.d.ts +18 -0
- package/dist/clis/douyin/_shared/text-extra.js +15 -0
- package/dist/clis/douyin/_shared/text-extra.test.d.ts +1 -0
- package/dist/clis/douyin/_shared/text-extra.test.js +37 -0
- package/dist/clis/douyin/_shared/timing.d.ts +2 -0
- package/dist/clis/douyin/_shared/timing.js +22 -0
- package/dist/clis/douyin/_shared/timing.test.d.ts +1 -0
- package/dist/clis/douyin/_shared/timing.test.js +28 -0
- package/dist/clis/douyin/_shared/tos-upload-short-read.test.d.ts +11 -0
- package/dist/clis/douyin/_shared/tos-upload-short-read.test.js +83 -0
- package/dist/clis/douyin/_shared/tos-upload.d.ts +53 -0
- package/dist/clis/douyin/_shared/tos-upload.js +295 -0
- package/dist/clis/douyin/_shared/tos-upload.test.d.ts +1 -0
- package/dist/clis/douyin/_shared/tos-upload.test.js +229 -0
- package/dist/clis/douyin/_shared/transcode.d.ts +27 -0
- package/dist/clis/douyin/_shared/transcode.js +45 -0
- package/dist/clis/douyin/_shared/transcode.test.d.ts +1 -0
- package/dist/clis/douyin/_shared/transcode.test.js +93 -0
- package/dist/clis/douyin/_shared/types.d.ts +26 -0
- package/dist/clis/douyin/_shared/types.js +1 -0
- package/dist/clis/douyin/activities.d.ts +1 -0
- package/dist/clis/douyin/activities.js +20 -0
- package/dist/clis/douyin/activities.test.d.ts +1 -0
- package/dist/clis/douyin/activities.test.js +22 -0
- package/dist/clis/douyin/collections.d.ts +1 -0
- package/dist/clis/douyin/collections.js +22 -0
- package/dist/clis/douyin/collections.test.d.ts +1 -0
- package/dist/clis/douyin/collections.test.js +23 -0
- package/dist/clis/douyin/delete.d.ts +1 -0
- package/dist/clis/douyin/delete.js +18 -0
- package/dist/clis/douyin/delete.test.d.ts +1 -0
- package/dist/clis/douyin/delete.test.js +11 -0
- package/dist/clis/douyin/draft.d.ts +14 -0
- package/dist/clis/douyin/draft.js +237 -0
- package/dist/clis/douyin/draft.test.d.ts +1 -0
- package/dist/clis/douyin/draft.test.js +11 -0
- package/dist/clis/douyin/drafts.d.ts +1 -0
- package/dist/clis/douyin/drafts.js +23 -0
- package/dist/clis/douyin/drafts.test.d.ts +1 -0
- package/dist/clis/douyin/drafts.test.js +11 -0
- package/dist/clis/douyin/hashtag.d.ts +1 -0
- package/dist/clis/douyin/hashtag.js +45 -0
- package/dist/clis/douyin/hashtag.test.d.ts +1 -0
- package/dist/clis/douyin/hashtag.test.js +25 -0
- package/dist/clis/douyin/location.d.ts +1 -0
- package/dist/clis/douyin/location.js +24 -0
- package/dist/clis/douyin/location.test.d.ts +1 -0
- package/dist/clis/douyin/location.test.js +23 -0
- package/dist/clis/douyin/profile.d.ts +1 -0
- package/dist/clis/douyin/profile.js +28 -0
- package/dist/clis/douyin/profile.test.d.ts +1 -0
- package/dist/clis/douyin/profile.test.js +11 -0
- package/dist/clis/douyin/publish.d.ts +14 -0
- package/dist/clis/douyin/publish.js +288 -0
- package/dist/clis/douyin/publish.test.d.ts +1 -0
- package/dist/clis/douyin/publish.test.js +38 -0
- package/dist/clis/douyin/stats.d.ts +1 -0
- package/dist/clis/douyin/stats.js +27 -0
- package/dist/clis/douyin/stats.test.d.ts +1 -0
- package/dist/clis/douyin/stats.test.js +22 -0
- package/dist/clis/douyin/update.d.ts +1 -0
- package/dist/clis/douyin/update.js +31 -0
- package/dist/clis/douyin/update.test.d.ts +1 -0
- package/dist/clis/douyin/update.test.js +11 -0
- package/dist/clis/douyin/videos.d.ts +1 -0
- package/dist/clis/douyin/videos.js +34 -0
- package/dist/clis/douyin/videos.test.d.ts +1 -0
- package/dist/clis/douyin/videos.test.js +11 -0
- package/dist/clis/grok/ask.d.ts +4 -0
- package/dist/clis/grok/ask.js +28 -10
- package/dist/clis/grok/ask.test.js +18 -0
- package/dist/clis/hackernews/search.yaml +1 -1
- package/dist/clis/instagram/search.yaml +2 -1
- package/dist/clis/jd/item.d.ts +1 -0
- package/dist/clis/jd/item.js +96 -0
- package/dist/clis/jd/item.test.d.ts +1 -0
- package/dist/clis/jd/item.test.js +28 -0
- package/dist/clis/jike/feed.js +1 -1
- package/dist/clis/jike/search.js +1 -1
- package/dist/clis/linkedin/search.js +5 -4
- package/dist/clis/linkedin/timeline.d.ts +21 -0
- package/dist/clis/linkedin/timeline.js +503 -0
- package/dist/clis/linkedin/timeline.test.d.ts +1 -0
- package/dist/clis/linkedin/timeline.test.js +81 -0
- package/dist/clis/linux-do/search.yaml +3 -1
- package/dist/clis/medium/feed.js +1 -1
- package/dist/clis/medium/search.js +2 -2
- package/dist/clis/medium/user.js +1 -1
- package/dist/clis/medium/{shared.js → utils.js} +2 -1
- package/dist/clis/pixiv/detail.yaml +49 -0
- package/dist/clis/pixiv/download.d.ts +7 -0
- package/dist/clis/pixiv/download.js +78 -0
- package/dist/clis/pixiv/download.test.d.ts +1 -0
- package/dist/clis/pixiv/download.test.js +87 -0
- package/dist/clis/pixiv/illusts.d.ts +8 -0
- package/dist/clis/pixiv/illusts.js +65 -0
- package/dist/clis/pixiv/illusts.test.d.ts +1 -0
- package/dist/clis/pixiv/illusts.test.js +99 -0
- package/dist/clis/pixiv/ranking.yaml +53 -0
- package/dist/clis/pixiv/search.d.ts +6 -0
- package/dist/clis/pixiv/search.js +43 -0
- package/dist/clis/pixiv/search.test.d.ts +1 -0
- package/dist/clis/pixiv/search.test.js +83 -0
- package/dist/clis/pixiv/test-utils.d.ts +12 -0
- package/dist/clis/pixiv/test-utils.js +23 -0
- package/dist/clis/pixiv/user.yaml +46 -0
- package/dist/clis/pixiv/utils.d.ts +27 -0
- package/dist/clis/pixiv/utils.js +49 -0
- package/dist/clis/reddit/comment.js +2 -1
- package/dist/clis/reddit/read.js +4 -3
- package/dist/clis/reddit/read.test.d.ts +1 -0
- package/dist/clis/reddit/read.test.js +28 -0
- package/dist/clis/reddit/save.js +2 -1
- package/dist/clis/reddit/saved.js +7 -3
- package/dist/clis/reddit/subscribe.js +2 -1
- package/dist/clis/reddit/upvote.js +2 -1
- package/dist/clis/reddit/upvoted.js +7 -3
- package/dist/clis/reuters/search.js +0 -1
- package/dist/clis/sinablog/article.js +1 -1
- package/dist/clis/sinablog/hot.js +1 -1
- package/dist/clis/sinablog/user.js +1 -1
- package/dist/clis/substack/feed.js +1 -1
- package/dist/clis/substack/publication.js +1 -1
- package/dist/clis/substack/search.js +3 -2
- package/dist/clis/substack/{shared.js → utils.js} +3 -2
- package/dist/clis/tiktok/search.yaml +2 -1
- package/dist/clis/twitter/accept.js +2 -1
- package/dist/clis/twitter/article.js +4 -1
- package/dist/clis/twitter/block.js +2 -1
- package/dist/clis/twitter/bookmark.js +2 -1
- package/dist/clis/twitter/bookmarks.js +3 -2
- package/dist/clis/twitter/delete.js +2 -1
- package/dist/clis/twitter/follow.js +2 -1
- package/dist/clis/twitter/followers.js +3 -2
- package/dist/clis/twitter/following.js +3 -2
- package/dist/clis/twitter/hide-reply.js +2 -1
- package/dist/clis/twitter/like.js +2 -1
- package/dist/clis/twitter/notifications.js +2 -1
- package/dist/clis/twitter/post.js +2 -1
- package/dist/clis/twitter/profile.js +5 -2
- package/dist/clis/twitter/reply-dm.js +2 -1
- package/dist/clis/twitter/reply.js +2 -1
- package/dist/clis/twitter/search.js +32 -13
- package/dist/clis/twitter/search.test.d.ts +1 -0
- package/dist/clis/twitter/search.test.js +156 -0
- package/dist/clis/twitter/thread.js +2 -2
- package/dist/clis/twitter/timeline.js +3 -2
- package/dist/clis/twitter/trending.js +3 -2
- package/dist/clis/twitter/unblock.js +2 -1
- package/dist/clis/twitter/unbookmark.js +2 -1
- package/dist/clis/twitter/unfollow.js +2 -1
- package/dist/clis/v2ex/daily.js +3 -2
- package/dist/clis/v2ex/me.js +3 -2
- package/dist/clis/v2ex/notifications.js +4 -4
- package/dist/clis/web/read.d.ts +16 -0
- package/dist/clis/web/read.js +202 -0
- package/dist/clis/weibo/comments.d.ts +1 -0
- package/dist/clis/weibo/comments.js +53 -0
- package/dist/clis/weibo/feed.d.ts +1 -0
- package/dist/clis/weibo/feed.js +56 -0
- package/dist/clis/weibo/hot.js +0 -1
- package/dist/clis/weibo/me.d.ts +1 -0
- package/dist/clis/weibo/me.js +76 -0
- package/dist/clis/weibo/post.d.ts +1 -0
- package/dist/clis/weibo/post.js +75 -0
- package/dist/clis/weibo/user.d.ts +1 -0
- package/dist/clis/weibo/user.js +63 -0
- package/dist/clis/weibo/utils.d.ts +6 -0
- package/dist/clis/weibo/utils.js +30 -0
- package/dist/clis/weread/search.js +3 -2
- package/dist/clis/xueqiu/danjuan-utils.d.ts +55 -0
- package/dist/clis/xueqiu/danjuan-utils.js +126 -0
- package/dist/clis/xueqiu/danjuan-utils.test.d.ts +1 -0
- package/dist/clis/xueqiu/danjuan-utils.test.js +41 -0
- package/dist/clis/xueqiu/fund-holdings.d.ts +1 -0
- package/dist/clis/xueqiu/fund-holdings.js +28 -0
- package/dist/clis/xueqiu/fund-snapshot.d.ts +1 -0
- package/dist/clis/xueqiu/fund-snapshot.js +25 -0
- package/dist/clis/xueqiu/search.yaml +2 -1
- package/dist/clis/yahoo-finance/quote.js +0 -1
- package/dist/clis/youtube/channel.d.ts +1 -0
- package/dist/clis/youtube/channel.js +150 -0
- package/dist/clis/youtube/comments.d.ts +1 -0
- package/dist/clis/youtube/comments.js +95 -0
- package/dist/clis/youtube/search.js +0 -1
- package/dist/clis/youtube/transcript.js +5 -4
- package/dist/clis/youtube/video.js +3 -2
- package/dist/clis/zhihu/search.yaml +2 -1
- package/dist/daemon.js +7 -3
- package/dist/discovery.js +11 -10
- package/dist/doctor.js +2 -1
- package/dist/download/index.d.ts +4 -12
- package/dist/download/index.js +33 -12
- package/dist/download/index.test.js +79 -2
- package/dist/download/media-download.js +4 -2
- package/dist/engine.test.js +76 -4
- package/dist/execution.d.ts +1 -9
- package/dist/execution.js +56 -46
- package/dist/explore.js +12 -111
- package/dist/external-clis.yaml +0 -25
- package/dist/external.js +7 -5
- package/dist/external.test.js +4 -0
- package/dist/generate.d.ts +0 -9
- package/dist/generate.js +4 -20
- package/dist/hooks.d.ts +46 -0
- package/dist/hooks.js +56 -0
- package/dist/hooks.test.d.ts +4 -0
- package/dist/hooks.test.js +92 -0
- package/dist/interceptor.js +70 -23
- package/dist/main.js +2 -0
- package/dist/output.js +12 -6
- package/dist/pipeline/executor.js +1 -1
- package/dist/pipeline/steps/browser.js +1 -3
- package/dist/pipeline/steps/download.js +42 -26
- package/dist/pipeline/steps/download.test.d.ts +1 -0
- package/dist/pipeline/steps/download.test.js +101 -0
- package/dist/pipeline/steps/fetch.js +40 -22
- package/dist/pipeline/steps/fetch.test.d.ts +1 -0
- package/dist/pipeline/steps/fetch.test.js +123 -0
- package/dist/pipeline/steps/transform.js +2 -6
- package/dist/pipeline/template.js +66 -52
- package/dist/pipeline/template.test.js +28 -0
- package/dist/pipeline/transform.test.js +18 -0
- package/dist/plugin.d.ts +40 -1
- package/dist/plugin.js +214 -17
- package/dist/plugin.test.d.ts +1 -1
- package/dist/plugin.test.js +219 -3
- package/dist/record.js +6 -98
- package/dist/registry-api.d.ts +2 -0
- package/dist/registry-api.js +1 -0
- package/dist/registry.d.ts +5 -2
- package/dist/registry.js +1 -2
- package/dist/runtime.d.ts +0 -1
- package/dist/runtime.js +14 -4
- package/dist/snapshotFormatter.d.ts +7 -14
- package/dist/snapshotFormatter.js +38 -78
- package/dist/utils.d.ts +9 -0
- package/dist/utils.js +29 -0
- package/dist/validate.js +3 -5
- package/dist/weread-search-regression.test.d.ts +1 -0
- package/dist/weread-search-regression.test.js +39 -0
- package/dist/yaml-schema.d.ts +26 -0
- package/dist/yaml-schema.js +5 -0
- package/docs/.vitepress/config.mts +16 -0
- package/docs/adapters/browser/dictionary.md +27 -0
- package/docs/adapters/browser/douyin.md +75 -0
- package/docs/adapters/browser/jd.md +27 -0
- package/docs/adapters/browser/linkedin.md +6 -0
- package/docs/adapters/browser/pixiv.md +92 -0
- package/docs/adapters/browser/twitter.md +6 -0
- package/docs/adapters/browser/web.md +30 -0
- package/docs/adapters/browser/xueqiu.md +27 -9
- package/docs/adapters/index.md +9 -2
- package/docs/comparison.md +125 -0
- package/docs/developer/contributing.md +21 -2
- package/docs/developer/testing.md +14 -8
- package/docs/developer/ts-adapter.md +18 -0
- package/docs/developer/yaml-adapter.md +16 -0
- package/docs/guide/plugins.md +10 -0
- package/docs/zh/guide/plugins.md +10 -0
- package/extension/dist/background.js +100 -35
- package/extension/manifest.json +6 -2
- package/extension/package.json +1 -1
- package/extension/popup.html +84 -0
- package/extension/popup.js +25 -0
- package/extension/src/background.test.ts +46 -1
- package/extension/src/background.ts +128 -34
- package/extension/src/cdp.ts +9 -9
- package/package.json +3 -2
- package/scripts/check-doc-coverage.sh +2 -0
- package/src/analysis.ts +170 -0
- package/src/browser/cdp.test.ts +66 -0
- package/src/browser/cdp.ts +59 -44
- package/src/browser/dom-snapshot.test.ts +42 -0
- package/src/browser/dom-snapshot.ts +56 -3
- package/src/browser/index.ts +2 -2
- package/src/browser/mcp.ts +2 -4
- package/src/browser/page.ts +34 -37
- package/src/browser/stealth.ts +24 -10
- package/src/browser.test.ts +2 -2
- package/src/build-manifest.test.ts +14 -0
- package/src/build-manifest.ts +13 -31
- package/src/cascade.ts +5 -3
- package/src/cli.ts +66 -34
- package/src/clis/_shared/desktop-commands.ts +121 -0
- package/src/clis/antigravity/serve.ts +6 -3
- package/src/clis/apple-podcasts/search.ts +2 -1
- package/src/clis/arxiv/search.ts +3 -3
- package/src/clis/bbc/news.ts +0 -1
- package/src/clis/bilibili/dynamic.test.ts +79 -0
- package/src/clis/bilibili/favorite.ts +5 -2
- package/src/clis/bilibili/following.ts +3 -2
- package/src/clis/bilibili/subtitle.ts +8 -7
- package/src/clis/bilibili/utils.ts +2 -2
- package/src/clis/boss/batchgreet.ts +1 -1
- package/src/clis/boss/chatlist.ts +1 -1
- package/src/clis/boss/chatmsg.ts +1 -1
- package/src/clis/boss/detail.ts +1 -1
- package/src/clis/boss/exchange.ts +1 -1
- package/src/clis/boss/greet.ts +1 -1
- package/src/clis/boss/invite.ts +1 -1
- package/src/clis/boss/joblist.ts +1 -1
- package/src/clis/boss/mark.ts +4 -3
- package/src/clis/boss/recommend.ts +1 -1
- package/src/clis/boss/resume.ts +1 -1
- package/src/clis/boss/search.ts +1 -1
- package/src/clis/boss/send.ts +5 -4
- package/src/clis/boss/stats.ts +1 -1
- package/src/clis/chatgpt/ask.ts +5 -0
- package/src/clis/chatgpt/new.ts +7 -2
- package/src/clis/chatgpt/read.ts +7 -2
- package/src/clis/chatgpt/send.ts +3 -2
- package/src/clis/chatgpt/status.ts +6 -1
- package/src/clis/chatwise/ask.ts +7 -2
- package/src/clis/chatwise/export.ts +2 -0
- package/src/clis/chatwise/history.ts +2 -0
- package/src/clis/chatwise/model.ts +7 -3
- package/src/clis/chatwise/new.ts +3 -20
- package/src/clis/chatwise/read.ts +2 -0
- package/src/clis/chatwise/screenshot.ts +3 -32
- package/src/clis/chatwise/send.ts +7 -2
- package/src/clis/chatwise/shared.ts +8 -0
- package/src/clis/chatwise/status.ts +3 -24
- package/src/clis/codex/ask.ts +5 -2
- package/src/clis/codex/dump.ts +2 -27
- package/src/clis/codex/new.ts +2 -28
- package/src/clis/codex/screenshot.ts +2 -32
- package/src/clis/codex/send.ts +5 -4
- package/src/clis/codex/status.ts +2 -24
- package/src/clis/ctrip/search.ts +0 -1
- package/src/clis/cursor/ask.ts +2 -1
- package/src/clis/cursor/composer.ts +2 -1
- package/src/clis/cursor/dump.ts +2 -27
- package/src/clis/cursor/new.ts +2 -20
- package/src/clis/cursor/read.ts +2 -1
- package/src/clis/cursor/screenshot.ts +1 -36
- package/src/clis/cursor/send.ts +2 -1
- package/src/clis/cursor/status.ts +2 -22
- package/src/clis/dictionary/examples.yaml +25 -0
- package/src/clis/dictionary/search.yaml +27 -0
- package/src/clis/dictionary/synonyms.yaml +25 -0
- package/src/clis/douban/book-hot.ts +1 -1
- package/src/clis/douban/movie-hot.ts +1 -1
- package/src/clis/douban/search.ts +1 -1
- package/src/clis/douban/utils.ts +165 -1
- package/src/clis/doubao/ask.ts +1 -1
- package/src/clis/doubao/new.ts +1 -1
- package/src/clis/doubao/read.ts +1 -1
- package/src/clis/doubao/send.ts +1 -1
- package/src/clis/doubao/status.ts +1 -1
- package/src/clis/doubao-app/ask.ts +1 -1
- package/src/clis/doubao-app/new.ts +1 -1
- package/src/clis/doubao-app/read.ts +1 -1
- package/src/clis/doubao-app/send.ts +1 -1
- package/src/clis/douyin/_shared/browser-fetch.test.ts +38 -0
- package/src/clis/douyin/_shared/browser-fetch.ts +45 -0
- package/src/clis/douyin/_shared/creation-id.test.ts +26 -0
- package/src/clis/douyin/_shared/creation-id.ts +8 -0
- package/src/clis/douyin/_shared/imagex-upload.test.ts +113 -0
- package/src/clis/douyin/_shared/imagex-upload.ts +76 -0
- package/src/clis/douyin/_shared/sts2.ts +20 -0
- package/src/clis/douyin/_shared/text-extra.test.ts +42 -0
- package/src/clis/douyin/_shared/text-extra.ts +33 -0
- package/src/clis/douyin/_shared/timing.test.ts +38 -0
- package/src/clis/douyin/_shared/timing.ts +22 -0
- package/src/clis/douyin/_shared/tos-upload-short-read.test.ts +102 -0
- package/src/clis/douyin/_shared/tos-upload.test.ts +281 -0
- package/src/clis/douyin/_shared/tos-upload.ts +444 -0
- package/src/clis/douyin/_shared/transcode.test.ts +117 -0
- package/src/clis/douyin/_shared/transcode.ts +78 -0
- package/src/clis/douyin/_shared/types.ts +29 -0
- package/src/clis/douyin/activities.test.ts +25 -0
- package/src/clis/douyin/activities.ts +23 -0
- package/src/clis/douyin/collections.test.ts +26 -0
- package/src/clis/douyin/collections.ts +25 -0
- package/src/clis/douyin/delete.test.ts +12 -0
- package/src/clis/douyin/delete.ts +20 -0
- package/src/clis/douyin/draft.test.ts +12 -0
- package/src/clis/douyin/draft.ts +282 -0
- package/src/clis/douyin/drafts.test.ts +12 -0
- package/src/clis/douyin/drafts.ts +27 -0
- package/src/clis/douyin/hashtag.test.ts +28 -0
- package/src/clis/douyin/hashtag.ts +56 -0
- package/src/clis/douyin/location.test.ts +26 -0
- package/src/clis/douyin/location.ts +27 -0
- package/src/clis/douyin/profile.test.ts +12 -0
- package/src/clis/douyin/profile.ts +37 -0
- package/src/clis/douyin/publish.test.ts +45 -0
- package/src/clis/douyin/publish.ts +340 -0
- package/src/clis/douyin/stats.test.ts +25 -0
- package/src/clis/douyin/stats.ts +30 -0
- package/src/clis/douyin/update.test.ts +12 -0
- package/src/clis/douyin/update.ts +43 -0
- package/src/clis/douyin/videos.test.ts +12 -0
- package/src/clis/douyin/videos.ts +49 -0
- package/src/clis/grok/ask.test.ts +25 -0
- package/src/clis/grok/ask.ts +25 -12
- package/src/clis/hackernews/search.yaml +1 -1
- package/src/clis/instagram/search.yaml +2 -1
- package/src/clis/jd/item.test.ts +35 -0
- package/src/clis/jd/item.ts +101 -0
- package/src/clis/jike/feed.ts +1 -1
- package/src/clis/jike/search.ts +1 -1
- package/src/clis/linkedin/search.ts +5 -4
- package/src/clis/linkedin/timeline.test.ts +99 -0
- package/src/clis/linkedin/timeline.ts +532 -0
- package/src/clis/linux-do/search.yaml +3 -1
- package/src/clis/medium/feed.ts +1 -1
- package/src/clis/medium/search.ts +2 -2
- package/src/clis/medium/user.ts +1 -1
- package/src/clis/medium/{shared.ts → utils.ts} +2 -1
- package/src/clis/pixiv/detail.yaml +49 -0
- package/src/clis/pixiv/download.test.ts +114 -0
- package/src/clis/pixiv/download.ts +91 -0
- package/src/clis/pixiv/illusts.test.ts +115 -0
- package/src/clis/pixiv/illusts.ts +78 -0
- package/src/clis/pixiv/ranking.yaml +53 -0
- package/src/clis/pixiv/search.test.ts +97 -0
- package/src/clis/pixiv/search.ts +53 -0
- package/src/clis/pixiv/test-utils.ts +29 -0
- package/src/clis/pixiv/user.yaml +46 -0
- package/src/clis/pixiv/utils.ts +62 -0
- package/src/clis/reddit/comment.ts +2 -1
- package/src/clis/reddit/read.test.ts +34 -0
- package/src/clis/reddit/read.ts +4 -3
- package/src/clis/reddit/save.ts +2 -1
- package/src/clis/reddit/saved.ts +6 -2
- package/src/clis/reddit/subscribe.ts +2 -1
- package/src/clis/reddit/upvote.ts +2 -1
- package/src/clis/reddit/upvoted.ts +6 -2
- package/src/clis/reuters/search.ts +0 -1
- package/src/clis/sinablog/article.ts +1 -1
- package/src/clis/sinablog/hot.ts +1 -1
- package/src/clis/sinablog/user.ts +1 -1
- package/src/clis/substack/feed.ts +1 -1
- package/src/clis/substack/publication.ts +1 -1
- package/src/clis/substack/search.ts +3 -2
- package/src/clis/substack/{shared.ts → utils.ts} +3 -2
- package/src/clis/tiktok/search.yaml +2 -1
- package/src/clis/twitter/accept.ts +2 -1
- package/src/clis/twitter/article.ts +3 -1
- package/src/clis/twitter/block.ts +2 -1
- package/src/clis/twitter/bookmark.ts +2 -1
- package/src/clis/twitter/bookmarks.ts +3 -2
- package/src/clis/twitter/delete.ts +2 -1
- package/src/clis/twitter/follow.ts +2 -1
- package/src/clis/twitter/followers.ts +3 -2
- package/src/clis/twitter/following.ts +3 -2
- package/src/clis/twitter/hide-reply.ts +2 -1
- package/src/clis/twitter/like.ts +2 -1
- package/src/clis/twitter/notifications.ts +2 -1
- package/src/clis/twitter/post.ts +2 -1
- package/src/clis/twitter/profile.ts +4 -2
- package/src/clis/twitter/reply-dm.ts +2 -1
- package/src/clis/twitter/reply.ts +2 -1
- package/src/clis/twitter/search.test.ts +180 -0
- package/src/clis/twitter/search.ts +40 -14
- package/src/clis/twitter/thread.ts +2 -2
- package/src/clis/twitter/timeline.ts +3 -2
- package/src/clis/twitter/trending.ts +3 -2
- package/src/clis/twitter/unblock.ts +2 -1
- package/src/clis/twitter/unbookmark.ts +2 -1
- package/src/clis/twitter/unfollow.ts +2 -1
- package/src/clis/v2ex/daily.ts +3 -2
- package/src/clis/v2ex/me.ts +3 -2
- package/src/clis/v2ex/notifications.ts +3 -4
- package/src/clis/web/read.ts +210 -0
- package/src/clis/weibo/comments.ts +54 -0
- package/src/clis/weibo/feed.ts +57 -0
- package/src/clis/weibo/hot.ts +0 -1
- package/src/clis/weibo/me.ts +77 -0
- package/src/clis/weibo/post.ts +77 -0
- package/src/clis/weibo/user.ts +64 -0
- package/src/clis/weibo/utils.ts +32 -0
- package/src/clis/weread/search.ts +3 -2
- package/src/clis/xueqiu/danjuan-utils.test.ts +49 -0
- package/src/clis/xueqiu/danjuan-utils.ts +176 -0
- package/src/clis/xueqiu/fund-holdings.ts +32 -0
- package/src/clis/xueqiu/fund-snapshot.ts +27 -0
- package/src/clis/xueqiu/search.yaml +2 -1
- package/src/clis/yahoo-finance/quote.ts +0 -1
- package/src/clis/youtube/channel.ts +155 -0
- package/src/clis/youtube/comments.ts +97 -0
- package/src/clis/youtube/search.ts +0 -1
- package/src/clis/youtube/transcript.ts +5 -4
- package/src/clis/youtube/video.ts +3 -2
- package/src/clis/zhihu/search.yaml +2 -1
- package/src/daemon.ts +5 -4
- package/src/discovery.ts +12 -34
- package/src/doctor.ts +3 -2
- package/src/download/index.test.ts +93 -2
- package/src/download/index.ts +44 -23
- package/src/download/media-download.ts +5 -3
- package/src/engine.test.ts +84 -3
- package/src/execution.ts +62 -46
- package/src/explore.ts +21 -90
- package/src/external-clis.yaml +0 -25
- package/src/external.test.ts +9 -0
- package/src/external.ts +12 -10
- package/src/generate.ts +4 -41
- package/src/hooks.test.ts +126 -0
- package/src/hooks.ts +90 -0
- package/src/interceptor.ts +73 -23
- package/src/main.ts +2 -0
- package/src/output.ts +14 -6
- package/src/pipeline/executor.ts +1 -1
- package/src/pipeline/steps/browser.ts +1 -3
- package/src/pipeline/steps/download.test.ts +136 -0
- package/src/pipeline/steps/download.ts +47 -34
- package/src/pipeline/steps/fetch.test.ts +179 -0
- package/src/pipeline/steps/fetch.ts +39 -23
- package/src/pipeline/steps/transform.ts +2 -6
- package/src/pipeline/template.test.ts +28 -0
- package/src/pipeline/template.ts +67 -79
- package/src/pipeline/transform.test.ts +20 -0
- package/src/plugin.test.ts +251 -3
- package/src/plugin.ts +265 -21
- package/src/record.ts +12 -84
- package/src/registry-api.ts +2 -0
- package/src/registry.ts +7 -4
- package/src/runtime.ts +14 -4
- package/src/snapshotFormatter.ts +43 -121
- package/src/utils.ts +39 -0
- package/src/validate.ts +3 -5
- package/src/weread-search-regression.test.ts +44 -0
- package/src/yaml-schema.ts +28 -0
- package/tests/e2e/browser-auth.test.ts +25 -0
- package/tests/e2e/browser-public-extended.test.ts +162 -0
- package/tests/e2e/browser-public.test.ts +7 -146
- package/tests/e2e/plugin-management.test.ts +137 -0
- package/tests/e2e/public-commands.test.ts +34 -1
- package/vitest.config.ts +33 -8
- package/.github/workflows/pkg-pr-new.yml +0 -30
- package/dist/clis/douban/shared.d.ts +0 -4
- package/dist/clis/douban/shared.js +0 -155
- package/src/clis/douban/shared.ts +0 -165
- /package/dist/clis/boss/{common.d.ts → utils.d.ts} +0 -0
- /package/dist/clis/boss/{common.js → utils.js} +0 -0
- /package/dist/clis/doubao/{common.d.ts → utils.d.ts} +0 -0
- /package/dist/clis/doubao/{common.js → utils.js} +0 -0
- /package/dist/clis/doubao-app/{common.d.ts → utils.d.ts} +0 -0
- /package/dist/clis/doubao-app/{common.js → utils.js} +0 -0
- /package/dist/clis/jike/{shared.d.ts → utils.d.ts} +0 -0
- /package/dist/clis/jike/{shared.js → utils.js} +0 -0
- /package/dist/clis/medium/{shared.d.ts → utils.d.ts} +0 -0
- /package/dist/clis/sinablog/{shared.d.ts → utils.d.ts} +0 -0
- /package/dist/clis/sinablog/{shared.js → utils.js} +0 -0
- /package/dist/clis/substack/{shared.d.ts → utils.d.ts} +0 -0
- /package/src/clis/boss/{common.ts → utils.ts} +0 -0
- /package/src/clis/doubao/{common.ts → utils.ts} +0 -0
- /package/src/clis/doubao-app/{common.ts → utils.ts} +0 -0
- /package/src/clis/jike/{shared.ts → utils.ts} +0 -0
- /package/src/clis/sinablog/{shared.ts → utils.ts} +0 -0
package/dist/interceptor.js
CHANGED
|
@@ -8,6 +8,42 @@
|
|
|
8
8
|
* - stepIntercept (pipeline/steps/intercept.ts)
|
|
9
9
|
* - stepTap (pipeline/steps/tap.ts)
|
|
10
10
|
*/
|
|
11
|
+
/**
|
|
12
|
+
* Helper: define a non-enumerable property on window.
|
|
13
|
+
* Avoids detection via Object.keys(window) or for..in loops.
|
|
14
|
+
*/
|
|
15
|
+
const DEFINE_HIDDEN = `
|
|
16
|
+
function __defHidden(obj, key, val) {
|
|
17
|
+
try {
|
|
18
|
+
Object.defineProperty(obj, key, { value: val, writable: true, enumerable: false, configurable: true });
|
|
19
|
+
} catch { obj[key] = val; }
|
|
20
|
+
}`;
|
|
21
|
+
/**
|
|
22
|
+
* Helper: disguise a patched function so toString() returns native code signature.
|
|
23
|
+
*/
|
|
24
|
+
const DISGUISE_FN = `
|
|
25
|
+
function __disguise(fn, name) {
|
|
26
|
+
const nativeStr = 'function ' + name + '() { [native code] }';
|
|
27
|
+
// Override toString on the instance AND patch Function.prototype.toString
|
|
28
|
+
// to handle Function.prototype.toString.call(fn) bypasses.
|
|
29
|
+
const _origToString = Function.prototype.toString;
|
|
30
|
+
const _patchedFns = window.__dFns || (function() {
|
|
31
|
+
const m = new Map();
|
|
32
|
+
Object.defineProperty(window, '__dFns', { value: m, enumerable: false, configurable: true });
|
|
33
|
+
// Patch Function.prototype.toString once to consult the map
|
|
34
|
+
Object.defineProperty(Function.prototype, 'toString', {
|
|
35
|
+
value: function() {
|
|
36
|
+
const override = m.get(this);
|
|
37
|
+
return override !== undefined ? override : _origToString.call(this);
|
|
38
|
+
},
|
|
39
|
+
writable: true, configurable: true
|
|
40
|
+
});
|
|
41
|
+
return m;
|
|
42
|
+
})();
|
|
43
|
+
_patchedFns.set(fn, nativeStr);
|
|
44
|
+
try { Object.defineProperty(fn, 'name', { value: name, configurable: true }); } catch {}
|
|
45
|
+
return fn;
|
|
46
|
+
}`;
|
|
11
47
|
/**
|
|
12
48
|
* Generate JavaScript source that installs a fetch/XHR interceptor.
|
|
13
49
|
* Captured responses are pushed to `window.__opencli_intercepted`.
|
|
@@ -19,18 +55,23 @@
|
|
|
19
55
|
export function generateInterceptorJs(patternExpr, opts = {}) {
|
|
20
56
|
const arr = opts.arrayName ?? '__opencli_intercepted';
|
|
21
57
|
const guard = opts.patchGuard ?? '__opencli_interceptor_patched';
|
|
58
|
+
// Store the current pattern in a separate global so it can be updated
|
|
59
|
+
// without re-patching fetch/XHR (the patchGuard only prevents double-patching).
|
|
60
|
+
const patternVar = `${guard}_pattern`;
|
|
22
61
|
return `
|
|
23
62
|
() => {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
const __pattern = ${patternExpr};
|
|
63
|
+
${DEFINE_HIDDEN}
|
|
64
|
+
${DISGUISE_FN}
|
|
27
65
|
|
|
28
|
-
if (!window.${
|
|
29
|
-
|
|
66
|
+
if (!window.${arr}) __defHidden(window, '${arr}', []);
|
|
67
|
+
if (!window.${arr}_errors) __defHidden(window, '${arr}_errors', []);
|
|
68
|
+
__defHidden(window, '${patternVar}', ${patternExpr});
|
|
69
|
+
const __checkMatch = (url) => window.${patternVar} && url.includes(window.${patternVar});
|
|
30
70
|
|
|
71
|
+
if (!window.${guard}) {
|
|
31
72
|
// ── Patch fetch ──
|
|
32
73
|
const __origFetch = window.fetch;
|
|
33
|
-
window.fetch = async function(...args) {
|
|
74
|
+
window.fetch = __disguise(async function(...args) {
|
|
34
75
|
const reqUrl = typeof args[0] === 'string' ? args[0]
|
|
35
76
|
: (args[0] && args[0].url) || '';
|
|
36
77
|
const response = await __origFetch.apply(this, args);
|
|
@@ -42,28 +83,28 @@ export function generateInterceptorJs(patternExpr, opts = {}) {
|
|
|
42
83
|
} catch(e) { window.${arr}_errors.push({ url: reqUrl, error: String(e) }); }
|
|
43
84
|
}
|
|
44
85
|
return response;
|
|
45
|
-
};
|
|
86
|
+
}, 'fetch');
|
|
46
87
|
|
|
47
88
|
// ── Patch XMLHttpRequest ──
|
|
48
89
|
const __XHR = XMLHttpRequest.prototype;
|
|
49
90
|
const __origOpen = __XHR.open;
|
|
50
91
|
const __origSend = __XHR.send;
|
|
51
|
-
__XHR.open = function(method, url) {
|
|
52
|
-
this
|
|
92
|
+
__XHR.open = __disguise(function(method, url) {
|
|
93
|
+
Object.defineProperty(this, '__iurl', { value: String(url), writable: true, enumerable: false, configurable: true });
|
|
53
94
|
return __origOpen.apply(this, arguments);
|
|
54
|
-
};
|
|
55
|
-
__XHR.send = function() {
|
|
56
|
-
if (__checkMatch(this.
|
|
95
|
+
}, 'open');
|
|
96
|
+
__XHR.send = __disguise(function() {
|
|
97
|
+
if (__checkMatch(this.__iurl)) {
|
|
57
98
|
this.addEventListener('load', function() {
|
|
58
99
|
try {
|
|
59
100
|
window.${arr}.push(JSON.parse(this.responseText));
|
|
60
|
-
} catch(e) { window.${arr}_errors.push({ url: this.
|
|
101
|
+
} catch(e) { window.${arr}_errors.push({ url: this.__iurl, error: String(e) }); }
|
|
61
102
|
});
|
|
62
103
|
}
|
|
63
104
|
return __origSend.apply(this, arguments);
|
|
64
|
-
};
|
|
105
|
+
}, 'send');
|
|
65
106
|
|
|
66
|
-
window
|
|
107
|
+
__defHidden(window, '${guard}', true);
|
|
67
108
|
}
|
|
68
109
|
}
|
|
69
110
|
`;
|
|
@@ -94,13 +135,19 @@ export function generateTapInterceptorJs(patternExpr) {
|
|
|
94
135
|
let captureResolve;
|
|
95
136
|
const capturePromise = new Promise(r => { captureResolve = r; });
|
|
96
137
|
const capturePattern = ${patternExpr};
|
|
138
|
+
function __disguise(fn, name) {
|
|
139
|
+
const s = 'function ' + name + '() { [native code] }';
|
|
140
|
+
Object.defineProperty(fn, 'toString', { value: function() { return s; }, writable: true, configurable: true, enumerable: false });
|
|
141
|
+
try { Object.defineProperty(fn, 'name', { value: name, configurable: true }); } catch {}
|
|
142
|
+
return fn;
|
|
143
|
+
}
|
|
97
144
|
`,
|
|
98
145
|
capturedVar: 'captured',
|
|
99
146
|
promiseVar: 'capturePromise',
|
|
100
147
|
resolveVar: 'captureResolve',
|
|
101
148
|
fetchPatch: `
|
|
102
149
|
const origFetch = window.fetch;
|
|
103
|
-
window.fetch = async function(...fetchArgs) {
|
|
150
|
+
window.fetch = __disguise(async function(...fetchArgs) {
|
|
104
151
|
const resp = await origFetch.apply(this, fetchArgs);
|
|
105
152
|
try {
|
|
106
153
|
const url = typeof fetchArgs[0] === 'string' ? fetchArgs[0]
|
|
@@ -110,17 +157,17 @@ export function generateTapInterceptorJs(patternExpr) {
|
|
|
110
157
|
}
|
|
111
158
|
} catch {}
|
|
112
159
|
return resp;
|
|
113
|
-
};
|
|
160
|
+
}, 'fetch');
|
|
114
161
|
`,
|
|
115
162
|
xhrPatch: `
|
|
116
163
|
const origXhrOpen = XMLHttpRequest.prototype.open;
|
|
117
164
|
const origXhrSend = XMLHttpRequest.prototype.send;
|
|
118
|
-
XMLHttpRequest.prototype.open = function(method, url) {
|
|
119
|
-
this
|
|
165
|
+
XMLHttpRequest.prototype.open = __disguise(function(method, url) {
|
|
166
|
+
Object.defineProperty(this, '__iurl', { value: String(url), writable: true, enumerable: false, configurable: true });
|
|
120
167
|
return origXhrOpen.apply(this, arguments);
|
|
121
|
-
};
|
|
122
|
-
XMLHttpRequest.prototype.send = function(body) {
|
|
123
|
-
if (capturePattern && this.
|
|
168
|
+
}, 'open');
|
|
169
|
+
XMLHttpRequest.prototype.send = __disguise(function(body) {
|
|
170
|
+
if (capturePattern && this.__iurl?.includes(capturePattern)) {
|
|
124
171
|
this.addEventListener('load', function() {
|
|
125
172
|
if (!captured) {
|
|
126
173
|
try { captured = JSON.parse(this.responseText); captureResolve(); } catch {}
|
|
@@ -128,7 +175,7 @@ export function generateTapInterceptorJs(patternExpr) {
|
|
|
128
175
|
});
|
|
129
176
|
}
|
|
130
177
|
return origXhrSend.apply(this, arguments);
|
|
131
|
-
};
|
|
178
|
+
}, 'send');
|
|
132
179
|
`,
|
|
133
180
|
restorePatch: `
|
|
134
181
|
window.fetch = origFetch;
|
package/dist/main.js
CHANGED
|
@@ -18,6 +18,7 @@ import { fileURLToPath } from 'node:url';
|
|
|
18
18
|
import { discoverClis, discoverPlugins } from './discovery.js';
|
|
19
19
|
import { getCompletions } from './completion.js';
|
|
20
20
|
import { runCli } from './cli.js';
|
|
21
|
+
import { emitHook } from './hooks.js';
|
|
21
22
|
const __filename = fileURLToPath(import.meta.url);
|
|
22
23
|
const __dirname = path.dirname(__filename);
|
|
23
24
|
const BUILTIN_CLIS = path.resolve(__dirname, 'clis');
|
|
@@ -46,4 +47,5 @@ if (getCompIdx !== -1) {
|
|
|
46
47
|
process.stdout.write(candidates.join('\n') + '\n');
|
|
47
48
|
process.exit(0);
|
|
48
49
|
}
|
|
50
|
+
await emitHook('onStartup', { command: '__startup__', args: {} });
|
|
49
51
|
runCli(BUILTIN_CLIS, USER_CLIS);
|
package/dist/output.js
CHANGED
|
@@ -4,6 +4,12 @@
|
|
|
4
4
|
import chalk from 'chalk';
|
|
5
5
|
import Table from 'cli-table3';
|
|
6
6
|
import yaml from 'js-yaml';
|
|
7
|
+
function normalizeRows(data) {
|
|
8
|
+
return Array.isArray(data) ? data : [data];
|
|
9
|
+
}
|
|
10
|
+
function resolveColumns(rows, opts) {
|
|
11
|
+
return opts.columns ?? Object.keys(rows[0] ?? {});
|
|
12
|
+
}
|
|
7
13
|
export function render(data, opts = {}) {
|
|
8
14
|
const fmt = opts.fmt ?? 'table';
|
|
9
15
|
if (data === null || data === undefined) {
|
|
@@ -31,12 +37,12 @@ export function render(data, opts = {}) {
|
|
|
31
37
|
}
|
|
32
38
|
}
|
|
33
39
|
function renderTable(data, opts) {
|
|
34
|
-
const rows =
|
|
40
|
+
const rows = normalizeRows(data);
|
|
35
41
|
if (!rows.length) {
|
|
36
42
|
console.log(chalk.dim('(no data)'));
|
|
37
43
|
return;
|
|
38
44
|
}
|
|
39
|
-
const columns =
|
|
45
|
+
const columns = resolveColumns(rows, opts);
|
|
40
46
|
const header = columns.map(c => capitalize(c));
|
|
41
47
|
const table = new Table({
|
|
42
48
|
head: header.map(h => chalk.bold(h)),
|
|
@@ -68,10 +74,10 @@ function renderJson(data) {
|
|
|
68
74
|
console.log(JSON.stringify(data, null, 2));
|
|
69
75
|
}
|
|
70
76
|
function renderMarkdown(data, opts) {
|
|
71
|
-
const rows =
|
|
77
|
+
const rows = normalizeRows(data);
|
|
72
78
|
if (!rows.length)
|
|
73
79
|
return;
|
|
74
|
-
const columns =
|
|
80
|
+
const columns = resolveColumns(rows, opts);
|
|
75
81
|
console.log('| ' + columns.join(' | ') + ' |');
|
|
76
82
|
console.log('| ' + columns.map(() => '---').join(' | ') + ' |');
|
|
77
83
|
for (const row of rows) {
|
|
@@ -79,10 +85,10 @@ function renderMarkdown(data, opts) {
|
|
|
79
85
|
}
|
|
80
86
|
}
|
|
81
87
|
function renderCsv(data, opts) {
|
|
82
|
-
const rows =
|
|
88
|
+
const rows = normalizeRows(data);
|
|
83
89
|
if (!rows.length)
|
|
84
90
|
return;
|
|
85
|
-
const columns =
|
|
91
|
+
const columns = resolveColumns(rows, opts);
|
|
86
92
|
console.log(columns.join(','));
|
|
87
93
|
for (const row of rows) {
|
|
88
94
|
console.log(columns.map(c => {
|
|
@@ -5,7 +5,7 @@ import { getStep } from './registry.js';
|
|
|
5
5
|
import { log } from '../logger.js';
|
|
6
6
|
import { ConfigError } from '../errors.js';
|
|
7
7
|
/** Steps that interact with the browser and may fail transiently */
|
|
8
|
-
const BROWSER_STEPS = new Set(['navigate', 'evaluate', 'click', 'type', 'press', 'wait', 'snapshot'
|
|
8
|
+
const BROWSER_STEPS = new Set(['navigate', 'evaluate', 'click', 'type', 'press', 'wait', 'snapshot']);
|
|
9
9
|
export async function executePipeline(page, pipeline, ctx = {}) {
|
|
10
10
|
const args = ctx.args ?? {};
|
|
11
11
|
const debug = ctx.debug ?? false;
|
|
@@ -3,9 +3,7 @@
|
|
|
3
3
|
* Browser interaction primitives.
|
|
4
4
|
*/
|
|
5
5
|
import { render } from '../template.js';
|
|
6
|
-
|
|
7
|
-
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
8
|
-
}
|
|
6
|
+
import { isRecord } from '../../utils.js';
|
|
9
7
|
export async function stepNavigate(page, params, data, args) {
|
|
10
8
|
if (isRecord(params) && 'url' in params) {
|
|
11
9
|
const url = String(render(params.url, { args, data }));
|
|
@@ -10,30 +10,16 @@
|
|
|
10
10
|
import * as fs from 'node:fs';
|
|
11
11
|
import * as path from 'node:path';
|
|
12
12
|
import { render } from '../template.js';
|
|
13
|
+
import { getErrorMessage } from '../../errors.js';
|
|
13
14
|
import { httpDownload, ytdlpDownload, saveDocument, detectContentType, requiresYtdlp, sanitizeFilename, generateFilename, exportCookiesToNetscape, getTempDir, formatCookieHeader, } from '../../download/index.js';
|
|
14
15
|
import { DownloadProgressTracker, formatBytes } from '../../download/progress.js';
|
|
15
|
-
|
|
16
|
-
* Simple async concurrency limiter for downloads.
|
|
17
|
-
*/
|
|
18
|
-
async function mapConcurrent(items, limit, fn) {
|
|
19
|
-
const results = new Array(items.length);
|
|
20
|
-
let index = 0;
|
|
21
|
-
async function worker() {
|
|
22
|
-
while (index < items.length) {
|
|
23
|
-
const i = index++;
|
|
24
|
-
results[i] = await fn(items[i], i);
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
const workers = Array.from({ length: Math.min(limit, items.length) }, () => worker());
|
|
28
|
-
await Promise.all(workers);
|
|
29
|
-
return results;
|
|
30
|
-
}
|
|
16
|
+
import { mapConcurrent } from '../../utils.js';
|
|
31
17
|
/**
|
|
32
18
|
* Extract cookies from browser page.
|
|
33
19
|
*/
|
|
34
20
|
async function extractBrowserCookies(page, domain) {
|
|
35
21
|
try {
|
|
36
|
-
const cookies = await page.getCookies(
|
|
22
|
+
const cookies = await page.getCookies({ domain });
|
|
37
23
|
return formatCookieHeader(cookies);
|
|
38
24
|
}
|
|
39
25
|
catch {
|
|
@@ -61,6 +47,13 @@ async function extractCookiesArray(page, domain) {
|
|
|
61
47
|
return [];
|
|
62
48
|
}
|
|
63
49
|
}
|
|
50
|
+
function dedupeCookies(cookies) {
|
|
51
|
+
const deduped = new Map();
|
|
52
|
+
for (const cookie of cookies) {
|
|
53
|
+
deduped.set(`${cookie.domain}\t${cookie.path}\t${cookie.name}`, cookie);
|
|
54
|
+
}
|
|
55
|
+
return [...deduped.values()];
|
|
56
|
+
}
|
|
64
57
|
/**
|
|
65
58
|
* Download step handler for YAML pipelines.
|
|
66
59
|
*
|
|
@@ -101,21 +94,28 @@ export async function stepDownload(page, params, data, args) {
|
|
|
101
94
|
}
|
|
102
95
|
// Create progress tracker
|
|
103
96
|
const tracker = new DownloadProgressTracker(items.length, showProgress);
|
|
104
|
-
//
|
|
105
|
-
|
|
97
|
+
// Cache cookie lookups per domain so mixed-domain batches stay isolated without repeated browser calls.
|
|
98
|
+
const cookieHeaderCache = new Map();
|
|
106
99
|
let cookiesFile;
|
|
107
100
|
if (page) {
|
|
108
|
-
cookies = await extractBrowserCookies(page);
|
|
109
101
|
// For yt-dlp, we need to export cookies to Netscape format
|
|
110
102
|
if (useYtdlp || items.some((item, index) => {
|
|
111
103
|
const url = String(render(urlTemplate, { args, data, item, index }));
|
|
112
104
|
return requiresYtdlp(url);
|
|
113
105
|
})) {
|
|
114
106
|
try {
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
107
|
+
const ytdlpDomains = [...new Set(items.flatMap((item, index) => {
|
|
108
|
+
const url = String(render(urlTemplate, { args, data, item, index }));
|
|
109
|
+
if (!useYtdlp && !requiresYtdlp(url))
|
|
110
|
+
return [];
|
|
111
|
+
try {
|
|
112
|
+
return [new URL(url).hostname];
|
|
113
|
+
}
|
|
114
|
+
catch {
|
|
115
|
+
return [];
|
|
116
|
+
}
|
|
117
|
+
}))];
|
|
118
|
+
const cookiesArray = dedupeCookies((await Promise.all(ytdlpDomains.map((domain) => extractCookiesArray(page, domain)))).flat());
|
|
119
119
|
if (cookiesArray.length > 0) {
|
|
120
120
|
const tempDir = getTempDir();
|
|
121
121
|
fs.mkdirSync(tempDir, { recursive: true });
|
|
@@ -199,6 +199,21 @@ export async function stepDownload(page, params, data, args) {
|
|
|
199
199
|
}
|
|
200
200
|
else {
|
|
201
201
|
// Direct HTTP download
|
|
202
|
+
let cookies = '';
|
|
203
|
+
if (page) {
|
|
204
|
+
try {
|
|
205
|
+
const targetDomain = new URL(url).hostname;
|
|
206
|
+
let cookiePromise = cookieHeaderCache.get(targetDomain);
|
|
207
|
+
if (!cookiePromise) {
|
|
208
|
+
cookiePromise = extractBrowserCookies(page, targetDomain);
|
|
209
|
+
cookieHeaderCache.set(targetDomain, cookiePromise);
|
|
210
|
+
}
|
|
211
|
+
cookies = await cookiePromise;
|
|
212
|
+
}
|
|
213
|
+
catch {
|
|
214
|
+
cookies = '';
|
|
215
|
+
}
|
|
216
|
+
}
|
|
202
217
|
result = await httpDownload(url, destPath, {
|
|
203
218
|
cookies,
|
|
204
219
|
timeout,
|
|
@@ -214,9 +229,10 @@ export async function stepDownload(page, params, data, args) {
|
|
|
214
229
|
}
|
|
215
230
|
}
|
|
216
231
|
catch (err) {
|
|
217
|
-
|
|
232
|
+
const msg = getErrorMessage(err);
|
|
233
|
+
result = { success: false, size: 0, error: msg };
|
|
218
234
|
if (progressBar) {
|
|
219
|
-
progressBar.fail(
|
|
235
|
+
progressBar.fail(msg);
|
|
220
236
|
}
|
|
221
237
|
}
|
|
222
238
|
tracker.onFileComplete(result.success);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
2
|
+
import * as os from 'node:os';
|
|
3
|
+
import * as path from 'node:path';
|
|
4
|
+
const { mockHttpDownload, mockYtdlpDownload, mockExportCookiesToNetscape } = vi.hoisted(() => ({
|
|
5
|
+
mockHttpDownload: vi.fn(),
|
|
6
|
+
mockYtdlpDownload: vi.fn(),
|
|
7
|
+
mockExportCookiesToNetscape: vi.fn(),
|
|
8
|
+
}));
|
|
9
|
+
vi.mock('../../download/index.js', async () => {
|
|
10
|
+
const actual = await vi.importActual('../../download/index.js');
|
|
11
|
+
return {
|
|
12
|
+
...actual,
|
|
13
|
+
httpDownload: mockHttpDownload,
|
|
14
|
+
ytdlpDownload: mockYtdlpDownload,
|
|
15
|
+
exportCookiesToNetscape: mockExportCookiesToNetscape,
|
|
16
|
+
};
|
|
17
|
+
});
|
|
18
|
+
import { stepDownload } from './download.js';
|
|
19
|
+
function createMockPage(getCookies) {
|
|
20
|
+
return {
|
|
21
|
+
goto: vi.fn(),
|
|
22
|
+
evaluate: vi.fn().mockResolvedValue(null),
|
|
23
|
+
getCookies,
|
|
24
|
+
snapshot: vi.fn().mockResolvedValue(''),
|
|
25
|
+
click: vi.fn(),
|
|
26
|
+
typeText: vi.fn(),
|
|
27
|
+
pressKey: vi.fn(),
|
|
28
|
+
scrollTo: vi.fn(),
|
|
29
|
+
getFormState: vi.fn().mockResolvedValue({}),
|
|
30
|
+
wait: vi.fn(),
|
|
31
|
+
tabs: vi.fn().mockResolvedValue([]),
|
|
32
|
+
closeTab: vi.fn(),
|
|
33
|
+
newTab: vi.fn(),
|
|
34
|
+
selectTab: vi.fn(),
|
|
35
|
+
networkRequests: vi.fn().mockResolvedValue([]),
|
|
36
|
+
consoleMessages: vi.fn().mockResolvedValue([]),
|
|
37
|
+
scroll: vi.fn(),
|
|
38
|
+
autoScroll: vi.fn(),
|
|
39
|
+
installInterceptor: vi.fn(),
|
|
40
|
+
getInterceptedRequests: vi.fn().mockResolvedValue([]),
|
|
41
|
+
screenshot: vi.fn().mockResolvedValue(''),
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
describe('stepDownload', () => {
|
|
45
|
+
beforeEach(() => {
|
|
46
|
+
mockHttpDownload.mockReset();
|
|
47
|
+
mockHttpDownload.mockResolvedValue({ success: true, size: 2 });
|
|
48
|
+
mockYtdlpDownload.mockReset();
|
|
49
|
+
mockYtdlpDownload.mockResolvedValue({ success: true, size: 2 });
|
|
50
|
+
mockExportCookiesToNetscape.mockReset();
|
|
51
|
+
});
|
|
52
|
+
it('scopes browser cookies to each direct-download target domain', async () => {
|
|
53
|
+
const page = createMockPage(vi.fn().mockImplementation(async (opts) => {
|
|
54
|
+
const domain = opts?.domain ?? 'unknown';
|
|
55
|
+
return [{ name: 'sid', value: domain, domain }];
|
|
56
|
+
}));
|
|
57
|
+
await stepDownload(page, {
|
|
58
|
+
url: '${{ item.url }}',
|
|
59
|
+
dir: path.join(os.tmpdir(), 'opencli-download-test'),
|
|
60
|
+
filename: '${{ index }}.txt',
|
|
61
|
+
progress: false,
|
|
62
|
+
concurrency: 1,
|
|
63
|
+
}, [
|
|
64
|
+
{ url: 'https://a.example/file-1.txt' },
|
|
65
|
+
{ url: 'https://b.example/file-2.txt' },
|
|
66
|
+
], {});
|
|
67
|
+
expect(mockHttpDownload).toHaveBeenNthCalledWith(1, 'https://a.example/file-1.txt', path.join(os.tmpdir(), 'opencli-download-test', '0.txt'), expect.objectContaining({ cookies: 'sid=a.example' }));
|
|
68
|
+
expect(mockHttpDownload).toHaveBeenNthCalledWith(2, 'https://b.example/file-2.txt', path.join(os.tmpdir(), 'opencli-download-test', '1.txt'), expect.objectContaining({ cookies: 'sid=b.example' }));
|
|
69
|
+
});
|
|
70
|
+
it('builds yt-dlp cookies from all target domains instead of only the first item', async () => {
|
|
71
|
+
const getCookies = vi.fn().mockImplementation(async (opts) => {
|
|
72
|
+
const domain = opts?.domain ?? 'unknown';
|
|
73
|
+
return [{
|
|
74
|
+
name: `sid-${domain}`,
|
|
75
|
+
value: domain,
|
|
76
|
+
domain,
|
|
77
|
+
path: '/',
|
|
78
|
+
secure: false,
|
|
79
|
+
httpOnly: false,
|
|
80
|
+
}];
|
|
81
|
+
});
|
|
82
|
+
const page = createMockPage(getCookies);
|
|
83
|
+
await stepDownload(page, {
|
|
84
|
+
url: '${{ item.url }}',
|
|
85
|
+
dir: '/tmp/opencli-download-test',
|
|
86
|
+
filename: '${{ index }}.mp4',
|
|
87
|
+
progress: false,
|
|
88
|
+
concurrency: 1,
|
|
89
|
+
}, [
|
|
90
|
+
{ url: 'https://www.youtube.com/watch?v=one' },
|
|
91
|
+
{ url: 'https://www.bilibili.com/video/BV1xx411c7mD' },
|
|
92
|
+
], {});
|
|
93
|
+
expect(getCookies).toHaveBeenCalledWith({ domain: 'www.youtube.com' });
|
|
94
|
+
expect(getCookies).toHaveBeenCalledWith({ domain: 'www.bilibili.com' });
|
|
95
|
+
expect(mockExportCookiesToNetscape).toHaveBeenCalledWith(expect.arrayContaining([
|
|
96
|
+
expect.objectContaining({ name: 'sid-www.youtube.com', domain: 'www.youtube.com' }),
|
|
97
|
+
expect.objectContaining({ name: 'sid-www.bilibili.com', domain: 'www.bilibili.com' }),
|
|
98
|
+
]), expect.any(String));
|
|
99
|
+
expect(mockYtdlpDownload).toHaveBeenCalledTimes(2);
|
|
100
|
+
});
|
|
101
|
+
});
|
|
@@ -1,24 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Pipeline step: fetch — HTTP API requests.
|
|
3
3
|
*/
|
|
4
|
+
import { CliError, getErrorMessage } from '../../errors.js';
|
|
5
|
+
import { log } from '../../logger.js';
|
|
4
6
|
import { render } from '../template.js';
|
|
5
|
-
|
|
6
|
-
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
7
|
-
}
|
|
8
|
-
/** Simple async concurrency limiter */
|
|
9
|
-
async function mapConcurrent(items, limit, fn) {
|
|
10
|
-
const results = new Array(items.length);
|
|
11
|
-
let index = 0;
|
|
12
|
-
async function worker() {
|
|
13
|
-
while (index < items.length) {
|
|
14
|
-
const i = index++;
|
|
15
|
-
results[i] = await fn(items[i], i);
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
const workers = Array.from({ length: Math.min(limit, items.length) }, () => worker());
|
|
19
|
-
await Promise.all(workers);
|
|
20
|
-
return results;
|
|
21
|
-
}
|
|
7
|
+
import { isRecord, mapConcurrent } from '../../utils.js';
|
|
22
8
|
/** Single URL fetch helper */
|
|
23
9
|
async function fetchSingle(page, url, method, queryParams, headers, args, data) {
|
|
24
10
|
const renderedParams = {};
|
|
@@ -34,19 +20,32 @@ async function fetchSingle(page, url, method, queryParams, headers, args, data)
|
|
|
34
20
|
}
|
|
35
21
|
if (page === null) {
|
|
36
22
|
const resp = await fetch(finalUrl, { method: method.toUpperCase(), headers: renderedHeaders });
|
|
23
|
+
if (!resp.ok) {
|
|
24
|
+
throw new CliError('FETCH_ERROR', `HTTP ${resp.status} ${resp.statusText} from ${finalUrl}`);
|
|
25
|
+
}
|
|
37
26
|
return resp.json();
|
|
38
27
|
}
|
|
39
28
|
const headersJs = JSON.stringify(renderedHeaders);
|
|
40
29
|
const urlJs = JSON.stringify(finalUrl);
|
|
41
30
|
const methodJs = JSON.stringify(method.toUpperCase());
|
|
42
|
-
|
|
31
|
+
// Return error status instead of throwing inside evaluate to avoid CDP wrapper
|
|
32
|
+
// rewriting the message (CDP prepends "Evaluate error: " to thrown errors).
|
|
33
|
+
const result = await page.evaluate(`
|
|
43
34
|
async () => {
|
|
44
35
|
const resp = await fetch(${urlJs}, {
|
|
45
36
|
method: ${methodJs}, headers: ${headersJs}, credentials: "include"
|
|
46
37
|
});
|
|
38
|
+
if (!resp.ok) {
|
|
39
|
+
return { __httpError: resp.status, statusText: resp.statusText };
|
|
40
|
+
}
|
|
47
41
|
return await resp.json();
|
|
48
42
|
}
|
|
49
43
|
`);
|
|
44
|
+
if (result && typeof result === 'object' && '__httpError' in result) {
|
|
45
|
+
const { __httpError: status, statusText } = result;
|
|
46
|
+
throw new CliError('FETCH_ERROR', `HTTP ${status} ${statusText} from ${finalUrl}`);
|
|
47
|
+
}
|
|
48
|
+
return result;
|
|
50
49
|
}
|
|
51
50
|
/**
|
|
52
51
|
* Batch fetch: send all URLs into the browser as a single evaluate() call.
|
|
@@ -56,10 +55,11 @@ async function fetchSingle(page, url, method, queryParams, headers, args, data)
|
|
|
56
55
|
async function fetchBatchInBrowser(page, urls, method, headers, concurrency) {
|
|
57
56
|
const headersJs = JSON.stringify(headers);
|
|
58
57
|
const urlsJs = JSON.stringify(urls);
|
|
58
|
+
const methodJs = JSON.stringify(method);
|
|
59
59
|
return (await page.evaluate(`
|
|
60
60
|
async () => {
|
|
61
61
|
const urls = ${urlsJs};
|
|
62
|
-
const method =
|
|
62
|
+
const method = ${methodJs};
|
|
63
63
|
const headers = ${headersJs};
|
|
64
64
|
const concurrency = ${concurrency};
|
|
65
65
|
|
|
@@ -71,9 +71,13 @@ async function fetchBatchInBrowser(page, urls, method, headers, concurrency) {
|
|
|
71
71
|
const i = idx++;
|
|
72
72
|
try {
|
|
73
73
|
const resp = await fetch(urls[i], { method, headers, credentials: "include" });
|
|
74
|
+
if (!resp.ok) {
|
|
75
|
+
throw new Error('HTTP ' + resp.status + ' ' + resp.statusText + ' from ' + urls[i]);
|
|
76
|
+
}
|
|
74
77
|
results[i] = await resp.json();
|
|
75
78
|
} catch (e) {
|
|
76
|
-
results[i] = { error: e.message };
|
|
79
|
+
results[i] = { error: e instanceof Error ? e.message : String(e) };
|
|
80
|
+
// Note: getErrorMessage() is a Node.js utility — can't use it inside evaluate()
|
|
77
81
|
}
|
|
78
82
|
}
|
|
79
83
|
}
|
|
@@ -111,12 +115,26 @@ export async function stepFetch(page, params, data, args) {
|
|
|
111
115
|
});
|
|
112
116
|
// BATCH IPC: if browser is available, batch all fetches into a single evaluate() call
|
|
113
117
|
if (page !== null) {
|
|
114
|
-
|
|
118
|
+
const results = await fetchBatchInBrowser(page, urls, method.toUpperCase(), renderedHeaders, concurrency);
|
|
119
|
+
for (let i = 0; i < results.length; i++) {
|
|
120
|
+
const r = results[i];
|
|
121
|
+
if (r && typeof r === 'object' && 'error' in r) {
|
|
122
|
+
log.warn(`Batch fetch failed for ${urls[i]}: ${r.error}`);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
return results;
|
|
115
126
|
}
|
|
116
127
|
// Non-browser: use concurrent pool (already optimized)
|
|
117
128
|
return mapConcurrent(data, concurrency, async (item, index) => {
|
|
118
129
|
const itemUrl = String(render(urlTemplate, { args, data, item, index }));
|
|
119
|
-
|
|
130
|
+
try {
|
|
131
|
+
return await fetchSingle(null, itemUrl, method, queryParams, headers, args, data);
|
|
132
|
+
}
|
|
133
|
+
catch (error) {
|
|
134
|
+
const message = getErrorMessage(error);
|
|
135
|
+
log.warn(`Batch fetch failed for ${itemUrl}: ${message}`);
|
|
136
|
+
return { error: message };
|
|
137
|
+
}
|
|
120
138
|
});
|
|
121
139
|
}
|
|
122
140
|
const url = render(urlOrObj, { args, data });
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|