my-frontend-observer 0.1.0 → 0.3.0

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.
Files changed (46) hide show
  1. package/CHANGELOG.md +82 -1
  2. package/README.md +30 -7
  3. package/dist/application/observationPersistence.js +1 -0
  4. package/dist/application/observationPersistence.js.map +1 -1
  5. package/dist/browser/chromiumAdapter.js +58 -4
  6. package/dist/browser/chromiumAdapter.js.map +1 -1
  7. package/dist/browser/evidenceCapture.d.ts +46 -3
  8. package/dist/browser/evidenceCapture.js +393 -94
  9. package/dist/browser/evidenceCapture.js.map +1 -1
  10. package/dist/browser/scrollCapture.d.ts +32 -0
  11. package/dist/browser/scrollCapture.js +163 -0
  12. package/dist/browser/scrollCapture.js.map +1 -0
  13. package/dist/browser/types.d.ts +3 -1
  14. package/dist/cli.js +165 -7
  15. package/dist/cli.js.map +1 -1
  16. package/dist/domain/diagnostics.d.ts +1 -1
  17. package/dist/domain/diagnostics.js +2 -0
  18. package/dist/domain/diagnostics.js.map +1 -1
  19. package/dist/domain/identity.d.ts +8 -3
  20. package/dist/domain/identity.js +10 -4
  21. package/dist/domain/identity.js.map +1 -1
  22. package/dist/domain/schema.d.ts +164 -6
  23. package/dist/domain/schema.js +314 -4
  24. package/dist/domain/schema.js.map +1 -1
  25. package/dist/domain/scrollEvidence.d.ts +51 -0
  26. package/dist/domain/scrollEvidence.js +134 -0
  27. package/dist/domain/scrollEvidence.js.map +1 -0
  28. package/dist/index.d.ts +4 -4
  29. package/dist/index.js +2 -2
  30. package/dist/index.js.map +1 -1
  31. package/dist/request/request.d.ts +57 -1
  32. package/dist/request/request.js +292 -14
  33. package/dist/request/request.js.map +1 -1
  34. package/docs/ARCHITECTURE.md +62 -1
  35. package/docs/CI_CD.md +49 -8
  36. package/docs/COMMANDS.md +184 -9
  37. package/docs/CONTRACTS.md +135 -6
  38. package/docs/CURRENT_STATE.md +128 -6
  39. package/docs/DEVELOPMENT.md +41 -3
  40. package/docs/PROJECT_OVERVIEW.md +12 -6
  41. package/docs/QUICKSTART.md +3 -1
  42. package/docs/RELEASE.md +12 -5
  43. package/docs/ROADMAP.md +9 -0
  44. package/docs/SECURITY.md +6 -2
  45. package/docs/WORKFLOWS.md +41 -14
  46. package/package.json +1 -1
