reset-framework-cli 1.2.1 → 1.2.4
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/LICENSE +20 -20
- package/README.md +25 -25
- package/package.json +8 -6
- package/src/commands/build.js +144 -126
- package/src/commands/dev.js +195 -174
- package/src/commands/doctor.js +140 -133
- package/src/commands/init.js +946 -866
- package/src/commands/package.js +68 -68
- package/src/index.js +195 -195
- package/src/lib/backend.js +123 -0
- package/src/lib/context.js +66 -66
- package/src/lib/framework.js +57 -57
- package/src/lib/logger.js +11 -11
- package/src/lib/output.js +283 -268
- package/src/lib/process.js +303 -303
- package/src/lib/project.js +897 -833
- package/src/lib/toolchain.js +62 -62
- package/src/lib/ui.js +244 -244
- package/templates/basic/README.md +15 -15
- package/templates/basic/frontend/README.md +73 -73
- package/templates/basic/frontend/eslint.config.js +23 -23
- package/templates/basic/frontend/index.html +13 -13
- package/templates/basic/frontend/package.json +31 -31
- package/templates/basic/frontend/public/icons.svg +24 -24
- package/templates/basic/frontend/src/App.css +216 -216
- package/templates/basic/frontend/src/App.tsx +77 -77
- package/templates/basic/frontend/src/assets/vite.svg +1 -1
- package/templates/basic/frontend/src/index.css +111 -111
- package/templates/basic/frontend/src/lib/reset.ts +1 -1
- package/templates/basic/frontend/src/main.tsx +10 -10
- package/templates/basic/frontend/tsconfig.app.json +28 -28
- package/templates/basic/frontend/tsconfig.json +7 -7
- package/templates/basic/frontend/tsconfig.node.json +26 -26
- package/templates/basic/frontend/vite.config.ts +16 -16
- package/templates/basic/reset.config.json +58 -58
package/src/lib/project.js
CHANGED
|
@@ -1,265 +1,291 @@
|
|
|
1
|
-
import { existsSync, readFileSync } from "node:fs"
|
|
2
|
-
import { createRequire } from "node:module"
|
|
3
|
-
import path from "node:path"
|
|
4
|
-
import { fileURLToPath } from "node:url"
|
|
5
|
-
|
|
6
|
-
const require = createRequire(import.meta.url)
|
|
7
|
-
|
|
8
|
-
const runtimePackageDescriptors = [
|
|
9
|
-
{
|
|
10
|
-
packageName: "@reset-framework/runtime-darwin-arm64",
|
|
11
|
-
workspaceDirName: "runtime-darwin-arm64",
|
|
12
|
-
platform: "darwin",
|
|
13
|
-
arch: "arm64",
|
|
14
|
-
artifactRootSegments: ["dist", "darwin-arm64", "reset-framework.app"],
|
|
15
|
-
binarySegments: ["dist", "darwin-arm64", "reset-framework.app", "Contents", "MacOS", "reset-framework"]
|
|
16
|
-
},
|
|
17
|
-
{
|
|
18
|
-
packageName: "@reset-framework/runtime-darwin-x64",
|
|
19
|
-
workspaceDirName: "runtime-darwin-x64",
|
|
20
|
-
platform: "darwin",
|
|
21
|
-
arch: "x64",
|
|
22
|
-
artifactRootSegments: ["dist", "darwin-x64", "reset-framework.app"],
|
|
23
|
-
binarySegments: ["dist", "darwin-x64", "reset-framework.app", "Contents", "MacOS", "reset-framework"]
|
|
24
|
-
},
|
|
25
|
-
{
|
|
26
|
-
packageName: "@reset-framework/runtime-win32-x64",
|
|
27
|
-
workspaceDirName: "runtime-win32-x64",
|
|
28
|
-
platform: "win32",
|
|
29
|
-
arch: "x64",
|
|
30
|
-
artifactRootSegments: ["dist", "win32-x64"],
|
|
31
|
-
binarySegments: ["dist", "win32-x64", "reset-framework.exe"]
|
|
32
|
-
}
|
|
33
|
-
]
|
|
34
|
-
|
|
35
|
-
function requireString(object, key, scope) {
|
|
36
|
-
if (typeof object?.[key] !== "string" || object[key].trim() === "") {
|
|
37
|
-
throw new Error(`Missing or invalid string field '${scope}.${key}'`)
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
return object[key]
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
function optionalString(object, key, fallback) {
|
|
44
|
-
if (object == null || !(key in object)) {
|
|
45
|
-
return fallback
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
if (typeof object[key] !== "string" || object[key].trim() === "") {
|
|
49
|
-
throw new Error(`Missing or invalid string field '${key}'`)
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
return object[key]
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
function optionalObject(object, key) {
|
|
56
|
-
if (object == null || !(key in object)) {
|
|
57
|
-
return {}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
if (typeof object[key] !== "object" || object[key] === null || Array.isArray(object[key])) {
|
|
61
|
-
throw new Error(`Missing or invalid object field '${key}'`)
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
return object[key]
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
function sanitizeName(value) {
|
|
68
|
-
return value
|
|
69
|
-
.toLowerCase()
|
|
70
|
-
.replace(/[^a-z0-9]+/g, "-")
|
|
71
|
-
.replace(/^-+|-+$/g, "") || "reset-app"
|
|
1
|
+
import { existsSync, readFileSync } from "node:fs"
|
|
2
|
+
import { createRequire } from "node:module"
|
|
3
|
+
import path from "node:path"
|
|
4
|
+
import { fileURLToPath } from "node:url"
|
|
5
|
+
|
|
6
|
+
const require = createRequire(import.meta.url)
|
|
7
|
+
|
|
8
|
+
const runtimePackageDescriptors = [
|
|
9
|
+
{
|
|
10
|
+
packageName: "@reset-framework/runtime-darwin-arm64",
|
|
11
|
+
workspaceDirName: "runtime-darwin-arm64",
|
|
12
|
+
platform: "darwin",
|
|
13
|
+
arch: "arm64",
|
|
14
|
+
artifactRootSegments: ["dist", "darwin-arm64", "reset-framework.app"],
|
|
15
|
+
binarySegments: ["dist", "darwin-arm64", "reset-framework.app", "Contents", "MacOS", "reset-framework"]
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
packageName: "@reset-framework/runtime-darwin-x64",
|
|
19
|
+
workspaceDirName: "runtime-darwin-x64",
|
|
20
|
+
platform: "darwin",
|
|
21
|
+
arch: "x64",
|
|
22
|
+
artifactRootSegments: ["dist", "darwin-x64", "reset-framework.app"],
|
|
23
|
+
binarySegments: ["dist", "darwin-x64", "reset-framework.app", "Contents", "MacOS", "reset-framework"]
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
packageName: "@reset-framework/runtime-win32-x64",
|
|
27
|
+
workspaceDirName: "runtime-win32-x64",
|
|
28
|
+
platform: "win32",
|
|
29
|
+
arch: "x64",
|
|
30
|
+
artifactRootSegments: ["dist", "win32-x64"],
|
|
31
|
+
binarySegments: ["dist", "win32-x64", "reset-framework.exe"]
|
|
32
|
+
}
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
function requireString(object, key, scope) {
|
|
36
|
+
if (typeof object?.[key] !== "string" || object[key].trim() === "") {
|
|
37
|
+
throw new Error(`Missing or invalid string field '${scope}.${key}'`)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return object[key]
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function optionalString(object, key, fallback) {
|
|
44
|
+
if (object == null || !(key in object)) {
|
|
45
|
+
return fallback
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (typeof object[key] !== "string" || object[key].trim() === "") {
|
|
49
|
+
throw new Error(`Missing or invalid string field '${key}'`)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return object[key]
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function optionalObject(object, key) {
|
|
56
|
+
if (object == null || !(key in object)) {
|
|
57
|
+
return {}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (typeof object[key] !== "object" || object[key] === null || Array.isArray(object[key])) {
|
|
61
|
+
throw new Error(`Missing or invalid object field '${key}'`)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return object[key]
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function sanitizeName(value) {
|
|
68
|
+
return value
|
|
69
|
+
.toLowerCase()
|
|
70
|
+
.replace(/[^a-z0-9]+/g, "-")
|
|
71
|
+
.replace(/^-+|-+$/g, "") || "reset-app"
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function normalizeFrontendDir(value) {
|
|
75
|
+
const trimmed = value.trim()
|
|
76
|
+
|
|
77
|
+
if (trimmed === "." || trimmed === "./") {
|
|
78
|
+
return "."
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (path.isAbsolute(trimmed)) {
|
|
82
|
+
throw new Error("project.frontendDir must be a relative path")
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const normalized = path.normalize(trimmed).replace(/\\/g, "/").replace(/\/+$/g, "")
|
|
86
|
+
|
|
87
|
+
if (normalized === "" || normalized === ".") {
|
|
88
|
+
return "."
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (normalized.startsWith("../")) {
|
|
92
|
+
throw new Error("project.frontendDir cannot point outside the app root")
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return normalized
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function normalizeStyling(value) {
|
|
99
|
+
if (value === "css" || value === "tailwindcss") {
|
|
100
|
+
return value
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
throw new Error("project.styling must be either 'css' or 'tailwindcss'")
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function normalizeProtocolScheme(value) {
|
|
107
|
+
if (typeof value !== "string" || value.trim() === "") {
|
|
108
|
+
throw new Error("protocols.schemes[].scheme must be a non-empty string")
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const normalized = value.trim().toLowerCase()
|
|
112
|
+
if (!/^[a-z][a-z0-9+.-]*$/.test(normalized)) {
|
|
113
|
+
throw new Error(
|
|
114
|
+
"protocols.schemes[].scheme must start with a letter and only contain letters, numbers, '+', '-', and '.'"
|
|
115
|
+
)
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return normalized
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function normalizeProtocolRole(value) {
|
|
122
|
+
if (value === "Editor" || value === "Viewer" || value === "Shell" || value === "None") {
|
|
123
|
+
return value
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
throw new Error("protocols.schemes[].role must be one of Editor, Viewer, Shell, None")
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function toTitleCase(value) {
|
|
130
|
+
return value
|
|
131
|
+
.split(/[^a-zA-Z0-9]+/)
|
|
132
|
+
.filter(Boolean)
|
|
133
|
+
.map((segment) => segment.charAt(0).toUpperCase() + segment.slice(1))
|
|
134
|
+
.join(" ") || "Reset App"
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function readJsonFile(filePath) {
|
|
138
|
+
return JSON.parse(readFileSync(filePath, "utf8"))
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function fileExists(filePath) {
|
|
142
|
+
return existsSync(filePath)
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function getFrameworkBuildType(mode) {
|
|
146
|
+
return mode === "release" ? "Release" : "Debug"
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function resolveExistingCandidate(candidates) {
|
|
150
|
+
return candidates.find((candidate) => existsSync(candidate)) ?? null
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function isPathInside(parentDir, candidatePath) {
|
|
154
|
+
const relative = path.relative(parentDir, candidatePath)
|
|
155
|
+
return relative !== "" && !relative.startsWith("..") && !path.isAbsolute(relative)
|
|
72
156
|
}
|
|
73
157
|
|
|
74
|
-
function
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
if (trimmed === "." || trimmed === "./") {
|
|
78
|
-
return "."
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
if (path.isAbsolute(trimmed)) {
|
|
82
|
-
throw new Error("project.frontendDir must be a relative path")
|
|
158
|
+
function normalizeResolutionPaths(value) {
|
|
159
|
+
if (!Array.isArray(value)) {
|
|
160
|
+
return []
|
|
83
161
|
}
|
|
84
162
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
if (normalized === "" || normalized === ".") {
|
|
88
|
-
return "."
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
if (normalized.startsWith("../")) {
|
|
92
|
-
throw new Error("project.frontendDir cannot point outside the app root")
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
return normalized
|
|
163
|
+
return value.filter((entry) => typeof entry === "string" && entry.trim() !== "")
|
|
96
164
|
}
|
|
97
165
|
|
|
98
|
-
function
|
|
99
|
-
|
|
100
|
-
return value
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
throw new Error("project.styling must be either 'css' or 'tailwindcss'")
|
|
104
|
-
}
|
|
166
|
+
function resolvePackageJsonPath(packageName, resolutionPaths) {
|
|
167
|
+
const packageJsonSpecifier = `${packageName}/package.json`
|
|
105
168
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
if (!/^[a-z][a-z0-9+.-]*$/.test(normalized)) {
|
|
113
|
-
throw new Error(
|
|
114
|
-
"protocols.schemes[].scheme must start with a letter and only contain letters, numbers, '+', '-', and '.'"
|
|
115
|
-
)
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
return normalized
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
function normalizeProtocolRole(value) {
|
|
122
|
-
if (value === "Editor" || value === "Viewer" || value === "Shell" || value === "None") {
|
|
123
|
-
return value
|
|
169
|
+
if (resolutionPaths.length > 0) {
|
|
170
|
+
try {
|
|
171
|
+
return require.resolve(packageJsonSpecifier, { paths: resolutionPaths })
|
|
172
|
+
} catch {
|
|
173
|
+
return require.resolve(packageJsonSpecifier)
|
|
174
|
+
}
|
|
124
175
|
}
|
|
125
176
|
|
|
126
|
-
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
function toTitleCase(value) {
|
|
130
|
-
return value
|
|
131
|
-
.split(/[^a-zA-Z0-9]+/)
|
|
132
|
-
.filter(Boolean)
|
|
133
|
-
.map((segment) => segment.charAt(0).toUpperCase() + segment.slice(1))
|
|
134
|
-
.join(" ") || "Reset App"
|
|
177
|
+
return require.resolve(packageJsonSpecifier)
|
|
135
178
|
}
|
|
136
179
|
|
|
137
|
-
function
|
|
138
|
-
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
function fileExists(filePath) {
|
|
142
|
-
return existsSync(filePath)
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
function getFrameworkBuildType(mode) {
|
|
146
|
-
return mode === "release" ? "Release" : "Debug"
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
function resolveExistingCandidate(candidates) {
|
|
150
|
-
return candidates.find((candidate) => existsSync(candidate)) ?? null
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
function isPathInside(parentDir, candidatePath) {
|
|
154
|
-
const relative = path.relative(parentDir, candidatePath)
|
|
155
|
-
return relative !== "" && !relative.startsWith("..") && !path.isAbsolute(relative)
|
|
156
|
-
}
|
|
180
|
+
function resolvePackageInfo(packageName, fallbackRoot, options = {}) {
|
|
181
|
+
const resolutionPaths = normalizeResolutionPaths(options.resolutionPaths)
|
|
157
182
|
|
|
158
|
-
function resolvePackageInfo(packageName, fallbackRoot) {
|
|
159
183
|
try {
|
|
160
|
-
const packageJsonPath =
|
|
184
|
+
const packageJsonPath = resolvePackageJsonPath(packageName, resolutionPaths)
|
|
161
185
|
const packageRoot = path.dirname(packageJsonPath)
|
|
162
186
|
const manifest = readJsonFile(packageJsonPath)
|
|
163
187
|
|
|
164
188
|
return {
|
|
165
|
-
packageName: manifest.name ?? packageName,
|
|
166
|
-
packageRoot,
|
|
167
|
-
packageJsonPath,
|
|
168
|
-
version: manifest.version ?? "0.0.0",
|
|
169
|
-
localFallback: false
|
|
170
|
-
}
|
|
171
|
-
} catch {
|
|
172
|
-
const packageJsonPath = path.join(fallbackRoot, "package.json")
|
|
173
|
-
const manifest = readJsonFile(packageJsonPath)
|
|
174
|
-
|
|
175
|
-
return {
|
|
176
|
-
packageName: manifest.name ?? packageName,
|
|
177
|
-
packageRoot: fallbackRoot,
|
|
178
|
-
packageJsonPath,
|
|
179
|
-
version: manifest.version ?? "0.0.0",
|
|
180
|
-
localFallback: true
|
|
181
|
-
}
|
|
189
|
+
packageName: manifest.name ?? packageName,
|
|
190
|
+
packageRoot,
|
|
191
|
+
packageJsonPath,
|
|
192
|
+
version: manifest.version ?? "0.0.0",
|
|
193
|
+
localFallback: false
|
|
194
|
+
}
|
|
195
|
+
} catch {
|
|
196
|
+
const packageJsonPath = path.join(fallbackRoot, "package.json")
|
|
197
|
+
const manifest = readJsonFile(packageJsonPath)
|
|
198
|
+
|
|
199
|
+
return {
|
|
200
|
+
packageName: manifest.name ?? packageName,
|
|
201
|
+
packageRoot: fallbackRoot,
|
|
202
|
+
packageJsonPath,
|
|
203
|
+
version: manifest.version ?? "0.0.0",
|
|
204
|
+
localFallback: true
|
|
205
|
+
}
|
|
182
206
|
}
|
|
183
207
|
}
|
|
184
208
|
|
|
185
209
|
function resolveWorkspacePackageInfo(packageName, workspaceRoot, fallbackInfo) {
|
|
186
210
|
const packageJsonPath = path.join(workspaceRoot, "package.json")
|
|
187
|
-
|
|
188
|
-
if (!existsSync(packageJsonPath)) {
|
|
189
|
-
return fallbackInfo
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
const manifest = readJsonFile(packageJsonPath)
|
|
193
|
-
|
|
194
|
-
return {
|
|
195
|
-
packageName: manifest.name ?? packageName,
|
|
196
|
-
packageRoot: workspaceRoot,
|
|
197
|
-
packageJsonPath,
|
|
198
|
-
version: manifest.version ?? fallbackInfo.version,
|
|
199
|
-
localFallback: true
|
|
211
|
+
|
|
212
|
+
if (!existsSync(packageJsonPath)) {
|
|
213
|
+
return fallbackInfo
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
const manifest = readJsonFile(packageJsonPath)
|
|
217
|
+
|
|
218
|
+
return {
|
|
219
|
+
packageName: manifest.name ?? packageName,
|
|
220
|
+
packageRoot: workspaceRoot,
|
|
221
|
+
packageJsonPath,
|
|
222
|
+
version: manifest.version ?? fallbackInfo.version,
|
|
223
|
+
localFallback: true
|
|
200
224
|
}
|
|
201
225
|
}
|
|
202
226
|
|
|
203
|
-
function resolveOptionalPackageInfo(packageName, fallbackRoot) {
|
|
227
|
+
function resolveOptionalPackageInfo(packageName, fallbackRoot, options = {}) {
|
|
228
|
+
const resolutionPaths = normalizeResolutionPaths(options.resolutionPaths)
|
|
229
|
+
|
|
204
230
|
try {
|
|
205
|
-
const packageJsonPath =
|
|
231
|
+
const packageJsonPath = resolvePackageJsonPath(packageName, resolutionPaths)
|
|
206
232
|
const packageRoot = path.dirname(packageJsonPath)
|
|
207
233
|
const manifest = readJsonFile(packageJsonPath)
|
|
208
|
-
|
|
209
|
-
return {
|
|
210
|
-
packageName: manifest.name ?? packageName,
|
|
211
|
-
packageRoot,
|
|
212
|
-
packageJsonPath,
|
|
213
|
-
version: manifest.version ?? "0.0.0",
|
|
214
|
-
localFallback: false
|
|
215
|
-
}
|
|
216
|
-
} catch {
|
|
217
|
-
const packageJsonPath = path.join(fallbackRoot, "package.json")
|
|
218
|
-
|
|
219
|
-
if (!existsSync(packageJsonPath)) {
|
|
220
|
-
return null
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
const manifest = readJsonFile(packageJsonPath)
|
|
224
|
-
|
|
225
|
-
return {
|
|
226
|
-
packageName: manifest.name ?? packageName,
|
|
227
|
-
packageRoot: fallbackRoot,
|
|
228
|
-
packageJsonPath,
|
|
229
|
-
version: manifest.version ?? "0.0.0",
|
|
230
|
-
localFallback: true
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
function resolveOptionalWorkspacePackageInfo(packageName, workspaceRoot, fallbackInfo) {
|
|
236
|
-
const packageJsonPath = path.join(workspaceRoot, "package.json")
|
|
237
|
-
|
|
238
|
-
if (!existsSync(packageJsonPath)) {
|
|
239
|
-
return fallbackInfo
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
const manifest = readJsonFile(packageJsonPath)
|
|
243
|
-
const version = fallbackInfo?.version ?? manifest.version ?? "0.0.0"
|
|
244
|
-
|
|
245
|
-
return {
|
|
246
|
-
packageName: manifest.name ?? packageName,
|
|
247
|
-
packageRoot: workspaceRoot,
|
|
248
|
-
packageJsonPath,
|
|
249
|
-
version,
|
|
250
|
-
localFallback: true
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
|
|
234
|
+
|
|
235
|
+
return {
|
|
236
|
+
packageName: manifest.name ?? packageName,
|
|
237
|
+
packageRoot,
|
|
238
|
+
packageJsonPath,
|
|
239
|
+
version: manifest.version ?? "0.0.0",
|
|
240
|
+
localFallback: false
|
|
241
|
+
}
|
|
242
|
+
} catch {
|
|
243
|
+
const packageJsonPath = path.join(fallbackRoot, "package.json")
|
|
244
|
+
|
|
245
|
+
if (!existsSync(packageJsonPath)) {
|
|
246
|
+
return null
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
const manifest = readJsonFile(packageJsonPath)
|
|
250
|
+
|
|
251
|
+
return {
|
|
252
|
+
packageName: manifest.name ?? packageName,
|
|
253
|
+
packageRoot: fallbackRoot,
|
|
254
|
+
packageJsonPath,
|
|
255
|
+
version: manifest.version ?? "0.0.0",
|
|
256
|
+
localFallback: true
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
function resolveOptionalWorkspacePackageInfo(packageName, workspaceRoot, fallbackInfo) {
|
|
262
|
+
const packageJsonPath = path.join(workspaceRoot, "package.json")
|
|
263
|
+
|
|
264
|
+
if (!existsSync(packageJsonPath)) {
|
|
265
|
+
return fallbackInfo
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
const manifest = readJsonFile(packageJsonPath)
|
|
269
|
+
const version = fallbackInfo?.version ?? manifest.version ?? "0.0.0"
|
|
270
|
+
|
|
271
|
+
return {
|
|
272
|
+
packageName: manifest.name ?? packageName,
|
|
273
|
+
packageRoot: workspaceRoot,
|
|
274
|
+
packageJsonPath,
|
|
275
|
+
version,
|
|
276
|
+
localFallback: true
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
254
280
|
function resolveCurrentRuntimeDescriptor() {
|
|
255
281
|
return runtimePackageDescriptors.find(
|
|
256
|
-
(descriptor) =>
|
|
257
|
-
descriptor.platform === process.platform &&
|
|
258
|
-
descriptor.arch === process.arch
|
|
282
|
+
(descriptor) =>
|
|
283
|
+
descriptor.platform === process.platform &&
|
|
284
|
+
descriptor.arch === process.arch
|
|
259
285
|
) ?? null
|
|
260
286
|
}
|
|
261
287
|
|
|
262
|
-
function resolveRuntimePackage(packagesDir) {
|
|
288
|
+
function resolveRuntimePackage(packagesDir, options = {}) {
|
|
263
289
|
const descriptor = resolveCurrentRuntimeDescriptor()
|
|
264
290
|
|
|
265
291
|
if (!descriptor) {
|
|
@@ -270,626 +296,664 @@ function resolveRuntimePackage(packagesDir) {
|
|
|
270
296
|
const packageInfo = resolveOptionalWorkspacePackageInfo(
|
|
271
297
|
descriptor.packageName,
|
|
272
298
|
workspaceRoot,
|
|
273
|
-
resolveOptionalPackageInfo(descriptor.packageName, workspaceRoot)
|
|
299
|
+
resolveOptionalPackageInfo(descriptor.packageName, workspaceRoot, options)
|
|
274
300
|
)
|
|
275
|
-
|
|
276
|
-
return {
|
|
277
|
-
descriptor,
|
|
278
|
-
packageInfo,
|
|
279
|
-
artifactRoot: packageInfo ? path.join(packageInfo.packageRoot, ...descriptor.artifactRootSegments) : null,
|
|
280
|
-
binaryPath: packageInfo ? path.join(packageInfo.packageRoot, ...descriptor.binarySegments) : null
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
function hasSourceRuntimeLayout(frameworkPaths) {
|
|
285
|
-
return Boolean(
|
|
286
|
-
frameworkPaths.frameworkPackage &&
|
|
287
|
-
frameworkPaths.frameworkRoot &&
|
|
288
|
-
frameworkPaths.runtimeDir &&
|
|
289
|
-
frameworkPaths.rootCMakePath &&
|
|
290
|
-
frameworkPaths.vcpkgManifestPath &&
|
|
291
|
-
existsSync(frameworkPaths.frameworkPackage.packageJsonPath) &&
|
|
292
|
-
existsSync(frameworkPaths.frameworkRoot) &&
|
|
293
|
-
existsSync(frameworkPaths.runtimeDir) &&
|
|
294
|
-
existsSync(frameworkPaths.rootCMakePath) &&
|
|
295
|
-
existsSync(frameworkPaths.vcpkgManifestPath)
|
|
296
|
-
)
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
function isSourceRuntimeRequested(options = {}) {
|
|
300
|
-
if (options.preferSource === true) {
|
|
301
|
-
return true
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
const raw = process.env.RESET_FRAMEWORK_RUNTIME_SOURCE
|
|
305
|
-
if (typeof raw !== "string") {
|
|
306
|
-
return false
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
return ["1", "true", "yes", "on", "source"].includes(raw.trim().toLowerCase())
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
export function resolveFrameworkPaths() {
|
|
301
|
+
|
|
302
|
+
return {
|
|
303
|
+
descriptor,
|
|
304
|
+
packageInfo,
|
|
305
|
+
artifactRoot: packageInfo ? path.join(packageInfo.packageRoot, ...descriptor.artifactRootSegments) : null,
|
|
306
|
+
binaryPath: packageInfo ? path.join(packageInfo.packageRoot, ...descriptor.binarySegments) : null
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
function hasSourceRuntimeLayout(frameworkPaths) {
|
|
311
|
+
return Boolean(
|
|
312
|
+
frameworkPaths.frameworkPackage &&
|
|
313
|
+
frameworkPaths.frameworkRoot &&
|
|
314
|
+
frameworkPaths.runtimeDir &&
|
|
315
|
+
frameworkPaths.rootCMakePath &&
|
|
316
|
+
frameworkPaths.vcpkgManifestPath &&
|
|
317
|
+
existsSync(frameworkPaths.frameworkPackage.packageJsonPath) &&
|
|
318
|
+
existsSync(frameworkPaths.frameworkRoot) &&
|
|
319
|
+
existsSync(frameworkPaths.runtimeDir) &&
|
|
320
|
+
existsSync(frameworkPaths.rootCMakePath) &&
|
|
321
|
+
existsSync(frameworkPaths.vcpkgManifestPath)
|
|
322
|
+
)
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
function isSourceRuntimeRequested(options = {}) {
|
|
326
|
+
if (options.preferSource === true) {
|
|
327
|
+
return true
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
const raw = process.env.RESET_FRAMEWORK_RUNTIME_SOURCE
|
|
331
|
+
if (typeof raw !== "string") {
|
|
332
|
+
return false
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
return ["1", "true", "yes", "on", "source"].includes(raw.trim().toLowerCase())
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
export function resolveFrameworkPaths(options = {}) {
|
|
313
339
|
const moduleDir = path.dirname(fileURLToPath(import.meta.url))
|
|
314
340
|
const cliDir = path.resolve(moduleDir, "../..")
|
|
315
341
|
const packagesDir = path.resolve(cliDir, "..")
|
|
316
342
|
const isWorkspacePackagesDir = path.basename(packagesDir) === "packages"
|
|
343
|
+
const resolutionPaths = normalizeResolutionPaths([options.appRoot])
|
|
317
344
|
const cliPackageJsonPath = path.join(cliDir, "package.json")
|
|
318
345
|
const cliManifest = readJsonFile(cliPackageJsonPath)
|
|
319
346
|
const nativePackage = resolveOptionalWorkspacePackageInfo(
|
|
320
347
|
"@reset-framework/native",
|
|
321
348
|
path.join(packagesDir, "native"),
|
|
322
|
-
resolveOptionalPackageInfo("@reset-framework/native", path.join(packagesDir, "native"))
|
|
349
|
+
resolveOptionalPackageInfo("@reset-framework/native", path.join(packagesDir, "native"), { resolutionPaths })
|
|
323
350
|
)
|
|
324
351
|
const sdkPackage = resolveWorkspacePackageInfo(
|
|
325
352
|
"@reset-framework/sdk",
|
|
326
353
|
path.join(packagesDir, "sdk"),
|
|
327
|
-
resolvePackageInfo("@reset-framework/sdk", path.join(packagesDir, "sdk"))
|
|
354
|
+
resolvePackageInfo("@reset-framework/sdk", path.join(packagesDir, "sdk"), { resolutionPaths })
|
|
355
|
+
)
|
|
356
|
+
const backendPackage = resolveWorkspacePackageInfo(
|
|
357
|
+
"@reset-framework/backend",
|
|
358
|
+
path.join(packagesDir, "backend"),
|
|
359
|
+
resolvePackageInfo("@reset-framework/backend", path.join(packagesDir, "backend"), { resolutionPaths })
|
|
328
360
|
)
|
|
329
361
|
const schemaPackage = resolveWorkspacePackageInfo(
|
|
330
362
|
"@reset-framework/schema",
|
|
331
363
|
path.join(packagesDir, "schema"),
|
|
332
|
-
resolvePackageInfo("@reset-framework/schema", path.join(packagesDir, "schema"))
|
|
333
|
-
)
|
|
334
|
-
const runtimePackage = resolveRuntimePackage(packagesDir)
|
|
335
|
-
const isWorkspaceLayout =
|
|
336
|
-
isWorkspacePackagesDir &&
|
|
337
|
-
[cliDir, sdkPackage.packageRoot, schemaPackage.packageRoot].every((packageRoot) =>
|
|
338
|
-
isPathInside(packagesDir, packageRoot)
|
|
339
|
-
)
|
|
340
|
-
|
|
341
|
-
return {
|
|
342
|
-
cliDir,
|
|
343
|
-
cliPackage: {
|
|
344
|
-
packageName: cliManifest.name,
|
|
345
|
-
packageRoot: cliDir,
|
|
346
|
-
packageJsonPath: cliPackageJsonPath,
|
|
347
|
-
version: cliManifest.version ?? "0.0.0",
|
|
348
|
-
localFallback: isWorkspaceLayout
|
|
349
|
-
},
|
|
350
|
-
packagesDir,
|
|
351
|
-
frameworkRoot: nativePackage?.packageRoot ?? null,
|
|
352
|
-
frameworkPackage: nativePackage,
|
|
353
|
-
isWorkspaceLayout,
|
|
354
|
-
sdkPackage,
|
|
355
|
-
schemaPackage,
|
|
356
|
-
runtimePackage,
|
|
357
|
-
runtimeDir: nativePackage ? path.join(nativePackage.packageRoot, "runtime") : null,
|
|
358
|
-
rootCMakePath: nativePackage ? path.join(nativePackage.packageRoot, "CMakeLists.txt") : null,
|
|
359
|
-
cmakePresetsPath: nativePackage ? path.join(nativePackage.packageRoot, "CMakePresets.json") : null,
|
|
360
|
-
vcpkgManifestPath: nativePackage ? path.join(nativePackage.packageRoot, "vcpkg.json") : null,
|
|
361
|
-
templatesDir: path.join(cliDir, "templates")
|
|
362
|
-
}
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
export function resolveFrameworkBuildPaths(appPaths) {
|
|
366
|
-
const frameworkCacheRoot = path.join(appPaths.appRoot, ".reset", "framework")
|
|
367
|
-
const isWindows = process.platform === "win32"
|
|
368
|
-
const devRuntimeRoot = path.join(frameworkCacheRoot, "build", "dev", "runtime")
|
|
369
|
-
const releaseRuntimeRoot = path.join(frameworkCacheRoot, "build", "release", "runtime")
|
|
370
|
-
const devAppBinaryCandidates = isWindows
|
|
371
|
-
? [
|
|
372
|
-
path.join(devRuntimeRoot, getFrameworkBuildType("dev"), "reset-framework.exe"),
|
|
373
|
-
path.join(devRuntimeRoot, "reset-framework.exe")
|
|
374
|
-
]
|
|
375
|
-
: [
|
|
376
|
-
path.join(
|
|
377
|
-
frameworkCacheRoot,
|
|
378
|
-
"build",
|
|
379
|
-
"dev",
|
|
380
|
-
"runtime",
|
|
381
|
-
"reset-framework.app",
|
|
382
|
-
"Contents",
|
|
383
|
-
"MacOS",
|
|
384
|
-
"reset-framework"
|
|
385
|
-
)
|
|
386
|
-
]
|
|
387
|
-
const releaseAppBinaryCandidates = isWindows
|
|
388
|
-
? [
|
|
389
|
-
path.join(releaseRuntimeRoot, getFrameworkBuildType("release"), "reset-framework.exe"),
|
|
390
|
-
path.join(releaseRuntimeRoot, "reset-framework.exe")
|
|
391
|
-
]
|
|
392
|
-
: [
|
|
393
|
-
path.join(
|
|
394
|
-
frameworkCacheRoot,
|
|
395
|
-
"build",
|
|
396
|
-
"release",
|
|
397
|
-
"runtime",
|
|
398
|
-
"reset-framework.app"
|
|
399
|
-
)
|
|
400
|
-
]
|
|
401
|
-
|
|
402
|
-
return {
|
|
403
|
-
frameworkCacheRoot,
|
|
404
|
-
devBuildDir: path.join(frameworkCacheRoot, "build", "dev"),
|
|
405
|
-
releaseBuildDir: path.join(frameworkCacheRoot, "build", "release"),
|
|
406
|
-
devRuntimeOutputCandidates: isWindows
|
|
407
|
-
? [path.join(devRuntimeRoot, getFrameworkBuildType("dev")), devRuntimeRoot]
|
|
408
|
-
: [path.join(frameworkCacheRoot, "build", "dev", "runtime", "reset-framework.app")],
|
|
409
|
-
releaseRuntimeOutputCandidates: isWindows
|
|
410
|
-
? [path.join(releaseRuntimeRoot, getFrameworkBuildType("release")), releaseRuntimeRoot]
|
|
411
|
-
: [path.join(frameworkCacheRoot, "build", "release", "runtime", "reset-framework.app")],
|
|
412
|
-
devAppBinaryCandidates,
|
|
413
|
-
releaseAppBinaryCandidates,
|
|
414
|
-
devAppBinary: devAppBinaryCandidates[0],
|
|
415
|
-
releaseAppTemplate: releaseAppBinaryCandidates[0]
|
|
416
|
-
}
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
export function resolveFrameworkRuntimeStrategy(frameworkPaths, options = {}) {
|
|
420
|
-
const sourceRequested = isSourceRuntimeRequested(options)
|
|
421
|
-
const runtimePackage = frameworkPaths.runtimePackage
|
|
422
|
-
const hasPrebuiltRuntime =
|
|
423
|
-
Boolean(runtimePackage?.packageInfo) &&
|
|
424
|
-
Boolean(runtimePackage?.artifactRoot) &&
|
|
425
|
-
Boolean(runtimePackage?.binaryPath) &&
|
|
426
|
-
existsSync(runtimePackage.artifactRoot) &&
|
|
427
|
-
existsSync(runtimePackage.binaryPath)
|
|
428
|
-
const hasSourceRuntime = hasSourceRuntimeLayout(frameworkPaths)
|
|
429
|
-
|
|
430
|
-
if (sourceRequested) {
|
|
431
|
-
if (!hasSourceRuntime) {
|
|
432
|
-
throw new Error(
|
|
433
|
-
"Source runtime was requested, but @reset-framework/native is not installed in this CLI environment."
|
|
434
|
-
)
|
|
435
|
-
}
|
|
436
|
-
|
|
437
|
-
return {
|
|
438
|
-
kind: "source",
|
|
439
|
-
packageInfo: frameworkPaths.frameworkPackage,
|
|
440
|
-
label: `${frameworkPaths.frameworkPackage.packageName}@${frameworkPaths.frameworkPackage.version}`
|
|
441
|
-
}
|
|
442
|
-
}
|
|
443
|
-
|
|
444
|
-
if (hasPrebuiltRuntime) {
|
|
445
|
-
return {
|
|
446
|
-
kind: "prebuilt",
|
|
447
|
-
packageInfo: runtimePackage.packageInfo,
|
|
448
|
-
descriptor: runtimePackage.descriptor,
|
|
449
|
-
artifactRoot: runtimePackage.artifactRoot,
|
|
450
|
-
binaryPath: runtimePackage.binaryPath,
|
|
451
|
-
label: `${runtimePackage.packageInfo.packageName}@${runtimePackage.packageInfo.version}`
|
|
452
|
-
}
|
|
453
|
-
}
|
|
454
|
-
|
|
455
|
-
if (hasSourceRuntime) {
|
|
456
|
-
return {
|
|
457
|
-
kind: "source",
|
|
458
|
-
packageInfo: frameworkPaths.frameworkPackage,
|
|
459
|
-
label: `${frameworkPaths.frameworkPackage.packageName}@${frameworkPaths.frameworkPackage.version}`
|
|
460
|
-
}
|
|
461
|
-
}
|
|
462
|
-
|
|
463
|
-
if (runtimePackage?.packageInfo) {
|
|
464
|
-
throw new Error(
|
|
465
|
-
`Installed runtime package ${runtimePackage.packageInfo.packageName} is missing bundled runtime artifacts under ${runtimePackage.artifactRoot}.`
|
|
466
|
-
)
|
|
467
|
-
}
|
|
468
|
-
|
|
469
|
-
if (runtimePackage?.descriptor) {
|
|
470
|
-
throw new Error(
|
|
471
|
-
`No bundled runtime package is installed for ${process.platform}-${process.arch}. Expected ${runtimePackage.descriptor.packageName}.`
|
|
472
|
-
)
|
|
473
|
-
}
|
|
474
|
-
|
|
475
|
-
throw new Error(
|
|
476
|
-
`Reset Framework does not currently provide a bundled runtime for ${process.platform}-${process.arch}.`
|
|
477
|
-
)
|
|
478
|
-
}
|
|
479
|
-
|
|
480
|
-
export function resolveFrameworkRuntimeBinary(frameworkPaths, frameworkBuildPaths, mode, options = {}) {
|
|
481
|
-
const { mustExist = false } = options
|
|
482
|
-
const strategy = options.strategy ?? resolveFrameworkRuntimeStrategy(frameworkPaths, options)
|
|
483
|
-
|
|
484
|
-
if (strategy.kind === "prebuilt") {
|
|
485
|
-
if (existsSync(strategy.binaryPath)) {
|
|
486
|
-
return strategy.binaryPath
|
|
487
|
-
}
|
|
488
|
-
|
|
489
|
-
if (mustExist) {
|
|
490
|
-
throw new Error(`Missing bundled runtime executable at ${strategy.binaryPath}.`)
|
|
491
|
-
}
|
|
492
|
-
|
|
493
|
-
return strategy.binaryPath
|
|
494
|
-
}
|
|
495
|
-
|
|
496
|
-
const candidates =
|
|
497
|
-
mode === "release"
|
|
498
|
-
? (frameworkBuildPaths.releaseAppBinaryCandidates ?? [frameworkBuildPaths.releaseAppTemplate])
|
|
499
|
-
: (frameworkBuildPaths.devAppBinaryCandidates ?? [frameworkBuildPaths.devAppBinary])
|
|
500
|
-
const existing = resolveExistingCandidate(candidates)
|
|
501
|
-
|
|
502
|
-
if (existing) {
|
|
503
|
-
return existing
|
|
504
|
-
}
|
|
505
|
-
|
|
506
|
-
if (mustExist) {
|
|
507
|
-
throw new Error(`Missing built runtime executable. Looked in: ${candidates.join(", ")}`)
|
|
508
|
-
}
|
|
509
|
-
|
|
510
|
-
return candidates[0]
|
|
511
|
-
}
|
|
512
|
-
|
|
513
|
-
export function resolveFrameworkRuntimeOutputDir(frameworkPaths, frameworkBuildPaths, mode, options = {}) {
|
|
514
|
-
const { mustExist = false } = options
|
|
515
|
-
const strategy = options.strategy ?? resolveFrameworkRuntimeStrategy(frameworkPaths, options)
|
|
516
|
-
|
|
517
|
-
if (strategy.kind === "prebuilt") {
|
|
518
|
-
if (existsSync(strategy.artifactRoot)) {
|
|
519
|
-
return strategy.artifactRoot
|
|
520
|
-
}
|
|
521
|
-
|
|
522
|
-
if (mustExist) {
|
|
523
|
-
throw new Error(`Missing bundled runtime output directory at ${strategy.artifactRoot}.`)
|
|
524
|
-
}
|
|
525
|
-
|
|
526
|
-
return strategy.artifactRoot
|
|
527
|
-
}
|
|
528
|
-
|
|
529
|
-
const candidates =
|
|
530
|
-
mode === "release"
|
|
531
|
-
? (frameworkBuildPaths.releaseRuntimeOutputCandidates ?? [])
|
|
532
|
-
: (frameworkBuildPaths.devRuntimeOutputCandidates ?? [])
|
|
533
|
-
const existing = resolveExistingCandidate(candidates)
|
|
534
|
-
|
|
535
|
-
if (existing) {
|
|
536
|
-
return existing
|
|
537
|
-
}
|
|
538
|
-
|
|
539
|
-
if (candidates.length > 0) {
|
|
540
|
-
if (mustExist) {
|
|
541
|
-
throw new Error(`Missing built runtime output directory. Looked in: ${candidates.join(", ")}`)
|
|
542
|
-
}
|
|
543
|
-
|
|
544
|
-
return candidates[0]
|
|
545
|
-
}
|
|
546
|
-
|
|
547
|
-
return path.dirname(resolveFrameworkRuntimeBinary(frameworkPaths, frameworkBuildPaths, mode, options))
|
|
548
|
-
}
|
|
549
|
-
|
|
550
|
-
export function resolveAppPaths(appRoot) {
|
|
551
|
-
return {
|
|
552
|
-
appRoot,
|
|
553
|
-
appPackageJsonPath: path.join(appRoot, "package.json"),
|
|
554
|
-
frontendDir: path.join(appRoot, "frontend"),
|
|
555
|
-
resetConfigPath: path.join(appRoot, "reset.config.json"),
|
|
556
|
-
legacyResetConfigPath: path.join(appRoot, "frontend", "reset.config.json")
|
|
557
|
-
}
|
|
558
|
-
}
|
|
559
|
-
|
|
560
|
-
export function resolveConfigPath(appPaths) {
|
|
561
|
-
if (existsSync(appPaths.resetConfigPath)) {
|
|
562
|
-
return appPaths.resetConfigPath
|
|
563
|
-
}
|
|
564
|
-
|
|
565
|
-
if (existsSync(appPaths.legacyResetConfigPath)) {
|
|
566
|
-
return appPaths.legacyResetConfigPath
|
|
567
|
-
}
|
|
568
|
-
|
|
569
|
-
return appPaths.resetConfigPath
|
|
570
|
-
}
|
|
571
|
-
|
|
572
|
-
export function getFrameworkChecks(frameworkPaths) {
|
|
573
|
-
return [
|
|
574
|
-
["sdk", frameworkPaths.sdkPackage.packageJsonPath],
|
|
575
|
-
["schema", frameworkPaths.schemaPackage.packageJsonPath],
|
|
576
|
-
["templates", frameworkPaths.templatesDir]
|
|
577
|
-
]
|
|
578
|
-
}
|
|
579
|
-
|
|
580
|
-
export function getFrameworkRuntimeChecks(frameworkPaths) {
|
|
581
|
-
const checks = []
|
|
582
|
-
|
|
583
|
-
if (frameworkPaths.runtimePackage?.packageInfo) {
|
|
584
|
-
checks.push(["runtime package", frameworkPaths.runtimePackage.packageInfo.packageJsonPath])
|
|
585
|
-
if (frameworkPaths.runtimePackage.artifactRoot) {
|
|
586
|
-
checks.push(["runtime artifact", frameworkPaths.runtimePackage.artifactRoot])
|
|
587
|
-
}
|
|
588
|
-
}
|
|
589
|
-
|
|
590
|
-
if (frameworkPaths.frameworkPackage) {
|
|
591
|
-
checks.push(["native source", frameworkPaths.frameworkPackage.packageJsonPath])
|
|
592
|
-
}
|
|
593
|
-
|
|
594
|
-
if (frameworkPaths.rootCMakePath) {
|
|
595
|
-
checks.push(["cmake", frameworkPaths.rootCMakePath])
|
|
596
|
-
}
|
|
597
|
-
|
|
598
|
-
if (frameworkPaths.runtimeDir) {
|
|
599
|
-
checks.push(["runtime source", frameworkPaths.runtimeDir])
|
|
600
|
-
}
|
|
601
|
-
|
|
602
|
-
if (frameworkPaths.vcpkgManifestPath) {
|
|
603
|
-
checks.push(["vcpkg", frameworkPaths.vcpkgManifestPath])
|
|
604
|
-
}
|
|
605
|
-
|
|
606
|
-
return checks
|
|
607
|
-
}
|
|
608
|
-
|
|
609
|
-
export function getFrameworkRuntimeModeSummary(frameworkPaths, options = {}) {
|
|
610
|
-
const strategy = resolveFrameworkRuntimeStrategy(frameworkPaths, options)
|
|
611
|
-
|
|
612
|
-
return {
|
|
613
|
-
kind: strategy.kind,
|
|
614
|
-
label: strategy.label
|
|
615
|
-
}
|
|
616
|
-
}
|
|
617
|
-
|
|
618
|
-
export function hasFrameworkSourcePackage(frameworkPaths) {
|
|
619
|
-
return hasSourceRuntimeLayout(frameworkPaths)
|
|
620
|
-
}
|
|
621
|
-
|
|
622
|
-
export function isFrameworkSourceRequested(options = {}) {
|
|
623
|
-
return isSourceRuntimeRequested(options)
|
|
624
|
-
}
|
|
625
|
-
|
|
626
|
-
export function assertFrameworkInstall(frameworkPaths) {
|
|
627
|
-
const missing = getFrameworkChecks(frameworkPaths)
|
|
628
|
-
.filter(([, filePath]) => !existsSync(filePath))
|
|
629
|
-
.map(([label]) => label)
|
|
630
|
-
|
|
631
|
-
if (missing.length > 0) {
|
|
632
|
-
throw new Error(
|
|
633
|
-
`Reset CLI installation is incomplete. Missing: ${missing.join(", ")}`
|
|
634
|
-
)
|
|
635
|
-
}
|
|
636
|
-
}
|
|
637
|
-
|
|
638
|
-
export function assertFrameworkSourceInstall(frameworkPaths) {
|
|
639
|
-
const missing = [
|
|
640
|
-
["native source", frameworkPaths.frameworkPackage?.packageJsonPath],
|
|
641
|
-
["sdk", frameworkPaths.sdkPackage.packageJsonPath],
|
|
642
|
-
["cmake", frameworkPaths.rootCMakePath],
|
|
643
|
-
["runtime", frameworkPaths.runtimeDir],
|
|
644
|
-
["vcpkg", frameworkPaths.vcpkgManifestPath],
|
|
645
|
-
["templates", frameworkPaths.templatesDir]
|
|
646
|
-
]
|
|
647
|
-
.filter(([, filePath]) => !filePath || !existsSync(filePath))
|
|
648
|
-
.map(([label]) => label)
|
|
649
|
-
|
|
650
|
-
if (missing.length > 0) {
|
|
651
|
-
throw new Error(
|
|
652
|
-
`Source runtime is unavailable in this CLI installation. Missing: ${missing.join(", ")}`
|
|
653
|
-
)
|
|
654
|
-
}
|
|
655
|
-
}
|
|
656
|
-
|
|
657
|
-
export function getAppChecks(appPaths) {
|
|
658
|
-
return [["config", resolveConfigPath(appPaths)]]
|
|
659
|
-
}
|
|
660
|
-
|
|
661
|
-
export function assertAppProject(appPaths, config) {
|
|
662
|
-
const checks = [...getAppChecks(appPaths)]
|
|
663
|
-
|
|
664
|
-
if (config) {
|
|
665
|
-
checks.unshift(["frontend", resolveFrontendDir(appPaths, config)])
|
|
666
|
-
}
|
|
667
|
-
|
|
668
|
-
const missing = checks
|
|
669
|
-
.filter(([, filePath]) => !existsSync(filePath))
|
|
670
|
-
.map(([label]) => label)
|
|
671
|
-
|
|
672
|
-
if (missing.length > 0) {
|
|
673
|
-
throw new Error(
|
|
674
|
-
`Current directory does not look like a Reset app. Missing: ${missing.join(", ")}`
|
|
675
|
-
)
|
|
676
|
-
}
|
|
677
|
-
}
|
|
678
|
-
|
|
679
|
-
export function validateResetConfig(rawConfig) {
|
|
680
|
-
const frontend = optionalObject(rawConfig, "frontend")
|
|
681
|
-
const build = optionalObject(rawConfig, "build")
|
|
682
|
-
const project = optionalObject(rawConfig, "project")
|
|
683
|
-
const security = optionalObject(rawConfig, "security")
|
|
684
|
-
const protocols = optionalObject(rawConfig, "protocols")
|
|
685
|
-
const windowConfig = optionalObject(rawConfig, "window")
|
|
686
|
-
const rawProtocolSchemes = Array.isArray(protocols.schemes) ? protocols.schemes : []
|
|
687
|
-
const seenProtocolSchemes = new Set()
|
|
688
|
-
|
|
689
|
-
return {
|
|
690
|
-
...rawConfig,
|
|
691
|
-
name: sanitizeName(requireString(rawConfig, "name", "config")),
|
|
692
|
-
productName: requireString(rawConfig, "productName", "config"),
|
|
693
|
-
appId: requireString(rawConfig, "appId", "config"),
|
|
694
|
-
version: requireString(rawConfig, "version", "config"),
|
|
695
|
-
window: {
|
|
696
|
-
title: optionalString(windowConfig, "title", "Reset App")
|
|
697
|
-
},
|
|
698
|
-
frontend: {
|
|
699
|
-
devUrl: requireString(frontend, "devUrl", "frontend"),
|
|
700
|
-
distDir: optionalString(frontend, "distDir", "dist"),
|
|
701
|
-
entryHtml: optionalString(frontend, "entryHtml", "index.html")
|
|
702
|
-
},
|
|
703
|
-
project: {
|
|
704
|
-
frontendDir: normalizeFrontendDir(optionalString(project, "frontendDir", "frontend")),
|
|
705
|
-
styling: normalizeStyling(optionalString(project, "styling", "css"))
|
|
706
|
-
},
|
|
707
|
-
build: {
|
|
708
|
-
outputDir: optionalString(build, "outputDir", ".reset/build")
|
|
709
|
-
},
|
|
710
|
-
security: {
|
|
711
|
-
permissions: Array.isArray(security.permissions)
|
|
712
|
-
? security.permissions.map((value) => {
|
|
713
|
-
if (typeof value !== "string" || value.trim() === "") {
|
|
714
|
-
throw new Error("Missing or invalid string field 'security.permissions'")
|
|
715
|
-
}
|
|
716
|
-
|
|
717
|
-
return value
|
|
718
|
-
})
|
|
719
|
-
: []
|
|
720
|
-
},
|
|
721
|
-
protocols: {
|
|
722
|
-
schemes: rawProtocolSchemes.map((entry) => {
|
|
723
|
-
if (typeof entry !== "object" || entry === null || Array.isArray(entry)) {
|
|
724
|
-
throw new Error("protocols.schemes entries must be objects")
|
|
725
|
-
}
|
|
726
|
-
|
|
727
|
-
const scheme = normalizeProtocolScheme(entry.scheme)
|
|
728
|
-
if (seenProtocolSchemes.has(scheme)) {
|
|
729
|
-
throw new Error(`Duplicate protocol scheme '${scheme}'`)
|
|
730
|
-
}
|
|
731
|
-
|
|
732
|
-
seenProtocolSchemes.add(scheme)
|
|
733
|
-
|
|
734
|
-
return {
|
|
735
|
-
scheme,
|
|
736
|
-
name:
|
|
737
|
-
typeof entry.name === "string" && entry.name.trim() !== ""
|
|
738
|
-
? entry.name
|
|
739
|
-
: scheme,
|
|
740
|
-
role:
|
|
741
|
-
entry.role === undefined
|
|
742
|
-
? "Viewer"
|
|
743
|
-
: normalizeProtocolRole(entry.role)
|
|
744
|
-
}
|
|
745
|
-
})
|
|
746
|
-
}
|
|
747
|
-
}
|
|
748
|
-
}
|
|
749
|
-
|
|
750
|
-
export function loadResetConfig(appPaths) {
|
|
751
|
-
const configPath = resolveConfigPath(appPaths)
|
|
752
|
-
const raw = readFileSync(configPath, "utf8")
|
|
753
|
-
|
|
754
|
-
try {
|
|
755
|
-
return validateResetConfig(JSON.parse(raw))
|
|
756
|
-
} catch (error) {
|
|
757
|
-
if (error instanceof SyntaxError) {
|
|
758
|
-
throw new Error(`Invalid JSON in ${configPath}: ${error.message}`)
|
|
759
|
-
}
|
|
760
|
-
|
|
761
|
-
throw error
|
|
762
|
-
}
|
|
763
|
-
}
|
|
764
|
-
|
|
765
|
-
export function resolveAppOutputPaths(appPaths, config) {
|
|
766
|
-
const outputRoot = path.resolve(appPaths.appRoot, config.build.outputDir)
|
|
767
|
-
const frontendDir = resolveFrontendDir(appPaths, config)
|
|
768
|
-
const isWindows = process.platform === "win32"
|
|
769
|
-
const appBundleName = isWindows ? config.productName : `${config.productName}.app`
|
|
770
|
-
const platformDir = path.join(outputRoot, isWindows ? "windows" : "macos")
|
|
771
|
-
const appBundlePath = path.join(platformDir, appBundleName)
|
|
772
|
-
const resourcesDir = isWindows
|
|
773
|
-
? path.join(appBundlePath, "resources")
|
|
774
|
-
: path.join(appBundlePath, "Contents", "Resources")
|
|
775
|
-
const packagesDir = path.join(outputRoot, "packages")
|
|
776
|
-
|
|
777
|
-
return {
|
|
778
|
-
outputRoot,
|
|
779
|
-
macosDir: isWindows ? undefined : platformDir,
|
|
780
|
-
windowsDir: isWindows ? platformDir : undefined,
|
|
781
|
-
appBundlePath,
|
|
782
|
-
appExecutablePath: isWindows
|
|
783
|
-
? path.join(appBundlePath, `${config.productName}.exe`)
|
|
784
|
-
: undefined,
|
|
785
|
-
resourcesDir,
|
|
786
|
-
bundledConfigPath: path.join(resourcesDir, "reset.config.json"),
|
|
787
|
-
bundledFrontendDir: path.join(resourcesDir, config.frontend.distDir),
|
|
788
|
-
frontendDistDir: path.resolve(frontendDir, config.frontend.distDir),
|
|
789
|
-
frontendEntryFile: path.resolve(
|
|
790
|
-
frontendDir,
|
|
791
|
-
config.frontend.distDir,
|
|
792
|
-
config.frontend.entryHtml
|
|
793
|
-
),
|
|
794
|
-
packagesDir,
|
|
795
|
-
zipPath: path.join(packagesDir, `${config.name}-${isWindows ? "windows" : "macos"}.zip`)
|
|
796
|
-
}
|
|
797
|
-
}
|
|
798
|
-
|
|
799
|
-
export function resolveFrontendDir(appPaths, config) {
|
|
800
|
-
return path.resolve(appPaths.appRoot, config.project.frontendDir)
|
|
801
|
-
}
|
|
802
|
-
|
|
803
|
-
export function resolveDevServerOptions(config) {
|
|
804
|
-
const url = new URL(config.frontend.devUrl)
|
|
805
|
-
|
|
806
|
-
return {
|
|
807
|
-
host: url.hostname,
|
|
808
|
-
port: url.port || "5173",
|
|
809
|
-
url: url.toString()
|
|
810
|
-
}
|
|
811
|
-
}
|
|
812
|
-
|
|
813
|
-
export function makeAppMetadata(appName) {
|
|
814
|
-
const name = sanitizeName(appName)
|
|
815
|
-
const productName = toTitleCase(appName)
|
|
816
|
-
|
|
817
|
-
return {
|
|
818
|
-
name,
|
|
819
|
-
productName,
|
|
820
|
-
appId: `com.example.${name}`,
|
|
821
|
-
title: productName
|
|
822
|
-
}
|
|
823
|
-
}
|
|
824
|
-
|
|
825
|
-
export function resolveSdkDependencySpec(frameworkPaths) {
|
|
826
|
-
if (frameworkPaths.isWorkspaceLayout || frameworkPaths.sdkPackage.localFallback) {
|
|
827
|
-
return `file:${frameworkPaths.sdkPackage.packageRoot}`
|
|
828
|
-
}
|
|
829
|
-
|
|
830
|
-
return `^${frameworkPaths.sdkPackage.version}`
|
|
831
|
-
}
|
|
832
|
-
|
|
833
|
-
export function resolveCliDependencySpec(frameworkPaths) {
|
|
834
|
-
if (frameworkPaths.isWorkspaceLayout || frameworkPaths.cliPackage.localFallback) {
|
|
835
|
-
return `file:${frameworkPaths.cliPackage.packageRoot}`
|
|
836
|
-
}
|
|
837
|
-
|
|
838
|
-
return `^${frameworkPaths.cliPackage.version}`
|
|
839
|
-
}
|
|
840
|
-
|
|
841
|
-
function detectPackageManagerFromManifest(packageJsonPath) {
|
|
842
|
-
if (!fileExists(packageJsonPath)) {
|
|
843
|
-
return null
|
|
844
|
-
}
|
|
845
|
-
|
|
846
|
-
const manifest = readJsonFile(packageJsonPath)
|
|
847
|
-
const raw = typeof manifest.packageManager === "string" ? manifest.packageManager.trim() : ""
|
|
848
|
-
if (raw === "") {
|
|
849
|
-
return null
|
|
850
|
-
}
|
|
851
|
-
|
|
852
|
-
const [name] = raw.split("@")
|
|
853
|
-
if (name === "npm" || name === "pnpm" || name === "yarn" || name === "bun") {
|
|
854
|
-
return name
|
|
855
|
-
}
|
|
856
|
-
|
|
857
|
-
return null
|
|
858
|
-
}
|
|
859
|
-
|
|
860
|
-
function detectPackageManagerFromLocks(directory) {
|
|
861
|
-
if (!fileExists(directory)) {
|
|
862
|
-
return null
|
|
863
|
-
}
|
|
864
|
-
|
|
865
|
-
if (fileExists(path.join(directory, "bun.lock")) || fileExists(path.join(directory, "bun.lockb"))) {
|
|
866
|
-
return "bun"
|
|
867
|
-
}
|
|
868
|
-
|
|
869
|
-
if (fileExists(path.join(directory, "pnpm-lock.yaml"))) {
|
|
870
|
-
return "pnpm"
|
|
871
|
-
}
|
|
872
|
-
|
|
873
|
-
if (fileExists(path.join(directory, "yarn.lock"))) {
|
|
874
|
-
return "yarn"
|
|
875
|
-
}
|
|
876
|
-
|
|
877
|
-
if (fileExists(path.join(directory, "package-lock.json"))) {
|
|
878
|
-
return "npm"
|
|
879
|
-
}
|
|
880
|
-
|
|
881
|
-
return null
|
|
882
|
-
}
|
|
883
|
-
|
|
884
|
-
export function resolveAppPackageManager(appPaths, config) {
|
|
885
|
-
const frontendDir = resolveFrontendDir(appPaths, config)
|
|
886
|
-
const frontendPackageJsonPath = path.join(frontendDir, "package.json")
|
|
887
|
-
|
|
888
|
-
return (
|
|
889
|
-
detectPackageManagerFromManifest(appPaths.appPackageJsonPath) ??
|
|
890
|
-
detectPackageManagerFromManifest(frontendPackageJsonPath) ??
|
|
891
|
-
detectPackageManagerFromLocks(appPaths.appRoot) ??
|
|
892
|
-
detectPackageManagerFromLocks(frontendDir) ??
|
|
893
|
-
"npm"
|
|
364
|
+
resolvePackageInfo("@reset-framework/schema", path.join(packagesDir, "schema"), { resolutionPaths })
|
|
894
365
|
)
|
|
895
|
-
}
|
|
366
|
+
const runtimePackage = resolveRuntimePackage(packagesDir, { resolutionPaths })
|
|
367
|
+
const isWorkspaceLayout =
|
|
368
|
+
isWorkspacePackagesDir &&
|
|
369
|
+
[cliDir, backendPackage.packageRoot, sdkPackage.packageRoot, schemaPackage.packageRoot].every((packageRoot) =>
|
|
370
|
+
isPathInside(packagesDir, packageRoot)
|
|
371
|
+
)
|
|
372
|
+
|
|
373
|
+
return {
|
|
374
|
+
cliDir,
|
|
375
|
+
cliPackage: {
|
|
376
|
+
packageName: cliManifest.name,
|
|
377
|
+
packageRoot: cliDir,
|
|
378
|
+
packageJsonPath: cliPackageJsonPath,
|
|
379
|
+
version: cliManifest.version ?? "0.0.0",
|
|
380
|
+
localFallback: isWorkspaceLayout
|
|
381
|
+
},
|
|
382
|
+
packagesDir,
|
|
383
|
+
frameworkRoot: nativePackage?.packageRoot ?? null,
|
|
384
|
+
frameworkPackage: nativePackage,
|
|
385
|
+
isWorkspaceLayout,
|
|
386
|
+
backendPackage,
|
|
387
|
+
sdkPackage,
|
|
388
|
+
schemaPackage,
|
|
389
|
+
runtimePackage,
|
|
390
|
+
runtimeDir: nativePackage ? path.join(nativePackage.packageRoot, "runtime") : null,
|
|
391
|
+
rootCMakePath: nativePackage ? path.join(nativePackage.packageRoot, "CMakeLists.txt") : null,
|
|
392
|
+
cmakePresetsPath: nativePackage ? path.join(nativePackage.packageRoot, "CMakePresets.json") : null,
|
|
393
|
+
vcpkgManifestPath: nativePackage ? path.join(nativePackage.packageRoot, "vcpkg.json") : null,
|
|
394
|
+
templatesDir: path.join(cliDir, "templates")
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
export function resolveFrameworkBuildPaths(appPaths) {
|
|
399
|
+
const frameworkCacheRoot = path.join(appPaths.appRoot, ".reset", "framework")
|
|
400
|
+
const isWindows = process.platform === "win32"
|
|
401
|
+
const devRuntimeRoot = path.join(frameworkCacheRoot, "build", "dev", "runtime")
|
|
402
|
+
const releaseRuntimeRoot = path.join(frameworkCacheRoot, "build", "release", "runtime")
|
|
403
|
+
const devAppBinaryCandidates = isWindows
|
|
404
|
+
? [
|
|
405
|
+
path.join(devRuntimeRoot, getFrameworkBuildType("dev"), "reset-framework.exe"),
|
|
406
|
+
path.join(devRuntimeRoot, "reset-framework.exe")
|
|
407
|
+
]
|
|
408
|
+
: [
|
|
409
|
+
path.join(
|
|
410
|
+
frameworkCacheRoot,
|
|
411
|
+
"build",
|
|
412
|
+
"dev",
|
|
413
|
+
"runtime",
|
|
414
|
+
"reset-framework.app",
|
|
415
|
+
"Contents",
|
|
416
|
+
"MacOS",
|
|
417
|
+
"reset-framework"
|
|
418
|
+
)
|
|
419
|
+
]
|
|
420
|
+
const releaseAppBinaryCandidates = isWindows
|
|
421
|
+
? [
|
|
422
|
+
path.join(releaseRuntimeRoot, getFrameworkBuildType("release"), "reset-framework.exe"),
|
|
423
|
+
path.join(releaseRuntimeRoot, "reset-framework.exe")
|
|
424
|
+
]
|
|
425
|
+
: [
|
|
426
|
+
path.join(
|
|
427
|
+
frameworkCacheRoot,
|
|
428
|
+
"build",
|
|
429
|
+
"release",
|
|
430
|
+
"runtime",
|
|
431
|
+
"reset-framework.app"
|
|
432
|
+
)
|
|
433
|
+
]
|
|
434
|
+
|
|
435
|
+
return {
|
|
436
|
+
frameworkCacheRoot,
|
|
437
|
+
devBuildDir: path.join(frameworkCacheRoot, "build", "dev"),
|
|
438
|
+
releaseBuildDir: path.join(frameworkCacheRoot, "build", "release"),
|
|
439
|
+
devRuntimeOutputCandidates: isWindows
|
|
440
|
+
? [path.join(devRuntimeRoot, getFrameworkBuildType("dev")), devRuntimeRoot]
|
|
441
|
+
: [path.join(frameworkCacheRoot, "build", "dev", "runtime", "reset-framework.app")],
|
|
442
|
+
releaseRuntimeOutputCandidates: isWindows
|
|
443
|
+
? [path.join(releaseRuntimeRoot, getFrameworkBuildType("release")), releaseRuntimeRoot]
|
|
444
|
+
: [path.join(frameworkCacheRoot, "build", "release", "runtime", "reset-framework.app")],
|
|
445
|
+
devAppBinaryCandidates,
|
|
446
|
+
releaseAppBinaryCandidates,
|
|
447
|
+
devAppBinary: devAppBinaryCandidates[0],
|
|
448
|
+
releaseAppTemplate: releaseAppBinaryCandidates[0]
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
export function resolveFrameworkRuntimeStrategy(frameworkPaths, options = {}) {
|
|
453
|
+
const sourceRequested = isSourceRuntimeRequested(options)
|
|
454
|
+
const runtimePackage = frameworkPaths.runtimePackage
|
|
455
|
+
const hasPrebuiltRuntime =
|
|
456
|
+
Boolean(runtimePackage?.packageInfo) &&
|
|
457
|
+
Boolean(runtimePackage?.artifactRoot) &&
|
|
458
|
+
Boolean(runtimePackage?.binaryPath) &&
|
|
459
|
+
existsSync(runtimePackage.artifactRoot) &&
|
|
460
|
+
existsSync(runtimePackage.binaryPath)
|
|
461
|
+
const hasSourceRuntime = hasSourceRuntimeLayout(frameworkPaths)
|
|
462
|
+
|
|
463
|
+
if (sourceRequested) {
|
|
464
|
+
if (!hasSourceRuntime) {
|
|
465
|
+
throw new Error(
|
|
466
|
+
"Source runtime was requested, but @reset-framework/native is not installed in this CLI environment."
|
|
467
|
+
)
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
return {
|
|
471
|
+
kind: "source",
|
|
472
|
+
packageInfo: frameworkPaths.frameworkPackage,
|
|
473
|
+
label: `${frameworkPaths.frameworkPackage.packageName}@${frameworkPaths.frameworkPackage.version}`
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
if (hasPrebuiltRuntime) {
|
|
478
|
+
return {
|
|
479
|
+
kind: "prebuilt",
|
|
480
|
+
packageInfo: runtimePackage.packageInfo,
|
|
481
|
+
descriptor: runtimePackage.descriptor,
|
|
482
|
+
artifactRoot: runtimePackage.artifactRoot,
|
|
483
|
+
binaryPath: runtimePackage.binaryPath,
|
|
484
|
+
label: `${runtimePackage.packageInfo.packageName}@${runtimePackage.packageInfo.version}`
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
if (hasSourceRuntime) {
|
|
489
|
+
return {
|
|
490
|
+
kind: "source",
|
|
491
|
+
packageInfo: frameworkPaths.frameworkPackage,
|
|
492
|
+
label: `${frameworkPaths.frameworkPackage.packageName}@${frameworkPaths.frameworkPackage.version}`
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
if (runtimePackage?.packageInfo) {
|
|
497
|
+
throw new Error(
|
|
498
|
+
`Installed runtime package ${runtimePackage.packageInfo.packageName} is missing bundled runtime artifacts under ${runtimePackage.artifactRoot}.`
|
|
499
|
+
)
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
if (runtimePackage?.descriptor) {
|
|
503
|
+
throw new Error(
|
|
504
|
+
`No bundled runtime package is installed for ${process.platform}-${process.arch}. Expected ${runtimePackage.descriptor.packageName}.`
|
|
505
|
+
)
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
throw new Error(
|
|
509
|
+
`Reset Framework does not currently provide a bundled runtime for ${process.platform}-${process.arch}.`
|
|
510
|
+
)
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
export function resolveFrameworkRuntimeBinary(frameworkPaths, frameworkBuildPaths, mode, options = {}) {
|
|
514
|
+
const { mustExist = false } = options
|
|
515
|
+
const strategy = options.strategy ?? resolveFrameworkRuntimeStrategy(frameworkPaths, options)
|
|
516
|
+
|
|
517
|
+
if (strategy.kind === "prebuilt") {
|
|
518
|
+
if (existsSync(strategy.binaryPath)) {
|
|
519
|
+
return strategy.binaryPath
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
if (mustExist) {
|
|
523
|
+
throw new Error(`Missing bundled runtime executable at ${strategy.binaryPath}.`)
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
return strategy.binaryPath
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
const candidates =
|
|
530
|
+
mode === "release"
|
|
531
|
+
? (frameworkBuildPaths.releaseAppBinaryCandidates ?? [frameworkBuildPaths.releaseAppTemplate])
|
|
532
|
+
: (frameworkBuildPaths.devAppBinaryCandidates ?? [frameworkBuildPaths.devAppBinary])
|
|
533
|
+
const existing = resolveExistingCandidate(candidates)
|
|
534
|
+
|
|
535
|
+
if (existing) {
|
|
536
|
+
return existing
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
if (mustExist) {
|
|
540
|
+
throw new Error(`Missing built runtime executable. Looked in: ${candidates.join(", ")}`)
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
return candidates[0]
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
export function resolveFrameworkRuntimeOutputDir(frameworkPaths, frameworkBuildPaths, mode, options = {}) {
|
|
547
|
+
const { mustExist = false } = options
|
|
548
|
+
const strategy = options.strategy ?? resolveFrameworkRuntimeStrategy(frameworkPaths, options)
|
|
549
|
+
|
|
550
|
+
if (strategy.kind === "prebuilt") {
|
|
551
|
+
if (existsSync(strategy.artifactRoot)) {
|
|
552
|
+
return strategy.artifactRoot
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
if (mustExist) {
|
|
556
|
+
throw new Error(`Missing bundled runtime output directory at ${strategy.artifactRoot}.`)
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
return strategy.artifactRoot
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
const candidates =
|
|
563
|
+
mode === "release"
|
|
564
|
+
? (frameworkBuildPaths.releaseRuntimeOutputCandidates ?? [])
|
|
565
|
+
: (frameworkBuildPaths.devRuntimeOutputCandidates ?? [])
|
|
566
|
+
const existing = resolveExistingCandidate(candidates)
|
|
567
|
+
|
|
568
|
+
if (existing) {
|
|
569
|
+
return existing
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
if (candidates.length > 0) {
|
|
573
|
+
if (mustExist) {
|
|
574
|
+
throw new Error(`Missing built runtime output directory. Looked in: ${candidates.join(", ")}`)
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
return candidates[0]
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
return path.dirname(resolveFrameworkRuntimeBinary(frameworkPaths, frameworkBuildPaths, mode, options))
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
export function resolveAppPaths(appRoot) {
|
|
584
|
+
return {
|
|
585
|
+
appRoot,
|
|
586
|
+
appPackageJsonPath: path.join(appRoot, "package.json"),
|
|
587
|
+
backendDir: path.join(appRoot, "backend"),
|
|
588
|
+
frontendDir: path.join(appRoot, "frontend"),
|
|
589
|
+
resetConfigPath: path.join(appRoot, "reset.config.json"),
|
|
590
|
+
legacyResetConfigPath: path.join(appRoot, "frontend", "reset.config.json")
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
export function resolveOptionalBackendEntry(appPaths) {
|
|
595
|
+
const candidates = [
|
|
596
|
+
path.join(appPaths.backendDir, "src", "index.ts"),
|
|
597
|
+
path.join(appPaths.backendDir, "src", "index.js"),
|
|
598
|
+
path.join(appPaths.backendDir, "index.ts"),
|
|
599
|
+
path.join(appPaths.backendDir, "index.js")
|
|
600
|
+
]
|
|
601
|
+
|
|
602
|
+
return resolveExistingCandidate(candidates)
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
export function resolveConfigPath(appPaths) {
|
|
606
|
+
if (existsSync(appPaths.resetConfigPath)) {
|
|
607
|
+
return appPaths.resetConfigPath
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
if (existsSync(appPaths.legacyResetConfigPath)) {
|
|
611
|
+
return appPaths.legacyResetConfigPath
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
return appPaths.resetConfigPath
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
export function getFrameworkChecks(frameworkPaths) {
|
|
618
|
+
return [
|
|
619
|
+
["backend", frameworkPaths.backendPackage.packageJsonPath],
|
|
620
|
+
["sdk", frameworkPaths.sdkPackage.packageJsonPath],
|
|
621
|
+
["schema", frameworkPaths.schemaPackage.packageJsonPath],
|
|
622
|
+
["templates", frameworkPaths.templatesDir]
|
|
623
|
+
]
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
export function getFrameworkRuntimeChecks(frameworkPaths) {
|
|
627
|
+
const checks = []
|
|
628
|
+
|
|
629
|
+
if (frameworkPaths.runtimePackage?.packageInfo) {
|
|
630
|
+
checks.push(["runtime package", frameworkPaths.runtimePackage.packageInfo.packageJsonPath])
|
|
631
|
+
if (frameworkPaths.runtimePackage.artifactRoot) {
|
|
632
|
+
checks.push(["runtime artifact", frameworkPaths.runtimePackage.artifactRoot])
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
if (frameworkPaths.frameworkPackage) {
|
|
637
|
+
checks.push(["native source", frameworkPaths.frameworkPackage.packageJsonPath])
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
if (frameworkPaths.rootCMakePath) {
|
|
641
|
+
checks.push(["cmake", frameworkPaths.rootCMakePath])
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
if (frameworkPaths.runtimeDir) {
|
|
645
|
+
checks.push(["runtime source", frameworkPaths.runtimeDir])
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
if (frameworkPaths.vcpkgManifestPath) {
|
|
649
|
+
checks.push(["vcpkg", frameworkPaths.vcpkgManifestPath])
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
return checks
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
export function getFrameworkRuntimeModeSummary(frameworkPaths, options = {}) {
|
|
656
|
+
const strategy = resolveFrameworkRuntimeStrategy(frameworkPaths, options)
|
|
657
|
+
|
|
658
|
+
return {
|
|
659
|
+
kind: strategy.kind,
|
|
660
|
+
label: strategy.label
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
export function hasFrameworkSourcePackage(frameworkPaths) {
|
|
665
|
+
return hasSourceRuntimeLayout(frameworkPaths)
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
export function isFrameworkSourceRequested(options = {}) {
|
|
669
|
+
return isSourceRuntimeRequested(options)
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
export function assertFrameworkInstall(frameworkPaths) {
|
|
673
|
+
const missing = getFrameworkChecks(frameworkPaths)
|
|
674
|
+
.filter(([, filePath]) => !existsSync(filePath))
|
|
675
|
+
.map(([label]) => label)
|
|
676
|
+
|
|
677
|
+
if (missing.length > 0) {
|
|
678
|
+
throw new Error(
|
|
679
|
+
`Reset CLI installation is incomplete. Missing: ${missing.join(", ")}`
|
|
680
|
+
)
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
export function assertFrameworkSourceInstall(frameworkPaths) {
|
|
685
|
+
const missing = [
|
|
686
|
+
["native source", frameworkPaths.frameworkPackage?.packageJsonPath],
|
|
687
|
+
["backend", frameworkPaths.backendPackage.packageJsonPath],
|
|
688
|
+
["sdk", frameworkPaths.sdkPackage.packageJsonPath],
|
|
689
|
+
["cmake", frameworkPaths.rootCMakePath],
|
|
690
|
+
["runtime", frameworkPaths.runtimeDir],
|
|
691
|
+
["vcpkg", frameworkPaths.vcpkgManifestPath],
|
|
692
|
+
["templates", frameworkPaths.templatesDir]
|
|
693
|
+
]
|
|
694
|
+
.filter(([, filePath]) => !filePath || !existsSync(filePath))
|
|
695
|
+
.map(([label]) => label)
|
|
696
|
+
|
|
697
|
+
if (missing.length > 0) {
|
|
698
|
+
throw new Error(
|
|
699
|
+
`Source runtime is unavailable in this CLI installation. Missing: ${missing.join(", ")}`
|
|
700
|
+
)
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
export function getAppChecks(appPaths) {
|
|
705
|
+
return [["config", resolveConfigPath(appPaths)]]
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
export function assertAppProject(appPaths, config) {
|
|
709
|
+
const checks = [...getAppChecks(appPaths)]
|
|
710
|
+
|
|
711
|
+
if (config) {
|
|
712
|
+
checks.unshift(["frontend", resolveFrontendDir(appPaths, config)])
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
const missing = checks
|
|
716
|
+
.filter(([, filePath]) => !existsSync(filePath))
|
|
717
|
+
.map(([label]) => label)
|
|
718
|
+
|
|
719
|
+
if (missing.length > 0) {
|
|
720
|
+
throw new Error(
|
|
721
|
+
`Current directory does not look like a Reset app. Missing: ${missing.join(", ")}`
|
|
722
|
+
)
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
export function validateResetConfig(rawConfig) {
|
|
727
|
+
const frontend = optionalObject(rawConfig, "frontend")
|
|
728
|
+
const build = optionalObject(rawConfig, "build")
|
|
729
|
+
const project = optionalObject(rawConfig, "project")
|
|
730
|
+
const security = optionalObject(rawConfig, "security")
|
|
731
|
+
const protocols = optionalObject(rawConfig, "protocols")
|
|
732
|
+
const windowConfig = optionalObject(rawConfig, "window")
|
|
733
|
+
const rawProtocolSchemes = Array.isArray(protocols.schemes) ? protocols.schemes : []
|
|
734
|
+
const seenProtocolSchemes = new Set()
|
|
735
|
+
|
|
736
|
+
return {
|
|
737
|
+
...rawConfig,
|
|
738
|
+
name: sanitizeName(requireString(rawConfig, "name", "config")),
|
|
739
|
+
productName: requireString(rawConfig, "productName", "config"),
|
|
740
|
+
appId: requireString(rawConfig, "appId", "config"),
|
|
741
|
+
version: requireString(rawConfig, "version", "config"),
|
|
742
|
+
window: {
|
|
743
|
+
title: optionalString(windowConfig, "title", "Reset App")
|
|
744
|
+
},
|
|
745
|
+
frontend: {
|
|
746
|
+
devUrl: requireString(frontend, "devUrl", "frontend"),
|
|
747
|
+
distDir: optionalString(frontend, "distDir", "dist"),
|
|
748
|
+
entryHtml: optionalString(frontend, "entryHtml", "index.html")
|
|
749
|
+
},
|
|
750
|
+
project: {
|
|
751
|
+
frontendDir: normalizeFrontendDir(optionalString(project, "frontendDir", "frontend")),
|
|
752
|
+
styling: normalizeStyling(optionalString(project, "styling", "css"))
|
|
753
|
+
},
|
|
754
|
+
build: {
|
|
755
|
+
outputDir: optionalString(build, "outputDir", ".reset/build")
|
|
756
|
+
},
|
|
757
|
+
security: {
|
|
758
|
+
permissions: Array.isArray(security.permissions)
|
|
759
|
+
? security.permissions.map((value) => {
|
|
760
|
+
if (typeof value !== "string" || value.trim() === "") {
|
|
761
|
+
throw new Error("Missing or invalid string field 'security.permissions'")
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
return value
|
|
765
|
+
})
|
|
766
|
+
: []
|
|
767
|
+
},
|
|
768
|
+
protocols: {
|
|
769
|
+
schemes: rawProtocolSchemes.map((entry) => {
|
|
770
|
+
if (typeof entry !== "object" || entry === null || Array.isArray(entry)) {
|
|
771
|
+
throw new Error("protocols.schemes entries must be objects")
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
const scheme = normalizeProtocolScheme(entry.scheme)
|
|
775
|
+
if (seenProtocolSchemes.has(scheme)) {
|
|
776
|
+
throw new Error(`Duplicate protocol scheme '${scheme}'`)
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
seenProtocolSchemes.add(scheme)
|
|
780
|
+
|
|
781
|
+
return {
|
|
782
|
+
scheme,
|
|
783
|
+
name:
|
|
784
|
+
typeof entry.name === "string" && entry.name.trim() !== ""
|
|
785
|
+
? entry.name
|
|
786
|
+
: scheme,
|
|
787
|
+
role:
|
|
788
|
+
entry.role === undefined
|
|
789
|
+
? "Viewer"
|
|
790
|
+
: normalizeProtocolRole(entry.role)
|
|
791
|
+
}
|
|
792
|
+
})
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
export function loadResetConfig(appPaths) {
|
|
798
|
+
const configPath = resolveConfigPath(appPaths)
|
|
799
|
+
const raw = readFileSync(configPath, "utf8")
|
|
800
|
+
|
|
801
|
+
try {
|
|
802
|
+
return validateResetConfig(JSON.parse(raw))
|
|
803
|
+
} catch (error) {
|
|
804
|
+
if (error instanceof SyntaxError) {
|
|
805
|
+
throw new Error(`Invalid JSON in ${configPath}: ${error.message}`)
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
throw error
|
|
809
|
+
}
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
export function resolveAppOutputPaths(appPaths, config) {
|
|
813
|
+
const outputRoot = path.resolve(appPaths.appRoot, config.build.outputDir)
|
|
814
|
+
const frontendDir = resolveFrontendDir(appPaths, config)
|
|
815
|
+
const isWindows = process.platform === "win32"
|
|
816
|
+
const appBundleName = isWindows ? config.productName : `${config.productName}.app`
|
|
817
|
+
const platformDir = path.join(outputRoot, isWindows ? "windows" : "macos")
|
|
818
|
+
const appBundlePath = path.join(platformDir, appBundleName)
|
|
819
|
+
const resourcesDir = isWindows
|
|
820
|
+
? path.join(appBundlePath, "resources")
|
|
821
|
+
: path.join(appBundlePath, "Contents", "Resources")
|
|
822
|
+
const packagesDir = path.join(outputRoot, "packages")
|
|
823
|
+
|
|
824
|
+
return {
|
|
825
|
+
outputRoot,
|
|
826
|
+
macosDir: isWindows ? undefined : platformDir,
|
|
827
|
+
windowsDir: isWindows ? platformDir : undefined,
|
|
828
|
+
appBundlePath,
|
|
829
|
+
appExecutablePath: isWindows
|
|
830
|
+
? path.join(appBundlePath, `${config.productName}.exe`)
|
|
831
|
+
: undefined,
|
|
832
|
+
resourcesDir,
|
|
833
|
+
bundledConfigPath: path.join(resourcesDir, "reset.config.json"),
|
|
834
|
+
bundledBackendDir: path.join(resourcesDir, "backend"),
|
|
835
|
+
bundledBackendEntryPath: path.join(resourcesDir, "backend", "app.mjs"),
|
|
836
|
+
bundledBackendRunnerPath: path.join(resourcesDir, "backend", "runner.mjs"),
|
|
837
|
+
bundledBackendSupportModulePath: path.join(resourcesDir, "backend", "index.js"),
|
|
838
|
+
bundledBackendRuntimePath: path.join(
|
|
839
|
+
resourcesDir,
|
|
840
|
+
"backend",
|
|
841
|
+
process.platform === "win32" ? "backend-runtime.exe" : "backend-runtime"
|
|
842
|
+
),
|
|
843
|
+
bundledFrontendDir: path.join(resourcesDir, config.frontend.distDir),
|
|
844
|
+
frontendDistDir: path.resolve(frontendDir, config.frontend.distDir),
|
|
845
|
+
frontendEntryFile: path.resolve(
|
|
846
|
+
frontendDir,
|
|
847
|
+
config.frontend.distDir,
|
|
848
|
+
config.frontend.entryHtml
|
|
849
|
+
),
|
|
850
|
+
packagesDir,
|
|
851
|
+
zipPath: path.join(packagesDir, `${config.name}-${isWindows ? "windows" : "macos"}.zip`)
|
|
852
|
+
}
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
export function resolveFrontendDir(appPaths, config) {
|
|
856
|
+
return path.resolve(appPaths.appRoot, config.project.frontendDir)
|
|
857
|
+
}
|
|
858
|
+
|
|
859
|
+
export function resolveDevServerOptions(config) {
|
|
860
|
+
const url = new URL(config.frontend.devUrl)
|
|
861
|
+
|
|
862
|
+
return {
|
|
863
|
+
host: url.hostname,
|
|
864
|
+
port: url.port || "5173",
|
|
865
|
+
url: url.toString()
|
|
866
|
+
}
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
export function makeAppMetadata(appName) {
|
|
870
|
+
const name = sanitizeName(appName)
|
|
871
|
+
const productName = toTitleCase(appName)
|
|
872
|
+
|
|
873
|
+
return {
|
|
874
|
+
name,
|
|
875
|
+
productName,
|
|
876
|
+
appId: `com.example.${name}`,
|
|
877
|
+
title: productName
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
|
|
881
|
+
export function resolveSdkDependencySpec(frameworkPaths) {
|
|
882
|
+
if (frameworkPaths.isWorkspaceLayout || frameworkPaths.sdkPackage.localFallback) {
|
|
883
|
+
return `file:${frameworkPaths.sdkPackage.packageRoot}`
|
|
884
|
+
}
|
|
885
|
+
|
|
886
|
+
return `^${frameworkPaths.sdkPackage.version}`
|
|
887
|
+
}
|
|
888
|
+
|
|
889
|
+
export function resolveBackendDependencySpec(frameworkPaths) {
|
|
890
|
+
if (frameworkPaths.isWorkspaceLayout || frameworkPaths.backendPackage.localFallback) {
|
|
891
|
+
return `file:${frameworkPaths.backendPackage.packageRoot}`
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
return `^${frameworkPaths.backendPackage.version}`
|
|
895
|
+
}
|
|
896
|
+
|
|
897
|
+
export function resolveCliDependencySpec(frameworkPaths) {
|
|
898
|
+
if (frameworkPaths.isWorkspaceLayout || frameworkPaths.cliPackage.localFallback) {
|
|
899
|
+
return `file:${frameworkPaths.cliPackage.packageRoot}`
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
return `^${frameworkPaths.cliPackage.version}`
|
|
903
|
+
}
|
|
904
|
+
|
|
905
|
+
function detectPackageManagerFromManifest(packageJsonPath) {
|
|
906
|
+
if (!fileExists(packageJsonPath)) {
|
|
907
|
+
return null
|
|
908
|
+
}
|
|
909
|
+
|
|
910
|
+
const manifest = readJsonFile(packageJsonPath)
|
|
911
|
+
const raw = typeof manifest.packageManager === "string" ? manifest.packageManager.trim() : ""
|
|
912
|
+
if (raw === "") {
|
|
913
|
+
return null
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
const [name] = raw.split("@")
|
|
917
|
+
if (name === "npm" || name === "pnpm" || name === "yarn" || name === "bun") {
|
|
918
|
+
return name
|
|
919
|
+
}
|
|
920
|
+
|
|
921
|
+
return null
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
function detectPackageManagerFromLocks(directory) {
|
|
925
|
+
if (!fileExists(directory)) {
|
|
926
|
+
return null
|
|
927
|
+
}
|
|
928
|
+
|
|
929
|
+
if (fileExists(path.join(directory, "bun.lock")) || fileExists(path.join(directory, "bun.lockb"))) {
|
|
930
|
+
return "bun"
|
|
931
|
+
}
|
|
932
|
+
|
|
933
|
+
if (fileExists(path.join(directory, "pnpm-lock.yaml"))) {
|
|
934
|
+
return "pnpm"
|
|
935
|
+
}
|
|
936
|
+
|
|
937
|
+
if (fileExists(path.join(directory, "yarn.lock"))) {
|
|
938
|
+
return "yarn"
|
|
939
|
+
}
|
|
940
|
+
|
|
941
|
+
if (fileExists(path.join(directory, "package-lock.json"))) {
|
|
942
|
+
return "npm"
|
|
943
|
+
}
|
|
944
|
+
|
|
945
|
+
return null
|
|
946
|
+
}
|
|
947
|
+
|
|
948
|
+
export function resolveAppPackageManager(appPaths, config) {
|
|
949
|
+
const frontendDir = resolveFrontendDir(appPaths, config)
|
|
950
|
+
const frontendPackageJsonPath = path.join(frontendDir, "package.json")
|
|
951
|
+
|
|
952
|
+
return (
|
|
953
|
+
detectPackageManagerFromManifest(appPaths.appPackageJsonPath) ??
|
|
954
|
+
detectPackageManagerFromManifest(frontendPackageJsonPath) ??
|
|
955
|
+
detectPackageManagerFromLocks(appPaths.appRoot) ??
|
|
956
|
+
detectPackageManagerFromLocks(frontendDir) ??
|
|
957
|
+
"npm"
|
|
958
|
+
)
|
|
959
|
+
}
|