peri-fuse 0.1.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/dist/commands/logs.js +101 -0
- package/dist/commands/restart.js +33 -0
- package/dist/commands/start.js +35 -0
- package/dist/commands/status.js +35 -0
- package/dist/commands/stop.js +22 -0
- package/dist/drizzle/0000_init.sql +160 -0
- package/dist/drizzle/meta/0000_snapshot.json +1101 -0
- package/dist/drizzle/meta/_journal.json +13 -0
- package/dist/index.js +86 -0
- package/dist/lib/daemon.js +187 -0
- package/dist/lib/output.js +48 -0
- package/dist/lib/paths.js +131 -0
- package/dist/server.cjs +151674 -0
- package/drizzle/0000_free_bucky.sql +1128 -0
- package/drizzle/meta/0000_snapshot.json +8072 -0
- package/drizzle/meta/_journal.json +13 -0
- package/package.json +40 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
4
|
+
if (k2 === undefined) k2 = k;
|
|
5
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
6
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
7
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
8
|
+
}
|
|
9
|
+
Object.defineProperty(o, k2, desc);
|
|
10
|
+
}) : (function(o, m, k, k2) {
|
|
11
|
+
if (k2 === undefined) k2 = k;
|
|
12
|
+
o[k2] = m[k];
|
|
13
|
+
}));
|
|
14
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
15
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
16
|
+
}) : function(o, v) {
|
|
17
|
+
o["default"] = v;
|
|
18
|
+
});
|
|
19
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
20
|
+
var ownKeys = function(o) {
|
|
21
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
22
|
+
var ar = [];
|
|
23
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
24
|
+
return ar;
|
|
25
|
+
};
|
|
26
|
+
return ownKeys(o);
|
|
27
|
+
};
|
|
28
|
+
return function (mod) {
|
|
29
|
+
if (mod && mod.__esModule) return mod;
|
|
30
|
+
var result = {};
|
|
31
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
32
|
+
__setModuleDefault(result, mod);
|
|
33
|
+
return result;
|
|
34
|
+
};
|
|
35
|
+
})();
|
|
36
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
37
|
+
/**
|
|
38
|
+
* Peri-Fuse CLI entry point.
|
|
39
|
+
*
|
|
40
|
+
* Manages the background observability server as a detached daemon.
|
|
41
|
+
* Commands: start / stop / restart / status / logs.
|
|
42
|
+
*/
|
|
43
|
+
const commander_1 = require("commander");
|
|
44
|
+
const fs = __importStar(require("node:fs"));
|
|
45
|
+
const path = __importStar(require("node:path"));
|
|
46
|
+
const logs_1 = require("./commands/logs");
|
|
47
|
+
const restart_1 = require("./commands/restart");
|
|
48
|
+
const start_1 = require("./commands/start");
|
|
49
|
+
const status_1 = require("./commands/status");
|
|
50
|
+
const stop_1 = require("./commands/stop");
|
|
51
|
+
const pkg = JSON.parse(fs.readFileSync(path.join(__dirname, "..", "package.json"), "utf8"));
|
|
52
|
+
const program = new commander_1.Command();
|
|
53
|
+
program
|
|
54
|
+
.name("peri-fuse")
|
|
55
|
+
.description("Manage the Peri-Fuse background observability server")
|
|
56
|
+
.version(pkg.version);
|
|
57
|
+
program
|
|
58
|
+
.command("start")
|
|
59
|
+
.description("Start the server as a background daemon")
|
|
60
|
+
.action(start_1.startCommand);
|
|
61
|
+
program
|
|
62
|
+
.command("stop")
|
|
63
|
+
.description("Stop the background server")
|
|
64
|
+
.action(stop_1.stopCommand);
|
|
65
|
+
program
|
|
66
|
+
.command("restart")
|
|
67
|
+
.description("Restart the background server")
|
|
68
|
+
.action(restart_1.restartCommand);
|
|
69
|
+
program
|
|
70
|
+
.command("status")
|
|
71
|
+
.description("Show whether the server is running")
|
|
72
|
+
.action(status_1.statusCommand);
|
|
73
|
+
program
|
|
74
|
+
.command("logs")
|
|
75
|
+
.description("View server logs")
|
|
76
|
+
.option("-n, --lines <number>", "Number of lines to show", "50")
|
|
77
|
+
.option("-f, --follow", "Follow log output")
|
|
78
|
+
.action(logs_1.logsCommand);
|
|
79
|
+
// No subcommand given: print help and exit cleanly (code 0) instead of erroring.
|
|
80
|
+
program.action(() => {
|
|
81
|
+
program.outputHelp();
|
|
82
|
+
});
|
|
83
|
+
program.parseAsync(process.argv).catch((err) => {
|
|
84
|
+
console.error(err);
|
|
85
|
+
process.exit(1);
|
|
86
|
+
});
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.isAlive = isAlive;
|
|
37
|
+
exports.getRunningState = getRunningState;
|
|
38
|
+
exports.startServer = startServer;
|
|
39
|
+
exports.stopServer = stopServer;
|
|
40
|
+
exports.waitForHealthy = waitForHealthy;
|
|
41
|
+
exports.checkHealth = checkHealth;
|
|
42
|
+
/**
|
|
43
|
+
* Daemon management — spawn/stop/inspect the background server process.
|
|
44
|
+
*
|
|
45
|
+
* The server runs as a detached child process so the CLI can exit while the
|
|
46
|
+
* server keeps running. State (pid/port/startedAt/logFile) is persisted to
|
|
47
|
+
* <root>/.peri-fuse/server.json; combined stdout/stderr goes to server.log.
|
|
48
|
+
*/
|
|
49
|
+
const node_child_process_1 = require("node:child_process");
|
|
50
|
+
const fs = __importStar(require("node:fs"));
|
|
51
|
+
const dotenv = __importStar(require("dotenv"));
|
|
52
|
+
const paths_1 = require("./paths");
|
|
53
|
+
const DEFAULT_PORT = 23332;
|
|
54
|
+
/** Check whether a process with the given pid is alive. */
|
|
55
|
+
function isAlive(pid) {
|
|
56
|
+
try {
|
|
57
|
+
process.kill(pid, 0);
|
|
58
|
+
return true;
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
/** Read state and confirm the recorded process is actually running. */
|
|
65
|
+
function getRunningState() {
|
|
66
|
+
const state = (0, paths_1.readState)();
|
|
67
|
+
if (!state)
|
|
68
|
+
return null;
|
|
69
|
+
if (!isAlive(state.pid))
|
|
70
|
+
return null;
|
|
71
|
+
return state;
|
|
72
|
+
}
|
|
73
|
+
/** Resolve the port to use, honoring LITE_SERVER_PORT and .env. */
|
|
74
|
+
function resolvePort(env) {
|
|
75
|
+
const raw = env.LITE_SERVER_PORT ?? process.env.LITE_SERVER_PORT;
|
|
76
|
+
const parsed = raw ? parseInt(raw, 10) : DEFAULT_PORT;
|
|
77
|
+
return Number.isFinite(parsed) && parsed > 0 ? parsed : DEFAULT_PORT;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Start the server as a detached background process.
|
|
81
|
+
* Returns the runtime state, or indicates it was already running.
|
|
82
|
+
*/
|
|
83
|
+
function startServer() {
|
|
84
|
+
const existing = getRunningState();
|
|
85
|
+
if (existing) {
|
|
86
|
+
return { state: existing, alreadyRunning: true };
|
|
87
|
+
}
|
|
88
|
+
const entry = (0, paths_1.serverEntry)();
|
|
89
|
+
if (!fs.existsSync(entry)) {
|
|
90
|
+
throw new Error(`Server build not found at ${entry}\n Run "pnpm build" first to compile the server.`);
|
|
91
|
+
}
|
|
92
|
+
(0, paths_1.ensureRuntimeDir)();
|
|
93
|
+
// Load .env from project root (server does not read it itself).
|
|
94
|
+
const dotenvEnv = {};
|
|
95
|
+
const envPath = (0, paths_1.envFile)();
|
|
96
|
+
if (fs.existsSync(envPath)) {
|
|
97
|
+
const parsed = dotenv.parse(fs.readFileSync(envPath, "utf8"));
|
|
98
|
+
Object.assign(dotenvEnv, parsed);
|
|
99
|
+
}
|
|
100
|
+
const mergedEnv = { ...process.env, ...dotenvEnv };
|
|
101
|
+
const port = resolvePort(mergedEnv);
|
|
102
|
+
const log = (0, paths_1.logFile)();
|
|
103
|
+
const out = fs.openSync(log, "a");
|
|
104
|
+
const child = (0, node_child_process_1.spawn)(process.execPath, [entry], {
|
|
105
|
+
detached: true,
|
|
106
|
+
stdio: ["ignore", out, out],
|
|
107
|
+
cwd: (0, paths_1.findProjectRoot)(),
|
|
108
|
+
env: { ...mergedEnv, LITE_SERVER_PORT: String(port) },
|
|
109
|
+
});
|
|
110
|
+
fs.closeSync(out);
|
|
111
|
+
if (child.pid == null) {
|
|
112
|
+
throw new Error("Failed to spawn server process (no pid returned).");
|
|
113
|
+
}
|
|
114
|
+
const state = {
|
|
115
|
+
pid: child.pid,
|
|
116
|
+
port,
|
|
117
|
+
startedAt: Date.now(),
|
|
118
|
+
logFile: log,
|
|
119
|
+
};
|
|
120
|
+
(0, paths_1.writeState)(state);
|
|
121
|
+
child.unref();
|
|
122
|
+
return { state, alreadyRunning: false };
|
|
123
|
+
}
|
|
124
|
+
function sleep(ms) {
|
|
125
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Stop the background server. Sends SIGTERM, waits for exit, escalates to
|
|
129
|
+
* SIGKILL on timeout, then clears the state file.
|
|
130
|
+
*/
|
|
131
|
+
async function stopServer(timeoutMs = 8000) {
|
|
132
|
+
const state = (0, paths_1.readState)();
|
|
133
|
+
if (!state) {
|
|
134
|
+
return { stopped: false, wasRunning: false };
|
|
135
|
+
}
|
|
136
|
+
if (!isAlive(state.pid)) {
|
|
137
|
+
// Stale state — clean up.
|
|
138
|
+
(0, paths_1.clearState)();
|
|
139
|
+
return { stopped: false, wasRunning: false };
|
|
140
|
+
}
|
|
141
|
+
process.kill(state.pid, "SIGTERM");
|
|
142
|
+
const deadline = Date.now() + timeoutMs;
|
|
143
|
+
while (Date.now() < deadline) {
|
|
144
|
+
if (!isAlive(state.pid)) {
|
|
145
|
+
(0, paths_1.clearState)();
|
|
146
|
+
return { stopped: true, wasRunning: true };
|
|
147
|
+
}
|
|
148
|
+
await sleep(200);
|
|
149
|
+
}
|
|
150
|
+
// Escalate.
|
|
151
|
+
try {
|
|
152
|
+
process.kill(state.pid, "SIGKILL");
|
|
153
|
+
}
|
|
154
|
+
catch {
|
|
155
|
+
/* already gone */
|
|
156
|
+
}
|
|
157
|
+
await sleep(300);
|
|
158
|
+
(0, paths_1.clearState)();
|
|
159
|
+
return { stopped: true, wasRunning: true };
|
|
160
|
+
}
|
|
161
|
+
/** Poll the server health endpoint until it responds OK or times out. */
|
|
162
|
+
async function waitForHealthy(port, timeoutMs = 10000) {
|
|
163
|
+
const url = `http://localhost:${port}/api/public/health`;
|
|
164
|
+
const deadline = Date.now() + timeoutMs;
|
|
165
|
+
while (Date.now() < deadline) {
|
|
166
|
+
try {
|
|
167
|
+
const res = await fetch(url);
|
|
168
|
+
if (res.ok)
|
|
169
|
+
return true;
|
|
170
|
+
}
|
|
171
|
+
catch {
|
|
172
|
+
/* not up yet */
|
|
173
|
+
}
|
|
174
|
+
await sleep(300);
|
|
175
|
+
}
|
|
176
|
+
return false;
|
|
177
|
+
}
|
|
178
|
+
/** One-shot health check (no retry). */
|
|
179
|
+
async function checkHealth(port) {
|
|
180
|
+
try {
|
|
181
|
+
const res = await fetch(`http://localhost:${port}/api/public/health`);
|
|
182
|
+
return res.ok;
|
|
183
|
+
}
|
|
184
|
+
catch {
|
|
185
|
+
return false;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.output = void 0;
|
|
7
|
+
exports.formatUptime = formatUptime;
|
|
8
|
+
/**
|
|
9
|
+
* Colored console output helpers for the Peri-Fuse CLI.
|
|
10
|
+
*/
|
|
11
|
+
const picocolors_1 = __importDefault(require("picocolors"));
|
|
12
|
+
exports.output = {
|
|
13
|
+
info(msg) {
|
|
14
|
+
console.log(picocolors_1.default.cyan("ℹ"), msg);
|
|
15
|
+
},
|
|
16
|
+
success(msg) {
|
|
17
|
+
console.log(picocolors_1.default.green("✔"), msg);
|
|
18
|
+
},
|
|
19
|
+
warn(msg) {
|
|
20
|
+
console.log(picocolors_1.default.yellow("⚠"), msg);
|
|
21
|
+
},
|
|
22
|
+
error(msg) {
|
|
23
|
+
console.error(picocolors_1.default.red("✖"), msg);
|
|
24
|
+
},
|
|
25
|
+
dim(msg) {
|
|
26
|
+
console.log(picocolors_1.default.dim(msg));
|
|
27
|
+
},
|
|
28
|
+
plain(msg) {
|
|
29
|
+
console.log(msg);
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
/** Format a millisecond duration into a human-readable string. */
|
|
33
|
+
function formatUptime(ms) {
|
|
34
|
+
const sec = Math.floor(ms / 1000);
|
|
35
|
+
const d = Math.floor(sec / 86400);
|
|
36
|
+
const h = Math.floor((sec % 86400) / 3600);
|
|
37
|
+
const m = Math.floor((sec % 3600) / 60);
|
|
38
|
+
const s = sec % 60;
|
|
39
|
+
const parts = [];
|
|
40
|
+
if (d)
|
|
41
|
+
parts.push(`${d}d`);
|
|
42
|
+
if (h)
|
|
43
|
+
parts.push(`${h}h`);
|
|
44
|
+
if (m)
|
|
45
|
+
parts.push(`${m}m`);
|
|
46
|
+
parts.push(`${s}s`);
|
|
47
|
+
return parts.join(" ");
|
|
48
|
+
}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.findProjectRoot = findProjectRoot;
|
|
37
|
+
exports.runtimeDir = runtimeDir;
|
|
38
|
+
exports.stateFile = stateFile;
|
|
39
|
+
exports.logFile = logFile;
|
|
40
|
+
exports.serverEntry = serverEntry;
|
|
41
|
+
exports.envFile = envFile;
|
|
42
|
+
exports.ensureRuntimeDir = ensureRuntimeDir;
|
|
43
|
+
exports.readState = readState;
|
|
44
|
+
exports.writeState = writeState;
|
|
45
|
+
exports.clearState = clearState;
|
|
46
|
+
/**
|
|
47
|
+
* Path resolution for the Peri-Fuse CLI.
|
|
48
|
+
*
|
|
49
|
+
* Locates the monorepo root (by walking up to `pnpm-workspace.yaml`), the
|
|
50
|
+
* server entry point, and the runtime directory used for the PID/state file
|
|
51
|
+
* and server logs. Mirrors the `findProjectRoot` logic in the server's env.ts
|
|
52
|
+
* so data directories resolve identically.
|
|
53
|
+
*/
|
|
54
|
+
const fs = __importStar(require("node:fs"));
|
|
55
|
+
const os = __importStar(require("node:os"));
|
|
56
|
+
const path = __importStar(require("node:path"));
|
|
57
|
+
let cachedRoot = null;
|
|
58
|
+
/** Walk up from the CLI package until we find the monorepo root. */
|
|
59
|
+
function findProjectRoot() {
|
|
60
|
+
if (cachedRoot)
|
|
61
|
+
return cachedRoot;
|
|
62
|
+
let dir = __dirname;
|
|
63
|
+
while (dir !== path.dirname(dir)) {
|
|
64
|
+
if (fs.existsSync(path.join(dir, "pnpm-workspace.yaml"))) {
|
|
65
|
+
cachedRoot = dir;
|
|
66
|
+
return dir;
|
|
67
|
+
}
|
|
68
|
+
dir = path.dirname(dir);
|
|
69
|
+
}
|
|
70
|
+
// Fallback to cwd if no workspace marker found.
|
|
71
|
+
cachedRoot = process.cwd();
|
|
72
|
+
return cachedRoot;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Global data/runtime directory. Shared with the server and gateway so the
|
|
76
|
+
* PID/state file, logs, databases and salt all live in one place, independent
|
|
77
|
+
* of the repo location. Override with PERIFUSE_HOME. Defaults to ~/.peri-fuse.
|
|
78
|
+
*/
|
|
79
|
+
function runtimeDir() {
|
|
80
|
+
return process.env.PERIFUSE_HOME || path.join(os.homedir(), ".peri-fuse");
|
|
81
|
+
}
|
|
82
|
+
/** State file: ~/.peri-fuse/server.json */
|
|
83
|
+
function stateFile() {
|
|
84
|
+
return path.join(runtimeDir(), "server.json");
|
|
85
|
+
}
|
|
86
|
+
/** Log file: ~/.peri-fuse/server.log */
|
|
87
|
+
function logFile() {
|
|
88
|
+
return path.join(runtimeDir(), "server.log");
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Server entry point.
|
|
92
|
+
* - Published package: bundled dist/server.cjs (self-contained).
|
|
93
|
+
* - Monorepo dev: falls back to <root>/packages/server/dist/index.js.
|
|
94
|
+
*/
|
|
95
|
+
function serverEntry() {
|
|
96
|
+
const bundled = path.join(__dirname, "server.cjs");
|
|
97
|
+
if (fs.existsSync(bundled))
|
|
98
|
+
return bundled;
|
|
99
|
+
return path.join(findProjectRoot(), "packages", "server", "dist", "index.js");
|
|
100
|
+
}
|
|
101
|
+
/** Path to the project root .env file (may not exist). */
|
|
102
|
+
function envFile() {
|
|
103
|
+
return path.join(findProjectRoot(), ".env");
|
|
104
|
+
}
|
|
105
|
+
function ensureRuntimeDir() {
|
|
106
|
+
const dir = runtimeDir();
|
|
107
|
+
if (!fs.existsSync(dir)) {
|
|
108
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
function readState() {
|
|
112
|
+
const file = stateFile();
|
|
113
|
+
if (!fs.existsSync(file))
|
|
114
|
+
return null;
|
|
115
|
+
try {
|
|
116
|
+
return JSON.parse(fs.readFileSync(file, "utf8"));
|
|
117
|
+
}
|
|
118
|
+
catch {
|
|
119
|
+
return null;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
function writeState(state) {
|
|
123
|
+
ensureRuntimeDir();
|
|
124
|
+
fs.writeFileSync(stateFile(), JSON.stringify(state, null, 2), "utf8");
|
|
125
|
+
}
|
|
126
|
+
function clearState() {
|
|
127
|
+
const file = stateFile();
|
|
128
|
+
if (fs.existsSync(file)) {
|
|
129
|
+
fs.unlinkSync(file);
|
|
130
|
+
}
|
|
131
|
+
}
|