@rindle/cli 0.1.0-rc.6
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 +132 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +27 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +30 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +82 -0
- package/dist/index.js.map +1 -0
- package/dist/platform.d.ts +17 -0
- package/dist/platform.d.ts.map +1 -0
- package/dist/platform.js +54 -0
- package/dist/platform.js.map +1 -0
- package/package.json +100 -0
- package/src/cli.ts +28 -0
- package/src/index.ts +104 -0
- package/src/platform.ts +67 -0
package/README.md
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
# @rindle/cli — the Rindle toolchain, prebuilt for npm
|
|
2
|
+
|
|
3
|
+
The Rindle **CLI** (`rindle`) and **daemon** (`rindled`), shipped as prebuilt, per-platform binaries
|
|
4
|
+
you can `npm install`. This is how a JS/TS developer runs Rindle locally:
|
|
5
|
+
|
|
6
|
+
- **`rindled`** — the production Rindle server: the `rindle-server` crate (the SQLite-backed
|
|
7
|
+
[`rindle-replica`](../../rindle-replica) live-query engine plus the public subscription/lease
|
|
8
|
+
plane).
|
|
9
|
+
- **`rindle`** — the CLI to inspect, run, and manage a daemon: `rindle status` / `migrate` /
|
|
10
|
+
`schema`, plus the local-dev pair **`rindle init`** (scaffold) and **`rindle up`**
|
|
11
|
+
(run-and-supervise a local `rindled`, respawning it on crash or migrate-restart).
|
|
12
|
+
|
|
13
|
+
This is the network counterpart of [`@rindle/replica`](../replica): both run the same
|
|
14
|
+
`rindle-replica` engine, but `@rindle/replica` is a napi addon that embeds it **in-process**,
|
|
15
|
+
whereas `rindled` is the standalone daemon **executable** that serves many clients over the wire.
|
|
16
|
+
Talk to a running daemon from JS with [`@rindle/daemon-client`](../daemon-client).
|
|
17
|
+
|
|
18
|
+
> The all-TypeScript [`@rindle/server`](../reference/server) is the *reference* implementation of
|
|
19
|
+
> the same wire protocol; `rindled` is its production replacement.
|
|
20
|
+
|
|
21
|
+
## Install & run
|
|
22
|
+
|
|
23
|
+
```sh
|
|
24
|
+
npm i -D @rindle/cli
|
|
25
|
+
npx rindle init # scaffold daemon.json
|
|
26
|
+
npx rindle up # start + supervise a local rindled; prints how to connect
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
`rindle up` prints the address the daemon is reachable at (default `http://127.0.0.1:7600`) and how
|
|
30
|
+
to talk to it. From another terminal:
|
|
31
|
+
|
|
32
|
+
```sh
|
|
33
|
+
npx rindle status # inspect the running daemon
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
…or from your app, via [`@rindle/daemon-client`](../daemon-client) pointed at the same URL.
|
|
37
|
+
|
|
38
|
+
Installing pulls in exactly one prebuilt-binary package for your platform via
|
|
39
|
+
`optionalDependencies` (the esbuild/napi pattern) — nothing is compiled, and the other platforms'
|
|
40
|
+
binaries are never downloaded.
|
|
41
|
+
|
|
42
|
+
### `npm run rindle` / `npm run rindled`
|
|
43
|
+
|
|
44
|
+
`npm run <name>` runs a **script**, so add this to *your* `package.json` to drive `rindle` through
|
|
45
|
+
your package scripts:
|
|
46
|
+
|
|
47
|
+
```jsonc
|
|
48
|
+
{
|
|
49
|
+
"scripts": {
|
|
50
|
+
"rindle": "rindle"
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Then `npm run rindle up`. (Or skip the script and use `npx rindle …` directly — the bin is on your
|
|
56
|
+
`node_modules/.bin`.) The daemon is run by `rindle up`, not as its own command — see below.
|
|
57
|
+
|
|
58
|
+
## The daemon (`rindled`)
|
|
59
|
+
|
|
60
|
+
`rindled` is **not** exposed as a CLI command here — this package is a dev convenience, and `rindle
|
|
61
|
+
up` is the way to run a local daemon. The binary still ships (co-located with `rindle`), so for
|
|
62
|
+
embedding it in your own Node supervisor there are programmatic helpers:
|
|
63
|
+
|
|
64
|
+
```ts
|
|
65
|
+
import { spawnRindled, rindledBinaryPath } from "@rindle/cli";
|
|
66
|
+
|
|
67
|
+
const child = spawnRindled(["--config", "./rindled.toml"]); // inherits stdio
|
|
68
|
+
// …or just locate the binary and manage the process yourself:
|
|
69
|
+
const bin = rindledBinaryPath();
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
> Running the daemon directly under an external supervisor (systemd / Docker / k8s) in production is
|
|
73
|
+
> a job for the cargo-dist installers or a container image, not npm.
|
|
74
|
+
|
|
75
|
+
## How the packaging works
|
|
76
|
+
|
|
77
|
+
- **`@rindle/cli`** (this package) is a tiny, dependency-free launcher. Its `bin/rindle`
|
|
78
|
+
(`dist/cli.js`) resolves the matching `rindle` binary for the host and execs it, forwarding
|
|
79
|
+
argv/stdio and the exit code.
|
|
80
|
+
- **`@rindle/cli-<key>`** — one package per target (`darwin-arm64`, `darwin-x64`, `linux-x64-gnu`,
|
|
81
|
+
`linux-arm64-gnu`, `linux-x64-musl`, `linux-arm64-musl`, `win32-x64-msvc`), each carrying **both**
|
|
82
|
+
`rindle` and `rindled` for that platform under `bin/`,
|
|
83
|
+
gated by `os`/`cpu`/`libc`. They're listed as `optionalDependencies` of this package, so the
|
|
84
|
+
installer fetches only the matching one. They are **generated at release time** (like the napi
|
|
85
|
+
platform packages for `@rindle/replica`), never committed.
|
|
86
|
+
|
|
87
|
+
Both binaries ship **co-located** on purpose: even though only `rindle` is a bin, `rindle up` runs
|
|
88
|
+
`rindled` by finding it as a sibling of its own executable (rindle-cli §7.1), so the two must live in
|
|
89
|
+
the same `bin/` directory.
|
|
90
|
+
|
|
91
|
+
Resolution order at runtime (`src/index.ts`):
|
|
92
|
+
|
|
93
|
+
1. `RINDLE_BINARY_PATH` / `RINDLED_BINARY_PATH` — explicit path to that one binary.
|
|
94
|
+
2. `RINDLE_BIN_DIR` — a directory holding both (see dev usage below).
|
|
95
|
+
3. the installed `@rindle/cli-<key>` optional dependency.
|
|
96
|
+
|
|
97
|
+
## Local development (in this monorepo)
|
|
98
|
+
|
|
99
|
+
No platform packages are installed in the workspace, so build the binaries and point the launcher at
|
|
100
|
+
the build directory — one env var lights up both (and keeps them co-located for `rindle up`):
|
|
101
|
+
|
|
102
|
+
```sh
|
|
103
|
+
cargo build -p rindle-cli -p rindle-server --bin rindle --bin rindled --release
|
|
104
|
+
RINDLE_BIN_DIR="$PWD/target/release" npx rindle up # finds rindled in the same dir
|
|
105
|
+
RINDLE_BIN_DIR="$PWD/target/release" npx rindle status
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
(Or set `RINDLE_BINARY_PATH` / `RINDLED_BINARY_PATH` to point at one binary each — e.g.
|
|
109
|
+
`RINDLED_BINARY_PATH` is what `spawnRindled()` / `rindledBinaryPath()` resolve in dev.)
|
|
110
|
+
|
|
111
|
+
## Releasing
|
|
112
|
+
|
|
113
|
+
The native binaries already come from dist (cargo-dist): `rindle-cli` and `rindle-server` are both
|
|
114
|
+
`[package.metadata.dist] dist = true`, so dist builds `rindle` and `rindled` for all four targets
|
|
115
|
+
and uploads the archives + `dist-manifest.json` to a GitHub release.
|
|
116
|
+
`scripts/build-npm-packages.mjs` is the bridge from those artifacts to npm:
|
|
117
|
+
|
|
118
|
+
```sh
|
|
119
|
+
# from a published release (reads its dist-manifest.json — no archive-name guessing):
|
|
120
|
+
node scripts/build-npm-packages.mjs --from-release rindle-cli-v0.1.0 --update-root
|
|
121
|
+
|
|
122
|
+
# …or from locally available binaries laid out as <dir>/<rust-target>/<bin>[.exe]:
|
|
123
|
+
node scripts/build-npm-packages.mjs --bin-dir ./bins --version 0.1.0 --update-root
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
`--update-root` writes this package's `version` + `optionalDependencies` in lockstep. Then publish
|
|
127
|
+
each `npm/<key>` package, then the umbrella. (The binaries + targets live in `package.json` under
|
|
128
|
+
`"rindle"`, the single source of truth shared by the generator and the runtime resolver.)
|
|
129
|
+
|
|
130
|
+
> This package is currently `"private": true` / `0.0.0` while the API surface settles. Clear
|
|
131
|
+
> `private` and set a real version (the generator's `--version`/`--update-root` does the latter)
|
|
132
|
+
> before the first publish.
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// The `rindle` CLI bin (package.json "bin" → dist/cli.js; tsc preserves this shebang). Resolves the
|
|
3
|
+
// prebuilt `rindle` binary for this host and execs it, forwarding argv + stdio and propagating its
|
|
4
|
+
// exit code (or re-raising its terminating signal). The daemon (`rindled`) is intentionally NOT a
|
|
5
|
+
// bin — run it via `rindle up` (dev) or `spawnRindled()`; its binary still ships co-located so
|
|
6
|
+
// `rindle up` finds it as a sibling.
|
|
7
|
+
import { spawnSync } from "node:child_process";
|
|
8
|
+
import { binaryPath, UnsupportedPlatformError } from "./index.js";
|
|
9
|
+
let bin;
|
|
10
|
+
try {
|
|
11
|
+
bin = binaryPath("rindle");
|
|
12
|
+
}
|
|
13
|
+
catch (err) {
|
|
14
|
+
process.stderr.write(`rindle: ${err instanceof Error ? err.message : String(err)}\n`);
|
|
15
|
+
process.exit(err instanceof UnsupportedPlatformError ? 64 : 1); // 64 = EX_USAGE
|
|
16
|
+
}
|
|
17
|
+
const { status, signal, error } = spawnSync(bin, process.argv.slice(2), { stdio: "inherit" });
|
|
18
|
+
if (error) {
|
|
19
|
+
process.stderr.write(`rindle: failed to launch ${bin}: ${error.message}\n`);
|
|
20
|
+
process.exit(1);
|
|
21
|
+
}
|
|
22
|
+
if (typeof status === "number") {
|
|
23
|
+
process.exit(status);
|
|
24
|
+
}
|
|
25
|
+
// Killed by a signal — re-raise it on ourselves so the parent observes the same cause.
|
|
26
|
+
process.kill(process.pid, signal ?? "SIGTERM");
|
|
27
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,oGAAoG;AACpG,mGAAmG;AACnG,kGAAkG;AAClG,+FAA+F;AAC/F,qCAAqC;AACrC,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAE/C,OAAO,EAAE,UAAU,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAC;AAElE,IAAI,GAAW,CAAC;AAChB,IAAI,CAAC;IACH,GAAG,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC;AAC7B,CAAC;AAAC,OAAO,GAAG,EAAE,CAAC;IACb,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,WAAW,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACtF,OAAO,CAAC,IAAI,CAAC,GAAG,YAAY,wBAAwB,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,gBAAgB;AAClF,CAAC;AAED,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,SAAS,CAAC,GAAG,EAAE,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC;AAC9F,IAAI,KAAK,EAAE,CAAC;IACV,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,4BAA4B,GAAG,KAAK,KAAK,CAAC,OAAO,IAAI,CAAC,CAAC;IAC5E,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AACD,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE,CAAC;IAC/B,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AACvB,CAAC;AACD,uFAAuF;AACvF,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,MAAM,IAAI,SAAS,CAAC,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { type ChildProcess, type SpawnOptions } from "node:child_process";
|
|
2
|
+
import { type Binary } from "./platform.ts";
|
|
3
|
+
export { binaryName, platformKey, platformPackageName, UnsupportedPlatformError, } from "./platform.ts";
|
|
4
|
+
export type { Binary, Libc } from "./platform.ts";
|
|
5
|
+
/**
|
|
6
|
+
* Absolute path to a Rindle binary (`"rindle"` or `"rindled"`) for the current platform.
|
|
7
|
+
*
|
|
8
|
+
* Resolution order (the first three are dev overrides for working in this monorepo):
|
|
9
|
+
* 1. `RINDLE_BINARY_PATH` / `RINDLED_BINARY_PATH` — an explicit path to that one binary.
|
|
10
|
+
* 2. `RINDLE_BIN_DIR` — a directory holding both binaries. Point it at `target/release` after
|
|
11
|
+
* `cargo build -p rindle-cli -p rindle-server --release` and a single env var lights up both
|
|
12
|
+
* (and keeps them co-located, so `rindle up` still finds `rindled` as a sibling).
|
|
13
|
+
* 3. The matching `@rindle/cli-<key>` optional dependency that npm/pnpm installed.
|
|
14
|
+
*
|
|
15
|
+
* Throws `UnsupportedPlatformError` for an un-targeted host, or a descriptive Error if the
|
|
16
|
+
* platform package isn't installed (e.g. installed with `--no-optional`, or on a host the last
|
|
17
|
+
* publish didn't target) and no override is set.
|
|
18
|
+
*/
|
|
19
|
+
export declare function binaryPath(bin: Binary): string;
|
|
20
|
+
/** Absolute path to the `rindle` CLI binary for the current platform. See {@link binaryPath}. */
|
|
21
|
+
export declare function rindleBinaryPath(): string;
|
|
22
|
+
/** Absolute path to the `rindled` daemon binary for the current platform. See {@link binaryPath}. */
|
|
23
|
+
export declare function rindledBinaryPath(): string;
|
|
24
|
+
/** Spawn `bin` with `args`, inheriting stdio by default. A thin wrapper over `child_process.spawn`. */
|
|
25
|
+
export declare function spawnBinary(bin: Binary, args?: string[], options?: SpawnOptions): ChildProcess;
|
|
26
|
+
/** Spawn the `rindle` CLI with `args`. See {@link spawnBinary}. */
|
|
27
|
+
export declare function spawnRindle(args?: string[], options?: SpawnOptions): ChildProcess;
|
|
28
|
+
/** Spawn the `rindled` daemon with `args`, for embedding it in a Node supervisor. See {@link spawnBinary}. */
|
|
29
|
+
export declare function spawnRindled(args?: string[], options?: SpawnOptions): ChildProcess;
|
|
30
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAWA,OAAO,EAAS,KAAK,YAAY,EAAE,KAAK,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAKjF,OAAO,EAKL,KAAK,MAAM,EACZ,MAAM,eAAe,CAAC;AAEvB,OAAO,EACL,UAAU,EACV,WAAW,EACX,mBAAmB,EACnB,wBAAwB,GACzB,MAAM,eAAe,CAAC;AACvB,YAAY,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAIlD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CA8B9C;AAED,iGAAiG;AACjG,wBAAgB,gBAAgB,IAAI,MAAM,CAEzC;AAED,qGAAqG;AACrG,wBAAgB,iBAAiB,IAAI,MAAM,CAE1C;AAED,uGAAuG;AACvG,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,GAAE,MAAM,EAAO,EAAE,OAAO,GAAE,YAAiB,GAAG,YAAY,CAEtG;AAED,mEAAmE;AACnE,wBAAgB,WAAW,CAAC,IAAI,GAAE,MAAM,EAAO,EAAE,OAAO,GAAE,YAAiB,GAAG,YAAY,CAEzF;AAED,8GAA8G;AAC9G,wBAAgB,YAAY,CAAC,IAAI,GAAE,MAAM,EAAO,EAAE,OAAO,GAAE,YAAiB,GAAG,YAAY,CAE1F"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
// @rindle/cli — the Rindle toolchain (`rindle` CLI + `rindled` daemon) as prebuilt npm binaries.
|
|
2
|
+
//
|
|
3
|
+
// `rindled` is the *network front* of the engine: the `rindle-server` crate — the SQLite-backed
|
|
4
|
+
// `rindle-replica` live-query engine plus the public subscription/lease plane. `rindle` is the CLI
|
|
5
|
+
// that inspects and manages a deployed daemon (`rindle status`/`migrate`/…) and, for local dev,
|
|
6
|
+
// scaffolds and supervises one (`rindle init` / `rindle up`). Where `@rindle/replica` is a napi
|
|
7
|
+
// addon that embeds the engine *in-process*, this package ships the standalone executables,
|
|
8
|
+
// prebuilt per platform by dist (cargo-dist), **co-located** so `rindle up` finds `rindled` beside
|
|
9
|
+
// it. This module resolves the right binary for the host; the `rindle` bin (dist/cli.js) execs the
|
|
10
|
+
// CLI, and the daemon runs via `rindle up` or `spawnRindled()` (it is not exposed as its own bin —
|
|
11
|
+
// this package is a dev convenience). Pair with `@rindle/daemon-client` to talk to a running daemon.
|
|
12
|
+
import { spawn } from "node:child_process";
|
|
13
|
+
import { existsSync } from "node:fs";
|
|
14
|
+
import { createRequire } from "node:module";
|
|
15
|
+
import { dirname, join } from "node:path";
|
|
16
|
+
import { binaryName, platformKey, platformPackageName, UnsupportedPlatformError, } from "./platform.js";
|
|
17
|
+
export { binaryName, platformKey, platformPackageName, UnsupportedPlatformError, } from "./platform.js";
|
|
18
|
+
const require = createRequire(import.meta.url);
|
|
19
|
+
/**
|
|
20
|
+
* Absolute path to a Rindle binary (`"rindle"` or `"rindled"`) for the current platform.
|
|
21
|
+
*
|
|
22
|
+
* Resolution order (the first three are dev overrides for working in this monorepo):
|
|
23
|
+
* 1. `RINDLE_BINARY_PATH` / `RINDLED_BINARY_PATH` — an explicit path to that one binary.
|
|
24
|
+
* 2. `RINDLE_BIN_DIR` — a directory holding both binaries. Point it at `target/release` after
|
|
25
|
+
* `cargo build -p rindle-cli -p rindle-server --release` and a single env var lights up both
|
|
26
|
+
* (and keeps them co-located, so `rindle up` still finds `rindled` as a sibling).
|
|
27
|
+
* 3. The matching `@rindle/cli-<key>` optional dependency that npm/pnpm installed.
|
|
28
|
+
*
|
|
29
|
+
* Throws `UnsupportedPlatformError` for an un-targeted host, or a descriptive Error if the
|
|
30
|
+
* platform package isn't installed (e.g. installed with `--no-optional`, or on a host the last
|
|
31
|
+
* publish didn't target) and no override is set.
|
|
32
|
+
*/
|
|
33
|
+
export function binaryPath(bin) {
|
|
34
|
+
const explicit = process.env[`${bin.toUpperCase()}_BINARY_PATH`];
|
|
35
|
+
if (explicit) {
|
|
36
|
+
if (!existsSync(explicit)) {
|
|
37
|
+
throw new Error(`${bin.toUpperCase()}_BINARY_PATH points at a missing file: ${explicit}`);
|
|
38
|
+
}
|
|
39
|
+
return explicit;
|
|
40
|
+
}
|
|
41
|
+
const file = binaryName(bin);
|
|
42
|
+
const binDir = process.env.RINDLE_BIN_DIR;
|
|
43
|
+
if (binDir) {
|
|
44
|
+
const candidate = join(binDir, file);
|
|
45
|
+
if (existsSync(candidate))
|
|
46
|
+
return candidate;
|
|
47
|
+
// Fall through to the installed package — `RINDLE_BIN_DIR` may legitimately hold only one bin.
|
|
48
|
+
}
|
|
49
|
+
const key = platformKey(); // throws UnsupportedPlatformError for un-targeted hosts
|
|
50
|
+
const pkg = platformPackageName(key);
|
|
51
|
+
let manifest;
|
|
52
|
+
try {
|
|
53
|
+
manifest = require.resolve(`${pkg}/package.json`);
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
throw new Error(`${pkg} is not installed — the prebuilt Rindle binaries for "${key}" are missing.\n` +
|
|
57
|
+
`They ship as an optional dependency of @rindle/cli; reinstall without --no-optional, ` +
|
|
58
|
+
`or set RINDLE_BIN_DIR to a directory of locally built binaries.`);
|
|
59
|
+
}
|
|
60
|
+
return join(dirname(manifest), "bin", file);
|
|
61
|
+
}
|
|
62
|
+
/** Absolute path to the `rindle` CLI binary for the current platform. See {@link binaryPath}. */
|
|
63
|
+
export function rindleBinaryPath() {
|
|
64
|
+
return binaryPath("rindle");
|
|
65
|
+
}
|
|
66
|
+
/** Absolute path to the `rindled` daemon binary for the current platform. See {@link binaryPath}. */
|
|
67
|
+
export function rindledBinaryPath() {
|
|
68
|
+
return binaryPath("rindled");
|
|
69
|
+
}
|
|
70
|
+
/** Spawn `bin` with `args`, inheriting stdio by default. A thin wrapper over `child_process.spawn`. */
|
|
71
|
+
export function spawnBinary(bin, args = [], options = {}) {
|
|
72
|
+
return spawn(binaryPath(bin), args, { stdio: "inherit", ...options });
|
|
73
|
+
}
|
|
74
|
+
/** Spawn the `rindle` CLI with `args`. See {@link spawnBinary}. */
|
|
75
|
+
export function spawnRindle(args = [], options = {}) {
|
|
76
|
+
return spawnBinary("rindle", args, options);
|
|
77
|
+
}
|
|
78
|
+
/** Spawn the `rindled` daemon with `args`, for embedding it in a Node supervisor. See {@link spawnBinary}. */
|
|
79
|
+
export function spawnRindled(args = [], options = {}) {
|
|
80
|
+
return spawnBinary("rindled", args, options);
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,iGAAiG;AACjG,EAAE;AACF,gGAAgG;AAChG,mGAAmG;AACnG,gGAAgG;AAChG,gGAAgG;AAChG,4FAA4F;AAC5F,mGAAmG;AACnG,mGAAmG;AACnG,mGAAmG;AACnG,qGAAqG;AACrG,OAAO,EAAE,KAAK,EAAwC,MAAM,oBAAoB,CAAC;AACjF,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAE1C,OAAO,EACL,UAAU,EACV,WAAW,EACX,mBAAmB,EACnB,wBAAwB,GAEzB,MAAM,eAAe,CAAC;AAEvB,OAAO,EACL,UAAU,EACV,WAAW,EACX,mBAAmB,EACnB,wBAAwB,GACzB,MAAM,eAAe,CAAC;AAGvB,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAE/C;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,UAAU,CAAC,GAAW;IACpC,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,WAAW,EAAE,cAAc,CAAC,CAAC;IACjE,IAAI,QAAQ,EAAE,CAAC;QACb,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC1B,MAAM,IAAI,KAAK,CAAC,GAAG,GAAG,CAAC,WAAW,EAAE,0CAA0C,QAAQ,EAAE,CAAC,CAAC;QAC5F,CAAC;QACD,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,MAAM,IAAI,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC;IAC7B,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC;IAC1C,IAAI,MAAM,EAAE,CAAC;QACX,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QACrC,IAAI,UAAU,CAAC,SAAS,CAAC;YAAE,OAAO,SAAS,CAAC;QAC5C,+FAA+F;IACjG,CAAC;IAED,MAAM,GAAG,GAAG,WAAW,EAAE,CAAC,CAAC,wDAAwD;IACnF,MAAM,GAAG,GAAG,mBAAmB,CAAC,GAAG,CAAC,CAAC;IACrC,IAAI,QAAgB,CAAC;IACrB,IAAI,CAAC;QACH,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,GAAG,eAAe,CAAC,CAAC;IACpD,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CACb,GAAG,GAAG,yDAAyD,GAAG,kBAAkB;YAClF,uFAAuF;YACvF,iEAAiE,CACpE,CAAC;IACJ,CAAC;IACD,OAAO,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC;AAC9C,CAAC;AAED,iGAAiG;AACjG,MAAM,UAAU,gBAAgB;IAC9B,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC;AAC9B,CAAC;AAED,qGAAqG;AACrG,MAAM,UAAU,iBAAiB;IAC/B,OAAO,UAAU,CAAC,SAAS,CAAC,CAAC;AAC/B,CAAC;AAED,uGAAuG;AACvG,MAAM,UAAU,WAAW,CAAC,GAAW,EAAE,OAAiB,EAAE,EAAE,UAAwB,EAAE;IACtF,OAAO,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,OAAO,EAAE,CAAC,CAAC;AACxE,CAAC;AAED,mEAAmE;AACnE,MAAM,UAAU,WAAW,CAAC,OAAiB,EAAE,EAAE,UAAwB,EAAE;IACzE,OAAO,WAAW,CAAC,QAAQ,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;AAC9C,CAAC;AAED,8GAA8G;AAC9G,MAAM,UAAU,YAAY,CAAC,OAAiB,EAAE,EAAE,UAAwB,EAAE;IAC1E,OAAO,WAAW,CAAC,SAAS,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;AAC/C,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export type Libc = "gnu" | "musl";
|
|
2
|
+
/** A Rindle binary shipped by this toolchain: the CLI (`rindle`) or the daemon (`rindled`). */
|
|
3
|
+
export type Binary = "rindle" | "rindled";
|
|
4
|
+
/**
|
|
5
|
+
* The package-name suffix identifying a build target for the current (or given) host:
|
|
6
|
+
* `darwin-{arm64,x64}`, `linux-{x64,arm64}-{gnu,musl}`, `win32-x64-msvc`. Throws
|
|
7
|
+
* `UnsupportedPlatformError` for a host we don't publish binaries for.
|
|
8
|
+
*/
|
|
9
|
+
export declare function platformKey(platform?: NodeJS.Platform, arch?: string, libc?: Libc): string;
|
|
10
|
+
/** The npm package name carrying the binaries for `key` (default: the current host's key). */
|
|
11
|
+
export declare function platformPackageName(key?: string): string;
|
|
12
|
+
/** The on-disk filename of `bin` inside a platform package (`rindle` / `rindled.exe`). */
|
|
13
|
+
export declare function binaryName(bin: Binary, platform?: NodeJS.Platform): string;
|
|
14
|
+
export declare class UnsupportedPlatformError extends Error {
|
|
15
|
+
constructor(platform: string, arch: string);
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=platform.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"platform.d.ts","sourceRoot":"","sources":["../src/platform.ts"],"names":[],"mappings":"AASA,MAAM,MAAM,IAAI,GAAG,KAAK,GAAG,MAAM,CAAC;AAElC,+FAA+F;AAC/F,MAAM,MAAM,MAAM,GAAG,QAAQ,GAAG,SAAS,CAAC;AAE1C;;;;GAIG;AACH,wBAAgB,WAAW,CACzB,QAAQ,GAAE,MAAM,CAAC,QAA2B,EAC5C,IAAI,GAAE,MAAqB,EAC3B,IAAI,GAAE,IAA2B,GAChC,MAAM,CAWR;AAED,8FAA8F;AAC9F,wBAAgB,mBAAmB,CAAC,GAAG,GAAE,MAAsB,GAAG,MAAM,CAEvE;AAED,0FAA0F;AAC1F,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,GAAE,MAAM,CAAC,QAA2B,GAAG,MAAM,CAE5F;AAED,qBAAa,wBAAyB,SAAQ,KAAK;gBACrC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM;CAI3C"}
|
package/dist/platform.js
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
// Single source of truth for mapping the *running* Node platform to the per-platform package that
|
|
2
|
+
// carries the prebuilt Rindle binaries (`rindle` + `rindled`) for it. Those packages
|
|
3
|
+
// (`@rindle/cli-<key>`) are generated at release time by `scripts/build-npm-packages.mjs` from
|
|
4
|
+
// dist's (cargo-dist) release archives, and declared as optionalDependencies of this umbrella
|
|
5
|
+
// package — so npm/pnpm install only the one whose `os`/`cpu` match the host. Both binaries ship
|
|
6
|
+
// **co-located** in that one package's `bin/`, which is required: the `rindle` CLI's `rindle up`
|
|
7
|
+
// finds `rindled` as a sibling of its own executable (rindle-cli §7.1). This module and the
|
|
8
|
+
// generator MUST agree on the `<key>` scheme; it is defined here and mirrored in the generator.
|
|
9
|
+
/**
|
|
10
|
+
* The package-name suffix identifying a build target for the current (or given) host:
|
|
11
|
+
* `darwin-{arm64,x64}`, `linux-{x64,arm64}-{gnu,musl}`, `win32-x64-msvc`. Throws
|
|
12
|
+
* `UnsupportedPlatformError` for a host we don't publish binaries for.
|
|
13
|
+
*/
|
|
14
|
+
export function platformKey(platform = process.platform, arch = process.arch, libc = detectLibc(platform)) {
|
|
15
|
+
switch (platform) {
|
|
16
|
+
case "darwin":
|
|
17
|
+
return `darwin-${arch}`;
|
|
18
|
+
case "linux":
|
|
19
|
+
return `linux-${arch}-${libc}`;
|
|
20
|
+
case "win32":
|
|
21
|
+
return `win32-${arch}-msvc`;
|
|
22
|
+
default:
|
|
23
|
+
throw new UnsupportedPlatformError(platform, arch);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
/** The npm package name carrying the binaries for `key` (default: the current host's key). */
|
|
27
|
+
export function platformPackageName(key = platformKey()) {
|
|
28
|
+
return `@rindle/cli-${key}`;
|
|
29
|
+
}
|
|
30
|
+
/** The on-disk filename of `bin` inside a platform package (`rindle` / `rindled.exe`). */
|
|
31
|
+
export function binaryName(bin, platform = process.platform) {
|
|
32
|
+
return platform === "win32" ? `${bin}.exe` : bin;
|
|
33
|
+
}
|
|
34
|
+
export class UnsupportedPlatformError extends Error {
|
|
35
|
+
constructor(platform, arch) {
|
|
36
|
+
super(`@rindle/cli ships no prebuilt Rindle binaries for ${platform}-${arch}`);
|
|
37
|
+
this.name = "UnsupportedPlatformError";
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
// glibc vs musl: Node reports the runtime glibc version in its process report on glibc systems;
|
|
41
|
+
// its absence on linux implies musl. We publish both `-gnu` and `-musl` Linux packages, so this
|
|
42
|
+
// picks the right one (and avoids a `detect-libc` dependency — the launcher stays dep-free).
|
|
43
|
+
function detectLibc(platform) {
|
|
44
|
+
if (platform !== "linux")
|
|
45
|
+
return "gnu";
|
|
46
|
+
try {
|
|
47
|
+
const report = process.report?.getReport();
|
|
48
|
+
return report?.header?.glibcVersionRuntime ? "gnu" : "musl";
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
return "gnu";
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=platform.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"platform.js","sourceRoot":"","sources":["../src/platform.ts"],"names":[],"mappings":"AAAA,kGAAkG;AAClG,qFAAqF;AACrF,+FAA+F;AAC/F,8FAA8F;AAC9F,iGAAiG;AACjG,iGAAiG;AACjG,4FAA4F;AAC5F,gGAAgG;AAOhG;;;;GAIG;AACH,MAAM,UAAU,WAAW,CACzB,WAA4B,OAAO,CAAC,QAAQ,EAC5C,OAAe,OAAO,CAAC,IAAI,EAC3B,OAAa,UAAU,CAAC,QAAQ,CAAC;IAEjC,QAAQ,QAAQ,EAAE,CAAC;QACjB,KAAK,QAAQ;YACX,OAAO,UAAU,IAAI,EAAE,CAAC;QAC1B,KAAK,OAAO;YACV,OAAO,SAAS,IAAI,IAAI,IAAI,EAAE,CAAC;QACjC,KAAK,OAAO;YACV,OAAO,SAAS,IAAI,OAAO,CAAC;QAC9B;YACE,MAAM,IAAI,wBAAwB,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;IACvD,CAAC;AACH,CAAC;AAED,8FAA8F;AAC9F,MAAM,UAAU,mBAAmB,CAAC,MAAc,WAAW,EAAE;IAC7D,OAAO,eAAe,GAAG,EAAE,CAAC;AAC9B,CAAC;AAED,0FAA0F;AAC1F,MAAM,UAAU,UAAU,CAAC,GAAW,EAAE,WAA4B,OAAO,CAAC,QAAQ;IAClF,OAAO,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,GAAG,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC;AACnD,CAAC;AAED,MAAM,OAAO,wBAAyB,SAAQ,KAAK;IACjD,YAAY,QAAgB,EAAE,IAAY;QACxC,KAAK,CAAC,qDAAqD,QAAQ,IAAI,IAAI,EAAE,CAAC,CAAC;QAC/E,IAAI,CAAC,IAAI,GAAG,0BAA0B,CAAC;IACzC,CAAC;CACF;AAED,gGAAgG;AAChG,gGAAgG;AAChG,6FAA6F;AAC7F,SAAS,UAAU,CAAC,QAAyB;IAC3C,IAAI,QAAQ,KAAK,OAAO;QAAE,OAAO,KAAK,CAAC;IACvC,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,SAAS,EAE3B,CAAC;QACd,OAAO,MAAM,EAAE,MAAM,EAAE,mBAAmB,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC;IAC9D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@rindle/cli",
|
|
3
|
+
"version": "0.1.0-rc.6",
|
|
4
|
+
"license": "Apache-2.0",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "git+https://github.com/rindle-sh/rindle.git",
|
|
8
|
+
"directory": "packages/cli"
|
|
9
|
+
},
|
|
10
|
+
"type": "module",
|
|
11
|
+
"description": "The Rindle toolchain for JS devs: the `rindle` CLI and the `rindled` daemon as prebuilt, per-platform binaries you can `npm install`. `rindle up` scaffolds and supervises a local daemon.",
|
|
12
|
+
"main": "./dist/index.js",
|
|
13
|
+
"types": "./dist/index.d.ts",
|
|
14
|
+
"sideEffects": false,
|
|
15
|
+
"bin": {
|
|
16
|
+
"rindle": "./dist/cli.js"
|
|
17
|
+
},
|
|
18
|
+
"exports": {
|
|
19
|
+
".": {
|
|
20
|
+
"@rindle/source": "./src/index.ts",
|
|
21
|
+
"types": "./dist/index.d.ts",
|
|
22
|
+
"default": "./dist/index.js"
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"files": [
|
|
26
|
+
"dist",
|
|
27
|
+
"src",
|
|
28
|
+
"README.md"
|
|
29
|
+
],
|
|
30
|
+
"engines": {
|
|
31
|
+
"node": ">=22"
|
|
32
|
+
},
|
|
33
|
+
"scripts": {
|
|
34
|
+
"build": "tsc -p tsconfig.build.json",
|
|
35
|
+
"typecheck": "tsc --noEmit",
|
|
36
|
+
"test": "tsc --noEmit && node --conditions=@rindle/source --test test/*.test.ts",
|
|
37
|
+
"build:npm": "node scripts/build-npm-packages.mjs"
|
|
38
|
+
},
|
|
39
|
+
"rindle": {
|
|
40
|
+
"binaries": [
|
|
41
|
+
"rindle",
|
|
42
|
+
"rindled"
|
|
43
|
+
],
|
|
44
|
+
"repository": "rindle-sh/rindle",
|
|
45
|
+
"targets": [
|
|
46
|
+
{
|
|
47
|
+
"rust": "aarch64-apple-darwin",
|
|
48
|
+
"os": "darwin",
|
|
49
|
+
"cpu": "arm64"
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
"rust": "x86_64-apple-darwin",
|
|
53
|
+
"os": "darwin",
|
|
54
|
+
"cpu": "x64"
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
"rust": "x86_64-unknown-linux-gnu",
|
|
58
|
+
"os": "linux",
|
|
59
|
+
"cpu": "x64",
|
|
60
|
+
"libc": "gnu"
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
"rust": "aarch64-unknown-linux-gnu",
|
|
64
|
+
"os": "linux",
|
|
65
|
+
"cpu": "arm64",
|
|
66
|
+
"libc": "gnu"
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
"rust": "x86_64-unknown-linux-musl",
|
|
70
|
+
"os": "linux",
|
|
71
|
+
"cpu": "x64",
|
|
72
|
+
"libc": "musl"
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
"rust": "aarch64-unknown-linux-musl",
|
|
76
|
+
"os": "linux",
|
|
77
|
+
"cpu": "arm64",
|
|
78
|
+
"libc": "musl"
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
"rust": "x86_64-pc-windows-msvc",
|
|
82
|
+
"os": "win32",
|
|
83
|
+
"cpu": "x64"
|
|
84
|
+
}
|
|
85
|
+
]
|
|
86
|
+
},
|
|
87
|
+
"devDependencies": {
|
|
88
|
+
"@types/node": "^22.10.0",
|
|
89
|
+
"typescript": "^5.7.0"
|
|
90
|
+
},
|
|
91
|
+
"optionalDependencies": {
|
|
92
|
+
"@rindle/cli-darwin-arm64": "0.1.0-rc.6",
|
|
93
|
+
"@rindle/cli-darwin-x64": "0.1.0-rc.6",
|
|
94
|
+
"@rindle/cli-linux-arm64-gnu": "0.1.0-rc.6",
|
|
95
|
+
"@rindle/cli-linux-arm64-musl": "0.1.0-rc.6",
|
|
96
|
+
"@rindle/cli-linux-x64-gnu": "0.1.0-rc.6",
|
|
97
|
+
"@rindle/cli-linux-x64-musl": "0.1.0-rc.6",
|
|
98
|
+
"@rindle/cli-win32-x64-msvc": "0.1.0-rc.6"
|
|
99
|
+
}
|
|
100
|
+
}
|
package/src/cli.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// The `rindle` CLI bin (package.json "bin" → dist/cli.js; tsc preserves this shebang). Resolves the
|
|
3
|
+
// prebuilt `rindle` binary for this host and execs it, forwarding argv + stdio and propagating its
|
|
4
|
+
// exit code (or re-raising its terminating signal). The daemon (`rindled`) is intentionally NOT a
|
|
5
|
+
// bin — run it via `rindle up` (dev) or `spawnRindled()`; its binary still ships co-located so
|
|
6
|
+
// `rindle up` finds it as a sibling.
|
|
7
|
+
import { spawnSync } from "node:child_process";
|
|
8
|
+
|
|
9
|
+
import { binaryPath, UnsupportedPlatformError } from "./index.ts";
|
|
10
|
+
|
|
11
|
+
let bin: string;
|
|
12
|
+
try {
|
|
13
|
+
bin = binaryPath("rindle");
|
|
14
|
+
} catch (err) {
|
|
15
|
+
process.stderr.write(`rindle: ${err instanceof Error ? err.message : String(err)}\n`);
|
|
16
|
+
process.exit(err instanceof UnsupportedPlatformError ? 64 : 1); // 64 = EX_USAGE
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const { status, signal, error } = spawnSync(bin, process.argv.slice(2), { stdio: "inherit" });
|
|
20
|
+
if (error) {
|
|
21
|
+
process.stderr.write(`rindle: failed to launch ${bin}: ${error.message}\n`);
|
|
22
|
+
process.exit(1);
|
|
23
|
+
}
|
|
24
|
+
if (typeof status === "number") {
|
|
25
|
+
process.exit(status);
|
|
26
|
+
}
|
|
27
|
+
// Killed by a signal — re-raise it on ourselves so the parent observes the same cause.
|
|
28
|
+
process.kill(process.pid, signal ?? "SIGTERM");
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
// @rindle/cli — the Rindle toolchain (`rindle` CLI + `rindled` daemon) as prebuilt npm binaries.
|
|
2
|
+
//
|
|
3
|
+
// `rindled` is the *network front* of the engine: the `rindle-server` crate — the SQLite-backed
|
|
4
|
+
// `rindle-replica` live-query engine plus the public subscription/lease plane. `rindle` is the CLI
|
|
5
|
+
// that inspects and manages a deployed daemon (`rindle status`/`migrate`/…) and, for local dev,
|
|
6
|
+
// scaffolds and supervises one (`rindle init` / `rindle up`). Where `@rindle/replica` is a napi
|
|
7
|
+
// addon that embeds the engine *in-process*, this package ships the standalone executables,
|
|
8
|
+
// prebuilt per platform by dist (cargo-dist), **co-located** so `rindle up` finds `rindled` beside
|
|
9
|
+
// it. This module resolves the right binary for the host; the `rindle` bin (dist/cli.js) execs the
|
|
10
|
+
// CLI, and the daemon runs via `rindle up` or `spawnRindled()` (it is not exposed as its own bin —
|
|
11
|
+
// this package is a dev convenience). Pair with `@rindle/daemon-client` to talk to a running daemon.
|
|
12
|
+
import { spawn, type ChildProcess, type SpawnOptions } from "node:child_process";
|
|
13
|
+
import { existsSync } from "node:fs";
|
|
14
|
+
import { createRequire } from "node:module";
|
|
15
|
+
import { dirname, join } from "node:path";
|
|
16
|
+
|
|
17
|
+
import {
|
|
18
|
+
binaryName,
|
|
19
|
+
platformKey,
|
|
20
|
+
platformPackageName,
|
|
21
|
+
UnsupportedPlatformError,
|
|
22
|
+
type Binary,
|
|
23
|
+
} from "./platform.ts";
|
|
24
|
+
|
|
25
|
+
export {
|
|
26
|
+
binaryName,
|
|
27
|
+
platformKey,
|
|
28
|
+
platformPackageName,
|
|
29
|
+
UnsupportedPlatformError,
|
|
30
|
+
} from "./platform.ts";
|
|
31
|
+
export type { Binary, Libc } from "./platform.ts";
|
|
32
|
+
|
|
33
|
+
const require = createRequire(import.meta.url);
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Absolute path to a Rindle binary (`"rindle"` or `"rindled"`) for the current platform.
|
|
37
|
+
*
|
|
38
|
+
* Resolution order (the first three are dev overrides for working in this monorepo):
|
|
39
|
+
* 1. `RINDLE_BINARY_PATH` / `RINDLED_BINARY_PATH` — an explicit path to that one binary.
|
|
40
|
+
* 2. `RINDLE_BIN_DIR` — a directory holding both binaries. Point it at `target/release` after
|
|
41
|
+
* `cargo build -p rindle-cli -p rindle-server --release` and a single env var lights up both
|
|
42
|
+
* (and keeps them co-located, so `rindle up` still finds `rindled` as a sibling).
|
|
43
|
+
* 3. The matching `@rindle/cli-<key>` optional dependency that npm/pnpm installed.
|
|
44
|
+
*
|
|
45
|
+
* Throws `UnsupportedPlatformError` for an un-targeted host, or a descriptive Error if the
|
|
46
|
+
* platform package isn't installed (e.g. installed with `--no-optional`, or on a host the last
|
|
47
|
+
* publish didn't target) and no override is set.
|
|
48
|
+
*/
|
|
49
|
+
export function binaryPath(bin: Binary): string {
|
|
50
|
+
const explicit = process.env[`${bin.toUpperCase()}_BINARY_PATH`];
|
|
51
|
+
if (explicit) {
|
|
52
|
+
if (!existsSync(explicit)) {
|
|
53
|
+
throw new Error(`${bin.toUpperCase()}_BINARY_PATH points at a missing file: ${explicit}`);
|
|
54
|
+
}
|
|
55
|
+
return explicit;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const file = binaryName(bin);
|
|
59
|
+
const binDir = process.env.RINDLE_BIN_DIR;
|
|
60
|
+
if (binDir) {
|
|
61
|
+
const candidate = join(binDir, file);
|
|
62
|
+
if (existsSync(candidate)) return candidate;
|
|
63
|
+
// Fall through to the installed package — `RINDLE_BIN_DIR` may legitimately hold only one bin.
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const key = platformKey(); // throws UnsupportedPlatformError for un-targeted hosts
|
|
67
|
+
const pkg = platformPackageName(key);
|
|
68
|
+
let manifest: string;
|
|
69
|
+
try {
|
|
70
|
+
manifest = require.resolve(`${pkg}/package.json`);
|
|
71
|
+
} catch {
|
|
72
|
+
throw new Error(
|
|
73
|
+
`${pkg} is not installed — the prebuilt Rindle binaries for "${key}" are missing.\n` +
|
|
74
|
+
`They ship as an optional dependency of @rindle/cli; reinstall without --no-optional, ` +
|
|
75
|
+
`or set RINDLE_BIN_DIR to a directory of locally built binaries.`,
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
return join(dirname(manifest), "bin", file);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/** Absolute path to the `rindle` CLI binary for the current platform. See {@link binaryPath}. */
|
|
82
|
+
export function rindleBinaryPath(): string {
|
|
83
|
+
return binaryPath("rindle");
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/** Absolute path to the `rindled` daemon binary for the current platform. See {@link binaryPath}. */
|
|
87
|
+
export function rindledBinaryPath(): string {
|
|
88
|
+
return binaryPath("rindled");
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/** Spawn `bin` with `args`, inheriting stdio by default. A thin wrapper over `child_process.spawn`. */
|
|
92
|
+
export function spawnBinary(bin: Binary, args: string[] = [], options: SpawnOptions = {}): ChildProcess {
|
|
93
|
+
return spawn(binaryPath(bin), args, { stdio: "inherit", ...options });
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/** Spawn the `rindle` CLI with `args`. See {@link spawnBinary}. */
|
|
97
|
+
export function spawnRindle(args: string[] = [], options: SpawnOptions = {}): ChildProcess {
|
|
98
|
+
return spawnBinary("rindle", args, options);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/** Spawn the `rindled` daemon with `args`, for embedding it in a Node supervisor. See {@link spawnBinary}. */
|
|
102
|
+
export function spawnRindled(args: string[] = [], options: SpawnOptions = {}): ChildProcess {
|
|
103
|
+
return spawnBinary("rindled", args, options);
|
|
104
|
+
}
|
package/src/platform.ts
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
// Single source of truth for mapping the *running* Node platform to the per-platform package that
|
|
2
|
+
// carries the prebuilt Rindle binaries (`rindle` + `rindled`) for it. Those packages
|
|
3
|
+
// (`@rindle/cli-<key>`) are generated at release time by `scripts/build-npm-packages.mjs` from
|
|
4
|
+
// dist's (cargo-dist) release archives, and declared as optionalDependencies of this umbrella
|
|
5
|
+
// package — so npm/pnpm install only the one whose `os`/`cpu` match the host. Both binaries ship
|
|
6
|
+
// **co-located** in that one package's `bin/`, which is required: the `rindle` CLI's `rindle up`
|
|
7
|
+
// finds `rindled` as a sibling of its own executable (rindle-cli §7.1). This module and the
|
|
8
|
+
// generator MUST agree on the `<key>` scheme; it is defined here and mirrored in the generator.
|
|
9
|
+
|
|
10
|
+
export type Libc = "gnu" | "musl";
|
|
11
|
+
|
|
12
|
+
/** A Rindle binary shipped by this toolchain: the CLI (`rindle`) or the daemon (`rindled`). */
|
|
13
|
+
export type Binary = "rindle" | "rindled";
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* The package-name suffix identifying a build target for the current (or given) host:
|
|
17
|
+
* `darwin-{arm64,x64}`, `linux-{x64,arm64}-{gnu,musl}`, `win32-x64-msvc`. Throws
|
|
18
|
+
* `UnsupportedPlatformError` for a host we don't publish binaries for.
|
|
19
|
+
*/
|
|
20
|
+
export function platformKey(
|
|
21
|
+
platform: NodeJS.Platform = process.platform,
|
|
22
|
+
arch: string = process.arch,
|
|
23
|
+
libc: Libc = detectLibc(platform),
|
|
24
|
+
): string {
|
|
25
|
+
switch (platform) {
|
|
26
|
+
case "darwin":
|
|
27
|
+
return `darwin-${arch}`;
|
|
28
|
+
case "linux":
|
|
29
|
+
return `linux-${arch}-${libc}`;
|
|
30
|
+
case "win32":
|
|
31
|
+
return `win32-${arch}-msvc`;
|
|
32
|
+
default:
|
|
33
|
+
throw new UnsupportedPlatformError(platform, arch);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** The npm package name carrying the binaries for `key` (default: the current host's key). */
|
|
38
|
+
export function platformPackageName(key: string = platformKey()): string {
|
|
39
|
+
return `@rindle/cli-${key}`;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** The on-disk filename of `bin` inside a platform package (`rindle` / `rindled.exe`). */
|
|
43
|
+
export function binaryName(bin: Binary, platform: NodeJS.Platform = process.platform): string {
|
|
44
|
+
return platform === "win32" ? `${bin}.exe` : bin;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export class UnsupportedPlatformError extends Error {
|
|
48
|
+
constructor(platform: string, arch: string) {
|
|
49
|
+
super(`@rindle/cli ships no prebuilt Rindle binaries for ${platform}-${arch}`);
|
|
50
|
+
this.name = "UnsupportedPlatformError";
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// glibc vs musl: Node reports the runtime glibc version in its process report on glibc systems;
|
|
55
|
+
// its absence on linux implies musl. We publish both `-gnu` and `-musl` Linux packages, so this
|
|
56
|
+
// picks the right one (and avoids a `detect-libc` dependency — the launcher stays dep-free).
|
|
57
|
+
function detectLibc(platform: NodeJS.Platform): Libc {
|
|
58
|
+
if (platform !== "linux") return "gnu";
|
|
59
|
+
try {
|
|
60
|
+
const report = process.report?.getReport() as
|
|
61
|
+
| { header?: { glibcVersionRuntime?: string } }
|
|
62
|
+
| undefined;
|
|
63
|
+
return report?.header?.glibcVersionRuntime ? "gnu" : "musl";
|
|
64
|
+
} catch {
|
|
65
|
+
return "gnu";
|
|
66
|
+
}
|
|
67
|
+
}
|