craft-native 0.0.330 → 0.0.338

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/dist/cli.js CHANGED
@@ -126,7 +126,7 @@ var init_temp_dir = __esm(() => {
126
126
  });
127
127
 
128
128
  // src/package.ts
129
- import { spawn } from "child_process";
129
+ import { spawn, spawnSync } from "child_process";
130
130
  import { createHash } from "crypto";
131
131
  import {
132
132
  chmodSync,
@@ -144,7 +144,7 @@ import {
144
144
  writeFileSync as writeFileSync3
145
145
  } from "fs";
146
146
  import { homedir } from "os";
147
- import { basename, join as join2, resolve } from "path";
147
+ import { basename, dirname, join as join2, resolve } from "path";
148
148
  import { deflateRawSync } from "zlib";
149
149
  function crc32(data) {
150
150
  let c = 4294967295;
@@ -241,6 +241,15 @@ async function packageApp(config) {
241
241
  }
242
242
  return results;
243
243
  }
244
+ function macOSAppStoreRuntimePath(providerPath) {
245
+ const runtime = basename(providerPath) === "craft-app-store" ? providerPath : join2(dirname(providerPath), "craft-app-store");
246
+ if (!existsSync4(runtime))
247
+ throw new Error("App Store packaging requires Pantry\u2019s craft-app-store runtime. Upgrade Craft with Pantry before building.");
248
+ const probe = spawnSync(runtime, ["--distribution"], { encoding: "utf8", timeout: 1e4 });
249
+ if (probe.status !== 0 || probe.stdout.trim() !== "app-store")
250
+ throw new Error("App Store packaging refused a runtime that includes private platform APIs.");
251
+ return runtime;
252
+ }
244
253
  async function packageMacOS(config, outDir) {
245
254
  const results = [];
246
255
  const { name, version, bundleId = `com.myapp.${name.toLowerCase()}` } = config;
@@ -248,6 +257,14 @@ async function packageMacOS(config, outDir) {
248
257
  const hardenedRuntime = !opts.appStore;
249
258
  if (opts.appStore && (!opts.entitlements || !opts.provisioningProfile))
250
259
  return [{ success: false, platform: "macos", format: "app", error: "App Store packaging requires macos.entitlements and macos.provisioningProfile" }];
260
+ let nativeRuntimePath = opts.nativeRuntimePath;
261
+ if (opts.appStore && nativeRuntimePath) {
262
+ try {
263
+ nativeRuntimePath = macOSAppStoreRuntimePath(nativeRuntimePath);
264
+ } catch (error) {
265
+ return [{ success: false, platform: "macos", format: "app", error: error.message }];
266
+ }
267
+ }
251
268
  const appBundlePath = join2(outDir, `${name}.app`);
252
269
  const appBundle = opts.appBundlePath ? copyMacOSAppBundle(opts.appBundlePath, appBundlePath) : createMacOSAppBundle({
253
270
  name,
@@ -262,7 +279,9 @@ async function packageMacOS(config, outDir) {
262
279
  iconPath: config.iconPath,
263
280
  provisioningProfile: opts.provisioningProfile,
264
281
  additionalExecutables: opts.additionalExecutables,
265
- nativeRuntimePath: opts.nativeRuntimePath,
282
+ nativeRuntimePath,
283
+ nativeHost: opts.appStore === true && Boolean(nativeRuntimePath),
284
+ nativeWindow: opts.nativeWindow,
266
285
  outputPath: appBundlePath
267
286
  });
268
287
  if (!appBundle.success) {
@@ -715,7 +734,7 @@ function createMacOSAppBundle(opts) {
715
734
  const macOS = join2(contents, "MacOS");
716
735
  mkdirSync(macOS, { recursive: true });
717
736
  mkdirSync(join2(contents, "Resources"), { recursive: true });
718
- copyFileSync(binaryPath, join2(macOS, name));
737
+ copyFileSync(opts.nativeHost ? opts.nativeRuntimePath : binaryPath, join2(macOS, name));
719
738
  chmodSync(join2(macOS, name), 493);
720
739
  for (const executable of additionalExecutables || []) {
721
740
  if (!existsSync4(executable))
@@ -724,7 +743,18 @@ function createMacOSAppBundle(opts) {
724
743
  copyFileSync(executable, destination);
725
744
  chmodSync(destination, 493);
726
745
  }
727
- if (opts.nativeRuntimePath) {
746
+ if (opts.nativeHost) {
747
+ const backend = join2(macOS, "craft-backend");
748
+ copyFileSync(binaryPath, backend);
749
+ chmodSync(backend, 493);
750
+ writeFileSync3(join2(contents, "Resources", "craft.json"), `${JSON.stringify({
751
+ title: name,
752
+ appName: name,
753
+ ...opts.nativeWindow,
754
+ backend: { executable: "craft-backend" }
755
+ }, null, 2)}
756
+ `);
757
+ } else if (opts.nativeRuntimePath) {
728
758
  const helper = macOSRuntimeExecutablePath(outputPath);
729
759
  const helperContents = resolve(helper, "..", "..");
730
760
  mkdirSync(join2(helperContents, "MacOS"), { recursive: true });
@@ -2988,7 +3018,7 @@ function pinCraftNativeDependency(packagePath, craftVersion) {
2988
3018
  `);
2989
3019
  }
2990
3020
  // package.json
2991
- var version = "0.0.330";
3021
+ var version = "0.0.338";
2992
3022
 
2993
3023
  // bin/cli.ts
2994
3024
  var spawnedFrom = process6.env[CRAFT_CLI_SPAWN_MARKER];
package/dist/index.cjs CHANGED
@@ -375,7 +375,7 @@ function craftBinaryNotFoundMessage(triedPath) {
375
375
  `);
376
376
  }
377
377
  // package.json
378
- var version = "0.0.330";
378
+ var version = "0.0.338";
379
379
 
380
380
  // src/sdk-version.ts
381
381
  var SDK_VERSION = version;
@@ -607,6 +607,15 @@ async function packageApp(config) {
607
607
  }
608
608
  return results;
609
609
  }
610
+ function macOSAppStoreRuntimePath(providerPath) {
611
+ const runtime = import_path.basename(providerPath) === "craft-app-store" ? providerPath : import_path.join(import_path.dirname(providerPath), "craft-app-store");
612
+ if (!import_fs.existsSync(runtime))
613
+ throw new Error("App Store packaging requires Pantry’s craft-app-store runtime. Upgrade Craft with Pantry before building.");
614
+ const probe = import_child_process.spawnSync(runtime, ["--distribution"], { encoding: "utf8", timeout: 1e4 });
615
+ if (probe.status !== 0 || probe.stdout.trim() !== "app-store")
616
+ throw new Error("App Store packaging refused a runtime that includes private platform APIs.");
617
+ return runtime;
618
+ }
610
619
  async function packageMacOS(config, outDir) {
611
620
  const results = [];
612
621
  const { name, version, bundleId = `com.myapp.${name.toLowerCase()}` } = config;
@@ -614,6 +623,14 @@ async function packageMacOS(config, outDir) {
614
623
  const hardenedRuntime = !opts.appStore;
615
624
  if (opts.appStore && (!opts.entitlements || !opts.provisioningProfile))
616
625
  return [{ success: false, platform: "macos", format: "app", error: "App Store packaging requires macos.entitlements and macos.provisioningProfile" }];
626
+ let nativeRuntimePath = opts.nativeRuntimePath;
627
+ if (opts.appStore && nativeRuntimePath) {
628
+ try {
629
+ nativeRuntimePath = macOSAppStoreRuntimePath(nativeRuntimePath);
630
+ } catch (error) {
631
+ return [{ success: false, platform: "macos", format: "app", error: error.message }];
632
+ }
633
+ }
617
634
  const appBundlePath = import_path.join(outDir, `${name}.app`);
618
635
  const appBundle = opts.appBundlePath ? copyMacOSAppBundle(opts.appBundlePath, appBundlePath) : createMacOSAppBundle({
619
636
  name,
@@ -628,7 +645,9 @@ async function packageMacOS(config, outDir) {
628
645
  iconPath: config.iconPath,
629
646
  provisioningProfile: opts.provisioningProfile,
630
647
  additionalExecutables: opts.additionalExecutables,
631
- nativeRuntimePath: opts.nativeRuntimePath,
648
+ nativeRuntimePath,
649
+ nativeHost: opts.appStore === true && Boolean(nativeRuntimePath),
650
+ nativeWindow: opts.nativeWindow,
632
651
  outputPath: appBundlePath
633
652
  });
634
653
  if (!appBundle.success) {
@@ -1082,7 +1101,7 @@ function createMacOSAppBundle(opts) {
1082
1101
  const macOS = import_path.join(contents, "MacOS");
1083
1102
  import_fs.mkdirSync(macOS, { recursive: true });
1084
1103
  import_fs.mkdirSync(import_path.join(contents, "Resources"), { recursive: true });
1085
- import_fs.copyFileSync(binaryPath, import_path.join(macOS, name));
1104
+ import_fs.copyFileSync(opts.nativeHost ? opts.nativeRuntimePath : binaryPath, import_path.join(macOS, name));
1086
1105
  import_fs.chmodSync(import_path.join(macOS, name), 493);
1087
1106
  for (const executable of additionalExecutables || []) {
1088
1107
  if (!import_fs.existsSync(executable))
@@ -1091,7 +1110,18 @@ function createMacOSAppBundle(opts) {
1091
1110
  import_fs.copyFileSync(executable, destination);
1092
1111
  import_fs.chmodSync(destination, 493);
1093
1112
  }
1094
- if (opts.nativeRuntimePath) {
1113
+ if (opts.nativeHost) {
1114
+ const backend = import_path.join(macOS, "craft-backend");
1115
+ import_fs.copyFileSync(binaryPath, backend);
1116
+ import_fs.chmodSync(backend, 493);
1117
+ import_fs.writeFileSync(import_path.join(contents, "Resources", "craft.json"), `${JSON.stringify({
1118
+ title: name,
1119
+ appName: name,
1120
+ ...opts.nativeWindow,
1121
+ backend: { executable: "craft-backend" }
1122
+ }, null, 2)}
1123
+ `);
1124
+ } else if (opts.nativeRuntimePath) {
1095
1125
  const helper = macOSRuntimeExecutablePath(outputPath);
1096
1126
  const helperContents = import_path.resolve(helper, "..", "..");
1097
1127
  import_fs.mkdirSync(import_path.join(helperContents, "MacOS"), { recursive: true });
package/dist/index.js CHANGED
@@ -117,7 +117,7 @@ function craftBinaryNotFoundMessage(triedPath) {
117
117
  `);
118
118
  }
119
119
  // package.json
120
- var version = "0.0.330";
120
+ var version = "0.0.338";
121
121
 
122
122
  // src/sdk-version.ts
123
123
  var SDK_VERSION = version;
@@ -237,7 +237,7 @@ function removeTempDir(dir) {
237
237
  }
238
238
 
239
239
  // src/package.ts
240
- import { spawn } from "child_process";
240
+ import { spawn, spawnSync } from "child_process";
241
241
  import { createHash } from "crypto";
242
242
  import {
243
243
  chmodSync,
@@ -255,7 +255,7 @@ import {
255
255
  writeFileSync as writeFileSync2
256
256
  } from "fs";
257
257
  import { homedir } from "os";
258
- import { basename, join as join2, resolve } from "path";
258
+ import { basename, dirname, join as join2, resolve } from "path";
259
259
  import { deflateRawSync } from "zlib";
260
260
  var DEFAULT_DEB_DEPENDENCIES = ["libgtk-3-0", "libwebkit2gtk-4.1-37", "libnotify-bin"];
261
261
  var CRC32_TABLE = (() => {
@@ -363,6 +363,15 @@ async function packageApp(config) {
363
363
  }
364
364
  return results;
365
365
  }
366
+ function macOSAppStoreRuntimePath(providerPath) {
367
+ const runtime = basename(providerPath) === "craft-app-store" ? providerPath : join2(dirname(providerPath), "craft-app-store");
368
+ if (!existsSync3(runtime))
369
+ throw new Error("App Store packaging requires Pantry\u2019s craft-app-store runtime. Upgrade Craft with Pantry before building.");
370
+ const probe = spawnSync(runtime, ["--distribution"], { encoding: "utf8", timeout: 1e4 });
371
+ if (probe.status !== 0 || probe.stdout.trim() !== "app-store")
372
+ throw new Error("App Store packaging refused a runtime that includes private platform APIs.");
373
+ return runtime;
374
+ }
366
375
  async function packageMacOS(config, outDir) {
367
376
  const results = [];
368
377
  const { name, version, bundleId = `com.myapp.${name.toLowerCase()}` } = config;
@@ -370,6 +379,14 @@ async function packageMacOS(config, outDir) {
370
379
  const hardenedRuntime = !opts.appStore;
371
380
  if (opts.appStore && (!opts.entitlements || !opts.provisioningProfile))
372
381
  return [{ success: false, platform: "macos", format: "app", error: "App Store packaging requires macos.entitlements and macos.provisioningProfile" }];
382
+ let nativeRuntimePath = opts.nativeRuntimePath;
383
+ if (opts.appStore && nativeRuntimePath) {
384
+ try {
385
+ nativeRuntimePath = macOSAppStoreRuntimePath(nativeRuntimePath);
386
+ } catch (error) {
387
+ return [{ success: false, platform: "macos", format: "app", error: error.message }];
388
+ }
389
+ }
373
390
  const appBundlePath = join2(outDir, `${name}.app`);
374
391
  const appBundle = opts.appBundlePath ? copyMacOSAppBundle(opts.appBundlePath, appBundlePath) : createMacOSAppBundle({
375
392
  name,
@@ -384,7 +401,9 @@ async function packageMacOS(config, outDir) {
384
401
  iconPath: config.iconPath,
385
402
  provisioningProfile: opts.provisioningProfile,
386
403
  additionalExecutables: opts.additionalExecutables,
387
- nativeRuntimePath: opts.nativeRuntimePath,
404
+ nativeRuntimePath,
405
+ nativeHost: opts.appStore === true && Boolean(nativeRuntimePath),
406
+ nativeWindow: opts.nativeWindow,
388
407
  outputPath: appBundlePath
389
408
  });
390
409
  if (!appBundle.success) {
@@ -838,7 +857,7 @@ function createMacOSAppBundle(opts) {
838
857
  const macOS = join2(contents, "MacOS");
839
858
  mkdirSync(macOS, { recursive: true });
840
859
  mkdirSync(join2(contents, "Resources"), { recursive: true });
841
- copyFileSync(binaryPath, join2(macOS, name));
860
+ copyFileSync(opts.nativeHost ? opts.nativeRuntimePath : binaryPath, join2(macOS, name));
842
861
  chmodSync(join2(macOS, name), 493);
843
862
  for (const executable of additionalExecutables || []) {
844
863
  if (!existsSync3(executable))
@@ -847,7 +866,18 @@ function createMacOSAppBundle(opts) {
847
866
  copyFileSync(executable, destination);
848
867
  chmodSync(destination, 493);
849
868
  }
850
- if (opts.nativeRuntimePath) {
869
+ if (opts.nativeHost) {
870
+ const backend = join2(macOS, "craft-backend");
871
+ copyFileSync(binaryPath, backend);
872
+ chmodSync(backend, 493);
873
+ writeFileSync2(join2(contents, "Resources", "craft.json"), `${JSON.stringify({
874
+ title: name,
875
+ appName: name,
876
+ ...opts.nativeWindow,
877
+ backend: { executable: "craft-backend" }
878
+ }, null, 2)}
879
+ `);
880
+ } else if (opts.nativeRuntimePath) {
851
881
  const helper = macOSRuntimeExecutablePath(outputPath);
852
882
  const helperContents = resolve(helper, "..", "..");
853
883
  mkdirSync(join2(helperContents, "MacOS"), { recursive: true });
@@ -10387,7 +10417,7 @@ var commonOptimizations = {
10387
10417
  };
10388
10418
  // src/updater/index.ts
10389
10419
  import { createReadStream, createWriteStream, existsSync as existsSync5, mkdirSync as mkdirSync2, readFileSync as readFileSync2, rmdirSync, statSync as statSync3, unlinkSync, writeFileSync as writeFileSync3 } from "fs";
10390
- import { join as join4, basename as basename3, dirname as dirname2 } from "path";
10420
+ import { join as join4, basename as basename3, dirname as dirname3 } from "path";
10391
10421
  import { tmpdir as tmpdir2 } from "os";
10392
10422
  import { execFileSync as execFileSync2, spawn as spawn3 } from "child_process";
10393
10423
  import { createHash as createHash2 } from "crypto";
@@ -10396,7 +10426,7 @@ import { EventEmitter as EventEmitter3 } from "events";
10396
10426
  // src/updater/macos-bundle.ts
10397
10427
  import { execFile, execFileSync } from "child_process";
10398
10428
  import { accessSync, constants, existsSync as existsSync4, renameSync, rmSync as rmSync3, statSync as statSync2 } from "fs";
10399
- import { basename as basename2, dirname, join as join3 } from "path";
10429
+ import { basename as basename2, dirname as dirname2, join as join3 } from "path";
10400
10430
  import { promisify } from "util";
10401
10431
  var execFileAsync = promisify(execFile);
10402
10432
  function isMacOS() {
@@ -10549,7 +10579,7 @@ async function extractBundle(archivePath, stagingDir) {
10549
10579
  async function swapBundle(stagedPath, installedPath) {
10550
10580
  if (!existsSync4(stagedPath))
10551
10581
  throw new Error(`Staged bundle is missing: ${stagedPath}`);
10552
- const parent = dirname(installedPath);
10582
+ const parent = dirname2(installedPath);
10553
10583
  const stamp = `${Date.now()}.${process.pid}`;
10554
10584
  const incoming = join3(parent, `.${basename2(installedPath)}.${stamp}.incoming`);
10555
10585
  const retired = join3(parent, `.${basename2(installedPath)}.${stamp}.retired`);
@@ -10590,7 +10620,7 @@ async function swapBundle(stagedPath, installedPath) {
10590
10620
  }
10591
10621
  function canReplaceBundle(installedPath) {
10592
10622
  try {
10593
- const parent = dirname(installedPath);
10623
+ const parent = dirname2(installedPath);
10594
10624
  accessSync(parent, constants.W_OK);
10595
10625
  if (existsSync4(installedPath))
10596
10626
  statSync2(installedPath);
@@ -10911,7 +10941,7 @@ class AutoUpdater extends EventEmitter3 {
10911
10941
  return;
10912
10942
  }
10913
10943
  if (!canReplaceBundle(appPath)) {
10914
- throw new Error(`Cannot replace ${appPath}: ${dirname2(appPath)} is not writable by this user. ` + "Install the update manually, or move the app somewhere you own.");
10944
+ throw new Error(`Cannot replace ${appPath}: ${dirname3(appPath)} is not writable by this user. ` + "Install the update manually, or move the app somewhere you own.");
10915
10945
  }
10916
10946
  const staged = await extractBundle(downloadPath);
10917
10947
  try {
@@ -10957,7 +10987,7 @@ class AutoUpdater extends EventEmitter3 {
10957
10987
  stdio: "ignore"
10958
10988
  });
10959
10989
  } else if (downloadPath.endsWith(".zip")) {
10960
- const appDir = dirname2(this.config.appPath);
10990
+ const appDir = dirname3(this.config.appPath);
10961
10991
  execFileSync2("powershell", [
10962
10992
  "-NoProfile",
10963
10993
  "-NonInteractive",
@@ -10979,7 +11009,7 @@ class AutoUpdater extends EventEmitter3 {
10979
11009
  } else if (downloadPath.endsWith(".rpm")) {
10980
11010
  execFileSync2("sudo", ["rpm", "-U", downloadPath]);
10981
11011
  } else if (downloadPath.endsWith(".tar.gz")) {
10982
- const appDir = dirname2(this.config.appPath);
11012
+ const appDir = dirname3(this.config.appPath);
10983
11013
  execFileSync2("tar", ["-xzf", downloadPath, "-C", appDir]);
10984
11014
  }
10985
11015
  }
@@ -6919,10 +6919,12 @@ final class CraftNativeScreenController: UIViewController, UIScrollViewDelegate,
6919
6919
  }
6920
6920
  // The app script has no screen, so no bar and no tab bar to change.
6921
6921
  guard !isAppScript else { return }
6922
+ // Prepared tabs have a window and a top controller too. Keep their
6923
+ // options, but only the focused screen may change the shared chrome.
6922
6924
  if options.keys.contains("tabAccessory") {
6923
6925
  tabAccessory = options["tabAccessory"] as? [String: Any]
6924
6926
  tabAccessoryDeclared = true
6925
- if navigationController?.topViewController === self, view.window != nil {
6927
+ if navigationController?.topViewController === self, isShownOnScreen {
6926
6928
  CraftChrome.shared.updateTabAccessory(tabAccessory, owner: self)
6927
6929
  }
6928
6930
  }
@@ -6941,7 +6943,7 @@ final class CraftNativeScreenController: UIViewController, UIScrollViewDelegate,
6941
6943
  }
6942
6944
  if let hidden = options["tabBarHidden"] as? Bool {
6943
6945
  tabBarHidden = hidden
6944
- if navigationController?.topViewController === self, view.window != nil {
6946
+ if navigationController?.topViewController === self, isShownOnScreen {
6945
6947
  CraftChrome.shared.setHiddenByScreen(hidden)
6946
6948
  }
6947
6949
  }
package/dist/package.d.ts CHANGED
@@ -4,6 +4,7 @@
4
4
  * Enables users to create installers for their Craft applications
5
5
  * across all platforms (macOS, Windows, Linux)
6
6
  */
7
+ import type { WindowOptions } from './types.js';
7
8
  /** Runtime packages required by the default Linux DEB, including notify-send. */
8
9
  export declare const DEFAULT_DEB_DEPENDENCIES: readonly ['libgtk-3-0', 'libwebkit2gtk-4.1-37', 'libnotify-bin'];
9
10
  export interface PackageConfig {
@@ -89,6 +90,10 @@ export interface PackageConfig {
89
90
  * the GUI process to its own CFBundleExecutable.
90
91
  */
91
92
  nativeRuntimePath?: string;
93
+ /** Window settings for Craft's sandboxed App Store UI host. The compiled
94
+ * binary becomes its inherited backend and implements the bundle protocol.
95
+ */
96
+ nativeWindow?: Pick<WindowOptions, 'width' | 'height' | 'x' | 'y' | 'headless' | 'systemTray' | 'keepRunning' | 'hideDockIcon' | 'titlebarHidden' | 'frameless' | 'transparent' | 'alwaysOnTop' | 'resizable' | 'darkMode' | 'trayPopover'>;
92
97
  /**
93
98
  * Extra executables copied into `Contents/MacOS/` beside the app binary.
94
99
  *
@@ -175,6 +180,10 @@ export declare function formatPackagingCommandError(tool: string, code: number |
175
180
  * Package a Craft application for distribution
176
181
  */
177
182
  export declare function packageApp(config: PackageConfig): Promise<PackageResult[]>;
183
+ /** Select the public-only runtime shipped beside Pantry's direct runtime.
184
+ * App Store packaging fails closed if an older provider has no public build.
185
+ */
186
+ export declare function macOSAppStoreRuntimePath(providerPath: string): string;
178
187
  export interface MacOSBundleMetadata {
179
188
  name: string;
180
189
  /** Actual executable basename when it differs from the app's display name. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "craft-native",
3
- "version": "0.0.330",
3
+ "version": "0.0.338",
4
4
  "type": "module",
5
5
  "description": "Build desktop apps with web languages - TypeScript SDK for Craft",
6
6
  "author": "Chris Breuer <chris@stacksjs.org>",