@@ -0,0 +1,51 @@
1
+ import type { EvidenceField } from './evidence.js';
2
+ import type { Viewport } from '../request/request.js';
3
+ import type { ScrollableMetrics, OverflowEvidence, ViewportRelationEvidence, TargetGeometry, ScrollRuntimeSnapshot, TargetScrollRuntimeState, TargetScrollTransition, ScrollScenarioTransition, ScrollOwnerInterpretation } from './schema.js';
4
+ /**
5
+ * Derived only from a bounding rectangle (viewport-relative, as produced by
6
+ * `getBoundingClientRect()`) plus viewport width/height - never from source
7
+ * styles or locator kind (Batch 1 frozen contract). `above`/`below` require
8
+ * the rectangle to be *entirely* outside the viewport on that axis; any
9
+ * vertical overlap with `[0, viewport.height)` is `intersecting`.
10
+ */
11
+ export declare function deriveViewportRelation(rect: TargetGeometry, viewport: Viewport): ViewportRelationEvidence;
12
+ /**
13
+ * Distinguishes a computed `overflow-x`/`overflow-y` CSS declaration from
14
+ * actual dimensional overflow. `overflow-x: auto`/`overflow-y: scroll` alone
15
+ * never implies actual overflow - only `scrollWidth > clientWidth` /
16
+ * `scrollHeight > clientHeight` do.
17
+ */
18
+ export declare function deriveOverflowEvidence(metrics: ScrollableMetrics, overflowX: string, overflowY: string): OverflowEvidence;
19
+ /**
20
+ * Bounded before/after change evidence for one configured target across the
21
+ * one scroll action - not a generic recursive diff. Returns `undefined`
22
+ * (rather than fabricating zeroed/default values) when either snapshot's
23
+ * metrics/boundingRect/viewportRelation evidence for this target is not
24
+ * itself usable (e.g. the target never resolved), consistent with
25
+ * `enteredViewport`/`leftViewport` only being evaluated when both
26
+ * viewport-relation states are valid.
27
+ */
28
+ export declare function deriveTargetScrollTransition(initial: TargetScrollRuntimeState, final: TargetScrollRuntimeState): TargetScrollTransition | undefined;
29
+ /** Derives the bounded scenario transition evidence purely from the two already-captured runtime snapshots - no re-measurement, no generic JSON diffing. A target absent from either snapshot's `targets` map, or whose per-target transition cannot be derived (see `deriveTargetScrollTransition`), is simply omitted from `targets` here. */
30
+ export declare function deriveScrollScenarioTransition(initial: ScrollRuntimeSnapshot, final: ScrollRuntimeSnapshot): ScrollScenarioTransition;
31
+ /**
32
+ * Conservative scroll-owner derivation, shared by both `window-scroll-by`
33
+ * and `target-scroll-by` scenarios: relies solely on observed scroll
34
+ * *position* changes (`scrollTop`/`scrollLeft`/`window.scrollX`/
35
+ * `window.scrollY`), never on a target's bounding-rectangle movement (which
36
+ * moves for every configured target whenever the document scrolls,
37
+ * regardless of who "owns" scrolling - using it here would falsely
38
+ * attribute document scrolling to every visible target) and never on
39
+ * computed overflow, `position: fixed`/`sticky`, target name, locator kind,
40
+ * or DOM hierarchy.
41
+ *
42
+ * Rules (frozen Batch 1 vocabulary):
43
+ * - no window movement, no target movement -> `none`;
44
+ * - window movement, no competing target movement -> `document`;
45
+ * - no window movement, exactly one target's own scroll position moved
46
+ * (on either or both axes - two axes of the *same* target is still one
47
+ * owner) -> `target:<name>`;
48
+ * - anything else (window plus a target, or more than one target) ->
49
+ * `indeterminate` - multiple plausible owners, never forced to pick one.
50
+ */
51
+ export declare function deriveScrollOwner(transition: ScrollScenarioTransition): EvidenceField<ScrollOwnerInterpretation>;
@@ -0,0 +1,134 @@
1
+ /**
2
+ * Derived only from a bounding rectangle (viewport-relative, as produced by
3
+ * `getBoundingClientRect()`) plus viewport width/height - never from source
4
+ * styles or locator kind (Batch 1 frozen contract). `above`/`below` require
5
+ * the rectangle to be *entirely* outside the viewport on that axis; any
6
+ * vertical overlap with `[0, viewport.height)` is `intersecting`.
7
+ */
8
+ export function deriveViewportRelation(rect, viewport) {
9
+ const vertical = rect.bottom <= 0 ? 'above' : rect.y >= viewport.height ? 'below' : 'intersecting';
10
+ const intersectsViewport = rect.right > 0 && rect.x < viewport.width && rect.bottom > 0 && rect.y < viewport.height;
11
+ const fullyWithinViewport = rect.x >= 0 && rect.y >= 0 && rect.right <= viewport.width && rect.bottom <= viewport.height;
12
+ return { vertical, intersectsViewport, fullyWithinViewport };
13
+ }
14
+ /**
15
+ * Distinguishes a computed `overflow-x`/`overflow-y` CSS declaration from
16
+ * actual dimensional overflow. `overflow-x: auto`/`overflow-y: scroll` alone
17
+ * never implies actual overflow - only `scrollWidth > clientWidth` /
18
+ * `scrollHeight > clientHeight` do.
19
+ */
20
+ export function deriveOverflowEvidence(metrics, overflowX, overflowY) {
21
+ return {
22
+ horizontalOverflow: metrics.scrollWidth > metrics.clientWidth,
23
+ verticalOverflow: metrics.scrollHeight > metrics.clientHeight,
24
+ overflowX,
25
+ overflowY,
26
+ };
27
+ }
28
+ function numberChange(before, after) {
29
+ return { before, after, changed: before !== after };
30
+ }
31
+ function extractAvailable(field) {
32
+ return field.state === 'available' || field.state === 'partial' ? field.value : undefined;
33
+ }
34
+ /**
35
+ * Bounded before/after change evidence for one configured target across the
36
+ * one scroll action - not a generic recursive diff. Returns `undefined`
37
+ * (rather than fabricating zeroed/default values) when either snapshot's
38
+ * metrics/boundingRect/viewportRelation evidence for this target is not
39
+ * itself usable (e.g. the target never resolved), consistent with
40
+ * `enteredViewport`/`leftViewport` only being evaluated when both
41
+ * viewport-relation states are valid.
42
+ */
43
+ export function deriveTargetScrollTransition(initial, final) {
44
+ const initialMetrics = extractAvailable(initial.metrics);
45
+ const finalMetrics = extractAvailable(final.metrics);
46
+ const initialRect = extractAvailable(initial.boundingRect);
47
+ const finalRect = extractAvailable(final.boundingRect);
48
+ const initialRelation = extractAvailable(initial.viewportRelation);
49
+ const finalRelation = extractAvailable(final.viewportRelation);
50
+ if (!initialMetrics || !finalMetrics || !initialRect || !finalRect || !initialRelation || !finalRelation) {
51
+ return undefined;
52
+ }
53
+ const enteredViewport = !initialRelation.intersectsViewport && finalRelation.intersectsViewport;
54
+ const leftViewport = initialRelation.intersectsViewport && !finalRelation.intersectsViewport;
55
+ return {
56
+ scrollTop: numberChange(initialMetrics.scrollTop, finalMetrics.scrollTop),
57
+ scrollLeft: numberChange(initialMetrics.scrollLeft, finalMetrics.scrollLeft),
58
+ boundingRectPosition: {
59
+ before: { x: initialRect.x, y: initialRect.y },
60
+ after: { x: finalRect.x, y: finalRect.y },
61
+ changed: initialRect.x !== finalRect.x || initialRect.y !== finalRect.y,
62
+ },
63
+ viewportRelation: { before: initialRelation.vertical, after: finalRelation.vertical, changed: initialRelation.vertical !== finalRelation.vertical },
64
+ enteredViewport,
65
+ leftViewport,
66
+ };
67
+ }
68
+ /** Derives the bounded scenario transition evidence purely from the two already-captured runtime snapshots - no re-measurement, no generic JSON diffing. A target absent from either snapshot's `targets` map, or whose per-target transition cannot be derived (see `deriveTargetScrollTransition`), is simply omitted from `targets` here. */
69
+ export function deriveScrollScenarioTransition(initial, final) {
70
+ const targets = {};
71
+ for (const [name, initialState] of Object.entries(initial.targets)) {
72
+ const finalState = final.targets[name];
73
+ if (!finalState)
74
+ continue;
75
+ const transition = deriveTargetScrollTransition(initialState, finalState);
76
+ if (transition)
77
+ targets[name] = transition;
78
+ }
79
+ return {
80
+ windowScrollX: numberChange(initial.window.scrollX, final.window.scrollX),
81
+ windowScrollY: numberChange(initial.window.scrollY, final.window.scrollY),
82
+ targets,
83
+ };
84
+ }
85
+ /**
86
+ * Conservative scroll-owner derivation, shared by both `window-scroll-by`
87
+ * and `target-scroll-by` scenarios: relies solely on observed scroll
88
+ * *position* changes (`scrollTop`/`scrollLeft`/`window.scrollX`/
89
+ * `window.scrollY`), never on a target's bounding-rectangle movement (which
90
+ * moves for every configured target whenever the document scrolls,
91
+ * regardless of who "owns" scrolling - using it here would falsely
92
+ * attribute document scrolling to every visible target) and never on
93
+ * computed overflow, `position: fixed`/`sticky`, target name, locator kind,
94
+ * or DOM hierarchy.
95
+ *
96
+ * Rules (frozen Batch 1 vocabulary):
97
+ * - no window movement, no target movement -> `none`;
98
+ * - window movement, no competing target movement -> `document`;
99
+ * - no window movement, exactly one target's own scroll position moved
100
+ * (on either or both axes - two axes of the *same* target is still one
101
+ * owner) -> `target:<name>`;
102
+ * - anything else (window plus a target, or more than one target) ->
103
+ * `indeterminate` - multiple plausible owners, never forced to pick one.
104
+ */
105
+ export function deriveScrollOwner(transition) {
106
+ const windowMoved = transition.windowScrollX.changed || transition.windowScrollY.changed;
107
+ const changedTargetNames = Object.entries(transition.targets)
108
+ .filter(([, t]) => t.scrollTop.changed || t.scrollLeft.changed)
109
+ .map(([name]) => name);
110
+ let value;
111
+ let derivedFrom;
112
+ if (!windowMoved && changedTargetNames.length === 0) {
113
+ value = { kind: 'none' };
114
+ derivedFrom = ['window.scrollX', 'window.scrollY', ...Object.keys(transition.targets).flatMap((name) => [`${name}.scrollTop`, `${name}.scrollLeft`])];
115
+ }
116
+ else if (windowMoved && changedTargetNames.length === 0) {
117
+ value = { kind: 'document' };
118
+ derivedFrom = ['window.scrollX', 'window.scrollY'];
119
+ }
120
+ else if (!windowMoved && changedTargetNames.length === 1) {
121
+ const target = changedTargetNames[0];
122
+ value = { kind: 'target', target };
123
+ derivedFrom = [`${target}.scrollTop`, `${target}.scrollLeft`];
124
+ }
125
+ else {
126
+ value = { kind: 'indeterminate' };
127
+ derivedFrom = [
128
+ ...(windowMoved ? ['window.scrollX', 'window.scrollY'] : []),
129
+ ...changedTargetNames.flatMap((name) => [`${name}.scrollTop`, `${name}.scrollLeft`]),
130
+ ];
131
+ }
132
+ return { state: 'available', source: 'derived', value, derivedFrom };
133
+ }
134
+ //# sourceMappingURL=scrollEvidence.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scrollEvidence.js","sourceRoot":"","sources":["../../src/domain/scrollEvidence.ts"],"names":[],"mappings":"AAeA;;;;;;GAMG;AACH,MAAM,UAAU,sBAAsB,CAAC,IAAoB,EAAE,QAAkB;IAC7E,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,cAAc,CAAC;IACnG,MAAM,kBAAkB,GAAG,IAAI,CAAC,KAAK,GAAG,CAAC,IAAI,IAAI,CAAC,CAAC,GAAG,QAAQ,CAAC,KAAK,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,IAAI,IAAI,CAAC,CAAC,GAAG,QAAQ,CAAC,MAAM,CAAC;IACpH,MAAM,mBAAmB,GAAG,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,KAAK,IAAI,QAAQ,CAAC,KAAK,IAAI,IAAI,CAAC,MAAM,IAAI,QAAQ,CAAC,MAAM,CAAC;IACzH,OAAO,EAAE,QAAQ,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,CAAC;AAC/D,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,sBAAsB,CAAC,OAA0B,EAAE,SAAiB,EAAE,SAAiB;IACrG,OAAO;QACL,kBAAkB,EAAE,OAAO,CAAC,WAAW,GAAG,OAAO,CAAC,WAAW;QAC7D,gBAAgB,EAAE,OAAO,CAAC,YAAY,GAAG,OAAO,CAAC,YAAY;QAC7D,SAAS;QACT,SAAS;KACV,CAAC;AACJ,CAAC;AAED,SAAS,YAAY,CAAC,MAAc,EAAE,KAAa;IACjD,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,KAAK,KAAK,EAAE,CAAC;AACtD,CAAC;AAED,SAAS,gBAAgB,CAAI,KAAuB;IAClD,OAAO,KAAK,CAAC,KAAK,KAAK,WAAW,IAAI,KAAK,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;AAC5F,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,4BAA4B,CAAC,OAAiC,EAAE,KAA+B;IAC7G,MAAM,cAAc,GAAG,gBAAgB,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IACzD,MAAM,YAAY,GAAG,gBAAgB,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IACrD,MAAM,WAAW,GAAG,gBAAgB,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;IAC3D,MAAM,SAAS,GAAG,gBAAgB,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;IACvD,MAAM,eAAe,GAAG,gBAAgB,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC;IACnE,MAAM,aAAa,GAAG,gBAAgB,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC;IAC/D,IAAI,CAAC,cAAc,IAAI,CAAC,YAAY,IAAI,CAAC,WAAW,IAAI,CAAC,SAAS,IAAI,CAAC,eAAe,IAAI,CAAC,aAAa,EAAE,CAAC;QACzG,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,MAAM,eAAe,GAAG,CAAC,eAAe,CAAC,kBAAkB,IAAI,aAAa,CAAC,kBAAkB,CAAC;IAChG,MAAM,YAAY,GAAG,eAAe,CAAC,kBAAkB,IAAI,CAAC,aAAa,CAAC,kBAAkB,CAAC;IAE7F,OAAO;QACL,SAAS,EAAE,YAAY,CAAC,cAAc,CAAC,SAAS,EAAE,YAAY,CAAC,SAAS,CAAC;QACzE,UAAU,EAAE,YAAY,CAAC,cAAc,CAAC,UAAU,EAAE,YAAY,CAAC,UAAU,CAAC;QAC5E,oBAAoB,EAAE;YACpB,MAAM,EAAE,EAAE,CAAC,EAAE,WAAW,CAAC,CAAC,EAAE,CAAC,EAAE,WAAW,CAAC,CAAC,EAAE;YAC9C,KAAK,EAAE,EAAE,CAAC,EAAE,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,SAAS,CAAC,CAAC,EAAE;YACzC,OAAO,EAAE,WAAW,CAAC,CAAC,KAAK,SAAS,CAAC,CAAC,IAAI,WAAW,CAAC,CAAC,KAAK,SAAS,CAAC,CAAC;SACxE;QACD,gBAAgB,EAAE,EAAE,MAAM,EAAE,eAAe,CAAC,QAAQ,EAAE,KAAK,EAAE,aAAa,CAAC,QAAQ,EAAE,OAAO,EAAE,eAAe,CAAC,QAAQ,KAAK,aAAa,CAAC,QAAQ,EAAE;QACnJ,eAAe;QACf,YAAY;KACb,CAAC;AACJ,CAAC;AAED,gVAAgV;AAChV,MAAM,UAAU,8BAA8B,CAAC,OAA8B,EAAE,KAA4B;IACzG,MAAM,OAAO,GAA2C,EAAE,CAAC;IAC3D,KAAK,MAAM,CAAC,IAAI,EAAE,YAAY,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;QACnE,MAAM,UAAU,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QACvC,IAAI,CAAC,UAAU;YAAE,SAAS;QAC1B,MAAM,UAAU,GAAG,4BAA4B,CAAC,YAAY,EAAE,UAAU,CAAC,CAAC;QAC1E,IAAI,UAAU;YAAE,OAAO,CAAC,IAAI,CAAC,GAAG,UAAU,CAAC;IAC7C,CAAC;IAED,OAAO;QACL,aAAa,EAAE,YAAY,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,EAAE,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC;QACzE,aAAa,EAAE,YAAY,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,EAAE,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC;QACzE,OAAO;KACR,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,UAAU,iBAAiB,CAAC,UAAoC;IACpE,MAAM,WAAW,GAAG,UAAU,CAAC,aAAa,CAAC,OAAO,IAAI,UAAU,CAAC,aAAa,CAAC,OAAO,CAAC;IACzF,MAAM,kBAAkB,GAAG,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC;SAC1D,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,OAAO,IAAI,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC;SAC9D,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC;IAEzB,IAAI,KAAgC,CAAC;IACrC,IAAI,WAAqB,CAAC;IAE1B,IAAI,CAAC,WAAW,IAAI,kBAAkB,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACpD,KAAK,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;QACzB,WAAW,GAAG,CAAC,gBAAgB,EAAE,gBAAgB,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,GAAG,IAAI,YAAY,EAAE,GAAG,IAAI,aAAa,CAAC,CAAC,CAAC,CAAC;IACxJ,CAAC;SAAM,IAAI,WAAW,IAAI,kBAAkB,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1D,KAAK,GAAG,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC;QAC7B,WAAW,GAAG,CAAC,gBAAgB,EAAE,gBAAgB,CAAC,CAAC;IACrD,CAAC;SAAM,IAAI,CAAC,WAAW,IAAI,kBAAkB,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC3D,MAAM,MAAM,GAAG,kBAAkB,CAAC,CAAC,CAAW,CAAC;QAC/C,KAAK,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC;QACnC,WAAW,GAAG,CAAC,GAAG,MAAM,YAAY,EAAE,GAAG,MAAM,aAAa,CAAC,CAAC;IAChE,CAAC;SAAM,CAAC;QACN,KAAK,GAAG,EAAE,IAAI,EAAE,eAAe,EAAE,CAAC;QAClC,WAAW,GAAG;YACZ,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,gBAAgB,EAAE,gBAAgB,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YAC5D,GAAG,kBAAkB,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,GAAG,IAAI,YAAY,EAAE,GAAG,IAAI,aAAa,CAAC,CAAC;SACrF,CAAC;IACJ,CAAC;IAED,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC;AACvE,CAAC"}
package/dist/index.d.ts CHANGED
@@ -4,11 +4,11 @@ export type { DiagnosticCode, DiagnosticSeverity, Diagnostic } from './domain/di
4
4
  export { DIAGNOSTIC_CODES, DIAGNOSTIC_SEVERITY, orderDiagnostics } from './domain/diagnostics.js';
