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.
- package/LICENSE +21 -0
- package/README.md +87 -2
- package/dist/bytes.js +37 -0
- package/dist/channel-placeholder.js +5 -0
- package/dist/collection-scan.js +17 -0
- package/dist/collections.html +353 -0
- package/dist/compare.html +358 -0
- package/dist/composed-source.js +205 -0
- package/dist/connect-prompt.html +47 -0
- package/dist/debug/icons.html +211 -0
- package/dist/debug/storage.html +163 -0
- package/dist/debug-log.js +75 -0
- package/dist/diagnostic-location.js +64 -0
- package/dist/eval-hook.js +308 -0
- package/dist/extension/background.js +5263 -0
- package/dist/extension/channel.js +133 -0
- package/dist/extension/code-links.js +187 -0
- package/dist/extension/code-tabs.js +460 -0
- package/dist/extension/collection-dialog.js +619 -0
- package/dist/extension/collection-display.js +322 -0
- package/dist/extension/collections.js +2905 -0
- package/dist/extension/compare.js +867 -0
- package/dist/extension/concurrency.js +186 -0
- package/dist/extension/connect-grants.js +109 -0
- package/dist/extension/connect-prompt-page.js +70 -0
- package/dist/extension/connect-prompt.js +266 -0
- package/dist/extension/copy-button.js +63 -0
- package/dist/extension/copy-dialog.js +502 -0
- package/dist/extension/copy-preference.js +66 -0
- package/dist/extension/debug/icons.js +203 -0
- package/dist/extension/debug/storage.js +365 -0
- package/dist/extension/deep-link.js +77 -0
- package/dist/extension/delete-dialog.js +432 -0
- package/dist/extension/delete-icon.js +40 -0
- package/dist/extension/details-tooltips.js +66 -0
- package/dist/extension/directories.js +679 -0
- package/dist/extension/export-backup.js +407 -0
- package/dist/extension/export-dialog.js +142 -0
- package/dist/extension/file-access.js +74 -0
- package/dist/extension/file-changes.js +346 -0
- package/dist/extension/frame-info.js +85 -0
- package/dist/extension/github-provider.js +336 -0
- package/dist/extension/glyph.js +84 -0
- package/dist/extension/gm-bindings.js +601 -0
- package/dist/extension/gm-download.js +419 -0
- package/dist/extension/gm-menu.js +228 -0
- package/dist/extension/gm-notification.js +141 -0
- package/dist/extension/gm-originator-map.js +23 -0
- package/dist/extension/gm-tab-data.js +121 -0
- package/dist/extension/gm-tab.js +160 -0
- package/dist/extension/gm-url-change.js +111 -0
- package/dist/extension/gm-url-scheme.js +27 -0
- package/dist/extension/gm-values.js +176 -0
- package/dist/extension/gm-window-control.js +104 -0
- package/dist/extension/gm-xhr-headers.js +333 -0
- package/dist/extension/gm-xhr.js +584 -0
- package/dist/extension/injector.js +3145 -0
- package/dist/extension/install-capture.js +277 -0
- package/dist/extension/line-diff.js +233 -0
- package/dist/extension/local-copy.js +560 -0
- package/dist/extension/local-delete.js +276 -0
- package/dist/extension/location-kinds.js +108 -0
- package/dist/extension/log-format.js +158 -0
- package/dist/extension/managed-changes.js +361 -0
- package/dist/extension/managed-items.js +57 -0
- package/dist/extension/match-index.js +375 -0
- package/dist/extension/missing-scripts.js +66 -0
- package/dist/extension/more-menu.js +109 -0
- package/dist/extension/move-dialog.js +197 -0
- package/dist/extension/offscreen.js +37 -0
- package/dist/extension/options.js +504 -0
- package/dist/extension/page-heading.js +170 -0
- package/dist/extension/page-links.js +199 -0
- package/dist/extension/parse-check-client.js +70 -0
- package/dist/extension/parse-check.js +161 -0
- package/dist/extension/parse-sandbox-host.js +172 -0
- package/dist/extension/parse-sandbox.js +175 -0
- package/dist/extension/popup-commands-open.js +41 -0
- package/dist/extension/popup-view.js +387 -0
- package/dist/extension/popup.js +703 -0
- package/dist/extension/prism-userscript.js +53 -0
- package/dist/extension/refresh-error.js +136 -0
- package/dist/extension/refresh-targets.js +160 -0
- package/dist/extension/related-versions.js +1144 -0
- package/dist/extension/resize-observer-loop.js +19 -0
- package/dist/extension/row-cache.js +387 -0
- package/dist/extension/script-blobs.js +413 -0
- package/dist/extension/script-details.js +658 -0
- package/dist/extension/script-enablement.js +285 -0
- package/dist/extension/script-identity.js +310 -0
- package/dist/extension/script-keys.js +54 -0
- package/dist/extension/script-log-id.js +155 -0
- package/dist/extension/script-log.js +290 -0
- package/dist/extension/script-rejection.js +104 -0
- package/dist/extension/script-sites.js +158 -0
- package/dist/extension/script-store.js +3507 -0
- package/dist/extension/script-updater.js +991 -0
- package/dist/extension/script-url-hash.js +61 -0
- package/dist/extension/select-all.js +37 -0
- package/dist/extension/select-open-guard.js +90 -0
- package/dist/extension/site-icon.js +1261 -0
- package/dist/extension/sm-dev-link.js +302 -0
- package/dist/extension/solo-click.js +58 -0
- package/dist/extension/sticky-numbers.js +188 -0
- package/dist/extension/storage-breakdown.js +253 -0
- package/dist/extension/storage-scan.js +86 -0
- package/dist/extension/storage-usage.js +194 -0
- package/dist/extension/structural-keys.js +29 -0
- package/dist/extension/sw-teardown.js +36 -0
- package/dist/extension/tab-status.js +403 -0
- package/dist/extension/toolbar-summary.js +105 -0
- package/dist/extension/user-scripts-access.js +43 -0
- package/dist/extension/userscript.js +3672 -0
- package/dist/extension/value-store.js +204 -0
- package/dist/extension/version-probe-fetch.js +68 -0
- package/dist/extension/worker-client.js +109 -0
- package/dist/extension/worker-ops.js +171 -0
- package/dist/extension/zip-writer.js +24 -0
- package/dist/external-files.js +878 -0
- package/dist/file-loader.js +436 -0
- package/dist/file-locations.js +439 -0
- package/dist/generated-wrappers.js +5 -0
- package/dist/github-auth.js +148 -0
- package/dist/github-urls.js +46 -0
- package/dist/gm-api-catalog.js +217 -0
- package/dist/gm-connect.js +273 -0
- package/dist/gm-xhr-types.js +5 -0
- package/dist/http-read.js +142 -0
- package/dist/icons/icon-128.png +0 -0
- package/dist/icons/icon-16.png +0 -0
- package/dist/icons/icon-48.png +0 -0
- package/dist/local-file-overrides.js +558 -0
- package/dist/manifest.json +38 -0
- package/dist/markup-response.js +126 -0
- package/dist/match-targets.js +305 -0
- package/dist/menu-captions.js +22 -0
- package/dist/offscreen.html +39 -0
- package/dist/options.html +197 -0
- package/dist/parse-check-protocol.js +51 -0
- package/dist/parse-location.js +171 -0
- package/dist/parse-sandbox.html +56 -0
- package/dist/phase-timing.js +155 -0
- package/dist/popup.html +197 -0
- package/dist/public-suffixes.js +6957 -0
- package/dist/run-context.js +31 -0
- package/dist/runtime-messages.js +34 -0
- package/dist/sandboxed-page.js +35 -0
- package/dist/script-build.js +787 -0
- package/dist/script-display.js +383 -0
- package/dist/script-icon.js +43 -0
- package/dist/script-links.js +204 -0
- package/dist/script-source-url.js +214 -0
- package/dist/script-world.js +65 -0
- package/dist/sm-dev-protocol.js +84 -0
- package/dist/source-map.js +177 -0
- package/dist/stack-link.js +138 -0
- package/dist/styles.css +825 -0
- package/dist/unsafe-window-use.js +229 -0
- package/dist/url-match.js +734 -0
- package/dist/userscript-header.js +248 -0
- package/dist/userscript.html +1165 -0
- package/dist/vendor/fflate.LICENSE +21 -0
- package/dist/vendor/fflate.js +2692 -0
- package/dist/vendor/prism/prism-line-numbers.css +1 -0
- package/dist/vendor/prism/prism-line-numbers.js +1 -0
- package/dist/vendor/prism/prism.css +1 -0
- package/dist/vendor/prism/prism.js +1946 -0
- package/dist/version-compare.js +141 -0
- package/dist/version-probe.js +120 -0
- package/lib/build-info.json +1 -0
- package/lib/bytes.d.ts +3 -0
- package/lib/bytes.js +37 -0
- package/lib/channel-placeholder.d.ts +1 -0
- package/lib/channel-placeholder.js +5 -0
- package/lib/collection-scan.d.ts +8 -0
- package/lib/collection-scan.js +17 -0
- package/lib/composed-source.d.ts +28 -0
- package/lib/composed-source.js +205 -0
- package/lib/debug-log.d.ts +9 -0
- package/lib/debug-log.js +75 -0
- package/lib/diagnostic-location.d.ts +8 -0
- package/lib/diagnostic-location.js +64 -0
- package/lib/eval-hook.d.ts +34 -0
- package/lib/eval-hook.js +308 -0
- package/lib/external-files.d.ts +111 -0
- package/lib/external-files.js +878 -0
- package/lib/file-loader.d.ts +48 -0
- package/lib/file-loader.js +436 -0
- package/lib/file-locations.d.ts +44 -0
- package/lib/file-locations.js +439 -0
- package/lib/generated-wrappers.d.ts +11 -0
- package/lib/generated-wrappers.js +5 -0
- package/lib/github-auth.d.ts +12 -0
- package/lib/github-auth.js +148 -0
- package/lib/github-urls.d.ts +1 -0
- package/lib/github-urls.js +46 -0
- package/lib/gm-api-catalog.d.ts +24 -0
- package/lib/gm-api-catalog.js +217 -0
- package/lib/gm-connect.d.ts +34 -0
- package/lib/gm-connect.js +273 -0
- package/lib/gm-xhr-types.d.ts +68 -0
- package/lib/gm-xhr-types.js +5 -0
- package/lib/harness/browser-extensions.d.ts +73 -0
- package/lib/harness/browser-extensions.js +285 -0
- package/lib/harness/browser-lang.d.ts +20 -0
- package/lib/harness/browser-lang.js +86 -0
- package/lib/harness/browser-launch.d.ts +14 -0
- package/lib/harness/browser-launch.js +184 -0
- package/lib/harness/checks.d.ts +110 -0
- package/lib/harness/checks.js +321 -0
- package/lib/harness/cli.d.ts +2 -0
- package/lib/harness/cli.js +2259 -0
- package/lib/harness/command-args.d.ts +91 -0
- package/lib/harness/command-args.js +369 -0
- package/lib/harness/command-lines.d.ts +80 -0
- package/lib/harness/command-lines.js +180 -0
- package/lib/harness/command-list.d.ts +206 -0
- package/lib/harness/command-list.js +1475 -0
- package/lib/harness/console-commands.d.ts +463 -0
- package/lib/harness/console-commands.js +3216 -0
- package/lib/harness/download-watch.d.ts +21 -0
- package/lib/harness/download-watch.js +156 -0
- package/lib/harness/extension-backend.d.ts +41 -0
- package/lib/harness/extension-backend.js +100 -0
- package/lib/harness/extension-host.d.ts +112 -0
- package/lib/harness/extension-host.js +552 -0
- package/lib/harness/extension-launch.d.ts +67 -0
- package/lib/harness/extension-launch.js +285 -0
- package/lib/harness/extension-link.d.ts +315 -0
- package/lib/harness/extension-link.js +607 -0
- package/lib/harness/external-manager.d.ts +146 -0
- package/lib/harness/external-manager.js +414 -0
- package/lib/harness/fixture.d.ts +165 -0
- package/lib/harness/fixture.js +461 -0
- package/lib/harness/frame-sessions.d.ts +71 -0
- package/lib/harness/frame-sessions.js +248 -0
- package/lib/harness/frames.d.ts +68 -0
- package/lib/harness/frames.js +216 -0
- package/lib/harness/help-format.d.ts +17 -0
- package/lib/harness/help-format.js +127 -0
- package/lib/harness/host.d.ts +352 -0
- package/lib/harness/host.js +423 -0
- package/lib/harness/index.d.ts +8 -0
- package/lib/harness/index.js +10 -0
- package/lib/harness/input-file.d.ts +18 -0
- package/lib/harness/input-file.js +61 -0
- package/lib/harness/json-output.d.ts +565 -0
- package/lib/harness/json-output.js +71 -0
- package/lib/harness/manager-actions.d.ts +21 -0
- package/lib/harness/manager-actions.js +129 -0
- package/lib/harness/manager-commands.d.ts +142 -0
- package/lib/harness/manager-commands.js +1196 -0
- package/lib/harness/manager-fetch.d.ts +33 -0
- package/lib/harness/manager-fetch.js +239 -0
- package/lib/harness/managers.d.ts +24 -0
- package/lib/harness/managers.js +27 -0
- package/lib/harness/output-style.d.ts +125 -0
- package/lib/harness/output-style.js +322 -0
- package/lib/harness/page-commands.d.ts +134 -0
- package/lib/harness/page-commands.js +1141 -0
- package/lib/harness/page-output.d.ts +67 -0
- package/lib/harness/page-output.js +139 -0
- package/lib/harness/page-watch.d.ts +171 -0
- package/lib/harness/page-watch.js +607 -0
- package/lib/harness/parse-check-node.d.ts +3 -0
- package/lib/harness/parse-check-node.js +132 -0
- package/lib/harness/path-args.d.ts +22 -0
- package/lib/harness/path-args.js +148 -0
- package/lib/harness/playwright-chromium.d.ts +16 -0
- package/lib/harness/playwright-chromium.js +86 -0
- package/lib/harness/prepare.d.ts +168 -0
- package/lib/harness/prepare.js +364 -0
- package/lib/harness/prompt-editor.d.ts +17 -0
- package/lib/harness/prompt-editor.js +354 -0
- package/lib/harness/prompt-history.d.ts +13 -0
- package/lib/harness/prompt-history.js +89 -0
- package/lib/harness/rebuild-advice.d.ts +6 -0
- package/lib/harness/rebuild-advice.js +39 -0
- package/lib/harness/run-log.d.ts +47 -0
- package/lib/harness/run-log.js +140 -0
- package/lib/harness/run-logs.d.ts +132 -0
- package/lib/harness/run-logs.js +241 -0
- package/lib/harness/run.d.ts +194 -0
- package/lib/harness/run.js +1973 -0
- package/lib/harness/runs.d.ts +229 -0
- package/lib/harness/runs.js +726 -0
- package/lib/harness/save-html.d.ts +39 -0
- package/lib/harness/save-html.js +89 -0
- package/lib/harness/saved-pages.d.ts +120 -0
- package/lib/harness/saved-pages.js +275 -0
- package/lib/harness/script-mark.d.ts +17 -0
- package/lib/harness/script-mark.js +56 -0
- package/lib/harness/snapshot.d.ts +143 -0
- package/lib/harness/snapshot.js +474 -0
- package/lib/harness/stuck-tabs.d.ts +19 -0
- package/lib/harness/stuck-tabs.js +131 -0
- package/lib/harness/tab-refs.d.ts +20 -0
- package/lib/harness/tab-refs.js +80 -0
- package/lib/harness/tampermonkey.d.ts +71 -0
- package/lib/harness/tampermonkey.js +356 -0
- package/lib/harness/tm-ids.d.ts +18 -0
- package/lib/harness/tm-ids.js +88 -0
- package/lib/harness/violentmonkey.d.ts +34 -0
- package/lib/harness/violentmonkey.js +162 -0
- package/lib/harness/wait.d.ts +77 -0
- package/lib/harness/wait.js +458 -0
- package/lib/http-read.d.ts +30 -0
- package/lib/http-read.js +142 -0
- package/lib/local-file-overrides.d.ts +35 -0
- package/lib/local-file-overrides.js +558 -0
- package/lib/manifest.json +38 -0
- package/lib/markup-response.d.ts +11 -0
- package/lib/markup-response.js +126 -0
- package/lib/match-targets.d.ts +18 -0
- package/lib/match-targets.js +305 -0
- package/lib/menu-captions.d.ts +1 -0
- package/lib/menu-captions.js +22 -0
- package/lib/parse-check-protocol.d.ts +27 -0
- package/lib/parse-check-protocol.js +51 -0
- package/lib/parse-location.d.ts +12 -0
- package/lib/parse-location.js +171 -0
- package/lib/phase-timing.d.ts +12 -0
- package/lib/phase-timing.js +155 -0
- package/lib/public-suffixes.d.ts +1 -0
- package/lib/public-suffixes.js +6957 -0
- package/lib/run-context.d.ts +2 -0
- package/lib/run-context.js +31 -0
- package/lib/runtime-messages.d.ts +10 -0
- package/lib/runtime-messages.js +34 -0
- package/lib/sandboxed-page.d.ts +5 -0
- package/lib/sandboxed-page.js +35 -0
- package/lib/script-build.d.ts +111 -0
- package/lib/script-build.js +787 -0
- package/lib/script-display.d.ts +51 -0
- package/lib/script-display.js +383 -0
- package/lib/script-icon.d.ts +16 -0
- package/lib/script-icon.js +43 -0
- package/lib/script-links.d.ts +24 -0
- package/lib/script-links.js +204 -0
- package/lib/script-source-url.d.ts +8 -0
- package/lib/script-source-url.js +214 -0
- package/lib/script-world.d.ts +6 -0
- package/lib/script-world.js +65 -0
- package/lib/sm-dev-protocol.d.ts +251 -0
- package/lib/sm-dev-protocol.js +84 -0
- package/lib/source-map.d.ts +32 -0
- package/lib/source-map.js +177 -0
- package/lib/stack-link.d.ts +15 -0
- package/lib/stack-link.js +138 -0
- package/lib/unsafe-window-use.d.ts +1 -0
- package/lib/unsafe-window-use.js +229 -0
- package/lib/url-match.d.ts +40 -0
- package/lib/url-match.js +734 -0
- package/lib/userscript-header.d.ts +33 -0
- package/lib/userscript-header.js +248 -0
- package/lib/version-compare.d.ts +6 -0
- package/lib/version-compare.js +141 -0
- package/lib/version-probe.d.ts +17 -0
- package/lib/version-probe.js +120 -0
- package/package.json +55 -3
- package/skills/SourceMonkey-dev/SKILL.md +868 -0
- package/skills/SourceMonkey-dev/references/cdp.md +293 -0
- package/skills/SourceMonkey-dev/references/commands.md +297 -0
- package/skills/SourceMonkey-dev/references/other-managers.md +63 -0
- package/skills/SourceMonkey-dev/references/specs.md +46 -0
- package/skills/SourceMonkey-friction/SKILL.md +103 -0
- package/skills/SourceMonkey-friction/references/template.md +59 -0
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import type { ConsoleContext } from './console-commands.js';
|
|
2
|
+
import { type ManagerControl } from './manager-commands.js';
|
|
3
|
+
import type { ManagerName } from './managers.js';
|
|
4
|
+
import { type PreparedScript } from './prepare.js';
|
|
5
|
+
/** One installed script, as sm-dev reads it from the manager. */
|
|
6
|
+
export interface ExternalScript {
|
|
7
|
+
/** The manager's own number for it, sm-dev's E-id. */
|
|
8
|
+
id: number;
|
|
9
|
+
name: string;
|
|
10
|
+
namespace?: string;
|
|
11
|
+
version?: string;
|
|
12
|
+
description?: string;
|
|
13
|
+
author?: string;
|
|
14
|
+
enabled: boolean;
|
|
15
|
+
match: string[];
|
|
16
|
+
include: string[];
|
|
17
|
+
exclude: string[];
|
|
18
|
+
excludeMatch: string[];
|
|
19
|
+
runAt?: string;
|
|
20
|
+
grants: string[];
|
|
21
|
+
requires: string[];
|
|
22
|
+
resources: {
|
|
23
|
+
name: string;
|
|
24
|
+
url: string;
|
|
25
|
+
}[];
|
|
26
|
+
/** The URL it was installed from, when the manager keeps one. */
|
|
27
|
+
installUrl?: string;
|
|
28
|
+
/** When its text last changed, in epoch ms. */
|
|
29
|
+
updatedAt?: number;
|
|
30
|
+
}
|
|
31
|
+
/** The contents of a script's `@require` and `@resource` files, by URL, handed over so the manager needn't fetch them. */
|
|
32
|
+
export interface InstallFiles {
|
|
33
|
+
requires: Record<string, string>;
|
|
34
|
+
resources: Record<string, {
|
|
35
|
+
contentType: string;
|
|
36
|
+
base64: string;
|
|
37
|
+
}>;
|
|
38
|
+
}
|
|
39
|
+
export interface InstallOptions {
|
|
40
|
+
/** The script to replace. */
|
|
41
|
+
id?: number;
|
|
42
|
+
/** Where it's installed from, which its relative `@require`s resolve against. */
|
|
43
|
+
url?: string;
|
|
44
|
+
files?: InstallFiles;
|
|
45
|
+
/** Read from a local file, which the manager can't check for updates. */
|
|
46
|
+
local?: boolean;
|
|
47
|
+
}
|
|
48
|
+
/** What sm-dev needs of a manager. */
|
|
49
|
+
export interface ExternalManager {
|
|
50
|
+
readonly name: ManagerName;
|
|
51
|
+
readonly label: string;
|
|
52
|
+
readonly version: string;
|
|
53
|
+
readonly extensionId: string;
|
|
54
|
+
scripts(): Promise<ExternalScript[]>;
|
|
55
|
+
/** Each script's text as installed, by id. */
|
|
56
|
+
texts(ids: number[]): Promise<Map<number, string>>;
|
|
57
|
+
/** Installs `code`, or replaces script `id`, or else the one with the same name and namespace. */
|
|
58
|
+
install(code: string, options?: InstallOptions): Promise<{
|
|
59
|
+
id: number;
|
|
60
|
+
isNew: boolean;
|
|
61
|
+
}>;
|
|
62
|
+
setEnabled(id: number, enabled: boolean): Promise<void>;
|
|
63
|
+
/** Uninstalls a script so that it can be restored, as the manager's own page does. */
|
|
64
|
+
uninstall(id: number): Promise<void>;
|
|
65
|
+
/** Removes scripts for good. */
|
|
66
|
+
remove(ids: number[]): Promise<void>;
|
|
67
|
+
/** The manager's own switch for all its scripts. */
|
|
68
|
+
applied(): Promise<boolean>;
|
|
69
|
+
setApplied(on: boolean): Promise<void>;
|
|
70
|
+
/** Lets scripts run on `file://` pages. True when that changed a setting. */
|
|
71
|
+
allowFilePages(): Promise<boolean>;
|
|
72
|
+
/** The script a stack frame's URL is the code of. */
|
|
73
|
+
scriptIdOf(url: string): number | undefined;
|
|
74
|
+
/** What every URL the manager runs code under starts with. */
|
|
75
|
+
readonly scriptUrlPrefix: string;
|
|
76
|
+
/** The scripts the manager's own rules match to `url`, on or not, when it can say. */
|
|
77
|
+
matching?(url: string): Promise<number[]>;
|
|
78
|
+
/** Notes a run's script's `@require` files, in order, for `remapStack`. */
|
|
79
|
+
noteRequires?(id: number, requires: {
|
|
80
|
+
url: string;
|
|
81
|
+
source: string;
|
|
82
|
+
}[]): void;
|
|
83
|
+
/** `text` with stack lines the manager moved pointed back at the scripts' own lines. */
|
|
84
|
+
remapStack?(text: string): string;
|
|
85
|
+
close(): Promise<void>;
|
|
86
|
+
}
|
|
87
|
+
/** Connects to `name` in the browser at `endpoint` (see `Violentmonkey.open`). */
|
|
88
|
+
export declare function openExternalManager(name: 'violentmonkey' | 'tampermonkey', endpoint: string, browserArg?: string): Promise<ExternalManager>;
|
|
89
|
+
/** The URL a local file is installed from (see LOCAL_BASE). */
|
|
90
|
+
export declare function installUrlOf(fileUrl: string): string;
|
|
91
|
+
/** The files a prepared script read, for the manager, by the URLs it resolves them to. */
|
|
92
|
+
export declare function installFiles(prepared: PreparedScript): InstallFiles;
|
|
93
|
+
/** The `collection` and `script` commands' calls, made of the manager's. */
|
|
94
|
+
export declare function externalControl(manager: ExternalManager): ManagerControl;
|
|
95
|
+
/**
|
|
96
|
+
* A run's scripts in the manager: installed marked as the run's, and
|
|
97
|
+
* removed when it ends. Scripts that aren't the run's are never
|
|
98
|
+
* replaced.
|
|
99
|
+
*/
|
|
100
|
+
export declare class ExternalRunScripts {
|
|
101
|
+
private readonly manager;
|
|
102
|
+
private readonly run;
|
|
103
|
+
/** The manager's id for each of the run's scripts, by the file it came from. */
|
|
104
|
+
private readonly ids;
|
|
105
|
+
constructor(manager: ExternalManager, run: {
|
|
106
|
+
id: string;
|
|
107
|
+
started: string;
|
|
108
|
+
});
|
|
109
|
+
private isOwn;
|
|
110
|
+
/**
|
|
111
|
+
* Removes the scripts runs that have ended left behind (ones that
|
|
112
|
+
* crashed), returning a line saying so for each such run.
|
|
113
|
+
*/
|
|
114
|
+
removeLeftovers(): Promise<string[]>;
|
|
115
|
+
/**
|
|
116
|
+
* Installs one of the run's scripts, or replaces its copy. Returns
|
|
117
|
+
* the manager's id for it, or throws saying why it can't be.
|
|
118
|
+
*/
|
|
119
|
+
push(prepared: PreparedScript, text: string): Promise<{
|
|
120
|
+
id: number;
|
|
121
|
+
replaced: boolean;
|
|
122
|
+
}>;
|
|
123
|
+
/** Removes the run's scripts, as it ends. */
|
|
124
|
+
removeAll(): Promise<void>;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* The manager's other scripts, for `scripts` and `status`
|
|
128
|
+
* (`ConsoleContext.others`): those expected on a tab, by the manager's
|
|
129
|
+
* own matching where it gives it, else by sm-dev's, since the manager
|
|
130
|
+
* doesn't say what ran.
|
|
131
|
+
* `runScripts`: the manager's ids of the run's own, which the run lists
|
|
132
|
+
* apart.
|
|
133
|
+
*/
|
|
134
|
+
export declare function externalOthers(manager: ExternalManager, runScripts: () => Set<string | undefined>, guarded: boolean): NonNullable<ConsoleContext['others']>;
|
|
135
|
+
/**
|
|
136
|
+
* Which scripts the manager has off, all of them while its own switch
|
|
137
|
+
* is (`ConsoleContext.predictedOff`), as of the last `refresh`. A
|
|
138
|
+
* failed refresh keeps what was known before.
|
|
139
|
+
*/
|
|
140
|
+
export declare function externalOff(manager: ExternalManager): NonNullable<ConsoleContext['predictedOff']>;
|
|
141
|
+
/** A script's rules, as sm-dev's matching takes them. */
|
|
142
|
+
export declare function matchingOf(script: ExternalScript): {
|
|
143
|
+
matches: string[];
|
|
144
|
+
includes: string[];
|
|
145
|
+
excludes: string[];
|
|
146
|
+
};
|
|
@@ -0,0 +1,414 @@
|
|
|
1
|
+
// sm-dev's `collection` and `script` commands, and a run's scripts,
|
|
2
|
+
// under a manager other than SourceMonkey: Violentmonkey and
|
|
3
|
+
// Tampermonkey, behind `ExternalManager`. See
|
|
4
|
+
// docs/sm-dev-violentmonkey.md and docs/sm-dev-tampermonkey.md.
|
|
5
|
+
//
|
|
6
|
+
// - The manager has no collections, so one stands for all its scripts:
|
|
7
|
+
// `C0`, a number SourceMonkey never gives.
|
|
8
|
+
// - sm-dev marks what it installs with a comment as the script's last
|
|
9
|
+
// line (script-mark.ts): the file it came from, and for a run's
|
|
10
|
+
// script, the run. That's how a run's scripts are told from the
|
|
11
|
+
// person's own.
|
|
12
|
+
import { readFile } from 'node:fs/promises';
|
|
13
|
+
import path from 'node:path';
|
|
14
|
+
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
15
|
+
import { getValue, parseHeader } from '../userscript-header.js';
|
|
16
|
+
import { ReplaceRefused } from './manager-commands.js';
|
|
17
|
+
import { explainMatch, prepareScript } from './prepare.js';
|
|
18
|
+
import { liveRuns } from './runs.js';
|
|
19
|
+
import { markedText, readMark, sameScript, withoutMark } from './script-mark.js';
|
|
20
|
+
import { quoted } from './output-style.js';
|
|
21
|
+
/** Connects to `name` in the browser at `endpoint` (see `Violentmonkey.open`). */
|
|
22
|
+
export async function openExternalManager(name, endpoint, browserArg = '') {
|
|
23
|
+
if (name === 'tampermonkey')
|
|
24
|
+
return (await import('./tampermonkey.js')).Tampermonkey.open(endpoint, browserArg);
|
|
25
|
+
return (await import('./violentmonkey.js')).Violentmonkey.open(endpoint, browserArg);
|
|
26
|
+
}
|
|
27
|
+
/** The internal id of `C0`, the collection standing for all the manager's scripts. */
|
|
28
|
+
const ALL = 'all';
|
|
29
|
+
// Whether a run's mark is from a run that's still going.
|
|
30
|
+
async function liveMarks() {
|
|
31
|
+
const runs = await liveRuns().catch(() => []);
|
|
32
|
+
return (mark) => mark.run !== undefined && runs.some((r) => r.id === mark.run && new Date(r.started).toISOString() === mark.started);
|
|
33
|
+
}
|
|
34
|
+
async function listAll(manager) {
|
|
35
|
+
const scripts = await manager.scripts();
|
|
36
|
+
const [texts, live] = await Promise.all([manager.texts(scripts.map((s) => s.id)), liveMarks()]);
|
|
37
|
+
return scripts.map((script) => {
|
|
38
|
+
const text = texts.get(script.id);
|
|
39
|
+
const mark = text === undefined ? null : readMark(text);
|
|
40
|
+
return { script, mark, ...(mark && live(mark) ? { liveRun: mark.run } : {}) };
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
// Where a script came from: the file in sm-dev's comment, or the URL the
|
|
44
|
+
// manager keeps, a local file's (see LOCAL_BASE) as that file.
|
|
45
|
+
function sourceOf(listed) {
|
|
46
|
+
if (listed.mark?.file)
|
|
47
|
+
return pathToFileURL(listed.mark.file).href;
|
|
48
|
+
const url = listed.script.installUrl;
|
|
49
|
+
return url?.startsWith(`${LOCAL_BASE}/`) ? `file://${url.slice(LOCAL_BASE.length)}` : url;
|
|
50
|
+
}
|
|
51
|
+
function managedOf(listed) {
|
|
52
|
+
const { script, mark } = listed;
|
|
53
|
+
return {
|
|
54
|
+
id: String(script.id),
|
|
55
|
+
number: script.id,
|
|
56
|
+
name: script.name,
|
|
57
|
+
...(script.namespace !== undefined ? { namespace: script.namespace } : {}),
|
|
58
|
+
...(script.version !== undefined ? { version: script.version } : {}),
|
|
59
|
+
location: sourceOf(listed) ?? '',
|
|
60
|
+
...(mark?.file ? { loadedAs: mark.file } : {}),
|
|
61
|
+
collectionId: ALL,
|
|
62
|
+
enabled: script.enabled,
|
|
63
|
+
status: 'ok',
|
|
64
|
+
...(listed.liveRun !== undefined ? { run: listed.liveRun } : mark?.run !== undefined ? { leftBy: mark.run } : {}),
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
function detailsOf(listed) {
|
|
68
|
+
const { script } = listed;
|
|
69
|
+
return {
|
|
70
|
+
...managedOf(listed),
|
|
71
|
+
...(script.description !== undefined ? { description: script.description } : {}),
|
|
72
|
+
...(script.author !== undefined ? { author: script.author } : {}),
|
|
73
|
+
...(script.updatedAt !== undefined ? { updatedAt: script.updatedAt } : {}),
|
|
74
|
+
match: script.match,
|
|
75
|
+
include: script.include,
|
|
76
|
+
exclude: script.exclude,
|
|
77
|
+
excludeMatch: script.excludeMatch,
|
|
78
|
+
...(script.runAt !== undefined ? { runAt: script.runAt } : {}),
|
|
79
|
+
grants: script.grants,
|
|
80
|
+
// The manager doesn't say whether each one loaded.
|
|
81
|
+
requires: script.requires.map((url) => ({ url })),
|
|
82
|
+
resources: script.resources.map(({ name, url }) => ({ name, url })),
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
// Where a local file is said to be installed from. A manager resolves
|
|
86
|
+
// a script's relative `@require` and `@resource` against its install
|
|
87
|
+
// URL, but refuses `file://` ones (Violentmonkey's default
|
|
88
|
+
// `blacklistNet`), so a local script's is under `sm-dev.invalid`, a
|
|
89
|
+
// name that never resolves, with each file's contents handed over.
|
|
90
|
+
const LOCAL_BASE = 'https://sm-dev.invalid';
|
|
91
|
+
/** The URL a local file is installed from (see LOCAL_BASE). */
|
|
92
|
+
export function installUrlOf(fileUrl) {
|
|
93
|
+
return fileUrl.startsWith('file:') ? `${LOCAL_BASE}${new URL(fileUrl).pathname}` : fileUrl;
|
|
94
|
+
}
|
|
95
|
+
/** The files a prepared script read, for the manager, by the URLs it resolves them to. */
|
|
96
|
+
export function installFiles(prepared) {
|
|
97
|
+
const requires = {};
|
|
98
|
+
const resources = {};
|
|
99
|
+
for (const r of prepared.script.requires ?? [])
|
|
100
|
+
requires[installUrlOf(r.url)] = r.source;
|
|
101
|
+
for (const r of prepared.script.resources ?? [])
|
|
102
|
+
resources[installUrlOf(r.url)] = { contentType: r.contentType ?? '', base64: r.bytesBase64 };
|
|
103
|
+
return { requires, resources };
|
|
104
|
+
}
|
|
105
|
+
// Reads a script to install: a file with its local `@require` and
|
|
106
|
+
// `@resource` files, or a URL, whose files the manager fetches itself.
|
|
107
|
+
async function readSource(location) {
|
|
108
|
+
if (location.startsWith('file:')) {
|
|
109
|
+
const file = fileURLToPath(location);
|
|
110
|
+
const prepared = await prepareScript({ file, collectionRoot: path.dirname(file), localRoots: [] });
|
|
111
|
+
if (prepared.status !== 'ok')
|
|
112
|
+
throw new Error(prepared.diagnostic ?? prepared.errorMessage ?? 'The script is not valid');
|
|
113
|
+
return { text: await readFile(file, 'utf8'), files: installFiles(prepared) };
|
|
114
|
+
}
|
|
115
|
+
let res;
|
|
116
|
+
try {
|
|
117
|
+
res = await fetch(location, { signal: AbortSignal.timeout(30_000) });
|
|
118
|
+
}
|
|
119
|
+
catch (err) {
|
|
120
|
+
throw new Error(`It could not be downloaded: ${err.message}`, { cause: err });
|
|
121
|
+
}
|
|
122
|
+
if (!res.ok)
|
|
123
|
+
throw new Error(`It could not be downloaded: HTTP ${res.status}`);
|
|
124
|
+
return { text: await res.text() };
|
|
125
|
+
}
|
|
126
|
+
// How a script read from `location` is installed: a local one with its
|
|
127
|
+
// files, and no update checks, since the manager can't fetch it.
|
|
128
|
+
function installOptions(location, read, id) {
|
|
129
|
+
return {
|
|
130
|
+
...(id !== undefined ? { id } : {}),
|
|
131
|
+
url: installUrlOf(location),
|
|
132
|
+
...(read.files ? { files: read.files } : {}),
|
|
133
|
+
...(location.startsWith('file:') ? { local: true } : {}),
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
// The name and namespace a script's header gives, which the manager
|
|
137
|
+
// tells scripts apart by.
|
|
138
|
+
function identityOf(text) {
|
|
139
|
+
const header = parseHeader(text);
|
|
140
|
+
const name = header ? getValue(header, 'name') : undefined;
|
|
141
|
+
if (!header || !name)
|
|
142
|
+
throw new Error('It has no @name in a ==UserScript== header');
|
|
143
|
+
return { name, namespace: getValue(header, 'namespace') ?? '' };
|
|
144
|
+
}
|
|
145
|
+
function sameIdentity(script, id) {
|
|
146
|
+
return script.name === id.name && (script.namespace ?? '') === id.namespace;
|
|
147
|
+
}
|
|
148
|
+
/** `E3: Name`. */
|
|
149
|
+
function shown(script) {
|
|
150
|
+
return `E${script.id}: ${script.name}`;
|
|
151
|
+
}
|
|
152
|
+
/** The `collection` and `script` commands' calls, made of the manager's. */
|
|
153
|
+
export function externalControl(manager) {
|
|
154
|
+
const { label } = manager;
|
|
155
|
+
const find = async (id) => {
|
|
156
|
+
const found = (await listAll(manager)).find((l) => String(l.script.id) === id);
|
|
157
|
+
if (!found)
|
|
158
|
+
throw new Error(`There is no script E${id}. Use ${quoted('script list')} to list the installed scripts.`);
|
|
159
|
+
return found;
|
|
160
|
+
};
|
|
161
|
+
const collection = async (scripts) => ({
|
|
162
|
+
id: ALL,
|
|
163
|
+
number: 0,
|
|
164
|
+
name: label,
|
|
165
|
+
kind: 'container',
|
|
166
|
+
enabled: await manager.applied(),
|
|
167
|
+
scriptCount: scripts ?? (await manager.scripts()).length,
|
|
168
|
+
});
|
|
169
|
+
// Re-reads one script from where it came from, and installs it in
|
|
170
|
+
// place when its text changed. Its comment is kept.
|
|
171
|
+
const refresh = async (listed) => {
|
|
172
|
+
const source = sourceOf(listed);
|
|
173
|
+
if (!source)
|
|
174
|
+
throw new Error(`${shown(listed.script)} has no file or URL to refresh from`);
|
|
175
|
+
const read = await readSource(source);
|
|
176
|
+
const before = (await manager.texts([listed.script.id])).get(listed.script.id) ?? '';
|
|
177
|
+
if (sameScript(before, read.text))
|
|
178
|
+
return false;
|
|
179
|
+
await manager.install(listed.mark ? markedText(read.text, listed.mark) : read.text, installOptions(source, read, listed.script.id));
|
|
180
|
+
return true;
|
|
181
|
+
};
|
|
182
|
+
return {
|
|
183
|
+
label,
|
|
184
|
+
collections: async () => [await collection()],
|
|
185
|
+
scripts: async () => (await listAll(manager)).map(managedOf),
|
|
186
|
+
onDisk: async () => null,
|
|
187
|
+
setScriptEnabled: async (id, enabled) => {
|
|
188
|
+
await manager.setEnabled(Number(id), enabled);
|
|
189
|
+
return { script: managedOf(await find(id)), turnedOff: [] };
|
|
190
|
+
},
|
|
191
|
+
setCollectionEnabled: async (_id, enabled) => {
|
|
192
|
+
await manager.setApplied(enabled);
|
|
193
|
+
return collection();
|
|
194
|
+
},
|
|
195
|
+
refreshScript: async (id) => {
|
|
196
|
+
const updated = await refresh(await find(id));
|
|
197
|
+
return { script: managedOf(await find(id)), updated };
|
|
198
|
+
},
|
|
199
|
+
refreshCollection: async () => {
|
|
200
|
+
const all = await listAll(manager);
|
|
201
|
+
const updated = [];
|
|
202
|
+
const failed = [];
|
|
203
|
+
let unchanged = 0;
|
|
204
|
+
// Not a live run's scripts, which only their run changes; nor
|
|
205
|
+
// those with nowhere to read from. One that fails is said, and
|
|
206
|
+
// the rest go on.
|
|
207
|
+
for (const listed of all) {
|
|
208
|
+
if (listed.liveRun !== undefined || !sourceOf(listed)) {
|
|
209
|
+
unchanged++;
|
|
210
|
+
continue;
|
|
211
|
+
}
|
|
212
|
+
try {
|
|
213
|
+
if (await refresh(listed))
|
|
214
|
+
updated.push(listed.script.id);
|
|
215
|
+
else
|
|
216
|
+
unchanged++;
|
|
217
|
+
}
|
|
218
|
+
catch (err) {
|
|
219
|
+
failed.push({ ...managedOf(listed), refreshError: err.message });
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
const after = await listAll(manager);
|
|
223
|
+
return {
|
|
224
|
+
collection: await collection(after.length),
|
|
225
|
+
updated: after.filter((l) => updated.includes(l.script.id)).map(managedOf),
|
|
226
|
+
unchanged,
|
|
227
|
+
removed: [],
|
|
228
|
+
...(failed.length > 0 ? { failed } : {}),
|
|
229
|
+
};
|
|
230
|
+
},
|
|
231
|
+
installScript: async (location, _collection, replace = false) => {
|
|
232
|
+
const read = await readSource(location);
|
|
233
|
+
const identity = identityOf(read.text);
|
|
234
|
+
const all = await listAll(manager);
|
|
235
|
+
const existing = all.find((l) => sameIdentity(l.script, identity));
|
|
236
|
+
if (existing?.liveRun !== undefined) {
|
|
237
|
+
throw new Error(`${shown(existing.script)} has the same name and namespace, and is a script of run ${existing.liveRun}, which only that run changes`);
|
|
238
|
+
}
|
|
239
|
+
const file = location.startsWith('file:') ? fileURLToPath(location) : undefined;
|
|
240
|
+
if (existing && sameScript((await manager.texts([existing.script.id])).get(existing.script.id) ?? '', read.text)) {
|
|
241
|
+
return { script: managedOf(existing), turnedOff: [], already: true };
|
|
242
|
+
}
|
|
243
|
+
// The person's own, or one sm-dev installed to stay; not one an
|
|
244
|
+
// ended run left.
|
|
245
|
+
if (existing && !existing.mark?.run && !replace)
|
|
246
|
+
throw new ReplaceRefused(shown(existing.script));
|
|
247
|
+
const code = file ? markedText(read.text, { file }) : read.text;
|
|
248
|
+
const { id } = await manager.install(code, installOptions(location, read));
|
|
249
|
+
return { script: managedOf(await find(String(id))), turnedOff: [], ...(existing ? { replaced: true } : {}) };
|
|
250
|
+
},
|
|
251
|
+
uninstallScript: async (id) => {
|
|
252
|
+
const listed = await find(id);
|
|
253
|
+
await manager.uninstall(listed.script.id);
|
|
254
|
+
return managedOf(listed);
|
|
255
|
+
},
|
|
256
|
+
moveScript: async () => {
|
|
257
|
+
throw new Error(`${label} has one collection, C0, which holds all its scripts`);
|
|
258
|
+
},
|
|
259
|
+
renameCollection: async () => {
|
|
260
|
+
throw new Error(`C0 stands for all of ${label}'s scripts, so it has no name of its own to change`);
|
|
261
|
+
},
|
|
262
|
+
scriptDetails: async (id) => detailsOf(await find(id)),
|
|
263
|
+
scriptText: async (id) => {
|
|
264
|
+
const text = (await manager.texts([Number(id)])).get(Number(id));
|
|
265
|
+
return text === undefined ? null : withoutMark(text);
|
|
266
|
+
},
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* A run's scripts in the manager: installed marked as the run's, and
|
|
271
|
+
* removed when it ends. Scripts that aren't the run's are never
|
|
272
|
+
* replaced.
|
|
273
|
+
*/
|
|
274
|
+
export class ExternalRunScripts {
|
|
275
|
+
manager;
|
|
276
|
+
run;
|
|
277
|
+
/** The manager's id for each of the run's scripts, by the file it came from. */
|
|
278
|
+
ids = new Map();
|
|
279
|
+
constructor(manager, run) {
|
|
280
|
+
this.manager = manager;
|
|
281
|
+
this.run = run;
|
|
282
|
+
}
|
|
283
|
+
isOwn(mark) {
|
|
284
|
+
return mark?.run === this.run.id && mark.started === this.run.started;
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
287
|
+
* Removes the scripts runs that have ended left behind (ones that
|
|
288
|
+
* crashed), returning a line saying so for each such run.
|
|
289
|
+
*/
|
|
290
|
+
async removeLeftovers() {
|
|
291
|
+
const all = await listAll(this.manager);
|
|
292
|
+
const left = all.filter((l) => l.mark?.run !== undefined && l.liveRun === undefined && !this.isOwn(l.mark));
|
|
293
|
+
if (left.length === 0)
|
|
294
|
+
return [];
|
|
295
|
+
await this.manager.remove(left.map((l) => l.script.id));
|
|
296
|
+
const byRun = new Map();
|
|
297
|
+
for (const l of left)
|
|
298
|
+
byRun.set(l.mark.run, [...byRun.get(l.mark.run) ?? [], l]);
|
|
299
|
+
return [...byRun].map(([run, scripts]) => `Removed ${scripts.length === 1 ? 'a script' : `${scripts.length} scripts`} run ${run} left in ${this.manager.label} when it ended: ${scripts.map((l) => shown(l.script)).join(', ')}`);
|
|
300
|
+
}
|
|
301
|
+
/**
|
|
302
|
+
* Installs one of the run's scripts, or replaces its copy. Returns
|
|
303
|
+
* the manager's id for it, or throws saying why it can't be.
|
|
304
|
+
*/
|
|
305
|
+
async push(prepared, text) {
|
|
306
|
+
const file = fileURLToPath(prepared.script.fileUrl);
|
|
307
|
+
const identity = identityOf(text);
|
|
308
|
+
const all = await listAll(this.manager);
|
|
309
|
+
const before = this.ids.get(file);
|
|
310
|
+
const clash = all.find((l) => sameIdentity(l.script, identity) && l.script.id !== before);
|
|
311
|
+
let id = before;
|
|
312
|
+
if (clash) {
|
|
313
|
+
const { label } = this.manager;
|
|
314
|
+
// Another of this run's files: the manager keeps one script by
|
|
315
|
+
// a name and namespace, so loading this would replace that one.
|
|
316
|
+
if (this.isOwn(clash.mark) && clash.mark?.file !== undefined && clash.mark.file !== file) {
|
|
317
|
+
throw new Error(`This run loaded ${clash.mark.file} as ${shown(clash.script)}, with the same name and namespace. ${label} keeps one script by a name and namespace, so the run can't load both. Give one of them another @name or @namespace.`);
|
|
318
|
+
}
|
|
319
|
+
if (clash.liveRun !== undefined && !this.isOwn(clash.mark)) {
|
|
320
|
+
throw new Error(`${label} has ${shown(clash.script)} with the same name and namespace, loaded by run ${clash.liveRun}. Two runs can't both load one script.`);
|
|
321
|
+
}
|
|
322
|
+
if (!clash.mark?.run) {
|
|
323
|
+
throw new Error(`${label} has ${shown(clash.script)} with the same name and namespace, installed apart from this run, which a run doesn't replace. To load this one, uninstall that one first: script E${clash.script.id} uninstall --force.`);
|
|
324
|
+
}
|
|
325
|
+
// One an ended run left: replaced.
|
|
326
|
+
id ??= clash.script.id;
|
|
327
|
+
}
|
|
328
|
+
const code = markedText(text, { run: this.run.id, started: this.run.started, file });
|
|
329
|
+
const result = await this.manager.install(code, { ...(id !== undefined ? { id } : {}), url: installUrlOf(prepared.script.fileUrl), files: installFiles(prepared), local: true });
|
|
330
|
+
this.ids.set(file, result.id);
|
|
331
|
+
this.manager.noteRequires?.(result.id, (prepared.script.requires ?? []).map((r) => ({ url: r.url, source: r.source })));
|
|
332
|
+
return { id: result.id, replaced: before !== undefined || !result.isNew };
|
|
333
|
+
}
|
|
334
|
+
/** Removes the run's scripts, as it ends. */
|
|
335
|
+
async removeAll() {
|
|
336
|
+
const all = await listAll(this.manager);
|
|
337
|
+
await this.manager.remove(all.filter((l) => this.isOwn(l.mark)).map((l) => l.script.id));
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
/**
|
|
341
|
+
* The manager's other scripts, for `scripts` and `status`
|
|
342
|
+
* (`ConsoleContext.others`): those expected on a tab, by the manager's
|
|
343
|
+
* own matching where it gives it, else by sm-dev's, since the manager
|
|
344
|
+
* doesn't say what ran.
|
|
345
|
+
* `runScripts`: the manager's ids of the run's own, which the run lists
|
|
346
|
+
* apart.
|
|
347
|
+
*/
|
|
348
|
+
export function externalOthers(manager, runScripts, guarded) {
|
|
349
|
+
const known = new Map();
|
|
350
|
+
const other = (id, name) => {
|
|
351
|
+
const label = `E${id}`;
|
|
352
|
+
const found = known.get(label) ?? {
|
|
353
|
+
label,
|
|
354
|
+
name,
|
|
355
|
+
collection: '',
|
|
356
|
+
status: 'EXPECTED',
|
|
357
|
+
values: async () => {
|
|
358
|
+
throw new Error(`${manager.label} doesn't give sm-dev a script's stored values`);
|
|
359
|
+
},
|
|
360
|
+
setValues: async () => {
|
|
361
|
+
throw new Error(`${manager.label} doesn't let sm-dev change a script's stored values`);
|
|
362
|
+
},
|
|
363
|
+
};
|
|
364
|
+
known.set(label, found);
|
|
365
|
+
return found;
|
|
366
|
+
};
|
|
367
|
+
return {
|
|
368
|
+
guarded,
|
|
369
|
+
kind: `${manager.label} scripts expected`,
|
|
370
|
+
byLabel: (label) => known.get(label),
|
|
371
|
+
onTab: async (tab) => {
|
|
372
|
+
const url = tab.page.url();
|
|
373
|
+
if (!await manager.applied())
|
|
374
|
+
return [];
|
|
375
|
+
const own = runScripts();
|
|
376
|
+
// Listed first, so the manager knows every script's id. Its
|
|
377
|
+
// matching doesn't leave out the scripts turned off.
|
|
378
|
+
const scripts = await manager.scripts();
|
|
379
|
+
const matched = manager.matching ? new Set(await manager.matching(url)) : null;
|
|
380
|
+
return scripts
|
|
381
|
+
.filter((s) => s.enabled && !own.has(String(s.id)) && (matched ? matched.has(s.id) : explainMatch(matchingOf(s), url).matches))
|
|
382
|
+
.map((s) => other(s.id, s.name));
|
|
383
|
+
},
|
|
384
|
+
installed: (id, _label, name) => other(Number(id), name),
|
|
385
|
+
};
|
|
386
|
+
}
|
|
387
|
+
/**
|
|
388
|
+
* Which scripts the manager has off, all of them while its own switch
|
|
389
|
+
* is (`ConsoleContext.predictedOff`), as of the last `refresh`. A
|
|
390
|
+
* failed refresh keeps what was known before.
|
|
391
|
+
*/
|
|
392
|
+
export function externalOff(manager) {
|
|
393
|
+
let off = new Set();
|
|
394
|
+
let applied = true;
|
|
395
|
+
return {
|
|
396
|
+
refresh: async () => {
|
|
397
|
+
try {
|
|
398
|
+
const [scripts, on] = await Promise.all([manager.scripts(), manager.applied()]);
|
|
399
|
+
off = new Set(scripts.filter((s) => !s.enabled).map((s) => String(s.id)));
|
|
400
|
+
applied = on;
|
|
401
|
+
}
|
|
402
|
+
catch {
|
|
403
|
+
// The lists then go by what was read last.
|
|
404
|
+
}
|
|
405
|
+
},
|
|
406
|
+
has: (id) => !applied || (id !== undefined && off.has(id)),
|
|
407
|
+
};
|
|
408
|
+
}
|
|
409
|
+
/** A script's rules, as sm-dev's matching takes them. */
|
|
410
|
+
export function matchingOf(script) {
|
|
411
|
+
// `@exclude-match` is a match pattern, which reads the same as a glob
|
|
412
|
+
// in nearly every case.
|
|
413
|
+
return { matches: script.match, includes: script.include, excludes: [...script.exclude, ...script.excludeMatch] };
|
|
414
|
+
}
|