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.
- 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 +103 -27
- package/dist/cli/commands/add-auth.js.map +1 -1
- package/dist/cli/commands/configure-mcp.d.ts +12 -0
- package/dist/cli/commands/configure-mcp.d.ts.map +1 -0
- package/dist/cli/commands/configure-mcp.js +42 -0
- package/dist/cli/commands/configure-mcp.js.map +1 -0
- package/dist/cli/commands/dev.d.ts +5 -2
- package/dist/cli/commands/dev.d.ts.map +1 -1
- package/dist/cli/commands/dev.js +143 -67
- package/dist/cli/commands/dev.js.map +1 -1
- package/dist/cli/commands/init.d.ts +14 -7
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +149 -170
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/migrations.d.ts.map +1 -1
- package/dist/cli/commands/migrations.js +25 -0
- package/dist/cli/commands/migrations.js.map +1 -1
- package/dist/cli/commands/provision.d.ts +5 -0
- package/dist/cli/commands/provision.d.ts.map +1 -1
- package/dist/cli/commands/provision.js +278 -55
- package/dist/cli/commands/provision.js.map +1 -1
- package/dist/cli/commands/scaffold.d.ts +5 -1
- package/dist/cli/commands/scaffold.d.ts.map +1 -1
- package/dist/cli/commands/scaffold.js +123 -18
- package/dist/cli/commands/scaffold.js.map +1 -1
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +49 -8
- 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/operations/create-model.d.ts +2 -0
- package/dist/core/operations/create-model.d.ts.map +1 -1
- package/dist/core/operations/create-model.js +60 -8
- package/dist/core/operations/create-model.js.map +1 -1
- package/dist/core/operations/migration-generator.d.ts.map +1 -1
- package/dist/core/operations/migration-generator.js +12 -1
- package/dist/core/operations/migration-generator.js.map +1 -1
- package/dist/core/operations/model-migration.d.ts +22 -0
- package/dist/core/operations/model-migration.d.ts.map +1 -0
- package/dist/core/operations/model-migration.js +36 -0
- package/dist/core/operations/model-migration.js.map +1 -0
- package/dist/core/operations/provision-deployment.d.ts +52 -0
- package/dist/core/operations/provision-deployment.d.ts.map +1 -0
- package/dist/core/operations/provision-deployment.js +164 -0
- package/dist/core/operations/provision-deployment.js.map +1 -0
- package/dist/core/operations/provision-operations.d.ts +62 -6
- package/dist/core/operations/provision-operations.d.ts.map +1 -1
- package/dist/core/operations/provision-operations.js +653 -115
- package/dist/core/operations/provision-operations.js.map +1 -1
- package/dist/core/operations/scaffold-apply.d.ts +1 -0
- package/dist/core/operations/scaffold-apply.d.ts.map +1 -1
- package/dist/core/operations/scaffold-apply.js +1 -0
- package/dist/core/operations/scaffold-apply.js.map +1 -1
- package/dist/core/operations/scaffold-machine.d.ts +1 -0
- package/dist/core/operations/scaffold-machine.d.ts.map +1 -1
- package/dist/core/operations/scaffold-machine.js.map +1 -1
- package/dist/core/operations/scaffold-plan.d.ts +2 -0
- package/dist/core/operations/scaffold-plan.d.ts.map +1 -1
- package/dist/core/operations/scaffold-plan.js +3 -1
- package/dist/core/operations/scaffold-plan.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 +15 -0
- package/dist/core/project/agent-instructions.js.map +1 -1
- package/dist/core/project/boundaries.d.ts +5 -2
- package/dist/core/project/boundaries.d.ts.map +1 -1
- package/dist/core/project/boundaries.js +51 -20
- package/dist/core/project/boundaries.js.map +1 -1
- package/dist/core/project/capabilities.d.ts +17 -0
- package/dist/core/project/capabilities.d.ts.map +1 -1
- package/dist/core/project/capabilities.js +45 -6
- package/dist/core/project/capabilities.js.map +1 -1
- package/dist/core/project/home-page.d.ts +4 -0
- package/dist/core/project/home-page.d.ts.map +1 -0
- package/dist/core/project/home-page.js +113 -0
- package/dist/core/project/home-page.js.map +1 -0
- 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/mcp-config.d.ts +26 -0
- package/dist/core/project/mcp-config.d.ts.map +1 -0
- package/dist/core/project/mcp-config.js +117 -0
- package/dist/core/project/mcp-config.js.map +1 -0
- 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 +443 -0
- package/dist/core/project/react-project.js.map +1 -0
- package/dist/core/project/state.d.ts +7 -0
- package/dist/core/project/state.d.ts.map +1 -1
- package/dist/core/project/state.js +86 -0
- package/dist/core/project/state.js.map +1 -1
- 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/project/workflows.d.ts.map +1 -1
- package/dist/core/project/workflows.js +53 -7
- package/dist/core/project/workflows.js.map +1 -1
- package/dist/core/scaffold/auth-generator.d.ts.map +1 -1
- package/dist/core/scaffold/auth-generator.js +26 -27
- package/dist/core/scaffold/auth-generator.js.map +1 -1
- package/dist/core/scaffold/model-parser.d.ts +23 -0
- package/dist/core/scaffold/model-parser.d.ts.map +1 -1
- package/dist/core/scaffold/model-parser.js +407 -137
- package/dist/core/scaffold/model-parser.js.map +1 -1
- package/dist/core/scaffold/native-schema-generator.d.ts +13 -0
- package/dist/core/scaffold/native-schema-generator.d.ts.map +1 -1
- package/dist/core/scaffold/native-schema-generator.js +294 -91
- package/dist/core/scaffold/native-schema-generator.js.map +1 -1
- package/dist/core/scaffold/openapi-generator.d.ts +5 -0
- package/dist/core/scaffold/openapi-generator.d.ts.map +1 -1
- package/dist/core/scaffold/openapi-generator.js +53 -3
- package/dist/core/scaffold/openapi-generator.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/core/scaffold/ui-generator.d.ts +0 -3
- package/dist/core/scaffold/ui-generator.d.ts.map +1 -1
- package/dist/core/scaffold/ui-generator.js +68 -7
- package/dist/core/scaffold/ui-generator.js.map +1 -1
- package/dist/core/verify/index.d.ts +4 -3
- package/dist/core/verify/index.d.ts.map +1 -1
- package/dist/core/verify/index.js +122 -5
- package/dist/core/verify/index.js.map +1 -1
- 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/contracts.d.ts +1 -0
- package/dist/machine/contracts.d.ts.map +1 -1
- package/dist/machine/errors.d.ts +3 -2
- package/dist/machine/errors.d.ts.map +1 -1
- package/dist/machine/errors.js +2 -1
- package/dist/machine/errors.js.map +1 -1
- package/dist/machine/index.d.ts.map +1 -1
- package/dist/machine/index.js +61 -30
- package/dist/machine/index.js.map +1 -1
- package/dist/mcp/index.d.ts +6 -4
- package/dist/mcp/index.d.ts.map +1 -1
- package/dist/mcp/index.js +210 -25
- package/dist/mcp/index.js.map +1 -1
- package/dist/mcp/version-selection.d.ts +55 -0
- package/dist/mcp/version-selection.d.ts.map +1 -0
- package/dist/mcp/version-selection.js +152 -0
- package/dist/mcp/version-selection.js.map +1 -0
- package/dist/types/index.d.ts +4 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/utils/azure-cli.d.ts +56 -0
- package/dist/utils/azure-cli.d.ts.map +1 -0
- package/dist/utils/azure-cli.js +326 -0
- package/dist/utils/azure-cli.js.map +1 -0
- package/dist/utils/azure-diagnostics.d.ts +16 -0
- package/dist/utils/azure-diagnostics.d.ts.map +1 -0
- package/dist/utils/azure-diagnostics.js +68 -0
- package/dist/utils/azure-diagnostics.js.map +1 -0
- 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 +6 -3
- package/dist/utils/package-manager.js.map +1 -1
- package/dist/utils/python-uv.d.ts +5 -7
- package/dist/utils/python-uv.d.ts.map +1 -1
- package/dist/utils/python-uv.js +50 -24
- package/dist/utils/python-uv.js.map +1 -1
- package/dist/utils/react-dev.d.ts +4 -0
- package/dist/utils/react-dev.d.ts.map +1 -0
- package/dist/utils/react-dev.js +35 -0
- package/dist/utils/react-dev.js.map +1 -0
- package/dist/utils/semver.d.ts +14 -0
- package/dist/utils/semver.d.ts.map +1 -0
- package/dist/utils/semver.js +61 -0
- package/dist/utils/semver.js.map +1 -0
- package/package.json +7 -4
- package/src/__tests__/__snapshots__/boundaries.test.ts.snap +154 -0
- package/src/__tests__/agent-instructions.test.ts +6 -1
- package/src/__tests__/agent-loop-phase34.test.ts +143 -8
- package/src/__tests__/auth.test.ts +9 -0
- package/src/__tests__/azure-cli.test.ts +202 -0
- package/src/__tests__/boundaries.test.ts +42 -0
- package/src/__tests__/csharp-schema.test.ts +261 -0
- package/src/__tests__/dev.test.ts +13 -6
- package/src/__tests__/fixtures/az wrapper.cmd +2 -0
- package/src/__tests__/fixtures/azure-cli.cjs +153 -0
- package/src/__tests__/fixtures/provision-runner.cjs +28 -0
- package/src/__tests__/generated-project-matrix.test.ts +789 -0
- package/src/__tests__/home-page.test.ts +50 -0
- package/src/__tests__/init.test.ts +145 -5
- package/src/__tests__/mcp-version.test.ts +262 -0
- package/src/__tests__/mcp.test.ts +120 -3
- package/src/__tests__/multi-auth.test.ts +115 -4
- package/src/__tests__/package-manager.test.ts +17 -2
- package/src/__tests__/plan-apply.test.ts +179 -0
- package/src/__tests__/provision-runtime.test.ts +722 -0
- package/src/__tests__/python-uv.test.ts +50 -14
- package/src/__tests__/python-venv.test.ts +48 -0
- package/src/__tests__/react-dev.test.ts +72 -0
- package/src/__tests__/react.test.ts +838 -0
- package/src/__tests__/release-metadata.test.ts +121 -0
- package/src/__tests__/schema-analysis.test.ts +329 -0
- package/src/cli/commands/add-auth.ts +103 -29
- package/src/cli/commands/configure-mcp.ts +54 -0
- package/src/cli/commands/dev.ts +145 -73
- package/src/cli/commands/init.ts +147 -172
- package/src/cli/commands/migrations.ts +22 -0
- package/src/cli/commands/provision.ts +294 -56
- package/src/cli/commands/scaffold.ts +145 -22
- package/src/cli/index.ts +46 -10
- package/src/core/config.ts +21 -1
- package/src/core/operations/create-model.ts +51 -13
- package/src/core/operations/migration-generator.ts +14 -1
- package/src/core/operations/model-migration.ts +52 -0
- package/src/core/operations/provision-deployment.ts +183 -0
- package/src/core/operations/provision-operations.ts +662 -154
- package/src/core/operations/scaffold-apply.ts +2 -0
- package/src/core/operations/scaffold-machine.ts +1 -0
- package/src/core/operations/scaffold-plan.ts +5 -1
- package/src/core/project/agent-instructions.ts +17 -1
- package/src/core/project/agent-templates/AGENTS.md +113 -15
- package/src/core/project/agent-templates/CLAUDE.md +14 -1
- package/src/core/project/agent-templates/bff-routes.instructions.md +5 -3
- package/src/core/project/agent-templates/copilot-instructions.md +15 -1
- package/src/core/project/agent-templates/shared-models.instructions.md +11 -3
- package/src/core/project/boundaries.ts +62 -20
- package/src/core/project/capabilities.ts +63 -6
- package/src/core/project/home-page.ts +114 -0
- package/src/core/project/manifest.ts +52 -27
- package/src/core/project/mcp-config.ts +84 -0
- package/src/core/project/react-project.ts +529 -0
- package/src/core/project/state.ts +70 -0
- package/src/core/project/validation.ts +32 -10
- package/src/core/project/workflows.ts +53 -7
- package/src/core/scaffold/auth-generator.ts +26 -27
- package/src/core/scaffold/model-parser.ts +413 -129
- package/src/core/scaffold/native-schema-generator.ts +319 -103
- package/src/core/scaffold/openapi-generator.ts +63 -5
- package/src/core/scaffold/react-bff-generator.ts +292 -0
- package/src/core/scaffold/react-ui-generator.ts +51 -0
- package/src/core/scaffold/ui-generator.ts +70 -8
- package/src/core/verify/index.ts +118 -6
- package/src/index.ts +3 -1
- package/src/machine/contracts.ts +1 -0
- package/src/machine/errors.ts +4 -2
- package/src/machine/index.ts +67 -36
- package/src/mcp/index.ts +221 -31
- package/src/mcp/version-selection.ts +163 -0
- package/src/types/index.ts +4 -0
- package/src/utils/azure-cli.ts +315 -0
- package/src/utils/azure-diagnostics.ts +75 -0
- package/src/utils/package-manager.ts +7 -4
- package/src/utils/python-uv.ts +53 -33
- package/src/utils/react-dev.ts +31 -0
- package/src/utils/semver.ts +59 -0
|
@@ -48,7 +48,11 @@ exports.buildCSharpFunctionsProjectSource = buildCSharpFunctionsProjectSource;
|
|
|
48
48
|
exports.buildSwallowKitConfigSource = buildSwallowKitConfigSource;
|
|
49
49
|
exports.buildGeneratedProjectDependencies = buildGeneratedProjectDependencies;
|
|
50
50
|
exports.buildGeneratedProjectDevDependencies = buildGeneratedProjectDevDependencies;
|
|
51
|
+
exports.ensureNextTailwindPostcssConfig = ensureNextTailwindPostcssConfig;
|
|
51
52
|
exports.buildSwallowKitMcpProjectConfigSource = buildSwallowKitMcpProjectConfigSource;
|
|
53
|
+
exports.selectInitialMcpVersion = selectInitialMcpVersion;
|
|
54
|
+
exports.createSharedPackage = createSharedPackage;
|
|
55
|
+
exports.createAzureFunctionsProject = createAzureFunctionsProject;
|
|
52
56
|
exports.buildTypeScriptFunctionsPackageJson = buildTypeScriptFunctionsPackageJson;
|
|
53
57
|
exports.buildFunctionsHostKeyBicepExpression = buildFunctionsHostKeyBicepExpression;
|
|
54
58
|
exports.buildStaticWebAppConfigBicepSource = buildStaticWebAppConfigBicepSource;
|
|
@@ -62,6 +66,7 @@ const fs = __importStar(require("fs"));
|
|
|
62
66
|
const path = __importStar(require("path"));
|
|
63
67
|
const child_process_1 = require("child_process");
|
|
64
68
|
const prompts_1 = __importDefault(require("prompts"));
|
|
69
|
+
const react_project_1 = require("../../core/project/react-project");
|
|
65
70
|
const package_manager_1 = require("../../utils/package-manager");
|
|
66
71
|
const manifest_1 = require("../../core/project/manifest");
|
|
67
72
|
const workflows_1 = require("../../core/project/workflows");
|
|
@@ -69,6 +74,8 @@ const agent_instructions_1 = require("../../core/project/agent-instructions");
|
|
|
69
74
|
const migration_generator_1 = require("../../core/operations/migration-generator");
|
|
70
75
|
const native_schema_generator_1 = require("../../core/scaffold/native-schema-generator");
|
|
71
76
|
const python_uv_1 = require("../../utils/python-uv");
|
|
77
|
+
const home_page_1 = require("../../core/project/home-page");
|
|
78
|
+
const mcp_config_1 = require("../../core/project/mcp-config");
|
|
72
79
|
function getStaticWebAppSku(plan) {
|
|
73
80
|
return plan === 'free' ? 'Free' : 'Standard';
|
|
74
81
|
}
|
|
@@ -156,7 +163,7 @@ function getFunctionsRuntimeConfig(backendLanguage) {
|
|
|
156
163
|
return { name: "dotnet-isolated", version: "10.0" };
|
|
157
164
|
}
|
|
158
165
|
if (backendLanguage === "python") {
|
|
159
|
-
return { name: "python", version:
|
|
166
|
+
return { name: "python", version: python_uv_1.DEFAULT_AZURE_PYTHON_VERSION };
|
|
160
167
|
}
|
|
161
168
|
return { name: "node", version: "22" };
|
|
162
169
|
}
|
|
@@ -260,6 +267,9 @@ const VALID_COSMOS_DB_MODE = ['freetier', 'serverless'];
|
|
|
260
267
|
const VALID_VNET = ['none', 'outbound'];
|
|
261
268
|
const VALID_SWA_PLAN = ['free', 'standard'];
|
|
262
269
|
function validateInitFlags(options) {
|
|
270
|
+
if (options.frontend && !["nextjs", "react"].includes(options.frontend)) {
|
|
271
|
+
throw new Error("Invalid --frontend: expected nextjs or react");
|
|
272
|
+
}
|
|
263
273
|
if (options.packageManager && !['npm', 'pnpm'].includes(options.packageManager)) {
|
|
264
274
|
throw new Error('Invalid --package-manager: expected npm or pnpm');
|
|
265
275
|
}
|
|
@@ -320,24 +330,36 @@ async function initCommand(options) {
|
|
|
320
330
|
process.exit(1);
|
|
321
331
|
}
|
|
322
332
|
}
|
|
333
|
+
// Preserve existing non-interactive invocations while offering a frontend choice in the wizard.
|
|
334
|
+
const frontend = options.frontend ?? (interactive
|
|
335
|
+
? (await (0, prompts_1.default)({
|
|
336
|
+
type: "select", name: "frontend", message: "Frontend framework:",
|
|
337
|
+
choices: [{ title: "Next.js (App Router)", value: "nextjs" }, { title: "React (Vite SPA + SWA managed Functions BFF)", value: "react" }],
|
|
338
|
+
initial: 0,
|
|
339
|
+
})).frontend || "nextjs"
|
|
340
|
+
: "nextjs");
|
|
341
|
+
options = { ...options, frontend };
|
|
323
342
|
// Use flag values if provided, otherwise prompt interactively
|
|
324
343
|
const cicdProvider = options.cicd || await promptCiCd();
|
|
325
344
|
const backendLanguage = options.backendLanguage || await promptBackendLanguage();
|
|
326
345
|
const azureConfig = await promptAzureConfig(options);
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
346
|
+
if (frontend === "react") {
|
|
347
|
+
(0, react_project_1.createReactProject)(projectDir, options.name, pm);
|
|
348
|
+
}
|
|
349
|
+
else {
|
|
350
|
+
await createNextJsProject(options.name, pm);
|
|
351
|
+
await upgradeNextJs(projectDir, options.nextVersion || 'latest', pm);
|
|
352
|
+
}
|
|
331
353
|
// Add SwallowKit specific files
|
|
332
354
|
await addSwallowKitFiles(projectDir, options, cicdProvider, azureConfig, pm, backendLanguage);
|
|
333
355
|
// Create infrastructure files (Bicep)
|
|
334
356
|
await createInfrastructure(projectDir, options.name, azureConfig, backendLanguage);
|
|
335
357
|
// Create CI/CD files based on choice
|
|
336
358
|
if (cicdProvider === 'github') {
|
|
337
|
-
await createGitHubActionsWorkflows(projectDir, azureConfig, pm, backendLanguage);
|
|
359
|
+
await createGitHubActionsWorkflows(projectDir, azureConfig, pm, backendLanguage, frontend);
|
|
338
360
|
}
|
|
339
361
|
else if (cicdProvider === 'azure') {
|
|
340
|
-
await createAzurePipelines(projectDir, pm, backendLanguage);
|
|
362
|
+
await createAzurePipelines(projectDir, pm, backendLanguage, frontend);
|
|
341
363
|
}
|
|
342
364
|
await (0, manifest_1.syncProjectManifest)(projectDir);
|
|
343
365
|
// Initialize Git repository and create initial commit
|
|
@@ -588,7 +610,11 @@ function parseIgnoredBuilds(output) {
|
|
|
588
610
|
return Array.from(new Set(list));
|
|
589
611
|
}
|
|
590
612
|
function injectSwallowKitNextConfig(nextConfigContent, projectName) {
|
|
591
|
-
|
|
613
|
+
const compatibleConfig = nextConfigContent.replace(/(\b(?:cacheComponents|partialPrefetching)\s*:\s*)true\b/g, '$1false');
|
|
614
|
+
const cacheComponentsSetting = /\bcacheComponents\s*:/.test(compatibleConfig)
|
|
615
|
+
? ''
|
|
616
|
+
: ' cacheComponents: false,\n';
|
|
617
|
+
return compatibleConfig.replace(/(const\s+nextConfig[:\s]*(?::\s*NextConfig\s*)?=\s*\{)(\s*\/\*[^*]*\*\/)?/, `$1\n output: 'standalone',\n${cacheComponentsSetting} agentRules: false, // SwallowKit owns the canonical root AGENTS.md contract\n transpilePackages: ['@${projectName}/shared'],\n serverExternalPackages: ['applicationinsights', 'diagnostic-channel-publishers'],$2`);
|
|
592
618
|
}
|
|
593
619
|
function buildCSharpFunctionsProgramSource() {
|
|
594
620
|
return `using Microsoft.Azure.Functions.Worker;
|
|
@@ -623,7 +649,7 @@ function buildCSharpFunctionsProjectSource() {
|
|
|
623
649
|
<None Remove="generated\\**\\bin\\**;generated\\**\\obj\\**" />
|
|
624
650
|
</ItemGroup>
|
|
625
651
|
<ItemGroup>
|
|
626
|
-
<PackageReference Include="Microsoft.Azure.Cosmos" Version="3.
|
|
652
|
+
<PackageReference Include="Microsoft.Azure.Cosmos" Version="3.63.2" />
|
|
627
653
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
|
628
654
|
<PackageReference Include="Azure.Identity" Version="1.17.0" />
|
|
629
655
|
<PackageReference Include="Microsoft.Azure.Functions.Worker" Version="2.52.0" />
|
|
@@ -635,8 +661,11 @@ function buildCSharpFunctionsProjectSource() {
|
|
|
635
661
|
</Project>
|
|
636
662
|
`;
|
|
637
663
|
}
|
|
638
|
-
function buildSwallowKitConfigSource(backendLanguage) {
|
|
664
|
+
function buildSwallowKitConfigSource(backendLanguage, frontend = "nextjs") {
|
|
639
665
|
return `module.exports = {
|
|
666
|
+
frontend: {
|
|
667
|
+
framework: '${frontend}',
|
|
668
|
+
},
|
|
640
669
|
backend: {
|
|
641
670
|
language: '${backendLanguage}',
|
|
642
671
|
},
|
|
@@ -650,10 +679,9 @@ function buildSwallowKitConfigSource(backendLanguage) {
|
|
|
650
679
|
}
|
|
651
680
|
`;
|
|
652
681
|
}
|
|
653
|
-
function buildGeneratedProjectDependencies(projectName, pm = 'pnpm') {
|
|
682
|
+
function buildGeneratedProjectDependencies(projectName, pm = 'pnpm', frontend = "nextjs") {
|
|
654
683
|
return {
|
|
655
|
-
'@azure/cosmos': '^4.0.0',
|
|
656
|
-
'applicationinsights': '^3.3.0',
|
|
684
|
+
...(frontend === "nextjs" ? { '@azure/cosmos': '^4.0.0', 'applicationinsights': '^3.3.0' } : {}),
|
|
657
685
|
'zod': '^4.0.0',
|
|
658
686
|
[`@${projectName}/shared`]: pm === 'pnpm' ? 'workspace:*' : 'file:shared',
|
|
659
687
|
};
|
|
@@ -675,13 +703,27 @@ function getSwallowKitPackageMetadata() {
|
|
|
675
703
|
version: "latest",
|
|
676
704
|
};
|
|
677
705
|
}
|
|
678
|
-
function buildGeneratedProjectDevDependencies() {
|
|
706
|
+
function buildGeneratedProjectDevDependencies(frontend = "nextjs") {
|
|
679
707
|
const { name, version } = getSwallowKitPackageMetadata();
|
|
680
708
|
return {
|
|
681
709
|
[name]: version,
|
|
710
|
+
...(frontend === "nextjs" ? { "@tailwindcss/postcss": "^4.0.0" } : {}),
|
|
682
711
|
};
|
|
683
712
|
}
|
|
684
|
-
function
|
|
713
|
+
function ensureNextTailwindPostcssConfig(projectDir) {
|
|
714
|
+
if (["postcss.config.mjs", "postcss.config.js", "postcss.config.cjs", "postcss.config.json"]
|
|
715
|
+
.some(file => fs.existsSync(path.join(projectDir, file)))) {
|
|
716
|
+
return;
|
|
717
|
+
}
|
|
718
|
+
// New create-next-app templates can configure Tailwind for Turbopack only.
|
|
719
|
+
fs.writeFileSync(path.join(projectDir, "postcss.config.mjs"), `export default {
|
|
720
|
+
plugins: {
|
|
721
|
+
"@tailwindcss/postcss": {},
|
|
722
|
+
},
|
|
723
|
+
};
|
|
724
|
+
`);
|
|
725
|
+
}
|
|
726
|
+
function buildSwallowKitMcpProjectConfigSource(pm = 'pnpm', mcpVersion = mcp_config_1.MCP_LATEST) {
|
|
685
727
|
const { name } = getSwallowKitPackageMetadata();
|
|
686
728
|
return JSON.stringify({
|
|
687
729
|
mcpServers: {
|
|
@@ -692,31 +734,43 @@ function buildSwallowKitMcpProjectConfigSource(pm = 'pnpm') {
|
|
|
692
734
|
: ["--yes", "--package", `${name}@\${SWALLOWKIT_MCP_VERSION}`, "swallowkit-mcp"],
|
|
693
735
|
cwd: ".",
|
|
694
736
|
env: {
|
|
695
|
-
SWALLOWKIT_MCP_VERSION:
|
|
737
|
+
SWALLOWKIT_MCP_VERSION: mcpVersion,
|
|
696
738
|
},
|
|
697
739
|
},
|
|
698
740
|
},
|
|
699
741
|
}, null, 2);
|
|
700
742
|
}
|
|
743
|
+
/** latest by default; pinned to this CLI version only when it is newer than published latest. */
|
|
744
|
+
function selectInitialMcpVersion(lookupLatest = mcp_config_1.lookupPublishedLatestVersion) {
|
|
745
|
+
const { name, version } = getSwallowKitPackageMetadata();
|
|
746
|
+
if (version === mcp_config_1.MCP_LATEST)
|
|
747
|
+
return { version: mcp_config_1.MCP_LATEST, reason: "SwallowKit package metadata is unavailable." };
|
|
748
|
+
return (0, mcp_config_1.resolveMcpPinVersion)(version, lookupLatest(name));
|
|
749
|
+
}
|
|
701
750
|
async function addSwallowKitFiles(projectDir, options, cicdChoice, azureConfig, pm, backendLanguage) {
|
|
702
751
|
console.log('📦 Adding SwallowKit files...\n');
|
|
703
752
|
const projectName = options.name;
|
|
753
|
+
const frontend = options.frontend ?? "nextjs";
|
|
704
754
|
// 1. Update package.json to add runtime dependencies for generated projects
|
|
705
755
|
const packageJsonPath = path.join(projectDir, 'package.json');
|
|
706
756
|
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
|
|
707
757
|
// Root BFF/auth code imports Zod directly; declare it as well as the shared package.
|
|
708
758
|
packageJson.dependencies = {
|
|
709
759
|
...packageJson.dependencies,
|
|
710
|
-
...buildGeneratedProjectDependencies(projectName, pm),
|
|
760
|
+
...buildGeneratedProjectDependencies(projectName, pm, frontend),
|
|
711
761
|
};
|
|
712
762
|
packageJson.devDependencies = {
|
|
713
763
|
...packageJson.devDependencies,
|
|
714
|
-
...buildGeneratedProjectDevDependencies(),
|
|
764
|
+
...buildGeneratedProjectDevDependencies(frontend),
|
|
715
765
|
};
|
|
716
766
|
packageJson.scripts = {
|
|
717
767
|
...packageJson.scripts,
|
|
718
|
-
'build': (0, package_manager_1.getBuildScript)(pm),
|
|
719
|
-
'start': 'next start',
|
|
768
|
+
'build': (0, package_manager_1.getBuildScript)(pm, frontend),
|
|
769
|
+
'start': frontend === "react" ? "vite preview" : 'next start',
|
|
770
|
+
...(frontend === "react" ? {
|
|
771
|
+
typecheck: `tsc --noEmit && ${(0, package_manager_1.getCommands)(pm).exec} tsc --noEmit -p bff`,
|
|
772
|
+
"bff:start": `${(0, package_manager_1.getCommands)(pm).runFilter("bff")} start`,
|
|
773
|
+
} : {}),
|
|
720
774
|
'functions:start': (0, package_manager_1.getFunctionsStartScript)(pm, backendLanguage),
|
|
721
775
|
};
|
|
722
776
|
packageJson.engines = {
|
|
@@ -728,16 +782,18 @@ async function addSwallowKitFiles(projectDir, options, cicdChoice, azureConfig,
|
|
|
728
782
|
};
|
|
729
783
|
delete packageJson.packageManager;
|
|
730
784
|
// Keep package.json workspaces for npm-based CI/CD even when local development uses pnpm.
|
|
731
|
-
const workspacePackages = usesNodeFunctionsProject(backendLanguage) ? ['shared', 'functions'] : ['shared'];
|
|
785
|
+
const workspacePackages = [...(usesNodeFunctionsProject(backendLanguage) ? ['shared', 'functions'] : ['shared']), ...(frontend === "react" ? ["bff"] : [])];
|
|
732
786
|
const wsConfig = (0, package_manager_1.getWorkspaceConfig)(pm, workspacePackages);
|
|
733
787
|
packageJson.workspaces = workspacePackages;
|
|
734
788
|
if (wsConfig.type !== 'file') {
|
|
735
789
|
packageJson.workspaces = wsConfig.value;
|
|
736
790
|
}
|
|
737
791
|
fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2));
|
|
792
|
+
if (frontend === "nextjs")
|
|
793
|
+
ensureNextTailwindPostcssConfig(projectDir);
|
|
738
794
|
// Create pnpm-workspace.yaml for local pnpm development when needed.
|
|
739
795
|
if (wsConfig.type === 'file') {
|
|
740
|
-
fs.writeFileSync(path.join(projectDir, wsConfig.filename), wsConfig.content);
|
|
796
|
+
fs.writeFileSync(path.join(projectDir, wsConfig.filename), wsConfig.content + (frontend === "react" ? " esbuild: true\n" : ""));
|
|
741
797
|
}
|
|
742
798
|
// Don't install yet — wait until all workspace packages (shared, functions) are created
|
|
743
799
|
// 2. Update next.config to add standalone output
|
|
@@ -770,17 +826,18 @@ async function addSwallowKitFiles(projectDir, options, cicdChoice, azureConfig,
|
|
|
770
826
|
fs.writeFileSync(tsconfigPath, JSON.stringify(tsconfig, null, 2));
|
|
771
827
|
}
|
|
772
828
|
// 3. Create SwallowKit config
|
|
773
|
-
const swallowkitConfig = buildSwallowKitConfigSource(backendLanguage);
|
|
829
|
+
const swallowkitConfig = buildSwallowKitConfigSource(backendLanguage, frontend);
|
|
774
830
|
fs.writeFileSync(path.join(projectDir, 'swallowkit.config.js'), swallowkitConfig);
|
|
775
831
|
// 4. Create shared workspace package for Zod models (Single Source of Truth)
|
|
776
832
|
await createSharedPackage(projectDir, projectName);
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
833
|
+
if (frontend === "nextjs") {
|
|
834
|
+
// Create lib directory for Next.js-specific utilities
|
|
835
|
+
const libDir = path.join(projectDir, 'lib');
|
|
836
|
+
// Create lib/api directory for backend utilities
|
|
837
|
+
const apiLibDir = path.join(libDir, 'api');
|
|
838
|
+
fs.mkdirSync(apiLibDir, { recursive: true });
|
|
839
|
+
// Create backend utility for calling Azure Functions
|
|
840
|
+
const backendUtilContent = `// Get Functions base URL at runtime (not at build time)
|
|
784
841
|
function getFunctionsBaseUrl(): string {
|
|
785
842
|
return process.env.BACKEND_FUNCTIONS_BASE_URL || process.env.FUNCTIONS_BASE_URL || 'http://localhost:7071';
|
|
786
843
|
}
|
|
@@ -890,7 +947,8 @@ export const api = {
|
|
|
890
947
|
},
|
|
891
948
|
};
|
|
892
949
|
`;
|
|
893
|
-
|
|
950
|
+
fs.writeFileSync(path.join(apiLibDir, 'backend.ts'), backendUtilContent);
|
|
951
|
+
}
|
|
894
952
|
// 5. Create components directory
|
|
895
953
|
const componentsDir = path.join(projectDir, 'components');
|
|
896
954
|
fs.mkdirSync(componentsDir, { recursive: true });
|
|
@@ -976,7 +1034,8 @@ export async function register() {
|
|
|
976
1034
|
}
|
|
977
1035
|
}
|
|
978
1036
|
`;
|
|
979
|
-
|
|
1037
|
+
if (frontend === "nextjs")
|
|
1038
|
+
fs.writeFileSync(path.join(projectDir, 'instrumentation.ts'), instrumentationContent);
|
|
980
1039
|
// 8. Create .env.local for local development
|
|
981
1040
|
const envLocalContent = [
|
|
982
1041
|
'# Azure Functions Backend URL (Local)',
|
|
@@ -1005,21 +1064,30 @@ export async function register() {
|
|
|
1005
1064
|
".json": "application/json"
|
|
1006
1065
|
}
|
|
1007
1066
|
};
|
|
1008
|
-
fs.writeFileSync(path.join(projectDir, 'staticwebapp.config.json'), JSON.stringify(swaConfig, null, 2));
|
|
1067
|
+
fs.writeFileSync(path.join(projectDir, 'staticwebapp.config.json'), JSON.stringify(frontend === "react" ? (0, react_project_1.buildReactSwaConfig)() : swaConfig, null, 2));
|
|
1009
1068
|
// 14. Create Azure Functions project
|
|
1010
1069
|
await createAzureFunctionsProject(projectDir, pm, backendLanguage);
|
|
1011
1070
|
// 15. Create BFF API route to call Azure Functions
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1071
|
+
if (frontend === "react") {
|
|
1072
|
+
(0, react_project_1.createReactBffProject)(projectDir, projectName, pm);
|
|
1073
|
+
}
|
|
1074
|
+
else {
|
|
1075
|
+
await createBffApiRoute(projectDir);
|
|
1076
|
+
await createHomePage(projectDir, pm);
|
|
1077
|
+
}
|
|
1015
1078
|
// 17. Install all workspace dependencies (root + shared + functions)
|
|
1016
1079
|
console.log('📦 Installing workspace dependencies...\n');
|
|
1017
1080
|
await installDependencies(projectDir, pm);
|
|
1018
1081
|
console.log('✅ Project structure created\n');
|
|
1019
1082
|
// 18. Create README.md
|
|
1020
|
-
|
|
1083
|
+
if (frontend === "react") {
|
|
1084
|
+
fs.writeFileSync(path.join(projectDir, "README.md"), (0, react_project_1.buildReactReadme)(projectName, pm, backendLanguage));
|
|
1085
|
+
}
|
|
1086
|
+
else {
|
|
1087
|
+
createReadme(projectDir, projectName, cicdChoice, azureConfig, pm, backendLanguage);
|
|
1088
|
+
}
|
|
1021
1089
|
// 19. Create AI agent instruction files (AGENTS.md, CLAUDE.md, .github/copilot-instructions.md, etc.)
|
|
1022
|
-
createAiAgentFiles(projectDir, projectName, backendLanguage, pm);
|
|
1090
|
+
createAiAgentFiles(projectDir, projectName, backendLanguage, pm, frontend);
|
|
1023
1091
|
}
|
|
1024
1092
|
async function createSharedPackage(projectDir, projectName) {
|
|
1025
1093
|
console.log('📦 Creating shared workspace package for Zod models...\n');
|
|
@@ -1049,7 +1117,7 @@ async function createSharedPackage(projectDir, projectName) {
|
|
|
1049
1117
|
// shared/tsconfig.json
|
|
1050
1118
|
fs.writeFileSync(path.join(sharedDir, 'tsconfig.json'), JSON.stringify(buildSharedTsConfig(), null, 2));
|
|
1051
1119
|
// shared/index.ts (empty re-export file, scaffold will add entries)
|
|
1052
|
-
fs.writeFileSync(path.join(sharedDir, 'index.ts'), `// Shared Zod models
|
|
1120
|
+
fs.writeFileSync(path.join(sharedDir, 'index.ts'), `// Shared Zod models. SwallowKit create-model/scaffold append missing model exports.\n// You may add exports manually; existing exports and comments are preserved. No managed markers.\n`);
|
|
1053
1121
|
// shared/.gitignore
|
|
1054
1122
|
fs.writeFileSync(path.join(sharedDir, '.gitignore'), `node_modules\ndist\n`);
|
|
1055
1123
|
console.log('✅ Shared package created\n');
|
|
@@ -1287,7 +1355,6 @@ public sealed class GreetFunction
|
|
|
1287
1355
|
`);
|
|
1288
1356
|
}
|
|
1289
1357
|
function createPythonFunctionsProject(projectDir, functionsDir) {
|
|
1290
|
-
fs.writeFileSync(path.join(projectDir, '.python-version'), '3.11\n');
|
|
1291
1358
|
ensureProjectGitignoreEntry(projectDir, '.uv');
|
|
1292
1359
|
fs.writeFileSync(path.join(functionsDir, 'requirements.txt'), `azure-functions>=1.20.0
|
|
1293
1360
|
azure-cosmos>=4.9.0
|
|
@@ -1408,114 +1475,7 @@ export async function POST(request: NextRequest) {
|
|
|
1408
1475
|
}
|
|
1409
1476
|
async function createHomePage(projectDir, pm = 'pnpm') {
|
|
1410
1477
|
console.log('📦 Creating home page...\n');
|
|
1411
|
-
|
|
1412
|
-
const pageContent = `'use client'
|
|
1413
|
-
|
|
1414
|
-
export const dynamic = 'force-dynamic';
|
|
1415
|
-
|
|
1416
|
-
import { useState } from 'react';
|
|
1417
|
-
import { scaffoldConfig } from '@/lib/scaffold-config';
|
|
1418
|
-
|
|
1419
|
-
export default function Home() {
|
|
1420
|
-
const [greetingStatus, setGreetingStatus] = useState<'idle' | 'loading' | 'success' | 'error'>('idle');
|
|
1421
|
-
const [message, setMessage] = useState('');
|
|
1422
|
-
|
|
1423
|
-
const testConnection = async () => {
|
|
1424
|
-
setGreetingStatus('loading');
|
|
1425
|
-
try {
|
|
1426
|
-
const response = await fetch('/api/greet?name=SwallowKit');
|
|
1427
|
-
const data = await response.json();
|
|
1428
|
-
if (!response.ok) {
|
|
1429
|
-
throw new Error(data.error || \`Server error: \${response.status}\`);
|
|
1430
|
-
}
|
|
1431
|
-
setMessage(data.message);
|
|
1432
|
-
setGreetingStatus('success');
|
|
1433
|
-
} catch (error) {
|
|
1434
|
-
setMessage(error instanceof Error ? error.message : 'Failed to connect to Azure Functions');
|
|
1435
|
-
setGreetingStatus('error');
|
|
1436
|
-
}
|
|
1437
|
-
};
|
|
1438
|
-
|
|
1439
|
-
return (
|
|
1440
|
-
<div className="min-h-screen bg-gradient-to-br from-blue-50 to-indigo-50 dark:from-gray-900 dark:to-gray-800">
|
|
1441
|
-
<div className="container mx-auto px-4 py-12">
|
|
1442
|
-
<header className="text-center mb-16">
|
|
1443
|
-
<h1 className="text-5xl font-bold text-gray-800 dark:text-white mb-4">
|
|
1444
|
-
Welcome to SwallowKit
|
|
1445
|
-
</h1>
|
|
1446
|
-
<p className="text-xl text-gray-600 dark:text-gray-400">
|
|
1447
|
-
Next.js on Azure Static Web Apps + Functions + Cosmos DB — Zod schema sharing
|
|
1448
|
-
</p>
|
|
1449
|
-
</header>
|
|
1450
|
-
|
|
1451
|
-
{/* Connection Test */}
|
|
1452
|
-
<section className="max-w-2xl mx-auto mb-12">
|
|
1453
|
-
<div className="bg-white dark:bg-gray-800 rounded-xl p-8 border border-gray-200 dark:border-gray-700">
|
|
1454
|
-
<h2 className="text-2xl font-semibold mb-4 text-gray-900 dark:text-gray-100">
|
|
1455
|
-
Test BFF → Functions Connection
|
|
1456
|
-
</h2>
|
|
1457
|
-
<button
|
|
1458
|
-
onClick={testConnection}
|
|
1459
|
-
disabled={greetingStatus === 'loading'}
|
|
1460
|
-
className="px-6 py-3 bg-blue-600 hover:bg-blue-700 disabled:bg-gray-400 text-white rounded-lg font-medium transition-colors"
|
|
1461
|
-
>
|
|
1462
|
-
{greetingStatus === 'loading' ? 'Testing...' : 'Test Connection'}
|
|
1463
|
-
</button>
|
|
1464
|
-
{greetingStatus === 'success' && (
|
|
1465
|
-
<div className="mt-4 p-4 bg-green-50 dark:bg-green-900/20 border border-green-200 dark:border-green-800 rounded-lg">
|
|
1466
|
-
<p className="text-green-800 dark:text-green-200 font-medium">✅ Connection successful!</p>
|
|
1467
|
-
<p className="text-green-700 dark:text-green-300 text-sm mt-1">{message}</p>
|
|
1468
|
-
</div>
|
|
1469
|
-
)}
|
|
1470
|
-
{greetingStatus === 'error' && (
|
|
1471
|
-
<div className="mt-4 p-4 bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800 rounded-lg">
|
|
1472
|
-
<p className="text-red-800 dark:text-red-200 font-medium">❌ Connection failed</p>
|
|
1473
|
-
<p className="text-red-700 dark:text-red-300 text-sm mt-1">{message}</p>
|
|
1474
|
-
</div>
|
|
1475
|
-
)}
|
|
1476
|
-
</div>
|
|
1477
|
-
</section>
|
|
1478
|
-
|
|
1479
|
-
{/* Scaffolded Models Menu */}
|
|
1480
|
-
{scaffoldConfig.models.length > 0 ? (
|
|
1481
|
-
<section className="max-w-6xl mx-auto">
|
|
1482
|
-
<h2 className="text-3xl font-bold mb-8 text-gray-900 dark:text-gray-100">Your Models</h2>
|
|
1483
|
-
<div className="grid gap-6 grid-cols-1 md:grid-cols-2 lg:grid-cols-3">
|
|
1484
|
-
{scaffoldConfig.models.map((model) => (
|
|
1485
|
-
<a
|
|
1486
|
-
key={model.name}
|
|
1487
|
-
href={model.path}
|
|
1488
|
-
className="block p-8 bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-xl hover:shadow-lg hover:border-blue-400 dark:hover:border-blue-600 transition-all"
|
|
1489
|
-
>
|
|
1490
|
-
<h3 className="text-2xl font-semibold mb-2 text-gray-900 dark:text-gray-100">{model.label}</h3>
|
|
1491
|
-
<p className="text-gray-600 dark:text-gray-400">Manage {model.label.toLowerCase()}</p>
|
|
1492
|
-
</a>
|
|
1493
|
-
))}
|
|
1494
|
-
</div>
|
|
1495
|
-
</section>
|
|
1496
|
-
) : (
|
|
1497
|
-
<section className="max-w-2xl mx-auto text-center">
|
|
1498
|
-
<div className="bg-white dark:bg-gray-800 rounded-xl p-12 border border-gray-200 dark:border-gray-700">
|
|
1499
|
-
<h2 className="text-2xl font-semibold mb-4 text-gray-900 dark:text-gray-100">Get Started</h2>
|
|
1500
|
-
<p className="text-gray-600 dark:text-gray-400 mb-6">
|
|
1501
|
-
Create your first model with Zod and generate CRUD operations automatically.
|
|
1502
|
-
</p>
|
|
1503
|
-
<code className="block bg-gray-100 dark:bg-gray-900 p-4 rounded text-left text-sm">
|
|
1504
|
-
${pmCmd.exec} swallowkit scaffold shared/models/your-model.ts
|
|
1505
|
-
</code>
|
|
1506
|
-
</div>
|
|
1507
|
-
</section>
|
|
1508
|
-
)}
|
|
1509
|
-
|
|
1510
|
-
<footer className="mt-16 text-center text-gray-600 dark:text-gray-400 text-sm">
|
|
1511
|
-
<p>Built with SwallowKit</p>
|
|
1512
|
-
</footer>
|
|
1513
|
-
</div>
|
|
1514
|
-
</div>
|
|
1515
|
-
);
|
|
1516
|
-
}
|
|
1517
|
-
`;
|
|
1518
|
-
fs.writeFileSync(path.join(projectDir, 'app', 'page.tsx'), pageContent);
|
|
1478
|
+
fs.writeFileSync(path.join(projectDir, 'app', 'page.tsx'), (0, home_page_1.buildHomePage)("nextjs", pm));
|
|
1519
1479
|
console.log('✅ Home page created\n');
|
|
1520
1480
|
// Create initial scaffold-config.ts
|
|
1521
1481
|
const scaffoldConfigDir = path.join(projectDir, 'lib');
|
|
@@ -1556,9 +1516,8 @@ function createReadme(projectDir, projectName, cicdChoice, azureConfig, pm, back
|
|
|
1556
1516
|
const backendScaffoldNote = backendLanguage === 'typescript'
|
|
1557
1517
|
? '- Azure Functions CRUD endpoints'
|
|
1558
1518
|
: `- Azure Functions ${backendLanguageLabel} CRUD handlers\n- OpenAPI export + native-generated ${backendLanguageLabel} schema assets`;
|
|
1559
|
-
const pythonUvPaths = (0, python_uv_1.getProjectLocalUvPaths)(projectDir);
|
|
1560
1519
|
const pythonLocalDevNote = backendLanguage === 'python'
|
|
1561
|
-
? `\n**Python local dev note**: SwallowKit uses \`uv\`
|
|
1520
|
+
? `\n**Python local dev note**: SwallowKit uses normal \`uv\` interpreter discovery and settings, including installed Python, \`.python-version\`, and \`UV_PYTHON\`. It does not pin local Python to the Azure deployment version (${python_uv_1.DEFAULT_AZURE_PYTHON_VERSION}). Local Functions uses \`functions/.venv\` and schema generation uses \`functions/.codegen-venv\`. Existing environments are preserved; explicitly recreate them with uv when switching interpreters. A missing uv binary is bootstrapped under \`.uv/bin\` without changing PATH. Keep \`functions/requirements.txt\` and \`functions/requirements.codegen.txt\` as the dependency sources of truth.\n`
|
|
1562
1521
|
: '';
|
|
1563
1522
|
const readme = `# ${projectName}
|
|
1564
1523
|
|
|
@@ -1666,10 +1625,12 @@ ${pmCmd.exec} swallowkit provision --resource-group <rg-name>
|
|
|
1666
1625
|
|
|
1667
1626
|
This creates:
|
|
1668
1627
|
- Static Web App (\`swa-${projectName}\`)
|
|
1669
|
-
- Azure Functions (\`func-${projectName}
|
|
1670
|
-
- Cosmos DB (\`cosmos-${projectName}
|
|
1628
|
+
- Azure Functions (\`func-${projectName}-<suffix>\`)
|
|
1629
|
+
- Cosmos DB (\`cosmos-${projectName}-<suffix>\`)
|
|
1671
1630
|
- Storage Account
|
|
1672
1631
|
|
|
1632
|
+
Cosmos DB and Function App names must be globally unique, so they include a short suffix derived from the resource group. When provisioning completes, the command prints the actual resource names and the CI/CD settings to use.
|
|
1633
|
+
|
|
1673
1634
|
You will be prompted to select Azure regions:
|
|
1674
1635
|
1. **Primary location**: For Functions and Cosmos DB (default: Japan East)
|
|
1675
1636
|
2. **Static Web App location**: Limited availability (default: East Asia)
|
|
@@ -1685,12 +1646,12 @@ ${cicdChoice === 'github' ? `#### GitHub Actions
|
|
|
1685
1646
|
|
|
1686
1647
|
2. Get Function App publish profile:
|
|
1687
1648
|
\`\`\`bash
|
|
1688
|
-
az webapp deployment list-publishing-profiles --name
|
|
1649
|
+
az webapp deployment list-publishing-profiles --name <functions-app-name> --resource-group <rg-name> --xml
|
|
1689
1650
|
\`\`\`
|
|
1690
1651
|
|
|
1691
1652
|
3. Add secrets to GitHub repository:
|
|
1692
1653
|
- \`AZURE_STATIC_WEB_APPS_API_TOKEN\`: SWA deployment token (from step 1)
|
|
1693
|
-
- \`AZURE_FUNCTIONAPP_NAME\`: \`func-${projectName}
|
|
1654
|
+
- \`AZURE_FUNCTIONAPP_NAME\`: Functions app name printed by \`swallowkit provision\` (\`func-${projectName}-<suffix>\`)
|
|
1694
1655
|
- \`AZURE_FUNCTIONAPP_PUBLISH_PROFILE\`: Functions publish profile (from step 2)
|
|
1695
1656
|
|
|
1696
1657
|
4. Push to \`main\` branch to trigger deployment (or use **Actions** → **Run workflow** for manual deployment)` : cicdChoice === 'azure' ? `#### Azure Pipelines
|
|
@@ -1712,8 +1673,10 @@ az staticwebapp deploy --name swa-${projectName} --resource-group <rg-name> --ap
|
|
|
1712
1673
|
\`\`\`bash
|
|
1713
1674
|
cd functions
|
|
1714
1675
|
${pmCmd.run} build
|
|
1715
|
-
func azure functionapp publish
|
|
1716
|
-
|
|
1676
|
+
func azure functionapp publish <functions-app-name>
|
|
1677
|
+
\`\`\`
|
|
1678
|
+
|
|
1679
|
+
Use the Functions app name printed by \`swallowkit provision\`.`}
|
|
1717
1680
|
|
|
1718
1681
|
## 🔧 Available Commands
|
|
1719
1682
|
|
|
@@ -1767,20 +1730,24 @@ This project was generated by SwallowKit. If you encounter any issues or have su
|
|
|
1767
1730
|
fs.writeFileSync(path.join(projectDir, 'README.md'), readme);
|
|
1768
1731
|
console.log('✅ README.md created\n');
|
|
1769
1732
|
}
|
|
1770
|
-
function createAiAgentFiles(projectDir, projectName, backendLanguage, pm) {
|
|
1733
|
+
function createAiAgentFiles(projectDir, projectName, backendLanguage, pm, frontend = "nextjs") {
|
|
1771
1734
|
console.log('🤖 Creating AI agent instruction files...\n');
|
|
1772
1735
|
const runCmd = (0, package_manager_1.getCommands)(pm).exec;
|
|
1773
1736
|
(0, agent_instructions_1.writeAgentInstructionFiles)(projectDir, {
|
|
1774
1737
|
projectName,
|
|
1775
1738
|
backendLanguage,
|
|
1776
1739
|
packageManager: pm,
|
|
1740
|
+
frontend,
|
|
1777
1741
|
});
|
|
1778
1742
|
console.log(' ✅ AGENTS.md (canonical project contract)');
|
|
1779
1743
|
console.log(' ✅ CLAUDE.md (Claude Code adapter)');
|
|
1780
1744
|
console.log(' ✅ .github/copilot-instructions.md (GitHub Copilot adapter)');
|
|
1781
1745
|
console.log(' ✅ .github/instructions/ (path-specific instructions)');
|
|
1782
|
-
|
|
1783
|
-
|
|
1746
|
+
const mcpVersion = selectInitialMcpVersion();
|
|
1747
|
+
fs.writeFileSync(path.join(projectDir, '.mcp.json'), buildSwallowKitMcpProjectConfigSource(pm, mcpVersion.version));
|
|
1748
|
+
console.log(mcpVersion.version === mcp_config_1.MCP_LATEST
|
|
1749
|
+
? ' ✅ .mcp.json (project-scoped MCP bootstrap, resolves latest)'
|
|
1750
|
+
: ` ✅ .mcp.json (project-scoped MCP bootstrap, pinned to ${mcpVersion.version}: ${mcpVersion.reason} Run "${runCmd} swallowkit configure-mcp" to re-select later.)`);
|
|
1784
1751
|
(0, workflows_1.writeWorkflowDocs)(projectDir, runCmd);
|
|
1785
1752
|
console.log(' ✅ .swallowkit/workflows/ (agent-agnostic autonomous-loop runbooks)');
|
|
1786
1753
|
const skillPaths = (0, workflows_1.writeAgentSkills)(projectDir, runCmd);
|
|
@@ -1858,6 +1825,14 @@ param cosmosDbMode string = '${azureConfig.cosmosDbMode}'
|
|
|
1858
1825
|
@description('Enable VNet integration')
|
|
1859
1826
|
param enableVNet bool = ${enableVNet}
|
|
1860
1827
|
|
|
1828
|
+
// Cosmos DB account and Function App names are globally unique across Azure.
|
|
1829
|
+
// A suffix derived from the resource group keeps names stable for redeployments
|
|
1830
|
+
// to the same resource group while avoiding collisions with other environments
|
|
1831
|
+
// and with names Azure still reserves after a previous resource group is deleted.
|
|
1832
|
+
var resourceSuffix = take(uniqueString(resourceGroup().id, projectName), 6)
|
|
1833
|
+
var cosmosAccountName = 'cosmos-\${take(toLower(projectName), 30)}-\${resourceSuffix}'
|
|
1834
|
+
var functionsAppName = 'func-\${take(projectName, 40)}-\${resourceSuffix}'
|
|
1835
|
+
|
|
1861
1836
|
// Shared Log Analytics Workspace (in Functions region for data residency)
|
|
1862
1837
|
module logAnalytics 'modules/loganalytics.bicep' = {
|
|
1863
1838
|
name: 'logAnalytics'
|
|
@@ -1911,7 +1886,7 @@ module vnet 'modules/vnet.bicep' = if (enableVNet) {
|
|
|
1911
1886
|
module cosmosDbFreeTier 'modules/cosmosdb-freetier.bicep' = if (cosmosDbMode == 'freetier') {
|
|
1912
1887
|
name: 'cosmosDb'
|
|
1913
1888
|
params: {
|
|
1914
|
-
accountName:
|
|
1889
|
+
accountName: cosmosAccountName
|
|
1915
1890
|
databaseName: '\${projectName}Database'
|
|
1916
1891
|
location: location
|
|
1917
1892
|
publicNetworkAccess: enableVNet ? 'Disabled' : 'Enabled'
|
|
@@ -1921,7 +1896,7 @@ module cosmosDbFreeTier 'modules/cosmosdb-freetier.bicep' = if (cosmosDbMode ==
|
|
|
1921
1896
|
module cosmosDbServerless 'modules/cosmosdb-serverless.bicep' = if (cosmosDbMode == 'serverless') {
|
|
1922
1897
|
name: 'cosmosDb'
|
|
1923
1898
|
params: {
|
|
1924
|
-
accountName:
|
|
1899
|
+
accountName: cosmosAccountName
|
|
1925
1900
|
databaseName: '\${projectName}Database'
|
|
1926
1901
|
location: location
|
|
1927
1902
|
publicNetworkAccess: enableVNet ? 'Disabled' : 'Enabled'
|
|
@@ -1945,7 +1920,7 @@ module cosmosPrivateEndpoint 'modules/private-endpoint-cosmos.bicep' = if (enabl
|
|
|
1945
1920
|
module functionsFlex 'modules/functions-flex.bicep' = {
|
|
1946
1921
|
name: 'functionsApp'
|
|
1947
1922
|
params: {
|
|
1948
|
-
name:
|
|
1923
|
+
name: functionsAppName
|
|
1949
1924
|
location: location
|
|
1950
1925
|
storageAccountName: 'stg\${uniqueString(resourceGroup().id, projectName)}'
|
|
1951
1926
|
appInsightsConnectionString: appInsightsFunctions.outputs.connectionString
|
|
@@ -2662,7 +2637,7 @@ jobs:
|
|
|
2662
2637
|
${commonSetup} - name: Setup Python
|
|
2663
2638
|
uses: actions/setup-python@v5
|
|
2664
2639
|
with:
|
|
2665
|
-
python-version: '
|
|
2640
|
+
python-version: '${python_uv_1.DEFAULT_AZURE_PYTHON_VERSION}'
|
|
2666
2641
|
|
|
2667
2642
|
- name: Install Functions dependencies
|
|
2668
2643
|
run: |
|
|
@@ -2847,7 +2822,7 @@ variables:
|
|
|
2847
2822
|
steps:
|
|
2848
2823
|
${commonSetup} - task: UsePythonVersion@0
|
|
2849
2824
|
inputs:
|
|
2850
|
-
versionSpec: '
|
|
2825
|
+
versionSpec: '${python_uv_1.DEFAULT_AZURE_PYTHON_VERSION}'
|
|
2851
2826
|
displayName: 'Install Python'
|
|
2852
2827
|
|
|
2853
2828
|
- script: |
|
|
@@ -2878,7 +2853,9 @@ ${commonSetup} - task: UsePythonVersion@0
|
|
|
2878
2853
|
function getSwaNodeVersionCommand() {
|
|
2879
2854
|
return `node -e "const fs=require('fs');const p=JSON.parse(fs.readFileSync('package.json','utf8'));p.engines={...p.engines,node:'>=22.14.0 <23'};fs.writeFileSync('package.json',JSON.stringify(p,null,2)+String.fromCharCode(10));"`;
|
|
2880
2855
|
}
|
|
2881
|
-
function buildAzureSwaPipeline(pm, projectPm = pm) {
|
|
2856
|
+
function buildAzureSwaPipeline(pm, projectPm = pm, frontend = "nextjs") {
|
|
2857
|
+
if (frontend === "react")
|
|
2858
|
+
return (0, react_project_1.buildReactAzureSwaPipeline)(projectPm);
|
|
2882
2859
|
// SWA/Oryx also invokes npm internally; normalize only the disposable CI checkout.
|
|
2883
2860
|
pm = 'npm';
|
|
2884
2861
|
const pmCmd = (0, package_manager_1.getCommands)(pm);
|
|
@@ -3056,19 +3033,21 @@ function getGitHubNpmWorkspaceNormalizationStep(pm, projectPm) {
|
|
|
3056
3033
|
npm install --package-lock-only --ignore-scripts
|
|
3057
3034
|
`;
|
|
3058
3035
|
}
|
|
3059
|
-
async function createGitHubActionsWorkflows(projectDir, azureConfig, pm, backendLanguage) {
|
|
3036
|
+
async function createGitHubActionsWorkflows(projectDir, azureConfig, pm, backendLanguage, frontend = "nextjs") {
|
|
3060
3037
|
console.log('📦 Creating GitHub Actions workflows...\n');
|
|
3061
3038
|
const workflowsDir = path.join(projectDir, '.github', 'workflows');
|
|
3062
3039
|
fs.mkdirSync(workflowsDir, { recursive: true });
|
|
3063
3040
|
const actionsPm = pm;
|
|
3064
|
-
const swaWorkflow = buildGitHubSwaWorkflow(actionsPm, pm);
|
|
3041
|
+
const swaWorkflow = buildGitHubSwaWorkflow(actionsPm, pm, frontend);
|
|
3065
3042
|
fs.writeFileSync(path.join(workflowsDir, 'deploy-swa.yml'), swaWorkflow);
|
|
3066
3043
|
// deploy-functions.yml
|
|
3067
3044
|
const functionsWorkflow = getGitHubFunctionsWorkflow(actionsPm, backendLanguage, pm);
|
|
3068
3045
|
fs.writeFileSync(path.join(workflowsDir, 'deploy-functions.yml'), functionsWorkflow);
|
|
3069
3046
|
console.log('✅ GitHub Actions workflows created\n');
|
|
3070
3047
|
}
|
|
3071
|
-
function buildGitHubSwaWorkflow(pm, projectPm = pm) {
|
|
3048
|
+
function buildGitHubSwaWorkflow(pm, projectPm = pm, frontend = "nextjs") {
|
|
3049
|
+
if (frontend === "react")
|
|
3050
|
+
return (0, react_project_1.buildReactGitHubSwaWorkflow)(projectPm);
|
|
3072
3051
|
// SWA/Oryx also invokes npm internally; normalize only the disposable CI checkout.
|
|
3073
3052
|
pm = 'npm';
|
|
3074
3053
|
const npmWorkspaceNormalizationStep = getGitHubNpmWorkspaceNormalizationStep(pm, projectPm);
|
|
@@ -3144,13 +3123,13 @@ ${npmWorkspaceNormalizationStep ? `\n${npmWorkspaceNormalizationStep}` : ''}
|
|
|
3144
3123
|
NEXT_TURBOPACK_EXPERIMENTAL_USE_SYSTEM_TLS_CERTS: '1'
|
|
3145
3124
|
`;
|
|
3146
3125
|
}
|
|
3147
|
-
async function createAzurePipelines(projectDir, pm, backendLanguage) {
|
|
3126
|
+
async function createAzurePipelines(projectDir, pm, backendLanguage, frontend = "nextjs") {
|
|
3148
3127
|
console.log('📦 Creating Azure Pipelines...\n');
|
|
3149
3128
|
const pipelinesPm = pm;
|
|
3150
3129
|
const pipelinesDir = path.join(projectDir, 'pipelines');
|
|
3151
3130
|
fs.mkdirSync(pipelinesDir, { recursive: true });
|
|
3152
3131
|
// swa.yml
|
|
3153
|
-
const swaPipeline = buildAzureSwaPipeline(pipelinesPm, pm);
|
|
3132
|
+
const swaPipeline = buildAzureSwaPipeline(pipelinesPm, pm, frontend);
|
|
3154
3133
|
fs.writeFileSync(path.join(pipelinesDir, 'swa.yml'), swaPipeline);
|
|
3155
3134
|
// functions.yml
|
|
3156
3135
|
const functionsPipeline = getAzureFunctionsPipeline(pipelinesPm, backendLanguage, pm);
|