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,51 @@
1
+ import type { StoredScript } from './script-build.js';
2
+ import { type ParsedHeader } from './userscript-header.js';
3
+ import { type VersionProbe } from './version-probe.js';
4
+ export declare const ENABLE_TITLE = "Enable this script";
5
+ export declare function decodeForDisplay(text: string): string;
6
+ export declare function leafName(path: string): string;
7
+ export declare function displayLocation(urlOrPath: string): string;
8
+ export declare function scriptBasename(urlOrPath: string): string;
9
+ export declare function logIdSuffix(logId: string): string;
10
+ /** The script number a log ID ends with (`foo.user.js#E4` → 4), or null for none. */
11
+ export declare function logIdScriptNumber(logId: string): number | null;
12
+ export declare function scriptDisplayName(script: Pick<StoredScript, 'header' | 'relativePath'>, fallback?: string): string;
13
+ export declare function compareScriptNames(a: string, b: string): number;
14
+ export declare function headerDisplayName(header: ParsedHeader | null | undefined): string;
15
+ export declare function scriptLabel(header: ParsedHeader | null | undefined, location: string): string;
16
+ export declare function appendWithSlashBreaks(el: HTMLElement, text: string): void;
17
+ export declare function formatBytes(size: number): string;
18
+ export declare function formatStorageUsage(used: number, quota: number): string;
19
+ export declare function formatQuota(bytes: number): string;
20
+ export declare function formatScriptSize(script: Pick<StoredScript, 'status' | 'size'>): string;
21
+ export type DisplayStatus = 'ok' | 'invalid' | 'rejected' | 'refresh-failed' | 'outdated' | 'warning' | 'error';
22
+ export type LoadState = Exclude<DisplayStatus, 'warning' | 'error'>;
23
+ export declare const LOAD_STATES: readonly LoadState[];
24
+ export declare function isLoadState(value: unknown): value is LoadState;
25
+ export type LogLevelForStatus = 'info' | 'warning' | 'error';
26
+ export declare function effectiveScriptStatus(script: Pick<StoredScript, 'status' | 'refreshError'>, maxLogLevel: LogLevelForStatus | undefined, outdated?: boolean, rejected?: boolean): DisplayStatus;
27
+ export declare function scriptOutdatedProbe(script: Pick<StoredScript, 'header' | 'versionProbes'>): VersionProbe | null;
28
+ export declare function formatScriptStatusLabel(status: DisplayStatus): string;
29
+ export declare function viewerUrl(scriptId: string, tab?: 'log'): string;
30
+ export declare function compareUrl(base: {
31
+ script: string;
32
+ } | {
33
+ preview: string;
34
+ }, other: string): string;
35
+ export declare function previewUrl(location: string): string;
36
+ export interface ScriptStatusView {
37
+ status: DisplayStatus;
38
+ label: string;
39
+ title?: string;
40
+ }
41
+ export declare function scriptStatusView(script: Pick<StoredScript, 'status' | 'refreshError' | 'errorMessage' | 'errorLocation' | 'header' | 'versionProbes'>, maxLogLevel: LogLevelForStatus | undefined, rejection: string | undefined): ScriptStatusView;
42
+ export declare function stripSriFragment(urlOrRef: string): string;
43
+ export declare function fullSource(script: StoredScript): string;
44
+ export declare function requireBasename(url: string, ref: string): string;
45
+ export interface PendingOnDisk {
46
+ modified: number;
47
+ deleted: number;
48
+ added: number;
49
+ manifest?: true;
50
+ }
51
+ export declare function pendingSummary(counts: PendingOnDisk): string;
@@ -0,0 +1,383 @@
1
+ // Display helpers shared by the collections page, the userscript viewer,
2
+ // the script preview, and the service worker.
3
+ //
4
+ // Two groups live here: the script-status row formatting (size +
5
+ // status label) both pages render, and the name/path formatting that
6
+ // turns a stored URL into something a human wants to read. Pure
7
+ // functions — no DOM, no chrome.* calls. (`version-probe.js` is the
8
+ // pure half of the probe module; its fetching half lives in
9
+ // `version-probe-fetch.js` and is deliberately not reachable here.)
10
+ import { getValue, joinFullSource } from './userscript-header.js';
11
+ import { outdatedProbe, probeLabel } from './version-probe.js';
12
+ import { describeDiagnostic } from './diagnostic-location.js';
13
+ // ---------- Names and paths ----------
14
+ // Anything of the form `<scheme>://…`. Used to decide whether
15
+ // percent-decoding is safe: URL path segments are encoded, on-disk
16
+ // names are literal.
17
+ const ABSOLUTE_URL_RE = /^[a-z][a-z0-9+.-]*:\/\//i;
18
+ // Percent-decode for display. Never throws: a lone `%` (a literal
19
+ // percent in a filename) would make decodeURIComponent raise URIError,
20
+ // and losing the whole string is far worse than leaving one escape
21
+ // undecoded.
22
+ // Tooltip on a script's enable checkbox, wherever one is drawn: the
23
+ // collections page's per-row toggle, the viewer's controls row, the
24
+ // "Other versions" panel, and the toolbar popup's rows. The viewer and
25
+ // the popup append a multi-enable hint to it where other copies exist
26
+ // (see `enableTitle` in solo-click.ts); the collections page shows it
27
+ // bare.
28
+ export const ENABLE_TITLE = 'Enable this script';
29
+ export function decodeForDisplay(text) {
30
+ try {
31
+ return decodeURIComponent(text);
32
+ }
33
+ catch {
34
+ return text;
35
+ }
36
+ }
37
+ // Last `/`-separated segment of a path. No decoding — callers that
38
+ // want a display form pass the result through decodeForDisplay.
39
+ export function leafName(path) {
40
+ const slash = path.lastIndexOf('/');
41
+ return slash < 0 ? path : path.slice(slash + 1);
42
+ }
43
+ // Readable form of a stored location — the string a heading, tooltip,
44
+ // or title shows. Scripts installed from the web (GreasyFork above
45
+ // all) carry their human name inside the URL path, so the stored URL
46
+ // is a wall of `%20` / `%F0%9F…`; Chrome's own omnibox shows those
47
+ // decoded and so do we.
48
+ //
49
+ // Only absolute URLs are decoded. A relativePath from a local directory
50
+ // collection is a literal on-disk name, where a `%20` really is a
51
+ // percent followed by two digits.
52
+ //
53
+ // Display only: hrefs, clipboard copies, fetches, and stored values
54
+ // all keep the encoded form.
55
+ export function displayLocation(urlOrPath) {
56
+ return ABSOLUTE_URL_RE.test(urlOrPath) ? decodeForDisplay(urlOrPath) : urlOrPath;
57
+ }
58
+ // Short display name for a script's location: the URL's filename (no
59
+ // query string, decoded), or the last path segment for an on-disk
60
+ // relativePath. Falls back to the whole input when a URL-shaped string
61
+ // won't parse or has an empty path, so the caller always has something
62
+ // to render.
63
+ //
64
+ // The second `leafName` is not redundant: an escaped `%2F` decodes to
65
+ // a real slash, and this feeds log IDs — a "basename" carrying a path
66
+ // separator would read as a directory in every log line.
67
+ export function scriptBasename(urlOrPath) {
68
+ if (!ABSOLUTE_URL_RE.test(urlOrPath))
69
+ return leafName(urlOrPath);
70
+ try {
71
+ return leafName(decodeForDisplay(leafName(new URL(urlOrPath).pathname))) || urlOrPath;
72
+ }
73
+ catch {
74
+ return leafName(urlOrPath);
75
+ }
76
+ }
77
+ // The trailing suffix a log ID carries: the script's number (`#E4`),
78
+ // or `#N` for an unnumbered script sharing its basename; '' for none.
79
+ // Anchored to that shape rather than the first `#` in the string: log
80
+ // IDs are decoded filenames, so a script whose URL carries a `%23` has
81
+ // a literal `#` mid-name and would otherwise render half its own name
82
+ // as a suffix.
83
+ export function logIdSuffix(logId) {
84
+ return /#E?\d+$/.exec(logId)?.[0] ?? '';
85
+ }
86
+ /** The script number a log ID ends with (`foo.user.js#E4` → 4), or null for none. */
87
+ export function logIdScriptNumber(logId) {
88
+ const n = /#E(\d+)$/.exec(logId)?.[1];
89
+ return n === undefined ? null : Number(n);
90
+ }
91
+ // The name to show for a script in badges, menus, the collections list,
92
+ // and match listings: its `@name` when it declares a usable one, else
93
+ // its location in readable form. Shared so every surface labels the
94
+ // same script the same way.
95
+ //
96
+ // A whitespace-only `@name` counts as no name — a header that parsed
97
+ // but declared `// @name ` must not paint a blank row where a name
98
+ // belongs.
99
+ //
100
+ // `fallback` lets a caller substitute its own location text (the
101
+ // collections page shortens a container script's URL to its basename);
102
+ // omitted, the whole location is used.
103
+ export function scriptDisplayName(script, fallback) {
104
+ return headerDisplayName(script.header) || fallback || displayLocation(script.relativePath);
105
+ }
106
+ // The order scripts are listed in wherever names are shown in a list:
107
+ // case-insensitive, with numbers compared by value ("Item 9" before
108
+ // "Item 10"). Shared so every list orders the same scripts alike.
109
+ const nameCollator = new Intl.Collator(undefined, { sensitivity: 'base', numeric: true });
110
+ export function compareScriptNames(a, b) {
111
+ return nameCollator.compare(a, b);
112
+ }
113
+ // The `@name` a header declares, or '' when it declares none usable.
114
+ // Split out so the viewer's heading label and every other surface agree
115
+ // on what counts as a name — a future change to the rule (a localized
116
+ // `@name:en`, different trimming) must not land in only one of them.
117
+ export function headerDisplayName(header) {
118
+ return (header ? getValue(header, 'name')?.trim() : undefined) || '';
119
+ }
120
+ // The script's `@name`, or its location when it declares no usable one.
121
+ // The location is NOT appended to a name that exists — a heading
122
+ // carrying both runs the width of the window, and the details panel's
123
+ // `Location` row is where a reader goes for the full path.
124
+ //
125
+ // `headerDisplayName`, not a local read of `@name`: the viewer must not
126
+ // disagree with the collections page about what a script is called.
127
+ export function scriptLabel(header, location) {
128
+ return headerDisplayName(header) || displayLocation(location);
129
+ }
130
+ // Lives here rather than in collection-display.ts, its first caller: this
131
+ // module is a leaf, and page-heading.ts needs the helper on the early
132
+ // path where dragging in collection-display's scan/network graph would
133
+ // undo the point of loading early.
134
+ // Append a path / URL string to an element, inserting a `<wbr>` after
135
+ // each `/` so the browser prefers slash boundaries when wrapping a
136
+ // long value. Combined with `overflow-wrap: anywhere` on the element,
137
+ // the wrap order becomes: spaces first, then slashes, then anywhere
138
+ // inside a word only when nothing else fits. The slash itself stays
139
+ // attached to the preceding segment so it reads as `foo/` then a
140
+ // break, not a `/bar` continuation.
141
+ //
142
+ // Use this for any field that may render a long path or URL: the
143
+ // collections page display name, the viewer's Location row, the Match /
144
+ // Exclude pattern rows, etc.
145
+ export function appendWithSlashBreaks(el, text) {
146
+ const doc = el.ownerDocument;
147
+ const parts = text.split('/');
148
+ parts.forEach((part, i) => {
149
+ if (i > 0) {
150
+ el.appendChild(doc.createTextNode('/'));
151
+ el.appendChild(doc.createElement('wbr'));
152
+ }
153
+ if (part)
154
+ el.appendChild(doc.createTextNode(part));
155
+ });
156
+ }
157
+ // Format a byte count for the size column. Returns "12 KB", "950 B",
158
+ // "1.4 MB", etc. — short enough to fit comfortably alongside filename +
159
+ // status. Whole KB: a tenth of a KB is never the interesting part. The
160
+ // MB switch is on the ROUNDED KB, so 1023.6 KB reads "1.0 MB", not
161
+ // "1024 KB".
162
+ export function formatBytes(size) {
163
+ if (size < 1024)
164
+ return `${size} B`;
165
+ const kb = Math.round(size / 1024);
166
+ if (kb < 1024)
167
+ return `${kb} KB`;
168
+ return `${(size / (1024 * 1024)).toFixed(1)} MB`;
169
+ }
170
+ // Storage use against a quota, both in MB: `9.9 MB of 10 MB (99%)`.
171
+ // One unit on both sides, since `10,106 KB of 10 MB` reads as over the
172
+ // limit at a glance. Rounded DOWN, so a store that still has room never
173
+ // reads as `10.0 MB of 10 MB (100%)`.
174
+ export function formatStorageUsage(used, quota) {
175
+ const tenths = Math.floor((used / (1024 * 1024)) * 10) / 10;
176
+ const percent = Math.floor((used / quota) * 100);
177
+ return `${tenths.toFixed(1)} MB of ${formatQuota(quota)} (${percent}%)`;
178
+ }
179
+ // A storage quota: `10 MB` for a whole number of MB (Chrome's is), not
180
+ // `10.0 MB`.
181
+ export function formatQuota(bytes) {
182
+ const mb = bytes / (1024 * 1024);
183
+ return Number.isInteger(mb) ? `${mb} MB` : `${mb.toFixed(1)} MB`;
184
+ }
185
+ // Text shown in the "Size" cell. Size is independent of status:
186
+ // `invalid` rows that retain prior content still show its byte count,
187
+ // and a 0-byte file shows "0 B" (distinct from unknown). Only rows
188
+ // that have never successfully loaded — `size == null` — render as
189
+ // "—" to signal "unknown".
190
+ export function formatScriptSize(script) {
191
+ if (script.size == null)
192
+ return '—';
193
+ return formatBytes(script.size);
194
+ }
195
+ export const LOAD_STATES = ['ok', 'invalid', 'rejected', 'refresh-failed', 'outdated'];
196
+ export function isLoadState(value) {
197
+ return LOAD_STATES.includes(value);
198
+ }
199
+ // `outdated` and `rejected` come in as caller-computed flags rather
200
+ // than being derived here: neither lives on the script row (one is a
201
+ // version probe, the other is session state the injector writes), and
202
+ // the collections page's repaint path rebuilds status cells from DOM
203
+ // datasets with no script row in hand. Both callers read `outdated`
204
+ // from `scriptOutdatedProbe` below and `rejected` from the shared
205
+ // rejection map, so the two surfaces can't drift.
206
+ export function effectiveScriptStatus(script, maxLogLevel, outdated = false, rejected = false) {
207
+ if (script.status === 'invalid')
208
+ return 'invalid';
209
+ if (rejected)
210
+ return 'rejected';
211
+ if (script.refreshError)
212
+ return 'refresh-failed';
213
+ if (outdated)
214
+ return 'outdated';
215
+ if (maxLogLevel === 'error')
216
+ return 'error';
217
+ if (maxLogLevel === 'warning')
218
+ return 'warning';
219
+ return 'ok';
220
+ }
221
+ // The probe (if any) saying an upstream copy is ahead of the version we
222
+ // hold. Null whenever nothing is ahead, nothing was probed, or either
223
+ // side has no `@version` to compare.
224
+ export function scriptOutdatedProbe(script) {
225
+ const loadedVersion = script.header ? getValue(script.header, 'version') : undefined;
226
+ return outdatedProbe(loadedVersion, script.versionProbes);
227
+ }
228
+ // Text shown in the "Status" cell. REJECTED means the script is fine but Chrome refused to register it. REFRESH
229
+ // FAILED means the script still runs from its cached copy but the last
230
+ // update attempt failed. OUTDATED means a newer version exists at a URL
231
+ // we deliberately don't update from. WARNING / ERROR mean the script
232
+ // loaded fine but its Log carries entries at that level (see
233
+ // `effectiveScriptStatus`).
234
+ export function formatScriptStatusLabel(status) {
235
+ switch (status) {
236
+ case 'ok': return 'OK';
237
+ case 'invalid': return 'INVALID';
238
+ case 'rejected': return 'REJECTED';
239
+ case 'refresh-failed': return 'REFRESH FAILED';
240
+ case 'outdated': return 'OUTDATED';
241
+ case 'warning': return 'WARNING';
242
+ case 'error': return 'ERROR';
243
+ }
244
+ }
245
+ // The viewer URL for a stored script, optionally landing on its Log
246
+ // pane. Shared by every in-page surface that links to or navigates to
247
+ // a script, so none of them can drift on how the tab is addressed.
248
+ //
249
+ // Page-relative, not the absolute `chrome.runtime.getURL(...)` form:
250
+ // every extension page lives at the extension root, so the browser
251
+ // resolves it against the current page, and the long
252
+ // `chrome-extension://<id>/` prefix stays out of a table that can hold
253
+ // hundreds of rows with two links each. The service worker builds the
254
+ // absolute form instead (`viewerUrlForScript` in background.ts)
255
+ // because it has no page to be relative to.
256
+ export function viewerUrl(scriptId, tab) {
257
+ const params = new URLSearchParams({ script: scriptId });
258
+ // The viewer parses `#Log` via parseHash and lands on the Log pane.
259
+ return `userscript.html?${params.toString()}${tab === 'log' ? '#Log' : ''}`;
260
+ }
261
+ // The compare page for two copies of a script (src/extension/compare.ts). The
262
+ // right-hand side is the base: the copy on screen, or the download a
263
+ // preview is showing; `other` is the copy to hold up against it.
264
+ export function compareUrl(base, other) {
265
+ const params = new URLSearchParams('script' in base ? { script: base.script } : { preview: base.preview });
266
+ params.set('other', other);
267
+ return `compare.html?${params.toString()}`;
268
+ }
269
+ // The install-preview URL for a location the user typed or pasted.
270
+ // Page-relative for the same reason `viewerUrl` is; callers that need
271
+ // the absolute form wrap it in `chrome.runtime.getURL`.
272
+ export function previewUrl(location) {
273
+ return `userscript.html?preview=${encodeURIComponent(location)}`;
274
+ }
275
+ // What a script's Status cell should say. The label follows
276
+ // `effectiveScriptStatus`; the hover text follows whatever the cell is
277
+ // actually showing — Chrome's rejection reason, the refresh-failure
278
+ // reason, the newer version found upstream, or the load error.
279
+ //
280
+ // Shared by the viewer's own Status row and the "Other versions"
281
+ // panel's Status column, which would otherwise explain the same
282
+ // verdict two ways. The collections page keeps its own copy of this
283
+ // logic: its repaint path rebuilds status cells from DOM datasets with
284
+ // no script row in hand, which is exactly what this takes.
285
+ export function scriptStatusView(script, maxLogLevel, rejection) {
286
+ const outdated = scriptOutdatedProbe(script);
287
+ const status = effectiveScriptStatus(script, maxLogLevel, outdated !== null, rejection !== undefined);
288
+ return { status, label: formatScriptStatusLabel(status), title: statusTitle() };
289
+ function statusTitle() {
290
+ if (status === 'rejected' && rejection)
291
+ return rejection;
292
+ if (status === 'refresh-failed')
293
+ return script.refreshError;
294
+ if (status === 'outdated' && outdated) {
295
+ return `Version ${outdated.version} at ${probeLabel(outdated.kinds)}: ${outdated.url}`;
296
+ }
297
+ if (script.errorMessage)
298
+ return describeDiagnostic(script.errorMessage, script.errorLocation);
299
+ return undefined;
300
+ }
301
+ }
302
+ // Drop a Subresource Integrity fragment from a `@require` / `@resource`
303
+ // reference, for DISPLAY only.
304
+ //
305
+ // Lives here rather than in `file-loader.ts` (which owns resolution and
306
+ // fetching) precisely because loading must never use it — it sits
307
+ // beside `displayLocation`, the other transform every human-facing URL
308
+ // goes through.
309
+ //
310
+ // Tampermonkey carries the expected hash in the URL fragment, as a
311
+ // comma-separated list of `<algo>=<hex>` or `<algo>-<base64>` parts:
312
+ //
313
+ // @require https://example.com/lib.js#sha256=e3b0c44298fc1c149…
314
+ // @require https://example.com/lib.js#md5=abc,sha256=def
315
+ //
316
+ // A 64-hex-digit tail is most of the width of a tooltip or a details
317
+ // row and tells the reader nothing they can act on, so every surface
318
+ // that shows a ref to a human strips it. Fetching, resolution, dedup,
319
+ // storage, and error messages all keep the verbatim form — an error
320
+ // should name what the author actually wrote.
321
+ //
322
+ // Only stripped when EVERY comma-separated part looks like a hash
323
+ // declaration. An ordinary fragment (`#section`) is content the author
324
+ // meant, so it survives; a malformed hash tail survives too, which is
325
+ // the right way round — a reader wondering why validation didn't happen
326
+ // needs to see what they typed.
327
+ //
328
+ // SourceMonkey does not yet validate these hashes; see TODO.md.
329
+ const SRI_PART_RE = /^(?:md5|sha1|sha256|sha384|sha512)[=-]\S+$/i;
330
+ export function stripSriFragment(urlOrRef) {
331
+ const hash = urlOrRef.indexOf('#');
332
+ if (hash < 0)
333
+ return urlOrRef;
334
+ const fragment = urlOrRef.slice(hash + 1);
335
+ if (!fragment)
336
+ return urlOrRef;
337
+ if (!fragment.split(',').every((part) => SRI_PART_RE.test(part)))
338
+ return urlOrRef;
339
+ return urlOrRef.slice(0, hash);
340
+ }
341
+ // A stored script's text as it was on disk, rebuilt from the stored
342
+ // split: what is above the header, the header, the body. The same
343
+ // string the injector splices into the registered code, so the viewer's
344
+ // main tab line N matches the file's line N AND the injected line N
345
+ // (modulo any @require sections that sit before the main script). The
346
+ // compare page diffs this too.
347
+ export function fullSource(script) {
348
+ return joinFullSource(script.leadingText ?? '', script.headerText ?? '', script.bodyText);
349
+ }
350
+ // Pull a display basename off a require's resolved URL. Falls back to
351
+ // the verbatim ref if URL parsing fails — won't happen for entries we
352
+ // stored (the resolver wouldn't have accepted the URL otherwise), but
353
+ // the fallback keeps a future shape change from breaking the tab UI.
354
+ // Not `scriptBasename`: that one falls back to the whole URL, and a
355
+ // require tab labeled with a full CDN URL would wreck the tab strip.
356
+ export function requireBasename(url, ref) {
357
+ let name;
358
+ try {
359
+ name = leafName(new URL(url).pathname);
360
+ }
361
+ catch {
362
+ return ref;
363
+ }
364
+ return name ? decodeForDisplay(name) : ref;
365
+ }
366
+ // The counts in words, per kind, since each is a different thing to go
367
+ // and check: `1 file modified, 2 new files`. Empty when nothing differs.
368
+ export function pendingSummary(counts) {
369
+ const files = (n) => `${n} ${n === 1 ? 'file' : 'files'}`;
370
+ const parts = [];
371
+ if (counts.manifest)
372
+ parts.push('the manifest changed');
373
+ if (counts.modified > 0)
374
+ parts.push(`${files(counts.modified)} modified`);
375
+ if (counts.deleted > 0)
376
+ parts.push(`${files(counts.deleted)} deleted`);
377
+ if (counts.added > 0)
378
+ parts.push(`${counts.added} new ${counts.added === 1 ? 'file' : 'files'}`);
379
+ if (parts.length === 0)
380
+ return '';
381
+ const text = parts.join(', ');
382
+ return `${text[0].toUpperCase()}${text.slice(1)}`;
383
+ }
@@ -0,0 +1,16 @@
1
+ export declare const MAX_ICON_BYTES: number;
2
+ export declare function isIconContentType(contentType: string): boolean;
3
+ interface IconHeader {
4
+ tags: {
5
+ tag: string;
6
+ locale?: string;
7
+ value: string;
8
+ line?: number;
9
+ }[];
10
+ }
11
+ export declare function iconDeclFromHeader(header: IconHeader | null): {
12
+ ref: string;
13
+ line?: number;
14
+ } | null;
15
+ export declare function iconRefFromHeader(header: IconHeader | null): string | null;
16
+ export {};
@@ -0,0 +1,43 @@
1
+ // A script's own icon (`@icon` and its aliases): which header tag names
2
+ // it, and the rules an icon file has to meet to be shown. Shared by the
3
+ // pages that paint icons (`extension/site-icon.ts`) and the load-time
4
+ // check that warns about an icon that can't be shown
5
+ // (`checkScriptIcon` in `external-files.ts`), so both apply one rule.
6
+ // Tag priority for a script-declared icon. `@icon` is the only form
7
+ // documented by all three managers (TM/VM/GM, i.e. Tampermonkey,
8
+ // Violentmonkey, Greasemonkey); the rest are TM-only aliases. The
9
+ // smaller variants come first so a script that declares both a regular
10
+ // and a 64×64 icon picks the one closer to our 16×16 display size.
11
+ const ICON_HEADER_TAGS = ['icon', 'iconurl', 'defaulticon', 'icon64url', 'icon64'];
12
+ // Largest icon file we will show. An icon is drawn at 16px, so anything
13
+ // near this is far bigger than it needs to be.
14
+ export const MAX_ICON_BYTES = 128 * 1024;
15
+ // Whether a response's Content-Type is one an icon can have.
16
+ export function isIconContentType(contentType) {
17
+ return contentType.startsWith('image/');
18
+ }
19
+ // The icon declaration that wins: its reference, raw (just trimmed and
20
+ // non-empty), and the header line it is on. Null when none is set.
21
+ export function iconDeclFromHeader(header) {
22
+ if (!header)
23
+ return null;
24
+ for (const tag of ICON_HEADER_TAGS) {
25
+ for (const e of header.tags) {
26
+ if (e.tag !== tag || e.locale !== undefined)
27
+ continue;
28
+ const trimmed = e.value.trim();
29
+ if (trimmed)
30
+ return e.line === undefined ? { ref: trimmed } : { ref: trimmed, line: e.line };
31
+ }
32
+ }
33
+ return null;
34
+ }
35
+ // Read the highest-priority icon reference declared in the parsed
36
+ // metadata, or null when none is set. The reference comes back raw
37
+ // (just trimmed + non-empty); resolving it into an absolute URL —
38
+ // including the relative-path-against-script-parent rules and `..`
39
+ // rejection — is the file-loader's job and happens at render time
40
+ // when the script's `fileUrl` is in scope.
41
+ export function iconRefFromHeader(header) {
42
+ return iconDeclFromHeader(header)?.ref ?? null;
43
+ }
@@ -0,0 +1,24 @@
1
+ export declare const RESOLVABLE_HEADER_TAGS: ReadonlySet<string>;
2
+ export declare const MATCH_HEADER_TAGS: ReadonlySet<string>;
3
+ export interface TextRun {
4
+ kind: 'text' | 'url';
5
+ value: string;
6
+ }
7
+ export declare function splitTextByUrls(text: string): TextRun[];
8
+ export interface ParsedTagLine {
9
+ before: string;
10
+ tag: string;
11
+ locale?: string;
12
+ value: string;
13
+ after: string;
14
+ }
15
+ export declare function parseTagLine(line: string): ParsedTagLine | null;
16
+ export interface ResourceValueParts {
17
+ prefix: string;
18
+ url: string;
19
+ suffix: string;
20
+ }
21
+ export declare function splitResourceValue(value: string): ResourceValueParts | null;
22
+ export declare function connectLinkUrl(raw: string): string | null;
23
+ export declare function isHeaderOpenLine(line: string): boolean;
24
+ export declare function isHeaderCloseLine(line: string): boolean;