5
5
  export type { CompletionState, RequestPhase } from './domain/completion.js';
6
6
  export { deriveCompletion } from './domain/completion.js';
7
- export type { ObservationArtifact, ArtifactReference, TargetEvidenceRecord, TargetGeometry, TargetComputedStyle, TargetLayoutMetrics, TargetVisibility, TargetSemantics, SchemaValidationResult, } from './domain/schema.js';
8
- export { ARTIFACT_KIND, SCHEMA_VERSION, PRODUCER_NAME, getProducerInfo, isValidObservationArtifact } from './domain/schema.js';
7
+ export type { ObservationArtifact, ArtifactReference, TargetEvidenceRecord, TargetGeometry, TargetComputedStyle, TargetLayoutMetrics, TargetVisibility, TargetSemantics, TargetLocatorKind, TargetSelectionStatus, TargetSelectionConfidence, TargetLocatorAttemptStatus, TargetLocatorAttempt, TargetResolution, TargetSemanticState, TargetLandmarkRole, TargetContainment, SchemaValidationResult, ScrollableMetrics, OverflowEvidence, WindowScrollSnapshot, DocumentScrollSnapshot, VerticalViewportRelation, ViewportRelationEvidence, TargetScrollRuntimeState, ScrollRuntimeSnapshot, ScrollValueChange, TargetScrollTransition, ScrollScenarioTransition, ScrollOwnerInterpretation, ScrollScenarioEvidence, } from './domain/schema.js';
8
+ export { ARTIFACT_KIND, SCHEMA_VERSION, PRODUCER_NAME, TARGET_LANDMARK_ROLES, getProducerInfo, isValidObservationArtifact, } from './domain/schema.js';
9
9
  export { buildRequestIdentity, buildObservationIdentity } from './domain/identity.js';
