create-vidra-app 0.3.1 → 0.4.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/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  // src/index.ts
2
2
  import prompts2 from "prompts";
3
- import fs2 from "fs-extra";
4
- import path2 from "path";
3
+ import fs9 from "fs-extra";
4
+ import path10 from "path";
5
5
  import { randomUUID } from "crypto";
6
6
  import { fileURLToPath } from "url";
7
7
 
@@ -170,15 +170,53 @@ var applyReplacements = (str, replacements) => {
170
170
  };
171
171
 
172
172
  // src/doctor.ts
173
- import { execFileSync } from "child_process";
173
+ import { execFileSync as execFileSync5 } from "child_process";
174
+ import fs8 from "fs";
175
+ import path9 from "path";
174
176
  import prompts from "prompts";
177
+
178
+ // src/signing.ts
179
+ import path2 from "path";
180
+ import fs2 from "fs-extra";
181
+ import { execFileSync, spawnSync } from "child_process";
182
+
183
+ // src/notarize.ts
184
+ import path3 from "path";
185
+ import { execFileSync as execFileSync2 } from "child_process";
186
+
187
+ // src/windows-signing.ts
188
+ import path4 from "path";
189
+ import fs3 from "fs-extra";
190
+ import { execFileSync as execFileSync3 } from "child_process";
191
+
192
+ // src/velopack.ts
193
+ import path5 from "path";
194
+ import os from "os";
195
+ import fs4 from "fs-extra";
196
+ import { execFileSync as execFileSync4 } from "child_process";
197
+
198
+ // src/update-config.ts
199
+ import path6 from "path";
200
+ import fs5 from "fs-extra";
201
+
202
+ // src/project.ts
203
+ import path8 from "path";
204
+
205
+ // src/version.ts
206
+ import fs6 from "fs-extra";
207
+ import path7 from "path";
208
+
209
+ // src/project.ts
210
+ import fs7 from "fs-extra";
211
+
212
+ // src/doctor.ts
175
213
  var DOTNET = process.platform === "win32" ? "dotnet.exe" : "dotnet";
176
214
  var MAUI_DOCS = "https://learn.microsoft.com/dotnet/maui/get-started/installation";
177
215
  var INSTALL_NET_10_FIX = "Install the .NET 10 SDK \u2014 https://dotnet.microsoft.com/download";
178
216
  var bufToStr = (v) => v == null ? "" : Buffer.isBuffer(v) ? v.toString() : v;
