systemview 1.16.9 → 1.17.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.
@@ -0,0 +1,78 @@
1
+ const fs = require("fs");
2
+ const path = require("path");
3
+ const { HttpClient, Client } = require("systemlynx");
4
+ const log = require("./logger");
5
+
6
+ async function probeService(url) {
7
+ const connectionData = await HttpClient.request({ url });
8
+ if (!connectionData.SystemLynxService) {
9
+ throw new Error(`No SystemLynx service found at ${url}`);
10
+ }
11
+ const client = Client.createService(connectionData);
12
+ const connection = await client.Plugin.getConnection();
13
+ return connection; // { projectCode, serviceId, system, specList }
14
+ }
15
+
16
+ function readManifest(manifestFile) {
17
+ if (!fs.existsSync(manifestFile)) return null;
18
+ try {
19
+ return JSON.parse(fs.readFileSync(manifestFile, "utf8"));
20
+ } catch {
21
+ return null;
22
+ }
23
+ }
24
+
25
+ function writeManifest(manifestFile, connection) {
26
+ const manifest = readManifest(manifestFile) || { projectCode: connection.projectCode, services: [] };
27
+ if (!manifest.services) manifest.services = [];
28
+ const entry = { serviceId: connection.serviceId, system: connection.system, specList: connection.specList };
29
+ const idx = manifest.services.findIndex((s) => s.serviceId === connection.serviceId);
30
+ if (idx > -1) manifest.services[idx] = entry;
31
+ else manifest.services.push(entry);
32
+ manifest.projectCode = connection.projectCode;
33
+ fs.writeFileSync(manifestFile, JSON.stringify(manifest, null, 2));
34
+ }
35
+
36
+ module.exports = async function connectService(serviceId, url, { manifest: manifestPath } = {}) {
37
+ const manifestFile = manifestPath || path.join(process.cwd(), "systemview.manifest.json");
38
+
39
+ if (!url) {
40
+ // Re-probe all services already in the manifest
41
+ const manifest = readManifest(manifestFile);
42
+ if (!manifest || !manifest.services || !manifest.services.length) {
43
+ log.warn("No manifest found. Use: systemview connect <serviceId> <url>");
44
+ return;
45
+ }
46
+ log.info(`Re-probing ${manifest.services.length} service(s)...`);
47
+ for (const { serviceId: id, system } of manifest.services) {
48
+ try {
49
+ const connection = await probeService(system.connectionData.serviceUrl);
50
+ writeManifest(manifestFile, connection);
51
+ log.success(`${id} updated`);
52
+ } catch (err) {
53
+ log.error(`${id} failed: ${err.message}`);
54
+ }
55
+ }
56
+ printManifestSummary(readManifest(manifestFile));
57
+ return;
58
+ }
59
+
60
+ log.info(`Connecting to ${serviceId || "service"} @ ${url}...`);
61
+ try {
62
+ const connection = await probeService(url);
63
+ writeManifest(manifestFile, connection);
64
+ printManifestSummary(readManifest(manifestFile));
65
+ } catch (err) {
66
+ log.error(`Connection failed: ${err.message}`);
67
+ }
68
+ };
69
+
70
+ function printManifestSummary(manifest) {
71
+ if (!manifest) return;
72
+ log.plain(`\n Project: ${manifest.projectCode}`);
73
+ log.plain(` Services:`);
74
+ (manifest.services || []).forEach(({ serviceId, system }) => {
75
+ log.plain(` - ${serviceId} @ ${system.connectionData.serviceUrl}`);
76
+ });
77
+ log.plain("");
78
+ }
package/cli/index.js CHANGED
@@ -1,53 +1,44 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- /**
4
- * SystemView
5
- * A documentation and testing suite for SystemLynx
6
- *
7
- * @author Odion Edwards <none>
8
- */
9
3
  process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
10
- const openBrowser = require("./openBrowser");
11
- const init = require("./utils/init");
12
- const cli = require("./utils/cli");
13
- const log = require("./utils/log");
14
4
 
5
+ const { input, flags, showHelp } = require("./utils/cli");
6
+ const init = require("./utils/init");
7
+ const log = require("./logger");
15
8
  const launchApp = require("./launchApp");
16
9
  const runTests = require("./runTests");
17
10
  const appIsRunning = require("./appIsRunning");
11
+ const openBrowser = require("./openBrowser");
12
+ const connectService = require("./connectService");
13
+ const probe = require("./probe");
18
14
  const { HttpClient } = require("systemlynx");
19
15
 
20
- const input = cli.input;
21
- const flags = cli.flags;
22
- const { clear, debug } = flags;
23
16
  const DEFAULT_PORT = 3000;
24
17
 
25
18
  async function startApp() {
26
- const port = isNaN(input[1]) ? DEFAULT_PORT : input[1];
27
-
19
+ const port = isNaN(input[1]) ? DEFAULT_PORT : Number(input[1]);
28
20
  try {
29
- await launchApp(port);
21
+ await launchApp(port, { interactive: true });
30
22
  } catch (error) {
31
- log("Launch failed:" + error.message, "error");
32
- console.log(error);
23
+ log.error("Launch failed: " + error.message);
33
24
  }
34
25
  }
