@opencraw/studio 0.0.5 → 0.0.6
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 +888 -10
- package/dist/src/index.d.ts +2 -2
- package/dist/src/page-snapshot/hidden-marks.algorithm.d.ts +23 -0
- package/dist/src/page-snapshot/index.d.ts +7 -0
- package/dist/src/page-snapshot/rewrite-document.mapper.d.ts +27 -0
- package/dist/src/page-snapshot/snapshot.store.d.ts +14 -0
- package/dist/src/page-snapshot/take-snapshot.use-case.d.ts +34 -0
- package/dist/src/sample-run/run-sample.use-case.d.ts +3 -1
- package/dist/src/selector-inference/class-token.policy.d.ts +35 -0
- package/dist/src/selector-inference/dom-path.model.d.ts +73 -0
- package/dist/src/selector-inference/index.d.ts +12 -0
- package/dist/src/selector-inference/list-inference.algorithm.d.ts +43 -0
- package/dist/src/selector-inference/selector-candidates.algorithm.d.ts +22 -0
- package/dist/src/selector-inference/selector-ranking.policy.d.ts +27 -0
- package/dist/src/selector-inference/shadow-dom.error.d.ts +11 -0
- package/dist/src/selector-inference/take-kind.policy.d.ts +12 -0
- package/dist/src/studio-api/command.contract.d.ts +44 -0
- package/dist/src/studio-api/index.d.ts +8 -2
- package/dist/src/studio-api/infer-selector-view.contract.d.ts +68 -0
- package/dist/src/studio-api/snapshot-view.contract.d.ts +9 -0
- package/dist/src/studio-api/verify-selector-view.contract.d.ts +18 -0
- package/dist/src/studio-server/infer-selector.handler.d.ts +18 -0
- package/dist/src/studio-server/studio-http.use-case.d.ts +3 -0
- package/dist/src/studio-server/take-snapshot.handler.d.ts +16 -0
- package/dist/src/studio-server/verify-selector.handler.d.ts +18 -0
- package/dist/src/studio-server/workspace.store.d.ts +7 -2
- package/dist/ui/assets/index-BfbrsfCv.js +13 -0
- package/dist/ui/index.html +1 -1
- package/package.json +5 -3
- package/dist/ui/assets/index-DYb-tdmr.js +0 -12
package/dist/src/index.d.ts
CHANGED
|
@@ -5,6 +5,6 @@ export { openWorkspace, saveRecipe } from './recipe-workspace/index.js';
|
|
|
5
5
|
export { runSample, loadRecipePair } from './sample-run/index.js';
|
|
6
6
|
export type { RecipePair, SampleRunCallbacks, SampleRunHandle, SampleRunRecord, SampleRunResult, SampleStoppedBy } from './sample-run/index.js';
|
|
7
7
|
export { fetchStartPage } from './page-snapshot/index.js';
|
|
8
|
-
export { sampleBudgetSchema, openWorkspaceCommandSchema, runSampleCommandSchema, stopRunCommandSchema, saveRecipeCommandSchema, fetchStartPageCommandSchema, saveOutlineCommandSchema, studioCommandSchema, stoppedBySchema, traceLineEventSchema, recordEventSchema, runFinishedEventSchema, workspaceChangedEventSchema, studioEventSchema, recipeIssueSchema, recipeListingSchema, workspaceViewSchema, sampleRunRecordSchema, sampleRunViewSchema, startPageViewSchema, sentencePartSchema, outlineCardSchema, outlineBracketSchema, outlineNodeSchema, outlineViewSchema, } from './studio-api/index.js';
|
|
9
|
-
export type { SampleBudget, OpenWorkspaceCommand, RunSampleCommand, StopRunCommand, SaveRecipeCommand, FetchStartPageCommand, SaveOutlineCommand, StudioCommand, StoppedBy, TraceLineEvent, RecordEvent, RunFinishedEvent, WorkspaceChangedEvent, StudioEvent, RecipeIssue, RecipeListing, WorkspaceView, SampleRunView, StartPageView, SentencePart, OutlineCard, OutlineBracket, OutlineNode, OutlineView, } from './studio-api/index.js';
|
|
8
|
+
export { sampleBudgetSchema, openWorkspaceCommandSchema, runSampleCommandSchema, stopRunCommandSchema, saveRecipeCommandSchema, fetchStartPageCommandSchema, saveOutlineCommandSchema, takeSnapshotCommandSchema, verifySelectorCommandSchema, inferSelectorCommandSchema, studioCommandSchema, stoppedBySchema, traceLineEventSchema, recordEventSchema, runFinishedEventSchema, workspaceChangedEventSchema, studioEventSchema, recipeIssueSchema, recipeListingSchema, workspaceViewSchema, sampleRunRecordSchema, sampleRunViewSchema, startPageViewSchema, snapshotViewSchema, verifySelectorViewSchema, fieldPickSchema, inferSelectorViewSchema, sentencePartSchema, outlineCardSchema, outlineBracketSchema, outlineNodeSchema, outlineViewSchema, } from './studio-api/index.js';
|
|
9
|
+
export type { SampleBudget, OpenWorkspaceCommand, RunSampleCommand, StopRunCommand, SaveRecipeCommand, FetchStartPageCommand, SaveOutlineCommand, TakeSnapshotCommand, VerifySelectorCommand, InferSelectorCommand, StudioCommand, StoppedBy, TraceLineEvent, RecordEvent, RunFinishedEvent, WorkspaceChangedEvent, StudioEvent, RecipeIssue, RecipeListing, WorkspaceView, SampleRunView, StartPageView, SnapshotView, VerifySelectorView, FieldPick, InferSelectorView, SentencePart, OutlineCard, OutlineBracket, OutlineNode, OutlineView, } from './studio-api/index.js';
|
|
10
10
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/** The attribute `hiddenMarksScript` stamps on an element hidden on the live page. */
|
|
2
|
+
export declare const HIDDEN_ATTRIBUTE = "data-oc-hidden";
|
|
3
|
+
/**
|
|
4
|
+
* The in-page script `take-snapshot.use-case.ts` runs with `page.evaluate`
|
|
5
|
+
* *before* `page.content()`, so a `display: none`/`visibility: hidden`/
|
|
6
|
+
* zero-size element carries `data-oc-hidden="1"` into the captured markup
|
|
7
|
+
* (studio plan §3.1, issue #91) — the only way to know an element was
|
|
8
|
+
* hidden on the live page, since a static parse of the HTML afterwards has
|
|
9
|
+
* no computed style to ask.
|
|
10
|
+
*
|
|
11
|
+
* Kept as a plain string, not a TypeScript function passed to
|
|
12
|
+
* `page.evaluate`, because it references `window`/`document` as globals: `AGENTS.md`'s
|
|
13
|
+
* "things that bit before" calls out that in-page functions must not do
|
|
14
|
+
* that (the repo's `isolated-functions` lint rule), and every existing
|
|
15
|
+
* `page.evaluate` call with real DOM logic in this codebase (see
|
|
16
|
+
* `packages/core/src/captcha/resolve-captcha.use-case.ts`) already uses
|
|
17
|
+
* this same string-template shape.
|
|
18
|
+
*
|
|
19
|
+
* @param attribute - The attribute to stamp; defaults to `HIDDEN_ATTRIBUTE` (parameterised for tests and for a future caller that wants a different name).
|
|
20
|
+
* @returns A self-invoking script, ready for `page.evaluate(hiddenMarksScript())`.
|
|
21
|
+
*/
|
|
22
|
+
export declare function hiddenMarksScript(attribute?: string): string;
|
|
23
|
+
//# sourceMappingURL=hidden-marks.algorithm.d.ts.map
|
|
@@ -1,2 +1,9 @@
|
|
|
1
1
|
export { fetchStartPage } from './fetch-start-page.use-case.js';
|
|
2
|
+
export { takeSnapshot } from './take-snapshot.use-case.js';
|
|
3
|
+
export type { SnapshotResult } from './take-snapshot.use-case.js';
|
|
4
|
+
export { rewriteDocument } from './rewrite-document.mapper.js';
|
|
5
|
+
export type { RewrittenDocument } from './rewrite-document.mapper.js';
|
|
6
|
+
export { hiddenMarksScript, HIDDEN_ATTRIBUTE } from './hidden-marks.algorithm.js';
|
|
7
|
+
export { createSnapshotCache, cachedSnapshot, putSnapshot, invalidateRecipe } from './snapshot.store.js';
|
|
8
|
+
export type { SnapshotCache } from './snapshot.store.js';
|
|
2
9
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export interface RewrittenDocument {
|
|
2
|
+
/** The document, ready for the sandboxed iframe: absolute URLs, a `<base>`, no `<script>`, forms disabled, `<meta http-equiv="refresh">` stripped, every element carrying a `data-oc-node` id. */
|
|
3
|
+
html: string;
|
|
4
|
+
/** How many elements were stamped with a node id — the same count `page-inspector` (phase 4) and the picker's match counts can be checked against. */
|
|
5
|
+
nodeCount: number;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Rewrites captured HTML into what the content pane's sandboxed iframe shows
|
|
9
|
+
* (studio plan §3.1, issue #91): every URL made absolute against `baseUrl`,
|
|
10
|
+
* a `<base>` injected, every `<script>` removed, forms disabled (`onsubmit`
|
|
11
|
+
* stripped, fields made read-only), `<meta http-equiv="refresh">` stripped
|
|
12
|
+
* (it would otherwise navigate the sandboxed frame on its own), and every
|
|
13
|
+
* element given a stable `data-oc-node` id, in document order, for the
|
|
14
|
+
* picker overlay and `selector-inference` to address specific nodes by.
|
|
15
|
+
*
|
|
16
|
+
* Purely a markup transform: it does not know whether an element is hidden
|
|
17
|
+
* on the live page (`display: none`, `visibility: hidden`, zero size) — in
|
|
18
|
+
* web mode that is `hidden-marks.algorithm.ts`'s job, run against the live
|
|
19
|
+
* page *before* this function ever sees the markup, so a `data-oc-hidden`
|
|
20
|
+
* attribute it wrote just survives serialisation untouched here.
|
|
21
|
+
*
|
|
22
|
+
* @param html - The captured document (`page.content()` in web mode, the fetched body in api mode).
|
|
23
|
+
* @param baseUrl - The page's own URL, for resolving relative links and as the `<base>`.
|
|
24
|
+
* @returns The rewritten document and how many elements it stamped.
|
|
25
|
+
*/
|
|
26
|
+
export declare function rewriteDocument(html: string, baseUrl: string): RewrittenDocument;
|
|
27
|
+
//# sourceMappingURL=rewrite-document.mapper.d.ts.map
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { SnapshotResult } from './take-snapshot.use-case.js';
|
|
2
|
+
/** A cache of the last snapshot taken per step path, so switching the selected step in the Steps outline does not always re-run the recipe (studio plan §3.1, issue #91). One per open recipe: key by `${recipeId}:${path}`. */
|
|
3
|
+
export interface SnapshotCache {
|
|
4
|
+
entries: Map<string, SnapshotResult>;
|
|
5
|
+
}
|
|
6
|
+
/** @returns An empty cache, for a freshly opened workspace. */
|
|
7
|
+
export declare function createSnapshotCache(): SnapshotCache;
|
|
8
|
+
/** @returns The cached snapshot for `recipeId`/`path`, or `undefined` when none was taken yet. */
|
|
9
|
+
export declare function cachedSnapshot(cache: SnapshotCache, recipeId: string, path: string): SnapshotResult | undefined;
|
|
10
|
+
/** Records a freshly taken snapshot, replacing whatever was cached for the same recipe and step path. */
|
|
11
|
+
export declare function putSnapshot(cache: SnapshotCache, recipeId: string, path: string, snapshot: SnapshotResult): void;
|
|
12
|
+
/** Drops every cached snapshot of one recipe — called after a save, since the steps up to any path may now capture something different. */
|
|
13
|
+
export declare function invalidateRecipe(cache: SnapshotCache, recipeId: string): void;
|
|
14
|
+
//# sourceMappingURL=snapshot.store.d.ts.map
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { BrowserSessionConfig, InputRecipe } from '@opencraw/core';
|
|
2
|
+
export interface SnapshotResult {
|
|
3
|
+
/** The rewritten document, ready for the content pane's sandboxed iframe. */
|
|
4
|
+
html: string;
|
|
5
|
+
/** How many elements carry a `data-oc-node` id. */
|
|
6
|
+
nodeCount: number;
|
|
7
|
+
/** The page's own URL, used to resolve every relative URL and as the `<base>`. */
|
|
8
|
+
baseUrl: string;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Captures the snapshot the content pane shows (studio plan §3.1, issue
|
|
12
|
+
* #91): runs the recipe up to `stepPath`, serialises the document, marks
|
|
13
|
+
* hidden elements in web mode, and hands it to `rewrite-document.mapper.ts`
|
|
14
|
+
* for display.
|
|
15
|
+
*
|
|
16
|
+
* `stepPath` is accepted (and cached against, by `snapshot.store.ts`) for
|
|
17
|
+
* the API the UI needs — one snapshot per selected step — but v1 only
|
|
18
|
+
* actually *captures* `"start"`: the first `start` point, before any step
|
|
19
|
+
* of the recipe has run, the same reach `fetch-start-page.use-case.ts` (phase
|
|
20
|
+
* 0) already had. Snapshotting mid-recipe (after an arbitrary later step)
|
|
21
|
+
* needs a "stop the crawl after step X and hand back the live page/document"
|
|
22
|
+
* hook in `crawl-execution` that does not exist yet; building one was out of
|
|
23
|
+
* this phase's budget (see this phase's final report for the tradeoff this
|
|
24
|
+
* was weighed against). Any other `stepPath` throws, clearly, rather than
|
|
25
|
+
* silently returning the start page under a misleading label.
|
|
26
|
+
*
|
|
27
|
+
* @param input - The input recipe; only `mode` and the first `start` point are used.
|
|
28
|
+
* @param stepPath - The step to snapshot after, e.g. `"start"` or `"steps.2"` (`scope-outline`'s path format).
|
|
29
|
+
* @param browser - Browser launch settings for web mode.
|
|
30
|
+
* @returns The rewritten snapshot.
|
|
31
|
+
* @throws Error when the recipe has no start point, or `stepPath` is not `"start"`.
|
|
32
|
+
*/
|
|
33
|
+
export declare function takeSnapshot(input: InputRecipe, stepPath: string, browser?: BrowserSessionConfig): Promise<SnapshotResult>;
|
|
34
|
+
//# sourceMappingURL=take-snapshot.use-case.d.ts.map
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { BrowserSessionConfig } from '@opencraw/core';
|
|
1
2
|
import type { SampleBudget } from '../studio-api/index.js';
|
|
2
3
|
import type { SampleRunRecord, SampleRunResult } from './sample-run-record.contract.js';
|
|
3
4
|
/** Where trace lines and records go as a sample run proceeds. */
|
|
@@ -23,8 +24,9 @@ export interface SampleRunHandle {
|
|
|
23
24
|
* @param recipeId - The input recipe to run.
|
|
24
25
|
* @param budget - The sample budget; unset runs the recipe to completion (still capped by its own `limits`).
|
|
25
26
|
* @param callbacks - Where trace lines and records go as the run proceeds.
|
|
27
|
+
* @param browser - Browser launch settings for a web-mode recipe (an executable path override, headless…); the server-wide setting `studio-http.use-case.ts`'s `StudioServerOptions.browser` carries in, e.g. `OPENCRAW_CHROMIUM` in a sandbox with no full Playwright install.
|
|
26
28
|
* @returns A handle: `stop` closes the crawler cleanly, `result` resolves when the run ends.
|
|
27
29
|
* @throws RecipeValidationError, RecipeBindingError, Error when the recipe or its output cannot be loaded or bound.
|
|
28
30
|
*/
|
|
29
|
-
export declare function runSample(folder: string, recipeId: string, budget: SampleBudget | undefined, callbacks: SampleRunCallbacks): Promise<SampleRunHandle>;
|
|
31
|
+
export declare function runSample(folder: string, recipeId: string, budget: SampleBudget | undefined, callbacks: SampleRunCallbacks, browser?: BrowserSessionConfig): Promise<SampleRunHandle>;
|
|
30
32
|
//# sourceMappingURL=run-sample.use-case.d.ts.map
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which class tokens are worth building a selector on. A hand-authored class
|
|
3
|
+
* (`product_pod`, `price_color`) survives a rebuild; a generated one
|
|
4
|
+
* (a content hash, a CSS-module suffix, a styled-components token) does not,
|
|
5
|
+
* so a candidate built on it looks fine on the snapshot it was picked from
|
|
6
|
+
* and breaks on the very next deploy. This is the "generated/hashed class
|
|
7
|
+
* names" tradeoff issue #91 calls out explicitly: the heuristics below are a
|
|
8
|
+
* reasoned judgement call, not a guarantee — see the doc comments on each
|
|
9
|
+
* pattern for what real-world tool it targets.
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Whether a class token looks hand-authored and safe to build a selector on.
|
|
13
|
+
*
|
|
14
|
+
* @param token - One class, no surrounding whitespace.
|
|
15
|
+
* @returns `false` for anything matching a known generated-class shape.
|
|
16
|
+
*/
|
|
17
|
+
export declare function isStableClassToken(token: string): boolean;
|
|
18
|
+
/**
|
|
19
|
+
* The subset of `tokens` worth ranking a selector candidate on, order kept.
|
|
20
|
+
*
|
|
21
|
+
* @param tokens - An element's class list.
|
|
22
|
+
* @returns Only the stable tokens.
|
|
23
|
+
*/
|
|
24
|
+
export declare function stableClasses(tokens: readonly string[]): string[];
|
|
25
|
+
/**
|
|
26
|
+
* Whether two class lists describe "the same kind of element" for list
|
|
27
|
+
* inference: same stable classes, generated tokens (which often differ
|
|
28
|
+
* per-instance, e.g. a React `key`-derived class) ignored on both sides.
|
|
29
|
+
*
|
|
30
|
+
* @param a - One element's classes.
|
|
31
|
+
* @param b - Another element's classes.
|
|
32
|
+
* @returns Whether their stable class sets are equal, order ignored.
|
|
33
|
+
*/
|
|
34
|
+
export declare function sameClassSignature(a: readonly string[], b: readonly string[]): boolean;
|
|
35
|
+
//# sourceMappingURL=class-token.policy.d.ts.map
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import type { AnyNode } from 'domhandler';
|
|
2
|
+
import type { Cheerio, CheerioAPI } from 'cheerio';
|
|
3
|
+
/**
|
|
4
|
+
* One level of a node's ancestry, root first: the element's own shape (tag,
|
|
5
|
+
* id, classes, attributes) plus where it sits among its same-tag siblings.
|
|
6
|
+
* Built over parsed HTML (cheerio), never a live DOM: the studio infers
|
|
7
|
+
* selectors from the snapshot the server captured, not from a browser
|
|
8
|
+
* window in the UI process (studio plan §3.1/§3.2, issue #91).
|
|
9
|
+
*/
|
|
10
|
+
export interface DomPathLevel {
|
|
11
|
+
tag: string;
|
|
12
|
+
id?: string;
|
|
13
|
+
classes: string[];
|
|
14
|
+
attrs: Record<string, string>;
|
|
15
|
+
/** 1-based position among same-tag siblings under the same parent (an `nth-of-type` index). */
|
|
16
|
+
index: number;
|
|
17
|
+
/** How many same-tag siblings share the parent, `index` included. */
|
|
18
|
+
siblingCount: number;
|
|
19
|
+
}
|
|
20
|
+
/** A node's whole ancestry, root first, the node itself last. */
|
|
21
|
+
export type DomPath = DomPathLevel[];
|
|
22
|
+
/**
|
|
23
|
+
* The path from the document root to `node`, one level per ancestor. Two
|
|
24
|
+
* elements that share an ancestor produce identical levels up to that
|
|
25
|
+
* ancestor and diverge exactly where their parents stop being the same node
|
|
26
|
+
* — `list-inference.algorithm.ts` leans on that to find the nearest pair of
|
|
27
|
+
* siblings two picks belong to, without ever touching cheerio again.
|
|
28
|
+
*
|
|
29
|
+
* @param $ - The parsed document.
|
|
30
|
+
* @param node - The element to describe.
|
|
31
|
+
* @returns The path, root first.
|
|
32
|
+
*/
|
|
33
|
+
export declare function domPathOf($: CheerioAPI, node: Cheerio<AnyNode>): DomPath;
|
|
34
|
+
/**
|
|
35
|
+
* Whether `id` looks handed by a framework (`react-`, a CSS-module or a
|
|
36
|
+
* `radix-`/`mui-` autogenerated one) rather than by the site's own markup —
|
|
37
|
+
* `class-token.policy.ts` has the equivalent check for class tokens, kept
|
|
38
|
+
* separate because ids and classes are ranked at different tiers.
|
|
39
|
+
*/
|
|
40
|
+
export declare function isStableId(id: string): boolean;
|
|
41
|
+
/**
|
|
42
|
+
* Whether `path` failed to reach the real document root. `domPathOf` walks
|
|
43
|
+
* up through cheerio's own `.parent()`, which (matching real DOM semantics)
|
|
44
|
+
* never crosses from a `<template>`'s content into the light DOM outside
|
|
45
|
+
* it — a `<template shadowrootmode>` is exactly declarative shadow DOM, the
|
|
46
|
+
* only shadow-DOM shape that can show up in static, server-captured markup
|
|
47
|
+
* at all (imperative `attachShadow()` content never serialises into
|
|
48
|
+
* `page.content()`/a fetched response in the first place, so that case
|
|
49
|
+
* cannot reach this slice and needs no separate detection). A path whose
|
|
50
|
+
* first level is not `html` was cut short at exactly this kind of boundary:
|
|
51
|
+
* v1 does not pierce it, so callers report a clear "shadow DOM is not
|
|
52
|
+
* supported" error instead of building ancestor-based candidates over a
|
|
53
|
+
* chain that stops partway up.
|
|
54
|
+
*/
|
|
55
|
+
export declare function crossesShadowRoot(path: DomPath): boolean;
|
|
56
|
+
/** Parses `html` and returns cheerio's API, for callers that need more than one path from the same document. */
|
|
57
|
+
export declare function parseDocument(html: string): CheerioAPI;
|
|
58
|
+
/**
|
|
59
|
+
* The path to the element the snapshot stamped with `nodeId` (its
|
|
60
|
+
* `data-oc-node` attribute — `@opencraw/core`'s `NODE_ID_ATTRIBUTE`,
|
|
61
|
+
* `packages/studio/src/page-snapshot/rewrite-document.mapper.ts`). This is
|
|
62
|
+
* how a click in the content pane's iframe — which only ever needs to read
|
|
63
|
+
* that one attribute off the element the user clicked — turns into
|
|
64
|
+
* something `selector-inference`'s other algorithms can work with, without
|
|
65
|
+
* the browser-side picker script needing to know anything about ancestry,
|
|
66
|
+
* classes or candidate ranking itself.
|
|
67
|
+
*
|
|
68
|
+
* @param html - The snapshot document (already stamped with node ids).
|
|
69
|
+
* @param nodeId - The `data-oc-node` value to find.
|
|
70
|
+
* @returns The node's path, or `undefined` when no element carries that id.
|
|
71
|
+
*/
|
|
72
|
+
export declare function pathToNode(html: string, nodeId: string): DomPath | undefined;
|
|
73
|
+
//# sourceMappingURL=dom-path.model.d.ts.map
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export { domPathOf, isStableId, crossesShadowRoot, parseDocument, pathToNode } from './dom-path.model.js';
|
|
2
|
+
export type { DomPath, DomPathLevel } from './dom-path.model.js';
|
|
3
|
+
export { takeKindFor } from './take-kind.policy.js';
|
|
4
|
+
export { isStableClassToken, stableClasses, sameClassSignature } from './class-token.policy.js';
|
|
5
|
+
export { ShadowDomUnsupportedError } from './shadow-dom.error.js';
|
|
6
|
+
export { candidatesFor } from './selector-candidates.algorithm.js';
|
|
7
|
+
export type { SelectorCandidate, CandidateTier } from './selector-candidates.algorithm.js';
|
|
8
|
+
export { rankCandidates, bestCandidate } from './selector-ranking.policy.js';
|
|
9
|
+
export type { RankedCandidate } from './selector-ranking.policy.js';
|
|
10
|
+
export { inferList } from './list-inference.algorithm.js';
|
|
11
|
+
export type { ListInferenceResult } from './list-inference.algorithm.js';
|
|
12
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { DomPath } from './dom-path.model.js';
|
|
2
|
+
export interface ListInferenceResult {
|
|
3
|
+
/**
|
|
4
|
+
* The item's shape, generalised across both picks (root first, item
|
|
5
|
+
* last): only the tag, the stable classes and the attributes the two
|
|
6
|
+
* picked items actually share survive the merge. An id or a `data-id`
|
|
7
|
+
* that differs per item (the ordinary case) is dropped here on purpose —
|
|
8
|
+
* built into a selector it would match one item and silently miss every
|
|
9
|
+
* other, which is a shifted-field-shaped bug in its own right even though
|
|
10
|
+
* it is not the one issue #91 names.
|
|
11
|
+
*/
|
|
12
|
+
itemPath: DomPath;
|
|
13
|
+
/** The field's shape from the item down to the click, generalised the same way as `itemPath`, for a selector that reads `from` the item and still works on every item, not just the one it was picked from. */
|
|
14
|
+
fieldPath: DomPath;
|
|
15
|
+
/** The concrete path of the first click, item-relative (index 0 = the item), kept for provenance (e.g. the value the pick actually read). */
|
|
16
|
+
fieldPathA: DomPath;
|
|
17
|
+
/** Same, for the second click. */
|
|
18
|
+
fieldPathB: DomPath;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Infers "these two picks are the same field on two items of a list" from
|
|
22
|
+
* two node paths, by walking up from both to the nearest ancestors that are
|
|
23
|
+
* real siblings (the same parent) with the same tag and stable-class
|
|
24
|
+
* signature — studio plan §3.2, issue #91. That ancestor is the item; the
|
|
25
|
+
* remainder of each path is the field, relative to it.
|
|
26
|
+
*
|
|
27
|
+
* Because a `DomPath` is built root-down (`dom-path.model.ts`), two paths
|
|
28
|
+
* from the same document are byte-for-byte identical up to their real
|
|
29
|
+
* common ancestor and diverge exactly at its differing children — so the
|
|
30
|
+
* *first* level where they differ is always the nearest-sibling test point;
|
|
31
|
+
* there is no need to look further down. This also makes the "wrapper trap"
|
|
32
|
+
* (an extra single-child element around each item) resolve itself: a
|
|
33
|
+
* wrapper's own instances are never one another's siblings, only the
|
|
34
|
+
* genuine repeating element is, so the walk naturally lands there instead of
|
|
35
|
+
* on the wrapper (see the wrapper-trap fixture in this slice's tests).
|
|
36
|
+
*
|
|
37
|
+
* @param pathA - The first click's path.
|
|
38
|
+
* @param pathB - The second click's path.
|
|
39
|
+
* @returns The item and field shapes (generalised) plus each pick's raw path, or `null` when the two picks are not on a coherent list (different branches entirely, the same node twice, or one path nested inside the other).
|
|
40
|
+
* @throws ShadowDomUnsupportedError when either path crosses a declarative shadow root.
|
|
41
|
+
*/
|
|
42
|
+
export declare function inferList(pathA: DomPath, pathB: DomPath): ListInferenceResult | null;
|
|
43
|
+
//# sourceMappingURL=list-inference.algorithm.d.ts.map
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { DomPath } from './dom-path.model.js';
|
|
2
|
+
/** The engine only ever runs `css` selectors from the studio (studio plan §3.2); xpath is a separate, text-only fallback the UI builds by hand. */
|
|
3
|
+
export type CandidateTier = 'id' | 'data-attr' | 'class' | 'structure' | 'position';
|
|
4
|
+
export interface SelectorCandidate {
|
|
5
|
+
selector: string;
|
|
6
|
+
tier: CandidateTier;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Every selector candidate worth trying for the last node of `path`, ranked
|
|
10
|
+
* best-first: `id` > stable `data-*`/`itemprop` attributes > stable class
|
|
11
|
+
* tokens > ancestor structure (`parent > tag`) > position (`nth-of-type`) as
|
|
12
|
+
* a last resort (issue #91's ranking, studio plan §3.2). Structure and
|
|
13
|
+
* position candidates only look as far up as `path` itself goes — pass a
|
|
14
|
+
* sub-path (e.g. from an item's root down) to keep a field's selector
|
|
15
|
+
* relative to its item instead of absolute to the document.
|
|
16
|
+
*
|
|
17
|
+
* @param path - The node's ancestry, root (or scope root) first, itself last.
|
|
18
|
+
* @param includePosition - `false` for an item selector: a position candidate would only ever match one of the items, which is never what an item selector should do.
|
|
19
|
+
* @returns Candidates, best tier first; ties keep this function's own order.
|
|
20
|
+
*/
|
|
21
|
+
export declare function candidatesFor(path: DomPath, includePosition?: boolean): SelectorCandidate[];
|
|
22
|
+
//# sourceMappingURL=selector-candidates.algorithm.d.ts.map
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { SelectorCandidate } from './selector-candidates.algorithm.js';
|
|
2
|
+
export interface RankedCandidate extends SelectorCandidate {
|
|
3
|
+
/** How many elements this candidate matches in the document it was verified against. */
|
|
4
|
+
matches: number;
|
|
5
|
+
/** Whether it matches `targetNodeId` (when one was given); a candidate that misses its own target is worse than useless. */
|
|
6
|
+
hitsTarget: boolean;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Verifies and orders selector candidates against real markup, by running
|
|
10
|
+
* each one through the engine's own CSS matching (`@opencraw/core`'s
|
|
11
|
+
* `countMatches`/`matchesOf`) rather than reimplementing it — issue #91's
|
|
12
|
+
* "every candidate is verified" requirement.
|
|
13
|
+
*
|
|
14
|
+
* Ordering: candidates that do not match `targetNodeId` (when given) sort
|
|
15
|
+
* last; among the rest, best tier first, and within a tier the fewest
|
|
16
|
+
* matches first (the most specific selector that still hits the target).
|
|
17
|
+
* A candidate matching nothing is dropped entirely: it is not a real option.
|
|
18
|
+
*
|
|
19
|
+
* @param html - The document to verify against (the snapshot, or the live page for the second, cross-check pass).
|
|
20
|
+
* @param candidates - Unranked candidates, e.g. from `candidatesFor`.
|
|
21
|
+
* @param targetNodeId - The `data-oc-node` id the pick landed on, when the document carries those stamps (the snapshot does; a live page fetched separately does not).
|
|
22
|
+
* @returns Every candidate that matched at least one element, ranked best first.
|
|
23
|
+
*/
|
|
24
|
+
export declare function rankCandidates(html: string, candidates: readonly SelectorCandidate[], targetNodeId?: string): RankedCandidate[];
|
|
25
|
+
/** The single best candidate, or `undefined` when none of them matched anything. */
|
|
26
|
+
export declare function bestCandidate(html: string, candidates: readonly SelectorCandidate[], targetNodeId?: string): RankedCandidate | undefined;
|
|
27
|
+
//# sourceMappingURL=selector-ranking.policy.d.ts.map
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Thrown when a pick or a list-inference walk crosses a declarative shadow
|
|
3
|
+
* root (`<template shadowrootmode>`). v1 does not pierce shadow DOM: rather
|
|
4
|
+
* than infer a selector that silently matches the wrong thing (or nothing,
|
|
5
|
+
* once the page hydrates), the studio surfaces this and stops.
|
|
6
|
+
*/
|
|
7
|
+
export declare class ShadowDomUnsupportedError extends Error {
|
|
8
|
+
readonly path: string;
|
|
9
|
+
constructor(path: string);
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=shadow-dom.error.d.ts.map
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { DomPathLevel } from './dom-path.model.js';
|
|
2
|
+
/**
|
|
3
|
+
* What a `Read` card's `take` should be for the element a pick landed on
|
|
4
|
+
* (issue #91, studio plan §3.2): `attr:href` for an `<a>`, `attr:src` for an
|
|
5
|
+
* `<img>`, `attr:<name>` for the first `data-*` attribute otherwise, `json`
|
|
6
|
+
* for a `<script type="application/json">`, else the default, `text`.
|
|
7
|
+
*
|
|
8
|
+
* @param level - The clicked element's own level (the last entry of its `DomPath`).
|
|
9
|
+
* @returns The `take` value to put on the `extract` step.
|
|
10
|
+
*/
|
|
11
|
+
export declare function takeKindFor(level: DomPathLevel): string;
|
|
12
|
+
//# sourceMappingURL=take-kind.policy.d.ts.map
|
|
@@ -50,6 +50,33 @@ export declare const saveOutlineCommandSchema: z.ZodObject<{
|
|
|
50
50
|
path: z.ZodString;
|
|
51
51
|
outline: z.ZodType<import("./outline-view.contract").OutlineView, unknown, z.core.$ZodTypeInternals<import("./outline-view.contract").OutlineView, unknown>>;
|
|
52
52
|
}, z.core.$strip>;
|
|
53
|
+
/**
|
|
54
|
+
* Captures the snapshot the content pane shows for a step (`page-snapshot`'s
|
|
55
|
+
* `take-snapshot.use-case.ts`), caching it by recipe and step path so
|
|
56
|
+
* switching the selected step does not always re-run the recipe.
|
|
57
|
+
*/
|
|
58
|
+
export declare const takeSnapshotCommandSchema: z.ZodObject<{
|
|
59
|
+
type: z.ZodLiteral<"take-snapshot">;
|
|
60
|
+
recipeId: z.ZodString;
|
|
61
|
+
path: z.ZodString;
|
|
62
|
+
}, z.core.$strip>;
|
|
63
|
+
/**
|
|
64
|
+
* Verifies a candidate selector against the cached snapshot and, when
|
|
65
|
+
* reachable, the live page — the studio's own selection (`@opencraw/core`'s
|
|
66
|
+
* `countMatches`), never the browser's or a guess (issue #91).
|
|
67
|
+
*/
|
|
68
|
+
export declare const verifySelectorCommandSchema: z.ZodObject<{
|
|
69
|
+
type: z.ZodLiteral<"verify-selector">;
|
|
70
|
+
recipeId: z.ZodString;
|
|
71
|
+
path: z.ZodString;
|
|
72
|
+
selector: z.ZodString;
|
|
73
|
+
}, z.core.$strip>;
|
|
74
|
+
export declare const inferSelectorCommandSchema: z.ZodObject<{
|
|
75
|
+
type: z.ZodLiteral<"infer-selector">;
|
|
76
|
+
recipeId: z.ZodString;
|
|
77
|
+
path: z.ZodString;
|
|
78
|
+
nodeIds: z.ZodUnion<readonly [z.ZodTuple<[z.ZodString], null>, z.ZodTuple<[z.ZodString, z.ZodString], null>]>;
|
|
79
|
+
}, z.core.$strip>;
|
|
53
80
|
export declare const studioCommandSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
54
81
|
type: z.ZodLiteral<"open-workspace">;
|
|
55
82
|
folder: z.ZodString;
|
|
@@ -74,6 +101,20 @@ export declare const studioCommandSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
74
101
|
type: z.ZodLiteral<"save-outline">;
|
|
75
102
|
path: z.ZodString;
|
|
76
103
|
outline: z.ZodType<import("./outline-view.contract").OutlineView, unknown, z.core.$ZodTypeInternals<import("./outline-view.contract").OutlineView, unknown>>;
|
|
104
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
105
|
+
type: z.ZodLiteral<"take-snapshot">;
|
|
106
|
+
recipeId: z.ZodString;
|
|
107
|
+
path: z.ZodString;
|
|
108
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
109
|
+
type: z.ZodLiteral<"verify-selector">;
|
|
110
|
+
recipeId: z.ZodString;
|
|
111
|
+
path: z.ZodString;
|
|
112
|
+
selector: z.ZodString;
|
|
113
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
114
|
+
type: z.ZodLiteral<"infer-selector">;
|
|
115
|
+
recipeId: z.ZodString;
|
|
116
|
+
path: z.ZodString;
|
|
117
|
+
nodeIds: z.ZodUnion<readonly [z.ZodTuple<[z.ZodString], null>, z.ZodTuple<[z.ZodString, z.ZodString], null>]>;
|
|
77
118
|
}, z.core.$strip>], "type">;
|
|
78
119
|
export type SampleBudget = z.infer<typeof sampleBudgetSchema>;
|
|
79
120
|
export type OpenWorkspaceCommand = z.infer<typeof openWorkspaceCommandSchema>;
|
|
@@ -82,6 +123,9 @@ export type StopRunCommand = z.infer<typeof stopRunCommandSchema>;
|
|
|
82
123
|
export type SaveRecipeCommand = z.infer<typeof saveRecipeCommandSchema>;
|
|
83
124
|
export type FetchStartPageCommand = z.infer<typeof fetchStartPageCommandSchema>;
|
|
84
125
|
export type SaveOutlineCommand = z.infer<typeof saveOutlineCommandSchema>;
|
|
126
|
+
export type TakeSnapshotCommand = z.infer<typeof takeSnapshotCommandSchema>;
|
|
127
|
+
export type VerifySelectorCommand = z.infer<typeof verifySelectorCommandSchema>;
|
|
128
|
+
export type InferSelectorCommand = z.infer<typeof inferSelectorCommandSchema>;
|
|
85
129
|
/** Every command the UI can send the server, over HTTP POST. */
|
|
86
130
|
export type StudioCommand = z.infer<typeof studioCommandSchema>;
|
|
87
131
|
//# sourceMappingURL=command.contract.d.ts.map
|
|
@@ -1,5 +1,11 @@
|
|
|
1
|
-
export { sampleBudgetSchema, openWorkspaceCommandSchema, runSampleCommandSchema, stopRunCommandSchema, saveRecipeCommandSchema, fetchStartPageCommandSchema, saveOutlineCommandSchema, studioCommandSchema } from './command.contract.js';
|
|
2
|
-
export type { SampleBudget, OpenWorkspaceCommand, RunSampleCommand, StopRunCommand, SaveRecipeCommand, FetchStartPageCommand, SaveOutlineCommand, StudioCommand } from './command.contract.js';
|
|
1
|
+
export { sampleBudgetSchema, openWorkspaceCommandSchema, runSampleCommandSchema, stopRunCommandSchema, saveRecipeCommandSchema, fetchStartPageCommandSchema, saveOutlineCommandSchema, takeSnapshotCommandSchema, verifySelectorCommandSchema, inferSelectorCommandSchema, studioCommandSchema } from './command.contract.js';
|
|
2
|
+
export type { SampleBudget, OpenWorkspaceCommand, RunSampleCommand, StopRunCommand, SaveRecipeCommand, FetchStartPageCommand, SaveOutlineCommand, TakeSnapshotCommand, VerifySelectorCommand, InferSelectorCommand, StudioCommand } from './command.contract.js';
|
|
3
|
+
export { snapshotViewSchema } from './snapshot-view.contract.js';
|
|
4
|
+
export type { SnapshotView } from './snapshot-view.contract.js';
|
|
5
|
+
export { verifySelectorViewSchema } from './verify-selector-view.contract.js';
|
|
6
|
+
export type { VerifySelectorView } from './verify-selector-view.contract.js';
|
|
7
|
+
export { fieldPickSchema, inferSelectorViewSchema } from './infer-selector-view.contract.js';
|
|
8
|
+
export type { FieldPick, InferSelectorView } from './infer-selector-view.contract.js';
|
|
3
9
|
export { stoppedBySchema, traceLineEventSchema, recordEventSchema, runFinishedEventSchema, workspaceChangedEventSchema, studioEventSchema } from './event.contract.js';
|
|
4
10
|
export type { StoppedBy, TraceLineEvent, RecordEvent, RunFinishedEvent, WorkspaceChangedEvent, StudioEvent } from './event.contract.js';
|
|
5
11
|
export { recipeIssueSchema, recipeListingSchema, workspaceViewSchema } from './workspace-view.contract.js';
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
/** One clicked node's field: the best selector found for it, verified against the snapshot. */
|
|
3
|
+
export declare const fieldPickSchema: z.ZodObject<{
|
|
4
|
+
selector: z.ZodString;
|
|
5
|
+
tier: z.ZodEnum<{
|
|
6
|
+
id: "id";
|
|
7
|
+
"data-attr": "data-attr";
|
|
8
|
+
class: "class";
|
|
9
|
+
structure: "structure";
|
|
10
|
+
position: "position";
|
|
11
|
+
}>;
|
|
12
|
+
take: z.ZodString;
|
|
13
|
+
matches: z.ZodNumber;
|
|
14
|
+
}, z.core.$strip>;
|
|
15
|
+
/**
|
|
16
|
+
* What `infer-selector` answers with (issue #91, studio plan §3.2):
|
|
17
|
+
* `"field"` for one clicked node — a `Read` card's shape; `"list"` for two
|
|
18
|
+
* similar nodes — the safe `extract`(items)+`forEach`(field) shape, item and
|
|
19
|
+
* field each verified separately; `"unsupported"` when the two picks are not
|
|
20
|
+
* a coherent list (different branches, the same node twice, or shadow DOM),
|
|
21
|
+
* with a message the card can show as-is.
|
|
22
|
+
*/
|
|
23
|
+
export declare const inferSelectorViewSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
24
|
+
kind: z.ZodLiteral<"field">;
|
|
25
|
+
field: z.ZodObject<{
|
|
26
|
+
selector: z.ZodString;
|
|
27
|
+
tier: z.ZodEnum<{
|
|
28
|
+
id: "id";
|
|
29
|
+
"data-attr": "data-attr";
|
|
30
|
+
class: "class";
|
|
31
|
+
structure: "structure";
|
|
32
|
+
position: "position";
|
|
33
|
+
}>;
|
|
34
|
+
take: z.ZodString;
|
|
35
|
+
matches: z.ZodNumber;
|
|
36
|
+
}, z.core.$strip>;
|
|
37
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
38
|
+
kind: z.ZodLiteral<"list">;
|
|
39
|
+
item: z.ZodObject<{
|
|
40
|
+
selector: z.ZodString;
|
|
41
|
+
tier: z.ZodEnum<{
|
|
42
|
+
id: "id";
|
|
43
|
+
"data-attr": "data-attr";
|
|
44
|
+
class: "class";
|
|
45
|
+
structure: "structure";
|
|
46
|
+
position: "position";
|
|
47
|
+
}>;
|
|
48
|
+
matches: z.ZodNumber;
|
|
49
|
+
}, z.core.$strip>;
|
|
50
|
+
field: z.ZodObject<{
|
|
51
|
+
selector: z.ZodString;
|
|
52
|
+
tier: z.ZodEnum<{
|
|
53
|
+
id: "id";
|
|
54
|
+
"data-attr": "data-attr";
|
|
55
|
+
class: "class";
|
|
56
|
+
structure: "structure";
|
|
57
|
+
position: "position";
|
|
58
|
+
}>;
|
|
59
|
+
take: z.ZodString;
|
|
60
|
+
matches: z.ZodNumber;
|
|
61
|
+
}, z.core.$strip>;
|
|
62
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
63
|
+
kind: z.ZodLiteral<"unsupported">;
|
|
64
|
+
reason: z.ZodString;
|
|
65
|
+
}, z.core.$strip>], "kind">;
|
|
66
|
+
export type FieldPick = z.infer<typeof fieldPickSchema>;
|
|
67
|
+
export type InferSelectorView = z.infer<typeof inferSelectorViewSchema>;
|
|
68
|
+
//# sourceMappingURL=infer-selector-view.contract.d.ts.map
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
/** What `take-snapshot` answers with: the rewritten document ready for the content pane's sandboxed iframe (studio plan §3.1, issue #91). */
|
|
3
|
+
export declare const snapshotViewSchema: z.ZodObject<{
|
|
4
|
+
html: z.ZodString;
|
|
5
|
+
nodeCount: z.ZodNumber;
|
|
6
|
+
baseUrl: z.ZodString;
|
|
7
|
+
}, z.core.$strip>;
|
|
8
|
+
export type SnapshotView = z.infer<typeof snapshotViewSchema>;
|
|
9
|
+
//# sourceMappingURL=snapshot-view.contract.d.ts.map
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
/**
|
|
3
|
+
* What `verify-selector` answers with: the match count against the snapshot
|
|
4
|
+
* and, when the live page could be reached, against it too (issue #91's
|
|
5
|
+
* "flag a selector that matches the snapshot but not the live page").
|
|
6
|
+
* `liveChecked` is `false` when the live page could not be fetched (offline,
|
|
7
|
+
* blocked by `allowedHosts`, a transient error) — the card shows the
|
|
8
|
+
* snapshot count alone rather than a misleading "0 on the live page".
|
|
9
|
+
*/
|
|
10
|
+
export declare const verifySelectorViewSchema: z.ZodObject<{
|
|
11
|
+
selector: z.ZodString;
|
|
12
|
+
snapshotMatches: z.ZodNumber;
|
|
13
|
+
liveChecked: z.ZodBoolean;
|
|
14
|
+
liveMatches: z.ZodOptional<z.ZodNumber>;
|
|
15
|
+
liveError: z.ZodOptional<z.ZodString>;
|
|
16
|
+
}, z.core.$strip>;
|
|
17
|
+
export type VerifySelectorView = z.infer<typeof verifySelectorViewSchema>;
|
|
18
|
+
//# sourceMappingURL=verify-selector-view.contract.d.ts.map
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { InferSelectorCommand, InferSelectorView } from '../studio-api/index.js';
|
|
2
|
+
import type { StudioState } from './workspace.store.js';
|
|
3
|
+
/**
|
|
4
|
+
* Handles `infer-selector`: turns one or two picked nodes (their
|
|
5
|
+
* `data-oc-node` ids, off the cached snapshot) into a verified selector —
|
|
6
|
+
* one id for a `Read` card's field, two for the safe item+field list shape
|
|
7
|
+
* `selector-inference`'s `inferList` builds by construction (issue #91,
|
|
8
|
+
* studio plan §3.2). All the actual candidate/ranking/list-inference work
|
|
9
|
+
* is `selector-inference`'s (pure); this handler only locates the clicked
|
|
10
|
+
* nodes in the cached document and calls into it.
|
|
11
|
+
*
|
|
12
|
+
* @param state - The server state.
|
|
13
|
+
* @param command - The command; `command.path` must already have a cached snapshot (call `take-snapshot` first).
|
|
14
|
+
* @returns A field pick, a list pick, or `"unsupported"` with why.
|
|
15
|
+
* @throws Error when no workspace is open, or `command.path` has no cached snapshot yet.
|
|
16
|
+
*/
|
|
17
|
+
export declare function handleInferSelector(state: StudioState, command: InferSelectorCommand): InferSelectorView;
|
|
18
|
+
//# sourceMappingURL=infer-selector.handler.d.ts.map
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { BrowserSessionConfig } from '@opencraw/core';
|
|
1
2
|
export interface StudioServerOptions {
|
|
2
3
|
/** Where the built UI lives; default: `dist/ui` next to the running server code. */
|
|
3
4
|
uiRoot?: string;
|
|
@@ -11,6 +12,8 @@ export interface StudioServerOptions {
|
|
|
11
12
|
* the folder reaches it through the URL's `folder` query param).
|
|
12
13
|
*/
|
|
13
14
|
initialFolder?: string;
|
|
15
|
+
/** Browser launch settings every web-mode command shares (`take-snapshot`, `verify-selector`, `run-sample`); an executable path override (e.g. `OPENCRAW_CHROMIUM`, read by the caller — the server itself has no opinion on env vars) for a sandbox with no full Playwright install. Default: Playwright's own bundled browser. */
|
|
16
|
+
browser?: BrowserSessionConfig;
|
|
14
17
|
}
|
|
15
18
|
/** The running server: its URL (token included, ready to open), the token alone, and how to stop it. */
|
|
16
19
|
export interface StudioServer {
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { SnapshotView, TakeSnapshotCommand } from '../studio-api/index.js';
|
|
2
|
+
import type { StudioState } from './workspace.store.js';
|
|
3
|
+
/**
|
|
4
|
+
* Handles `take-snapshot`: loads the named input recipe, captures its
|
|
5
|
+
* snapshot at `command.path` (only `"start"` is captured for now — see
|
|
6
|
+
* `page-snapshot`'s `take-snapshot.use-case.ts`), and caches it so a later
|
|
7
|
+
* `verify-selector`/`infer-selector` against the same recipe and path, or
|
|
8
|
+
* the UI reselecting the same step, does not recapture it.
|
|
9
|
+
*
|
|
10
|
+
* @param state - The server state: `folder` must already be set.
|
|
11
|
+
* @param command - The command.
|
|
12
|
+
* @returns The rewritten snapshot.
|
|
13
|
+
* @throws Error when no workspace is open, or the recipe cannot be found or loaded.
|
|
14
|
+
*/
|
|
15
|
+
export declare function handleTakeSnapshot(state: StudioState, command: TakeSnapshotCommand): Promise<SnapshotView>;
|
|
16
|
+
//# sourceMappingURL=take-snapshot.handler.d.ts.map
|