graphify-sf 0.3.8 → 0.4.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/install.js CHANGED
@@ -2,27 +2,42 @@
2
2
 
3
3
  // postinstall hook.
4
4
  //
5
- // The graphify-sf npm package is a thin wrapper that fetches a prebuilt binary
6
- // from the project's GitHub Releases. In locked-down corporate networks the
7
- // download can be blocked by a proxy or firewall. A failed download here MUST
8
- // NOT abort `npm install` for the whole dependency tree — graphify-sf is an
9
- // optional second engine for its consumers, so a missing binary should degrade
10
- // gracefully (the binary is fetched lazily on first run, and there are offline
11
- // remediation paths).
5
+ // As of 0.3.9 the prebuilt binary normally arrives WITH `npm install`, shipped
6
+ // inside a platform-specific scoped subpackage (@graphify-sf/cli-<plat>-<arch>)
7
+ // declared in optionalDependencies. npm installs only the subpackage matching
8
+ // the host os/cpu, so on a supported platform the binary is already present and
9
+ // this hook makes ZERO network requests.
12
10
  //
13
- // Therefore: never exit non-zero from postinstall. Print a clear, actionable
14
- // warning and exit 0. The actual binary resolution happens later via
15
- // download.ensureBinary() at first invocation.
11
+ // Resolution order (see lib/download.js ensureBinary):
12
+ // 1. GRAPHIFY_BIN env override
13
+ // 2. the installed platform subpackage <-- 0.3.9 happy path, no network
14
+ // 3. a previously-downloaded binary in bin/
15
+ // 4. download from GitHub Releases <-- fallback only
16
+ //
17
+ // A failed download in step 4 MUST NOT abort the consumer's `npm install`
18
+ // (graphify-sf is an optional second engine for its consumers). So this hook
19
+ // always exits 0: if no binary resolves and the fallback download fails, we
20
+ // print actionable remediation and still exit 0; the binary is fetched lazily
21
+ // on first run instead.
22
+
23
+ const { envBinary, subpackageBinary, download } = require("./lib/download");
16
24
 
17
- const { download } = require("./lib/download");
25
+ async function main() {
26
+ // If a binary already resolves (env override or the platform subpackage),
27
+ // there is nothing to do — and crucially, no network request.
28
+ if (envBinary() || subpackageBinary()) {
29
+ process.exit(0);
30
+ }
18
31
 
19
- download()
20
- .then(() => {
32
+ // No prebuilt binary available for this platform (unsupported platform,
33
+ // --no-optional, or a registry that doesn't carry the scoped subpackages).
34
+ // Try the GitHub Releases fallback, but never fail the install.
35
+ try {
36
+ await download();
21
37
  process.exit(0);
22
- })
23
- .catch((err) => {
38
+ } catch (err) {
24
39
  process.stderr.write(
25
- `\ngraphify-sf: could not pre-fetch the CLI binary during install.\n` +
40
+ `\ngraphify-sf: no prebuilt binary for this platform and the fallback download failed.\n` +
26
41
  ` Reason: ${err.message}\n` +
27
42
  `\n` +
28
43
  ` This is non-fatal — installation will continue. The binary will be\n` +
@@ -34,6 +49,8 @@ download()
34
49
  ` • Point at an existing binary: export GRAPHIFY_BIN=/path/to/graphify-sf\n` +
35
50
  `\n`
36
51
  );
37
- // Non-fatal: do not break the consumer's `npm install`.
38
52
  process.exit(0);
39
- });
53
+ }
54
+ }
55
+
56
+ main();
package/lib/download.js CHANGED
@@ -132,6 +132,63 @@ function envBinary() {
132
132
  return null;
133
133
  }
134
134
 