10
- export type { NamedTarget, Viewport, ReadinessCondition, ReadinessConfig, NormalizedObservationRequest, RawObservationRequest, NormalizeRequestResult, } from './request/request.js';
11
- export { normalizeRequest } from './request/request.js';
10
+ export type { NamedTarget, RawNamedTarget, TargetLocator, Viewport, ReadinessCondition, ReadinessConfig, NormalizedObservationRequest, RawObservationRequest, NormalizeRequestResult, ScrollAction, ScrollScenario, } from './request/request.js';
11
+ export { normalizeRequest, SCROLL_DELTA_MAX_ABS } from './request/request.js';
12
12
  export type { NormalizeOutputLocationResult } from './request/paths.js';
13
13
  export { normalizeOutputLocation } from './request/paths.js';
14
14
  export type { SafetyDecision } from './safety/policy.js';
package/dist/index.js CHANGED
@@ -1,9 +1,9 @@
1
1
  export { isValidEvidenceField } from './domain/evidence.js';
2
2
  export { DIAGNOSTIC_CODES, DIAGNOSTIC_SEVERITY, orderDiagnostics } from './domain/diagnostics.js';
3
3
  export { deriveCompletion } from './domain/completion.js';
4
- export { ARTIFACT_KIND, SCHEMA_VERSION, PRODUCER_NAME, getProducerInfo, isValidObservationArtifact } from './domain/schema.js';
4
+ export { ARTIFACT_KIND, SCHEMA_VERSION, PRODUCER_NAME, TARGET_LANDMARK_ROLES, getProducerInfo, isValidObservationArtifact, } from './domain/schema.js';
5
5
  export { buildRequestIdentity, buildObservationIdentity } from './domain/identity.js';
