@opencraw/studio 0.0.6 → 0.0.8
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 +3632 -861
- package/dist/src/document-view/deck-view.mapper.d.ts +70 -0
- package/dist/src/document-view/index.d.ts +11 -0
- package/dist/src/document-view/pdf-view.mapper.d.ts +47 -0
- package/dist/src/document-view/table-preview.use-case.d.ts +152 -0
- package/dist/src/document-view/tree-view.mapper.d.ts +47 -0
- package/dist/src/document-view/workbook-view.mapper.d.ts +51 -0
- package/dist/src/explain-why/index.d.ts +5 -0
- package/dist/src/explain-why/item-hint.algorithm.d.ts +13 -0
- package/dist/src/explain-why/why-sentence.mapper.d.ts +48 -0
- package/dist/src/explain-why/why.use-case.d.ts +26 -0
- package/dist/src/flow-recording/action-to-step.mapper.d.ts +16 -0
- package/dist/src/flow-recording/index.d.ts +13 -0
- package/dist/src/flow-recording/next-link.policy.d.ts +27 -0
- package/dist/src/flow-recording/recorded-action.contract.d.ts +114 -0
- package/dist/src/flow-recording/recorder-script.client.d.ts +48 -0
- package/dist/src/flow-recording/recorder-session.use-case.d.ts +67 -0
- package/dist/src/flow-recording/secret-field.policy.d.ts +33 -0
- package/dist/src/flow-recording/wait-insertion.policy.d.ts +26 -0
- package/dist/src/index.d.ts +4 -3
- package/dist/src/page-inspector/dom-tree.mapper.d.ts +32 -0
- package/dist/src/page-inspector/index.d.ts +7 -0
- package/dist/src/page-inspector/page-data.algorithm.d.ts +39 -0
- package/dist/src/page-inspector/responses-seen.use-case.d.ts +36 -0
- package/dist/src/page-snapshot/index.d.ts +3 -0
- package/dist/src/page-snapshot/pdf-bytes.use-case.d.ts +16 -0
- package/dist/src/page-snapshot/reread-csv.use-case.d.ts +22 -0
- package/dist/src/page-snapshot/take-snapshot.use-case.d.ts +26 -1
- package/dist/src/sample-run/index.d.ts +3 -1
- package/dist/src/sample-run/last-run.store.d.ts +17 -0
- package/dist/src/sample-run/run-sample.use-case.d.ts +12 -6
- package/dist/src/sample-run/sample-run-record.contract.d.ts +30 -1
- package/dist/src/studio-api/command.contract.d.ts +359 -0
- package/dist/src/studio-api/deck-preview-view.contract.d.ts +28 -0
- package/dist/src/studio-api/deck-view.contract.d.ts +127 -0
- package/dist/src/studio-api/document-tree-view.contract.d.ts +26 -0
- package/dist/src/studio-api/event.contract.d.ts +86 -1
- package/dist/src/studio-api/grid-preview-view.contract.d.ts +26 -0
- package/dist/src/studio-api/grid-view.contract.d.ts +75 -0
- package/dist/src/studio-api/index.d.ts +24 -4
- package/dist/src/studio-api/inspect-view.contract.d.ts +62 -0
- package/dist/src/studio-api/pdf-view.contract.d.ts +66 -0
- package/dist/src/studio-api/responses-seen-view.contract.d.ts +20 -0
- package/dist/src/studio-api/snapshot-view.contract.d.ts +22 -1
- package/dist/src/studio-api/table-preview-view.contract.d.ts +65 -0
- package/dist/src/studio-api/why-view.contract.d.ts +16 -0
- package/dist/src/studio-server/deck-preview.handler.d.ts +17 -0
- package/dist/src/studio-server/deck-view.handler.d.ts +15 -0
- package/dist/src/studio-server/document-tree.handler.d.ts +14 -0
- package/dist/src/studio-server/explain-why.handler.d.ts +14 -0
- package/dist/src/studio-server/grid-preview.handler.d.ts +17 -0
- package/dist/src/studio-server/grid-view.handler.d.ts +20 -0
- package/dist/src/studio-server/inspect-page.handler.d.ts +18 -0
- package/dist/src/studio-server/pdf-bytes.handler.d.ts +17 -0
- package/dist/src/studio-server/pdf-view.handler.d.ts +14 -0
- package/dist/src/studio-server/recording.handler.d.ts +33 -0
- package/dist/src/studio-server/responses-seen.handler.d.ts +16 -0
- package/dist/src/studio-server/studio-http.use-case.d.ts +3 -1
- package/dist/src/studio-server/table-preview.handler.d.ts +16 -0
- package/dist/src/studio-server/workspace.store.d.ts +8 -3
- package/dist/ui/assets/index-DdiGdaTN.js +13 -0
- package/dist/ui/assets/pdf-lqXfRfkR.js +56 -0
- package/dist/ui/assets/pdf.worker.min-BmVo14Nb.mjs +28 -0
- package/dist/ui/assets/pdf.worker.min-D7i8o3wR.js +1 -0
- package/dist/ui/index.html +1 -1
- package/package.json +3 -2
- package/dist/ui/assets/index-BfbrsfCv.js +0 -13
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The in-page script `recorder-session.use-case.ts` installs on every page
|
|
3
|
+
* of the studio's own headed browser window (`context.addInitScript`),
|
|
4
|
+
* reporting the person's actions to the binding it also exposes on the
|
|
5
|
+
* context (`context.exposeBinding`) — issue #95's "a script injected into
|
|
6
|
+
* every page ... reports the user's actions: click, type, select, key
|
|
7
|
+
* press, scroll".
|
|
8
|
+
*
|
|
9
|
+
* Kept as a plain string, not a TypeScript function passed to
|
|
10
|
+
* `page.evaluate`/`addInitScript`, for the same reason as
|
|
11
|
+
* `page-snapshot/hidden-marks.algorithm.ts`'s `hiddenMarksScript`: it
|
|
12
|
+
* references `window`/`document` as globals, which `AGENTS.md`'s "things
|
|
13
|
+
* that bit before" and the repo's `isolated-functions` lint rule forbid for
|
|
14
|
+
* an in-page TypeScript function.
|
|
15
|
+
*
|
|
16
|
+
* What it reports, and what it deliberately does not:
|
|
17
|
+
*
|
|
18
|
+
* - **click**: the nearest clickable ancestor (`a`, `button`,
|
|
19
|
+
* `input[type=submit|button]`) of the element clicked, or the element
|
|
20
|
+
* itself; for an `<a>`, also its `rel`, text and `aria-label` —
|
|
21
|
+
* `next-link.policy.ts`'s only input.
|
|
22
|
+
* - **fill**: on `blur` of a text-like input/textarea whose value changed
|
|
23
|
+
* since it was focused (never on every keystroke) — the field's `type`,
|
|
24
|
+
* `name` and `id`, and the value *as typed*; whether that value is a
|
|
25
|
+
* secret, and what replaces it, is `secret-field.policy.ts`'s call,
|
|
26
|
+
* server-side, not this script's.
|
|
27
|
+
* - **select**: on `change` of a `<select>`.
|
|
28
|
+
* - **keypress**: `Enter` only (issue #95's own example, "Press Enter");
|
|
29
|
+
* every other key is noise a recipe step has no shape for.
|
|
30
|
+
* - **scroll**: once per "scroll session" (debounced), when the page has
|
|
31
|
+
* been scrolled within `NEAR_BOTTOM_PX` of its bottom.
|
|
32
|
+
* - **unsupported**: once, the first time an event's target sits inside a
|
|
33
|
+
* shadow root, or this script runs in a frame that is not the top window
|
|
34
|
+
* (an iframe) — issue #95's explicit out-of-scope cases, reported instead
|
|
35
|
+
* of attempted.
|
|
36
|
+
*
|
|
37
|
+
* Every reported element is marked with `attribute` (`data-oc-node` by
|
|
38
|
+
* default, `@opencraw/core`'s `NODE_ID_ATTRIBUTE`) if it does not already
|
|
39
|
+
* carry one, the same attribute `selector-inference`'s `pathToNode` reads —
|
|
40
|
+
* so `recorder-session.use-case.ts` can turn a report straight into a
|
|
41
|
+
* verified selector with the phase 2 generator, never inventing its own.
|
|
42
|
+
*
|
|
43
|
+
* @param bindingName - The name Playwright's `exposeBinding` gave the reporting function (`window[bindingName]`).
|
|
44
|
+
* @param attribute - The marker attribute; defaults to `NODE_ID_ATTRIBUTE`.
|
|
45
|
+
* @returns A self-invoking script, ready for `context.addInitScript({ content: recorderScript(...) })`.
|
|
46
|
+
*/
|
|
47
|
+
export declare function recorderScript(bindingName: string, attribute?: string): string;
|
|
48
|
+
//# sourceMappingURL=recorder-script.client.d.ts.map
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import type { Page } from 'playwright';
|
|
2
|
+
import type { BrowserSessionConfig } from '@opencraw/core';
|
|
3
|
+
import type { OutlineNode } from '../studio-api/index.js';
|
|
4
|
+
export interface RecorderNote {
|
|
5
|
+
kind: 'next-link' | 'unsupported' | 'info';
|
|
6
|
+
message: string;
|
|
7
|
+
}
|
|
8
|
+
/** Where recorded actions and notices go as a recording proceeds. */
|
|
9
|
+
export interface RecorderCallbacks {
|
|
10
|
+
onCard: (node: OutlineNode, secret: boolean) => void;
|
|
11
|
+
onNote: (note: RecorderNote) => void;
|
|
12
|
+
}
|
|
13
|
+
export interface RecorderSessionOptions {
|
|
14
|
+
/** The page the headed window opens on. */
|
|
15
|
+
startUrl: string;
|
|
16
|
+
/** Where the studio's own recorder profiles live — see `BrowserProfiles`; never the folder a crawl's own `session.browserProfile` uses. */
|
|
17
|
+
profileDir: string;
|
|
18
|
+
/** Browser launch settings; `headless` is always forced `false` — a recording is, by definition, a window the person watches and drives. */
|
|
19
|
+
browser?: BrowserSessionConfig;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* A recording in progress: `stop` closes the window and hands back every
|
|
23
|
+
* step recorded, in order. `page` is the window's own live Playwright page
|
|
24
|
+
* — public the same way `BrowserSession.page` already is, for a caller (a
|
|
25
|
+
* future embedded view, this phase's own e2e test driving the window "as
|
|
26
|
+
* the person would") that needs to reach the live window itself, not just
|
|
27
|
+
* the reported actions.
|
|
28
|
+
*/
|
|
29
|
+
export interface RecorderSessionHandle {
|
|
30
|
+
page: Page;
|
|
31
|
+
stop: () => Promise<{
|
|
32
|
+
steps: Record<string, unknown>[];
|
|
33
|
+
}>;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Opens the headed browser window a flow is recorded in (issue #95, studio
|
|
37
|
+
* plan §3.1's last paragraph / phase 6): a Playwright persistent context, in
|
|
38
|
+
* the studio's own profile (`BrowserProfiles`, `headless: false` — the only
|
|
39
|
+
* precedent this codebase already has for a headed launch,
|
|
40
|
+
* `packages/core/src/browser-session/browser-profile.store.ts`), with
|
|
41
|
+
* `recorder-script.client.ts` installed on every page
|
|
42
|
+
* (`context.addInitScript`) and reporting through a context-wide binding
|
|
43
|
+
* (`context.exposeBinding`, so a page opened mid-recording — a link with
|
|
44
|
+
* `target=_blank`, say — is covered too, not only the first page).
|
|
45
|
+
*
|
|
46
|
+
* Each reported action is resolved into a verified selector
|
|
47
|
+
* (`selector-inference`, against the page's own current markup — issue
|
|
48
|
+
* #95's "verified against the page"), turned into a step
|
|
49
|
+
* (`action-to-step.mapper.ts`), and broadcast as an outline card built by
|
|
50
|
+
* `scope-outline`'s own `recipeToOutline` — the same sentence/bracket logic
|
|
51
|
+
* every other phase's cards already go through, never a second card format.
|
|
52
|
+
* A secret field's value is replaced by its `{{env.NAME}}` placeholder
|
|
53
|
+
* before it reaches a step, a card, or this function's return value: the
|
|
54
|
+
* real value is discarded the instant `secret-field.policy.ts` flags the
|
|
55
|
+
* field, never logged, never kept.
|
|
56
|
+
*
|
|
57
|
+
* Recording inside an iframe or shadow DOM is out of this phase's scope
|
|
58
|
+
* (issue #95): `recorder-script.client.ts` detects both and reports them as
|
|
59
|
+
* `unsupported` notes instead of guessing at a selector that would not
|
|
60
|
+
* verify.
|
|
61
|
+
*
|
|
62
|
+
* @param options - The start URL, the profile directory, and browser launch settings.
|
|
63
|
+
* @param callbacks - Where cards and notices go as they happen.
|
|
64
|
+
* @returns A handle: `stop` closes the window and returns every step recorded.
|
|
65
|
+
*/
|
|
66
|
+
export declare function openRecorderSession(options: RecorderSessionOptions, callbacks: RecorderCallbacks): Promise<RecorderSessionHandle>;
|
|
67
|
+
//# sourceMappingURL=recorder-session.use-case.d.ts.map
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { RecordedField } from './recorded-action.contract.js';
|
|
2
|
+
/**
|
|
3
|
+
* Whether a recorded `fill`/`select` field's typed value is a secret: a
|
|
4
|
+
* `type="password"` input, or a field the person explicitly marked (`marked`,
|
|
5
|
+
* a future "mark as secret" UI action — not built by this phase, but the
|
|
6
|
+
* flag is honoured wherever it comes from), or a name/id matching `token`,
|
|
7
|
+
* `secret` or `api[-_]?key` (issue #95's exact wording).
|
|
8
|
+
*
|
|
9
|
+
* @param field - The field's type/name/id, as reported by `recorder-script.client.ts`.
|
|
10
|
+
* @param marked - The person explicitly marked this field as secret; default `false`.
|
|
11
|
+
* @returns Whether the field's value must become `{{env.NAME}}` instead of the real text.
|
|
12
|
+
*/
|
|
13
|
+
export declare function isSecretField(field: RecordedField, marked?: boolean): boolean;
|
|
14
|
+
/**
|
|
15
|
+
* The `{{env.NAME}}` variable name a secret field suggests, from its own
|
|
16
|
+
* name/id (falling back to `PASSWORD` for a bare `type="password"` field
|
|
17
|
+
* with neither): `camelCase`/`kebab-case`/`snake_case` all become
|
|
18
|
+
* `SCREAMING_SNAKE_CASE`, punctuation dropped, so `user-pass`, `userPass`
|
|
19
|
+
* and `user_pass` all suggest `USER_PASS`.
|
|
20
|
+
*
|
|
21
|
+
* @param field - The field's type/name/id.
|
|
22
|
+
* @returns A valid env-var-shaped name (letters, digits, underscores, not starting with a digit).
|
|
23
|
+
*/
|
|
24
|
+
export declare function secretEnvName(field: RecordedField): string;
|
|
25
|
+
/**
|
|
26
|
+
* The placeholder a secret field's value becomes in the recorded recipe:
|
|
27
|
+
* never the real text, in the recipe JSON or anywhere the studio logs.
|
|
28
|
+
*
|
|
29
|
+
* @param field - The field's type/name/id.
|
|
30
|
+
* @returns `{{env.NAME}}`.
|
|
31
|
+
*/
|
|
32
|
+
export declare function secretPlaceholder(field: RecordedField): string;
|
|
33
|
+
//# sourceMappingURL=secret-field.policy.d.ts.map
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { Step } from '@opencraw/core';
|
|
2
|
+
export type WaitStep = Extract<Step, {
|
|
3
|
+
type: 'wait';
|
|
4
|
+
}>;
|
|
5
|
+
/** What happened right after the previous recorded action, before this one. */
|
|
6
|
+
export interface WaitContext {
|
|
7
|
+
/** The previous action's click/key press changed the page. */
|
|
8
|
+
navigated: boolean;
|
|
9
|
+
/** The page fetched something (XHR/`fetch`) since the previous action, without necessarily navigating. */
|
|
10
|
+
xhr: boolean;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Whether a `Wait for <selector>` step belongs between the action that just
|
|
14
|
+
* happened and the next one (issue #95): after a navigation or an XHR, the
|
|
15
|
+
* recorder inserts a wait for the element the person interacts with next, so
|
|
16
|
+
* a replayed recipe does not race the page's own load. Nothing to wait for
|
|
17
|
+
* without a next selector (a page-level key press, a scroll) — and no
|
|
18
|
+
* navigation or fetch either: a recording of a page that never moves should
|
|
19
|
+
* not fill up with waits nobody asked for.
|
|
20
|
+
*
|
|
21
|
+
* @param context - What happened since the previous action.
|
|
22
|
+
* @param nextSelector - The next action's own resolved selector, when it has one.
|
|
23
|
+
* @returns The wait step to insert before the next action's own step, or `undefined`.
|
|
24
|
+
*/
|
|
25
|
+
export declare function insertWaitStep(context: WaitContext, nextSelector: string | undefined): WaitStep | undefined;
|
|
26
|
+
//# sourceMappingURL=wait-insertion.policy.d.ts.map
|
package/dist/src/index.d.ts
CHANGED
|
@@ -3,8 +3,9 @@ export { startStudioServer } from './studio-server/index.js';
|
|
|
3
3
|
export type { StudioServer, StudioServerOptions } from './studio-server/index.js';
|
|
4
4
|
export { openWorkspace, saveRecipe } from './recipe-workspace/index.js';
|
|
5
5
|
export { runSample, loadRecipePair } from './sample-run/index.js';
|
|
6
|
-
export type { RecipePair, SampleRunCallbacks, SampleRunHandle, SampleRunRecord, SampleRunResult, SampleStoppedBy } from './sample-run/index.js';
|
|
6
|
+
export type { RecipePair, SampleRunCallbacks, SampleRunHandle, SampleRunRecord, SampleRunRejected, SampleRunResult, SampleStepSummary, SampleStoppedBy } from './sample-run/index.js';
|
|
7
7
|
export { fetchStartPage } from './page-snapshot/index.js';
|
|
8
|
-
export {
|
|
9
|
-
export
|
|
8
|
+
export type { WhyFacts, WhyStepFact } from './explain-why/index.js';
|
|
9
|
+
export { sampleBudgetSchema, openWorkspaceCommandSchema, runSampleCommandSchema, stopRunCommandSchema, saveRecipeCommandSchema, fetchStartPageCommandSchema, saveOutlineCommandSchema, takeSnapshotCommandSchema, verifySelectorCommandSchema, inferSelectorCommandSchema, missingWhyTargetSchema, rejectedWhyTargetSchema, whyTargetSchema, explainWhyCommandSchema, studioCommandSchema, stoppedBySchema, fieldTraceSchema, traceLineEventSchema, recordEventSchema, recordRejectedEventSchema, runFinishedEventSchema, workspaceChangedEventSchema, studioEventSchema, recipeIssueSchema, recipeListingSchema, workspaceViewSchema, sampleRunRecordSchema, sampleRunViewSchema, startPageViewSchema, snapshotViewSchema, verifySelectorViewSchema, fieldPickSchema, inferSelectorViewSchema, sentencePartSchema, outlineCardSchema, outlineBracketSchema, outlineNodeSchema, outlineViewSchema, whyViewSchema, inspectPageCommandSchema, responsesSeenCommandSchema, documentTreeCommandSchema, pdfViewCommandSchema, tablePreviewOptionsSchema, tablePreviewCommandSchema, gridViewCommandSchema, gridPreviewOptionsSchema, gridPreviewCommandSchema, deckViewCommandSchema, deckPreviewOptionsSchema, deckPreviewCommandSchema, domTreeNodeViewSchema, pageDataFindingSchema, inspectViewSchema, observedResponseSchema, responsesSeenViewSchema, documentTreeNodeViewSchema, documentTreeViewSchema, pdfCellViewSchema, pdfRowViewSchema, pdfPageViewSchema, pdfDocumentViewSchema, tablePreviewTableSchema, tablePreviewBandSchema, tablePreviewMatchSchema, tablePreviewViewSchema, gridCellViewSchema, gridMergeViewSchema, gridSheetViewSchema, workbookDocumentViewSchema, gridTablePreviewMatchSchema, gridTablePreviewViewSchema, deckShapeViewSchema, deckChartSeriesViewSchema, deckChartViewSchema, deckSlideViewSchema, deckDocumentViewSchema, deckTablePreviewMatchSchema, deckTablePreviewViewSchema, startRecordingCommandSchema, stopRecordingCommandSchema, recordingCardEventSchema, recordingNoteEventSchema, recordingStoppedEventSchema, } from './studio-api/index.js';
|
|
10
|
+
export type { SampleBudget, OpenWorkspaceCommand, RunSampleCommand, StopRunCommand, SaveRecipeCommand, FetchStartPageCommand, SaveOutlineCommand, TakeSnapshotCommand, VerifySelectorCommand, InferSelectorCommand, MissingWhyTarget, RejectedWhyTarget, WhyTarget, ExplainWhyCommand, InspectPageCommand, ResponsesSeenCommand, DocumentTreeCommand, PdfViewCommand, TablePreviewOptions, TablePreviewCommand, GridViewCommand, GridPreviewOptions, GridPreviewCommand, DeckViewCommand, DeckPreviewOptions, DeckPreviewCommand, StudioCommand, StoppedBy, FieldTraceView, TraceLineEvent, RecordEvent, RecordRejectedEvent, RunFinishedEvent, WorkspaceChangedEvent, StudioEvent, RecipeIssue, RecipeListing, WorkspaceView, SampleRunView, StartPageView, SnapshotView, VerifySelectorView, FieldPick, InferSelectorView, SentencePart, OutlineCard, OutlineBracket, OutlineNode, OutlineView, WhyView, DomTreeNodeView, PageDataKind, PageDataFindingView, InspectView, ObservedResponseView, ResponsesSeenView, DocumentTreeNodeView, DocumentTreeView, PdfCellView, PdfRowView, PdfPageView, PdfDocumentView, TablePreviewTableView, TablePreviewBandView, TablePreviewMatchView, TablePreviewView, GridCellView, GridMergeView, GridSheetView, WorkbookDocumentView, GridTablePreviewMatchView, GridTablePreviewView, DeckShapeView, DeckChartSeriesView, DeckChartView, DeckSlideView, DeckDocumentView, DeckTablePreviewMatchView, DeckTablePreviewView, StartRecordingCommand, StopRecordingCommand, RecordingCardEvent, RecordingNoteEvent, RecordingStoppedEvent, } from './studio-api/index.js';
|
|
10
11
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/** One row of the Inspect panel's DOM tree (studio plan §3.3, issue #93): a snapshot element, or a collapsed run of identical siblings. */
|
|
2
|
+
export interface DomTreeNode {
|
|
3
|
+
/** The snapshot's own `data-oc-node` id — what a pick addresses. Present on every real element; absent only on the synthetic wrapper a collapsed run never needs (a run always keeps its first member's id here). */
|
|
4
|
+
nodeId: string;
|
|
5
|
+
tag: string;
|
|
6
|
+
id?: string;
|
|
7
|
+
classes?: string[];
|
|
8
|
+
/** Every other attribute (the internal `data-oc-node`/`data-oc-hidden` marks stripped). */
|
|
9
|
+
attributes: Record<string, string>;
|
|
10
|
+
/** This element's own text, trimmed and cut to `TEXT_LIMIT`, when it has no element children (mixed element+text content shows only the element children — see this file's `buildNode`). */
|
|
11
|
+
text?: string;
|
|
12
|
+
/** From the snapshot's `data-oc-hidden` mark (`hidden-marks.algorithm.ts`, phase 2). */
|
|
13
|
+
hidden: boolean;
|
|
14
|
+
children: DomTreeNode[];
|
|
15
|
+
/** Set when this row stands for a run of `repeatCount` structurally identical consecutive siblings (same tag, attributes and subtree — ids aside): the issue's `×20`. `repeatNodeIds` carries every collapsed sibling's own id, so a pick still knows every node the row represents. */
|
|
16
|
+
repeatCount?: number;
|
|
17
|
+
repeatNodeIds?: string[];
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Builds the Inspect panel's DOM tree from a captured snapshot (studio plan
|
|
21
|
+
* §3.3, issue #93): the same rewritten, marked-up document the content pane's
|
|
22
|
+
* iframe shows (`page-snapshot`'s `take-snapshot.use-case.ts`), so a tree
|
|
23
|
+
* row's `nodeId` addresses exactly the element the iframe would highlight —
|
|
24
|
+
* no separate capture, per issue #93's scope note to reuse phase 2's
|
|
25
|
+
* snapshot rather than recapture.
|
|
26
|
+
*
|
|
27
|
+
* @param snapshotHtml - The cached, rewritten snapshot (`SnapshotResult.html`).
|
|
28
|
+
* @returns The tree's root (the document's `<html>` element).
|
|
29
|
+
* @throws Error when the document has no `<html>` element (should not happen: `rewriteDocument` always produces one).
|
|
30
|
+
*/
|
|
31
|
+
export declare function domTree(snapshotHtml: string): DomTreeNode;
|
|
32
|
+
//# sourceMappingURL=dom-tree.mapper.d.ts.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { domTree } from './dom-tree.mapper.js';
|
|
2
|
+
export type { DomTreeNode } from './dom-tree.mapper.js';
|
|
3
|
+
export { pageData } from './page-data.algorithm.js';
|
|
4
|
+
export type { PageDataFinding, PageDataKind } from './page-data.algorithm.js';
|
|
5
|
+
export { responsesSeen } from './responses-seen.use-case.js';
|
|
6
|
+
export type { ObservedResponse } from './responses-seen.use-case.js';
|
|
7
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
export type PageDataKind = 'ld-json' | 'json-script' | 'inline-state' | 'meta' | 'link';
|
|
2
|
+
/** One pickable value in "data in the page" (studio plan §3.3, issue #93): a `<script type="application/ld+json">`/`"application/json">` block, an inline state assignment, a `<meta>`, or a `<link rel>`. */
|
|
3
|
+
export interface PageDataFinding {
|
|
4
|
+
kind: PageDataKind;
|
|
5
|
+
/** What the UI shows for this row: the JSON-LD `@type`, the global name assigned (`__NEXT_DATA__`), or `meta:`/`link:` and its name/rel. */
|
|
6
|
+
label: string;
|
|
7
|
+
/** A selector verified against the real page (never the sanitised snapshot: `ld-json`/`json-script`/`inline-state` live inside a `<script>`, which the snapshot's `rewriteDocument` strips for the sandboxed iframe — see this file's own doc comment). */
|
|
8
|
+
selector: string;
|
|
9
|
+
selectorKind: 'css';
|
|
10
|
+
/** How many elements this selector reaches on the real page — always 1 by construction (`structuralSelector` is a full ancestor path), kept as a field so the UI's "N matches" confidence reads the same as a tree pick's. */
|
|
11
|
+
matches: number;
|
|
12
|
+
/** The parsed value's top-level keys, each pickable as its own `$.<key>` `jsonpath` card — absent when the value is not a JSON object (an array, a scalar, or text that did not parse). */
|
|
13
|
+
keys?: string[];
|
|
14
|
+
/** `meta`/`link` only: which attribute holds the pickable value (`content`/`href`). */
|
|
15
|
+
attribute?: string;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Finds the data-in-the-page findings the Inspect panel lists apart from the
|
|
19
|
+
* DOM tree (studio plan §3.3, issue #93): JSON-LD and `application/json`
|
|
20
|
+
* script blocks, inline state assignments, `<meta>` name/property values and
|
|
21
|
+
* `<link rel>`s — reusing `@opencraw/probe`'s `describeJson` for a found
|
|
22
|
+
* value's shape (its own `find-data.algorithm.ts`/`html-findings.mapper.ts`
|
|
23
|
+
* scan a page's raw text for *reporting*, with no element to point a pick at;
|
|
24
|
+
* this function's own job — locating each finding's element so a pick can
|
|
25
|
+
* reach it — is new).
|
|
26
|
+
*
|
|
27
|
+
* Takes the **raw** captured document, not the display snapshot
|
|
28
|
+
* (`page-snapshot`'s `SnapshotResult.html`): `rewriteDocument` strips every
|
|
29
|
+
* `<script>` for the sandboxed iframe, which would make JSON-LD, inline
|
|
30
|
+
* state and other script-tag data invisible here. `<meta>`/`<link>` survive
|
|
31
|
+
* rewriting untouched, so using the raw document for every kind (rather than
|
|
32
|
+
* mixing two documents) keeps this function simple and its selectors
|
|
33
|
+
* verified against what the engine will actually crawl.
|
|
34
|
+
*
|
|
35
|
+
* @param rawHtml - The document as fetched/rendered, before `rewriteDocument` strips scripts.
|
|
36
|
+
* @returns The findings, in document order.
|
|
37
|
+
*/
|
|
38
|
+
export declare function pageData(rawHtml: string): PageDataFinding[];
|
|
39
|
+
//# sourceMappingURL=page-data.algorithm.d.ts.map
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { BrowserSessionConfig, InputRecipe } from '@opencraw/core';
|
|
2
|
+
/** One JSON response the page fetched while it rendered (studio plan §3.3, issue #93): what "responses seen" lists, and what picking one switches the recipe to api mode on. */
|
|
3
|
+
export interface ObservedResponse {
|
|
4
|
+
url: string;
|
|
5
|
+
status: number;
|
|
6
|
+
/** The response body's size in bytes (its UTF-8 text length). */
|
|
7
|
+
size: number;
|
|
8
|
+
/** The top-level shape (`describeJson`'s own `type`: `"object"`, `"array (12) of object"`…), or `"text"` when the body did not parse as JSON despite its content type. */
|
|
9
|
+
shape: string;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Records the JSON responses seen while an input recipe's start page
|
|
13
|
+
* rendered (studio plan §3.3, issue #93): the same technique `packages/cli`'s
|
|
14
|
+
* `probe --browser` uses (`observeBrowserJson`) — render the page, listen for
|
|
15
|
+
* `response` events whose content type is JSON, give it a few seconds to
|
|
16
|
+
* settle. Kept as its own capture, independent of `page-snapshot`'s
|
|
17
|
+
* `take-snapshot.use-case.ts`: that capture reads `page.content()` right
|
|
18
|
+
* after `goto` resolves, with no observation window, and changing its shape
|
|
19
|
+
* to also collect responses was a larger, riskier change to already-shipped,
|
|
20
|
+
* tested code than this phase's budget allowed (see this phase's final
|
|
21
|
+
* report) — so this opens its own short-lived browser session instead of
|
|
22
|
+
* piggy-backing on the cached snapshot.
|
|
23
|
+
*
|
|
24
|
+
* Only `"start"` is supported, mirroring `take-snapshot.use-case.ts`'s own
|
|
25
|
+
* reach; api-mode recipes have no page load to observe, so they always
|
|
26
|
+
* answer with an empty list rather than an error (there is nothing wrong
|
|
27
|
+
* with asking, the answer is just "none").
|
|
28
|
+
*
|
|
29
|
+
* @param input - The input recipe; only `mode` and the first `start` point are used.
|
|
30
|
+
* @param stepPath - The step to observe after, e.g. `"start"`.
|
|
31
|
+
* @param browser - Browser launch settings, shared with `take-snapshot`/`verify-selector`/`run-sample`.
|
|
32
|
+
* @returns The distinct JSON responses observed, at most `RESPONSE_LIMIT`.
|
|
33
|
+
* @throws Error when the recipe has no start point, or `stepPath` is not `"start"`.
|
|
34
|
+
*/
|
|
35
|
+
export declare function responsesSeen(input: InputRecipe, stepPath: string, browser?: BrowserSessionConfig): Promise<ObservedResponse[]>;
|
|
36
|
+
//# sourceMappingURL=responses-seen.use-case.d.ts.map
|
|
@@ -6,4 +6,7 @@ export type { RewrittenDocument } from './rewrite-document.mapper.js';
|
|
|
6
6
|
export { hiddenMarksScript, HIDDEN_ATTRIBUTE } from './hidden-marks.algorithm.js';
|
|
7
7
|
export { createSnapshotCache, cachedSnapshot, putSnapshot, invalidateRecipe } from './snapshot.store.js';
|
|
8
8
|
export type { SnapshotCache } from './snapshot.store.js';
|
|
9
|
+
export { pdfBytes } from './pdf-bytes.use-case.js';
|
|
10
|
+
export { rereadCsv } from './reread-csv.use-case.js';
|
|
11
|
+
export type { CsvOverride } from './reread-csv.use-case.js';
|
|
9
12
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fetches a PDF's raw bytes for the PDF canvas's `pdf.js` to render in the
|
|
3
|
+
* browser (studio plan §3.4, issue #94's 5b: "the PDF bytes served by the
|
|
4
|
+
* studio"). `take-snapshot` already read this same document with
|
|
5
|
+
* `@opencraw/core`'s `readPdf` for the cells/rows `document-view` maps, but
|
|
6
|
+
* `HttpClient`/`readPdf` parse the bytes and keep only the result — pdf.js
|
|
7
|
+
* needs the file itself, so this re-fetches it from the same URL a cached
|
|
8
|
+
* snapshot's own `SnapshotResult.baseUrl` gives, the way `HttpClient`'s own
|
|
9
|
+
* `file:` branch (`readLocalFile`) and its HTTP fetch do.
|
|
10
|
+
*
|
|
11
|
+
* @param url - The document's URL — a `file:` URL or an `http(s):` URL.
|
|
12
|
+
* @returns The raw bytes.
|
|
13
|
+
* @throws Error when a `file:` URL cannot be read, or the fetch does not succeed.
|
|
14
|
+
*/
|
|
15
|
+
export declare function pdfBytes(url: string): Promise<Uint8Array>;
|
|
16
|
+
//# sourceMappingURL=pdf-bytes.use-case.d.ts.map
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { WorkbookDocument } from '@opencraw/core';
|
|
2
|
+
/** `delimiter`/`encoding` on a `grid-view` request overriding what was auto-detected (issue #94's 5c: "the detected delimiter and encoding shown and overridable"); either, both, or neither. */
|
|
3
|
+
export interface CsvOverride {
|
|
4
|
+
delimiter?: string;
|
|
5
|
+
encoding?: string;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Re-reads a CSV document with an overridden delimiter and/or encoding
|
|
9
|
+
* (studio plan §3.4, issue #94's 5c). `take-snapshot` already read this same
|
|
10
|
+
* document once with auto-detection (`http.client.ts`'s own `csvWorkbook`
|
|
11
|
+
* call); it keeps only the parsed result, not the raw bytes, so re-reading
|
|
12
|
+
* the file/URL is the only way to apply a different choice — the same
|
|
13
|
+
* "the studio re-fetches, the reader keeps no bytes around" tradeoff
|
|
14
|
+
* `pdf-bytes.use-case.ts` documents for pdf.js.
|
|
15
|
+
*
|
|
16
|
+
* @param url - The document's URL — a `file:` URL or an `http(s):` URL (`page-snapshot`'s cached `SnapshotResult.baseUrl`).
|
|
17
|
+
* @param override - The delimiter and/or encoding to force; `HttpClient` still detects whichever one is left out.
|
|
18
|
+
* @returns The freshly read workbook.
|
|
19
|
+
* @throws Error when the URL cannot be read, or it no longer reads back as a workbook.
|
|
20
|
+
*/
|
|
21
|
+
export declare function rereadCsv(url: string, override: CsvOverride): Promise<WorkbookDocument>;
|
|
22
|
+
//# sourceMappingURL=reread-csv.use-case.d.ts.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { BrowserSessionConfig, InputRecipe } from '@opencraw/core';
|
|
1
|
+
import type { BodyKind, BrowserSessionConfig, HttpBody, InputRecipe } from '@opencraw/core';
|
|
2
2
|
export interface SnapshotResult {
|
|
3
3
|
/** The rewritten document, ready for the content pane's sandboxed iframe. */
|
|
4
4
|
html: string;
|
|
@@ -6,6 +6,31 @@ export interface SnapshotResult {
|
|
|
6
6
|
nodeCount: number;
|
|
7
7
|
/** The page's own URL, used to resolve every relative URL and as the `<base>`. */
|
|
8
8
|
baseUrl: string;
|
|
9
|
+
/**
|
|
10
|
+
* The document as captured, before `rewriteDocument` strips every
|
|
11
|
+
* `<script>` for the sandboxed iframe — server-side only, never sent to the
|
|
12
|
+
* UI (`studio-api`'s `SnapshotView` does not carry it): `page-inspector`'s
|
|
13
|
+
* `page-data.algorithm.ts` (issue #93) needs the JSON-LD, inline state and
|
|
14
|
+
* `application/json` blocks a script tag can hold, which the display
|
|
15
|
+
* snapshot no longer has by the time it is cached.
|
|
16
|
+
*/
|
|
17
|
+
rawHtml: string;
|
|
18
|
+
/**
|
|
19
|
+
* The format `http.client.ts` read the body as (api mode only; `undefined`
|
|
20
|
+
* in web mode, whose document is always HTML) — what the content pane
|
|
21
|
+
* uses to pick a canvas: `document-view`'s tree/pdf/grid/deck for
|
|
22
|
+
* `json`/`yaml`/`xml`/`pdf`/`csv`/`xlsx`/`pptx`, the snapshot iframe for
|
|
23
|
+
* `html` (and `docx`/`markdown`, which `http.client.ts` already turns into
|
|
24
|
+
* HTML), studio plan §3.4, issue #94.
|
|
25
|
+
*/
|
|
26
|
+
format?: BodyKind;
|
|
27
|
+
/**
|
|
28
|
+
* The parsed body itself (api mode only), for `document-view`'s mappers to
|
|
29
|
+
* read — server-side only, never sent to the UI as-is (`studio-api`'s
|
|
30
|
+
* `SnapshotView` carries only `format`; a canvas asks for its own view
|
|
31
|
+
* model with a follow-up command, `inspect-page`'s own pattern).
|
|
32
|
+
*/
|
|
33
|
+
body?: HttpBody;
|
|
9
34
|
}
|
|
10
35
|
/**
|
|
11
36
|
* Captures the snapshot the content pane shows (studio plan §3.1, issue
|
|
@@ -2,5 +2,7 @@ export { loadRecipePair } from './load-recipe-pair.use-case.js';
|
|
|
2
2
|
export type { RecipePair } from './load-recipe-pair.use-case.js';
|
|
3
3
|
export { runSample } from './run-sample.use-case.js';
|
|
4
4
|
export type { SampleRunCallbacks, SampleRunHandle } from './run-sample.use-case.js';
|
|
5
|
-
export type { SampleRunRecord, SampleRunResult, SampleStoppedBy } from './sample-run-record.contract.js';
|
|
5
|
+
export type { SampleRunRecord, SampleRunRejected, SampleRunResult, SampleStepSummary, SampleStoppedBy } from './sample-run-record.contract.js';
|
|
6
|
+
export { createLastRunCache, lastRunOf, recordLastRun } from './last-run.store.js';
|
|
7
|
+
export type { LastRunCache, LastRunEntry } from './last-run.store.js';
|
|
6
8
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { SampleRunResult } from './sample-run-record.contract.js';
|
|
2
|
+
/** The last completed sample run of one input recipe: its records, rejections, mapping traces and step summary, kept for `explain-why` (issue #92) so a Why? click needs no second run. */
|
|
3
|
+
export interface LastRunEntry {
|
|
4
|
+
recipeId: string;
|
|
5
|
+
result: SampleRunResult;
|
|
6
|
+
}
|
|
7
|
+
/** One server's worth of last-run entries, by recipe id: a run replaces the previous one for the same recipe. */
|
|
8
|
+
export interface LastRunCache {
|
|
9
|
+
entries: Map<string, LastRunEntry>;
|
|
10
|
+
}
|
|
11
|
+
/** @returns A fresh, empty cache. */
|
|
12
|
+
export declare function createLastRunCache(): LastRunCache;
|
|
13
|
+
/** Records a finished sample run, replacing whatever this recipe's cache entry held before. */
|
|
14
|
+
export declare function recordLastRun(cache: LastRunCache, recipeId: string, result: SampleRunResult): void;
|
|
15
|
+
/** @returns The recipe's last completed sample run, or `undefined` when none has finished yet. */
|
|
16
|
+
export declare function lastRunOf(cache: LastRunCache, recipeId: string): LastRunEntry | undefined;
|
|
17
|
+
//# sourceMappingURL=last-run.store.d.ts.map
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import type { BrowserSessionConfig } from '@opencraw/core';
|
|
2
2
|
import type { SampleBudget } from '../studio-api/index.js';
|
|
3
|
-
import type { SampleRunRecord, SampleRunResult } from './sample-run-record.contract.js';
|
|
3
|
+
import type { SampleRunRecord, SampleRunRejected, SampleRunResult } from './sample-run-record.contract.js';
|
|
4
4
|
/** Where trace lines and records go as a sample run proceeds. */
|
|
5
5
|
export interface SampleRunCallbacks {
|
|
6
6
|
onTraceLine: (line: string) => void;
|
|
7
7
|
onRecord: (record: SampleRunRecord) => void;
|
|
8
|
+
/** A record was rejected (a field's `skip-record` missing/coercion policy); optional, most callers only need the final `rejectedRecords` list. */
|
|
9
|
+
onRejected?: (rejected: SampleRunRejected) => void;
|
|
8
10
|
}
|
|
9
11
|
/** A sample run in progress. */
|
|
10
12
|
export interface SampleRunHandle {
|
|
@@ -14,11 +16,15 @@ export interface SampleRunHandle {
|
|
|
14
16
|
}
|
|
15
17
|
/**
|
|
16
18
|
* Runs one input recipe of a workspace folder as a sample: `debug: true` (so
|
|
17
|
-
* each `record:emit` carries its
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
* `
|
|
19
|
+
* each `record:emit` carries its scope snapshot and mapping trace, and each
|
|
20
|
+
* `record:reject` its scope), an in-memory sink, and `budget` as the
|
|
21
|
+
* crawler's `sample` (`@opencraw/core`'s `CrawlOptions.sample`, #89). Every
|
|
22
|
+
* engine event becomes a trace line with the same `traceLine` formatter the
|
|
23
|
+
* cli's `--trace` uses; every emitted record reaches `callbacks.onRecord` as
|
|
24
|
+
* it happens, not only in the final result. Step events (`step:start`,
|
|
25
|
+
* `step:skip`, `step:retry`) are aggregated by path into `result.steps`, so
|
|
26
|
+
* `explain-why` (#92) can later say whether the step that bound a mapping's
|
|
27
|
+
* source id ran, was skipped, or retried — without a second run.
|
|
22
28
|
*
|
|
23
29
|
* @param folder - The workspace folder the recipe lives in.
|
|
24
30
|
* @param recipeId - The input recipe to run.
|
|
@@ -1,10 +1,37 @@
|
|
|
1
|
-
|
|
1
|
+
import type { MappingTrace } from '@opencraw/core';
|
|
2
|
+
/**
|
|
3
|
+
* One record streamed or kept from a sample run. `scope` (the snapshot it
|
|
4
|
+
* was mapped from) and `mapping` (each field's source value and its value
|
|
5
|
+
* after every transform, `@opencraw/core`'s `record:emit.mapping`, core
|
|
6
|
+
* since 0.1.12) are always present: `runSample` runs with `debug: true`.
|
|
7
|
+
* Kept per record (studio plan §4.2/§4.4, issue #92) so the Record tab can
|
|
8
|
+
* show a transform chain's real values and the Why? tab can explain a
|
|
9
|
+
* missing one, without a second run.
|
|
10
|
+
*/
|
|
2
11
|
export interface SampleRunRecord {
|
|
3
12
|
key: string | null;
|
|
4
13
|
data: Record<string, unknown>;
|
|
14
|
+
scope?: Record<string, unknown>;
|
|
15
|
+
mapping?: MappingTrace;
|
|
16
|
+
}
|
|
17
|
+
/** One record a sample run rejected (`RecordRejectedError`, a field's `skip-record` policy), kept for the Why? tab. */
|
|
18
|
+
export interface SampleRunRejected {
|
|
19
|
+
field: string;
|
|
20
|
+
reason: string;
|
|
21
|
+
url: string;
|
|
22
|
+
scope?: Record<string, unknown>;
|
|
5
23
|
}
|
|
6
24
|
/** A sample run's stopping reason: mirrors `@opencraw/core`'s `RecipeReport.stoppedBy`. */
|
|
7
25
|
export type SampleStoppedBy = 'sample-maxRecords' | 'sample-maxPages' | 'sample-maxMs';
|
|
26
|
+
/** One outcome of a step during a sample run, aggregated over every time its path ran: whether it ever ran cleanly, was skipped, or retried, kept for the Why? tab (issue #92) — which step bound a mapping's source id, and whether it found nothing. */
|
|
27
|
+
export interface SampleStepSummary {
|
|
28
|
+
path: string;
|
|
29
|
+
stepType: string;
|
|
30
|
+
stepId?: string;
|
|
31
|
+
as?: string;
|
|
32
|
+
outcome: 'ran' | 'skipped' | 'retried';
|
|
33
|
+
error?: string;
|
|
34
|
+
}
|
|
8
35
|
/** What a sample run finished with. */
|
|
9
36
|
export interface SampleRunResult {
|
|
10
37
|
recipeId: string;
|
|
@@ -15,5 +42,7 @@ export interface SampleRunResult {
|
|
|
15
42
|
error?: string;
|
|
16
43
|
stoppedBy?: SampleStoppedBy;
|
|
17
44
|
records: SampleRunRecord[];
|
|
45
|
+
rejectedRecords: SampleRunRejected[];
|
|
46
|
+
steps: SampleStepSummary[];
|
|
18
47
|
}
|
|
19
48
|
//# sourceMappingURL=sample-run-record.contract.d.ts.map
|