@opencraw/studio 0.0.11 → 0.0.13
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 +37 -13
- package/package.json +3 -3
package/dist/index.esm.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { join, dirname, basename, extname, normalize, sep, resolve } from 'node:path';
|
|
2
2
|
import { createServer } from 'node:http';
|
|
3
|
+
import { promisify, stripVTControlCharacters } from 'node:util';
|
|
3
4
|
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
4
5
|
import { z } from 'zod';
|
|
5
|
-
import { BODY_KINDS, HttpClient, BrowserClient, NODE_ID_ATTRIBUTE, rowsOfCells, parseXml, findDeckTables, findGridTables, analyzeTables, parseRegion, regionText, deckRegionText, isDeckDocument, readRecipeSource, parseInputRecipe, parseOutputRecipe, bindRecipeSet, memorySink, createCrawler, traceLine, UnknownHookError, resolveMissingPolicy, isWorkbookDocument, RecipeBindingError, RecipeValidationError, countMatches, matchesOf, tryParseJson, isPdfDocument, BrowserProfiles } from '@opencraw/core';
|
|
6
|
+
import { BODY_KINDS, HttpClient, BrowserClient, NODE_ID_ATTRIBUTE, sessionStateOf, rowsOfCells, parseXml, findDeckTables, findGridTables, analyzeTables, parseRegion, regionText, deckRegionText, isDeckDocument, readRecipeSource, parseInputRecipe, parseOutputRecipe, bindRecipeSet, memorySink, createCrawler, traceLine, UnknownHookError, resolveMissingPolicy, isWorkbookDocument, RecipeBindingError, RecipeValidationError, countMatches, matchesOf, tryParseJson, isPdfDocument, BrowserProfiles } from '@opencraw/core';
|
|
6
7
|
import { randomBytes, createHash } from 'node:crypto';
|
|
7
8
|
import { execFile } from 'node:child_process';
|
|
8
9
|
import { createRequire } from 'node:module';
|
|
9
|
-
import { promisify } from 'node:util';
|
|
10
10
|
import { load } from 'cheerio';
|
|
11
11
|
import { readFile, writeFile, mkdir } from 'node:fs/promises';
|
|
12
12
|
import { describeJson } from '@opencraw/probe';
|
|
@@ -1119,12 +1119,30 @@ async function takeSnapshot(input, stepPath, browser) {
|
|
|
1119
1119
|
if (stepPath !== 'start') throw new Error(`takeSnapshot: "${stepPath}" is not supported yet — only "start" (the first start point, before any step runs) is; see this function's doc comment`);
|
|
1120
1120
|
const point = input.start[0];
|
|
1121
1121
|
if (point === undefined) throw new Error(`recipe "${input.id}" has no start point`);
|
|
1122
|
-
|
|
1122
|
+
const storageState = await loginState(input, browser);
|
|
1123
|
+
return input.mode === 'web' ? snapshotWeb(point.url, storageState, browser) : snapshotApi(point.url, storageState);
|
|
1123
1124
|
}
|
|
1124
|
-
|
|
1125
|
+
/** What the recipe's own login leaves behind, so the snapshot shows the page as the crawl sees it (issue #185); nothing when it declares no login. */
|
|
1126
|
+
async function loginState(input, browser) {
|
|
1127
|
+
if (input.session === undefined) return undefined;
|
|
1128
|
+
let client;
|
|
1129
|
+
try {
|
|
1130
|
+
return await sessionStateOf(input, {
|
|
1131
|
+
browser: async () => {
|
|
1132
|
+
client = await ensureBrowserLaunch(browser, () => BrowserClient.launch(browser));
|
|
1133
|
+
return client;
|
|
1134
|
+
}
|
|
1135
|
+
});
|
|
1136
|
+
} finally {
|
|
1137
|
+
await client?.close();
|
|
1138
|
+
}
|
|
1139
|
+
}
|
|
1140
|
+
async function snapshotWeb(url, storageState, browser) {
|
|
1125
1141
|
const client = await ensureBrowserLaunch(browser, () => BrowserClient.launch(browser));
|
|
1126
1142
|
try {
|
|
1127
|
-
const session = await client.newSession(
|
|
1143
|
+
const session = await client.newSession({
|
|
1144
|
+
storageState
|
|
1145
|
+
});
|
|
1128
1146
|
try {
|
|
1129
1147
|
await session.page.goto(url);
|
|
1130
1148
|
await session.page.evaluate(hiddenMarksScript(HIDDEN_ATTRIBUTE));
|
|
@@ -1143,8 +1161,10 @@ async function snapshotWeb(url, browser) {
|
|
|
1143
1161
|
await client.close();
|
|
1144
1162
|
}
|
|
1145
1163
|
}
|
|
1146
|
-
async function snapshotApi(url) {
|
|
1147
|
-
const client = await HttpClient.open({
|
|
1164
|
+
async function snapshotApi(url, storageState) {
|
|
1165
|
+
const client = await HttpClient.open({
|
|
1166
|
+
storageState
|
|
1167
|
+
});
|
|
1148
1168
|
try {
|
|
1149
1169
|
const response = await client.send({
|
|
1150
1170
|
url
|
|
@@ -2105,9 +2125,9 @@ async function runToResult(crawler, set, recipeId, records, rejectedRecords, ste
|
|
|
2105
2125
|
}
|
|
2106
2126
|
/** What a run that could not start reports. A hook is the author's own code, which Studio never loads (issue #150): say so, instead of leaving "unknown hook" to read as a typo. */
|
|
2107
2127
|
function failureMessage(error) {
|
|
2108
|
-
if (error instanceof UnknownHookError) return `${error.message}. Studio does not load hooks, so a recipe that uses one cannot be sample-run here; run it with the cli or the mcp server, or temporarily replace the hook step to preview the rest.`;
|
|
2109
|
-
if (error instanceof Error) return error.message;
|
|
2110
|
-
return String(error);
|
|
2128
|
+
if (error instanceof UnknownHookError) return `${stripVTControlCharacters(error.message)}. Studio does not load hooks, so a recipe that uses one cannot be sample-run here; run it with the cli or the mcp server, or temporarily replace the hook step to preview the rest.`;
|
|
2129
|
+
if (error instanceof Error) return stripVTControlCharacters(error.message);
|
|
2130
|
+
return stripVTControlCharacters(String(error));
|
|
2111
2131
|
}
|
|
2112
2132
|
|
|
2113
2133
|
/** @returns A fresh, empty cache. */
|
|
@@ -5070,7 +5090,7 @@ async function handlePdfBytesRequest(response, state, query) {
|
|
|
5070
5090
|
response.end(Buffer.from(bytes));
|
|
5071
5091
|
} catch (error) {
|
|
5072
5092
|
respondJson(response, 500, {
|
|
5073
|
-
error:
|
|
5093
|
+
error: messageOf(error)
|
|
5074
5094
|
});
|
|
5075
5095
|
}
|
|
5076
5096
|
}
|
|
@@ -5088,7 +5108,7 @@ async function handleCommand(request, response, state) {
|
|
|
5088
5108
|
command = parsed.data;
|
|
5089
5109
|
} catch (error) {
|
|
5090
5110
|
respondJson(response, 400, {
|
|
5091
|
-
error:
|
|
5111
|
+
error: messageOf(error)
|
|
5092
5112
|
});
|
|
5093
5113
|
return;
|
|
5094
5114
|
}
|
|
@@ -5096,7 +5116,7 @@ async function handleCommand(request, response, state) {
|
|
|
5096
5116
|
respondJson(response, 200, await dispatch(command, state));
|
|
5097
5117
|
} catch (error) {
|
|
5098
5118
|
respondJson(response, 500, {
|
|
5099
|
-
error:
|
|
5119
|
+
error: messageOf(error)
|
|
5100
5120
|
});
|
|
5101
5121
|
}
|
|
5102
5122
|
}
|
|
@@ -5226,6 +5246,10 @@ function handleUpgrade(request, socket, token, state) {
|
|
|
5226
5246
|
state.sockets.delete(connection);
|
|
5227
5247
|
});
|
|
5228
5248
|
}
|
|
5249
|
+
/** An error's message as plain text: Playwright colours its call logs with ANSI codes, which a browser would show as raw escapes (issue #187). */
|
|
5250
|
+
function messageOf(error) {
|
|
5251
|
+
return stripVTControlCharacters(error instanceof Error ? error.message : String(error));
|
|
5252
|
+
}
|
|
5229
5253
|
|
|
5230
5254
|
/**
|
|
5231
5255
|
* Runs `opencraw-studio`: starts the server, opens `folder` (if given) as
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@opencraw/studio",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.13",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.esm.js",
|
|
6
6
|
"module": "./dist/index.esm.js",
|
|
@@ -24,8 +24,8 @@
|
|
|
24
24
|
"!**/*.js.map"
|
|
25
25
|
],
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"@opencraw/core": "^0.1.
|
|
28
|
-
"@opencraw/probe": "^0.0.
|
|
27
|
+
"@opencraw/core": "^0.1.24",
|
|
28
|
+
"@opencraw/probe": "^0.0.7",
|
|
29
29
|
"cheerio": "^1.2.0",
|
|
30
30
|
"playwright": "^1.63.0",
|
|
31
31
|
"zod": "^4.6.5",
|