@opencraw/cli 0.1.12 → 0.1.14
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/dist/index.esm.js +46 -1
- package/dist/src/arguments/command.contract.d.ts +4 -0
- package/dist/src/arguments/parse-arguments.algorithm.d.ts +1 -1
- package/dist/src/index.d.ts +2 -0
- package/dist/src/studio/index.d.ts +3 -0
- package/dist/src/studio/run-studio.use-case.d.ts +22 -0
- package/package.json +10 -2
package/dist/index.esm.js
CHANGED
|
@@ -12,6 +12,8 @@ Commands
|
|
|
12
12
|
run <recipe files or directories...> Crawl. Records go to --out as JSON Lines, or to stdout.
|
|
13
13
|
probe <url> Fetch a page and report where its data lives.
|
|
14
14
|
diff <previous.jsonl> <current.jsonl> Compare two runs' records by key: added, removed, changed.
|
|
15
|
+
studio [folder] Open a recipe folder in the browser: run samples, read
|
|
16
|
+
the trace next to the page (needs @opencraw/studio).
|
|
15
17
|
|
|
16
18
|
Options for run
|
|
17
19
|
--out <file> Write records to this JSON Lines file (default: stdout).
|
|
@@ -236,6 +238,14 @@ function parseArguments(argv, env = {}) {
|
|
|
236
238
|
options
|
|
237
239
|
};
|
|
238
240
|
}
|
|
241
|
+
case 'studio':
|
|
242
|
+
{
|
|
243
|
+
if (rest.length > 1) throw new Error('studio takes at most one folder');
|
|
244
|
+
return {
|
|
245
|
+
name: 'studio',
|
|
246
|
+
folder: rest[0]
|
|
247
|
+
};
|
|
248
|
+
}
|
|
239
249
|
default:
|
|
240
250
|
{
|
|
241
251
|
throw new Error(`unknown command "${name}"`);
|
|
@@ -1403,6 +1413,37 @@ function loadErrorLines(error) {
|
|
|
1403
1413
|
return [error instanceof Error ? error.message : String(error)];
|
|
1404
1414
|
}
|
|
1405
1415
|
|
|
1416
|
+
/**
|
|
1417
|
+
* Runs `opencraw studio [folder]`: imports `@opencraw/studio` lazily and
|
|
1418
|
+
* delegates to its own `main`, which starts the server, prints the URL with
|
|
1419
|
+
* the token, and keeps running until interrupted (Ctrl+C) — the cli's own
|
|
1420
|
+
* call does not return before that. `@opencraw/studio` is an optional peer
|
|
1421
|
+
* dependency (`peerDependenciesMeta`), never a hard one: the cli stays light
|
|
1422
|
+
* for callers who only need to crawl. When it is not installed, this prints
|
|
1423
|
+
* how to add it instead of letting a raw `ERR_MODULE_NOT_FOUND` stack trace
|
|
1424
|
+
* through.
|
|
1425
|
+
*
|
|
1426
|
+
* @param folder - The recipe folder to open; `@opencraw/studio`'s own default (the current directory) when omitted.
|
|
1427
|
+
* @param terminal - Where output goes.
|
|
1428
|
+
* @param importStudio - How the module is loaded; the real dynamic `import()` by default, replaced in tests.
|
|
1429
|
+
* @returns The exit code: 0 once the server has stopped, 1 when `@opencraw/studio` is missing.
|
|
1430
|
+
*/
|
|
1431
|
+
async function runStudio(folder, terminal, importStudio = () => import('@opencraw/studio')) {
|
|
1432
|
+
let studio;
|
|
1433
|
+
try {
|
|
1434
|
+
studio = await importStudio();
|
|
1435
|
+
} catch (error) {
|
|
1436
|
+
if (!isModuleNotFound(error)) throw error;
|
|
1437
|
+
terminal.err('the studio is not installed: run `npm install @opencraw/studio`, then try again');
|
|
1438
|
+
return 1;
|
|
1439
|
+
}
|
|
1440
|
+
await studio.main(folder === undefined ? [] : [folder]);
|
|
1441
|
+
return 0;
|
|
1442
|
+
}
|
|
1443
|
+
function isModuleNotFound(error) {
|
|
1444
|
+
return error instanceof Error && 'code' in error && error.code === 'ERR_MODULE_NOT_FOUND';
|
|
1445
|
+
}
|
|
1446
|
+
|
|
1406
1447
|
/**
|
|
1407
1448
|
* Loads and binds recipe files, printing every problem with its JSON path.
|
|
1408
1449
|
*
|
|
@@ -1496,6 +1537,10 @@ async function main(argv, terminal) {
|
|
|
1496
1537
|
{
|
|
1497
1538
|
return diffFiles(command, terminal);
|
|
1498
1539
|
}
|
|
1540
|
+
case 'studio':
|
|
1541
|
+
{
|
|
1542
|
+
return runStudio(command.folder, terminal);
|
|
1543
|
+
}
|
|
1499
1544
|
}
|
|
1500
1545
|
}
|
|
1501
1546
|
|
|
@@ -1511,5 +1556,5 @@ function processTerminal() {
|
|
|
1511
1556
|
};
|
|
1512
1557
|
}
|
|
1513
1558
|
|
|
1514
|
-
export { USAGE, diffReport, findData, loadForRun, loadHooks, loadPlugins, main, parseArguments, probeReport, probeUrl, processTerminal, readRecipeFiles, resolveAccess, writeChanges };
|
|
1559
|
+
export { USAGE, diffReport, findData, loadForRun, loadHooks, loadPlugins, main, parseArguments, probeReport, probeUrl, processTerminal, readRecipeFiles, resolveAccess, runStudio, writeChanges };
|
|
1515
1560
|
//# sourceMappingURL=index.esm.js.map
|
|
@@ -65,5 +65,9 @@ export type Command = {
|
|
|
65
65
|
/** Also render the page in a browser and watch the JSON it fetches. */
|
|
66
66
|
browser: boolean;
|
|
67
67
|
options: CommonOptions;
|
|
68
|
+
} | {
|
|
69
|
+
name: 'studio';
|
|
70
|
+
/** The recipe folder to open; the current directory when not given. */
|
|
71
|
+
folder?: string;
|
|
68
72
|
};
|
|
69
73
|
//# sourceMappingURL=command.contract.d.ts.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Command } from './command.contract.js';
|
|
2
|
-
export declare const USAGE = "opencraw <command> [options]\n\nCommands\n validate <recipe files or directories...> Parse and bind the recipes; list every problem with its path.\n run <recipe files or directories...> Crawl. Records go to --out as JSON Lines, or to stdout.\n probe <url> Fetch a page and report where its data lives.\n diff <previous.jsonl> <current.jsonl> Compare two runs' records by key: added, removed, changed.\n\nOptions for run\n --out <file> Write records to this JSON Lines file (default: stdout).\n --append Keep what --out holds and add to it (each line carries _key).\n --resume Skip records --out already has (needs --append).\n --only <id> Run only this input recipe (repeatable).\n --dry-run One record per input, printed with the scope it was mapped from.\n --trace Print the crawl trace to stderr.\n --headed Show the browser.\n --parallel <n> Run this many input recipes at once (default 1). Iterations inside a recipe\n follow its limits.concurrency.\n --retries <n> Tries per request that fails in passing (connection, timeout, 429, 5xx), for\n recipes whose limits.retry says nothing. Default 3; 1 turns retrying off.\n --profiles <dir> Where recipes' session.browserProfile profiles live (or OPENCRAW_PROFILES;\n default .opencraw/profiles).\n --diff <file> Compare this run's records with a previous run's JSON Lines file (it may be\n --out itself: it is read before the crawl). Keys come from the output recipe.\n --host-delay <ms> At least this long between two requests to one site, across every recipe.\n --host-concurrency <n>\n At most this many requests to one site in flight, across every recipe.\n Both override the access config's \"throttle\" defaults.\n\nOptions for diff\n --key <a,b> The fields that identify a record (default: each line's _key).\n --ignore <a,b> Fields left out of the comparison (a date the crawl stamps, say).\n --changes <file> Also write every change as a JSON line (run --diff takes it too).\n\nOptions for probe\n --browser Also render the page in a browser and list the JSON it fetches.\n\nOptions for both\n --browser-path <p> A browser binary other than the one Playwright installed (or OPENCRAW_CHROMIUM).\n --insecure-tls Accept an intercepting proxy's certificate (or OPENCRAW_INSECURE_TLS=1).\n --user-agent <ua> The user agent to send.\n --access <file> An access config: proxy profiles, credentials as {{env.NAME}} (or OPENCRAW_ACCESS).\n --access-profile <name>\n The access profile to use when a recipe names none.\n --plugins <file> A JavaScript module exporting hooks (the recipes' hook steps and transforms),\n accessPlugins (for { kind: \"plugin\" } access profiles) and captchaSolvers\n (for session.captcha and captcha steps); --hooks, or OPENCRAW_PLUGINS /\n OPENCRAW_HOOKS. It runs as your code: trust it.\n --help, --version";
|
|
2
|
+
export declare const USAGE = "opencraw <command> [options]\n\nCommands\n validate <recipe files or directories...> Parse and bind the recipes; list every problem with its path.\n run <recipe files or directories...> Crawl. Records go to --out as JSON Lines, or to stdout.\n probe <url> Fetch a page and report where its data lives.\n diff <previous.jsonl> <current.jsonl> Compare two runs' records by key: added, removed, changed.\n studio [folder] Open a recipe folder in the browser: run samples, read\n the trace next to the page (needs @opencraw/studio).\n\nOptions for run\n --out <file> Write records to this JSON Lines file (default: stdout).\n --append Keep what --out holds and add to it (each line carries _key).\n --resume Skip records --out already has (needs --append).\n --only <id> Run only this input recipe (repeatable).\n --dry-run One record per input, printed with the scope it was mapped from.\n --trace Print the crawl trace to stderr.\n --headed Show the browser.\n --parallel <n> Run this many input recipes at once (default 1). Iterations inside a recipe\n follow its limits.concurrency.\n --retries <n> Tries per request that fails in passing (connection, timeout, 429, 5xx), for\n recipes whose limits.retry says nothing. Default 3; 1 turns retrying off.\n --profiles <dir> Where recipes' session.browserProfile profiles live (or OPENCRAW_PROFILES;\n default .opencraw/profiles).\n --diff <file> Compare this run's records with a previous run's JSON Lines file (it may be\n --out itself: it is read before the crawl). Keys come from the output recipe.\n --host-delay <ms> At least this long between two requests to one site, across every recipe.\n --host-concurrency <n>\n At most this many requests to one site in flight, across every recipe.\n Both override the access config's \"throttle\" defaults.\n\nOptions for diff\n --key <a,b> The fields that identify a record (default: each line's _key).\n --ignore <a,b> Fields left out of the comparison (a date the crawl stamps, say).\n --changes <file> Also write every change as a JSON line (run --diff takes it too).\n\nOptions for probe\n --browser Also render the page in a browser and list the JSON it fetches.\n\nOptions for both\n --browser-path <p> A browser binary other than the one Playwright installed (or OPENCRAW_CHROMIUM).\n --insecure-tls Accept an intercepting proxy's certificate (or OPENCRAW_INSECURE_TLS=1).\n --user-agent <ua> The user agent to send.\n --access <file> An access config: proxy profiles, credentials as {{env.NAME}} (or OPENCRAW_ACCESS).\n --access-profile <name>\n The access profile to use when a recipe names none.\n --plugins <file> A JavaScript module exporting hooks (the recipes' hook steps and transforms),\n accessPlugins (for { kind: \"plugin\" } access profiles) and captchaSolvers\n (for session.captcha and captcha steps); --hooks, or OPENCRAW_PLUGINS /\n OPENCRAW_HOOKS. It runs as your code: trust it.\n --help, --version";
|
|
3
3
|
/**
|
|
4
4
|
* Turns argv into a command.
|
|
5
5
|
*
|
package/dist/src/index.d.ts
CHANGED
|
@@ -13,4 +13,6 @@ export type { CommonOptions } from './arguments/index.js';
|
|
|
13
13
|
export { resolveAccess } from './access/index.js';
|
|
14
14
|
export { loadHooks, loadPlugins } from './hooks-module/index.js';
|
|
15
15
|
export type { PluginModule } from './hooks-module/index.js';
|
|
16
|
+
export { runStudio } from './studio/index.js';
|
|
17
|
+
export type { StudioModule } from './studio/index.js';
|
|
16
18
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { Terminal } from '../terminal/index.js';
|
|
2
|
+
/** The one export the cli needs from `@opencraw/studio`. */
|
|
3
|
+
export interface StudioModule {
|
|
4
|
+
main: (argv: readonly string[]) => Promise<void>;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Runs `opencraw studio [folder]`: imports `@opencraw/studio` lazily and
|
|
8
|
+
* delegates to its own `main`, which starts the server, prints the URL with
|
|
9
|
+
* the token, and keeps running until interrupted (Ctrl+C) — the cli's own
|
|
10
|
+
* call does not return before that. `@opencraw/studio` is an optional peer
|
|
11
|
+
* dependency (`peerDependenciesMeta`), never a hard one: the cli stays light
|
|
12
|
+
* for callers who only need to crawl. When it is not installed, this prints
|
|
13
|
+
* how to add it instead of letting a raw `ERR_MODULE_NOT_FOUND` stack trace
|
|
14
|
+
* through.
|
|
15
|
+
*
|
|
16
|
+
* @param folder - The recipe folder to open; `@opencraw/studio`'s own default (the current directory) when omitted.
|
|
17
|
+
* @param terminal - Where output goes.
|
|
18
|
+
* @param importStudio - How the module is loaded; the real dynamic `import()` by default, replaced in tests.
|
|
19
|
+
* @returns The exit code: 0 once the server has stopped, 1 when `@opencraw/studio` is missing.
|
|
20
|
+
*/
|
|
21
|
+
export declare function runStudio(folder: string | undefined, terminal: Terminal, importStudio?: () => Promise<StudioModule>): Promise<number>;
|
|
22
|
+
//# sourceMappingURL=run-studio.use-case.d.ts.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@opencraw/cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.14",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.esm.js",
|
|
6
6
|
"module": "./dist/index.esm.js",
|
|
@@ -24,9 +24,17 @@
|
|
|
24
24
|
"!**/*.js.map"
|
|
25
25
|
],
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"@opencraw/core": "^0.1.
|
|
27
|
+
"@opencraw/core": "^0.1.14",
|
|
28
28
|
"playwright": "^1.63.0"
|
|
29
29
|
},
|
|
30
|
+
"peerDependencies": {
|
|
31
|
+
"@opencraw/studio": "^0.0.3"
|
|
32
|
+
},
|
|
33
|
+
"peerDependenciesMeta": {
|
|
34
|
+
"@opencraw/studio": {
|
|
35
|
+
"optional": true
|
|
36
|
+
}
|
|
37
|
+
},
|
|
30
38
|
"publishConfig": {
|
|
31
39
|
"access": "public"
|
|
32
40
|
},
|