@nickderobertis/allowlister-remote-plugin 0.2.4 → 0.3.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/README.md CHANGED
@@ -9,5 +9,23 @@ allowlister-remote-plugin --version
9
9
  ```
10
10
 
11
11
  Configure allowlister to run `allowlister-remote-plugin --server-url <url>` as a
12
- dynamic plugin command. The package includes the release-built native binary for
13
- the current platform.
12
+ dynamic plugin command.
13
+
14
+ ## How it installs
15
+
16
+ The native binary for each platform ships in its own package
17
+ (`@nickderobertis/allowlister-remote-plugin-darwin-arm64`, `-linux-x64`,
18
+ `-win32-x64`), declared here as optional dependencies and gated by `os`/`cpu`, so
19
+ npm downloads only the one matching your machine. On install, a small step links
20
+ that native binary directly onto the `allowlister-remote-plugin` command, so the
21
+ command on your `PATH` **is** the Rust executable — no Node process is started per
22
+ invocation. This matters because allowlister may call the plugin hundreds of
23
+ times in a single agent session.
24
+
25
+ A JS launcher is shipped as a fallback and is used only when the in-place link
26
+ cannot be made — on Windows (where npm's command shims require it) or when
27
+ install scripts are disabled (`npm install --ignore-scripts`).
28
+
29
+ On macOS and Linux the resolved `allowlister-remote-plugin` command is already the
30
+ native binary, so pointing allowlister (or `ALLOWLISTER_REMOTE_PLUGIN_BIN`) at it
31
+ keeps the hot path free of Node.
@@ -0,0 +1,33 @@
1
+ #!/usr/bin/env node
2
+ // JS launcher fallback.
3
+ //
4
+ // On install, `install.mjs` replaces this file in place with the native binary
5
+ // (on macOS and Linux) so the command on PATH *is* the Rust executable with no
6
+ // Node in the hot path. This launcher only runs when that replacement was
7
+ // skipped — on Windows, or when install scripts were disabled (`--ignore-scripts`).
8
+ // In that case it resolves the native binary from the matching platform package
9
+ // and execs it, forwarding stdio and the exit code unchanged.
10
+
11
+ import { spawnSync } from "node:child_process";
12
+ import { createRequire } from "node:module";
13
+ import { binarySpecifier } from "../lib/platform.mjs";
14
+
15
+ const require = createRequire(import.meta.url);
16
+
17
+ let binary;
18
+ try {
19
+ binary = require.resolve(binarySpecifier());
20
+ } catch (error) {
21
+ console.error(
22
+ `Missing native allowlister-remote-plugin binary for ${process.platform}-${process.arch}.`,
23
+ );
24
+ console.error(error instanceof Error ? error.message : String(error));
25
+ process.exit(1);
26
+ }
27
+
28
+ const result = spawnSync(binary, process.argv.slice(2), { stdio: "inherit" });
29
+ if (result.error) {
30
+ console.error(result.error.message);
31
+ process.exit(1);
32
+ }
33
+ process.exit(result.status ?? 1);
package/install.mjs ADDED
@@ -0,0 +1,76 @@
1
+ // Post-install step: link the native binary directly onto the command path.
2
+ //
3
+ // npm has already installed the one platform package that matches this host
4
+ // (the others are skipped by their `os`/`cpu` fields). On macOS and Linux we
5
+ // copy that native binary over the JS launcher at `bin/allowlister-remote-plugin`,
6
+ // which is the file the `allowlister-remote-plugin` command symlinks to. After
7
+ // this the command on PATH is the Rust executable itself -- no Node process is
8
+ // spawned per invocation, which matters because allowlister can call the plugin
9
+ // hundreds of times in a single agent session.
10
+ //
11
+ // On Windows npm generates `.cmd`/`.ps1` shims that invoke the launcher through
12
+ // Node, so replacing the target in place would break them; we keep the JS
13
+ // launcher there instead. Either way, if anything goes wrong we leave the
14
+ // launcher in place as a working fallback and never fail the install.
15
+
16
+ import { chmodSync, copyFileSync, existsSync, readFileSync, realpathSync } from "node:fs";
17
+ import { createRequire } from "node:module";
18
+ import { basename, dirname, join } from "node:path";
19
+ import { fileURLToPath } from "node:url";
20
+ import { binarySpecifier } from "./lib/platform.mjs";
21
+
22
+ const require = createRequire(import.meta.url);
23
+ // Resolve symlinks so a workspace link does not make us look like an install.
24
+ const here = realpathSync(dirname(fileURLToPath(import.meta.url)));
25
+
26
+ // When this package lives in its source monorepo (linked as a workspace rather
27
+ // than installed under node_modules), overwriting the launcher would clobber the
28
+ // committed source file. Detect that by walking up to a `workspaces`-bearing
29
+ // package.json without first crossing a `node_modules` boundary.
30
+ function inWorkspaceCheckout(startDir) {
31
+ let dir = startDir;
32
+ for (;;) {
33
+ if (basename(dir) === "node_modules") {
34
+ return false;
35
+ }
36
+ const manifestPath = join(dir, "package.json");
37
+ if (existsSync(manifestPath)) {
38
+ try {
39
+ if (JSON.parse(readFileSync(manifestPath, "utf8")).workspaces) {
40
+ return true;
41
+ }
42
+ } catch {
43
+ // Ignore unreadable/partial manifests and keep walking up.
44
+ }
45
+ }
46
+ const parent = dirname(dir);
47
+ if (parent === dir) {
48
+ return false;
49
+ }
50
+ dir = parent;
51
+ }
52
+ }
53
+
54
+ if (inWorkspaceCheckout(here)) {
55
+ console.log("allowlister-remote-plugin: source checkout detected, keeping the JS launcher");
56
+ } else {
57
+ try {
58
+ const native = require.resolve(binarySpecifier());
59
+
60
+ if (process.platform === "win32") {
61
+ console.log(
62
+ "allowlister-remote-plugin: keeping the JS launcher (required by npm shims on Windows)",
63
+ );
64
+ } else {
65
+ const onPath = join(here, "bin", "allowlister-remote-plugin");
66
+ copyFileSync(native, onPath);
67
+ chmodSync(onPath, 0o755);
68
+ console.log(
69
+ "allowlister-remote-plugin: linked the native binary directly onto the command path",
70
+ );
71
+ }
72
+ } catch (error) {
73
+ const message = error instanceof Error ? error.message : String(error);
74
+ console.log(`allowlister-remote-plugin: keeping the JS launcher fallback (${message})`);
75
+ }
76
+ }
@@ -0,0 +1,51 @@
1
+ // Shared resolution for the per-platform native binary packages.
2
+ //
3
+ // Each supported platform ships the native `allowlister-remote-plugin` binary in
4
+ // its own npm package (declared as an optional dependency of this package). npm
5
+ // installs only the package whose `os`/`cpu` match the host, so resolving the
6
+ // binary is a matter of mapping the running platform/arch onto that package and
7
+ // asking Node where it landed in `node_modules`.
8
+
9
+ const PLATFORM_PACKAGES = new Map([
10
+ [
11
+ "darwin-arm64",
12
+ { pkg: "allowlister-remote-plugin-darwin-arm64", file: "allowlister-remote-plugin" },
13
+ ],
14
+ ["linux-x64", { pkg: "allowlister-remote-plugin-linux-x64", file: "allowlister-remote-plugin" }],
15
+ [
16
+ "win32-x64",
17
+ { pkg: "allowlister-remote-plugin-win32-x64", file: "allowlister-remote-plugin.exe" },
18
+ ],
19
+ ]);
20
+
21
+ const SCOPE = "@nickderobertis";
22
+
23
+ /**
24
+ * Describe the platform package for a given platform/arch, throwing for any
25
+ * combination we do not publish a binary for.
26
+ */
27
+ export function platformPackage(platform = process.platform, arch = process.arch) {
28
+ const entry = PLATFORM_PACKAGES.get(`${platform}-${arch}`);
29
+ if (!entry) {
30
+ throw new Error(`Unsupported platform: ${platform}-${arch}`);
31
+ }
32
+ return { name: `${SCOPE}/${entry.pkg}`, file: entry.file };
33
+ }
34
+
35
+ /**
36
+ * The bare specifier Node uses to locate the native binary inside the installed
37
+ * platform package, e.g. `@nickderobertis/allowlister-remote-plugin-linux-x64/bin/allowlister-remote-plugin`.
38
+ */
39
+ export function binarySpecifier(platform = process.platform, arch = process.arch) {
40
+ const { name, file } = platformPackage(platform, arch);
41
+ return `${name}/bin/${file}`;
42
+ }
43
+
44
+ /**
45
+ * Resolve the absolute path to the native binary using the caller's `require`
46
+ * (created with `createRequire(import.meta.url)`). Throws if the matching
47
+ * platform package is not installed.
48
+ */
49
+ export function resolveNativeBinary(require, platform = process.platform, arch = process.arch) {
50
+ return require.resolve(binarySpecifier(platform, arch));
51
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nickderobertis/allowlister-remote-plugin",
3
- "version": "0.2.4",
3
+ "version": "0.3.0",
4
4
  "description": "npm installer for the allowlister remote dynamic approval plugin",
5
5
  "type": "module",
6
6
  "license": "UNLICENSED",
@@ -9,12 +9,16 @@
9
9
  "url": "git+https://github.com/nickderobertis/allowlister-remote.git"
10
10
  },
11
11
  "bin": {
12
- "allowlister-remote-plugin": "bin/allowlister-remote-plugin.js"
12
+ "allowlister-remote-plugin": "bin/allowlister-remote-plugin"
13
+ },
14
+ "scripts": {
15
+ "postinstall": "node install.mjs"
13
16
  },
14
17
  "files": [
15
18
  "README.md",
16
19
  "bin/",
17
- "vendor/"
20
+ "lib/",
21
+ "install.mjs"
18
22
  ],
19
23
  "publishConfig": {
20
24
  "access": "public",
@@ -22,5 +26,10 @@
22
26
  },
23
27
  "engines": {
24
28
  "node": ">=20"
29
+ },
30
+ "optionalDependencies": {
31
+ "@nickderobertis/allowlister-remote-plugin-darwin-arm64": "0.3.0",
32
+ "@nickderobertis/allowlister-remote-plugin-linux-x64": "0.3.0",
33
+ "@nickderobertis/allowlister-remote-plugin-win32-x64": "0.3.0"
25
34
  }
26
35
  }
@@ -1,53 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- import { spawnSync } from "node:child_process";
4
- import { existsSync, realpathSync } from "node:fs";
5
- import { dirname, join } from "node:path";
6
- import { fileURLToPath } from "node:url";
7
-
8
- const supportedPlatforms = new Map([
9
- ["darwin-arm64", "darwin-arm64/allowlister-remote-plugin"],
10
- ["linux-x64", "linux-x64/allowlister-remote-plugin"],
11
- ["win32-x64", "win32-x64/allowlister-remote-plugin.exe"],
12
- ]);
13
-
14
- export function nativeBinaryPath(platform = process.platform, arch = process.arch) {
15
- const relativePath = supportedPlatforms.get(`${platform}-${arch}`);
16
- if (!relativePath) {
17
- throw new Error(`Unsupported platform: ${platform}-${arch}`);
18
- }
19
-
20
- return join(dirname(fileURLToPath(import.meta.url)), "..", "vendor", relativePath);
21
- }
22
-
23
- function main() {
24
- const binary = nativeBinaryPath();
25
-
26
- if (!existsSync(binary)) {
27
- console.error(
28
- `Missing native allowlister-remote-plugin binary for ${process.platform}-${process.arch}.`,
29
- );
30
- process.exit(1);
31
- }
32
-
33
- const result = spawnSync(binary, process.argv.slice(2), { stdio: "inherit" });
34
-
35
- if (result.error) {
36
- console.error(result.error.message);
37
- process.exit(1);
38
- }
39
-
40
- process.exit(result.status ?? 1);
41
- }
42
-
43
- function isMainModule() {
44
- if (!process.argv[1]) {
45
- return false;
46
- }
47
-
48
- return realpathSync(process.argv[1]) === fileURLToPath(import.meta.url);
49
- }
50
-
51
- if (isMainModule()) {
52
- main();
53
- }
@@ -1,15 +0,0 @@
1
- import assert from "node:assert/strict";
2
- import { join } from "node:path";
3
- import { nativeBinaryPath } from "./allowlister-remote-plugin.js";
4
-
5
- assert.ok(
6
- nativeBinaryPath("linux", "x64").endsWith(
7
- join("vendor", "linux-x64", "allowlister-remote-plugin"),
8
- ),
9
- );
10
- assert.ok(
11
- nativeBinaryPath("win32", "x64").endsWith(
12
- join("vendor", "win32-x64", "allowlister-remote-plugin.exe"),
13
- ),
14
- );
15
- assert.throws(() => nativeBinaryPath("sunos", "x64"), /Unsupported platform: sunos-x64/);