dartvel_dev 0.2.1 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +22 -22
  2. package/index.js +131 -67
  3. package/package.json +2 -2
package/README.md CHANGED
@@ -10,33 +10,33 @@ npm install -g dartvel_dev
10
10
  dartvel --help
11
11
  ```
12
12
 
13
- ## Why the package is `dartvel_dev` and the command is `dartvel`
14
-
15
- `dartvel` on pub.dev was taken on 2026-08-06 by an unrelated package, so the
16
- published identifier carries a suffix. The command you type does not, and
17
- neither does anything else you interact with.
13
+ ## No SDK needed to run it
18
14
 
19
- The same name is used on [pub.dev](https://pub.dev/packages/dartvel_dev) and in
20
- the [Homebrew tap](https://github.com/Danroyal001/homebrew-dartvel_dev), so
21
- whichever way you install it, it is called the same thing.
15
+ This downloads a self-contained `dartvel` binary for your platform. The Dart
16
+ runtime and the Rust server library are linked into it, so nothing has to be
17
+ installed first.
22
18
 
23
- ## What this package does
19
+ Building an application still needs Flutter, for whichever target you are
20
+ building. Running the CLI does not.
24
21
 
25
- It launches the real CLI rather than containing a copy of it.
22
+ An earlier version of this package ran `dart pub global activate` instead, and
23
+ that could not work: the umbrella package depends on the Flutter SDK, and pub
24
+ refuses to run a global executable from a package that does. It activated and
25
+ then would not run.
26
26
 
27
- Dartvel is a Dart toolchain: `dartvel` is a Dart executable published on
28
- pub.dev. Vendoring a compiled build into an npm package would ship a second
29
- copy that drifts from the one `dart pub global activate` installs, and would
30
- need a release per platform before this package could exist at all.
27
+ ## Platforms
31
28
 
32
- So on first run this finds `dartvel` on your PATH, and if it is not there,
33
- installs it with `dart pub global activate dartvel_dev` and runs it through
34
- `dart pub global run` — which works whether or not `~/.pub-cache/bin` is on
35
- your PATH.
29
+ Linux, macOS and Windows, on x64; Linux and macOS also on arm64. An
30
+ unsupported combination says which one rather than fetching a URL that 404s.
36
31
 
37
- If there is no Dart SDK at all, it says so and points at the Flutter installer,
38
- rather than failing with a command-not-found from somewhere three layers down.
32
+ The download is checked against the SHA256SUMS published with the release
33
+ before it is made executable, so a truncated fetch fails as a checksum
34
+ mismatch rather than as a mysterious crash in the tool.
39
35
 
40
- ## Requirements
36
+ ## Why the package is `dartvel_dev` and the command is `dartvel`
41
37
 
42
- The Dart SDK, which the Flutter SDK includes. Node 18 or newer.
38
+ `dartvel` on pub.dev was taken on 2026-08-06 by an unrelated package, so the
39
+ published identifier carries a suffix. The command does not, and neither does
40
+ anything else you interact with. The same name is used on
41
+ [pub.dev](https://pub.dev/packages/dartvel_dev), npm and in the
42
+ [Homebrew tap](https://github.com/Danroyal001/homebrew-dartvel_dev).
package/index.js CHANGED
@@ -1,101 +1,165 @@
1
- // A launcher, not a copy of the framework.
1
+ // Fetches the self-contained `dartvel` binary for this platform and runs it.
2
2
  //
3
- // Dartvel is a Dart toolchain: the `dartvel` command is a Dart executable
4
- // published on pub.dev as `dartvel_dev`. Vendoring a compiled build of it into
5
- // an npm package would ship a second copy that drifts from the one
6
- // `dart pub global activate` installs, so this finds the real one, installs it
7
- // on first use, and gets out of the way.
3
+ // The CLI is a Dart program, but it does not need a Dart SDK to run: `dart
4
+ // build cli` links the Dart runtime and dartvel_shelf's Rust library into one
5
+ // executable. So this package downloads that executable rather than requiring
6
+ // a toolchain.
8
7
  //
9
- // The npm package exists because many people reach for `npx` before anything
10
- // else, and because the name should belong to the project.
8
+ // It used to run `dart pub global activate` instead, and that could not work.
9
+ // The umbrella depends on the Flutter SDK and pub refuses to run a global
10
+ // executable from a package that does — it activated and then would not run,
11
+ // which looks installed and is not:
11
12
  //
12
- // The package is `dartvel_dev` and the command is `dartvel`. Those differ on
13
- // purpose: `dartvel` was taken on pub.dev on 2026-08-06 by an unrelated
14
- // package, so the published name carries the suffix while the thing you type
15
- // does not.
13
+ // dartvel_dev as globally activated requires the Flutter SDK, which is
14
+ // unsupported for global executables
15
+ //
16
+ // Building the CLI still needs Flutter, for whichever target you are building.
17
+ // Running the CLI does not.
16
18
 
