create-vidra-app 0.3.1 → 0.5.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/README.md CHANGED
@@ -1,53 +1,46 @@
1
1
  # create-vidra-app
2
2
 
3
- Scaffold a new [Vidra](https://vidra.build) application — a
4
- **React UI + .NET MAUI native host**, shipped from a single codebase.
3
+ Scaffold a [Vidra](https://vidra.build) desktop app with a web UI and a
4
+ C#/.NET native host.
5
5
 
6
- > **Alpha.** APIs and templates may change between 0.x releases.
6
+ > **Alpha:** APIs and templates may change between 0.x releases.
7
7
 
8
- ## Usage
8
+ ## Create an app
9
9
 
10
10
  ```bash
11
11
  npm create vidra-app@latest
12
12
  # or
13
13
  npx create-vidra-app my-app
14
- ```
15
-
16
- You'll be prompted for a project name and an app ID (reverse-domain). Then:
17
14
 
18
- ```bash
19
15
  cd my-app
20
- npm run dev # starts Vite + the native host together
16
+ npm run dev
21
17
  ```
22
18
 
23
- Scaffolded apps get the `vidra` CLI as a local dev dependency — there's no
24
- global `vidra` to install. Run it from inside your project via the npm scripts
25
- or `npx`:
19
+ The generated project depends on [`vidra-cli`](https://www.npmjs.com/package/vidra-cli),
20
+ which provides the `vidra` command. This package is only needed to create the
21
+ app; nothing depends on it afterwards. Use the provided npm scripts or run
22
+ `vidra` through `npx`; no global install is required.
26
23
 
27
- ```bash
28
- npm run dev # start Vite + native host
29
- npm run build # build + package for distribution
30
- npm run doctor # check your .NET / MAUI / Xcode setup
31
- npx vidra dev --target windows # run a specific desktop target
32
- npx vidra build --target macos # build + package a macOS .dmg
33
- ```
34
-
35
- ## Prerequisites
24
+ ## Requirements
36
25
 
37
26
  - .NET 10 SDK
38
- - The .NET MAUI workload: `dotnet workload install maui`
39
- - Node.js 18+
40
- - macOS targets require Xcode; Windows targets must be built on Windows
27
+ - .NET MAUI workload: `dotnet workload install maui`
28
+ - Node.js 22 or newer
29
+ - Xcode for macOS builds
30
+
31
+ Windows targets must be built on Windows.
41
32
 
42
- If the MAUI workload is missing, `create-vidra-app` will detect it after
43
- scaffolding and offer to install it for you. You can re-check at any time with
44
- `npm run doctor`.
33
+ ## Common commands
45
34
 
46
- ## Links
35
+ ```bash
36
+ npm run dev
37
+ npm run build
38
+ npm run doctor
39
+ npx vidra --help
40
+ ```
47
41
 
48
- - Website: [vidra.build](https://vidra.build)
49
- - GitHub: [rzamfiriu/vidra](https://github.com/rzamfiriu/vidra)
50
- - npm: [create-vidra-app](https://www.npmjs.com/package/create-vidra-app)
42
+ See the [getting started guide](https://vidra.build/docs/getting-started/) for
43
+ project structure, development, and build options.
51
44
 
52
45
  ## License
53
46
 
package/dist/index.js CHANGED
@@ -5,7 +5,7 @@ import path2 from "path";
5
5
  import { randomUUID } from "crypto";
6
6
  import { fileURLToPath } from "url";
7
7
 
8
- // src/utils.ts
8
+ // ../shared/src/utils.ts
9
9
  var toPascalCase = (str) => {
10
10
  return str.replace(
11
11
  /[-_]+(.)?/g,
@@ -42,11 +42,13 @@ var parseArgs = (argv) => {
42
42
  }
43
43
  return args;
44
44
  };
45
+ var splitLines = (text) => text.split(/\r?\n/);
46
+ var isInteractive = () => Boolean(process.stdin.isTTY && process.stdout.isTTY);
45
47
 
46
- // src/exec.ts
47
- import { execSync, spawn } from "child_process";
48
+ // ../shared/src/exec.ts
49
+ import { execFileSync, execSync, spawn } from "child_process";
48
50
 
49
- // src/theme.ts
51
+ // ../shared/src/theme.ts
50
52
  import chalk from "chalk";
51
53
  var lime = chalk.hex("#c8f751");
52
54
  var value = chalk.hex("#e8e8ec");
@@ -88,11 +90,28 @@ var row = (opts) => {
88
90
  var footer = (content) => ` ${content}`;
89
91
  var fixLine = (cmd, label = "fix:") => ` ${amber(label)} ${lime(cmd)}`;
90
92
 
91
- // src/exec.ts
93
+ // ../shared/src/exec.ts
92
94
  var toText = (value2) => {
93
95
  if (value2 == null) return "";
94
96
  return Buffer.isBuffer(value2) ? value2.toString() : value2;
95
97
  };
98
+ var run = (cmd, args) => {
99
+ try {
100
+ const stdout = execFileSync(cmd, args, {
101
+ encoding: "utf-8",
102
+ stdio: ["ignore", "pipe", "pipe"]
103
+ });
104
+ return { found: true, ok: true, stdout: stdout ?? "", stderr: "" };
105
+ } catch (e) {
106
+ const err = e;
107
+ return {
108
+ found: err.code !== "ENOENT",
109
+ ok: false,
110
+ stdout: toText(err.stdout),
111
+ stderr: toText(err.stderr)
112
+ };
113
+ }
114
+ };
96
115
  var formatProcessError = (error) => {
97
116
  const err = error;
98
117
  const combined = [toText(err.stderr), toText(err.stdout)].map((s) => s.trim()).filter((s) => s.length > 0).join("\n").trim();
@@ -169,31 +188,12 @@ var applyReplacements = (str, replacements) => {
169
188
  return str;
170
189
  };
171
190
 
172
- // src/doctor.ts
173
- import { execFileSync } from "child_process";
191
+ // ../shared/src/dotnet-toolchain.ts
192
+ import { execFileSync as execFileSync2 } from "child_process";
174
193
  import prompts from "prompts";
175
194
  var DOTNET = process.platform === "win32" ? "dotnet.exe" : "dotnet";
176
195
  var MAUI_DOCS = "https://learn.microsoft.com/dotnet/maui/get-started/installation";
177
196
  var INSTALL_NET_10_FIX = "Install the .NET 10 SDK \u2014 https://dotnet.microsoft.com/download";
178
- var bufToStr = (v) => v == null ? "" : Buffer.isBuffer(v) ? v.toString() : v;
179
- var run = (cmd, args) => {
180
- try {
181
- const stdout = execFileSync(cmd, args, {
182
- encoding: "utf-8",
183
- stdio: ["ignore", "pipe", "pipe"]
184
- });
185
- return { found: true, ok: true, stdout: stdout ?? "", stderr: "" };
186
- } catch (e) {
187
- const err = e;
188
- return {
189
- found: err.code !== "ENOENT",
190
- ok: false,
191
- stdout: bufToStr(err.stdout),
192
- stderr: bufToStr(err.stderr)
193
- };
194
- }
195
- };
196
- var splitLines = (text) => text.split(/\r?\n/);
197
197
  var NET_10_VERSION = /^10\./;
198
198
  var MAUI_WORKLOAD = /\bmaui\b/i;
199
199
  var hasNet10Sdk = (listSdksOutput) => splitLines(listSdksOutput).some((line) => NET_10_VERSION.test(line.trim()));
@@ -227,7 +227,6 @@ var checkDotnetSdk = () => {
227
227
  };
228
228
  };
229
229
  var isMauiWorkloadInstalled = () => outputMentionsMaui(run(DOTNET, ["workload", "list"]).stdout);
230
- var isInteractive = () => Boolean(process.stdin.isTTY && process.stdout.isTTY);
231
230
  var installWorkload = (csprojPath) => {
232
231
  const args = csprojPath ? ["workload", "restore", csprojPath] : ["workload", "install", "maui"];
233
232
  console.log();
@@ -244,7 +243,7 @@ var installWorkload = (csprojPath) => {
244
243
  );
245
244
  console.log();
246
245
  try {
247
- execFileSync(DOTNET, args, { stdio: "inherit" });
246
+ execFileSync2(DOTNET, args, { stdio: "inherit" });
248
247
  return true;
249
248
  } catch {
250
249
  console.error();
@@ -327,10 +326,12 @@ var CLI_ROOT = path2.resolve(__dirname, "..");
327
326
  var TEMPLATES_DIR = path2.join(CLI_ROOT, "templates");
328
327
  var VIDRA_REPO_ROOT = path2.resolve(CLI_ROOT, "..", "..", "..");
329
328
  var LOCAL_FEED_DIR = path2.join(VIDRA_REPO_ROOT, "dist", "packages");
330
- var LOCAL_CLI_DIR = CLI_ROOT;
329
+ var LOCAL_CLI_DIR = path2.join(VIDRA_REPO_ROOT, "src", "cli", "vidra-cli");
331
330
  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";
331
+ var VIDRA_VERSION = JSON.parse(
332
+ fs2.readFileSync(path2.join(CLI_ROOT, "package.json"), "utf-8")
333
+ ).version;
334
+ var SDK_VERSION = VIDRA_VERSION;
334
335
  var main = async () => {
335
336
  console.log();
336
337
  console.log(` create-${lime("vidra")}-app`);
@@ -438,7 +439,7 @@ var main = async () => {
438
439
  }
439
440
  if (isMonorepo) {
440
441
  console.log(note("npm", `${dim("@vidra-dev/sdk \u2192")} ${value(LOCAL_SDK_DIR)}`));
441
- console.log(note("npm", `${dim("create-vidra-app \u2192")} ${value(LOCAL_CLI_DIR)}`));
442
+ console.log(note("npm", `${dim("vidra-cli \u2192")} ${value(LOCAL_CLI_DIR)}`));
442
443
  }
443
444
  console.log();
444
445
  if (!npmOk) {
package/package.json CHANGED
@@ -1,11 +1,10 @@
1
1
  {
2
2
  "name": "create-vidra-app",
3
- "version": "0.3.1",
3
+ "version": "0.5.0",
4
4
  "description": "Scaffold a new Vidra application (React + .NET MAUI)",
5
5
  "type": "module",
6
6
  "bin": {
7
- "create-vidra-app": "./bin/create-vidra-app.mjs",
8
- "vidra": "./bin/vidra.mjs"
7
+ "create-vidra-app": "bin/create-vidra-app.mjs"
9
8
  },
10
9
  "files": [
11
10
  "bin/",
@@ -15,6 +14,7 @@
15
14
  "scripts": {
16
15
  "build": "tsup",
17
16
  "dev": "tsup --watch",
17
+ "typecheck": "tsc --noEmit",
18
18
  "test": "vitest run",
19
19
  "test:watch": "vitest",
20
20
  "prepublishOnly": "npm run build"
@@ -33,8 +33,7 @@
33
33
  "desktop",
34
34
  "electron-alternative",
35
35
  "tauri-alternative",
36
- "scaffold",
37
- "cli"
36
+ "scaffold"
38
37
  ],
39
38
  "repository": {
40
39
  "type": "git",
@@ -47,19 +46,23 @@
47
46
  },
48
47
  "license": "MIT",
49
48
  "engines": {
50
- "node": ">=18"
49
+ "node": ">=22"
50
+ },
51
+ "publishConfig": {
52
+ "access": "public"
51
53
  },
52
54
  "dependencies": {
53
- "chalk": "^5.4.1",
55
+ "chalk": "^6.0.0",
54
56
  "fs-extra": "^11.2.0",
55
57
  "prompts": "^2.4.2"
56
58
  },
57
59
  "devDependencies": {
60
+ "@vidra-dev/cli-shared": "*",
58
61
  "@types/fs-extra": "^11.0.4",
59
- "@types/node": "^22.9.0",
62
+ "@types/node": "^22.20.0",
60
63
  "@types/prompts": "^2.4.9",
61
64
  "tsup": "^8.5.1",
62
- "typescript": "^6.0.2",
63
- "vitest": "^2.1.4"
65
+ "typescript": "^7.0.2",
66
+ "vitest": "^4.1.10"
64
67
  }
65
68
  }
@@ -1,90 +1,45 @@
1
1
  # {{appTitle}}
2
2
 
3
- A cross-platform application built with [Vidra](https://vidra.build) — React UI + .NET MAUI native host.
3
+ A desktop application built with [Vidra](https://vidra.build): a React UI and a
4
+ C#/.NET native host.
4
5
 
5
- ## Getting Started
6
-
7
- ### Prerequisites
6
+ ## Requirements
8
7
 
9
8
  - [.NET 10 SDK](https://dotnet.microsoft.com/download)
10
- - The .NET MAUI workload: `dotnet workload install maui`
11
- - [Node.js](https://nodejs.org/) 18+
12
- - macOS targets require Xcode; Windows targets must be built on Windows
13
-
14
- Not sure if you're set up? Run:
15
-
16
- ```bash
17
- npm run doctor
18
- ```
9
+ - .NET MAUI workload: `dotnet workload install maui`
10
+ - [Node.js](https://nodejs.org/) 22 or newer
11
+ - Xcode for macOS builds
19
12
 
20
- It checks your .NET SDK, the MAUI workload, and (on macOS) Xcode, and prints the
21
- exact command to fix anything that's missing.
13
+ Windows targets must be built on Windows.
22
14
 
23
- > The `vidra` CLI ships as a local dev dependency of this project, so run it
24
- > through npm (`npm run dev`, `npm run doctor`) or with `npx vidra <command>` —
25
- > there is no global `vidra` command to install.
26
-
27
- ### Development
15
+ ## Development
28
16
 
29
17
  ```bash
18
+ npm run doctor
30
19
  npm run dev
31
20
  ```
32
21
 
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:
35
-
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:
45
-
46
- ```bash
47
- npx vidra dev --no-hot-reload
48
- ```
49
-
50
- To target a specific desktop platform explicitly:
51
-
52
- ```bash
53
- npx vidra dev --target macos
54
- npx vidra dev --target windows
55
- ```
56
-
57
- If you want to run the pieces separately:
22
+ `npm run dev` starts Vite and the native host together. Changes to the web UI
23
+ reload through Vite; supported C# changes reload through the .NET development
24
+ loop.
58
25
 
59
- ```bash
60
- npm run dev:ui
61
- npm run dev:host:macos
62
- npm run dev:host:windows
63
- ```
64
-
65
- ### Production Build
26
+ ## Build
66
27
 
67
28
  ```bash
68
29
  npm run build
69
30
  ```
70
31
 
71
- ## Project Structure
32
+ The `vidra` CLI is a local project dependency. Run `npx vidra --help` to see
33
+ target, packaging, and update options.
72
34
 
73
- ```
35
+ ## Project structure
36
+
37
+ ```text
74
38
  {{projectNameKebab}}/
75
39
  ├── src/
76
- │ └── {{projectName}}.Host/ # .NET MAUI native host
77
- │ ├── MauiProgram.cs # App configuration + Vidra setup
78
- │ ├── MainPage.cs # Main page (extends VidraPage)
79
- │ └── Platforms/ # Platform-specific code
80
- └── ui/ # React frontend
81
- ├── src/
82
- │ ├── App.tsx # Main React component
83
- │ └── main.tsx # Entry point
84
- ├── vite.config.ts
85
- └── package.json
40
+ │ └── {{projectName}}.Host/ # .NET MAUI host and C# contracts
41
+ └── ui/ # React application and generated TypeScript
86
42
  ```
87
43
 
88
- ---
89
-
90
- Built with [Vidra](https://vidra.build) — a C#/.NET native core with a web UI.
44
+ Read the [Vidra documentation](https://vidra.build/docs/) for bridge guides,
45
+ capabilities, distribution, and updates.
@@ -1,6 +1,8 @@
1
1
  # Build artifacts
2
2
  dist/
3
3
  src/*/Resources/Raw/wwwroot/
4
+ src/*/Resources/Raw/vidra-bridge-policy.json
5
+ ui/src/generated/vidra-access-policy.ts
4
6
  *.tsbuildinfo
5
7
 
6
8
  # .NET
@@ -14,3 +16,7 @@ node_modules/
14
16
  .vs/
15
17
  .vscode/
16
18
  *.user
19
+
20
+ # Update signing keys — whoever holds one can run code in every installed copy
21
+ *-signing-key.pem
22
+ 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",
@@ -10,6 +11,7 @@
10
11
  "doctor": "vidra doctor"
11
12
  },
12
13
  "devDependencies": {
13
- "create-vidra-app": "{{cliVersion}}"
14
+ "@vidra-dev/sdk": "{{sdkVersion}}",
15
+ "vidra-cli": "{{cliVersion}}"
14
16
  }
15
17
  }
@@ -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>
@@ -23,11 +23,22 @@ public class MainPage : VidraPage
23
23
  try
24
24
  {
25
25
  var count = await Bridge.Js().Counter.IncrementAsync();
26
- System.Diagnostics.Debug.WriteLine($"[MainPage] Counter is now {count}");
26
+ Console.WriteLine($"[MainPage] Counter is now {count}");
27
27
  }
28
28
  catch (Exception ex)
29
29
  {
30
- System.Diagnostics.Debug.WriteLine($"[MainPage] Counter increment failed: {ex.Message}");
30
+ // Console, which is what Vidra.Hosting itself logs through, and the
31
+ // only one of the three that a Release build actually emits.
32
+ // Debug.WriteLine is compiled out of Release entirely, and Release is
33
+ // exactly the build where someone is looking at a counter stuck at
34
+ // zero. Trace.TraceError survives the compile but goes to
35
+ // DefaultTraceListener, which writes nothing unless a debugger is
36
+ // attached, and this template registers no listener.
37
+ //
38
+ // The whole exception, not ex.Message: the bridge's answer to "why"
39
+ // is the error code on it, and JS_HANDLER_NOT_FOUND, JS_HANDLER_ERROR
40
+ // and JS_RESPONSE_INVALID are three different problems.
41
+ Console.Error.WriteLine($"[MainPage] Counter increment failed: {ex}");
31
42
  }
32
43
  }
33
44
  }
@@ -9,9 +9,32 @@ public static class MauiProgram
9
9
  {
10
10
  var builder = MauiApp.CreateBuilder();
11
11
 
12
+ // Updates are wired up and doing nothing, which is the intended state
13
+ // until this app has a feed to check. The switch is already in
14
+ // vidra.config.ts, empty — filling it in is the whole opt-in:
15
+ //
16
+ // updates: { feed: "https://updates.example.com/notes/" }
17
+ //
18
+ // Type a URL there, or run `npx vidra updates init --feed <url>`, then
19
+ // publish with `npx vidra build` (both tiers) or `npx vidra build --web`
20
+ // (just the UI, no compile).
21
+ //
22
+ // One directory serves both tiers. To split them across two hosts:
23
+ //
24
+ // "feed": { "web": "https://cdn/notes/", "app": "https://dl/notes/" }
25
+ //
26
+ // Web bundle: your `ui/` build, applied on the next launch, no reinstall.
27
+ // A bundle only installs when its contract fingerprints match this build,
28
+ // so JS can never call a bridge the installed binary lacks.
29
+ //
30
+ // Whole app: native code included, via Velopack. Its other half is the
31
+ // `VelopackApp` line in Platforms/*/Program.cs, which has to run before
32
+ // the UI framework starts.
12
33
  builder
13
34
  .UseMauiApp<App>()
14
35
  .UseVidra()
36
+ .UseVidraUpdates()
37
+ .UseVidraNativeUpdates()
15
38
  .ConfigureFonts(fonts =>
16
39
  {
17
40
  fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
@@ -1,3 +1,22 @@
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
+ // It is live from the first scaffold and does nothing at all until this app is
10
+ // installed from a Velopack release — which it is not, until `vidra.config.ts`
11
+ // names an updates feed and `vidra build` packs
12
+ // a release into it. Filling in that URL is the whole opt-in.
13
+ //
14
+ // `UseVidraLocator()` is the Mac Catalyst part. Velopack's client picks its
15
+ // locator from `RuntimeInformation.IsOSPlatform`, which answers false for OSX
16
+ // here, so without it, `Run()` throws before any update logic executes.
17
+
18
+ using Velopack;
19
+ using Vidra.Hosting;
1
20
  using UIKit;
2
21
 
3
22
  namespace {{projectName}};
@@ -6,6 +25,8 @@ public static class Program
6
25
  {
7
26
  static void Main(string[] args)
8
27
  {
28
+ VelopackApp.Build().UseVidraLocator().Run();
29
+
9
30
  UIApplication.Main(args, null, typeof(AppDelegate));
10
31
  }
11
32
  }
@@ -0,0 +1,41 @@
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.
13
+ //
14
+ // It is live from the first scaffold and does nothing at all until this app is
15
+ // installed from a Velopack release — which it is not, until `vidra.config.ts`
16
+ // names an updates feed and `vidra build` packs
17
+ // a release into it. Filling in that URL is the whole opt-in.
18
+
19
+ using Velopack;
20
+ using Vidra.Hosting;
21
+
22
+ namespace {{projectName}}.WinUI;
23
+
24
+ public static class Program
25
+ {
26
+ [STAThread]
27
+ static void Main(string[] args)
28
+ {
29
+ VelopackApp.Build().UseVidraLocator().Run();
30
+
31
+ WinRT.ComWrappersSupport.InitializeComWrappers();
32
+
33
+ Microsoft.UI.Xaml.Application.Start(p =>
34
+ {
35
+ var context = new Microsoft.UI.Dispatching.DispatcherQueueSynchronizationContext(
36
+ Microsoft.UI.Dispatching.DispatcherQueue.GetForCurrentThread());
37
+ System.Threading.SynchronizationContext.SetSynchronizationContext(context);
38
+ _ = new App();
39
+ });
40
+ }
41
+ }
@@ -1,6 +1,13 @@
1
1
  <Project Sdk="Microsoft.NET.Sdk">
2
2
 
3
3
  <PropertyGroup>
4
+ <!-- Pinned, not inferred: a Release Catalyst publish is universal
5
+ (maccatalyst-x64 + maccatalyst-arm64) while a Debug build takes
6
+ the host RID alone, and both share one obj/. Whichever restored
7
+ last owns project.assets.json, so a publish that no-ops its
8
+ restore can read an assets file with no x64 target and fail with
9
+ NETSDK1047. Naming the set here makes every restore write both. -->
10
+ <RuntimeIdentifiers Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'maccatalyst'">maccatalyst-x64;maccatalyst-arm64</RuntimeIdentifiers>
4
11
  <TargetFrameworks Condition="$([MSBuild]::IsOSPlatform('osx'))">net10.0-maccatalyst</TargetFrameworks>
5
12
  <TargetFrameworks Condition="$([MSBuild]::IsOSPlatform('windows'))">net10.0-windows10.0.19041.0</TargetFrameworks>
6
13
  <ValidateXcodeVersion>false</ValidateXcodeVersion>
@@ -18,6 +25,28 @@
18
25
  <ApplicationVersion>1</ApplicationVersion>
19
26
  <ApplicationDisplayVersion>0.1.0</ApplicationDisplayVersion>
20
27
  <EnableCodeSigning Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'maccatalyst'">true</EnableCodeSigning>
28
+ <!--
29
+ Entitlements for the hardened runtime, which notarization requires and
30
+ which would otherwise kill .NET's JIT. `vidra build` re-signs the bundle
31
+ with this same file, so pointing MAUI at it keeps both passes consistent.
32
+
33
+ What Entitlements.plist grants (it carries no comments of its own — the
34
+ MacCatalyst SDK's plist parser rejects XML comments inside <dict>):
35
+ allow-jit + allow-unsigned-executable-memory .NET compiles to
36
+ writable-then-executable memory
37
+ disable-library-validation the runtime loads dylibs
38
+ signed by another team
39
+ network.client the WebView reaches the
40
+ Vite dev server
41
+ files.user-selected.read-write filePicker hands back paths
42
+ the app then reads
43
+ app-sandbox = false Vidra's filesystem module
44
+ exposes unrestricted paths;
45
+ Developer ID (unlike the App
46
+ Store) does not require the
47
+ sandbox
48
+ -->
49
+ <CodesignEntitlements Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'maccatalyst'">Entitlements.plist</CodesignEntitlements>
21
50
 
22
51
  <SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'maccatalyst'">15.0</SupportedOSPlatformVersion>
23
52
  <SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'windows'">10.0.17763.0</SupportedOSPlatformVersion>
@@ -31,6 +60,21 @@
31
60
  -->
32
61
  <WindowsPackageType Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'windows'">None</WindowsPackageType>
33
62
 
63
+ <!--
64
+ This app owns its Windows entry point (Platforms/Windows/Program.cs)
65
+ instead of the one the XAML compiler generates.
66
+
67
+ A native updater has to run before any UI framework starts: on install,
68
+ update and uninstall Velopack re-launches the app with a `veloapp`
69
+ argument and expects it to do that work and exit without ever showing a
70
+ window, and `vpk pack` inspects the assembly and warns when it finds the
71
+ call outside the entry point. Entry-point shape is the one thing a package
72
+ reference cannot retrofit, so every Vidra app ships with it, live, from the
73
+ first scaffold. Mac Catalyst already has a real `Main`, so it needs no
74
+ equivalent switch.
75
+ -->
76
+ <DefineConstants Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'windows'">$(DefineConstants);DISABLE_XAML_GENERATED_MAIN</DefineConstants>
77
+
34
78
  <!--
35
79
  Skip the MacCatalyst managed linker in Debug. The linker's Setup step
36
80
  validates the MacCatalyst SDK headers against the maui workload version,
@@ -51,8 +95,16 @@
51
95
 
52
96
  <ItemGroup>
53
97
  <PackageReference Include="Microsoft.Maui.Controls" Version="$(MauiVersion)" />
54
- <PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="9.0.0" />
98
+ <PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="10.0.10" />
55
99
  <PackageReference Include="Vidra.Hosting.Maui" Version="{{vidraVersion}}" />
100
+ <!--
101
+ Whole-app updates, via Velopack. Referenced from the first scaffold and
102
+ inert until vidra.config.ts names a native feed: ~280 KB of managed code
103
+ against a self-contained .NET + MAUI app, which is the price of never
104
+ having to retrofit an entry point, a package reference and a builder call
105
+ into an app that has already shipped.
106
+ -->
107
+ <PackageReference Include="Vidra.Updates.Native" Version="{{vidraVersion}}" />
56
108
  </ItemGroup>
57
109
 
58
110
  </Project>
@@ -16,8 +16,8 @@
16
16
  "devDependencies": {
17
17
  "@types/react": "^19.0.0",
18
18
  "@types/react-dom": "^19.0.0",
19
- "@vitejs/plugin-react": "^4.4.0",
20
- "typescript": "^5.7.0",
21
- "vite": "^6.0.0"
19
+ "@vitejs/plugin-react": "^6.0.5",
20
+ "typescript": "^7.0.2",
21
+ "vite": "^8.2.1"
22
22
  }
23
23
  }