35
26
 
36
27
  async function startTest() {
28
+ const project_code = input[1];
29
+ const namespace = input[2];
37
30
  const url = `http://localhost:${DEFAULT_PORT}`;
38
- input.shift();
39
31
  try {
40
- const lineReader = await launchApp(DEFAULT_PORT);
41
- setTimeout(async () => {
42
- await runTests(url, ...input);
43
- if (lineReader) {
44
- lineReader.prompt();
45
- } else {
46
- process.exit(0);
47
- }
48
- }, 0);
32
+ await launchApp(DEFAULT_PORT);
33
+ const exitCode = await runTests(url, project_code, namespace, {
34
+ json: flags.json,
35
+ verbose: flags.verbose,
36
+ manifest: flags.manifest,
37
+ });
38
+ process.exit(exitCode);
49
39
  } catch (error) {
50
- console.error("Error executing tests:", error.message);
40
+ log.error("Error executing tests: " + error.message);
41
+ process.exit(1);
51
42
  }
52
43
  }
53
44
 
@@ -56,56 +47,58 @@ async function open() {
56
47
  const namespace = input[2];
57
48
  const ui = `http://localhost:${DEFAULT_PORT}`;
58
49
  const api = `${ui}/systemview/api`;
59
- if (await appIsRunning(api)) {
60
- openBrowser(ui, project_code, namespace);
61
- process.exit(0);
62
- } else {
50
+ if (!(await appIsRunning(api))) {
63
51
  await launchApp(DEFAULT_PORT);
64
- openBrowser(ui, project_code, namespace);
65
52
  }
53
+ openBrowser(ui, project_code, namespace);
54
+ process.exit(0);
66
55
  }
56
+
67
57
  async function quitApp() {
68
- const port = isNaN(input[1]) ? DEFAULT_PORT : input[1];
58
+ const port = isNaN(input[1]) ? DEFAULT_PORT : Number(input[1]);
69
59
  const api = `http://localhost:${port}/systemview/api`;
70
60
 
71
61
  if (await appIsRunning(api)) {
72
- log("SystemView is running from another terminal", "info", "info");
73
- log("Attempting remote shutdown...", "info", "info");
74
-
62
+ log.info("Attempting remote shutdown...");
75
63
  const url = `${api}/SystemView/shutdown`;
76
- const method = "put";
77
- HttpClient.request({ url, method })
78
- .then(() => console.log("SystemView shutdown successful!"))
79
- .catch(async (error) => {
80
- if (await appIsRunning(api)) {
81
- log("Remote shutdown failed!", "error", "error");
82
- console.error(error);
83
- } else {
84
- console.log("SystemView shutdown successful!");
85
- }
86
- });
64
+ try {
65
+ await HttpClient.request({ url, method: "put" });
66
+ log.success("SystemView shutdown successful!");
67
+ process.exit(0);
68
+ } catch (error) {
69
+ if (!(await appIsRunning(api))) {
70
+ log.success("SystemView shutdown successful!");
71
+ process.exit(0);
72
+ } else {
73
+ log.error("Remote shutdown failed!");
74
+ process.exit(1);
75
+ }
76
+ }
87
77
  } else {
88
- log(`SystemView instance not found @${api}`, "warning", "warning");
89
- console.log("Please include the port if default port is not being used:");
90
- log("systemview shutdown 4000", "info", "example");
78
+ log.warn(`No SystemView instance found @ ${api}`);
79
+ process.exit(0);
91
80
  }
92
81
  }
93
82
 
94
83
  (async () => {
95
- init({ clear });
96
- if (input[0] === "open") {
97
- open();
98
- } else if (input.includes(`help`)) {
99
- cli.showHelp(0);
100
- } else if (input.includes("test")) {
101
- startTest();
102
- } else if (["exit", "q", "shutdown", "stop"].includes(input[0])) {
103
- quitApp();
104
- } else if (input[0] === "start") {
105
- startApp();
84
+ init();
85
+ const command = input[0];
86
+
87
+ if (command === "open") {
88
+ await open();
89
+ } else if (command === "help" || input.includes("help")) {
90
+ showHelp();
91
+ } else if (command === "test") {
92
+ await startTest();
93
+ } else if (["exit", "q", "shutdown", "stop"].includes(command)) {
94
+ await quitApp();
95
+ } else if (command === "connect") {
96
+ await connectService(input[1], input[2], { manifest: flags.manifest });
97
+ process.exit(0);
98
+ } else if (command === "probe") {
99
+ const exitCode = await probe(input[1], input[2], { json: flags.json, manifest: flags.manifest });
100
+ process.exit(exitCode || 0);
106
101
  } else {
107
102
  await startApp();
108
103
  }
109
- cli.input = [];
110
- debug && log(flags);
111
104
  })();
package/cli/launchApp.js CHANGED
@@ -1,24 +1,31 @@
1
- const log = require("./utils/log");
1
+ const log = require("./logger");
2
2
  const appIsRunning = require("./appIsRunning");
3
3
  const launchSystemView = require("../api");
4
4
  const startLineReader = require("./startLineReader");
5
5
 
6
- module.exports = async function launchApp(port) {
6
+ module.exports = async function launchApp(port, { interactive = false } = {}) {
7
7
  const ui = `http://localhost:${port}`;
8
8
  const api = `${ui}/systemview/api`;
9
+
9
10
  function logConnection() {
10
- log("connected!", "success");
11
- console.log(`SystemView UI running @${ui}`);
12
- console.log(`SystemView API running @${api}\n`);
11
+ log.success("connected!");
12
+ console.log(` SystemView UI ${ui}`);
13
+ console.log(` SystemView API ${api}\n`);
13
14
  }
14
15
 
15
16
  if (await appIsRunning(api)) {
16
- log("SystemView is running from another terminal", "info", "info");
17
- logConnection();
18
- } else {
19
- log("Launching...");
20
- await launchSystemView(port);
21
- logConnection();
17
+ if (interactive) {
18
+ log.info("SystemView is running from another terminal");
19
+ logConnection();
20
+ }
21
+ return;
22
+ }
23
+
24
+ if (interactive) log.info("Launching...");
25
+ await launchSystemView(port);
26
+ logConnection();
27
+
28
+ if (interactive) {
22
29
  return startLineReader(ui);
23
30
  }
24
31
  };
package/cli/logger.js ADDED
@@ -0,0 +1,9 @@
1
+ const chalk = require("chalk");
2
+
3
+ module.exports = {
4
+ info: (msg) => console.log(chalk.blue(" ℹ ") + msg),
5
+ success: (msg) => console.log(chalk.green(" ✔ ") + msg),
6
+ warn: (msg) => console.log(chalk.yellow(" ⚠ ") + msg),
7
+ error: (msg) => console.error(chalk.red(" ✖ ") + msg),
8
+ plain: (msg) => console.log(msg),
9
+ };
package/cli/probe.js ADDED
@@ -0,0 +1,71 @@
1
+ const fs = require("fs");
2
+ const path = require("path");
3
+ const { Client } = require("systemlynx");
4
+ const log = require("./logger");
5
+
6
+ module.exports = async function probe(namespace, argsStr, { json = false, manifest: manifestPath } = {}) {
7
+ if (!namespace) {
8
+ log.error("Usage: systemview probe <ServiceId.Module.method> [args]");
9
+ return 1;
10
+ }
11
+
12
+ const parts = namespace.split(".");
13
+ if (parts.length !== 3) {
14
+ log.error("Namespace must be in format: ServiceId.Module.method");
15
+ return 1;
16
+ }
17
+
18
+ const [serviceId, moduleName, methodName] = parts;
19
+
20
+ let args = [];
21
+ if (argsStr) {
22
+ try {
23
+ const parsed = JSON.parse(argsStr);
24
+ args = Array.isArray(parsed) ? parsed : [parsed];
25
+ } catch {
26
+ args = [argsStr];
27
+ }
28
+ }
29
+
30
+ const manifestFile = manifestPath || path.join(process.cwd(), "systemview.manifest.json");
31
+ if (!fs.existsSync(manifestFile)) {
32
+ log.error(`No manifest found at ${manifestFile}. Run: systemview connect <serviceId> <url>`);
33
+ return 1;
34
+ }
35
+
36
+ let manifest;
37
+ try {
38
+ manifest = JSON.parse(fs.readFileSync(manifestFile, "utf8"));
39
+ } catch (err) {
40
+ log.error(`Failed to read manifest: ${err.message}`);
41
+ return 1;
42
+ }
43
+
44
+ const services = manifest.services || [manifest];
45
+ const service = services.find((s) => s.serviceId === serviceId);
46
+ if (!service) {
47
+ log.error(`Service "${serviceId}" not found in manifest`);
48
+ return 1;
49
+ }
50
+
51
+ if (!json) log.info(`${serviceId}.${moduleName}.${methodName}(${argsStr || ""})`);
52
+
53
+ try {
54
+ const client = Client.createService(service.system.connectionData);
55
+ const result = await client[moduleName][methodName](...args);
56
+ if (json) {
57
+ process.stdout.write(JSON.stringify({ serviceId, moduleName, methodName, args, result }, null, 2) + "\n");
58
+ } else {
59
+ log.success("result:");
60
+ console.log(JSON.stringify(result, null, 2));
61
+ }
62
+ return 0;
63
+ } catch (err) {
64
+ if (json) {
65
+ process.stdout.write(JSON.stringify({ serviceId, moduleName, methodName, args, error: err.message }, null, 2) + "\n");
66
+ } else {
67
+ log.error(err.message);
68
+ }
69
+ return 1;
70
+ }
71
+ };