@opencraw/cli 0.1.44 → 0.1.47
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 +19 -2
- package/dist/arguments/command.contract.d.ts +9 -0
- package/dist/arguments/parse-arguments.algorithm.d.ts +1 -1
- package/dist/export/export-records.use-case.d.ts +14 -0
- package/dist/export/index.d.ts +2 -0
- package/dist/index.esm.js +67 -8
- package/dist/src/arguments/command.contract.d.ts +9 -0
- package/dist/src/arguments/parse-arguments.algorithm.d.ts +1 -1
- package/dist/src/export/export-records.use-case.d.ts +14 -0
- package/dist/src/export/index.d.ts +2 -0
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -41,8 +41,8 @@ input recipes) and reports what happened.
|
|
|
41
41
|
|
|
42
42
|
| Flag | Meaning |
|
|
43
43
|
|---|---|
|
|
44
|
-
| `--out <file>` | Write records to this
|
|
45
|
-
| `--append` | Keep what `--out` holds and add to it; each line carries `_key`. |
|
|
44
|
+
| `--out <file>` | Write records to this file; **its extension is the format** (see below). Without it, records print to stdout as JSON Lines. |
|
|
45
|
+
| `--append` | Keep what `--out` holds and add to it; each line carries `_key`. `.jsonl` only. |
|
|
46
46
|
| `--resume` | Skip records `--out` already has (needs `--append`). |
|
|
47
47
|
| `--only <id>` | Run only this input recipe; repeat for more than one. |
|
|
48
48
|
| `--dry-run` | One record per input recipe, printed with the scope it was mapped from — for checking a recipe under construction without a full run. |
|
|
@@ -54,6 +54,23 @@ input recipes) and reports what happened.
|
|
|
54
54
|
| `--host-delay <ms>`, `--host-concurrency <n>` | Per-site politeness across every recipe: at least `ms` between two requests to one site, at most `n` in flight. They override the access config's `throttle` defaults. See [access.md](https://github.com/Open-Craw/OpenCraw/blob/main/docs/recipes/access.md#throttling-per-site). |
|
|
55
55
|
| `--plugins <file>` (or `--hooks`) | A plugins module: named exports `hooks` (the recipes' hook steps and transforms), `accessPlugins` (for `{ kind: "plugin" }` access profiles) and `captchaSolvers`. A module whose default export is `{ name: function }` is read as hooks alone. `OPENCRAW_PLUGINS` / `OPENCRAW_HOOKS` when not given; `probe` reads it too. It runs as your code; load only files you trust. See [§6 of the authoring guide](https://github.com/Open-Craw/OpenCraw/blob/main/docs/recipes/authoring.md#6-hooks). |
|
|
56
56
|
|
|
57
|
+
### Output formats
|
|
58
|
+
|
|
59
|
+
The extension of `--out` chooses the format. Any other extension is an error, raised before the crawl starts.
|
|
60
|
+
|
|
61
|
+
| Extension | What is written |
|
|
62
|
+
|---|---|
|
|
63
|
+
| `.jsonl` | One JSON object per line (the record's fields and a `_source`), written as records arrive. The only format `--append`, `--resume` and `--diff` work with. |
|
|
64
|
+
| `.json` | A JSON array of the same objects. |
|
|
65
|
+
| `.csv` | A header row of the output recipe's fields, then one row per record (RFC 4180, UTF-8). |
|
|
66
|
+
| `.xlsx` | An Excel workbook: one sheet named after the output, a violet header row with the filter on and frozen, numbers and booleans kept as numbers and booleans. |
|
|
67
|
+
| `.yml` / `.yaml` | A YAML list of the same objects. |
|
|
68
|
+
| `.html` | One self-contained page that looks like Studio: the OpenCraw logo, the output's name and description, the record count, and the records in a table. Light or dark by the reader's setting; no script. |
|
|
69
|
+
| `.pdf` | That page, printed (A4, landscape, header repeated on each page). Needs a Chromium, as a `web` recipe does: Playwright's, or `OPENCRAW_CHROMIUM` / `--browser-path`. |
|
|
70
|
+
|
|
71
|
+
The tabular formats (`.csv`, `.xlsx`, `.html`, `.pdf`) carry the output recipe's fields as columns, in the order the recipe declares them; a list or an
|
|
72
|
+
object becomes its JSON in one cell. Everything but `.jsonl` is written when the run closes.
|
|
73
|
+
|
|
57
74
|
```sh
|
|
58
75
|
opencraw run recipes/ --out out/products.jsonl --trace
|
|
59
76
|
opencraw run recipes/movie.output.json recipes/tmdb.input.json --dry-run
|
|
@@ -20,6 +20,15 @@ export type Command = {
|
|
|
20
20
|
} | {
|
|
21
21
|
name: 'validate';
|
|
22
22
|
paths: string[];
|
|
23
|
+
} | {
|
|
24
|
+
name: 'export';
|
|
25
|
+
/** A finished run's JSON Lines file. */
|
|
26
|
+
records: string;
|
|
27
|
+
/** The output recipe the records were mapped to: it names the columns. */
|
|
28
|
+
output: string;
|
|
29
|
+
/** The file to write; its extension is the format. */
|
|
30
|
+
out: string;
|
|
31
|
+
options: CommonOptions;
|
|
23
32
|
} | {
|
|
24
33
|
name: 'diff';
|
|
25
34
|
previous: string;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Command } from './command.contract';
|
|
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
|
|
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 (its extension picks the format), or to stdout as JSON Lines.\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 export <records.jsonl> <output recipe> --out <file>\n Write a finished run's records again in another format (the extension\n of --out chooses it, as for run).\n studio [folder] [--open <path>] Open a recipe folder in the browser: run samples, read\n the trace next to the page (needs @opencraw/studio).\n --open prints a link that opens a folder, recipe or\n document straight away.\n\nOptions for run\n --out <file> Write records to this file; the extension is the format: .jsonl, .json, .csv, .xlsx, .yml/.yaml,\n .html (a page that looks like Studio) or .pdf (that page, printed; needs Chromium). Any other\n extension is an error. Default: stdout as JSON Lines.\n --append Keep what --out holds and add to it (each line carries _key); .jsonl only.\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
|
*
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Command } from '../arguments';
|
|
2
|
+
import type { Terminal } from '../terminal';
|
|
3
|
+
/**
|
|
4
|
+
* Writes a finished run's JSON Lines file again in another format: the extension of `--out` chooses it, as it does for `run`. The output recipe
|
|
5
|
+
* supplies the columns (its fields, in order, with their types and descriptions).
|
|
6
|
+
*
|
|
7
|
+
* @param command - The parsed `export` command.
|
|
8
|
+
* @param terminal - Where the result and errors go.
|
|
9
|
+
* @returns The exit code: 0, or 1 when a file cannot be read, the recipe is not an output recipe, or the extension names no format.
|
|
10
|
+
*/
|
|
11
|
+
export declare function exportRecords(command: Extract<Command, {
|
|
12
|
+
name: 'export';
|
|
13
|
+
}>, terminal: Terminal): Promise<number>;
|
|
14
|
+
//# sourceMappingURL=export-records.use-case.d.ts.map
|
package/dist/index.esm.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { parseArgs } from 'node:util';
|
|
2
|
-
import { writeFile } from 'node:fs/promises';
|
|
3
|
-
import { readableKey, readRecordsFile, diffRecords, loadAccessConfig, HostAllowlist, AccessBroker, HttpClient, parseXml, BrowserClient, readRecipeSource,
|
|
2
|
+
import { writeFile, readFile } from 'node:fs/promises';
|
|
3
|
+
import { readableKey, readRecordsFile, diffRecords, fileSink, parseOutputRecipe, outputRecordOf, RecipeValidationError, loadAccessConfig, HostAllowlist, AccessBroker, HttpClient, parseXml, BrowserClient, readRecipeSource, parseInputRecipe, bindRecipeSet, memorySink, createCrawler, RecipeSet, variantLabel, diffOptionsFor, RecipeBindingError, traceLine } from '@opencraw/core';
|
|
4
4
|
import { resolve } from 'node:path';
|
|
5
5
|
import { pathToFileURL } from 'node:url';
|
|
6
6
|
import { describePdf, findData, describeWorkbook, describeDeck, describeJson, describeXml, describeHtml } from '@opencraw/probe';
|
|
@@ -11,17 +11,22 @@ const USAGE = `opencraw <command> [options]
|
|
|
11
11
|
|
|
12
12
|
Commands
|
|
13
13
|
validate <recipe files or directories...> Parse and bind the recipes; list every problem with its path.
|
|
14
|
-
run <recipe files or directories...> Crawl. Records go to --out
|
|
14
|
+
run <recipe files or directories...> Crawl. Records go to --out (its extension picks the format), or to stdout as JSON Lines.
|
|
15
15
|
probe <url> Fetch a page and report where its data lives.
|
|
16
16
|
diff <previous.jsonl> <current.jsonl> Compare two runs' records by key: added, removed, changed.
|
|
17
|
+
export <records.jsonl> <output recipe> --out <file>
|
|
18
|
+
Write a finished run's records again in another format (the extension
|
|
19
|
+
of --out chooses it, as for run).
|
|
17
20
|
studio [folder] [--open <path>] Open a recipe folder in the browser: run samples, read
|
|
18
21
|
the trace next to the page (needs @opencraw/studio).
|
|
19
22
|
--open prints a link that opens a folder, recipe or
|
|
20
23
|
document straight away.
|
|
21
24
|
|
|
22
25
|
Options for run
|
|
23
|
-
--out <file> Write records to this
|
|
24
|
-
|
|
26
|
+
--out <file> Write records to this file; the extension is the format: .jsonl, .json, .csv, .xlsx, .yml/.yaml,
|
|
27
|
+
.html (a page that looks like Studio) or .pdf (that page, printed; needs Chromium). Any other
|
|
28
|
+
extension is an error. Default: stdout as JSON Lines.
|
|
29
|
+
--append Keep what --out holds and add to it (each line carries _key); .jsonl only.
|
|
25
30
|
--resume Skip records --out already has (needs --append).
|
|
26
31
|
--only <id> Run only this input recipe (repeatable).
|
|
27
32
|
--dry-run One record per input, printed with the scope it was mapped from.
|
|
@@ -194,6 +199,18 @@ function parseArguments(argv, env = {}) {
|
|
|
194
199
|
paths: rest
|
|
195
200
|
};
|
|
196
201
|
}
|
|
202
|
+
case 'export':
|
|
203
|
+
{
|
|
204
|
+
if (rest.length !== 2) throw new Error('export needs the records file (JSON Lines) and the output recipe');
|
|
205
|
+
if (values.out === undefined) throw new Error('export needs --out <file>: its extension is the format');
|
|
206
|
+
return {
|
|
207
|
+
name: 'export',
|
|
208
|
+
records: rest[0],
|
|
209
|
+
output: rest[1],
|
|
210
|
+
out: values.out,
|
|
211
|
+
options
|
|
212
|
+
};
|
|
213
|
+
}
|
|
197
214
|
case 'diff':
|
|
198
215
|
{
|
|
199
216
|
if (rest.length !== 2) throw new Error('diff needs two JSON Lines files: the previous run, then the current one');
|
|
@@ -339,6 +356,34 @@ async function writeChanges(path, diff) {
|
|
|
339
356
|
await writeFile(path, diff.changes.map(change => `${JSON.stringify(change)}\n`).join(''));
|
|
340
357
|
}
|
|
341
358
|
|
|
359
|
+
/**
|
|
360
|
+
* Writes a finished run's JSON Lines file again in another format: the extension of `--out` chooses it, as it does for `run`. The output recipe
|
|
361
|
+
* supplies the columns (its fields, in order, with their types and descriptions).
|
|
362
|
+
*
|
|
363
|
+
* @param command - The parsed `export` command.
|
|
364
|
+
* @param terminal - Where the result and errors go.
|
|
365
|
+
* @returns The exit code: 0, or 1 when a file cannot be read, the recipe is not an output recipe, or the extension names no format.
|
|
366
|
+
*/
|
|
367
|
+
async function exportRecords(command, terminal) {
|
|
368
|
+
try {
|
|
369
|
+
const sink = fileSink(command.out, {
|
|
370
|
+
browser: {
|
|
371
|
+
executablePath: command.options.browserPath
|
|
372
|
+
}
|
|
373
|
+
});
|
|
374
|
+
const output = parseOutputRecipe(JSON.parse(await readFile(command.output, 'utf8')), command.output);
|
|
375
|
+
const stored = await readRecordsFile(command.records);
|
|
376
|
+
await sink.open(output);
|
|
377
|
+
for (const line of stored) await sink.write(outputRecordOf(line));
|
|
378
|
+
const summary = await sink.close();
|
|
379
|
+
terminal.err(`${String(summary.written)} records written to ${summary.location ?? command.out}`);
|
|
380
|
+
return 0;
|
|
381
|
+
} catch (error) {
|
|
382
|
+
if (error instanceof RecipeValidationError) for (const issue of error.issues) terminal.err(`${error.source}: ${issue.path === '' ? '(root)' : issue.path}: ${issue.message}`);else terminal.err(error instanceof Error ? error.message : String(error));
|
|
383
|
+
return 1;
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
|
|
342
387
|
/**
|
|
343
388
|
* The access config a command runs with: the file `--access` (or
|
|
344
389
|
* `OPENCRAW_ACCESS`) names, with `--access-profile` as its default.
|
|
@@ -793,6 +838,19 @@ async function runRecipes(command, terminal) {
|
|
|
793
838
|
terminal.err(command.only.length > 0 ? `no input recipe matches --only ${command.only.join(', ')}` : 'no input recipes found');
|
|
794
839
|
return 1;
|
|
795
840
|
}
|
|
841
|
+
// The extension of --out names the format: one that names none is refused here, before the crawl, not after it.
|
|
842
|
+
let sink;
|
|
843
|
+
try {
|
|
844
|
+
sink = command.dryRun || command.out === undefined ? memorySink() : fileSink(command.out, {
|
|
845
|
+
append: command.append,
|
|
846
|
+
browser: {
|
|
847
|
+
executablePath: command.options.browserPath
|
|
848
|
+
}
|
|
849
|
+
});
|
|
850
|
+
} catch (error) {
|
|
851
|
+
terminal.err(error instanceof Error ? error.message : String(error));
|
|
852
|
+
return 1;
|
|
853
|
+
}
|
|
796
854
|
let access;
|
|
797
855
|
let plugins;
|
|
798
856
|
let previous;
|
|
@@ -806,9 +864,6 @@ async function runRecipes(command, terminal) {
|
|
|
806
864
|
terminal.err(error instanceof Error ? error.message : String(error));
|
|
807
865
|
return 1;
|
|
808
866
|
}
|
|
809
|
-
const sink = command.dryRun || command.out === undefined ? memorySink() : jsonLinesSink(command.out, {
|
|
810
|
-
append: command.append
|
|
811
|
-
});
|
|
812
867
|
const crawler = createCrawler({
|
|
813
868
|
sink,
|
|
814
869
|
access,
|
|
@@ -1027,6 +1082,10 @@ async function main(argv, terminal) {
|
|
|
1027
1082
|
{
|
|
1028
1083
|
return diffFiles(command, terminal);
|
|
1029
1084
|
}
|
|
1085
|
+
case 'export':
|
|
1086
|
+
{
|
|
1087
|
+
return exportRecords(command, terminal);
|
|
1088
|
+
}
|
|
1030
1089
|
case 'studio':
|
|
1031
1090
|
{
|
|
1032
1091
|
return runStudio(command.folder, terminal, undefined, command.plugins, undefined, command.open);
|
|
@@ -20,6 +20,15 @@ export type Command = {
|
|
|
20
20
|
} | {
|
|
21
21
|
name: 'validate';
|
|
22
22
|
paths: string[];
|
|
23
|
+
} | {
|
|
24
|
+
name: 'export';
|
|
25
|
+
/** A finished run's JSON Lines file. */
|
|
26
|
+
records: string;
|
|
27
|
+
/** The output recipe the records were mapped to: it names the columns. */
|
|
28
|
+
output: string;
|
|
29
|
+
/** The file to write; its extension is the format. */
|
|
30
|
+
out: string;
|
|
31
|
+
options: CommonOptions;
|
|
23
32
|
} | {
|
|
24
33
|
name: 'diff';
|
|
25
34
|
previous: string;
|
|
@@ -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
|
|
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 (its extension picks the format), or to stdout as JSON Lines.\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 export <records.jsonl> <output recipe> --out <file>\n Write a finished run's records again in another format (the extension\n of --out chooses it, as for run).\n studio [folder] [--open <path>] Open a recipe folder in the browser: run samples, read\n the trace next to the page (needs @opencraw/studio).\n --open prints a link that opens a folder, recipe or\n document straight away.\n\nOptions for run\n --out <file> Write records to this file; the extension is the format: .jsonl, .json, .csv, .xlsx, .yml/.yaml,\n .html (a page that looks like Studio) or .pdf (that page, printed; needs Chromium). Any other\n extension is an error. Default: stdout as JSON Lines.\n --append Keep what --out holds and add to it (each line carries _key); .jsonl only.\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
|
*
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Command } from '../arguments/index.js';
|
|
2
|
+
import type { Terminal } from '../terminal/index.js';
|
|
3
|
+
/**
|
|
4
|
+
* Writes a finished run's JSON Lines file again in another format: the extension of `--out` chooses it, as it does for `run`. The output recipe
|
|
5
|
+
* supplies the columns (its fields, in order, with their types and descriptions).
|
|
6
|
+
*
|
|
7
|
+
* @param command - The parsed `export` command.
|
|
8
|
+
* @param terminal - Where the result and errors go.
|
|
9
|
+
* @returns The exit code: 0, or 1 when a file cannot be read, the recipe is not an output recipe, or the extension names no format.
|
|
10
|
+
*/
|
|
11
|
+
export declare function exportRecords(command: Extract<Command, {
|
|
12
|
+
name: 'export';
|
|
13
|
+
}>, terminal: Terminal): Promise<number>;
|
|
14
|
+
//# sourceMappingURL=export-records.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.47",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.esm.js",
|
|
6
6
|
"module": "./dist/index.esm.js",
|
|
@@ -24,12 +24,12 @@
|
|
|
24
24
|
"!**/*.js.map"
|
|
25
25
|
],
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"@opencraw/core": "^0.1.
|
|
28
|
-
"@opencraw/probe": "^0.0.
|
|
27
|
+
"@opencraw/core": "^0.1.42",
|
|
28
|
+
"@opencraw/probe": "^0.0.25",
|
|
29
29
|
"playwright": "^1.63.0"
|
|
30
30
|
},
|
|
31
31
|
"peerDependencies": {
|
|
32
|
-
"@opencraw/studio": "^0.0.
|
|
32
|
+
"@opencraw/studio": "^0.0.36"
|
|
33
33
|
},
|
|
34
34
|
"peerDependenciesMeta": {
|
|
35
35
|
"@opencraw/studio": {
|