17
19
  'use strict';
18
20
 
19
- const { spawn, spawnSync } = require('child_process');
21
+ const fs = require('fs');
22
+ const https = require('https');
23
+ const os = require('os');
24
+ const path = require('path');
25
+ const crypto = require('crypto');
26
+ const { spawn } = require('child_process');
20
27
 
21
- /** The pub.dev package that carries the CLI. */
22
- const PUB_PACKAGE = 'dartvel_dev';
28
+ const VERSION = require('./package.json').version;
29
+ const REPO = 'Danroyal001/dartvel_dev';
30
+ const RELEASE_BASE = `https://github.com/${REPO}/releases/download/v${VERSION}`;
23
31
 
24
- /** The command that package installs. */
25
- const COMMAND = 'dartvel';
32
+ /**
33
+ * The release asset for a platform.
34
+ *
35
+ * Named for the operating system and architecture rather than Node's own
36
+ * spellings, because the release is what has to be matched.
37
+ */
38
+ function assetName(platform = process.platform, arch = process.arch) {
39
+ const osName = { linux: 'linux', darwin: 'darwin', win32: 'windows' }[platform];
40
+ if (!osName) {
41
+ throw new Error(
42
+ `Dartvel has no build for ${platform}. Supported: Linux, macOS, Windows.`
43
+ );
44
+ }
26
45
 
27
- /** Where to send someone who has no Dart at all. */
28
- const INSTALL_DART = 'https://docs.flutter.dev/get-started/install';
46
+ const archName = { x64: 'amd64', arm64: 'arm64' }[arch];
47
+ if (!archName) {
48
+ throw new Error(
49
+ `Dartvel has no build for ${arch}. Supported: x64, arm64.`
50
+ );
51
+ }
29
52
 
30
- function which(command) {
31
- const probe = spawnSync(
32
- process.platform === 'win32' ? 'where' : 'which',
33
- [command],
34
- { encoding: 'utf8' }
35
- );
36
- return probe.status === 0 && String(probe.stdout).trim().length > 0;
37
- }
53
+ // Windows on ARM is not published yet, and saying so beats a 404 from a URL
54
+ // this would otherwise construct confidently.
55
+ if (osName === 'windows' && archName === 'arm64') {
56
+ throw new Error(
57
+ 'Dartvel has no Windows on ARM build yet. The x64 build runs under ' +
58
+ 'emulation; install it directly from the releases page.'
59
+ );
60
+ }
38
61
 
39
- /** Whether the Dartvel CLI is already on the PATH. */
40
- function hasDartvel() {
41
- return which(COMMAND);
62
+ return `dartvel-${osName}-${archName}${osName === 'windows' ? '.exe' : ''}`;
42
63
  }
43
64
 
44
- /** Whether a Dart SDK is available to install it with. */
45
- function hasDart() {
46
- return which('dart') || which('flutter');
65
+ /** Where the downloaded binary is kept, beside this package. */
66
+ function binaryPath() {
67
+ const name = process.platform === 'win32' ? 'dartvel.exe' : 'dartvel';
68
+ return path.join(__dirname, 'vendor', name);
47
69
  }
48
70
 
49
- function activate() {
50
- // Not silent: this downloads and compiles, and a launcher that appears to
51
- // hang is worse than one that says what it is doing.
52
- process.stderr.write(
53
- `${COMMAND} is not installed yet — running: ` +
54
- `dart pub global activate ${PUB_PACKAGE}\n`
55
- );
56
- const result = spawnSync('dart', ['pub', 'global', 'activate', PUB_PACKAGE], {
57
- stdio: 'inherit',
71
+ function download(url, redirectsLeft = 5) {
72
+ return new Promise((resolve, reject) => {
73
+ https
74
+ .get(url, { headers: { 'user-agent': 'dartvel-npm' } }, (response) => {
75
+ const status = response.statusCode || 0;
76
+ if (status >= 300 && status < 400 && response.headers.location) {
77
+ if (redirectsLeft <= 0) {
78
+ reject(new Error('too many redirects'));
79
+ return;
80
+ }
81
+ response.resume();
82
+ resolve(download(response.headers.location, redirectsLeft - 1));
83
+ return;
84
+ }
85
+ if (status !== 200) {
86
+ response.resume();
87
+ reject(new Error(`HTTP ${status} for ${url}`));
88
+ return;
89
+ }
90
+ const chunks = [];
91
+ response.on('data', (chunk) => chunks.push(chunk));
92
+ response.on('end', () => resolve(Buffer.concat(chunks)));
93
+ response.on('error', reject);
94
+ })
95
+ .on('error', reject);
58
96
  });
59
- return result.status === 0;
60
97
  }
61
98
 
62
- /** Run the Dartvel CLI with `args`, resolving to its exit code. */
63
- function run(args) {
64
- if (hasDartvel()) {
65
- return spawnThrough(COMMAND, args);
99
+ /**
100
+ * Fetch the binary if it is not already here.
101
+ *
102
+ * The checksum published alongside the release is verified before anything is
103
+ * made executable. A truncated download otherwise becomes a binary that fails
104
+ * in a way that looks like a bug in the tool.
105
+ */
106
+ async function ensureBinary() {
107
+ const target = binaryPath();
108
+ if (fs.existsSync(target)) return target;
109
+
110
+ const asset = assetName();
111
+ process.stderr.write(`Fetching ${asset} ${VERSION}…\n`);
112
+
113
+ const binary = await download(`${RELEASE_BASE}/${asset}`);
114
+
115
+ let expected = null;
116
+ try {
117
+ const sums = (await download(`${RELEASE_BASE}/SHA256SUMS`)).toString('utf8');
118
+ for (const line of sums.split('\n')) {
119
+ const [digest, name] = line.trim().split(/\s+/);
120
+ if (name === asset) expected = digest;
121
+ }
122
+ } catch {
123
+ // A release without a checksum file is still installable; say so rather
124
+ // than refusing, and never claim it was verified.
125
+ process.stderr.write('No SHA256SUMS published for this release; skipping verification.\n');
66
126
  }
67
127
 
68
- if (!hasDart()) {
69
- process.stderr.write(
70
- 'Dartvel needs the Dart SDK, and there is no `dart` on your PATH.\n' +
71
- `Install Flutter, which includes Dart: ${INSTALL_DART}\n`
72
- );
73
- return Promise.resolve(1);
128
+ if (expected) {
129
+ const actual = crypto.createHash('sha256').update(binary).digest('hex');
130
+ if (actual !== expected) {
131
+ throw new Error(
132
+ `Checksum mismatch for ${asset}.\n expected ${expected}\n got ${actual}`
133
+ );
134
+ }
74
135
  }
75
136
 
76
- if (!activate()) {
137
+ fs.mkdirSync(path.dirname(target), { recursive: true });
138
+ fs.writeFileSync(target, binary, { mode: 0o755 });
139
+ return target;
140
+ }
141
+
142
+ /** Run the CLI with `args`, resolving to its exit code. */
143
+ async function run(args) {
144
+ let binary;
145
+ try {
146
+ binary = await ensureBinary();
147
+ } catch (error) {
148
+ process.stderr.write(`${error.message}\n`);
77
149
  process.stderr.write(
78
- `Could not install ${PUB_PACKAGE} from pub.dev.\n` +
79
- `Try it directly: dart pub global activate ${PUB_PACKAGE}\n`
150
+ `Releases: https://github.com/${REPO}/releases/tag/v${VERSION}\n`
80
151
  );
81
- return Promise.resolve(1);
152
+ return 1;
82
153
  }
83
154
 
84
- // `pub global activate` installs into ~/.pub-cache/bin, which is on the PATH
85
- // only if the user has put it there. Going through `dart pub global run`
86
- // works either way.
87
- return spawnThrough('dart', ['pub', 'global', 'run', PUB_PACKAGE, ...args]);
88
- }
89
-
90
- function spawnThrough(command, args) {
91
155
  return new Promise((resolve) => {
92
- const child = spawn(command, args, { stdio: 'inherit' });
156
+ const child = spawn(binary, args, { stdio: 'inherit' });
93
157
  child.on('error', (error) => {
94
- process.stderr.write(`Could not run ${command}: ${error.message}\n`);
158
+ process.stderr.write(`Could not run dartvel: ${error.message}\n`);
95
159
  resolve(1);
96
160
  });
97
161
  child.on('close', (code) => resolve(code === null ? 1 : code));
98
162
  });
99
163
  }
100
164
 
101
- module.exports = { run, hasDartvel, hasDart, PUB_PACKAGE, COMMAND };
165
+ module.exports = { run, assetName, binaryPath, ensureBinary, VERSION };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "dartvel_dev",
3
- "version": "0.2.1",
4
- "description": "Dartvel — a batteries-included, AI-native full-stack application platform built around Flutter. This is the npm launcher for the CLI published on pub.dev as dartvel_dev.",
3
+ "version": "0.2.2",
4
+ "description": "Dartvel \u2014 a batteries-included, AI-native full-stack application platform built around Flutter. This is the npm launcher for the CLI published on pub.dev as dartvel_dev.",
5
5
  "main": "./index.js",
6
6
  "bin": {
7
7
  "dartvel": "./bin/dartvel.js",