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
@@ -41,6 +41,7 @@ exports.buildFunctionsCoreToolsCommand = buildFunctionsCoreToolsCommand;
41
41
  exports.buildNextDevArgs = buildNextDevArgs;
42
42
  exports.buildFunctionsBaseUrl = buildFunctionsBaseUrl;
43
43
  exports.buildSwaStartArgs = buildSwaStartArgs;
44
+ exports.buildReactDevArgs = buildReactDevArgs;
44
45
  exports.getSwaCliInstallCommand = getSwaCliInstallCommand;
45
46
  exports.getFunctionsReadinessTimeoutMs = getFunctionsReadinessTimeoutMs;
46
47
  exports.waitForHttpServerReady = waitForHttpServerReady;
@@ -48,6 +49,7 @@ exports.getPythonVirtualEnvPaths = getPythonVirtualEnvPaths;
48
49
  exports.getCSharpFunctionsBuildArtifactPaths = getCSharpFunctionsBuildArtifactPaths;
49
50
  exports.buildPythonFunctionsEnv = buildPythonFunctionsEnv;
50
51
  exports.buildFunctionsCosmosEnvironment = buildFunctionsCosmosEnvironment;
52
+ exports.assertDevPortAvailable = assertDevPortAvailable;
51
53
  exports.buildDevCommand = buildDevCommand;
52
54
  const commander_1 = require("commander");
53
55
  const child_process_1 = require("child_process");
@@ -63,6 +65,7 @@ const dev_seeds_1 = require("./dev-seeds");
63
65
  const package_manager_1 = require("../../utils/package-manager");
64
66
  const python_uv_1 = require("../../utils/python-uv");
65
67
  const connector_mock_server_1 = require("../../core/mock/connector-mock-server");
68
+ const react_dev_1 = require("../../utils/react-dev");
66
69
  const MINIMUM_CSHARP_CORE_TOOLS_VERSION = '4.6.0';
67
70
  const NPM_CORE_TOOLS_PACKAGE = 'azure-functions-core-tools@4';
68
71
  function normalizeParsedDevOptions(options) {
@@ -72,8 +75,8 @@ function normalizeParsedDevOptions(options) {
72
75
  noSwa: options.noSwa ?? options.swa === false,
73
76
  };
74
77
  }
