graphify-sf 0.3.2

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/README.md ADDED
@@ -0,0 +1,70 @@
1
+ # graphify-sf (npm)
2
+
3
+ Install and run [graphify-sf](https://github.com/raykuonz/graphify-sf) — the Salesforce SFDX
4
+ knowledge-graph tool — from npm, without needing Python.
5
+
6
+ On install, a pre-built binary matching your OS/arch is downloaded from the GitHub Release.
7
+
8
+ ## Install
9
+
10
+ ```bash
11
+ npm install graphify-sf
12
+ # or
13
+ pnpm add graphify-sf
14
+ ```
15
+
16
+ > **pnpm note:** pnpm sets `ignore-scripts=true` by default, so the `postinstall` step may not
17
+ > run automatically. The binary is downloaded lazily on first use instead, so everything still
18
+ > works — you may just see a one-time download message the first time you invoke the CLI.
19
+
20
+ ## CLI usage
21
+
22
+ ```bash
23
+ npx graphify-sf ./force-app --out my-graph-out --no-viz
24
+ ```
25
+
26
+ The output directory will contain `graph.json` with the full knowledge graph.
27
+
28
+ ## Programmatic usage (Node.js / sf-cockpit)
29
+
30
+ ```js
31
+ const { runGraphify } = require("graphify-sf");
32
+
33
+ const { graphJsonPath } = await runGraphify("./force-app", { outDir: "my-graph-out" });
34
+ console.log("Graph written to:", graphJsonPath);
35
+ ```
36
+
37
+ `runGraphify` returns a Promise that resolves with `{ code, graphJsonPath }` on success and
38
+ rejects on non-zero exit.
39
+
40
+ Additional exports: `ensureBinary()` (downloads if missing, returns path), `binaryPath()`
41
+ (returns expected path without triggering a download).
42
+
43
+ ## What's bundled
44
+
45
+ This package wraps the **core static-extraction path** of graphify-sf: Apex, Flow, Object, LWC,
46
+ Aura, Profile/PermSet, and Agentforce metadata — everything that can be parsed without an org
47
+ connection. Community detection and the knowledge-graph JSON export are included.
48
+
49
+ **Not bundled:** LLM-assisted extraction (`--backend`), SVG export, Neo4j export, MCP server, and
50
+ file-watcher mode. Those extras require a full Python install:
51
+
52
+ ```bash
53
+ pip install "graphify-sf[all]"
54
+ # or
55
+ pipx install "graphify-sf[all]"
56
+ ```
57
+
58
+ ## Supported platforms
59
+
60
+ | Platform | x64 | arm64 |
61
+ |-----------|-----|-------|
62
+ | linux | ✓ | ✓ |
63
+ | macOS | ✓ | ✓ |
64
+ | Windows | ✓ | — |
65
+
66
+ For unsupported platforms, install via PyPI: `pipx install graphify-sf`.
67
+
68
+ ## License
69
+
70
+ MIT — see [LICENSE](https://github.com/raykuonz/graphify-sf/blob/main/LICENSE).
@@ -0,0 +1,21 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+
4
+ const { spawn } = require("child_process");
5
+ const { ensureBinary } = require("../lib/download");
6
+
7
+ ensureBinary()
8
+ .then((bin) => {
9
+ const child = spawn(bin, process.argv.slice(2), { stdio: "inherit" });
10
+ child.on("error", (err) => {
11
+ process.stderr.write(`graphify-sf: failed to start binary: ${err.message}\n`);
12
+ process.exit(1);
13
+ });
14
+ child.on("close", (code) => {
15
+ process.exit(code == null ? 1 : code);
16
+ });
17
+ })
18
+ .catch((err) => {
19
+ process.stderr.write(`graphify-sf: ${err.message}\n`);
20
+ process.exit(1);
21
+ });
package/index.js ADDED
@@ -0,0 +1,47 @@
1
+ "use strict";
2
+
3
+ const { spawn } = require("child_process");
4
+ const path = require("path");
5
+ const { ensureBinary, binaryPath } = require("./lib/download");
6
+
7
+ /**
8
+ * Run graphify-sf programmatically.
9
+ *
10
+ * @param {string} sfdxPath - Path to the SFDX project root.
11
+ * @param {object} [options]
12
+ * @param {string} [options.outDir] - Output directory (default: "graphify-sf-out").
13
+ * @param {string[]} [options.extraArgs] - Additional CLI args forwarded verbatim.
14
+ * @param {"inherit"|"pipe"|"ignore"} [options.stdio] - stdio mode for the child process (default: "inherit").
15
+ * @returns {Promise<{code: number, graphJsonPath: string}>}
16
+ */
17
+ async function runGraphify(sfdxPath, options) {
18
+ if (!sfdxPath) throw new Error("graphify-sf: sfdxPath is required");
19
+
20
+ const opts = options || {};
21
+ const outDir = opts.outDir || "graphify-sf-out";
22
+ const extraArgs = opts.extraArgs || [];
23
+ const stdioMode = opts.stdio || "inherit";
24
+
25
+ const bin = await ensureBinary();
26
+ const args = [sfdxPath, "--out", outDir, "--no-viz", ...extraArgs];
27
+ const graphJsonPath = path.join(outDir, "graph.json");
28
+
29
+ return new Promise((resolve, reject) => {
30
+ const child = spawn(bin, args, { stdio: stdioMode });
31
+ child.on("error", reject);
32
+ child.on("close", (code) => {
33
+ if (code === 0) {
34
+ resolve({ code, graphJsonPath });
35
+ } else {
36
+ reject(
37
+ new Error(
38
+ `graphify-sf exited with code ${code}. ` +
39
+ `Command: ${bin} ${args.join(" ")}`
40
+ )
41
+ );
42
+ }
43
+ });
44
+ });
45
+ }
46
+
47
+ module.exports = { runGraphify, ensureBinary, binaryPath };
package/install.js ADDED
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+
3
+ const { download } = require("./lib/download");
4
+
5
+ download().catch((err) => {
6
+ process.stderr.write(`graphify-sf postinstall failed: ${err.message}\n`);
7
+ process.exit(1);
8
+ });
@@ -0,0 +1,131 @@
1
+ "use strict";
2
+
3
+ const https = require("https");
4
+ const fs = require("fs");
5
+ const path = require("path");
6
+
7
+ const PKG = require("../package.json");
8
+ const VERSION = PKG.version;
9
+
10
+ const SUPPORTED = {
11
+ linux: ["x64", "arm64"],
12
+ darwin: ["x64", "arm64"],
13
+ win32: ["x64"],
14
+ };
15
+
16
+ function assetName() {
17
+ const plat = process.platform;
18
+ const arch = process.arch;
19
+
20
+ const supported = SUPPORTED[plat];
21
+ if (!supported) {
22
+ throw new Error(
23
+ `graphify-sf: unsupported platform "${plat}". ` +
24
+ `Supported: ${Object.keys(SUPPORTED).join(", ")}. ` +
25
+ `Remediation: install via pip/pipx instead: pipx install graphify-sf`
26
+ );
27
+ }
28
+ if (!supported.includes(arch)) {
29
+ throw new Error(
30
+ `graphify-sf: unsupported arch "${arch}" on ${plat}. ` +
31
+ `Supported archs for ${plat}: ${supported.join(", ")}. ` +
32
+ `Remediation: install via pip/pipx instead: pipx install graphify-sf`
33
+ );
34
+ }
35
+
36
+ const ext = plat === "win32" ? ".exe" : "";
37
+ return `graphify-sf-${plat}-${arch}${ext}`;
38
+ }
39
+
40
+ function binDir() {
41
+ return path.join(__dirname, "..", "bin");
42
+ }
43
+
44
+ function binaryPath() {
45
+ const ext = process.platform === "win32" ? ".exe" : "";
46
+ return path.join(binDir(), `graphify-sf-bin${ext}`);
47
+ }
48
+
49
+ function downloadUrl(asset) {
50
+ return `https://github.com/raykuonz/graphify-sf/releases/download/v${VERSION}/${asset}`;
51
+ }
52
+
53
+ function fetchFollow(url, redirects) {
54
+ if (redirects === undefined) redirects = 5;
55
+ return new Promise((resolve, reject) => {
56
+ https
57
+ .get(url, { headers: { "User-Agent": "graphify-sf-npm-installer" } }, (res) => {
58
+ if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
59
+ if (redirects === 0) {
60
+ reject(new Error(`graphify-sf: too many redirects downloading ${url}`));
61
+ return;
62
+ }
63
+ resolve(fetchFollow(res.headers.location, redirects - 1));
64
+ return;
65
+ }
66
+ if (res.statusCode !== 200) {
67
+ reject(
68
+ new Error(
69
+ `graphify-sf: download failed with HTTP ${res.statusCode} from ${url}. ` +
70
+ `Remediation: install via pip/pipx instead: pipx install graphify-sf`
71
+ )
72
+ );
73
+ return;
74
+ }
75
+ resolve(res);
76
+ })
77
+ .on("error", reject);
78
+ });
79
+ }
80
+
81
+ async function download() {
82
+ const asset = assetName();
83
+ const url = downloadUrl(asset);
84
+ const dest = binaryPath();
85
+
86
+ fs.mkdirSync(binDir(), { recursive: true });
87
+
88
+ process.stdout.write(`graphify-sf: downloading ${asset} from ${url}\n`);
89
+
90
+ const res = await fetchFollow(url);
91
+
92
+ await new Promise((resolve, reject) => {
93
+ const tmp = dest + ".tmp";
94
+ const out = fs.createWriteStream(tmp);
95
+ res.pipe(out);
96
+ out.on("finish", () => {
97
+ out.close(() => {
98
+ try {
99
+ fs.renameSync(tmp, dest);
100
+ resolve();
101
+ } catch (e) {
102
+ reject(e);
103
+ }
104
+ });
105
+ });
106
+ out.on("error", (e) => {
107
+ fs.unlink(tmp, () => {});
108
+ reject(e);
109
+ });
110
+ res.on("error", (e) => {
111
+ fs.unlink(tmp, () => {});
112
+ reject(e);
113
+ });
114
+ });
115
+
116
+ if (process.platform !== "win32") {
117
+ fs.chmodSync(dest, 0o755);
118
+ }
119
+
120
+ process.stdout.write(`graphify-sf: installed to ${dest}\n`);
121
+ }
122
+
123
+ async function ensureBinary() {
124
+ const dest = binaryPath();
125
+ if (!fs.existsSync(dest)) {
126
+ await download();
127
+ }
128
+ return dest;
129
+ }
130
+
131
+ module.exports = { assetName, binaryPath, binDir, download, ensureBinary };
package/package.json ADDED
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "graphify-sf",
3
+ "version": "0.3.2",
4
+ "description": "Turn any Salesforce SFDX project into a queryable knowledge graph — no Python required.",
5
+ "bin": {
6
+ "graphify-sf": "bin/graphify-sf.js"
7
+ },
8
+ "main": "index.js",
9
+ "scripts": {
10
+ "postinstall": "node install.js"
11
+ },
12
+ "files": [
13
+ "bin/",
14
+ "lib/",
15
+ "index.js",
16
+ "install.js",
17
+ "README.md"
18
+ ],
19
+ "engines": {
20
+ "node": ">=18"
21
+ },
22
+ "os": [
23
+ "linux",
24
+ "darwin",
25
+ "win32"
26
+ ],
27
+ "cpu": [
28
+ "x64",
29
+ "arm64"
30
+ ],
31
+ "license": "MIT",
32
+ "repository": {
33
+ "type": "git",
34
+ "url": "git+https://github.com/raykuonz/graphify-sf.git"
35
+ },
36
+ "homepage": "https://github.com/raykuonz/graphify-sf#readme",
37
+ "bugs": {
38
+ "url": "https://github.com/raykuonz/graphify-sf/issues"
39
+ }
40
+ }