sourcemonkey 0.0.0-stage → 0.5.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.
Files changed (367) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +87 -2
  3. package/dist/bytes.js +37 -0
  4. package/dist/channel-placeholder.js +5 -0
  5. package/dist/collection-scan.js +17 -0
  6. package/dist/collections.html +353 -0
  7. package/dist/compare.html +358 -0
  8. package/dist/composed-source.js +205 -0
  9. package/dist/connect-prompt.html +47 -0
  10. package/dist/debug/icons.html +211 -0
  11. package/dist/debug/storage.html +163 -0
  12. package/dist/debug-log.js +75 -0
  13. package/dist/diagnostic-location.js +64 -0
  14. package/dist/eval-hook.js +308 -0
  15. package/dist/extension/background.js +5263 -0
  16. package/dist/extension/channel.js +133 -0
  17. package/dist/extension/code-links.js +187 -0
  18. package/dist/extension/code-tabs.js +460 -0
  19. package/dist/extension/collection-dialog.js +619 -0
  20. package/dist/extension/collection-display.js +322 -0
  21. package/dist/extension/collections.js +2905 -0
  22. package/dist/extension/compare.js +867 -0
  23. package/dist/extension/concurrency.js +186 -0
  24. package/dist/extension/connect-grants.js +109 -0
  25. package/dist/extension/connect-prompt-page.js +70 -0
  26. package/dist/extension/connect-prompt.js +266 -0
  27. package/dist/extension/copy-button.js +63 -0
  28. package/dist/extension/copy-dialog.js +502 -0
  29. package/dist/extension/copy-preference.js +66 -0
  30. package/dist/extension/debug/icons.js +203 -0
  31. package/dist/extension/debug/storage.js +365 -0
  32. package/dist/extension/deep-link.js +77 -0
  33. package/dist/extension/delete-dialog.js +432 -0
  34. package/dist/extension/delete-icon.js +40 -0
  35. package/dist/extension/details-tooltips.js +66 -0
  36. package/dist/extension/directories.js +679 -0
  37. package/dist/extension/export-backup.js +407 -0
  38. package/dist/extension/export-dialog.js +142 -0
  39. package/dist/extension/file-access.js +74 -0
  40. package/dist/extension/file-changes.js +346 -0
  41. package/dist/extension/frame-info.js +85 -0
  42. package/dist/extension/github-provider.js +336 -0
  43. package/dist/extension/glyph.js +84 -0
  44. package/dist/extension/gm-bindings.js +601 -0
  45. package/dist/extension/gm-download.js +419 -0
  46. package/dist/extension/gm-menu.js +228 -0
  47. package/dist/extension/gm-notification.js +141 -0
  48. package/dist/extension/gm-originator-map.js +23 -0
  49. package/dist/extension/gm-tab-data.js +121 -0
  50. package/dist/extension/gm-tab.js +160 -0
  51. package/dist/extension/gm-url-change.js +111 -0
  52. package/dist/extension/gm-url-scheme.js +27 -0
  53. package/dist/extension/gm-values.js +176 -0
  54. package/dist/extension/gm-window-control.js +104 -0
  55. package/dist/extension/gm-xhr-headers.js +333 -0
  56. package/dist/extension/gm-xhr.js +584 -0
  57. package/dist/extension/injector.js +3145 -0
  58. package/dist/extension/install-capture.js +277 -0
  59. package/dist/extension/line-diff.js +233 -0
  60. package/dist/extension/local-copy.js +560 -0
  61. package/dist/extension/local-delete.js +276 -0
  62. package/dist/extension/location-kinds.js +108 -0
  63. package/dist/extension/log-format.js +158 -0
  64. package/dist/extension/managed-changes.js +361 -0
  65. package/dist/extension/managed-items.js +57 -0
  66. package/dist/extension/match-index.js +375 -0
  67. package/dist/extension/missing-scripts.js +66 -0
  68. package/dist/extension/more-menu.js +109 -0
  69. package/dist/extension/move-dialog.js +197 -0
  70. package/dist/extension/offscreen.js +37 -0
  71. package/dist/extension/options.js +504 -0
  72. package/dist/extension/page-heading.js +170 -0
  73. package/dist/extension/page-links.js +199 -0
  74. package/dist/extension/parse-check-client.js +70 -0
  75. package/dist/extension/parse-check.js +161 -0
  76. package/dist/extension/parse-sandbox-host.js +172 -0
  77. package/dist/extension/parse-sandbox.js +175 -0
  78. package/dist/extension/popup-commands-open.js +41 -0
  79. package/dist/extension/popup-view.js +387 -0
  80. package/dist/extension/popup.js +703 -0
  81. package/dist/extension/prism-userscript.js +53 -0
  82. package/dist/extension/refresh-error.js +136 -0
  83. package/dist/extension/refresh-targets.js +160 -0
  84. package/dist/extension/related-versions.js +1144 -0
  85. package/dist/extension/resize-observer-loop.js +19 -0
  86. package/dist/extension/row-cache.js +387 -0
  87. package/dist/extension/script-blobs.js +413 -0
  88. package/dist/extension/script-details.js +658 -0
  89. package/dist/extension/script-enablement.js +285 -0
  90. package/dist/extension/script-identity.js +310 -0
  91. package/dist/extension/script-keys.js +54 -0
  92. package/dist/extension/script-log-id.js +155 -0
  93. package/dist/extension/script-log.js +290 -0
  94. package/dist/extension/script-rejection.js +104 -0
  95. package/dist/extension/script-sites.js +158 -0
  96. package/dist/extension/script-store.js +3507 -0
  97. package/dist/extension/script-updater.js +991 -0
  98. package/dist/extension/script-url-hash.js +61 -0
  99. package/dist/extension/select-all.js +37 -0
  100. package/dist/extension/select-open-guard.js +90 -0
  101. package/dist/extension/site-icon.js +1261 -0
  102. package/dist/extension/sm-dev-link.js +302 -0
  103. package/dist/extension/solo-click.js +58 -0
  104. package/dist/extension/sticky-numbers.js +188 -0
  105. package/dist/extension/storage-breakdown.js +253 -0
  106. package/dist/extension/storage-scan.js +86 -0
  107. package/dist/extension/storage-usage.js +194 -0
  108. package/dist/extension/structural-keys.js +29 -0
  109. package/dist/extension/sw-teardown.js +36 -0
  110. package/dist/extension/tab-status.js +403 -0
  111. package/dist/extension/toolbar-summary.js +105 -0
  112. package/dist/extension/user-scripts-access.js +43 -0
  113. package/dist/extension/userscript.js +3672 -0
  114. package/dist/extension/value-store.js +204 -0
  115. package/dist/extension/version-probe-fetch.js +68 -0
  116. package/dist/extension/worker-client.js +109 -0
  117. package/dist/extension/worker-ops.js +171 -0
  118. package/dist/extension/zip-writer.js +24 -0
  119. package/dist/external-files.js +878 -0
  120. package/dist/file-loader.js +436 -0
  121. package/dist/file-locations.js +439 -0
  122. package/dist/generated-wrappers.js +5 -0
  123. package/dist/github-auth.js +148 -0
  124. package/dist/github-urls.js +46 -0
  125. package/dist/gm-api-catalog.js +217 -0
  126. package/dist/gm-connect.js +273 -0
  127. package/dist/gm-xhr-types.js +5 -0
  128. package/dist/http-read.js +142 -0
  129. package/dist/icons/icon-128.png +0 -0
  130. package/dist/icons/icon-16.png +0 -0
  131. package/dist/icons/icon-48.png +0 -0
  132. package/dist/local-file-overrides.js +558 -0
  133. package/dist/manifest.json +38 -0
  134. package/dist/markup-response.js +126 -0
  135. package/dist/match-targets.js +305 -0
  136. package/dist/menu-captions.js +22 -0
  137. package/dist/offscreen.html +39 -0
  138. package/dist/options.html +197 -0
  139. package/dist/parse-check-protocol.js +51 -0
  140. package/dist/parse-location.js +171 -0
  141. package/dist/parse-sandbox.html +56 -0
  142. package/dist/phase-timing.js +155 -0
  143. package/dist/popup.html +197 -0
  144. package/dist/public-suffixes.js +6957 -0
  145. package/dist/run-context.js +31 -0
  146. package/dist/runtime-messages.js +34 -0
  147. package/dist/sandboxed-page.js +35 -0
  148. package/dist/script-build.js +787 -0
  149. package/dist/script-display.js +383 -0
  150. package/dist/script-icon.js +43 -0
  151. package/dist/script-links.js +204 -0
  152. package/dist/script-source-url.js +214 -0
  153. package/dist/script-world.js +65 -0
  154. package/dist/sm-dev-protocol.js +84 -0
  155. package/dist/source-map.js +177 -0
  156. package/dist/stack-link.js +138 -0
  157. package/dist/styles.css +825 -0
  158. package/dist/unsafe-window-use.js +229 -0
  159. package/dist/url-match.js +734 -0
  160. package/dist/userscript-header.js +248 -0
  161. package/dist/userscript.html +1165 -0
  162. package/dist/vendor/fflate.LICENSE +21 -0
  163. package/dist/vendor/fflate.js +2692 -0
  164. package/dist/vendor/prism/prism-line-numbers.css +1 -0
  165. package/dist/vendor/prism/prism-line-numbers.js +1 -0
  166. package/dist/vendor/prism/prism.css +1 -0
  167. package/dist/vendor/prism/prism.js +1946 -0
  168. package/dist/version-compare.js +141 -0
  169. package/dist/version-probe.js +120 -0
  170. package/lib/build-info.json +1 -0
  171. package/lib/bytes.d.ts +3 -0
  172. package/lib/bytes.js +37 -0
  173. package/lib/channel-placeholder.d.ts +1 -0
  174. package/lib/channel-placeholder.js +5 -0
  175. package/lib/collection-scan.d.ts +8 -0
  176. package/lib/collection-scan.js +17 -0
  177. package/lib/composed-source.d.ts +28 -0
  178. package/lib/composed-source.js +205 -0
  179. package/lib/debug-log.d.ts +9 -0
  180. package/lib/debug-log.js +75 -0
  181. package/lib/diagnostic-location.d.ts +8 -0
  182. package/lib/diagnostic-location.js +64 -0
  183. package/lib/eval-hook.d.ts +34 -0
  184. package/lib/eval-hook.js +308 -0
  185. package/lib/external-files.d.ts +111 -0
  186. package/lib/external-files.js +878 -0
  187. package/lib/file-loader.d.ts +48 -0
  188. package/lib/file-loader.js +436 -0
  189. package/lib/file-locations.d.ts +44 -0
  190. package/lib/file-locations.js +439 -0
  191. package/lib/generated-wrappers.d.ts +11 -0
  192. package/lib/generated-wrappers.js +5 -0
  193. package/lib/github-auth.d.ts +12 -0
  194. package/lib/github-auth.js +148 -0
  195. package/lib/github-urls.d.ts +1 -0
  196. package/lib/github-urls.js +46 -0
  197. package/lib/gm-api-catalog.d.ts +24 -0
  198. package/lib/gm-api-catalog.js +217 -0
  199. package/lib/gm-connect.d.ts +34 -0
  200. package/lib/gm-connect.js +273 -0
  201. package/lib/gm-xhr-types.d.ts +68 -0
  202. package/lib/gm-xhr-types.js +5 -0
  203. package/lib/harness/browser-extensions.d.ts +73 -0
  204. package/lib/harness/browser-extensions.js +285 -0
  205. package/lib/harness/browser-lang.d.ts +20 -0
  206. package/lib/harness/browser-lang.js +86 -0
  207. package/lib/harness/browser-launch.d.ts +14 -0
  208. package/lib/harness/browser-launch.js +184 -0
  209. package/lib/harness/checks.d.ts +110 -0
  210. package/lib/harness/checks.js +321 -0
  211. package/lib/harness/cli.d.ts +2 -0
  212. package/lib/harness/cli.js +2259 -0
  213. package/lib/harness/command-args.d.ts +91 -0
  214. package/lib/harness/command-args.js +369 -0
  215. package/lib/harness/command-lines.d.ts +80 -0
  216. package/lib/harness/command-lines.js +180 -0
  217. package/lib/harness/command-list.d.ts +206 -0
  218. package/lib/harness/command-list.js +1475 -0
  219. package/lib/harness/console-commands.d.ts +463 -0
  220. package/lib/harness/console-commands.js +3216 -0
  221. package/lib/harness/download-watch.d.ts +21 -0
  222. package/lib/harness/download-watch.js +156 -0
  223. package/lib/harness/extension-backend.d.ts +41 -0
  224. package/lib/harness/extension-backend.js +100 -0
  225. package/lib/harness/extension-host.d.ts +112 -0
  226. package/lib/harness/extension-host.js +552 -0
  227. package/lib/harness/extension-launch.d.ts +67 -0
  228. package/lib/harness/extension-launch.js +285 -0
  229. package/lib/harness/extension-link.d.ts +315 -0
  230. package/lib/harness/extension-link.js +607 -0
  231. package/lib/harness/external-manager.d.ts +146 -0
  232. package/lib/harness/external-manager.js +414 -0
  233. package/lib/harness/fixture.d.ts +165 -0
  234. package/lib/harness/fixture.js +461 -0
  235. package/lib/harness/frame-sessions.d.ts +71 -0
  236. package/lib/harness/frame-sessions.js +248 -0
  237. package/lib/harness/frames.d.ts +68 -0
  238. package/lib/harness/frames.js +216 -0
  239. package/lib/harness/help-format.d.ts +17 -0
  240. package/lib/harness/help-format.js +127 -0
  241. package/lib/harness/host.d.ts +352 -0
  242. package/lib/harness/host.js +423 -0
  243. package/lib/harness/index.d.ts +8 -0
  244. package/lib/harness/index.js +10 -0
  245. package/lib/harness/input-file.d.ts +18 -0
  246. package/lib/harness/input-file.js +61 -0
  247. package/lib/harness/json-output.d.ts +565 -0
  248. package/lib/harness/json-output.js +71 -0
  249. package/lib/harness/manager-actions.d.ts +21 -0
  250. package/lib/harness/manager-actions.js +129 -0
  251. package/lib/harness/manager-commands.d.ts +142 -0
  252. package/lib/harness/manager-commands.js +1196 -0
  253. package/lib/harness/manager-fetch.d.ts +33 -0
  254. package/lib/harness/manager-fetch.js +239 -0
  255. package/lib/harness/managers.d.ts +24 -0
  256. package/lib/harness/managers.js +27 -0
  257. package/lib/harness/output-style.d.ts +125 -0
  258. package/lib/harness/output-style.js +322 -0
  259. package/lib/harness/page-commands.d.ts +134 -0
  260. package/lib/harness/page-commands.js +1141 -0
  261. package/lib/harness/page-output.d.ts +67 -0
  262. package/lib/harness/page-output.js +139 -0
  263. package/lib/harness/page-watch.d.ts +171 -0
  264. package/lib/harness/page-watch.js +607 -0
  265. package/lib/harness/parse-check-node.d.ts +3 -0
  266. package/lib/harness/parse-check-node.js +132 -0
  267. package/lib/harness/path-args.d.ts +22 -0
  268. package/lib/harness/path-args.js +148 -0
  269. package/lib/harness/playwright-chromium.d.ts +16 -0
  270. package/lib/harness/playwright-chromium.js +86 -0
  271. package/lib/harness/prepare.d.ts +168 -0
  272. package/lib/harness/prepare.js +364 -0
  273. package/lib/harness/prompt-editor.d.ts +17 -0
  274. package/lib/harness/prompt-editor.js +354 -0
  275. package/lib/harness/prompt-history.d.ts +13 -0
  276. package/lib/harness/prompt-history.js +89 -0
  277. package/lib/harness/rebuild-advice.d.ts +6 -0
  278. package/lib/harness/rebuild-advice.js +39 -0
  279. package/lib/harness/run-log.d.ts +47 -0
  280. package/lib/harness/run-log.js +140 -0
  281. package/lib/harness/run-logs.d.ts +132 -0
  282. package/lib/harness/run-logs.js +241 -0
  283. package/lib/harness/run.d.ts +194 -0
  284. package/lib/harness/run.js +1973 -0
  285. package/lib/harness/runs.d.ts +229 -0
  286. package/lib/harness/runs.js +726 -0
  287. package/lib/harness/save-html.d.ts +39 -0
  288. package/lib/harness/save-html.js +89 -0
  289. package/lib/harness/saved-pages.d.ts +120 -0
  290. package/lib/harness/saved-pages.js +275 -0
  291. package/lib/harness/script-mark.d.ts +17 -0
  292. package/lib/harness/script-mark.js +56 -0
  293. package/lib/harness/snapshot.d.ts +143 -0
  294. package/lib/harness/snapshot.js +474 -0
  295. package/lib/harness/stuck-tabs.d.ts +19 -0
  296. package/lib/harness/stuck-tabs.js +131 -0
  297. package/lib/harness/tab-refs.d.ts +20 -0
  298. package/lib/harness/tab-refs.js +80 -0
  299. package/lib/harness/tampermonkey.d.ts +71 -0
  300. package/lib/harness/tampermonkey.js +356 -0
  301. package/lib/harness/tm-ids.d.ts +18 -0
  302. package/lib/harness/tm-ids.js +88 -0
  303. package/lib/harness/violentmonkey.d.ts +34 -0
  304. package/lib/harness/violentmonkey.js +162 -0
  305. package/lib/harness/wait.d.ts +77 -0
  306. package/lib/harness/wait.js +458 -0
  307. package/lib/http-read.d.ts +30 -0
  308. package/lib/http-read.js +142 -0
  309. package/lib/local-file-overrides.d.ts +35 -0
  310. package/lib/local-file-overrides.js +558 -0
  311. package/lib/manifest.json +38 -0
  312. package/lib/markup-response.d.ts +11 -0
  313. package/lib/markup-response.js +126 -0
  314. package/lib/match-targets.d.ts +18 -0
  315. package/lib/match-targets.js +305 -0
  316. package/lib/menu-captions.d.ts +1 -0
  317. package/lib/menu-captions.js +22 -0
  318. package/lib/parse-check-protocol.d.ts +27 -0
  319. package/lib/parse-check-protocol.js +51 -0
  320. package/lib/parse-location.d.ts +12 -0
  321. package/lib/parse-location.js +171 -0
  322. package/lib/phase-timing.d.ts +12 -0
  323. package/lib/phase-timing.js +155 -0
  324. package/lib/public-suffixes.d.ts +1 -0
  325. package/lib/public-suffixes.js +6957 -0
  326. package/lib/run-context.d.ts +2 -0
  327. package/lib/run-context.js +31 -0
  328. package/lib/runtime-messages.d.ts +10 -0
  329. package/lib/runtime-messages.js +34 -0
  330. package/lib/sandboxed-page.d.ts +5 -0
  331. package/lib/sandboxed-page.js +35 -0
  332. package/lib/script-build.d.ts +111 -0
  333. package/lib/script-build.js +787 -0
  334. package/lib/script-display.d.ts +51 -0
  335. package/lib/script-display.js +383 -0
  336. package/lib/script-icon.d.ts +16 -0
  337. package/lib/script-icon.js +43 -0
  338. package/lib/script-links.d.ts +24 -0
  339. package/lib/script-links.js +204 -0
  340. package/lib/script-source-url.d.ts +8 -0
  341. package/lib/script-source-url.js +214 -0
  342. package/lib/script-world.d.ts +6 -0
  343. package/lib/script-world.js +65 -0
  344. package/lib/sm-dev-protocol.d.ts +251 -0
  345. package/lib/sm-dev-protocol.js +84 -0
  346. package/lib/source-map.d.ts +32 -0
  347. package/lib/source-map.js +177 -0
  348. package/lib/stack-link.d.ts +15 -0
  349. package/lib/stack-link.js +138 -0
  350. package/lib/unsafe-window-use.d.ts +1 -0
  351. package/lib/unsafe-window-use.js +229 -0
  352. package/lib/url-match.d.ts +40 -0
  353. package/lib/url-match.js +734 -0
  354. package/lib/userscript-header.d.ts +33 -0
  355. package/lib/userscript-header.js +248 -0
  356. package/lib/version-compare.d.ts +6 -0
  357. package/lib/version-compare.js +141 -0
  358. package/lib/version-probe.d.ts +17 -0
  359. package/lib/version-probe.js +120 -0
  360. package/package.json +55 -3
  361. package/skills/SourceMonkey-dev/SKILL.md +868 -0
  362. package/skills/SourceMonkey-dev/references/cdp.md +293 -0
  363. package/skills/SourceMonkey-dev/references/commands.md +297 -0
  364. package/skills/SourceMonkey-dev/references/other-managers.md +63 -0
  365. package/skills/SourceMonkey-dev/references/specs.md +46 -0
  366. package/skills/SourceMonkey-friction/SKILL.md +103 -0
  367. package/skills/SourceMonkey-friction/references/template.md +59 -0
