apex-dev 3.10.20 → 3.10.23

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/cli.js CHANGED
@@ -7,6 +7,8 @@ const https = require("https");
7
7
  const { spawnSync, spawn } = require("child_process");
8
8
 
9
9
  const VERSION = require("./package.json").version;
10
+ const RELEASE_OWNER = "Marcus-Mok-GH";
11
+ const RELEASE_REPO = "apex-dev";
10
12
 
11
13
  // ── Config ────────────────────────────────────────────────────────────────
12
14
  const CONFIG_PATH = path.join(os.homedir(), ".apex-dev", "config.json");
@@ -135,9 +137,91 @@ function getCacheDir() {
135
137
  return dir;
136
138
  }
137
139
 
140
+ function getBinaryCacheDir() {
141
+ return path.join(getCacheDir(), "bin", `v${VERSION}`);
142
+ }
143
+
144
+ function getBinaryMetadataPath() {
145
+ return path.join(getBinaryCacheDir(), `${getBinaryName()}.json`);
146
+ }
147
+
148
+ function readBinaryMetadata() {
149
+ try {
150
+ const metadataPath = getBinaryMetadataPath();
151
+ if (!fs.existsSync(metadataPath)) return null;
152
+ return JSON.parse(fs.readFileSync(metadataPath, "utf-8"));
153
+ } catch {
154
+ return null;
155
+ }
156
+ }
157
+
158
+ function saveBinaryMetadata(metadata) {
159
+ const metadataPath = getBinaryMetadataPath();
160
+ fs.mkdirSync(path.dirname(metadataPath), { recursive: true });
161
+ fs.writeFileSync(metadataPath, JSON.stringify(metadata, null, 2));
162
+ fs.chmodSync(metadataPath, 0o600);
163
+ }
164
+
165
+ function clearBinaryMetadata() {
166
+ try { fs.unlinkSync(getBinaryMetadataPath()); } catch {}
167
+ }
168
+
169
+ function fetchReleaseAssetInfo() {
170
+ const apiUrl = `https://api.github.com/repos/${RELEASE_OWNER}/${RELEASE_REPO}/releases/tags/v${VERSION}`;
171
+ return new Promise((resolve, reject) => {
172
+ const req = https.get(apiUrl, {
173
+ headers: {
174
+ "accept": "application/vnd.github+json",
175
+ "user-agent": "apex-dev-installer"
176
+ }
177
+ }, (res) => {
178
+ let body = "";
179
+ res.setEncoding("utf8");
180
+ res.on("data", (chunk) => {
181
+ body += chunk;
182
+ });
183
+ res.on("end", () => {
184
+ if (res.statusCode !== 200) {
185
+ reject(new Error(`Release metadata request failed with status ${res.statusCode}`));
186
+ return;
187
+ }
188
+ try {
189
+ const release = JSON.parse(body);
190
+ const assetName = getBinaryName();
191
+ const asset = Array.isArray(release.assets) ? release.assets.find((item) => item.name === assetName) : null;
192
+ if (!asset) {
193
+ reject(new Error(`Release asset ${assetName} not found`));
194
+ return;
195
+ }
196
+ resolve({
197
+ id: asset.id,
198
+ name: asset.name,
199
+ size: asset.size,
200
+ updatedAt: asset.updated_at,
201
+ downloadUrl: asset.browser_download_url || getDownloadUrl()
202
+ });
203
+ } catch (err) {
204
+ reject(new Error(`Invalid release metadata: ${err.message}`));
205
+ }
206
+ });
207
+ });
208
+ req.on("error", (err) => reject(err));
209
+ req.setTimeout(DOWNLOAD_TIMEOUT, () => {
210
+ req.destroy(new Error("Release metadata request timed out"));
211
+ });
212
+ });
213
+ }
214
+
215
+ function looksValidBinary(pathToBinary) {
216
+ try {
217
+ return fs.existsSync(pathToBinary) && fs.statSync(pathToBinary).size > 0;
218
+ } catch {
219
+ return false;
220
+ }
221
+ }
222
+
138
223
  function getLocalBinaryPath() {
139
- const cacheDir = getCacheDir();
140
- return path.join(cacheDir, getBinaryName());
224
+ return path.join(getBinaryCacheDir(), getBinaryName());
141
225
  }
142
226
 
143
227
  function getDownloadUrl() {
@@ -153,6 +237,7 @@ function downloadBinary(destPath) {
153
237
  console.error(`URL: ${url}`);
154
238
 
155
239
  return new Promise((resolve, reject) => {
240
+ fs.mkdirSync(path.dirname(destPath), { recursive: true });
156
241
  const file = fs.createWriteStream(destPath, { mode: 0o755 });
157
242
  let settled = false;
158
243
 
@@ -233,28 +318,51 @@ function downloadBinary(destPath) {
233
318
 
234
319
  async function ensureBinary() {
235
320
  const localPath = getLocalBinaryPath();
321
+ const cachedMetadata = readBinaryMetadata();
236
322
 
237
- if (fs.existsSync(localPath)) {
238
- // Check for empty/partial downloads and remove them
239
- try {
240
- const stat = fs.statSync(localPath);
241
- if (stat.size === 0) {
242
- fs.unlinkSync(localPath);
243
- } else {
244
- return localPath;
245
- }
246
- } catch {
247
- try { fs.unlinkSync(localPath); } catch {}
323
+ let releaseMetadata = null;
324
+ try {
325
+ releaseMetadata = await fetchReleaseAssetInfo();
326
+ } catch {
327
+ releaseMetadata = null;
328
+ }
329
+
330
+ const binaryExists = looksValidBinary(localPath);
331
+
332
+ if (binaryExists) {
333
+ if (!releaseMetadata || !cachedMetadata) {
334
+ return localPath;
335
+ }
336
+
337
+ const cacheMatches =
338
+ cachedMetadata.assetId === releaseMetadata.id &&
339
+ cachedMetadata.assetSize === releaseMetadata.size &&
340
+ cachedMetadata.assetUpdatedAt === releaseMetadata.updatedAt;
341
+
342
+ if (cacheMatches) {
343
+ return localPath;
248
344
  }
345
+
346
+ try { fs.unlinkSync(localPath); } catch {}
347
+ clearBinaryMetadata();
249
348
  }
250
349
 
251
350
  try {
252
351
  await downloadBinary(localPath);
352
+ if (releaseMetadata) {
353
+ saveBinaryMetadata({
354
+ assetId: releaseMetadata.id,
355
+ assetSize: releaseMetadata.size,
356
+ assetUpdatedAt: releaseMetadata.updatedAt,
357
+ downloadedAt: new Date().toISOString()
358
+ });
359
+ }
253
360
  console.error(`Binary downloaded to ${localPath}`);
254
361
  return localPath;
255
362
  } catch (err) {
256
363
  console.error(`Failed to download binary: ${err.message}`);
257
364
  try { fs.unlinkSync(localPath); } catch {}
365
+ clearBinaryMetadata();
258
366
  return null;
259
367
  }
260
368
  }
package/dist/apex CHANGED
Binary file