@gate-forge/witness 0.12.0 → 0.13.1
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/client/witness-client.d.ts +10 -1
- package/dist/client/witness-client.d.ts.map +1 -1
- package/dist/client/witness-client.js +11 -3
- package/dist/client/witness-client.js.map +1 -1
- package/dist/constants.d.ts +15 -0
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +21 -0
- package/dist/constants.js.map +1 -1
- package/dist/witness/api-settlement.d.ts +88 -0
- package/dist/witness/api-settlement.d.ts.map +1 -0
- package/dist/witness/api-settlement.js +160 -0
- package/dist/witness/api-settlement.js.map +1 -0
- package/dist/witness/browser.d.ts +14 -3
- package/dist/witness/browser.d.ts.map +1 -1
- package/dist/witness/browser.js +208 -2
- package/dist/witness/browser.js.map +1 -1
- package/dist/witness/classifications.d.ts +4 -6
- package/dist/witness/classifications.d.ts.map +1 -1
- package/dist/witness/classifications.js.map +1 -1
- package/dist/witness/page-live-channels.d.ts +46 -0
- package/dist/witness/page-live-channels.d.ts.map +1 -0
- package/dist/witness/page-live-channels.js +68 -0
- package/dist/witness/page-live-channels.js.map +1 -0
- package/dist/witness/page-observation.d.ts +108 -0
- package/dist/witness/page-observation.d.ts.map +1 -0
- package/dist/witness/page-observation.js +134 -0
- package/dist/witness/page-observation.js.map +1 -0
- package/dist/witness/page-observer-registration.d.ts +86 -0
- package/dist/witness/page-observer-registration.d.ts.map +1 -0
- package/dist/witness/page-observer-registration.js +258 -0
- package/dist/witness/page-observer-registration.js.map +1 -0
- package/dist/witness/page-observer.d.ts +20 -0
- package/dist/witness/page-observer.d.ts.map +1 -0
- package/dist/witness/page-observer.js +520 -0
- package/dist/witness/page-observer.js.map +1 -0
- package/dist/witness/server.d.ts.map +1 -1
- package/dist/witness/server.js +201 -1
- package/dist/witness/server.js.map +1 -1
- package/dist/witness/types.d.ts +82 -0
- package/dist/witness/types.d.ts.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Grades a visit's tracked app data request set as settled: no request is
|
|
3
|
+
* still outstanding, and every failure is a client-side cancel
|
|
4
|
+
* (`net::ERR_ABORTED`) that a completed request with the same method and
|
|
5
|
+
* the same full URL (origin+path+query) superseded within the same visit.
|
|
6
|
+
* Evaluated at grading time, so the superseding request may start before
|
|
7
|
+
* or after the abort. Any other failure text (connection refused, empty
|
|
8
|
+
* response, dead body, ...), or an unretried cancel, stays unsettled.
|
|
9
|
+
*/
|
|
10
|
+
export function apiRequestsSettled(input) {
|
|
11
|
+
if (input.outstandingCount !== 0)
|
|
12
|
+
return false;
|
|
13
|
+
const completed = new Set(input.completions.map(({ method, url }) => `${method} ${url}`));
|
|
14
|
+
return input.failures.every((failure) => failure.errorText === 'net::ERR_ABORTED' && completed.has(`${failure.method} ${failure.url}`));
|
|
15
|
+
}
|
|
16
|
+
function pathname(raw) {
|
|
17
|
+
try {
|
|
18
|
+
return new URL(raw, 'http://gateforge.invalid').pathname.replace(/\/+$/, '') || '/';
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
/** Match an absolute route template, where each `:name` consumes one segment. */
|
|
25
|
+
export function matchPageRoute(routePath, rawUrl) {
|
|
26
|
+
const actual = pathname(rawUrl);
|
|
27
|
+
const expected = pathname(routePath);
|
|
28
|
+
if (actual === null || expected === null)
|
|
29
|
+
return false;
|
|
30
|
+
const templateParts = expected.split('/').filter(Boolean);
|
|
31
|
+
const actualParts = actual.split('/').filter(Boolean);
|
|
32
|
+
return templateParts.length === actualParts.length && templateParts.every((part, index) => part.startsWith(':') ? actualParts[index] !== '' : part === actualParts[index]);
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* The declared login route a visit landed on, or null. A visit whose
|
|
36
|
+
* REQUESTED route is itself a declared login page never counts: a
|
|
37
|
+
* directly opened declared login page is a legitimate public page, only
|
|
38
|
+
* a bounced protected navigation is a rejected session.
|
|
39
|
+
*/
|
|
40
|
+
export function landedLoginRoute(finalUrl, requestedPath, loginRoutes) {
|
|
41
|
+
const finalPath = pathname(finalUrl);
|
|
42
|
+
if (finalPath === null)
|
|
43
|
+
return null;
|
|
44
|
+
const matched = loginRoutes.find((route) => pathname(route) === finalPath);
|
|
45
|
+
if (matched === undefined)
|
|
46
|
+
return null;
|
|
47
|
+
const requested = pathname(requestedPath);
|
|
48
|
+
if (requested !== null && loginRoutes.some((route) => pathname(route) === requested))
|
|
49
|
+
return null;
|
|
50
|
+
return matched;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Grade one settled visit using only witness-collected browser observations.
|
|
54
|
+
*
|
|
55
|
+
* `expectedPage` grades the visit against the one configured page the driver
|
|
56
|
+
* deliberately requested: the settled URL must be that page, so a redirect to
|
|
57
|
+
* a login route or to any other page refuses the expected page under its own
|
|
58
|
+
* id instead of matching an incidental route. Without it the visit is
|
|
59
|
+
* attributed to the last opened declared page, where a directly opened
|
|
60
|
+
* declared login page counts as a legitimate public page while a bounced
|
|
61
|
+
* protected navigation never does.
|
|
62
|
+
*/
|
|
63
|
+
export function gradePageVisit(input) {
|
|
64
|
+
const { visit } = input;
|
|
65
|
+
const urls = [...visit.navigations, visit.url];
|
|
66
|
+
const navigatedPaths = urls.map(pathname).filter((value) => value !== null);
|
|
67
|
+
const loginPaths = (input.loginRoutes ?? []).map(pathname).filter((value) => value !== null);
|
|
68
|
+
const observedLogin = loginPaths.some((loginPath) => navigatedPaths.includes(loginPath));
|
|
69
|
+
let page;
|
|
70
|
+
if (input.expectedPage !== undefined) {
|
|
71
|
+
page = input.expectedPage;
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
for (const url of [...urls].reverse()) {
|
|
75
|
+
if (loginPaths.includes(pathname(url) ?? ''))
|
|
76
|
+
continue;
|
|
77
|
+
page = input.pages.find(({ path }) => matchPageRoute(path, url));
|
|
78
|
+
if (page !== undefined)
|
|
79
|
+
break;
|
|
80
|
+
}
|
|
81
|
+
// A declared login page reached without any other requested page is a
|
|
82
|
+
// legitimate public page; after a bounced protected navigation it is not.
|
|
83
|
+
if (page === undefined && navigatedPaths.length > 0 && navigatedPaths.every((value) => loginPaths.includes(value))) {
|
|
84
|
+
for (const url of [...urls].reverse()) {
|
|
85
|
+
page = input.pages.find(({ path }) => matchPageRoute(path, url));
|
|
86
|
+
if (page !== undefined)
|
|
87
|
+
break;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
const routeMatched = page !== undefined && matchPageRoute(page.path, visit.url);
|
|
92
|
+
const pageIsLoginRoute = page !== undefined && loginPaths.includes(pathname(page.path) ?? '');
|
|
93
|
+
const bounced = observedLogin && !pageIsLoginRoute;
|
|
94
|
+
const loadsReasons = [];
|
|
95
|
+
if (!routeMatched)
|
|
96
|
+
loadsReasons.push('PAGE_ROUTE_UNMATCHED');
|
|
97
|
+
if (bounced)
|
|
98
|
+
loadsReasons.push('PAGE_BOUNCED_TO_LOGIN');
|
|
99
|
+
if (visit.exceptions.length > 0)
|
|
100
|
+
loadsReasons.push('PAGE_UNCAUGHT_EXCEPTION');
|
|
101
|
+
if (visit.domMarkerHit)
|
|
102
|
+
loadsReasons.push('PAGE_ERROR_MARKER');
|
|
103
|
+
const dataReasons = [];
|
|
104
|
+
// An observation whose app request set did not settle (a request failed
|
|
105
|
+
// or a bounded wait expired) is unverifiable: both promises refuse with
|
|
106
|
+
// the typed unsettled reason, never a fabricated JS exception.
|
|
107
|
+
if (visit.apiRequestsSettled !== true) {
|
|
108
|
+
loadsReasons.push('PAGE_API_UNSETTLED');
|
|
109
|
+
dataReasons.push('PAGE_API_UNSETTLED');
|
|
110
|
+
}
|
|
111
|
+
for (const response of visit.apiResponses) {
|
|
112
|
+
if (response.remoteAddress === null || !response.proxied) {
|
|
113
|
+
loadsReasons.push('PAGE_LOCALLY_FULFILLED');
|
|
114
|
+
dataReasons.push('PAGE_LOCALLY_FULFILLED');
|
|
115
|
+
}
|
|
116
|
+
else if (response.status >= 400 &&
|
|
117
|
+
// Owner decision (0.13): on a page whose audience has NO login
|
|
118
|
+
// configured, an app data answer of exactly 401 IS the expected
|
|
119
|
+
// not-logged-in answer. Every other >= 400 status, and 401 on a
|
|
120
|
+
// page whose audience HAS a login, still refuses — as does a 401
|
|
121
|
+
// on an unresolved page (`page` undefined fails closed).
|
|
122
|
+
!(response.status === 401 && page?.anonymous === true)) {
|
|
123
|
+
dataReasons.push('PAGE_API_ERROR');
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return {
|
|
127
|
+
pageId: page?.id ?? null,
|
|
128
|
+
finalUrl: visit.url,
|
|
129
|
+
loads: { satisfied: loadsReasons.length === 0, refusalReasons: [...new Set(loadsReasons)] },
|
|
130
|
+
dataOk: { satisfied: dataReasons.length === 0, refusalReasons: [...new Set(dataReasons)] },
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
/** Browser-backed observer attached to an existing Chromium debugging port. */
|
|
134
|
+
//# sourceMappingURL=page-observation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"page-observation.js","sourceRoot":"","sources":["../../src/witness/page-observation.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import type { ServerResponse } from 'node:http';
|
|
2
|
+
import type { PageObservationContext, SessionPageObserverRequest } from './types.js';
|
|
3
|
+
import { type EngineBrowserManager } from './browser.js';
|
|
4
|
+
import { type PageObserver } from './page-observer.js';
|
|
5
|
+
import { type PageRoute, type PageVisitVerdict } from './page-observation.js';
|
|
6
|
+
export interface PageObserverRegistrationState {
|
|
7
|
+
pageObservers: Map<string, PageObserver>;
|
|
8
|
+
pageObservationRecords: Map<string, string[]>;
|
|
9
|
+
observed: Array<{
|
|
10
|
+
seq: number;
|
|
11
|
+
sessionId: string | null;
|
|
12
|
+
path: string;
|
|
13
|
+
status: number;
|
|
14
|
+
}>;
|
|
15
|
+
/** Controller-held page-observation context (0.13 authority cutover). */
|
|
16
|
+
pageObservation: PageObservationContext | null;
|
|
17
|
+
}
|
|
18
|
+
export declare class PageObserverRegistrationError extends Error {
|
|
19
|
+
readonly status: number;
|
|
20
|
+
constructor(message: string, status: number);
|
|
21
|
+
}
|
|
22
|
+
export declare function registerPageObserver(input: {
|
|
23
|
+
state: PageObserverRegistrationState;
|
|
24
|
+
response: ServerResponse;
|
|
25
|
+
body: SessionPageObserverRequest;
|
|
26
|
+
requireSession(body: Record<string, unknown>): {
|
|
27
|
+
sessionId: string;
|
|
28
|
+
testId: string;
|
|
29
|
+
activity: number;
|
|
30
|
+
/** The supervisor-registered spec file this session was minted for. */
|
|
31
|
+
registeredFile: string | null;
|
|
32
|
+
};
|
|
33
|
+
issueRecord(obligationId: string, testId: string, payload: unknown): string;
|
|
34
|
+
}): Promise<void>;
|
|
35
|
+
/**
|
|
36
|
+
* One sweep progress line, emitted as each visit finishes so a killed run
|
|
37
|
+
* keeps the lines it already earned.
|
|
38
|
+
*/
|
|
39
|
+
export declare function formatSweepProgress(info: {
|
|
40
|
+
index: number;
|
|
41
|
+
total: number;
|
|
42
|
+
audience: string;
|
|
43
|
+
path: string;
|
|
44
|
+
proven: boolean;
|
|
45
|
+
firstReason: string | null;
|
|
46
|
+
ms: number;
|
|
47
|
+
}): string;
|
|
48
|
+
/** One swept route outcome: the page verdict plus whether the sweep visited it. */
|
|
49
|
+
export interface SweptPageVisit {
|
|
50
|
+
routeId: string;
|
|
51
|
+
verdict: PageVisitVerdict;
|
|
52
|
+
/** False when the sweep refused this page WITHOUT visiting it. */
|
|
53
|
+
visited: boolean;
|
|
54
|
+
}
|
|
55
|
+
/** The outcome of one audience's swept page visits. */
|
|
56
|
+
export interface PageSweepResult {
|
|
57
|
+
visits: SweptPageVisit[];
|
|
58
|
+
/**
|
|
59
|
+
* Set when the audience's session was rejected on the FIRST visited
|
|
60
|
+
* page (it landed on a declared login route): the remaining pages were
|
|
61
|
+
* refused WITHOUT visiting, with PAGE_AUDIENCE_SESSION_INVALID.
|
|
62
|
+
*/
|
|
63
|
+
sessionRejected: {
|
|
64
|
+
path: string;
|
|
65
|
+
login: string;
|
|
66
|
+
notVisited: number;
|
|
67
|
+
} | null;
|
|
68
|
+
}
|
|
69
|
+
export declare function sweepPageVisits(input: {
|
|
70
|
+
browser: EngineBrowserManager;
|
|
71
|
+
sessionId: string;
|
|
72
|
+
testId: string;
|
|
73
|
+
appBase: string;
|
|
74
|
+
/** The audience these routes belong to (named in progress lines). */
|
|
75
|
+
audience: string;
|
|
76
|
+
routes: readonly PageRoute[];
|
|
77
|
+
loginRoutes: readonly string[];
|
|
78
|
+
errorMarkers: readonly string[];
|
|
79
|
+
/** Declared live-channel path prefixes (same rule as the observed channel). */
|
|
80
|
+
liveChannels: readonly string[];
|
|
81
|
+
storageState?: unknown;
|
|
82
|
+
/** Called as each visited page finishes, with its one progress line. */
|
|
83
|
+
onProgress?: (line: string) => void;
|
|
84
|
+
issueRecord(obligationId: string, testId: string, payload: unknown): string;
|
|
85
|
+
}): Promise<PageSweepResult>;
|
|
86
|
+
//# sourceMappingURL=page-observer-registration.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"page-observer-registration.d.ts","sourceRoot":"","sources":["../../src/witness/page-observer-registration.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
import { driveEngineVisit } from './browser.js';
|
|
2
|
+
import { observePageBrowser } from './page-observer.js';
|
|
3
|
+
import { landedLoginRoute } from './page-observation.js';
|
|
4
|
+
export class PageObserverRegistrationError extends Error {
|
|
5
|
+
status;
|
|
6
|
+
constructor(message, status) {
|
|
7
|
+
super(message);
|
|
8
|
+
this.status = status;
|
|
9
|
+
this.name = 'PageObserverRegistrationError';
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
export async function registerPageObserver(input) {
|
|
13
|
+
const { state, body } = input;
|
|
14
|
+
const session = input.requireSession(body);
|
|
15
|
+
if (body.testId !== session.testId)
|
|
16
|
+
throw new PageObserverRegistrationError('page observer test identity does not match its session', 403);
|
|
17
|
+
if (!Number.isInteger(body.debuggingPort) || body.debuggingPort < 1 || body.debuggingPort > 65535) {
|
|
18
|
+
throw new PageObserverRegistrationError('page observer debuggingPort must be a valid TCP port', 400);
|
|
19
|
+
}
|
|
20
|
+
// Authority cutover (0.13): the request carries NOTHING but session
|
|
21
|
+
// credentials and the debugging port. Every grading input comes from
|
|
22
|
+
// the supervisor-registered context; without one there is no page
|
|
23
|
+
// proof, whatever the suite body or environment claims.
|
|
24
|
+
const context = state.pageObservation;
|
|
25
|
+
if (context === null) {
|
|
26
|
+
throw new PageObserverRegistrationError('page observation refused: no controller-registered page-observation context exists for this run', 409);
|
|
27
|
+
}
|
|
28
|
+
// Static browser-API tamper risks match the SUPERVISOR-opened session
|
|
29
|
+
// identity (its registered spec file, or an applicable trusted test id)
|
|
30
|
+
// — never suite metadata, and never a mutable environment variable.
|
|
31
|
+
const tamperRisk = context.tamperRisks.find((risk) => (risk.testId !== null && risk.testId === session.testId) ||
|
|
32
|
+
(session.registeredFile !== null && risk.file === session.registeredFile));
|
|
33
|
+
if (tamperRisk !== undefined) {
|
|
34
|
+
throw new PageObserverRegistrationError('PAGE_OBSERVATION_TAMPER_RISK: page records refused for this test; browser API mutation at ' +
|
|
35
|
+
`${tamperRisk.locationFile}:${String(tamperRisk.line)}`, 403);
|
|
36
|
+
}
|
|
37
|
+
if (state.pageObservers.has(session.sessionId)) {
|
|
38
|
+
throw new PageObserverRegistrationError('page observer is already registered for this session', 409);
|
|
39
|
+
}
|
|
40
|
+
const usedExchanges = new Set();
|
|
41
|
+
let observationSequence = 0;
|
|
42
|
+
let observer;
|
|
43
|
+
try {
|
|
44
|
+
observer = await observePageBrowser({
|
|
45
|
+
debuggingPort: body.debuggingPort,
|
|
46
|
+
pages: context.pages,
|
|
47
|
+
loginRoutes: context.loginRoutes,
|
|
48
|
+
errorMarkers: context.errorMarkers,
|
|
49
|
+
appOrigins: context.appOrigins,
|
|
50
|
+
liveChannels: context.liveChannels ?? [],
|
|
51
|
+
isProxiedExchange(url, status) {
|
|
52
|
+
const path = new URL(url).pathname;
|
|
53
|
+
const exchange = state.observed.find((candidate) => candidate.sessionId === session.sessionId && candidate.path === path && candidate.status === status &&
|
|
54
|
+
!usedExchanges.has(candidate.seq));
|
|
55
|
+
if (exchange === undefined)
|
|
56
|
+
return false;
|
|
57
|
+
usedExchanges.add(exchange.seq);
|
|
58
|
+
return true;
|
|
59
|
+
},
|
|
60
|
+
onVisit(visit, verdict) {
|
|
61
|
+
// An unmatched observation (out-of-table or undeclared-login page)
|
|
62
|
+
// must never mint obligation ids like `null:page:loads`; a matched
|
|
63
|
+
// page keeps its records even when the verdict refuses it.
|
|
64
|
+
if (!context.pages.some((page) => page.id === verdict.pageId))
|
|
65
|
+
return;
|
|
66
|
+
// Origin enforcement (0.13 authority cutover): a MATCHED route
|
|
67
|
+
// whose FINAL URL origin the controller never declared can never
|
|
68
|
+
// mint proof — the explicit refusal replaces the verdict, so
|
|
69
|
+
// wrong-origin content is recorded as refused, never satisfied.
|
|
70
|
+
let finalOrigin = null;
|
|
71
|
+
try {
|
|
72
|
+
finalOrigin = new URL(visit.url).origin;
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
finalOrigin = null;
|
|
76
|
+
}
|
|
77
|
+
let finalVerdict = verdict;
|
|
78
|
+
if (finalOrigin === null || !context.appOrigins.includes(finalOrigin)) {
|
|
79
|
+
finalVerdict = {
|
|
80
|
+
pageId: verdict.pageId,
|
|
81
|
+
finalUrl: visit.url,
|
|
82
|
+
loads: { satisfied: false, refusalReasons: ['PAGE_APP_ORIGIN_MISMATCH'] },
|
|
83
|
+
dataOk: { satisfied: false, refusalReasons: ['PAGE_APP_ORIGIN_MISMATCH'] },
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
const payload = {
|
|
87
|
+
channel: 'observed',
|
|
88
|
+
routeId: finalVerdict.pageId,
|
|
89
|
+
finalUrl: visit.url,
|
|
90
|
+
navigations: visit.navigations,
|
|
91
|
+
exceptions: visit.exceptions,
|
|
92
|
+
domMarkerHit: visit.domMarkerHit,
|
|
93
|
+
apiStatuses: visit.apiResponses.map(({ url, status, remoteAddress, proxied }) => ({ url, status, remoteAddress, proxied })),
|
|
94
|
+
// One payload shared by both promise records; the sequence
|
|
95
|
+
// increases on every observation of this registered session.
|
|
96
|
+
apiRequestsSettled: visit.apiRequestsSettled,
|
|
97
|
+
liveChannels: visit.liveChannels,
|
|
98
|
+
observationSequence: observationSequence++,
|
|
99
|
+
loads: finalVerdict.loads,
|
|
100
|
+
dataOk: finalVerdict.dataOk,
|
|
101
|
+
};
|
|
102
|
+
const recordIds = state.pageObservationRecords.get(session.sessionId) ?? [];
|
|
103
|
+
recordIds.push(input.issueRecord(`${finalVerdict.pageId}:page:loads`, session.testId, payload));
|
|
104
|
+
recordIds.push(input.issueRecord(`${finalVerdict.pageId}:page:data-ok`, session.testId, payload));
|
|
105
|
+
state.pageObservationRecords.set(session.sessionId, recordIds);
|
|
106
|
+
},
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
catch (error) {
|
|
110
|
+
throw new PageObserverRegistrationError(`could not attach page observer: ${error instanceof Error ? error.message : String(error)}`, 503);
|
|
111
|
+
}
|
|
112
|
+
state.pageObservers.set(session.sessionId, observer);
|
|
113
|
+
session.activity += 1;
|
|
114
|
+
input.response.writeHead(200, { 'content-type': 'application/json' });
|
|
115
|
+
input.response.end(JSON.stringify({ registered: true }));
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Visits referee-selected page gaps in the engine-owned session and issues
|
|
119
|
+
* the same page-observation records with their independent channel.
|
|
120
|
+
*/
|
|
121
|
+
function normalizePageStorageState(raw) {
|
|
122
|
+
if (raw === undefined)
|
|
123
|
+
return undefined;
|
|
124
|
+
if (raw === null || typeof raw !== 'object' || !('cookies' in raw) || !Array.isArray(raw.cookies) ||
|
|
125
|
+
!('origins' in raw) || !Array.isArray(raw.origins)) {
|
|
126
|
+
throw new PageObserverRegistrationError('page sweep storage state must contain cookie and origin arrays', 400);
|
|
127
|
+
}
|
|
128
|
+
const cookies = raw.cookies.map((entry) => {
|
|
129
|
+
if (entry === null || typeof entry !== 'object' || !('name' in entry) || typeof entry.name !== 'string' ||
|
|
130
|
+
!('value' in entry) || typeof entry.value !== 'string' || !('domain' in entry) || typeof entry.domain !== 'string' ||
|
|
131
|
+
!('path' in entry) || typeof entry.path !== 'string' || !('expires' in entry) || typeof entry.expires !== 'number' ||
|
|
132
|
+
!('httpOnly' in entry) || typeof entry.httpOnly !== 'boolean' || !('secure' in entry) || typeof entry.secure !== 'boolean' ||
|
|
133
|
+
!('sameSite' in entry) || (entry.sameSite !== 'Strict' && entry.sameSite !== 'Lax' && entry.sameSite !== 'None')) {
|
|
134
|
+
throw new PageObserverRegistrationError('page sweep storage state contains an invalid cookie', 400);
|
|
135
|
+
}
|
|
136
|
+
return {
|
|
137
|
+
name: entry.name,
|
|
138
|
+
value: entry.value,
|
|
139
|
+
domain: entry.domain,
|
|
140
|
+
path: entry.path,
|
|
141
|
+
expires: entry.expires,
|
|
142
|
+
httpOnly: entry.httpOnly,
|
|
143
|
+
secure: entry.secure,
|
|
144
|
+
sameSite: entry.sameSite,
|
|
145
|
+
};
|
|
146
|
+
});
|
|
147
|
+
const origins = raw.origins.map((entry) => {
|
|
148
|
+
if (entry === null || typeof entry !== 'object' || !('origin' in entry) || typeof entry.origin !== 'string' ||
|
|
149
|
+
!('localStorage' in entry) || !Array.isArray(entry.localStorage)) {
|
|
150
|
+
throw new PageObserverRegistrationError('page sweep storage state contains an invalid origin', 400);
|
|
151
|
+
}
|
|
152
|
+
const localStorage = entry.localStorage.map((item) => {
|
|
153
|
+
if (item === null || typeof item !== 'object' || !('name' in item) || typeof item.name !== 'string' ||
|
|
154
|
+
!('value' in item) || typeof item.value !== 'string') {
|
|
155
|
+
throw new PageObserverRegistrationError('page sweep storage state contains an invalid local-storage value', 400);
|
|
156
|
+
}
|
|
157
|
+
return { name: item.name, value: item.value };
|
|
158
|
+
});
|
|
159
|
+
return { origin: entry.origin, localStorage };
|
|
160
|
+
});
|
|
161
|
+
return { cookies, origins };
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* One sweep progress line, emitted as each visit finishes so a killed run
|
|
165
|
+
* keeps the lines it already earned.
|
|
166
|
+
*/
|
|
167
|
+
export function formatSweepProgress(info) {
|
|
168
|
+
const outcome = info.proven ? 'proven' : `refused${info.firstReason === null ? '' : ` ${info.firstReason}`}`;
|
|
169
|
+
return `page ${String(info.index)}/${String(info.total)} ${info.audience} ${info.path} -> ${outcome} (${String(info.ms)} ms)`;
|
|
170
|
+
}
|
|
171
|
+
export async function sweepPageVisits(input) {
|
|
172
|
+
const page = await input.browser.pageFor(input.sessionId, normalizePageStorageState(input.storageState));
|
|
173
|
+
const visits = [];
|
|
174
|
+
let observationSequence = 0;
|
|
175
|
+
// A session the app rejects (e.g. a rotating refresh token the suite's
|
|
176
|
+
// own storage-state file already consumed) bounces the FIRST visited
|
|
177
|
+
// page to a declared login route. Every further route could only
|
|
178
|
+
// bounce the same way, so they are refused WITHOUT visiting; the
|
|
179
|
+
// records still issue, and the payload says the page was not visited
|
|
180
|
+
// and why. Session-less audiences are unaffected.
|
|
181
|
+
let sessionRejected = null;
|
|
182
|
+
for (const [index, route] of input.routes.entries()) {
|
|
183
|
+
if (sessionRejected !== null) {
|
|
184
|
+
const verdict = {
|
|
185
|
+
pageId: route.id,
|
|
186
|
+
finalUrl: route.path,
|
|
187
|
+
loads: { satisfied: false, refusalReasons: ['PAGE_AUDIENCE_SESSION_INVALID'] },
|
|
188
|
+
dataOk: { satisfied: false, refusalReasons: ['PAGE_AUDIENCE_SESSION_INVALID'] },
|
|
189
|
+
};
|
|
190
|
+
const payload = {
|
|
191
|
+
channel: 'swept',
|
|
192
|
+
routeId: verdict.pageId,
|
|
193
|
+
// The page was never visited; the payload says so and why.
|
|
194
|
+
notVisited: 'PAGE_AUDIENCE_SESSION_INVALID',
|
|
195
|
+
finalUrl: route.path,
|
|
196
|
+
navigations: [],
|
|
197
|
+
exceptions: [],
|
|
198
|
+
domMarkerHit: false,
|
|
199
|
+
apiStatuses: [],
|
|
200
|
+
apiRequestsSettled: true,
|
|
201
|
+
liveChannels: { count: 0, paths: [] },
|
|
202
|
+
observationSequence: observationSequence++,
|
|
203
|
+
loads: verdict.loads,
|
|
204
|
+
dataOk: verdict.dataOk,
|
|
205
|
+
};
|
|
206
|
+
input.issueRecord(`${verdict.pageId}:page:loads`, input.testId, payload);
|
|
207
|
+
input.issueRecord(`${verdict.pageId}:page:data-ok`, input.testId, payload);
|
|
208
|
+
visits.push({ routeId: route.id, verdict, visited: false });
|
|
209
|
+
continue;
|
|
210
|
+
}
|
|
211
|
+
const visitStartedAt = Date.now();
|
|
212
|
+
const observation = await driveEngineVisit(page, input.appBase, route, input.routes, {
|
|
213
|
+
loginRoutes: input.loginRoutes,
|
|
214
|
+
errorMarkers: input.errorMarkers,
|
|
215
|
+
liveChannels: input.liveChannels,
|
|
216
|
+
});
|
|
217
|
+
const { verdict, visit } = observation;
|
|
218
|
+
if (verdict.pageId === null) {
|
|
219
|
+
throw new PageObserverRegistrationError(`engine visit did not match a declared page route: ${route.path}`, 503);
|
|
220
|
+
}
|
|
221
|
+
const payload = {
|
|
222
|
+
channel: 'swept',
|
|
223
|
+
routeId: verdict.pageId,
|
|
224
|
+
finalUrl: visit.url,
|
|
225
|
+
navigations: visit.navigations,
|
|
226
|
+
exceptions: visit.exceptions,
|
|
227
|
+
domMarkerHit: visit.domMarkerHit,
|
|
228
|
+
apiStatuses: visit.apiResponses.map(({ url, status, remoteAddress, proxied }) => ({ url, status, remoteAddress, proxied })),
|
|
229
|
+
// One payload reused for both contracts; the sequence increases
|
|
230
|
+
// within this sweep.
|
|
231
|
+
apiRequestsSettled: visit.apiRequestsSettled,
|
|
232
|
+
liveChannels: visit.liveChannels,
|
|
233
|
+
observationSequence: observationSequence++,
|
|
234
|
+
loads: verdict.loads,
|
|
235
|
+
dataOk: verdict.dataOk,
|
|
236
|
+
};
|
|
237
|
+
input.issueRecord(`${verdict.pageId}:page:loads`, input.testId, payload);
|
|
238
|
+
input.issueRecord(`${verdict.pageId}:page:data-ok`, input.testId, payload);
|
|
239
|
+
visits.push({ routeId: verdict.pageId, verdict, visited: true });
|
|
240
|
+
input.onProgress?.(formatSweepProgress({
|
|
241
|
+
index: index + 1,
|
|
242
|
+
total: input.routes.length,
|
|
243
|
+
audience: input.audience,
|
|
244
|
+
path: route.path,
|
|
245
|
+
proven: verdict.loads.satisfied && verdict.dataOk.satisfied,
|
|
246
|
+
firstReason: verdict.loads.refusalReasons[0] ?? verdict.dataOk.refusalReasons[0] ?? null,
|
|
247
|
+
ms: Date.now() - visitStartedAt,
|
|
248
|
+
}));
|
|
249
|
+
if (index === 0 && input.storageState !== undefined) {
|
|
250
|
+
const login = landedLoginRoute(visit.url, route.path, input.loginRoutes);
|
|
251
|
+
if (login !== null) {
|
|
252
|
+
sessionRejected = { path: route.path, login, notVisited: input.routes.length - 1 };
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
return { visits, sessionRejected };
|
|
257
|
+
}
|
|
258
|
+
//# sourceMappingURL=page-observer-registration.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"page-observer-registration.js","sourceRoot":"","sources":["../../src/witness/page-observer-registration.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { type ObservedPageVisit, type PageRoute, type PageVisitVerdict } from './page-observation.js';
|
|
2
|
+
export interface PageObserverOptions {
|
|
3
|
+
debuggingPort: number;
|
|
4
|
+
pages: readonly PageRoute[];
|
|
5
|
+
loginRoutes?: readonly string[];
|
|
6
|
+
errorMarkers: readonly string[];
|
|
7
|
+
appOrigins: readonly string[];
|
|
8
|
+
/** Controller-declared live-channel path prefixes (`pages.liveChannels`). */
|
|
9
|
+
liveChannels?: readonly string[];
|
|
10
|
+
isProxiedExchange: (url: string, status: number) => boolean;
|
|
11
|
+
onVisit: (visit: ObservedPageVisit, verdict: PageVisitVerdict) => void | Promise<void>;
|
|
12
|
+
quietMs?: number;
|
|
13
|
+
}
|
|
14
|
+
export interface PageObserver {
|
|
15
|
+
flush(): Promise<void>;
|
|
16
|
+
close(): Promise<void>;
|
|
17
|
+
}
|
|
18
|
+
/** Attach the witness's independent Playwright/CDP client to an existing browser. */
|
|
19
|
+
export declare function observePageBrowser(options: PageObserverOptions): Promise<PageObserver>;
|
|
20
|
+
//# sourceMappingURL=page-observer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"page-observer.d.ts","sourceRoot":"","sources":["../../src/witness/page-observer.ts"],"names":[],"mappings":"AACA,OAAO,EAKL,KAAK,iBAAiB,EACtB,KAAK,SAAS,EACd,KAAK,gBAAgB,EACtB,MAAM,uBAAuB,CAAC;AAQ/B,MAAM,WAAW,mBAAmB;IAClC,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,SAAS,SAAS,EAAE,CAAC;IAC5B,WAAW,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAChC,YAAY,EAAE,SAAS,MAAM,EAAE,CAAC;IAChC,UAAU,EAAE,SAAS,MAAM,EAAE,CAAC;IAC9B,6EAA6E;IAC7E,YAAY,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC,iBAAiB,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC;IAC5D,OAAO,EAAE,CAAC,KAAK,EAAE,iBAAiB,EAAE,OAAO,EAAE,gBAAgB,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACvF,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AA2DD,MAAM,WAAW,YAAY;IAC3B,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AA4DD,qFAAqF;AACrF,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,YAAY,CAAC,CA+a5F"}
|