create-vidra-app 0.2.2 → 0.3.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/cli.js +91 -3
- package/dist/index.js +2 -2
- package/package.json +1 -1
- package/templates/react-vite/src/{{projectName}}.Host/CounterJsContract.cs +10 -0
- package/templates/react-vite/src/{{projectName}}.Host/MainPage.cs +1 -1
- package/templates/react-vite/src/{{projectName}}.Host/{{projectName}}.Host.csproj +1 -0
- package/templates/react-vite/ui/src/App.tsx +14 -6
- package/templates/react-vite/ui/src/generated/counter.ts +10 -0
- package/templates/react-vite/ui/src/generated/index.ts +9 -0
- package/templates/react-vite/ui/src/generated/manifest.json +17 -0
package/dist/cli.js
CHANGED
|
@@ -33,7 +33,7 @@ import { execSync, spawn } from "child_process";
|
|
|
33
33
|
|
|
34
34
|
// src/theme.ts
|
|
35
35
|
import chalk from "chalk";
|
|
36
|
-
var CLI_VERSION = "0.
|
|
36
|
+
var CLI_VERSION = "0.3.0";
|
|
37
37
|
var STEP_LABEL_WIDTH = 16;
|
|
38
38
|
var lime = chalk.hex("#c8f751");
|
|
39
39
|
var value = chalk.hex("#e8e8ec");
|
|
@@ -1034,6 +1034,83 @@ import path6 from "path";
|
|
|
1034
1034
|
import fs5 from "fs-extra";
|
|
1035
1035
|
import { execFileSync as execFileSync4, spawn as spawn2 } from "child_process";
|
|
1036
1036
|
import { request } from "http";
|
|
1037
|
+
|
|
1038
|
+
// src/dev-port.ts
|
|
1039
|
+
import { createServer } from "net";
|
|
1040
|
+
import prompts2 from "prompts";
|
|
1041
|
+
var MIN_PORT = 1;
|
|
1042
|
+
var MAX_PORT = 65535;
|
|
1043
|
+
var isValidPort = (port) => Number.isInteger(port) && port >= MIN_PORT && port <= MAX_PORT;
|
|
1044
|
+
var isPortAvailable = (port, hostname) => new Promise((resolve, reject) => {
|
|
1045
|
+
const server = createServer();
|
|
1046
|
+
server.unref();
|
|
1047
|
+
server.once("error", (error) => {
|
|
1048
|
+
if (error.code === "EADDRINUSE" || error.code === "EACCES") {
|
|
1049
|
+
resolve(false);
|
|
1050
|
+
return;
|
|
1051
|
+
}
|
|
1052
|
+
reject(error);
|
|
1053
|
+
});
|
|
1054
|
+
server.listen({ host: hostname, port, exclusive: true }, () => {
|
|
1055
|
+
server.close((error) => {
|
|
1056
|
+
if (error) {
|
|
1057
|
+
reject(error);
|
|
1058
|
+
return;
|
|
1059
|
+
}
|
|
1060
|
+
resolve(true);
|
|
1061
|
+
});
|
|
1062
|
+
});
|
|
1063
|
+
});
|
|
1064
|
+
var findNextAvailablePort = async (occupiedPort, hostname, probe = isPortAvailable) => {
|
|
1065
|
+
for (let port = occupiedPort + 1; port <= MAX_PORT; port++) {
|
|
1066
|
+
if (await probe(port, hostname)) return port;
|
|
1067
|
+
}
|
|
1068
|
+
throw new Error(`No available port found after ${occupiedPort}`);
|
|
1069
|
+
};
|
|
1070
|
+
var defaultPrompt = async (question) => {
|
|
1071
|
+
const result = await prompts2(question, { onCancel: () => false });
|
|
1072
|
+
return { port: result.port };
|
|
1073
|
+
};
|
|
1074
|
+
var selectDevServerUrl = async (configuredUrl, options = {}) => {
|
|
1075
|
+
const url = new URL(configuredUrl);
|
|
1076
|
+
const port = Number(url.port);
|
|
1077
|
+
if (!isValidPort(port)) {
|
|
1078
|
+
throw new Error(`Dev server URL must include a valid port: ${configuredUrl}`);
|
|
1079
|
+
}
|
|
1080
|
+
const probe = options.isPortAvailable ?? isPortAvailable;
|
|
1081
|
+
if (await probe(port, url.hostname)) return configuredUrl;
|
|
1082
|
+
const interactive = options.interactive ?? isInteractive();
|
|
1083
|
+
if (!interactive) {
|
|
1084
|
+
throw new Error(
|
|
1085
|
+
`Port ${port} is already in use and no interactive terminal is available`
|
|
1086
|
+
);
|
|
1087
|
+
}
|
|
1088
|
+
const suggestedPort = await findNextAvailablePort(port, url.hostname, probe);
|
|
1089
|
+
const prompt = options.prompt ?? defaultPrompt;
|
|
1090
|
+
const result = await prompt({
|
|
1091
|
+
type: "number",
|
|
1092
|
+
name: "port",
|
|
1093
|
+
message: `Port ${port} is already in use. Choose another port:`,
|
|
1094
|
+
initial: suggestedPort,
|
|
1095
|
+
validate: async (value2) => {
|
|
1096
|
+
if (!isValidPort(value2)) {
|
|
1097
|
+
return `Enter a port between ${MIN_PORT} and ${MAX_PORT}`;
|
|
1098
|
+
}
|
|
1099
|
+
return await probe(value2, url.hostname) || `Port ${value2} is already in use`;
|
|
1100
|
+
}
|
|
1101
|
+
});
|
|
1102
|
+
const selectedPort = result.port;
|
|
1103
|
+
if (selectedPort === void 0) {
|
|
1104
|
+
throw new Error("Port selection cancelled");
|
|
1105
|
+
}
|
|
1106
|
+
if (!isValidPort(selectedPort) || !await probe(selectedPort, url.hostname)) {
|
|
1107
|
+
throw new Error(`Port ${selectedPort} is not available`);
|
|
1108
|
+
}
|
|
1109
|
+
url.port = String(selectedPort);
|
|
1110
|
+
return url.toString();
|
|
1111
|
+
};
|
|
1112
|
+
|
|
1113
|
+
// src/commands/dev.ts
|
|
1037
1114
|
var POLL_INTERVAL_MS = 500;
|
|
1038
1115
|
var POLL_TIMEOUT_MS = 3e4;
|
|
1039
1116
|
var NPM_COMMAND = process.platform === "win32" ? "npm.cmd" : "npm";
|
|
@@ -1056,7 +1133,7 @@ var startSession = async (argv, opts) => {
|
|
|
1056
1133
|
const targetName = args["target"] || detectPlatform();
|
|
1057
1134
|
const verbose = !!args["verbose"];
|
|
1058
1135
|
let hotReload = opts.hotReloadDefault && !args["no-hot-reload"];
|
|
1059
|
-
|
|
1136
|
+
let viteUrl = process.env.VIDRA_DEV_URL || "http://localhost:5173";
|
|
1060
1137
|
const target = TARGETS2[targetName];
|
|
1061
1138
|
if (!target) {
|
|
1062
1139
|
const supported = Object.keys(TARGETS2).join(", ");
|
|
@@ -1087,6 +1164,9 @@ var startSession = async (argv, opts) => {
|
|
|
1087
1164
|
console.log(fixLine(blocker.fix));
|
|
1088
1165
|
}
|
|
1089
1166
|
}
|
|
1167
|
+
if (opts.vite) {
|
|
1168
|
+
viteUrl = await selectDevServerUrl(viteUrl);
|
|
1169
|
+
}
|
|
1090
1170
|
const session = new DevSession(project, target, viteUrl, verbose, {
|
|
1091
1171
|
vite: opts.vite,
|
|
1092
1172
|
hotReload
|
|
@@ -1117,6 +1197,14 @@ var dotnetWatchEnv = (devUrl) => ({
|
|
|
1117
1197
|
DOTNET_WATCH_SUPPRESS_EMOJIS: "1",
|
|
1118
1198
|
DOTNET_WATCH_SUPPRESS_LAUNCH_BROWSER: "1"
|
|
1119
1199
|
});
|
|
1200
|
+
var buildViteArgs = (devUrl) => [
|
|
1201
|
+
"run",
|
|
1202
|
+
"dev",
|
|
1203
|
+
"--",
|
|
1204
|
+
"--port",
|
|
1205
|
+
new URL(devUrl).port,
|
|
1206
|
+
"--strictPort"
|
|
1207
|
+
];
|
|
1120
1208
|
var HOST_READY_SENTINEL = "[vidra] host ready";
|
|
1121
1209
|
var classifyWatchLine = (line) => {
|
|
1122
1210
|
if (/waiting for a file to change/i.test(line)) return "appWaiting";
|
|
@@ -1223,7 +1311,7 @@ var DevSession = class {
|
|
|
1223
1311
|
}
|
|
1224
1312
|
startVite() {
|
|
1225
1313
|
console.log(taggedRow("active", "ui", dim("starting dev server\u2026")));
|
|
1226
|
-
const vite = spawn2(NPM_COMMAND,
|
|
1314
|
+
const vite = spawn2(NPM_COMMAND, buildViteArgs(this.viteUrl), {
|
|
1227
1315
|
cwd: this.project.uiDir,
|
|
1228
1316
|
stdio: ["ignore", "pipe", "pipe"],
|
|
1229
1317
|
shell: process.platform === "win32"
|
package/dist/index.js
CHANGED
|
@@ -329,8 +329,8 @@ var VIDRA_REPO_ROOT = path2.resolve(CLI_ROOT, "..", "..", "..");
|
|
|
329
329
|
var LOCAL_FEED_DIR = path2.join(VIDRA_REPO_ROOT, "dist", "packages");
|
|
330
330
|
var LOCAL_CLI_DIR = CLI_ROOT;
|
|
331
331
|
var LOCAL_SDK_DIR = path2.join(VIDRA_REPO_ROOT, "src", "sdk", "vidra-js");
|
|
332
|
-
var VIDRA_VERSION = "0.
|
|
333
|
-
var SDK_VERSION = "0.
|
|
332
|
+
var VIDRA_VERSION = "0.3.0";
|
|
333
|
+
var SDK_VERSION = "0.2.0";
|
|
334
334
|
var main = async () => {
|
|
335
335
|
console.log();
|
|
336
336
|
console.log(` create-${lime("vidra")}-app`);
|
package/package.json
CHANGED
|
@@ -22,7 +22,7 @@ public class MainPage : VidraPage
|
|
|
22
22
|
{
|
|
23
23
|
try
|
|
24
24
|
{
|
|
25
|
-
var count = await Bridge.
|
|
25
|
+
var count = await Bridge.Js().Counter.IncrementAsync();
|
|
26
26
|
System.Diagnostics.Debug.WriteLine($"[MainPage] Counter is now {count}");
|
|
27
27
|
}
|
|
28
28
|
catch (Exception ex)
|
|
@@ -42,6 +42,7 @@
|
|
|
42
42
|
preserved.
|
|
43
43
|
-->
|
|
44
44
|
<MtouchLink Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'maccatalyst' And '$(Configuration)' == 'Debug'">None</MtouchLink>
|
|
45
|
+
<VidraTsOutputDir>$(MSBuildProjectDirectory)/../../ui/src/generated</VidraTsOutputDir>
|
|
45
46
|
</PropertyGroup>
|
|
46
47
|
|
|
47
48
|
<ItemGroup>
|
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
import { type MouseEvent, useEffect, useRef, useState } from "react";
|
|
2
|
-
import {
|
|
3
|
-
|
|
2
|
+
import {
|
|
3
|
+
app,
|
|
4
|
+
appWindow,
|
|
5
|
+
browser,
|
|
6
|
+
clipboard,
|
|
7
|
+
notifications,
|
|
8
|
+
runtime,
|
|
9
|
+
vidra,
|
|
10
|
+
} from "@vidra-dev/sdk";
|
|
11
|
+
import type { Capabilities, WindowInfo, WindowSupport } from "@vidra-dev/sdk";
|
|
12
|
+
import { counterHandlers } from "./generated/index.js";
|
|
4
13
|
|
|
5
14
|
const describeWindow = (windowInfo: WindowInfo): string => {
|
|
6
15
|
const title = windowInfo.title || "(untitled)";
|
|
@@ -17,22 +26,21 @@ const App = () => {
|
|
|
17
26
|
"Window controls are ready. Click a button to inspect or update the native window.",
|
|
18
27
|
);
|
|
19
28
|
const [windowSupport, setWindowSupport] = useState<WindowSupport | null>(null);
|
|
20
|
-
const [caps, setCaps] = useState<
|
|
29
|
+
const [caps, setCaps] = useState<Capabilities | null>(null);
|
|
21
30
|
const [count, setCount] = useState(0);
|
|
22
31
|
const [csReloaded, setCsReloaded] = useState<string | null>(null);
|
|
23
32
|
const countRef = useRef(0);
|
|
24
33
|
const reloadFlashTimer = useRef<number | undefined>(undefined);
|
|
25
34
|
|
|
26
35
|
useEffect(() => {
|
|
27
|
-
const unsubscribeCounter =
|
|
36
|
+
const unsubscribeCounter = counterHandlers.increment(() => {
|
|
28
37
|
countRef.current += 1;
|
|
29
38
|
setCount(countRef.current);
|
|
30
39
|
return countRef.current;
|
|
31
40
|
});
|
|
32
41
|
|
|
33
42
|
// Emitted by the native host when `vidra dev` hot reloads edited C#.
|
|
34
|
-
const unsubscribeHotReloaded =
|
|
35
|
-
"vidra.hotReloaded",
|
|
43
|
+
const unsubscribeHotReloaded = runtime.onHotReloaded(
|
|
36
44
|
(data) => {
|
|
37
45
|
const typeName = data?.updatedTypes?.[0]?.split(".").pop();
|
|
38
46
|
setCsReloaded(typeName ? `C# reloaded · ${typeName}` : "C# reloaded");
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// Auto-generated by vidra-codegen. Do not edit.
|
|
2
|
+
import type { VidraClient } from "@vidra-dev/sdk";
|
|
3
|
+
|
|
4
|
+
export class CounterHandlers {
|
|
5
|
+
constructor(private client: VidraClient) {}
|
|
6
|
+
|
|
7
|
+
increment(handler: () => number | Promise<number>): () => void {
|
|
8
|
+
return this.client.unsafe.handle("counter", "increment", handler);
|
|
9
|
+
}
|
|
10
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
// Auto-generated by vidra-codegen. Do not edit.
|
|
2
|
+
import { vidra } from "@vidra-dev/sdk";
|
|
3
|
+
import { CounterHandlers } from "./counter.js";
|
|
4
|
+
|
|
5
|
+
vidra.registerGeneratedManifest("app", "d3044812d17c42049962d730fced04a6ecd711e287cdd0da7b218b327ee6cd56");
|
|
6
|
+
|
|
7
|
+
export const counterHandlers = new CounterHandlers(vidra);
|
|
8
|
+
|
|
9
|
+
export * from "./counter.js";
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"contracts": {
|
|
3
|
+
"counter": {
|
|
4
|
+
"nativeMethods": {},
|
|
5
|
+
"events": {},
|
|
6
|
+
"jsMethods": {
|
|
7
|
+
"increment": {
|
|
8
|
+
"returns": {
|
|
9
|
+
"kind": "primitive",
|
|
10
|
+
"tsType": "number"
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"fingerprint": "d3044812d17c42049962d730fced04a6ecd711e287cdd0da7b218b327ee6cd56"
|
|
17
|
+
}
|