mz-dev 0.1.0-beta.0 → 0.1.0-beta.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,45 +1,57 @@
1
1
  # mz-dev
2
2
 
3
- Network debugging proxy + dashboard for Flutter / mobile development.
3
+ A local-first developer workbench that runs your coding agents the way you
4
+ would. It sees your app's traffic and runtime, knows your tickets and designs,
5
+ and works to your standards.
4
6
 
5
7
  ```bash
6
- # One-shot
7
- npx mz-dev start
8
+ # One-shot (prereleases are published under the `beta` dist-tag)
9
+ npx mz-dev@beta start
8
10
 
9
11
  # Persistent install
10
- npm install -g mz-dev
12
+ npm install -g mz-dev@beta
11
13
  mz start
12
14
  ```
13
15
 
16
+ Pin an exact version (`mz-dev@0.1.0-beta.N`) when reporting issues.
17
+
14
18
  ## What you get
15
19
 
16
- - A local HTTP/HTTPS proxy that captures every request your app
17
- makes.
18
- - A web dashboard at `http://localhost:8889` to inspect, replay,
19
- mock, intercept, and AI-analyse traffic.
20
- - An MCP server so AI tools can drive the same workflows.
20
+ - A local HTTP(S) proxy and traffic inspector, with intercept rules and a
21
+ mock server.
22
+ - A web dashboard at `http://localhost:8889` for traffic, the API client,
23
+ environments, credentials and Vault, attached Flutter apps and the Jira
24
+ workspace.
25
+ - An MCP server (`mz mcp`, or `http://127.0.0.1:8892/mcp` while `mz start`
26
+ runs) so coding agents can use the same tools.
21
27
 
22
28
  ## Supported platforms
23
29
 
24
- `darwin-arm64`, `darwin-x64`, `linux-x64`, `linux-arm64`, `windows-x64`.
30
+ macOS on Apple silicon (`darwin-arm64`). Node.js 18 or newer runs the `mz`
31
+ launcher.
32
+
33
+ Other platforms aren't published yet; on them `mz` says so and exits.
34
+
35
+ ## How the install works
25
36
 
26
- The package itself is platform-agnostic. The `postinstall` step
27
- downloads the matching prebuilt binary + Flutter web bundle from
28
- the GitHub Release tagged `v<this package version>`.
37
+ `mz-dev` is a small launcher. The binary, the dashboard and the Dart packages
38
+ for your apps (`mz_client`) come in a separate package for your platform,
39
+ `mz-dev-darwin-arm64`, which npm installs automatically as an optional
40
+ dependency. Nothing is downloaded when the package installs, and there are no
41
+ install scripts.
29
42
 
30
- ## First-launch warnings
43
+ If you install with optional dependencies turned off (`--omit=optional`),
44
+ `mz` tells you to reinstall without that flag.
31
45
 
32
- - **macOS**: The binary is unsigned (we don't yet pay for an Apple
33
- Developer account). On first run macOS Gatekeeper will refuse to
34
- open it. Workaround:
35
- ```bash
36
- xattr -d com.apple.quarantine "$(npm root -g)/mz-dev/platform/$(node -p "process.platform + '-' + process.arch")/bin/mz"
37
- ```
38
- Or right-click the binary in Finder → Open.
39
- - **Windows**: SmartScreen will prompt "Windows protected your PC"
40
- on first launch. Click *More info* → *Run anyway*.
41
- - **Linux**: nothing to do.
46
+ `mz update --check` tells you when a newer version is published on your
47
+ channel (set `MZ_NO_UPDATE_CHECK=1` to turn update checks off).
42
48
 
43
- ## Source
49
+ ## First launch on macOS
44
50
 
