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,33 @@
1
+ import { type ManagerName } from './managers.js';
2
+ /** Where fetched managers are kept. */
3
+ export declare function managerCacheDir(): string;
4
+ /** The folder a manager is fetched into, which is loaded unpacked. */
5
+ export declare function fetchedDir(name: ManagerName): string;
6
+ /** The version fetched, or null when there is none. */
7
+ export declare function fetchedVersion(name: ManagerName): string | null;
8
+ export interface Fetched {
9
+ dir: string;
10
+ version: string;
11
+ /** Newly downloaded, rather than already the newest. */
12
+ downloaded: boolean;
13
+ /** The version it replaced, if any. */
14
+ replaced?: string;
15
+ }
16
+ /**
17
+ * Fetches the manager's newest version, unless it's fetched already.
18
+ * Throws an error saying which step failed.
19
+ */
20
+ export declare function fetchManager(name: ManagerName, out: (line: string) => void): Promise<Fetched>;
21
+ /**
22
+ * A CRX3 file's zip, and the public key (base64) its extension id comes
23
+ * from. Throws when it isn't one, or none of its keys gives `id`.
24
+ */
25
+ export declare function readCrx(crx: Buffer, id: string): {
26
+ key: string;
27
+ zip: Buffer;
28
+ };
29
+ /**
30
+ * Writes a zip's files under `dir`: stored or deflated entries, which
31
+ * is what a CRX holds. A name that would land outside `dir` is refused.
32
+ */
33
+ export declare function unzipTo(zip: Buffer, dir: string): Promise<void>;
@@ -0,0 +1,239 @@
1
+ // `manager fetch`: downloads Tampermonkey or Violentmonkey from the
2
+ // Chrome Web Store, unpacked, into sm-dev's cache, for `manager
3
+ // install` and a temp browser to load.
4
+ //
5
+ // - One folder per manager, `~/.cache/sm-dev/managers/<name>`
6
+ // (`$XDG_CACHE_HOME` when set), replaced whole by a newer version, so
7
+ // a browser that loaded it from there reloads the new one.
8
+ // - The download is a CRX: a header, with the store's signature and
9
+ // public key, then a zip. The key goes into the unpacked manifest as
10
+ // `key`, so the copy keeps the store's extension id, as the store's
11
+ // own install would have.
12
+ // - The store's update check says the newest version and the file's
13
+ // SHA-256, which the download is checked against.
14
+ import { createHash, randomBytes } from 'node:crypto';
15
+ import { existsSync, readFileSync } from 'node:fs';
16
+ import { mkdir, rename, rm, writeFile } from 'node:fs/promises';
17
+ import os from 'node:os';
18
+ import path from 'node:path';
19
+ import { inflateRawSync } from 'node:zlib';
20
+ import { extensionIdFromKey } from './extension-backend.js';
21
+ import { MANAGERS } from './managers.js';
22
+ // The update service Chrome itself asks. `prodversion` is the Chrome
23
+ // version asking: a high one gets the newest build.
24
+ const UPDATE_URL = 'https://clients2.google.com/service/update2/crx';
25
+ const PROD_VERSION = '999.0';
26
+ /** Where fetched managers are kept. */
27
+ export function managerCacheDir() {
28
+ const cache = process.env.XDG_CACHE_HOME?.trim() || path.join(os.homedir(), '.cache');
29
+ return path.join(cache, 'sm-dev', 'managers');
30
+ }
31
+ /** The folder a manager is fetched into, which is loaded unpacked. */
32
+ export function fetchedDir(name) {
33
+ return path.join(managerCacheDir(), name);
34
+ }
35
+ /** The version fetched, or null when there is none. */
36
+ export function fetchedVersion(name) {
37
+ try {
38
+ const manifest = JSON.parse(readFileSync(path.join(fetchedDir(name), 'manifest.json'), 'utf8'));
39
+ return typeof manifest.version === 'string' ? manifest.version : null;
40
+ }
41
+ catch {
42
+ return null;
43
+ }
44
+ }
45
+ /**
46
+ * Fetches the manager's newest version, unless it's fetched already.
47
+ * Throws an error saying which step failed.
48
+ */
49
+ export async function fetchManager(name, out) {
50
+ const { label, storeId } = MANAGERS[name];
51
+ if (!storeId)
52
+ throw new Error(`Internal error: ${label} has no Web Store id to fetch it by`);
53
+ const dir = fetchedDir(name);
54
+ const have = fetchedVersion(name);
55
+ const latest = await newestVersion(label, storeId);
56
+ if (have === latest.version)
57
+ return { dir, version: have, downloaded: false };
58
+ out(`[sm-dev] Fetching ${label} ${latest.version} from the Chrome Web Store`);
59
+ let crx;
60
+ try {
61
+ const res = await fetch(latest.url, { signal: AbortSignal.timeout(120_000) });
62
+ if (!res.ok)
63
+ throw new Error(`HTTP ${res.status}`);
64
+ crx = Buffer.from(await res.arrayBuffer());
65
+ }
66
+ catch (err) {
67
+ throw new Error(`${label} could not be downloaded from the Chrome Web Store: ${err.message}`);
68
+ }
69
+ if (latest.sha256 && createHash('sha256').update(crx).digest('hex') !== latest.sha256) {
70
+ throw new Error(`The ${label} download from the Chrome Web Store doesn't match the checksum the store gave. Try again.`);
71
+ }
72
+ const { key, zip } = readCrx(crx, storeId);
73
+ const parent = managerCacheDir();
74
+ await mkdir(parent, { recursive: true });
75
+ // Unpacked beside it, then swapped in, so a failure leaves the old
76
+ // copy as it was.
77
+ const fresh = path.join(parent, `.${name}-${randomBytes(4).toString('hex')}`);
78
+ try {
79
+ await unzipTo(zip, fresh);
80
+ // The store's signature over the files, which Chrome refuses in an
81
+ // unpacked extension (a name starting with _ is reserved).
82
+ await rm(path.join(fresh, '_metadata'), { recursive: true, force: true });
83
+ const manifestFile = path.join(fresh, 'manifest.json');
84
+ const manifest = JSON.parse(readFileSync(manifestFile, 'utf8'));
85
+ manifest.key = key;
86
+ await writeFile(manifestFile, JSON.stringify(manifest, null, 2));
87
+ if (existsSync(dir)) {
88
+ const old = `${fresh}-old`;
89
+ await rename(dir, old);
90
+ await rename(fresh, dir);
91
+ await rm(old, { recursive: true, force: true });
92
+ }
93
+ else {
94
+ await rename(fresh, dir);
95
+ }
96
+ }
97
+ catch (err) {
98
+ await rm(fresh, { recursive: true, force: true });
99
+ throw new Error(`${label} could not be unpacked into ${dir}: ${err.message}`);
100
+ }
101
+ return { dir, version: latest.version, downloaded: true, ...(have ? { replaced: have } : {}) };
102
+ }
103
+ // The store's newest version of an extension, with where to download it.
104
+ async function newestVersion(label, storeId) {
105
+ const query = `${UPDATE_URL}?prodversion=${PROD_VERSION}&acceptformat=crx3&x=${encodeURIComponent(`id=${storeId}&uc`)}`;
106
+ let xml;
107
+ try {
108
+ const res = await fetch(query, { signal: AbortSignal.timeout(30_000) });
109
+ if (!res.ok)
110
+ throw new Error(`HTTP ${res.status}`);
111
+ xml = await res.text();
112
+ }
113
+ catch (err) {
114
+ throw new Error(`The Chrome Web Store could not be asked for ${label}'s newest version: ${err.message}`);
115
+ }
116
+ const check = /<updatecheck\b([^>]*)>/.exec(xml)?.[1] ?? '';
117
+ const attr = (attrName) => new RegExp(`\\b${attrName}="([^"]*)"`).exec(check)?.[1];
118
+ const version = attr('version');
119
+ const url = attr('codebase');
120
+ if (attr('status') !== 'ok' || !version || !url) {
121
+ throw new Error(`The Chrome Web Store has no download for ${label} (status ${attr('status') ?? 'missing'})`);
122
+ }
123
+ return { version, url: url.replace(/&amp;/g, '&'), sha256: attr('hash_sha256') };
124
+ }
125
+ /**
126
+ * A CRX3 file's zip, and the public key (base64) its extension id comes
127
+ * from. Throws when it isn't one, or none of its keys gives `id`.
128
+ */
129
+ export function readCrx(crx, id) {
130
+ if (crx.length < 12 || crx.toString('latin1', 0, 4) !== 'Cr24' || crx.readUInt32LE(4) !== 3) {
131
+ throw new Error('The download is not a Chrome extension package (CRX3)');
132
+ }
133
+ const headerSize = crx.readUInt32LE(8);
134
+ const header = crx.subarray(12, 12 + headerSize);
135
+ // CrxFileHeader: field 2 (sha256_with_rsa) and 3 (sha256_with_ecdsa)
136
+ // are AsymmetricKeyProofs, whose field 1 is the public key.
137
+ const keys = [];
138
+ for (const [field, proof] of protoFields(header)) {
139
+ if (field !== 2 && field !== 3)
140
+ continue;
141
+ for (const [inner, value] of protoFields(proof))
142
+ if (inner === 1)
143
+ keys.push(value);
144
+ }
145
+ const key = keys.map((k) => k.toString('base64')).find((k) => extensionIdFromKey(k) === id);
146
+ if (!key)
147
+ throw new Error(`The package has no key for extension id ${id}`);
148
+ return { key, zip: crx.subarray(12 + headerSize) };
149
+ }
150
+ // The length-delimited fields of a protobuf message, as [number, bytes].
151
+ // Other wire types are skipped.
152
+ function protoFields(buf) {
153
+ const fields = [];
154
+ let i = 0;
155
+ const varint = () => {
156
+ let value = 0;
157
+ let shift = 0;
158
+ for (;;) {
159
+ if (i >= buf.length)
160
+ throw new Error('The package header is cut short');
161
+ const byte = buf[i++];
162
+ value += (byte & 0x7f) * 2 ** shift;
163
+ if (!(byte & 0x80))
164
+ return value;
165
+ shift += 7;
166
+ }
167
+ };
168
+ while (i < buf.length) {
169
+ const tag = varint();
170
+ const wire = tag % 8;
171
+ const field = Math.floor(tag / 8);
172
+ if (wire === 0)
173
+ varint();
174
+ else if (wire === 1)
175
+ i += 8;
176
+ else if (wire === 5)
177
+ i += 4;
178
+ else if (wire === 2) {
179
+ const length = varint();
180
+ fields.push([field, buf.subarray(i, i + length)]);
181
+ i += length;
182
+ }
183
+ else {
184
+ throw new Error('The package header is not readable');
185
+ }
186
+ }
187
+ return fields;
188
+ }
189
+ /**
190
+ * Writes a zip's files under `dir`: stored or deflated entries, which
191
+ * is what a CRX holds. A name that would land outside `dir` is refused.
192
+ */
193
+ export async function unzipTo(zip, dir) {
194
+ // The end of central directory record, last in the file but for a
195
+ // comment of up to 64KB.
196
+ let end = -1;
197
+ for (let i = zip.length - 22; i >= Math.max(0, zip.length - 22 - 65_535); i--) {
198
+ if (zip.readUInt32LE(i) === 0x06054b50) {
199
+ end = i;
200
+ break;
201
+ }
202
+ }
203
+ if (end < 0)
204
+ throw new Error('The package\'s zip has no central directory');
205
+ const count = zip.readUInt16LE(end + 10);
206
+ let at = zip.readUInt32LE(end + 16);
207
+ const root = path.resolve(dir);
208
+ await mkdir(root, { recursive: true });
209
+ for (let n = 0; n < count; n++) {
210
+ if (zip.readUInt32LE(at) !== 0x02014b50)
211
+ throw new Error('The package\'s zip directory is damaged');
212
+ const method = zip.readUInt16LE(at + 10);
213
+ const size = zip.readUInt32LE(at + 20);
214
+ const nameLength = zip.readUInt16LE(at + 28);
215
+ const extraLength = zip.readUInt16LE(at + 30);
216
+ const commentLength = zip.readUInt16LE(at + 32);
217
+ const local = zip.readUInt32LE(at + 42);
218
+ const name = zip.toString('utf8', at + 46, at + 46 + nameLength);
219
+ at += 46 + nameLength + extraLength + commentLength;
220
+ const target = path.resolve(root, name);
221
+ if (target !== root && !target.startsWith(root + path.sep))
222
+ throw new Error(`The package holds a file outside its folder: ${name}`);
223
+ if (name.endsWith('/')) {
224
+ await mkdir(target, { recursive: true });
225
+ continue;
226
+ }
227
+ const start = local + 30 + zip.readUInt16LE(local + 26) + zip.readUInt16LE(local + 28);
228
+ const data = zip.subarray(start, start + size);
229
+ let body;
230
+ if (method === 0)
231
+ body = data;
232
+ else if (method === 8)
233
+ body = inflateRawSync(data);
234
+ else
235
+ throw new Error(`The package's file ${name} is compressed in a way sm-dev can't read (method ${method})`);
236
+ await mkdir(path.dirname(target), { recursive: true });
237
+ await writeFile(target, body);
238
+ }
239
+ }
@@ -0,0 +1,24 @@
1
+ import type { ManagerName } from './json-output.js';
2
+ export type { ManagerName };
3
+ export interface ManagerInfo {
4
+ name: ManagerName;
5
+ /** `sm`, `tm`, `vm`: what `--manager` takes, besides the full name. */
6
+ short: string;
7
+ label: string;
8
+ /**
9
+ * Its Chrome Web Store id, which `manager fetch` downloads by. The
10
+ * same as in tests/fixtures/managers.mjs, which can't import this.
11
+ * SourceMonkey comes with sm-dev instead.
12
+ */
13
+ storeId?: string;
14
+ }
15
+ export declare const MANAGERS: Record<ManagerName, ManagerInfo>;
16
+ export declare const MANAGER_NAMES: ManagerName[];
17
+ /** The default, when `--manager` isn't given. */
18
+ export declare const DEFAULT_MANAGER: ManagerName;
19
+ /** The manager `value` names (`tm`, `Tampermonkey`, any case), or null. */
20
+ export declare function managerNamed(value: string): ManagerName | null;
21
+ /** What `--manager` says of a value it doesn't take. */
22
+ export declare function managerMistake(value: string): string;
23
+ /** `--manager tm`, the flag that picks it, for a command to show. */
24
+ export declare function managerFlag(name: ManagerName): string;
@@ -0,0 +1,27 @@
1
+ // The userscript managers sm-dev knows: SourceMonkey, Tampermonkey (TM)
2
+ // and Violentmonkey (VM). `--manager` picks one for the whole line,
3
+ // and each command says which it works with (command-list.ts).
4
+ //
5
+ // It imports only json-output.ts, which imports nothing, so
6
+ // command-list.ts can load it for help.
7
+ export const MANAGERS = {
8
+ sourcemonkey: { name: 'sourcemonkey', short: 'sm', label: 'SourceMonkey' },
9
+ tampermonkey: { name: 'tampermonkey', short: 'tm', label: 'Tampermonkey', storeId: 'dhdgffkkebhmkfjojejmpbldmpobfkfo' },
10
+ violentmonkey: { name: 'violentmonkey', short: 'vm', label: 'Violentmonkey', storeId: 'jinjaccalgkegednnccohejagnlnfdag' },
11
+ };
12
+ export const MANAGER_NAMES = Object.keys(MANAGERS);
13
+ /** The default, when `--manager` isn't given. */
14
+ export const DEFAULT_MANAGER = 'sourcemonkey';
15
+ /** The manager `value` names (`tm`, `Tampermonkey`, any case), or null. */
16
+ export function managerNamed(value) {
17
+ const v = value.trim().toLowerCase();
18
+ return MANAGER_NAMES.find((name) => name === v || MANAGERS[name].short === v) ?? null;
19
+ }
20
+ /** What `--manager` says of a value it doesn't take. */
21
+ export function managerMistake(value) {
22
+ return `There is no manager ${value}. The --manager flag takes sm, tm or vm, or sourcemonkey, tampermonkey or violentmonkey`;
23
+ }
24
+ /** `--manager tm`, the flag that picks it, for a command to show. */
25
+ export function managerFlag(name) {
26
+ return `--manager ${MANAGERS[name].short}`;
27
+ }
@@ -0,0 +1,125 @@
1
+ /**
2
+ * Starts a line's markup: a control character and a private-use one, a
3
+ * pair page text won't hold by chance (icon fonts use U+E000 alone),
4
+ * and invisible if it ever leaks.
5
+ */
6
+ export declare const MARKUP = "\u0002\uE000";
7
+ /** What a piece of output is. Each has one style, in STYLES. */
8
+ export type Role = 'prompt' | 'typed' | 'cmd' | 'code' | 'err' | 'warn' | 'h' | 'sel' | 'id' | 'dim' | 'url' | 'name';
9
+ /**
10
+ * A role's SGR codes, on and off, for text painted elsewhere (help's
11
+ * code and headings). Off undoes only that role's looks, so it can
12
+ * nest inside another (code in a bold heading), as long as the two
13
+ * share no look: were `cmd` bold too, its off would end the heading's
14
+ * bold.
15
+ */
16
+ export declare function styleCodes(roleName: Role): [string, string];
17
+ /**
18
+ * Whether a code span keeps its backticks in plain text (help, and sm-dev's messages): one of several
19
+ * words (`--lang zh-CN`), a lowercase word that reads as English (a
20
+ * command, `all`), or punctuation (`{{`). A flag, ID, number, path or
21
+ * name reads as code without them.
22
+ */
23
+ export declare function keepsBackticks(span: string): boolean;
24
+ /** Starts sm-dev's own messages. */
25
+ export declare const SM_DEV_PREFIX = "[sm-dev] ";
26
+ /** Starts the client's line for a command given wrongly. */
27
+ export declare const ERROR_PREFIX = "ERROR: ";
28
+ /** Starts a run's line for a command given wrongly (exit code 2). */
29
+ export declare const MISTAKE_PREFIX = "[sm-dev] ERROR: ";
30
+ /** Starts a warning about the browser. */
31
+ export declare const WARNING_PREFIX = "Warning: ";
32
+ /** Starts a script's warning from preparing it (`warningLines`). */
33
+ export declare const WARNING_LEVEL = "warn: ";
34
+ /** Starts a script's warning from preparing it, as a run prints it. */
35
+ export declare const SCRIPT_WARNING_PREFIX = "[sm-dev] warn: ";
36
+ /** Starts a failed `wait`. */
37
+ export declare const WAIT_FAILED = "[sm-dev] Wait failed: ";
38
+ /** Starts `validate`'s line for an invalid script, and a run's. */
39
+ export declare const INVALID_PREFIX = "INVALID ";
40
+ /**
41
+ * Text in backticks, for a message: a command, flag or the user's input
42
+ * (`` Use `tabs` ``). Shown as a command in color, and plain with its
43
+ * backticks where they help it read (see keepsBackticks). Text holding a
44
+ * backtick itself (a selector, say) goes in double ones, as Markdown
45
+ * does: ``` `` a`b `` ```.
46
+ */
47
+ export declare function quoted(text: unknown): string;
48
+ /** Text escaped for markup. */
49
+ export declare function escapeMarkup(text: string): string;
50
+ /** A table cell: its text, and the same as markup. Columns line up by the text. */
51
+ export interface Cell {
52
+ plain: string;
53
+ styled: string;
54
+ }
55
+ /** A cell of plain text. */
56
+ export declare const textCell: (text: string) => Cell;
57
+ /** A cell in a role: `roleCell(url, 'https://x/')`. */
58
+ export declare const roleCell: (style: (text: string) => string, text: string) => Cell;
59
+ /**
60
+ * Rows as lines: columns two spaces apart, each as wide as its widest
61
+ * cell. The last column isn't padded, so no line ends in spaces. As
62
+ * markup, or with `markup: false`, as plain text.
63
+ */
64
+ export declare function tableLines(rows: Cell[][], { markup }?: {
65
+ markup?: boolean;
66
+ }): string[];
67
+ /** Text as a role: `role('id', 'T1')`. Text that is markup already stays markup. */
68
+ export declare function role(name: Role, text: string | number): string;
69
+ export declare const id: (text: string | number) => string;
70
+ export declare const name: (text: string) => string;
71
+ export declare const url: (text: string) => string;
72
+ export declare const cmd: (text: string) => string;
73
+ export declare const code: (text: string) => string;
74
+ export declare const heading: (text: string) => string;
75
+ export declare const selected: (text: string) => string;
76
+ export declare const dim: (text: string) => string;
77
+ /** A message we wrote, as an error: its `backticked` spans are commands (see `message`). */
78
+ export declare const err: (text: string) => string;
79
+ /** A message we wrote, as a warning. */
80
+ export declare const warn: (text: string) => string;
81
+ /** Text we didn't write (a script's console line, a page's error), as an error, taken as it is. */
82
+ export declare const asError: (text: string) => string;
83
+ /** Text we didn't write, as a warning. */
84
+ export declare const asWarning: (text: string) => string;
85
+ /**
86
+ * A line of markup, from a template: what is put in is escaped, unless
87
+ * it is markup already (from `ui` or a role helper).
88
+ */
89
+ export declare function ui(strings: TemplateStringsArray, ...values: unknown[]): string;
90
+ /**
91
+ * A message we wrote, as markup: each `backticked` span is a command
92
+ * (`Use `tabs` to list them`), shown in color, or with its backticks
93
+ * where they help it read (see keepsBackticks). Text that is markup
94
+ * already stays as it is.
95
+ */
96
+ export declare function message(text: string): string;
97
+ /**
98
+ * A line as shown: painted for a terminal with color, or plain. Plain
99
+ * text that is not one of sm-dev's messages is returned as it is.
100
+ */
101
+ export declare function paintOutput(line: string, color: boolean): string;
102
+ /**
103
+ * Output that may span lines (a stack trace in one error) as lines that
104
+ * each stand alone, for a reader that paints line by line. A role open
105
+ * at a line break is closed there and opened again on the next line, so
106
+ * every line is markup of its own; without that, the lines after the
107
+ * first would show their tags and escapes as text.
108
+ * - Plain text before the markup stays as it is at the start of its
109
+ * line, where readers look for a prefix (`[sm-dev] `).
110
+ * - Plain text with no markup is just split: each line is read on its
111
+ * own, by its own prefix.
112
+ */
113
+ export declare function markupLines(line: string): string[];
114
+ /** A line as plain text: for the log file, and for clients that didn't ask for markup. */
115
+ export declare function plainLine(line: string): string;
116
+ /**
117
+ * Whether output to `stream` is painted: at a terminal that has color.
118
+ * FORCE_COLOR asks for it anyway (or, as 0 or false, not), as Node
119
+ * reads it; NO_COLOR is honored by hasColors.
120
+ */
121
+ export declare function streamHasColor(stream: NodeJS.WriteStream): boolean;
122
+ /** A command echoed before its output, as the prompt shows it: `arg > status`. */
123
+ export declare function echoLine(mark: string, text: string): string;
124
+ /** Text painted as one role, for a terminal with color: the prompt and typed commands. */
125
+ export declare function paintAs(roleName: Role, text: string): string;