135
+ // Name of the platform-specific scoped subpackage that ships the prebuilt
136
+ // binary for the current platform/arch, e.g. "@graphify-sf/cli-linux-x64".
137
+ // Returns null on unsupported platforms.
138
+ function subpackageName() {
139
+ const plat = process.platform;
140
+ const arch = process.arch;
141
+ const supported = SUPPORTED[plat];
142
+ if (!supported || !supported.includes(arch)) {
143
+ return null;
144
+ }
145
+ return `@graphify-sf/cli-${plat}-${arch}`;
146
+ }
147
+
148
+ // Resolve the binary from an installed platform subpackage (the 0.3.9 happy
149
+ // path — the binary arrives with `npm install` via optionalDependencies, no
150
+ // network). Returns the absolute path, or null if the subpackage is not
151
+ // installed (unsupported platform, --no-optional, or a registry mirror that
152
+ // does not carry the scoped subpackages).
153
+ function subpackageBinary() {
154
+ const name = subpackageName();
155
+ if (!name) return null;
156
+ const binName = process.platform === "win32" ? "graphify-sf.exe" : "graphify-sf";
157
+
158
+ // Build a robust set of resolution roots. In a normal install the subpackage
159
+ // is a peer in the consumer's node_modules and resolves from this module's
160
+ // own location; but with non-hoisted / nested layouts (or when invoked from a
161
+ // different cwd, e.g. tests) it may live elsewhere. Searching from this
162
+ // module, the package root, and the current working directory covers npm,
163
+ // pnpm and yarn layouts.
164
+ const searchPaths = [__dirname, path.join(__dirname, ".."), process.cwd()];
165
+
166
+ let resolved = null;
167
+ try {
168
+ resolved = require.resolve(`${name}/${binName}`, { paths: searchPaths });
169
+ } catch {
170
+ // Subpackage not installed — fall through to other resolution strategies.
171
+ return null;
172
+ }
173
+
174
+ if (resolved && fs.existsSync(resolved)) {
175
+ // Defensive: npm tarballs preserve mode, but ensure executable on Unix.
176
+ if (process.platform !== "win32") {
177
+ try {
178
+ fs.accessSync(resolved, fs.constants.X_OK);
179
+ } catch {
180
+ try {
181
+ fs.chmodSync(resolved, 0o755);
182
+ } catch {
183
+ /* best-effort; resolution still returned below */
184
+ }
185
+ }
186
+ }
187
+ return resolved;
188
+ }
189
+ return null;
190
+ }
191
+
135
192
  async function ensureBinary() {
136
193
  // 1. Explicit override always wins.
137
194
  const fromEnv = envBinary();
@@ -139,15 +196,31 @@ async function ensureBinary() {
139
196
  return fromEnv;
140
197
  }
141
198
 
142
- // 2. Already-downloaded binary in the package's bin/ dir.
199
+ // 2. Prebuilt binary shipped in the platform subpackage (0.3.9 happy path,
200
+ // no network).
201
+ const fromSubpkg = subpackageBinary();
202
+ if (fromSubpkg) {
203
+ return fromSubpkg;
204
+ }
205
+
206
+ // 3. Already-downloaded binary in the package's bin/ dir (legacy cache).
143
207
  const dest = binaryPath();
144
208
  if (fs.existsSync(dest)) {
145
209
  return dest;
146
210
  }
147
211
 
148
- // 3. Lazily download on first use.
212
+ // 4. Last resort: lazily download from GitHub Releases on first use.
149
213
  await download();
150
214
  return dest;
151
215
  }
152
216
 
153
- module.exports = { assetName, binaryPath, binDir, download, ensureBinary, envBinary };
217
+ module.exports = {
218
+ assetName,
219
+ binaryPath,
220
+ binDir,
221
+ download,
222
+ ensureBinary,
223
+ envBinary,
224
+ subpackageName,
225
+ subpackageBinary,
226
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "graphify-sf",
3
- "version": "0.3.8",
3
+ "version": "0.4.0",
4
4
  "description": "Turn any Salesforce SFDX project into a queryable knowledge graph — no Python required.",
5
5
  "bin": {
6
6
  "graphify-sf": "bin/graphify-sf.js"
@@ -10,6 +10,13 @@
10
10
  "postinstall": "node install.js",
11
11
  "test": "node --test"
12
12
  },
13
+ "optionalDependencies": {
14
+ "@graphify-sf/cli-linux-x64": "0.4.0",
15
+ "@graphify-sf/cli-linux-arm64": "0.4.0",
16
+ "@graphify-sf/cli-darwin-x64": "0.4.0",
17
+ "@graphify-sf/cli-darwin-arm64": "0.4.0",
18
+ "@graphify-sf/cli-win32-x64": "0.4.0"
19
+ },
13
20
  "files": [
14
21
  "bin/",
15
22
  "lib/",