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 +24 -31
- package/dist/index.js +33 -32
- package/package.json +13 -10
- package/templates/react-vite/README.md +22 -67
- package/templates/react-vite/_gitignore +6 -0
- package/templates/react-vite/package.json +3 -1
- package/templates/react-vite/src/{{projectName}}.Host/Entitlements.plist +18 -0
- package/templates/react-vite/src/{{projectName}}.Host/MainPage.cs +13 -2
- package/templates/react-vite/src/{{projectName}}.Host/MauiProgram.cs +23 -0
- package/templates/react-vite/src/{{projectName}}.Host/Platforms/MacCatalyst/Program.cs +21 -0
- package/templates/react-vite/src/{{projectName}}.Host/Platforms/Windows/Program.cs +41 -0
- package/templates/react-vite/src/{{projectName}}.Host/{{projectName}}.Host.csproj +53 -1
- package/templates/react-vite/ui/package.json +3 -3
- package/templates/react-vite/ui/src/generated/vidra-access-policy.ts +6 -0
- package/templates/react-vite/ui/src/main.tsx +1 -0
- package/templates/react-vite/ui/vite.config.ts +4 -1
- package/templates/react-vite/vidra.config.ts +29 -0
- package/bin/vidra.mjs +0 -2
- package/dist/cli.js +0 -1898
package/README.md
CHANGED
|
@@ -1,53 +1,46 @@
|
|
|
1
1
|
# create-vidra-app
|
|
2
2
|
|
|
3
|
-
Scaffold a
|
|
4
|
-
|
|
3
|
+
Scaffold a [Vidra](https://vidra.build) desktop app with a web UI and a
|
|
4
|
+
C#/.NET native host.
|
|
5
5
|
|
|
6
|
-
> **Alpha
|
|
6
|
+
> **Alpha:** APIs and templates may change between 0.x releases.
|
|
7
7
|
|
|
8
|
-
##
|
|
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
|
|
16
|
+
npm run dev
|
|
21
17
|
```
|
|
22
18
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
or
|
|
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
|
-
|
|
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
|
-
-
|
|
39
|
-
- Node.js
|
|
40
|
-
-
|
|
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
|
-
|
|
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
|
-
|
|
35
|
+
```bash
|
|
36
|
+
npm run dev
|
|
37
|
+
npm run build
|
|
38
|
+
npm run doctor
|
|
39
|
+
npx vidra --help
|
|
40
|
+
```
|
|
47
41
|
|
|
48
|
-
|
|
49
|
-
|
|
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/
|
|
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
|
-
|
|
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 =
|
|
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 =
|
|
333
|
-
|
|
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("
|
|
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
|
+
"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": "
|
|
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": ">=
|
|
49
|
+
"node": ">=22"
|
|
50
|
+
},
|
|
51
|
+
"publishConfig": {
|
|
52
|
+
"access": "public"
|
|
51
53
|
},
|
|
52
54
|
"dependencies": {
|
|
53
|
-
"chalk": "^
|
|
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.
|
|
62
|
+
"@types/node": "^22.20.0",
|
|
60
63
|
"@types/prompts": "^2.4.9",
|
|
61
64
|
"tsup": "^8.5.1",
|
|
62
|
-
"typescript": "^
|
|
63
|
-
"vitest": "^
|
|
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
|
|
3
|
+
A desktop application built with [Vidra](https://vidra.build): a React UI and a
|
|
4
|
+
C#/.NET native host.
|
|
4
5
|
|
|
5
|
-
##
|
|
6
|
-
|
|
7
|
-
### Prerequisites
|
|
6
|
+
## Requirements
|
|
8
7
|
|
|
9
8
|
- [.NET 10 SDK](https://dotnet.microsoft.com/download)
|
|
10
|
-
-
|
|
11
|
-
- [Node.js](https://nodejs.org/)
|
|
12
|
-
-
|
|
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
|
-
|
|
21
|
-
exact command to fix anything that's missing.
|
|
13
|
+
Windows targets must be built on Windows.
|
|
22
14
|
|
|
23
|
-
|
|
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
|
-
|
|
34
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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/
|
|
77
|
-
|
|
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
|
-
"
|
|
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
|
-
|
|
26
|
+
Console.WriteLine($"[MainPage] Counter is now {count}");
|
|
27
27
|
}
|
|
28
28
|
catch (Exception ex)
|
|
29
29
|
{
|
|
30
|
-
|
|
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="
|
|
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": "^
|
|
20
|
-
"typescript": "^
|
|
21
|
-
"vite": "^
|
|
19
|
+
"@vitejs/plugin-react": "^6.0.5",
|
|
20
|
+
"typescript": "^7.0.2",
|
|
21
|
+
"vite": "^8.2.1"
|
|
22
22
|
}
|
|
23
23
|
}
|