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,148 @@
1
+ // GitHub personal access token storage + helper for attaching the
2
+ // `Authorization: Bearer <token>` header onto requests that target a
3
+ // GitHub host (so we can fetch private repos and lift the
4
+ // unauthenticated 60/hour rate limit to 5000/hour).
5
+ //
6
+ // Mirrors `debug-log.ts`'s shape: one chrome.storage.local key, a
7
+ // cached in-memory copy, a `load…` for boot-time hydration, and an
8
+ // `install…Listener` for live updates without an SW restart.
9
+ //
10
+ // Hosts we attach the header to:
11
+ // - api.github.com (Contents API, repo metadata)
12
+ // - raw.githubusercontent.com (raw bytes for blob URLs we rewrite to)
13
+ // Any other URL passes through untouched. Sending the header to
14
+ // non-GitHub hosts would leak the token, so the gate is strict.
15
+ //
16
+ // Notable omission: `github.com/<o>/<r>/raw/<ref>/<path>` (the "Raw"
17
+ // button URL). GitHub serves a 302 to raw.githubusercontent.com on
18
+ // that route, and the Fetch spec strips the `Authorization` header
19
+ // on cross-origin redirects — so the auth header would never reach
20
+ // raw, and the github.com hop itself doesn't honour our PAT for the
21
+ // bytes either. `normalizeGithubInput` rewrites `/blob/` and bare-
22
+ // repo URLs to the raw form at add time; users with a `/raw/` URL
23
+ // in hand can paste either the `/blob/` form (auto-rewritten) or the
24
+ // `raw.githubusercontent.com` form directly.
25
+ export const GITHUB_AUTH_TOKEN_KEY = 'githubAuthToken';
26
+ let cachedToken = '';
27
+ export function getGithubAuthToken() {
28
+ return cachedToken;
29
+ }
30
+ // Test/debug hook. Production callers should toggle the storage key
31
+ // instead so the change persists and is observed via onChanged.
32
+ export function _setGithubAuthTokenForTests(value) {
33
+ cachedToken = value;
34
+ }
35
+ export async function loadGithubAuthToken() {
36
+ try {
37
+ const got = await chrome.storage.local.get(GITHUB_AUTH_TOKEN_KEY);
38
+ const raw = got[GITHUB_AUTH_TOKEN_KEY];
39
+ cachedToken = typeof raw === 'string' ? raw : '';
40
+ }
41
+ catch {
42
+ cachedToken = '';
43
+ }
44
+ }
45
+ // The load, memoized. A service worker that woke up to answer a fetch
46
+ // request has a startup read in flight; a caller that needs the token
47
+ // to be *there* awaits this instead of racing it. Subsequent changes
48
+ // arrive through the onChanged listener below, so one load is enough.
49
+ let loadOnce = null;
50
+ export function ensureGithubAuthTokenLoaded() {
51
+ if (!loadOnce)
52
+ loadOnce = loadGithubAuthToken();
53
+ return loadOnce;
54
+ }
55
+ // The worker's `writeSetting` publishes the token at once, so a refresh
56
+ // it runs next doesn't wait for the change event.
57
+ export function setGithubAuthToken(token) {
58
+ cachedToken = token;
59
+ }
60
+ export function installGithubAuthListener() {
61
+ chrome.storage.onChanged.addListener((changes, areaName) => {
62
+ if (areaName !== 'local')
63
+ return;
64
+ const change = changes[GITHUB_AUTH_TOKEN_KEY];
65
+ if (!change)
66
+ return;
67
+ cachedToken = typeof change.newValue === 'string' ? change.newValue : '';
68
+ });
69
+ }
70
+ // True if the URL targets a GitHub-controlled host we'd want to
71
+ // authenticate against. Pure function — exported for unit tests.
72
+ export function isGithubAuthUrl(url) {
73
+ let parsed;
74
+ try {
75
+ parsed = new URL(url);
76
+ }
77
+ catch {
78
+ return false;
79
+ }
80
+ const host = parsed.hostname.toLowerCase();
81
+ if (host === 'api.github.com')
82
+ return true;
83
+ if (host === 'raw.githubusercontent.com')
84
+ return true;
85
+ // `github.com` itself is intentionally NOT in the gate — the only
86
+ // bytes-serving route on that host (`/<o>/<r>/raw/...`) 302s to
87
+ // raw.githubusercontent.com, and the Fetch spec strips
88
+ // `Authorization` on cross-origin redirects. See the module header.
89
+ return false;
90
+ }
91
+ // Return the `Authorization` header (and the `X-GitHub-Api-Version`
92
+ // pinning header) for a GitHub URL when a token is set; an empty
93
+ // object otherwise. Safe to spread into a `headers` object that may
94
+ // already carry an `Accept`. Callers should ALWAYS go through this
95
+ // helper rather than reading `cachedToken` directly so the host gate
96
+ // can't be accidentally skipped.
97
+ export function githubAuthHeaders(url) {
98
+ if (!cachedToken)
99
+ return {};
100
+ if (!isGithubAuthUrl(url))
101
+ return {};
102
+ return {
103
+ Authorization: `Bearer ${cachedToken}`,
104
+ // Pin the REST API version. Optional for the endpoints we hit
105
+ // today, but cheap insurance against a future shape change.
106
+ 'X-GitHub-Api-Version': '2022-11-28',
107
+ };
108
+ }
109
+ // True when a request to this URL would actually carry the GitHub
110
+ // auth header (URL is GitHub-eligible AND a token is configured).
111
+ // Same predicate `githubAuthHeaders` uses; exposed so log/UI callers
112
+ // can mirror its decision without re-running the header build.
113
+ export function isGithubAuthInUse(url) {
114
+ if (!cachedToken)
115
+ return false;
116
+ return isGithubAuthUrl(url);
117
+ }
118
+ // True when a *collection URL* (the stored collectionPath, not a
119
+ // per-fetch URL) describes content SourceMonkey reaches through GitHub
120
+ // — covers the github-dir case where `collectionPath` is a
121
+ // `github.com/<o>/<r>/tree/...` page URL but the actual scan + per-
122
+ // script fetches go to api.github.com + raw.githubusercontent.com.
123
+ // Returns true iff a token is configured AND the collection URL is
124
+ // recognisably GitHub. Used by the collection-refresh log line.
125
+ export function isGithubAuthInUseForCollection(collectionPath) {
126
+ if (!cachedToken)
127
+ return false;
128
+ if (isGithubAuthUrl(collectionPath))
129
+ return true;
130
+ // github.com page URLs (`/blob/`, `/tree/`, bare repo) aren't
131
+ // fetched directly — but a github-dir collection resolves to authed
132
+ // api.github.com + raw.githubusercontent.com calls. Recognise the
133
+ // github.com host so those collections get the suffix too.
134
+ try {
135
+ const host = new URL(collectionPath).hostname.toLowerCase();
136
+ return host === 'github.com';
137
+ }
138
+ catch {
139
+ return false;
140
+ }
141
+ }
142
+ // Log-line suffix used by the updater so the SW console makes it
143
+ // obvious when a collection refresh / per-script check is going out
144
+ // authenticated. Empty string when no token would apply, so callers
145
+ // can unconditionally `${label}${githubTokenLogSuffix(url)}`.
146
+ export function githubTokenLogSuffix(url) {
147
+ return isGithubAuthInUseForCollection(url) ? ' (with GitHub token)' : '';
148
+ }
@@ -0,0 +1,46 @@
1
+ // A GitHub raw URL's page on github.com. Its own module so code that
2
+ // only shows links (match-targets.ts) needn't load the GitHub provider.
3
+ // Reverse of `githubFileUrlToRaw` (github-provider.ts): take a
4
+ // raw-content GitHub URL and return its
5
+ // `github.com/<o>/<r>/blob/<ref>/<path>` counterpart — the
6
+ // page a human would open in a browser. Used wherever the UI surfaces
7
+ // a github URL for clicking (collections-page bubble, viewer Location
8
+ // row): the raw URL is what we fetch from, but the blob URL is what
9
+ // the user wants to see.
10
+ //
11
+ // "Raw" here covers both hosts GitHub serves raw bytes from:
12
+ // - `raw.githubusercontent.com/<o>/<r>/[refs/<type>/]<ref>/<path>`
13
+ // - `github.com/<o>/<r>/raw/[refs/<type>/]<ref>/<path>` (the form
14
+ // produced by github.com's own "Raw" button — it 302s to the
15
+ // `raw.githubusercontent.com` host but we may store the URL in
16
+ // this form when the user pastes it directly, or when a manifest
17
+ // entry resolves to a URL in this shape).
18
+ //
19
+ // The optional `/refs/<type>/` segment is the new-style raw URL.
20
+ // `<type>` is typically `heads` (branch) but can also be `tags` or
21
+ // `pull` — we accept any single segment there so tag URLs map
22
+ // correctly to `blob/<tag>/<path>`. Both stripped shapes resolve to
23
+ // the same content.
24
+ //
25
+ // Limitation shared with github-provider.ts: branch names
26
+ // containing `/` (e.g. `feature/foo`) are not supported — the
27
+ // first ref segment is taken and the rest folded into the path.
28
+ //
29
+ // Returns null for any URL that isn't a recognised raw URL — callers
30
+ // fall back to the original URL.
31
+ //
32
+ // Query strings + fragments get stripped — they don't carry over to
33
+ // the github.com page (a `?token=…` is raw-only; an `#L42` fragment
34
+ // would point at the wrong viewer anchor).
35
+ export function githubRawToBlobUrl(rawUrl) {
36
+ // Two regexes (rather than one with alternation) because owner/repo
37
+ // sit at different positions in the two shapes.
38
+ let m = /^https?:\/\/raw\.githubusercontent\.com\/([^\/]+)\/([^\/]+)\/(?:refs\/[^\/]+\/)?([^\/]+)\/([^?#]+)/i.exec(rawUrl);
39
+ if (!m) {
40
+ m = /^https?:\/\/github\.com\/([^\/]+)\/([^\/]+)\/raw\/(?:refs\/[^\/]+\/)?([^\/]+)\/([^?#]+)/i.exec(rawUrl);
41
+ }
42
+ if (!m)
43
+ return null;
44
+ const [, owner, repo, ref, path] = m;
45
+ return `https://github.com/${owner}/${repo}/blob/${ref}/${path}`;
46
+ }
@@ -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
+ }