6
- export { normalizeRequest } from './request/request.js';
6
+ export { normalizeRequest, SCROLL_DELTA_MAX_ABS } from './request/request.js';
7
7
  export { normalizeOutputLocation } from './request/paths.js';
8
8
  export { classifyUrl, classifyRedirect, classifySubresource, classifyPopup, classifyDownload } from './safety/policy.js';
9
9
  export { runBrowserCapture } from './application/browserCaptureService.js';
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAG5D,OAAO,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAGlG,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAa1D,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,aAAa,EAAE,eAAe,EAAE,0BAA0B,EAAE,MAAM,oBAAoB,CAAC;AAE/H,OAAO,EAAE,oBAAoB,EAAE,wBAAwB,EAAE,MAAM,sBAAsB,CAAC;AAWtF,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAGxD,OAAO,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAC;AAG7D,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAGzH,OAAO,EAAE,iBAAiB,EAAE,MAAM,wCAAwC,CAAC;AAG3E,OAAO,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,+BAA+B,CAAC;AAEvF,OAAO,EAAE,wBAAwB,EAAE,qBAAqB,EAAE,OAAO,EAAE,MAAM,yCAAyC,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAG5D,OAAO,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAGlG,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAmC1D,OAAO,EACL,aAAa,EACb,cAAc,EACd,aAAa,EACb,qBAAqB,EACrB,eAAe,EACf,0BAA0B,GAC3B,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EAAE,oBAAoB,EAAE,wBAAwB,EAAE,MAAM,sBAAsB,CAAC;AAetF,OAAO,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAG9E,OAAO,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAC;AAG7D,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAGzH,OAAO,EAAE,iBAAiB,EAAE,MAAM,wCAAwC,CAAC;AAG3E,OAAO,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,+BAA+B,CAAC;AAEvF,OAAO,EAAE,wBAAwB,EAAE,qBAAqB,EAAE,OAAO,EAAE,MAAM,yCAAyC,CAAC"}
@@ -1,7 +1,34 @@
1
1
  import type { Diagnostic } from '../domain/diagnostics.js';
