swallowkit 1.1.2 → 2.0.0-alpha.10

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.
Files changed (262) hide show
  1. package/README.ja.md +61 -7
  2. package/README.md +61 -7
  3. package/dist/cli/commands/add-auth.d.ts.map +1 -1
  4. package/dist/cli/commands/add-auth.js +103 -27
  5. package/dist/cli/commands/add-auth.js.map +1 -1
  6. package/dist/cli/commands/configure-mcp.d.ts +12 -0
  7. package/dist/cli/commands/configure-mcp.d.ts.map +1 -0
  8. package/dist/cli/commands/configure-mcp.js +42 -0
  9. package/dist/cli/commands/configure-mcp.js.map +1 -0
  10. package/dist/cli/commands/dev.d.ts +5 -2
  11. package/dist/cli/commands/dev.d.ts.map +1 -1
  12. package/dist/cli/commands/dev.js +143 -67
  13. package/dist/cli/commands/dev.js.map +1 -1
  14. package/dist/cli/commands/init.d.ts +14 -7
  15. package/dist/cli/commands/init.d.ts.map +1 -1
  16. package/dist/cli/commands/init.js +149 -170
  17. package/dist/cli/commands/init.js.map +1 -1
  18. package/dist/cli/commands/migrations.d.ts.map +1 -1
  19. package/dist/cli/commands/migrations.js +25 -0
  20. package/dist/cli/commands/migrations.js.map +1 -1
  21. package/dist/cli/commands/provision.d.ts +5 -0
  22. package/dist/cli/commands/provision.d.ts.map +1 -1
  23. package/dist/cli/commands/provision.js +278 -55
  24. package/dist/cli/commands/provision.js.map +1 -1
  25. package/dist/cli/commands/scaffold.d.ts +5 -1
  26. package/dist/cli/commands/scaffold.d.ts.map +1 -1
  27. package/dist/cli/commands/scaffold.js +123 -18
  28. package/dist/cli/commands/scaffold.js.map +1 -1
  29. package/dist/cli/index.d.ts +2 -0
  30. package/dist/cli/index.d.ts.map +1 -1
  31. package/dist/cli/index.js +49 -8
  32. package/dist/cli/index.js.map +1 -1
  33. package/dist/core/config.d.ts +2 -1
  34. package/dist/core/config.d.ts.map +1 -1
  35. package/dist/core/config.js +19 -0
  36. package/dist/core/config.js.map +1 -1
  37. package/dist/core/operations/create-model.d.ts +2 -0
  38. package/dist/core/operations/create-model.d.ts.map +1 -1
  39. package/dist/core/operations/create-model.js +60 -8
  40. package/dist/core/operations/create-model.js.map +1 -1
  41. package/dist/core/operations/migration-generator.d.ts.map +1 -1
  42. package/dist/core/operations/migration-generator.js +12 -1
  43. package/dist/core/operations/migration-generator.js.map +1 -1
  44. package/dist/core/operations/model-migration.d.ts +22 -0
  45. package/dist/core/operations/model-migration.d.ts.map +1 -0
  46. package/dist/core/operations/model-migration.js +36 -0
  47. package/dist/core/operations/model-migration.js.map +1 -0
  48. package/dist/core/operations/provision-deployment.d.ts +52 -0
  49. package/dist/core/operations/provision-deployment.d.ts.map +1 -0
  50. package/dist/core/operations/provision-deployment.js +164 -0
  51. package/dist/core/operations/provision-deployment.js.map +1 -0
  52. package/dist/core/operations/provision-operations.d.ts +62 -6
  53. package/dist/core/operations/provision-operations.d.ts.map +1 -1
  54. package/dist/core/operations/provision-operations.js +653 -115
  55. package/dist/core/operations/provision-operations.js.map +1 -1
  56. package/dist/core/operations/scaffold-apply.d.ts +1 -0
  57. package/dist/core/operations/scaffold-apply.d.ts.map +1 -1
  58. package/dist/core/operations/scaffold-apply.js +1 -0
  59. package/dist/core/operations/scaffold-apply.js.map +1 -1
  60. package/dist/core/operations/scaffold-machine.d.ts +1 -0
  61. package/dist/core/operations/scaffold-machine.d.ts.map +1 -1
  62. package/dist/core/operations/scaffold-machine.js.map +1 -1
  63. package/dist/core/operations/scaffold-plan.d.ts +2 -0
  64. package/dist/core/operations/scaffold-plan.d.ts.map +1 -1
  65. package/dist/core/operations/scaffold-plan.js +3 -1
  66. package/dist/core/operations/scaffold-plan.js.map +1 -1
  67. package/dist/core/project/agent-instructions.d.ts +2 -1
  68. package/dist/core/project/agent-instructions.d.ts.map +1 -1
  69. package/dist/core/project/agent-instructions.js +15 -0
  70. package/dist/core/project/agent-instructions.js.map +1 -1
  71. package/dist/core/project/boundaries.d.ts +5 -2
  72. package/dist/core/project/boundaries.d.ts.map +1 -1
  73. package/dist/core/project/boundaries.js +51 -20
  74. package/dist/core/project/boundaries.js.map +1 -1
  75. package/dist/core/project/capabilities.d.ts +17 -0
  76. package/dist/core/project/capabilities.d.ts.map +1 -1
  77. package/dist/core/project/capabilities.js +45 -6
  78. package/dist/core/project/capabilities.js.map +1 -1
  79. package/dist/core/project/home-page.d.ts +4 -0
  80. package/dist/core/project/home-page.d.ts.map +1 -0
  81. package/dist/core/project/home-page.js +113 -0
  82. package/dist/core/project/home-page.js.map +1 -0
  83. package/dist/core/project/manifest.d.ts +3 -1
  84. package/dist/core/project/manifest.d.ts.map +1 -1
  85. package/dist/core/project/manifest.js +47 -25
  86. package/dist/core/project/manifest.js.map +1 -1
  87. package/dist/core/project/mcp-config.d.ts +26 -0
  88. package/dist/core/project/mcp-config.d.ts.map +1 -0
  89. package/dist/core/project/mcp-config.js +117 -0
  90. package/dist/core/project/mcp-config.js.map +1 -0
  91. package/dist/core/project/react-project.d.ts +26 -0
  92. package/dist/core/project/react-project.d.ts.map +1 -0
  93. package/dist/core/project/react-project.js +443 -0
  94. package/dist/core/project/react-project.js.map +1 -0
  95. package/dist/core/project/state.d.ts +7 -0
  96. package/dist/core/project/state.d.ts.map +1 -1
  97. package/dist/core/project/state.js +86 -0
  98. package/dist/core/project/state.js.map +1 -1
  99. package/dist/core/project/validation.d.ts.map +1 -1
  100. package/dist/core/project/validation.js +32 -10
  101. package/dist/core/project/validation.js.map +1 -1
  102. package/dist/core/project/workflows.d.ts.map +1 -1
  103. package/dist/core/project/workflows.js +53 -7
  104. package/dist/core/project/workflows.js.map +1 -1
  105. package/dist/core/scaffold/auth-generator.d.ts.map +1 -1
  106. package/dist/core/scaffold/auth-generator.js +26 -27
  107. package/dist/core/scaffold/auth-generator.js.map +1 -1
  108. package/dist/core/scaffold/model-parser.d.ts +23 -0
  109. package/dist/core/scaffold/model-parser.d.ts.map +1 -1
  110. package/dist/core/scaffold/model-parser.js +407 -137
  111. package/dist/core/scaffold/model-parser.js.map +1 -1
  112. package/dist/core/scaffold/native-schema-generator.d.ts +13 -0
  113. package/dist/core/scaffold/native-schema-generator.d.ts.map +1 -1
  114. package/dist/core/scaffold/native-schema-generator.js +294 -91
  115. package/dist/core/scaffold/native-schema-generator.js.map +1 -1
  116. package/dist/core/scaffold/openapi-generator.d.ts +5 -0
  117. package/dist/core/scaffold/openapi-generator.d.ts.map +1 -1
  118. package/dist/core/scaffold/openapi-generator.js +53 -3
  119. package/dist/core/scaffold/openapi-generator.js.map +1 -1
  120. package/dist/core/scaffold/react-bff-generator.d.ts +10 -0
  121. package/dist/core/scaffold/react-bff-generator.d.ts.map +1 -0
  122. package/dist/core/scaffold/react-bff-generator.js +252 -0
  123. package/dist/core/scaffold/react-bff-generator.js.map +1 -0
  124. package/dist/core/scaffold/react-ui-generator.d.ts +6 -0
  125. package/dist/core/scaffold/react-ui-generator.d.ts.map +1 -0
  126. package/dist/core/scaffold/react-ui-generator.js +41 -0
  127. package/dist/core/scaffold/react-ui-generator.js.map +1 -0
  128. package/dist/core/scaffold/ui-generator.d.ts +0 -3
  129. package/dist/core/scaffold/ui-generator.d.ts.map +1 -1
  130. package/dist/core/scaffold/ui-generator.js +68 -7
  131. package/dist/core/scaffold/ui-generator.js.map +1 -1
  132. package/dist/core/verify/index.d.ts +4 -3
  133. package/dist/core/verify/index.d.ts.map +1 -1
  134. package/dist/core/verify/index.js +122 -5
  135. package/dist/core/verify/index.js.map +1 -1
  136. package/dist/index.d.ts +3 -3
  137. package/dist/index.d.ts.map +1 -1
  138. package/dist/index.js +3 -2
  139. package/dist/index.js.map +1 -1
  140. package/dist/machine/contracts.d.ts +1 -0
  141. package/dist/machine/contracts.d.ts.map +1 -1
  142. package/dist/machine/errors.d.ts +3 -2
  143. package/dist/machine/errors.d.ts.map +1 -1
  144. package/dist/machine/errors.js +2 -1
  145. package/dist/machine/errors.js.map +1 -1
  146. package/dist/machine/index.d.ts.map +1 -1
  147. package/dist/machine/index.js +61 -30
  148. package/dist/machine/index.js.map +1 -1
  149. package/dist/mcp/index.d.ts +6 -4
  150. package/dist/mcp/index.d.ts.map +1 -1
  151. package/dist/mcp/index.js +210 -25
  152. package/dist/mcp/index.js.map +1 -1
  153. package/dist/mcp/version-selection.d.ts +55 -0
  154. package/dist/mcp/version-selection.d.ts.map +1 -0
  155. package/dist/mcp/version-selection.js +152 -0
  156. package/dist/mcp/version-selection.js.map +1 -0
  157. package/dist/types/index.d.ts +4 -0
  158. package/dist/types/index.d.ts.map +1 -1
  159. package/dist/utils/azure-cli.d.ts +56 -0
  160. package/dist/utils/azure-cli.d.ts.map +1 -0
  161. package/dist/utils/azure-cli.js +326 -0
  162. package/dist/utils/azure-cli.js.map +1 -0
  163. package/dist/utils/azure-diagnostics.d.ts +16 -0
  164. package/dist/utils/azure-diagnostics.d.ts.map +1 -0
  165. package/dist/utils/azure-diagnostics.js +68 -0
  166. package/dist/utils/azure-diagnostics.js.map +1 -0
  167. package/dist/utils/package-manager.d.ts +2 -2
  168. package/dist/utils/package-manager.d.ts.map +1 -1
  169. package/dist/utils/package-manager.js +6 -3
  170. package/dist/utils/package-manager.js.map +1 -1
  171. package/dist/utils/python-uv.d.ts +5 -7
  172. package/dist/utils/python-uv.d.ts.map +1 -1
  173. package/dist/utils/python-uv.js +50 -24
  174. package/dist/utils/python-uv.js.map +1 -1
  175. package/dist/utils/react-dev.d.ts +4 -0
  176. package/dist/utils/react-dev.d.ts.map +1 -0
  177. package/dist/utils/react-dev.js +35 -0
  178. package/dist/utils/react-dev.js.map +1 -0
  179. package/dist/utils/semver.d.ts +14 -0
  180. package/dist/utils/semver.d.ts.map +1 -0
  181. package/dist/utils/semver.js +61 -0
  182. package/dist/utils/semver.js.map +1 -0
  183. package/package.json +7 -4
  184. package/src/__tests__/__snapshots__/boundaries.test.ts.snap +154 -0
  185. package/src/__tests__/agent-instructions.test.ts +6 -1
  186. package/src/__tests__/agent-loop-phase34.test.ts +143 -8
  187. package/src/__tests__/auth.test.ts +9 -0
  188. package/src/__tests__/azure-cli.test.ts +202 -0
  189. package/src/__tests__/boundaries.test.ts +42 -0
  190. package/src/__tests__/csharp-schema.test.ts +261 -0
  191. package/src/__tests__/dev.test.ts +13 -6
  192. package/src/__tests__/fixtures/az wrapper.cmd +2 -0
  193. package/src/__tests__/fixtures/azure-cli.cjs +153 -0
  194. package/src/__tests__/fixtures/provision-runner.cjs +28 -0
  195. package/src/__tests__/generated-project-matrix.test.ts +789 -0
  196. package/src/__tests__/home-page.test.ts +50 -0
  197. package/src/__tests__/init.test.ts +145 -5
  198. package/src/__tests__/mcp-version.test.ts +262 -0
  199. package/src/__tests__/mcp.test.ts +120 -3
  200. package/src/__tests__/multi-auth.test.ts +115 -4
  201. package/src/__tests__/package-manager.test.ts +17 -2
  202. package/src/__tests__/plan-apply.test.ts +179 -0
  203. package/src/__tests__/provision-runtime.test.ts +722 -0
  204. package/src/__tests__/python-uv.test.ts +50 -14
  205. package/src/__tests__/python-venv.test.ts +48 -0
  206. package/src/__tests__/react-dev.test.ts +72 -0
  207. package/src/__tests__/react.test.ts +838 -0
  208. package/src/__tests__/release-metadata.test.ts +121 -0
  209. package/src/__tests__/schema-analysis.test.ts +329 -0
  210. package/src/cli/commands/add-auth.ts +103 -29
  211. package/src/cli/commands/configure-mcp.ts +54 -0
  212. package/src/cli/commands/dev.ts +145 -73
  213. package/src/cli/commands/init.ts +147 -172
  214. package/src/cli/commands/migrations.ts +22 -0
  215. package/src/cli/commands/provision.ts +294 -56
  216. package/src/cli/commands/scaffold.ts +145 -22
  217. package/src/cli/index.ts +46 -10
  218. package/src/core/config.ts +21 -1
  219. package/src/core/operations/create-model.ts +51 -13
  220. package/src/core/operations/migration-generator.ts +14 -1
  221. package/src/core/operations/model-migration.ts +52 -0
  222. package/src/core/operations/provision-deployment.ts +183 -0
  223. package/src/core/operations/provision-operations.ts +662 -154
  224. package/src/core/operations/scaffold-apply.ts +2 -0
  225. package/src/core/operations/scaffold-machine.ts +1 -0
  226. package/src/core/operations/scaffold-plan.ts +5 -1
  227. package/src/core/project/agent-instructions.ts +17 -1
  228. package/src/core/project/agent-templates/AGENTS.md +113 -15
  229. package/src/core/project/agent-templates/CLAUDE.md +14 -1
  230. package/src/core/project/agent-templates/bff-routes.instructions.md +5 -3
  231. package/src/core/project/agent-templates/copilot-instructions.md +15 -1
  232. package/src/core/project/agent-templates/shared-models.instructions.md +11 -3
  233. package/src/core/project/boundaries.ts +62 -20
  234. package/src/core/project/capabilities.ts +63 -6
  235. package/src/core/project/home-page.ts +114 -0
  236. package/src/core/project/manifest.ts +52 -27
  237. package/src/core/project/mcp-config.ts +84 -0
  238. package/src/core/project/react-project.ts +529 -0
  239. package/src/core/project/state.ts +70 -0
  240. package/src/core/project/validation.ts +32 -10
  241. package/src/core/project/workflows.ts +53 -7
  242. package/src/core/scaffold/auth-generator.ts +26 -27
  243. package/src/core/scaffold/model-parser.ts +413 -129
  244. package/src/core/scaffold/native-schema-generator.ts +319 -103
  245. package/src/core/scaffold/openapi-generator.ts +63 -5
  246. package/src/core/scaffold/react-bff-generator.ts +292 -0
  247. package/src/core/scaffold/react-ui-generator.ts +51 -0
  248. package/src/core/scaffold/ui-generator.ts +70 -8
  249. package/src/core/verify/index.ts +118 -6
  250. package/src/index.ts +3 -1
  251. package/src/machine/contracts.ts +1 -0
  252. package/src/machine/errors.ts +4 -2
  253. package/src/machine/index.ts +67 -36
  254. package/src/mcp/index.ts +221 -31
  255. package/src/mcp/version-selection.ts +163 -0
  256. package/src/types/index.ts +4 -0
  257. package/src/utils/azure-cli.ts +315 -0
  258. package/src/utils/azure-diagnostics.ts +75 -0
  259. package/src/utils/package-manager.ts +7 -4
  260. package/src/utils/python-uv.ts +53 -33
  261. package/src/utils/react-dev.ts +31 -0
  262. package/src/utils/semver.ts +59 -0
