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.
- package/README.md +22 -22
- package/index.js +131 -67
- 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
|
-
##
|
|
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
|
-
|
|
20
|
-
the
|
|
21
|
-
|
|
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
|
-
|
|
19
|
+
Building an application still needs Flutter, for whichever target you are
|
|
20
|
+
building. Running the CLI does not.
|
|
24
21
|
|
|
25
|
-
|
|
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
|
-
|
|
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
|
-
|
|
33
|
-
|
|
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
|
-
|
|
38
|
-
|
|
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
|
-
##
|
|
36
|
+
## Why the package is `dartvel_dev` and the command is `dartvel`
|
|
41
37
|
|
|
42
|
-
|
|
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
|
-
//
|
|
1
|
+
// Fetches the self-contained `dartvel` binary for this platform and runs it.
|
|
2
2
|
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
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
|
-
//
|
|
10
|
-
//
|
|
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
|
-
//
|
|
13
|
-
//
|
|
14
|
-
//
|
|
15
|
-
//
|
|
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
|
|
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
|
-
|
|
22
|
-
const
|
|
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
|
-
/**
|
|
25
|
-
|
|
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
|
-
|
|
28
|
-
|
|
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
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
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
|
-
|
|
40
|
-
function hasDartvel() {
|
|
41
|
-
return which(COMMAND);
|
|
62
|
+
return `dartvel-${osName}-${archName}${osName === 'windows' ? '.exe' : ''}`;
|
|
42
63
|
}
|
|
43
64
|
|
|
44
|
-
/**
|
|
45
|
-
function
|
|
46
|
-
|
|
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
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
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
|
-
/**
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
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 (
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
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
|
-
|
|
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
|
-
`
|
|
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
|
|
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(
|
|
156
|
+
const child = spawn(binary, args, { stdio: 'inherit' });
|
|
93
157
|
child.on('error', (error) => {
|
|
94
|
-
process.stderr.write(`Could not run
|
|
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,
|
|
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.
|
|
4
|
-
"description": "Dartvel
|
|
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",
|