2
+ export type TargetLocator = {
3
+ kind: 'role';
4
+ role: string;
5
+ name?: string;
6
+ } | {
7
+ kind: 'id';
8
+ value: string;
9
+ } | {
10
+ kind: 'data-attribute';
11
+ attribute: string;
12
+ value: string;
13
+ } | {
14
+ kind: 'semantic-element';
15
+ tag: string;
16
+ } | {
17
+ kind: 'css';
18
+ selector: string;
19
+ } | {
20
+ kind: 'text';
21
+ text: string;
22
+ };
2
23
  export interface NamedTarget {
3
24
  name: string;
4
- selector: string;
25
+ locators: TargetLocator[];
26
+ }
27
+ /** Raw, not-yet-validated target shape as it may appear in a RawObservationRequest. Exactly one of `selector` (legacy) or `locators` (canonical) may be present, never both. */
28
+ export interface RawNamedTarget {
29
+ name?: unknown;
30
+ selector?: unknown;
31
+ locators?: unknown;
5
32
  }
6
33
  export interface Viewport {
7
34
  width: number;
@@ -12,6 +39,25 @@ export interface ReadinessConfig {
12
39
  condition: ReadinessCondition;
13
40
  timeoutMs: number;
14
41
  }
42
+ /**
43
+ * v0.3 Batch 1 canonical scroll-action shape. Exactly the two bounded action
44
+ * kinds below are supported; `target` on `target-scroll-by` refers to the
45
+ * existing stable observer-owned target `name` (see `NamedTarget`), never a
46
+ * CSS selector, Playwright locator, or DOM id evaluated directly.
47
+ */
48
+ export type ScrollAction = {
49
+ kind: 'window-scroll-by';
50
+ deltaX: number;
51
+ deltaY: number;
52
+ } | {
53
+ kind: 'target-scroll-by';
54
+ target: string;
55
+ deltaX: number;
56
+ deltaY: number;
57
+ };
58
+ export interface ScrollScenario {
59
+ action: ScrollAction;
60
+ }
15
61
  export interface NormalizedObservationRequest {
16
62
  targetUrl: string;
17
63
  viewport: Viewport;
@@ -19,6 +65,7 @@ export interface NormalizedObservationRequest {
19
65
  outputLocation: string;
20
66
  timeoutMs: number;
21
67
  readiness: ReadinessConfig;
68
+ scrollScenario?: ScrollScenario;
22
69
  }
23
70
  export interface RawObservationRequest {
24
71
  targetUrl?: unknown;
@@ -27,6 +74,7 @@ export interface RawObservationRequest {
27
74
  outputLocation?: unknown;
28
75
  timeoutMs?: unknown;
29
76
  readiness?: unknown;
77
+ scrollScenario?: unknown;
30
78
  }
31
79
  export type NormalizeRequestResult = {
32
80
  ok: true;
@@ -35,6 +83,14 @@ export type NormalizeRequestResult = {
35
83
  ok: false;
36
84
  diagnostics: Diagnostic[];
37
85
  };
86
+ /**
87
+ * Conservative bound for a single controlled-observation scroll action. No
88
+ * existing repository precedent for a scroll-delta magnitude; chosen large
89
+ * enough to reach realistic overflow content (documents/containers well
90
+ * beyond one viewport) while staying far short of a pathological/runaway
91
+ * request - see docs/CONTRACTS.md and tests/unit/request.test.ts.
92
+ */
93
+ export declare const SCROLL_DELTA_MAX_ABS = 20000;
38
94
  /**
39
95
  * Total, never throws. Collects every applicable diagnostic before returning
40
96
  * (does not short-circuit on the first violation) so callers see every