swallowkit 1.0.0-beta.8 → 1.0.0
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 +87 -181
- package/README.md +87 -238
- package/dist/__tests__/fixtures.d.ts +12 -0
- package/dist/__tests__/fixtures.d.ts.map +1 -1
- package/dist/__tests__/fixtures.js +101 -0
- package/dist/__tests__/fixtures.js.map +1 -1
- package/dist/cli/commands/add-auth.d.ts +15 -0
- package/dist/cli/commands/add-auth.d.ts.map +1 -0
- package/dist/cli/commands/add-auth.js +790 -0
- package/dist/cli/commands/add-auth.js.map +1 -0
- package/dist/cli/commands/add-connector.d.ts +20 -0
- package/dist/cli/commands/add-connector.d.ts.map +1 -0
- package/dist/cli/commands/add-connector.js +164 -0
- package/dist/cli/commands/add-connector.js.map +1 -0
- package/dist/cli/commands/cosmos-worktree-isolation.d.ts +25 -0
- package/dist/cli/commands/cosmos-worktree-isolation.d.ts.map +1 -0
- package/dist/cli/commands/cosmos-worktree-isolation.js +124 -0
- package/dist/cli/commands/cosmos-worktree-isolation.js.map +1 -0
- package/dist/cli/commands/create-model.d.ts +1 -4
- package/dist/cli/commands/create-model.d.ts.map +1 -1
- package/dist/cli/commands/create-model.js +20 -82
- package/dist/cli/commands/create-model.js.map +1 -1
- package/dist/cli/commands/dev-seeds.d.ts +27 -0
- package/dist/cli/commands/dev-seeds.d.ts.map +1 -1
- package/dist/cli/commands/dev-seeds.js +188 -6
- package/dist/cli/commands/dev-seeds.js.map +1 -1
- package/dist/cli/commands/dev.d.ts +30 -0
- package/dist/cli/commands/dev.d.ts.map +1 -1
- package/dist/cli/commands/dev.js +495 -129
- package/dist/cli/commands/dev.js.map +1 -1
- package/dist/cli/commands/init.d.ts +70 -0
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +797 -768
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/scaffold.d.ts +24 -3
- package/dist/cli/commands/scaffold.d.ts.map +1 -1
- package/dist/cli/commands/scaffold.js +408 -189
- package/dist/cli/commands/scaffold.js.map +1 -1
- package/dist/cli/index.d.ts +5 -1
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +335 -58
- package/dist/cli/index.js.map +1 -1
- package/dist/core/config.d.ts +13 -3
- package/dist/core/config.d.ts.map +1 -1
- package/dist/core/config.js +151 -8
- package/dist/core/config.js.map +1 -1
- package/dist/core/mock/connector-mock-server.d.ts +101 -0
- package/dist/core/mock/connector-mock-server.d.ts.map +1 -0
- package/dist/core/mock/connector-mock-server.js +480 -0
- package/dist/core/mock/connector-mock-server.js.map +1 -0
- package/dist/core/mock/zod-mock-generator.d.ts +14 -0
- package/dist/core/mock/zod-mock-generator.d.ts.map +1 -0
- package/dist/core/mock/zod-mock-generator.js +163 -0
- package/dist/core/mock/zod-mock-generator.js.map +1 -0
- package/dist/core/operations/auth-operations.d.ts +61 -0
- package/dist/core/operations/auth-operations.d.ts.map +1 -0
- package/dist/core/operations/auth-operations.js +272 -0
- package/dist/core/operations/auth-operations.js.map +1 -0
- package/dist/core/operations/create-model.d.ts +15 -0
- package/dist/core/operations/create-model.d.ts.map +1 -0
- package/dist/core/operations/create-model.js +185 -0
- package/dist/core/operations/create-model.js.map +1 -0
- package/dist/core/operations/file-session.d.ts +56 -0
- package/dist/core/operations/file-session.d.ts.map +1 -0
- package/dist/core/operations/file-session.js +203 -0
- package/dist/core/operations/file-session.js.map +1 -0
- package/dist/core/operations/provision-operations.d.ts +52 -0
- package/dist/core/operations/provision-operations.d.ts.map +1 -0
- package/dist/core/operations/provision-operations.js +211 -0
- package/dist/core/operations/provision-operations.js.map +1 -0
- package/dist/core/operations/runtime.d.ts +37 -0
- package/dist/core/operations/runtime.d.ts.map +1 -0
- package/dist/core/operations/runtime.js +248 -0
- package/dist/core/operations/runtime.js.map +1 -0
- package/dist/core/operations/scaffold-apply.d.ts +21 -0
- package/dist/core/operations/scaffold-apply.d.ts.map +1 -0
- package/dist/core/operations/scaffold-apply.js +57 -0
- package/dist/core/operations/scaffold-apply.js.map +1 -0
- package/dist/core/operations/scaffold-machine.d.ts +16 -0
- package/dist/core/operations/scaffold-machine.d.ts.map +1 -0
- package/dist/core/operations/scaffold-machine.js +51 -0
- package/dist/core/operations/scaffold-machine.js.map +1 -0
- package/dist/core/operations/scaffold-plan.d.ts +43 -0
- package/dist/core/operations/scaffold-plan.d.ts.map +1 -0
- package/dist/core/operations/scaffold-plan.js +187 -0
- package/dist/core/operations/scaffold-plan.js.map +1 -0
- package/dist/core/project/agent-instructions.d.ts +29 -0
- package/dist/core/project/agent-instructions.d.ts.map +1 -0
- package/dist/core/project/agent-instructions.js +160 -0
- package/dist/core/project/agent-instructions.js.map +1 -0
- package/dist/core/project/artifacts.d.ts +58 -0
- package/dist/core/project/artifacts.d.ts.map +1 -0
- package/dist/core/project/artifacts.js +179 -0
- package/dist/core/project/artifacts.js.map +1 -0
- package/dist/core/project/boundaries.d.ts +50 -0
- package/dist/core/project/boundaries.d.ts.map +1 -0
- package/dist/core/project/boundaries.js +117 -0
- package/dist/core/project/boundaries.js.map +1 -0
- package/dist/core/project/capabilities.d.ts +58 -0
- package/dist/core/project/capabilities.d.ts.map +1 -0
- package/dist/core/project/capabilities.js +135 -0
- package/dist/core/project/capabilities.js.map +1 -0
- package/dist/core/project/drift.d.ts +29 -0
- package/dist/core/project/drift.d.ts.map +1 -0
- package/dist/core/project/drift.js +188 -0
- package/dist/core/project/drift.js.map +1 -0
- package/dist/core/project/infra.d.ts +49 -0
- package/dist/core/project/infra.d.ts.map +1 -0
- package/dist/core/project/infra.js +167 -0
- package/dist/core/project/infra.js.map +1 -0
- package/dist/core/project/manifest.d.ts +92 -0
- package/dist/core/project/manifest.d.ts.map +1 -0
- package/dist/core/project/manifest.js +321 -0
- package/dist/core/project/manifest.js.map +1 -0
- package/dist/core/project/state.d.ts +15 -0
- package/dist/core/project/state.d.ts.map +1 -0
- package/dist/core/project/state.js +106 -0
- package/dist/core/project/state.js.map +1 -0
- package/dist/core/project/validation.d.ts +20 -0
- package/dist/core/project/validation.d.ts.map +1 -0
- package/dist/core/project/validation.js +274 -0
- package/dist/core/project/validation.js.map +1 -0
- package/dist/core/project/workflows.d.ts +43 -0
- package/dist/core/project/workflows.d.ts.map +1 -0
- package/dist/core/project/workflows.js +299 -0
- package/dist/core/project/workflows.js.map +1 -0
- package/dist/core/scaffold/auth-generator.d.ts +63 -0
- package/dist/core/scaffold/auth-generator.d.ts.map +1 -0
- package/dist/core/scaffold/auth-generator.js +1774 -0
- package/dist/core/scaffold/auth-generator.js.map +1 -0
- package/dist/core/scaffold/connector-functions-generator.d.ts +41 -0
- package/dist/core/scaffold/connector-functions-generator.d.ts.map +1 -0
- package/dist/core/scaffold/connector-functions-generator.js +1029 -0
- package/dist/core/scaffold/connector-functions-generator.js.map +1 -0
- package/dist/core/scaffold/functions-generator.d.ts +4 -3
- package/dist/core/scaffold/functions-generator.d.ts.map +1 -1
- package/dist/core/scaffold/functions-generator.js +405 -134
- package/dist/core/scaffold/functions-generator.js.map +1 -1
- package/dist/core/scaffold/model-parser.d.ts +20 -0
- package/dist/core/scaffold/model-parser.d.ts.map +1 -1
- package/dist/core/scaffold/model-parser.js +229 -78
- package/dist/core/scaffold/model-parser.js.map +1 -1
- package/dist/core/scaffold/native-schema-generator.d.ts +19 -0
- package/dist/core/scaffold/native-schema-generator.d.ts.map +1 -0
- package/dist/core/scaffold/native-schema-generator.js +753 -0
- package/dist/core/scaffold/native-schema-generator.js.map +1 -0
- package/dist/core/scaffold/nextjs-generator.d.ts +8 -0
- package/dist/core/scaffold/nextjs-generator.d.ts.map +1 -1
- package/dist/core/scaffold/nextjs-generator.js +152 -8
- package/dist/core/scaffold/nextjs-generator.js.map +1 -1
- package/dist/core/scaffold/ui-generator.d.ts +17 -4
- package/dist/core/scaffold/ui-generator.d.ts.map +1 -1
- package/dist/core/scaffold/ui-generator.js +174 -34
- package/dist/core/scaffold/ui-generator.js.map +1 -1
- package/dist/core/verify/index.d.ts +69 -0
- package/dist/core/verify/index.d.ts.map +1 -0
- package/dist/core/verify/index.js +412 -0
- package/dist/core/verify/index.js.map +1 -0
- package/dist/machine/contracts.d.ts +24 -0
- package/dist/machine/contracts.d.ts.map +1 -0
- package/dist/machine/contracts.js +3 -0
- package/dist/machine/contracts.js.map +1 -0
- package/dist/machine/errors.d.ts +14 -0
- package/dist/machine/errors.d.ts.map +1 -0
- package/dist/machine/errors.js +42 -0
- package/dist/machine/errors.js.map +1 -0
- package/dist/machine/index.d.ts +3 -0
- package/dist/machine/index.d.ts.map +1 -0
- package/dist/machine/index.js +566 -0
- package/dist/machine/index.js.map +1 -0
- package/dist/mcp/index.d.ts +25 -0
- package/dist/mcp/index.d.ts.map +1 -0
- package/dist/mcp/index.js +425 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/types/index.d.ts +105 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/utils/package-manager.d.ts +7 -11
- package/dist/utils/package-manager.d.ts.map +1 -1
- package/dist/utils/package-manager.js +42 -17
- package/dist/utils/package-manager.js.map +1 -1
- package/dist/utils/python-uv.d.ts +21 -0
- package/dist/utils/python-uv.d.ts.map +1 -0
- package/dist/utils/python-uv.js +111 -0
- package/dist/utils/python-uv.js.map +1 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +49 -0
- package/dist/version.js.map +1 -0
- package/package.json +15 -17
- package/src/__tests__/__snapshots__/functions-generator.test.ts.snap +716 -22
- package/src/__tests__/__snapshots__/nextjs-generator.test.ts.snap +19 -7
- package/src/__tests__/__snapshots__/ui-generator.test.ts.snap +20 -12
- package/src/__tests__/agent-instructions.test.ts +237 -0
- package/src/__tests__/agent-loop-phase34.test.ts +513 -0
- package/src/__tests__/auth.test.ts +770 -0
- package/src/__tests__/bff-swa-auth.test.ts +275 -0
- package/src/__tests__/config.test.ts +176 -3
- package/src/__tests__/connector-functions-generator.test.ts +288 -0
- package/src/__tests__/connector-mock-server.test.ts +459 -0
- package/src/__tests__/connector-model-bff.test.ts +162 -0
- package/src/__tests__/cosmos-worktree-isolation.test.ts +149 -0
- package/src/__tests__/dev-seeds.test.ts +124 -0
- package/src/__tests__/dev.test.ts +254 -0
- package/src/__tests__/file-session.test.ts +98 -0
- package/src/__tests__/fixtures.ts +101 -0
- package/src/__tests__/functions-generator.test.ts +137 -1
- package/src/__tests__/init.test.ts +386 -1
- package/src/__tests__/jest-globals.d.ts +8 -0
- package/src/__tests__/machine.test.ts +371 -0
- package/src/__tests__/mcp.test.ts +253 -0
- package/src/__tests__/model-parser.test.ts +142 -0
- package/src/__tests__/multi-auth.test.ts +160 -0
- package/src/__tests__/nextjs-generator.test.ts +8 -0
- package/src/__tests__/package-manager.test.ts +59 -4
- package/src/__tests__/plan-apply.test.ts +499 -0
- package/src/__tests__/python-uv.test.ts +48 -0
- package/src/__tests__/scaffold.test.ts +287 -24
- package/src/__tests__/tsconfig.json +15 -0
- package/src/__tests__/ui-generator.test.ts +104 -0
- package/src/__tests__/zod-mock-generator.test.ts +132 -0
- package/src/cli/commands/add-auth.ts +853 -0
- package/src/cli/commands/add-connector.ts +159 -0
- package/src/cli/commands/cosmos-worktree-isolation.ts +130 -0
- package/src/cli/commands/create-model.ts +21 -100
- package/src/cli/commands/dev-seeds.ts +278 -7
- package/src/cli/commands/dev.ts +607 -160
- package/src/cli/commands/init.ts +880 -808
- package/src/cli/commands/scaffold.ts +531 -236
- package/src/cli/index.ts +338 -60
- package/src/core/config.ts +145 -9
- package/src/core/mock/connector-mock-server.ts +555 -0
- package/src/core/mock/zod-mock-generator.ts +205 -0
- package/src/core/operations/auth-operations.ts +360 -0
- package/src/core/operations/create-model.ts +191 -0
- package/src/core/operations/file-session.ts +222 -0
- package/src/core/operations/provision-operations.ts +297 -0
- package/src/core/operations/runtime.ts +258 -0
- package/src/core/operations/scaffold-apply.ts +106 -0
- package/src/core/operations/scaffold-machine.ts +77 -0
- package/src/core/operations/scaffold-plan.ts +215 -0
- package/src/core/project/agent-instructions.ts +167 -0
- package/src/core/project/agent-templates/AGENTS.md +504 -0
- package/src/core/project/agent-templates/CLAUDE.md +31 -0
- package/src/core/project/agent-templates/azure-functions.instructions.md +22 -0
- package/src/core/project/agent-templates/bff-routes.instructions.md +18 -0
- package/src/core/project/agent-templates/copilot-instructions.md +27 -0
- package/src/core/project/agent-templates/shared-models.instructions.md +72 -0
- package/src/core/project/artifacts.ts +205 -0
- package/src/core/project/boundaries.ts +170 -0
- package/src/core/project/capabilities.ts +193 -0
- package/src/core/project/drift.ts +202 -0
- package/src/core/project/infra.ts +196 -0
- package/src/core/project/manifest.ts +402 -0
- package/src/core/project/state.ts +77 -0
- package/src/core/project/validation.ts +295 -0
- package/src/core/project/workflows.ts +295 -0
- package/src/core/scaffold/auth-generator.ts +1824 -0
- package/src/core/scaffold/connector-functions-generator.ts +1133 -0
- package/src/core/scaffold/functions-generator.ts +432 -134
- package/src/core/scaffold/model-parser.ts +244 -90
- package/src/core/scaffold/native-schema-generator.ts +904 -0
- package/src/core/scaffold/nextjs-generator.ts +174 -9
- package/src/core/scaffold/ui-generator.ts +191 -36
- package/src/core/verify/index.ts +468 -0
- package/src/machine/contracts.ts +33 -0
- package/src/machine/errors.ts +45 -0
- package/src/machine/index.ts +690 -0
- package/src/mcp/index.ts +423 -0
- package/src/types/index.ts +137 -0
- package/src/utils/package-manager.ts +41 -19
- package/src/utils/python-uv.ts +96 -0
- package/src/version.ts +13 -0
package/src/cli/index.ts
CHANGED
|
@@ -1,74 +1,352 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
require('child_process').execSync('chcp 65001', { stdio: 'ignore' });
|
|
7
|
-
} catch { /* ignore — non-critical */ }
|
|
8
|
-
}
|
|
9
|
-
|
|
3
|
+
import { execSync } from "child_process";
|
|
4
|
+
import { readFileSync } from "fs";
|
|
5
|
+
import * as path from "path";
|
|
10
6
|
import { Command } from "commander";
|
|
11
7
|
import { initCommand, devCommand, devSeedsCommand, scaffoldCommand, createModelCommand } from "./commands";
|
|
12
8
|
import { provisionCommand } from "./commands/provision";
|
|
9
|
+
import { addConnectorCommand } from "./commands/add-connector";
|
|
10
|
+
import { addAuthCommand } from "./commands/add-auth";
|
|
11
|
+
import { planScaffoldOperation } from "../core/operations/scaffold-plan";
|
|
12
|
+
import { inspectArtifacts } from "../core/project/artifacts";
|
|
13
|
+
import { detectDrift } from "../core/project/drift";
|
|
14
|
+
import { runVerify } from "../core/verify";
|
|
15
|
+
import { isMachineCommand, runMachineCli } from "../machine";
|
|
16
|
+
|
|
17
|
+
const packageJsonPath = path.resolve(__dirname, "../../package.json");
|
|
18
|
+
export const CLI_VERSION = JSON.parse(readFileSync(packageJsonPath, "utf8")).version as string;
|
|
19
|
+
|
|
20
|
+
const DEV_OPTION_ARITY = new Map<string, 0 | 1>([
|
|
21
|
+
["-p", 1],
|
|
22
|
+
["--port", 1],
|
|
23
|
+
["-f", 1],
|
|
24
|
+
["--functions-port", 1],
|
|
25
|
+
["--host", 1],
|
|
26
|
+
["--seed-env", 1],
|
|
27
|
+
["-o", 0],
|
|
28
|
+
["--open", 0],
|
|
29
|
+
["-v", 0],
|
|
30
|
+
["--verbose", 0],
|
|
31
|
+
["--no-functions", 0],
|
|
32
|
+
["--mock-connectors", 0],
|
|
33
|
+
["--swa-port", 1],
|
|
34
|
+
["--no-swa", 0],
|
|
35
|
+
]);
|
|
36
|
+
|
|
37
|
+
function ensureUtf8ConsoleOnWindows(): void {
|
|
38
|
+
if (process.platform === 'win32') {
|
|
39
|
+
try {
|
|
40
|
+
execSync('chcp 65001', { stdio: 'ignore' });
|
|
41
|
+
} catch {
|
|
42
|
+
// ignore — non-critical
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function isDevOptionSequence(tokens: string[]): boolean {
|
|
48
|
+
if (tokens.length === 0) {
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
for (let index = 0; index < tokens.length; index += 1) {
|
|
53
|
+
const token = tokens[index];
|
|
54
|
+
const arity = DEV_OPTION_ARITY.get(token);
|
|
55
|
+
|
|
56
|
+
if (arity === undefined) {
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (arity === 1) {
|
|
61
|
+
const value = tokens[index + 1];
|
|
62
|
+
if (value === undefined || value === "dev") {
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
index += 1;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return true;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export function normalizeDevCommandArgv(argv: string[]): string[] {
|
|
73
|
+
if (argv.length <= 3) {
|
|
74
|
+
return argv;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const prefix = argv.slice(0, 2);
|
|
78
|
+
const args = argv.slice(2);
|
|
79
|
+
const devIndex = args.indexOf("dev");
|
|
80
|
+
|
|
81
|
+
if (devIndex <= 0) {
|
|
82
|
+
return argv;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const leadingTokens = args.slice(0, devIndex);
|
|
86
|
+
if (!isDevOptionSequence(leadingTokens)) {
|
|
87
|
+
return argv;
|
|
88
|
+
}
|
|
13
89
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
90
|
+
return [
|
|
91
|
+
...prefix,
|
|
92
|
+
"dev",
|
|
93
|
+
...leadingTokens,
|
|
94
|
+
...args.slice(devIndex + 1),
|
|
95
|
+
];
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export function createProgram(devCommandOverride: Command = devCommand): Command {
|
|
99
|
+
const program = new Command();
|
|
100
|
+
|
|
101
|
+
program
|
|
102
|
+
.name("swallowkit")
|
|
103
|
+
.description("Next.js framework optimized for Azure deployment - Automatically splits SSR into individual Azure Functions")
|
|
104
|
+
.version(CLI_VERSION);
|
|
105
|
+
|
|
106
|
+
// Register commands
|
|
107
|
+
program
|
|
108
|
+
.command("init [project-name]")
|
|
109
|
+
.description("Initialize a new SwallowKit project")
|
|
110
|
+
.option("--template <template>", "Template to use", "default")
|
|
111
|
+
.option("--next-version <version>", "Next.js version to install (e.g., 16.0.7, latest)", "latest")
|
|
112
|
+
.option("--package-manager <manager>", "Package manager: npm | pnpm (defaults to invocation context)")
|
|
113
|
+
.option("--cicd <provider>", "CI/CD provider: github | azure | skip")
|
|
114
|
+
.option("--backend-language <language>", "Azure Functions backend language: typescript | csharp | python")
|
|
115
|
+
.option("--cosmos-db-mode <mode>", "Cosmos DB mode: freetier | serverless")
|
|
116
|
+
.option("--vnet <option>", "Network security: outbound | none")
|
|
117
|
+
.option("--swa-plan <plan>", "Azure Static Web Apps plan: free | standard")
|
|
118
|
+
.action((projectName, options) => {
|
|
119
|
+
initCommand({
|
|
120
|
+
name: projectName || "swallowkit-app",
|
|
121
|
+
template: options.template,
|
|
122
|
+
nextVersion: options.nextVersion,
|
|
123
|
+
packageManager: options.packageManager,
|
|
124
|
+
cicd: options.cicd,
|
|
125
|
+
backendLanguage: options.backendLanguage,
|
|
126
|
+
cosmosDbMode: options.cosmosDbMode,
|
|
127
|
+
vnet: options.vnet,
|
|
128
|
+
swaPlan: options.swaPlan,
|
|
129
|
+
});
|
|
40
130
|
});
|
|
41
|
-
});
|
|
42
131
|
|
|
43
|
-
program.addCommand(
|
|
44
|
-
program.addCommand(devSeedsCommand);
|
|
132
|
+
program.addCommand(devCommandOverride);
|
|
133
|
+
program.addCommand(devSeedsCommand);
|
|
45
134
|
|
|
46
|
-
program.addCommand(provisionCommand);
|
|
135
|
+
program.addCommand(provisionCommand);
|
|
47
136
|
|
|
48
|
-
program
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
137
|
+
program
|
|
138
|
+
.command("create-model <names...>")
|
|
139
|
+
.description("Create model template files with id, createdAt, and updatedAt fields")
|
|
140
|
+
.option("--models-dir <dir>", "Models directory", "shared/models")
|
|
141
|
+
.option("--connector <name>", "Associate model with a connector defined in swallowkit.config.js")
|
|
142
|
+
.action((names, options) => {
|
|
143
|
+
createModelCommand({
|
|
144
|
+
names,
|
|
145
|
+
modelsDir: options.modelsDir,
|
|
146
|
+
connector: options.connector,
|
|
147
|
+
});
|
|
56
148
|
});
|
|
57
|
-
});
|
|
58
149
|
|
|
59
|
-
program
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
150
|
+
program
|
|
151
|
+
.command("scaffold <model>")
|
|
152
|
+
.description("Generate CRUD code for Azure Functions and Next.js BFF from Zod models")
|
|
153
|
+
.option("--functions-dir <dir>", "Azure Functions directory", "functions")
|
|
154
|
+
.option("--api-dir <dir>", "Next.js API routes directory", "app/api")
|
|
155
|
+
.option("--api-only", "Skip UI components; still update Functions, BFF routes, OpenAPI, and native schema assets", false)
|
|
156
|
+
.option("--dry-run", "Show planned file changes without writing anything", false)
|
|
157
|
+
.action(async (model, options) => {
|
|
158
|
+
if (options.dryRun) {
|
|
159
|
+
await runScaffoldDryRun({
|
|
160
|
+
model,
|
|
161
|
+
functionsDir: options.functionsDir,
|
|
162
|
+
apiDir: options.apiDir,
|
|
163
|
+
apiOnly: options.apiOnly,
|
|
164
|
+
});
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
await scaffoldCommand({
|
|
169
|
+
model,
|
|
170
|
+
functionsDir: options.functionsDir,
|
|
171
|
+
apiDir: options.apiDir,
|
|
172
|
+
apiOnly: options.apiOnly,
|
|
173
|
+
});
|
|
71
174
|
});
|
|
72
|
-
});
|
|
73
175
|
|
|
74
|
-
program
|
|
176
|
+
program
|
|
177
|
+
.command("add-connector <name>")
|
|
178
|
+
.description("Add an external data source connector configuration")
|
|
179
|
+
.requiredOption("--type <type>", "Connector type: rdb | api")
|
|
180
|
+
.option("--provider <provider>", "RDB provider: mysql | postgres | sqlserver", "mysql")
|
|
181
|
+
.action((name, options) => {
|
|
182
|
+
addConnectorCommand({
|
|
183
|
+
name,
|
|
184
|
+
type: options.type,
|
|
185
|
+
provider: options.provider,
|
|
186
|
+
});
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
program
|
|
190
|
+
.command("add-auth")
|
|
191
|
+
.description("Add authentication and authorization to the project")
|
|
192
|
+
.option("--provider <provider>", "Auth provider: custom-jwt | swa | external-token | swa-custom | none", "custom-jwt")
|
|
193
|
+
.option("--scheme <name>", "Add a named authentication scheme")
|
|
194
|
+
.option("--allowed-providers <list>", "Comma-separated SWA identity providers to allow (e.g. github,aad); defaults to aad")
|
|
195
|
+
.action((options) => {
|
|
196
|
+
addAuthCommand({
|
|
197
|
+
provider: options.provider,
|
|
198
|
+
scheme: options.scheme,
|
|
199
|
+
allowedProviders: options.allowedProviders ? String(options.allowedProviders).split(",") : undefined,
|
|
200
|
+
});
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
program
|
|
204
|
+
.command("status")
|
|
205
|
+
.description("Show generated artifact status and drift against the current project state")
|
|
206
|
+
.option("--artifacts", "List all tracked artifacts with ownership", false)
|
|
207
|
+
.action(async (options) => {
|
|
208
|
+
await runStatusCommand({ artifacts: options.artifacts });
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
program
|
|
212
|
+
.command("verify")
|
|
213
|
+
.description("Run verification checks (structure, drift, typecheck)")
|
|
214
|
+
.option("--checks <ids>", "Comma-separated check ids to run (structure,drift,typecheck)")
|
|
215
|
+
.action(async (options) => {
|
|
216
|
+
await runVerifyCommand({ checks: options.checks });
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
return program;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
async function runScaffoldDryRun(options: { model: string; functionsDir?: string; apiDir?: string; apiOnly?: boolean }): Promise<void> {
|
|
223
|
+
console.log("🔍 Scaffold dry-run — no files will be written.\n");
|
|
224
|
+
|
|
225
|
+
const plan = await planScaffoldOperation(options);
|
|
226
|
+
|
|
227
|
+
const actionIcons: Record<string, string> = {
|
|
228
|
+
create: "➕",
|
|
229
|
+
update: "♻️ ",
|
|
230
|
+
overwrite: "⚠️ ",
|
|
231
|
+
append: "🔗",
|
|
232
|
+
delete: "🗑️ ",
|
|
233
|
+
skip: "⏭️ ",
|
|
234
|
+
};
|
|
235
|
+
|
|
236
|
+
for (const operation of plan.operations) {
|
|
237
|
+
if (operation.action === "skip") continue;
|
|
238
|
+
const icon = actionIcons[operation.action] ?? "•";
|
|
239
|
+
const conflictNote = operation.conflict ? ` (conflict: ${operation.conflictReason})` : "";
|
|
240
|
+
console.log(` ${icon} ${operation.action.padEnd(9)} ${operation.path} [${operation.ownership}]${conflictNote}`);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
const skipped = plan.operations.filter((operation) => operation.action === "skip").length;
|
|
244
|
+
if (skipped > 0) {
|
|
245
|
+
console.log(` ⏭️ ${skipped} file(s) unchanged (skipped)`);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
if (plan.warnings.length > 0) {
|
|
249
|
+
console.log("\n⚠️ Warnings:");
|
|
250
|
+
for (const warning of plan.warnings) {
|
|
251
|
+
console.log(` - ${warning}`);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
console.log(`\n📋 Plan ${plan.planId} saved.`);
|
|
256
|
+
if (plan.requiresApproval) {
|
|
257
|
+
console.log(`⚠️ ${plan.conflicts.length} file(s) were modified after generation and would be overwritten.`);
|
|
258
|
+
console.log(` Review the conflicts, then run: swallowkit scaffold ${options.model} (or machine apply scaffold --plan ${plan.planId} --approve)`);
|
|
259
|
+
} else {
|
|
260
|
+
console.log(` Run without --dry-run to apply: swallowkit scaffold ${options.model}`);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
async function runStatusCommand(options: { artifacts?: boolean }): Promise<void> {
|
|
265
|
+
const inspection = inspectArtifacts();
|
|
266
|
+
const drift = await detectDrift();
|
|
267
|
+
|
|
268
|
+
console.log("📦 SwallowKit project status\n");
|
|
269
|
+
|
|
270
|
+
if (!inspection.ledgerFound) {
|
|
271
|
+
console.log("ℹ️ No artifact ledger (.swallowkit/artifacts.json) found yet.");
|
|
272
|
+
console.log(" Run scaffold once with this SwallowKit version to start tracking artifacts.\n");
|
|
273
|
+
} else {
|
|
274
|
+
const total = inspection.artifacts.length;
|
|
275
|
+
const missing = inspection.artifacts.filter((artifact) => !artifact.exists).length;
|
|
276
|
+
const modified = inspection.artifacts.filter((artifact) => artifact.modified).length;
|
|
277
|
+
console.log(` Tracked artifacts: ${total}`);
|
|
278
|
+
console.log(` Modified after generation: ${modified}`);
|
|
279
|
+
console.log(` Missing: ${missing}\n`);
|
|
280
|
+
|
|
281
|
+
if (options.artifacts) {
|
|
282
|
+
for (const artifact of inspection.artifacts) {
|
|
283
|
+
const flags = [
|
|
284
|
+
artifact.modified ? "modified" : null,
|
|
285
|
+
!artifact.exists ? "missing" : null,
|
|
286
|
+
].filter(Boolean);
|
|
287
|
+
const suffix = flags.length > 0 ? ` (${flags.join(", ")})` : "";
|
|
288
|
+
console.log(` - ${artifact.path} [${artifact.ownership}]${suffix}`);
|
|
289
|
+
}
|
|
290
|
+
console.log("");
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
if (drift.findings.length === 0) {
|
|
295
|
+
console.log("✅ No drift detected.");
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
console.log(`⚠️ Drift findings (${drift.findings.length}):`);
|
|
300
|
+
for (const finding of drift.findings) {
|
|
301
|
+
console.log(` [${finding.severity}] ${finding.kind}: ${finding.message}`);
|
|
302
|
+
console.log(` → ${finding.repairAction}`);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
async function runVerifyCommand(options: { checks?: string }): Promise<void> {
|
|
307
|
+
console.log("🔎 Running verification checks...\n");
|
|
308
|
+
|
|
309
|
+
const result = await runVerify(options.checks ? options.checks.split(",") : undefined);
|
|
310
|
+
|
|
311
|
+
const statusIcons: Record<string, string> = {
|
|
312
|
+
pass: "✅",
|
|
313
|
+
fail: "❌",
|
|
314
|
+
skip: "⏭️ ",
|
|
315
|
+
error: "💥",
|
|
316
|
+
};
|
|
317
|
+
|
|
318
|
+
for (const check of result.checks) {
|
|
319
|
+
console.log(` ${statusIcons[check.status]} ${check.id.padEnd(10)} ${check.title} (${check.durationMs}ms)`);
|
|
320
|
+
if (check.status === "fail" || check.status === "error") {
|
|
321
|
+
for (const action of check.suggestedActions) {
|
|
322
|
+
console.log(` → ${action}`);
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
console.log(
|
|
328
|
+
`\n${result.summary.done ? "✅" : "❌"} ${result.summary.passed} passed, ${result.summary.failed} failed, ${result.summary.skipped} skipped, ${result.summary.errors} error(s)`
|
|
329
|
+
);
|
|
330
|
+
|
|
331
|
+
if (!result.summary.done) {
|
|
332
|
+
console.log(' Details: swallowkit machine explain failure');
|
|
333
|
+
process.exitCode = 1;
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
export async function runCli(argv: string[] = process.argv): Promise<void> {
|
|
338
|
+
ensureUtf8ConsoleOnWindows();
|
|
339
|
+
if (isMachineCommand(argv)) {
|
|
340
|
+
await runMachineCli(argv);
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
await createProgram().parseAsync(normalizeDevCommandArgv(argv));
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
if (require.main === module) {
|
|
348
|
+
void runCli().catch((error) => {
|
|
349
|
+
console.error(error);
|
|
350
|
+
process.exitCode = 1;
|
|
351
|
+
});
|
|
352
|
+
}
|
package/src/core/config.ts
CHANGED
|
@@ -1,8 +1,20 @@
|
|
|
1
1
|
import * as fs from "fs";
|
|
2
|
+
import { createRequire } from "module";
|
|
2
3
|
import * as path from "path";
|
|
3
|
-
import { BackendLanguage, SwallowKitConfig } from "../types";
|
|
4
|
+
import { AuthConfig, AuthProvider, BackendLanguage, ConnectorDefinition, NormalizedAuthConfig, SwallowKitConfig } from "../types";
|
|
4
5
|
import { detectFromProject, getCommands } from "../utils/package-manager";
|
|
5
6
|
|
|
7
|
+
const requireFromHere = createRequire(__filename);
|
|
8
|
+
|
|
9
|
+
function unwrapConfigModule(
|
|
10
|
+
loadedConfig: Partial<SwallowKitConfig> | { default?: Partial<SwallowKitConfig> }
|
|
11
|
+
): Partial<SwallowKitConfig> {
|
|
12
|
+
if (typeof loadedConfig === "object" && loadedConfig !== null && "default" in loadedConfig) {
|
|
13
|
+
return loadedConfig.default ?? {};
|
|
14
|
+
}
|
|
15
|
+
return loadedConfig as Partial<SwallowKitConfig>;
|
|
16
|
+
}
|
|
17
|
+
|
|
6
18
|
const VALID_BACKEND_LANGUAGES: BackendLanguage[] = ["typescript", "csharp", "python"];
|
|
7
19
|
|
|
8
20
|
/**
|
|
@@ -25,7 +37,7 @@ const DEFAULT_CONFIG: SwallowKitConfig = {
|
|
|
25
37
|
/**
|
|
26
38
|
* 設定ファイルを読み込み
|
|
27
39
|
*/
|
|
28
|
-
export function loadConfig(configPath?: string): SwallowKitConfig {
|
|
40
|
+
export function loadConfig(configPath?: string, throwOnError = false, quiet = false): SwallowKitConfig {
|
|
29
41
|
const defaultPaths = [
|
|
30
42
|
"swallowkit.config.json",
|
|
31
43
|
"swallowkit.config.js",
|
|
@@ -39,24 +51,25 @@ export function loadConfig(configPath?: string): SwallowKitConfig {
|
|
|
39
51
|
|
|
40
52
|
if (fs.existsSync(fullPath)) {
|
|
41
53
|
try {
|
|
42
|
-
console.log(`📋 設定ファイルを読み込み: ${filePath}`);
|
|
54
|
+
if (!quiet) console.log(`📋 設定ファイルを読み込み: ${filePath}`);
|
|
43
55
|
|
|
44
56
|
if (filePath.endsWith(".json")) {
|
|
45
57
|
const configData = fs.readFileSync(fullPath, "utf-8");
|
|
46
58
|
const userConfig = JSON.parse(configData);
|
|
47
59
|
return mergeConfig(DEFAULT_CONFIG, userConfig);
|
|
48
60
|
} else if (filePath.endsWith(".js")) {
|
|
49
|
-
delete
|
|
50
|
-
const
|
|
51
|
-
return mergeConfig(DEFAULT_CONFIG,
|
|
61
|
+
delete requireFromHere.cache[fullPath];
|
|
62
|
+
const loadedConfig = requireFromHere(fullPath) as Partial<SwallowKitConfig> | { default?: Partial<SwallowKitConfig> };
|
|
63
|
+
return mergeConfig(DEFAULT_CONFIG, unwrapConfigModule(loadedConfig));
|
|
52
64
|
}
|
|
53
65
|
} catch (error) {
|
|
54
|
-
|
|
66
|
+
if (throwOnError) throw error;
|
|
67
|
+
if (!quiet) console.warn(`⚠️ 設定ファイルの読み込みに失敗: ${filePath}`, error);
|
|
55
68
|
}
|
|
56
69
|
}
|
|
57
70
|
}
|
|
58
71
|
|
|
59
|
-
console.log("📋 デフォルト設定を使用");
|
|
72
|
+
if (!quiet) console.log("📋 デフォルト設定を使用");
|
|
60
73
|
return DEFAULT_CONFIG;
|
|
61
74
|
}
|
|
62
75
|
|
|
@@ -81,6 +94,11 @@ function mergeConfig(defaultConfig: SwallowKitConfig, userConfig: Partial<Swallo
|
|
|
81
94
|
...userConfig.api?.cors,
|
|
82
95
|
},
|
|
83
96
|
},
|
|
97
|
+
connectors: userConfig.connectors ?? defaultConfig.connectors,
|
|
98
|
+
auth: userConfig.auth
|
|
99
|
+
? { ...defaultConfig.auth, ...userConfig.auth }
|
|
100
|
+
: defaultConfig.auth,
|
|
101
|
+
verify: userConfig.verify ?? defaultConfig.verify,
|
|
84
102
|
};
|
|
85
103
|
}
|
|
86
104
|
|
|
@@ -168,14 +186,104 @@ export function getFullConfig(configPath?: string): SwallowKitConfig {
|
|
|
168
186
|
return mergeConfig(fileConfig, envConfig);
|
|
169
187
|
}
|
|
170
188
|
|
|
189
|
+
/**
|
|
190
|
+
* コネクタ定義を名前で取得
|
|
191
|
+
*/
|
|
192
|
+
export function getConnectorDefinition(connectorName: string, configPath?: string): ConnectorDefinition | undefined {
|
|
193
|
+
const config = getFullConfig(configPath);
|
|
194
|
+
return config.connectors?.[connectorName];
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* 認証設定を取得
|
|
199
|
+
*/
|
|
200
|
+
export function getAuthConfig(configPath?: string): AuthConfig | undefined {
|
|
201
|
+
const config = getFullConfig(configPath);
|
|
202
|
+
return config.auth;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/** Load configuration for mutating/generation commands and fail instead of silently falling back. */
|
|
206
|
+
export function getValidatedFullConfig(configPath?: string): SwallowKitConfig {
|
|
207
|
+
const config = mergeConfig(loadConfig(configPath, true), loadConfigFromEnv());
|
|
208
|
+
const validation = validateConfig(config);
|
|
209
|
+
if (!validation.valid) throw new Error(`Invalid SwallowKit configuration:\n${validation.errors.map(error => `- ${error}`).join("\n")}`);
|
|
210
|
+
return config;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
const VALID_AUTH_PROVIDERS: AuthProvider[] = ["custom-jwt", "swa", "external-token", "swa-custom", "none"];
|
|
214
|
+
const AUTH_NAME = /^[A-Za-z][A-Za-z0-9_-]*$/;
|
|
215
|
+
|
|
216
|
+
/** Convert the legacy single-provider shape to the canonical named-scheme shape. */
|
|
217
|
+
export function normalizeAuthConfig(auth?: AuthConfig): NormalizedAuthConfig | undefined {
|
|
218
|
+
if (!auth) return undefined;
|
|
219
|
+
const schemes = { ...(auth.schemes ?? {}) };
|
|
220
|
+
if (auth.provider && auth.provider !== "none" && !schemes.default) {
|
|
221
|
+
schemes.default = { provider: auth.provider, customJwt: auth.customJwt, swa: auth.swa };
|
|
222
|
+
}
|
|
223
|
+
const rawDefault = auth.authorization?.defaultPolicy ?? (Object.keys(schemes).length ? "authenticated" : "anonymous");
|
|
224
|
+
return {
|
|
225
|
+
...auth,
|
|
226
|
+
schemes,
|
|
227
|
+
authorization: {
|
|
228
|
+
...auth.authorization,
|
|
229
|
+
defaultPolicy: rawDefault === "public" ? "anonymous" : rawDefault,
|
|
230
|
+
policies: { ...(auth.authorization?.policies ?? {}) },
|
|
231
|
+
},
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
export function getNormalizedAuthConfig(configPath?: string): NormalizedAuthConfig | undefined {
|
|
236
|
+
return normalizeAuthConfig(getAuthConfig(configPath));
|
|
237
|
+
}
|
|
238
|
+
|
|
171
239
|
/**
|
|
172
240
|
* 設定の検証
|
|
173
241
|
*/
|
|
242
|
+
const VALID_CONNECTOR_TYPES = ["rdb", "api"];
|
|
243
|
+
const VALID_RDB_PROVIDERS = ["mysql", "postgres", "sqlserver"];
|
|
244
|
+
const VALID_API_AUTH_TYPES = ["apiKey", "bearer", "oauth2"];
|
|
245
|
+
|
|
246
|
+
function hasConfiguredDatabase(config: SwallowKitConfig): boolean {
|
|
247
|
+
return Boolean(config.database && Object.keys(config.database).length > 0);
|
|
248
|
+
}
|
|
249
|
+
|
|
174
250
|
export function validateConfig(config: SwallowKitConfig): { valid: boolean; errors: string[] } {
|
|
175
251
|
const errors: string[] = [];
|
|
176
252
|
|
|
253
|
+
const auth = normalizeAuthConfig(config.auth);
|
|
254
|
+
if (auth) {
|
|
255
|
+
for (const [name, scheme] of Object.entries(auth.schemes)) {
|
|
256
|
+
const base = `auth.schemes.${name}`;
|
|
257
|
+
if (!AUTH_NAME.test(name)) errors.push(`${base}: scheme name must match ${AUTH_NAME}; rename the scheme`);
|
|
258
|
+
if (!VALID_AUTH_PROVIDERS.includes(scheme.provider)) errors.push(`${base}.provider: unsupported provider '${scheme.provider}'; use ${VALID_AUTH_PROVIDERS.join(", ")}`);
|
|
259
|
+
if (scheme.provider === "none" || scheme.provider === "swa-custom") errors.push(`${base}.provider: '${scheme.provider}' cannot be used as a named scheme; use swa, external-token, or custom-jwt`);
|
|
260
|
+
if (scheme.provider === "custom-jwt") {
|
|
261
|
+
const jwt = scheme.customJwt ?? (name === "default" ? auth.customJwt : undefined);
|
|
262
|
+
for (const key of ["userConnector", "userTable", "loginIdColumn", "passwordHashColumn", "rolesColumn"] as const) {
|
|
263
|
+
if (!jwt?.[key]) errors.push(`${base}.customJwt.${key}: required for custom-jwt; configure this value`);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
for (const [name, policy] of Object.entries(auth.authorization.policies)) {
|
|
268
|
+
const base = `auth.authorization.policies.${name}`;
|
|
269
|
+
if (!AUTH_NAME.test(name)) errors.push(`${base}: policy name must match ${AUTH_NAME}; rename the policy`);
|
|
270
|
+
if (!Array.isArray(policy.schemes) || policy.schemes.length === 0) errors.push(`${base}.schemes: provide at least one named scheme`);
|
|
271
|
+
for (const scheme of policy.schemes ?? []) if (!auth.schemes[scheme]) errors.push(`${base}.schemes: undefined scheme '${scheme}'; define auth.schemes.${scheme}`);
|
|
272
|
+
const sources = new Map<string, string>();
|
|
273
|
+
for (const schemeName of policy.schemes ?? []) {
|
|
274
|
+
const provider = auth.schemes[schemeName]?.provider;
|
|
275
|
+
const source = provider === "swa" ? "x-ms-client-principal" : provider === "custom-jwt" || provider === "external-token" ? "authorization-bearer" : provider;
|
|
276
|
+
if (source && sources.has(source)) errors.push(`${base}.schemes: '${sources.get(source)}' and '${schemeName}' both use ${source}; split the policy so credential selection is deterministic`);
|
|
277
|
+
else if (source) sources.set(source, schemeName);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
const defaultPolicy = auth.authorization.defaultPolicy;
|
|
281
|
+
if (defaultPolicy === "authenticated" && !auth.schemes.default && Object.keys(auth.schemes).length !== 1) errors.push("auth.authorization.defaultPolicy: 'authenticated' requires auth.schemes.default (or exactly one scheme); set a default scheme or use a named policy");
|
|
282
|
+
else if (!["anonymous", "authenticated"].includes(defaultPolicy) && !auth.authorization.policies[defaultPolicy]) errors.push(`auth.authorization.defaultPolicy: undefined policy '${defaultPolicy}'; define auth.authorization.policies.${defaultPolicy}`);
|
|
283
|
+
}
|
|
284
|
+
|
|
177
285
|
// データベース設定の検証
|
|
178
|
-
if (config
|
|
286
|
+
if (hasConfiguredDatabase(config) && !config.database?.connectionString) {
|
|
179
287
|
errors.push("Cosmos DB connection string is required");
|
|
180
288
|
}
|
|
181
289
|
|
|
@@ -188,6 +296,34 @@ export function validateConfig(config: SwallowKitConfig): { valid: boolean; erro
|
|
|
188
296
|
errors.push("Backend language must be one of: typescript, csharp, python");
|
|
189
297
|
}
|
|
190
298
|
|
|
299
|
+
// コネクタ設定の検証
|
|
300
|
+
if (config.connectors) {
|
|
301
|
+
for (const [name, connector] of Object.entries(config.connectors)) {
|
|
302
|
+
if (!VALID_CONNECTOR_TYPES.includes(connector.type)) {
|
|
303
|
+
errors.push(`Connector '${name}': type must be one of: ${VALID_CONNECTOR_TYPES.join(", ")}`);
|
|
304
|
+
continue;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
if (connector.type === "rdb") {
|
|
308
|
+
if (!connector.provider || !VALID_RDB_PROVIDERS.includes(connector.provider)) {
|
|
309
|
+
errors.push(`Connector '${name}': provider must be one of: ${VALID_RDB_PROVIDERS.join(", ")}`);
|
|
310
|
+
}
|
|
311
|
+
if (!connector.connectionEnvVar) {
|
|
312
|
+
errors.push(`Connector '${name}': connectionEnvVar is required`);
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
if (connector.type === "api") {
|
|
317
|
+
if (!connector.baseUrlEnvVar) {
|
|
318
|
+
errors.push(`Connector '${name}': baseUrlEnvVar is required`);
|
|
319
|
+
}
|
|
320
|
+
if (connector.auth && !VALID_API_AUTH_TYPES.includes(connector.auth.type)) {
|
|
321
|
+
errors.push(`Connector '${name}': auth.type must be one of: ${VALID_API_AUTH_TYPES.join(", ")}`);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
|
|
191
327
|
return {
|
|
192
328
|
valid: errors.length === 0,
|
|
193
329
|
errors,
|