bgrun 3.12.11 → 3.12.13

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.
Files changed (50) hide show
  1. package/README.md +2 -2
  2. package/dashboard/app/api/config/[name]/route.ts +1 -1
  3. package/dashboard/app/api/debug/route.ts +1 -1
  4. package/dashboard/app/api/dependencies/route.ts +40 -40
  5. package/dashboard/app/api/deploy/[name]/route.ts +1 -1
  6. package/dashboard/app/api/deploy-all/route.ts +25 -25
  7. package/dashboard/app/api/deps/route.ts +3 -3
  8. package/dashboard/app/api/guard/route.ts +1 -1
  9. package/dashboard/app/api/guard-all/route.ts +1 -1
  10. package/dashboard/app/api/guard-events/route.ts +4 -4
  11. package/dashboard/app/api/history/route.ts +105 -105
  12. package/dashboard/app/api/logs/[name]/route.ts +100 -100
  13. package/dashboard/app/api/logs/rotate/route.ts +2 -2
  14. package/dashboard/app/api/next-port/route.ts +32 -32
  15. package/dashboard/app/api/processes/[name]/route.ts +2 -2
  16. package/dashboard/app/api/processes/route.ts +4 -4
  17. package/dashboard/app/api/restart/[name]/route.ts +2 -2
  18. package/dashboard/app/api/start/route.ts +2 -2
  19. package/dashboard/app/api/stop/[name]/route.ts +2 -2
  20. package/dashboard/app/api/templates/route.ts +46 -46
  21. package/dashboard/app/api/version/route.ts +1 -1
  22. package/dashboard/lib/runtime.ts +49 -0
  23. package/dist/api.js +94 -67
  24. package/dist/deploy.js +1373 -0
  25. package/dist/deps.js +1004 -0
  26. package/dist/index.js +224 -224
  27. package/dist/log-rotation.js +95 -0
  28. package/dist/server.js +1488 -0
  29. package/package.json +2 -17
  30. package/src/api.ts +0 -63
  31. package/src/build.ts +0 -24
  32. package/src/commands/cleanup.ts +0 -141
  33. package/src/commands/details.ts +0 -60
  34. package/src/commands/list.ts +0 -133
  35. package/src/commands/logs.ts +0 -49
  36. package/src/commands/run.ts +0 -217
  37. package/src/commands/watch.ts +0 -223
  38. package/src/config.ts +0 -37
  39. package/src/db.ts +0 -422
  40. package/src/deploy.ts +0 -163
  41. package/src/deps.ts +0 -126
  42. package/src/guard.ts +0 -208
  43. package/src/index.ts +0 -623
  44. package/src/log-rotation.ts +0 -93
  45. package/src/logger.ts +0 -40
  46. package/src/platform.ts +0 -665
  47. package/src/server.ts +0 -217
  48. package/src/table.ts +0 -232
  49. package/src/types.ts +0 -14
  50. package/src/utils.ts +0 -96
@@ -1,32 +1,32 @@
1
- /**
2
- * GET /api/next-port — Find the next available port
3
- *
4
- * Scans existing processes' env for PORT= values,
5
- * then returns the next unused port starting from a base (default 3001).
6
- */
7
- import { getAllProcesses } from '../../../../src/db';
8
-
9
- export async function GET(req: Request) {
10
- const url = new URL(req.url);
11
- const base = parseInt(url.searchParams.get('base') || '3001') || 3001;
12
-
13
- const processes = getAllProcesses();
14
- const usedPorts = new Set<number>();
15
-
16
- for (const proc of processes) {
17
- // Parse PORT from env string (comma-separated KEY=VAL)
18
- const envStr = proc.env || '';
19
- const portMatch = envStr.match(/(?:^|,)PORT=(\d+)/);
20
- if (portMatch) {
21
- usedPorts.add(parseInt(portMatch[1]));
22
- }
23
- }
24
-
25
- // Find next available port
26
- let nextPort = base;
27
- while (usedPorts.has(nextPort)) {
28
- nextPort++;
29
- }
30
-
31
- return Response.json({ port: nextPort, usedPorts: Array.from(usedPorts).sort((a, b) => a - b) });
32
- }
1
+ /**
2
+ * GET /api/next-port — Find the next available port
3
+ *
4
+ * Scans existing processes' env for PORT= values,
5
+ * then returns the next unused port starting from a base (default 3001).
6
+ */
7
+ import { getAllProcesses } from '../../../lib/runtime';
8
+
9
+ export async function GET(req: Request) {
10
+ const url = new URL(req.url);
11
+ const base = parseInt(url.searchParams.get('base') || '3001') || 3001;
12
+
13
+ const processes = getAllProcesses();
14
+ const usedPorts = new Set<number>();
15
+
16
+ for (const proc of processes) {
17
+ // Parse PORT from env string (comma-separated KEY=VAL)
18
+ const envStr = proc.env || '';
19
+ const portMatch = envStr.match(/(?:^|,)PORT=(\d+)/);
20
+ if (portMatch) {
21
+ usedPorts.add(parseInt(portMatch[1]));
22
+ }
23
+ }
24
+
25
+ // Find next available port
26
+ let nextPort = base;
27
+ while (usedPorts.has(nextPort)) {
28
+ nextPort++;
29
+ }
30
+
31
+ return Response.json({ port: nextPort, usedPorts: Array.from(usedPorts).sort((a, b) => a - b) });
32
+ }
@@ -1,8 +1,8 @@
1
1
  /**
2
2
  * DELETE /api/processes/:name — Stop and remove a process
3
3
  */