45
- <https://github.com/koiralapankaj7/mz_dev>
51
+ Beta binaries are not yet signed by Apple. Files that npm installs are not
52
+ quarantined, so macOS normally runs `mz` without asking. If it ever reports
53
+ that `mz` "cannot be opened", clear the quarantine flag:
54
+
55
+ ```bash
56
+ xattr -d com.apple.quarantine "$(npm root -g)/mz-dev-darwin-arm64/bin/mz"
57
+ ```
package/bin/mz.js CHANGED
@@ -1,11 +1,11 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
- * Thin shim that execs the platform-specific `mz` binary the
4
- * `postinstall` step downloaded.
3
+ * Thin shim that execs the `mz` binary from the platform package npm
4
+ * installed alongside (`mz-dev-darwin-arm64`, …; see scripts/resolve.js).
5
5
  *
6
6
  * Sets `MZ_DEV_UI_DIR` so the binary finds the bundled Flutter web
7
- * assets next to itself (`<package>/platform/<arch>/ui/web/`)
8
- * regardless of the user's current working directory.
7
+ * assets in that package (`ui/web/`) regardless of the user's current
8
+ * working directory.
9
9
  *
10
10
  * Forwards stdio + signals so the binary feels native: Ctrl+C, pipes,
11
11
  * exit codes all behave as if the user invoked the binary directly.
