@atom-js-org/cli 0.4.1-alpha.0 → 0.4.3-alpha.0

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": "@atom-js-org/cli",
3
- "version": "0.4.1-alpha.0",
3
+ "version": "0.4.3-alpha.0",
4
4
  "description": "CLI for running and building AtomJS desktop applications.",
5
5
  "bin": {
6
6
  "atom": "bin/atom.cjs"
package/src/build.cjs CHANGED
@@ -70,6 +70,7 @@ async function localBuild(project, target, options = {}) {
70
70
  appDir,
71
71
  target,
72
72
  productName,
73
+ appId: project.config.appId,
73
74
  payloadPath
74
75
  });
75
76
 
@@ -106,7 +107,7 @@ async function localBuild(project, target, options = {}) {
106
107
  }
107
108
 
108
109
  const manifest = {
109
- atomjsVersion: '0.3.0-alpha.0',
110
+ atomjsVersion: '0.4.3-alpha.0',
110
111
  target,
111
112
  productName,
112
113
  appId: project.config.appId,
@@ -287,7 +288,7 @@ async function createApplicationPayload(appDir, outputPath) {
287
288
  await fs.promises.writeFile(outputPath, compressed);
288
289
  }
289
290
 
290
- async function createSeaLauncher({ executablePath, appDir, target, productName, payloadPath = null }) {
291
+ async function createSeaLauncher({ executablePath, appDir, target, productName, appId, payloadPath = null }) {
291
292
  const work = path.join(path.dirname(executablePath), '.sea-' + crypto.randomBytes(5).toString('hex'));
292
293
  await fse.ensureDir(work);
293
294
  const launcherPath = path.join(work, 'launcher.cjs');
@@ -295,7 +296,7 @@ async function createSeaLauncher({ executablePath, appDir, target, productName,
295
296
  const configPath = path.join(work, 'sea-config.json');
296
297
 
297
298
  if (!payloadPath) throw new Error('AtomJS SEA payload is required.');
298
- const launcher = createEmbeddedLauncherSource(productName);
299
+ const launcher = createEmbeddedLauncherSource(productName, appId);
299
300
  await fs.promises.writeFile(launcherPath, launcher, 'utf8');
300
301
 
301
302
  const seaConfig = {
@@ -314,8 +315,8 @@ async function createSeaLauncher({ executablePath, appDir, target, productName,
314
315
  if (target === 'windows') {
315
316
  await prepareWindowsExecutableForInjection(executablePath);
316
317
  }
317
- if (target === 'macos' && commandExists('codesign', ['--version'])) {
318
- spawnSync('codesign', ['--remove-signature', executablePath], { stdio: 'ignore' });
318
+ if (target === 'macos' && hasMacCodeSigningTool()) {
319
+ spawnSync('/usr/bin/codesign', ['--remove-signature', executablePath], { stdio: 'ignore' });
319
320
  }
320
321
 
321
322
  await inject(executablePath, 'NODE_SEA_BLOB', await fs.promises.readFile(blobPath), {
@@ -328,8 +329,8 @@ async function createSeaLauncher({ executablePath, appDir, target, productName,
328
329
  } else {
329
330
  await fs.promises.chmod(executablePath, 0o755);
330
331
  }
331
- if (target === 'macos' && commandExists('codesign', ['--version'])) {
332
- await run('codesign', ['--force', '--sign', '-', executablePath]);
332
+ if (target === 'macos' && hasMacCodeSigningTool()) {
333
+ await run('/usr/bin/codesign', ['--force', '--sign', '-', executablePath]);
333
334
  }
334
335
  await fse.remove(work);
335
336
  }
@@ -367,23 +368,36 @@ function readPortableExecutableLayout(image) {
367
368
  }
368
369
 
369
370
  const peOffset = image.readUInt32LE(0x3c);
370
- if (peOffset < 0x40 || peOffset + 0x100 > image.length || image.toString('ascii', peOffset, peOffset + 4) !== 'PE\\0\\0') {
371
+ const coffHeaderSize = 24;
372
+ if (peOffset < 0x40 || peOffset + coffHeaderSize > image.length || image.readUInt32LE(peOffset) !== 0x00004550) {
371
373
  throw new Error('AtomJS expected a Windows PE executable but the PE header is invalid.');
372
374
  }
373
375
 
374
- const optionalHeaderOffset = peOffset + 24;
376
+ const optionalHeaderSize = image.readUInt16LE(peOffset + 20);
377
+ const optionalHeaderOffset = peOffset + coffHeaderSize;
378
+ const optionalHeaderEnd = optionalHeaderOffset + optionalHeaderSize;
379
+ if (optionalHeaderSize < 2 || optionalHeaderEnd > image.length) {
380
+ throw new Error('AtomJS expected a complete Windows PE optional header.');
381
+ }
382
+
375
383
  const magic = image.readUInt16LE(optionalHeaderOffset);
376
384
  if (magic !== 0x10b && magic !== 0x20b) {
377
385
  throw new Error(`AtomJS does not support Windows PE optional-header magic 0x${magic.toString(16)}.`);
378
386
  }
379
387
 
388
+ const dataDirectoryOffset = optionalHeaderOffset + (magic === 0x20b ? 112 : 96);
389
+ const certificateDirectoryEnd = dataDirectoryOffset + (8 * 5);
390
+ if (certificateDirectoryEnd > optionalHeaderEnd) {
391
+ throw new Error('AtomJS expected the Windows PE certificate data directory.');
392
+ }
393
+
380
394
  return {
381
395
  optionalHeaderOffset,
382
- dataDirectoryOffset: optionalHeaderOffset + (magic === 0x20b ? 112 : 96)
396
+ dataDirectoryOffset
383
397
  };
384
398
  }
385
399
 
386
- function createEmbeddedLauncherSource(productName) {
400
+ function createEmbeddedLauncherSource(productName, appId) {
387
401
  return `
388
402
  'use strict';
389
403
  const path = require('node:path');
@@ -396,6 +410,7 @@ const { pathToFileURL } = require('node:url');
396
410
  const { getAsset } = require('node:sea');
397
411
 
398
412
  const productName = ${JSON.stringify(productName)};
413
+ const appId = ${JSON.stringify(appId || 'com.atomjs.app')};
399
414
  const payload = Buffer.from(getAsset('atom-app'));
400
415
  const payloadHash = crypto.createHash('sha256').update(payload).digest('hex').slice(0, 24);
401
416
  const dataRoot = process.platform === 'darwin'
@@ -435,10 +450,16 @@ if (!fs.existsSync(packagePath)) throw new Error('AtomJS could not materialize t
435
450
  const executableDir = path.dirname(process.execPath);
436
451
  process.chdir(appDir);
437
452
  process.env.ATOM_PROJECT_ROOT = appDir;
453
+ process.env.ATOM_APP_NAME = productName;
454
+ process.env.ATOM_APP_ID = appId;
438
455
  process.env.ATOM_BUILD = '1';
439
456
  process.env.ATOM_EMBEDDED_RUNTIME = '1';
440
457
  process.env.ATOM_WINDOW_HOST_ENTRY = path.join(appDir, 'vendor', 'atomjs', 'src', 'runtime', 'window-host.mjs');
441
458
  process.env.ATOM_MACOS_HOST_EXECUTABLE = path.join(executableDir, 'AtomJSWindowHost');
459
+ const bundledMacIcon = path.join(executableDir, '..', 'Resources', 'AppIcon.icns');
460
+ if (process.platform === 'darwin' && fs.existsSync(bundledMacIcon)) {
461
+ process.env.ATOM_APP_ICON = bundledMacIcon;
462
+ }
442
463
  const hostModeIndex = process.argv.indexOf('--atomjs-window-host');
443
464
  if (hostModeIndex !== -1) {
444
465
  const hostEntry = process.env.ATOM_WINDOW_HOST_ENTRY;
@@ -545,6 +566,10 @@ function resolveNsisExecutable() {
545
566
  return candidates.find((candidate) => fs.existsSync(candidate)) || null;
546
567
  }
547
568
 
569
+ function hasMacCodeSigningTool() {
570
+ return process.platform === 'darwin' && fs.existsSync('/usr/bin/codesign');
571
+ }
572
+
548
573
  async function packageMacOS({ project, buildRoot, unpacked, executableName, productName, hostSource }) {
549
574
  const outputs = [];
550
575
  const appBundle = path.join(buildRoot, `${productName}.app`);
@@ -609,7 +634,7 @@ ${iconEntry}
609
634
  await run('/usr/bin/plutil', ['-lint', plistPath]);
610
635
  }
611
636
 
612
- if (commandExists('/usr/bin/codesign', ['--version'])) {
637
+ if (hasMacCodeSigningTool()) {
613
638
  await run('/usr/bin/codesign', ['--force', '--sign', '-', nativeHost]);
614
639
  await run('/usr/bin/codesign', ['--force', '--sign', '-', mainExecutable]);
615
640
  await run('/usr/bin/codesign', ['--force', '--deep', '--sign', '-', appBundle]);
@@ -783,4 +808,4 @@ function xml(value) {
783
808
  return String(value).replace(/[<>&'\"]/g, (char) => ({ '<': '&lt;', '>': '&gt;', '&': '&amp;', "'": '&apos;', '"': '&quot;' })[char]);
784
809
  }
785
810
 
786
- module.exports = { buildCommand, localBuild, createApplicationPayload };
811
+ module.exports = { buildCommand, localBuild, createApplicationPayload, readPortableExecutableLayout };
package/src/doctor.cjs CHANGED
@@ -19,7 +19,7 @@ async function doctorCommand(options = {}) {
19
19
  rows.push(check('Xcode Command Line Tools', commandExists('/usr/bin/xcrun', ['--version']), 'required to compile the native Cocoa host'));
20
20
  rows.push(check('Clang', commandExists('/usr/bin/xcrun', ['clang', '--version'])));
21
21
  rows.push(check('WebKit framework', fs.existsSync('/System/Library/Frameworks/WebKit.framework')));
22
- rows.push(check('codesign', commandExists('/usr/bin/codesign', ['--version'])));
22
+ rows.push(check('codesign', fs.existsSync('/usr/bin/codesign'), '/usr/bin/codesign'));
23
23
  rows.push(check('hdiutil', commandExists('hdiutil', ['help'])));
24
24
  } else {
25
25
  rows.push(check('pkg-config', commandExists('pkg-config', ['--version'])));
package/src/init.cjs CHANGED
@@ -30,14 +30,14 @@ async function initCommand(directory, options = {}) {
30
30
  start: 'atom run build'
31
31
  },
32
32
  dependencies: {
33
- '@atom-js-org/runtime': '0.3.0-alpha.0',
34
- electron: 'npm:@atom-js-org/electron@0.3.0-alpha.0'
33
+ '@atom-js-org/runtime': '0.4.3-alpha.0',
34
+ electron: 'npm:@atom-js-org/electron@0.4.3-alpha.0'
35
35
  },
36
36
  optionalDependencies: {
37
37
  'webview-nodejs': '0.5.0'
38
38
  },
39
39
  devDependencies: {
40
- '@atom-js-org/cli': '0.3.0-alpha.0'
40
+ '@atom-js-org/cli': '0.4.3-alpha.0'
41
41
  },
42
42
  overrides: {
43
43
  tar: '7.5.20'
package/src/run.cjs CHANGED
@@ -23,11 +23,17 @@ async function runDev(options) {
23
23
 
24
24
  await ensureElectronCompatibility(project.root);
25
25
 
26
+ const iconPath = project.config.icon
27
+ ? path.resolve(project.root, project.config.icon)
28
+ : null;
26
29
  const child = spawn(process.execPath, [mainPath], {
27
30
  cwd: project.root,
28
31
  env: {
29
32
  ...process.env,
30
33
  ATOM_PROJECT_ROOT: project.root,
34
+ ATOM_APP_NAME: project.config.productName,
35
+ ATOM_APP_ID: project.config.appId,
36
+ ...(iconPath && fs.existsSync(iconPath) ? { ATOM_APP_ICON: iconPath } : {}),
31
37
  ATOM_DEV: '1'
32
38
  },
33
39
  stdio: 'inherit'