gorsee 0.2.10 → 0.2.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +52 -4
- package/bin/gorsee.js +38 -0
- package/dist-pkg/ai/bundle.d.ts +1 -0
- package/dist-pkg/ai/framework-context.d.ts +2 -0
- package/dist-pkg/ai/framework-context.js +6 -1
- package/dist-pkg/ai/ide.d.ts +1 -0
- package/dist-pkg/ai/ide.js +3 -0
- package/dist-pkg/ai/index.d.ts +10 -1
- package/dist-pkg/ai/index.js +13 -2
- package/dist-pkg/ai/mcp.js +4 -0
- package/dist-pkg/ai/session-pack.d.ts +8 -0
- package/dist-pkg/ai/session-pack.js +51 -1
- package/dist-pkg/ai/store.d.ts +25 -1
- package/dist-pkg/ai/store.js +89 -3
- package/dist-pkg/ai/summary.d.ts +88 -0
- package/dist-pkg/ai/summary.js +310 -1
- package/dist-pkg/build/manifest.d.ts +4 -2
- package/dist-pkg/build/manifest.js +32 -2
- package/dist-pkg/cli/cmd-ai.js +66 -0
- package/dist-pkg/cli/cmd-build.js +72 -26
- package/dist-pkg/cli/cmd-check.js +104 -11
- package/dist-pkg/cli/cmd-create.js +333 -7
- package/dist-pkg/cli/cmd-deploy.js +17 -3
- package/dist-pkg/cli/cmd-docs.d.ts +3 -1
- package/dist-pkg/cli/cmd-docs.js +5 -3
- package/dist-pkg/cli/cmd-start.js +8 -1
- package/dist-pkg/cli/cmd-upgrade.d.ts +3 -0
- package/dist-pkg/cli/cmd-upgrade.js +14 -2
- package/dist-pkg/cli/cmd-worker.d.ts +9 -0
- package/dist-pkg/cli/cmd-worker.js +78 -0
- package/dist-pkg/cli/framework-md.js +16 -4
- package/dist-pkg/cli/index.js +5 -0
- package/dist-pkg/runtime/app-config.d.ts +5 -0
- package/dist-pkg/runtime/app-config.js +26 -5
- package/dist-pkg/server/index.d.ts +2 -1
- package/dist-pkg/server/index.js +1 -0
- package/dist-pkg/server/jobs.d.ts +35 -1
- package/dist-pkg/server/jobs.js +226 -3
- package/dist-pkg/server/manifest.d.ts +30 -0
- package/dist-pkg/server/manifest.js +30 -1
- package/dist-pkg/server/redis-client.d.ts +9 -0
- package/dist-pkg/server/redis-client.js +4 -1
- package/dist-pkg/server/redis-job-queue.d.ts +2 -0
- package/dist-pkg/server/redis-job-queue.js +434 -16
- package/dist-pkg/server/worker-service.d.ts +33 -0
- package/dist-pkg/server/worker-service.js +135 -0
- package/dist-pkg/server-entry.d.ts +2 -1
- package/dist-pkg/server-entry.js +4 -0
- package/package.json +3 -2
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { join } from "node:path";
|
|
2
|
-
import { mkdir, rm, writeFile, readdir, stat, watch } from "node:fs/promises";
|
|
2
|
+
import { mkdir, rm, writeFile, readdir, stat, watch, readFile } from "node:fs/promises";
|
|
3
3
|
import { createRouter } from "../router/scanner.js";
|
|
4
4
|
import { buildClientBundles } from "../build/client.js";
|
|
5
5
|
import { configureClientBuildBackend } from "../build/client-backend.js";
|
|
6
6
|
import { initializeBuildBackends } from "../build/init.js";
|
|
7
7
|
import { generateStaticPages } from "../build/ssg.js";
|
|
8
|
-
import { createBuildManifest } from "../build/manifest.js";
|
|
8
|
+
import { createBuildManifest, createReleaseArtifact } from "../build/manifest.js";
|
|
9
9
|
import { createHash } from "node:crypto";
|
|
10
10
|
import { wrapHTML } from "../server/html-shell.js";
|
|
11
11
|
import { createProjectContext } from "../runtime/project.js";
|
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
resolveAIObservabilityConfig,
|
|
18
18
|
runWithAITrace
|
|
19
19
|
} from "../ai/index.js";
|
|
20
|
-
import { loadAppConfig, resolveAIConfig } from "../runtime/app-config.js";
|
|
20
|
+
import { loadAppConfig, resolveAIConfig, resolveAppMode } from "../runtime/app-config.js";
|
|
21
21
|
import { initializeCompilerBackends } from "../compiler/init.js";
|
|
22
22
|
async function hashFile(path) {
|
|
23
23
|
const content = await Bun.file(path).arrayBuffer();
|
|
@@ -41,7 +41,7 @@ export async function buildProject(options = {}) {
|
|
|
41
41
|
const { cwd, paths } = createProjectContext(options);
|
|
42
42
|
initializeCompilerBackends(options.env ?? process.env);
|
|
43
43
|
initializeBuildBackends(options.env ?? process.env);
|
|
44
|
-
const appConfig = await loadAppConfig(cwd);
|
|
44
|
+
const appConfig = await loadAppConfig(cwd), appMode = resolveAppMode(appConfig);
|
|
45
45
|
configureAIObservability(resolveAIConfig(cwd, appConfig, options.ai) ?? resolveAIObservabilityConfig(cwd));
|
|
46
46
|
try {
|
|
47
47
|
await runWithAITrace({
|
|
@@ -50,7 +50,7 @@ export async function buildProject(options = {}) {
|
|
|
50
50
|
source: "build",
|
|
51
51
|
message: "production build",
|
|
52
52
|
phase: "build",
|
|
53
|
-
data: { cwd, minify: options.minify ?? !0, sourcemap: options.sourcemap ?? !0 }
|
|
53
|
+
data: { cwd, appMode, minify: options.minify ?? !0, sourcemap: options.sourcemap ?? !0 }
|
|
54
54
|
}, async () => {
|
|
55
55
|
const startTime = performance.now();
|
|
56
56
|
console.log(`
|
|
@@ -58,50 +58,59 @@ export async function buildProject(options = {}) {
|
|
|
58
58
|
`);
|
|
59
59
|
await rm(paths.distDir, { recursive: !0, force: !0 });
|
|
60
60
|
await mkdir(paths.clientDir, { recursive: !0 });
|
|
61
|
-
|
|
61
|
+
if (appMode !== "frontend")
|
|
62
|
+
await mkdir(paths.serverDir, { recursive: !0 });
|
|
62
63
|
const routes = await createRouter(paths.routesDir);
|
|
63
|
-
console.log(` [1/5] Found ${routes.length} route(s)`);
|
|
64
|
+
console.log(` [1/5] Found ${routes.length} route(s) (${appMode})`);
|
|
64
65
|
await emitAIEvent({
|
|
65
66
|
kind: "build.phase",
|
|
66
67
|
severity: "info",
|
|
67
68
|
source: "build",
|
|
68
69
|
message: "routes scanned",
|
|
69
70
|
phase: "scan-routes",
|
|
70
|
-
data: { routes: routes.length }
|
|
71
|
+
data: { routes: routes.length, appMode }
|
|
71
72
|
});
|
|
72
|
-
const build = await buildClientBundles(routes, cwd, {
|
|
73
|
+
const shouldBuildClient = appMode !== "server", build = shouldBuildClient ? await buildClientBundles(routes, cwd, {
|
|
73
74
|
minify: options.minify ?? !0,
|
|
74
75
|
sourcemap: options.sourcemap ?? !0,
|
|
75
76
|
backend: options.clientBuildBackend ?? configureClientBuildBackend(options.env ?? process.env)
|
|
76
|
-
});
|
|
77
|
-
console.log(` [2/5] Client bundles built (${build.entryMap.size} entries)`);
|
|
77
|
+
}) : { entryMap: new Map };
|
|
78
|
+
console.log(` [2/5] ${shouldBuildClient ? `Client bundles built (${build.entryMap.size} entries)` : "Client bundle phase skipped for server mode"}`);
|
|
78
79
|
await emitAIEvent({
|
|
79
80
|
kind: "build.phase",
|
|
80
81
|
severity: "info",
|
|
81
82
|
source: "build",
|
|
82
|
-
message: "client bundles built",
|
|
83
|
+
message: shouldBuildClient ? "client bundles built" : "client bundle phase skipped",
|
|
83
84
|
phase: "client-bundles",
|
|
84
|
-
data: { entries: build.entryMap.size }
|
|
85
|
+
data: { entries: build.entryMap.size, skipped: !shouldBuildClient, appMode }
|
|
85
86
|
});
|
|
86
|
-
const clientSrc = join(paths.gorseeDir, "client"),
|
|
87
|
-
|
|
88
|
-
const
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
87
|
+
const clientSrc = join(paths.gorseeDir, "client"), hashMap = new Map;
|
|
88
|
+
if (shouldBuildClient) {
|
|
89
|
+
const clientFiles = await getAllFiles(clientSrc);
|
|
90
|
+
for (const file of clientFiles) {
|
|
91
|
+
const rel = file.slice(clientSrc.length + 1), preserveRuntimePath = rel.startsWith("chunks/") || rel.endsWith(".map"), hash = preserveRuntimePath ? null : await hashFile(file), ext = rel.lastIndexOf("."), hashed = preserveRuntimePath ? rel : ext > 0 ? `${rel.slice(0, ext)}.${hash}${rel.slice(ext)}` : `${rel}.${hash}`, dest = join(paths.clientDir, hashed);
|
|
92
|
+
await mkdir(join(dest, ".."), { recursive: !0 });
|
|
93
|
+
await Bun.write(dest, Bun.file(file));
|
|
94
|
+
hashMap.set(rel, hashed);
|
|
95
|
+
}
|
|
92
96
|
}
|
|
93
97
|
console.log(` [3/5] Assets hashed (${hashMap.size} files)`);
|
|
94
|
-
const manifest = await createBuildManifest(routes, build.entryMap, hashMap);
|
|
98
|
+
const manifest = await createBuildManifest(routes, build.entryMap, hashMap, [], appMode);
|
|
95
99
|
await writeFile(join(paths.distDir, "manifest.json"), JSON.stringify(manifest, null, 2));
|
|
96
|
-
const serverArtifacts = await buildServerArtifacts(cwd, paths.distDir);
|
|
97
|
-
console.log(
|
|
98
|
-
const ssgResult = await generateStaticPages({
|
|
100
|
+
const serverArtifacts = appMode === "frontend" ? { serverEntries: [] } : await buildServerArtifacts(cwd, paths.distDir);
|
|
101
|
+
console.log(` [4/5] ${appMode === "frontend" ? "Manifest generated for frontend mode" : "Manifest + server entries generated"}`);
|
|
102
|
+
const ssgResult = shouldBuildClient ? await generateStaticPages({
|
|
99
103
|
routesDir: paths.routesDir,
|
|
100
104
|
outDir: join(paths.distDir, "static"),
|
|
101
105
|
wrapHTML: (body, htmlOptions = {}) => wrapHTML(body, void 0, htmlOptions)
|
|
102
|
-
})
|
|
103
|
-
if (
|
|
104
|
-
await
|
|
106
|
+
}) : { pages: new Map, errors: [] };
|
|
107
|
+
if (appMode === "frontend")
|
|
108
|
+
await assertFrontendBuildContract(routes);
|
|
109
|
+
else if (appMode === "server")
|
|
110
|
+
await assertServerBuildContract(routes);
|
|
111
|
+
const finalManifest = ssgResult.pages.size > 0 ? await createBuildManifest(routes, build.entryMap, hashMap, ssgResult.pages.keys(), appMode) : manifest, releaseArtifact = createReleaseArtifact(finalManifest, hashMap.values(), serverArtifacts.serverEntries);
|
|
112
|
+
await writeFile(join(paths.distDir, "manifest.json"), JSON.stringify(finalManifest, null, 2));
|
|
113
|
+
await writeFile(join(paths.distDir, "release.json"), JSON.stringify(releaseArtifact, null, 2));
|
|
105
114
|
if (ssgResult.errors.length > 0) {
|
|
106
115
|
for (const err of ssgResult.errors)
|
|
107
116
|
console.error(` SSG error: ${err}`);
|
|
@@ -135,10 +144,12 @@ export async function buildProject(options = {}) {
|
|
|
135
144
|
phase: "summary",
|
|
136
145
|
data: {
|
|
137
146
|
artifact: "dist/",
|
|
147
|
+
appMode,
|
|
138
148
|
routes: routes.length,
|
|
139
149
|
entries: build.entryMap.size,
|
|
140
150
|
assets: hashMap.size,
|
|
141
151
|
serverEntries: serverArtifacts.serverEntries,
|
|
152
|
+
releaseArtifact: "release.json",
|
|
142
153
|
prerenderedPages: ssgResult.pages.size,
|
|
143
154
|
ssgErrors: ssgResult.errors.length,
|
|
144
155
|
clientKb: Number((totalSize / 1024).toFixed(1)),
|
|
@@ -196,3 +207,38 @@ export async function runBuild(args, options = {}) {
|
|
|
196
207
|
return watchBuildProject(options);
|
|
197
208
|
return buildProject(options);
|
|
198
209
|
}
|
|
210
|
+
async function assertFrontendBuildContract(routes) {
|
|
211
|
+
const apiRoutes = routes.filter((route) => route.filePath.includes("/api/")), pageRoutes = routes.filter((route) => !route.filePath.includes("/api/"));
|
|
212
|
+
if (pageRoutes.length === 0)
|
|
213
|
+
return;
|
|
214
|
+
const missingPrerender = [], serverOnlyViolations = [], errors = [];
|
|
215
|
+
if (apiRoutes.length > 0)
|
|
216
|
+
errors.push(`frontend mode does not allow API routes: ${apiRoutes.map((route) => route.path).join(", ")}`);
|
|
217
|
+
for (const route of pageRoutes) {
|
|
218
|
+
const source = await readFile(route.filePath, "utf-8");
|
|
219
|
+
if (!/export\s+const\s+prerender\s*=\s*true\b/.test(source))
|
|
220
|
+
missingPrerender.push(route.path);
|
|
221
|
+
if (source.includes('"gorsee/server"') || source.includes('"gorsee/auth"') || source.includes('"gorsee/db"') || source.includes("server(") || /\bexport\s+async\s+function\s+(load|action)\b/.test(source) || /\bexport\s+function\s+(GET|POST|PUT|PATCH|DELETE)\b/.test(source))
|
|
222
|
+
serverOnlyViolations.push(route.path);
|
|
223
|
+
}
|
|
224
|
+
if (missingPrerender.length > 0 || serverOnlyViolations.length > 0 || errors.length > 0) {
|
|
225
|
+
if (missingPrerender.length > 0)
|
|
226
|
+
errors.push(`frontend mode requires export const prerender = true for every page route: ${missingPrerender.join(", ")}`);
|
|
227
|
+
if (serverOnlyViolations.length > 0)
|
|
228
|
+
errors.push(`frontend mode page routes must stay browser-safe and avoid server exports/imports: ${serverOnlyViolations.join(", ")}`);
|
|
229
|
+
throw Error(errors.join(". "));
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
async function assertServerBuildContract(routes) {
|
|
233
|
+
const serviceRoutes = routes.filter((route) => !route.filePath.includes("/api/"));
|
|
234
|
+
if (serviceRoutes.length === 0)
|
|
235
|
+
return;
|
|
236
|
+
const errors = [];
|
|
237
|
+
for (const route of serviceRoutes) {
|
|
238
|
+
const source = await readFile(route.filePath, "utf-8");
|
|
239
|
+
if (source.includes('"gorsee/client"') || source.includes('"gorsee/forms"') || source.includes('"gorsee/routes"') || source.includes("export default function") || source.includes("export default async function"))
|
|
240
|
+
errors.push(route.path);
|
|
241
|
+
}
|
|
242
|
+
if (errors.length > 0)
|
|
243
|
+
throw Error(`server mode does not allow page/UI route behavior: ${errors.join(", ")}`);
|
|
244
|
+
}
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
emitAIDiagnostic,
|
|
12
12
|
emitAIEvent
|
|
13
13
|
} from "../ai/index.js";
|
|
14
|
-
import { loadAppConfig, resolveAIConfig, resolveRuntimeTopology } from "../runtime/app-config.js";
|
|
14
|
+
import { loadAppConfig, resolveAIConfig, resolveAppMode, resolveRuntimeTopology } from "../runtime/app-config.js";
|
|
15
15
|
const MAX_FILE_LINES = 500;
|
|
16
16
|
async function getAllTsFiles(dir) {
|
|
17
17
|
const files = [];
|
|
@@ -130,17 +130,18 @@ async function collectASTFacts(files, cwd) {
|
|
|
130
130
|
}
|
|
131
131
|
return facts;
|
|
132
132
|
}
|
|
133
|
-
async function checkProjectStructure(cwd) {
|
|
133
|
+
async function checkProjectStructure(cwd, appMode) {
|
|
134
134
|
const issues = [];
|
|
135
135
|
try {
|
|
136
136
|
await stat(join(cwd, "routes"));
|
|
137
137
|
} catch {
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
138
|
+
if (appMode !== "server")
|
|
139
|
+
issues.push({
|
|
140
|
+
code: "E902",
|
|
141
|
+
file: ".",
|
|
142
|
+
message: "Missing routes/ directory",
|
|
143
|
+
fix: "Create routes/ directory with at least routes/index.ts"
|
|
144
|
+
});
|
|
144
145
|
}
|
|
145
146
|
try {
|
|
146
147
|
await stat(join(cwd, "app.config.ts"));
|
|
@@ -241,6 +242,93 @@ async function checkDistributedContracts(cwd, files, astFacts) {
|
|
|
241
242
|
});
|
|
242
243
|
return issues;
|
|
243
244
|
}
|
|
245
|
+
async function checkAppModeContracts(cwd, files, astFacts, appMode) {
|
|
246
|
+
const issues = [];
|
|
247
|
+
if (appMode === "fullstack")
|
|
248
|
+
return issues;
|
|
249
|
+
for (const file of files) {
|
|
250
|
+
const rel = relative(cwd, file), facts = astFacts.get(file), source = await tryReadFile(file), imports = facts?.imports ?? [];
|
|
251
|
+
if (appMode === "frontend") {
|
|
252
|
+
const serverImport = imports.find((entry) => [
|
|
253
|
+
"gorsee/server",
|
|
254
|
+
"gorsee/auth",
|
|
255
|
+
"gorsee/db",
|
|
256
|
+
"gorsee/env",
|
|
257
|
+
"gorsee/log"
|
|
258
|
+
].includes(entry.specifier)) ?? (source && [
|
|
259
|
+
"gorsee/server",
|
|
260
|
+
"gorsee/auth",
|
|
261
|
+
"gorsee/db",
|
|
262
|
+
"gorsee/env",
|
|
263
|
+
"gorsee/log"
|
|
264
|
+
].find((specifier) => source.includes(`"${specifier}"`) || source.includes(`'${specifier}'`)) ? { specifier: [
|
|
265
|
+
"gorsee/server",
|
|
266
|
+
"gorsee/auth",
|
|
267
|
+
"gorsee/db",
|
|
268
|
+
"gorsee/env",
|
|
269
|
+
"gorsee/log"
|
|
270
|
+
].find((specifier) => source.includes(`"${specifier}"`) || source.includes(`'${specifier}'`)) } : void 0);
|
|
271
|
+
if (serverImport)
|
|
272
|
+
issues.push({
|
|
273
|
+
code: "W922",
|
|
274
|
+
file: rel,
|
|
275
|
+
message: `frontend app imports server-oriented surface "${serverImport.specifier}"`,
|
|
276
|
+
fix: 'Keep frontend mode browser-safe; move server logic to another service or switch app.mode to "fullstack"'
|
|
277
|
+
});
|
|
278
|
+
const hasApiRoute = rel.startsWith("routes/api/"), hasServerUsage = facts ? facts.hasServerCall || facts.hasRouteCacheCall || facts.hasCreateAuthCall : Boolean(source && (source.includes("server(") || source.includes("routeCache(") || source.includes("createAuth(") || source.includes('from "gorsee/server"')));
|
|
279
|
+
if (hasApiRoute || hasServerUsage)
|
|
280
|
+
issues.push({
|
|
281
|
+
code: "W923",
|
|
282
|
+
file: rel,
|
|
283
|
+
message: "frontend app contains server/runtime-only route behavior",
|
|
284
|
+
fix: 'Keep frontend mode to prerendered browser-safe routes only, or switch app.mode to "fullstack"'
|
|
285
|
+
});
|
|
286
|
+
if (rel.startsWith("routes/") && !rel.startsWith("routes/api/") && (rel.endsWith(".ts") || rel.endsWith(".tsx"))) {
|
|
287
|
+
const content = source ?? await readFile(file, "utf-8");
|
|
288
|
+
if (!/export\s+const\s+prerender\s*=\s*true\b/.test(content))
|
|
289
|
+
issues.push({
|
|
290
|
+
code: "W924",
|
|
291
|
+
file: rel,
|
|
292
|
+
message: "frontend mode page route is missing export const prerender = true",
|
|
293
|
+
fix: "Mark every frontend page route with `export const prerender = true` so the app stays static/browser-first"
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
if (appMode === "server") {
|
|
298
|
+
const clientImport = imports.find((entry) => [
|
|
299
|
+
"gorsee/client",
|
|
300
|
+
"gorsee/forms",
|
|
301
|
+
"gorsee/routes"
|
|
302
|
+
].includes(entry.specifier)) ?? (source && [
|
|
303
|
+
"gorsee/client",
|
|
304
|
+
"gorsee/forms",
|
|
305
|
+
"gorsee/routes"
|
|
306
|
+
].find((specifier) => source.includes(`"${specifier}"`) || source.includes(`'${specifier}'`)) ? { specifier: [
|
|
307
|
+
"gorsee/client",
|
|
308
|
+
"gorsee/forms",
|
|
309
|
+
"gorsee/routes"
|
|
310
|
+
].find((specifier) => source.includes(`"${specifier}"`) || source.includes(`'${specifier}'`)) } : void 0);
|
|
311
|
+
if (clientImport)
|
|
312
|
+
issues.push({
|
|
313
|
+
code: "W925",
|
|
314
|
+
file: rel,
|
|
315
|
+
message: `server app imports browser-oriented surface "${clientImport.specifier}"`,
|
|
316
|
+
fix: 'Keep server mode UI-free; remove browser imports or switch app.mode to "fullstack"'
|
|
317
|
+
});
|
|
318
|
+
if (rel.startsWith("routes/") && !rel.startsWith("routes/api/") && (rel.endsWith(".ts") || rel.endsWith(".tsx"))) {
|
|
319
|
+
const content = source ?? await readFile(file, "utf-8");
|
|
320
|
+
if (content.includes('from "gorsee/client"') || /\bexport\s+default\s+function\b/.test(content))
|
|
321
|
+
issues.push({
|
|
322
|
+
code: "W926",
|
|
323
|
+
file: rel,
|
|
324
|
+
message: "server mode route tree should stay API/service-oriented and avoid page UI exports",
|
|
325
|
+
fix: 'Move browser routes out of server mode, or switch app.mode to "fullstack"'
|
|
326
|
+
});
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
return issues;
|
|
331
|
+
}
|
|
244
332
|
function checkImportContracts(cwd, astFacts) {
|
|
245
333
|
const issues = [];
|
|
246
334
|
for (const [file, facts] of astFacts) {
|
|
@@ -485,7 +573,7 @@ async function tryReadFile(path) {
|
|
|
485
573
|
export async function checkProject(options = {}) {
|
|
486
574
|
const { cwd, paths } = createProjectContext(options);
|
|
487
575
|
initializeCompilerBackends(options.env ?? process.env);
|
|
488
|
-
const runTypeScript = options.runTypeScript ?? !0, strictSecurity = options.strictSecurity ?? !1, rewriteImports = options.rewriteImports ?? !1, rewriteLoaders = options.rewriteLoaders ?? !1, result = { errors: [], warnings: [], info: [] }, appConfig = await loadAppConfig(cwd);
|
|
576
|
+
const runTypeScript = options.runTypeScript ?? !0, strictSecurity = options.strictSecurity ?? !1, rewriteImports = options.rewriteImports ?? !1, rewriteLoaders = options.rewriteLoaders ?? !1, result = { errors: [], warnings: [], info: [] }, appConfig = await loadAppConfig(cwd), appMode = resolveAppMode(appConfig);
|
|
489
577
|
configureAIObservability(resolveAIConfig(cwd, appConfig, options.ai));
|
|
490
578
|
await emitAIEvent({
|
|
491
579
|
kind: "check.start",
|
|
@@ -493,7 +581,7 @@ export async function checkProject(options = {}) {
|
|
|
493
581
|
source: "check",
|
|
494
582
|
message: "project check started",
|
|
495
583
|
phase: "check",
|
|
496
|
-
data: { cwd, runTypeScript, strictSecurity, rewriteImports, rewriteLoaders }
|
|
584
|
+
data: { cwd, appMode, runTypeScript, strictSecurity, rewriteImports, rewriteLoaders }
|
|
497
585
|
});
|
|
498
586
|
if (rewriteImports) {
|
|
499
587
|
const rewrite = await rewriteCanonicalImportsInProject(cwd);
|
|
@@ -503,7 +591,7 @@ export async function checkProject(options = {}) {
|
|
|
503
591
|
const rewrite = await rewriteLegacyLoadersInProject(cwd);
|
|
504
592
|
result.info.push(rewrite.changedFiles.length > 0 ? `Rewrote legacy loader exports in ${rewrite.changedFiles.length} file(s)` : "Legacy loader rewrite found no changes");
|
|
505
593
|
}
|
|
506
|
-
const structIssues = await checkProjectStructure(cwd);
|
|
594
|
+
const structIssues = await checkProjectStructure(cwd, appMode);
|
|
507
595
|
for (const issue of structIssues)
|
|
508
596
|
if (issue.code.startsWith("E"))
|
|
509
597
|
result.errors.push(issue);
|
|
@@ -512,6 +600,7 @@ export async function checkProject(options = {}) {
|
|
|
512
600
|
try {
|
|
513
601
|
const routes = await createRouter(paths.routesDir);
|
|
514
602
|
result.info.push(`Found ${routes.length} route(s)`);
|
|
603
|
+
result.info.push(`App mode: ${appMode}`);
|
|
515
604
|
} catch {
|
|
516
605
|
result.info.push("Could not scan routes");
|
|
517
606
|
}
|
|
@@ -534,6 +623,9 @@ export async function checkProject(options = {}) {
|
|
|
534
623
|
const distributedIssues = await checkDistributedContracts(cwd, files, astFacts);
|
|
535
624
|
for (const issue of distributedIssues)
|
|
536
625
|
pushIssue(result, issue, strictSecurity);
|
|
626
|
+
const appModeIssues = await checkAppModeContracts(cwd, files, astFacts, appMode);
|
|
627
|
+
for (const issue of appModeIssues)
|
|
628
|
+
pushIssue(result, issue, strictSecurity);
|
|
537
629
|
const dependencyIssues = await checkDependencyPolicy(cwd);
|
|
538
630
|
for (const issue of dependencyIssues)
|
|
539
631
|
pushIssue(result, issue, strictSecurity);
|
|
@@ -591,6 +683,7 @@ ${details}`
|
|
|
591
683
|
errors: result.errors.length,
|
|
592
684
|
warnings: result.warnings.length,
|
|
593
685
|
info: result.info.length,
|
|
686
|
+
appMode,
|
|
594
687
|
strictSecurity,
|
|
595
688
|
runTypeScript,
|
|
596
689
|
rewriteImports,
|