@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 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,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=cli.d.ts.map
@@ -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
@@ -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"}
@@ -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":"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"}
@@ -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"}
@@ -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
+ }
@@ -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
+ }