@mjasnikovs/pi-task 0.40.35 → 0.40.36
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.
|
@@ -113,9 +113,9 @@ export interface DeepSessionFacts {
|
|
|
113
113
|
* The three request-shaped facts, computed from the log and from nothing else. The
|
|
114
114
|
* driver records `sessionRequests` and calls this; the values are exactly what the
|
|
115
115
|
* pre-log driver computed by filtering the same map (the sign-in request is the
|
|
116
|
-
* first same-origin non-GET issued at or after the submit; the data requests are
|
|
117
|
-
* same-origin
|
|
118
|
-
*
|
|
116
|
+
* first same-origin non-GET issued at or after the submit; the data requests are
|
|
117
|
+
* the same-origin XHR/fetch issued at or after the sign-in request, that request
|
|
118
|
+
* itself excluded).
|
|
119
119
|
*/
|
|
120
120
|
export declare function deriveLegacyFacts(log: SessionRequest[]): Pick<DeepSessionFacts, 'authRequest' | 'postAuthDataAttempted' | 'postAuthData2xx'>;
|
|
121
121
|
/**
|
|
@@ -202,9 +202,9 @@ export function pinnedLocalPort(vars) {
|
|
|
202
202
|
* The three request-shaped facts, computed from the log and from nothing else. The
|
|
203
203
|
* driver records `sessionRequests` and calls this; the values are exactly what the
|
|
204
204
|
* pre-log driver computed by filtering the same map (the sign-in request is the
|
|
205
|
-
* first same-origin non-GET issued at or after the submit; the data requests are
|
|
206
|
-
* same-origin
|
|
207
|
-
*
|
|
205
|
+
* first same-origin non-GET issued at or after the submit; the data requests are
|
|
206
|
+
* the same-origin XHR/fetch issued at or after the sign-in request, that request
|
|
207
|
+
* itself excluded).
|
|
208
208
|
*/
|
|
209
209
|
export function deriveLegacyFacts(log) {
|
|
210
210
|
const auth = log.find(r => r.phase === 'auth') ?? null;
|
|
@@ -659,10 +659,15 @@ export async function driveSession(cdp, { url, credentials, judge, quietMs }) {
|
|
|
659
659
|
// judges it is the chain's last, so the first hop stays and the eventual
|
|
660
660
|
// response lands on it. Overwriting reads a POST that 302s as a GET, and
|
|
661
661
|
// then no sign-in request is ever found.
|
|
662
|
-
|
|
663
|
-
|
|
662
|
+
const req = p.request;
|
|
663
|
+
const existing = requests.get(id);
|
|
664
|
+
if (p.redirectResponse !== undefined && existing) {
|
|
665
|
+
existing.finalUrl = String(req?.url ?? existing.finalUrl);
|
|
666
|
+
}
|
|
667
|
+
else {
|
|
664
668
|
requests.set(id, {
|
|
665
669
|
url: String(req?.url ?? ''),
|
|
670
|
+
finalUrl: String(req?.url ?? ''),
|
|
666
671
|
method: String(req?.method ?? 'GET'),
|
|
667
672
|
type: String(p.type ?? ''),
|
|
668
673
|
status: null,
|
|
@@ -706,15 +711,15 @@ export async function driveSession(cdp, { url, credentials, judge, quietMs }) {
|
|
|
706
711
|
const before = await evaluate(INSPECT_EXPR);
|
|
707
712
|
if (!before)
|
|
708
713
|
throw new Error('the page could not be inspected');
|
|
709
|
-
const sameOrigin = (r) => r.
|
|
714
|
+
const sameOrigin = (r) => r.finalUrl.startsWith(`${origin}/`) || r.finalUrl === origin;
|
|
710
715
|
const isData = (r) => r.type === 'XHR' || r.type === 'Fetch';
|
|
711
716
|
const foreignOriginFailures = () => {
|
|
712
717
|
const out = new Set();
|
|
713
718
|
for (const r of requests.values()) {
|
|
714
|
-
if (sameOrigin(r) || !r.failed || !r.
|
|
719
|
+
if (sameOrigin(r) || !r.failed || !r.finalUrl.startsWith('http'))
|
|
715
720
|
continue;
|
|
716
721
|
try {
|
|
717
|
-
out.add(new URL(r.
|
|
722
|
+
out.add(new URL(r.finalUrl).origin);
|
|
718
723
|
}
|
|
719
724
|
catch {
|
|
720
725
|
// unparseable url — nothing to name
|
|
@@ -725,10 +730,11 @@ export async function driveSession(cdp, { url, credentials, judge, quietMs }) {
|
|
|
725
730
|
const initiatorOf = (r) => isData(r) ? 'xhr'
|
|
726
731
|
: r.type === 'Document' ? 'document'
|
|
727
732
|
: 'other';
|
|
728
|
-
/** The same-origin request log
|
|
729
|
-
*
|
|
730
|
-
*
|
|
731
|
-
*
|
|
733
|
+
/** The same-origin request log. `postSeq` is where the authenticated half
|
|
734
|
+
* begins — Infinity while no submit has happened — so everything before it is
|
|
735
|
+
* 'pre'; the sign-in request itself is 'auth', not 'post'. The boundary is the
|
|
736
|
+
* sign-in request, not the submit: a CSRF token or a beacon the submit fires
|
|
737
|
+
* BEFORE the login is not evidence about the authenticated client. */
|
|
732
738
|
const sessionLog = (authId, postSeq) => [...requests]
|
|
733
739
|
.filter(([, r]) => sameOrigin(r))
|
|
734
740
|
.map(([id, r]) => ({
|
|
@@ -759,6 +765,7 @@ export async function driveSession(cdp, { url, credentials, judge, quietMs }) {
|
|
|
759
765
|
const unsubmitted = (over) => facts(sessionLog(null, Number.POSITIVE_INFINITY), over);
|
|
760
766
|
if (!before.hasPassword || credentials === null)
|
|
761
767
|
return judge(unsubmitted({}));
|
|
768
|
+
const fillSeq = nextSeq;
|
|
762
769
|
const filled = await evaluate(fillExpr(credentials.identifier, credentials.password));
|
|
763
770
|
if (!filled?.ok)
|
|
764
771
|
return judge(unsubmitted({ submitted: false }));
|
|
@@ -784,6 +791,18 @@ export async function driveSession(cdp, { url, credentials, judge, quietMs }) {
|
|
|
784
791
|
break;
|
|
785
792
|
}
|
|
786
793
|
}
|
|
794
|
+
// Nothing after the submit: a form that submits from the fill's own input
|
|
795
|
+
// events already sent it. Only a NAVIGATION qualifies here — a form submission
|
|
796
|
+
// is one, and the background traffic the fill races (beacons, telemetry) is
|
|
797
|
+
// XHR or fetch, never a document.
|
|
798
|
+
if (authId === null) {
|
|
799
|
+
for (const [id, r] of requests) {
|
|
800
|
+
if (r.seq >= fillSeq && sameOrigin(r) && r.method !== 'GET' && r.type === 'Document') {
|
|
801
|
+
authId = id;
|
|
802
|
+
break;
|
|
803
|
+
}
|
|
804
|
+
}
|
|
805
|
+
}
|
|
787
806
|
const authReq = authId === null ? null : requests.get(authId);
|
|
788
807
|
const now = await evaluate(INSPECT_EXPR);
|
|
789
808
|
const domJudgment = judgeRenderedDom(now?.html ?? '');
|
|
@@ -805,7 +824,7 @@ export async function driveSession(cdp, { url, credentials, judge, quietMs }) {
|
|
|
805
824
|
lastActivity = Date.now();
|
|
806
825
|
await settle(() => lastActivity, RE_NAV_CAP_MS, quietMs);
|
|
807
826
|
}
|
|
808
|
-
return judge(facts(sessionLog(authId, submitSeq), {
|
|
827
|
+
return judge(facts(sessionLog(authId, authReq?.seq ?? submitSeq), {
|
|
809
828
|
submitted: true,
|
|
810
829
|
foreignOriginFailures: foreignOriginFailures(),
|
|
811
830
|
leftAuthWall,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mjasnikovs/pi-task",
|
|
3
|
-
"version": "0.40.
|
|
3
|
+
"version": "0.40.36",
|
|
4
4
|
"description": "Deterministic task planning and spec-orchestration for local models — crash-safe /task pipelines with verify/enforce gates, a real-time remote web view, and web/docs/fetch/worker subagent tools.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|