@@ -5,8 +5,10 @@
5
5
 
6
6
  import * as fs from "fs";
7
7
  import * as path from "path";
8
- import { ensureSwallowKitProject, getBackendLanguage, getConnectorDefinition, getValidatedFullConfig } from "../../core/config";
9
- import { AuthProvider, BackendLanguage, CustomJwtConfig, RdbConnectorConfig } from "../../types";
8
+ import { ensureSwallowKitProject, getBackendLanguage, getFrontendFramework, getConnectorDefinition, getValidatedFullConfig } from "../../core/config";
9
+ import { generateManagedFunctionConfig, generateReactAuthBff, generateReactBffHelper } from "../../core/scaffold/react-bff-generator";
10
+ import { adaptReactPage } from "../../core/scaffold/react-ui-generator";
11
+ import { AuthConfig, AuthProvider, BackendLanguage, CustomJwtConfig, RdbConnectorConfig } from "../../types";
10
12
  import {
11
13
  generateAuthModels,
12
14
  generateAuthFunctionsTS,
@@ -98,6 +100,32 @@ function defaultCustomJwtConfig(): CustomJwtConfig {
98
100
  };
99
101
  }
100
102
 
103
+ function writeCallFunction(cwd: string, session: FileOperationSession, nextSource: string, auth: AuthConfig): void {
104
+ if (getFrontendFramework() === "react") {
105
+ const name = JSON.parse(session.readFile(path.join(cwd, "package.json"))).name;
106
+ session.writeFile(path.join(cwd, "bff", "src", "lib", "call-function.ts"), generateReactBffHelper(name, auth), managedMeta);
107
+ } else {
108
+ session.writeFile(path.join(cwd, "lib", "api", "call-function.ts"), nextSource, managedMeta);
109
+ }
110
+ }
111
+
112
+ function writeLoginPage(cwd: string, session: FileOperationSession, source: string): void {
113
+ const react = getFrontendFramework() === "react";
114
+ const destination = react ? path.join(cwd, "src", "pages", "login.tsx") : path.join(cwd, "app", "login", "page.tsx");
115
+ session.writeFile(destination, react ? adaptReactPage(source) : source, managedMeta);
116
+ }
117
+
118
+ function writeAuthContext(cwd: string, session: FileOperationSession, source: string): void {
119
+ session.writeFile(path.join(cwd, "lib", "auth", "auth-context.tsx"), getFrontendFramework() === "react" ? adaptReactPage(source) : source, managedMeta);
120
+ }
121
+
122
+ function writeManagedAuthRoute(cwd: string, session: FileOperationSession, customJwt: boolean): void {
123
+ const name = JSON.parse(session.readFile(path.join(cwd, "package.json"))).name;
124
+ const sharedName = JSON.parse(session.readFile(path.join(cwd, "shared", "package.json"))).name;
125
+ session.writeFile(path.join(cwd, "bff", "src", "auth", "index.ts"), generateReactAuthBff(name, sharedName, customJwt), managedMeta);
126
+ session.writeFile(path.join(cwd, "bff", "auth", "function.json"), generateManagedFunctionConfig("auth/{action}", ["GET", "POST"], "auth"), managedMeta);
127
+ }
128
+
101
129
  function setupSwaAuth(cwd: string, backendLanguage: BackendLanguage, session: FileOperationSession, allowedProviders?: string[]): void {
102
130
  const providers = normalizeSwaProviders(allowedProviders);
103
131
  const helperPath = backendLanguage === "typescript"
@@ -112,14 +140,12 @@ function setupSwaAuth(cwd: string, backendLanguage: BackendLanguage, session: Fi
112
140
  : generateSwaAuthHelperPython();
113
141
  session.writeFile(helperPath, helper, managedMeta);
114
142
 
115
- const callFnPath = path.join(cwd, "lib", "api", "call-function.ts");
116
- session.writeFile(callFnPath, generateBFFCallFunctionWithSwaAuth(), managedMeta);
143
+ writeCallFunction(cwd, session, generateBFFCallFunctionWithSwaAuth(), { provider: "swa" });
117
144
 
118
145
  const authDir = path.join(cwd, "lib", "auth");
119
146
  session.writeFile(path.join(authDir, "auth-context.tsx"), generateSwaAuthContext(providers), managedMeta);
120
147
  updateRootLayoutWithAuthProvider(cwd, session);
121
- const loginDir = path.join(cwd, "app", "login");
122
- session.writeFile(path.join(loginDir, "page.tsx"), generateSwaLoginPage(providers), managedMeta);
148
+ writeLoginPage(cwd, session, generateSwaLoginPage(providers));
123
149
  updateSwaRouteConfig(cwd, session, providers);
124
150
  }
125
151
 
@@ -127,10 +153,10 @@ function setupExternalTokenAuth(cwd: string, backendLanguage: BackendLanguage, s
127
153
  const authDir = path.join(cwd, "lib", "auth");
128
154
  writeIfMissing(session, path.join(authDir, "external-token-adapter.ts"), generateExternalTokenAdapter());
129
155
  session.writeFile(path.join(authDir, "authenticated-fetch.ts"), generateAuthenticatedFetch(), managedMeta);
130
- session.writeFile(path.join(authDir, "auth-context.tsx"), generateExternalTokenAuthContext(), managedMeta);
131
- session.writeFile(path.join(cwd, "lib", "api", "call-function.ts"), generateBFFCallFunctionWithAuth(), managedMeta);
132
- const meDir = path.join(cwd, "app", "api", "auth", "me");
133
- session.writeFile(path.join(meDir, "route.ts"), generateExternalTokenBFFMeRoute(), managedMeta);
156
+ writeAuthContext(cwd, session, generateExternalTokenAuthContext());
157
+ writeCallFunction(cwd, session, generateBFFCallFunctionWithAuth(), { provider: "external-token" });
158
+ if (getFrontendFramework() === "react") writeManagedAuthRoute(cwd, session, false);
159
+ else session.writeFile(path.join(cwd, "app", "api", "auth", "me", "route.ts"), generateExternalTokenBFFMeRoute(), managedMeta);
134
160
  updateRootLayoutWithAuthProvider(cwd, session);
135
161
 
136
162
  if (backendLanguage === "typescript") {
@@ -240,6 +266,14 @@ export function addAuthProviderToRootLayout(layout: string): string {
240
266
  }
241
267
 
242
268
  function updateRootLayoutWithAuthProvider(cwd: string, session: FileOperationSession): void {
269
+ if (getFrontendFramework() === "react") {
270
+ const mainPath = path.join(cwd, "src", "main.tsx");
271
+ const main = session.readFile(mainPath);
272
+ if (main.includes("<AuthProvider>")) return;
273
+ if (!main.includes("<App />")) throw new Error("Could not find <App /> in src/main.tsx; cannot install AuthProvider");
274
+ session.writeFile(mainPath, `import { AuthProvider } from '@/lib/auth/auth-context';\n${main.replace("<App />", "<AuthProvider><App /></AuthProvider>")}`, extensionMeta);
275
+ return;
276
+ }
243
277
  const layoutPath = path.join(cwd, "app", "layout.tsx");
244
278
  if (!session.fileExists(layoutPath)) {
245
279
  throw new Error("app/layout.tsx was not found; cannot install AuthProvider");
@@ -364,27 +398,25 @@ export async function addAuthCommand(options: AddAuthOptions) {
364
398
 
365
399
  // 4. Generate proxy
366
400
  console.log("\n Generating proxy...");
367
- const proxyPath = path.join(cwd, "proxy.ts");
368
- session.writeFile(proxyPath, generateProxy(projectName), managedMeta);
369
- console.log(` Created: proxy.ts`);
401
+ if (getFrontendFramework() === "nextjs") {
402
+ const proxyPath = path.join(cwd, "proxy.ts");
403
+ session.writeFile(proxyPath, generateProxy(projectName), managedMeta);
404
+ console.log(` Created: proxy.ts`);
405
+ }
370
406
 
371
407
  // 5. Generate login page
372
408
  console.log("\n Generating login page...");
373
- const loginDir = path.join(cwd, "app", "login");
374
- session.writeFile(path.join(loginDir, "page.tsx"), generateLoginPage(), managedMeta);
375
- console.log(` Created: app/login/page.tsx`);
409
+ writeLoginPage(cwd, session, generateLoginPage());
376
410
 
377
411
  // 6. Generate auth context
378
412
  console.log("\n Generating auth context...");
379
- const authLibDir = path.join(cwd, "lib", "auth");
380
- session.writeFile(path.join(authLibDir, "auth-context.tsx"), generateAuthContext(), managedMeta);
413
+ writeAuthContext(cwd, session, generateAuthContext());
381
414
  console.log(`✅ Created: lib/auth/auth-context.tsx`);
382
415
 
383
416
  // 7. Update callFunction with auth support
384
417
  console.log("\n Updating callFunction with auth support...");
385
- const callFnPath = path.join(cwd, "lib", "api", "call-function.ts");
386
- session.writeFile(callFnPath, generateBFFCallFunctionWithAuth(), managedMeta);
387
- console.log(` Updated: lib/api/call-function.ts`);
418
+ writeCallFunction(cwd, session, generateBFFCallFunctionWithAuth(), { provider: "custom-jwt" });
419
+ console.log(` Updated: ${getFrontendFramework() === "react" ? "bff/src/lib" : "lib/api"}/call-function.ts`);
388
420
 
389
421
  // 8. Update swallowkit.config.js
390
422
  console.log("\n Updating configuration...");
@@ -396,7 +428,7 @@ export async function addAuthCommand(options: AddAuthOptions) {
396
428
 
397
429
  // 10. Install dependencies
398
430
  console.log("\n Installing auth dependencies...");
399
- await installAuthDependencies(cwd, backendLanguage, rdbProvider, session);
431
+ installAuthDependenciesSync(cwd, backendLanguage, rdbProvider, session);
400
432
  await finalize();
401
433
 
402
434
  console.log("\n Authentication setup complete!");
@@ -426,7 +458,8 @@ function findObjectEnd(content: string, open: number): number {
426
458
  function updateConfigWithNamedScheme(cwd: string, scheme: string, provider: AuthProvider, session: FileOperationSession, allowedProviders?: string[]): void {
427
459
  const jsPath = path.join(cwd, "swallowkit.config.js");
428
460
  const jsonPath = path.join(cwd, "swallowkit.config.json");
429
- const configPath = session.fileExists(jsPath) ? jsPath : jsonPath;
461
+ // Match loadConfig precedence: swallowkit.config.json wins when both files exist.
462
+ const configPath = session.fileExists(jsonPath) ? jsonPath : jsPath;
430
463
  if (!session.fileExists(configPath)) throw new Error("swallowkit.config.js or swallowkit.config.json is required");
431
464
  const swaProviders = provider === "swa" ? normalizeSwaProviders(allowedProviders) : undefined;
432
465
  if (configPath.endsWith(".json")) {
@@ -478,6 +511,11 @@ function addNamedScheme(cwd: string, scheme: string, provider: AuthProvider, lan
478
511
  // Validate/update config before creating files, so duplicate names stop safely.
479
512
  updateConfigWithNamedScheme(cwd, scheme, provider, session, allowedProviders);
480
513
  const slug = scheme.replace(/([a-z0-9])([A-Z])/g, "$1-$2").replace(/_/g, "-").toLowerCase();
514
+ if (provider === "custom-jwt") {
515
+ // The scheme's JWT helper needs the same token/password/driver packages as single-provider custom-jwt.
516
+ const connector = getConnectorDefinition(defaultCustomJwtConfig().userConnector) as RdbConnectorConfig | undefined;
517
+ installAuthDependenciesSync(cwd, language, connector?.provider ?? "mysql", session);
518
+ }
481
519
  if (language === "typescript") {
482
520
  const dir = path.join(cwd, "functions", "src", "auth", "schemes", slug);
483
521
  if (provider === "external-token") writeIfMissing(session, path.join(dir, "verifier.ts"), generateExternalTokenVerifierTS());
@@ -498,11 +536,19 @@ function addNamedScheme(cwd: string, scheme: string, provider: AuthProvider, lan
498
536
  if (provider === "external-token") {
499
537
  writeIfMissing(session, path.join(clientDir, "token-adapter.ts"), generateExternalTokenAdapter());
500
538
  writeIfMissing(session, path.join(clientDir, "authenticated-fetch.ts"), generateAuthenticatedFetch().replace("'./external-token-adapter'", "'./token-adapter'"));
501
- writeIfMissing(session, path.join(clientDir, "auth-context.tsx"), generateExternalTokenAuthContext().replace(/external-token-adapter/g, "token-adapter"));
539
+ const source = generateExternalTokenAuthContext().replace(/external-token-adapter/g, "token-adapter");
540
+ writeIfMissing(session, path.join(clientDir, "auth-context.tsx"), getFrontendFramework() === "react" ? adaptReactPage(source) : source);
502
541
  } else if (provider === "swa") {
503
542
  writeIfMissing(session, path.join(clientDir, "auth-context.tsx"), generateSwaAuthContext(allowedProviders));
504
543
  } else if (provider === "custom-jwt") {
505
- writeIfMissing(session, path.join(clientDir, "auth-context.tsx"), generateAuthContext());
544
+ writeIfMissing(session, path.join(clientDir, "auth-context.tsx"), getFrontendFramework() === "react" ? adaptReactPage(generateAuthContext()) : generateAuthContext());
545
+ }
546
+ if (getFrontendFramework() === "react") {
547
+ const existing = getValidatedFullConfig().auth;
548
+ writeCallFunction(cwd, session, "", {
549
+ ...existing, schemes: { ...existing?.schemes, [scheme]: { provider } },
550
+ });
551
+ return;
506
552
  }
507
553
  const callFunctionPath = path.join(cwd, "lib", "api", "call-function.ts");
508
554
  if (!session.fileExists(callFunctionPath)) writeIfMissing(session, callFunctionPath, generateBFFCallFunctionWithMultipleAuth());
@@ -649,9 +695,14 @@ function generateFunctionsAuth(
649
695
  const functionAppPath = path.join(functionsDir, "function_app.py");
650
696
  if (session.fileExists(functionAppPath)) {
651
697
  const content = session.readFile(functionAppPath);
652
- const authImport = "from blueprints.auth import bp as auth_bp";
698
+ const authImport = "from blueprints.auth import auth_bp";
653
699
  const authRegister = "app.register_blueprint(auth_bp)";
654
- if (!content.includes(authImport)) {
700
+ // Earlier releases imported a non-existent `bp`; repair it in place when re-running.
701
+ const legacyImport = "from blueprints.auth import bp as auth_bp";
702
+ if (content.includes(legacyImport)) {
703
+ session.writeFile(functionAppPath, content.replace(legacyImport, authImport), extensionMeta);
704
+ console.log(` Updated: functions/function_app.py (fixed auth blueprint import)`);
705
+ } else if (!content.includes(authImport)) {
655
706
  const marker = "# SwallowKit scaffold registrations";
656
707
  if (content.includes(marker)) {
657
708
  const updated = content.replace(
@@ -667,6 +718,10 @@ function generateFunctionsAuth(
667
718
  }
668
719
 
669
720
  function generateBFFAuth(cwd: string, projectName: string, sharedPackageName: string, session: FileOperationSession): void {
721
+ if (getFrontendFramework() === "react") {
722
+ writeManagedAuthRoute(cwd, session, true);
723
+ return;
724
+ }
670
725
  const authApiDir = path.join(cwd, "app", "api", "auth");
671
726
 
672
727
  // Login route
@@ -698,6 +753,24 @@ function generateBFFAuth(cwd: string, projectName: string, sharedPackageName: st
698
753
  }
699
754
 
700
755
  function updateConfigWithAuth(cwd: string, provider: AuthProvider, config: CustomJwtConfig, session: FileOperationSession, allowedProviders?: string[]): void {
756
+ const jsonPath = path.join(cwd, "swallowkit.config.json");
757
+ if (session.fileExists(jsonPath)) {
758
+ // loadConfig reads swallowkit.config.json first, so it is the effective configuration.
759
+ const value = JSON.parse(session.readFile(jsonPath));
760
+ if (value.auth) {
761
+ console.log(" 'auth' section already exists in swallowkit.config.json");
762
+ return;
763
+ }
764
+ value.auth = {
765
+ provider,
766
+ ...(provider === "custom-jwt" ? { customJwt: { ...config, jwtSecretEnv: config.jwtSecretEnv || "JWT_SECRET", tokenExpiry: config.tokenExpiry || "24h" } } : {}),
767
+ ...(provider === "swa" ? { swa: { allowedProviders: normalizeSwaProviders(allowedProviders), roleSource: "swa-roles" } } : {}),
768
+ authorization: { defaultPolicy: provider === "none" ? "anonymous" : "authenticated" },
769
+ };
770
+ session.writeFile(jsonPath, JSON.stringify(value, null, 2) + "\n", extensionMeta);
771
+ console.log(` Updated: swallowkit.config.json`);
772
+ return;
773
+ }
701
774
  const configPath = path.join(cwd, "swallowkit.config.js");
702
775
  if (!session.fileExists(configPath)) {
703
776
  console.warn(" swallowkit.config.js not found. Please add auth config manually.");
@@ -742,7 +815,8 @@ function updateConfigWithAuth(cwd: string, provider: AuthProvider, config: Custo
742
815
  provider: '${provider}',
743
816
  ${providerSettings}
744
817
  authorization: {
745
- defaultPolicy: 'authenticated',
818
+ // Disabled auth has no scheme to authenticate against; 'authenticated' would fail validateConfig.
819
+ defaultPolicy: '${provider === "none" ? "anonymous" : "authenticated"}',
746
820
  },
747
821
  },
748
822
  `;
@@ -777,7 +851,7 @@ function updateEnvironmentFiles(cwd: string, session: FileOperationSession): voi
777
851
  }
778
852
  }
779
853
 
780
- async function installAuthDependencies(cwd: string, backendLanguage: BackendLanguage, provider: "mysql" | "postgres" | "sqlserver" = "mysql", session: FileOperationSession): Promise<void> {
854
+ function installAuthDependenciesSync(cwd: string, backendLanguage: BackendLanguage, provider: "mysql" | "postgres" | "sqlserver" = "mysql", session: FileOperationSession): void {
781
855
  if (backendLanguage === "typescript") {
782
856
  const funcPkgPath = path.join(cwd, "functions", "package.json");
783
857
  if (session.fileExists(funcPkgPath)) {
@@ -0,0 +1,54 @@
1
+ import { Command } from "commander";
2
+ import { ensureSwallowKitProject } from "../../core/config";
3
+ import {
4
+ MCP_CONFIG_PATH,
5
+ MCP_LATEST,
6
+ lookupPublishedLatestVersion,
7
+ readMcpConfigVersion,
8
+ resolveMcpPinVersion,
9
+ writeMcpConfigVersion,
10
+ } from "../../core/project/mcp-config";
11
+ import { resolveProjectSwallowKit } from "../../mcp/version-selection";
12
+ import { parseSemver } from "../../utils/semver";
13
+ import { getSwallowKitVersion } from "../../version";
14
+
15
+ export interface ConfigureMcpResult {
16
+ previousVersion: string | null;
17
+ version: string;
18
+ reason: string;
19
+ }
20
+
21
+ export function configureMcp(
22
+ options: { version?: string; cwd?: string },
23
+ lookupLatest: (packageName: string) => string | null = lookupPublishedLatestVersion
24
+ ): ConfigureMcpResult {
25
+ const cwd = options.cwd ?? process.cwd();
26
+ const requested = (options.version ?? "auto").trim();
27
+ const previousVersion = readMcpConfigVersion(cwd);
28
+
29
+ let decision: { version: string; reason: string };
30
+ if (requested === "auto") {
31
+ const projectVersion = resolveProjectSwallowKit(cwd)?.version ?? getSwallowKitVersion();
32
+ decision = resolveMcpPinVersion(projectVersion, lookupLatest("swallowkit"));
33
+ } else if (requested === MCP_LATEST) {
34
+ decision = { version: MCP_LATEST, reason: "Explicitly requested latest." };
35
+ } else if (parseSemver(requested)) {
36
+ decision = { version: requested, reason: "Explicitly pinned version." };
37
+ } else {
38
+ throw new Error(`--version must be "auto", "latest", or a semantic version (got "${requested}").`);
39
+ }
40
+
41
+ writeMcpConfigVersion(cwd, decision.version);
42
+ return { previousVersion, ...decision };
43
+ }
44
+
45
+ export const configureMcpCommand = new Command("configure-mcp")
46
+ .description(`Select the SwallowKit MCP version used by ${MCP_CONFIG_PATH} (auto: latest unless the project is newer)`)
47
+ .option("--version <version>", "auto | latest | <semver>", "auto")
48
+ .action((options: { version?: string }) => {
49
+ ensureSwallowKitProject("configure-mcp");
50
+ const result = configureMcp({ version: options.version });
51
+ console.log(`${MCP_CONFIG_PATH}: SWALLOWKIT_MCP_VERSION ${result.previousVersion ?? "(unset)"} -> ${result.version}`);
52
+ console.log(`Reason: ${result.reason}`);
53
+ console.log("Restart the MCP server (or reload your agent) to apply the change.");
54
+ });