my-frontend-observer 0.1.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.
- package/CHANGELOG.md +22 -0
- package/README.md +69 -0
- package/dist/application/browserCaptureService.d.ts +11 -0
- package/dist/application/browserCaptureService.js +12 -0
- package/dist/application/browserCaptureService.js.map +1 -0
- package/dist/application/observationPersistence.d.ts +59 -0
- package/dist/application/observationPersistence.js +78 -0
- package/dist/application/observationPersistence.js.map +1 -0
- package/dist/artifacts/artifactWriter.d.ts +25 -0
- package/dist/artifacts/artifactWriter.js +68 -0
- package/dist/artifacts/artifactWriter.js.map +1 -0
- package/dist/artifacts/types.d.ts +17 -0
- package/dist/artifacts/types.js +2 -0
- package/dist/artifacts/types.js.map +1 -0
- package/dist/browser/chromiumAdapter.d.ts +21 -0
- package/dist/browser/chromiumAdapter.js +150 -0
- package/dist/browser/chromiumAdapter.js.map +1 -0
- package/dist/browser/evidenceCapture.d.ts +19 -0
- package/dist/browser/evidenceCapture.js +201 -0
- package/dist/browser/evidenceCapture.js.map +1 -0
- package/dist/browser/types.d.ts +22 -0
- package/dist/browser/types.js +2 -0
- package/dist/browser/types.js.map +1 -0
- package/dist/cli.d.ts +7 -0
- package/dist/cli.js +216 -0
- package/dist/cli.js.map +1 -0
- package/dist/domain/completion.d.ts +30 -0
- package/dist/domain/completion.js +22 -0
- package/dist/domain/completion.js.map +1 -0
- package/dist/domain/diagnostics.d.ts +17 -0
- package/dist/domain/diagnostics.js +55 -0
- package/dist/domain/diagnostics.js.map +1 -0
- package/dist/domain/evidence.d.ts +27 -0
- package/dist/domain/evidence.js +55 -0
- package/dist/domain/evidence.js.map +1 -0
- package/dist/domain/identity.d.ts +13 -0
- package/dist/domain/identity.js +37 -0
- package/dist/domain/identity.js.map +1 -0
- package/dist/domain/schema.d.ts +111 -0
- package/dist/domain/schema.js +126 -0
- package/dist/domain/schema.js.map +1 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -0
- package/dist/request/paths.d.ts +14 -0
- package/dist/request/paths.js +33 -0
- package/dist/request/paths.js.map +1 -0
- package/dist/request/request.d.ts +43 -0
- package/dist/request/request.js +174 -0
- package/dist/request/request.js.map +1 -0
- package/dist/safety/policy.d.ts +14 -0
- package/dist/safety/policy.js +81 -0
- package/dist/safety/policy.js.map +1 -0
- package/docs/ARCHITECTURE.md +85 -0
- package/docs/CI_CD.md +28 -0
- package/docs/COMMANDS.md +82 -0
- package/docs/CONTRACTS.md +54 -0
- package/docs/CURRENT_STATE.md +113 -0
- package/docs/DEVELOPMENT.md +65 -0
- package/docs/DOCUMENTATION_PRESERVATION_POLICY.md +33 -0
- package/docs/PROJECT_DESCRIPTION.md +1770 -0
- package/docs/PROJECT_MILESTONES.md +2073 -0
- package/docs/PROJECT_OVERVIEW.md +53 -0
- package/docs/QUICKSTART.md +35 -0
- package/docs/RELEASE.md +9 -0
- package/docs/ROADMAP.md +352 -0
- package/docs/SECURITY.md +33 -0
- package/docs/WORKFLOWS.md +51 -0
- package/package.json +46 -0
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import { DIAGNOSTIC_SEVERITY } from '../domain/diagnostics.js';
|
|
2
|
+
function diagnostic(code, message, targetName) {
|
|
3
|
+
const base = { code, severity: DIAGNOSTIC_SEVERITY[code], message };
|
|
4
|
+
return targetName === undefined ? base : { ...base, targetName };
|
|
5
|
+
}
|
|
6
|
+
function browserField(value) {
|
|
7
|
+
return { state: 'available', source: 'browser', value };
|
|
8
|
+
}
|
|
9
|
+
function derivedField(value, derivedFrom) {
|
|
10
|
+
return { state: 'available', source: 'derived', value, derivedFrom };
|
|
11
|
+
}
|
|
12
|
+
function computedField(value) {
|
|
13
|
+
return { state: 'available', source: 'computed-browser', value };
|
|
14
|
+
}
|
|
15
|
+
function unavailableField(reason) {
|
|
16
|
+
return { state: 'unavailable', reason };
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Captures the v0.1 minimum page evidence (docs/PROJECT_MILESTONES.md
|
|
20
|
+
* "Minimum page evidence") from the already-navigated, already-ready page.
|
|
21
|
+
* `documentWidth`/`documentHeight` are the one explicitly *derived* pair -
|
|
22
|
+
* max(scroll, client) in each axis - everything else is a direct browser
|
|
23
|
+
* read, per the Batch 1 evidence-source model.
|
|
24
|
+
*/
|
|
25
|
+
export async function capturePageEvidence(page, requestedUrl, viewport) {
|
|
26
|
+
const raw = await page.evaluate(() => ({
|
|
27
|
+
title: document.title,
|
|
28
|
+
windowScrollX: window.scrollX,
|
|
29
|
+
windowScrollY: window.scrollY,
|
|
30
|
+
documentScrollWidth: document.documentElement.scrollWidth,
|
|
31
|
+
documentScrollHeight: document.documentElement.scrollHeight,
|
|
32
|
+
documentClientWidth: document.documentElement.clientWidth,
|
|
33
|
+
documentClientHeight: document.documentElement.clientHeight,
|
|
34
|
+
}));
|
|
35
|
+
const documentWidth = Math.max(raw.documentScrollWidth, raw.documentClientWidth);
|
|
36
|
+
const documentHeight = Math.max(raw.documentScrollHeight, raw.documentClientHeight);
|
|
37
|
+
return {
|
|
38
|
+
requestedUrl: browserField(requestedUrl),
|
|
39
|
+
finalUrl: browserField(page.url()),
|
|
40
|
+
title: browserField(raw.title),
|
|
41
|
+
viewportWidth: browserField(viewport.width),
|
|
42
|
+
viewportHeight: browserField(viewport.height),
|
|
43
|
+
devicePixelRatio: browserField(await page.evaluate(() => window.devicePixelRatio)),
|
|
44
|
+
documentScrollWidth: browserField(raw.documentScrollWidth),
|
|
45
|
+
documentScrollHeight: browserField(raw.documentScrollHeight),
|
|
46
|
+
documentClientWidth: browserField(raw.documentClientWidth),
|
|
47
|
+
documentClientHeight: browserField(raw.documentClientHeight),
|
|
48
|
+
documentWidth: derivedField(documentWidth, ['documentScrollWidth', 'documentClientWidth']),
|
|
49
|
+
documentHeight: derivedField(documentHeight, ['documentScrollHeight', 'documentClientHeight']),
|
|
50
|
+
windowScrollX: browserField(raw.windowScrollX),
|
|
51
|
+
windowScrollY: browserField(raw.windowScrollY),
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Extracts only the target element's own role/name from a Playwright
|
|
56
|
+
* `ariaSnapshot()` string (e.g. `- button "Click me"`), never its
|
|
57
|
+
* descendants - bounded, target-local semantic evidence, not an
|
|
58
|
+
* accessibility-tree dump. A generic `- text: ...` line (no distinct ARIA
|
|
59
|
+
* role) or an empty snapshot both mean "no reliable role/name", not a role
|
|
60
|
+
* of "text".
|
|
61
|
+
*/
|
|
62
|
+
function parseAriaSnapshotFirstLine(snapshot) {
|
|
63
|
+
const firstLine = snapshot.split('\n')[0]?.trim();
|
|
64
|
+
if (!firstLine)
|
|
65
|
+
return undefined;
|
|
66
|
+
const match = /^-\s+([A-Za-z][\w-]*)\s*(?:"([^"]*)")?:?$/.exec(firstLine);
|
|
67
|
+
if (!match)
|
|
68
|
+
return undefined;
|
|
69
|
+
const role = match[1];
|
|
70
|
+
const name = match[2];
|
|
71
|
+
if (role === undefined || role === 'text')
|
|
72
|
+
return undefined;
|
|
73
|
+
return name !== undefined && name.length > 0 ? { role, name } : { role };
|
|
74
|
+
}
|
|
75
|
+
function missingTargetRecord() {
|
|
76
|
+
const reason = 'target selector matched no element';
|
|
77
|
+
return {
|
|
78
|
+
resolution: { state: 'available', source: 'derived', value: { selectionMethod: 'css-selector', selectionStatus: 'not-found' }, derivedFrom: ['selector-query'] },
|
|
79
|
+
tag: unavailableField(reason),
|
|
80
|
+
geometry: unavailableField(reason),
|
|
81
|
+
style: unavailableField(reason),
|
|
82
|
+
layout: unavailableField(reason),
|
|
83
|
+
visibility: unavailableField(reason),
|
|
84
|
+
semantics: unavailableField(reason),
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
function ambiguousTargetRecord(matchCount) {
|
|
88
|
+
const reason = `target selector matched ${matchCount} elements; expected exactly one`;
|
|
89
|
+
return {
|
|
90
|
+
resolution: { state: 'available', source: 'derived', value: { selectionMethod: 'css-selector', selectionStatus: 'ambiguous' }, derivedFrom: ['selector-query'] },
|
|
91
|
+
tag: unavailableField(reason),
|
|
92
|
+
geometry: unavailableField(reason),
|
|
93
|
+
style: unavailableField(reason),
|
|
94
|
+
layout: unavailableField(reason),
|
|
95
|
+
visibility: unavailableField(reason),
|
|
96
|
+
semantics: unavailableField(reason),
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Captures the v0.1 minimum target evidence for one resolved (single-match)
|
|
101
|
+
* target element, from the same live page/readiness state as the page
|
|
102
|
+
* evidence and screenshot. Role/name come from Playwright's real
|
|
103
|
+
* accessibility tree (`page.accessibility.snapshot`), not a hand-rolled
|
|
104
|
+
* approximation; when the browser cannot supply them reliably for this
|
|
105
|
+
* element, they are reported `unavailable` rather than guessed.
|
|
106
|
+
*/
|
|
107
|
+
async function captureResolvedTargetRecord(page, selector) {
|
|
108
|
+
const handle = await page.$(selector);
|
|
109
|
+
if (!handle)
|
|
110
|
+
return missingTargetRecord();
|
|
111
|
+
try {
|
|
112
|
+
const raw = await handle.evaluate((el) => {
|
|
113
|
+
const rect = el.getBoundingClientRect();
|
|
114
|
+
const computed = getComputedStyle(el);
|
|
115
|
+
return {
|
|
116
|
+
tag: el.tagName.toLowerCase(),
|
|
117
|
+
geometry: { x: rect.x, y: rect.y, width: rect.width, height: rect.height, right: rect.right, bottom: rect.bottom },
|
|
118
|
+
style: { display: computed.display, position: computed.position, overflowX: computed.overflowX, overflowY: computed.overflowY },
|
|
119
|
+
layout: {
|
|
120
|
+
scrollWidth: el.scrollWidth,
|
|
121
|
+
scrollHeight: el.scrollHeight,
|
|
122
|
+
clientWidth: el.clientWidth,
|
|
123
|
+
clientHeight: el.clientHeight,
|
|
124
|
+
scrollTop: el.scrollTop,
|
|
125
|
+
scrollLeft: el.scrollLeft,
|
|
126
|
+
},
|
|
127
|
+
computedVisibility: computed.visibility,
|
|
128
|
+
};
|
|
129
|
+
});
|
|
130
|
+
const visible = raw.style.display !== 'none' && raw.computedVisibility !== 'hidden' && raw.geometry.width > 0 && raw.geometry.height > 0;
|
|
131
|
+
let semantics;
|
|
132
|
+
try {
|
|
133
|
+
const snapshot = await page.locator(selector).ariaSnapshot();
|
|
134
|
+
const parsed = parseAriaSnapshotFirstLine(snapshot);
|
|
135
|
+
semantics = parsed ? computedField(parsed) : unavailableField('no distinct accessible role/name is exposed for this target');
|
|
136
|
+
}
|
|
137
|
+
catch (err) {
|
|
138
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
139
|
+
semantics = unavailableField(`accessibility snapshot failed: ${message}`);
|
|
140
|
+
}
|
|
141
|
+
return {
|
|
142
|
+
resolution: {
|
|
143
|
+
state: 'available',
|
|
144
|
+
source: 'derived',
|
|
145
|
+
value: { selectionMethod: 'css-selector', selectionStatus: 'matched' },
|
|
146
|
+
derivedFrom: ['selector-query'],
|
|
147
|
+
},
|
|
148
|
+
tag: browserField(raw.tag),
|
|
149
|
+
geometry: browserField(raw.geometry),
|
|
150
|
+
style: computedField(raw.style),
|
|
151
|
+
layout: browserField(raw.layout),
|
|
152
|
+
visibility: derivedField({ visible }, ['style.display', 'computed-visibility', 'geometry.width', 'geometry.height']),
|
|
153
|
+
semantics,
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
finally {
|
|
157
|
+
await handle.dispose();
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
/** Observes every explicitly configured Batch 1 target from the same live page, honoring the 0/1/many cardinality contract. */
|
|
161
|
+
export async function captureTargetEvidence(page, targets) {
|
|
162
|
+
const targetEvidence = {};
|
|
163
|
+
const diagnostics = [];
|
|
164
|
+
for (const target of targets) {
|
|
165
|
+
const matchCount = await page.evaluate((selector) => document.querySelectorAll(selector).length, target.selector);
|
|
166
|
+
if (matchCount === 0) {
|
|
167
|
+
targetEvidence[target.name] = missingTargetRecord();
|
|
168
|
+
diagnostics.push(diagnostic('target-missing', `no element matched selector for target "${target.name}"`, target.name));
|
|
169
|
+
continue;
|
|
170
|
+
}
|
|
171
|
+
if (matchCount > 1) {
|
|
172
|
+
targetEvidence[target.name] = ambiguousTargetRecord(matchCount);
|
|
173
|
+
diagnostics.push(diagnostic('target-ambiguous', `${matchCount} elements matched selector for target "${target.name}"`, target.name));
|
|
174
|
+
continue;
|
|
175
|
+
}
|
|
176
|
+
try {
|
|
177
|
+
targetEvidence[target.name] = await captureResolvedTargetRecord(page, target.selector);
|
|
178
|
+
}
|
|
179
|
+
catch (err) {
|
|
180
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
181
|
+
const reason = `target evaluation failed: ${message}`;
|
|
182
|
+
targetEvidence[target.name] = {
|
|
183
|
+
resolution: {
|
|
184
|
+
state: 'available',
|
|
185
|
+
source: 'derived',
|
|
186
|
+
value: { selectionMethod: 'css-selector', selectionStatus: 'matched' },
|
|
187
|
+
derivedFrom: ['selector-query'],
|
|
188
|
+
},
|
|
189
|
+
tag: unavailableField(reason),
|
|
190
|
+
geometry: unavailableField(reason),
|
|
191
|
+
style: unavailableField(reason),
|
|
192
|
+
layout: unavailableField(reason),
|
|
193
|
+
visibility: unavailableField(reason),
|
|
194
|
+
semantics: unavailableField(reason),
|
|
195
|
+
};
|
|
196
|
+
diagnostics.push(diagnostic('browser-evidence-unavailable', reason, target.name));
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
return { targetEvidence, diagnostics };
|
|
200
|
+
}
|
|
201
|
+
//# sourceMappingURL=evidenceCapture.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"evidenceCapture.js","sourceRoot":"","sources":["../../src/browser/evidenceCapture.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAI/D,SAAS,UAAU,CAAC,IAAoB,EAAE,OAAe,EAAE,UAAmB;IAC5E,MAAM,IAAI,GAAe,EAAE,IAAI,EAAE,QAAQ,EAAE,mBAAmB,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,CAAC;IAChF,OAAO,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,GAAG,IAAI,EAAE,UAAU,EAAE,CAAC;AACnE,CAAC;AAED,SAAS,YAAY,CAAI,KAAQ;IAC/B,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;AAC1D,CAAC;AAED,SAAS,YAAY,CAAI,KAAQ,EAAE,WAAqB;IACtD,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC;AACvE,CAAC;AAED,SAAS,aAAa,CAAI,KAAQ;IAChC,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,EAAE,kBAAkB,EAAE,KAAK,EAAE,CAAC;AACnE,CAAC;AAED,SAAS,gBAAgB,CAAI,MAAc;IACzC,OAAO,EAAE,KAAK,EAAE,aAAa,EAAE,MAAM,EAAE,CAAC;AAC1C,CAAC;AAYD;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,IAAU,EACV,YAAoB,EACpB,QAAkB;IAElB,MAAM,GAAG,GAAuB,MAAM,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,CAAC,CAAC;QACzD,KAAK,EAAE,QAAQ,CAAC,KAAK;QACrB,aAAa,EAAE,MAAM,CAAC,OAAO;QAC7B,aAAa,EAAE,MAAM,CAAC,OAAO;QAC7B,mBAAmB,EAAE,QAAQ,CAAC,eAAe,CAAC,WAAW;QACzD,oBAAoB,EAAE,QAAQ,CAAC,eAAe,CAAC,YAAY;QAC3D,mBAAmB,EAAE,QAAQ,CAAC,eAAe,CAAC,WAAW;QACzD,oBAAoB,EAAE,QAAQ,CAAC,eAAe,CAAC,YAAY;KAC5D,CAAC,CAAC,CAAC;IAEJ,MAAM,aAAa,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,mBAAmB,EAAE,GAAG,CAAC,mBAAmB,CAAC,CAAC;IACjF,MAAM,cAAc,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,oBAAoB,EAAE,GAAG,CAAC,oBAAoB,CAAC,CAAC;IAEpF,OAAO;QACL,YAAY,EAAE,YAAY,CAAC,YAAY,CAAC;QACxC,QAAQ,EAAE,YAAY,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC;QAClC,KAAK,EAAE,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC;QAC9B,aAAa,EAAE,YAAY,CAAC,QAAQ,CAAC,KAAK,CAAC;QAC3C,cAAc,EAAE,YAAY,CAAC,QAAQ,CAAC,MAAM,CAAC;QAC7C,gBAAgB,EAAE,YAAY,CAAC,MAAM,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC;QAClF,mBAAmB,EAAE,YAAY,CAAC,GAAG,CAAC,mBAAmB,CAAC;QAC1D,oBAAoB,EAAE,YAAY,CAAC,GAAG,CAAC,oBAAoB,CAAC;QAC5D,mBAAmB,EAAE,YAAY,CAAC,GAAG,CAAC,mBAAmB,CAAC;QAC1D,oBAAoB,EAAE,YAAY,CAAC,GAAG,CAAC,oBAAoB,CAAC;QAC5D,aAAa,EAAE,YAAY,CAAC,aAAa,EAAE,CAAC,qBAAqB,EAAE,qBAAqB,CAAC,CAAC;QAC1F,cAAc,EAAE,YAAY,CAAC,cAAc,EAAE,CAAC,sBAAsB,EAAE,sBAAsB,CAAC,CAAC;QAC9F,aAAa,EAAE,YAAY,CAAC,GAAG,CAAC,aAAa,CAAC;QAC9C,aAAa,EAAE,YAAY,CAAC,GAAG,CAAC,aAAa,CAAC;KAC/C,CAAC;AACJ,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,0BAA0B,CAAC,QAAgB;IAClD,MAAM,SAAS,GAAG,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC;IAClD,IAAI,CAAC,SAAS;QAAE,OAAO,SAAS,CAAC;IACjC,MAAM,KAAK,GAAG,2CAA2C,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAC1E,IAAI,CAAC,KAAK;QAAE,OAAO,SAAS,CAAC;IAC7B,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;IACtB,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;IACtB,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,KAAK,MAAM;QAAE,OAAO,SAAS,CAAC;IAC5D,OAAO,IAAI,KAAK,SAAS,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC;AAC3E,CAAC;AAUD,SAAS,mBAAmB;IAC1B,MAAM,MAAM,GAAG,oCAAoC,CAAC;IACpD,OAAO;QACL,UAAU,EAAE,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,EAAE,eAAe,EAAE,cAAc,EAAE,eAAe,EAAE,WAAW,EAAE,EAAE,WAAW,EAAE,CAAC,gBAAgB,CAAC,EAAE;QAChK,GAAG,EAAE,gBAAgB,CAAC,MAAM,CAAC;QAC7B,QAAQ,EAAE,gBAAgB,CAAC,MAAM,CAAC;QAClC,KAAK,EAAE,gBAAgB,CAAC,MAAM,CAAC;QAC/B,MAAM,EAAE,gBAAgB,CAAC,MAAM,CAAC;QAChC,UAAU,EAAE,gBAAgB,CAAC,MAAM,CAAC;QACpC,SAAS,EAAE,gBAAgB,CAAC,MAAM,CAAC;KACpC,CAAC;AACJ,CAAC;AAED,SAAS,qBAAqB,CAAC,UAAkB;IAC/C,MAAM,MAAM,GAAG,2BAA2B,UAAU,iCAAiC,CAAC;IACtF,OAAO;QACL,UAAU,EAAE,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,EAAE,eAAe,EAAE,cAAc,EAAE,eAAe,EAAE,WAAW,EAAE,EAAE,WAAW,EAAE,CAAC,gBAAgB,CAAC,EAAE;QAChK,GAAG,EAAE,gBAAgB,CAAC,MAAM,CAAC;QAC7B,QAAQ,EAAE,gBAAgB,CAAC,MAAM,CAAC;QAClC,KAAK,EAAE,gBAAgB,CAAC,MAAM,CAAC;QAC/B,MAAM,EAAE,gBAAgB,CAAC,MAAM,CAAC;QAChC,UAAU,EAAE,gBAAgB,CAAC,MAAM,CAAC;QACpC,SAAS,EAAE,gBAAgB,CAAC,MAAM,CAAC;KACpC,CAAC;AACJ,CAAC;AAED;;;;;;;GAOG;AACH,KAAK,UAAU,2BAA2B,CAAC,IAAU,EAAE,QAAgB;IACrE,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;IACtC,IAAI,CAAC,MAAM;QAAE,OAAO,mBAAmB,EAAE,CAAC;IAE1C,IAAI,CAAC;QACH,MAAM,GAAG,GAAyB,MAAM,MAAM,CAAC,QAAQ,CAAC,CAAC,EAAE,EAAE,EAAE;YAC7D,MAAM,IAAI,GAAG,EAAE,CAAC,qBAAqB,EAAE,CAAC;YACxC,MAAM,QAAQ,GAAG,gBAAgB,CAAC,EAAE,CAAC,CAAC;YACtC,OAAO;gBACL,GAAG,EAAE,EAAE,CAAC,OAAO,CAAC,WAAW,EAAE;gBAC7B,QAAQ,EAAE,EAAE,CAAC,EAAE,IAAI,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE;gBAClH,KAAK,EAAE,EAAE,OAAO,EAAE,QAAQ,CAAC,OAAO,EAAE,QAAQ,EAAE,QAAQ,CAAC,QAAQ,EAAE,SAAS,EAAE,QAAQ,CAAC,SAAS,EAAE,SAAS,EAAE,QAAQ,CAAC,SAAS,EAAE;gBAC/H,MAAM,EAAE;oBACN,WAAW,EAAE,EAAE,CAAC,WAAW;oBAC3B,YAAY,EAAE,EAAE,CAAC,YAAY;oBAC7B,WAAW,EAAE,EAAE,CAAC,WAAW;oBAC3B,YAAY,EAAE,EAAE,CAAC,YAAY;oBAC7B,SAAS,EAAE,EAAE,CAAC,SAAS;oBACvB,UAAU,EAAE,EAAE,CAAC,UAAU;iBAC1B;gBACD,kBAAkB,EAAE,QAAQ,CAAC,UAAU;aACxC,CAAC;QACJ,CAAC,CAAC,CAAC;QAEH,MAAM,OAAO,GAAG,GAAG,CAAC,KAAK,CAAC,OAAO,KAAK,MAAM,IAAI,GAAG,CAAC,kBAAkB,KAAK,QAAQ,IAAI,GAAG,CAAC,QAAQ,CAAC,KAAK,GAAG,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC;QAEzI,IAAI,SAA0D,CAAC;QAC/D,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,YAAY,EAAE,CAAC;YAC7D,MAAM,MAAM,GAAG,0BAA0B,CAAC,QAAQ,CAAC,CAAC;YACpD,SAAS,GAAG,MAAM,CAAC,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,gBAAgB,CAAC,6DAA6D,CAAC,CAAC;QAC/H,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACjE,SAAS,GAAG,gBAAgB,CAAC,kCAAkC,OAAO,EAAE,CAAC,CAAC;QAC5E,CAAC;QAED,OAAO;YACL,UAAU,EAAE;gBACV,KAAK,EAAE,WAAW;gBAClB,MAAM,EAAE,SAAS;gBACjB,KAAK,EAAE,EAAE,eAAe,EAAE,cAAc,EAAE,eAAe,EAAE,SAAS,EAAE;gBACtE,WAAW,EAAE,CAAC,gBAAgB,CAAC;aAChC;YACD,GAAG,EAAE,YAAY,CAAC,GAAG,CAAC,GAAG,CAAC;YAC1B,QAAQ,EAAE,YAAY,CAAC,GAAG,CAAC,QAAQ,CAAC;YACpC,KAAK,EAAE,aAAa,CAAC,GAAG,CAAC,KAAK,CAAC;YAC/B,MAAM,EAAE,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC;YAChC,UAAU,EAAE,YAAY,CAAC,EAAE,OAAO,EAAE,EAAE,CAAC,eAAe,EAAE,qBAAqB,EAAE,gBAAgB,EAAE,iBAAiB,CAAC,CAAC;YACpH,SAAS;SACV,CAAC;IACJ,CAAC;YAAS,CAAC;QACT,MAAM,MAAM,CAAC,OAAO,EAAE,CAAC;IACzB,CAAC;AACH,CAAC;AAOD,+HAA+H;AAC/H,MAAM,CAAC,KAAK,UAAU,qBAAqB,CAAC,IAAU,EAAE,OAA+B;IACrF,MAAM,cAAc,GAAyC,EAAE,CAAC;IAChE,MAAM,WAAW,GAAiB,EAAE,CAAC;IAErC,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,gBAAgB,CAAC,QAAQ,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC;QAElH,IAAI,UAAU,KAAK,CAAC,EAAE,CAAC;YACrB,cAAc,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,mBAAmB,EAAE,CAAC;YACpD,WAAW,CAAC,IAAI,CAAC,UAAU,CAAC,gBAAgB,EAAE,2CAA2C,MAAM,CAAC,IAAI,GAAG,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;YACvH,SAAS;QACX,CAAC;QAED,IAAI,UAAU,GAAG,CAAC,EAAE,CAAC;YACnB,cAAc,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,qBAAqB,CAAC,UAAU,CAAC,CAAC;YAChE,WAAW,CAAC,IAAI,CAAC,UAAU,CAAC,kBAAkB,EAAE,GAAG,UAAU,0CAA0C,MAAM,CAAC,IAAI,GAAG,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;YACrI,SAAS;QACX,CAAC;QAED,IAAI,CAAC;YACH,cAAc,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,MAAM,2BAA2B,CAAC,IAAI,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC;QACzF,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACjE,MAAM,MAAM,GAAG,6BAA6B,OAAO,EAAE,CAAC;YACtD,cAAc,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG;gBAC5B,UAAU,EAAE;oBACV,KAAK,EAAE,WAAW;oBAClB,MAAM,EAAE,SAAS;oBACjB,KAAK,EAAE,EAAE,eAAe,EAAE,cAAc,EAAE,eAAe,EAAE,SAAS,EAAE;oBACtE,WAAW,EAAE,CAAC,gBAAgB,CAAC;iBAChC;gBACD,GAAG,EAAE,gBAAgB,CAAC,MAAM,CAAC;gBAC7B,QAAQ,EAAE,gBAAgB,CAAC,MAAM,CAAC;gBAClC,KAAK,EAAE,gBAAgB,CAAC,MAAM,CAAC;gBAC/B,MAAM,EAAE,gBAAgB,CAAC,MAAM,CAAC;gBAChC,UAAU,EAAE,gBAAgB,CAAC,MAAM,CAAC;gBACpC,SAAS,EAAE,gBAAgB,CAAC,MAAM,CAAC;aACpC,CAAC;YACF,WAAW,CAAC,IAAI,CAAC,UAAU,CAAC,8BAA8B,EAAE,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;QACpF,CAAC;IACH,CAAC;IAED,OAAO,EAAE,cAAc,EAAE,WAAW,EAAE,CAAC;AACzC,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { Diagnostic } from '../domain/diagnostics.js';
|
|
2
|
+
import type { EvidenceField } from '../domain/evidence.js';
|
|
3
|
+
import type { TargetEvidenceRecord } from '../domain/schema.js';
|
|
4
|
+
export interface BrowserProvenance {
|
|
5
|
+
engine: string;
|
|
6
|
+
version: string;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Observer-owned result of the browser boundary. Contains no Playwright
|
|
10
|
+
* object anywhere in its shape - only plain, serializable data.
|
|
11
|
+
*/
|
|
12
|
+
export type BrowserCaptureResult = {
|
|
13
|
+
ok: true;
|
|
14
|
+
provenance: BrowserProvenance;
|
|
15
|
+
screenshot: Uint8Array;
|
|
16
|
+
pageEvidence: Record<string, EvidenceField<unknown>>;
|
|
17
|
+
targetEvidence: Record<string, TargetEvidenceRecord>;
|
|
18
|
+
diagnostics: Diagnostic[];
|
|
19
|
+
} | {
|
|
20
|
+
ok: false;
|
|
21
|
+
diagnostics: Diagnostic[];
|
|
22
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/browser/types.ts"],"names":[],"mappings":""}
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
export interface CliIO {
|
|
3
|
+
stdout: (text: string) => void;
|
|
4
|
+
stderr: (text: string) => void;
|
|
5
|
+
}
|
|
6
|
+
/** Testable CLI entry point: pure function of argv (+ injectable IO), no direct process.exit. */
|
|
7
|
+
export declare function runCli(argv: readonly string[], io?: CliIO): Promise<number>;
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { realpathSync } from 'node:fs';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
import { normalizeRequest } from './request/request.js';
|
|
5
|
+
import { getProducerInfo } from './domain/schema.js';
|
|
6
|
+
import { observe } from './application/observationPersistence.js';
|
|
7
|
+
const defaultIO = {
|
|
8
|
+
stdout: (text) => {
|
|
9
|
+
process.stdout.write(text);
|
|
10
|
+
},
|
|
11
|
+
stderr: (text) => {
|
|
12
|
+
process.stderr.write(text);
|
|
13
|
+
},
|
|
14
|
+
};
|
|
15
|
+
const TOP_LEVEL_HELP = `my-frontend-observer - local-first browser runtime evidence producer
|
|
16
|
+
|
|
17
|
+
Usage:
|
|
18
|
+
my-frontend-observer <command> [options]
|
|
19
|
+
|
|
20
|
+
Commands:
|
|
21
|
+
observe Capture one bounded browser observation and persist it as a
|
|
22
|
+
portable artifact.
|
|
23
|
+
|
|
24
|
+
Options:
|
|
25
|
+
--help Show this help.
|
|
26
|
+
--version Print the package version.
|
|
27
|
+
|
|
28
|
+
Run "my-frontend-observer observe --help" for observe command options.
|
|
29
|
+
`;
|
|
30
|
+
const OBSERVE_HELP = `Usage:
|
|
31
|
+
my-frontend-observer observe --url <loopback-url> [options]
|
|
32
|
+
|
|
33
|
+
Required:
|
|
34
|
+
--url <url> Loopback target URL (http/https, localhost/127.x.x.x/::1 only).
|
|
35
|
+
|
|
36
|
+
Options:
|
|
37
|
+
--viewport <WIDTHxHEIGHT> Viewport size, e.g. 1280x720.
|
|
38
|
+
--target <id=selector> An explicit observation target. Repeatable.
|
|
39
|
+
Parsed on the first "=" only, so selectors
|
|
40
|
+
containing "=" (e.g. button[data-state="active"])
|
|
41
|
+
are preserved intact.
|
|
42
|
+
--output <directory> Portable, relative output location for the
|
|
43
|
+
observation artifact.
|
|
44
|
+
--timeout <ms> Overall request timeout in milliseconds.
|
|
45
|
+
--help Show this help.
|
|
46
|
+
|
|
47
|
+
On success, prints a concise result and exits 0. On invalid syntax, invalid
|
|
48
|
+
request, unsafe/failed navigation, or a failed artifact write, prints
|
|
49
|
+
structured diagnostics to stderr and exits nonzero. No progress output is
|
|
50
|
+
printed during a normal capture.
|
|
51
|
+
`;
|
|
52
|
+
function parseViewport(raw) {
|
|
53
|
+
const match = /^(\d+)x(\d+)$/.exec(raw);
|
|
54
|
+
if (!match)
|
|
55
|
+
return undefined;
|
|
56
|
+
const width = Number(match[1]);
|
|
57
|
+
const height = Number(match[2]);
|
|
58
|
+
return { width, height };
|
|
59
|
+
}
|
|
60
|
+
function parseTarget(raw) {
|
|
61
|
+
const eq = raw.indexOf('=');
|
|
62
|
+
if (eq <= 0 || eq === raw.length - 1)
|
|
63
|
+
return undefined;
|
|
64
|
+
return { name: raw.slice(0, eq), selector: raw.slice(eq + 1) };
|
|
65
|
+
}
|
|
66
|
+
/** CLI-syntax-only parsing: shape/format errors only. Domain bounds and policy are Batch 1's job, not this function's. */
|
|
67
|
+
function parseObserveArgs(argv) {
|
|
68
|
+
const errors = [];
|
|
69
|
+
let targetUrl;
|
|
70
|
+
let viewport;
|
|
71
|
+
const targets = [];
|
|
72
|
+
let outputLocation;
|
|
73
|
+
let timeoutMs;
|
|
74
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
75
|
+
const arg = argv[i];
|
|
76
|
+
switch (arg) {
|
|
77
|
+
case '--url':
|
|
78
|
+
targetUrl = argv[(i += 1)];
|
|
79
|
+
break;
|
|
80
|
+
case '--viewport': {
|
|
81
|
+
const value = argv[(i += 1)];
|
|
82
|
+
const parsed = value === undefined ? undefined : parseViewport(value);
|
|
83
|
+
if (parsed === undefined) {
|
|
84
|
+
errors.push(`--viewport must be WIDTHxHEIGHT (e.g. 1280x720); got ${JSON.stringify(value)}`);
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
viewport = parsed;
|
|
88
|
+
}
|
|
89
|
+
break;
|
|
90
|
+
}
|
|
91
|
+
case '--target': {
|
|
92
|
+
const value = argv[(i += 1)];
|
|
93
|
+
const parsed = value === undefined ? undefined : parseTarget(value);
|
|
94
|
+
if (parsed === undefined) {
|
|
95
|
+
errors.push(`--target must be id=css-selector; got ${JSON.stringify(value)}`);
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
targets.push(parsed);
|
|
99
|
+
}
|
|
100
|
+
break;
|
|
101
|
+
}
|
|
102
|
+
case '--output':
|
|
103
|
+
outputLocation = argv[(i += 1)];
|
|
104
|
+
break;
|
|
105
|
+
case '--timeout': {
|
|
106
|
+
const value = argv[(i += 1)];
|
|
107
|
+
const parsedNumber = value === undefined ? NaN : Number(value);
|
|
108
|
+
if (!Number.isFinite(parsedNumber)) {
|
|
109
|
+
errors.push(`--timeout must be a number of milliseconds; got ${JSON.stringify(value)}`);
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
timeoutMs = parsedNumber;
|
|
113
|
+
}
|
|
114
|
+
break;
|
|
115
|
+
}
|
|
116
|
+
default:
|
|
117
|
+
errors.push(`unrecognized argument: ${arg}`);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
if (targetUrl === undefined)
|
|
121
|
+
errors.push('--url is required');
|
|
122
|
+
if (errors.length > 0)
|
|
123
|
+
return { ok: false, errors };
|
|
124
|
+
const raw = {
|
|
125
|
+
targetUrl,
|
|
126
|
+
...(viewport === undefined ? {} : { viewport }),
|
|
127
|
+
...(targets.length > 0 ? { targets } : {}),
|
|
128
|
+
...(outputLocation === undefined ? {} : { outputLocation }),
|
|
129
|
+
...(timeoutMs === undefined ? {} : { timeoutMs }),
|
|
130
|
+
};
|
|
131
|
+
return { ok: true, raw };
|
|
132
|
+
}
|
|
133
|
+
function formatDiagnostic(diagnostic) {
|
|
134
|
+
const target = diagnostic.targetName === undefined ? '' : ` (target: ${diagnostic.targetName})`;
|
|
135
|
+
return `[${diagnostic.code}] ${diagnostic.message}${target}`;
|
|
136
|
+
}
|
|
137
|
+
/** Completion states that must never be reported as a successful process exit, even though they may still have a persisted artifact. */
|
|
138
|
+
const NON_SUCCESS_COMPLETION_STATES = new Set(['fatal', 'invalid-request']);
|
|
139
|
+
async function runObserveCommand(argv, io) {
|
|
140
|
+
if (argv.includes('--help')) {
|
|
141
|
+
io.stdout(OBSERVE_HELP);
|
|
142
|
+
return 0;
|
|
143
|
+
}
|
|
144
|
+
const parsedArgs = parseObserveArgs(argv);
|
|
145
|
+
if (!parsedArgs.ok) {
|
|
146
|
+
for (const error of parsedArgs.errors)
|
|
147
|
+
io.stderr(`error: ${error}\n`);
|
|
148
|
+
io.stderr(OBSERVE_HELP);
|
|
149
|
+
return 1;
|
|
150
|
+
}
|
|
151
|
+
const normalized = normalizeRequest(parsedArgs.raw);
|
|
152
|
+
if (!normalized.ok) {
|
|
153
|
+
for (const diagnostic of normalized.diagnostics)
|
|
154
|
+
io.stderr(`${formatDiagnostic(diagnostic)}\n`);
|
|
155
|
+
return 1;
|
|
156
|
+
}
|
|
157
|
+
// Exactly one application observation attempt: one browser capture, persisted at most once.
|
|
158
|
+
const result = await observe(normalized.request);
|
|
159
|
+
if (!result.ok) {
|
|
160
|
+
for (const diagnostic of result.diagnostics)
|
|
161
|
+
io.stderr(`${formatDiagnostic(diagnostic)}\n`);
|
|
162
|
+
return 1;
|
|
163
|
+
}
|
|
164
|
+
io.stdout(`Observation: ${result.observationId}\n`);
|
|
165
|
+
io.stdout(`State: ${result.completion.state}\n`);
|
|
166
|
+
io.stdout(`Artifact: ${result.artifactRoot}\n`);
|
|
167
|
+
io.stdout(`Targets: ${result.targetCount}\n`);
|
|
168
|
+
io.stdout(`Diagnostics: ${result.diagnostics.length}\n`);
|
|
169
|
+
return NON_SUCCESS_COMPLETION_STATES.has(result.completion.state) ? 1 : 0;
|
|
170
|
+
}
|
|
171
|
+
/** Testable CLI entry point: pure function of argv (+ injectable IO), no direct process.exit. */
|
|
172
|
+
export async function runCli(argv, io = defaultIO) {
|
|
173
|
+
const [command, ...rest] = argv;
|
|
174
|
+
if (command === undefined) {
|
|
175
|
+
io.stderr(TOP_LEVEL_HELP);
|
|
176
|
+
return 1;
|
|
177
|
+
}
|
|
178
|
+
if (command === '--help' || command === '-h') {
|
|
179
|
+
io.stdout(TOP_LEVEL_HELP);
|
|
180
|
+
return 0;
|
|
181
|
+
}
|
|
182
|
+
if (command === '--version') {
|
|
183
|
+
io.stdout(`${getProducerInfo().version}\n`);
|
|
184
|
+
return 0;
|
|
185
|
+
}
|
|
186
|
+
if (command === 'observe') {
|
|
187
|
+
return runObserveCommand(rest, io);
|
|
188
|
+
}
|
|
189
|
+
io.stderr(`error: unrecognized command "${command}"\n`);
|
|
190
|
+
io.stderr(TOP_LEVEL_HELP);
|
|
191
|
+
return 1;
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Resolves symlinks on both sides before comparing paths, not just a raw URL string
|
|
195
|
+
* comparison: on macOS, `os.tmpdir()` (and other paths) live under `/var`, which is
|
|
196
|
+
* itself a symlink to `/private/var`. A plain `import.meta.url === pathToFileURL(...)`
|
|
197
|
+
* comparison silently evaluates false in that case (mismatched but equivalent paths),
|
|
198
|
+
* so the CLI's own entry point never runs - `node dist/cli.js ...` exits 0 having
|
|
199
|
+
* printed nothing. Real-pathing both sides makes the comparison symlink-safe.
|
|
200
|
+
*/
|
|
201
|
+
function isMainModule() {
|
|
202
|
+
if (process.argv[1] === undefined)
|
|
203
|
+
return false;
|
|
204
|
+
try {
|
|
205
|
+
return realpathSync(process.argv[1]) === realpathSync(fileURLToPath(import.meta.url));
|
|
206
|
+
}
|
|
207
|
+
catch {
|
|
208
|
+
return false;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
if (isMainModule()) {
|
|
212
|
+
runCli(process.argv.slice(2)).then((exitCode) => {
|
|
213
|
+
process.exitCode = exitCode;
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { Diagnostic } from './diagnostics.js';
|
|
2
|
+
/**
|
|
3
|
+
* The "warning" variant is reserved for a future non-blocking diagnostic
|
|
4
|
+
* class; no DiagnosticCode frozen in v0.1 Batch 1 maps to it (see
|
|
5
|
+
* deriveCompletion below - every warning-severity diagnostic produces
|
|
6
|
+
* "partial", never "warning").
|
|
7
|
+
*/
|
|
8
|
+
export type CompletionState = {
|
|
9
|
+
state: 'complete';
|
|
10
|
+
} | {
|
|
11
|
+
state: 'partial';
|
|
12
|
+
diagnostics: Diagnostic[];
|
|
13
|
+
} | {
|
|
14
|
+
state: 'warning';
|
|
15
|
+
diagnostics: Diagnostic[];
|
|
16
|
+
} | {
|
|
17
|
+
state: 'invalid-request';
|
|
18
|
+
diagnostics: Diagnostic[];
|
|
19
|
+
} | {
|
|
20
|
+
state: 'fatal';
|
|
21
|
+
diagnostics: Diagnostic[];
|
|
22
|
+
};
|
|
23
|
+
export type RequestPhase = 'pre-capture' | 'post-capture';
|
|
24
|
+
/**
|
|
25
|
+
* pre-capture + any diagnostic -> invalid-request (capture never attempted).
|
|
26
|
+
* post-capture + any error-severity diagnostic -> fatal.
|
|
27
|
+
* post-capture + only warning-severity diagnostics -> partial (never silently complete).
|
|
28
|
+
* no diagnostics, either phase -> complete.
|
|
29
|
+
*/
|
|
30
|
+
export declare function deriveCompletion(diagnostics: readonly Diagnostic[], requestPhase: RequestPhase): CompletionState;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { orderDiagnostics } from './diagnostics.js';
|
|
2
|
+
/**
|
|
3
|
+
* pre-capture + any diagnostic -> invalid-request (capture never attempted).
|
|
4
|
+
* post-capture + any error-severity diagnostic -> fatal.
|
|
5
|
+
* post-capture + only warning-severity diagnostics -> partial (never silently complete).
|
|
6
|
+
* no diagnostics, either phase -> complete.
|
|
7
|
+
*/
|
|
8
|
+
export function deriveCompletion(diagnostics, requestPhase) {
|
|
9
|
+
const ordered = orderDiagnostics(diagnostics);
|
|
10
|
+
if (ordered.length === 0) {
|
|
11
|
+
return { state: 'complete' };
|
|
12
|
+
}
|
|
13
|
+
if (requestPhase === 'pre-capture') {
|
|
14
|
+
return { state: 'invalid-request', diagnostics: ordered };
|
|
15
|
+
}
|
|
16
|
+
const hasError = ordered.some((diagnostic) => diagnostic.severity === 'error');
|
|
17
|
+
if (hasError) {
|
|
18
|
+
return { state: 'fatal', diagnostics: ordered };
|
|
19
|
+
}
|
|
20
|
+
return { state: 'partial', diagnostics: ordered };
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=completion.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"completion.js","sourceRoot":"","sources":["../../src/domain/completion.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAiBpD;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAAC,WAAkC,EAAE,YAA0B;IAC7F,MAAM,OAAO,GAAG,gBAAgB,CAAC,WAAW,CAAC,CAAC;IAC9C,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC;IAC/B,CAAC;IACD,IAAI,YAAY,KAAK,aAAa,EAAE,CAAC;QACnC,OAAO,EAAE,KAAK,EAAE,iBAAiB,EAAE,WAAW,EAAE,OAAO,EAAE,CAAC;IAC5D,CAAC;IACD,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,UAAU,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC;IAC/E,IAAI,QAAQ,EAAE,CAAC;QACb,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,CAAC;IAClD,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,OAAO,EAAE,CAAC;AACpD,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export declare const DIAGNOSTIC_CODES: readonly ["invalid-request", "unsupported-configuration", "unsafe-url", "prohibited-navigation", "prohibited-redirect", "prohibited-subresource-request", "readiness-timeout", "navigation-failure", "target-missing", "target-ambiguous", "browser-evidence-unavailable", "partial-evidence", "bounded-truncated-evidence", "artifact-write-failure", "browser-runtime-failure"];
|
|
2
|
+
export type DiagnosticCode = (typeof DIAGNOSTIC_CODES)[number];
|
|
3
|
+
export type DiagnosticSeverity = 'error' | 'warning';
|
|
4
|
+
/** Single source of truth for code->severity; ordering/completion logic must consult this, never a duplicated mapping. */
|
|
5
|
+
export declare const DIAGNOSTIC_SEVERITY: Record<DiagnosticCode, DiagnosticSeverity>;
|
|
6
|
+
export interface Diagnostic {
|
|
7
|
+
code: DiagnosticCode;
|
|
8
|
+
severity: DiagnosticSeverity;
|
|
9
|
+
message: string;
|
|
10
|
+
targetName?: string;
|
|
11
|
+
details?: Record<string, unknown>;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Deterministic ordering: error before warning, then code, then targetName
|
|
15
|
+
* (absent-first). Pure - returns a new array, never mutates the input.
|
|
16
|
+
*/
|
|
17
|
+
export declare function orderDiagnostics(diagnostics: readonly Diagnostic[]): Diagnostic[];
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
export const DIAGNOSTIC_CODES = [
|
|
2
|
+
'invalid-request',
|
|
3
|
+
'unsupported-configuration',
|
|
4
|
+
'unsafe-url',
|
|
5
|
+
'prohibited-navigation',
|
|
6
|
+
'prohibited-redirect',
|
|
7
|
+
'prohibited-subresource-request',
|
|
8
|
+
'readiness-timeout',
|
|
9
|
+
'navigation-failure',
|
|
10
|
+
'target-missing',
|
|
11
|
+
'target-ambiguous',
|
|
12
|
+
'browser-evidence-unavailable',
|
|
13
|
+
'partial-evidence',
|
|
14
|
+
'bounded-truncated-evidence',
|
|
15
|
+
'artifact-write-failure',
|
|
16
|
+
'browser-runtime-failure',
|
|
17
|
+
];
|
|
18
|
+
/** Single source of truth for code->severity; ordering/completion logic must consult this, never a duplicated mapping. */
|
|
19
|
+
export const DIAGNOSTIC_SEVERITY = {
|
|
20
|
+
'invalid-request': 'error',
|
|
21
|
+
'unsupported-configuration': 'error',
|
|
22
|
+
'unsafe-url': 'error',
|
|
23
|
+
'prohibited-navigation': 'error',
|
|
24
|
+
'prohibited-redirect': 'error',
|
|
25
|
+
'prohibited-subresource-request': 'error',
|
|
26
|
+
'readiness-timeout': 'warning',
|
|
27
|
+
'navigation-failure': 'error',
|
|
28
|
+
'target-missing': 'warning',
|
|
29
|
+
'target-ambiguous': 'warning',
|
|
30
|
+
'browser-evidence-unavailable': 'warning',
|
|
31
|
+
'partial-evidence': 'warning',
|
|
32
|
+
'bounded-truncated-evidence': 'warning',
|
|
33
|
+
'artifact-write-failure': 'error',
|
|
34
|
+
'browser-runtime-failure': 'error',
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* Deterministic ordering: error before warning, then code, then targetName
|
|
38
|
+
* (absent-first). Pure - returns a new array, never mutates the input.
|
|
39
|
+
*/
|
|
40
|
+
export function orderDiagnostics(diagnostics) {
|
|
41
|
+
const severityRank = (d) => (d.severity === 'error' ? 0 : 1);
|
|
42
|
+
return [...diagnostics].sort((a, b) => {
|
|
43
|
+
const rankDiff = severityRank(a) - severityRank(b);
|
|
44
|
+
if (rankDiff !== 0)
|
|
45
|
+
return rankDiff;
|
|
46
|
+
if (a.code !== b.code)
|
|
47
|
+
return a.code < b.code ? -1 : 1;
|
|
48
|
+
const targetA = a.targetName ?? '';
|
|
49
|
+
const targetB = b.targetName ?? '';
|
|
50
|
+
if (targetA !== targetB)
|
|
51
|
+
return targetA < targetB ? -1 : 1;
|
|
52
|
+
return 0;
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=diagnostics.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diagnostics.js","sourceRoot":"","sources":["../../src/domain/diagnostics.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,gBAAgB,GAAG;IAC9B,iBAAiB;IACjB,2BAA2B;IAC3B,YAAY;IACZ,uBAAuB;IACvB,qBAAqB;IACrB,gCAAgC;IAChC,mBAAmB;IACnB,oBAAoB;IACpB,gBAAgB;IAChB,kBAAkB;IAClB,8BAA8B;IAC9B,kBAAkB;IAClB,4BAA4B;IAC5B,wBAAwB;IACxB,yBAAyB;CACjB,CAAC;AAMX,0HAA0H;AAC1H,MAAM,CAAC,MAAM,mBAAmB,GAA+C;IAC7E,iBAAiB,EAAE,OAAO;IAC1B,2BAA2B,EAAE,OAAO;IACpC,YAAY,EAAE,OAAO;IACrB,uBAAuB,EAAE,OAAO;IAChC,qBAAqB,EAAE,OAAO;IAC9B,gCAAgC,EAAE,OAAO;IACzC,mBAAmB,EAAE,SAAS;IAC9B,oBAAoB,EAAE,OAAO;IAC7B,gBAAgB,EAAE,SAAS;IAC3B,kBAAkB,EAAE,SAAS;IAC7B,8BAA8B,EAAE,SAAS;IACzC,kBAAkB,EAAE,SAAS;IAC7B,4BAA4B,EAAE,SAAS;IACvC,wBAAwB,EAAE,OAAO;IACjC,yBAAyB,EAAE,OAAO;CACnC,CAAC;AAUF;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAC,WAAkC;IACjE,MAAM,YAAY,GAAG,CAAC,CAAa,EAAU,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACjF,OAAO,CAAC,GAAG,WAAW,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;QACpC,MAAM,QAAQ,GAAG,YAAY,CAAC,CAAC,CAAC,GAAG,YAAY,CAAC,CAAC,CAAC,CAAC;QACnD,IAAI,QAAQ,KAAK,CAAC;YAAE,OAAO,QAAQ,CAAC;QACpC,IAAI,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,IAAI;YAAE,OAAO,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACvD,MAAM,OAAO,GAAG,CAAC,CAAC,UAAU,IAAI,EAAE,CAAC;QACnC,MAAM,OAAO,GAAG,CAAC,CAAC,UAAU,IAAI,EAAE,CAAC;QACnC,IAAI,OAAO,KAAK,OAAO;YAAE,OAAO,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC3D,OAAO,CAAC,CAAC;IACX,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export type EvidenceState = 'available' | 'unavailable' | 'not-applicable' | 'partial';
|
|
2
|
+
export type EvidenceSource = 'browser' | 'computed-browser' | 'derived';
|
|
3
|
+
export type EvidenceField<T> = {
|
|
4
|
+
state: 'available';
|
|
5
|
+
source: EvidenceSource;
|
|
6
|
+
value: T;
|
|
7
|
+
derivedFrom?: string[];
|
|
8
|
+
} | {
|
|
9
|
+
state: 'partial';
|
|
10
|
+
source: EvidenceSource;
|
|
11
|
+
value: T;
|
|
12
|
+
reason: string;
|
|
13
|
+
derivedFrom?: string[];
|
|
14
|
+
} | {
|
|
15
|
+
state: 'unavailable';
|
|
16
|
+
reason: string;
|
|
17
|
+
} | {
|
|
18
|
+
state: 'not-applicable';
|
|
19
|
+
reason?: string;
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Structural validator for the frozen EvidenceField<T> contract. Enforces the
|
|
23
|
+
* per-state field-combination invariants (available/partial require
|
|
24
|
+
* source+value; unavailable/not-applicable forbid both) and the
|
|
25
|
+
* derivedFrom-iff-derived-source invariant.
|
|
26
|
+
*/
|
|
27
|
+
export declare function isValidEvidenceField<T = unknown>(field: unknown): field is EvidenceField<T>;
|