swallowkit 1.1.2 → 2.0.0-alpha.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/README.ja.md +61 -7
- package/README.md +61 -7
- package/dist/cli/commands/add-auth.d.ts.map +1 -1
- package/dist/cli/commands/add-auth.js +66 -21
- package/dist/cli/commands/add-auth.js.map +1 -1
- package/dist/cli/commands/dev.d.ts +4 -1
- package/dist/cli/commands/dev.d.ts.map +1 -1
- package/dist/cli/commands/dev.js +108 -44
- package/dist/cli/commands/dev.js.map +1 -1
- package/dist/cli/commands/init.d.ts +6 -5
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +83 -39
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/scaffold.d.ts +1 -1
- package/dist/cli/commands/scaffold.d.ts.map +1 -1
- package/dist/cli/commands/scaffold.js +38 -15
- package/dist/cli/commands/scaffold.js.map +1 -1
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +6 -3
- package/dist/cli/index.js.map +1 -1
- package/dist/core/config.d.ts +2 -1
- package/dist/core/config.d.ts.map +1 -1
- package/dist/core/config.js +19 -0
- package/dist/core/config.js.map +1 -1
- package/dist/core/project/agent-instructions.d.ts +2 -1
- package/dist/core/project/agent-instructions.d.ts.map +1 -1
- package/dist/core/project/agent-instructions.js +12 -0
- package/dist/core/project/agent-instructions.js.map +1 -1
- package/dist/core/project/capabilities.d.ts +7 -0
- package/dist/core/project/capabilities.d.ts.map +1 -1
- package/dist/core/project/capabilities.js +7 -0
- package/dist/core/project/capabilities.js.map +1 -1
- package/dist/core/project/manifest.d.ts +3 -1
- package/dist/core/project/manifest.d.ts.map +1 -1
- package/dist/core/project/manifest.js +47 -25
- package/dist/core/project/manifest.js.map +1 -1
- package/dist/core/project/react-project.d.ts +26 -0
- package/dist/core/project/react-project.d.ts.map +1 -0
- package/dist/core/project/react-project.js +422 -0
- package/dist/core/project/react-project.js.map +1 -0
- package/dist/core/project/validation.d.ts.map +1 -1
- package/dist/core/project/validation.js +32 -10
- package/dist/core/project/validation.js.map +1 -1
- package/dist/core/scaffold/react-bff-generator.d.ts +10 -0
- package/dist/core/scaffold/react-bff-generator.d.ts.map +1 -0
- package/dist/core/scaffold/react-bff-generator.js +252 -0
- package/dist/core/scaffold/react-bff-generator.js.map +1 -0
- package/dist/core/scaffold/react-ui-generator.d.ts +6 -0
- package/dist/core/scaffold/react-ui-generator.d.ts.map +1 -0
- package/dist/core/scaffold/react-ui-generator.js +41 -0
- package/dist/core/scaffold/react-ui-generator.js.map +1 -0
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/dist/machine/index.js +2 -2
- package/dist/machine/index.js.map +1 -1
- package/dist/types/index.d.ts +4 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/utils/package-manager.d.ts +2 -2
- package/dist/utils/package-manager.d.ts.map +1 -1
- package/dist/utils/package-manager.js +5 -2
- package/dist/utils/package-manager.js.map +1 -1
- package/package.json +2 -2
- package/src/__tests__/agent-instructions.test.ts +1 -1
- package/src/__tests__/init.test.ts +29 -5
- package/src/__tests__/package-manager.test.ts +15 -0
- package/src/__tests__/react.test.ts +819 -0
- package/src/__tests__/release-metadata.test.ts +121 -0
- package/src/cli/commands/add-auth.ts +67 -23
- package/src/cli/commands/dev.ts +109 -46
- package/src/cli/commands/init.ts +75 -35
- package/src/cli/commands/scaffold.ts +40 -19
- package/src/cli/index.ts +6 -3
- package/src/core/config.ts +21 -1
- package/src/core/project/agent-instructions.ts +14 -1
- package/src/core/project/agent-templates/AGENTS.md +24 -9
- package/src/core/project/agent-templates/bff-routes.instructions.md +5 -3
- package/src/core/project/capabilities.ts +14 -0
- package/src/core/project/manifest.ts +52 -27
- package/src/core/project/react-project.ts +507 -0
- package/src/core/project/validation.ts +32 -10
- package/src/core/scaffold/react-bff-generator.ts +292 -0
- package/src/core/scaffold/react-ui-generator.ts +51 -0
- package/src/index.ts +3 -1
- package/src/machine/index.ts +2 -2
- package/src/types/index.ts +4 -0
- package/src/utils/package-manager.ts +6 -3
|
@@ -393,9 +393,9 @@ This is a full-stack application deployed on Azure with a TypeScript
|
|
|
393
393
|
frontend/BFF and an Azure Functions backend in {{backendLanguageLabel}}.
|
|
394
394
|
|
|
395
395
|
```text
|
|
396
|
-
Frontend (
|
|
396
|
+
Frontend ({{frontendLabel}})
|
|
397
397
|
↓
|
|
398
|
-
BFF (
|
|
398
|
+
BFF ({{bffLabel}})
|
|
399
399
|
↓
|
|
400
400
|
Azure Functions
|
|
401
401
|
↓
|
|
@@ -404,7 +404,7 @@ Azure Cosmos DB
|
|
|
404
404
|
|
|
405
405
|
### Core architecture rules
|
|
406
406
|
|
|
407
|
-
1.
|
|
407
|
+
1. {{bffLabel}} are a BFF/proxy layer. Do not place application business
|
|
408
408
|
logic or direct database access there.
|
|
409
409
|
2. Zod schemas under `shared/models/` are the application model source of truth.
|
|
410
410
|
3. Do not duplicate model definitions across layers.
|
|
@@ -415,6 +415,11 @@ Azure Cosmos DB
|
|
|
415
415
|
markers and boundaries.
|
|
416
416
|
7. Production access to Azure resources must follow the generated security
|
|
417
417
|
architecture; do not introduce hard-coded credentials or connection strings.
|
|
418
|
+
8. Never link standalone Functions to SWA. The same-origin BFF calls the
|
|
419
|
+
independent backend with server-side BACKEND_FUNCTIONS_BASE_URL and
|
|
420
|
+
BACKEND_FUNCTIONS_KEY. Never expose these values in browser bundles or VITE_*.
|
|
421
|
+
Managed Functions use HTTP triggers only; database access, non-HTTP triggers,
|
|
422
|
+
managed identity, and private networking belong to the standalone backend.
|
|
418
423
|
|
|
419
424
|
### Backend-specific rules
|
|
420
425
|
|
|
@@ -427,16 +432,13 @@ values for these fields.
|
|
|
427
432
|
|
|
428
433
|
```text
|
|
429
434
|
{{projectName}}/
|
|
430
|
-
|
|
431
|
-
│ ├── api/ # BFF routes
|
|
432
|
-
│ └── {model}/ # generated/custom UI
|
|
435
|
+
{{frontendStructure}}
|
|
433
436
|
├── functions/ # Azure Functions backend
|
|
434
437
|
{{functionsStructureLine}}
|
|
435
438
|
├── shared/
|
|
436
439
|
│ ├── models/ # Zod source-of-truth models
|
|
437
440
|
│ └── index.ts
|
|
438
|
-
├── lib/
|
|
439
|
-
│ └── api/
|
|
441
|
+
├── lib/ # auth, navigation, and shared application utilities
|
|
440
442
|
├── components/
|
|
441
443
|
├── infra/ # Bicep infrastructure
|
|
442
444
|
├── .swallowkit/ # SwallowKit project metadata and runbooks
|
|
@@ -470,13 +472,26 @@ same generated structure.
|
|
|
470
472
|
{{pm}} install
|
|
471
473
|
{{runCmd}} swallowkit dev
|
|
472
474
|
{{pm}} run build
|
|
473
|
-
{{pm}} run lint
|
|
475
|
+
{{pm}} run --if-present lint
|
|
474
476
|
{{runCmd}} swallowkit machine verify project
|
|
475
477
|
```
|
|
476
478
|
|
|
477
479
|
Always invoke SwallowKit using the package-runner convention generated for this
|
|
478
480
|
project. Do not arbitrarily mix package-manager invocation styles.
|
|
479
481
|
|
|
482
|
+
{{devGuidance}}
|
|
483
|
+
|
|
484
|
+
Check for an already-running Cosmos DB Emulator before database tests. If it is
|
|
485
|
+
unavailable, report that prerequisite; do not start/restart it or change global
|
|
486
|
+
tools, TLS trust, or machine settings without explicit permission. Test against
|
|
487
|
+
an isolated database and ports, never reset user data, and stop only processes
|
|
488
|
+
you started. `dev --seed-env` replaces data, so inspect its target first.
|
|
489
|
+
|
|
490
|
+
Build and run `verify project`, then exercise UI, CRUD, error/validation paths,
|
|
491
|
+
and configured authentication through the same-origin BFF. A passing typecheck
|
|
492
|
+
or server readiness probe alone is not an end-to-end verification. Report
|
|
493
|
+
unverified cloud deployment or unavailable local prerequisites explicitly.
|
|
494
|
+
|
|
480
495
|
## Final Rules
|
|
481
496
|
|
|
482
497
|
Do not:
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
applyTo: "
|
|
2
|
+
applyTo: "{{bffGlob}}"
|
|
3
3
|
---
|
|
4
4
|
|
|
5
5
|
# BFF API Routes — Rules
|
|
@@ -7,10 +7,12 @@ applyTo: "app/api/**"
|
|
|
7
7
|
The root `AGENTS.md` is the canonical contract. Inspect the current
|
|
8
8
|
responsibility boundary before editing files in this layer.
|
|
9
9
|
|
|
10
|
-
- `
|
|
10
|
+
- `{{bffPath}}/` is a BFF/proxy layer. Never place business logic, database access,
|
|
11
11
|
or direct Cosmos DB calls here.
|
|
12
|
-
- Use `callFunction()` from
|
|
12
|
+
- Use `callFunction()` from `{{helperImport}}` to forward requests to
|
|
13
13
|
Azure Functions.
|
|
14
|
+
- Keep credentials request-local. Never put the backend URL/key in client
|
|
15
|
+
code or VITE_* variables. Do not link standalone Functions to SWA.
|
|
14
16
|
- Input/output validation may use schemas imported from `@{{projectName}}/shared`.
|
|
15
17
|
- Never directly edit a route reported as deterministic. Change its source of
|
|
16
18
|
truth and use MCP-first plan/apply, with the machine interface as fallback.
|
|
@@ -27,6 +27,13 @@ export interface CapabilityAuthProvider {
|
|
|
27
27
|
export interface CapabilitiesContract {
|
|
28
28
|
contractVersion: number;
|
|
29
29
|
swallowkitVersion: string;
|
|
30
|
+
frontends: {
|
|
31
|
+
supported: string[];
|
|
32
|
+
default: string;
|
|
33
|
+
configuration: string;
|
|
34
|
+
reactArchitecture: string;
|
|
35
|
+
development: string;
|
|
36
|
+
};
|
|
30
37
|
modelDeclarations: CapabilityModelDeclaration[];
|
|
31
38
|
authentication: {
|
|
32
39
|
correctWorkflow: string[];
|
|
@@ -64,6 +71,13 @@ export function inspectCapabilities(): CapabilitiesContract {
|
|
|
64
71
|
return {
|
|
65
72
|
contractVersion: 1,
|
|
66
73
|
swallowkitVersion: getSwallowKitVersion(),
|
|
74
|
+
frontends: {
|
|
75
|
+
supported: ["nextjs", "react"],
|
|
76
|
+
default: "nextjs",
|
|
77
|
+
configuration: "init --frontend nextjs|react; stored as frontend.framework in swallowkit.config.js. Missing settings preserve Next.js.",
|
|
78
|
+
reactArchitecture: "React/Vite SPA on SWA -> HTTP-only SWA managed Functions BFF (bff/) -> standalone Functions (functions/). Never link standalone Functions to SWA. Backend keys stay server-side.",
|
|
79
|
+
development: "React dev runs Vite:3000, BFF:7073, Functions:7071 and SWA CLI:4280; use the SWA port for same-origin APIs and authentication. Build/verify include BFF typechecking.",
|
|
80
|
+
},
|
|
67
81
|
modelDeclarations: [
|
|
68
82
|
{
|
|
69
83
|
name: "schema",
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import * as fs from "fs";
|
|
2
2
|
import * as path from "path";
|
|
3
|
-
import { getBackendLanguage, getFullConfig, normalizeAuthConfig, validateConfig } from "../config";
|
|
3
|
+
import { getBackendLanguage, getFrontendFramework, getFullConfig, normalizeAuthConfig, validateConfig } from "../config";
|
|
4
4
|
import { getAllModels, toCamelCase, toKebabCase } from "../scaffold/model-parser";
|
|
5
|
-
import { AuthConfig, BackendLanguage, ConnectorDefinition, ModelAuthPolicy, ModelConnectorConfig } from "../../types";
|
|
5
|
+
import { AuthConfig, BackendLanguage, FrontendFramework, ConnectorDefinition, ModelAuthPolicy, ModelConnectorConfig } from "../../types";
|
|
6
6
|
import { captureConsoleMessages, withWorkingDirectory } from "../operations/runtime";
|
|
7
7
|
|
|
8
8
|
const CONFIG_CANDIDATES = [
|
|
@@ -69,6 +69,7 @@ export interface ProjectManifestArtifacts {
|
|
|
69
69
|
|
|
70
70
|
export interface ProjectManifestArchitecture {
|
|
71
71
|
pattern: string;
|
|
72
|
+
frontendFramework?: FrontendFramework;
|
|
72
73
|
backendLanguage: BackendLanguage;
|
|
73
74
|
layerBoundaries: string[];
|
|
74
75
|
hasSharedWorkspace: boolean;
|
|
@@ -81,6 +82,7 @@ export interface ProjectManifest {
|
|
|
81
82
|
generatedAt: string;
|
|
82
83
|
configPath: string | null;
|
|
83
84
|
backendLanguage: BackendLanguage;
|
|
85
|
+
frontendFramework?: FrontendFramework;
|
|
84
86
|
configValidation: {
|
|
85
87
|
valid: boolean;
|
|
86
88
|
errors: string[];
|
|
@@ -115,7 +117,10 @@ function relativeProjectPath(projectRoot: string, targetPath: string): string {
|
|
|
115
117
|
return path.relative(projectRoot, targetPath).replace(/\\/g, "/");
|
|
116
118
|
}
|
|
117
119
|
|
|
118
|
-
function buildModules(projectRoot: string): ProjectManifestModule[] {
|
|
120
|
+
function buildModules(projectRoot: string, frontend: FrontendFramework): ProjectManifestModule[] {
|
|
121
|
+
const bffRoot = frontend === "react" ? "bff" : "app/api";
|
|
122
|
+
const uiRoot = frontend === "react" ? "src" : "app";
|
|
123
|
+
const authRoot = frontend === "react" ? "bff/src/auth" : "app/api/auth";
|
|
119
124
|
const candidates: ProjectManifestModule[] = [
|
|
120
125
|
{
|
|
121
126
|
name: "shared-models",
|
|
@@ -126,8 +131,8 @@ function buildModules(projectRoot: string): ProjectManifestModule[] {
|
|
|
126
131
|
{
|
|
127
132
|
name: "bff",
|
|
128
133
|
kind: "bff",
|
|
129
|
-
rootPath:
|
|
130
|
-
exists: fs.existsSync(path.join(projectRoot,
|
|
134
|
+
rootPath: bffRoot,
|
|
135
|
+
exists: fs.existsSync(path.join(projectRoot, bffRoot)),
|
|
131
136
|
},
|
|
132
137
|
{
|
|
133
138
|
name: "functions",
|
|
@@ -138,8 +143,8 @@ function buildModules(projectRoot: string): ProjectManifestModule[] {
|
|
|
138
143
|
{
|
|
139
144
|
name: "ui",
|
|
140
145
|
kind: "ui",
|
|
141
|
-
rootPath:
|
|
142
|
-
exists: fs.existsSync(path.join(projectRoot,
|
|
146
|
+
rootPath: uiRoot,
|
|
147
|
+
exists: fs.existsSync(path.join(projectRoot, uiRoot)),
|
|
143
148
|
},
|
|
144
149
|
{
|
|
145
150
|
name: "infrastructure",
|
|
@@ -150,21 +155,21 @@ function buildModules(projectRoot: string): ProjectManifestModule[] {
|
|
|
150
155
|
{
|
|
151
156
|
name: "auth",
|
|
152
157
|
kind: "auth",
|
|
153
|
-
rootPath:
|
|
154
|
-
exists: fs.existsSync(path.join(projectRoot,
|
|
158
|
+
rootPath: authRoot,
|
|
159
|
+
exists: fs.existsSync(path.join(projectRoot, authRoot)),
|
|
155
160
|
},
|
|
156
161
|
];
|
|
157
162
|
|
|
158
163
|
return candidates;
|
|
159
164
|
}
|
|
160
165
|
|
|
161
|
-
function buildArtifacts(projectRoot: string): ProjectManifestArtifacts {
|
|
166
|
+
function buildArtifacts(projectRoot: string, frontend: FrontendFramework): ProjectManifestArtifacts {
|
|
162
167
|
const openApiDir = path.join(projectRoot, "functions", "openapi");
|
|
163
168
|
const generatedDir = path.join(projectRoot, "functions", "generated");
|
|
164
169
|
|
|
165
170
|
return {
|
|
166
|
-
callFunctionHelperPath: "lib/api/call-function.ts",
|
|
167
|
-
callFunctionHelperExists: fs.existsSync(path.join(projectRoot, "lib", "api", "call-function.ts")),
|
|
171
|
+
callFunctionHelperPath: frontend === "react" ? "bff/src/lib/call-function.ts" : "lib/api/call-function.ts",
|
|
172
|
+
callFunctionHelperExists: fs.existsSync(path.join(projectRoot, ...(frontend === "react" ? ["bff", "src", "lib", "call-function.ts"] : ["lib", "api", "call-function.ts"]))),
|
|
168
173
|
openApiSpecs: fs.existsSync(openApiDir)
|
|
169
174
|
? fs.readdirSync(openApiDir)
|
|
170
175
|
.filter((entry) => entry.endsWith(".json"))
|
|
@@ -178,8 +183,8 @@ function buildArtifacts(projectRoot: string): ProjectManifestArtifacts {
|
|
|
178
183
|
: [],
|
|
179
184
|
proxyPath: "proxy.ts",
|
|
180
185
|
proxyExists: fs.existsSync(path.join(projectRoot, "proxy.ts")),
|
|
181
|
-
loginPagePath: "app/login/page.tsx",
|
|
182
|
-
loginPageExists: fs.existsSync(path.join(projectRoot, "app", "login", "page.tsx")),
|
|
186
|
+
loginPagePath: frontend === "react" ? "src/pages/login.tsx" : "app/login/page.tsx",
|
|
187
|
+
loginPageExists: fs.existsSync(path.join(projectRoot, ...(frontend === "react" ? ["src", "pages", "login.tsx"] : ["app", "login", "page.tsx"]))),
|
|
183
188
|
authContextPath: "lib/auth/auth-context.tsx",
|
|
184
189
|
authContextExists: fs.existsSync(path.join(projectRoot, "lib", "auth", "auth-context.tsx")),
|
|
185
190
|
};
|
|
@@ -188,7 +193,8 @@ function buildArtifacts(projectRoot: string): ProjectManifestArtifacts {
|
|
|
188
193
|
function buildEntityRoutes(
|
|
189
194
|
projectRoot: string,
|
|
190
195
|
backendLanguage: BackendLanguage,
|
|
191
|
-
entity: ProjectManifestEntity
|
|
196
|
+
entity: ProjectManifestEntity,
|
|
197
|
+
frontend: FrontendFramework
|
|
192
198
|
): ProjectManifestRoute[] {
|
|
193
199
|
const modelCamel = toCamelCase(entity.name);
|
|
194
200
|
const modelKebab = toKebabCase(entity.name);
|
|
@@ -229,8 +235,10 @@ function buildEntityRoutes(
|
|
|
229
235
|
entityName: entity.name,
|
|
230
236
|
methods: listMethods,
|
|
231
237
|
publicPath: `/api/${modelCamel}`,
|
|
232
|
-
filePath: `app/api/${modelCamel}/route.ts`,
|
|
233
|
-
exists:
|
|
238
|
+
filePath: frontend === "react" ? `bff/src/${modelCamel}/index.ts` : `app/api/${modelCamel}/route.ts`,
|
|
239
|
+
exists: frontend === "react"
|
|
240
|
+
? fs.existsSync(path.join(projectRoot, "bff", "src", modelCamel, "index.ts")) && fs.existsSync(path.join(projectRoot, "bff", modelCamel, "function.json"))
|
|
241
|
+
: fs.existsSync(path.join(projectRoot, "app", "api", modelCamel, "route.ts")),
|
|
234
242
|
},
|
|
235
243
|
{
|
|
236
244
|
name: `${entity.name}-bff-detail`,
|
|
@@ -239,8 +247,10 @@ function buildEntityRoutes(
|
|
|
239
247
|
entityName: entity.name,
|
|
240
248
|
methods: detailMethods,
|
|
241
249
|
publicPath: `/api/${modelCamel}/{id}`,
|
|
242
|
-
filePath: `app/api/${modelCamel}/[id]/route.ts`,
|
|
243
|
-
exists:
|
|
250
|
+
filePath: frontend === "react" ? `bff/src/${modelCamel}/index.ts` : `app/api/${modelCamel}/[id]/route.ts`,
|
|
251
|
+
exists: frontend === "react"
|
|
252
|
+
? fs.existsSync(path.join(projectRoot, "bff", "src", modelCamel, "index.ts")) && fs.existsSync(path.join(projectRoot, "bff", modelCamel, "function.json"))
|
|
253
|
+
: fs.existsSync(path.join(projectRoot, "app", "api", modelCamel, "[id]", "route.ts")),
|
|
244
254
|
},
|
|
245
255
|
{
|
|
246
256
|
name: `${entity.name}-functions`,
|
|
@@ -255,7 +265,18 @@ function buildEntityRoutes(
|
|
|
255
265
|
];
|
|
256
266
|
}
|
|
257
267
|
|
|
258
|
-
function buildSystemRoutes(projectRoot: string): ProjectManifestRoute[] {
|
|
268
|
+
function buildSystemRoutes(projectRoot: string, frontend: FrontendFramework, auth?: AuthConfig): ProjectManifestRoute[] {
|
|
269
|
+
if (frontend === "react") {
|
|
270
|
+
const providers = Object.values(normalizeAuthConfig(auth)?.schemes ?? {}).map(scheme => scheme.provider);
|
|
271
|
+
return ["login", "logout", "me"].map(action => ({
|
|
272
|
+
name: `auth-${action}`, kind: "system", surface: "bff",
|
|
273
|
+
methods: [action === "me" ? "GET" : "POST"], publicPath: `/api/auth/${action}`,
|
|
274
|
+
filePath: "bff/src/auth/index.ts",
|
|
275
|
+
exists: (providers.includes("custom-jwt") || (action === "me" && providers.includes("external-token"))) &&
|
|
276
|
+
fs.existsSync(path.join(projectRoot, "bff", "src", "auth", "index.ts")) &&
|
|
277
|
+
fs.existsSync(path.join(projectRoot, "bff", "auth", "function.json")),
|
|
278
|
+
}));
|
|
279
|
+
}
|
|
259
280
|
return [
|
|
260
281
|
{
|
|
261
282
|
name: "auth-login",
|
|
@@ -296,6 +317,7 @@ export async function buildProjectManifest(projectRoot: string = process.cwd()):
|
|
|
296
317
|
return withWorkingDirectory(projectRoot, async () => {
|
|
297
318
|
const configPath = resolveConfigPath(projectRoot);
|
|
298
319
|
const backendLanguage = getBackendLanguage(configPath || undefined);
|
|
320
|
+
const frontendFramework = getFrontendFramework(configPath || undefined);
|
|
299
321
|
const config = getFullConfig(configPath || undefined);
|
|
300
322
|
const configValidation = validateConfig(config);
|
|
301
323
|
const { result: entities, messages } = await captureConsoleMessages(async () => {
|
|
@@ -327,8 +349,8 @@ export async function buildProjectManifest(projectRoot: string = process.cwd()):
|
|
|
327
349
|
);
|
|
328
350
|
|
|
329
351
|
const routes = [
|
|
330
|
-
...entities.flatMap((entity) => buildEntityRoutes(projectRoot, backendLanguage, entity)),
|
|
331
|
-
...buildSystemRoutes(projectRoot),
|
|
352
|
+
...entities.flatMap((entity) => buildEntityRoutes(projectRoot, backendLanguage, entity, frontendFramework)),
|
|
353
|
+
...buildSystemRoutes(projectRoot, frontendFramework, config.auth),
|
|
332
354
|
].sort((left, right) => left.name.localeCompare(right.name));
|
|
333
355
|
|
|
334
356
|
const manifest: ProjectManifest = {
|
|
@@ -336,6 +358,7 @@ export async function buildProjectManifest(projectRoot: string = process.cwd()):
|
|
|
336
358
|
generatedAt: new Date().toISOString(),
|
|
337
359
|
configPath,
|
|
338
360
|
backendLanguage,
|
|
361
|
+
frontendFramework,
|
|
339
362
|
configValidation,
|
|
340
363
|
connectors: Object.entries(config.connectors || {})
|
|
341
364
|
.map(([name, definition]) => ({ name, definition }))
|
|
@@ -343,16 +366,18 @@ export async function buildProjectManifest(projectRoot: string = process.cwd()):
|
|
|
343
366
|
auth: normalizeAuthConfig(config.auth) || null,
|
|
344
367
|
entities: entities.sort((left, right) => left.name.localeCompare(right.name)),
|
|
345
368
|
routes,
|
|
346
|
-
modules: buildModules(projectRoot),
|
|
347
|
-
artifacts: buildArtifacts(projectRoot),
|
|
369
|
+
modules: buildModules(projectRoot, frontendFramework),
|
|
370
|
+
artifacts: buildArtifacts(projectRoot, frontendFramework),
|
|
348
371
|
architecture: {
|
|
349
|
-
pattern: "Next.js BFF + Azure Functions + shared Zod models",
|
|
372
|
+
pattern: frontendFramework === "react" ? "React SPA + SWA managed Functions BFF + standalone Azure Functions + shared Zod models" : "Next.js BFF + Azure Functions + shared Zod models",
|
|
373
|
+
frontendFramework,
|
|
350
374
|
backendLanguage,
|
|
351
375
|
layerBoundaries: [
|
|
352
376
|
"shared/models -> schema source of truth",
|
|
353
|
-
"app/api -> BFF layer only
|
|
377
|
+
`${frontendFramework === "react" ? "bff" : "app/api"} -> BFF layer only`,
|
|
354
378
|
"functions -> backend logic and data access",
|
|
355
|
-
"app -> UI and pages
|
|
379
|
+
`${frontendFramework === "react" ? "src" : "app"} -> UI and pages`,
|
|
380
|
+
"SWA and standalone Functions are not linked; backend credentials stay in the BFF",
|
|
356
381
|
],
|
|
357
382
|
hasSharedWorkspace: fs.existsSync(path.join(projectRoot, "shared", "package.json")),
|
|
358
383
|
hasConnectors: Object.keys(config.connectors || {}).length > 0,
|