@extension.dev/mcp 7.0.0 → 9.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/CHANGELOG.md +224 -0
- package/README.md +13 -21
- package/claude/ARCHITECTURE.md +4 -4
- package/claude/CLAUDE.md +2 -2
- package/claude/README.md +1 -1
- package/claude/commands/extension-add.md +1 -1
- package/claude/commands/extension-debug.md +1 -1
- package/claude/commands/extension-publish.md +1 -1
- package/claude/commands/extension.md +3 -3
- package/claude/rules/mcp-tools.md +45 -49
- package/dist/module.js +1026 -1186
- package/dist/src/lib/common-schema.d.ts +28 -0
- package/dist/src/lib/launch-flags.d.ts +6 -6
- package/dist/src/lib/session-identity.d.ts +16 -0
- package/dist/src/tools/add-feature.d.ts +2 -2
- package/dist/src/tools/analyze.d.ts +29 -0
- package/dist/src/tools/auth.d.ts +33 -0
- package/dist/src/tools/browsers.d.ts +39 -0
- package/dist/src/tools/build.d.ts +5 -6
- package/dist/src/tools/detect-browsers.d.ts +1 -20
- package/dist/src/tools/dev.d.ts +11 -11
- package/dist/src/tools/{dom-inspect.d.ts → dom-snapshot.d.ts} +6 -6
- package/dist/src/tools/eval.d.ts +6 -6
- package/dist/src/tools/get-template-source.d.ts +1 -22
- package/dist/src/tools/inspect.d.ts +33 -5
- package/dist/src/tools/install-browser.d.ts +1 -18
- package/dist/src/tools/list-browsers.d.ts +1 -9
- package/dist/src/tools/list-extensions.d.ts +4 -4
- package/dist/src/tools/list-templates.d.ts +1 -35
- package/dist/src/tools/login.d.ts +1 -23
- package/dist/src/tools/logout.d.ts +1 -9
- package/dist/src/tools/logs-schema.d.ts +2 -2
- package/dist/src/tools/open.d.ts +6 -6
- package/dist/src/tools/preview-web.d.ts +4 -4
- package/dist/src/tools/publish.d.ts +2 -2
- package/dist/src/tools/release-list.d.ts +1 -23
- package/dist/src/tools/release-promote.d.ts +2 -2
- package/dist/src/tools/release-status.d.ts +37 -0
- package/dist/src/tools/reload.d.ts +6 -6
- package/dist/src/tools/shares.d.ts +2 -2
- package/dist/src/tools/start.d.ts +16 -10
- package/dist/src/tools/stop.d.ts +2 -2
- package/dist/src/tools/storage.d.ts +6 -6
- package/dist/src/tools/store-status.d.ts +1 -23
- package/dist/src/tools/{deploy.d.ts → submit.d.ts} +4 -4
- package/dist/src/tools/{source-inspect.d.ts → templates.d.ts} +27 -23
- package/dist/src/tools/uninstall-browser.d.ts +1 -21
- package/dist/src/tools/wait.d.ts +4 -4
- package/dist/src/tools/whoami.d.ts +1 -9
- package/extensions/live-preview/chromium/action/index.js +1 -9
- package/extensions/live-preview/chromium/background/service_worker.js +3 -11
- package/extensions/live-preview/chromium/manifest.json +1 -1
- package/package.json +2 -2
- package/server.json +3 -3
- package/dist/src/__tests__/fixtures/ready-contract.d.ts +0 -7
- package/dist/src/__tests__/setup-session-dir.d.ts +0 -1
- package/dist/src/tools/preview.d.ts +0 -66
- /package/dist/src/tools/{source-inspect-gecko.d.ts → inspect-gecko.d.ts} +0 -0
|
@@ -1,12 +1,4 @@
|
|
|
1
|
-
// ███╗ ███╗ ██████╗██████╗
|
|
2
|
-
// ████╗ ████║██╔════╝██╔══██╗
|
|
3
|
-
// ██╔████╔██║██║ ██████╔╝
|
|
4
|
-
// ██║╚██╔╝██║██║ ██╔═══╝
|
|
5
|
-
// ██║ ╚═╝ ██║╚██████╗██║
|
|
6
|
-
// ╚═╝ ╚═╝ ╚═════╝╚═╝
|
|
7
|
-
// Apache License 2.0 (c) 2026 Cezar Augusto and the extension.dev collaborators
|
|
8
|
-
|
|
9
|
-
(()=>{"use strict";let e={alarms:["alarms"],bookmarks:["bookmarks"],contextMenus:["contextMenus"],cookies:["cookies"],downloads:["downloads"],history:["history"],notifications:["notifications"],offscreen:["offscreen"],contentSettings:["contentSettings"],debugger:["debugger"],declarativeNetRequest:["declarativeNetRequest","declarativeNetRequestWithHostAccess"],fontSettings:["fontSettings"],identity:["identity"],idle:["idle"],instanceID:["gcm"],management:["management"],mdns:["mdns"],power:["power"],printerProvider:["printerProvider"],printing:["printing"],privacy:["privacy"],proxy:["proxy"],sidePanel:["sidePanel"],tabCapture:["tabCapture"],tabGroups:["tabGroups"],topSites:["topSites"],tts:["tts"],userScripts:["userScripts"],webNavigation:["webNavigation"],webRequest:["webRequest"]};function t(e){let t=e.discarded??!1;return{id:e.id,index:e.index,windowId:e.windowId,url:e.url,title:e.title,active:e.active,highlighted:e.active,selected:e.active,pinned:e.pinned??!1,discarded:t,autoDiscardable:!0,frozen:!1,groupId:e.groupId??-1,splitViewId:-1,status:e.status??(t?"unloaded":"complete"),incognito:e.incognito??!1,audible:!1,mutedInfo:{muted:!1},width:e.width??1280,height:e.height??800,...void 0===e.lastAccessed?{}:{lastAccessed:e.lastAccessed}}}function r(e,r,n){return t({id:r.id,index:r.index??n,windowId:e.id,url:r.url,title:r.title,active:r.active??r.id===e.activeTabId,pinned:r.pinned,discarded:r.discarded,groupId:r.tabGroupId,status:r.status,incognito:r.incognito})}JSON.stringify(e),JSON.stringify(["getSelf","getPermissionWarningsByManifest","uninstallSelf","installReplacementWebApp"]),JSON.stringify({"system.cpu":["system.cpu"],"system.memory":["system.memory"],"system.storage":["system.storage"],"system.display":["system.display"]});let n=new Set(["0","1","2","3"]),o="Invalid downloadId",s="Can't modify the root bookmark folders.";function a(e){return`No tab with id: ${String(e)}.`}function i(e){return`No window with id: ${String(e)}.`}function l(e){return null!=e}function c(e,t){for(let r of Array.isArray(t)?t:[t])if(l(r)&&!function(e,t){for(let r of e)for(let e=0;e<r.tabs.length;e+=1){let n=r.tabs[e];if(n&&n.id===t)return{window:r,index:e}}}(e,r))return r}function d(e,t){let r=String(t);return e.some(e=>void 0!==e.id&&String(e.id)===r)}function u(e){return n.has(String(e??""))}let g=new Set(["storage.setAccessLevel","storage.get","storage.set","storage.remove","storage.clear","tabs.create","tabs.update","tabs.remove","tabs.move","tabs.discard","tabs.goBack","tabs.goForward","tabs.group","tabs.ungroup","tabGroups.query","tabGroups.get","tabGroups.update","tabGroups.move","tabs.get"]);async function f(e){let{data:t,windows:n,getStorage:o,setStorage:s,removeStorageKeys:i,clearStorage:d,onStorageChanged:u,onCreateTab:g,onUpdateTab:f,onRemoveTab:m,onMoveTab:p,onDiscardTab:h,onGroupTabs:w,onUngroupTabs:b,onQueryTabGroups:y,onGetTabGroup:v,onUpdateTabGroup:x,onMoveTabGroup:I,onTabGoBack:k,onTabGoForward:S,onSetStorageAccessLevel:A,respond:C}=e;switch(t.api){case"storage.setAccessLevel":{let[e,r]=t.args,n=e?.accessLevel;if("TRUSTED_CONTEXTS"!==n&&"TRUSTED_AND_UNTRUSTED_CONTEXTS"!==n)return void C({error:"Invalid access level."});await A?.(t.extensionId,r??"session",n),C({result:void 0});return}case"storage.get":{let[e,r]=t.args,n=o(t.extensionId,r??"local");if(!e)return void C({result:n});if(Array.isArray(e)){let t={};e.forEach(e=>{e in n&&(t[e]=n[e])}),C({result:t});return}if("string"==typeof e)return void C({result:e in n?{[e]:n[e]}:{}});if("object"==typeof e){let t={};Object.keys(e).forEach(r=>{t[r]=r in n?n[r]:e[r]}),C({result:t});return}C({result:n});return}case"storage.set":{let[e,r]=t.args,n=r??"local";if(e&&"object"==typeof e){let r=o(t.extensionId,n),a={};for(let t of Object.keys(e)){let n=r[t],o=e[t];if(JSON.stringify(n)===JSON.stringify(o))continue;let s={newValue:o};t in r&&(s.oldValue=n),a[t]=s}await s(t.extensionId,e,n),u&&Object.keys(a).length>0&&u(t.extensionId,a,n)}C({result:!0});return}case"storage.remove":{let[e,r]=t.args,n=r??"local",s=(Array.isArray(e)?e:[e]).filter(Boolean).map(String),a=o(t.extensionId,n),l={};for(let e of s)e in a&&(l[e]={oldValue:a[e]});await i(t.extensionId,s,n),u&&Object.keys(l).length>0&&u(t.extensionId,l,n),C({result:!0});return}case"storage.clear":{let[e]=t.args,r=e??"local",n=o(t.extensionId,r),s={};for(let e of Object.keys(n))s[e]={oldValue:n[e]};await d(t.extensionId,r),u&&Object.keys(s).length>0&&u(t.extensionId,s,r),C({result:!0});return}case"tabs.create":{let[e]=t.args;C({result:await g(e?.url??"chrome://newtab",e)??!0});return}case"tabs.update":{let[e,r]=t.args;if(null!==e&&"object"==typeof e&&(r=e,e=void 0),l(e)&&void 0!==c(n,e))return void C({error:a(e),refused:!0});C({result:await f(e,r??{})??!0});return}case"tabs.remove":{let[e]=t.args,r=c(n,e);if(void 0!==r)return void C({error:a(r),refused:!0});await m(e),C({result:void 0});return}case"tabs.move":{let[e,r]=t.args;C({result:await p?.(t.extensionId,e,r??{})});return}case"tabs.discard":{let[e]=t.args,r=c(n,e);if(void 0!==r)return void C({error:a(r),refused:!0});C({result:await h?.(t.extensionId,e)});return}case"tabs.goBack":{let[e]=t.args;await k?.(t.extensionId,e),C({result:void 0});return}case"tabs.goForward":{let[e]=t.args;await S?.(t.extensionId,e),C({result:void 0});return}case"tabs.group":{let[e]=t.args,r=c(n,e?.tabIds);if(void 0!==r)return void C({error:a(r),refused:!0});C({result:await w?.(t.extensionId,e??{})});return}case"tabs.ungroup":{let[e]=t.args,r=c(n,e);if(void 0!==r)return void C({error:a(r),refused:!0});await b?.(t.extensionId,e),C({result:void 0});return}case"tabGroups.query":{let[e]=t.args;C({result:await y?.(t.extensionId,e)??[]});return}case"tabGroups.get":{let[e]=t.args;C({result:await v?.(t.extensionId,e)});return}case"tabGroups.update":{let[e,r]=t.args;C({result:await x?.(t.extensionId,e,r??{})});return}case"tabGroups.move":{let[e,r]=t.args;C({result:await I?.(t.extensionId,e,r??{})});return}case"tabs.get":{let[e]=t.args;for(let t of n)for(let n=0;n<t.tabs.length;n+=1){let o=t.tabs[n];if(o&&o.id===e)return void C({result:r(t,o,n)})}C({error:`No tab with id: ${String(e)}.`})}}}let m=[0,0,0,0],p=e=>Math.max(0,Math.min(255,Math.round(e))),h={transparent:[0,0,0,0],black:[0,0,0,255],white:[255,255,255,255],red:[255,0,0,255],green:[0,128,0,255],blue:[0,0,255,255],yellow:[255,255,0,255],orange:[255,165,0,255],grey:[128,128,128,255],gray:[128,128,128,255]};function w(e,t,r,n){let o;return"function"!=typeof e&&(r({error:(o=n?` on the ${n} lane`:"",`No backend implements ${t}${o}, so the call did not run. This is a preview limitation, not an error in your extension: the API is on the bridge's wire protocol but nothing is wired behind it here.`),refused:!0}),!0)}let b=new Set(["tabs.query","sidePanel.open","action.openPopup","runtime.openOptionsPage","devtools.panels.create","action.setPopup","action.getBadgeText","action.getBadgeBackgroundColor","action.getTitle","action.setBadgeText","action.setBadgeBackgroundColor","action.setTitle","action.setIcon"]);async function y(e){let{data:t,windows:n,onOpenSidePanel:o,onOpenActionPopup:s,onOpenOptionsPage:a,onDevtoolsPanelCreate:i,onSetActionPopup:l,onGetActionState:c,onSetBadgeText:d,onSetBadgeBackground:u,onSetActionTitle:g,onSetActionIcon:f,respond:b}=e;switch(t.api){case"tabs.query":{let[e]=t.args,o=n.find(e=>e.focused)??n[0],s=n;e?.windowId!==void 0?s=-2===e.windowId?o?[o]:[]:n.filter(t=>t.id===e.windowId):e?.currentWindow===!0||e?.lastFocusedWindow===!0?s=o?[o]:[]:e?.currentWindow===!1&&(s=n.filter(e=>e!==o));let a=e?.url?Array.isArray(e.url)?e.url:[e.url]:null;b({result:s.flatMap(t=>t.tabs.map((e,n)=>r(t,e,n)).filter(t=>e?.active===void 0||t.active===e.active).filter(t=>e?.pinned===void 0||t.pinned===e.pinned).filter(t=>e?.status===void 0||t.status===e.status).filter(t=>e?.discarded===void 0||t.discarded===e.discarded).filter(t=>e?.groupId===void 0||(t.groupId??-1)===e.groupId).filter(e=>!a||a.some(t=>(function(e,t){if(!e)return!1;if("<all_urls>"===t)return!0;let r=t.replace(/[.+?^${}()|[\]\\]/g,"\\$&");return RegExp(`^${r.replace(/\*/g,".*")}$`).test(e)})(e.url,t))))});return}case"sidePanel.open":await o(t.extensionId),b({result:void 0});return;case"action.openPopup":if(w(s,t.api,b))return;s?.(t.extensionId),b({result:void 0});return;case"runtime.openOptionsPage":if(w(a,t.api,b))return;a?.(t.extensionId),b({result:void 0});return;case"devtools.panels.create":{if(w(i,t.api,b))return;let[e]=t.args;i?.(t.extensionId,e?.page??""),b({result:!0});return}case"action.setPopup":{if(w(l,t.api,b))return;let[e]=t.args;l?.(t.extensionId,e?.popup??""),b({result:void 0});return}case"action.getBadgeText":{let[e]=t.args,r=await c?.(t.extensionId,e?.tabId);b({result:r?.badgeText??""});return}case"action.getBadgeBackgroundColor":{let[e]=t.args,r=await c?.(t.extensionId,e?.tabId);b({result:r?.badgeColor===void 0||null===r.badgeColor?m:function(e){if(Array.isArray(e)){let[t,r,n,o]=e;return[p(Number(t)||0),p(Number(r)||0),p(Number(n)||0),p(void 0===o?255:Number(o)||0)]}if("string"!=typeof e)return m;let t=e.trim().toLowerCase();if(!t)return m;let r=h[t];if(r)return[...r];let n=/^rgba?\(([^)]+)\)$/.exec(t);if(n?.[1]){let e=n[1].split(",").map(e=>Number(e.trim()));if(e.length>=3&&e.slice(0,3).every(e=>!Number.isNaN(e))){let t=e[3];return[p(e[0]),p(e[1]),p(e[2]),void 0===t||Number.isNaN(t)?255:p(255*t)]}return m}let o=/^#([0-9a-f]{3,8})$/.exec(t);if(o?.[1]){let e=o[1],t=e=>1===e.length?parseInt(e+e,16):parseInt(e,16);if(3===e.length||4===e.length)return[t(e[0]),t(e[1]),t(e[2]),4===e.length?t(e[3]):255];if(6===e.length||8===e.length)return[parseInt(e.slice(0,2),16),parseInt(e.slice(2,4),16),parseInt(e.slice(4,6),16),8===e.length?parseInt(e.slice(6,8),16):255]}return m}(r.badgeColor)});return}case"action.getTitle":{let[e]=t.args,r=await c?.(t.extensionId,e?.tabId);b({result:r?.title??""});return}case"action.setBadgeText":{let[e]=t.args;await d(t.extensionId,e?.text,e?.tabId),b({result:!0});return}case"action.setBadgeBackgroundColor":{let[e]=t.args;await u(t.extensionId,e?.color,e?.tabId),b({result:!0});return}case"action.setTitle":{let[e]=t.args;await g(t.extensionId,e?.title,e?.tabId),b({result:!0});return}case"action.setIcon":{let[e]=t.args,r="string"==typeof e?.path?e.path:"object"==typeof e?.path?Object.values(e.path)[0]:void 0;await f(t.extensionId,r),b({result:!0})}}}let v=new Set(["contextMenus.create","contextMenus.update","contextMenus.remove","contextMenus.removeAll","notifications.create","notifications.clear","notifications.update","notifications.getAll","downloads.search","downloads.cancel","downloads.pause","downloads.resume","downloads.erase","downloads.download"]);async function x(e){let{data:t,onCreateContextMenu:r,onUpdateContextMenu:n,onRemoveContextMenu:s,onClearContextMenus:a,onCreateNotification:i,onClearNotification:l,onUpdateNotification:c,onGetNotifications:d,onDownload:u,onSearchDownloads:g,onCancelDownload:f,onPauseDownload:m,onResumeDownload:p,onEraseDownloads:h,respond:b}=e;switch(t.api){case"contextMenus.create":{let[e]=t.args;b({result:await r(t.extensionId,e??{})});return}case"contextMenus.update":{let[e,r]=t.args;b({result:await n(t.extensionId,String(e??""),r??{})});return}case"contextMenus.remove":{let[e]=t.args;b({result:await s(t.extensionId,String(e??""))});return}case"contextMenus.removeAll":return void b({result:await a(t.extensionId)});case"notifications.create":{let[e,r]=t.args,n="string"==typeof e?e:void 0,o="string"==typeof e?r:e;b({result:await i(t.extensionId,n,o??{})});return}case"notifications.clear":{let[e]=t.args;b({result:await l(t.extensionId,String(e??""))});return}case"notifications.update":{let[e,r]=t.args;b({result:await c?.(t.extensionId,String(e??""),r??{})??!1});return}case"notifications.getAll":return void b({result:await d(t.extensionId)});case"downloads.search":{let[e]=t.args;b({result:await g?.(t.extensionId,e)??[]});return}case"downloads.cancel":{if(w(f,t.api,b))return;let[e]=t.args;if(await f?.(t.extensionId,e)===!1)return void b({error:o,refused:!0});b({result:void 0});return}case"downloads.pause":{if(w(m,t.api,b))return;let[e]=t.args;if(await m?.(t.extensionId,e)===!1)return void b({error:o,refused:!0});b({result:void 0});return}case"downloads.resume":{if(w(p,t.api,b))return;let[e]=t.args;if(await p?.(t.extensionId,e)===!1)return void b({error:o,refused:!0});b({result:void 0});return}case"downloads.erase":{if(w(h,t.api,b))return;let[e]=t.args;b({result:await h?.(t.extensionId,e)??[]});return}case"downloads.download":{let[e]=t.args;b({result:await u(t.extensionId,e??{})})}}}let I={"bookmarks-bar":"bookmarks-bar","other-bookmarks":"other","mobile-bookmarks":"mobile"};function k(e,t={}){let r=void 0===e.url,n=e.parentId??t.parentId,o=I[e.id];return{id:e.id,title:e.title??"",syncing:!1,...void 0===e.url?{}:{url:e.url},...void 0===e.index?{}:{index:e.index},...void 0===n?{}:{parentId:n},...void 0===e.dateAdded?{}:{dateAdded:e.dateAdded},...r&&void 0!==e.dateGroupModified?{dateGroupModified:e.dateGroupModified}:{},...o?{folderType:o}:{},...e.children?{children:e.children.map(t=>k(t,{parentId:e.id}))}:{}}}function S(e){return(e??[]).map(e=>k(e))}function A(e,r={}){let n={id:e.id,focused:e.focused??!1,incognito:e.incognito??!1,alwaysOnTop:e.alwaysOnTop??!1,state:e.state??"normal",type:e.type??"normal",top:e.top??0,left:e.left??0,width:e.width??1280,height:e.height??800};return r.populate?{...n,tabs:(e.tabs??[]).map((r,n)=>t({id:r.id,index:r.index??n,windowId:e.id,url:r.url,title:r.title,active:r.active??r.id===e.activeTabId,pinned:r.pinned,discarded:r.discarded,groupId:r.tabGroupId,status:r.status,incognito:r.incognito}))}:n}let C=new Set(["bookmarks.getTree","bookmarks.get","bookmarks.getChildren","bookmarks.search","bookmarks.create","bookmarks.update","bookmarks.remove","bookmarks.removeTree","bookmarks.move","history.search","history.getVisits","history.addUrl","history.deleteUrl","history.deleteRange","history.deleteAll","windows.get","windows.getAll","windows.getCurrent","windows.create","windows.update","windows.remove"]);async function T(e){let{data:t,windows:r,onGetWindow:n,onGetAllWindows:o,onCreateWindow:a,onUpdateWindow:c,onRemoveWindow:g,onGetBookmarkTree:f,onGetBookmarks:m,onGetBookmarkChildren:p,onSearchBookmarks:h,onCreateBookmark:w,onUpdateBookmark:b,onRemoveBookmark:y,onMoveBookmark:v,onSearchHistory:x,onGetHistoryVisits:I,onAddHistoryUrl:C,onDeleteHistoryUrl:T,onDeleteHistoryRange:$,onDeleteAllHistory:E,respond:N}=e;switch(t.api){case"bookmarks.getTree":let D,M;return void N({result:(M=(D=await f(t.extensionId)??[]).map(e=>e.dateAdded).filter(e=>void 0!==e).sort((e,t)=>e-t)[0],[k({id:"0",title:"",children:D,...void 0===M?{}:{dateAdded:M}})])});case"bookmarks.get":{let[e]=t.args,r=Array.isArray(e)?e:[e];N({result:S(await m(t.extensionId,r.filter(e=>null!=e).map(String)))});return}case"bookmarks.getChildren":{let[e]=t.args;N({result:S(await p(t.extensionId,null==e?void 0:String(e)))});return}case"bookmarks.search":{let[e]=t.args;N({result:S(await h(t.extensionId,e))});return}case"bookmarks.create":{let[e]=t.args,r=await w(t.extensionId,e??{});N({result:r?k(r):null});return}case"bookmarks.update":{let[e,r]=t.args;if(u(e))return void N({error:s,refused:!0});let n=await b(t.extensionId,String(e??""),r??{});N({result:n?k(n):null});return}case"bookmarks.remove":{let[e]=t.args;if(u(e))return void N({error:s,refused:!0});N({result:await y(t.extensionId,String(e??""),!1)});return}case"bookmarks.removeTree":{let[e]=t.args;if(u(e))return void N({error:s,refused:!0});N({result:await y(t.extensionId,String(e??""),!0)});return}case"bookmarks.move":{let[e,r]=t.args;if(u(e))return void N({error:s,refused:!0});N({result:await v?.(t.extensionId,String(e??""),r??{})});return}case"history.search":{let[e]=t.args;N({result:await x(t.extensionId,e??{})});return}case"history.getVisits":{let[e]=t.args;N({result:await I(t.extensionId,e??{})});return}case"history.addUrl":{let[e]=t.args;await C(t.extensionId,e??{}),N({result:!0});return}case"history.deleteUrl":{let[e]=t.args;await T(t.extensionId,e??{}),N({result:!0});return}case"history.deleteRange":{let[e]=t.args;await $(t.extensionId,e??{}),N({result:!0});return}case"history.deleteAll":await E(t.extensionId),N({result:!0});return;case"windows.get":{let[e,o]=t.args;if(l(e)&&!d(r,e))return void N({error:i(e),refused:!0});let s=await n(t.extensionId,null==e?void 0:String(e),o);N({result:s?A(s,{populate:o?.populate}):null});return}case"windows.getAll":{let[e]=t.args;N({result:function(e,t={}){return e.map(e=>A(e,t))}(await o(t.extensionId,e),{populate:e?.populate})});return}case"windows.getCurrent":{let[e]=t.args,n=r.find(e=>e.focused)??r[0];N({result:n?A(n,{populate:e?.populate}):null});return}case"windows.create":{let[e]=t.args,r=await a(t.extensionId,e?.url);N({result:r?A(r,{populate:!0}):null});return}case"windows.update":{let[e,n]=t.args;if(l(e)&&!d(r,e))return void N({error:i(e),refused:!0});let o=await c(t.extensionId,null==e?void 0:String(e),n??{});N({result:o?A(o):null});return}case"windows.remove":{let[e]=t.args;if(l(e)&&!d(r,e))return void N({error:i(e),refused:!0});N({result:await g(t.extensionId,null==e?void 0:String(e))})}}}let $=new Set(["runtime.sendMessage","tabs.sendMessage","runtime.getContexts","permissions.contains","permissions.request","permissions.remove","permissions.getAll","offscreen.createDocument","offscreen.closeDocument","offscreen.hasDocument","cookies.get","cookies.getAll","cookies.set","cookies.remove","scripting.executeScript","scripting.insertCSS"]);async function E(e){let{data:t,onRuntimeMessage:r,onTabMessage:n,onGetRuntimeContexts:o,onContainsPermissions:s,onRequestPermissions:a,onRemovePermissions:i,onGetAllPermissions:l,onCreateOffscreenDocument:c,onCloseOffscreenDocument:d,onHasOffscreenDocument:u,onGetCookie:g,onGetAllCookies:f,onSetCookie:m,onRemoveCookie:p,onExecuteScript:h,onInsertCss:w,respond:b,source:y}=e;switch(t.api){case"runtime.sendMessage":{let[e]=t.args;b({result:await r(t.extensionId,e,y)});return}case"tabs.sendMessage":{let[e,r]=t.args;if(!n)return void b({error:"Could not establish connection. Receiving end does not exist."});b({result:await n(t.extensionId,e,r)});return}case"runtime.getContexts":return void b({result:await o(t.extensionId)});case"permissions.contains":{let[e]=t.args;b({result:await s(t.extensionId,e??{})});return}case"permissions.request":{let[e]=t.args;b({result:await a(t.extensionId,e??{})});return}case"permissions.remove":{let[e]=t.args;b({result:await i(t.extensionId,e??{})});return}case"permissions.getAll":return void b({result:await l(t.extensionId)});case"offscreen.createDocument":{let[e]=t.args,r=await c(t.extensionId,e??{});b({result:"boolean"!=typeof r||r});return}case"offscreen.closeDocument":{let e=await d(t.extensionId);b({result:"boolean"!=typeof e||e});return}case"offscreen.hasDocument":return void b({result:await u(t.extensionId)});case"cookies.get":{let[e]=t.args;b({result:await g(t.extensionId,e??{})});return}case"cookies.getAll":{let[e]=t.args;b({result:await f(t.extensionId,e??{})});return}case"cookies.set":{let[e]=t.args;b({result:await m(t.extensionId,e??{})});return}case"cookies.remove":{let[e]=t.args;b({result:await p(t.extensionId,e??{})});return}case"scripting.executeScript":{let[e]=t.args;b({result:await h(t.extensionId,e??{})});return}case"scripting.insertCSS":{let[e]=t.args;await w(t.extensionId,e??{}),b({result:!0})}}}let N=["local","sync","session","managed"];function D(){return[...g,...b,...v,...C,...$].sort()}function M(e,t){let r=Math.min(e.length,t.length),n=0;for(;n<r&&e[n]===t[n];)n+=1;return n}function U(e){let t=function(e){let t=D();if(t.includes(e))return null;let r=e.split(".");if(3===r.length&&"storage"===r[0]&&N.includes(r[1]??"")){let e=`storage.${r[2]}`;if(t.includes(e))return e}let n=r[r.length-1]??"",o=t.filter(e=>e.endsWith(`.${n}`));if(o.length)return o.sort((t,r)=>M(r,e)-M(t,e))[0];let s=t.filter(e=>e.startsWith(`${r[0]}.`));return s.length?s[0]??null:null}(e),r=`Unsupported API: ${e}.`;if(!t)return`${r} No wire name resembles it, so this API is not on the bridge at all. It may still work natively inside your extension's own contexts: the bridge is what an observer page can DRIVE, not the whole runtime.`;let n=t.startsWith("storage.")&&e.startsWith("storage.")?` The bridge takes the storage area as an ARGUMENT, not as part of the name: ${t}(keys, "local").`:"";return`${r} The closest wire name the bridge routes is ${t}.${n}`}let R={dom:"*",extension:["getURL","inIncognitoContext","lastError","onRequest","sendRequest"],i18n:"*",runtime:["connect","getManifest","getURL","getVersion","id","onConnect","onMessage","sendMessage"],scripting:["globalParams"],storage:"*"};function B(e){let[t="",r=""]=e.split("."),n=R[t];return"*"===n||!!Array.isArray(n)&&n.includes(r)}let P=D().filter(e=>!B(e));function O(e){var t;let r;return e.untrustedContext?B(e.api)?null:(r=(t=e.api).split(".")[0]??t,`chrome.${r} is not available to content scripts. Chrome gives a content script only chrome.storage, chrome.i18n, chrome.dom, chrome.extension and the messaging half of chrome.runtime, so ${t} cannot be reached from a page context. Call it from the background service worker or an extension page and reach the content script with runtime.sendMessage.`):null}let j=["extension","i18n","runtime","scripting","storage"],q=P.filter(e=>j.includes(e.split(".")[0]??""));JSON.stringify(j),JSON.stringify(q);let G=["url","pendingUrl","title","favIconUrl"],L=new Set(["tabs.get","tabs.query","tabs.create","tabs.update","tabs.move","tabs.discard"]),_=new Set(["windows.get","windows.getAll","windows.getCurrent","windows.create","windows.update"]),W=["url","title"];function V(e){return"<all_urls>"===e||e.includes("://")}function H(e,t){if(!e||"object"!=typeof e||function(e,t){if(e.has("tabs"))return!0;if(!t)return!1;for(let r of e){if(!V(r))continue;let e=function(e){let t;if("<all_urls>"===e)return/^(?:https?|file|ftp):\/\//;let r=/^(\*|https?|file|ftp):\/\/([^/]*)(\/.*)?$/.exec(e);if(!r)return null;let[,n="",o="",s="/*"]=r,a="*"===n?"https?":n.replace(/[.+?^${}()|[\]\\]/g,"\\$&");t="*"===o?"[^/]+":o.startsWith("*.")?`(?:[^/]+\\.)?${o.slice(2).replace(/[.+?^${}()|[\]\\]/g,"\\$&").replace(/\*/g,"[^/]*")}`:o.replace(/[.+?^${}()|[\]\\]/g,"\\$&").replace(/\*/g,"[^/]*");let i=s.replace(/[.+?^${}()|[\]\\]/g,"\\$&").replace(/\*/g,".*");return RegExp(`^${a}://${t}${i}$`)}(r);if(e?.test(t))return!0}return!1}(t,"string"==typeof e.url?e.url:"string"==typeof e.pendingUrl?e.pendingUrl:void 0))return e;let r={...e};for(let e of G)delete r[e];return r}function F(e,t){return e&&"object"==typeof e&&Array.isArray(e.tabs)?{...e,tabs:e.tabs.map(e=>H(e,t))}:e}let J={...e,storage:["storage"],scripting:["scripting","activeTab"]};function z(e,t){let r=e.split(".")[0]??"",n=J[r];return!n||null===t||n.some(e=>t.has(e))?null:`chrome.${r} needs the "${n.join('" or "')}" permission, which this session did not declare. Declare it in the manifest (and re-register the session) to use this API.`}let X=e=>"string"==typeof e&&e.length>0;function K(e,t){return`Error in invocation of ${e}: ${t}`}function Q(e,t){return K(e,`missing required property '${t}'`)}function Y(e,t,r,n){return K(e,`'${t}' expects a ${r}, got ${typeof n}`)}async function Z(e){let{data:t,getDeclaredPermissions:r,getSessionStorageAccessLevel:n}=e,o=r?r(t.extensionId):void 0,s=r=>{var n,s;return e.respond("result"in r?{...r,result:(n=t.api,s=r.result,!o||o.has("tabs")?s:L.has(n)?Array.isArray(s)?s.map(e=>H(e,o)):H(s,o):_.has(n)?Array.isArray(s)?s.map(e=>F(e,o)):F(s,o):s)}:r)},a={...e,respond:s};try{var i;if(i=t.api,!(g.has(i)||b.has(i)||v.has(i)||C.has(i)||$.has(i)))return void s({error:U(t.api),refused:!0});let e=O(t);if(e)return void s({error:e,refused:!0});let r=function(e,t){let r=t[0];switch(e){case"downloads.download":if(!r||!("url"in r))return Q(e,"url");if(!X(r.url))return Y(e,"url","non-empty string",r.url);if(void 0!==r.filename&&"string"!=typeof r.filename)return Y(e,"filename","string",r.filename);return null;case"offscreen.createDocument":if(!r||!X(r.url))return Q(e,"url");if(!Array.isArray(r.reasons)||0===r.reasons.length)return Q(e,"reasons");if(!X(r.justification))return Q(e,"justification");return null;case"contextMenus.create":if(!r)return Q(e,"title");if(void 0!==r.id&&"string"!=typeof r.id)return Y(e,"id","string",r.id);if("separator"!==r.type&&!X(r.title))return Q(e,"title");return null;case"notifications.create":{let r="string"==typeof t[0]?t[1]:t[0];if(!r)return Q(e,"options");for(let t of["type","iconUrl","title","message"])if(!X(r[t]))return Q(e,t);return null}case"action.setTitle":if(r&&void 0!==r.title&&"string"!=typeof r.title)return Y(e,"title","string",r.title);return null;case"action.setBadgeText":if(r&&void 0!==r.text&&"string"!=typeof r.text)return Y(e,"text","string",r.text);return null;case"action.setBadgeBackgroundColor":if(!r||void 0===r.color)return Q(e,"color");if("string"!=typeof r.color&&!Array.isArray(r.color))return Y(e,"color","string or array",r.color);return null;case"tabs.create":if(r?.url!==void 0&&"string"!=typeof r.url)return Y(e,"url","string",r.url);return null;default:return null}}(t.api,t.args);if(r)return void s({error:r});let l=function(e,t,r){var n,o;let s=O(e);if(s)return s;if(void 0!==t){let r=z(e.api,t)??function(e,t,r){if("tabs.query"!==e||!r||r.has("tabs")||function(e){for(let t of e)if(V(t))return!0;return!1}(r))return null;let[n]=t;if(!n||"object"!=typeof n)return null;let o=W.filter(e=>void 0!==n[e]);return o.length?`chrome.tabs.query cannot filter by "${o.join('" or "')}" without the "tabs" permission or a matching host permission, which this session did not declare. Declare it in the manifest (and re-register the session) to filter on it.`:null}(e.api,e.args,t);if(r)return r}return e.untrustedContext&&e.api.startsWith("storage.")?"session"!==(n=e.api,o=e.args,"storage.clear"===n?o[0]:o[1])||"TRUSTED_AND_UNTRUSTED_CONTEXTS"===(r?.(e.extensionId)??"TRUSTED_CONTEXTS")?null:"Access to storage is not allowed from this context.":null}(t,o,n);if(l)return void s({error:l,refused:!0});if(g.has(t.api))return void await f(a);if(b.has(t.api))return void await y(a);if(v.has(t.api))return void await x(a);if(C.has(t.api))return void await T(a);if($.has(t.api))return void await E(a);s({error:U(t.api),refused:!0})}catch(e){s({error:e instanceof Error?e.message:"Unknown error"})}}function ee(e,t){if(t){if(/^(https?|blob|data|chrome-extension):/i.test(t))return t;if(e)for(let r of[t,t.replace(/^\.?\//,""),`/${t.replace(/^\.?\//,"")}`,`./${t.replace(/^\.?\//,"")}`]){let t=e[r];if(t)return t}}}async function et(e){let t=await fetch(e);if(!t.ok)throw Error(`could not read the guest asset (HTTP ${t.status})`);let r=await t.blob(),n=new Uint8Array(await r.arrayBuffer()),o="";for(let e of n)o+=String.fromCharCode(e);let s=r.type||"application/octet-stream";return`data:${s};base64,${btoa(o)}`}async function er(e){let t=await fetch(e);if(!t.ok)throw Error(`could not read the guest icon (HTTP ${t.status})`);let r=await createImageBitmap(await t.blob());try{let e=new OffscreenCanvas(r.width,r.height).getContext("2d");if(!e)throw Error("no 2d context is available to decode the guest icon");return e.drawImage(r,0,0),e.getImageData(0,0,r.width,r.height)}finally{r.close()}}async function en(e,t){let r={...e};for(let e of["iconUrl","imageUrl","appIconMaskUrl"]){let n=ee(t,r[e]);n&&(r[e]=await et(n))}return Array.isArray(r.buttons)&&(r.buttons=await Promise.all(r.buttons.map(async e=>{let r=ee(t,e.iconUrl);return r?{...e,iconUrl:await et(r)}:e}))),r}function eo(e,t){throw Error(`${e} did not run on the real lane: ${t}`)}let es=e=>{let t=Number(e);return Number.isFinite(t)?t:void 0},ea=e=>{let t=Number(e);return Number.isFinite(t)?t:void 0},ei=new Set(["system.cpu.getInfo","system.memory.getInfo","system.storage.getInfo","system.storage.ejectDevice","system.display.getInfo","system.display.getDisplayLayout","system.display.setDisplayProperties","system.display.setDisplayLayout"]),el=["topSites","fontSettings","printing","power","tts","userScripts","debugger","system.network","enterprise.deviceAttributes","instanceID","identity","webNavigation","proxy.settings","contentSettings","tabCapture"].sort((e,t)=>t.length-e.length);function ec(e){if(ei.has(e))return"refused";for(let t of el)if(e===t||e.startsWith(`${t}.`))return"mocked";return"emulated"}let ed=/^__(ext|extjs|extension)[a-z0-9-]*__$/i,eu=new Set(["runtime.connect","runtime.onConnect","runtime.sendMessage","runtime.onMessage","tabs.connect","tabs.sendMessage"]);function eg(e){return"string"==typeof e&&ed.test(e)}let ef=new Set(["storage","action","offscreen","runtime","tabs.sendMessage","scripting","downloads","notifications","contextMenus"]);function em(e){return!!e&&(e.startsWith("Unsupported API: ")||e.startsWith("No backend implements ")||/needs the ".+" permission, which this (session did not declare|extension's manifest does not declare)/.test(e))}function ep(e){return e.refused||em(e.error)?"refused":"real"===e.lane?"real":ec(e.api)}let eh=new Set(["local","sync","session","managed"]);function ew(e,t){let r=e.split(".");if("storage"!==r[0])return e;if(3===r.length&&eh.has(r[1]??""))return`storage.${r[2]}@${r[1]}`;if(2===r.length){let e="clear"===r[1]?t?.[0]:t?.[1];return`storage.${r[1]}@${"string"==typeof e?e:"local"}`}return e}let eb=new TextEncoder;function ey(e,t){return{path:e,bytes:eb.encode(t),text:t}}let ev={manifest_version:3,name:"Hello Emulator",version:"0.1.0",description:"Trace fixture exercising emulated, mocked, and refused chrome.* tiers.",permissions:["storage","tabs","notifications","system.cpu","bookmarks","history","cookies","alarms","topSites","fontSettings","power","tts","identity","webNavigation"],action:{default_title:"Hello Emulator",default_popup:"popup.html"},background:{service_worker:"background.js"}},ex=`<!doctype html>
|
|
1
|
+
(()=>{"use strict";let e={alarms:["alarms"],bookmarks:["bookmarks"],contextMenus:["contextMenus"],cookies:["cookies"],downloads:["downloads"],history:["history"],notifications:["notifications"],offscreen:["offscreen"],contentSettings:["contentSettings"],debugger:["debugger"],declarativeNetRequest:["declarativeNetRequest","declarativeNetRequestWithHostAccess"],fontSettings:["fontSettings"],identity:["identity"],idle:["idle"],instanceID:["gcm"],management:["management"],mdns:["mdns"],power:["power"],printerProvider:["printerProvider"],printing:["printing"],privacy:["privacy"],proxy:["proxy"],sidePanel:["sidePanel"],tabCapture:["tabCapture"],tabGroups:["tabGroups"],topSites:["topSites"],tts:["tts"],userScripts:["userScripts"],webNavigation:["webNavigation"],webRequest:["webRequest"]};function t(e){let t=e.discarded??!1;return{id:e.id,index:e.index,windowId:e.windowId,url:e.url,title:e.title,active:e.active,highlighted:e.active,selected:e.active,pinned:e.pinned??!1,discarded:t,autoDiscardable:!0,frozen:!1,groupId:e.groupId??-1,splitViewId:-1,status:e.status??(t?"unloaded":"complete"),incognito:e.incognito??!1,audible:!1,mutedInfo:{muted:!1},width:e.width??1280,height:e.height??800,...void 0===e.lastAccessed?{}:{lastAccessed:e.lastAccessed}}}function r(e,r,n){return t({id:r.id,index:r.index??n,windowId:e.id,url:r.url,title:r.title,active:r.active??r.id===e.activeTabId,pinned:r.pinned,discarded:r.discarded,groupId:r.tabGroupId,status:r.status,incognito:r.incognito})}JSON.stringify(e),JSON.stringify(["getSelf","getPermissionWarningsByManifest","uninstallSelf","installReplacementWebApp"]),JSON.stringify({"system.cpu":["system.cpu"],"system.memory":["system.memory"],"system.storage":["system.storage"],"system.display":["system.display"]});let n=new Set(["0","1","2","3"]),o="Invalid downloadId",s="Can't modify the root bookmark folders.";function a(e){return`No tab with id: ${String(e)}.`}function i(e){return`No window with id: ${String(e)}.`}function l(e){return null!=e}function c(e,t){for(let r of Array.isArray(t)?t:[t])if(l(r)&&!function(e,t){for(let r of e)for(let e=0;e<r.tabs.length;e+=1){let n=r.tabs[e];if(n&&n.id===t)return{window:r,index:e}}}(e,r))return r}function d(e,t){let r=String(t);return e.some(e=>void 0!==e.id&&String(e.id)===r)}function u(e){return n.has(String(e??""))}let f=new Set(["storage.setAccessLevel","storage.get","storage.set","storage.remove","storage.clear","tabs.create","tabs.update","tabs.remove","tabs.move","tabs.discard","tabs.goBack","tabs.goForward","tabs.group","tabs.ungroup","tabGroups.query","tabGroups.get","tabGroups.update","tabGroups.move","tabs.get"]);async function g(e){let{data:t,windows:n,getStorage:o,setStorage:s,removeStorageKeys:i,clearStorage:d,onStorageChanged:u,onCreateTab:f,onUpdateTab:g,onRemoveTab:m,onMoveTab:p,onDiscardTab:h,onGroupTabs:b,onUngroupTabs:w,onQueryTabGroups:y,onGetTabGroup:v,onUpdateTabGroup:k,onMoveTabGroup:x,onTabGoBack:I,onTabGoForward:S,onSetStorageAccessLevel:A,respond:C}=e;switch(t.api){case"storage.setAccessLevel":{let[e,r]=t.args,n=e?.accessLevel;if("TRUSTED_CONTEXTS"!==n&&"TRUSTED_AND_UNTRUSTED_CONTEXTS"!==n)return void C({error:"Invalid access level."});await A?.(t.extensionId,r??"session",n),C({result:void 0});return}case"storage.get":{let[e,r]=t.args,n=o(t.extensionId,r??"local");if(!e)return void C({result:n});if(Array.isArray(e)){let t={};e.forEach(e=>{e in n&&(t[e]=n[e])}),C({result:t});return}if("string"==typeof e)return void C({result:e in n?{[e]:n[e]}:{}});if("object"==typeof e){let t={};Object.keys(e).forEach(r=>{t[r]=r in n?n[r]:e[r]}),C({result:t});return}C({result:n});return}case"storage.set":{let[e,r]=t.args,n=r??"local";if(e&&"object"==typeof e){let r=o(t.extensionId,n),a={};for(let t of Object.keys(e)){let n=r[t],o=e[t];if(JSON.stringify(n)===JSON.stringify(o))continue;let s={newValue:o};t in r&&(s.oldValue=n),a[t]=s}await s(t.extensionId,e,n),u&&Object.keys(a).length>0&&u(t.extensionId,a,n)}C({result:!0});return}case"storage.remove":{let[e,r]=t.args,n=r??"local",s=(Array.isArray(e)?e:[e]).filter(Boolean).map(String),a=o(t.extensionId,n),l={};for(let e of s)e in a&&(l[e]={oldValue:a[e]});await i(t.extensionId,s,n),u&&Object.keys(l).length>0&&u(t.extensionId,l,n),C({result:!0});return}case"storage.clear":{let[e]=t.args,r=e??"local",n=o(t.extensionId,r),s={};for(let e of Object.keys(n))s[e]={oldValue:n[e]};await d(t.extensionId,r),u&&Object.keys(s).length>0&&u(t.extensionId,s,r),C({result:!0});return}case"tabs.create":{let[e]=t.args;C({result:await f(e?.url??"chrome://newtab",e)??!0});return}case"tabs.update":{let[e,r]=t.args;if(null!==e&&"object"==typeof e&&(r=e,e=void 0),l(e)&&void 0!==c(n,e))return void C({error:a(e),refused:!0});C({result:await g(e,r??{})??!0});return}case"tabs.remove":{let[e]=t.args,r=c(n,e);if(void 0!==r)return void C({error:a(r),refused:!0});await m(e),C({result:void 0});return}case"tabs.move":{let[e,r]=t.args;C({result:await p?.(t.extensionId,e,r??{})});return}case"tabs.discard":{let[e]=t.args,r=c(n,e);if(void 0!==r)return void C({error:a(r),refused:!0});C({result:await h?.(t.extensionId,e)});return}case"tabs.goBack":{let[e]=t.args;await I?.(t.extensionId,e),C({result:void 0});return}case"tabs.goForward":{let[e]=t.args;await S?.(t.extensionId,e),C({result:void 0});return}case"tabs.group":{let[e]=t.args,r=c(n,e?.tabIds);if(void 0!==r)return void C({error:a(r),refused:!0});C({result:await b?.(t.extensionId,e??{})});return}case"tabs.ungroup":{let[e]=t.args,r=c(n,e);if(void 0!==r)return void C({error:a(r),refused:!0});await w?.(t.extensionId,e),C({result:void 0});return}case"tabGroups.query":{let[e]=t.args;C({result:await y?.(t.extensionId,e)??[]});return}case"tabGroups.get":{let[e]=t.args;C({result:await v?.(t.extensionId,e)});return}case"tabGroups.update":{let[e,r]=t.args;C({result:await k?.(t.extensionId,e,r??{})});return}case"tabGroups.move":{let[e,r]=t.args;C({result:await x?.(t.extensionId,e,r??{})});return}case"tabs.get":{let[e]=t.args;for(let t of n)for(let n=0;n<t.tabs.length;n+=1){let o=t.tabs[n];if(o&&o.id===e)return void C({result:r(t,o,n)})}C({error:`No tab with id: ${String(e)}.`})}}}let m=[0,0,0,0],p=e=>Math.max(0,Math.min(255,Math.round(e))),h={aliceblue:"f0f8ff",antiquewhite:"faebd7",aqua:"00ffff",aquamarine:"7fffd4",azure:"f0ffff",beige:"f5f5dc",bisque:"ffe4c4",black:"000000",blanchedalmond:"ffebcd",blue:"0000ff",blueviolet:"8a2be2",brown:"a52a2a",burlywood:"deb887",cadetblue:"5f9ea0",chartreuse:"7fff00",chocolate:"d2691e",coral:"ff7f50",cornflowerblue:"6495ed",cornsilk:"fff8dc",crimson:"dc143c",cyan:"00ffff",darkblue:"00008b",darkcyan:"008b8b",darkgoldenrod:"b8860b",darkgray:"a9a9a9",darkgreen:"006400",darkgrey:"a9a9a9",darkkhaki:"bdb76b",darkmagenta:"8b008b",darkolivegreen:"556b2f",darkorange:"ff8c00",darkorchid:"9932cc",darkred:"8b0000",darksalmon:"e9967a",darkseagreen:"8fbc8f",darkslateblue:"483d8b",darkslategray:"2f4f4f",darkslategrey:"2f4f4f",darkturquoise:"00ced1",darkviolet:"9400d3",deeppink:"ff1493",deepskyblue:"00bfff",dimgray:"696969",dimgrey:"696969",dodgerblue:"1e90ff",firebrick:"b22222",floralwhite:"fffaf0",forestgreen:"228b22",fuchsia:"ff00ff",gainsboro:"dcdcdc",ghostwhite:"f8f8ff",gold:"ffd700",goldenrod:"daa520",gray:"808080",green:"008000",greenyellow:"adff2f",grey:"808080",honeydew:"f0fff0",hotpink:"ff69b4",indianred:"cd5c5c",indigo:"4b0082",ivory:"fffff0",khaki:"f0e68c",lavender:"e6e6fa",lavenderblush:"fff0f5",lawngreen:"7cfc00",lemonchiffon:"fffacd",lightblue:"add8e6",lightcoral:"f08080",lightcyan:"e0ffff",lightgoldenrodyellow:"fafad2",lightgray:"d3d3d3",lightgreen:"90ee90",lightgrey:"d3d3d3",lightpink:"ffb6c1",lightsalmon:"ffa07a",lightseagreen:"20b2aa",lightskyblue:"87cefa",lightslategray:"778899",lightslategrey:"778899",lightsteelblue:"b0c4de",lightyellow:"ffffe0",lime:"00ff00",limegreen:"32cd32",linen:"faf0e6",magenta:"ff00ff",maroon:"800000",mediumaquamarine:"66cdaa",mediumblue:"0000cd",mediumorchid:"ba55d3",mediumpurple:"9370db",mediumseagreen:"3cb371",mediumslateblue:"7b68ee",mediumspringgreen:"00fa9a",mediumturquoise:"48d1cc",mediumvioletred:"c71585",midnightblue:"191970",mintcream:"f5fffa",mistyrose:"ffe4e1",moccasin:"ffe4b5",navajowhite:"ffdead",navy:"000080",oldlace:"fdf5e6",olive:"808000",olivedrab:"6b8e23",orange:"ffa500",orangered:"ff4500",orchid:"da70d6",palegoldenrod:"eee8aa",palegreen:"98fb98",paleturquoise:"afeeee",palevioletred:"db7093",papayawhip:"ffefd5",peachpuff:"ffdab9",peru:"cd853f",pink:"ffc0cb",plum:"dda0dd",powderblue:"b0e0e6",purple:"800080",rebeccapurple:"663399",red:"ff0000",rosybrown:"bc8f8f",royalblue:"4169e1",saddlebrown:"8b4513",salmon:"fa8072",sandybrown:"f4a460",seagreen:"2e8b57",seashell:"fff5ee",sienna:"a0522d",silver:"c0c0c0",skyblue:"87ceeb",slateblue:"6a5acd",slategray:"708090",slategrey:"708090",snow:"fffafa",springgreen:"00ff7f",steelblue:"4682b4",tan:"d2b48c",teal:"008080",thistle:"d8bfd8",tomato:"ff6347",turquoise:"40e0d0",violet:"ee82ee",wheat:"f5deb3",white:"ffffff",whitesmoke:"f5f5f5",yellow:"ffff00",yellowgreen:"9acd32"},b={transparent:[0,0,0,0]};function w(e,t,r,n){let o;return"function"!=typeof e&&(r({error:(o=n?` on the ${n} lane`:"",`No backend implements ${t}${o}, so the call did not run. This is a preview limitation, not an error in your extension: the API is on the bridge's wire protocol but nothing is wired behind it here.`),refused:!0}),!0)}let y=new Set(["tabs.query","sidePanel.open","action.openPopup","runtime.openOptionsPage","devtools.panels.create","action.setPopup","action.getBadgeText","action.getBadgeBackgroundColor","action.getTitle","action.setBadgeText","action.setBadgeBackgroundColor","action.setTitle","action.setIcon"]);async function v(e){let{data:t,windows:n,onOpenSidePanel:o,onOpenActionPopup:s,onOpenOptionsPage:a,onDevtoolsPanelCreate:i,onSetActionPopup:l,onGetActionState:c,onSetBadgeText:d,onSetBadgeBackground:u,onSetActionTitle:f,onSetActionIcon:g,respond:y}=e;switch(t.api){case"tabs.query":{let[e]=t.args,o=n.find(e=>e.focused)??n[0],s=n;e?.windowId!==void 0?s=-2===e.windowId?o?[o]:[]:n.filter(t=>t.id===e.windowId):e?.currentWindow===!0||e?.lastFocusedWindow===!0?s=o?[o]:[]:e?.currentWindow===!1&&(s=n.filter(e=>e!==o));let a=e?.url?Array.isArray(e.url)?e.url:[e.url]:null;y({result:s.flatMap(t=>t.tabs.map((e,n)=>r(t,e,n)).filter(t=>e?.active===void 0||t.active===e.active).filter(t=>e?.pinned===void 0||t.pinned===e.pinned).filter(t=>e?.status===void 0||t.status===e.status).filter(t=>e?.discarded===void 0||t.discarded===e.discarded).filter(t=>e?.groupId===void 0||(t.groupId??-1)===e.groupId).filter(e=>!a||a.some(t=>(function(e,t){if(!e)return!1;if("<all_urls>"===t)return!0;let r=t.replace(/[.+?^${}()|[\]\\]/g,"\\$&");return RegExp(`^${r.replace(/\*/g,".*")}$`).test(e)})(e.url,t))))});return}case"sidePanel.open":await o(t.extensionId),y({result:void 0});return;case"action.openPopup":if(w(s,t.api,y))return;s?.(t.extensionId),y({result:void 0});return;case"runtime.openOptionsPage":if(w(a,t.api,y))return;a?.(t.extensionId),y({result:void 0});return;case"devtools.panels.create":{if(w(i,t.api,y))return;let[e]=t.args;i?.(t.extensionId,e?.page??""),y({result:!0});return}case"action.setPopup":{if(w(l,t.api,y))return;let[e]=t.args;l?.(t.extensionId,e?.popup??""),y({result:void 0});return}case"action.getBadgeText":{let[e]=t.args,r=await c?.(t.extensionId,e?.tabId);y({result:r?.badgeText??""});return}case"action.getBadgeBackgroundColor":{let[e]=t.args,r=await c?.(t.extensionId,e?.tabId);y({result:r?.badgeColor===void 0||null===r.badgeColor?m:function(e){if(Array.isArray(e)){let[t,r,n,o]=e;return[p(Number(t)||0),p(Number(r)||0),p(Number(n)||0),p(void 0===o?255:Number(o)||0)]}if("string"!=typeof e)return m;let t=e.trim().toLowerCase();if(!t)return m;let r=b[t];if(r)return[...r];let n=h[t];if(n)return[parseInt(n.slice(0,2),16),parseInt(n.slice(2,4),16),parseInt(n.slice(4,6),16),255];let o=/^rgba?\(([^)]+)\)$/.exec(t);if(o?.[1]){let e=o[1].split(",").map(e=>Number(e.trim()));if(e.length>=3&&e.slice(0,3).every(e=>!Number.isNaN(e))){let t=e[3];return[p(e[0]),p(e[1]),p(e[2]),void 0===t||Number.isNaN(t)?255:p(255*t)]}return m}let s=/^#([0-9a-f]{3,8})$/.exec(t);if(s?.[1]){let e=s[1],t=e=>1===e.length?parseInt(e+e,16):parseInt(e,16);if(3===e.length||4===e.length)return[t(e[0]),t(e[1]),t(e[2]),4===e.length?t(e[3]):255];if(6===e.length||8===e.length)return[parseInt(e.slice(0,2),16),parseInt(e.slice(2,4),16),parseInt(e.slice(4,6),16),8===e.length?parseInt(e.slice(6,8),16):255]}return m}(r.badgeColor)});return}case"action.getTitle":{let[e]=t.args,r=await c?.(t.extensionId,e?.tabId);y({result:r?.title??""});return}case"action.setBadgeText":{let[e]=t.args;await d(t.extensionId,e?.text,e?.tabId),y({result:!0});return}case"action.setBadgeBackgroundColor":{let[e]=t.args;await u(t.extensionId,e?.color,e?.tabId),y({result:!0});return}case"action.setTitle":{let[e]=t.args;await f(t.extensionId,e?.title,e?.tabId),y({result:!0});return}case"action.setIcon":{let[e]=t.args,r="string"==typeof e?.path?e.path:"object"==typeof e?.path?Object.values(e.path)[0]:void 0;await g(t.extensionId,r),y({result:!0})}}}let k=new Set(["contextMenus.create","contextMenus.update","contextMenus.remove","contextMenus.removeAll","notifications.create","notifications.clear","notifications.update","notifications.getAll","downloads.search","downloads.cancel","downloads.pause","downloads.resume","downloads.erase","downloads.download"]);async function x(e){let{data:t,onCreateContextMenu:r,onUpdateContextMenu:n,onRemoveContextMenu:s,onClearContextMenus:a,onCreateNotification:i,onClearNotification:l,onUpdateNotification:c,onGetNotifications:d,onDownload:u,onSearchDownloads:f,onCancelDownload:g,onPauseDownload:m,onResumeDownload:p,onEraseDownloads:h,respond:b}=e;switch(t.api){case"contextMenus.create":{let[e]=t.args;b({result:await r(t.extensionId,e??{})});return}case"contextMenus.update":{let[e,r]=t.args;b({result:await n(t.extensionId,String(e??""),r??{})});return}case"contextMenus.remove":{let[e]=t.args;b({result:await s(t.extensionId,String(e??""))});return}case"contextMenus.removeAll":return void b({result:await a(t.extensionId)});case"notifications.create":{let[e,r]=t.args,n="string"==typeof e?e:void 0,o="string"==typeof e?r:e;b({result:await i(t.extensionId,n,o??{})});return}case"notifications.clear":{let[e]=t.args;b({result:await l(t.extensionId,String(e??""))});return}case"notifications.update":{let[e,r]=t.args;b({result:await c?.(t.extensionId,String(e??""),r??{})??!1});return}case"notifications.getAll":return void b({result:await d(t.extensionId)});case"downloads.search":{let[e]=t.args;b({result:await f?.(t.extensionId,e)??[]});return}case"downloads.cancel":{if(w(g,t.api,b))return;let[e]=t.args;if(await g?.(t.extensionId,e)===!1)return void b({error:o,refused:!0});b({result:void 0});return}case"downloads.pause":{if(w(m,t.api,b))return;let[e]=t.args;if(await m?.(t.extensionId,e)===!1)return void b({error:o,refused:!0});b({result:void 0});return}case"downloads.resume":{if(w(p,t.api,b))return;let[e]=t.args;if(await p?.(t.extensionId,e)===!1)return void b({error:o,refused:!0});b({result:void 0});return}case"downloads.erase":{if(w(h,t.api,b))return;let[e]=t.args;b({result:await h?.(t.extensionId,e)??[]});return}case"downloads.download":{let[e]=t.args;b({result:await u(t.extensionId,e??{})})}}}let I={"bookmarks-bar":"bookmarks-bar","other-bookmarks":"other","mobile-bookmarks":"mobile"};function S(e,t={}){let r=void 0===e.url,n=e.parentId??t.parentId,o=I[e.id];return{id:e.id,title:e.title??"",syncing:!1,...void 0===e.url?{}:{url:e.url},...void 0===e.index?{}:{index:e.index},...void 0===n?{}:{parentId:n},...void 0===e.dateAdded?{}:{dateAdded:e.dateAdded},...r&&void 0!==e.dateGroupModified?{dateGroupModified:e.dateGroupModified}:{},...o?{folderType:o}:{},...e.children?{children:e.children.map(t=>S(t,{parentId:e.id}))}:{}}}function A(e){return(e??[]).map(e=>S(e))}function C(e,r={}){let n={id:e.id,focused:e.focused??!1,incognito:e.incognito??!1,alwaysOnTop:e.alwaysOnTop??!1,state:e.state??"normal",type:e.type??"normal",top:e.top??0,left:e.left??0,width:e.width??1280,height:e.height??800};return r.populate?{...n,tabs:(e.tabs??[]).map((r,n)=>t({id:r.id,index:r.index??n,windowId:e.id,url:r.url,title:r.title,active:r.active??r.id===e.activeTabId,pinned:r.pinned,discarded:r.discarded,groupId:r.tabGroupId,status:r.status,incognito:r.incognito}))}:n}let T=new Set(["bookmarks.getTree","bookmarks.get","bookmarks.getChildren","bookmarks.search","bookmarks.create","bookmarks.update","bookmarks.remove","bookmarks.removeTree","bookmarks.move","history.search","history.getVisits","history.addUrl","history.deleteUrl","history.deleteRange","history.deleteAll","windows.get","windows.getAll","windows.getCurrent","windows.create","windows.update","windows.remove"]);async function $(e){let{data:t,windows:r,onGetWindow:n,onGetAllWindows:o,onCreateWindow:a,onUpdateWindow:c,onRemoveWindow:f,onGetBookmarkTree:g,onGetBookmarks:m,onGetBookmarkChildren:p,onSearchBookmarks:h,onCreateBookmark:b,onUpdateBookmark:w,onRemoveBookmark:y,onMoveBookmark:v,onSearchHistory:k,onGetHistoryVisits:x,onAddHistoryUrl:I,onDeleteHistoryUrl:T,onDeleteHistoryRange:$,onDeleteAllHistory:E,respond:N}=e;switch(t.api){case"bookmarks.getTree":let D,M;return void N({result:(M=(D=await g(t.extensionId)??[]).map(e=>e.dateAdded).filter(e=>void 0!==e).sort((e,t)=>e-t)[0],[S({id:"0",title:"",children:D,...void 0===M?{}:{dateAdded:M}})])});case"bookmarks.get":{let[e]=t.args,r=Array.isArray(e)?e:[e];N({result:A(await m(t.extensionId,r.filter(e=>null!=e).map(String)))});return}case"bookmarks.getChildren":{let[e]=t.args;N({result:A(await p(t.extensionId,null==e?void 0:String(e)))});return}case"bookmarks.search":{let[e]=t.args;N({result:A(await h(t.extensionId,e))});return}case"bookmarks.create":{let[e]=t.args,r=await b(t.extensionId,e??{});N({result:r?S(r):null});return}case"bookmarks.update":{let[e,r]=t.args;if(u(e))return void N({error:s,refused:!0});let n=await w(t.extensionId,String(e??""),r??{});N({result:n?S(n):null});return}case"bookmarks.remove":{let[e]=t.args;if(u(e))return void N({error:s,refused:!0});N({result:await y(t.extensionId,String(e??""),!1)});return}case"bookmarks.removeTree":{let[e]=t.args;if(u(e))return void N({error:s,refused:!0});N({result:await y(t.extensionId,String(e??""),!0)});return}case"bookmarks.move":{let[e,r]=t.args;if(u(e))return void N({error:s,refused:!0});N({result:await v?.(t.extensionId,String(e??""),r??{})});return}case"history.search":{let[e]=t.args;N({result:await k(t.extensionId,e??{})});return}case"history.getVisits":{let[e]=t.args;N({result:await x(t.extensionId,e??{})});return}case"history.addUrl":{let[e]=t.args;await I(t.extensionId,e??{}),N({result:!0});return}case"history.deleteUrl":{let[e]=t.args;await T(t.extensionId,e??{}),N({result:!0});return}case"history.deleteRange":{let[e]=t.args;await $(t.extensionId,e??{}),N({result:!0});return}case"history.deleteAll":await E(t.extensionId),N({result:!0});return;case"windows.get":{let[e,o]=t.args;if(l(e)&&!d(r,e))return void N({error:i(e),refused:!0});let s=await n(t.extensionId,null==e?void 0:String(e),o);N({result:s?C(s,{populate:o?.populate}):null});return}case"windows.getAll":{let[e]=t.args;N({result:function(e,t={}){return e.map(e=>C(e,t))}(await o(t.extensionId,e),{populate:e?.populate})});return}case"windows.getCurrent":{let[e]=t.args,n=r.find(e=>e.focused)??r[0];N({result:n?C(n,{populate:e?.populate}):null});return}case"windows.create":{let[e]=t.args,r=await a(t.extensionId,e?.url);N({result:r?C(r,{populate:!0}):null});return}case"windows.update":{let[e,n]=t.args;if(l(e)&&!d(r,e))return void N({error:i(e),refused:!0});let o=await c(t.extensionId,null==e?void 0:String(e),n??{});N({result:o?C(o):null});return}case"windows.remove":{let[e]=t.args;if(l(e)&&!d(r,e))return void N({error:i(e),refused:!0});N({result:await f(t.extensionId,null==e?void 0:String(e))})}}}let E=new Set(["runtime.sendMessage","tabs.sendMessage","runtime.getContexts","permissions.contains","permissions.request","permissions.remove","permissions.getAll","offscreen.createDocument","offscreen.closeDocument","offscreen.hasDocument","cookies.get","cookies.getAll","cookies.set","cookies.remove","scripting.executeScript","scripting.insertCSS"]);async function N(e){let{data:t,onRuntimeMessage:r,onTabMessage:n,onGetRuntimeContexts:o,onContainsPermissions:s,onRequestPermissions:a,onRemovePermissions:i,onGetAllPermissions:l,onCreateOffscreenDocument:c,onCloseOffscreenDocument:d,onHasOffscreenDocument:u,onGetCookie:f,onGetAllCookies:g,onSetCookie:m,onRemoveCookie:p,onExecuteScript:h,onInsertCss:b,respond:w,source:y}=e;switch(t.api){case"runtime.sendMessage":{let[e]=t.args;w({result:await r(t.extensionId,e,y)});return}case"tabs.sendMessage":{let[e,r]=t.args;if(!n)return void w({error:"Could not establish connection. Receiving end does not exist."});w({result:await n(t.extensionId,e,r)});return}case"runtime.getContexts":return void w({result:await o(t.extensionId)});case"permissions.contains":{let[e]=t.args;w({result:await s(t.extensionId,e??{})});return}case"permissions.request":{let[e]=t.args;w({result:await a(t.extensionId,e??{})});return}case"permissions.remove":{let[e]=t.args;w({result:await i(t.extensionId,e??{})});return}case"permissions.getAll":return void w({result:await l(t.extensionId)});case"offscreen.createDocument":{let[e]=t.args,r=await c(t.extensionId,e??{});w({result:"boolean"!=typeof r||r});return}case"offscreen.closeDocument":{let e=await d(t.extensionId);w({result:"boolean"!=typeof e||e});return}case"offscreen.hasDocument":return void w({result:await u(t.extensionId)});case"cookies.get":{let[e]=t.args;w({result:await f(t.extensionId,e??{})});return}case"cookies.getAll":{let[e]=t.args;w({result:await g(t.extensionId,e??{})});return}case"cookies.set":{let[e]=t.args;w({result:await m(t.extensionId,e??{})});return}case"cookies.remove":{let[e]=t.args;w({result:await p(t.extensionId,e??{})});return}case"scripting.executeScript":{let[e]=t.args;w({result:await h(t.extensionId,e??{})});return}case"scripting.insertCSS":{let[e]=t.args;await b(t.extensionId,e??{}),w({result:!0})}}}let D=["local","sync","session","managed"];function M(){return[...f,...y,...k,...T,...E].sort()}function U(e,t){let r=Math.min(e.length,t.length),n=0;for(;n<r&&e[n]===t[n];)n+=1;return n}function R(e){let t=function(e){let t=M();if(t.includes(e))return null;let r=e.split(".");if(3===r.length&&"storage"===r[0]&&D.includes(r[1]??"")){let e=`storage.${r[2]}`;if(t.includes(e))return e}let n=r[r.length-1]??"",o=t.filter(e=>e.endsWith(`.${n}`));if(o.length)return o.sort((t,r)=>U(r,e)-U(t,e))[0];let s=t.filter(e=>e.startsWith(`${r[0]}.`));return s.length?s[0]??null:null}(e),r=`Unsupported API: ${e}.`;if(!t)return`${r} No wire name resembles it, so this API is not on the bridge at all. It may still work natively inside your extension's own contexts: the bridge is what an observer page can DRIVE, not the whole runtime.`;let n=t.startsWith("storage.")&&e.startsWith("storage.")?` The bridge takes the storage area as an ARGUMENT, not as part of the name: ${t}(keys, "local").`:"";return`${r} The closest wire name the bridge routes is ${t}.${n}`}let B={dom:"*",extension:["getURL","inIncognitoContext","lastError","onRequest","sendRequest"],i18n:"*",runtime:["connect","getManifest","getURL","getVersion","id","onConnect","onMessage","sendMessage"],scripting:["globalParams"],storage:"*"};function q(e){let[t="",r=""]=e.split("."),n=B[t];return"*"===n||!!Array.isArray(n)&&n.includes(r)}let P=M().filter(e=>!q(e));function O(e){var t;let r;return e.untrustedContext?q(e.api)?null:(r=(t=e.api).split(".")[0]??t,`chrome.${r} is not available to content scripts. Chrome gives a content script only chrome.storage, chrome.i18n, chrome.dom, chrome.extension and the messaging half of chrome.runtime, so ${t} cannot be reached from a page context. Call it from the background service worker or an extension page and reach the content script with runtime.sendMessage.`):null}let j=["extension","i18n","runtime","scripting","storage"],G=P.filter(e=>j.includes(e.split(".")[0]??""));JSON.stringify(j),JSON.stringify(G);let L=["url","pendingUrl","title","favIconUrl"],_=new Set(["tabs.get","tabs.query","tabs.create","tabs.update","tabs.move","tabs.discard"]),W=new Set(["windows.get","windows.getAll","windows.getCurrent","windows.create","windows.update"]),V=["url","title"];function H(e){return"<all_urls>"===e||e.includes("://")}function F(e,t){if(!e||"object"!=typeof e||function(e,t){if(e.has("tabs"))return!0;if(!t)return!1;for(let r of e){if(!H(r))continue;let e=function(e){let t;if("<all_urls>"===e)return/^(?:https?|file|ftp):\/\//;let r=/^(\*|https?|file|ftp):\/\/([^/]*)(\/.*)?$/.exec(e);if(!r)return null;let[,n="",o="",s="/*"]=r,a="*"===n?"https?":n.replace(/[.+?^${}()|[\]\\]/g,"\\$&");t="*"===o?"[^/]+":o.startsWith("*.")?`(?:[^/]+\\.)?${o.slice(2).replace(/[.+?^${}()|[\]\\]/g,"\\$&").replace(/\*/g,"[^/]*")}`:o.replace(/[.+?^${}()|[\]\\]/g,"\\$&").replace(/\*/g,"[^/]*");let i=s.replace(/[.+?^${}()|[\]\\]/g,"\\$&").replace(/\*/g,".*");return RegExp(`^${a}://${t}${i}$`)}(r);if(e?.test(t))return!0}return!1}(t,"string"==typeof e.url?e.url:"string"==typeof e.pendingUrl?e.pendingUrl:void 0))return e;let r={...e};for(let e of L)delete r[e];return r}function J(e,t){return e&&"object"==typeof e&&Array.isArray(e.tabs)?{...e,tabs:e.tabs.map(e=>F(e,t))}:e}let z={...e,storage:["storage"],scripting:["scripting","activeTab"]};function X(e,t){let r=e.split(".")[0]??"",n=z[r];return!n||null===t||n.some(e=>t.has(e))?null:`chrome.${r} needs the "${n.join('" or "')}" permission, which this session did not declare. Declare it in the manifest (and re-register the session) to use this API.`}let K=e=>"string"==typeof e&&e.length>0;function Q(e,t){return`Error in invocation of ${e}: ${t}`}function Y(e,t){return Q(e,`missing required property '${t}'`)}function Z(e,t,r,n){return Q(e,`'${t}' expects a ${r}, got ${typeof n}`)}async function ee(e){let{data:t,getDeclaredPermissions:r,getSessionStorageAccessLevel:n}=e,o=r?r(t.extensionId):void 0,s=r=>{var n,s;return e.respond("result"in r?{...r,result:(n=t.api,s=r.result,!o||o.has("tabs")?s:_.has(n)?Array.isArray(s)?s.map(e=>F(e,o)):F(s,o):W.has(n)?Array.isArray(s)?s.map(e=>J(e,o)):J(s,o):s)}:r)},a={...e,respond:s};try{var i;if(i=t.api,!(f.has(i)||y.has(i)||k.has(i)||T.has(i)||E.has(i)))return void s({error:R(t.api),refused:!0});let e=O(t);if(e)return void s({error:e,refused:!0});let r=function(e,t){let r=t[0];switch(e){case"downloads.download":if(!r||!("url"in r))return Y(e,"url");if(!K(r.url))return Z(e,"url","non-empty string",r.url);if(void 0!==r.filename&&"string"!=typeof r.filename)return Z(e,"filename","string",r.filename);return null;case"offscreen.createDocument":if(!r||!K(r.url))return Y(e,"url");if(!Array.isArray(r.reasons)||0===r.reasons.length)return Y(e,"reasons");if(!K(r.justification))return Y(e,"justification");return null;case"contextMenus.create":if(!r)return Y(e,"title");if(void 0!==r.id&&"string"!=typeof r.id)return Z(e,"id","string",r.id);if("separator"!==r.type&&!K(r.title))return Y(e,"title");return null;case"notifications.create":{let r="string"==typeof t[0]?t[1]:t[0];if(!r)return Y(e,"options");for(let t of["type","iconUrl","title","message"])if(!K(r[t]))return Y(e,t);return null}case"action.setTitle":if(r&&void 0!==r.title&&"string"!=typeof r.title)return Z(e,"title","string",r.title);return null;case"action.setBadgeText":if(r&&void 0!==r.text&&"string"!=typeof r.text)return Z(e,"text","string",r.text);return null;case"action.setBadgeBackgroundColor":if(!r||void 0===r.color)return Y(e,"color");if("string"!=typeof r.color&&!Array.isArray(r.color))return Z(e,"color","string or array",r.color);return null;case"tabs.create":if(r?.url!==void 0&&"string"!=typeof r.url)return Z(e,"url","string",r.url);return null;default:return null}}(t.api,t.args);if(r)return void s({error:r});let l=function(e,t,r){var n,o;let s=O(e);if(s)return s;if(void 0!==t){let r=X(e.api,t)??function(e,t,r){if("tabs.query"!==e||!r||r.has("tabs")||function(e){for(let t of e)if(H(t))return!0;return!1}(r))return null;let[n]=t;if(!n||"object"!=typeof n)return null;let o=V.filter(e=>void 0!==n[e]);return o.length?`chrome.tabs.query cannot filter by "${o.join('" or "')}" without the "tabs" permission or a matching host permission, which this session did not declare. Declare it in the manifest (and re-register the session) to filter on it.`:null}(e.api,e.args,t);if(r)return r}return e.untrustedContext&&e.api.startsWith("storage.")?"session"!==(n=e.api,o=e.args,"storage.clear"===n?o[0]:o[1])||"TRUSTED_AND_UNTRUSTED_CONTEXTS"===(r?.(e.extensionId)??"TRUSTED_CONTEXTS")?null:"Access to storage is not allowed from this context.":null}(t,o,n);if(l)return void s({error:l,refused:!0});if(f.has(t.api))return void await g(a);if(y.has(t.api))return void await v(a);if(k.has(t.api))return void await x(a);if(T.has(t.api))return void await $(a);if(E.has(t.api))return void await N(a);s({error:R(t.api),refused:!0})}catch(e){s({error:e instanceof Error?e.message:"Unknown error"})}}function et(e,t){if(t){if(/^(https?|blob|data|chrome-extension):/i.test(t))return t;if(e)for(let r of[t,t.replace(/^\.?\//,""),`/${t.replace(/^\.?\//,"")}`,`./${t.replace(/^\.?\//,"")}`]){let t=e[r];if(t)return t}}}async function er(e){let t=await fetch(e);if(!t.ok)throw Error(`could not read the guest asset (HTTP ${t.status})`);let r=await t.blob(),n=new Uint8Array(await r.arrayBuffer()),o="";for(let e of n)o+=String.fromCharCode(e);let s=r.type||"application/octet-stream";return`data:${s};base64,${btoa(o)}`}async function en(e){let t=await fetch(e);if(!t.ok)throw Error(`could not read the guest icon (HTTP ${t.status})`);let r=await createImageBitmap(await t.blob());try{let e=new OffscreenCanvas(r.width,r.height).getContext("2d");if(!e)throw Error("no 2d context is available to decode the guest icon");return e.drawImage(r,0,0),e.getImageData(0,0,r.width,r.height)}finally{r.close()}}async function eo(e,t){let r={...e};for(let e of["iconUrl","imageUrl","appIconMaskUrl"]){let n=et(t,r[e]);n&&(r[e]=await er(n))}return Array.isArray(r.buttons)&&(r.buttons=await Promise.all(r.buttons.map(async e=>{let r=et(t,e.iconUrl);return r?{...e,iconUrl:await er(r)}:e}))),r}function es(e,t){throw Error(`${e} did not run on the real lane: ${t}`)}let ea=e=>{let t=Number(e);return Number.isFinite(t)?t:void 0},ei=e=>{let t=Number(e);return Number.isFinite(t)?t:void 0},el=new Set(["system.cpu.getInfo","system.memory.getInfo","system.storage.getInfo","system.storage.ejectDevice","system.display.getInfo","system.display.getDisplayLayout","system.display.setDisplayProperties","system.display.setDisplayLayout"]),ec=["topSites","fontSettings","printing","power","tts","userScripts","debugger","system.network","enterprise.deviceAttributes","instanceID","identity","webNavigation","proxy.settings","contentSettings","tabCapture"].sort((e,t)=>t.length-e.length);function ed(e){if(el.has(e))return"refused";for(let t of ec)if(e===t||e.startsWith(`${t}.`))return"mocked";return"emulated"}let eu=/^__(ext|extjs|extension)[a-z0-9-]*__$/i,ef=new Set(["runtime.connect","runtime.onConnect","runtime.sendMessage","runtime.onMessage","tabs.connect","tabs.sendMessage"]);function eg(e){return"string"==typeof e&&eu.test(e)}let em=new Set(["storage","action","offscreen","runtime","tabs.sendMessage","scripting","downloads","notifications","contextMenus"]);function ep(e){return!!e&&(e.startsWith("Unsupported API: ")||e.startsWith("No backend implements ")||/needs the ".+" permission, which this (session did not declare|extension's manifest does not declare)/.test(e))}function eh(e){return e.refused||ep(e.error)?"refused":"real"===e.lane?"real":ed(e.api)}let eb=new Set(["local","sync","session","managed"]);function ew(e,t){let r=e.split(".");if("storage"!==r[0])return e;if(3===r.length&&eb.has(r[1]??""))return`storage.${r[2]}@${r[1]}`;if(2===r.length){let e="clear"===r[1]?t?.[0]:t?.[1];return`storage.${r[1]}@${"string"==typeof e?e:"local"}`}return e}let ey=new TextEncoder;function ev(e,t){return{path:e,bytes:ey.encode(t),text:t}}let ek={manifest_version:3,name:"Hello Emulator",version:"0.1.0",description:"Trace fixture exercising emulated, mocked, and refused chrome.* tiers.",permissions:["storage","tabs","notifications","system.cpu","bookmarks","history","cookies","alarms","topSites","fontSettings","power","tts","identity","webNavigation"],action:{default_title:"Hello Emulator",default_popup:"popup.html"},background:{service_worker:"background.js"}},ex=`<!doctype html>
|
|
10
2
|
<html>
|
|
11
3
|
<head>
|
|
12
4
|
<meta charset="utf-8" />
|
|
@@ -164,7 +156,7 @@ document.getElementById("battery").addEventListener("click", async () => {
|
|
|
164
156
|
failed: failed.length ? failed : "none",
|
|
165
157
|
});
|
|
166
158
|
});
|
|
167
|
-
`,
|
|
159
|
+
`,eS=`chrome.runtime.onInstalled.addListener(() => {
|
|
168
160
|
console.log("[hello-emulator] installed");
|
|
169
161
|
});
|
|
170
162
|
|
|
@@ -174,4 +166,4 @@ chrome.runtime.onMessage.addListener((message, _sender, sendResponse) => {
|
|
|
174
166
|
}
|
|
175
167
|
return true;
|
|
176
168
|
});
|
|
177
|
-
`;ey("manifest.json",JSON.stringify(ev,null,2)),ey("popup.html",ex),ey("popup.js",eI),ey("background.js",ek),ev.name;let{PING:eS,PONG:eA,BRIDGE:eC,SESSION:eT,INJECT:e$,EVENT_PORT:eE,EVENT:eN,TRACE:eD}={PING:"extensiondev:ping",PONG:"extensiondev:pong",BRIDGE:"extensiondev:bridge",SESSION:"extensiondev:session",INJECT:"extensiondev:inject",EVENT_PORT:"extensiondev:events",EVENT:"extensiondev:event",TRACE:"extensiondev:trace"},eM=function(e={}){let t=e.engine??"chromium-emulated",r=e.limit??500,n=e.now??(()=>new Date),o=n().toISOString(),s=[],a=new Set,i=0,l=e=>{for(s.push(e);s.length>r;){let e=s.findIndex(e=>"framework"===e.attribution);s.splice(-1===e?0:e,1)}for(let t of a)t(e);return e};return{recordCall(e,r,o,s){let a=o??[];return l({seq:i+=1,api:e,args:a,extensionId:r,at:n().toISOString(),tier:ec(e),engine:t,policy:s,...!function(e,t=[]){if(!eu.has(e))return!1;for(let e of t)if(eg(e)||e&&"object"==typeof e&&(eg(e.name)||eg(e.type)||eg(e.channel)))return!0;return!1}(e,a)?{}:{attribution:"framework"}})},recordOutcome(e){let r=ew(e.api,e.args),o=s.find(t=>t.extensionId===e.extensionId&&ew(t.api,t.args)===r&&void 0===t.status&&void 0===t.requestId),c={requestId:e.requestId,lane:e.lane,status:void 0===e.error?"ok":"error",error:e.error,result:e.result,durationMs:e.durationMs,laneDowngraded:e.laneDowngraded||void 0,downgradeReason:e.downgradeReason,carrierScoped:!e.refused&&!em(e.error)&&function(e,t){if("real"!==t)return!1;if(ef.has(e))return!0;let r=e.split(".")[0]??"";return ef.has(r)}(e.api,e.lane)||void 0};if(o){Object.assign(o,c),o.tier=ep(e);for(let e of a)e(o);return o}return l({seq:i+=1,api:e.api,args:e.args,extensionId:e.extensionId,at:n().toISOString(),tier:ep(e),engine:t,...c})},events:()=>[...s],snapshot(){let e={real:0,emulated:0,mocked:0,refused:0},r=0;for(let t of s)e[t.tier??ec(t.api)]+=1,"error"===t.status&&(r+=1);return{engine:t,startedAt:o,events:[...s],counts:{total:s.length,byTier:e,errors:r}}},subscribe:e=>(a.add(e),()=>a.delete(e)),clear(){s.length=0}}}({engine:"chromium-real"}),eU=new Set;eM.subscribe(e=>{for(let t of eU)try{t.postMessage({type:eD,event:e})}catch{}});let eR=new Map,eB=function(e={}){let t={local:{},sync:{},session:{},managed:{}},r=e=>chrome.storage[e??"local"]??chrome.storage.local,n=e=>t[e??"local"]??t.local;for(let e of["local","sync","session","managed"])r(e).get(null).then(t=>{Object.assign(n(e),t)}).catch(()=>void 0);chrome.storage.onChanged.addListener((e,r)=>{if(!(r in t))return;let o=n(r);for(let[t,r]of Object.entries(e))void 0===r.newValue?delete o[t]:o[t]=r.newValue});let o=new Map;return{getStorage:(e,t)=>({...n(t)}),setStorage:(e,t,o)=>(Object.assign(n(o),t),r(o).set(t)),removeStorageKeys:(e,t,o)=>{let s=n(o);for(let e of t)delete s[e];return r(o).remove(t)},clearStorage:(e,t)=>{let o=n(t);for(let e of Object.keys(o))delete o[e];return r(t).clear()},onSetStorageAccessLevel:async(e,t,r)=>{if("session"!==t)return;o.set(e,r);let n=chrome.storage.session;await n.setAccessLevel?.({accessLevel:r})},getSessionStorageAccessLevel:e=>o.get(e),...function(e={}){return{onCreateTab:(e,t)=>chrome.tabs.create({url:e,...t?.active!==void 0?{active:t.active}:{},...t?.pinned!==void 0?{pinned:t.pinned}:{},...t?.index!==void 0?{index:t.index}:{},...t?.windowId!==void 0?{windowId:t.windowId}:{},...t?.openerTabId!==void 0?{openerTabId:t.openerTabId}:{}}),onUpdateTab:(e,t)=>{let r=es(e);return null!=r?chrome.tabs.update(r,t):chrome.tabs.update(t)},onRemoveTab:e=>{let t=es(e);return null==t&&eo("tabs.remove",`"${String(e)}" is not a real tab id`),chrome.tabs.remove(t)},onDiscardTab:(e,t)=>{let r=es(t);return null!=r?chrome.tabs.discard(r):chrome.tabs.discard()},onGroupTabs:async(e,t)=>{let r=Array.isArray(t.tabIds)?t.tabIds:void 0!==t.tabIds?[t.tabIds]:[];return r.length||eo("tabs.group","no tabIds were given to group"),chrome.tabs.group({tabIds:r,...void 0===t.groupId?{}:{groupId:t.groupId}})},onUngroupTabs:(e,t)=>chrome.tabs.ungroup(Array.isArray(t)?t:[t]),onGetWindow:(e,t,r)=>{let n=ea(t);return null==n?chrome.windows.getCurrent(r??{}):chrome.windows.get(n,r??{})},onGetAllWindows:(e,t)=>chrome.windows.getAll(t??{}),onCreateWindow:(e,t)=>chrome.windows.create({url:t}),onUpdateWindow:(e,t,r)=>{let n=ea(t);return null==n?null:chrome.windows.update(n,r)},onRemoveWindow:async(e,t)=>{let r=ea(t);return null!=r&&(await chrome.windows.remove(r),!0)},onOpenSidePanel:async()=>{let e=await chrome.windows.getCurrent();null==e.id&&eo("sidePanel.open","there is no focused window to open it in"),await chrome.sidePanel.open({windowId:e.id})},onSetBadgeText:(e,t,r)=>{let n=es(r);return chrome.action.setBadgeText(null!=n?{text:t??"",tabId:n}:{text:t??""})},onSetBadgeBackground:(e,t,r)=>{t||eo("action.setBadgeBackgroundColor","no color was given");let n=es(r);return chrome.action.setBadgeBackgroundColor(null!=n?{color:t,tabId:n}:{color:t})},onSetActionTitle:(e,t,r)=>{let n=es(r);return chrome.action.setTitle(null!=n?{title:t??"",tabId:n}:{title:t??""})},onGetActionState:async(e,t)=>{let r=es(t),n=null!=r?{tabId:r}:{},[o,s,a]=await Promise.all([chrome.action.getBadgeText(n),chrome.action.getBadgeBackgroundColor(n),chrome.action.getTitle(n)]);return{badgeText:o,badgeColor:Array.isArray(s)?`rgba(${s[0]}, ${s[1]}, ${s[2]}, ${(s[3]??255)/255})`:s??void 0,title:a}},onSetActionIcon:async(t,r)=>{r||eo("action.setIcon","no icon path was given");let n=ee(e.getGuestAssetUrls?.(t),r);return n||eo("action.setIcon",`"${r}" is not in this guest's asset map, so the carrier cannot reach it`),chrome.action.setIcon({imageData:await er(n)})},onCreateContextMenu:(e,t)=>chrome.contextMenus.create(t),onUpdateContextMenu:async(e,t,r)=>(await chrome.contextMenus.update(t,r),!0),onRemoveContextMenu:async(e,t)=>(await chrome.contextMenus.remove(t),!0),onClearContextMenus:async()=>(await chrome.contextMenus.removeAll(),!0),onCreateNotification:async(t,r,n)=>chrome.notifications.create(r??"",await en(n??{},e.getGuestAssetUrls?.(t))),onClearNotification:(e,t)=>chrome.notifications.clear(t),onGetNotifications:()=>chrome.notifications.getAll(),onDownload:(e,t)=>chrome.downloads.download(t),onSearchDownloads:(e,t)=>chrome.downloads.search(t??{}),onCancelDownload:async(e,t)=>{await chrome.downloads.cancel(t).catch(()=>void 0)},onPauseDownload:(e,t)=>chrome.downloads.pause(t),onResumeDownload:(e,t)=>chrome.downloads.resume(t),onEraseDownloads:(e,t)=>chrome.downloads.erase(t??{}),onGetBookmarkTree:()=>chrome.bookmarks.getTree(),onGetBookmarks:(e,t)=>chrome.bookmarks.get(t),onGetBookmarkChildren:(e,t)=>t?chrome.bookmarks.getChildren(t):chrome.bookmarks.getTree(),onSearchBookmarks:(e,t)=>chrome.bookmarks.search(t??""),onCreateBookmark:(e,t)=>chrome.bookmarks.create(t),onUpdateBookmark:(e,t,r)=>chrome.bookmarks.update(t,r),onRemoveBookmark:async(e,t,r)=>(r?await chrome.bookmarks.removeTree(t):await chrome.bookmarks.remove(t),!0),onMoveBookmark:(e,t,r)=>chrome.bookmarks.move(t,r),onSearchHistory:(e,t)=>chrome.history.search({text:t?.text??"",...t}),onGetHistoryVisits:(e,t)=>chrome.history.getVisits({url:t?.url??""}),onAddHistoryUrl:async(e,t)=>{t?.url&&await chrome.history.addUrl({url:t.url})},onDeleteHistoryUrl:async(e,t)=>{t?.url&&await chrome.history.deleteUrl({url:t.url})},onDeleteHistoryRange:async(e,t)=>{await chrome.history.deleteRange({startTime:t?.startTime??0,endTime:t?.endTime??Date.now()})},onDeleteAllHistory:async()=>{await chrome.history.deleteAll()},onRuntimeMessage:(e,t)=>chrome.runtime.sendMessage(t),onGetRuntimeContexts:()=>chrome.runtime.getContexts({}),onContainsPermissions:(e,t)=>chrome.permissions.contains(t),onRequestPermissions:(e,t)=>chrome.permissions.request(t),onRemovePermissions:(e,t)=>chrome.permissions.remove(t),onGetAllPermissions:async()=>{let e=await chrome.permissions.getAll();return{permissions:e.permissions??[],origins:e.origins??[]}},onCreateOffscreenDocument:async(e,t)=>{let r=t?.url;eo("offscreen.createDocument",`the shared Live Preview carrier cannot host "${r??"an offscreen document"}", because Chrome only loads offscreen documents from the extension that asks for one. Run \`extension dev\` to load this extension as itself, where offscreen documents work normally`)},onCloseOffscreenDocument:async()=>(await chrome.offscreen.closeDocument(),await chrome.offscreen.hasDocument().catch(()=>!1)&&eo("offscreen.closeDocument","the offscreen document was still open after closeDocument resolved"),!0),onHasOffscreenDocument:()=>chrome.offscreen.hasDocument(),onGetCookie:(e,t)=>chrome.cookies.get(t),onGetAllCookies:(e,t)=>chrome.cookies.getAll(t),onSetCookie:(e,t)=>chrome.cookies.set(t),onRemoveCookie:(e,t)=>chrome.cookies.remove(t),onExecuteScript:(e,t)=>{let r=es(t.target?.tabId);return null==r&&eo("scripting.executeScript",`target.tabId "${String(t.target?.tabId)}" is not a real tab id`),t.files?.length||eo("scripting.executeScript","only the `files` form is supported here; a func/code body cannot be serialized across the bridge into a real page. Ship the code as a file in your extension and pass files: [...]"),chrome.scripting.executeScript({target:{tabId:r},files:t.files})},onInsertCss:async(e,t)=>{let r=es(t.target?.tabId);(null==r&&eo("scripting.insertCSS",`target.tabId "${String(t.target?.tabId)}" is not a real tab id`),t.css)?await chrome.scripting.insertCSS({target:{tabId:r},css:t.css}):t.files?.length?await chrome.scripting.insertCSS({target:{tabId:r},files:t.files}):eo("scripting.insertCSS","neither css nor files was given")}}}(e)}}({getGuestAssetUrls:e=>eR.get(e)}),eP=globalThis.crypto?.randomUUID?.()??String(Date.now()),eO=new Set(["TRUSTED_CONTEXTS","TRUSTED_AND_UNTRUSTED_CONTEXTS"]),ej=new Map;async function eq(){try{return(await chrome.windows.getAll({populate:!0})).map(e=>{let t=e.tabs??[],r=t.find(e=>e.active);return{id:e.id??void 0,focused:e.focused,activeTabId:r?.id??"",tabs:t.map(e=>({id:e.id??"",url:e.url??e.pendingUrl??"",title:e.title??"",active:e.active,index:e.index,status:e.status,pinned:e.pinned,discarded:e.discarded,incognito:e.incognito,tabGroupId:e.groupId}))}})}catch{return[]}}async function eG(e){let t,r=Date.now(),n=t=>(eM.recordOutcome({requestId:e.requestId,extensionId:e.extensionId,api:e.api,args:e.args,lane:"real",result:t.result,error:t.error,durationMs:Date.now()-r,source:"frame",...t.refused?{refused:!0}:{}}),t),o=(t=z(e.api,ej.get(e.extensionId)??new Set))?{error:t,refused:!0}:null;if(o)return n(o);let s="tabs.query"===e.api||"tabs.get"===e.api||"windows.getCurrent"===e.api?await eq():[];return new Promise(t=>{let r=!1,o=e=>{r||(r=!0,t(n(e)))};Z({data:e,windows:s,...eB,getDeclaredPermissions:e=>ej.get(e)??new Set,respond:o,source:"frame"}).catch(e=>o({error:e instanceof Error?e.message:"Bridge error"}))})}async function eL(e){let t,r,{extensionId:n,url:o,code:s,css:a,matches:i=[]}=e,l=!0===e.active,c=ej.get(n);if(!(c&&(c.has("scripting")||c.has("activeTab"))))return{ok:!1,error:'This extension does not declare the "scripting" (or "activeTab") permission.'};if(!i.length||!i.some(e=>{let t=function(e){let t;if("<all_urls>"===e)return/^https?:\/\/.*/;let r=/^(\*|https?|file|ftp):\/\/([^/]*)(\/.*)$/.exec(e);if(!r)return null;let[,n="",o="",s=""]=r,a="*"===n?"https?":n.replace(/[.+?^${}()|[\]\\]/g,"\\$&");t="*"===o?"[^/]+":o.startsWith("*.")?`(?:[^/]+\\.)?${o.slice(2).replace(/[.+?^${}()|[\]\\]/g,"\\$&").replace(/\*/g,"[^/]*")}`:o.replace(/[.+?^${}()|[\]\\]/g,"\\$&").replace(/\*/g,"[^/]*");let i=s.replace(/[.+?^${}()|[\]\\]/g,"\\$&").replace(/\*/g,".*");return RegExp(`^${a}://${t}${i}$`)}(e);return!!t&&t.test(o)}))return{ok:!1,error:`This extension's content scripts / host permissions do not match ${o}.`};try{t=await chrome.tabs.create({url:o,active:l})}catch(e){return{ok:!1,error:`Could not open the tab: ${String(e)}`}}let d=t.id;if(null==d)return{ok:!1,error:"No tab id."};if(await new Promise(e=>{let t=setTimeout(()=>e(),8e3),r=(n,o)=>{n===d&&"complete"===o.status&&(clearTimeout(t),chrome.tabs.onUpdated.removeListener(r),e())};chrome.tabs.onUpdated.addListener(r)}),a)try{await chrome.scripting.insertCSS({target:{tabId:d},css:a})}catch(e){r=String(e)}let u={tabId:d,active:l};if(!s)return{ok:!0,injected:!1,...u,...r?{cssError:r}:{}};try{let[e]=await chrome.scripting.executeScript({target:{tabId:d},world:"MAIN",func:e=>{try{return(0,eval)(e),{ran:!0}}catch(e){return{ran:!1,error:String(e)}}},args:[s]}),t=e?.result;if(t&&!1===t.ran)return{ok:!0,injected:!1,blocked:!0,reason:t.error,...u,...r?{cssError:r}:{}};return{ok:!0,injected:!0,...u,...r?{cssError:r}:{}}}catch(e){return{ok:!1,error:`Injection failed: ${String(e)}`}}}chrome.runtime.onInstalled.addListener(()=>{}),chrome.runtime.onConnectExternal.addListener(e=>{if(e.name!==eE)return;for(let t of(eU.add(e),eM.events()))try{e.postMessage({type:eD,event:t,backlog:!0})}catch{break}let t=[],r=(r,n)=>{let o=chrome[r],s=o?.[n];if(!s||"function"!=typeof s.addListener)return;let a=(...t)=>((t,r,n)=>{try{e.postMessage({type:eN,namespace:t,event:r,args:n})}catch{}})(r,n,t);s.addListener(a),t.push(()=>s.removeListener(a))};r("storage","onChanged"),r("alarms","onAlarm"),r("tabs","onCreated"),r("tabs","onUpdated"),r("tabs","onRemoved"),r("tabs","onActivated"),r("windows","onCreated"),r("windows","onRemoved"),r("windows","onFocusChanged"),r("bookmarks","onCreated"),r("bookmarks","onChanged"),r("bookmarks","onMoved"),r("bookmarks","onRemoved"),r("history","onVisited"),r("history","onVisitRemoved"),r("downloads","onCreated"),r("downloads","onChanged"),r("downloads","onErased"),r("cookies","onChanged"),r("notifications","onClicked"),r("notifications","onClosed"),r("notifications","onButtonClicked"),r("contextMenus","onClicked"),e.onDisconnect.addListener(()=>{for(let r of(eU.delete(e),t))r()})}),chrome.runtime.onMessageExternal.addListener((e,t,r)=>{if(e?.type===eS)return r({type:eA,version:chrome.runtime.getManifest().version,ready:!0,workerEpoch:eP}),!1;if(e?.type===eT&&"string"==typeof e.extensionId){var n,o;return ej.set(e.extensionId,new Set(Array.isArray(e.permissions)?e.permissions:[])),e.assetUrls&&"object"==typeof e.assetUrls&&eR.set(e.extensionId,e.assetUrls),n=e.extensionId,"string"==typeof(o=e.sessionAccessLevel)&&eO.has(o)&&Promise.resolve(eB.onSetStorageAccessLevel?.(n,"session",o)).catch(()=>void 0),r({ok:!0,workerEpoch:eP}),!1}return e?.type===eC&&e.request?(eG(e.request).then(r),!0):e?.type===e$&&"string"==typeof e.url&&(eL(e).then(r),!0)})})();
|
|
169
|
+
`;ev("manifest.json",JSON.stringify(ek,null,2)),ev("popup.html",ex),ev("popup.js",eI),ev("background.js",eS),ek.name;let{PING:eA,PONG:eC,BRIDGE:eT,SESSION:e$,INJECT:eE,EVENT_PORT:eN,EVENT:eD,TRACE:eM}={PING:"extensiondev:ping",PONG:"extensiondev:pong",BRIDGE:"extensiondev:bridge",SESSION:"extensiondev:session",INJECT:"extensiondev:inject",EVENT_PORT:"extensiondev:events",EVENT:"extensiondev:event",TRACE:"extensiondev:trace"},eU=function(e={}){let t=e.engine??"chromium-emulated",r=e.limit??500,n=e.now??(()=>new Date),o=n().toISOString(),s=[],a=new Set,i=0,l=e=>{for(s.push(e);s.length>r;){let e=s.findIndex(e=>"framework"===e.attribution);s.splice(-1===e?0:e,1)}for(let t of a)t(e);return e};return{recordCall(e,r,o,s){let a=o??[];return l({seq:i+=1,api:e,args:a,extensionId:r,at:n().toISOString(),tier:ed(e),engine:t,policy:s,...!function(e,t=[]){if(!ef.has(e))return!1;for(let e of t)if(eg(e)||e&&"object"==typeof e&&(eg(e.name)||eg(e.type)||eg(e.channel)))return!0;return!1}(e,a)?{}:{attribution:"framework"}})},recordOutcome(e){let r=ew(e.api,e.args),o=s.find(t=>t.extensionId===e.extensionId&&ew(t.api,t.args)===r&&void 0===t.status&&void 0===t.requestId),c={requestId:e.requestId,lane:e.lane,status:void 0===e.error?"ok":"error",error:e.error,result:e.result,durationMs:e.durationMs,laneDowngraded:e.laneDowngraded||void 0,downgradeReason:e.downgradeReason,carrierScoped:!e.refused&&!ep(e.error)&&function(e,t){if("real"!==t)return!1;if(em.has(e))return!0;let r=e.split(".")[0]??"";return em.has(r)}(e.api,e.lane)||void 0};if(o){Object.assign(o,c),o.tier=eh(e);for(let e of a)e(o);return o}return l({seq:i+=1,api:e.api,args:e.args,extensionId:e.extensionId,at:n().toISOString(),tier:eh(e),engine:t,...c})},events:()=>[...s],snapshot(){let e={real:0,emulated:0,mocked:0,refused:0},r=0;for(let t of s)e[t.tier??ed(t.api)]+=1,"error"===t.status&&(r+=1);return{engine:t,startedAt:o,events:[...s],counts:{total:s.length,byTier:e,errors:r}}},subscribe:e=>(a.add(e),()=>a.delete(e)),clear(){s.length=0}}}({engine:"chromium-real"}),eR=new Set;eU.subscribe(e=>{for(let t of eR)try{t.postMessage({type:eM,event:e})}catch{}});let eB=new Map,eq=function(e={}){let t={local:{},sync:{},session:{},managed:{}},r=e=>chrome.storage[e??"local"]??chrome.storage.local,n=e=>t[e??"local"]??t.local;for(let e of["local","sync","session","managed"])r(e).get(null).then(t=>{Object.assign(n(e),t)}).catch(()=>void 0);chrome.storage.onChanged.addListener((e,r)=>{if(!(r in t))return;let o=n(r);for(let[t,r]of Object.entries(e))void 0===r.newValue?delete o[t]:o[t]=r.newValue});let o=new Map;return{getStorage:(e,t)=>({...n(t)}),setStorage:(e,t,o)=>(Object.assign(n(o),t),r(o).set(t)),removeStorageKeys:(e,t,o)=>{let s=n(o);for(let e of t)delete s[e];return r(o).remove(t)},clearStorage:(e,t)=>{let o=n(t);for(let e of Object.keys(o))delete o[e];return r(t).clear()},onSetStorageAccessLevel:async(e,t,r)=>{if("session"!==t)return;o.set(e,r);let n=chrome.storage.session;await n.setAccessLevel?.({accessLevel:r})},getSessionStorageAccessLevel:e=>o.get(e),...function(e={}){return{onCreateTab:(e,t)=>chrome.tabs.create({url:e,...t?.active!==void 0?{active:t.active}:{},...t?.pinned!==void 0?{pinned:t.pinned}:{},...t?.index!==void 0?{index:t.index}:{},...t?.windowId!==void 0?{windowId:t.windowId}:{},...t?.openerTabId!==void 0?{openerTabId:t.openerTabId}:{}}),onUpdateTab:(e,t)=>{let r=ea(e);return null!=r?chrome.tabs.update(r,t):chrome.tabs.update(t)},onRemoveTab:e=>{let t=ea(e);return null==t&&es("tabs.remove",`"${String(e)}" is not a real tab id`),chrome.tabs.remove(t)},onDiscardTab:(e,t)=>{let r=ea(t);return null!=r?chrome.tabs.discard(r):chrome.tabs.discard()},onGroupTabs:async(e,t)=>{let r=Array.isArray(t.tabIds)?t.tabIds:void 0!==t.tabIds?[t.tabIds]:[];return r.length||es("tabs.group","no tabIds were given to group"),chrome.tabs.group({tabIds:r,...void 0===t.groupId?{}:{groupId:t.groupId}})},onUngroupTabs:(e,t)=>chrome.tabs.ungroup(Array.isArray(t)?t:[t]),onGetWindow:(e,t,r)=>{let n=ei(t);return null==n?chrome.windows.getCurrent(r??{}):chrome.windows.get(n,r??{})},onGetAllWindows:(e,t)=>chrome.windows.getAll(t??{}),onCreateWindow:(e,t)=>chrome.windows.create({url:t}),onUpdateWindow:(e,t,r)=>{let n=ei(t);return null==n?null:chrome.windows.update(n,r)},onRemoveWindow:async(e,t)=>{let r=ei(t);return null!=r&&(await chrome.windows.remove(r),!0)},onOpenSidePanel:async()=>{let e=await chrome.windows.getCurrent();null==e.id&&es("sidePanel.open","there is no focused window to open it in"),await chrome.sidePanel.open({windowId:e.id})},onSetBadgeText:(e,t,r)=>{let n=ea(r);return chrome.action.setBadgeText(null!=n?{text:t??"",tabId:n}:{text:t??""})},onSetBadgeBackground:(e,t,r)=>{t||es("action.setBadgeBackgroundColor","no color was given");let n=ea(r);return chrome.action.setBadgeBackgroundColor(null!=n?{color:t,tabId:n}:{color:t})},onSetActionTitle:(e,t,r)=>{let n=ea(r);return chrome.action.setTitle(null!=n?{title:t??"",tabId:n}:{title:t??""})},onGetActionState:async(e,t)=>{let r=ea(t),n=null!=r?{tabId:r}:{},[o,s,a]=await Promise.all([chrome.action.getBadgeText(n),chrome.action.getBadgeBackgroundColor(n),chrome.action.getTitle(n)]);return{badgeText:o,badgeColor:Array.isArray(s)?`rgba(${s[0]}, ${s[1]}, ${s[2]}, ${(s[3]??255)/255})`:s??void 0,title:a}},onSetActionIcon:async(t,r)=>{r||es("action.setIcon","no icon path was given");let n=et(e.getGuestAssetUrls?.(t),r);return n||es("action.setIcon",`"${r}" is not in this guest's asset map, so the carrier cannot reach it`),chrome.action.setIcon({imageData:await en(n)})},onCreateContextMenu:(e,t)=>chrome.contextMenus.create(t),onUpdateContextMenu:async(e,t,r)=>(await chrome.contextMenus.update(t,r),!0),onRemoveContextMenu:async(e,t)=>(await chrome.contextMenus.remove(t),!0),onClearContextMenus:async()=>(await chrome.contextMenus.removeAll(),!0),onCreateNotification:async(t,r,n)=>chrome.notifications.create(r??"",await eo(n??{},e.getGuestAssetUrls?.(t))),onClearNotification:(e,t)=>chrome.notifications.clear(t),onGetNotifications:()=>chrome.notifications.getAll(),onDownload:(e,t)=>chrome.downloads.download(t),onSearchDownloads:(e,t)=>chrome.downloads.search(t??{}),onCancelDownload:async(e,t)=>{await chrome.downloads.cancel(t).catch(()=>void 0)},onPauseDownload:(e,t)=>chrome.downloads.pause(t),onResumeDownload:(e,t)=>chrome.downloads.resume(t),onEraseDownloads:(e,t)=>chrome.downloads.erase(t??{}),onGetBookmarkTree:()=>chrome.bookmarks.getTree(),onGetBookmarks:(e,t)=>chrome.bookmarks.get(t),onGetBookmarkChildren:(e,t)=>t?chrome.bookmarks.getChildren(t):chrome.bookmarks.getTree(),onSearchBookmarks:(e,t)=>chrome.bookmarks.search(t??""),onCreateBookmark:(e,t)=>chrome.bookmarks.create(t),onUpdateBookmark:(e,t,r)=>chrome.bookmarks.update(t,r),onRemoveBookmark:async(e,t,r)=>(r?await chrome.bookmarks.removeTree(t):await chrome.bookmarks.remove(t),!0),onMoveBookmark:(e,t,r)=>chrome.bookmarks.move(t,r),onSearchHistory:(e,t)=>chrome.history.search({text:t?.text??"",...t}),onGetHistoryVisits:(e,t)=>chrome.history.getVisits({url:t?.url??""}),onAddHistoryUrl:async(e,t)=>{t?.url&&await chrome.history.addUrl({url:t.url})},onDeleteHistoryUrl:async(e,t)=>{t?.url&&await chrome.history.deleteUrl({url:t.url})},onDeleteHistoryRange:async(e,t)=>{await chrome.history.deleteRange({startTime:t?.startTime??0,endTime:t?.endTime??Date.now()})},onDeleteAllHistory:async()=>{await chrome.history.deleteAll()},onRuntimeMessage:(e,t)=>chrome.runtime.sendMessage(t),onGetRuntimeContexts:()=>chrome.runtime.getContexts({}),onContainsPermissions:(e,t)=>chrome.permissions.contains(t),onRequestPermissions:(e,t)=>chrome.permissions.request(t),onRemovePermissions:(e,t)=>chrome.permissions.remove(t),onGetAllPermissions:async()=>{let e=await chrome.permissions.getAll();return{permissions:e.permissions??[],origins:e.origins??[]}},onCreateOffscreenDocument:async(e,t)=>{let r=t?.url;es("offscreen.createDocument",`the shared Live Preview carrier cannot host "${r??"an offscreen document"}", because Chrome only loads offscreen documents from the extension that asks for one. Run \`extension dev\` to load this extension as itself, where offscreen documents work normally`)},onCloseOffscreenDocument:async()=>(await chrome.offscreen.closeDocument(),await chrome.offscreen.hasDocument().catch(()=>!1)&&es("offscreen.closeDocument","the offscreen document was still open after closeDocument resolved"),!0),onHasOffscreenDocument:()=>chrome.offscreen.hasDocument(),onGetCookie:(e,t)=>chrome.cookies.get(t),onGetAllCookies:(e,t)=>chrome.cookies.getAll(t),onSetCookie:(e,t)=>chrome.cookies.set(t),onRemoveCookie:(e,t)=>chrome.cookies.remove(t),onExecuteScript:(e,t)=>{let r=ea(t.target?.tabId);return null==r&&es("scripting.executeScript",`target.tabId "${String(t.target?.tabId)}" is not a real tab id`),t.files?.length||es("scripting.executeScript","only the `files` form is supported here; a func/code body cannot be serialized across the bridge into a real page. Ship the code as a file in your extension and pass files: [...]"),chrome.scripting.executeScript({target:{tabId:r},files:t.files})},onInsertCss:async(e,t)=>{let r=ea(t.target?.tabId);(null==r&&es("scripting.insertCSS",`target.tabId "${String(t.target?.tabId)}" is not a real tab id`),t.css)?await chrome.scripting.insertCSS({target:{tabId:r},css:t.css}):t.files?.length?await chrome.scripting.insertCSS({target:{tabId:r},files:t.files}):es("scripting.insertCSS","neither css nor files was given")}}}(e)}}({getGuestAssetUrls:e=>eB.get(e)}),eP=globalThis.crypto?.randomUUID?.()??String(Date.now()),eO=new Set(["TRUSTED_CONTEXTS","TRUSTED_AND_UNTRUSTED_CONTEXTS"]),ej=new Map;async function eG(){try{return(await chrome.windows.getAll({populate:!0})).map(e=>{let t=e.tabs??[],r=t.find(e=>e.active);return{id:e.id??void 0,focused:e.focused,activeTabId:r?.id??"",tabs:t.map(e=>({id:e.id??"",url:e.url??e.pendingUrl??"",title:e.title??"",active:e.active,index:e.index,status:e.status,pinned:e.pinned,discarded:e.discarded,incognito:e.incognito,tabGroupId:e.groupId}))}})}catch{return[]}}async function eL(e){let t,r=Date.now(),n=t=>(eU.recordOutcome({requestId:e.requestId,extensionId:e.extensionId,api:e.api,args:e.args,lane:"real",result:t.result,error:t.error,durationMs:Date.now()-r,source:"frame",...t.refused?{refused:!0}:{}}),t),o=(t=X(e.api,ej.get(e.extensionId)??new Set))?{error:t,refused:!0}:null;if(o)return n(o);let s="tabs.query"===e.api||"tabs.get"===e.api||"windows.getCurrent"===e.api?await eG():[];return new Promise(t=>{let r=!1,o=e=>{r||(r=!0,t(n(e)))};ee({data:e,windows:s,...eq,getDeclaredPermissions:e=>ej.get(e)??new Set,respond:o,source:"frame"}).catch(e=>o({error:e instanceof Error?e.message:"Bridge error"}))})}async function e_(e){let t,r,{extensionId:n,url:o,code:s,css:a,matches:i=[]}=e,l=!0===e.active,c=ej.get(n);if(!(c&&(c.has("scripting")||c.has("activeTab"))))return{ok:!1,error:'This extension does not declare the "scripting" (or "activeTab") permission.'};if(!i.length||!i.some(e=>{let t=function(e){let t;if("<all_urls>"===e)return/^https?:\/\/.*/;let r=/^(\*|https?|file|ftp):\/\/([^/]*)(\/.*)$/.exec(e);if(!r)return null;let[,n="",o="",s=""]=r,a="*"===n?"https?":n.replace(/[.+?^${}()|[\]\\]/g,"\\$&");t="*"===o?"[^/]+":o.startsWith("*.")?`(?:[^/]+\\.)?${o.slice(2).replace(/[.+?^${}()|[\]\\]/g,"\\$&").replace(/\*/g,"[^/]*")}`:o.replace(/[.+?^${}()|[\]\\]/g,"\\$&").replace(/\*/g,"[^/]*");let i=s.replace(/[.+?^${}()|[\]\\]/g,"\\$&").replace(/\*/g,".*");return RegExp(`^${a}://${t}${i}$`)}(e);return!!t&&t.test(o)}))return{ok:!1,error:`This extension's content scripts / host permissions do not match ${o}.`};try{t=await chrome.tabs.create({url:o,active:l})}catch(e){return{ok:!1,error:`Could not open the tab: ${String(e)}`}}let d=t.id;if(null==d)return{ok:!1,error:"No tab id."};if(await new Promise(e=>{let t=setTimeout(()=>e(),8e3),r=(n,o)=>{n===d&&"complete"===o.status&&(clearTimeout(t),chrome.tabs.onUpdated.removeListener(r),e())};chrome.tabs.onUpdated.addListener(r)}),a)try{await chrome.scripting.insertCSS({target:{tabId:d},css:a})}catch(e){r=String(e)}let u={tabId:d,active:l};if(!s)return{ok:!0,injected:!1,...u,...r?{cssError:r}:{}};try{let[e]=await chrome.scripting.executeScript({target:{tabId:d},world:"MAIN",func:e=>{try{return(0,eval)(e),{ran:!0}}catch(e){return{ran:!1,error:String(e)}}},args:[s]}),t=e?.result;if(t&&!1===t.ran)return{ok:!0,injected:!1,blocked:!0,reason:t.error,...u,...r?{cssError:r}:{}};return{ok:!0,injected:!0,...u,...r?{cssError:r}:{}}}catch(e){return{ok:!1,error:`Injection failed: ${String(e)}`}}}chrome.runtime.onInstalled.addListener(()=>{}),chrome.runtime.onConnectExternal.addListener(e=>{if(e.name!==eN)return;for(let t of(eR.add(e),eU.events()))try{e.postMessage({type:eM,event:t,backlog:!0})}catch{break}let t=[],r=(r,n)=>{let o=chrome[r],s=o?.[n];if(!s||"function"!=typeof s.addListener)return;let a=(...t)=>((t,r,n)=>{try{e.postMessage({type:eD,namespace:t,event:r,args:n})}catch{}})(r,n,t);s.addListener(a),t.push(()=>s.removeListener(a))};r("storage","onChanged"),r("alarms","onAlarm"),r("tabs","onCreated"),r("tabs","onUpdated"),r("tabs","onRemoved"),r("tabs","onActivated"),r("windows","onCreated"),r("windows","onRemoved"),r("windows","onFocusChanged"),r("bookmarks","onCreated"),r("bookmarks","onChanged"),r("bookmarks","onMoved"),r("bookmarks","onRemoved"),r("history","onVisited"),r("history","onVisitRemoved"),r("downloads","onCreated"),r("downloads","onChanged"),r("downloads","onErased"),r("cookies","onChanged"),r("notifications","onClicked"),r("notifications","onClosed"),r("notifications","onButtonClicked"),r("contextMenus","onClicked"),e.onDisconnect.addListener(()=>{for(let r of(eR.delete(e),t))r()})}),chrome.runtime.onMessageExternal.addListener((e,t,r)=>{if(e?.type===eA)return r({type:eC,version:chrome.runtime.getManifest().version,ready:!0,workerEpoch:eP}),!1;if(e?.type===e$&&"string"==typeof e.extensionId){var n,o;return ej.set(e.extensionId,new Set(Array.isArray(e.permissions)?e.permissions:[])),e.assetUrls&&"object"==typeof e.assetUrls&&eB.set(e.extensionId,e.assetUrls),n=e.extensionId,"string"==typeof(o=e.sessionAccessLevel)&&eO.has(o)&&Promise.resolve(eq.onSetStorageAccessLevel?.(n,"session",o)).catch(()=>void 0),r({ok:!0,workerEpoch:eP}),!1}return e?.type===eT&&e.request?(eL(e.request).then(r),!0):e?.type===eE&&"string"==typeof e.url&&(e_(e).then(r),!0)})})();
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@extension.dev/mcp",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "
|
|
5
|
-
"description": "MCP server that lets AI agents (Claude Code, Claude Desktop, Cursor, Copilot, Codex) build, run, inspect, and publish browser extensions.
|
|
4
|
+
"version": "9.0.0",
|
|
5
|
+
"description": "MCP server that lets AI agents (Claude Code, Claude Desktop, Cursor, Copilot, Codex) build, run, inspect, and publish browser extensions. 28 tools for scaffolding, live DOM inspection, log streaming, and store-ready builds across Chrome, Edge, Firefox, Safari, and every Chromium- or Gecko-based browser (Brave, Opera, Vivaldi, Yandex, Waterfox, LibreWolf). Powered by extension.dev and Extension.js.",
|
|
6
6
|
"mcpName": "io.github.extensiondev/mcp",
|
|
7
7
|
"license": "Apache-2.0",
|
|
8
8
|
"author": {
|
package/server.json
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-09-29/server.schema.json",
|
|
3
3
|
"name": "io.github.extensiondev/mcp",
|
|
4
|
-
"description": "Build, run, inspect, and publish browser extensions from any MCP client.
|
|
4
|
+
"description": "Build, run, inspect, and publish browser extensions from any MCP client. 28 tools, 11 browsers.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"url": "https://github.com/extensiondev/mcp",
|
|
7
7
|
"source": "github"
|
|
8
8
|
},
|
|
9
9
|
"websiteUrl": "https://extension.dev",
|
|
10
|
-
"version": "
|
|
10
|
+
"version": "9.0.0",
|
|
11
11
|
"packages": [
|
|
12
12
|
{
|
|
13
13
|
"registryType": "npm",
|
|
14
14
|
"registryBaseUrl": "https://registry.npmjs.org",
|
|
15
15
|
"identifier": "@extension.dev/mcp",
|
|
16
|
-
"version": "
|
|
16
|
+
"version": "9.0.0",
|
|
17
17
|
"runtimeHint": "npx",
|
|
18
18
|
"transport": {
|
|
19
19
|
"type": "stdio"
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
export declare function writeModernContract(projectPath: string, browser: string, overrides?: Record<string, unknown>): string;
|
|
2
|
-
export declare function writeLegacyContract(projectPath: string, browser: string, overrides?: Record<string, unknown>): string;
|
|
3
|
-
export declare function writeErrorContract(projectPath: string, browser: string): string;
|
|
4
|
-
export declare function writeLegacyEngineState(projectPath: string, browser: string): {
|
|
5
|
-
legacyPortFile: string;
|
|
6
|
-
legacyTokenFile: string;
|
|
7
|
-
};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
import { type LaunchFlagArgs } from "../lib/launch-flags";
|
|
2
|
-
export declare const schema: {
|
|
3
|
-
name: string;
|
|
4
|
-
description: string;
|
|
5
|
-
inputSchema: {
|
|
6
|
-
type: "object";
|
|
7
|
-
properties: {
|
|
8
|
-
profile: {
|
|
9
|
-
readonly type: "string";
|
|
10
|
-
readonly description: "Browser profile path, or \"false\" to reuse the default user profile. Omit for a fresh throwaway profile.";
|
|
11
|
-
};
|
|
12
|
-
startingUrl: {
|
|
13
|
-
readonly type: "string";
|
|
14
|
-
readonly description: "URL the browser opens on launch";
|
|
15
|
-
};
|
|
16
|
-
chromiumBinary: {
|
|
17
|
-
readonly type: "string";
|
|
18
|
-
readonly description: "Path to a custom Chromium-based binary (overrides browser)";
|
|
19
|
-
};
|
|
20
|
-
geckoBinary: {
|
|
21
|
-
readonly type: "string";
|
|
22
|
-
readonly description: "Path to a custom Gecko/Firefox binary (overrides browser)";
|
|
23
|
-
};
|
|
24
|
-
host: {
|
|
25
|
-
readonly type: "string";
|
|
26
|
-
readonly description: "Dev server bind host. Use 0.0.0.0 for Docker or devcontainers. Defaults to 127.0.0.1";
|
|
27
|
-
};
|
|
28
|
-
publicHost: {
|
|
29
|
-
readonly type: "string";
|
|
30
|
-
readonly description: "Connectable host the browser dials for HMR and reload when it differs from the bind host";
|
|
31
|
-
};
|
|
32
|
-
extensions: {
|
|
33
|
-
readonly type: "array";
|
|
34
|
-
readonly items: {
|
|
35
|
-
readonly type: "string";
|
|
36
|
-
};
|
|
37
|
-
readonly description: "Companion extension paths or store URLs to load alongside the project";
|
|
38
|
-
};
|
|
39
|
-
projectPath: {
|
|
40
|
-
type: string;
|
|
41
|
-
description: string;
|
|
42
|
-
};
|
|
43
|
-
browser: {
|
|
44
|
-
type: string;
|
|
45
|
-
enum: string[];
|
|
46
|
-
default: string;
|
|
47
|
-
};
|
|
48
|
-
port: {
|
|
49
|
-
type: string;
|
|
50
|
-
description: string;
|
|
51
|
-
};
|
|
52
|
-
noBrowser: {
|
|
53
|
-
type: string;
|
|
54
|
-
default: boolean;
|
|
55
|
-
description: string;
|
|
56
|
-
};
|
|
57
|
-
};
|
|
58
|
-
required: string[];
|
|
59
|
-
};
|
|
60
|
-
};
|
|
61
|
-
export declare function handler(args: {
|
|
62
|
-
projectPath: string;
|
|
63
|
-
browser?: string;
|
|
64
|
-
port?: number;
|
|
65
|
-
noBrowser?: boolean;
|
|
66
|
-
} & LaunchFlagArgs): Promise<string>;
|
|
File without changes
|