@wenathlan/extension 1.1.36 → 1.1.37
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/README.md +5 -4
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +272 -6
- package/dist/index.js.map +3 -3
- package/dist/memory.d.ts +39 -1
- package/dist/memory.d.ts.map +1 -1
- package/dist/policy.d.ts +17 -1
- package/dist/policy.d.ts.map +1 -1
- package/dist/protocol.d.ts +24 -1
- package/dist/protocol.d.ts.map +1 -1
- package/dist/types.d.ts +96 -3
- package/dist/types.d.ts.map +1 -1
- package/dist/version.d.ts +1 -1
- package/extension/dist/background.js +617 -8
- package/extension/dist/background.js.map +4 -4
- package/extension/dist/manifest.json +1 -1
- package/extension/dist/pagebridge.js +585 -5
- package/extension/dist/pagebridge.js.map +4 -4
- package/extension/dist/popup.html +1 -1
- package/extension/dist/popup.js +15 -2
- package/extension/dist/popup.js.map +2 -2
- package/extension/dist/sidepanel.html +1 -1
- package/extension/dist/sidepanel.js +185 -4
- package/extension/dist/sidepanel.js.map +3 -3
- package/extension/manifest.json +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,17 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
Devthink is a **consent-first browser-agent bridge** distributed as a TypeScript library and a Chromium Manifest V3 extension. It turns a user-provided browser objective into a bounded, reviewable plan. The user must start the active-tab session and approve the plan before any page action reaches the browser.
|
|
4
4
|
|
|
5
|
-
Version: **1.1.
|
|
5
|
+
Version: **1.1.37**. License: **GPL-3.0-only**. The repository is `wenathlan/extension`; the npm-compatible scoped package identifier is `@wenathlan/extension`.
|
|
6
6
|
|
|
7
7
|
## What it does
|
|
8
8
|
|
|
9
|
-
| Capability | Behavior in 1.1.
|
|
9
|
+
| Capability | Behavior in 1.1.37 |
|
|
10
10
|
| --- | --- |
|
|
11
11
|
| Active-tab session | The user starts a short-lived session for one HTTPS tab and one origin; the session records its origin grants. |
|
|
12
12
|
| Page observation | The extension captures the complete semantic inventory: every interactive element, every form control, every select option and the full page text. |
|
|
13
13
|
| Plan proposal | A local plan can be created immediately; an optional user-configured HTTPS endpoint can return a typed plan proposal of any length. |
|
|
14
14
|
| Review gate | Every remote proposal starts in `pending`; it cannot reach the page bridge before explicit approval. |
|
|
15
|
-
| Browser tools | Reviewed plans cover
|
|
15
|
+
| Browser tools | Reviewed plans cover two hundred one action kinds: pointer paths and coordinate clicks, text, aria, name, xpath, index and point target resolution, timed typing, key holds, sliders, dates, colors, shadow dom piercing, iframe entry, dialog answering, retry rules, a complete read vocabulary with clickable maps and verification reads, page mutation under review, and browser-level tab, window, zoom, snapshot and download commands. |
|
|
16
|
+
| Forms and data | The agent fills forms with review: `fillform` fills from a structured record of field matches, kinds and values, `filllabel` and `fillplaceholder` match controls by label, placeholder or aria label, `detectfields` reports the form map with field kinds, `generatevalues` seeds locale aware values per field kind while real looking card numbers and personal identifiers are refused, `saveprofiles` stores profiles behind origin grants, `asksubmit` opens the submission prompt with the values diff, `submitform` submits only under an approved consent ref, `readerrors` associates inline validation messages with fields, `retryform` retries with reviewed backoff windows, `runwizard`, `selectchain`, `picktypeahead` and `pickdate` drive wizards, dependent selects, typeaheads and calendars, `attachfile` attaches run store artifacts, `fillcard`, `fillcode` and `consentpassword` handle payment and secret fields behind explicit consent, `skiphoneypot` skips trap fields, `detectlogin` and `detecttemplate` flag login, signup and checkout shapes, and `handoffcaptcha` pauses the plan and hands control back to the user. |
|
|
16
17
|
| Tabs and windows command | The agent commands the whole browser surface with review: `querytabs` resolves reviewed url, title, id and pattern matchers against the live tab set, `closepattern` closes matching tabs only under the explicit reviewed flag, `pintab`, `mutetab`, `movetab`, `movetabwindow`, `duplicatetab`, `reloadtabs`, `discardtab`, `zoomin`, `zoomout` and `switchtab` mutate tabs, `grouptabs`, `colorgroup` and `collapsegroup` keep group registries, `savelayout` and `restorelayout` save and restore named tab layouts with window bounds, `snapshotsession` and `reopenrun` capture and reopen whole runs, `watchtab` observes title, activation and closure events, `findclones`, `searchtabs` and `listaudio` enumerate the surface read only, `badgetab` and `attachmeta` route task state per tab, and `maximizewindow`, `minimizewindow`, `restorewindow`, `focuswindow`, `scratchwindow` and `incognitowindow` command windows with incognito separated from grant inheritance. |
|
|
17
18
|
| Navigation mastery | The agent moves anywhere with review: `openlink`, `openprivate`, `reopentab`, `deeplink` and `openclipboard` open reviewed targets in resolved containers, `followlink`, `spanav`, `spawait`, `waitload` and `waiturl` navigate pages and single page app routes, `rewritequery` and `setfragment` edit the current url, `navlist` walks a reviewed url list with per entry progress, `navprofile` applies per site wait profiles, `checksafe` verifies urls before unreviewed origins open, `batchopen` opens curated lists with per url safety states, `navrate` enforces per domain rate limits with user configured windows and ceilings, and the navigation trail, redirect chains and final urls stay recorded for audit. |
|
|
18
19
|
| Observation depth | The agent sees the whole page read only: the accessibility tree beside the dom snapshot, reader views, visible text, outlines, selections, open graph and embedded json state, plus detected lists, tables, pagination, infinite scroll, virtualization, lazy images, sticky overlays and scroll locks offered as plan suggestions. |
|
|
@@ -50,7 +51,7 @@ The endpoint field intentionally has no default URL. Enter a URL such as `https:
|
|
|
50
51
|
|
|
51
52
|
```json
|
|
52
53
|
{
|
|
53
|
-
"version": "1.1.
|
|
54
|
+
"version": "1.1.37",
|
|
54
55
|
"objective": "User supplied objective",
|
|
55
56
|
"session": { "id": "uuid", "tabid": 1, "origin": "https://example.com" },
|
|
56
57
|
"observation": { "schemaversion": 3, "url": "https://example.com/path", "interactive": [] },
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export * from "./memory.js";
|
|
2
|
-
export { actionrisk as deriveactionrisk, canexecute, hostpattern, iswatchkind, normalizeendpoint, observationmodeof, resolutionverdict, validatestep, validatetargetref } from "./policy.js";
|
|
2
|
+
export { actionrisk as deriveactionrisk, canexecute, generatedvalueallowed, hostpattern, isformkind, iswatchkind, normalizeendpoint, observationmodeof, passwordconsentgranted, profilegrantgranted, resolutionverdict, submitreviewgranted, validatefieldmatch, validateformrecord, validatestep, validatetargetref, validatevaluegen } from "./policy.js";
|
|
3
3
|
export * from "./protocol.js";
|
|
4
4
|
export * from "./types.js";
|
|
5
5
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,OAAO,EAAE,UAAU,IAAI,gBAAgB,EAAE,UAAU,EAAE,WAAW,EAAE,WAAW,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,OAAO,EAAE,UAAU,IAAI,gBAAgB,EAAE,UAAU,EAAE,qBAAqB,EAAE,WAAW,EAAE,UAAU,EAAE,WAAW,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,sBAAsB,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,YAAY,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC5V,cAAc,eAAe,CAAC;AAC9B,cAAc,YAAY,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -435,20 +435,107 @@ var sessionmemory = class {
|
|
|
435
435
|
async setcontroltab(state) {
|
|
436
436
|
return this.adapter.set("controltab", state);
|
|
437
437
|
}
|
|
438
|
+
/** Stores one saved form profile under its reviewed name, replacing the previous profile of that name. */
|
|
439
|
+
async setprofile(profile) {
|
|
440
|
+
const records = (await this.getprofiles()).filter((item) => item.name !== profile.name);
|
|
441
|
+
await this.adapter.set("formprofiles", [profile, ...records]);
|
|
442
|
+
}
|
|
443
|
+
/** Returns one saved form profile by its reviewed name. */
|
|
444
|
+
async getprofile(name) {
|
|
445
|
+
return (await this.getprofiles()).find((item) => item.name === name);
|
|
446
|
+
}
|
|
447
|
+
/** Returns every saved form profile with its origin grants, newest first. */
|
|
448
|
+
async getprofiles() {
|
|
449
|
+
return await this.adapter.get("formprofiles") ?? [];
|
|
450
|
+
}
|
|
451
|
+
/** Removes one saved form profile by its reviewed name. */
|
|
452
|
+
async removeprofile(name) {
|
|
453
|
+
const records = (await this.getprofiles()).filter((item) => item.name !== name);
|
|
454
|
+
await this.adapter.set("formprofiles", records);
|
|
455
|
+
}
|
|
456
|
+
/** Records one wizard state with its step history. */
|
|
457
|
+
async addwizard(state) {
|
|
458
|
+
const records = await this.getwizards();
|
|
459
|
+
await this.adapter.set("wizards", [state, ...records]);
|
|
460
|
+
}
|
|
461
|
+
/** Returns every stored wizard state with its step history, newest first. */
|
|
462
|
+
async getwizards() {
|
|
463
|
+
return await this.adapter.get("wizards") ?? [];
|
|
464
|
+
}
|
|
465
|
+
/** Stores one submission ticket with its values hash, replacing the previous ticket of that id. */
|
|
466
|
+
async setticket(ticket) {
|
|
467
|
+
const records = (await this.gettickets()).filter((item) => item.id !== ticket.id);
|
|
468
|
+
await this.adapter.set("submittickets", [ticket, ...records]);
|
|
469
|
+
}
|
|
470
|
+
/** Returns every stored submission ticket with its values hash, newest first. */
|
|
471
|
+
async gettickets() {
|
|
472
|
+
return await this.adapter.get("submittickets") ?? [];
|
|
473
|
+
}
|
|
474
|
+
/** Records one collected error report for correction loops. */
|
|
475
|
+
async adderrorreport(report) {
|
|
476
|
+
const records = await this.geterrorreports();
|
|
477
|
+
await this.adapter.set("errorreports", [report, ...records]);
|
|
478
|
+
}
|
|
479
|
+
/** Returns every stored error report, newest first. */
|
|
480
|
+
async geterrorreports() {
|
|
481
|
+
return await this.adapter.get("errorreports") ?? [];
|
|
482
|
+
}
|
|
483
|
+
/** Records one typeahead pick observed when a reviewed suggestion entry was chosen. */
|
|
484
|
+
async addpick(pick) {
|
|
485
|
+
const records = await this.getpicks();
|
|
486
|
+
await this.adapter.set("typeaheadpicks", [pick, ...records]);
|
|
487
|
+
}
|
|
488
|
+
/** Returns every recorded typeahead pick, newest first. */
|
|
489
|
+
async getpicks() {
|
|
490
|
+
return await this.adapter.get("typeaheadpicks") ?? [];
|
|
491
|
+
}
|
|
492
|
+
/** Records one captcha handoff while the plan waits for the user. */
|
|
493
|
+
async addcaptcha(handoff) {
|
|
494
|
+
const records = await this.getcaptchas();
|
|
495
|
+
await this.adapter.set("captchas", [handoff, ...records]);
|
|
496
|
+
}
|
|
497
|
+
/** Returns every captcha handoff record with its resolution state, newest first. */
|
|
498
|
+
async getcaptchas() {
|
|
499
|
+
return await this.adapter.get("captchas") ?? [];
|
|
500
|
+
}
|
|
501
|
+
/** Resolves one captcha handoff by id once the user finished it. */
|
|
502
|
+
async resolvecaptcha(id, resolvedat) {
|
|
503
|
+
const records = await this.getcaptchas();
|
|
504
|
+
await this.adapter.set("captchas", records.map((handoff) => handoff.id === id && !handoff.resolved ? { ...handoff, resolved: true, resolvedat } : handoff));
|
|
505
|
+
}
|
|
506
|
+
/** Records one login or template detection for its origin. */
|
|
507
|
+
async adddetection(record2) {
|
|
508
|
+
const records = await this.getdetections();
|
|
509
|
+
await this.adapter.set("detections", [record2, ...records]);
|
|
510
|
+
}
|
|
511
|
+
/** Returns every stored login and template detection per origin, newest first. */
|
|
512
|
+
async getdetections() {
|
|
513
|
+
return await this.adapter.get("detections") ?? [];
|
|
514
|
+
}
|
|
515
|
+
/** Stores the reviewed one time code behind the consent gate of an active session. */
|
|
516
|
+
async setcodevalue(value) {
|
|
517
|
+
return this.adapter.set("codevalue", value);
|
|
518
|
+
}
|
|
519
|
+
/** Returns the reviewed one time code, if the user stored one behind the consent gate. */
|
|
520
|
+
async getcodevalue() {
|
|
521
|
+
return this.adapter.get("codevalue");
|
|
522
|
+
}
|
|
438
523
|
};
|
|
439
524
|
function randomid() {
|
|
440
525
|
return crypto.randomUUID();
|
|
441
526
|
}
|
|
442
527
|
|
|
443
528
|
// policy.ts
|
|
444
|
-
var sensitiveactions = /* @__PURE__ */ new Set(["click", "type", "navigate", "select", "presskey", "drag", "drop", "upload", "clear", "check", "uncheck", "toggle", "submit", "reload", "back", "forward", "writestorage", "setattribute", "removeattribute", "evaluate", "tabcreate", "tabactivate", "tabclose", "tabreload", "windowcreate", "windowclose", "windowresize", "downloadfile", "clickpoint", "shiftclick", "dismissdialog", "enterframe", "typetime", "appendtext", "setvalue", "typeedit", "keyhold", "keyrelease", "submitsearch", "selectmulti", "chooseradio", "setslider", "setdate", "setcolor", "openlink", "openprivate", "reloadcache", "stopnav", "followlink", "spanav", "rewritequery", "setfragment", "navlist", "navprofile", "handleauth", "printpdf", "prefetch", "preconnect", "deeplink", "reopentab", "pausenav", "navrate", "openclipboard", "batchopen", "duplicatetab", "closepattern", "pintab", "mutetab", "movetab", "movetabwindow", "grouptabs", "colorgroup", "collapsegroup", "discardtab", "reloadtabs", "zoomin", "zoomout", "switchtab", "maximizewindow", "minimizewindow", "restorewindow", "focuswindow", "scratchwindow", "incognitowindow", "restoretab", "restorelayout", "reopenrun", "badgetab"]);
|
|
529
|
+
var sensitiveactions = /* @__PURE__ */ new Set(["click", "type", "navigate", "select", "presskey", "drag", "drop", "upload", "clear", "check", "uncheck", "toggle", "submit", "reload", "back", "forward", "writestorage", "setattribute", "removeattribute", "evaluate", "tabcreate", "tabactivate", "tabclose", "tabreload", "windowcreate", "windowclose", "windowresize", "downloadfile", "clickpoint", "shiftclick", "dismissdialog", "enterframe", "typetime", "appendtext", "setvalue", "typeedit", "keyhold", "keyrelease", "submitsearch", "selectmulti", "chooseradio", "setslider", "setdate", "setcolor", "openlink", "openprivate", "reloadcache", "stopnav", "followlink", "spanav", "rewritequery", "setfragment", "navlist", "navprofile", "handleauth", "printpdf", "prefetch", "preconnect", "deeplink", "reopentab", "pausenav", "navrate", "openclipboard", "batchopen", "duplicatetab", "closepattern", "pintab", "mutetab", "movetab", "movetabwindow", "grouptabs", "colorgroup", "collapsegroup", "discardtab", "reloadtabs", "zoomin", "zoomout", "switchtab", "maximizewindow", "minimizewindow", "restorewindow", "focuswindow", "scratchwindow", "incognitowindow", "restoretab", "restorelayout", "reopenrun", "badgetab", "fillform", "filllabel", "fillplaceholder", "submitform", "retryform", "runwizard", "selectchain", "picktypeahead", "pickdate", "attachfile", "fillcard", "fillcode", "consentpassword"]);
|
|
445
530
|
var interactionactions = /* @__PURE__ */ new Set(["focus", "scroll", "hover", "clickdeep", "rightclick", "doubleclick", "scrollpage", "scrollby", "scrollend", "scrolltop", "fullscreen", "zoomset", "movepointer", "clicktext", "clickaria", "clickname", "expanddetails", "pierceshadow", "retryaction"]);
|
|
446
|
-
var readactions = /* @__PURE__ */ new Set(["observe", "inspect", "extract", "wait", "waitfor", "waittext", "readattribute", "readstyle", "readgeometry", "readvalue", "readtext", "readhtml", "countelements", "readtable", "readlinks", "readimages", "readmeta", "readforms", "readstorage", "highlight", "tablist", "windowlist", "tabsnapshot", "mapclicks", "verifyvisible", "verifyenabled", "resolvexpath", "a11ytree", "readvisible", "readertree", "detectlists", "detecttables", "readjson", "watchmutate", "waitquiet", "watchbanner", "detectinfinitescroll", "detectvirtual", "detectlazy", "readscrollpos", "readlang", "readoutline", "countpages", "listshadow", "listframes", "classifypage", "fingerprintsection", "diffsnapshots", "readselection", "watchfocus", "detectsticky", "detectscrolllock", "readopengraph", "detectlanguage", "deriveselector", "waitload", "waiturl", "spawait", "detecthttp", "readredirects", "readfinalurl", "trailaudit", "navintent", "checksafe", "querytabs", "watchtab", "findclones", "searchtabs", "listaudio", "snapshotsession", "savelayout", "attachmeta"]);
|
|
531
|
+
var readactions = /* @__PURE__ */ new Set(["observe", "inspect", "extract", "wait", "waitfor", "waittext", "readattribute", "readstyle", "readgeometry", "readvalue", "readtext", "readhtml", "countelements", "readtable", "readlinks", "readimages", "readmeta", "readforms", "readstorage", "highlight", "tablist", "windowlist", "tabsnapshot", "mapclicks", "verifyvisible", "verifyenabled", "resolvexpath", "a11ytree", "readvisible", "readertree", "detectlists", "detecttables", "readjson", "watchmutate", "waitquiet", "watchbanner", "detectinfinitescroll", "detectvirtual", "detectlazy", "readscrollpos", "readlang", "readoutline", "countpages", "listshadow", "listframes", "classifypage", "fingerprintsection", "diffsnapshots", "readselection", "watchfocus", "detectsticky", "detectscrolllock", "readopengraph", "detectlanguage", "deriveselector", "waitload", "waiturl", "spawait", "detecthttp", "readredirects", "readfinalurl", "trailaudit", "navintent", "checksafe", "querytabs", "watchtab", "findclones", "searchtabs", "listaudio", "snapshotsession", "savelayout", "attachmeta", "detectfields", "generatevalues", "saveprofiles", "asksubmit", "readerrors", "skiphoneypot", "detectlogin", "detecttemplate", "handoffcaptcha"]);
|
|
447
532
|
var allowedactions = /* @__PURE__ */ new Set([...sensitiveactions, ...interactionactions, ...readactions]);
|
|
448
533
|
var watchactions = /* @__PURE__ */ new Set(["watchmutate", "watchbanner", "watchfocus", "watchtab"]);
|
|
449
|
-
var targetactions = /* @__PURE__ */ new Set(["inspect", "focus", "click", "type", "scroll", "select", "hover", "clickdeep", "rightclick", "doubleclick", "drag", "drop", "upload", "clear", "check", "uncheck", "toggle", "submit", "readattribute", "readstyle", "readgeometry", "readvalue", "readtext", "readhtml", "countelements", "readtable", "highlight", "setattribute", "removeattribute", "waitfor", "shiftclick", "typetime", "appendtext", "setvalue", "typeedit", "submitsearch", "selectmulti", "chooseradio", "setslider", "setdate", "setcolor", "expanddetails", "verifyvisible", "verifyenabled", "pierceshadow", "deriveselector", "fingerprintsection"]);
|
|
450
|
-
var valueactions = /* @__PURE__ */ new Set(["presskey", "drag", "drop", "upload", "readattribute", "removeattribute", "waittext", "evaluate", "zoomset", "tabactivate", "tabclose", "tabreload", "windowclose", "windowresize", "tabcreate", "windowcreate", "downloadfile", "typetime", "appendtext", "setvalue", "typeedit", "keyhold", "keyrelease", "chooseradio", "setslider", "setdate", "setcolor", "followlink", "setfragment", "handleauth", "navintent", "openclipboard", "checksafe", "reopentab", "spanav", "duplicatetab", "pintab", "mutetab", "movetab", "movetabwindow", "searchtabs", "badgetab", "attachmeta", "focuswindow", "maximizewindow", "minimizewindow", "restorewindow", "incognitowindow"]);
|
|
534
|
+
var targetactions = /* @__PURE__ */ new Set(["inspect", "focus", "click", "type", "scroll", "select", "hover", "clickdeep", "rightclick", "doubleclick", "drag", "drop", "upload", "clear", "check", "uncheck", "toggle", "submit", "readattribute", "readstyle", "readgeometry", "readvalue", "readtext", "readhtml", "countelements", "readtable", "highlight", "setattribute", "removeattribute", "waitfor", "shiftclick", "typetime", "appendtext", "setvalue", "typeedit", "submitsearch", "selectmulti", "chooseradio", "setslider", "setdate", "setcolor", "expanddetails", "verifyvisible", "verifyenabled", "pierceshadow", "deriveselector", "fingerprintsection", "submitform", "retryform", "selectchain", "picktypeahead", "pickdate", "attachfile", "fillcode", "consentpassword"]);
|
|
535
|
+
var valueactions = /* @__PURE__ */ new Set(["presskey", "drag", "drop", "upload", "readattribute", "removeattribute", "waittext", "evaluate", "zoomset", "tabactivate", "tabclose", "tabreload", "windowclose", "windowresize", "tabcreate", "windowcreate", "downloadfile", "typetime", "appendtext", "setvalue", "typeedit", "keyhold", "keyrelease", "chooseradio", "setslider", "setdate", "setcolor", "followlink", "setfragment", "handleauth", "navintent", "openclipboard", "checksafe", "reopentab", "spanav", "duplicatetab", "pintab", "mutetab", "movetab", "movetabwindow", "searchtabs", "badgetab", "attachmeta", "focuswindow", "maximizewindow", "minimizewindow", "restorewindow", "incognitowindow", "asksubmit", "selectchain", "picktypeahead", "pickdate", "attachfile", "fillcode", "consentpassword"]);
|
|
451
536
|
var tabscommandactions = /* @__PURE__ */ new Set(["querytabs", "duplicatetab", "closepattern", "pintab", "mutetab", "movetab", "movetabwindow", "grouptabs", "colorgroup", "collapsegroup", "discardtab", "reloadtabs", "zoomin", "zoomout", "watchtab", "switchtab", "maximizewindow", "minimizewindow", "restorewindow", "focuswindow", "scratchwindow", "incognitowindow", "restoretab", "savelayout", "restorelayout", "findclones", "searchtabs", "badgetab", "attachmeta", "listaudio", "reopenrun", "snapshotsession"]);
|
|
537
|
+
var formactions = /* @__PURE__ */ new Set(["fillform", "filllabel", "fillplaceholder", "detectfields", "generatevalues", "saveprofiles", "asksubmit", "submitform", "readerrors", "retryform", "runwizard", "selectchain", "picktypeahead", "pickdate", "attachfile", "handoffcaptcha", "fillcard", "fillcode", "consentpassword", "skiphoneypot", "detectlogin", "detecttemplate"]);
|
|
538
|
+
var fieldkinds = ["text", "email", "phone", "date", "number", "select", "check", "radio", "file", "password", "card", "code"];
|
|
452
539
|
var layoutmutationactions = /* @__PURE__ */ new Set(["grouptabs", "colorgroup", "collapsegroup", "savelayout", "restorelayout"]);
|
|
453
540
|
var groupcolors = ["grey", "blue", "red", "yellow", "green", "pink", "purple", "cyan", "orange"];
|
|
454
541
|
function normalizeendpoint(value) {
|
|
@@ -492,6 +579,147 @@ function istabscommandkind(kind) {
|
|
|
492
579
|
function islayoutkind(kind) {
|
|
493
580
|
return layoutmutationactions.has(kind);
|
|
494
581
|
}
|
|
582
|
+
function isformkind(kind) {
|
|
583
|
+
return formactions.has(kind);
|
|
584
|
+
}
|
|
585
|
+
function validatefieldmatch(value) {
|
|
586
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return { allowed: false, reason: "A reviewed field match is required in options." };
|
|
587
|
+
const match = value;
|
|
588
|
+
if (match.mode !== "label" && match.mode !== "placeholder" && match.mode !== "arialabel" && match.mode !== "name") return { allowed: false, reason: "The reviewed field match mode must be label, placeholder, arialabel or name." };
|
|
589
|
+
const key = match.mode === "label" ? "label" : match.mode === "placeholder" ? "placeholder" : match.mode === "arialabel" ? "arialabel" : "name";
|
|
590
|
+
if (!isnonempty(match[key])) return { allowed: false, reason: `The reviewed ${match.mode} field match needs a non-empty ${key}.` };
|
|
591
|
+
return { allowed: true };
|
|
592
|
+
}
|
|
593
|
+
function validateformrecord(value) {
|
|
594
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return { allowed: false, reason: "A reviewed form record with entries is required in options." };
|
|
595
|
+
const record2 = value;
|
|
596
|
+
if (record2.form !== void 0 && !isnonempty(record2.form)) return { allowed: false, reason: "The reviewed form record form selector must be a non-empty string." };
|
|
597
|
+
if (!Array.isArray(record2.entries) || record2.entries.length === 0) return { allowed: false, reason: "The reviewed form record needs a non-empty list of entries." };
|
|
598
|
+
for (const item of record2.entries) {
|
|
599
|
+
if (!item || typeof item !== "object" || Array.isArray(item)) return { allowed: false, reason: "Every reviewed form record entry must be an object." };
|
|
600
|
+
const entry = item;
|
|
601
|
+
const matchcheck = validatefieldmatch(entry.match);
|
|
602
|
+
if (!matchcheck.allowed) return matchcheck;
|
|
603
|
+
if (typeof entry.kind !== "string" || !fieldkinds.includes(entry.kind)) return { allowed: false, reason: "Every reviewed form record entry needs a known field kind." };
|
|
604
|
+
if (typeof entry.value !== "string") return { allowed: false, reason: "Every reviewed form record entry needs a string value." };
|
|
605
|
+
if (entry.kind === "password") return { allowed: false, reason: "Password entries are refused inside form records; use consentpassword with a reviewed consent ref." };
|
|
606
|
+
}
|
|
607
|
+
return { allowed: true };
|
|
608
|
+
}
|
|
609
|
+
function validatevaluegen(value) {
|
|
610
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return { allowed: false, reason: "A reviewed valuegen rule with a field kind is required in options." };
|
|
611
|
+
const rule = value;
|
|
612
|
+
if (typeof rule.kind !== "string" || !fieldkinds.includes(rule.kind)) return { allowed: false, reason: "The reviewed valuegen kind must be a known field kind." };
|
|
613
|
+
if (rule.locale !== void 0 && !isnonempty(rule.locale)) return { allowed: false, reason: "The reviewed valuegen locale must be a non-empty string." };
|
|
614
|
+
if (rule.seed !== void 0 && (typeof rule.seed !== "number" || !Number.isFinite(rule.seed))) return { allowed: false, reason: "The reviewed valuegen seed must be a finite number." };
|
|
615
|
+
return { allowed: true };
|
|
616
|
+
}
|
|
617
|
+
function validatefieldpairs(options, mode) {
|
|
618
|
+
const pairs = options.fields;
|
|
619
|
+
if (!Array.isArray(pairs) || pairs.length === 0) return { allowed: false, reason: "A reviewed non-empty list of field pairs is required in options." };
|
|
620
|
+
for (const item of pairs) {
|
|
621
|
+
if (!item || typeof item !== "object" || Array.isArray(item)) return { allowed: false, reason: "Every reviewed field pair must be an object." };
|
|
622
|
+
const pair = item;
|
|
623
|
+
if (!isnonempty(pair[mode])) return { allowed: false, reason: `Every reviewed field pair needs a non-empty ${mode}.` };
|
|
624
|
+
if (typeof pair.value !== "string" || !pair.value.trim()) return { allowed: false, reason: "Every reviewed field pair needs a non-empty value." };
|
|
625
|
+
}
|
|
626
|
+
return { allowed: true };
|
|
627
|
+
}
|
|
628
|
+
function validatecardsegments(value) {
|
|
629
|
+
if (!Array.isArray(value) || value.length === 0) return { allowed: false, reason: "A reviewed non-empty list of card segments is required in options." };
|
|
630
|
+
for (const item of value) {
|
|
631
|
+
if (!item || typeof item !== "object" || Array.isArray(item)) return { allowed: false, reason: "Every reviewed card segment must be an object." };
|
|
632
|
+
const segment = item;
|
|
633
|
+
const matchcheck = validatefieldmatch(segment.match);
|
|
634
|
+
if (!matchcheck.allowed) return matchcheck;
|
|
635
|
+
if (typeof segment.value !== "string" || !segment.value.trim()) return { allowed: false, reason: "Every reviewed card segment needs a non-empty value." };
|
|
636
|
+
}
|
|
637
|
+
return { allowed: true };
|
|
638
|
+
}
|
|
639
|
+
function validateformgrammar(step, options) {
|
|
640
|
+
const kind = step.kind;
|
|
641
|
+
if (kind === "fillform" || kind === "saveprofiles" && options.formrecord !== void 0) {
|
|
642
|
+
const recordcheck = validateformrecord(options.formrecord);
|
|
643
|
+
if (!recordcheck.allowed) return recordcheck;
|
|
644
|
+
}
|
|
645
|
+
if (kind === "filllabel" || kind === "fillplaceholder") {
|
|
646
|
+
const paircheck = validatefieldpairs(options, kind === "filllabel" ? "label" : "placeholder");
|
|
647
|
+
if (!paircheck.allowed) return paircheck;
|
|
648
|
+
}
|
|
649
|
+
if (kind === "generatevalues" && options.valuegen !== void 0) {
|
|
650
|
+
const rulecheck = validatevaluegen(options.valuegen);
|
|
651
|
+
if (!rulecheck.allowed) return rulecheck;
|
|
652
|
+
}
|
|
653
|
+
if (kind === "saveprofiles" && !isnonempty(options.name)) return { allowed: false, reason: "A reviewed profile name is required in options." };
|
|
654
|
+
if (kind === "submitform" && !isnonempty(options.consentref)) return { allowed: false, reason: "A reviewed consent ref of an approved asksubmit ticket is required in options." };
|
|
655
|
+
if (kind === "retryform") {
|
|
656
|
+
const backoff = options.backoff;
|
|
657
|
+
if (!backoff || typeof backoff !== "object" || Array.isArray(backoff)) return { allowed: false, reason: "A reviewed backoff rule with wait and factor is required in options." };
|
|
658
|
+
const rule = backoff;
|
|
659
|
+
if (typeof rule.wait !== "number" || !Number.isFinite(rule.wait) || rule.wait <= 0) return { allowed: false, reason: "The reviewed retry backoff wait must be a positive number of milliseconds with no code ceiling." };
|
|
660
|
+
if (typeof rule.factor !== "number" || !Number.isFinite(rule.factor) || rule.factor < 1) return { allowed: false, reason: "The reviewed retry backoff factor must be one or greater with no code ceiling." };
|
|
661
|
+
if (options.attempts !== void 0 && (typeof options.attempts !== "number" || !Number.isInteger(options.attempts) || options.attempts < 1)) return { allowed: false, reason: "The reviewed retry attempts must be a positive integer with no code ceiling." };
|
|
662
|
+
}
|
|
663
|
+
if (kind === "runwizard" && options.steps !== void 0 && (typeof options.steps !== "number" || !Number.isInteger(options.steps) || options.steps < 1)) return { allowed: false, reason: "The reviewed wizard step count must be a positive integer with no code ceiling." };
|
|
664
|
+
if (kind === "selectchain") {
|
|
665
|
+
if (!isnonempty(options.child)) return { allowed: false, reason: "A reviewed child selector of the dependent control is required in options." };
|
|
666
|
+
if (!nonnegativeoption(options, "wait")) return { allowed: false, reason: "The reviewed dependent wait must be zero or a positive number of milliseconds." };
|
|
667
|
+
}
|
|
668
|
+
if (kind === "picktypeahead") {
|
|
669
|
+
if (!isnonempty(options.pick)) return { allowed: false, reason: "A reviewed suggestion entry to pick is required in options." };
|
|
670
|
+
if (!nonnegativeoption(options, "timeout")) return { allowed: false, reason: "The reviewed typeahead timeout must be zero or a positive number of milliseconds." };
|
|
671
|
+
}
|
|
672
|
+
if (kind === "pickdate" && !/^\d{4}-\d{2}-\d{2}$/.test(step.value ?? "")) return { allowed: false, reason: "The reviewed date must use the yyyy-mm-dd form." };
|
|
673
|
+
if (kind === "fillcard") {
|
|
674
|
+
const segmentcheck = validatecardsegments(options.segments);
|
|
675
|
+
if (!segmentcheck.allowed) return segmentcheck;
|
|
676
|
+
if (!nonnegativeoption(options, "pause")) return { allowed: false, reason: "The reviewed card typing pause must be zero or a positive number of milliseconds." };
|
|
677
|
+
}
|
|
678
|
+
if (kind === "fillcode" && !isnonempty(options.source)) return { allowed: false, reason: "A reviewed one time code source is required in options." };
|
|
679
|
+
if (kind === "consentpassword" && !isnonempty(options.consentref)) return { allowed: false, reason: "A reviewed consent ref is required in options before any password is filled." };
|
|
680
|
+
return { allowed: true };
|
|
681
|
+
}
|
|
682
|
+
function submitreviewgranted(steps, submitid) {
|
|
683
|
+
const position = steps.findIndex((candidate) => candidate.id === submitid);
|
|
684
|
+
const asked = steps.some((candidate, index) => candidate.kind === "asksubmit" && (position === -1 || index < position));
|
|
685
|
+
return asked ? { allowed: true } : { allowed: false, reason: "Form submission requires an asksubmit review step before it." };
|
|
686
|
+
}
|
|
687
|
+
function passwordconsentgranted(step) {
|
|
688
|
+
let options = {};
|
|
689
|
+
try {
|
|
690
|
+
options = parseoptions(step);
|
|
691
|
+
} catch {
|
|
692
|
+
options = {};
|
|
693
|
+
}
|
|
694
|
+
const consentref = options.consentref;
|
|
695
|
+
if (typeof consentref !== "string" || !consentref.trim()) return { allowed: false, reason: "A password fill requires a reviewed consent ref in options." };
|
|
696
|
+
return { allowed: true };
|
|
697
|
+
}
|
|
698
|
+
function luhnvalid(digits) {
|
|
699
|
+
let sum = 0;
|
|
700
|
+
let double = false;
|
|
701
|
+
for (let index = digits.length - 1; index >= 0; index -= 1) {
|
|
702
|
+
let value = Number.parseInt(digits[index] ?? "", 10);
|
|
703
|
+
if (!Number.isFinite(value)) return false;
|
|
704
|
+
if (double) {
|
|
705
|
+
value *= 2;
|
|
706
|
+
if (value > 9) value -= 9;
|
|
707
|
+
}
|
|
708
|
+
sum += value;
|
|
709
|
+
double = !double;
|
|
710
|
+
}
|
|
711
|
+
return sum % 10 === 0;
|
|
712
|
+
}
|
|
713
|
+
function generatedvalueallowed(value) {
|
|
714
|
+
const compact = value.replace(/[\s-]/g, "");
|
|
715
|
+
if (/^\d{13,19}$/.test(compact) && luhnvalid(compact) && !compact.startsWith("4111")) return { allowed: false, reason: "The generated value looks like a real card number and is refused; generated card values use the 4111 test prefix." };
|
|
716
|
+
if (/^\d{3}-\d{2}-\d{4}$/.test(value.trim())) return { allowed: false, reason: "The generated value looks like a personal identifier and is refused." };
|
|
717
|
+
return { allowed: true };
|
|
718
|
+
}
|
|
719
|
+
function profilegrantgranted(profile, origin) {
|
|
720
|
+
if (!profile.grants.includes(origin)) return { allowed: false, reason: `The saved profile ${profile.name} is not granted to ${origin}; add the origin to the profile grants first.` };
|
|
721
|
+
return { allowed: true };
|
|
722
|
+
}
|
|
495
723
|
function layoutmutationgranted(session, now) {
|
|
496
724
|
if (!session || session.stoppedat || session.expiresat <= now) return { allowed: false, reason: "Group and layout mutations stay inside the active session." };
|
|
497
725
|
return { allowed: true };
|
|
@@ -965,6 +1193,10 @@ function validatestep(step, origin) {
|
|
|
965
1193
|
const tabscheck = validatetabsgrammar(step, options);
|
|
966
1194
|
if (!tabscheck.allowed) return tabscheck;
|
|
967
1195
|
}
|
|
1196
|
+
if (isformkind(step.kind)) {
|
|
1197
|
+
const formcheck = validateformgrammar(step, options);
|
|
1198
|
+
if (!formcheck.allowed) return formcheck;
|
|
1199
|
+
}
|
|
968
1200
|
if (step.kind === "tabcreate") {
|
|
969
1201
|
if (options.background !== void 0 && typeof options.background !== "boolean") return { allowed: false, reason: "The reviewed background flag must be a boolean." };
|
|
970
1202
|
if (options.window !== void 0 && (typeof options.window !== "number" || !Number.isInteger(options.window) || options.window < 0)) return { allowed: false, reason: "The reviewed target window id must be a non-negative integer." };
|
|
@@ -1006,6 +1238,15 @@ function canexecute(input) {
|
|
|
1006
1238
|
}
|
|
1007
1239
|
}
|
|
1008
1240
|
if (islayoutkind(input.step.kind) && !layoutmutationgranted(input.session, now).allowed) return { allowed: false, reason: "Group and layout mutations stay inside the active session." };
|
|
1241
|
+
if (input.step.kind === "submitform" || input.step.kind === "retryform") {
|
|
1242
|
+
if (!input.plan) return { allowed: false, reason: "Form submission requires an asksubmit review step before it." };
|
|
1243
|
+
const reviewgate = submitreviewgranted(input.plan.steps, input.step.id);
|
|
1244
|
+
if (!reviewgate.allowed) return reviewgate;
|
|
1245
|
+
}
|
|
1246
|
+
if (input.step.kind === "consentpassword") {
|
|
1247
|
+
const consentgate = passwordconsentgranted(input.step);
|
|
1248
|
+
if (!consentgate.allowed) return consentgate;
|
|
1249
|
+
}
|
|
1009
1250
|
if (input.step.kind === "openlink" || input.step.kind === "openprivate" || input.step.kind === "batchopen" || input.step.kind === "prefetch" || input.step.kind === "deeplink" || input.step.kind === "reopentab") {
|
|
1010
1251
|
let options = {};
|
|
1011
1252
|
try {
|
|
@@ -1027,7 +1268,7 @@ function canexecute(input) {
|
|
|
1027
1268
|
}
|
|
1028
1269
|
|
|
1029
1270
|
// version.ts
|
|
1030
|
-
var packageversion = "1.1.
|
|
1271
|
+
var packageversion = "1.1.37";
|
|
1031
1272
|
|
|
1032
1273
|
// types.ts
|
|
1033
1274
|
var protocolversion = packageversion;
|
|
@@ -1068,6 +1309,11 @@ function parseproposal(value, origin) {
|
|
|
1068
1309
|
const options = parseoptions(step);
|
|
1069
1310
|
if (typeof options.stepid === "string" && !steps.some((candidate) => candidate.id === options.stepid)) throw new Error("A retry or frame wrapper references an unknown step id.");
|
|
1070
1311
|
}
|
|
1312
|
+
for (const step of steps) {
|
|
1313
|
+
if (step.kind !== "submitform" && step.kind !== "retryform") continue;
|
|
1314
|
+
const review = submitreviewgranted(steps, step.id);
|
|
1315
|
+
if (!review.allowed) throw new Error(review.reason);
|
|
1316
|
+
}
|
|
1071
1317
|
const createdat = Date.now();
|
|
1072
1318
|
const expiresat = typeof planinput.expiresat === "number" ? planinput.expiresat : createdat + 10 * 60 * 1e3;
|
|
1073
1319
|
const plan = {
|
|
@@ -1131,13 +1377,26 @@ function tabreportresponse(input) {
|
|
|
1131
1377
|
function layoutreport(input) {
|
|
1132
1378
|
return { version: protocolversion, layouts: input.layouts };
|
|
1133
1379
|
}
|
|
1380
|
+
function formreportresponse(input) {
|
|
1381
|
+
return JSON.stringify({ version: protocolversion, planid: input.plan.id, planstate: input.plan.state, report: input.report });
|
|
1382
|
+
}
|
|
1383
|
+
function errorreportresponse(input) {
|
|
1384
|
+
return JSON.stringify({ version: protocolversion, planid: input.plan.id, planstate: input.plan.state, report: input.report });
|
|
1385
|
+
}
|
|
1386
|
+
function wizardreport(input) {
|
|
1387
|
+
return { version: protocolversion, ...input.sessionid ? { sessionid: input.sessionid } : {}, wizards: input.wizards, picks: input.picks };
|
|
1388
|
+
}
|
|
1134
1389
|
export {
|
|
1135
1390
|
canexecute,
|
|
1136
1391
|
actionrisk as deriveactionrisk,
|
|
1137
1392
|
diffresponse,
|
|
1393
|
+
errorreportresponse,
|
|
1138
1394
|
eventresponse,
|
|
1395
|
+
formreportresponse,
|
|
1396
|
+
generatedvalueallowed,
|
|
1139
1397
|
heldkeysreport,
|
|
1140
1398
|
hostpattern,
|
|
1399
|
+
isformkind,
|
|
1141
1400
|
iswatchkind,
|
|
1142
1401
|
layoutreport,
|
|
1143
1402
|
mapresponse,
|
|
@@ -1147,6 +1406,8 @@ export {
|
|
|
1147
1406
|
observationresponse,
|
|
1148
1407
|
outcomeresponse,
|
|
1149
1408
|
parseproposal,
|
|
1409
|
+
passwordconsentgranted,
|
|
1410
|
+
profilegrantgranted,
|
|
1150
1411
|
protocolversion,
|
|
1151
1412
|
randomid,
|
|
1152
1413
|
requestbody,
|
|
@@ -1155,9 +1416,14 @@ export {
|
|
|
1155
1416
|
selectorresponse,
|
|
1156
1417
|
sessionmemory,
|
|
1157
1418
|
signalsreport,
|
|
1419
|
+
submitreviewgranted,
|
|
1158
1420
|
tabreportresponse,
|
|
1159
1421
|
trailreport,
|
|
1422
|
+
validatefieldmatch,
|
|
1423
|
+
validateformrecord,
|
|
1160
1424
|
validatestep,
|
|
1161
|
-
validatetargetref
|
|
1425
|
+
validatetargetref,
|
|
1426
|
+
validatevaluegen,
|
|
1427
|
+
wizardreport
|
|
1162
1428
|
};
|
|
1163
1429
|
//# sourceMappingURL=index.js.map
|