@previewio/cli 0.2.0-cf1b36a → 0.2.0-d26dd93

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.
@@ -1,14 +1,13 @@
1
- 'use strict';
2
-
3
- const { chmodSync, mkdirSync, readFileSync, renameSync, writeFileSync } = require('node:fs');
4
- const { dirname, join } = require('node:path');
1
+ import { chmodSync, mkdirSync, readFileSync, renameSync, writeFileSync } from 'node:fs';
2
+ import { dirname, join, resolve } from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
5
4
 
6
5
  const PUBLIC_DOWNLOAD_ORIGIN = 'https://download.preview.io';
7
6
  const VERSION_PATTERN = /^[A-Za-z0-9._-]+$/;
8
7
  const RESERVED_VERSIONS = new Set(['latest', 'install', '.', '..']);
9
8
  const BINARY_FETCH_TIMEOUT_MS = 120_000;
10
9
 
11
- function binaryObjectName(platform, arch) {
10
+ export function binaryObjectName(platform, arch) {
12
11
  if (platform === 'darwin' && arch === 'arm64') return 'preview-darwin-arm64';
13
12
  if (platform === 'darwin' && (arch === 'x64' || arch === 'x86_64')) return 'preview-darwin-x64';
14
13
  if (platform === 'linux' && (arch === 'x64' || arch === 'x86_64')) return 'preview-linux-x64';
@@ -18,18 +17,45 @@ function binaryObjectName(platform, arch) {
18
17
 
19
18
  function assertReleaseVersion(version) {
20
19
  if (!VERSION_PATTERN.test(version) || RESERVED_VERSIONS.has(version) || version === '0.0.0-dev') {
21
- throw new Error(
22
- `Invalid CLI release version ${version}. Publish stamps the package version to the CDN stamp.`,
23
- );
20
+ throw new Error(`Invalid CLI release version ${version}. Publish stamps the package version to the CDN stamp.`);
24
21
  }
25
22
  }
26
23
 
27
- function downloadUrl(origin, version, object) {
24
+ export function downloadUrl(origin, version, object) {
28
25
  assertReleaseVersion(version);
29
26
  return `${origin.replace(/\/+$/, '')}/cli/${version}/${object}`;
30
27
  }
31
28
 
32
- function looksLikePublishedBinary(bytes, platform) {
29
+ function installedBinaryName(platform) {
30
+ return platform === 'win32' ? 'preview.exe' : 'preview';
31
+ }
32
+
33
+ function npmGlobalInstall(env) {
34
+ const value = env.npm_config_global?.trim().toLowerCase();
35
+ return value === '1' || value === 'true' || value === 'yes';
36
+ }
37
+
38
+ function windowsShimDirs(packageRoot, env) {
39
+ const dirs = [join(packageRoot, '..', '..', '.bin')];
40
+ const prefix = env.npm_config_prefix?.trim();
41
+ if (prefix && npmGlobalInstall(env)) dirs.push(prefix);
42
+ return dirs;
43
+ }
44
+
45
+ function writeWindowsLaunchers(exePath, packageRoot, env) {
46
+ const cmd = `@ECHO OFF\r\n"${exePath}" %*\r\n`;
47
+ const ps1 = `& '${exePath.replaceAll("'", "''")}' @args\r\n`;
48
+ const sh = `#!/bin/sh\nexec "${exePath}" "$@"\n`;
49
+ for (const dir of windowsShimDirs(packageRoot, env)) {
50
+ mkdirSync(dir, { recursive: true });
51
+ writeFileSync(join(dir, 'preview.cmd'), cmd);
52
+ writeFileSync(join(dir, 'preview.ps1'), ps1);
53
+ writeFileSync(join(dir, 'preview'), sh);
54
+ chmodSync(join(dir, 'preview'), 0o755);
55
+ }
56
+ }
57
+
58
+ export function looksLikePublishedBinary(bytes, platform) {
33
59
  if (platform === 'linux') {
34
60
  return bytes.byteLength >= 4 && bytes[0] === 0x7f && bytes[1] === 0x45 && bytes[2] === 0x4c && bytes[3] === 0x46;
35
61
  }
@@ -52,11 +78,7 @@ function looksLikePublishedBinary(bytes, platform) {
52
78
  }
53
79
 
54
80
  function packageVersion(packageRoot) {
55
- const pkg = JSON.parse(readFileSync(join(packageRoot, 'package.json'), 'utf8'));
56
- if (typeof pkg.version !== 'string' || !pkg.version) {
57
- throw new Error('package.json is missing a version');
58
- }
59
- return pkg.version;
81
+ return JSON.parse(readFileSync(join(packageRoot, 'package.json'), 'utf8')).version;
60
82
  }
61
83
 
62
84
  async function fetchBinary(url, fetchImpl) {
@@ -71,8 +93,8 @@ async function fetchBinary(url, fetchImpl) {
71
93
  return new Uint8Array(await response.arrayBuffer());
72
94
  }
73
95
 
74
- async function install(opts = {}) {
75
- const packageRoot = opts.packageRoot ?? __dirname;
96
+ export async function install(opts = {}) {
97
+ const packageRoot = opts.packageRoot ?? dirname(fileURLToPath(import.meta.url));
76
98
  const version = opts.version ?? packageVersion(packageRoot);
77
99
  const platform = opts.platform ?? process.platform;
78
100
  const arch = opts.arch ?? process.arch;
@@ -81,7 +103,7 @@ async function install(opts = {}) {
81
103
  throw new Error(`Unsupported platform: ${platform} ${arch}`);
82
104
  }
83
105
  const url = downloadUrl(opts.origin ?? PUBLIC_DOWNLOAD_ORIGIN, version, object);
84
- const dest = join(opts.binDir ?? join(packageRoot, 'bin'), 'preview');
106
+ const dest = join(opts.binDir ?? join(packageRoot, 'bin'), installedBinaryName(platform));
85
107
  const bytes = await fetchBinary(url, opts.fetch ?? globalThis.fetch);
86
108
  if (bytes.byteLength === 0 || !looksLikePublishedBinary(bytes, platform)) {
87
109
  throw new Error(`Refused non-binary body from ${url}`);
@@ -91,17 +113,14 @@ async function install(opts = {}) {
91
113
  writeFileSync(tmp, bytes);
92
114
  chmodSync(tmp, 0o755);
93
115
  renameSync(tmp, dest);
116
+ if (platform === 'win32') {
117
+ writeWindowsLaunchers(dest, packageRoot, opts.env ?? process.env);
118
+ }
94
119
  return dest;
95
120
  }
96
121
 
97
- module.exports = {
98
- binaryObjectName,
99
- downloadUrl,
100
- looksLikePublishedBinary,
101
- install,
102
- };
103
-
104
- if (require.main === module) {
122
+ const invoked = process.argv[1] ? resolve(process.argv[1]) : '';
123
+ if (invoked && invoked === fileURLToPath(import.meta.url)) {
105
124
  install({}).catch((err) => {
106
125
  console.error(err instanceof Error ? err.message : err);
107
126
  process.exit(1);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@previewio/cli",
3
- "version": "0.2.0-cf1b36a",
3
+ "version": "0.2.0-d26dd93",
4
4
  "description": "Preview CLI — JSON-first client for agentic tooling",
5
5
  "license": "UNLICENSED",
6
6
  "repository": {
@@ -13,10 +13,10 @@
13
13
  },
14
14
  "files": [
15
15
  "bin",
16
- "install.cjs"
16
+ "install.mjs"
17
17
  ],
18
18
  "scripts": {
19
- "postinstall": "node install.cjs"
19
+ "postinstall": "node install.mjs"
20
20
  },
21
21
  "engines": {
22
22
  "node": ">=18"