kastell 2.2.6 → 2.3.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/.claude-plugin/plugin.json +5 -3
- package/CHANGELOG.md +112 -0
- package/README.md +34 -6
- package/README.tr.md +6 -6
- package/dist/commands/audit.d.ts +3 -2
- package/dist/commands/audit.d.ts.map +1 -1
- package/dist/commands/audit.js +88 -47
- package/dist/commands/audit.js.map +1 -1
- package/dist/commands/auth.d.ts.map +1 -1
- package/dist/commands/auth.js +14 -1
- package/dist/commands/auth.js.map +1 -1
- package/dist/commands/domain.d.ts.map +1 -1
- package/dist/commands/domain.js +18 -1
- package/dist/commands/domain.js.map +1 -1
- package/dist/commands/evidence.d.ts.map +1 -1
- package/dist/commands/evidence.js +2 -1
- package/dist/commands/evidence.js.map +1 -1
- package/dist/commands/fix.d.ts.map +1 -1
- package/dist/commands/fix.js +12 -4
- package/dist/commands/fix.js.map +1 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +2 -1
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/lock.d.ts.map +1 -1
- package/dist/commands/lock.js +7 -2
- package/dist/commands/lock.js.map +1 -1
- package/dist/commands/maintain.d.ts.map +1 -1
- package/dist/commands/maintain.js +13 -0
- package/dist/commands/maintain.js.map +1 -1
- package/dist/commands/plugin.d.ts.map +1 -1
- package/dist/commands/plugin.js +5 -4
- package/dist/commands/plugin.js.map +1 -1
- package/dist/commands/snapshot.d.ts.map +1 -1
- package/dist/commands/snapshot.js +16 -0
- package/dist/commands/snapshot.js.map +1 -1
- package/dist/commands/status.d.ts.map +1 -1
- package/dist/commands/status.js +2 -0
- package/dist/commands/status.js.map +1 -1
- package/dist/commands/update.d.ts.map +1 -1
- package/dist/commands/update.js +30 -10
- package/dist/commands/update.js.map +1 -1
- package/dist/core/audit/commands.d.ts +4 -1
- package/dist/core/audit/commands.d.ts.map +1 -1
- package/dist/core/audit/commands.js +7 -3
- package/dist/core/audit/commands.js.map +1 -1
- package/dist/core/audit/diff.d.ts +31 -0
- package/dist/core/audit/diff.d.ts.map +1 -1
- package/dist/core/audit/diff.js +43 -0
- package/dist/core/audit/diff.js.map +1 -1
- package/dist/core/audit/errors.d.ts +4 -0
- package/dist/core/audit/errors.d.ts.map +1 -0
- package/dist/core/audit/errors.js +4 -0
- package/dist/core/audit/errors.js.map +1 -0
- package/dist/core/audit/fix-history.d.ts.map +1 -1
- package/dist/core/audit/fix-history.js +3 -5
- package/dist/core/audit/fix-history.js.map +1 -1
- package/dist/core/audit/fix.d.ts.map +1 -1
- package/dist/core/audit/fix.js +16 -18
- package/dist/core/audit/fix.js.map +1 -1
- package/dist/core/audit/history.d.ts +8 -0
- package/dist/core/audit/history.d.ts.map +1 -1
- package/dist/core/audit/history.js +67 -5
- package/dist/core/audit/history.js.map +1 -1
- package/dist/core/audit/index.d.ts.map +1 -1
- package/dist/core/audit/index.js +24 -12
- package/dist/core/audit/index.js.map +1 -1
- package/dist/core/audit/listChecks.d.ts.map +1 -1
- package/dist/core/audit/listChecks.js +2 -1
- package/dist/core/audit/listChecks.js.map +1 -1
- package/dist/core/audit/pluginAudit.d.ts +10 -0
- package/dist/core/audit/pluginAudit.d.ts.map +1 -1
- package/dist/core/audit/pluginAudit.js +59 -23
- package/dist/core/audit/pluginAudit.js.map +1 -1
- package/dist/core/audit/pluginFix.d.ts +22 -1
- package/dist/core/audit/pluginFix.d.ts.map +1 -1
- package/dist/core/audit/pluginFix.js +27 -10
- package/dist/core/audit/pluginFix.js.map +1 -1
- package/dist/core/audit/regression.d.ts +1 -0
- package/dist/core/audit/regression.d.ts.map +1 -1
- package/dist/core/audit/regression.js +7 -5
- package/dist/core/audit/regression.js.map +1 -1
- package/dist/core/audit/snapshot.d.ts.map +1 -1
- package/dist/core/audit/snapshot.js +3 -4
- package/dist/core/audit/snapshot.js.map +1 -1
- package/dist/core/audit/types.d.ts +2 -2
- package/dist/core/audit/types.d.ts.map +1 -1
- package/dist/core/completions.d.ts.map +1 -1
- package/dist/core/completions.js +71 -47
- package/dist/core/completions.js.map +1 -1
- package/dist/core/configRepair.d.ts.map +1 -1
- package/dist/core/configRepair.js +5 -12
- package/dist/core/configRepair.js.map +1 -1
- package/dist/core/doctor.d.ts +2 -1
- package/dist/core/doctor.d.ts.map +1 -1
- package/dist/core/doctor.js +4 -5
- package/dist/core/doctor.js.map +1 -1
- package/dist/core/evidence.d.ts.map +1 -1
- package/dist/core/evidence.js +4 -7
- package/dist/core/evidence.js.map +1 -1
- package/dist/core/fleet.d.ts +5 -2
- package/dist/core/fleet.d.ts.map +1 -1
- package/dist/core/fleet.js +34 -22
- package/dist/core/fleet.js.map +1 -1
- package/dist/core/notify.d.ts.map +1 -1
- package/dist/core/notify.js +13 -24
- package/dist/core/notify.js.map +1 -1
- package/dist/core/plugin/audit.d.ts +25 -0
- package/dist/core/plugin/audit.d.ts.map +1 -0
- package/dist/core/plugin/audit.js +43 -0
- package/dist/core/plugin/audit.js.map +1 -0
- package/dist/core/plugin.d.ts +19 -6
- package/dist/core/plugin.d.ts.map +1 -1
- package/dist/core/plugin.js +40 -19
- package/dist/core/plugin.js.map +1 -1
- package/dist/core/provision.d.ts +25 -1
- package/dist/core/provision.d.ts.map +1 -1
- package/dist/core/provision.js +127 -12
- package/dist/core/provision.js.map +1 -1
- package/dist/core/scheduleManager.d.ts.map +1 -1
- package/dist/core/scheduleManager.js +7 -8
- package/dist/core/scheduleManager.js.map +1 -1
- package/dist/core/tokens.d.ts +1 -1
- package/dist/core/tokens.d.ts.map +1 -1
- package/dist/core/tokens.js +12 -11
- package/dist/core/tokens.js.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/mcp/index.js +2 -2
- package/dist/mcp/index.js.map +1 -1
- package/dist/mcp/server.d.ts +14 -0
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +118 -96
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/startupDiagnostic.d.ts +6 -0
- package/dist/mcp/startupDiagnostic.d.ts.map +1 -0
- package/dist/mcp/startupDiagnostic.js +7 -0
- package/dist/mcp/startupDiagnostic.js.map +1 -0
- package/dist/mcp/tools/serverAudit.d.ts +2 -1
- package/dist/mcp/tools/serverAudit.d.ts.map +1 -1
- package/dist/mcp/tools/serverAudit.js.map +1 -1
- package/dist/mcp/tools/serverBackup.handlers.d.ts.map +1 -1
- package/dist/mcp/tools/serverBackup.handlers.js +1 -0
- package/dist/mcp/tools/serverBackup.handlers.js.map +1 -1
- package/dist/mcp/tools/serverCompare.d.ts +13 -14
- package/dist/mcp/tools/serverCompare.d.ts.map +1 -1
- package/dist/mcp/tools/serverCompare.js +20 -15
- package/dist/mcp/tools/serverCompare.js.map +1 -1
- package/dist/mcp/tools/serverFix.d.ts +61 -17
- package/dist/mcp/tools/serverFix.d.ts.map +1 -1
- package/dist/mcp/tools/serverFix.js +67 -78
- package/dist/mcp/tools/serverFix.js.map +1 -1
- package/dist/mcp/tools/serverGuard.d.ts.map +1 -1
- package/dist/mcp/tools/serverGuard.js +4 -1
- package/dist/mcp/tools/serverGuard.js.map +1 -1
- package/dist/mcp/tools/serverInfo.d.ts +11 -3
- package/dist/mcp/tools/serverInfo.d.ts.map +1 -1
- package/dist/mcp/tools/serverInfo.js +11 -3
- package/dist/mcp/tools/serverInfo.js.map +1 -1
- package/dist/mcp/tools/serverLogs.d.ts.map +1 -1
- package/dist/mcp/tools/serverLogs.js +2 -1
- package/dist/mcp/tools/serverLogs.js.map +1 -1
- package/dist/mcp/tools/serverMaintain.d.ts +4 -2
- package/dist/mcp/tools/serverMaintain.d.ts.map +1 -1
- package/dist/mcp/tools/serverMaintain.js +4 -2
- package/dist/mcp/tools/serverMaintain.js.map +1 -1
- package/dist/mcp/tools/serverPlugin.js +2 -2
- package/dist/mcp/tools/serverPlugin.js.map +1 -1
- package/dist/mcp/tools/serverProvision.d.ts +8 -0
- package/dist/mcp/tools/serverProvision.d.ts.map +1 -1
- package/dist/mcp/tools/serverProvision.js +31 -3
- package/dist/mcp/tools/serverProvision.js.map +1 -1
- package/dist/mcp/tools/serverSecure.actions.d.ts +21 -0
- package/dist/mcp/tools/serverSecure.actions.d.ts.map +1 -0
- package/dist/mcp/tools/serverSecure.actions.js +22 -0
- package/dist/mcp/tools/serverSecure.actions.js.map +1 -0
- package/dist/mcp/tools/serverSecure.d.ts +23 -1
- package/dist/mcp/tools/serverSecure.d.ts.map +1 -1
- package/dist/mcp/tools/serverSecure.js +16 -9
- package/dist/mcp/tools/serverSecure.js.map +1 -1
- package/dist/mcp/utils/parseMetrics.d.ts +27 -0
- package/dist/mcp/utils/parseMetrics.d.ts.map +1 -0
- package/dist/mcp/utils/parseMetrics.js +35 -0
- package/dist/mcp/utils/parseMetrics.js.map +1 -0
- package/dist/mcp/utils.d.ts +9 -0
- package/dist/mcp/utils.d.ts.map +1 -1
- package/dist/mcp/utils.js +1 -2
- package/dist/mcp/utils.js.map +1 -1
- package/dist/mcp-bundle.mjs +5862 -4939
- package/dist/plugin/loader.js +3 -2
- package/dist/plugin/loader.js.map +1 -1
- package/dist/plugin/registry.d.ts +26 -5
- package/dist/plugin/registry.d.ts.map +1 -1
- package/dist/plugin/registry.js +46 -18
- package/dist/plugin/registry.js.map +1 -1
- package/dist/plugin/sdk/constants.d.ts +2 -0
- package/dist/plugin/sdk/constants.d.ts.map +1 -1
- package/dist/plugin/sdk/constants.js +1 -0
- package/dist/plugin/sdk/constants.js.map +1 -1
- package/dist/plugin/sdk/types.d.ts +18 -4
- package/dist/plugin/sdk/types.d.ts.map +1 -1
- package/dist/plugin/sdk/types.js +1 -1
- package/dist/plugin/sdk/types.js.map +1 -1
- package/dist/plugin/validate.d.ts.map +1 -1
- package/dist/plugin/validate.js +17 -8
- package/dist/plugin/validate.js.map +1 -1
- package/dist/types/severity.d.ts +3 -0
- package/dist/types/severity.d.ts.map +1 -0
- package/dist/types/severity.js +2 -0
- package/dist/types/severity.js.map +1 -0
- package/dist/utils/atomicWrite.d.ts +23 -0
- package/dist/utils/atomicWrite.d.ts.map +1 -0
- package/dist/utils/atomicWrite.js +44 -0
- package/dist/utils/atomicWrite.js.map +1 -0
- package/dist/utils/concurrency.d.ts +17 -0
- package/dist/utils/concurrency.d.ts.map +1 -0
- package/dist/utils/concurrency.js +38 -0
- package/dist/utils/concurrency.js.map +1 -0
- package/dist/utils/config.d.ts +1 -0
- package/dist/utils/config.d.ts.map +1 -1
- package/dist/utils/config.js +44 -33
- package/dist/utils/config.js.map +1 -1
- package/dist/utils/encryption.d.ts.map +1 -1
- package/dist/utils/encryption.js +7 -2
- package/dist/utils/encryption.js.map +1 -1
- package/dist/utils/exitCode.d.ts +2 -0
- package/dist/utils/exitCode.d.ts.map +1 -0
- package/dist/utils/exitCode.js +4 -0
- package/dist/utils/exitCode.js.map +1 -0
- package/dist/utils/fileLock.d.ts.map +1 -1
- package/dist/utils/fileLock.js +177 -30
- package/dist/utils/fileLock.js.map +1 -1
- package/dist/utils/fsMtime.d.ts +32 -0
- package/dist/utils/fsMtime.d.ts.map +1 -0
- package/dist/utils/fsMtime.js +61 -0
- package/dist/utils/fsMtime.js.map +1 -0
- package/dist/utils/fsRetry.d.ts +20 -0
- package/dist/utils/fsRetry.d.ts.map +1 -0
- package/dist/utils/fsRetry.js +56 -0
- package/dist/utils/fsRetry.js.map +1 -0
- package/dist/utils/logger.d.ts +1 -1
- package/dist/utils/logger.d.ts.map +1 -1
- package/dist/utils/logger.js +8 -3
- package/dist/utils/logger.js.map +1 -1
- package/dist/utils/openBrowser.d.ts.map +1 -1
- package/dist/utils/openBrowser.js +3 -2
- package/dist/utils/openBrowser.js.map +1 -1
- package/dist/utils/platform.d.ts +2 -0
- package/dist/utils/platform.d.ts.map +1 -0
- package/dist/utils/platform.js +2 -0
- package/dist/utils/platform.js.map +1 -0
- package/dist/utils/secureWrite.d.ts +1 -0
- package/dist/utils/secureWrite.d.ts.map +1 -1
- package/dist/utils/secureWrite.js +8 -2
- package/dist/utils/secureWrite.js.map +1 -1
- package/dist/utils/securityLogger.d.ts.map +1 -1
- package/dist/utils/securityLogger.js +16 -4
- package/dist/utils/securityLogger.js.map +1 -1
- package/dist/utils/ssh.d.ts +2 -1
- package/dist/utils/ssh.d.ts.map +1 -1
- package/dist/utils/ssh.js +14 -4
- package/dist/utils/ssh.js.map +1 -1
- package/dist/utils/version.d.ts +5 -0
- package/dist/utils/version.d.ts.map +1 -1
- package/dist/utils/version.js +26 -0
- package/dist/utils/version.js.map +1 -1
- package/dist/utils/webhookSecurity.d.ts +13 -0
- package/dist/utils/webhookSecurity.d.ts.map +1 -0
- package/dist/utils/webhookSecurity.js +130 -0
- package/dist/utils/webhookSecurity.js.map +1 -0
- package/kastell-plugin/.claude-plugin/plugin.json +2 -2
- package/kastell-plugin/README.md +6 -0
- package/package.json +3 -4
package/dist/utils/config.js
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
import { readFileSync
|
|
1
|
+
import { readFileSync } from "fs";
|
|
2
2
|
import { join } from "path";
|
|
3
3
|
import { withFileLock } from "./fileLock.js";
|
|
4
4
|
import { KASTELL_DIR } from "./paths.js";
|
|
5
5
|
import { SUPPORTED_PROVIDERS } from "../constants.js";
|
|
6
|
-
import { secureMkdirSync
|
|
6
|
+
import { secureMkdirSync } from "./secureWrite.js";
|
|
7
|
+
import { atomicWriteFileSync } from "./atomicWrite.js";
|
|
8
|
+
import { memoizeOnStat } from "./fsMtime.js";
|
|
7
9
|
const SERVERS_FILE = join(KASTELL_DIR, "servers.json");
|
|
8
10
|
export function getServersRaw() {
|
|
9
11
|
// Same as getServers but without mode default — for migration use only
|
|
@@ -19,47 +21,56 @@ function ensureConfigDir() {
|
|
|
19
21
|
}
|
|
20
22
|
/** Atomic write: write to tmp file, then rename to prevent corruption on crash */
|
|
21
23
|
export function atomicWriteServers(servers) {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
24
|
+
atomicWriteFileSync(SERVERS_FILE, JSON.stringify(servers, null, 2));
|
|
25
|
+
}
|
|
26
|
+
const serversCache = new Map();
|
|
27
|
+
export function clearServersCache() {
|
|
28
|
+
serversCache.clear();
|
|
25
29
|
}
|
|
26
30
|
export function getServers() {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
catch (err) {
|
|
32
|
-
if (err.code === "ENOENT") {
|
|
33
|
-
return [];
|
|
31
|
+
return memoizeOnStat(serversCache, SERVERS_FILE, SERVERS_FILE, () => {
|
|
32
|
+
let data;
|
|
33
|
+
try {
|
|
34
|
+
data = readFileSync(SERVERS_FILE, "utf-8");
|
|
34
35
|
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
}
|
|
41
|
-
catch {
|
|
42
|
-
throw new Error("servers.json corrupt (invalid JSON) — check ~/.kastell/servers.json manually");
|
|
43
|
-
}
|
|
44
|
-
if (!Array.isArray(parsed)) {
|
|
45
|
-
throw new Error("servers.json corrupt — check ~/.kastell/servers.json manually");
|
|
46
|
-
}
|
|
47
|
-
const validProviders = new Set(SUPPORTED_PROVIDERS);
|
|
48
|
-
const validRecords = parsed.filter((s) => {
|
|
49
|
-
if (s.provider && !validProviders.has(s.provider)) {
|
|
50
|
-
process.stderr.write(`Warning: skipping server "${s.name}" — unknown provider "${s.provider}"\n`);
|
|
51
|
-
return false;
|
|
36
|
+
catch (err) {
|
|
37
|
+
if (err.code === "ENOENT") {
|
|
38
|
+
return [];
|
|
39
|
+
}
|
|
40
|
+
throw err;
|
|
52
41
|
}
|
|
53
|
-
|
|
42
|
+
let parsed;
|
|
43
|
+
try {
|
|
44
|
+
parsed = JSON.parse(data);
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
throw new Error("servers.json corrupt (invalid JSON) — check ~/.kastell/servers.json manually");
|
|
48
|
+
}
|
|
49
|
+
if (!Array.isArray(parsed)) {
|
|
50
|
+
throw new Error("servers.json corrupt — check ~/.kastell/servers.json manually");
|
|
51
|
+
}
|
|
52
|
+
const validProviders = new Set(SUPPORTED_PROVIDERS);
|
|
53
|
+
const validRecords = parsed.filter((s) => {
|
|
54
|
+
if (s.provider && !validProviders.has(s.provider)) {
|
|
55
|
+
process.stderr.write(`Warning: skipping server "${s.name}" — unknown provider "${s.provider}"\n`);
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
return true;
|
|
59
|
+
});
|
|
60
|
+
return validRecords.map((s) => ({ ...s, mode: s.mode ?? "coolify" }));
|
|
54
61
|
});
|
|
55
|
-
|
|
56
|
-
|
|
62
|
+
}
|
|
63
|
+
function isSentinelIp(ip) {
|
|
64
|
+
return ip === "" || ip === "pending" || ip === "0.0.0.0";
|
|
57
65
|
}
|
|
58
66
|
export async function saveServer(record) {
|
|
59
67
|
await withFileLock(SERVERS_FILE, () => {
|
|
60
68
|
ensureConfigDir();
|
|
61
69
|
const servers = getServers();
|
|
62
|
-
const duplicate = servers.find((
|
|
70
|
+
const duplicate = servers.find((server) => server.name === record.name ||
|
|
71
|
+
(!isSentinelIp(record.ip) &&
|
|
72
|
+
!isSentinelIp(server.ip) &&
|
|
73
|
+
server.ip === record.ip));
|
|
63
74
|
if (duplicate) {
|
|
64
75
|
throw new Error(`Server already exists: ${duplicate.name === record.name ? `name "${record.name}"` : `IP ${record.ip}`}`);
|
|
65
76
|
}
|
package/dist/utils/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/utils/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/utils/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"encryption.d.ts","sourceRoot":"","sources":["../../src/utils/encryption.ts"],"names":[],"mappings":"AAWA,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,IAAI,CAAC;IAChB,OAAO,EAAE,CAAC,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;CACb;AAID,wBAAgB,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,gBAAgB,CAa5E;AAED,wBAAgB,WAAW,CAAC,OAAO,EAAE,gBAAgB,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAe1E;AAID,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,OAAO,GAAG,GAAG,IAAI,gBAAgB,CAIxE;
|
|
1
|
+
{"version":3,"file":"encryption.d.ts","sourceRoot":"","sources":["../../src/utils/encryption.ts"],"names":[],"mappings":"AAWA,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,IAAI,CAAC;IAChB,OAAO,EAAE,CAAC,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;CACb;AAID,wBAAgB,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,gBAAgB,CAa5E;AAED,wBAAgB,WAAW,CAAC,OAAO,EAAE,gBAAgB,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAe1E;AAID,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,OAAO,GAAG,GAAG,IAAI,gBAAgB,CAIxE;AA2DD,wBAAgB,aAAa,IAAI,MAAM,CAMtC"}
|
package/dist/utils/encryption.js
CHANGED
|
@@ -56,9 +56,14 @@ function getOrCreatePersistedValue(filePath, generate) {
|
|
|
56
56
|
return readFileSync(filePath, "utf8").trim();
|
|
57
57
|
}
|
|
58
58
|
}
|
|
59
|
-
catch (error) {
|
|
60
|
-
|
|
59
|
+
catch (error) {
|
|
60
|
+
// File exists but unreadable (e.g. EPERM on Windows) — do NOT fall back to
|
|
61
|
+
// random UUID here. That would produce a DIFFERENT encryption key each call,
|
|
62
|
+
// breaking decryption of tokens.json. Use in-memory fallback instead.
|
|
63
|
+
debugLog?.("encryption primary method failed, using in-memory fallback", { cause: error });
|
|
64
|
+
return generate();
|
|
61
65
|
}
|
|
66
|
+
// File does not exist — create it
|
|
62
67
|
ensureKastellDir();
|
|
63
68
|
const value = generate();
|
|
64
69
|
secureWriteFileSync(filePath, value);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"encryption.js","sourceRoot":"","sources":["../../src/utils/encryption.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,gBAAgB,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAC/F,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AAC9C,OAAO,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AACxE,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC1C,OAAO,EAAE,QAAQ,EAAE,MAAM,IAAI,CAAC;AAC9B,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAYvC,gFAAgF;AAEhF,MAAM,UAAU,WAAW,CAAC,SAAiB,EAAE,GAAW;IACxD,MAAM,EAAE,GAAG,WAAW,CAAC,EAAE,CAAC,CAAC;IAC3B,MAAM,MAAM,GAAG,cAAc,CAAC,aAAa,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC;IACtD,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;IACpF,MAAM,GAAG,GAAG,MAAM,CAAC,UAAU,EAAE,CAAC;IAEhC,OAAO;QACL,SAAS,EAAE,IAAI;QACf,OAAO,EAAE,CAAC;QACV,EAAE,EAAE,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC;QACtB,IAAI,EAAE,SAAS,CAAC,QAAQ,CAAC,KAAK,CAAC;QAC/B,GAAG,EAAE,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC;KACzB,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,OAAyB,EAAE,GAAW;IAChE,IAAI,CAAC;QACH,MAAM,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;QAC1C,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QAC9C,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;QAE5C,MAAM,QAAQ,GAAG,gBAAgB,CAAC,aAAa,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC;QAC1D,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;QACzB,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;QAC3E,OAAO,SAAS,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IACpC,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CACb,6HAA6H,CAC9H,CAAC;IACJ,CAAC;AACH,CAAC;AAED,gFAAgF;AAEhF,MAAM,UAAU,kBAAkB,CAAC,GAAY;IAC7C,IAAI,GAAG,KAAK,IAAI,IAAI,GAAG,KAAK,SAAS,IAAI,OAAO,GAAG,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IAC/E,MAAM,CAAC,GAAG,GAA8B,CAAC;IACzC,OAAO,CAAC,CAAC,SAAS,KAAK,IAAI,IAAI,OAAO,CAAC,CAAC,OAAO,KAAK,QAAQ,CAAC;AAC/D,CAAC;AAED,gFAAgF;AAEhF,MAAM,SAAS,GAAG,IAAI,CAAC,WAAW,EAAE,kBAAkB,CAAC,CAAC;AACxD,MAAM,gBAAgB,GAAG,IAAI,CAAC,WAAW,EAAE,aAAa,CAAC,CAAC;AAE1D,IAAI,UAAU,GAAkB,IAAI,CAAC;AAErC,SAAS,gBAAgB;IACvB,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC;QAAE,eAAe,CAAC,WAAW,CAAC,CAAC;AAC7D,CAAC;AAED,qEAAqE;AACrE,SAAS,yBAAyB,CAAC,QAAgB,EAAE,QAAsB;IACzE,IAAI,CAAC;QACH,IAAI,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YACzB,OAAO,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC;QAC/C,CAAC;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC,
|
|
1
|
+
{"version":3,"file":"encryption.js","sourceRoot":"","sources":["../../src/utils/encryption.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,gBAAgB,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAC/F,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AAC9C,OAAO,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AACxE,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC1C,OAAO,EAAE,QAAQ,EAAE,MAAM,IAAI,CAAC;AAC9B,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAYvC,gFAAgF;AAEhF,MAAM,UAAU,WAAW,CAAC,SAAiB,EAAE,GAAW;IACxD,MAAM,EAAE,GAAG,WAAW,CAAC,EAAE,CAAC,CAAC;IAC3B,MAAM,MAAM,GAAG,cAAc,CAAC,aAAa,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC;IACtD,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;IACpF,MAAM,GAAG,GAAG,MAAM,CAAC,UAAU,EAAE,CAAC;IAEhC,OAAO;QACL,SAAS,EAAE,IAAI;QACf,OAAO,EAAE,CAAC;QACV,EAAE,EAAE,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC;QACtB,IAAI,EAAE,SAAS,CAAC,QAAQ,CAAC,KAAK,CAAC;QAC/B,GAAG,EAAE,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC;KACzB,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,OAAyB,EAAE,GAAW;IAChE,IAAI,CAAC;QACH,MAAM,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;QAC1C,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QAC9C,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;QAE5C,MAAM,QAAQ,GAAG,gBAAgB,CAAC,aAAa,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC;QAC1D,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;QACzB,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;QAC3E,OAAO,SAAS,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IACpC,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CACb,6HAA6H,CAC9H,CAAC;IACJ,CAAC;AACH,CAAC;AAED,gFAAgF;AAEhF,MAAM,UAAU,kBAAkB,CAAC,GAAY;IAC7C,IAAI,GAAG,KAAK,IAAI,IAAI,GAAG,KAAK,SAAS,IAAI,OAAO,GAAG,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IAC/E,MAAM,CAAC,GAAG,GAA8B,CAAC;IACzC,OAAO,CAAC,CAAC,SAAS,KAAK,IAAI,IAAI,OAAO,CAAC,CAAC,OAAO,KAAK,QAAQ,CAAC;AAC/D,CAAC;AAED,gFAAgF;AAEhF,MAAM,SAAS,GAAG,IAAI,CAAC,WAAW,EAAE,kBAAkB,CAAC,CAAC;AACxD,MAAM,gBAAgB,GAAG,IAAI,CAAC,WAAW,EAAE,aAAa,CAAC,CAAC;AAE1D,IAAI,UAAU,GAAkB,IAAI,CAAC;AAErC,SAAS,gBAAgB;IACvB,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC;QAAE,eAAe,CAAC,WAAW,CAAC,CAAC;AAC7D,CAAC;AAED,qEAAqE;AACrE,SAAS,yBAAyB,CAAC,QAAgB,EAAE,QAAsB;IACzE,IAAI,CAAC;QACH,IAAI,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YACzB,OAAO,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC;QAC/C,CAAC;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,2EAA2E;QAC3E,6EAA6E;QAC7E,sEAAsE;QACtE,QAAQ,EAAE,CAAC,4DAA4D,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;QAC3F,OAAO,QAAQ,EAAE,CAAC;IACpB,CAAC;IACD,kCAAkC;IAClC,gBAAgB,EAAE,CAAC;IACnB,MAAM,KAAK,GAAG,QAAQ,EAAE,CAAC;IACzB,mBAAmB,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;IACrC,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,eAAe;IACtB,MAAM,IAAI,GAAG,QAAQ,EAAE,CAAC;IAExB,IAAI,CAAC;QACH,IAAI,IAAI,KAAK,OAAO,EAAE,CAAC;YACrB,OAAO,YAAY,CAAC,iBAAiB,EAAE,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC;QACxD,CAAC;QAED,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;YACtB,MAAM,MAAM,GAAG,SAAS,CAAC,OAAO,EAAE,CAAC,MAAM,EAAE,IAAI,EAAE,wBAAwB,CAAC,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC;YAClG,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,sCAAsC,CAAC,CAAC;YAC3E,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC;gBAAE,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QACzC,CAAC;QAED,IAAI,IAAI,KAAK,OAAO,EAAE,CAAC;YACrB,MAAM,MAAM,GAAG,SAAS,CAAC,KAAK,EAAE,CAAC,OAAO,EAAE,yCAAyC,EAAE,IAAI,EAAE,aAAa,CAAC,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC;YACjI,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,6BAA6B,CAAC,CAAC;YAClE,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC;gBAAE,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QACzC,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,2BAA2B;IAC7B,CAAC;IAED,OAAO,yBAAyB,CAAC,gBAAgB,EAAE,GAAG,EAAE,CAAC,UAAU,EAAE,CAAC,CAAC;AACzE,CAAC;AAED,MAAM,UAAU,aAAa;IAC3B,IAAI,UAAU;QAAE,OAAO,UAAU,CAAC;IAClC,MAAM,SAAS,GAAG,eAAe,EAAE,CAAC;IACpC,MAAM,IAAI,GAAG,yBAAyB,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;IACzF,UAAU,GAAG,UAAU,CAAC,SAAS,EAAE,IAAI,EAAE,EAAE,CAAW,CAAC;IACvD,OAAO,UAAU,CAAC;AACpB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exitCode.d.ts","sourceRoot":"","sources":["../../src/utils/exitCode.ts"],"names":[],"mappings":"AAAA,wBAAgB,iBAAiB,IAAI,IAAI,CAExC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exitCode.js","sourceRoot":"","sources":["../../src/utils/exitCode.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,iBAAiB;IAC/B,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;AACvB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fileLock.d.ts","sourceRoot":"","sources":["../../src/utils/fileLock.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"fileLock.d.ts","sourceRoot":"","sources":["../../src/utils/fileLock.ts"],"names":[],"mappings":"AAgCA,2EAA2E;AAC3E,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,SAAS,CAStE;AAoBD,KAAK,OAAO,GAAG,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,GAAG,MAAM,GAAG,SAAS,CAAC;AAkJ7D,wBAAsB,YAAY,CAAC,CAAC,EAClC,QAAQ,EAAE,MAAM,EAChB,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,EACxB,KAAK,GAAE,OAAsB,GAC5B,OAAO,CAAC,CAAC,CAAC,CAuFZ;AAED,yGAAyG;AACzG,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAO1E"}
|
package/dist/utils/fileLock.js
CHANGED
|
@@ -1,9 +1,27 @@
|
|
|
1
1
|
import { mkdirSync, rmSync, statSync, writeFileSync, readFileSync } from "fs";
|
|
2
2
|
import { dirname, join } from "path";
|
|
3
3
|
import { hostname } from "os";
|
|
4
|
+
import { createHash } from "crypto";
|
|
5
|
+
import { DEFAULT_PERMISSION_RETRY_ATTEMPTS, DEFAULT_PERMISSION_RETRY_DELAY_MS, retryOnPermission } from "./fsRetry.js";
|
|
4
6
|
const STALE_THRESHOLD_MS = 30_000;
|
|
5
7
|
// Reclaim even when probeProcess reports "alive" (guards against clock drift, zombies, PID reuse).
|
|
6
8
|
const HARD_CEILING_MS = 60_000;
|
|
9
|
+
function removeLockDirBestEffort(lockDir) {
|
|
10
|
+
try {
|
|
11
|
+
retryOnPermission(() => rmSync(lockDir, { recursive: true, force: true }), {
|
|
12
|
+
attempts: DEFAULT_PERMISSION_RETRY_ATTEMPTS,
|
|
13
|
+
delayMs: DEFAULT_PERMISSION_RETRY_DELAY_MS,
|
|
14
|
+
});
|
|
15
|
+
return { removed: true };
|
|
16
|
+
}
|
|
17
|
+
catch (error) {
|
|
18
|
+
return {
|
|
19
|
+
removed: false,
|
|
20
|
+
error,
|
|
21
|
+
errorCode: error.code,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
}
|
|
7
25
|
/** Module-local wrapper for testability — DO NOT inline `process.kill`. */
|
|
8
26
|
export function probeProcess(pid) {
|
|
9
27
|
try {
|
|
@@ -32,62 +50,157 @@ function readPidFile(lockDir) {
|
|
|
32
50
|
return null;
|
|
33
51
|
}
|
|
34
52
|
}
|
|
35
|
-
function
|
|
53
|
+
function assessLockState(lockDir, probe) {
|
|
36
54
|
let mtimeMs;
|
|
37
55
|
try {
|
|
38
56
|
mtimeMs = statSync(lockDir).mtimeMs;
|
|
39
57
|
}
|
|
40
58
|
catch {
|
|
41
|
-
return
|
|
59
|
+
return null; // lock disappeared between checks
|
|
42
60
|
}
|
|
43
61
|
const age = Date.now() - mtimeMs;
|
|
44
62
|
const parsed = readPidFile(lockDir);
|
|
63
|
+
let reclaimable;
|
|
45
64
|
if (parsed && parsed.host === hostname()) {
|
|
46
65
|
const liveness = probe(parsed.pid);
|
|
47
66
|
if (liveness === "dead")
|
|
48
|
-
|
|
49
|
-
if (liveness === "alive")
|
|
50
|
-
|
|
67
|
+
reclaimable = true;
|
|
68
|
+
else if (liveness === "alive")
|
|
69
|
+
reclaimable = age > HARD_CEILING_MS;
|
|
51
70
|
// "unknown" → mtime fallback (aggressive: STALE_THRESHOLD_MS)
|
|
71
|
+
else
|
|
72
|
+
reclaimable = age > STALE_THRESHOLD_MS;
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
// farklı hostname, parse fail, veya PID file yok → mtime fallback
|
|
76
|
+
reclaimable = age > STALE_THRESHOLD_MS;
|
|
77
|
+
}
|
|
78
|
+
return { mtimeMs, parsed, reclaimable };
|
|
79
|
+
}
|
|
80
|
+
function deriveProcessState(assessment, probe) {
|
|
81
|
+
if (!assessment.parsed)
|
|
82
|
+
return "not-probed";
|
|
83
|
+
if (assessment.parsed.host !== hostname())
|
|
84
|
+
return "not-probed";
|
|
85
|
+
return probe(assessment.parsed.pid);
|
|
86
|
+
}
|
|
87
|
+
function hashPid(pid) {
|
|
88
|
+
return `hash:${createHash("sha256").update(String(pid)).digest("hex").slice(0, 8)}`;
|
|
89
|
+
}
|
|
90
|
+
function collectLockDiagnostic(lockDir, probe, options) {
|
|
91
|
+
const result = {
|
|
92
|
+
lockDir,
|
|
93
|
+
ageMs: "unknown",
|
|
94
|
+
ownerPid: "unknown",
|
|
95
|
+
ownerHost: "unknown",
|
|
96
|
+
processState: "not-probed",
|
|
97
|
+
stale: "unknown",
|
|
98
|
+
reclaimAttempted: options.reclaimAttempted,
|
|
99
|
+
reclaimErrorCode: options.lastReclaimErrorCode,
|
|
100
|
+
retries: options.retries,
|
|
101
|
+
totalWaitMs: options.totalWaitMs,
|
|
102
|
+
};
|
|
103
|
+
// If caller pre-assessed, reuse — avoid re-statSync / re-readFileSync / re-probe.
|
|
104
|
+
const assessment = options.preAssessed;
|
|
105
|
+
let age;
|
|
106
|
+
let parsed;
|
|
107
|
+
if (assessment) {
|
|
108
|
+
age = Date.now() - assessment.mtimeMs;
|
|
109
|
+
result.ageMs = age;
|
|
110
|
+
parsed = assessment.parsed;
|
|
111
|
+
if (parsed) {
|
|
112
|
+
result.ownerPid = hashPid(parsed.pid);
|
|
113
|
+
result.ownerHost = "internal";
|
|
114
|
+
}
|
|
115
|
+
result.processState = deriveProcessState(assessment, probe);
|
|
52
116
|
}
|
|
53
|
-
|
|
54
|
-
|
|
117
|
+
else {
|
|
118
|
+
let mtimeMs;
|
|
119
|
+
try {
|
|
120
|
+
mtimeMs = statSync(lockDir).mtimeMs;
|
|
121
|
+
}
|
|
122
|
+
catch {
|
|
123
|
+
// statSync failed — keep age/stale unknown
|
|
124
|
+
return result;
|
|
125
|
+
}
|
|
126
|
+
age = Date.now() - mtimeMs;
|
|
127
|
+
result.ageMs = age;
|
|
128
|
+
parsed = readPidFile(lockDir);
|
|
129
|
+
if (parsed) {
|
|
130
|
+
result.ownerPid = hashPid(parsed.pid);
|
|
131
|
+
result.ownerHost = "internal";
|
|
132
|
+
}
|
|
133
|
+
result.processState = deriveProcessState({ mtimeMs, parsed, reclaimable: false }, probe);
|
|
134
|
+
}
|
|
135
|
+
// staleness — mirrors assessLockState's reclaimable decision.
|
|
136
|
+
if (parsed && parsed.host === hostname()) {
|
|
137
|
+
if (result.processState === "dead")
|
|
138
|
+
result.stale = true;
|
|
139
|
+
else if (result.processState === "alive")
|
|
140
|
+
result.stale = age > HARD_CEILING_MS;
|
|
141
|
+
else
|
|
142
|
+
result.stale = age > STALE_THRESHOLD_MS;
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
result.stale = age > STALE_THRESHOLD_MS;
|
|
146
|
+
}
|
|
147
|
+
return result;
|
|
148
|
+
}
|
|
149
|
+
function formatLockDiagnostic(filePath, diagnostic) {
|
|
150
|
+
const reclaimError = diagnostic.reclaimErrorCode ?? "none";
|
|
151
|
+
return [
|
|
152
|
+
`Could not acquire lock on ${filePath} after ${diagnostic.retries} retries ` +
|
|
153
|
+
`(${diagnostic.totalWaitMs}ms).`,
|
|
154
|
+
`lock=${diagnostic.lockDir}`,
|
|
155
|
+
`ageMs=${diagnostic.ageMs}`,
|
|
156
|
+
`ownerPid=${diagnostic.ownerPid}`,
|
|
157
|
+
`ownerHost=${diagnostic.ownerHost}`,
|
|
158
|
+
`processState=${diagnostic.processState}`,
|
|
159
|
+
`stale=${diagnostic.stale}`,
|
|
160
|
+
`reclaimAttempted=${diagnostic.reclaimAttempted}`,
|
|
161
|
+
`reclaimError=${reclaimError}`,
|
|
162
|
+
"Close other Kastell processes, then remove the stale lock only after verifying no writer is active.",
|
|
163
|
+
].join(" ");
|
|
55
164
|
}
|
|
56
165
|
export async function withFileLock(filePath, fn, probe = probeProcess) {
|
|
57
166
|
const lockDir = filePath + ".lock";
|
|
58
167
|
const maxRetries = 10;
|
|
59
168
|
const retryDelay = 200;
|
|
60
169
|
mkdirSync(dirname(lockDir), { recursive: true });
|
|
61
|
-
|
|
170
|
+
// Track the last assessment so the exhaust path can reuse it instead of
|
|
171
|
+
// re-running statSync / readPidFile / probe (Reuse-F7, Efficiency-F2).
|
|
172
|
+
let lastAssessment = null;
|
|
173
|
+
const runWithAcquiredLock = async () => {
|
|
62
174
|
try {
|
|
63
|
-
mkdirSync(lockDir);
|
|
64
175
|
try {
|
|
65
|
-
|
|
66
|
-
writeFileSync(join(lockDir, "owner.pid"), `${process.pid}@${hostname()}@${Date.now()}`, { encoding: "utf-8" });
|
|
67
|
-
}
|
|
68
|
-
catch {
|
|
69
|
-
/* best effort — if PID write fails, mtime fallback still protects */
|
|
70
|
-
}
|
|
71
|
-
return await fn();
|
|
176
|
+
writeFileSync(join(lockDir, "owner.pid"), `${process.pid}@${hostname()}@${Date.now()}`, { encoding: "utf-8" });
|
|
72
177
|
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
rmSync(lockDir, { recursive: true, force: true });
|
|
76
|
-
}
|
|
77
|
-
catch {
|
|
78
|
-
/* best effort */
|
|
79
|
-
}
|
|
178
|
+
catch {
|
|
179
|
+
/* best effort — if PID write fails, mtime fallback still protects */
|
|
80
180
|
}
|
|
181
|
+
return await fn();
|
|
182
|
+
}
|
|
183
|
+
finally {
|
|
184
|
+
removeLockDirBestEffort(lockDir);
|
|
185
|
+
}
|
|
186
|
+
};
|
|
187
|
+
for (let i = 0; i < maxRetries; i++) {
|
|
188
|
+
try {
|
|
189
|
+
mkdirSync(lockDir);
|
|
190
|
+
return await runWithAcquiredLock();
|
|
81
191
|
}
|
|
82
192
|
catch (err) {
|
|
83
193
|
if (err.code === "EEXIST") {
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
194
|
+
const assessment = assessLockState(lockDir, probe);
|
|
195
|
+
lastAssessment = assessment;
|
|
196
|
+
if (assessment?.reclaimable) {
|
|
197
|
+
const removal = removeLockDirBestEffort(lockDir);
|
|
198
|
+
if (removal.removed) {
|
|
199
|
+
continue;
|
|
90
200
|
}
|
|
201
|
+
// Stale and tried to reclaim, but failed — keep looping so next iteration
|
|
202
|
+
// can collect a richer diagnostic if retries also exhaust.
|
|
203
|
+
await new Promise((r) => setTimeout(r, retryDelay));
|
|
91
204
|
continue;
|
|
92
205
|
}
|
|
93
206
|
await new Promise((r) => setTimeout(r, retryDelay));
|
|
@@ -96,7 +209,41 @@ export async function withFileLock(filePath, fn, probe = probeProcess) {
|
|
|
96
209
|
throw err;
|
|
97
210
|
}
|
|
98
211
|
}
|
|
99
|
-
|
|
212
|
+
// Exhausted: reuse the last assessment and attempt a final best-effort reclaim
|
|
213
|
+
// to surface the rmSync error code in the diagnostic.
|
|
214
|
+
let reclaimAttempted = false;
|
|
215
|
+
let lastReclaimError;
|
|
216
|
+
let lastReclaimErrorCode;
|
|
217
|
+
if (lastAssessment?.reclaimable) {
|
|
218
|
+
reclaimAttempted = true;
|
|
219
|
+
const removal = removeLockDirBestEffort(lockDir);
|
|
220
|
+
if (removal.removed) {
|
|
221
|
+
try {
|
|
222
|
+
mkdirSync(lockDir);
|
|
223
|
+
return await runWithAcquiredLock();
|
|
224
|
+
}
|
|
225
|
+
catch (error) {
|
|
226
|
+
if (error.code !== "EEXIST") {
|
|
227
|
+
throw error;
|
|
228
|
+
}
|
|
229
|
+
lastAssessment = assessLockState(lockDir, probe);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
else {
|
|
233
|
+
lastReclaimError = removal.error;
|
|
234
|
+
lastReclaimErrorCode = removal.errorCode;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
const diagnostic = collectLockDiagnostic(lockDir, probe, {
|
|
238
|
+
reclaimAttempted,
|
|
239
|
+
lastReclaimErrorCode,
|
|
240
|
+
retries: maxRetries,
|
|
241
|
+
totalWaitMs: maxRetries * retryDelay,
|
|
242
|
+
preAssessed: lastAssessment ?? undefined,
|
|
243
|
+
});
|
|
244
|
+
throw new Error(formatLockDiagnostic(filePath, diagnostic), {
|
|
245
|
+
cause: lastReclaimError,
|
|
246
|
+
});
|
|
100
247
|
}
|
|
101
248
|
/** Warn on stderr if a caught error is a permission issue. Returns true if it was a permission error. */
|
|
102
249
|
export function warnIfPermissionError(err, label) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fileLock.js","sourceRoot":"","sources":["../../src/utils/fileLock.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,IAAI,CAAC;AAC9E,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AACrC,OAAO,EAAE,QAAQ,EAAE,MAAM,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"fileLock.js","sourceRoot":"","sources":["../../src/utils/fileLock.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/** Stat key: mtime + dev (dev guards against network FS remount per LESSONS) */
|
|
2
|
+
export interface StatKey {
|
|
3
|
+
mtime: number;
|
|
4
|
+
dev: number;
|
|
5
|
+
}
|
|
6
|
+
/** Cached entry: the stat key at compute-time + the computed value */
|
|
7
|
+
export interface MemoizedEntry<T> {
|
|
8
|
+
statKey: StatKey | null;
|
|
9
|
+
value: T;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Read file stat, returning a comparable key or null on ENOENT/I-O error.
|
|
13
|
+
* Single syscall — replaces existsSync + statSync pattern.
|
|
14
|
+
*/
|
|
15
|
+
export declare function statKey(filePath: string): StatKey | null;
|
|
16
|
+
/**
|
|
17
|
+
* Memoize a computation against a file's stat key. If the file's mtime/dev
|
|
18
|
+
* is unchanged since the last call, returns the cached value. Otherwise,
|
|
19
|
+
* runs compute() and caches the result.
|
|
20
|
+
*
|
|
21
|
+
* `cacheKey` distinguishes entries (caller composes — e.g. `filePath + '::' + serverIp`
|
|
22
|
+
* for per-server caches, or just `filePath` for single-entry files). `filePath` is the
|
|
23
|
+
* file to stat for invalidation — it can equal `cacheKey` for simple cases.
|
|
24
|
+
*
|
|
25
|
+
* `options.maxSize` opts the cache into bounded LRU semantics: once `cache.size`
|
|
26
|
+
* exceeds `maxSize`, the least-recently-used entry is evicted. Hits promote to
|
|
27
|
+
* MRU. Default (omitted) leaves the cache unbounded (back-compat).
|
|
28
|
+
*/
|
|
29
|
+
export declare function memoizeOnStat<T>(cache: Map<string, MemoizedEntry<T>>, cacheKey: string, filePath: string, compute: () => T, options?: {
|
|
30
|
+
maxSize?: number;
|
|
31
|
+
}): T;
|
|
32
|
+
//# sourceMappingURL=fsMtime.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fsMtime.d.ts","sourceRoot":"","sources":["../../src/utils/fsMtime.ts"],"names":[],"mappings":"AAEA,gFAAgF;AAChF,MAAM,WAAW,OAAO;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;CACb;AAED,sEAAsE;AACtE,MAAM,WAAW,aAAa,CAAC,CAAC;IAC9B,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC;IACxB,KAAK,EAAE,CAAC,CAAC;CACV;AAED;;;GAGG;AACH,wBAAgB,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI,CAOxD;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,aAAa,CAAC,CAAC,EAC7B,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC,EACpC,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,CAAC,EAChB,OAAO,CAAC,EAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,GAC7B,CAAC,CAqCH"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { statSync } from "fs";
|
|
2
|
+
/**
|
|
3
|
+
* Read file stat, returning a comparable key or null on ENOENT/I-O error.
|
|
4
|
+
* Single syscall — replaces existsSync + statSync pattern.
|
|
5
|
+
*/
|
|
6
|
+
export function statKey(filePath) {
|
|
7
|
+
try {
|
|
8
|
+
const s = statSync(filePath);
|
|
9
|
+
return { mtime: s.mtimeMs, dev: s.dev };
|
|
10
|
+
}
|
|
11
|
+
catch {
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Memoize a computation against a file's stat key. If the file's mtime/dev
|
|
17
|
+
* is unchanged since the last call, returns the cached value. Otherwise,
|
|
18
|
+
* runs compute() and caches the result.
|
|
19
|
+
*
|
|
20
|
+
* `cacheKey` distinguishes entries (caller composes — e.g. `filePath + '::' + serverIp`
|
|
21
|
+
* for per-server caches, or just `filePath` for single-entry files). `filePath` is the
|
|
22
|
+
* file to stat for invalidation — it can equal `cacheKey` for simple cases.
|
|
23
|
+
*
|
|
24
|
+
* `options.maxSize` opts the cache into bounded LRU semantics: once `cache.size`
|
|
25
|
+
* exceeds `maxSize`, the least-recently-used entry is evicted. Hits promote to
|
|
26
|
+
* MRU. Default (omitted) leaves the cache unbounded (back-compat).
|
|
27
|
+
*/
|
|
28
|
+
export function memoizeOnStat(cache, cacheKey, filePath, compute, options) {
|
|
29
|
+
const current = statKey(filePath);
|
|
30
|
+
const cached = cache.get(cacheKey);
|
|
31
|
+
const isHit = cached !== undefined &&
|
|
32
|
+
((cached.statKey === null && current === null) ||
|
|
33
|
+
(current !== null &&
|
|
34
|
+
cached.statKey !== null &&
|
|
35
|
+
cached.statKey.mtime === current.mtime &&
|
|
36
|
+
cached.statKey.dev === current.dev));
|
|
37
|
+
if (isHit) {
|
|
38
|
+
// MRU promote: only when LRU is active (preserves unbounded back-compat).
|
|
39
|
+
if (options?.maxSize !== undefined) {
|
|
40
|
+
cache.delete(cacheKey);
|
|
41
|
+
cache.set(cacheKey, cached);
|
|
42
|
+
}
|
|
43
|
+
return cached.value;
|
|
44
|
+
}
|
|
45
|
+
const value = compute();
|
|
46
|
+
// Re-insert at MRU position when LRU active so insertion order = recency.
|
|
47
|
+
if (options?.maxSize !== undefined) {
|
|
48
|
+
cache.delete(cacheKey);
|
|
49
|
+
}
|
|
50
|
+
cache.set(cacheKey, { statKey: current, value });
|
|
51
|
+
if (options?.maxSize !== undefined) {
|
|
52
|
+
while (cache.size > options.maxSize) {
|
|
53
|
+
const oldest = cache.keys().next().value;
|
|
54
|
+
if (oldest === undefined)
|
|
55
|
+
break;
|
|
56
|
+
cache.delete(oldest);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return value;
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=fsMtime.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fsMtime.js","sourceRoot":"","sources":["../../src/utils/fsMtime.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,IAAI,CAAC;AAc9B;;;GAGG;AACH,MAAM,UAAU,OAAO,CAAC,QAAgB;IACtC,IAAI,CAAC;QACH,MAAM,CAAC,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAC;QAC7B,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC;IAC1C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,aAAa,CAC3B,KAAoC,EACpC,QAAgB,EAChB,QAAgB,EAChB,OAAgB,EAChB,OAA8B;IAE9B,MAAM,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IAClC,MAAM,MAAM,GAAG,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IAEnC,MAAM,KAAK,GACT,MAAM,KAAK,SAAS;QACpB,CAAC,CAAC,MAAM,CAAC,OAAO,KAAK,IAAI,IAAI,OAAO,KAAK,IAAI,CAAC;YAC5C,CAAC,OAAO,KAAK,IAAI;gBACf,MAAM,CAAC,OAAO,KAAK,IAAI;gBACvB,MAAM,CAAC,OAAO,CAAC,KAAK,KAAK,OAAO,CAAC,KAAK;gBACtC,MAAM,CAAC,OAAO,CAAC,GAAG,KAAK,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC;IAE3C,IAAI,KAAK,EAAE,CAAC;QACV,0EAA0E;QAC1E,IAAI,OAAO,EAAE,OAAO,KAAK,SAAS,EAAE,CAAC;YACnC,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;YACvB,KAAK,CAAC,GAAG,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;QAC9B,CAAC;QACD,OAAO,MAAM,CAAC,KAAK,CAAC;IACtB,CAAC;IAED,MAAM,KAAK,GAAG,OAAO,EAAE,CAAC;IACxB,0EAA0E;IAC1E,IAAI,OAAO,EAAE,OAAO,KAAK,SAAS,EAAE,CAAC;QACnC,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IACzB,CAAC;IACD,KAAK,CAAC,GAAG,CAAC,QAAQ,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;IAEjD,IAAI,OAAO,EAAE,OAAO,KAAK,SAAS,EAAE,CAAC;QACnC,OAAO,KAAK,CAAC,IAAI,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;YACpC,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC;YACzC,IAAI,MAAM,KAAK,SAAS;gBAAE,MAAM;YAChC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QACvB,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/** Default retry budget for transient permission errors — used by atomic write, file lock, and security log. */
|
|
2
|
+
export declare const DEFAULT_PERMISSION_RETRY_ATTEMPTS = 3;
|
|
3
|
+
/** Default sync sleep between retries (10ms is enough to ride out most scanner holds). */
|
|
4
|
+
export declare const DEFAULT_PERMISSION_RETRY_DELAY_MS = 10;
|
|
5
|
+
export declare function isPermissionError(err: unknown): boolean;
|
|
6
|
+
/** Synchronous sleep using Atomics.wait. ms <= 0 returns immediately. */
|
|
7
|
+
export declare function sleepSync(ms: number): void;
|
|
8
|
+
/** Best-effort `unlinkSync` that silently swallows all errors (file may already be gone). */
|
|
9
|
+
export declare function unlinkBestEffort(path: string): void;
|
|
10
|
+
export interface RetryOptions {
|
|
11
|
+
attempts: number;
|
|
12
|
+
delayMs: number;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Run `fn` up to `attempts` times, retrying only on transient permission errors.
|
|
16
|
+
* Throws the first non-permission error. Re-throws the last permission error
|
|
17
|
+
* if all attempts fail.
|
|
18
|
+
*/
|
|
19
|
+
export declare function retryOnPermission<T>(fn: () => T, { attempts, delayMs }: RetryOptions): T;
|
|
20
|
+
//# sourceMappingURL=fsRetry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fsRetry.d.ts","sourceRoot":"","sources":["../../src/utils/fsRetry.ts"],"names":[],"mappings":"AAeA,gHAAgH;AAChH,eAAO,MAAM,iCAAiC,IAAI,CAAC;AACnD,0FAA0F;AAC1F,eAAO,MAAM,iCAAiC,KAAK,CAAC;AAEpD,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAEvD;AAED,yEAAyE;AACzE,wBAAgB,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAG1C;AAED,6FAA6F;AAC7F,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAMnD;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,CAAC,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,EAAE,YAAY,GAAG,CAAC,CAYxF"}
|