amaprice 1.0.13 → 1.0.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "amaprice",
3
- "version": "1.0.13",
3
+ "version": "1.0.15",
4
4
  "description": "CLI tool to scrape and track Amazon product prices",
5
5
  "main": "src/scraper.js",
6
6
  "type": "commonjs",
@@ -114,15 +114,17 @@ function isLaunchdSupported(platform = process.platform) {
114
114
  return platform === 'darwin';
115
115
  }
116
116
 
117
- function getLaunchdDomain() {
117
+ function getLaunchdDomains() {
118
118
  if (typeof process.getuid !== 'function') {
119
119
  throw new Error('launchd requires a POSIX uid');
120
120
  }
121
- return `gui/${process.getuid()}`;
121
+ const uid = process.getuid();
122
+ return [`gui/${uid}`, `user/${uid}`];
122
123
  }
123
124
 
124
- function buildServiceTarget(label) {
125
- return `${getLaunchdDomain()}/${label}`;
125
+ function buildServiceTarget(label, domain = null) {
126
+ const safeDomain = domain || getLaunchdDomains()[0];
127
+ return `${safeDomain}/${label}`;
126
128
  }
127
129
 
128
130
  async function runLaunchctl(args, { allowFailure = false } = {}) {
@@ -233,24 +235,38 @@ async function getLaunchdServiceStatus({ label }) {
233
235
  backend: 'launchd',
234
236
  label,
235
237
  plistPath,
238
+ domain: null,
236
239
  installed: false,
237
240
  loaded: false,
238
241
  running: false,
239
242
  };
240
243
  }
241
244
 
242
- const print = await runLaunchctl(['print', buildServiceTarget(label)], { allowFailure: true });
243
- const output = `${print.stdout}\n${print.stderr}`;
244
- const loaded = print.ok;
245
- const running = loaded && (/state = running/i.test(output) || /pid = \d+/i.test(output));
245
+ const domains = getLaunchdDomains();
246
+ for (const domain of domains) {
247
+ const print = await runLaunchctl(['print', buildServiceTarget(label, domain)], { allowFailure: true });
248
+ if (!print.ok) continue;
249
+ const output = `${print.stdout}\n${print.stderr}`;
250
+ const running = /state = running/i.test(output) || /pid = \d+/i.test(output);
251
+ return {
252
+ backend: 'launchd',
253
+ label,
254
+ plistPath,
255
+ domain,
256
+ installed: true,
257
+ loaded: true,
258
+ running,
259
+ };
260
+ }
246
261
 
247
262
  return {
248
263
  backend: 'launchd',
249
264
  label,
250
265
  plistPath,
266
+ domain: domains[0] || null,
251
267
  installed: true,
252
- loaded,
253
- running,
268
+ loaded: false,
269
+ running: false,
254
270
  };
255
271
  }
256
272
 
@@ -283,24 +299,53 @@ async function enableLaunchdService({
283
299
  });
284
300
  await fs.writeFile(plistPath, plist, 'utf8');
285
301
 
286
- const bootstrap = await runLaunchctl(['bootstrap', getLaunchdDomain(), plistPath], { allowFailure: true });
287
- if (!bootstrap.ok && !isAlreadyLoadedError(bootstrap)) {
288
- throw new Error(`Could not bootstrap launchd service: ${bootstrap.stderr || bootstrap.stdout || 'unknown error'}`);
289
- }
302
+ const domains = getLaunchdDomains();
303
+ const errors = [];
290
304
 
291
- await runLaunchctl(['enable', buildServiceTarget(label)], { allowFailure: true });
292
- const kick = await runLaunchctl(['kickstart', '-k', buildServiceTarget(label)], { allowFailure: true });
293
- if (!kick.ok) {
294
- await runLaunchctl(['start', label], { allowFailure: true });
305
+ for (const domain of domains) {
306
+ const domainTarget = buildServiceTarget(label, domain);
307
+
308
+ // Clean stale state first, then bootstrap fresh.
309
+ await runLaunchctl(['bootout', domainTarget], { allowFailure: true });
310
+ await runLaunchctl(['disable', domainTarget], { allowFailure: true });
311
+ await runLaunchctl(['enable', domainTarget], { allowFailure: true });
312
+
313
+ let bootstrap = await runLaunchctl(['bootstrap', domain, plistPath], { allowFailure: true });
314
+ if (!bootstrap.ok && !isAlreadyLoadedError(bootstrap)) {
315
+ await runLaunchctl(['bootout', domainTarget], { allowFailure: true });
316
+ await runLaunchctl(['enable', domainTarget], { allowFailure: true });
317
+ bootstrap = await runLaunchctl(['bootstrap', domain, plistPath], { allowFailure: true });
318
+ }
319
+
320
+ if (!bootstrap.ok && !isAlreadyLoadedError(bootstrap)) {
321
+ errors.push(`${domain}: ${bootstrap.stderr || bootstrap.stdout || 'unknown error'}`);
322
+ continue;
323
+ }
324
+
325
+ await runLaunchctl(['enable', domainTarget], { allowFailure: true });
326
+ const kick = await runLaunchctl(['kickstart', '-k', domainTarget], { allowFailure: true });
327
+ if (!kick.ok) {
328
+ await runLaunchctl(['start', label], { allowFailure: true });
329
+ }
330
+
331
+ const status = await getLaunchdServiceStatus({ label });
332
+ if (status.loaded) {
333
+ return status;
334
+ }
335
+ errors.push(`${domain}: bootstrapped but service not loaded`);
295
336
  }
296
337
 
297
- return getLaunchdServiceStatus({ label });
338
+ const msg = errors.length > 0 ? errors.join(' | ') : 'unknown error';
339
+ throw new Error(`Could not bootstrap launchd service: ${msg}`);
298
340
  }
299
341
 
300
342
  async function disableLaunchdService({ label }) {
301
343
  const plistPath = getLaunchdPlistPath(label);
302
- await runLaunchctl(['bootout', buildServiceTarget(label)], { allowFailure: true });
303
- await runLaunchctl(['disable', buildServiceTarget(label)], { allowFailure: true });
344
+ for (const domain of getLaunchdDomains()) {
345
+ const target = buildServiceTarget(label, domain);
346
+ await runLaunchctl(['bootout', target], { allowFailure: true });
347
+ await runLaunchctl(['disable', target], { allowFailure: true });
348
+ }
304
349
  try {
305
350
  await fs.unlink(plistPath);
306
351
  } catch (err) {
@@ -332,7 +377,7 @@ async function ensureBackgroundOn({
332
377
  const { collector, statePath } = await ensureCollectorEnabled({
333
378
  userId,
334
379
  collectorName,
335
- status: 'active',
380
+ status: 'paused',
336
381
  });
337
382
 
338
383
  const service = await enableLaunchdService({
@@ -342,6 +387,10 @@ async function ensureBackgroundOn({
342
387
  userId,
343
388
  });
344
389
 
390
+ if (!service.loaded) {
391
+ throw new Error('launchd service did not load');
392
+ }
393
+
345
394
  await heartbeatCollector({
346
395
  collectorId: collector.id,
347
396
  status: 'active',
@@ -500,6 +549,8 @@ module.exports.__test = {
500
549
  resolvePollSeconds,
501
550
  getLaunchdLabel,
502
551
  getLaunchdPlistPath,
552
+ getLaunchdDomains,
553
+ buildServiceTarget,
503
554
  renderLaunchdPlist,
504
555
  isLaunchdSupported,
505
556
  };