@jskit-ai/kernel 0.1.222 → 0.1.224
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/package.json
CHANGED
package/server/http/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
export { createCapabilityHttpRuntime } from "./capabilityHttpRuntime.js";
|
|
2
2
|
export { HttpProvider } from "./HttpProvider.js";
|
|
3
|
+
export { attachDirectRequestActionExecutor } from "./directRequestActionExecutor.js";
|
|
3
4
|
export { createCachedResponseSerializerFactory } from "./responseSerializerFactory.js";
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import { constants as fsConstants } from "node:fs";
|
|
3
|
+
import { open } from "node:fs/promises";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
|
|
6
|
+
const FILE_LOCK_ERROR_CODE = "file_lock_failed";
|
|
7
|
+
|
|
8
|
+
function fileLockError(message = "", code = FILE_LOCK_ERROR_CODE) {
|
|
9
|
+
const error = new Error(message || "Exclusive file lock failed.");
|
|
10
|
+
error.code = code;
|
|
11
|
+
return error;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function normalizedAbsolutePath(value = "", label = "path", errorCode = FILE_LOCK_ERROR_CODE) {
|
|
15
|
+
const normalized = String(value || "").trim();
|
|
16
|
+
if (!normalized || !path.isAbsolute(normalized) || path.normalize(normalized) !== normalized) {
|
|
17
|
+
throw fileLockError(`${label} must be a normalized absolute path.`, errorCode);
|
|
18
|
+
}
|
|
19
|
+
return normalized;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
async function tryAcquireExclusiveFileLock(lockPath = "", {
|
|
23
|
+
cwd = "",
|
|
24
|
+
errorCode = FILE_LOCK_ERROR_CODE
|
|
25
|
+
} = {}) {
|
|
26
|
+
const normalizedLockPath = normalizedAbsolutePath(lockPath, "lockPath", errorCode);
|
|
27
|
+
const normalizedCwd = cwd
|
|
28
|
+
? normalizedAbsolutePath(cwd, "cwd", errorCode)
|
|
29
|
+
: path.dirname(normalizedLockPath);
|
|
30
|
+
const lockHandle = await open(
|
|
31
|
+
normalizedLockPath,
|
|
32
|
+
fsConstants.O_CREAT | fsConstants.O_NOFOLLOW | fsConstants.O_RDWR,
|
|
33
|
+
0o660
|
|
34
|
+
);
|
|
35
|
+
let child = null;
|
|
36
|
+
let stderr = "";
|
|
37
|
+
let closed = Promise.resolve({ code: null, signal: null });
|
|
38
|
+
try {
|
|
39
|
+
child = spawn(
|
|
40
|
+
"/bin/sh",
|
|
41
|
+
[
|
|
42
|
+
"-c",
|
|
43
|
+
"/usr/bin/flock --exclusive --nonblock 3 || exit 1; " +
|
|
44
|
+
"printf 'locked\\n'; IFS= read -r _ || true"
|
|
45
|
+
],
|
|
46
|
+
{
|
|
47
|
+
cwd: normalizedCwd,
|
|
48
|
+
env: { PATH: "/usr/bin:/bin" },
|
|
49
|
+
stdio: ["pipe", "pipe", "pipe", lockHandle.fd]
|
|
50
|
+
}
|
|
51
|
+
);
|
|
52
|
+
closed = new Promise((resolve) => {
|
|
53
|
+
child.once("close", (code, signal) => resolve({ code, signal }));
|
|
54
|
+
});
|
|
55
|
+
const acquired = await new Promise((resolve, reject) => {
|
|
56
|
+
let output = "";
|
|
57
|
+
let settled = false;
|
|
58
|
+
const settle = (callback, value) => {
|
|
59
|
+
if (settled) {
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
settled = true;
|
|
63
|
+
callback(value);
|
|
64
|
+
};
|
|
65
|
+
child.once("error", (error) => settle(reject, error));
|
|
66
|
+
child.stderr.on("data", (chunk) => {
|
|
67
|
+
stderr = `${stderr}${String(chunk || "")}`.slice(-4096);
|
|
68
|
+
});
|
|
69
|
+
child.stdout.on("data", (chunk) => {
|
|
70
|
+
output += String(chunk || "");
|
|
71
|
+
if (output.includes("\n")) {
|
|
72
|
+
settle(resolve, true);
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
child.once("exit", (code) => {
|
|
76
|
+
if (code === 1) {
|
|
77
|
+
settle(resolve, false);
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
settle(reject, fileLockError(
|
|
81
|
+
`Exclusive file lock process failed${stderr ? `: ${stderr.trim()}` : "."}`, errorCode
|
|
82
|
+
));
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
if (!acquired) {
|
|
86
|
+
await lockHandle.close();
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
let released = false;
|
|
91
|
+
return async () => {
|
|
92
|
+
if (released) {
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
released = true;
|
|
96
|
+
try {
|
|
97
|
+
child.stdin.end("release\n");
|
|
98
|
+
const result = await closed;
|
|
99
|
+
if (result.code !== 0) {
|
|
100
|
+
throw fileLockError(
|
|
101
|
+
`Exclusive file lock process exited unexpectedly${stderr ? `: ${stderr.trim()}` : "."}`, errorCode
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
} finally {
|
|
105
|
+
await lockHandle.close();
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
} catch (error) {
|
|
109
|
+
child?.stdin?.destroy();
|
|
110
|
+
child?.kill?.("SIGTERM");
|
|
111
|
+
await closed;
|
|
112
|
+
await lockHandle.close().catch(() => null);
|
|
113
|
+
if (error?.code === errorCode) {
|
|
114
|
+
throw error;
|
|
115
|
+
}
|
|
116
|
+
throw fileLockError(error?.message || String(error || "Exclusive file lock failed."), errorCode);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export {
|
|
121
|
+
FILE_LOCK_ERROR_CODE,
|
|
122
|
+
tryAcquireExclusiveFileLock
|
|
123
|
+
};
|
package/server/support/index.js
CHANGED
|
@@ -131,6 +131,7 @@ const BARREL_EXPECTATIONS = Object.freeze([
|
|
|
131
131
|
filePath: path.join(REPO_ROOT, "packages", "kernel", "server", "http", "index.js"),
|
|
132
132
|
expectedExports: Object.freeze([
|
|
133
133
|
"HttpProvider",
|
|
134
|
+
"attachDirectRequestActionExecutor",
|
|
134
135
|
"createCachedResponseSerializerFactory",
|
|
135
136
|
"createCapabilityHttpRuntime"
|
|
136
137
|
])
|