@wenathlan/extension 1.1.37 → 1.1.38
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.js +227 -7
- package/dist/index.js.map +2 -2
- package/dist/memory.d.ts +35 -1
- package/dist/memory.d.ts.map +1 -1
- package/dist/policy.d.ts +8 -0
- package/dist/policy.d.ts.map +1 -1
- package/dist/protocol.d.ts +25 -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 +784 -9
- package/extension/dist/background.js.map +4 -4
- package/extension/dist/manifest.json +1 -1
- package/extension/dist/pagebridge.js +187 -2
- package/extension/dist/pagebridge.js.map +4 -4
- package/extension/dist/popup.html +1 -1
- package/extension/dist/popup.js +12 -2
- package/extension/dist/popup.js.map +2 -2
- package/extension/dist/sidepanel.html +1 -1
- package/extension/dist/sidepanel.js +173 -2
- package/extension/dist/sidepanel.js.map +4 -4
- package/extension/manifest.json +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,18 +2,19 @@
|
|
|
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.38**. 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.38 |
|
|
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 two hundred
|
|
15
|
+
| Browser tools | Reviewed plans cover two hundred eighteen 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
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. |
|
|
17
|
+
| Datasets and exports | The agent turns pages into data with audit: `scrapetable` reads tables into normalized column keys with rowspan and colspan expansion and nested child datasets, `paginateextract` follows next controls while waiting for fresh rows, `mergepages` aligns columns across pages, `transformvalues` applies reviewed expressions with per rule error surfacing, `deduperows` deduplicates by reviewed keys, `stamplerows` stamps every row with its source url, timestamp and step ref, `previewgrid` previews the grid before export, `importcsv` parses quoted csv with column mappings for fill loops, `looprows` interpolates `{{column}}` row variables into the wrapped inner step, `exportcsv`, `exportjson` and `exportexcel` write checksummed artifacts into the task artifact store with provenance records, `copytable` uses the clipboard under the optional clipboardWrite capability, `pushsheets` pushes only to a reviewed HTTPS endpoint behind its origin grant and the explicit reviewed flag, `streamdisk` streams chunk by chunk with backpressure and a persisted resume state, `resumeextract` continues an interrupted extraction from its stored cursor, and `logprovenance` logs provenance for audit; exports refuse to leave local memory while the session origin grants do not cover the active origin. |
|
|
17
18
|
| 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. |
|
|
18
19
|
| 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. |
|
|
19
20
|
| 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. |
|
|
@@ -51,7 +52,7 @@ The endpoint field intentionally has no default URL. Enter a URL such as `https:
|
|
|
51
52
|
|
|
52
53
|
```json
|
|
53
54
|
{
|
|
54
|
-
"version": "1.1.
|
|
55
|
+
"version": "1.1.38",
|
|
55
56
|
"objective": "User supplied objective",
|
|
56
57
|
"session": { "id": "uuid", "tabid": 1, "origin": "https://example.com" },
|
|
57
58
|
"observation": { "schemaversion": 3, "url": "https://example.com/path", "interactive": [] },
|
package/dist/index.js
CHANGED
|
@@ -520,21 +520,122 @@ var sessionmemory = class {
|
|
|
520
520
|
async getcodevalue() {
|
|
521
521
|
return this.adapter.get("codevalue");
|
|
522
522
|
}
|
|
523
|
+
/** Stores one dataset with its column specs and rows, replacing the previous record of that id. */
|
|
524
|
+
async setdataset(value) {
|
|
525
|
+
await this.adapter.set(`dataset${value.id}`, value);
|
|
526
|
+
const ids = (await this.adapter.get("datasets") ?? []).filter((id) => id !== value.id);
|
|
527
|
+
await this.adapter.set("datasets", [value.id, ...ids]);
|
|
528
|
+
}
|
|
529
|
+
/** Returns one stored dataset by its id with its column specs and row count. */
|
|
530
|
+
async getdataset(id) {
|
|
531
|
+
return this.adapter.get(`dataset${id}`);
|
|
532
|
+
}
|
|
533
|
+
/** Returns every stored dataset id, newest first. */
|
|
534
|
+
async getdatasets() {
|
|
535
|
+
const ids = await this.adapter.get("datasets") ?? [];
|
|
536
|
+
const records = [];
|
|
537
|
+
for (const id of ids) {
|
|
538
|
+
const record2 = await this.adapter.get(`dataset${id}`);
|
|
539
|
+
if (record2) records.push(record2);
|
|
540
|
+
}
|
|
541
|
+
return records;
|
|
542
|
+
}
|
|
543
|
+
/** Stores one imported csv dataset for fill loops beside the dataset store. */
|
|
544
|
+
async addimport(value) {
|
|
545
|
+
await this.setdataset(value);
|
|
546
|
+
const ids = (await this.adapter.get("imports") ?? []).filter((id) => id !== value.id);
|
|
547
|
+
await this.adapter.set("imports", [value.id, ...ids]);
|
|
548
|
+
}
|
|
549
|
+
/** Returns every imported csv dataset for fill loops, newest first. */
|
|
550
|
+
async getimports() {
|
|
551
|
+
const ids = await this.adapter.get("imports") ?? [];
|
|
552
|
+
const records = [];
|
|
553
|
+
for (const id of ids) {
|
|
554
|
+
const record2 = await this.adapter.get(`dataset${id}`);
|
|
555
|
+
if (record2) records.push(record2);
|
|
556
|
+
}
|
|
557
|
+
return records;
|
|
558
|
+
}
|
|
559
|
+
/** Stores one extraction session with its cursor and page history, replacing the previous session of that id. */
|
|
560
|
+
async setextractsession(value) {
|
|
561
|
+
await this.adapter.set(`extract${value.id}`, value);
|
|
562
|
+
const ids = (await this.adapter.get("extracts") ?? []).filter((id) => id !== value.id);
|
|
563
|
+
await this.adapter.set("extracts", [value.id, ...ids]);
|
|
564
|
+
}
|
|
565
|
+
/** Returns every extraction session with its cursor and page history, newest first. */
|
|
566
|
+
async getextractsessions() {
|
|
567
|
+
const ids = await this.adapter.get("extracts") ?? [];
|
|
568
|
+
const records = [];
|
|
569
|
+
for (const id of ids) {
|
|
570
|
+
const record2 = await this.adapter.get(`extract${id}`);
|
|
571
|
+
if (record2) records.push(record2);
|
|
572
|
+
}
|
|
573
|
+
return records;
|
|
574
|
+
}
|
|
575
|
+
/** Records one provenance record of an exported artifact. */
|
|
576
|
+
async addprovenance(record2) {
|
|
577
|
+
const records = await this.getprovenances();
|
|
578
|
+
await this.adapter.set("provenances", [record2, ...records]);
|
|
579
|
+
}
|
|
580
|
+
/** Returns every provenance record per exported artifact, newest first. */
|
|
581
|
+
async getprovenances() {
|
|
582
|
+
return await this.adapter.get("provenances") ?? [];
|
|
583
|
+
}
|
|
584
|
+
/** Stores the transform rules and dedupe keys of one task, replacing the previous record of that task. */
|
|
585
|
+
async settaskrules(value) {
|
|
586
|
+
const records = (await this.adapter.get("taskrules") ?? []).filter((item) => item.taskid !== value.taskid);
|
|
587
|
+
await this.adapter.set("taskrules", [value, ...records]);
|
|
588
|
+
}
|
|
589
|
+
/** Returns the transform rules and dedupe keys per task, newest first. */
|
|
590
|
+
async gettaskrules() {
|
|
591
|
+
return await this.adapter.get("taskrules") ?? [];
|
|
592
|
+
}
|
|
593
|
+
/** Stores one stream chunk state for resume, replacing the previous state of that dataset. */
|
|
594
|
+
async setstream(state) {
|
|
595
|
+
const records = (await this.adapter.get("streams") ?? []).filter((item) => item.datasetid !== state.datasetid);
|
|
596
|
+
await this.adapter.set("streams", [state, ...records]);
|
|
597
|
+
}
|
|
598
|
+
/** Returns every stream chunk state persisted for resume, newest first. */
|
|
599
|
+
async getstreams() {
|
|
600
|
+
return await this.adapter.get("streams") ?? [];
|
|
601
|
+
}
|
|
602
|
+
/** Stores one reviewed sheet endpoint config behind its origin grant, replacing the previous config of that origin. */
|
|
603
|
+
async setsheetendpoint(config) {
|
|
604
|
+
const records = (await this.adapter.get("sheetendpoints") ?? []).filter((item) => item.origin !== config.origin);
|
|
605
|
+
await this.adapter.set("sheetendpoints", [config, ...records]);
|
|
606
|
+
}
|
|
607
|
+
/** Returns every reviewed sheet endpoint config, newest first. */
|
|
608
|
+
async getsheetendpoints() {
|
|
609
|
+
return await this.adapter.get("sheetendpoints") ?? [];
|
|
610
|
+
}
|
|
611
|
+
/** Records one exported data artifact; artifact retention is a user setting and an absent setting keeps every artifact. */
|
|
612
|
+
async addexport(artifact) {
|
|
613
|
+
const records = await this.getexports();
|
|
614
|
+
const combined = [artifact, ...records.filter((item) => item.id !== artifact.id)];
|
|
615
|
+
const retention = (await this.getsettings())?.artifactretention;
|
|
616
|
+
await this.adapter.set("exports", retention === void 0 ? combined : combined.slice(0, retention));
|
|
617
|
+
}
|
|
618
|
+
/** Returns every exported data artifact with its content and checksum, newest first. */
|
|
619
|
+
async getexports() {
|
|
620
|
+
return await this.adapter.get("exports") ?? [];
|
|
621
|
+
}
|
|
523
622
|
};
|
|
524
623
|
function randomid() {
|
|
525
624
|
return crypto.randomUUID();
|
|
526
625
|
}
|
|
527
626
|
|
|
528
627
|
// policy.ts
|
|
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"]);
|
|
628
|
+
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", "exportcsv", "exportjson", "exportexcel", "copytable", "pushsheets", "streamdisk", "paginateextract", "resumeextract"]);
|
|
530
629
|
var interactionactions = /* @__PURE__ */ new Set(["focus", "scroll", "hover", "clickdeep", "rightclick", "doubleclick", "scrollpage", "scrollby", "scrollend", "scrolltop", "fullscreen", "zoomset", "movepointer", "clicktext", "clickaria", "clickname", "expanddetails", "pierceshadow", "retryaction"]);
|
|
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"]);
|
|
630
|
+
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", "scrapetable", "importcsv", "looprows", "transformvalues", "deduperows", "mergepages", "stamplerows", "previewgrid", "logprovenance"]);
|
|
532
631
|
var allowedactions = /* @__PURE__ */ new Set([...sensitiveactions, ...interactionactions, ...readactions]);
|
|
533
632
|
var watchactions = /* @__PURE__ */ new Set(["watchmutate", "watchbanner", "watchfocus", "watchtab"]);
|
|
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"]);
|
|
633
|
+
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", "scrapetable", "paginateextract"]);
|
|
535
634
|
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"]);
|
|
536
635
|
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
636
|
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"]);
|
|
637
|
+
var datasetactions = /* @__PURE__ */ new Set(["scrapetable", "exportcsv", "exportjson", "exportexcel", "copytable", "pushsheets", "importcsv", "looprows", "transformvalues", "deduperows", "paginateextract", "mergepages", "stamplerows", "previewgrid", "streamdisk", "resumeextract", "logprovenance"]);
|
|
638
|
+
var exportactions = /* @__PURE__ */ new Set(["exportcsv", "exportjson", "exportexcel", "copytable", "pushsheets", "streamdisk"]);
|
|
538
639
|
var fieldkinds = ["text", "email", "phone", "date", "number", "select", "check", "radio", "file", "password", "card", "code"];
|
|
539
640
|
var layoutmutationactions = /* @__PURE__ */ new Set(["grouptabs", "colorgroup", "collapsegroup", "savelayout", "restorelayout"]);
|
|
540
641
|
var groupcolors = ["grey", "blue", "red", "yellow", "green", "pink", "purple", "cyan", "orange"];
|
|
@@ -582,6 +683,16 @@ function islayoutkind(kind) {
|
|
|
582
683
|
function isformkind(kind) {
|
|
583
684
|
return formactions.has(kind);
|
|
584
685
|
}
|
|
686
|
+
function isdatasetkind(kind) {
|
|
687
|
+
return datasetactions.has(kind);
|
|
688
|
+
}
|
|
689
|
+
function isexportkind(kind) {
|
|
690
|
+
return exportactions.has(kind);
|
|
691
|
+
}
|
|
692
|
+
function exportgranted(session, origin) {
|
|
693
|
+
if (!origingranted(session, origin)) return { allowed: false, reason: `The export of extracted data from ${origin} needs the session origin grants before it leaves local memory.` };
|
|
694
|
+
return { allowed: true };
|
|
695
|
+
}
|
|
585
696
|
function validatefieldmatch(value) {
|
|
586
697
|
if (!value || typeof value !== "object" || Array.isArray(value)) return { allowed: false, reason: "A reviewed field match is required in options." };
|
|
587
698
|
const match = value;
|
|
@@ -679,6 +790,89 @@ function validateformgrammar(step, options) {
|
|
|
679
790
|
if (kind === "consentpassword" && !isnonempty(options.consentref)) return { allowed: false, reason: "A reviewed consent ref is required in options before any password is filled." };
|
|
680
791
|
return { allowed: true };
|
|
681
792
|
}
|
|
793
|
+
function validatetransformrule(value) {
|
|
794
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return { allowed: false, reason: "A reviewed transform rule with an expression, sources and a target is required in options." };
|
|
795
|
+
const rule = value;
|
|
796
|
+
const expression = rule.expression;
|
|
797
|
+
if (typeof expression !== "string" || !/^(trim|upper|lower|number|prefix|suffix|replace)(?::.+)?$/.test(expression)) return { allowed: false, reason: "The reviewed transform expression must be trim, upper, lower, number, prefix, suffix or replace with an optional argument." };
|
|
798
|
+
if (expression.startsWith("replace") && !expression.slice("replace".length).includes("=>")) return { allowed: false, reason: "The reviewed replace expression needs the from=>to separator." };
|
|
799
|
+
if (expression.startsWith("replace") && expression.slice("replace:".length).split("=>")[0] === "") return { allowed: false, reason: "The reviewed replace expression needs a non-empty from part." };
|
|
800
|
+
if (!Array.isArray(rule.sources) || rule.sources.length === 0 || !rule.sources.every((source) => isnonempty(source))) return { allowed: false, reason: "Every reviewed transform rule needs a non-empty list of source columns." };
|
|
801
|
+
if (!isnonempty(rule.target)) return { allowed: false, reason: "Every reviewed transform rule needs a non-empty target column." };
|
|
802
|
+
return { allowed: true };
|
|
803
|
+
}
|
|
804
|
+
function validatedatasetids(options, key) {
|
|
805
|
+
const ids = options[key];
|
|
806
|
+
if (!Array.isArray(ids) || ids.length === 0 || !ids.every((id) => isnonempty(id))) return { allowed: false, reason: `A reviewed non-empty list of dataset ids is required in options as ${key}.` };
|
|
807
|
+
return { allowed: true };
|
|
808
|
+
}
|
|
809
|
+
function validatedatagrammar(step, options, origin) {
|
|
810
|
+
const kind = step.kind;
|
|
811
|
+
if (kind === "scrapetable") {
|
|
812
|
+
if (options.name !== void 0 && !isnonempty(options.name)) return { allowed: false, reason: "The reviewed dataset name must be a non-empty string." };
|
|
813
|
+
if (options.rowlimit !== void 0 && (typeof options.rowlimit !== "number" || !Number.isInteger(options.rowlimit) || options.rowlimit < 1)) return { allowed: false, reason: "The reviewed row limit must be a positive integer with no code ceiling." };
|
|
814
|
+
}
|
|
815
|
+
if (kind === "paginateextract") {
|
|
816
|
+
if (!isnonempty(options.next)) return { allowed: false, reason: "A reviewed next control selector is required in options." };
|
|
817
|
+
if (options.pages !== void 0 && (typeof options.pages !== "number" || !Number.isInteger(options.pages) || options.pages < 1)) return { allowed: false, reason: "The reviewed page count must be a positive integer with no code ceiling." };
|
|
818
|
+
if (!nonnegativeoption(options, "wait")) return { allowed: false, reason: "The reviewed row freshness wait must be zero or a positive number of milliseconds." };
|
|
819
|
+
}
|
|
820
|
+
if (kind === "exportcsv" || kind === "exportjson" || kind === "exportexcel" || kind === "copytable" || kind === "streamdisk") {
|
|
821
|
+
if (!isnonempty(options.dataset)) return { allowed: false, reason: "A reviewed dataset id is required in options." };
|
|
822
|
+
if (options.name !== void 0 && !isnonempty(options.name)) return { allowed: false, reason: "The reviewed artifact name must be a non-empty string." };
|
|
823
|
+
}
|
|
824
|
+
if (kind === "exportcsv" && options.delimiter !== void 0 && (typeof options.delimiter !== "string" || options.delimiter.length !== 1)) return { allowed: false, reason: "The reviewed csv delimiter must be a single character." };
|
|
825
|
+
if (kind === "streamdisk" && (typeof options.chunk !== "number" || !Number.isInteger(options.chunk) || options.chunk < 1)) return { allowed: false, reason: "The reviewed streaming chunk size must be a positive integer with no code ceiling." };
|
|
826
|
+
if (kind === "pushsheets") {
|
|
827
|
+
if (!isnonempty(options.dataset)) return { allowed: false, reason: "A reviewed dataset id is required in options." };
|
|
828
|
+
if (!isnonempty(options.sheet)) return { allowed: false, reason: "A reviewed sheet endpoint url is required in options." };
|
|
829
|
+
if (!ishttpsurl(options.sheet)) return { allowed: false, reason: "The reviewed sheet endpoint url must use HTTPS." };
|
|
830
|
+
if (options.reviewed !== true) return { allowed: false, reason: "The sheet push needs the explicit reviewed flag before any data leaves local memory." };
|
|
831
|
+
}
|
|
832
|
+
if (kind === "importcsv") {
|
|
833
|
+
if (typeof options.csv !== "string" || !options.csv.trim()) return { allowed: false, reason: "Reviewed csv content is required in options." };
|
|
834
|
+
if (options.name !== void 0 && !isnonempty(options.name)) return { allowed: false, reason: "The reviewed dataset name must be a non-empty string." };
|
|
835
|
+
if (options.mapping !== void 0) {
|
|
836
|
+
const mapping = options.mapping;
|
|
837
|
+
if (!mapping || typeof mapping !== "object" || Array.isArray(mapping) || !Object.values(mapping).every((item) => typeof item === "string")) return { allowed: false, reason: "The reviewed csv column mapping must be an object of string values." };
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
if (kind === "looprows") {
|
|
841
|
+
if (!isnonempty(options.dataset)) return { allowed: false, reason: "A reviewed dataset id is required in options." };
|
|
842
|
+
if (options.variable !== void 0 && !isnonempty(options.variable)) return { allowed: false, reason: "The reviewed row variable name must be a non-empty string." };
|
|
843
|
+
const inner = validateinnerstep(options, origin);
|
|
844
|
+
if (!inner.allowed) return inner;
|
|
845
|
+
}
|
|
846
|
+
if (kind === "transformvalues") {
|
|
847
|
+
if (!isnonempty(options.dataset)) return { allowed: false, reason: "A reviewed dataset id is required in options." };
|
|
848
|
+
const rules = options.rules;
|
|
849
|
+
if (!Array.isArray(rules) || rules.length === 0) return { allowed: false, reason: "A reviewed non-empty list of transform rules is required in options." };
|
|
850
|
+
for (const item of rules) {
|
|
851
|
+
const rulecheck = validatetransformrule(item);
|
|
852
|
+
if (!rulecheck.allowed) return rulecheck;
|
|
853
|
+
}
|
|
854
|
+
}
|
|
855
|
+
if (kind === "deduperows") {
|
|
856
|
+
if (!isnonempty(options.dataset)) return { allowed: false, reason: "A reviewed dataset id is required in options." };
|
|
857
|
+
const keys = options.keys;
|
|
858
|
+
if (!Array.isArray(keys) || keys.length === 0 || !keys.every((key) => isnonempty(key))) return { allowed: false, reason: "A reviewed non-empty list of dedupe column keys is required in options." };
|
|
859
|
+
}
|
|
860
|
+
if (kind === "mergepages") {
|
|
861
|
+
const listcheck = validatedatasetids(options, "datasets");
|
|
862
|
+
if (!listcheck.allowed) return listcheck;
|
|
863
|
+
}
|
|
864
|
+
if (kind === "stamplerows") {
|
|
865
|
+
if (!isnonempty(options.dataset)) return { allowed: false, reason: "A reviewed dataset id is required in options." };
|
|
866
|
+
if (options.url !== void 0 && !ishttpsurl(options.url)) return { allowed: false, reason: "The reviewed source url must use HTTPS." };
|
|
867
|
+
}
|
|
868
|
+
if (kind === "previewgrid") {
|
|
869
|
+
if (!isnonempty(options.dataset)) return { allowed: false, reason: "A reviewed dataset id is required in options." };
|
|
870
|
+
if (options.sample !== void 0 && (typeof options.sample !== "number" || !Number.isInteger(options.sample) || options.sample < 1)) return { allowed: false, reason: "The reviewed sample row count must be a positive integer with no code ceiling." };
|
|
871
|
+
}
|
|
872
|
+
if (kind === "resumeextract" && !isnonempty(options.session)) return { allowed: false, reason: "A reviewed extract session id is required in options." };
|
|
873
|
+
if (kind === "logprovenance" && !isnonempty(options.artifact)) return { allowed: false, reason: "A reviewed artifact id or name is required in options." };
|
|
874
|
+
return { allowed: true };
|
|
875
|
+
}
|
|
682
876
|
function submitreviewgranted(steps, submitid) {
|
|
683
877
|
const position = steps.findIndex((candidate) => candidate.id === submitid);
|
|
684
878
|
const asked = steps.some((candidate, index) => candidate.kind === "asksubmit" && (position === -1 || index < position));
|
|
@@ -813,7 +1007,7 @@ function validateinnerstep(options, origin) {
|
|
|
813
1007
|
return { allowed: true };
|
|
814
1008
|
}
|
|
815
1009
|
if (typeof kind !== "string" || !kind.trim()) return { allowed: false, reason: "A reviewed step id or inline step kind is required in options." };
|
|
816
|
-
if (kind === "retryaction" || kind === "enterframe") return { allowed: false, reason: "The reviewed inner step cannot be another wrapper kind." };
|
|
1010
|
+
if (kind === "retryaction" || kind === "enterframe" || kind === "looprows") return { allowed: false, reason: "The reviewed inner step cannot be another wrapper kind." };
|
|
817
1011
|
if (!allowedactions.has(kind)) return { allowed: false, reason: "The reviewed inner step kind is unsupported." };
|
|
818
1012
|
const inneroptions = options.options;
|
|
819
1013
|
if (inneroptions !== void 0 && (!inneroptions || typeof inneroptions !== "object" || Array.isArray(inneroptions))) return { allowed: false, reason: "The reviewed inner step options must be an object." };
|
|
@@ -1197,6 +1391,10 @@ function validatestep(step, origin) {
|
|
|
1197
1391
|
const formcheck = validateformgrammar(step, options);
|
|
1198
1392
|
if (!formcheck.allowed) return formcheck;
|
|
1199
1393
|
}
|
|
1394
|
+
if (isdatasetkind(step.kind)) {
|
|
1395
|
+
const datacheck = validatedatagrammar(step, options, origin);
|
|
1396
|
+
if (!datacheck.allowed) return datacheck;
|
|
1397
|
+
}
|
|
1200
1398
|
if (step.kind === "tabcreate") {
|
|
1201
1399
|
if (options.background !== void 0 && typeof options.background !== "boolean") return { allowed: false, reason: "The reviewed background flag must be a boolean." };
|
|
1202
1400
|
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." };
|
|
@@ -1224,6 +1422,10 @@ function canexecute(input) {
|
|
|
1224
1422
|
if (input.plan.expiresat <= now) return { allowed: false, reason: "The approved plan has expired." };
|
|
1225
1423
|
if ((input.step.kind === "pierceshadow" || input.step.kind === "enterframe") && !origingranted(input.session, input.origin)) return { allowed: false, reason: "The shadow or frame step is outside the session origin grants." };
|
|
1226
1424
|
if (input.step.kind === "readjson" && !origingranted(input.session, input.origin)) return { allowed: false, reason: "The json state read is outside the session origin grants." };
|
|
1425
|
+
if (isexportkind(input.step.kind)) {
|
|
1426
|
+
const exportgate = exportgranted(input.session, input.origin);
|
|
1427
|
+
if (!exportgate.allowed) return exportgate;
|
|
1428
|
+
}
|
|
1227
1429
|
if (input.step.kind === "navlist") {
|
|
1228
1430
|
let options = {};
|
|
1229
1431
|
try {
|
|
@@ -1268,7 +1470,7 @@ function canexecute(input) {
|
|
|
1268
1470
|
}
|
|
1269
1471
|
|
|
1270
1472
|
// version.ts
|
|
1271
|
-
var packageversion = "1.1.
|
|
1473
|
+
var packageversion = "1.1.38";
|
|
1272
1474
|
|
|
1273
1475
|
// types.ts
|
|
1274
1476
|
var protocolversion = packageversion;
|
|
@@ -1305,9 +1507,9 @@ function parseproposal(value, origin) {
|
|
|
1305
1507
|
return step;
|
|
1306
1508
|
});
|
|
1307
1509
|
for (const step of steps) {
|
|
1308
|
-
if (step.kind !== "retryaction" && step.kind !== "enterframe") continue;
|
|
1510
|
+
if (step.kind !== "retryaction" && step.kind !== "enterframe" && step.kind !== "looprows") continue;
|
|
1309
1511
|
const options = parseoptions(step);
|
|
1310
|
-
if (typeof options.stepid === "string" && !steps.some((candidate) => candidate.id === options.stepid)) throw new Error("A retry or
|
|
1512
|
+
if (typeof options.stepid === "string" && !steps.some((candidate) => candidate.id === options.stepid)) throw new Error("A retry, frame or loop wrapper references an unknown step id.");
|
|
1311
1513
|
}
|
|
1312
1514
|
for (const step of steps) {
|
|
1313
1515
|
if (step.kind !== "submitform" && step.kind !== "retryform") continue;
|
|
@@ -1386,12 +1588,28 @@ function errorreportresponse(input) {
|
|
|
1386
1588
|
function wizardreport(input) {
|
|
1387
1589
|
return { version: protocolversion, ...input.sessionid ? { sessionid: input.sessionid } : {}, wizards: input.wizards, picks: input.picks };
|
|
1388
1590
|
}
|
|
1591
|
+
function datasetresponse(input) {
|
|
1592
|
+
const sample = Math.max(0, Math.floor(input.sample ?? 10));
|
|
1593
|
+
const payload = { ...input.dataset, rows: input.dataset.rows.slice(0, sample), totalrows: input.dataset.rows.length };
|
|
1594
|
+
return JSON.stringify({ version: protocolversion, planid: input.plan.id, planstate: input.plan.state, dataset: payload });
|
|
1595
|
+
}
|
|
1596
|
+
function extractionreport(input) {
|
|
1597
|
+
return { version: protocolversion, sessions: input.sessions };
|
|
1598
|
+
}
|
|
1599
|
+
function provenancereport(input) {
|
|
1600
|
+
return { version: protocolversion, records: input.records };
|
|
1601
|
+
}
|
|
1602
|
+
function transformgrammar(rules) {
|
|
1603
|
+
return JSON.stringify({ rules: rules.map((rule) => ({ expression: rule.expression, sources: rule.sources, target: rule.target })) });
|
|
1604
|
+
}
|
|
1389
1605
|
export {
|
|
1390
1606
|
canexecute,
|
|
1607
|
+
datasetresponse,
|
|
1391
1608
|
actionrisk as deriveactionrisk,
|
|
1392
1609
|
diffresponse,
|
|
1393
1610
|
errorreportresponse,
|
|
1394
1611
|
eventresponse,
|
|
1612
|
+
extractionreport,
|
|
1395
1613
|
formreportresponse,
|
|
1396
1614
|
generatedvalueallowed,
|
|
1397
1615
|
heldkeysreport,
|
|
@@ -1409,6 +1627,7 @@ export {
|
|
|
1409
1627
|
passwordconsentgranted,
|
|
1410
1628
|
profilegrantgranted,
|
|
1411
1629
|
protocolversion,
|
|
1630
|
+
provenancereport,
|
|
1412
1631
|
randomid,
|
|
1413
1632
|
requestbody,
|
|
1414
1633
|
resolutionverdict,
|
|
@@ -1419,6 +1638,7 @@ export {
|
|
|
1419
1638
|
submitreviewgranted,
|
|
1420
1639
|
tabreportresponse,
|
|
1421
1640
|
trailreport,
|
|
1641
|
+
transformgrammar,
|
|
1422
1642
|
validatefieldmatch,
|
|
1423
1643
|
validateformrecord,
|
|
1424
1644
|
validatestep,
|