@@ -0,0 +1,217 @@
1
+ // Catalog of GM_* / GM.* APIs that SourceMonkey supports (or has slots
2
+ // for). This is the single source of truth that:
3
+ //
4
+ // - The injector consults to decide which GM_* function definitions
5
+ // to compile into a given script's wrapper, based on its @grant
6
+ // lines. This is where @grant is actually enforced: an ungranted
7
+ // API is simply never bound into the script's scope.
8
+ // - The permission-test e2e spec consults to assert that ungranted
9
+ // APIs are not bound in the script's scope.
10
+ //
11
+ // NOTE: the SW-side async handlers do NOT re-validate @grant against
12
+ // this catalog. Enforcement is binding-time only (above). Re-checking
13
+ // in the SW would add no security: the per-message `scriptId` is
14
+ // wrapper-supplied and spoofable, so a script that wanted to bypass
15
+ // the grant would just claim the id of a script that has it. See the
16
+ // "trust caveat" notes in docs/GM-APIs.md.
17
+ //
18
+ // Each API entry says:
19
+ // - The canonical `GM_x` name and the GM4-style `GM.x` alias (if
20
+ // any). Scripts can @grant either form and we honor both.
21
+ // - Whether the call resolves in-page (`sync`) — runs in
22
+ // USER_SCRIPT world via the shared GM runtime — or makes a
23
+ // SW round-trip (`async`).
24
+ // - The subsystem the body delegates to. Drives both the wrapper-side
25
+ // stub and the SW-side message routing.
26
+ //
27
+ // Adding a new API: append an entry, then either (a) implement the
28
+ // sync body in src/wrapper-gm-runtime.js if `kind === 'sync'` or (b)
29
+ // add an SW-side handler if `kind === 'async'`.
30
+ import { getValues } from './userscript-header.js';
31
+ // What a request that reads or writes a script's stored values has to
32
+ // have granted: any storage API, or a value-change listener (its
33
+ // snapshot seeds the listener's remote-change detection). Used by the
34
+ // bridge gate in background.ts.
35
+ export const STORAGE_SUBSYSTEMS = ['storage', 'storage-listener'];
36
+ // The refusal a bridge-relayed request gets when the page may not act
37
+ // for the script it names. Shared by the same two gates.
38
+ export const BRIDGE_DENIED = 'This page is not allowed to act for that userscript';
39
+ // IMPORTANT: when adding entries here keep the order stable — emit
40
+ // order in the wrapper isn't load-bearing but stable order makes
41
+ // stack traces and diffed wrapper bodies easier to compare across
42
+ // runs.
43
+ export const GM_APIS = Object.freeze([
44
+ // ----- Compile-time / in-page constants -----
45
+ { name: 'GM_info', gmDotName: 'info', kind: 'sync', subsystem: 'info' },
46
+ { name: 'unsafeWindow', kind: 'sync', subsystem: 'unsafe-window' },
47
+ // ----- Non-GM_* window features (TM's `@grant window.x` family) -----
48
+ // `window.onurlchange` is not a callable and not a valid JS
49
+ // identifier, so it emits no `const` binding at all. What the grant
50
+ // buys is an eager `__smReg.gm.urlchange.enable(scriptId)` call that
51
+ // installs the `urlchange` event surface on the world's `window`.
52
+ // See docs/GM-APIs.md#windowonurlchange.
53
+ { name: 'window.onurlchange', kind: 'sync', subsystem: 'url-change' },
54
+ // `window.close` / `window.focus` are callables, but `window.close`
55
+ // is not a legal binding name either — so, like the grant above,
56
+ // they emit no `GM_*`-style binding. The grant's effect is an eager
57
+ // `__smReg.gm.windowControl` call that REPLACES the method the script
58
+ // sees (on its sandbox `window` in the page's world, on the world's
59
+ // `window` when isolated) with one that routes through the SW (`chrome.tabs.remove` / `chrome.windows.update`),
60
+ // which is what lets it work where the page's own call is a no-op.
61
+ // `async` for that SW round-trip; the script still sees the void,
62
+ // synchronous return TM gives it. See docs/GM-APIs.md#windowclose--windowfocus.
63
+ { name: 'window.close', kind: 'async', subsystem: 'window-control' },
64
+ { name: 'window.focus', kind: 'async', subsystem: 'window-control' },
65
+ // ----- Logging -----
66
+ { name: 'GM_log', gmDotName: 'log', kind: 'sync', subsystem: 'log' },
67
+ // ----- Storage (sync return; GM. form returns Promise per GM4) -----
68
+ { name: 'GM_setValue', gmDotName: 'setValue', gmDotPromised: true, kind: 'sync', subsystem: 'storage' },
69
+ { name: 'GM_getValue', gmDotName: 'getValue', gmDotPromised: true, kind: 'sync', subsystem: 'storage' },
70
+ { name: 'GM_deleteValue', gmDotName: 'deleteValue', gmDotPromised: true, kind: 'sync', subsystem: 'storage' },
71
+ { name: 'GM_listValues', gmDotName: 'listValues', gmDotPromised: true, kind: 'sync', subsystem: 'storage' },
72
+ // ----- Value-change listeners (sync register/unregister) -----
73
+ { name: 'GM_addValueChangeListener', gmDotName: 'addValueChangeListener', kind: 'sync', subsystem: 'storage-listener' },
74
+ { name: 'GM_removeValueChangeListener', gmDotName: 'removeValueChangeListener', kind: 'sync', subsystem: 'storage-listener' },
75
+ // ----- DOM injection -----
76
+ { name: 'GM_addStyle', gmDotName: 'addStyle', kind: 'sync', subsystem: 'dom' },
77
+ { name: 'GM_addElement', gmDotName: 'addElement', kind: 'sync', subsystem: 'dom' },
78
+ // ----- @resource lookups (require @resource header support) -----
79
+ // GM4 spelling is `GM.getResourceUrl` (lowercase 'u') — keep the
80
+ // casing mismatch with GM_getResourceURL, it's deliberate.
81
+ { name: 'GM_getResourceText', gmDotName: 'getResourceText', kind: 'sync', subsystem: 'resource', requires: ['resource'] },
82
+ { name: 'GM_getResourceURL', gmDotName: 'getResourceUrl', kind: 'sync', subsystem: 'resource', requires: ['resource'] },
83
+ // ----- Menu commands (stub: register/unregister) -----
84
+ { name: 'GM_registerMenuCommand', gmDotName: 'registerMenuCommand', kind: 'sync', subsystem: 'menu' },
85
+ { name: 'GM_unregisterMenuCommand', gmDotName: 'unregisterMenuCommand', kind: 'sync', subsystem: 'menu' },
86
+ // ----- Async APIs (cross-world, SW round-trip) -----
87
+ // Note: GM_xmlhttpRequest returns a sync control object, but the
88
+ // request itself is async. We classify by SW round-trip — `async` —
89
+ // because the wrapper has to message the SW to start the request.
90
+ { name: 'GM_xmlhttpRequest', gmDotName: 'xmlHttpRequest', kind: 'async', subsystem: 'xhr', requires: ['connect'] },
91
+ // GM_setClipboard is handled in-page via navigator.clipboard.writeText
92
+ // — no SW round-trip — so it's classified `sync` even though the
93
+ // underlying browser call is async (returns Promise<void>). Page-
94
+ // handled vs SW-handled is what `kind` actually means in this
95
+ // catalog. TM/VM use an offscreen document via execCommand('copy');
96
+ // we may revisit later if real users hit "navigator.clipboard
97
+ // requires focus" failures.
98
+ { name: 'GM_setClipboard', gmDotName: 'setClipboard', kind: 'sync', subsystem: 'clipboard' },
99
+ { name: 'GM_notification', gmDotName: 'notification', kind: 'async', subsystem: 'notification' },
100
+ { name: 'GM_openInTab', gmDotName: 'openInTab', kind: 'async', subsystem: 'tab' },
101
+ // Per-tab objects kept by the SW while the tab is open. Each takes an
102
+ // optional callback, as in TM, and returns a Promise when given none,
103
+ // which is what the `GM.` form passes through.
104
+ { name: 'GM_getTab', gmDotName: 'getTab', kind: 'async', subsystem: 'tab-data' },
105
+ { name: 'GM_saveTab', gmDotName: 'saveTab', kind: 'async', subsystem: 'tab-data' },
106
+ { name: 'GM_getTabs', gmDotName: 'getTabs', kind: 'async', subsystem: 'tab-data' },
107
+ // Like GM_xmlhttpRequest, GM_download hands back a sync `{abort}`
108
+ // control object while the transfer itself runs in the SW — `async`
109
+ // classifies the SW round-trip, not the return value. It is NOT
110
+ // `requires: ['connect']`: download URLs are runtime-discovered CDN
111
+ // hosts that scripts can't enumerate in a header, and the bytes go
112
+ // to disk rather than back to the script, so the exfiltration risk
113
+ // `@connect` guards doesn't apply. See docs/GM-APIs.md.
114
+ { name: 'GM_download', gmDotName: 'download', kind: 'async', subsystem: 'download' },
115
+ ]);
116
+ // Quick lookup. Built lazily so unit tests that only import types or
117
+ // constants don't pay the Map cost; callers that hit this in a hot
118
+ // loop should cache the result of `findApi` themselves.
119
+ let byName = null;
120
+ function ensureIndex() {
121
+ if (byName !== null)
122
+ return byName;
123
+ const m = new Map();
124
+ for (const a of GM_APIS) {
125
+ m.set(a.name, a);
126
+ if (a.gmDotName)
127
+ m.set(`GM.${a.gmDotName}`, a);
128
+ }
129
+ byName = m;
130
+ return m;
131
+ }
132
+ // Look up an API spec by either its `GM_x` name OR its `GM.x` form.
133
+ // Returns undefined for unknown names (e.g. APIs we don't support
134
+ // yet — `GM_webRequest`, `GM_audio`, etc.).
135
+ export function findApi(name) {
136
+ return ensureIndex().get(name);
137
+ }
138
+ // Normalize a single `@grant` line to its canonical `GM_x` name.
139
+ //
140
+ // Cases:
141
+ // - `GM_setValue` → `'GM_setValue'`
142
+ // - `GM.setValue` → `'GM_setValue'` (canonicalized to the legacy form)
143
+ // - unknown / blank → `null`
144
+ //
145
+ // Does NOT handle the `none` sentinel — that's a per-script policy,
146
+ // not a per-name canonicalization. `resolveGrants` is where `none`
147
+ // gets recognized and propagated.
148
+ export function canonicalizeGrant(raw) {
149
+ const trimmed = raw.trim();
150
+ if (trimmed === '')
151
+ return null;
152
+ if (trimmed.toLowerCase() === 'none')
153
+ return null;
154
+ const spec = findApi(trimmed);
155
+ return spec ? spec.name : null;
156
+ }
157
+ // Resolve the set of granted GM_* names for a script, given its raw
158
+ // @grant lines.
159
+ //
160
+ // Rules:
161
+ // - A `none` line anywhere wins — the script is treated as ungranted.
162
+ // Matches TM/VM behavior: a script with `@grant none` and `@grant
163
+ // GM_setValue` is treated as `@grant none`. The granted set is
164
+ // returned empty in this case; `unknown` is still populated so the
165
+ // caller can warn.
166
+ // - Unknown names are dropped from `granted` and surfaced in
167
+ // `unknown`. The wrapper simply won't emit a binding for them, and
168
+ // the script gets a natural ReferenceError at call time.
169
+ // - Duplicate names collapse to one (Set semantics).
170
+ export function resolveGrants(rawGrants) {
171
+ const granted = new Set();
172
+ let hasNone = false;
173
+ const unknown = [];
174
+ for (const raw of rawGrants) {
175
+ const trimmed = raw.trim();
176
+ if (trimmed === '')
177
+ continue;
178
+ if (trimmed.toLowerCase() === 'none') {
179
+ hasNone = true;
180
+ continue;
181
+ }
182
+ const canonical = canonicalizeGrant(trimmed);
183
+ if (canonical === null) {
184
+ unknown.push(trimmed);
185
+ continue;
186
+ }
187
+ granted.add(canonical);
188
+ }
189
+ // @grant none wins — even if other granted lines were also present.
190
+ if (hasNone)
191
+ granted.clear();
192
+ return { granted, hasNone, unknown };
193
+ }
194
+ // True iff the named API is part of the supported surface. Used by the
195
+ // SW-side message router to reject unknown method calls (a misbehaving
196
+ // or stale wrapper that asks for `GM_audio.play` shouldn't be able to
197
+ // drive any handler).
198
+ export function isSupportedApi(name) {
199
+ return findApi(name) !== undefined;
200
+ }
201
+ // The catalog subsystems the script's `@grant` lines reach — the set the
202
+ // SW's bridge gate (`bridgeMayActAs` in background.ts) checks a relayed
203
+ // request against, so a page can only act for a script through APIs
204
+ // that script actually has. `@grant none` and unknown names contribute
205
+ // nothing.
206
+ export function grantedSubsystems(header) {
207
+ const out = new Set();
208
+ if (!header)
209
+ return out;
210
+ const { granted } = resolveGrants(getValues(header, 'grant'));
211
+ for (const name of granted) {
212
+ const spec = findApi(name);
213
+ if (spec)
214
+ out.add(spec.subsystem);
215
+ }
216
+ return out;
217
+ }
@@ -0,0 +1,34 @@
1
+ import { type ParsedHeader } from './userscript-header.js';
2
+ export interface ConnectRule {
3
+ kind: 'wildcard' | 'self' | 'host' | 'subdomain';
4
+ host?: string;
5
+ }
6
+ export declare function parseConnectEntry(raw: string): ConnectRule | null;
7
+ export declare function parseConnectRules(header: ParsedHeader): ConnectRule[];
8
+ export declare function hostMatchesRule(host: string, rule: ConnectRule, selfHosts: ReadonlySet<string>): boolean;
9
+ export declare function hasNoConnectRules(header: ParsedHeader): boolean;
10
+ export declare function extractSelfHosts(header: ParsedHeader): Set<string>;
11
+ export type ConnectDecision = {
12
+ verdict: 'allow';
13
+ } | {
14
+ verdict: 'ask';
15
+ host: string;
16
+ } | {
17
+ verdict: 'deny';
18
+ reason: string;
19
+ } | {
20
+ verdict: 'invalid';
21
+ reason: string;
22
+ };
23
+ export declare function decideConnect(url: string, rules: readonly ConnectRule[], selfHosts: ReadonlySet<string>, pageOrigin?: string): ConnectDecision;
24
+ export declare function gmXhrError(problem: string): string;
25
+ export declare function headerRuleFailedMessage(): string;
26
+ export declare function headerStallMessage(stallMs: number): string;
27
+ export declare function redirectRefusedMessage(): string;
28
+ export declare function unreachableMessage(host: string): string;
29
+ export declare function connectBlockedMessage(reason: string): string;
30
+ export declare function connectDeniedMessage(host: string): string;
31
+ export declare function connectCancelledMessage(host: string): string;
32
+ export declare function connectPromptFailedMessage(host: string, cause: string): string;
33
+ export declare function connectTooManyPromptsMessage(host: string, open: number): string;
34
+ export declare function connectUnansweredMessage(host: string, waitMs: number): string;
@@ -0,0 +1,273 @@
1
+ // `@connect` URL gating for `GM_xmlhttpRequest`.
2
+ //
3
+ // @connect grammar (following Tampermonkey's docs):
4
+ // - `*` — wildcard, allow any host.
5
+ // - `self` — allow same-origin requests (matched against the
6
+ // script's @match / @include hosts).
7
+ // - `example.com` — that host OR any subdomain of it
8
+ // (`api.example.com`), as Tampermonkey documents. A label-boundary
9
+ // match: `evilexample.com` does not match. IP addresses and
10
+ // single-label names (`127.0.0.1`, `localhost`, `com`) match only
11
+ // exactly, so a bare rule can't stand for a whole TLD or IP range.
12
+ // Multi-label public suffixes (`co.uk`) are not special-cased.
13
+ // - `*.example.com` — `example.com` itself OR any subdomain.
14
+ //
15
+ // SW-side validation: when a script issues `GM_xmlhttpRequest`, the
16
+ // SW pulls the script's stored header, parses out the `@connect`
17
+ // lines, and rejects the request if the URL's host doesn't satisfy
18
+ // any of them.
19
+ //
20
+ // A host no rule covers isn't refused outright: the extension asks the
21
+ // user, as Tampermonkey does, and remembers the answer per script (see
22
+ // `decideConnect` and docs/connect-permissions.md). Violentmonkey doesn't enforce
23
+ // @connect at all.
24
+ import { getValues } from './userscript-header.js';
25
+ // Lower-case, normalize, classify a single raw @connect value.
26
+ // Returns null for empty / malformed entries.
27
+ export function parseConnectEntry(raw) {
28
+ const t = raw.trim().toLowerCase();
29
+ if (t === '')
30
+ return null;
31
+ if (t === '*')
32
+ return { kind: 'wildcard' };
33
+ if (t === 'self')
34
+ return { kind: 'self' };
35
+ if (t.startsWith('*.')) {
36
+ const host = t.slice(2);
37
+ if (!host)
38
+ return null;
39
+ return { kind: 'subdomain', host };
40
+ }
41
+ // Strip a leading scheme if the user pasted a URL by mistake — TM
42
+ // accepts both `example.com` and `https://example.com` in @connect
43
+ // lines; we normalize to the host.
44
+ try {
45
+ if (/^[a-z]+:\/\//.test(t)) {
46
+ const u = new URL(t);
47
+ return { kind: 'host', host: u.hostname };
48
+ }
49
+ }
50
+ catch {
51
+ // Fall through — treat the raw value as a host.
52
+ }
53
+ return { kind: 'host', host: t };
54
+ }
55
+ // Parse every `@connect` line from a header, dropping empties.
56
+ export function parseConnectRules(header) {
57
+ const out = [];
58
+ for (const raw of getValues(header, 'connect')) {
59
+ const rule = parseConnectEntry(raw);
60
+ if (rule)
61
+ out.push(rule);
62
+ }
63
+ return out;
64
+ }
65
+ // Match `host` (lowercased; no port) against one rule. The `self`
66
+ // rule is matched against the union of `selfHosts` — the set of
67
+ // hostnames the script declared via @match / @include.
68
+ export function hostMatchesRule(host, rule, selfHosts) {
69
+ const h = host.toLowerCase();
70
+ switch (rule.kind) {
71
+ case 'wildcard':
72
+ return true;
73
+ case 'self':
74
+ // TM/VM both treat `self` as "the script's own origins or
75
+ // their subdomains". We're conservative: exact match only.
76
+ // See TODO.md "@connect self subdomain handling" — known
77
+ // cross-manager divergence pending a real compat report.
78
+ return selfHosts.has(h);
79
+ case 'host':
80
+ // A bare `example.com` covers its subdomains too, as Tampermonkey
81
+ // documents. But not a bare IP or single label: `@connect 0.0.1`
82
+ // must not reach `127.0.0.1`, nor `@connect com` all of `.com`.
83
+ if (!rule.host)
84
+ return false;
85
+ if (h === rule.host)
86
+ return true;
87
+ return !isExactOnlyHost(rule.host) && h.endsWith('.' + rule.host);
88
+ case 'subdomain':
89
+ // The `.` prefix keeps it to whole labels, so `evilexample.com`
90
+ // doesn't match `*.example.com`.
91
+ if (!rule.host)
92
+ return false;
93
+ return h === rule.host || h.endsWith('.' + rule.host);
94
+ default:
95
+ return false;
96
+ }
97
+ }
98
+ // A bare `@connect` host that has no subdomains to cover: an IP
99
+ // address (all-numeric dotted, or IPv6 with `:`), or a single label
100
+ // (`localhost`, `com`).
101
+ function isExactOnlyHost(host) {
102
+ return /^[\d.]+$/.test(host) || host.includes(':') || !host.includes('.');
103
+ }
104
+ // True when the header has no usable `@connect` rule, so all its
105
+ // `GM_xmlhttpRequest` calls to other sites need the user's say-so. The
106
+ // same parse enforcement uses, so a header whose `@connect` lines are
107
+ // all malformed counts.
108
+ export function hasNoConnectRules(header) {
109
+ return parseConnectRules(header).length === 0;
110
+ }
111
+ // Extract the set of "self" hosts from a script header's match/
112
+ // include lines. Used to resolve the `self` @connect token.
113
+ // Patterns we don't understand (regex includes, malformed globs)
114
+ // are skipped — they don't contribute to "self".
115
+ export function extractSelfHosts(header) {
116
+ const out = new Set();
117
+ const all = [...getValues(header, 'match'), ...getValues(header, 'include')];
118
+ for (const pat of all) {
119
+ const host = extractHostFromPattern(pat);
120
+ if (host)
121
+ out.add(host.toLowerCase());
122
+ }
123
+ return out;
124
+ }
125
+ // Pull a hostname out of a `@match` / `@include` glob if it has one.
126
+ // `<all_urls>`, regex literals, and host-less patterns return null.
127
+ function extractHostFromPattern(pat) {
128
+ if (pat === '<all_urls>')
129
+ return null;
130
+ if (pat.startsWith('/') && pat.endsWith('/'))
131
+ return null; // regex literal
132
+ // Match an URL-like glob: <scheme>://<host>/...
133
+ const m = /^[\w*]+:\/\/([^/]+)\//.exec(pat);
134
+ if (!m)
135
+ return null;
136
+ const host = m[1];
137
+ // A pure `*` host doesn't tell us anything useful for "self".
138
+ if (host === '*')
139
+ return null;
140
+ // `*.example.com` → use `example.com` as the self host.
141
+ if (host.startsWith('*.'))
142
+ return host.slice(2);
143
+ return host;
144
+ }
145
+ export function decideConnect(url, rules, selfHosts, pageOrigin) {
146
+ let parsed;
147
+ try {
148
+ parsed = new URL(url);
149
+ }
150
+ catch {
151
+ return { verdict: 'invalid', reason: `${url} is not a valid URL` };
152
+ }
153
+ const web = parsed.protocol === 'http:' || parsed.protocol === 'https:';
154
+ const page = webOrigin(pageOrigin);
155
+ if (web && page && parsed.origin === page.origin)
156
+ return { verdict: 'allow' };
157
+ const host = parsed.hostname.toLowerCase();
158
+ const selfs = page ? new Set([...selfHosts, page.hostname]) : selfHosts;
159
+ for (const rule of rules) {
160
+ // A host-less URL has nothing for a host rule to match, but `*`
161
+ // means any URL at all.
162
+ if (!host && rule.kind !== 'wildcard')
163
+ continue;
164
+ if (hostMatchesRule(host, rule, selfs))
165
+ return { verdict: 'allow' };
166
+ }
167
+ if (web && host)
168
+ return { verdict: 'ask', host };
169
+ return {
170
+ verdict: 'deny',
171
+ reason: host
172
+ ? `Only http(s) sites can be allowed, so only @connect * covers a ${parsed.protocol} URL.`
173
+ : `A ${parsed.protocol} URL has no host to allow, so only @connect * covers it.`,
174
+ };
175
+ }
176
+ // The page's origin when it is an http(s) one, else null.
177
+ function webOrigin(origin) {
178
+ if (!origin)
179
+ return null;
180
+ try {
181
+ const u = new URL(origin);
182
+ return u.protocol === 'http:' || u.protocol === 'https:' ? u : null;
183
+ }
184
+ catch {
185
+ return null;
186
+ }
187
+ }
188
+ // Every error `GM_xmlhttpRequest` hands back to a userscript starts
189
+ // here, so the three paths that can fail it — the pre-flight check, the
190
+ // post-redirect re-check (`gm-xhr.ts`), and a policy we couldn't even
191
+ // load (`background.ts`) — read the same way.
192
+ export function gmXhrError(problem) {
193
+ return `[SourceMonkey] GM_xmlhttpRequest: ${problem}`;
194
+ }
195
+ // The one phrasing for "we could not set the headers you asked for".
196
+ // Says the request was not sent, because the alternative a reader would
197
+ // assume — sent without them — is exactly what we refuse to do: the
198
+ // headers here are the ones the browser won't let a script set, and
199
+ // dropping a `Cookie` override would send the user's own session
200
+ // instead.
201
+ export function headerRuleFailedMessage() {
202
+ return gmXhrError('The headers this request asked for could not be applied, so it was not sent');
203
+ }
204
+ // The one phrasing for a request the server never started answering.
205
+ // Says "no response headers" rather than "timed out" because the script
206
+ // may have set no timeout at all — this is the worker's own backstop,
207
+ // and a request left waiting forever would hold its header rule and
208
+ // block later requests to the same URL.
209
+ export function headerStallMessage(stallMs) {
210
+ const minutes = Math.round(stallMs / 60000);
211
+ const howLong = minutes === 1 ? '1 minute' : `${minutes} minutes`;
212
+ return gmXhrError(`The server sent no response headers within ${howLong}, so this request was given up on`);
213
+ }
214
+ // For a request the script asked to fail on a redirect
215
+ // (`redirect: 'error'`), which got one.
216
+ export function redirectRefusedMessage() {
217
+ return gmXhrError('The server redirected the request, and the script asked to fail on a redirect (redirect: "error")');
218
+ }
219
+ // For a request that never got a response: Chrome's `fetch` rejects
220
+ // with a bare "Failed to fetch" for a name that doesn't resolve, a
221
+ // refused or dropped connection, a failed TLS handshake, and a request
222
+ // another extension blocked alike, so the causes are listed rather than
223
+ // one guessed (see TODO.md for telling them apart). The host is the
224
+ // request's own; a redirect `fetch` followed to a dead host lands here
225
+ // too, with nothing to tell us which hop failed, so the message covers
226
+ // a site the host redirected to.
227
+ export function unreachableMessage(host) {
228
+ return gmXhrError(`Could not reach ${host} or a site it redirected to. The name may not resolve, or the connection was refused, failed or blocked.`);
229
+ }
230
+ // The one phrasing for a request the script's own header forbids: it
231
+ // names whose rules blocked the call rather than a "policy" object the
232
+ // reader can't see. `reason` is a sentence of its own.
233
+ //
234
+ // Only for a real denial. A URL we couldn't parse, or a failure to
235
+ // *evaluate* the rules, is not the header's doing and goes through
236
+ // `gmXhrError` directly.
237
+ export function connectBlockedMessage(reason) {
238
+ return gmXhrError(`This script's @connect rules don't allow this request. ${reason}`);
239
+ }
240
+ // The one phrasing for a host the user refused this script in the
241
+ // prompt. Says where the refusal can be undone, since it lasts until
242
+ // reset.
243
+ export function connectDeniedMessage(host) {
244
+ return gmXhrError(`Connecting to ${host} was denied for this script. `
245
+ + 'Manage permissions on the script\'s page in SourceMonkey.');
246
+ }
247
+ // The one phrasing for a request whose prompt the user cancelled (or
248
+ // closed). Nothing is kept, so the next request asks again, which goes
249
+ // without saying.
250
+ export function connectCancelledMessage(host) {
251
+ return gmXhrError(`SourceMonkey's permission prompt for connecting to ${host} was cancelled, so this request was blocked`);
252
+ }
253
+ // The one phrasing for a prompt that couldn't be shown. `cause` is
254
+ // Chrome's reason.
255
+ export function connectPromptFailedMessage(host, cause) {
256
+ // Chrome's reason, capitalized as a tail after `: ` is.
257
+ const tail = cause.charAt(0).toUpperCase() + cause.slice(1);
258
+ return gmXhrError(`SourceMonkey could not open its permission prompt for connecting to ${host}: ${tail}`);
259
+ }
260
+ // The one phrasing for a request refused because the script already has
261
+ // as many prompts open as it may (`MAX_PROMPTS_PER_SCRIPT`).
262
+ export function connectTooManyPromptsMessage(host, open) {
263
+ return gmXhrError(`SourceMonkey is already asking about ${open} other sites for this script, so this request to ${host} was blocked. `
264
+ + 'Answer those permission prompts, then try again.');
265
+ }
266
+ // The one phrasing for a request whose prompt went unanswered too long.
267
+ // The prompt closes with it, so the next request asks again.
268
+ export function connectUnansweredMessage(host, waitMs) {
269
+ const minutes = Math.round(waitMs / 60000);
270
+ const howLong = minutes === 1 ? '1 minute' : `${minutes} minutes`;
271
+ return gmXhrError(`SourceMonkey's permission prompt for connecting to ${host} had no answer within ${howLong}, `
272
+ + 'so this request was stopped');
273
+ }
@@ -0,0 +1,68 @@
1
+ export interface GmXhrRequestPayload {
2
+ method?: string;
3
+ url: string;
4
+ headers?: Record<string, string>;
5
+ data?: string;
6
+ body?: GmXhrBody;
7
+ timeout?: number;
8
+ responseType?: string;
9
+ anonymous?: boolean;
10
+ nocache?: boolean;
11
+ revalidate?: boolean;
12
+ redirect?: string;
13
+ }
14
+ export type GmXhrBody = {
15
+ kind: 'bytes';
16
+ data: string;
17
+ type: string;
18
+ } | {
19
+ kind: 'form';
20
+ entries: GmXhrFormEntry[];
21
+ } | {
22
+ kind: 'params';
23
+ data: string;
24
+ };
25
+ export type GmXhrFormEntry = {
26
+ name: string;
27
+ value: string;
28
+ } | {
29
+ name: string;
30
+ data: string;
31
+ filename: string;
32
+ type: string;
33
+ };
34
+ export interface GmXhrResponse {
35
+ status: number;
36
+ statusText: string;
37
+ responseURL: string;
38
+ responseText: string;
39
+ response: unknown;
40
+ responseMimeType?: string;
41
+ responseHeaders: string;
42
+ finalUrl: string;
43
+ }
44
+ export type GmXhrEvent = {
45
+ kind: 'load';
46
+ response: GmXhrResponse;
47
+ } | {
48
+ kind: 'error';
49
+ message: string;
50
+ } | {
51
+ kind: 'timeout';
52
+ } | {
53
+ kind: 'abort';
54
+ };
55
+ export type GmXhrStreamEvent = {
56
+ kind: 'headers';
57
+ status: number;
58
+ statusText: string;
59
+ finalUrl: string;
60
+ responseHeaders: string;
61
+ mimeType: string;
62
+ total: number | null;
63
+ } | {
64
+ kind: 'progress';
65
+ data: string;
66
+ loaded: number;
67
+ total: number | null;
68
+ };
@@ -0,0 +1,5 @@
1
+ // The `GM_xmlhttpRequest` wire types, between the page and the
2
+ // service worker's handler (gm-xhr.ts). Their own module so the
3
+ // harness, whose request fakes speak them, can use them without the
4
+ // handler.
5
+ export {};
@@ -0,0 +1,73 @@
1
+ import { type ManagerName } from './managers.js';
2
+ /** One manager extension in the browser. */
3
+ export interface InstalledManager {
4
+ manager: ManagerName;
5
+ /** Its extension id. */
6
+ id: string;
7
+ /** As the extension names itself (`Tampermonkey BETA`). */
8
+ name: string;
9
+ version: string;
10
+ enabled: boolean;
11
+ /** "Allow User Scripts" is on, which a manager needs to run scripts. */
12
+ userScripts: boolean;
13
+ /** The folder it was loaded from, when loaded unpacked, as Chrome says. */
14
+ path?: string;
15
+ /** Installed from the Chrome Web Store, as Chrome says. */
16
+ fromStore?: boolean;
17
+ }
18
+ /** Runs JavaScript in a page, and gives back its value. */
19
+ export type Evaluate = <R>(expression: string) => Promise<R>;
20
+ /** A hidden page kept open over its own connection, until `close`. */
21
+ export interface HiddenPage {
22
+ /** Fails when the page doesn't answer within `timeoutMs`. */
23
+ evaluate<R>(expression: string, timeoutMs?: number): Promise<R>;
24
+ close(): Promise<void>;
25
+ }
26
+ /**
27
+ * Opens a hidden page at `url` in the browser at `endpoint`, once
28
+ * `ready` (an expression) is true there, for several calls. Throws when
29
+ * it isn't ready within `timeoutMs`.
30
+ */
31
+ export declare function openHiddenPage(endpoint: string, url: string, ready: string, timeoutMs?: number): Promise<HiddenPage>;
32
+ /**
33
+ * The managers installed in the browser at `endpoint`, enabled or not:
34
+ * SourceMonkey first, then Tampermonkey, then Violentmonkey. Throws when
35
+ * it can't tell.
36
+ */
37
+ export declare function installedManagers(endpoint: string, timeoutMs?: number): Promise<InstalledManager[]>;
38
+ /** `installedManagers`, or null when it can't tell, for what only reports. */
39
+ export declare function managersIn(endpoint: string): Promise<InstalledManager[] | null>;
40
+ /** Turns an extension on or off, as its toggle in `chrome://extensions` does. */
41
+ export declare function setExtensionEnabled(endpoint: string, id: string, enabled: boolean): Promise<void>;
42
+ /** Turns on an extension's "Allow User Scripts", as its details page does. */
43
+ export declare function allowUserScripts(endpoint: string, id: string): Promise<void>;
44
+ /**
45
+ * Loads the unpacked extension in `dir` into the browser, or reloads it
46
+ * from there when it's loaded already. Returns its id.
47
+ */
48
+ export declare function loadUnpacked(endpoint: string, dir: string): Promise<string>;
49
+ /**
50
+ * Warns of each manager enabled beside `chosen`, whose scripts run in
51
+ * the run's tabs too, with how to turn it off. For a run's first lines,
52
+ * `status`, and the commands that connect without a run. `browserArg`:
53
+ * the flags that name the browser in the advice (see `browserArg` in
54
+ * run.ts).
55
+ */
56
+ export declare function otherManagersWarning(managers: InstalledManager[], chosen: ManagerName, browserArg?: string): string[];
57
+ /**
58
+ * The managers in the browser, for `status`: `SourceMonkey 0.0.1 (in
59
+ * use), Tampermonkey 5.5.1 (disabled)`. Each copy is listed, with what
60
+ * keeps it from running scripts. `None` when there are none. `mark`:
61
+ * what the chosen one is, when enabled.
62
+ */
63
+ export declare function managersText(managers: InstalledManager[], chosen: ManagerName, mark?: string): string;
64
+ /** Whether a manager is in a browser: enabled, there but turned off, or not there. */
65
+ export type ManagerState = 'installed' | 'disabled' | 'absent';
66
+ export declare function managerState(managers: InstalledManager[], name: ManagerName): ManagerState;
67
+ /** How a run's first line says the chosen manager's state: `has Tampermonkey`. */
68
+ export declare function stateLabel(state: ManagerState, name: ManagerName): string;
69
+ /** The browser at `endpoint`: Chrome's version, and whether it's headless. Null when nothing answers. */
70
+ export declare function browserVersion(endpoint: string): Promise<{
71
+ version: string;
72
+ headless: boolean;
73
+ } | null>;