@@ -27,8 +27,7 @@ try {
27
27
  if (!fs.existsSync(resolvedBinary)) {
28
28
  console.error(
29
29
  `mz-dev: binary missing at ${resolvedBinary}. ` +
30
- `The postinstall step may have failed — try ` +
31
- `\`npm rebuild mz-dev\` or reinstall the package.`,
30
+ 'Reinstall the package: npm install -g mz-dev',
32
31
  );
33
32
  process.exit(1);
34
33
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "mz-dev",
3
- "version": "0.1.0-beta.0",
4
- "description": "Network debugging proxy + dashboard for Flutter / mobile development",
3
+ "version": "0.1.0-beta.15",
4
+ "description": "Local-first developer workbench that runs your coding agents the way you would",
5
5
  "keywords": [
6
6
  "flutter",
7
7
  "network",
@@ -12,14 +12,6 @@
12
12
  "intercept",
13
13
  "cli"
14
14
  ],
15
- "homepage": "https://github.com/koiralapankaj7/mz_dev",
16
- "repository": {
17
- "type": "git",
18
- "url": "git+https://github.com/koiralapankaj7/mz_dev.git"
19
- },
20
- "bugs": {
21
- "url": "https://github.com/koiralapankaj7/mz_dev/issues"
22
- },
23
15
  "license": "MIT",
24
16
  "author": "Pankaj Koirala",
25
17
  "bin": {
@@ -28,18 +20,14 @@
28
20
  },
29
21
  "files": [
30
22
  "bin",
31
- "scripts",
23
+ "scripts/resolve.js",
32
24
  "README.md",
33
25
  "LICENSE"
34
26
  ],
35
- "scripts": {
36
- "postinstall": "node scripts/install.js",
37
- "preuninstall": "node scripts/uninstall.js"
27
+ "optionalDependencies": {
28
+ "mz-dev-darwin-arm64": "0.1.0-beta.15"
38
29
  },
39
30
  "engines": {
40
31
  "node": ">=18"
41
- },
42
- "dependencies": {
43
- "tar": "^7.5.22"
44
32
  }
45
33
  }
@@ -1,36 +1,39 @@
1
1
  /**
2
- * Maps the running process to a {platform, binary, archive} triple.
2
+ * Finds the platform package that carries the `mz` binary.
3
3
  *
4
- * Single source of truth for "which binary do we run / download".
5
- * Used by both `bin/mz.js` (to exec) and `scripts/install.js` (to
6
- * download). Keeping the map here means adding a new platform is a
7
- * one-line edit.
4
+ * `mz-dev` itself is a small launcher. Each supported platform's binary,
5
+ * dashboard and companion packages ship as their own npm package
6
+ * (`mz-dev-darwin-arm64`, …) listed in `optionalDependencies`; npm installs
7
+ * only the one whose `os`/`cpu` match the machine. Nothing is downloaded at
8
+ * install time.
8
9
  */
9
10
  'use strict';
10
11
 
12
+ const fs = require('fs');
11
13
  const path = require('path');
12
14
 
15
+ // Platforms with a published package. Adding one: build it with
16
+ // `release/manual-release.sh npm`, publish it, and list it here and in
17
+ // package.json `optionalDependencies`.
13
18
  const PLATFORM_MAP = {
14
19
  'darwin:arm64': 'darwin-arm64',
15
- 'darwin:x64': 'darwin-x64',
16
- 'linux:x64': 'linux-x64',
17
- 'linux:arm64': 'linux-arm64',
18
- 'win32:x64': 'windows-x64',
19
20
  };
20
21
 
21
- function platformDir() {
22
- const key = `${process.platform}:${process.arch}`;
23
- const dir = PLATFORM_MAP[key];
22
+ function platformDir(platform = process.platform, arch = process.arch) {
23
+ const dir = PLATFORM_MAP[`${platform}:${arch}`];
24
24
  if (!dir) {
25
25
  throw new Error(
26
- `mz-dev does not have a prebuilt binary for ${key}. ` +
27
- `Supported: ${Object.keys(PLATFORM_MAP).join(', ')}. ` +
28
- `File an issue at https://github.com/koiralapankaj7/mz_dev/issues.`,
26
+ `mz-dev has no prebuilt binary for ${platform}-${arch} yet. ` +
27
+ `Available: ${Object.values(PLATFORM_MAP).join(', ')}.`,
29
28
  );
30
29
  }
31
30
  return dir;
32
31
  }
33
32
 
33
+ function platformPackageName(platform = platformDir()) {
34
+ return `mz-dev-${platform}`;
35
+ }
36
+
34
37
  function binaryName() {
35
38
  return process.platform === 'win32' ? 'mz.exe' : 'mz';
36
39
  }
@@ -39,8 +42,23 @@ function packageRoot() {
39
42
  return path.resolve(__dirname, '..');
40
43
  }
41
44
 
45
+ /**
46
+ * The installed platform package's directory. Resolved from this package so
47
+ * it works for global installs, `npx` and local `node_modules` alike.
48
+ */
42
49
  function platformRoot(platform = platformDir()) {
43
- return path.join(packageRoot(), 'platform', platform);
50
+ const name = platformPackageName(platform);
51
+ try {
52
+ return path.dirname(
53
+ require.resolve(`${name}/package.json`, { paths: [packageRoot()] }),
54
+ );
55
+ } catch (_) {
56
+ throw new Error(
57
+ `mz-dev: ${name} is not installed. npm skips it when optional ` +
58
+ 'dependencies are disabled (--omit=optional, --no-optional). ' +
59
+ `Reinstall with them enabled: npm install -g mz-dev`,
60
+ );
61
+ }
44
62
  }
45
63
 
46
64
  function binaryPath(platform = platformDir()) {
@@ -48,12 +66,15 @@ function binaryPath(platform = platformDir()) {
48
66
  }
49
67
 
50
68
  function uiDir(platform = platformDir()) {
51
- return path.join(platformRoot(platform), 'ui', 'web');
69
+ const root = platformRoot(platform);
70
+ const web = path.join(root, 'ui', 'web');
71
+ return fs.existsSync(web) ? web : path.join(root, 'ui');
52
72
  }
53
73
 
54
74
  module.exports = {
55
75
  PLATFORM_MAP,
56
76
  platformDir,
77
+ platformPackageName,
57
78
  binaryName,
58
79
  packageRoot,
59
80
  platformRoot,
@@ -1,73 +0,0 @@
1
- 'use strict';
2
- const fs = require('node:fs');
3
- const path = require('node:path');
4
- const crypto = require('node:crypto');
5
- const { Readable, Transform } = require('node:stream');
6
- const { pipeline } = require('node:stream/promises');
7
-
8
- function expectedChecksum(manifest, archive) {
9
- const matches = [];
10
- for (const line of manifest.split('\n')) {
11
- const match = /^([a-fA-F0-9]{64}) [ *](.+)$/.exec(line.replace(/\r$/, ''));
12
- if (match && match[2].split('/').pop() === archive) matches.push(match[1].toLowerCase());
13
- }
14
- if (matches.length !== 1) throw new Error('Expected exactly one archive checksum in SHA256SUMS.txt');
15
- return matches[0];
16
- }
17
-
18
- async function downloadFile(url, destination, {
19
- maxBytes = 512 * 1024 * 1024, timeoutMs = 120000, fetchImpl = fetch,
20
- } = {}) {
21
- const controller = new AbortController();
22
- const timer = setTimeout(() => controller.abort(), timeoutMs);
23
- let response;
24
- try {
25
- for (let redirects = 0; ; redirects++) {
26
- const parsed = new URL(url);
27
- if (parsed.protocol !== 'https:' || parsed.username || parsed.password) {
28
- throw new Error('Installer downloads require HTTPS without URL credentials');
29
- }
30
- response = await fetchImpl(parsed.href, {
31
- redirect: 'manual', signal: controller.signal,
32
- headers: { 'User-Agent': 'mz-dev-installer' },
33
- });
34
- if (![301, 302, 303, 307, 308].includes(response.status)) break;
35
- await response.body?.cancel();
36
- const location = response.headers.get('location');
37
- if (!location || redirects >= 5) throw new Error('Invalid or excessive download redirects');
38
- url = new URL(location, parsed).href;
39
- }
40
- if (response.status !== 200 || !response.body) throw new Error(`Download HTTP ${response.status}`);
41
- const hash = crypto.createHash('sha256');
42
- let bytes = 0;
43
- const meter = new Transform({
44
- transform(chunk, encoding, callback) {
45
- bytes += chunk.length;
46
- if (bytes > maxBytes) return callback(new Error('Download exceeds size limit'));
47
- hash.update(chunk);
48
- callback(null, chunk);
49
- },
50
- });
51
- await pipeline(Readable.fromWeb(response.body), meter,
52
- fs.createWriteStream(destination, { flags: 'wx', mode: 0o600 }),
53
- { signal: controller.signal });
54
- return hash.digest('hex');
55
- } finally {
56
- controller.abort();
57
- clearTimeout(timer);
58
- }
59
- }
60
-
61
- async function verifiedArchive(baseUrl, archive, directory, options = {}) {
62
- if (!/^mz-dev-[a-z0-9-]+\.tar\.gz$/.test(archive)) throw new Error('Invalid archive name');
63
- const manifestPath = path.join(directory, 'SHA256SUMS.txt');
64
- await downloadFile(`${baseUrl}/SHA256SUMS.txt`, manifestPath,
65
- { ...options, maxBytes: 1024 * 1024 });
66
- const expected = expectedChecksum(await fs.promises.readFile(manifestPath, 'utf8'), archive);
67
- const archivePath = path.join(directory, archive);
68
- const actual = await downloadFile(`${baseUrl}/${archive}`, archivePath, options);
69
- if (actual !== expected) throw new Error('Archive SHA-256 checksum mismatch');
70
- return archivePath;
71
- }
72
-
73
- module.exports = { expectedChecksum, downloadFile, verifiedArchive };
@@ -1,34 +0,0 @@
1
- 'use strict';
2
- const tar = require('tar');
3
-
4
- function entryFilter(root, { maxEntries = 20000, maxBytes = 1024 * 1024 * 1024 } = {}) {
5
- let count = 0;
6
- let bytes = 0;
7
- const seen = new Set();
8
- return function (name, entry) {
9
- const clean = name.replace(/\/$/, '');
10
- const parts = clean.split('/');
11
- const key = clean.toLowerCase();
12
- count++;
13
- bytes += entry.size;
14
- if (parts[0] !== root || parts.some(part => !part || part === '.' || part === '..') ||
15
- /[\\:\x00-\x1f]/.test(name) || !['File', 'Directory'].includes(entry.type) ||
16
- seen.has(key) || !Number.isSafeInteger(entry.size) || entry.size < 0 ||
17
- count > maxEntries || bytes > maxBytes) {
18
- this.abort(new Error('Unsafe or oversized release archive entry'));
19
- return false;
20
- }
21
- seen.add(key);
22
- return true;
23
- };
24
- }
25
-
26
- async function extractArchive(file, directory, root, limits = {}) {
27
- // Preflight the complete archive before creating any extracted files.
28
- await tar.t({ file, strict: true, maxDecompressionRatio: 1000,
29
- filter: entryFilter(root, limits) });
30
- await tar.x({ file, cwd: directory, strip: 1, strict: true,
31
- preserveOwner: false, maxDecompressionRatio: 1000,
32
- filter: entryFilter(root, limits) });
33
- }
34
- module.exports = { extractArchive };
@@ -1,101 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * Postinstall: downloads the platform-specific mz_dev binary +
4
- * Flutter UI bundle from the matching GitHub Release and unpacks it
5
- * into `<package>/platform/<arch>/`.
6
- *
7
- * Why a downloader instead of bundling every platform's binary in
8
- * the npm package: keeps the published tarball tiny (~5 KB instead
9
- * of ~80 MB) and avoids tagging the npm registry with binaries it
10
- * shouldn't be hosting.
11
- *
12
- * Re-running install skips download only for a marked, complete bundle.
13
- *
14
- * Failure is non-fatal: we print a clear "download manually from X"
15
- * pointer and exit 0 so `npm install` itself doesn't break for
16
- * users who'll fetch the binary another way (offline, corporate
17
- * proxy, etc.).
18
- */
19
- 'use strict';
20
-
21
- const fs = require('fs');
22
- const path = require('path');
23
- const os = require('os');
24
- const { verifiedArchive } = require('./download');
25
- const { isCompleteInstall, installBundle } = require('./installation');
26
-
27
- const { extractArchive } = require('./extract');
28
-
29
- const {
30
- binaryPath,
31
- binaryName,
32
- platformDir,
33
- platformRoot,
34
- } = require('./resolve');
35
- const pkg = require('../package.json');
36
-
37
- const REPO = 'koiralapankaj7/mz_dev';
38
-
39
- function logFailure(reason, downloadUrl) {
40
- console.error(`\nmz-dev: postinstall failed — ${reason}`);
41
- if (downloadUrl) {
42
- console.error(
43
- `mz-dev: you can fetch the binary manually:\n ${downloadUrl}\n` +
44
- ` and unpack it under:\n ${platformRoot()}\n`,
45
- );
46
- }
47
- // Keep `npm install` green; the shim prints a friendlier error
48
- // when the user actually tries to run `mz`.
49
- process.exitCode = 0;
50
- }
51
-
52
- let platform;
53
- try {
54
- platform = platformDir();
55
- } catch (e) {
56
- // Unsupported platform → nothing to install. Exit 0 so installing
57
- // mz-dev as a transitive dep on an exotic CI doesn't blow up.
58
- console.warn(`mz-dev: ${e.message}`);
59
- process.exit(0);
60
- }
61
-
62
- const archive = `mz-dev-${platform}.tar.gz`;
63
- const url = `https://github.com/${REPO}/releases/download/v${pkg.version}/${archive}`;
64
- const targetDir = platformRoot(platform);
65
- const finalBinary = binaryPath(platform);
66
-
67
- if (isCompleteInstall(targetDir, binaryName(), pkg.version)) {
68
- // Already provisioned (npm cache hit, manual download, etc.).
69
- // Make sure the perm bit is right just in case.
70
- if (process.platform !== 'win32') fs.chmodSync(finalBinary, 0o755);
71
- process.exit(0);
72
- }
73
-
74
- (async () => {
75
- console.log(`mz-dev: downloading ${archive} (v${pkg.version})`);
76
- let temporary;
77
- try {
78
- temporary = fs.mkdtempSync(path.join(os.tmpdir(), 'mz-download-'));
79
- const verified = await verifiedArchive(url.slice(0, url.lastIndexOf('/')), archive, temporary);
80
- const backup = await installBundle({
81
- target: targetDir, binary: binaryName(), version: pkg.version,
82
- extract: directory => extractArchive(verified, directory, `mz-dev-${platform}`),
83
- });
84
- if (backup) console.log(`mz-dev: previous installation retained at ${backup}`);
85
- } catch (err) {
86
- logFailure(`download/verification/extraction failed (${err.message})`, url);
87
- return;
88
- } finally {
89
- if (temporary) fs.rmSync(temporary, { recursive: true, force: true });
90
- }
91
-
92
- if (!fs.existsSync(finalBinary)) {
93
- logFailure(
94
- `archive did not contain bin/${binaryName()} for ${platform}`,
95
- url,
96
- );
97
- return;
98
- }
99
- if (process.platform !== 'win32') fs.chmodSync(finalBinary, 0o755);
100
- console.log(`mz-dev: installed ${platform} binary`);
101
- })();
@@ -1,125 +0,0 @@
1
- 'use strict';
2
- const fs = require('node:fs');
3
- const path = require('node:path');
4
- const { createHash } = require('node:crypto');
5
-
6
- function digestFile(filename) {
7
- const descriptor = fs.openSync(filename, 'r');
8
- try {
9
- const hash = createHash('sha256');
10
- const buffer = Buffer.allocUnsafe(64 * 1024);
11
- let length;
12
- while ((length = fs.readSync(descriptor, buffer, 0, buffer.length, null)) > 0) {
13
- hash.update(buffer.subarray(0, length));
14
- }
15
- return hash.digest('hex');
16
- } finally {
17
- fs.closeSync(descriptor);
18
- }
19
- }
20
-
21
- function requiredAssets(binary) {
22
- return [`bin/${binary}`, ...(process.platform === 'win32' ? [] : ['bin/mz-check-supervisor']),
23
- 'ui/web/index.html', 'ui/web/main.dart.js',
24
- 'packages/mz_client/pubspec.yaml', 'packages/mz_client/lib/mz_client.dart',
25
- 'packages/mz_protocol/pubspec.yaml', 'packages/mz_protocol/lib/mz_protocol.dart'];
26
- }
27
-
28
- function requiredInventory(directory, binary) {
29
- return requiredAssets(binary).map(relative => [relative,
30
- digestFile(path.join(directory, relative))]);
31
- }
32
-
33
- // Inventory is derived from regular files, never paths supplied by the marker.
34
- // This detects accidental damage; it does not authenticate against a local
35
- // attacker who can rewrite both the libraries and installation marker.
36
- function nativeInventory(directory) {
37
- const root = path.join(directory, 'lib');
38
- if (!fs.existsSync(root)) return [];
39
- const result = [];
40
- function visit(relative) {
41
- const absolute = path.join(root, relative);
42
- const stat = fs.lstatSync(absolute);
43
- if (stat.isDirectory()) {
44
- for (const name of fs.readdirSync(absolute).sort()) {
45
- visit(relative ? `${relative}/${name}` : name);
46
- }
47
- } else if (stat.isFile() && stat.size > 0) {
48
- result.push([relative, digestFile(absolute)]);
49
- } else throw new Error('Invalid native library asset');
50
- }
51
- visit('');
52
- return result;
53
- }
54
-
55
- function validateBundle(directory, binary) {
56
- function inspect(entry) {
57
- const stat = fs.lstatSync(entry);
58
- if (stat.isDirectory()) {
59
- for (const child of fs.readdirSync(entry)) inspect(path.join(entry, child));
60
- } else if (!stat.isFile()) throw new Error('Bundle contains a non-regular entry');
61
- }
62
- inspect(directory);
63
- for (const relative of requiredAssets(binary)) {
64
- const stat = fs.lstatSync(path.join(directory, relative));
65
- if (!stat.isFile() || stat.size === 0) throw new Error(`Missing bundle asset: ${relative}`);
66
- }
67
- if (process.platform !== 'win32') {
68
- fs.accessSync(path.join(directory, 'bin/mz-check-supervisor'), fs.constants.X_OK);
69
- }
70
- }
71
-
72
- function isCompleteInstall(directory, binary, version) {
73
- try {
74
- const marker = JSON.parse(fs.readFileSync(path.join(directory, '.mz-install.json'), 'utf8'));
75
- if (marker.version !== version || marker.format !== 2) return false;
76
- validateBundle(directory, binary);
77
- if (process.platform !== 'win32') {
78
- fs.accessSync(path.join(directory, 'bin', binary), fs.constants.X_OK);
79
- }
80
- return JSON.stringify(marker.nativeAssets) === JSON.stringify(nativeInventory(directory)) &&
81
- JSON.stringify(marker.requiredAssets) === JSON.stringify(requiredInventory(directory, binary));
82
- } catch (_) { return false; }
83
- }
84
-
85
- async function installBundle({ target, binary, version, extract, rename = fs.renameSync }) {
86
- fs.mkdirSync(path.dirname(target), { recursive: true });
87
- const lock = `${target}.install-lock`;
88
- fs.mkdirSync(lock); // Refuse a concurrent or interrupted installation.
89
- let transaction;
90
- try {
91
- if (fs.existsSync(target) && !fs.lstatSync(target).isDirectory()) {
92
- throw new Error('Installation target must be a regular directory');
93
- }
94
- transaction = fs.mkdtempSync(path.join(path.dirname(target), '.mz-install-'));
95
- const staged = path.join(transaction, 'new');
96
- const previous = path.join(transaction, 'previous');
97
- fs.mkdirSync(staged);
98
- await extract(staged);
99
- validateBundle(staged, binary);
100
- if (process.platform !== 'win32') fs.chmodSync(path.join(staged, 'bin', binary), 0o755);
101
- fs.writeFileSync(path.join(staged, '.mz-install.json'), JSON.stringify({
102
- format: 2, version, nativeAssets: nativeInventory(staged),
103
- requiredAssets: requiredInventory(staged, binary),
104
- }));
105
- const hadPrevious = fs.existsSync(target);
106
- if (hadPrevious) rename(target, previous);
107
- try {
108
- rename(staged, target);
109
- } catch (error) {
110
- if (hadPrevious) {
111
- try { rename(previous, target); }
112
- catch (_) { throw new Error(`Installation failed; previous files retained at ${previous}`); }
113
- }
114
- throw error;
115
- }
116
- // Retain previous files rather than destroying a manual install or recovery data.
117
- return hadPrevious ? previous : null;
118
- } finally {
119
- if (transaction && !fs.existsSync(path.join(transaction, 'previous'))) {
120
- fs.rmSync(transaction, { recursive: true, force: true });
121
- }
122
- fs.rmdirSync(lock);
123
- }
124
- }
125
- module.exports = { validateBundle, isCompleteInstall, installBundle };
package/scripts/smoke.js DELETED
@@ -1,26 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * Sanity-check the resolver without invoking the binary.
4
- *
5
- * node release/npm/scripts/smoke.js
6
- *
7
- * Prints the platform/binary/UI paths the shim would use on this
8
- * machine. Useful when adding a new platform to verify the
9
- * `PLATFORM_MAP` entry resolves correctly before tagging a
10
- * release.
11
- */
12
- 'use strict';
13
-
14
- const {
15
- platformDir,
16
- binaryName,
17
- binaryPath,
18
- uiDir,
19
- } = require('./resolve');
20
-
21
- console.log(JSON.stringify({
22
- platform: platformDir(),
23
- binaryName: binaryName(),
24
- binaryPath: binaryPath(),
25
- uiDir: uiDir(),
26
- }, null, 2));
@@ -1,17 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * Best-effort cleanup of the downloaded `platform/` tree on
4
- * `npm uninstall`. Quiet — failure here is harmless because the
5
- * whole package directory is about to be removed anyway.
6
- */
7
- 'use strict';
8
-
9
- const fs = require('fs');
10
- const path = require('path');
11
-
12
- const platformRoot = path.join(__dirname, '..', 'platform');
13
- try {
14
- fs.rmSync(platformRoot, { recursive: true, force: true });
15
- } catch (_) {
16
- /* ignore */
17
- }