dsh-github-app 0.0.0-stage → 0.0.2
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 +149 -2
- package/api.d.ts +5 -0
- package/api.mjs +258 -0
- package/atomicFile.d.ts +14 -0
- package/atomicFile.mjs +53 -0
- package/client/client.js +3 -0
- package/constants.d.ts +20 -0
- package/constants.mjs +20 -0
- package/contracts.d.ts +40 -0
- package/cordis.patch.yml +5 -0
- package/declaration.d.ts +4 -0
- package/fence.d.ts +16 -0
- package/fence.mjs +136 -0
- package/github.d.ts +117 -0
- package/github.mjs +659 -0
- package/icon.png +0 -0
- package/index.d.ts +19 -0
- package/index.mjs +46 -0
- package/keyCrypto.d.ts +25 -0
- package/keyCrypto.mjs +132 -0
- package/locale/en.json +5 -0
- package/package.json +52 -3
- package/passphrase.d.ts +10 -0
- package/passphrase.mjs +18 -0
- package/secureFile.d.ts +21 -0
- package/secureFile.mjs +56 -0
- package/settings.d.ts +45 -0
- package/settings.mjs +127 -0
- package/time.d.ts +7 -0
- package/time.mjs +15 -0
- package/uninstall.d.ts +56 -0
- package/uninstall.mjs +124 -0
- package/utils/errorMessage.d.ts +1 -0
- package/utils/errorMessage.mjs +5 -0
package/uninstall.mjs
ADDED
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { PACKAGE_NAME } from "./constants.mjs";
|
|
2
|
+
import { dshHomeDir, pluginDir } from "./settings.mjs";
|
|
3
|
+
import { join, resolve } from "node:path";
|
|
4
|
+
import { existsSync, readFileSync, rmSync } from "node:fs";
|
|
5
|
+
// src/uninstall.ts
|
|
6
|
+
/**
|
|
7
|
+
* Removes plugin-owned artifacts after the bundle is uninstalled.
|
|
8
|
+
*
|
|
9
|
+
* DSH has no uninstall lifecycle: removing a bundle disposes the plugin fiber
|
|
10
|
+
* exactly like disabling it, an HMR reload, or a host restart. Disposal alone
|
|
11
|
+
* therefore proves nothing. The watcher keeps reading the profile manifest
|
|
12
|
+
* after disposal and deletes plugin data only after the package has stayed
|
|
13
|
+
* absent from both `dependencies` and `dsh.profile.bundles` for a quiet
|
|
14
|
+
* period. Until the package is gone, the manifest still declares it, so a
|
|
15
|
+
* disable, reload, or restart leaves the data alone.
|
|
16
|
+
*
|
|
17
|
+
* The watcher lives in the host process, so this covers removals performed
|
|
18
|
+
* while a DSH host is running. Removing the package with no host running
|
|
19
|
+
* (`dsh plugin remove`) leaves the data directory for manual cleanup.
|
|
20
|
+
*/
|
|
21
|
+
/** How often the watcher re-reads the profile manifest. */
|
|
22
|
+
const WATCH_INTERVAL_MS = 1e3;
|
|
23
|
+
/** Consecutive absent readings required before deleting anything. */
|
|
24
|
+
const WATCH_CONFIRMATIONS = 15;
|
|
25
|
+
/** Upper bound on one watcher's lifetime. */
|
|
26
|
+
const WATCH_TIMEOUT_MS = 3e5;
|
|
27
|
+
const activeWatchers = /* @__PURE__ */ new Set();
|
|
28
|
+
function isRecord(value) {
|
|
29
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Whether a profile manifest still claims this package.
|
|
33
|
+
*
|
|
34
|
+
* @param profileDir profile root holding `package.json`.
|
|
35
|
+
* @param packageName bundle package name.
|
|
36
|
+
* @returns true when declared, false when absent, null when the manifest
|
|
37
|
+
* cannot be read — callers must treat null as "still installed".
|
|
38
|
+
*/
|
|
39
|
+
function profileDeclaresPackage(profileDir, packageName = PACKAGE_NAME) {
|
|
40
|
+
let manifest;
|
|
41
|
+
try {
|
|
42
|
+
manifest = JSON.parse(readFileSync(join(profileDir, "package.json"), "utf8"));
|
|
43
|
+
} catch {
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
if (!isRecord(manifest)) return null;
|
|
47
|
+
if (isRecord(manifest.dependencies) && Object.hasOwn(manifest.dependencies, packageName)) return true;
|
|
48
|
+
if (isRecord(manifest.devDependencies) && Object.hasOwn(manifest.devDependencies, packageName)) return true;
|
|
49
|
+
const dsh = isRecord(manifest.dsh) ? manifest.dsh : {};
|
|
50
|
+
const profile = isRecord(dsh.profile) ? dsh.profile : {};
|
|
51
|
+
return (Array.isArray(profile.bundles) ? profile.bundles : []).includes(packageName);
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Delete the plugin data directory. Paths are derived from `DSH_HOME`, never
|
|
55
|
+
* from user input.
|
|
56
|
+
*
|
|
57
|
+
* @param env environment to read `DSH_HOME` from.
|
|
58
|
+
* @returns true when the directory was removed.
|
|
59
|
+
*/
|
|
60
|
+
function removePluginArtifacts(env = process.env) {
|
|
61
|
+
const home = resolve(dshHomeDir(env));
|
|
62
|
+
const dir = resolve(pluginDir(env));
|
|
63
|
+
if (dir !== join(home, "dsh-github-app")) return false;
|
|
64
|
+
if (!existsSync(dir)) return false;
|
|
65
|
+
try {
|
|
66
|
+
rmSync(dir, {
|
|
67
|
+
recursive: true,
|
|
68
|
+
force: true
|
|
69
|
+
});
|
|
70
|
+
} catch (error) {
|
|
71
|
+
console.warn("[dsh-github-app] cannot remove plugin data:", error instanceof Error && error.message ? error.message : error);
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
return true;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Watch the profile for this package's removal and delete plugin artifacts.
|
|
78
|
+
*
|
|
79
|
+
* @param options profile location and timing knobs.
|
|
80
|
+
* @returns a function that stops the watcher before it acts.
|
|
81
|
+
*/
|
|
82
|
+
function watchForUninstallCleanup(options) {
|
|
83
|
+
const { profileDir, packageName = PACKAGE_NAME, env = process.env } = options;
|
|
84
|
+
const intervalMs = Math.max(1, options.intervalMs ?? WATCH_INTERVAL_MS);
|
|
85
|
+
const confirmations = Math.max(1, options.confirmations ?? WATCH_CONFIRMATIONS);
|
|
86
|
+
const deadline = Date.now() + Math.max(intervalMs, options.timeoutMs ?? WATCH_TIMEOUT_MS);
|
|
87
|
+
let absentReadings = 0;
|
|
88
|
+
let timer;
|
|
89
|
+
let stopped = false;
|
|
90
|
+
const stop = () => {
|
|
91
|
+
if (stopped) return;
|
|
92
|
+
stopped = true;
|
|
93
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
94
|
+
activeWatchers.delete(stop);
|
|
95
|
+
};
|
|
96
|
+
const tick = () => {
|
|
97
|
+
if (stopped) return;
|
|
98
|
+
if (profileDeclaresPackage(profileDir, packageName) === false) absentReadings += 1;
|
|
99
|
+
else absentReadings = 0;
|
|
100
|
+
if (absentReadings >= confirmations) {
|
|
101
|
+
stop();
|
|
102
|
+
removePluginArtifacts(env);
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
if (Date.now() >= deadline) {
|
|
106
|
+
stop();
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
timer = setTimeout(tick, intervalMs);
|
|
110
|
+
timer.unref();
|
|
111
|
+
};
|
|
112
|
+
activeWatchers.add(stop);
|
|
113
|
+
timer = setTimeout(tick, intervalMs);
|
|
114
|
+
timer.unref();
|
|
115
|
+
return stop;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Cancel watchers started by this module instance, for example when the
|
|
119
|
+
* plugin mounts again after an HMR reload or a reinstall.
|
|
120
|
+
*/
|
|
121
|
+
function cancelUninstallCleanup() {
|
|
122
|
+
for (const stop of [...activeWatchers]) stop();
|
|
123
|
+
}
|
|
124
|
+
export { cancelUninstallCleanup, profileDeclaresPackage, removePluginArtifacts, watchForUninstallCleanup };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function errorMessage(error: unknown, fallback: string): string;
|