@jackwener/opencli 1.7.3 → 1.7.5
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/README.md +81 -59
- package/README.zh-CN.md +93 -67
- package/cli-manifest.json +5015 -2975
- package/clis/antigravity/serve.js +71 -25
- package/clis/baidu-scholar/search.js +87 -0
- package/clis/baidu-scholar/search.test.js +23 -0
- package/clis/bilibili/favorite.js +18 -13
- package/clis/binance/depth.js +3 -4
- package/clis/boss/utils.js +2 -3
- package/clis/chatgpt-app/ax.js +6 -3
- package/clis/deepseek/ask.js +74 -0
- package/clis/deepseek/history.js +25 -0
- package/clis/deepseek/new.js +20 -0
- package/clis/deepseek/read.js +22 -0
- package/clis/deepseek/status.js +24 -0
- package/clis/deepseek/utils.js +208 -0
- package/clis/douban/search.js +1 -0
- package/clis/douban/search.test.js +11 -0
- package/clis/douban/subject.js +20 -93
- package/clis/douban/subject.test.js +11 -0
- package/clis/douban/utils.js +250 -8
- package/clis/douban/utils.test.js +179 -4
- package/clis/doubao/utils.js +319 -130
- package/clis/doubao/utils.test.js +241 -2
- package/clis/eastmoney/_secid.js +78 -0
- package/clis/eastmoney/announcement.js +52 -0
- package/clis/eastmoney/convertible.js +73 -0
- package/clis/eastmoney/etf.js +65 -0
- package/clis/eastmoney/holders.js +78 -0
- package/clis/eastmoney/hot-rank.js +50 -0
- package/clis/eastmoney/hot-rank.test.js +59 -0
- package/clis/eastmoney/index-board.js +96 -0
- package/clis/eastmoney/kline.js +87 -0
- package/clis/eastmoney/kuaixun.js +54 -0
- package/clis/eastmoney/longhu.js +67 -0
- package/clis/eastmoney/money-flow.js +78 -0
- package/clis/eastmoney/northbound.js +57 -0
- package/clis/eastmoney/quote.js +107 -0
- package/clis/eastmoney/rank.js +94 -0
- package/clis/eastmoney/sectors.js +76 -0
- package/clis/google-scholar/search.js +58 -0
- package/clis/google-scholar/search.test.js +23 -0
- package/clis/gov-law/commands.test.js +39 -0
- package/clis/gov-law/recent.js +22 -0
- package/clis/gov-law/search.js +41 -0
- package/clis/gov-law/shared.js +51 -0
- package/clis/gov-policy/commands.test.js +27 -0
- package/clis/gov-policy/recent.js +47 -0
- package/clis/gov-policy/search.js +48 -0
- package/clis/grok/image.test.ts +107 -0
- package/clis/grok/image.ts +356 -0
- package/clis/nowcoder/companies.js +23 -0
- package/clis/nowcoder/creators.js +27 -0
- package/clis/nowcoder/detail.js +61 -0
- package/clis/nowcoder/experience.js +36 -0
- package/clis/nowcoder/hot.js +24 -0
- package/clis/nowcoder/jobs.js +21 -0
- package/clis/nowcoder/notifications.js +29 -0
- package/clis/nowcoder/papers.js +40 -0
- package/clis/nowcoder/practice.js +37 -0
- package/clis/nowcoder/recommend.js +30 -0
- package/clis/nowcoder/referral.js +39 -0
- package/clis/nowcoder/salary.js +40 -0
- package/clis/nowcoder/search.js +49 -0
- package/clis/nowcoder/suggest.js +33 -0
- package/clis/nowcoder/topics.js +27 -0
- package/clis/nowcoder/trending.js +25 -0
- package/clis/tdx/hot-rank.js +47 -0
- package/clis/tdx/hot-rank.test.js +59 -0
- package/clis/ths/hot-rank.js +49 -0
- package/clis/ths/hot-rank.test.js +64 -0
- package/clis/twitter/bookmarks.js +2 -1
- package/clis/twitter/list-add.js +337 -0
- package/clis/twitter/list-add.test.js +15 -0
- package/clis/twitter/list-remove.js +297 -0
- package/clis/twitter/list-remove.test.js +14 -0
- package/clis/twitter/list-tweets.js +185 -0
- package/clis/twitter/list-tweets.test.js +108 -0
- package/clis/twitter/lists.js +134 -47
- package/clis/twitter/lists.test.js +105 -38
- package/clis/uiverse/_shared.js +368 -0
- package/clis/uiverse/_shared.test.js +55 -0
- package/clis/uiverse/code.js +47 -0
- package/clis/uiverse/preview.js +71 -0
- package/clis/wanfang/search.js +66 -0
- package/clis/wanfang/search.test.js +23 -0
- package/clis/web/read.js +1 -1
- package/clis/weixin/download.js +3 -2
- package/clis/xiaohongshu/comments.js +2 -2
- package/clis/xiaohongshu/comments.test.js +46 -25
- package/clis/xiaohongshu/download.js +6 -7
- package/clis/xiaohongshu/download.test.js +17 -5
- package/clis/xiaohongshu/note-helpers.js +46 -12
- package/clis/xiaohongshu/note.js +3 -5
- package/clis/xiaohongshu/note.test.js +52 -25
- package/clis/xiaohongshu/publish.js +149 -28
- package/clis/xiaohongshu/publish.test.js +319 -6
- package/clis/xiaoyuzhou/auth.js +303 -0
- package/clis/xiaoyuzhou/auth.test.js +124 -0
- package/clis/xiaoyuzhou/download.js +53 -0
- package/clis/xiaoyuzhou/download.test.js +135 -0
- package/clis/xiaoyuzhou/episode.js +9 -4
- package/clis/xiaoyuzhou/podcast-episodes.js +15 -11
- package/clis/xiaoyuzhou/podcast.js +9 -4
- package/clis/xiaoyuzhou/transcript.js +76 -0
- package/clis/xiaoyuzhou/transcript.test.js +195 -0
- package/clis/xiaoyuzhou/utils.js +0 -40
- package/clis/xiaoyuzhou/utils.test.js +15 -75
- package/clis/youtube/feed.js +120 -0
- package/clis/youtube/history.js +118 -0
- package/clis/youtube/like.js +62 -0
- package/clis/youtube/playlist.js +97 -0
- package/clis/youtube/subscribe.js +71 -0
- package/clis/youtube/subscriptions.js +57 -0
- package/clis/youtube/unlike.js +62 -0
- package/clis/youtube/unsubscribe.js +71 -0
- package/clis/youtube/utils.js +122 -0
- package/clis/youtube/utils.test.js +32 -1
- package/clis/youtube/watch-later.js +76 -0
- package/clis/zsxq/dynamics.js +1 -1
- package/clis/zsxq/utils.js +6 -3
- package/clis/zsxq/utils.test.js +31 -0
- package/dist/src/browser/base-page.d.ts +1 -1
- package/dist/src/browser/base-page.js +25 -5
- package/dist/src/browser/bridge.d.ts +3 -0
- package/dist/src/browser/bridge.js +52 -15
- package/dist/src/browser/cdp.js +2 -1
- package/dist/src/browser/daemon-client.d.ts +7 -4
- package/dist/src/browser/daemon-client.js +6 -1
- package/dist/src/browser/daemon-client.test.js +40 -1
- package/dist/src/browser/dom-snapshot.js +20 -3
- package/dist/src/browser/page.d.ts +18 -5
- package/dist/src/browser/page.js +96 -15
- package/dist/src/browser/page.test.js +158 -1
- package/dist/src/browser/target-errors.d.ts +23 -0
- package/dist/src/browser/target-errors.js +29 -0
- package/dist/src/browser/target-errors.test.js +61 -0
- package/dist/src/browser/target-resolver.d.ts +57 -0
- package/dist/src/browser/target-resolver.js +298 -0
- package/dist/src/browser/target-resolver.test.js +43 -0
- package/dist/src/browser.test.js +38 -1
- package/dist/src/cli.js +272 -187
- package/dist/src/cli.test.js +167 -90
- package/dist/src/commanderAdapter.d.ts +0 -1
- package/dist/src/commanderAdapter.js +2 -16
- package/dist/src/commanderAdapter.test.js +1 -1
- package/dist/src/commands/daemon.d.ts +4 -2
- package/dist/src/commands/daemon.js +22 -2
- package/dist/src/commands/daemon.test.js +65 -2
- package/dist/src/completion-shared.js +2 -5
- package/dist/src/daemon.js +10 -0
- package/dist/src/doctor.d.ts +1 -0
- package/dist/src/doctor.js +32 -9
- package/dist/src/doctor.test.js +28 -12
- package/dist/src/download/article-download.d.ts +1 -0
- package/dist/src/download/article-download.js +3 -0
- package/dist/src/download/article-download.test.js +39 -0
- package/dist/src/external-clis.yaml +2 -2
- package/dist/src/logger.d.ts +2 -2
- package/dist/src/logger.js +3 -3
- package/dist/src/output.js +1 -5
- package/dist/src/output.test.js +0 -21
- package/dist/src/pipeline/steps/transform.js +1 -1
- package/dist/src/pipeline/template.d.ts +1 -0
- package/dist/src/pipeline/template.js +11 -3
- package/dist/src/pipeline/template.test.js +3 -0
- package/dist/src/pipeline/transform.test.js +14 -0
- package/dist/src/plugin.d.ts +8 -9
- package/dist/src/plugin.js +24 -28
- package/dist/src/plugin.test.js +16 -60
- package/dist/src/registry.d.ts +1 -0
- package/dist/src/registry.js +3 -2
- package/dist/src/registry.test.js +22 -0
- package/dist/src/types.d.ts +15 -6
- package/package.json +1 -1
- package/clis/twitter/lists-parser.js +0 -77
- package/clis/twitter/lists.d.ts +0 -5
- package/dist/src/cascade.d.ts +0 -46
- package/dist/src/cascade.js +0 -135
- package/dist/src/explore.d.ts +0 -99
- package/dist/src/explore.js +0 -402
- package/dist/src/generate-verified.d.ts +0 -105
- package/dist/src/generate-verified.js +0 -696
- package/dist/src/generate-verified.test.js +0 -925
- package/dist/src/generate.d.ts +0 -46
- package/dist/src/generate.js +0 -117
- package/dist/src/record.d.ts +0 -96
- package/dist/src/record.js +0 -657
- package/dist/src/record.test.js +0 -293
- package/dist/src/skill-generate.d.ts +0 -30
- package/dist/src/skill-generate.js +0 -75
- package/dist/src/skill-generate.test.js +0 -173
- package/dist/src/synthesize.d.ts +0 -97
- package/dist/src/synthesize.js +0 -208
- /package/dist/src/{generate-verified.test.d.ts → browser/target-errors.test.d.ts} +0 -0
- /package/dist/src/{record.test.d.ts → browser/target-resolver.test.d.ts} +0 -0
- /package/dist/src/{skill-generate.test.d.ts → download/article-download.test.d.ts} +0 -0
|
@@ -43,6 +43,17 @@ describe('cli() registration', () => {
|
|
|
43
43
|
});
|
|
44
44
|
expect(cmd.strategy).toBe(Strategy.PUBLIC);
|
|
45
45
|
});
|
|
46
|
+
it('preserves LOCAL strategy on registration', () => {
|
|
47
|
+
const cmd = cli({
|
|
48
|
+
site: 'test-registry',
|
|
49
|
+
name: 'local-strategy',
|
|
50
|
+
description: 'reads local credentials',
|
|
51
|
+
strategy: Strategy.LOCAL,
|
|
52
|
+
browser: false,
|
|
53
|
+
});
|
|
54
|
+
expect(cmd.strategy).toBe(Strategy.LOCAL);
|
|
55
|
+
expect(cmd.browser).toBe(false);
|
|
56
|
+
});
|
|
46
57
|
it('overwrites existing command on re-registration', () => {
|
|
47
58
|
cli({ site: 'test-registry', name: 'overwrite', description: 'v1' });
|
|
48
59
|
cli({ site: 'test-registry', name: 'overwrite', description: 'v2' });
|
|
@@ -148,6 +159,17 @@ describe('normalizeCommand (via registerCommand)', () => {
|
|
|
148
159
|
expect(cmd.browser).toBe(false);
|
|
149
160
|
expect(cmd.navigateBefore).toBeUndefined();
|
|
150
161
|
});
|
|
162
|
+
it('LOCAL → browser false, navigateBefore undefined', () => {
|
|
163
|
+
registerCommand({
|
|
164
|
+
site: 'test-norm', name: 'local', description: '', args: [],
|
|
165
|
+
strategy: Strategy.LOCAL,
|
|
166
|
+
});
|
|
167
|
+
const cmd = getRegistry().get('test-norm/local');
|
|
168
|
+
expect(cmd.strategy).toBe(Strategy.LOCAL);
|
|
169
|
+
expect(strategyLabel(cmd)).toBe('local');
|
|
170
|
+
expect(cmd.browser).toBe(false);
|
|
171
|
+
expect(cmd.navigateBefore).toBeUndefined();
|
|
172
|
+
});
|
|
151
173
|
it('explicit navigateBefore: false overrides COOKIE + domain', () => {
|
|
152
174
|
registerCommand({
|
|
153
175
|
site: 'test-norm', name: 'cookie-override', description: '', args: [],
|
package/dist/src/types.d.ts
CHANGED
|
@@ -58,9 +58,9 @@ export interface IPage {
|
|
|
58
58
|
getFormState(): Promise<any>;
|
|
59
59
|
wait(options: number | WaitOptions): Promise<void>;
|
|
60
60
|
tabs(): Promise<any>;
|
|
61
|
-
closeTab?(
|
|
62
|
-
newTab?(): Promise<
|
|
63
|
-
selectTab(
|
|
61
|
+
closeTab?(target?: number | string): Promise<void>;
|
|
62
|
+
newTab?(url?: string): Promise<string | undefined>;
|
|
63
|
+
selectTab(target: number | string): Promise<void>;
|
|
64
64
|
networkRequests(includeStatic?: boolean): Promise<any>;
|
|
65
65
|
consoleMessages(level?: string): Promise<any>;
|
|
66
66
|
scroll(direction?: string, amount?: number): Promise<void>;
|
|
@@ -72,7 +72,7 @@ export interface IPage {
|
|
|
72
72
|
getInterceptedRequests(): Promise<any[]>;
|
|
73
73
|
waitForCapture(timeout?: number): Promise<void>;
|
|
74
74
|
screenshot(options?: ScreenshotOptions): Promise<string>;
|
|
75
|
-
startNetworkCapture?(pattern?: string): Promise<
|
|
75
|
+
startNetworkCapture?(pattern?: string): Promise<boolean>;
|
|
76
76
|
readNetworkCapture?(): Promise<unknown[]>;
|
|
77
77
|
/**
|
|
78
78
|
* Set local file paths on a file input element via CDP DOM.setFileInputFiles.
|
|
@@ -89,10 +89,19 @@ export interface IPage {
|
|
|
89
89
|
getCurrentUrl?(): Promise<string | null>;
|
|
90
90
|
/** Returns the active page identity (targetId), or undefined if not yet resolved. */
|
|
91
91
|
getActivePage?(): string | undefined;
|
|
92
|
-
/**
|
|
93
|
-
|
|
92
|
+
/** Bind the page object to a specific page identity (targetId). */
|
|
93
|
+
setActivePage?(page?: string): void;
|
|
94
94
|
/** Send a raw CDP command via chrome.debugger passthrough. */
|
|
95
95
|
cdp?(method: string, params?: Record<string, unknown>): Promise<unknown>;
|
|
96
|
+
/** List cross-origin iframe targets in snapshot order. */
|
|
97
|
+
frames?(): Promise<Array<{
|
|
98
|
+
index: number;
|
|
99
|
+
frameId: string;
|
|
100
|
+
url: string;
|
|
101
|
+
name: string;
|
|
102
|
+
}>>;
|
|
103
|
+
/** Evaluate JavaScript inside a cross-origin iframe identified by its frame index. */
|
|
104
|
+
evaluateInFrame?(js: string, frameIndex: number): Promise<unknown>;
|
|
96
105
|
/** Click at native coordinates via CDP Input.dispatchMouseEvent. */
|
|
97
106
|
nativeClick?(x: number, y: number): Promise<void>;
|
|
98
107
|
/** Type text via CDP Input.insertText. */
|
package/package.json
CHANGED
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
const MEMBER_PATTERNS = [
|
|
2
|
-
/([\d.,]+(?:\s?[KMB千萬万亿])?)\s*members?/i,
|
|
3
|
-
/([\d.,]+(?:\s?[KMB千萬万亿])?)\s*位成员/,
|
|
4
|
-
];
|
|
5
|
-
const FOLLOWER_PATTERNS = [
|
|
6
|
-
/([\d.,]+(?:\s?[KMB千萬万亿])?)\s*followers?/i,
|
|
7
|
-
/([\d.,]+(?:\s?[KMB千萬万亿])?)\s*位关注者/,
|
|
8
|
-
];
|
|
9
|
-
const PRIVATE_PATTERNS = [/\bprivate\b/i, /锁定列表/];
|
|
10
|
-
const EMPTY_STATE_PATTERNS = [
|
|
11
|
-
/hasn't created any lists/i,
|
|
12
|
-
/has not created any lists/i,
|
|
13
|
-
/no lists yet/i,
|
|
14
|
-
/没有创建任何列表/,
|
|
15
|
-
/还没有创建任何列表/,
|
|
16
|
-
];
|
|
17
|
-
function normalizeText(text) {
|
|
18
|
-
return String(text || '').replace(/\s+/g, ' ').trim();
|
|
19
|
-
}
|
|
20
|
-
function matchMetric(text, patterns) {
|
|
21
|
-
for (const pattern of patterns) {
|
|
22
|
-
const match = text.match(pattern);
|
|
23
|
-
if (match)
|
|
24
|
-
return normalizeText(match[1]);
|
|
25
|
-
}
|
|
26
|
-
return '0';
|
|
27
|
-
}
|
|
28
|
-
function looksLikeMetadata(line) {
|
|
29
|
-
const text = normalizeText(line);
|
|
30
|
-
if (!text)
|
|
31
|
-
return true;
|
|
32
|
-
if (text.startsWith('@'))
|
|
33
|
-
return true;
|
|
34
|
-
if (MEMBER_PATTERNS.some((pattern) => pattern.test(text)))
|
|
35
|
-
return true;
|
|
36
|
-
if (FOLLOWER_PATTERNS.some((pattern) => pattern.test(text)))
|
|
37
|
-
return true;
|
|
38
|
-
if (PRIVATE_PATTERNS.some((pattern) => pattern.test(text)))
|
|
39
|
-
return true;
|
|
40
|
-
if (/^(public|pinned)$/i.test(text))
|
|
41
|
-
return true;
|
|
42
|
-
if (/^(lists?|你的列表)$/i.test(text))
|
|
43
|
-
return true;
|
|
44
|
-
return false;
|
|
45
|
-
}
|
|
46
|
-
export function parseListCards(cards) {
|
|
47
|
-
const seen = new Set();
|
|
48
|
-
const results = [];
|
|
49
|
-
for (const card of cards || []) {
|
|
50
|
-
const href = normalizeText(card?.href);
|
|
51
|
-
const rawText = String(card?.text || '');
|
|
52
|
-
if (!href || seen.has(href))
|
|
53
|
-
continue;
|
|
54
|
-
seen.add(href);
|
|
55
|
-
const text = normalizeText(rawText);
|
|
56
|
-
if (!text)
|
|
57
|
-
continue;
|
|
58
|
-
const lines = rawText
|
|
59
|
-
.split('\n')
|
|
60
|
-
.map((line) => normalizeText(line))
|
|
61
|
-
.filter(Boolean);
|
|
62
|
-
const name = lines.find((line) => !looksLikeMetadata(line));
|
|
63
|
-
if (!name)
|
|
64
|
-
continue;
|
|
65
|
-
results.push({
|
|
66
|
-
name,
|
|
67
|
-
members: matchMetric(text, MEMBER_PATTERNS),
|
|
68
|
-
followers: matchMetric(text, FOLLOWER_PATTERNS),
|
|
69
|
-
mode: PRIVATE_PATTERNS.some((pattern) => pattern.test(text)) ? 'private' : 'public',
|
|
70
|
-
});
|
|
71
|
-
}
|
|
72
|
-
return results;
|
|
73
|
-
}
|
|
74
|
-
export function isEmptyListsState(text) {
|
|
75
|
-
const normalized = normalizeText(text);
|
|
76
|
-
return EMPTY_STATE_PATTERNS.some((pattern) => pattern.test(normalized));
|
|
77
|
-
}
|
package/clis/twitter/lists.d.ts
DELETED
package/dist/src/cascade.d.ts
DELETED
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Strategy Cascade: automatic strategy downgrade chain.
|
|
3
|
-
*
|
|
4
|
-
* Probes an API endpoint starting from the simplest strategy (PUBLIC)
|
|
5
|
-
* and automatically downgrades through the strategy tiers until one works:
|
|
6
|
-
*
|
|
7
|
-
* PUBLIC → COOKIE → HEADER → INTERCEPT → UI
|
|
8
|
-
*
|
|
9
|
-
* This eliminates the need for manual strategy selection — the system
|
|
10
|
-
* automatically finds the minimum-privilege strategy that works.
|
|
11
|
-
*/
|
|
12
|
-
import { Strategy } from './registry.js';
|
|
13
|
-
import type { IPage } from './types.js';
|
|
14
|
-
interface ProbeResult {
|
|
15
|
-
strategy: Strategy;
|
|
16
|
-
success: boolean;
|
|
17
|
-
statusCode?: number;
|
|
18
|
-
hasData?: boolean;
|
|
19
|
-
error?: string;
|
|
20
|
-
responsePreview?: string;
|
|
21
|
-
}
|
|
22
|
-
interface CascadeResult {
|
|
23
|
-
bestStrategy: Strategy;
|
|
24
|
-
probes: ProbeResult[];
|
|
25
|
-
confidence: number;
|
|
26
|
-
}
|
|
27
|
-
/**
|
|
28
|
-
* Probe an endpoint with a specific strategy.
|
|
29
|
-
* Returns whether the probe succeeded and basic response info.
|
|
30
|
-
*/
|
|
31
|
-
export declare function probeEndpoint(page: IPage, url: string, strategy: Strategy, _opts?: {
|
|
32
|
-
timeout?: number;
|
|
33
|
-
}): Promise<ProbeResult>;
|
|
34
|
-
/**
|
|
35
|
-
* Run the cascade: try each strategy in order until one works.
|
|
36
|
-
* Returns the simplest working strategy.
|
|
37
|
-
*/
|
|
38
|
-
export declare function cascadeProbe(page: IPage, url: string, opts?: {
|
|
39
|
-
maxStrategy?: Strategy;
|
|
40
|
-
timeout?: number;
|
|
41
|
-
}): Promise<CascadeResult>;
|
|
42
|
-
/**
|
|
43
|
-
* Render cascade results for display.
|
|
44
|
-
*/
|
|
45
|
-
export declare function renderCascadeResult(result: CascadeResult): string;
|
|
46
|
-
export {};
|
package/dist/src/cascade.js
DELETED
|
@@ -1,135 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Strategy Cascade: automatic strategy downgrade chain.
|
|
3
|
-
*
|
|
4
|
-
* Probes an API endpoint starting from the simplest strategy (PUBLIC)
|
|
5
|
-
* and automatically downgrades through the strategy tiers until one works:
|
|
6
|
-
*
|
|
7
|
-
* PUBLIC → COOKIE → HEADER → INTERCEPT → UI
|
|
8
|
-
*
|
|
9
|
-
* This eliminates the need for manual strategy selection — the system
|
|
10
|
-
* automatically finds the minimum-privilege strategy that works.
|
|
11
|
-
*/
|
|
12
|
-
import { Strategy } from './registry.js';
|
|
13
|
-
import { getErrorMessage } from './errors.js';
|
|
14
|
-
/** Strategy cascade order (simplest → most complex) */
|
|
15
|
-
const CASCADE_ORDER = [
|
|
16
|
-
Strategy.PUBLIC,
|
|
17
|
-
Strategy.COOKIE,
|
|
18
|
-
Strategy.HEADER,
|
|
19
|
-
Strategy.INTERCEPT,
|
|
20
|
-
Strategy.UI,
|
|
21
|
-
];
|
|
22
|
-
/**
|
|
23
|
-
* Build the JavaScript source for a fetch probe.
|
|
24
|
-
* Shared logic for PUBLIC, COOKIE, and HEADER strategies.
|
|
25
|
-
*/
|
|
26
|
-
function buildFetchProbeJs(url, opts) {
|
|
27
|
-
const credentialsLine = opts.credentials ? `credentials: 'include',` : '';
|
|
28
|
-
const headerSetup = opts.extractCsrf
|
|
29
|
-
? `
|
|
30
|
-
const cookies = document.cookie.split(';').map(c => c.trim());
|
|
31
|
-
const csrf = cookies.find(c => c.startsWith('ct0=') || c.startsWith('csrf_token=') || c.startsWith('_csrf='))?.split('=').slice(1).join('=');
|
|
32
|
-
const headers = {};
|
|
33
|
-
if (csrf) { headers['X-Csrf-Token'] = csrf; headers['X-XSRF-Token'] = csrf; }
|
|
34
|
-
`
|
|
35
|
-
: 'const headers = {};';
|
|
36
|
-
return `
|
|
37
|
-
async () => {
|
|
38
|
-
try {
|
|
39
|
-
${headerSetup}
|
|
40
|
-
const resp = await fetch(${JSON.stringify(url)}, {
|
|
41
|
-
${credentialsLine}
|
|
42
|
-
headers
|
|
43
|
-
});
|
|
44
|
-
const status = resp.status;
|
|
45
|
-
if (!resp.ok) return { status, ok: false };
|
|
46
|
-
const text = await resp.text();
|
|
47
|
-
let hasData = false;
|
|
48
|
-
try {
|
|
49
|
-
const json = JSON.parse(text);
|
|
50
|
-
hasData = !!json && (Array.isArray(json) ? json.length > 0 :
|
|
51
|
-
typeof json === 'object' && Object.keys(json).length > 0);
|
|
52
|
-
// Check for API-level error codes (common in Chinese sites)
|
|
53
|
-
if (json.code !== undefined && json.code !== 0) hasData = false;
|
|
54
|
-
} catch {}
|
|
55
|
-
return { status, ok: true, hasData, preview: text.slice(0, 200) };
|
|
56
|
-
} catch (e) { return { ok: false, error: e.message }; }
|
|
57
|
-
}
|
|
58
|
-
`;
|
|
59
|
-
}
|
|
60
|
-
/** Strategy → fetch probe options mapping for strategies that support probing. */
|
|
61
|
-
const PROBE_OPTIONS = {
|
|
62
|
-
[Strategy.PUBLIC]: {},
|
|
63
|
-
[Strategy.COOKIE]: { credentials: true },
|
|
64
|
-
[Strategy.HEADER]: { credentials: true, extractCsrf: true },
|
|
65
|
-
};
|
|
66
|
-
/**
|
|
67
|
-
* Probe an endpoint with a specific strategy.
|
|
68
|
-
* Returns whether the probe succeeded and basic response info.
|
|
69
|
-
*/
|
|
70
|
-
export async function probeEndpoint(page, url, strategy, _opts = {}) {
|
|
71
|
-
const result = { strategy, success: false };
|
|
72
|
-
try {
|
|
73
|
-
const opts = PROBE_OPTIONS[strategy];
|
|
74
|
-
if (opts) {
|
|
75
|
-
const resp = (await page.evaluate(buildFetchProbeJs(url, opts)));
|
|
76
|
-
result.statusCode = resp?.status;
|
|
77
|
-
result.success = !!(resp?.ok && resp?.hasData);
|
|
78
|
-
result.hasData = resp?.hasData;
|
|
79
|
-
result.responsePreview = resp?.preview;
|
|
80
|
-
}
|
|
81
|
-
else {
|
|
82
|
-
// INTERCEPT / UI require site-specific implementation.
|
|
83
|
-
result.error = `Strategy ${strategy} requires site-specific implementation`;
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
catch (err) {
|
|
87
|
-
result.success = false;
|
|
88
|
-
result.error = getErrorMessage(err);
|
|
89
|
-
}
|
|
90
|
-
return result;
|
|
91
|
-
}
|
|
92
|
-
/**
|
|
93
|
-
* Run the cascade: try each strategy in order until one works.
|
|
94
|
-
* Returns the simplest working strategy.
|
|
95
|
-
*/
|
|
96
|
-
export async function cascadeProbe(page, url, opts = {}) {
|
|
97
|
-
const rawIdx = opts.maxStrategy
|
|
98
|
-
? CASCADE_ORDER.indexOf(opts.maxStrategy)
|
|
99
|
-
: CASCADE_ORDER.indexOf(Strategy.HEADER); // Don't auto-try INTERCEPT/UI
|
|
100
|
-
const maxIdx = rawIdx === -1 ? CASCADE_ORDER.indexOf(Strategy.HEADER) : rawIdx;
|
|
101
|
-
const probes = [];
|
|
102
|
-
for (let i = 0; i <= Math.min(maxIdx, CASCADE_ORDER.length - 1); i++) {
|
|
103
|
-
const strategy = CASCADE_ORDER[i];
|
|
104
|
-
const probe = await probeEndpoint(page, url, strategy, opts);
|
|
105
|
-
probes.push(probe);
|
|
106
|
-
if (probe.success) {
|
|
107
|
-
return {
|
|
108
|
-
bestStrategy: strategy,
|
|
109
|
-
probes,
|
|
110
|
-
confidence: 1.0 - (i * 0.1), // Higher confidence for simpler strategies
|
|
111
|
-
};
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
// None worked — default to COOKIE (most common for logged-in sites)
|
|
115
|
-
return {
|
|
116
|
-
bestStrategy: Strategy.COOKIE,
|
|
117
|
-
probes,
|
|
118
|
-
confidence: 0.3,
|
|
119
|
-
};
|
|
120
|
-
}
|
|
121
|
-
/**
|
|
122
|
-
* Render cascade results for display.
|
|
123
|
-
*/
|
|
124
|
-
export function renderCascadeResult(result) {
|
|
125
|
-
const lines = [
|
|
126
|
-
`Strategy Cascade: ${result.bestStrategy} (${(result.confidence * 100).toFixed(0)}% confidence)`,
|
|
127
|
-
];
|
|
128
|
-
for (const probe of result.probes) {
|
|
129
|
-
const icon = probe.success ? '✅' : '❌';
|
|
130
|
-
const status = probe.statusCode ? ` [${probe.statusCode}]` : '';
|
|
131
|
-
const err = probe.error ? ` — ${probe.error}` : '';
|
|
132
|
-
lines.push(` ${icon} ${probe.strategy}${status}${err}`);
|
|
133
|
-
}
|
|
134
|
-
return lines.join('\n');
|
|
135
|
-
}
|
package/dist/src/explore.d.ts
DELETED
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Deep Explore: intelligent API discovery with response analysis.
|
|
3
|
-
*
|
|
4
|
-
* Navigates to the target URL, auto-scrolls to trigger lazy loading,
|
|
5
|
-
* captures network traffic, analyzes JSON responses, and automatically
|
|
6
|
-
* infers CLI capabilities from discovered API endpoints.
|
|
7
|
-
*/
|
|
8
|
-
import type { IBrowserFactory } from './runtime.js';
|
|
9
|
-
export declare function detectSiteName(url: string): string;
|
|
10
|
-
export declare function slugify(value: string): string;
|
|
11
|
-
interface InferredCapability {
|
|
12
|
-
name: string;
|
|
13
|
-
description: string;
|
|
14
|
-
strategy: string;
|
|
15
|
-
endpoint: string;
|
|
16
|
-
itemPath: string | null;
|
|
17
|
-
recommendedColumns: string[];
|
|
18
|
-
recommendedArgs: Array<{
|
|
19
|
-
name: string;
|
|
20
|
-
type: string;
|
|
21
|
-
required: boolean;
|
|
22
|
-
default?: unknown;
|
|
23
|
-
}>;
|
|
24
|
-
storeHint?: {
|
|
25
|
-
store: string;
|
|
26
|
-
action: string;
|
|
27
|
-
};
|
|
28
|
-
}
|
|
29
|
-
export interface ExploreManifest {
|
|
30
|
-
site: string;
|
|
31
|
-
target_url: string;
|
|
32
|
-
final_url: string;
|
|
33
|
-
title: string;
|
|
34
|
-
framework: Record<string, boolean>;
|
|
35
|
-
stores: Array<{
|
|
36
|
-
type: DiscoveredStore['type'];
|
|
37
|
-
id: string;
|
|
38
|
-
actions: string[];
|
|
39
|
-
}>;
|
|
40
|
-
top_strategy: string;
|
|
41
|
-
explored_at?: string;
|
|
42
|
-
}
|
|
43
|
-
export interface ExploreAuthSummary {
|
|
44
|
-
top_strategy: string;
|
|
45
|
-
indicators: string[];
|
|
46
|
-
framework: Record<string, boolean>;
|
|
47
|
-
}
|
|
48
|
-
export interface ExploreEndpointArtifact {
|
|
49
|
-
pattern: string;
|
|
50
|
-
method: string;
|
|
51
|
-
url: string;
|
|
52
|
-
status: number | null;
|
|
53
|
-
contentType: string;
|
|
54
|
-
queryParams: string[];
|
|
55
|
-
itemPath: string | null;
|
|
56
|
-
itemCount: number;
|
|
57
|
-
detectedFields: Record<string, string>;
|
|
58
|
-
authIndicators: string[];
|
|
59
|
-
}
|
|
60
|
-
export interface ExploreResult {
|
|
61
|
-
site: string;
|
|
62
|
-
target_url: string;
|
|
63
|
-
final_url: string;
|
|
64
|
-
title: string;
|
|
65
|
-
framework: Record<string, boolean>;
|
|
66
|
-
stores: DiscoveredStore[];
|
|
67
|
-
top_strategy: string;
|
|
68
|
-
endpoint_count: number;
|
|
69
|
-
api_endpoint_count: number;
|
|
70
|
-
capabilities: InferredCapability[];
|
|
71
|
-
auth_indicators: string[];
|
|
72
|
-
out_dir: string;
|
|
73
|
-
}
|
|
74
|
-
export interface ExploreBundle {
|
|
75
|
-
manifest: ExploreManifest;
|
|
76
|
-
endpoints: ExploreEndpointArtifact[];
|
|
77
|
-
capabilities: InferredCapability[];
|
|
78
|
-
auth: ExploreAuthSummary;
|
|
79
|
-
}
|
|
80
|
-
export interface DiscoveredStore {
|
|
81
|
-
type: 'pinia' | 'vuex';
|
|
82
|
-
id: string;
|
|
83
|
-
actions: string[];
|
|
84
|
-
stateKeys: string[];
|
|
85
|
-
}
|
|
86
|
-
export declare function exploreUrl(url: string, opts: {
|
|
87
|
-
BrowserFactory: new () => IBrowserFactory;
|
|
88
|
-
site?: string;
|
|
89
|
-
goal?: string;
|
|
90
|
-
authenticated?: boolean;
|
|
91
|
-
outDir?: string;
|
|
92
|
-
waitSeconds?: number;
|
|
93
|
-
query?: string;
|
|
94
|
-
clickLabels?: string[];
|
|
95
|
-
auto?: boolean;
|
|
96
|
-
workspace?: string;
|
|
97
|
-
}): Promise<ExploreResult>;
|
|
98
|
-
export declare function renderExploreSummary(result: ExploreResult): string;
|
|
99
|
-
export {};
|