75
- function buildFunctionsStartArgs(functionsPort) {
76
- return ['start', '--port', functionsPort];
78
+ function buildFunctionsStartArgs(functionsPort, backendLanguage = 'typescript') {
79
+ return [...(backendLanguage === 'csharp' ? [] : ['start']), '--port', functionsPort];
77
80
  }
78
81
  function parseCoreToolsVersion(output) {
79
82
  const match = output.match(/\d+\.\d+\.\d+/);
@@ -100,14 +103,14 @@ function buildFunctionsCoreToolsCommand(backendLanguage, installedVersion) {
100
103
  : 'func is not installed';
101
104
  return {
102
105
  command: 'npm',
103
- argsPrefix: ['exec', '--yes', NPM_CORE_TOOLS_PACKAGE, '--'],
104
- label: `npm exec ${NPM_CORE_TOOLS_PACKAGE} (${reason})`,
106
+ argsPrefix: ['exec', '--yes', '--package', NPM_CORE_TOOLS_PACKAGE, '--', 'dotnet', 'run', '--no-launch-profile', '--'],
107
+ label: `dotnet run with npm ${NPM_CORE_TOOLS_PACKAGE} (${reason})`,
105
108
  };
106
109
  }
107
110
  return {
108
- command: 'func',
109
- argsPrefix: [],
110
- label: installedVersion ? `func ${installedVersion}` : 'func',
111
+ command: backendLanguage === 'csharp' ? 'dotnet' : 'func',
112
+ argsPrefix: backendLanguage === 'csharp' ? ['run', '--no-launch-profile', '--'] : [],
113
+ label: backendLanguage === 'csharp' ? 'dotnet run' : installedVersion ? `func ${installedVersion}` : 'func',
111
114
  };
112
115
  }
113
116
  function buildNextDevArgs(pm, port) {
@@ -117,7 +120,7 @@ function buildNextDevArgs(pm, port) {
117
120
  function buildFunctionsBaseUrl(host, functionsPort) {
118
121
  return `http://${host || 'localhost'}:${functionsPort}`;
119
122
  }
120
- function buildSwaStartArgs(host, nextPort, swaPort) {
123
+ function buildSwaStartArgs(host, nextPort, swaPort, bffPort) {
121
124
  return [
122
125
  'start',
123
126
  `http://${host || 'localhost'}:${nextPort}`,
@@ -125,8 +128,13 @@ function buildSwaStartArgs(host, nextPort, swaPort) {
125
128
  '.',
126
129
  '--port',
127
130
  swaPort,
131
+ ...(bffPort ? ['--api-devserver-url', buildFunctionsBaseUrl(host, bffPort)] : []),
128
132
  ];
129
133
  }
134
+ function buildReactDevArgs(pm, port, host = 'localhost', configPath) {
135
+ const args = ['vite', '--port', port, '--host', host, '--strictPort', ...(configPath ? ['--config', configPath] : [])];
136
+ return pm === 'pnpm' ? ['exec', ...args] : args;
137
+ }
130
138
  function getSwaCliInstallCommand(pm) {
131
139
  return pm === 'pnpm'
132
140
  ? 'pnpm add -Dw @azure/static-web-apps-cli'
@@ -215,7 +223,7 @@ async function checkCommand(command, args = ['--version'], options) {
215
223
  });
216
224
  }
217
225
  async function resolveProjectLocalUvCommand(projectRoot) {
218
- const uvEnv = (0, python_uv_1.buildProjectLocalUvEnv)(process.env, projectRoot);
226
+ const uvEnv = { ...process.env };
219
227
  const { localUvExecutable } = (0, python_uv_1.getProjectLocalUvPaths)(projectRoot);
220
228
  if (await checkCommand('uv', ['--version'], { shell: false })) {
221
229
  return { command: 'uv', env: uvEnv };
@@ -357,20 +365,8 @@ async function bridgePythonCoreToolsForWindowsArm64(functionsDir, env) {
357
365
  async function preparePythonFunctionsEnvironment(functionsDir) {
358
366
  const projectRoot = (0, python_uv_1.getPythonProjectRoot)(functionsDir);
359
367
  const { command: uvCommand, env: uvEnv } = await resolveProjectLocalUvCommand(projectRoot);
360
- const { venvDir, pythonExecutable } = getPythonVirtualEnvPaths(functionsDir);
361
- const hasUsableVirtualEnv = fs.existsSync(pythonExecutable) && await checkCommand(pythonExecutable, ['--version'], {
362
- cwd: functionsDir,
363
- env: uvEnv,
364
- shell: false,
365
- });
366
- if (!hasUsableVirtualEnv) {
367
- const venvArgs = (0, python_uv_1.buildUvVenvArgs)('.venv');
368
- if (fs.existsSync(venvDir)) {
369
- venvArgs.push('--clear');
370
- }
371
- console.log('📦 Creating Python virtual environment with uv...');
372
- await runCommand(uvCommand, venvArgs, functionsDir, 'python virtual environment setup', uvEnv, false);
373
- }
368
+ const { venvDir } = getPythonVirtualEnvPaths(functionsDir);
369
+ const pythonExecutable = await (0, python_uv_1.ensureUvVirtualEnvironment)(uvCommand, venvDir, functionsDir, uvEnv);
374
370
  console.log('📦 Installing Python Azure Functions dependencies with uv...');
375
371
  await runCommand(uvCommand, (0, python_uv_1.buildUvPipInstallArgs)(pythonExecutable, 'requirements.txt'), functionsDir, 'python dependency installation', uvEnv, false);
376
372
  const pythonEnv = buildPythonFunctionsEnv(uvEnv, functionsDir);
@@ -398,20 +394,45 @@ async function checkCosmosDBEmulator() {
398
394
  socket.connect(8081, 'localhost');
399
395
  });
400
396
  }
397
+ async function assertDevPortAvailable(port, host) {
398
+ await new Promise((resolve, reject) => {
399
+ const server = net.createServer();
400
+ server.once('error', error => reject(new Error(`Development port ${port} on ${host} is unavailable: ${error.message}`)));
401
+ server.listen({ port, host, exclusive: true }, () => server.close(error => error ? reject(error) : resolve()));
402
+ });
403
+ }
404
+ function stopDevProcesses(processes) {
405
+ const active = processes.filter(child => child.pid && !child.killed && child.exitCode === null && child.signalCode === null);
406
+ if (process.platform === 'win32' && active.length) {
407
+ // Windows shell termination alone leaves Vite, Core Tools, and SWA running.
408
+ const ids = active.map(child => child.pid).join(',');
409
+ const result = (0, child_process_1.spawnSync)('powershell.exe', ['-NoProfile', '-NonInteractive', '-Command',
410
+ `$all = @(Get-CimInstance Win32_Process); function Stop-OwnedTree([int]$id) { foreach ($child in ($all | Where-Object ParentProcessId -eq $id)) { Stop-OwnedTree $child.ProcessId }; Stop-Process -Id $id -Force -ErrorAction SilentlyContinue }; foreach ($id in @(${ids})) { Stop-OwnedTree $id }`,
411
+ ], { windowsHide: true, encoding: 'utf8' });
412
+ if (result.error || result.status !== 0) {
413
+ console.error('❌ Could not stop all development subprocesses:', result.error?.message || result.stderr);
414
+ }
415
+ }
416
+ else {
417
+ for (const child of active)
418
+ child.kill();
419
+ }
420
+ }
401
421
  function buildDevCommand(runDevEnvironment = startDevEnvironment, verifyProject = config_1.ensureSwallowKitProject) {
402
422
  return new commander_1.Command()
403
423
  .name('dev')
404
- .description('Start SwallowKit development server (Cosmos DB + Next.js + Azure Functions)')
405
- .option('-p, --port <port>', 'Next.js port', '3000')
424
+ .description('Start SwallowKit frontend, BFF, and standalone Azure Functions')
425
+ .option('-p, --port <port>', 'Frontend dev server port', '3000')
406
426
  .option('-f, --functions-port <port>', 'Azure Functions port', '7071')
427
+ .option('--bff-port <port>', 'React managed BFF Functions port', '7073')
407
428
  .option('--host <host>', 'Host name', 'localhost')
408
429
  .option('--open', 'Open browser automatically', false)
409
430
  .option('--verbose', 'Show verbose logs', false)
410
431
  .option('--no-functions', 'Skip Azure Functions startup')
411
432
  .option('--seed-env <environment>', 'Replace Cosmos DB Emulator data from dev-seeds/<environment> before startup')
412
433
  .option('--mock-connectors', 'Start mock server for connector models (serves Zod-generated data)', false)
413
- .option('--swa-port <port>', 'SWA authentication emulator port', '4280')
414
- .option('--no-swa', 'Skip the SWA authentication emulator')
434
+ .option('--swa-port <port>', 'SWA routing/authentication emulator port', '4280')
435
+ .option('--no-swa', 'Skip SWA routing/authentication emulation (React direct access has no same-origin API)')
415
436
  .action(async (options) => {
416
437
  const normalizedOptions = normalizeParsedDevOptions(options);
417
438
  // SwallowKit プロジェクトディレクトリかどうかを検証
@@ -512,17 +533,22 @@ async function startDevEnvironment(options) {
512
533
  const port = options.port || '3000';
513
534
  const functionsPort = options.functionsPort || '7071';
514
535
  const swaPort = options.swaPort || '4280';
536
+ const bffPort = options.bffPort || '7073';
515
537
  // Detect package manager from project lockfile
516
538
  const pm = (0, package_manager_1.detectFromProject)();
517
539
  const pmCmd = (0, package_manager_1.getCommands)(pm);
518
540
  const backendLanguage = (0, config_1.getBackendLanguage)();
541
+ const react = (0, config_1.getFrontendFramework)() === 'react';
542
+ const frontendLabel = react ? 'React/Vite' : 'Next.js';
519
543
  const authConfig = (0, config_1.getAuthConfig)();
520
544
  const normalizedAuth = (0, config_1.normalizeAuthConfig)(authConfig);
521
- const useSwaEmulator = Boolean(normalizedAuth && Object.values(normalizedAuth.schemes).some(scheme => scheme.provider === 'swa')) && !options.noSwa;
545
+ const authSchemes = Object.values(normalizedAuth?.schemes ?? {});
546
+ const swaScheme = authSchemes.find(scheme => scheme.provider === 'swa');
547
+ const useSwaEmulator = (react || Boolean(swaScheme)) && !options.noSwa;
522
548
  const swaCommand = useSwaEmulator ? await resolveSwaCliCommand(process.cwd()) : null;
523
549
  if (useSwaEmulator && !swaCommand) {
524
550
  const installCommand = getSwaCliInstallCommand(pm);
525
- console.error('❌ SWA authentication requires Azure Static Web Apps CLI for local development.');
551
+ console.error('❌ SWA routing/authentication requires Azure Static Web Apps CLI for local development.');
526
552
  console.error(' Install it in this project and retry:');
527
553
  console.error(`\n ${installCommand}\n`);
528
554
  process.exitCode = 1;
@@ -537,6 +563,14 @@ async function startDevEnvironment(options) {
537
563
  const functionsBaseUrl = buildFunctionsBaseUrl(options.host, functionsPort);
538
564
  let functionsReadinessPromise = null;
539
565
  let functionsReady = !!options.noFunctions;
566
+ let reactDevConfigDir;
567
+ const cleanupReactDevConfig = () => {
568
+ if (reactDevConfigDir) {
569
+ fs.rmSync(reactDevConfigDir, { recursive: true, force: true });
570
+ reactDevConfigDir = undefined;
571
+ }
572
+ };
573
+ process.once('exit', cleanupReactDevConfig);
540
574
  // Cleanup processes on Ctrl+C
541
575
  process.on('SIGINT', async () => {
542
576
  console.log('\n🛑 Stopping development servers...');
@@ -557,14 +591,22 @@ async function startDevEnvironment(options) {
557
591
  if (mockServer) {
558
592
  await mockServer.stop();
559
593
  }
560
- processes.forEach((proc) => {
561
- if (proc && !proc.killed) {
562
- proc.kill();
563
- }
564
- });
594
+ stopDevProcesses(processes);
565
595
  process.exit(0);
566
596
  });
567
597
  try {
598
+ if (react) {
599
+ const ports = [port, bffPort, ...(!options.noFunctions ? [functionsPort] : []), ...(useSwaEmulator ? [swaPort] : []), ...(options.mockConnectors ? [String(Number(functionsPort) + 1)] : [])];
600
+ if (ports.some(value => !/^\d+$/.test(value) || Number(value) < 1 || Number(value) > 65535) || new Set(ports).size !== ports.length) {
601
+ throw new Error('Frontend, BFF, standalone Functions, mock, and SWA ports must be valid and distinct');
602
+ }
603
+ for (const value of ports)
604
+ await assertDevPortAvailable(Number(value), options.host || 'localhost');
605
+ const coreToolsVersion = await resolveInstalledCoreToolsVersion();
606
+ if (!coreToolsVersion || compareVersionNumbers(coreToolsVersion, '4.0.0') < 0) {
607
+ throw new Error('React BFF requires Azure Functions Core Tools v4. Install it explicitly before running dev.');
608
+ }
609
+ }
568
610
  // 1. Check for Next.js project
569
611
  const packageJsonPath = path.join(process.cwd(), 'package.json');
570
612
  const nextConfigPathJs = path.join(process.cwd(), 'next.config.js');
@@ -572,10 +614,10 @@ async function startDevEnvironment(options) {
572
614
  const nextConfigPathMjs = path.join(process.cwd(), 'next.config.mjs');
573
615
  if (!fs.existsSync(packageJsonPath)) {
574
616
  console.log('❌ package.json not found.');
575
- console.log('💡 Please run this command in the root directory of a Next.js project.');
617
+ console.log('💡 Please run this command in the root directory of a SwallowKit project.');
576
618
  process.exit(1);
577
619
  }
578
- if (!fs.existsSync(nextConfigPathJs) && !fs.existsSync(nextConfigPathTs) && !fs.existsSync(nextConfigPathMjs)) {
620
+ if (!react && !fs.existsSync(nextConfigPathJs) && !fs.existsSync(nextConfigPathTs) && !fs.existsSync(nextConfigPathMjs)) {
579
621
  console.log('⚠️ next.config file not found. Is this a Next.js project?');
580
622
  }
581
623
  // 2. Check if Azure Functions exists
@@ -730,7 +772,7 @@ async function startDevEnvironment(options) {
730
772
  }
731
773
  // Azure Functions を起動
732
774
  const functionsCommand = functionsCoreToolsCommand ?? buildFunctionsCoreToolsCommand(backendLanguage, installedCoreToolsVersion);
733
- const funcProcess = (0, child_process_1.spawn)(functionsCommand.command, [...functionsCommand.argsPrefix, ...buildFunctionsStartArgs(functionsPort)], {
775
+ const funcProcess = (0, child_process_1.spawn)(functionsCommand.command, [...functionsCommand.argsPrefix, ...buildFunctionsStartArgs(functionsPort, backendLanguage)], {
734
776
  cwd: functionsDir,
735
777
  shell: true,
736
778
  stdio: 'pipe', // Always pipe to capture output
@@ -770,6 +812,8 @@ async function startDevEnvironment(options) {
770
812
  console.error('⚠️ Azure Functions startup error:', error.message);
771
813
  console.log('💡 Please ensure Azure Functions Core Tools is installed');
772
814
  console.log(` ${pmCmd.addGlobal} azure-functions-core-tools@4`);
815
+ stopDevProcesses(processes);
816
+ process.exit(1);
773
817
  });
774
818
  funcProcess.on('close', (code) => {
775
819
  if (code !== 0) {
@@ -779,6 +823,8 @@ async function startDevEnvironment(options) {
779
823
  console.log(' Reinstall a matching Core Tools v4 package (Windows users should prefer the official x64/x86 MSI for their machine).');
780
824
  console.log(' SwallowKit local Python dev uses functions/.venv and requirements.txt, but Core Tools still needs its own bundled Python worker.');
781
825
  }
826
+ stopDevProcesses(processes);
827
+ process.exit(code || 1);
782
828
  }
783
829
  });
784
830
  console.log(`⏳ Waiting for Azure Functions to accept requests at ${functionsBaseUrl}...`);
@@ -786,14 +832,14 @@ async function startDevEnvironment(options) {
786
832
  }
787
833
  else if (!hasFunctions) {
788
834
  console.log('');
789
- console.log('ℹ️ functions/ directory not found. Starting Next.js only.');
835
+ console.log(`ℹ️ functions/ directory not found. Starting ${frontendLabel}${react ? ' and managed BFF' : ''} only.`);
790
836
  }
791
837
  else if (options.noFunctions) {
792
838
  console.log('');
793
839
  console.log('ℹ️ --no-functions specified. Skipping Azure Functions.');
794
840
  }
795
841
  console.log('');
796
- console.log('🚀 Starting Next.js development server...');
842
+ console.log(`🚀 Starting ${frontendLabel} development server...`);
797
843
  // Mock connector server — start proxy if --mock-connectors is enabled
798
844
  let bffTargetPort = functionsPort;
799
845
  if (options.mockConnectors) {
@@ -857,7 +903,17 @@ async function startDevEnvironment(options) {
857
903
  }
858
904
  }
859
905
  // 5. Start Next.js development server
860
- const nextArgs = buildNextDevArgs(pm, port);
906
+ let reactDevConfigPath;
907
+ if (react) {
908
+ const stateDir = path.join(process.cwd(), '.swallowkit');
909
+ fs.mkdirSync(stateDir, { recursive: true });
910
+ reactDevConfigDir = fs.mkdtempSync(path.join(stateDir, 'vite-dev-'));
911
+ reactDevConfigPath = path.join(reactDevConfigDir, 'config.mjs');
912
+ fs.writeFileSync(reactDevConfigPath, (0, react_dev_1.buildReactDevConfigSource)());
913
+ }
914
+ const nextArgs = react
915
+ ? buildReactDevArgs(pm, port, options.host, reactDevConfigPath && path.relative(process.cwd(), reactDevConfigPath))
916
+ : buildNextDevArgs(pm, port);
861
917
  // Ensure .env.local points to bffTargetPort so Next.js reads the correct backend URL.
862
918
  // When --mock-connectors is active, bffTargetPort = mock port (7072); otherwise = Functions port (7071).
863
919
  // Next.js may load .env.local values that override spawn env vars, so we must keep them in sync.
@@ -880,6 +936,24 @@ async function startDevEnvironment(options) {
880
936
  BACKEND_FUNCTIONS_BASE_URL: bffTargetUrl,
881
937
  FUNCTIONS_BASE_URL: bffTargetUrl,
882
938
  };
939
+ if (react) {
940
+ await runCommand(pm, ['run', 'build'], path.join(process.cwd(), 'shared'), 'Shared schema build');
941
+ const bffDir = path.join(process.cwd(), 'bff');
942
+ await runCommand(pm, ['run', 'build'], bffDir, 'Managed BFF build');
943
+ const bffProcess = (0, child_process_1.spawn)('func', buildFunctionsStartArgs(bffPort), {
944
+ cwd: bffDir, shell: true, stdio: 'inherit', env: nextEnv,
945
+ });
946
+ processes.push(bffProcess);
947
+ bffProcess.on('error', error => console.error('❌ Managed BFF startup error:', error.message));
948
+ bffProcess.on('close', code => {
949
+ console.error(`⏹️ Managed BFF exited (exit code: ${code})`);
950
+ stopDevProcesses(processes);
951
+ process.exit(code || 1);
952
+ });
953
+ if (!await waitForHttpServerReady(buildFunctionsBaseUrl(options.host, bffPort))) {
954
+ throw new Error(`Managed BFF did not become ready on port ${bffPort}`);
955
+ }
956
+ }
883
957
  const nextProcess = (0, child_process_1.spawn)(pm === 'pnpm' ? 'pnpm' : 'npx', nextArgs, {
884
958
  cwd: process.cwd(),
885
959
  shell: true,
@@ -888,22 +962,19 @@ async function startDevEnvironment(options) {
888
962
  });
889
963
  processes.push(nextProcess);
890
964
  nextProcess.on('error', (error) => {
891
- console.error('❌ Next.js startup error:', error.message);
965
+ console.error(`❌ ${frontendLabel} startup error:`, error.message);
966
+ stopDevProcesses(processes);
892
967
  process.exit(1);
893
968
  });
894
969
  nextProcess.on('close', (code) => {
895
970
  if (code !== 0) {
896
- console.log(`\n⏹️ Next.js exited (exit code: ${code})`);
971
+ console.log(`\n⏹️ ${frontendLabel} exited (exit code: ${code})`);
897
972
  }
898
- // Exit all processes when Next.js exits
973
+ // Exit all owned processes when the frontend exits.
899
974
  if (mockServer) {
900
975
  mockServer.stop().catch(() => { });
901
976
  }
902
- processes.forEach((proc) => {
903
- if (proc && !proc.killed) {
904
- proc.kill();
905
- }
906
- });
977
+ stopDevProcesses(processes);
907
978
  process.exit(code || 0);
908
979
  });
909
980
  if (functionsReadinessPromise) {
@@ -919,13 +990,13 @@ async function startDevEnvironment(options) {
919
990
  let swaReady = false;
920
991
  if (useSwaEmulator && swaCommand) {
921
992
  const nextUrl = `http://${options.host || 'localhost'}:${port}`;
922
- console.log(`⏳ Waiting for Next.js before starting the SWA emulator at ${nextUrl}...`);
993
+ console.log(`⏳ Waiting for ${frontendLabel} before starting the SWA emulator at ${nextUrl}...`);
923
994
  const nextReady = await waitForHttpServerReady(nextUrl);
924
995
  if (!nextReady) {
925
- throw new Error(`Next.js did not become ready at ${nextUrl}`);
996
+ throw new Error(`${frontendLabel} did not become ready at ${nextUrl}`);
926
997
  }
927
- console.log(`🔐 Starting SWA authentication emulator (port: ${swaPort})...`);
928
- const swaProcess = (0, child_process_1.spawn)(swaCommand, buildSwaStartArgs(options.host, port, swaPort), {
998
+ console.log(`🔐 Starting SWA routing/authentication emulator (port: ${swaPort})...`);
999
+ const swaProcess = (0, child_process_1.spawn)(swaCommand, buildSwaStartArgs(options.host, port, swaPort, react ? bffPort : undefined), {
929
1000
  cwd: process.cwd(),
930
1001
  shell: true,
931
1002
  stdio: 'inherit',
@@ -938,7 +1009,7 @@ async function startDevEnvironment(options) {
938
1009
  const swaUrl = `http://${options.host || 'localhost'}:${swaPort}`;
939
1010
  swaReady = await waitForHttpServerReady(swaUrl);
940
1011
  if (!swaReady) {
941
- throw new Error(`SWA authentication emulator did not become ready at ${swaUrl}`);
1012
+ throw new Error(`SWA routing/authentication emulator did not become ready at ${swaUrl}`);
942
1013
  }
943
1014
  }
944
1015
  console.log('');
@@ -946,19 +1017,26 @@ async function startDevEnvironment(options) {
946
1017
  console.log('');
947
1018
  if (useSwaEmulator) {
948
1019
  const swaUrl = `http://${options.host || 'localhost'}:${swaPort}`;
949
- console.log('🔐 SWA authenticated app:');
1020
+ console.log('🔐 SWA app (same-origin frontend and BFF):');
950
1021
  console.log(` ${swaUrl}`);
951
1022
  console.log('');
952
- console.log('🔑 Local sign-in:');
953
- console.log(` ${swaUrl}/.auth/login/aad`);
954
- console.log(' Enter any username and select Login.');
955
- console.log(' The "authenticated" role is added automatically.');
956
- console.log('');
957
- console.log('📱 Next.js direct access (authentication is not emulated):');
1023
+ if (swaScheme) {
1024
+ const provider = swaScheme.swa?.allowedProviders?.[0] || 'aad';
1025
+ console.log('🔑 Local SWA sign-in:');
1026
+ console.log(` ${swaUrl}/.auth/login/${provider}`);
1027
+ console.log(' Enter any username and select Login.');
1028
+ console.log(' The "authenticated" role is added automatically.');
1029
+ console.log('');
1030
+ }
1031
+ if (authSchemes.some(scheme => scheme.provider === 'custom-jwt')) {
1032
+ console.log(`🔑 Application sign-in: ${swaUrl}/login`);
1033
+ console.log('');
1034
+ }
1035
+ console.log(`📱 ${frontendLabel} direct access (SWA routing/authentication is not emulated):`);
958
1036
  console.log(` http://${options.host || 'localhost'}:${port}`);
959
1037
  }
960
1038
  else {
961
- console.log(`📱 Next.js: http://${options.host || 'localhost'}:${port}`);
1039
+ console.log(`📱 ${frontendLabel}: http://${options.host || 'localhost'}:${port}`);
962
1040
  }
963
1041
  if (hasFunctions && !options.noFunctions) {
964
1042
  console.log(`${functionsReady ? '⚡ Azure Functions' : '⏳ Azure Functions (starting)'}: ${functionsBaseUrl}`);
@@ -968,7 +1046,7 @@ async function startDevEnvironment(options) {
968
1046
  }
969
1047
  console.log('');
970
1048
  if (hasFunctions && !options.noFunctions && functionsReady) {
971
- console.log('💡 Azure Functions and Next.js BFF are connected');
1049
+ console.log(`💡 Azure Functions and ${react ? 'managed Functions' : 'Next.js'} BFF are connected`);
972
1050
  }
973
1051
  else if (hasFunctions && !options.noFunctions) {
974
1052
  console.log('💡 Azure Functions is still warming up; BFF routes can fail until the backend responds.');
@@ -979,6 +1057,8 @@ async function startDevEnvironment(options) {
979
1057
  if (swaReady) {
980
1058
  console.log('💡 Open the app through the SWA port when testing authenticated pages and CRUD APIs.');
981
1059
  }
1060
+ if (react)
1061
+ console.log(`🔀 Managed BFF: ${buildFunctionsBaseUrl(options.host, bffPort)} (not the standalone Functions endpoint)`);
982
1062
  console.log('');
983
1063
  if (options.open) {
984
1064
  const url = useSwaEmulator
@@ -995,11 +1075,7 @@ async function startDevEnvironment(options) {
995
1075
  }
996
1076
  catch (error) {
997
1077
  console.error('❌ Failed to start development environment:', error instanceof Error ? error.message : error);
998
- processes.forEach((proc) => {
999
- if (proc && !proc.killed) {
1000
- proc.kill();
1001
- }
1002
- });
1078
+ stopDevProcesses(processes);
1003
1079
  process.exit(1);
1004
1080
  }
1005
1081
  }