4
- import { getProcess, removeProcessByName } from '../../../../../src/db';
5
- import { isProcessRunning, terminateProcess } from '../../../../../src/platform';
4
+ import { getProcess, removeProcessByName } from '../../../../lib/runtime';
5
+ import { isProcessRunning, terminateProcess } from '../../../../lib/runtime';
6
6
  import { measure } from 'measure-fn';
7
7
 
8
8
  export async function DELETE(req: Request, { params }: { params: { name: string } }) {
@@ -1,7 +1,7 @@
1
- import { getAllProcesses, updateProcessPid } from '../../../../src/db';
2
- import { calculateRuntime } from '../../../../src/utils';
3
- import { getProcessBatchResources, reconcileProcessPids } from '../../../../src/platform';
4
- import { guardRestartCounts } from '../../../../src/server';
1
+ import { getAllProcesses, updateProcessPid } from '../../../lib/runtime';
2
+ import { calculateRuntime } from '../../../lib/runtime';
3
+ import { getProcessBatchResources, reconcileProcessPids } from '../../../lib/runtime';
4
+ import { guardRestartCounts } from '../../../lib/runtime';
5
5
  import { measure, createMeasure } from 'measure-fn';
6
6
  import { $ } from 'bun';
7
7
 
@@ -1,8 +1,8 @@
1
1
  /**
2
2
  * POST /api/restart/:name — Force-restart a process
3
3
  */
4
- import { handleRun } from '../../../../../src/commands/run';
5
- import { addHistoryEntry, getProcess } from '../../../../../src/db';
4
+ import { handleRun } from '../../../../lib/runtime';
5
+ import { addHistoryEntry, getProcess } from '../../../../lib/runtime';
6
6
  import { measure } from 'measure-fn';
7
7
 
8
8
  export async function POST(req: Request, { params }: { params: { name: string } }) {
@@ -1,8 +1,8 @@
1
1
  /**
2
2
  * POST /api/start — Create or start a process
3
3
  */
4
- import { handleRun } from '../../../../src/commands/run';
5
- import { addHistoryEntry } from '../../../../src/db';
4
+ import { handleRun } from '../../../lib/runtime';
5
+ import { addHistoryEntry } from '../../../lib/runtime';
6
6
  import { measure } from 'measure-fn';
7
7
 
8
8
  export async function POST(req: Request) {
@@ -4,8 +4,8 @@
4
4
  * Kills the registered PID, then kills anything remaining on the port.
5
5
  * Sets PID to 0 to prevent reconciliation from hijacking unrelated processes.
6
6
  */
7
- import { getProcess, updateProcessPid, addHistoryEntry } from '../../../../../src/db';
8
- import { isProcessRunning, terminateProcess, getProcessPorts, killProcessOnPort } from '../../../../../src/platform';
7
+ import { getProcess, updateProcessPid, addHistoryEntry } from '../../../../lib/runtime';
8
+ import { isProcessRunning, terminateProcess, getProcessPorts, killProcessOnPort } from '../../../../lib/runtime';
9
9
  import { measure } from 'measure-fn';
10
10
 
11
11
  export async function POST(req: Request, { params }: { params: { name: string } }) {
@@ -1,47 +1,47 @@
1
- import { getAllTemplates, saveTemplate, deleteTemplate } from '../../../../src/db';
2
-
3
- export async function GET() {
4
- const templates = getAllTemplates();
5
- return Response.json(templates.map((t: any) => ({
6
- name: t.name,
7
- command: t.command,
8
- workdir: t.workdir,
9
- env: t.env,
10
- group: t.group,
11
- created_at: t.created_at,
12
- })));
13
- }
14
-
15
- export async function POST(req: Request) {
16
- try {
17
- const body = await req.json();
18
- const { name, command, workdir, env, group } = body;
19
-
20
- if (!name || !command) {
21
- return Response.json({ error: 'name and command are required' }, { status: 400 });
22
- }
23
-
24
- saveTemplate({ name, command, workdir, env, group });
25
- return Response.json({ success: true, name });
26
- } catch (err) {
27
- console.error('[api/templates] Error saving template:', err);
28
- return Response.json({ error: 'Failed to save template' }, { status: 500 });
29
- }
30
- }
31
-
32
- export async function DELETE(req: Request) {
33
- try {
34
- const url = new URL(req.url);
35
- const name = url.searchParams.get('name');
36
-
37
- if (!name) {
38
- return Response.json({ error: 'name is required' }, { status: 400 });
39
- }
40
-
41
- deleteTemplate(name);
42
- return Response.json({ success: true });
43
- } catch (err) {
44
- console.error('[api/templates] Error deleting template:', err);
45
- return Response.json({ error: 'Failed to delete template' }, { status: 500 });
46
- }
1
+ import { getAllTemplates, saveTemplate, deleteTemplate } from '../../../lib/runtime';
2
+
3
+ export async function GET() {
4
+ const templates = getAllTemplates();
5
+ return Response.json(templates.map((t: any) => ({
6
+ name: t.name,
7
+ command: t.command,
8
+ workdir: t.workdir,
9
+ env: t.env,
10
+ group: t.group,
11
+ created_at: t.created_at,
12
+ })));
13
+ }
14
+
15
+ export async function POST(req: Request) {
16
+ try {
17
+ const body = await req.json();
18
+ const { name, command, workdir, env, group } = body;
19
+
20
+ if (!name || !command) {
21
+ return Response.json({ error: 'name and command are required' }, { status: 400 });
22
+ }
23
+
24
+ saveTemplate({ name, command, workdir, env, group });
25
+ return Response.json({ success: true, name });
26
+ } catch (err) {
27
+ console.error('[api/templates] Error saving template:', err);
28
+ return Response.json({ error: 'Failed to save template' }, { status: 500 });
29
+ }
30
+ }
31
+
32
+ export async function DELETE(req: Request) {
33
+ try {
34
+ const url = new URL(req.url);
35
+ const name = url.searchParams.get('name');
36
+
37
+ if (!name) {
38
+ return Response.json({ error: 'name is required' }, { status: 400 });
39
+ }
40
+
41
+ deleteTemplate(name);
42
+ return Response.json({ success: true });
43
+ } catch (err) {
44
+ console.error('[api/templates] Error deleting template:', err);
45
+ return Response.json({ error: 'Failed to delete template' }, { status: 500 });
46
+ }
47
47
  }
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * GET /api/version — Return BGR version
3
3
  */
4
- import { getVersion } from '../../../../src/utils';
4
+ import { getVersion } from '../../../lib/runtime';
5
5
  import { measure } from 'measure-fn';
6
6
 
7
7
  export async function GET() {
@@ -0,0 +1,49 @@
1
+ export {
2
+ db,
3
+ getAllProcesses,
4
+ getProcess,
5
+ insertProcess,
6
+ removeProcess,
7
+ removeProcessByName,
8
+ removeAllProcesses,
9
+ updateProcessPid,
10
+ updateProcessEnv,
11
+ getAllTemplates,
12
+ saveTemplate,
13
+ deleteTemplate,
14
+ getProcessHistory,
15
+ getRecentHistory,
16
+ addHistoryEntry,
17
+ getDependencyGraph,
18
+ addDependency,
19
+ removeDependency,
20
+ getStartOrder,
21
+ getDbInfo,
22
+ dbPath,
23
+ bgrHome,
24
+ isProcessRunning,
25
+ terminateProcess,
26
+ readFileTail,
27
+ getProcessPorts,
28
+ findChildPid,
29
+ findPidByPort,
30
+ getShellCommand,
31
+ killProcessOnPort,
32
+ waitForPortFree,
33
+ ensureDir,
34
+ getHomeDir,
35
+ isWindows,
36
+ getProcessBatchResources,
37
+ getProcessMemory,
38
+ reconcileProcessPids,
39
+ handleRun,
40
+ getVersion,
41
+ calculateRuntime,
42
+ parseEnvString,
43
+ validateDirectory,
44
+ } from '../../dist/api.js'
45
+
46
+ export { deployProcess, deployAllProcesses } from '../../dist/deploy.js'
47
+ export { buildDepGraph } from '../../dist/deps.js'
48
+ export { rotateAllLogs } from '../../dist/log-rotation.js'
49
+ export { guardEvents, guardRestartCounts } from '../../dist/server.js'
package/dist/api.js CHANGED
@@ -828,41 +828,6 @@ var init_db = __esm(() => {
828
828
  });
829
829
  });
830
830
 
831
- // src/logger.ts
832
- import boxen from "boxen";
833
- import chalk from "chalk";
834
- function announce(message, title) {
835
- console.log(boxen(message, {
836
- padding: 1,
837
- margin: 1,
838
- borderColor: "green",
839
- title: title || "bgrun",
840
- titleAlignment: "center",
841
- borderStyle: "round"
842
- }));
843
- }
844
- function error(message) {
845
- const text = message instanceof Error ? message.stack || message.message : String(message);
846
- console.error(boxen(chalk.red(text), {
847
- padding: 1,
848
- margin: 1,
849
- borderColor: "red",
850
- title: "Error",
851
- titleAlignment: "center",
852
- borderStyle: "double"
853
- }));
854
- throw new BgrunError(text);
855
- }
856
- var BgrunError;
857
- var init_logger = __esm(() => {
858
- BgrunError = class BgrunError extends Error {
859
- constructor(message) {
860
- super(message);
861
- this.name = "BgrunError";
862
- }
863
- };
864
- });
865
-
866
831
  // src/utils.ts
867
832
  import * as fs2 from "fs";
868
833
  function parseEnvString(envString) {
@@ -942,37 +907,6 @@ var init_utils = __esm(() => {
942
907
  init_platform();
943
908
  });
944
909
 
945
- // src/config.ts
946
- function formatEnvKey(key) {
947
- return key.toUpperCase().replace(/\./g, "_");
948
- }
949
- function flattenConfig(obj, prefix = "") {
950
- return Object.keys(obj).reduce((acc, key) => {
951
- const value = obj[key];
952
- const newPrefix = prefix ? `${prefix}.${key}` : key;
953
- if (Array.isArray(value)) {
954
- value.forEach((item, index) => {
955
- const indexedPrefix = `${newPrefix}.${index}`;
956
- if (typeof item === "object" && item !== null) {
957
- Object.assign(acc, flattenConfig(item, indexedPrefix));
958
- } else {
959
- acc[formatEnvKey(indexedPrefix)] = String(item);
960
- }
961
- });
962
- } else if (typeof value === "object" && value !== null) {
963
- Object.assign(acc, flattenConfig(value, newPrefix));
964
- } else {
965
- acc[formatEnvKey(newPrefix)] = String(value);
966
- }
967
- return acc;
968
- }, {});
969
- }
970
- async function parseConfigFile(configPath) {
971
- const importPath = `${configPath}?t=${Date.now()}`;
972
- const parsedConfig = await import(importPath).then((m) => m.default);
973
- return flattenConfig(parsedConfig);
974
- }
975
-
976
910
  // src/deps.ts
977
911
  var exports_deps = {};
978
912
  __export(exports_deps, {
@@ -1062,6 +996,72 @@ var init_deps = __esm(() => {
1062
996
  init_utils();
1063
997
  });
1064
998
 
999
+ // src/logger.ts
1000
+ import boxen from "boxen";
1001
+ import chalk from "chalk";
1002
+ function announce(message, title) {
1003
+ console.log(boxen(message, {
1004
+ padding: 1,
1005
+ margin: 1,
1006
+ borderColor: "green",
1007
+ title: title || "bgrun",
1008
+ titleAlignment: "center",
1009
+ borderStyle: "round"
1010
+ }));
1011
+ }
1012
+ function error(message) {
1013
+ const text = message instanceof Error ? message.stack || message.message : String(message);
1014
+ console.error(boxen(chalk.red(text), {
1015
+ padding: 1,
1016
+ margin: 1,
1017
+ borderColor: "red",
1018
+ title: "Error",
1019
+ titleAlignment: "center",
1020
+ borderStyle: "double"
1021
+ }));
1022
+ throw new BgrunError(text);
1023
+ }
1024
+ var BgrunError;
1025
+ var init_logger = __esm(() => {
1026
+ BgrunError = class BgrunError extends Error {
1027
+ constructor(message) {
1028
+ super(message);
1029
+ this.name = "BgrunError";
1030
+ }
1031
+ };
1032
+ });
1033
+
1034
+ // src/config.ts
1035
+ function formatEnvKey(key) {
1036
+ return key.toUpperCase().replace(/\./g, "_");
1037
+ }
1038
+ function flattenConfig(obj, prefix = "") {
1039
+ return Object.keys(obj).reduce((acc, key) => {
1040
+ const value = obj[key];
1041
+ const newPrefix = prefix ? `${prefix}.${key}` : key;
1042
+ if (Array.isArray(value)) {
1043
+ value.forEach((item, index) => {
1044
+ const indexedPrefix = `${newPrefix}.${index}`;
1045
+ if (typeof item === "object" && item !== null) {
1046
+ Object.assign(acc, flattenConfig(item, indexedPrefix));
1047
+ } else {
1048
+ acc[formatEnvKey(indexedPrefix)] = String(item);
1049
+ }
1050
+ });
1051
+ } else if (typeof value === "object" && value !== null) {
1052
+ Object.assign(acc, flattenConfig(value, newPrefix));
1053
+ } else {
1054
+ acc[formatEnvKey(newPrefix)] = String(value);
1055
+ }
1056
+ return acc;
1057
+ }, {});
1058
+ }
1059
+ async function parseConfigFile(configPath) {
1060
+ const importPath = `${configPath}?t=${Date.now()}`;
1061
+ const parsedConfig = await import(importPath).then((m) => m.default);
1062
+ return flattenConfig(parsedConfig);
1063
+ }
1064
+
1065
1065
  // src/commands/run.ts
1066
1066
  var {$: $2 } = globalThis.Bun;
1067
1067
  var {sleep: sleep2 } = globalThis.Bun;
@@ -1247,12 +1247,25 @@ init_platform();
1247
1247
  init_run();
1248
1248
  init_utils();
1249
1249
  var api_default = {
1250
+ db,
1250
1251
  getAllProcesses,
1251
1252
  getProcess,
1252
1253
  insertProcess,
1253
1254
  removeProcess,
1254
1255
  removeProcessByName,
1255
1256
  removeAllProcesses,
1257
+ updateProcessPid,
1258
+ updateProcessEnv,
1259
+ getAllTemplates,
1260
+ saveTemplate,
1261
+ deleteTemplate,
1262
+ getProcessHistory,
1263
+ getRecentHistory,
1264
+ addHistoryEntry,
1265
+ getDependencyGraph,
1266
+ addDependency,
1267
+ removeDependency,
1268
+ getStartOrder,
1256
1269
  retryDatabaseOperation,
1257
1270
  getDbInfo,
1258
1271
  dbPath,
@@ -1271,6 +1284,7 @@ var api_default = {
1271
1284
  isWindows,
1272
1285
  getProcessBatchResources,
1273
1286
  getProcessMemory,
1287
+ reconcileProcessPids,
1274
1288
  handleRun,
1275
1289
  getVersion,
1276
1290
  calculateRuntime,
@@ -1280,11 +1294,16 @@ var api_default = {
1280
1294
  export {
1281
1295
  waitForPortFree,
1282
1296
  validateDirectory,
1297
+ updateProcessPid,
1298
+ updateProcessEnv,
1283
1299
  terminateProcess,
1300
+ saveTemplate,
1284
1301
  retryDatabaseOperation,
1285
1302
  removeProcessByName,
1286
1303
  removeProcess,
1304
+ removeDependency,
1287
1305
  removeAllProcesses,
1306
+ reconcileProcessPids,
1288
1307
  readFileTail,
1289
1308
  parseEnvString,
1290
1309
  killProcessOnPort,
@@ -1293,20 +1312,28 @@ export {
1293
1312
  insertProcess,
1294
1313
  handleRun,
1295
1314
  getVersion,
1315
+ getStartOrder,
1296
1316
  getShellCommand,
1317
+ getRecentHistory,
1297
1318
  getProcessPorts,
1298
1319
  getProcessMemory,
1320
+ getProcessHistory,
1299
1321
  getProcessBatchResources,
1300
1322
  getProcess,
1301
1323
  getHomeDir,
1324
+ getDependencyGraph,
1302
1325
  getDbInfo,
1326
+ getAllTemplates,
1303
1327
  getAllProcesses,
1304
1328
  findPidByPort,
1305
1329
  findChildPid,
1306
1330
  ensureDir,
1331
+ deleteTemplate,
1307
1332
  api_default as default,
1308
1333
  dbPath,
1309
1334
  db,
1310
1335
  calculateRuntime,
1311
- bgrHome
1336
+ bgrHome,
1337
+ addHistoryEntry,
1338
+ addDependency
1312
1339
  };