@jsorm/cli 0.1.0 → 0.1.3

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 (2) hide show
  1. package/dist/index.mjs +225 -206
  2. package/package.json +3 -3
package/dist/index.mjs CHANGED
@@ -1,28 +1,13 @@
1
1
  #!/usr/bin/env node
2
- import { execSync, spawn } from "node:child_process";
3
- import { createHash, createPublicKey, verify } from "node:crypto";
4
- import { chmodSync, createReadStream, createWriteStream, existsSync, mkdirSync, readFileSync, readdirSync, renameSync, statSync, unlinkSync } from "node:fs";
2
+ import { execFileSync, spawn } from "node:child_process";
3
+ import { chmodSync, createReadStream, createWriteStream, existsSync, mkdirSync, mkdtempSync, readFileSync, readdirSync, renameSync, rmSync, statSync } from "node:fs";
5
4
  import { dirname, join } from "node:path";
6
5
  import { homedir } from "node:os";
7
6
  import { fileURLToPath } from "node:url";
8
- //#region src/index.ts
9
- const __filename = fileURLToPath(import.meta.url);
10
- const __dirname = dirname(__filename);
11
- const VERSION = "0.1.0";
12
- const ENGINES_DIR = join(homedir(), ".jsorm", "engines");
13
- const DOWNLOAD_BASE = "https://download.jsorm.dev";
14
- const STABLE_MANIFEST_URL = `${DOWNLOAD_BASE}/engine/stable/manifest`;
15
- const STABLE_DOWNLOAD_URL = `${DOWNLOAD_BASE}/engine/download`;
16
- const EMBEDDED_PUBLIC_KEY_B64 = "pFJ+WOzwsMPbZyvF/bMPB0UNCvuosqFN7Hvjd/qmP78=";
17
- function getSpkiPublicKey() {
18
- const rawKey = Buffer.from(EMBEDDED_PUBLIC_KEY_B64, "base64");
19
- const spkiDer = Buffer.concat([Buffer.from("302a300506032b6570032100", "hex"), rawKey]);
20
- return createPublicKey({
21
- key: spkiDer,
22
- format: "der",
23
- type: "spki"
24
- });
25
- }
7
+ import { createHash, createPublicKey, verify } from "node:crypto";
8
+ import { Readable } from "node:stream";
9
+ import { pipeline } from "node:stream/promises";
10
+ //#region src/platform.ts
26
11
  function detectPlatform() {
27
12
  switch (process.platform) {
28
13
  case "linux": return "linux";
@@ -38,6 +23,10 @@ function detectArch() {
38
23
  default: throw new Error(`Unsupported architecture: ${process.arch}`);
39
24
  }
40
25
  }
26
+ function getEngineBinaryName() {
27
+ const platform = detectPlatform();
28
+ return `jsorm-${platform}-${detectArch()}${platform === "windows" ? ".exe" : ""}`;
29
+ }
41
30
  function detectPackageManager() {
42
31
  let dir = process.cwd();
43
32
  for (let i = 0; i < 10; i++) {
@@ -95,37 +84,78 @@ function detectFramework() {
95
84
  }
96
85
  return "none";
97
86
  }
98
- function getEngineBinaryName() {
99
- const platform = detectPlatform();
100
- return `jsorm-${platform}-${detectArch()}${platform === "windows" ? ".exe" : ""}`;
101
- }
102
- function getLocalDevEnginePath() {
103
- const debug = join(__dirname, "..", "..", "..", "engine", "target", "debug", "jsorm");
104
- if (existsSync(debug)) return debug;
105
- const release = join(__dirname, "..", "..", "..", "engine", "target", "release", "jsorm");
106
- if (existsSync(release)) return release;
107
- return null;
87
+ //#endregion
88
+ //#region src/manifest.ts
89
+ const EMBEDDED_PUBLIC_KEY_B64 = "6AUQMvF7jBV+S8yv9K8hnnoYzIznQw4nf5x5LAuEsfM=";
90
+ function getSpkiPublicKey(rawKeyB64 = EMBEDDED_PUBLIC_KEY_B64) {
91
+ const rawKey = Buffer.from(rawKeyB64, "base64");
92
+ const spkiDer = Buffer.concat([Buffer.from("302a300506032b6570032100", "hex"), rawKey]);
93
+ return createPublicKey({
94
+ key: spkiDer,
95
+ format: "der",
96
+ type: "spki"
97
+ });
108
98
  }
109
- function getInstalledEnginePath(binaryName) {
110
- const version = detectInstalledVersion(binaryName);
111
- if (!version) return null;
112
- return join(getVersionDir(version), binaryName);
99
+ function invalid(reason) {
100
+ return {
101
+ status: "invalid",
102
+ reason
103
+ };
113
104
  }
114
- function verifySignature(data, signature) {
105
+ /**
106
+ * Verifies the envelope `{ success, signature, signed_payload }` and returns
107
+ * the manifest decoded from `signed_payload`, the exact bytes that were signed.
108
+ * The unsigned `envelope.manifest` copy is never trusted.
109
+ */
110
+ function parseSignedEnvelope(envelope, publicKey) {
111
+ if (!envelope || typeof envelope !== "object") return invalid("Invalid manifest response");
112
+ const { success, signature, signed_payload } = envelope;
113
+ if (success !== true) return invalid("Invalid manifest response");
114
+ if (typeof signature !== "string" || typeof signed_payload !== "string") return invalid("Manifest signature or signed payload missing. Refusing to continue without signature verification.");
115
+ const sigBytes = Buffer.from(signature, "base64");
116
+ if (sigBytes.length !== 64) return invalid(`Invalid signature length: ${sigBytes.length} (expected 64)`);
117
+ const signedBytes = Buffer.from(signed_payload, "base64");
118
+ let valid = false;
119
+ try {
120
+ valid = verify(null, signedBytes, publicKey, sigBytes);
121
+ } catch {}
122
+ if (!valid) return invalid("Manifest signature verification failed. The manifest may have been tampered with.");
123
+ let manifest;
115
124
  try {
116
- const publicKey = getSpkiPublicKey();
117
- return verify(null, data, publicKey, signature);
125
+ manifest = JSON.parse(signedBytes.toString("utf-8"));
118
126
  } catch {
119
- return false;
127
+ return invalid("Signed manifest is not valid JSON");
120
128
  }
129
+ if (typeof manifest?.version !== "string" || !manifest.targets || typeof manifest.targets !== "object") return invalid("Invalid manifest format");
130
+ return {
131
+ status: "ok",
132
+ manifest
133
+ };
121
134
  }
122
- function verifyManifest(signedPayload, signature) {
123
- if (signature.length !== 64) {
124
- console.log(` ✖ Invalid signature length: ${signature.length} (expected 64)`);
125
- return false;
135
+ async function fetchManifest(url, publicKey = getSpkiPublicKey()) {
136
+ let res;
137
+ try {
138
+ res = await fetch(url, { signal: AbortSignal.timeout(1e4) });
139
+ } catch (err) {
140
+ return {
141
+ status: "unreachable",
142
+ reason: `Manifest fetch error: ${err instanceof Error ? err.message : err}`
143
+ };
144
+ }
145
+ if (!res.ok) return {
146
+ status: "unreachable",
147
+ reason: `Manifest fetch failed: ${res.status} ${res.statusText}`
148
+ };
149
+ let envelope;
150
+ try {
151
+ envelope = await res.json();
152
+ } catch {
153
+ return invalid("Invalid manifest response");
126
154
  }
127
- return verifySignature(signedPayload, signature);
155
+ return parseSignedEnvelope(envelope, publicKey);
128
156
  }
157
+ //#endregion
158
+ //#region src/install.ts
129
159
  function compareVersions(a, b) {
130
160
  const pa = a.split(".").map(Number);
131
161
  const pb = b.split(".").map(Number);
@@ -137,148 +167,162 @@ function compareVersions(a, b) {
137
167
  }
138
168
  return 0;
139
169
  }
140
- function detectInstalledVersion(target) {
141
- if (!existsSync(ENGINES_DIR)) return null;
142
- const dirs = readdirSync(ENGINES_DIR).filter((d) => d.startsWith("v")).sort((a, b) => {
143
- const va = a.slice(1);
144
- return compareVersions(b.slice(1), va);
145
- });
146
- for (const dir of dirs) {
147
- const binPath = join(ENGINES_DIR, dir, target);
148
- if (existsSync(binPath)) return dir.slice(1);
149
- }
170
+ function getVersionDir(enginesDir, version) {
171
+ return join(enginesDir, `v${version}`);
172
+ }
173
+ /** Newest installed version that holds `binaryName`, e.g. "0.1.3". */
174
+ function detectInstalledVersion(enginesDir, binaryName) {
175
+ if (!existsSync(enginesDir)) return null;
176
+ const dirs = readdirSync(enginesDir).filter((d) => d.startsWith("v")).sort((a, b) => compareVersions(b.slice(1), a.slice(1)));
177
+ for (const dir of dirs) if (existsSync(join(enginesDir, dir, binaryName))) return dir.slice(1);
150
178
  return null;
151
179
  }
152
- function getVersionDir(version) {
153
- return join(ENGINES_DIR, `v${version}`);
180
+ async function sha256File(filePath) {
181
+ const hash = createHash("sha256");
182
+ await pipeline(createReadStream(filePath), hash);
183
+ return hash.digest("hex");
184
+ }
185
+ async function downloadToFile(url, destPath) {
186
+ const res = await fetch(url, { signal: AbortSignal.timeout(6e4) });
187
+ if (!res.ok || !res.body) throw new Error(`Download failed: ${res.status} ${res.statusText}`);
188
+ await pipeline(Readable.fromWeb(res.body), createWriteStream(destPath));
154
189
  }
155
- async function downloadManifest() {
190
+ function extractTarGz(tarPath, destDir) {
156
191
  try {
157
- console.log(` Fetching manifest from ${STABLE_MANIFEST_URL}...`);
158
- const manifestRes = await fetch(STABLE_MANIFEST_URL, { signal: AbortSignal.timeout(1e4) });
159
- if (!manifestRes.ok) {
160
- console.log(` ✖ Manifest fetch failed: ${manifestRes.status} ${manifestRes.statusText}`);
161
- return null;
162
- }
163
- const envelope = await manifestRes.json();
164
- if (!envelope.success || !envelope.manifest) {
165
- console.log(` ✖ Invalid manifest response`);
166
- return null;
167
- }
168
- const manifest = envelope.manifest;
169
- if (!manifest.targets || typeof manifest.targets !== "object") {
170
- console.log(` ✖ Invalid manifest format`);
171
- return null;
172
- }
173
- if (envelope.signature && envelope.signed_payload) {
174
- const signedBytes = Buffer.from(envelope.signed_payload, "base64");
175
- const sigBytes = Buffer.from(envelope.signature, "base64");
176
- console.log(` Verifying manifest signature...`);
177
- if (!verifyManifest(signedBytes, sigBytes)) {
178
- console.error(` ✖ Manifest signature verification failed.`);
179
- console.error(` The manifest may have been tampered with.`);
180
- process.exit(1);
181
- }
182
- console.log(` ✓ Manifest signature verified`);
183
- } else {
184
- console.error(` ✖ Manifest signature or signed payload missing.`);
185
- console.error(` Refusing to continue without signature verification.`);
186
- return null;
187
- }
188
- console.log(` ✓ Manifest v${manifest.version} (${Object.keys(manifest.targets).length} targets)`);
189
- return {
190
- manifest,
191
- stableVersion: manifest.version
192
- };
192
+ execFileSync("tar", [
193
+ "-xzf",
194
+ tarPath,
195
+ "-C",
196
+ destDir
197
+ ], { stdio: "pipe" });
193
198
  } catch (err) {
194
- console.log(` ✖ Manifest fetch error: ${err instanceof Error ? err.message : err}`);
195
- return null;
199
+ const msg = err instanceof Error ? err.message : String(err);
200
+ throw new Error(`tar extraction failed: ${msg}`);
196
201
  }
197
202
  }
198
- async function sha256File(filePath) {
199
- return new Promise((resolve, reject) => {
200
- const hash = createHash("sha256");
201
- const stream = createReadStream(filePath);
202
- stream.on("data", (data) => hash.update(data));
203
- stream.on("end", () => resolve(hash.digest("hex")));
204
- stream.on("error", reject);
205
- });
206
- }
207
- async function downloadAndExtractEngine(url, destDir, binaryName, expectedSha256) {
208
- const tempDir = join(ENGINES_DIR, ".tmp");
209
- mkdirSync(tempDir, { recursive: true });
210
- const tarPath = join(tempDir, `${binaryName}.tar.gz`);
203
+ /**
204
+ * Downloads, verifies and extracts the engine inside a private temp directory,
205
+ * and only then moves the binary into `<enginesDir>/v<version>/<binaryName>`.
206
+ * A failed or interrupted install never leaves a binary at the final path.
207
+ * Returns the installed binary path.
208
+ */
209
+ async function installEngine(options) {
210
+ const { url, enginesDir, version, binaryName, expectedSha256, log = () => {} } = options;
211
+ mkdirSync(enginesDir, { recursive: true });
212
+ const tempDir = mkdtempSync(join(enginesDir, ".tmp-"));
211
213
  try {
212
- console.log(` Downloading from ${url}...`);
213
- const res = await fetch(url, { signal: AbortSignal.timeout(6e4) });
214
- if (!res.ok) {
215
- console.log(` ✖ Download failed: ${res.status} ${res.statusText}`);
216
- return false;
217
- }
218
- const fileStream = createWriteStream(tarPath);
219
- if (res.body) {
220
- const reader = res.body.getReader();
221
- while (true) {
222
- const { done, value } = await reader.read();
223
- if (done) break;
224
- fileStream.write(value);
225
- }
226
- }
227
- fileStream.end();
228
- await new Promise((resolve, reject) => {
229
- fileStream.on("finish", resolve);
230
- fileStream.on("error", reject);
231
- });
232
- const tarSize = statSync(tarPath).size;
233
- console.log(` ✓ Downloaded ${(tarSize / 1024).toFixed(1)} KB`);
234
- console.log(` Verifying checksum...`);
214
+ const tarPath = join(tempDir, "engine.tar.gz");
215
+ log(` Downloading from ${url}...`);
216
+ await downloadToFile(url, tarPath);
217
+ log(` ✓ Downloaded ${(statSync(tarPath).size / 1024).toFixed(1)} KB`);
218
+ log(` Verifying checksum...`);
235
219
  const hash = await sha256File(tarPath);
236
- if (hash !== expectedSha256) {
237
- console.error(` ✖ Checksum mismatch!`);
238
- console.error(` Expected: ${expectedSha256}`);
239
- console.error(` Got: ${hash}`);
240
- unlinkSync(tarPath);
241
- return false;
242
- }
243
- console.log(` ✓ Checksum verified`);
244
- console.log(` Extracting...`);
245
- mkdirSync(destDir, { recursive: true });
246
- await extractTarGz(tarPath, destDir);
247
- const extractedPath = join(destDir, "jsorm");
220
+ if (hash !== expectedSha256) throw new Error(`Checksum mismatch!\n Expected: ${expectedSha256}\n Got: ${hash}`);
221
+ log(` ✓ Checksum verified`);
222
+ log(` Extracting...`);
223
+ const extractDir = join(tempDir, "out");
224
+ mkdirSync(extractDir);
225
+ extractTarGz(tarPath, extractDir);
226
+ const extractedPath = join(extractDir, "jsorm");
227
+ if (!existsSync(extractedPath)) throw new Error(`Archive does not contain the "jsorm" binary`);
228
+ if (process.platform !== "win32") chmodSync(extractedPath, 493);
229
+ const destDir = getVersionDir(enginesDir, version);
248
230
  const destPath = join(destDir, binaryName);
249
- if (existsSync(extractedPath) && extractedPath !== destPath) renameSync(extractedPath, destPath);
250
- if (process.platform !== "win32") chmodSync(destPath, 493);
251
- console.log(` ✓ Engine installed: ${destPath}`);
252
- return true;
253
- } catch (err) {
254
- console.log(` ✖ Extract error: ${err instanceof Error ? err.message : err}`);
255
- return false;
231
+ mkdirSync(destDir, { recursive: true });
232
+ renameSync(extractedPath, destPath);
233
+ log(` ✓ Engine installed: ${destPath}`);
234
+ return destPath;
256
235
  } finally {
257
- try {
258
- unlinkSync(tarPath);
259
- } catch {}
236
+ rmSync(tempDir, {
237
+ recursive: true,
238
+ force: true
239
+ });
260
240
  }
261
241
  }
262
- async function extractTarGz(tarPath, destDir) {
263
- execSync(`tar --no-same-owner --no-same-link -xzf "${tarPath}" -C "${destDir}"`, { stdio: "pipe" });
242
+ //#endregion
243
+ //#region src/resolve.ts
244
+ /**
245
+ * Returns the path of an engine binary that is safe to run: the installed one
246
+ * when it is current, or a freshly installed stable release. When the server
247
+ * cannot be reached, an installed engine is used as is. Throws when no engine
248
+ * can be provided or when the server's answer cannot be trusted.
249
+ */
250
+ async function resolveEngine(options) {
251
+ const { enginesDir, binaryName, manifestUrl, downloadUrl, publicKey = getSpkiPublicKey(), log = () => {} } = options;
252
+ const installedVer = detectInstalledVersion(enginesDir, binaryName);
253
+ const installedPath = installedVer ? join(getVersionDir(enginesDir, installedVer), binaryName) : null;
254
+ log(` Fetching manifest from ${manifestUrl}...`);
255
+ const result = await fetchManifest(manifestUrl, publicKey);
256
+ if (result.status === "unreachable") {
257
+ if (installedPath) {
258
+ log(` ⚠ ${result.reason}`);
259
+ log(` ⚠ Using installed engine v${installedVer} without checking for updates`);
260
+ return installedPath;
261
+ }
262
+ throw new Error(`${result.reason}\n ✖ Failed to fetch manifest.`);
263
+ }
264
+ if (result.status === "invalid") throw new Error(result.reason);
265
+ const { manifest } = result;
266
+ const stableVersion = manifest.version;
267
+ log(` ✓ Manifest signature verified`);
268
+ log(` ✓ Manifest v${stableVersion} (${Object.keys(manifest.targets).length} targets)`);
269
+ const target = manifest.targets[binaryName];
270
+ if (!target) throw new Error(`No binary available for ${binaryName}\n Available: ${Object.keys(manifest.targets).join(", ")}`);
271
+ if (installedPath && installedVer && compareVersions(stableVersion, installedVer) <= 0) {
272
+ log(` ✓ Engine v${installedVer} is up to date (stable: v${stableVersion})`);
273
+ return installedPath;
274
+ }
275
+ log(installedVer ? ` Update available: v${installedVer} → v${stableVersion}` : ` Engine not found. Downloading v${stableVersion}...`);
276
+ log(` Requesting download URL...`);
277
+ const dlRes = await fetch(`${downloadUrl}/${binaryName}`, { signal: AbortSignal.timeout(1e4) });
278
+ if (!dlRes.ok) throw new Error(`Download request failed: ${dlRes.status} ${dlRes.statusText}`);
279
+ const dl = await dlRes.json();
280
+ if (dl.version !== stableVersion) throw new Error(`Version mismatch: server returned v${dl.version}, manifest says v${stableVersion}`);
281
+ if (dl.sha256 !== target.sha256) throw new Error(`SHA-256 mismatch: server returned ${String(dl.sha256).slice(0, 16)}, manifest says ${target.sha256.slice(0, 16)}`);
282
+ return installEngine({
283
+ url: dl.url,
284
+ enginesDir,
285
+ version: stableVersion,
286
+ binaryName,
287
+ expectedSha256: target.sha256,
288
+ log
289
+ });
290
+ }
291
+ //#endregion
292
+ //#region src/index.ts
293
+ const __filename = fileURLToPath(import.meta.url);
294
+ const __dirname = dirname(__filename);
295
+ const ENGINES_DIR = join(homedir(), ".jsorm", "engines");
296
+ const DOWNLOAD_BASE = "https://download.jsorm.dev";
297
+ const STABLE_MANIFEST_URL = `${DOWNLOAD_BASE}/engine/stable/manifest`;
298
+ const STABLE_DOWNLOAD_URL = `${DOWNLOAD_BASE}/engine/download`;
299
+ function readVersion() {
300
+ try {
301
+ return JSON.parse(readFileSync(join(__dirname, "..", "package.json"), "utf-8")).version;
302
+ } catch {
303
+ return "unknown";
304
+ }
305
+ }
306
+ function getLocalDevEnginePath() {
307
+ const debug = join(__dirname, "..", "..", "..", "engine", "target", "debug", "jsorm");
308
+ if (existsSync(debug)) return debug;
309
+ const release = join(__dirname, "..", "..", "..", "engine", "target", "release", "jsorm");
310
+ if (existsSync(release)) return release;
311
+ return null;
264
312
  }
265
313
  function executeEngine(enginePath, args) {
266
- const projectDir = process.cwd();
267
- const framework = detectFramework();
268
- const pm = detectPackageManager();
269
- const runtime = detectRuntime();
270
314
  const engineArgs = [
271
315
  ...args,
272
316
  "--framework",
273
- framework,
317
+ detectFramework(),
274
318
  "--pm",
275
- pm,
319
+ detectPackageManager(),
276
320
  "--runtime",
277
- runtime
321
+ detectRuntime()
278
322
  ];
279
323
  const child = spawn(enginePath, engineArgs, {
280
324
  stdio: "inherit",
281
- cwd: projectDir
325
+ cwd: process.cwd()
282
326
  });
283
327
  child.on("error", (err) => {
284
328
  console.error(` ✖ Failed to start engine: ${err.message}`);
@@ -290,8 +334,8 @@ function executeEngine(enginePath, args) {
290
334
  }
291
335
  async function main() {
292
336
  const args = process.argv.slice(2);
293
- if (args.includes("--version") || args.includes("-v")) {
294
- console.log(VERSION);
337
+ if (args.includes("--version") || args.includes("-v") || args.includes("-V")) {
338
+ console.log(readVersion());
295
339
  return;
296
340
  }
297
341
  if (args.length === 0 || args.includes("--help") || args.includes("-h")) {
@@ -300,7 +344,7 @@ async function main() {
300
344
  executeEngine(localEnginePath, args);
301
345
  return;
302
346
  }
303
- console.log(`jsorm ${VERSION}`);
347
+ console.log(`jsorm ${readVersion()}`);
304
348
  console.log("JSORM CLI — TypeScript ORM code generation");
305
349
  console.log();
306
350
  console.log("Commands:");
@@ -309,9 +353,9 @@ async function main() {
309
353
  console.log(" watch Watch model files and regenerate on changes");
310
354
  console.log();
311
355
  console.log("Options:");
312
- console.log(" --help, -h Print help");
313
- console.log(" --version, -V Print version");
314
- console.log(" --dry-run Show what would be generated without writing files");
356
+ console.log(" --help, -h Print help");
357
+ console.log(" --version, -v, -V Print version");
358
+ console.log(" --dry-run Show what would be generated without writing files");
315
359
  return;
316
360
  }
317
361
  const localEnginePath = getLocalDevEnginePath();
@@ -319,45 +363,20 @@ async function main() {
319
363
  executeEngine(localEnginePath, args);
320
364
  return;
321
365
  }
322
- const binaryName = getEngineBinaryName();
323
- const result = await downloadManifest();
324
- if (!result) {
325
- console.error(` ✖ Failed to fetch manifest.`);
326
- process.exit(1);
327
- }
328
- const { manifest, stableVersion } = result;
329
- const target = manifest.targets[binaryName];
330
- if (!target) {
331
- console.error(` ✖ No binary available for ${binaryName}`);
332
- console.error(` Available: ${Object.keys(manifest.targets).join(", ")}`);
333
- process.exit(1);
334
- }
335
- const installedPath = getInstalledEnginePath(binaryName);
336
- const installedVer = installedPath ? detectInstalledVersion(binaryName) : null;
337
- if (installedVer && compareVersions(stableVersion, installedVer) <= 0) {
338
- console.log(` ✓ Engine v${installedVer} is up to date (stable: v${stableVersion})`);
339
- executeEngine(installedPath, args);
340
- return;
341
- }
342
- if (installedVer) console.log(` Update available: v${installedVer} → v${stableVersion}`);
343
- else console.log(` Engine not found. Downloading v${stableVersion}...`);
344
- console.log(` Requesting download URL...`);
345
- const dlRes = await fetch(`${STABLE_DOWNLOAD_URL}/${binaryName}`, { signal: AbortSignal.timeout(1e4) });
346
- if (!dlRes.ok) {
347
- console.error(` ✖ Download request failed: ${dlRes.status} ${dlRes.statusText}`);
348
- process.exit(1);
349
- }
350
- const dl = await dlRes.json();
351
- if (dl.version !== stableVersion) {
352
- console.error(` ✖ Version mismatch: server returned v${dl.version}, manifest says v${stableVersion}`);
353
- process.exit(1);
354
- }
355
- if (dl.sha256 !== target.sha256) {
356
- console.error(` ✖ SHA-256 mismatch: server returned ${dl.sha256.slice(0, 16)}, manifest says ${target.sha256.slice(0, 16)}`);
366
+ let enginePath;
367
+ try {
368
+ enginePath = await resolveEngine({
369
+ enginesDir: ENGINES_DIR,
370
+ binaryName: getEngineBinaryName(),
371
+ manifestUrl: STABLE_MANIFEST_URL,
372
+ downloadUrl: STABLE_DOWNLOAD_URL,
373
+ log: console.log
374
+ });
375
+ } catch (err) {
376
+ console.error(` ✖ ${err instanceof Error ? err.message : err}`);
357
377
  process.exit(1);
358
378
  }
359
- const destDir = getVersionDir(stableVersion);
360
- if (await downloadAndExtractEngine(dl.url, destDir, binaryName, target.sha256)) executeEngine(join(destDir, binaryName), args);
379
+ executeEngine(enginePath, args);
361
380
  }
362
381
  main();
363
382
  //#endregion
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@jsorm/cli",
3
3
  "type": "module",
4
- "version": "0.1.0",
4
+ "version": "0.1.3",
5
5
  "description": "CLI de JSORM",
6
6
  "license": "MPL-2.0",
7
7
  "repository": {
@@ -20,7 +20,7 @@
20
20
  "main": "./dist/index.mjs",
21
21
  "types": "./dist/index.d.mts",
22
22
  "bin": {
23
- "@jsorm/cli": "./dist/index.mjs"
23
+ "jsorm": "./dist/index.mjs"
24
24
  },
25
25
  "exports": {
26
26
  ".": {
@@ -35,7 +35,7 @@
35
35
  "access": "public"
36
36
  },
37
37
  "dependencies": {
38
- "@jsorm/core": "1.0.1"
38
+ "@jsorm/core": "1.0.3"
39
39
  },
40
40
  "devDependencies": {
41
41
  "@types/node": "^26.1.1",