@noormdev/cli 1.0.0-alpha.11 → 1.0.0-alpha.13

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/noorm.js ADDED
@@ -0,0 +1,41 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Thin shim that execs the platform-specific noorm binary.
5
+ *
6
+ * npm points `bin.noorm` here. On postinstall, the real binary is
7
+ * downloaded to the same directory. This shim finds and execs it,
8
+ * passing through all arguments and signals.
9
+ */
10
+
11
+ import { execFileSync } from 'child_process';
12
+ import { existsSync } from 'fs';
13
+ import { resolve, dirname } from 'path';
14
+ import { fileURLToPath } from 'url';
15
+
16
+ const __dirname = dirname(fileURLToPath(import.meta.url));
17
+ const binaryName = process.platform === 'win32' ? 'noorm.exe' : 'noorm';
18
+ const binaryPath = resolve(__dirname, 'bin', binaryName);
19
+
20
+ if (!existsSync(binaryPath)) {
21
+
22
+ console.error('noorm binary not found. Try reinstalling:');
23
+ console.error(' npm install -g @noormdev/cli');
24
+ process.exit(1);
25
+
26
+ }
27
+
28
+ try {
29
+
30
+ execFileSync(binaryPath, process.argv.slice(2), {
31
+ stdio: 'inherit',
32
+ env: process.env,
33
+ });
34
+
35
+ }
36
+ catch (err) {
37
+
38
+ // execFileSync throws on non-zero exit — forward the exit code
39
+ process.exit(err.status ?? 1);
40
+
41
+ }
package/package.json CHANGED
@@ -1,24 +1,20 @@
1
1
  {
2
2
  "name": "@noormdev/cli",
3
- "version": "1.0.0-alpha.11",
3
+ "version": "1.0.0-alpha.13",
4
4
  "description": "Database schema & changeset manager CLI",
5
5
  "type": "module",
6
6
  "bin": {
7
- "noorm": "./dist/index.js"
7
+ "noorm": "./noorm.js"
8
8
  },
9
- "main": "./dist/index.js",
10
9
  "files": [
11
- "dist",
10
+ "noorm.js",
12
11
  "scripts"
13
12
  ],
14
13
  "scripts": {
15
14
  "postinstall": "node scripts/postinstall.js"
16
15
  },
17
- "dependencies": {
18
- "better-sqlite3": "^12.5.0"
19
- },
20
16
  "engines": {
21
- "node": ">=22.13"
17
+ "node": ">=18"
22
18
  },
23
19
  "keywords": [
24
20
  "database",
@@ -1,106 +1,155 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  /**
4
- * Creates a stable symlink in /usr/local/bin for Node version independence.
4
+ * Downloads the platform-specific noorm binary on npm install.
5
5
  *
6
- * When using nvm/fnm, npm bin directories are version-specific. This script
7
- * creates a symlink in /usr/local/bin so `noorm` works across version switches.
6
+ * The @noormdev/cli npm package is a thin wrapper. The actual CLI is a
7
+ * bun-compiled binary hosted on GitHub Releases. This script runs on
8
+ * postinstall to fetch the correct binary for the user's OS and architecture.
8
9
  */
9
10
 
10
- import { symlink, unlink, readlink, readFile, writeFile } from 'fs/promises';
11
- import { existsSync } from 'fs';
11
+ import { createWriteStream, existsSync, chmodSync, mkdirSync } from 'fs';
12
+ import { get as httpsGet } from 'https';
12
13
  import { dirname, resolve } from 'path';
13
14
  import { fileURLToPath } from 'url';
14
15
 
15
16
  const __dirname = dirname(fileURLToPath(import.meta.url));
16
- const BIN_PATH = '/usr/local/bin/noorm';
17
- const SOURCE = resolve(__dirname, '../dist/index.js');
17
+ const PACKAGE_ROOT = resolve(__dirname, '..');
18
+ const BIN_DIR = resolve(PACKAGE_ROOT, 'bin');
19
+ const REPO = 'noormdev/noorm';
18
20
 
19
- async function main() {
20
-
21
- // Skip on Windows
22
- if (process.platform === 'win32') {
23
-
24
- return;
21
+ /**
22
+ * Resolves the platform suffix used in binary asset names.
23
+ *
24
+ * Maps Node's process.platform and process.arch to the naming convention
25
+ * used by the build-binary script: noorm-{os}-{arch}
26
+ */
27
+ function getPlatformSuffix() {
25
28
 
26
- }
29
+ const platform = process.platform;
30
+ const arch = process.arch;
27
31
 
28
- // Skip if not a global install (local node_modules)
29
- if (__dirname.includes('node_modules') && !__dirname.includes('/lib/node_modules/')) {
32
+ const osMap = { darwin: 'darwin', linux: 'linux', win32: 'windows' };
33
+ const archMap = { arm64: 'arm64', x64: 'x64' };
30
34
 
31
- return;
35
+ const os = osMap[platform];
36
+ const cpu = archMap[arch];
32
37
 
38
+ if (!os || !cpu) {
39
+ console.error(`Unsupported platform: ${platform}-${arch}`);
40
+ process.exit(0); // Don't fail install
33
41
  }
34
42
 
35
- // Update hashbang in dist/index.js with current Node path
36
- if (existsSync(SOURCE)) {
43
+ const suffix = `${os}-${cpu}`;
37
44
 
38
- try {
45
+ if (platform === 'win32') {
46
+ return `${suffix}.exe`;
47
+ }
39
48
 
40
- const nodeLocation = process.execPath;
41
- const content = await readFile(SOURCE, 'utf8');
42
- const lines = content.split('\n');
49
+ return suffix;
43
50
 
44
- if (lines[0].startsWith('#!')) {
51
+ }
45
52
 
46
- lines[0] = `#!${nodeLocation} --experimental-strip-types`;
47
- await writeFile(SOURCE, lines.join('\n'), 'utf8');
48
- console.log(`✓ Updated hashbang to use /usr/bin/env ${nodeLocation}`);
53
+ /**
54
+ * Reads the package version to determine which release to download from.
55
+ */
56
+ async function getVersion() {
49
57
 
50
- }
58
+ const { readFile } = await import('fs/promises');
59
+ const pkg = JSON.parse(await readFile(resolve(PACKAGE_ROOT, 'package.json'), 'utf8'));
51
60
 
52
- }
53
- catch (err) {
61
+ return pkg.version;
54
62
 
55
- console.error('Error updating hashbang:', err.message);
63
+ }
56
64
 
57
- }
65
+ /**
66
+ * Follow redirects and download a URL to a file path.
67
+ *
68
+ * GitHub Releases URLs redirect to S3. This follows up to 5 redirects.
69
+ */
70
+ function download(url, dest, redirects = 0) {
58
71
 
72
+ if (redirects > 5) {
73
+ return Promise.reject(new Error('Too many redirects'));
59
74
  }
60
75
 
61
- // Check if symlink already exists and points to correct location
62
- if (existsSync(BIN_PATH)) {
76
+ return new Promise((resolve, reject) => {
63
77
 
64
- try {
78
+ httpsGet(url, { headers: { 'User-Agent': 'noorm-installer' } }, (res) => {
65
79
 
66
- const existing = await readlink(BIN_PATH);
80
+ // Follow redirects
81
+ if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
82
+ resolve(download(res.headers.location, dest, redirects + 1));
83
+ return;
84
+ }
67
85
 
68
- if (existing === SOURCE) {
86
+ if (res.statusCode !== 200) {
87
+ reject(new Error(`Download failed: HTTP ${res.statusCode}`));
88
+ return;
89
+ }
69
90
 
70
- return; // Already correct
91
+ const file = createWriteStream(dest);
92
+ res.pipe(file);
71
93
 
72
- }
94
+ file.on('finish', () => {
95
+ file.close();
96
+ resolve();
97
+ });
73
98
 
74
- await unlink(BIN_PATH);
99
+ file.on('error', (err) => {
100
+ file.close();
101
+ reject(err);
102
+ });
75
103
 
76
- }
77
- catch {
104
+ }).on('error', reject);
78
105
 
79
- // Not a symlink or can't read - try to proceed anyway
106
+ });
80
107
 
81
- }
108
+ }
82
109
 
83
- }
110
+ /**
111
+ * Main postinstall routine.
112
+ *
113
+ * Downloads the correct binary, saves it to bin/, and makes it executable.
114
+ * Exits cleanly on failure so npm install doesn't break.
115
+ */
116
+ async function main() {
84
117
 
85
- try {
118
+ const suffix = getPlatformSuffix();
119
+ const version = await getVersion();
120
+ const assetName = `noorm-${suffix}`;
121
+ const tag = `@noormdev/cli@${version}`;
122
+ const url = `https://github.com/${REPO}/releases/download/${tag}/${assetName}`;
86
123
 
87
- await symlink(SOURCE, BIN_PATH);
88
- console.log(`✓ Symlinked noorm to ${BIN_PATH}`);
124
+ const binaryName = process.platform === 'win32' ? 'noorm.exe' : 'noorm';
125
+ const dest = resolve(BIN_DIR, binaryName);
89
126
 
127
+ // Skip if binary already exists (e.g. reinstall)
128
+ if (existsSync(dest)) {
129
+ console.log(`noorm binary already exists at ${dest}`);
130
+ return;
90
131
  }
91
- catch (err) {
92
132
 
93
- if (err.code === 'EACCES') {
133
+ mkdirSync(BIN_DIR, { recursive: true });
94
134
 
95
- console.log(`\nTo enable noorm globally (survives Node version switches):\n`);
96
- console.log(` sudo ln -sf "${SOURCE}" ${BIN_PATH}\n`);
135
+ console.log(`Downloading noorm ${version} for ${suffix}...`);
97
136
 
98
- }
99
-
100
- // Don't fail install on symlink errors
137
+ await download(url, dest);
101
138
 
139
+ if (process.platform !== 'win32') {
140
+ chmodSync(dest, 0o755);
102
141
  }
103
142
 
143
+ console.log(`✓ noorm ${version} installed`);
144
+
104
145
  }
105
146
 
106
- main();
147
+ main().catch((err) => {
148
+
149
+ console.error(`Warning: Could not download noorm binary: ${err.message}`);
150
+ console.error('You can download it manually from:');
151
+ console.error(` https://github.com/${REPO}/releases`);
152
+ // Don't fail the install
153
+ process.exit(0);
154
+
155
+ });