179
217
  var run = (cmd, args) => {
180
218
  try {
181
- const stdout = execFileSync(cmd, args, {
219
+ const stdout = execFileSync5(cmd, args, {
182
220
  encoding: "utf-8",
183
221
  stdio: ["ignore", "pipe", "pipe"]
184
222
  });
@@ -244,7 +282,7 @@ var installWorkload = (csprojPath) => {
244
282
  );
245
283
  console.log();
246
284
  try {
247
- execFileSync(DOTNET, args, { stdio: "inherit" });
285
+ execFileSync5(DOTNET, args, { stdio: "inherit" });
248
286
  return true;
249
287
  } catch {
250
288
  console.error();
@@ -322,15 +360,17 @@ var ensureMauiWorkload = async (opts = {}) => {
322
360
 
323
361
  // src/index.ts
324
362
  var note = (label, body) => ` ${dim(label.padEnd(7))} ${body}`;
325
- var __dirname = path2.dirname(fileURLToPath(import.meta.url));
326
- var CLI_ROOT = path2.resolve(__dirname, "..");
327
- var TEMPLATES_DIR = path2.join(CLI_ROOT, "templates");
328
- var VIDRA_REPO_ROOT = path2.resolve(CLI_ROOT, "..", "..", "..");
329
- var LOCAL_FEED_DIR = path2.join(VIDRA_REPO_ROOT, "dist", "packages");
363
+ var __dirname = path10.dirname(fileURLToPath(import.meta.url));
364
+ var CLI_ROOT = path10.resolve(__dirname, "..");
365
+ var TEMPLATES_DIR = path10.join(CLI_ROOT, "templates");
366
+ var VIDRA_REPO_ROOT = path10.resolve(CLI_ROOT, "..", "..", "..");
367
+ var LOCAL_FEED_DIR = path10.join(VIDRA_REPO_ROOT, "dist", "packages");
330
368
  var LOCAL_CLI_DIR = CLI_ROOT;
331
- var LOCAL_SDK_DIR = path2.join(VIDRA_REPO_ROOT, "src", "sdk", "vidra-js");
332
- var VIDRA_VERSION = "0.3.1";
333
- var SDK_VERSION = "0.2.0";
369
+ var LOCAL_SDK_DIR = path10.join(VIDRA_REPO_ROOT, "src", "sdk", "vidra-js");
370
+ var VIDRA_VERSION = JSON.parse(
371
+ fs9.readFileSync(path10.join(CLI_ROOT, "package.json"), "utf-8")
372
+ ).version;
373
+ var SDK_VERSION = VIDRA_VERSION;
334
374
  var main = async () => {
335
375
  console.log();
336
376
  console.log(` create-${lime("vidra")}-app`);
@@ -369,8 +409,8 @@ var main = async () => {
369
409
  );
370
410
  appId = res.appId;
371
411
  }
372
- const root = path2.resolve(projectDir);
373
- if (fs2.existsSync(root) && fs2.readdirSync(root).length > 0) {
412
+ const root = path10.resolve(projectDir);
413
+ if (fs9.existsSync(root) && fs9.readdirSync(root).length > 0) {
374
414
  console.error();
375
415
  console.error(
376
416
  row({
@@ -386,8 +426,8 @@ var main = async () => {
386
426
  console.log(kv("directory", root));
387
427
  console.log(kv("app id", appId));
388
428
  console.log();
389
- const isMonorepo = fs2.existsSync(path2.join(LOCAL_SDK_DIR, "package.json"));
390
- const localFeedExists = isMonorepo && fs2.existsSync(LOCAL_FEED_DIR);
429
+ const isMonorepo = fs9.existsSync(path10.join(LOCAL_SDK_DIR, "package.json"));
430
+ const localFeedExists = isMonorepo && fs9.existsSync(LOCAL_FEED_DIR);
391
431
  const localFeedSource = localFeedExists ? ` <add key="vidra-local" value="${toTextPath(LOCAL_FEED_DIR)}" />` : "";
392
432
  const cliRef = isMonorepo ? `file:${toTextPath(LOCAL_CLI_DIR)}` : `^${VIDRA_VERSION}`;
393
433
  const sdkRef = isMonorepo ? `file:${toTextPath(LOCAL_SDK_DIR)}` : `^${SDK_VERSION}`;
@@ -402,17 +442,17 @@ var main = async () => {
402
442
  "{{sdkVersion}}": sdkRef,
403
443
  "{{localFeedSource}}": localFeedSource
404
444
  };
405
- const templateDir = path2.join(TEMPLATES_DIR, "react-vite");
445
+ const templateDir = path10.join(TEMPLATES_DIR, "react-vite");
406
446
  await scaffoldDir(templateDir, root, replacements);
407
447
  console.log(row({ glyph: "active", detail: dim("creating solution\u2026") }));
408
448
  exec(`dotnet new sln -n ${projectName} --force`, root);
409
- const slnFile = fs2.existsSync(path2.join(root, `${projectName}.slnx`)) ? `${projectName}.slnx` : `${projectName}.sln`;
449
+ const slnFile = fs9.existsSync(path10.join(root, `${projectName}.slnx`)) ? `${projectName}.slnx` : `${projectName}.sln`;
410
450
  exec(
411
451
  `dotnet sln ${slnFile} add src/${projectName}.Host/${projectName}.Host.csproj`,
412
452
  root
413
453
  );
414
454
  console.log(row({ glyph: "active", detail: dim("installing dependencies\u2026") }));
415
- const uiDir = path2.join(root, "ui");
455
+ const uiDir = path10.join(root, "ui");
416
456
  const [rootNpmOk, uiNpmOk] = await Promise.all([
417
457
  tryExecAsync("npm install", root),
418
458
  tryExecAsync("npm install", uiDir)
@@ -450,7 +490,7 @@ var main = async () => {
450
490
  );
451
491
  console.log();
452
492
  }
453
- const hostCsproj = path2.join(
493
+ const hostCsproj = path10.join(
454
494
  root,
455
495
  "src",
456
496
  `${projectName}.Host`,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-vidra-app",
3
- "version": "0.3.1",
3
+ "version": "0.4.0",
4
4
  "description": "Scaffold a new Vidra application (React + .NET MAUI)",
5
5
  "type": "module",
6
6
  "bin": {
@@ -31,17 +31,24 @@ npm run dev
31
31
  ```
32
32
 
33
33
  This starts the Vite dev server and launches the native host for the current OS
34
- under `dotnet watch`. Both sides of the app hot reload:
34
+ under `dotnet watch`. Both sides of the app pick up your edits:
35
35
 
36
36
  - **UI**: edit anything in `ui/src` — Vite HMR updates the WebView instantly.
37
- - **C#**: edit the host (for example `OnTickAsync` in `MainPage.cs`) — supported
38
- edits apply to the running app in seconds, and the UI flashes a
39
- "C# reloaded" badge. Edits hot reload can't express (new fields, changed
40
- signatures, …) trigger an automatic rebuild and relaunch.
41
-
42
- C# hot reload needs a recent toolchain (on macOS, the .NET 10.0.203+ workload
43
- set — run `npm run doctor` to check). When unavailable, `vidra dev` falls back
44
- to a one-shot build and launch. To skip `dotnet watch` explicitly:
37
+ - **C#**: edit the host (for example `OnTickAsync` in `MainPage.cs`) and save —
38
+ the session puts the change in front of you in seconds. *How* depends on the
39
+ platform:
40
+ - **Windows**: supported edits apply to the *running* app and the UI flashes a
41
+ "C# reloaded" badge. Edits hot reload can't express (new fields, changed
42
+ signatures, …) trigger an automatic rebuild and relaunch.
43
+ - **macOS**: the same, when the toolchain cooperates. Mac Catalyst's
44
+ hot-reload agent often drops its connection mid-session (dotnet/sdk#55488);
45
+ a dropped agent applies nothing while `dotnet watch` still reports success,
46
+ so `vidra dev` watches for it and switches the session to rebuild +
47
+ relaunch on save. You'll see it say so — after that, edits arrive with a
48
+ restart and no badge.
49
+ `npm run doctor` says which loop you get.
50
+
51
+ To skip `dotnet watch` entirely and do a single build and launch:
45
52
 
46
53
  ```bash
47
54
  npx vidra dev --no-hot-reload
@@ -14,3 +14,7 @@ node_modules/
14
14
  .vs/
15
15
  .vscode/
16
16
  *.user
17
+
18
+ # Update signing keys — whoever holds one can run code in every installed copy
19
+ *-signing-key.pem
20
+ vidra-signing-key.pem
@@ -1,5 +1,6 @@
1
1
  {
2
2
  "name": "{{projectNameKebab}}",
3
+ "version": "0.1.0",
3
4
  "private": true,
4
5
  "scripts": {
5
6
  "build": "vidra build",
@@ -0,0 +1,18 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+ <plist version="1.0">
4
+ <dict>
5
+ <key>com.apple.security.cs.allow-jit</key>
6
+ <true/>
7
+ <key>com.apple.security.cs.allow-unsigned-executable-memory</key>
8
+ <true/>
9
+ <key>com.apple.security.cs.disable-library-validation</key>
10
+ <true/>
11
+ <key>com.apple.security.network.client</key>
12
+ <true/>
13
+ <key>com.apple.security.files.user-selected.read-write</key>
14
+ <true/>
15
+ <key>com.apple.security.app-sandbox</key>
16
+ <false/>
17
+ </dict>
18
+ </plist>
@@ -9,6 +9,25 @@ public static class MauiProgram
9
9
  {
10
10
  var builder = MauiApp.CreateBuilder();
11
11
 
12
+ // Updates come in two tiers. Both are opt-in and both read one
13
+ // `vidra.updates` block in package.json.
14
+ //
15
+ // Web bundle: fast, no reinstall. Add `.UseVidraUpdates()` below and
16
+ //
17
+ // "vidra": { "updates": { "feedUrl": "https://example.com/bundles.json" } }
18
+ //
19
+ // then publish with `npx vidra bundle`. A bundle only installs when its
20
+ // contract fingerprints match this build, so JS can never call a bridge
21
+ // the installed binary lacks.
22
+ //
23
+ // Whole app: native code included. Reference Vidra.Updates.Native, add
24
+ // `.UseVidraNativeUpdates()`, uncomment the line in Platforms/*/Program.cs,
25
+ // and add
26
+ //
27
+ // "vidra": { "updates": { "native": { "feedUrl": "https://example.com/app/" } } }
28
+ //
29
+ // then build with `npx vidra build --target <target> --native-update`.
30
+ // `npx vidra doctor` names whichever half is missing.
12
31
  builder
13
32
  .UseMauiApp<App>()
14
33
  .UseVidra()
@@ -1,3 +1,25 @@
1
+ // The app's entry point on Mac Catalyst.
2
+ //
3
+ // A native updater has to run before UIKit does: on install, update and
4
+ // uninstall Velopack re-launches the app with a `--veloapp-*` argument and
5
+ // expects it to do that work and exit without ever showing a window. `vpk pack`
6
+ // also inspects the assembly statically and warns when
7
+ // `VelopackApp.Build()...Run()` is anywhere other than the entry point.
8
+ //
9
+ // `UseVidraLocator()` is the Mac Catalyst part. Velopack's client picks its
10
+ // locator from `RuntimeInformation.IsOSPlatform`, which answers false for OSX
11
+ // here, so without it, `Run()` throws before any update logic executes.
12
+ //
13
+ // To turn native updates on:
14
+ // 1. add the Vidra.Updates.Native package reference to this project
15
+ // 2. uncomment the two lines below, and the ones in MauiProgram.cs
16
+ // 3. add a `vidra.updates.native.feedUrl` to package.json
17
+ // 4. build with `npx vidra build --target macos --native-update`
18
+ //
19
+ // `npx vidra doctor` checks all four and names whichever is missing.
20
+
21
+ // using Velopack;
22
+ // using Vidra.Hosting;
1
23
  using UIKit;
2
24
 
3
25
  namespace {{projectName}};
@@ -6,6 +28,8 @@ public static class Program
6
28
  {
7
29
  static void Main(string[] args)
8
30
  {
31
+ // VelopackApp.Build().UseVidraLocator().Run();
32
+
9
33
  UIApplication.Main(args, null, typeof(AppDelegate));
10
34
  }
11
35
  }
@@ -0,0 +1,45 @@
1
+ // The app's real entry point on Windows.
2
+ //
3
+ // MAUI generates one of these for you. This app takes it over, via
4
+ // `<DefineConstants>` in the csproj setting DISABLE_XAML_GENERATED_MAIN, for
5
+ // one reason: a native updater has to run *first*, before any UI framework
6
+ // starts.
7
+ //
8
+ // On install, update and uninstall, Velopack re-launches the app with a
9
+ // `--veloapp-*` argument and expects it to do that work and exit without ever
10
+ // showing a window. `VelopackApp.Build()...Run()` is what handles those launches,
11
+ // and `vpk pack` statically inspects the assembly and warns when it finds the
12
+ // call anywhere other than the entry point. Putting it here costs nothing and
13
+ // means an app that later enables updates needs no migration into generated code.
14
+ //
15
+ // To turn native updates on:
16
+ // 1. add the Vidra.Updates.Native package reference to this project
17
+ // 2. uncomment the two lines below, and the ones in MauiProgram.cs
18
+ // 3. add a `vidra.updates.native.feedUrl` to package.json
19
+ // 4. build with `npx vidra build --target windows --native-update`
20
+ //
21
+ // `npx vidra doctor` checks all four and names whichever is missing.
22
+
23
+ // using Velopack;
24
+ // using Vidra.Hosting;
25
+
26
+ namespace {{projectName}}.WinUI;
27
+
28
+ public static class Program
29
+ {
30
+ [STAThread]
31
+ static void Main(string[] args)
32
+ {
33
+ // VelopackApp.Build().UseVidraLocator().Run();
34
+
35
+ WinRT.ComWrappersSupport.InitializeComWrappers();
36
+
37
+ Microsoft.UI.Xaml.Application.Start(p =>
38
+ {
39
+ var context = new Microsoft.UI.Dispatching.DispatcherQueueSynchronizationContext(
40
+ Microsoft.UI.Dispatching.DispatcherQueue.GetForCurrentThread());
41
+ System.Threading.SynchronizationContext.SetSynchronizationContext(context);
42
+ _ = new App();
43
+ });
44
+ }
45
+ }
@@ -18,6 +18,28 @@
18
18
  <ApplicationVersion>1</ApplicationVersion>
19
19
  <ApplicationDisplayVersion>0.1.0</ApplicationDisplayVersion>
20
20
  <EnableCodeSigning Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'maccatalyst'">true</EnableCodeSigning>
21
+ <!--
22
+ Entitlements for the hardened runtime, which notarization requires and
23
+ which would otherwise kill .NET's JIT. `vidra build` re-signs the bundle
24
+ with this same file, so pointing MAUI at it keeps both passes consistent.
25
+
26
+ What Entitlements.plist grants (it carries no comments of its own — the
27
+ MacCatalyst SDK's plist parser rejects XML comments inside <dict>):
28
+ allow-jit + allow-unsigned-executable-memory .NET compiles to
29
+ writable-then-executable memory
30
+ disable-library-validation the runtime loads dylibs
31
+ signed by another team
32
+ network.client the WebView reaches the
33
+ Vite dev server
34
+ files.user-selected.read-write filePicker hands back paths
35
+ the app then reads
36
+ app-sandbox = false Vidra's filesystem module
37
+ exposes unrestricted paths;
38
+ Developer ID (unlike the App
39
+ Store) does not require the
40
+ sandbox
41
+ -->
42
+ <CodesignEntitlements Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'maccatalyst'">Entitlements.plist</CodesignEntitlements>
21
43
 
22
44
  <SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'maccatalyst'">15.0</SupportedOSPlatformVersion>
23
45
  <SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'windows'">10.0.17763.0</SupportedOSPlatformVersion>
@@ -31,6 +53,21 @@
31
53
  -->
32
54
  <WindowsPackageType Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'windows'">None</WindowsPackageType>
33
55
 
56
+ <!--
57
+ This app owns its Windows entry point (Platforms/Windows/Program.cs)
58
+ instead of the one the XAML compiler generates.
59
+
60
+ A native updater has to run before any UI framework starts: on install,
61
+ update and uninstall Velopack re-launches the app with a `veloapp`
62
+ argument and expects it to do that work and exit without ever showing a
63
+ window, and `vpk pack` inspects the assembly and warns when it finds the
64
+ call outside the entry point. Entry-point shape is the one thing a package
65
+ reference cannot retrofit, so every Vidra app ships with it and the
66
+ Velopack line stays commented out until the app opts in. Mac Catalyst
67
+ already has a real `Main`, so it needs no equivalent switch.
68
+ -->
69
+ <DefineConstants Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'windows'">$(DefineConstants);DISABLE_XAML_GENERATED_MAIN</DefineConstants>
70
+
34
71
  <!--
35
72
  Skip the MacCatalyst managed linker in Debug. The linker's Setup step
36
73
  validates the MacCatalyst SDK headers against the maui workload version,