reset-framework-cli 1.2.0 → 1.2.2
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 +19 -19
- package/package.json +8 -6
- package/src/commands/build.js +91 -73
- package/src/commands/dev.js +143 -122
- package/src/commands/doctor.js +61 -54
- 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 +251 -236
- package/src/lib/process.js +303 -303
- package/src/lib/project.js +531 -494
- 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,8 +1,8 @@
|
|
|
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
|
-
|
|
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
6
|
const require = createRequire(import.meta.url)
|
|
7
7
|
|
|
8
8
|
const runtimePackageDescriptors = [
|
|
@@ -31,166 +31,166 @@ const runtimePackageDescriptors = [
|
|
|
31
31
|
binarySegments: ["dist", "win32-x64", "reset-framework.exe"]
|
|
32
32
|
}
|
|
33
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)
|
|
156
|
-
}
|
|
157
|
-
|
|
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)
|
|
156
|
+
}
|
|
157
|
+
|
|
158
158
|
function resolvePackageInfo(packageName, fallbackRoot) {
|
|
159
159
|
try {
|
|
160
|
-
const packageJsonPath = require.resolve(`${packageName}/package.json`)
|
|
161
|
-
const packageRoot = path.dirname(packageJsonPath)
|
|
162
|
-
const manifest = readJsonFile(packageJsonPath)
|
|
163
|
-
|
|
164
|
-
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
|
-
}
|
|
160
|
+
const packageJsonPath = require.resolve(`${packageName}/package.json`)
|
|
161
|
+
const packageRoot = path.dirname(packageJsonPath)
|
|
162
|
+
const manifest = readJsonFile(packageJsonPath)
|
|
163
|
+
|
|
164
|
+
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
|
+
}
|
|
182
182
|
}
|
|
183
183
|
}
|
|
184
184
|
|
|
185
185
|
function resolveWorkspacePackageInfo(packageName, workspaceRoot, fallbackInfo) {
|
|
186
|
-
const packageJsonPath = path.join(workspaceRoot, "package.json")
|
|
187
|
-
|
|
188
|
-
if (!existsSync(packageJsonPath)) {
|
|
189
|
-
return fallbackInfo
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
const manifest = readJsonFile(packageJsonPath)
|
|
193
|
-
|
|
186
|
+
const packageJsonPath = path.join(workspaceRoot, "package.json")
|
|
187
|
+
|
|
188
|
+
if (!existsSync(packageJsonPath)) {
|
|
189
|
+
return fallbackInfo
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
const manifest = readJsonFile(packageJsonPath)
|
|
193
|
+
|
|
194
194
|
return {
|
|
195
195
|
packageName: manifest.name ?? packageName,
|
|
196
196
|
packageRoot: workspaceRoot,
|
|
@@ -325,7 +325,12 @@ export function resolveFrameworkPaths() {
|
|
|
325
325
|
"@reset-framework/sdk",
|
|
326
326
|
path.join(packagesDir, "sdk"),
|
|
327
327
|
resolvePackageInfo("@reset-framework/sdk", path.join(packagesDir, "sdk"))
|
|
328
|
-
)
|
|
328
|
+
)
|
|
329
|
+
const backendPackage = resolveWorkspacePackageInfo(
|
|
330
|
+
"@reset-framework/backend",
|
|
331
|
+
path.join(packagesDir, "backend"),
|
|
332
|
+
resolvePackageInfo("@reset-framework/backend", path.join(packagesDir, "backend"))
|
|
333
|
+
)
|
|
329
334
|
const schemaPackage = resolveWorkspacePackageInfo(
|
|
330
335
|
"@reset-framework/schema",
|
|
331
336
|
path.join(packagesDir, "schema"),
|
|
@@ -334,7 +339,7 @@ export function resolveFrameworkPaths() {
|
|
|
334
339
|
const runtimePackage = resolveRuntimePackage(packagesDir)
|
|
335
340
|
const isWorkspaceLayout =
|
|
336
341
|
isWorkspacePackagesDir &&
|
|
337
|
-
[cliDir, sdkPackage.packageRoot, schemaPackage.packageRoot].every((packageRoot) =>
|
|
342
|
+
[cliDir, backendPackage.packageRoot, sdkPackage.packageRoot, schemaPackage.packageRoot].every((packageRoot) =>
|
|
338
343
|
isPathInside(packagesDir, packageRoot)
|
|
339
344
|
)
|
|
340
345
|
|
|
@@ -351,6 +356,7 @@ export function resolveFrameworkPaths() {
|
|
|
351
356
|
frameworkRoot: nativePackage?.packageRoot ?? null,
|
|
352
357
|
frameworkPackage: nativePackage,
|
|
353
358
|
isWorkspaceLayout,
|
|
359
|
+
backendPackage,
|
|
354
360
|
sdkPackage,
|
|
355
361
|
schemaPackage,
|
|
356
362
|
runtimePackage,
|
|
@@ -361,58 +367,58 @@ export function resolveFrameworkPaths() {
|
|
|
361
367
|
templatesDir: path.join(cliDir, "templates")
|
|
362
368
|
}
|
|
363
369
|
}
|
|
364
|
-
|
|
370
|
+
|
|
365
371
|
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]
|
|
372
|
+
const frameworkCacheRoot = path.join(appPaths.appRoot, ".reset", "framework")
|
|
373
|
+
const isWindows = process.platform === "win32"
|
|
374
|
+
const devRuntimeRoot = path.join(frameworkCacheRoot, "build", "dev", "runtime")
|
|
375
|
+
const releaseRuntimeRoot = path.join(frameworkCacheRoot, "build", "release", "runtime")
|
|
376
|
+
const devAppBinaryCandidates = isWindows
|
|
377
|
+
? [
|
|
378
|
+
path.join(devRuntimeRoot, getFrameworkBuildType("dev"), "reset-framework.exe"),
|
|
379
|
+
path.join(devRuntimeRoot, "reset-framework.exe")
|
|
380
|
+
]
|
|
381
|
+
: [
|
|
382
|
+
path.join(
|
|
383
|
+
frameworkCacheRoot,
|
|
384
|
+
"build",
|
|
385
|
+
"dev",
|
|
386
|
+
"runtime",
|
|
387
|
+
"reset-framework.app",
|
|
388
|
+
"Contents",
|
|
389
|
+
"MacOS",
|
|
390
|
+
"reset-framework"
|
|
391
|
+
)
|
|
392
|
+
]
|
|
393
|
+
const releaseAppBinaryCandidates = isWindows
|
|
394
|
+
? [
|
|
395
|
+
path.join(releaseRuntimeRoot, getFrameworkBuildType("release"), "reset-framework.exe"),
|
|
396
|
+
path.join(releaseRuntimeRoot, "reset-framework.exe")
|
|
397
|
+
]
|
|
398
|
+
: [
|
|
399
|
+
path.join(
|
|
400
|
+
frameworkCacheRoot,
|
|
401
|
+
"build",
|
|
402
|
+
"release",
|
|
403
|
+
"runtime",
|
|
404
|
+
"reset-framework.app"
|
|
405
|
+
)
|
|
406
|
+
]
|
|
407
|
+
|
|
408
|
+
return {
|
|
409
|
+
frameworkCacheRoot,
|
|
410
|
+
devBuildDir: path.join(frameworkCacheRoot, "build", "dev"),
|
|
411
|
+
releaseBuildDir: path.join(frameworkCacheRoot, "build", "release"),
|
|
412
|
+
devRuntimeOutputCandidates: isWindows
|
|
413
|
+
? [path.join(devRuntimeRoot, getFrameworkBuildType("dev")), devRuntimeRoot]
|
|
414
|
+
: [path.join(frameworkCacheRoot, "build", "dev", "runtime", "reset-framework.app")],
|
|
415
|
+
releaseRuntimeOutputCandidates: isWindows
|
|
416
|
+
? [path.join(releaseRuntimeRoot, getFrameworkBuildType("release")), releaseRuntimeRoot]
|
|
417
|
+
: [path.join(frameworkCacheRoot, "build", "release", "runtime", "reset-framework.app")],
|
|
418
|
+
devAppBinaryCandidates,
|
|
419
|
+
releaseAppBinaryCandidates,
|
|
420
|
+
devAppBinary: devAppBinaryCandidates[0],
|
|
421
|
+
releaseAppTemplate: releaseAppBinaryCandidates[0]
|
|
416
422
|
}
|
|
417
423
|
}
|
|
418
424
|
|
|
@@ -497,15 +503,15 @@ export function resolveFrameworkRuntimeBinary(frameworkPaths, frameworkBuildPath
|
|
|
497
503
|
mode === "release"
|
|
498
504
|
? (frameworkBuildPaths.releaseAppBinaryCandidates ?? [frameworkBuildPaths.releaseAppTemplate])
|
|
499
505
|
: (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
|
-
}
|
|
506
|
+
const existing = resolveExistingCandidate(candidates)
|
|
507
|
+
|
|
508
|
+
if (existing) {
|
|
509
|
+
return existing
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
if (mustExist) {
|
|
513
|
+
throw new Error(`Missing built runtime executable. Looked in: ${candidates.join(", ")}`)
|
|
514
|
+
}
|
|
509
515
|
|
|
510
516
|
return candidates[0]
|
|
511
517
|
}
|
|
@@ -530,47 +536,60 @@ export function resolveFrameworkRuntimeOutputDir(frameworkPaths, frameworkBuildP
|
|
|
530
536
|
mode === "release"
|
|
531
537
|
? (frameworkBuildPaths.releaseRuntimeOutputCandidates ?? [])
|
|
532
538
|
: (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
|
-
|
|
539
|
+
const existing = resolveExistingCandidate(candidates)
|
|
540
|
+
|
|
541
|
+
if (existing) {
|
|
542
|
+
return existing
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
if (candidates.length > 0) {
|
|
546
|
+
if (mustExist) {
|
|
547
|
+
throw new Error(`Missing built runtime output directory. Looked in: ${candidates.join(", ")}`)
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
return candidates[0]
|
|
551
|
+
}
|
|
552
|
+
|
|
547
553
|
return path.dirname(resolveFrameworkRuntimeBinary(frameworkPaths, frameworkBuildPaths, mode, options))
|
|
548
554
|
}
|
|
549
|
-
|
|
550
|
-
export function resolveAppPaths(appRoot) {
|
|
551
|
-
return {
|
|
552
|
-
appRoot,
|
|
553
|
-
appPackageJsonPath: path.join(appRoot, "package.json"),
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
}
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
return
|
|
570
|
-
}
|
|
571
|
-
|
|
555
|
+
|
|
556
|
+
export function resolveAppPaths(appRoot) {
|
|
557
|
+
return {
|
|
558
|
+
appRoot,
|
|
559
|
+
appPackageJsonPath: path.join(appRoot, "package.json"),
|
|
560
|
+
backendDir: path.join(appRoot, "backend"),
|
|
561
|
+
frontendDir: path.join(appRoot, "frontend"),
|
|
562
|
+
resetConfigPath: path.join(appRoot, "reset.config.json"),
|
|
563
|
+
legacyResetConfigPath: path.join(appRoot, "frontend", "reset.config.json")
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
export function resolveOptionalBackendEntry(appPaths) {
|
|
568
|
+
const candidates = [
|
|
569
|
+
path.join(appPaths.backendDir, "src", "index.ts"),
|
|
570
|
+
path.join(appPaths.backendDir, "src", "index.js"),
|
|
571
|
+
path.join(appPaths.backendDir, "index.ts"),
|
|
572
|
+
path.join(appPaths.backendDir, "index.js")
|
|
573
|
+
]
|
|
574
|
+
|
|
575
|
+
return resolveExistingCandidate(candidates)
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
export function resolveConfigPath(appPaths) {
|
|
579
|
+
if (existsSync(appPaths.resetConfigPath)) {
|
|
580
|
+
return appPaths.resetConfigPath
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
if (existsSync(appPaths.legacyResetConfigPath)) {
|
|
584
|
+
return appPaths.legacyResetConfigPath
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
return appPaths.resetConfigPath
|
|
588
|
+
}
|
|
589
|
+
|
|
572
590
|
export function getFrameworkChecks(frameworkPaths) {
|
|
573
591
|
return [
|
|
592
|
+
["backend", frameworkPaths.backendPackage.packageJsonPath],
|
|
574
593
|
["sdk", frameworkPaths.sdkPackage.packageJsonPath],
|
|
575
594
|
["schema", frameworkPaths.schemaPackage.packageJsonPath],
|
|
576
595
|
["templates", frameworkPaths.templatesDir]
|
|
@@ -638,6 +657,7 @@ export function assertFrameworkInstall(frameworkPaths) {
|
|
|
638
657
|
export function assertFrameworkSourceInstall(frameworkPaths) {
|
|
639
658
|
const missing = [
|
|
640
659
|
["native source", frameworkPaths.frameworkPackage?.packageJsonPath],
|
|
660
|
+
["backend", frameworkPaths.backendPackage.packageJsonPath],
|
|
641
661
|
["sdk", frameworkPaths.sdkPackage.packageJsonPath],
|
|
642
662
|
["cmake", frameworkPaths.rootCMakePath],
|
|
643
663
|
["runtime", frameworkPaths.runtimeDir],
|
|
@@ -657,239 +677,256 @@ export function assertFrameworkSourceInstall(frameworkPaths) {
|
|
|
657
677
|
export function getAppChecks(appPaths) {
|
|
658
678
|
return [["config", resolveConfigPath(appPaths)]]
|
|
659
679
|
}
|
|
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
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
}
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
}
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
}
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
if (
|
|
866
|
-
return
|
|
867
|
-
}
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
)
|
|
895
|
-
|
|
680
|
+
|
|
681
|
+
export function assertAppProject(appPaths, config) {
|
|
682
|
+
const checks = [...getAppChecks(appPaths)]
|
|
683
|
+
|
|
684
|
+
if (config) {
|
|
685
|
+
checks.unshift(["frontend", resolveFrontendDir(appPaths, config)])
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
const missing = checks
|
|
689
|
+
.filter(([, filePath]) => !existsSync(filePath))
|
|
690
|
+
.map(([label]) => label)
|
|
691
|
+
|
|
692
|
+
if (missing.length > 0) {
|
|
693
|
+
throw new Error(
|
|
694
|
+
`Current directory does not look like a Reset app. Missing: ${missing.join(", ")}`
|
|
695
|
+
)
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
export function validateResetConfig(rawConfig) {
|
|
700
|
+
const frontend = optionalObject(rawConfig, "frontend")
|
|
701
|
+
const build = optionalObject(rawConfig, "build")
|
|
702
|
+
const project = optionalObject(rawConfig, "project")
|
|
703
|
+
const security = optionalObject(rawConfig, "security")
|
|
704
|
+
const protocols = optionalObject(rawConfig, "protocols")
|
|
705
|
+
const windowConfig = optionalObject(rawConfig, "window")
|
|
706
|
+
const rawProtocolSchemes = Array.isArray(protocols.schemes) ? protocols.schemes : []
|
|
707
|
+
const seenProtocolSchemes = new Set()
|
|
708
|
+
|
|
709
|
+
return {
|
|
710
|
+
...rawConfig,
|
|
711
|
+
name: sanitizeName(requireString(rawConfig, "name", "config")),
|
|
712
|
+
productName: requireString(rawConfig, "productName", "config"),
|
|
713
|
+
appId: requireString(rawConfig, "appId", "config"),
|
|
714
|
+
version: requireString(rawConfig, "version", "config"),
|
|
715
|
+
window: {
|
|
716
|
+
title: optionalString(windowConfig, "title", "Reset App")
|
|
717
|
+
},
|
|
718
|
+
frontend: {
|
|
719
|
+
devUrl: requireString(frontend, "devUrl", "frontend"),
|
|
720
|
+
distDir: optionalString(frontend, "distDir", "dist"),
|
|
721
|
+
entryHtml: optionalString(frontend, "entryHtml", "index.html")
|
|
722
|
+
},
|
|
723
|
+
project: {
|
|
724
|
+
frontendDir: normalizeFrontendDir(optionalString(project, "frontendDir", "frontend")),
|
|
725
|
+
styling: normalizeStyling(optionalString(project, "styling", "css"))
|
|
726
|
+
},
|
|
727
|
+
build: {
|
|
728
|
+
outputDir: optionalString(build, "outputDir", ".reset/build")
|
|
729
|
+
},
|
|
730
|
+
security: {
|
|
731
|
+
permissions: Array.isArray(security.permissions)
|
|
732
|
+
? security.permissions.map((value) => {
|
|
733
|
+
if (typeof value !== "string" || value.trim() === "") {
|
|
734
|
+
throw new Error("Missing or invalid string field 'security.permissions'")
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
return value
|
|
738
|
+
})
|
|
739
|
+
: []
|
|
740
|
+
},
|
|
741
|
+
protocols: {
|
|
742
|
+
schemes: rawProtocolSchemes.map((entry) => {
|
|
743
|
+
if (typeof entry !== "object" || entry === null || Array.isArray(entry)) {
|
|
744
|
+
throw new Error("protocols.schemes entries must be objects")
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
const scheme = normalizeProtocolScheme(entry.scheme)
|
|
748
|
+
if (seenProtocolSchemes.has(scheme)) {
|
|
749
|
+
throw new Error(`Duplicate protocol scheme '${scheme}'`)
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
seenProtocolSchemes.add(scheme)
|
|
753
|
+
|
|
754
|
+
return {
|
|
755
|
+
scheme,
|
|
756
|
+
name:
|
|
757
|
+
typeof entry.name === "string" && entry.name.trim() !== ""
|
|
758
|
+
? entry.name
|
|
759
|
+
: scheme,
|
|
760
|
+
role:
|
|
761
|
+
entry.role === undefined
|
|
762
|
+
? "Viewer"
|
|
763
|
+
: normalizeProtocolRole(entry.role)
|
|
764
|
+
}
|
|
765
|
+
})
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
export function loadResetConfig(appPaths) {
|
|
771
|
+
const configPath = resolveConfigPath(appPaths)
|
|
772
|
+
const raw = readFileSync(configPath, "utf8")
|
|
773
|
+
|
|
774
|
+
try {
|
|
775
|
+
return validateResetConfig(JSON.parse(raw))
|
|
776
|
+
} catch (error) {
|
|
777
|
+
if (error instanceof SyntaxError) {
|
|
778
|
+
throw new Error(`Invalid JSON in ${configPath}: ${error.message}`)
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
throw error
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
export function resolveAppOutputPaths(appPaths, config) {
|
|
786
|
+
const outputRoot = path.resolve(appPaths.appRoot, config.build.outputDir)
|
|
787
|
+
const frontendDir = resolveFrontendDir(appPaths, config)
|
|
788
|
+
const isWindows = process.platform === "win32"
|
|
789
|
+
const appBundleName = isWindows ? config.productName : `${config.productName}.app`
|
|
790
|
+
const platformDir = path.join(outputRoot, isWindows ? "windows" : "macos")
|
|
791
|
+
const appBundlePath = path.join(platformDir, appBundleName)
|
|
792
|
+
const resourcesDir = isWindows
|
|
793
|
+
? path.join(appBundlePath, "resources")
|
|
794
|
+
: path.join(appBundlePath, "Contents", "Resources")
|
|
795
|
+
const packagesDir = path.join(outputRoot, "packages")
|
|
796
|
+
|
|
797
|
+
return {
|
|
798
|
+
outputRoot,
|
|
799
|
+
macosDir: isWindows ? undefined : platformDir,
|
|
800
|
+
windowsDir: isWindows ? platformDir : undefined,
|
|
801
|
+
appBundlePath,
|
|
802
|
+
appExecutablePath: isWindows
|
|
803
|
+
? path.join(appBundlePath, `${config.productName}.exe`)
|
|
804
|
+
: undefined,
|
|
805
|
+
resourcesDir,
|
|
806
|
+
bundledConfigPath: path.join(resourcesDir, "reset.config.json"),
|
|
807
|
+
bundledBackendDir: path.join(resourcesDir, "backend"),
|
|
808
|
+
bundledBackendEntryPath: path.join(resourcesDir, "backend", "app.mjs"),
|
|
809
|
+
bundledBackendRunnerPath: path.join(resourcesDir, "backend", "runner.mjs"),
|
|
810
|
+
bundledBackendSupportModulePath: path.join(resourcesDir, "backend", "index.js"),
|
|
811
|
+
bundledBackendRuntimePath: path.join(
|
|
812
|
+
resourcesDir,
|
|
813
|
+
"backend",
|
|
814
|
+
process.platform === "win32" ? "backend-runtime.exe" : "backend-runtime"
|
|
815
|
+
),
|
|
816
|
+
bundledFrontendDir: path.join(resourcesDir, config.frontend.distDir),
|
|
817
|
+
frontendDistDir: path.resolve(frontendDir, config.frontend.distDir),
|
|
818
|
+
frontendEntryFile: path.resolve(
|
|
819
|
+
frontendDir,
|
|
820
|
+
config.frontend.distDir,
|
|
821
|
+
config.frontend.entryHtml
|
|
822
|
+
),
|
|
823
|
+
packagesDir,
|
|
824
|
+
zipPath: path.join(packagesDir, `${config.name}-${isWindows ? "windows" : "macos"}.zip`)
|
|
825
|
+
}
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
export function resolveFrontendDir(appPaths, config) {
|
|
829
|
+
return path.resolve(appPaths.appRoot, config.project.frontendDir)
|
|
830
|
+
}
|
|
831
|
+
|
|
832
|
+
export function resolveDevServerOptions(config) {
|
|
833
|
+
const url = new URL(config.frontend.devUrl)
|
|
834
|
+
|
|
835
|
+
return {
|
|
836
|
+
host: url.hostname,
|
|
837
|
+
port: url.port || "5173",
|
|
838
|
+
url: url.toString()
|
|
839
|
+
}
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
export function makeAppMetadata(appName) {
|
|
843
|
+
const name = sanitizeName(appName)
|
|
844
|
+
const productName = toTitleCase(appName)
|
|
845
|
+
|
|
846
|
+
return {
|
|
847
|
+
name,
|
|
848
|
+
productName,
|
|
849
|
+
appId: `com.example.${name}`,
|
|
850
|
+
title: productName
|
|
851
|
+
}
|
|
852
|
+
}
|
|
853
|
+
|
|
854
|
+
export function resolveSdkDependencySpec(frameworkPaths) {
|
|
855
|
+
if (frameworkPaths.isWorkspaceLayout || frameworkPaths.sdkPackage.localFallback) {
|
|
856
|
+
return `file:${frameworkPaths.sdkPackage.packageRoot}`
|
|
857
|
+
}
|
|
858
|
+
|
|
859
|
+
return `^${frameworkPaths.sdkPackage.version}`
|
|
860
|
+
}
|
|
861
|
+
|
|
862
|
+
export function resolveBackendDependencySpec(frameworkPaths) {
|
|
863
|
+
if (frameworkPaths.isWorkspaceLayout || frameworkPaths.backendPackage.localFallback) {
|
|
864
|
+
return `file:${frameworkPaths.backendPackage.packageRoot}`
|
|
865
|
+
}
|
|
866
|
+
|
|
867
|
+
return `^${frameworkPaths.backendPackage.version}`
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
export function resolveCliDependencySpec(frameworkPaths) {
|
|
871
|
+
if (frameworkPaths.isWorkspaceLayout || frameworkPaths.cliPackage.localFallback) {
|
|
872
|
+
return `file:${frameworkPaths.cliPackage.packageRoot}`
|
|
873
|
+
}
|
|
874
|
+
|
|
875
|
+
return `^${frameworkPaths.cliPackage.version}`
|
|
876
|
+
}
|
|
877
|
+
|
|
878
|
+
function detectPackageManagerFromManifest(packageJsonPath) {
|
|
879
|
+
if (!fileExists(packageJsonPath)) {
|
|
880
|
+
return null
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
const manifest = readJsonFile(packageJsonPath)
|
|
884
|
+
const raw = typeof manifest.packageManager === "string" ? manifest.packageManager.trim() : ""
|
|
885
|
+
if (raw === "") {
|
|
886
|
+
return null
|
|
887
|
+
}
|
|
888
|
+
|
|
889
|
+
const [name] = raw.split("@")
|
|
890
|
+
if (name === "npm" || name === "pnpm" || name === "yarn" || name === "bun") {
|
|
891
|
+
return name
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
return null
|
|
895
|
+
}
|
|
896
|
+
|
|
897
|
+
function detectPackageManagerFromLocks(directory) {
|
|
898
|
+
if (!fileExists(directory)) {
|
|
899
|
+
return null
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
if (fileExists(path.join(directory, "bun.lock")) || fileExists(path.join(directory, "bun.lockb"))) {
|
|
903
|
+
return "bun"
|
|
904
|
+
}
|
|
905
|
+
|
|
906
|
+
if (fileExists(path.join(directory, "pnpm-lock.yaml"))) {
|
|
907
|
+
return "pnpm"
|
|
908
|
+
}
|
|
909
|
+
|
|
910
|
+
if (fileExists(path.join(directory, "yarn.lock"))) {
|
|
911
|
+
return "yarn"
|
|
912
|
+
}
|
|
913
|
+
|
|
914
|
+
if (fileExists(path.join(directory, "package-lock.json"))) {
|
|
915
|
+
return "npm"
|
|
916
|
+
}
|
|
917
|
+
|
|
918
|
+
return null
|
|
919
|
+
}
|
|
920
|
+
|
|
921
|
+
export function resolveAppPackageManager(appPaths, config) {
|
|
922
|
+
const frontendDir = resolveFrontendDir(appPaths, config)
|
|
923
|
+
const frontendPackageJsonPath = path.join(frontendDir, "package.json")
|
|
924
|
+
|
|
925
|
+
return (
|
|
926
|
+
detectPackageManagerFromManifest(appPaths.appPackageJsonPath) ??
|
|
927
|
+
detectPackageManagerFromManifest(frontendPackageJsonPath) ??
|
|
928
|
+
detectPackageManagerFromLocks(appPaths.appRoot) ??
|
|
929
|
+
detectPackageManagerFromLocks(frontendDir) ??
|
|
930
|
+
"npm"
|
|
931
|
+
)
|
|
932
|
+
}
|