swallowkit 1.0.0-beta.2 → 1.0.0-beta.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (191) hide show
  1. package/LICENSE +21 -21
  2. package/README.ja.md +312 -215
  3. package/README.md +369 -216
  4. package/dist/__tests__/fixtures.d.ts +22 -0
  5. package/dist/__tests__/fixtures.d.ts.map +1 -0
  6. package/dist/__tests__/fixtures.js +146 -0
  7. package/dist/__tests__/fixtures.js.map +1 -0
  8. package/dist/cli/commands/add-auth.d.ts +10 -0
  9. package/dist/cli/commands/add-auth.d.ts.map +1 -0
  10. package/dist/cli/commands/add-auth.js +444 -0
  11. package/dist/cli/commands/add-auth.js.map +1 -0
  12. package/dist/cli/commands/add-connector.d.ts +20 -0
  13. package/dist/cli/commands/add-connector.d.ts.map +1 -0
  14. package/dist/cli/commands/add-connector.js +163 -0
  15. package/dist/cli/commands/add-connector.js.map +1 -0
  16. package/dist/cli/commands/create-model.d.ts +1 -4
  17. package/dist/cli/commands/create-model.d.ts.map +1 -1
  18. package/dist/cli/commands/create-model.js +21 -82
  19. package/dist/cli/commands/create-model.js.map +1 -1
  20. package/dist/cli/commands/dev-seeds.d.ts +35 -0
  21. package/dist/cli/commands/dev-seeds.d.ts.map +1 -0
  22. package/dist/cli/commands/dev-seeds.js +292 -0
  23. package/dist/cli/commands/dev-seeds.js.map +1 -0
  24. package/dist/cli/commands/dev.d.ts +19 -0
  25. package/dist/cli/commands/dev.d.ts.map +1 -1
  26. package/dist/cli/commands/dev.js +476 -117
  27. package/dist/cli/commands/dev.js.map +1 -1
  28. package/dist/cli/commands/index.d.ts +1 -0
  29. package/dist/cli/commands/index.d.ts.map +1 -1
  30. package/dist/cli/commands/index.js +3 -1
  31. package/dist/cli/commands/index.js.map +1 -1
  32. package/dist/cli/commands/init.d.ts +13 -0
  33. package/dist/cli/commands/init.d.ts.map +1 -1
  34. package/dist/cli/commands/init.js +2627 -1708
  35. package/dist/cli/commands/init.js.map +1 -1
  36. package/dist/cli/commands/scaffold.d.ts +3 -0
  37. package/dist/cli/commands/scaffold.d.ts.map +1 -1
  38. package/dist/cli/commands/scaffold.js +617 -129
  39. package/dist/cli/commands/scaffold.js.map +1 -1
  40. package/dist/cli/index.d.ts +5 -1
  41. package/dist/cli/index.d.ts.map +1 -1
  42. package/dist/cli/index.js +164 -42
  43. package/dist/cli/index.js.map +1 -1
  44. package/dist/core/config.d.ts +8 -2
  45. package/dist/core/config.d.ts.map +1 -1
  46. package/dist/core/config.js +90 -4
  47. package/dist/core/config.js.map +1 -1
  48. package/dist/core/mock/connector-mock-server.d.ts +101 -0
  49. package/dist/core/mock/connector-mock-server.d.ts.map +1 -0
  50. package/dist/core/mock/connector-mock-server.js +480 -0
  51. package/dist/core/mock/connector-mock-server.js.map +1 -0
  52. package/dist/core/mock/zod-mock-generator.d.ts +14 -0
  53. package/dist/core/mock/zod-mock-generator.d.ts.map +1 -0
  54. package/dist/core/mock/zod-mock-generator.js +163 -0
  55. package/dist/core/mock/zod-mock-generator.js.map +1 -0
  56. package/dist/core/operations/create-model.d.ts +15 -0
  57. package/dist/core/operations/create-model.d.ts.map +1 -0
  58. package/dist/core/operations/create-model.js +171 -0
  59. package/dist/core/operations/create-model.js.map +1 -0
  60. package/dist/core/operations/runtime.d.ts +32 -0
  61. package/dist/core/operations/runtime.d.ts.map +1 -0
  62. package/dist/core/operations/runtime.js +225 -0
  63. package/dist/core/operations/runtime.js.map +1 -0
  64. package/dist/core/operations/scaffold-machine.d.ts +16 -0
  65. package/dist/core/operations/scaffold-machine.d.ts.map +1 -0
  66. package/dist/core/operations/scaffold-machine.js +63 -0
  67. package/dist/core/operations/scaffold-machine.js.map +1 -0
  68. package/dist/core/project/manifest.d.ts +92 -0
  69. package/dist/core/project/manifest.d.ts.map +1 -0
  70. package/dist/core/project/manifest.js +321 -0
  71. package/dist/core/project/manifest.js.map +1 -0
  72. package/dist/core/project/validation.d.ts +20 -0
  73. package/dist/core/project/validation.d.ts.map +1 -0
  74. package/dist/core/project/validation.js +204 -0
  75. package/dist/core/project/validation.js.map +1 -0
  76. package/dist/core/scaffold/auth-generator.d.ts +38 -0
  77. package/dist/core/scaffold/auth-generator.d.ts.map +1 -0
  78. package/dist/core/scaffold/auth-generator.js +1244 -0
  79. package/dist/core/scaffold/auth-generator.js.map +1 -0
  80. package/dist/core/scaffold/connector-functions-generator.d.ts +41 -0
  81. package/dist/core/scaffold/connector-functions-generator.d.ts.map +1 -0
  82. package/dist/core/scaffold/connector-functions-generator.js +1027 -0
  83. package/dist/core/scaffold/connector-functions-generator.js.map +1 -0
  84. package/dist/core/scaffold/functions-generator.d.ts +7 -1
  85. package/dist/core/scaffold/functions-generator.d.ts.map +1 -1
  86. package/dist/core/scaffold/functions-generator.js +920 -213
  87. package/dist/core/scaffold/functions-generator.js.map +1 -1
  88. package/dist/core/scaffold/model-parser.d.ts +20 -1
  89. package/dist/core/scaffold/model-parser.d.ts.map +1 -1
  90. package/dist/core/scaffold/model-parser.js +329 -135
  91. package/dist/core/scaffold/model-parser.js.map +1 -1
  92. package/dist/core/scaffold/nextjs-generator.d.ts +8 -0
  93. package/dist/core/scaffold/nextjs-generator.d.ts.map +1 -1
  94. package/dist/core/scaffold/nextjs-generator.js +314 -182
  95. package/dist/core/scaffold/nextjs-generator.js.map +1 -1
  96. package/dist/core/scaffold/openapi-generator.d.ts +3 -0
  97. package/dist/core/scaffold/openapi-generator.d.ts.map +1 -0
  98. package/dist/core/scaffold/openapi-generator.js +190 -0
  99. package/dist/core/scaffold/openapi-generator.js.map +1 -0
  100. package/dist/core/scaffold/ui-generator.d.ts +10 -4
  101. package/dist/core/scaffold/ui-generator.d.ts.map +1 -1
  102. package/dist/core/scaffold/ui-generator.js +768 -663
  103. package/dist/core/scaffold/ui-generator.js.map +1 -1
  104. package/dist/database/base-model.d.ts +3 -3
  105. package/dist/database/base-model.js +3 -3
  106. package/dist/index.d.ts +2 -2
  107. package/dist/index.d.ts.map +1 -1
  108. package/dist/index.js +2 -1
  109. package/dist/index.js.map +1 -1
  110. package/dist/machine/contracts.d.ts +16 -0
  111. package/dist/machine/contracts.d.ts.map +1 -0
  112. package/dist/machine/contracts.js +3 -0
  113. package/dist/machine/contracts.js.map +1 -0
  114. package/dist/machine/errors.d.ts +11 -0
  115. package/dist/machine/errors.d.ts.map +1 -0
  116. package/dist/machine/errors.js +34 -0
  117. package/dist/machine/errors.js.map +1 -0
  118. package/dist/machine/index.d.ts +3 -0
  119. package/dist/machine/index.d.ts.map +1 -0
  120. package/dist/machine/index.js +156 -0
  121. package/dist/machine/index.js.map +1 -0
  122. package/dist/mcp/index.d.ts +25 -0
  123. package/dist/mcp/index.d.ts.map +1 -0
  124. package/dist/mcp/index.js +184 -0
  125. package/dist/mcp/index.js.map +1 -0
  126. package/dist/types/index.d.ts +65 -0
  127. package/dist/types/index.d.ts.map +1 -1
  128. package/dist/utils/package-manager.d.ts +109 -0
  129. package/dist/utils/package-manager.d.ts.map +1 -0
  130. package/dist/utils/package-manager.js +215 -0
  131. package/dist/utils/package-manager.js.map +1 -0
  132. package/package.json +85 -73
  133. package/src/__tests__/__snapshots__/functions-generator.test.ts.snap +1139 -0
  134. package/src/__tests__/__snapshots__/nextjs-generator.test.ts.snap +194 -0
  135. package/src/__tests__/__snapshots__/ui-generator.test.ts.snap +532 -0
  136. package/src/__tests__/auth.test.ts +654 -0
  137. package/src/__tests__/config.test.ts +263 -0
  138. package/src/__tests__/connector-functions-generator.test.ts +288 -0
  139. package/src/__tests__/connector-mock-server.test.ts +439 -0
  140. package/src/__tests__/connector-model-bff.test.ts +162 -0
  141. package/src/__tests__/dev-seeds.test.ts +112 -0
  142. package/src/__tests__/dev.test.ts +154 -0
  143. package/src/__tests__/fixtures.ts +144 -0
  144. package/src/__tests__/functions-generator.test.ts +237 -0
  145. package/src/__tests__/init.test.ts +80 -0
  146. package/src/__tests__/machine.test.ts +212 -0
  147. package/src/__tests__/mcp.test.ts +56 -0
  148. package/src/__tests__/model-parser.test.ts +72 -0
  149. package/src/__tests__/nextjs-generator.test.ts +97 -0
  150. package/src/__tests__/openapi-generator.test.ts +43 -0
  151. package/src/__tests__/package-manager.test.ts +189 -0
  152. package/src/__tests__/scaffold.test.ts +39 -0
  153. package/src/__tests__/string-utils.test.ts +75 -0
  154. package/src/__tests__/ui-generator.test.ts +144 -0
  155. package/src/__tests__/zod-mock-generator.test.ts +132 -0
  156. package/src/cli/commands/add-auth.ts +500 -0
  157. package/src/cli/commands/add-connector.ts +158 -0
  158. package/src/cli/commands/create-model.ts +62 -0
  159. package/src/cli/commands/dev-seeds.ts +358 -0
  160. package/src/cli/commands/dev.ts +962 -0
  161. package/src/cli/commands/index.ts +9 -0
  162. package/src/cli/commands/init.ts +3371 -0
  163. package/src/cli/commands/provision.ts +193 -0
  164. package/src/cli/commands/scaffold.ts +1211 -0
  165. package/src/cli/index.ts +193 -0
  166. package/src/core/config.ts +308 -0
  167. package/src/core/mock/connector-mock-server.ts +555 -0
  168. package/src/core/mock/zod-mock-generator.ts +205 -0
  169. package/src/core/operations/create-model.ts +174 -0
  170. package/src/core/operations/runtime.ts +235 -0
  171. package/src/core/operations/scaffold-machine.ts +91 -0
  172. package/src/core/project/manifest.ts +402 -0
  173. package/src/core/project/validation.ts +221 -0
  174. package/src/core/scaffold/auth-generator.ts +1284 -0
  175. package/src/core/scaffold/connector-functions-generator.ts +1128 -0
  176. package/src/core/scaffold/functions-generator.ts +970 -0
  177. package/src/core/scaffold/model-parser.ts +841 -0
  178. package/src/core/scaffold/nextjs-generator.ts +370 -0
  179. package/src/core/scaffold/openapi-generator.ts +212 -0
  180. package/src/core/scaffold/ui-generator.ts +1061 -0
  181. package/src/database/base-model.ts +184 -0
  182. package/src/database/client.ts +140 -0
  183. package/src/database/repository.ts +104 -0
  184. package/src/database/runtime-check.ts +25 -0
  185. package/src/index.ts +27 -0
  186. package/src/machine/contracts.ts +17 -0
  187. package/src/machine/errors.ts +34 -0
  188. package/src/machine/index.ts +173 -0
  189. package/src/mcp/index.ts +185 -0
  190. package/src/types/index.ts +134 -0
  191. package/src/utils/package-manager.ts +229 -0
@@ -0,0 +1,193 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { execSync } from "child_process";
4
+ import { Command } from "commander";
5
+ import { initCommand, devCommand, devSeedsCommand, scaffoldCommand, createModelCommand } from "./commands";
6
+ import { provisionCommand } from "./commands/provision";
7
+ import { addConnectorCommand } from "./commands/add-connector";
8
+ import { addAuthCommand } from "./commands/add-auth";
9
+ import { isMachineCommand, runMachineCli } from "../machine";
10
+
11
+ export const CLI_VERSION = require("../../package.json").version as string;
12
+
13
+ const DEV_OPTION_ARITY = new Map<string, 0 | 1>([
14
+ ["-p", 1],
15
+ ["--port", 1],
16
+ ["-f", 1],
17
+ ["--functions-port", 1],
18
+ ["--host", 1],
19
+ ["--seed-env", 1],
20
+ ["-o", 0],
21
+ ["--open", 0],
22
+ ["-v", 0],
23
+ ["--verbose", 0],
24
+ ["--no-functions", 0],
25
+ ["--mock-connectors", 0],
26
+ ]);
27
+
28
+ function ensureUtf8ConsoleOnWindows(): void {
29
+ if (process.platform === 'win32') {
30
+ try {
31
+ execSync('chcp 65001', { stdio: 'ignore' });
32
+ } catch {
33
+ // ignore — non-critical
34
+ }
35
+ }
36
+ }
37
+
38
+ function isDevOptionSequence(tokens: string[]): boolean {
39
+ if (tokens.length === 0) {
40
+ return false;
41
+ }
42
+
43
+ for (let index = 0; index < tokens.length; index += 1) {
44
+ const token = tokens[index];
45
+ const arity = DEV_OPTION_ARITY.get(token);
46
+
47
+ if (arity === undefined) {
48
+ return false;
49
+ }
50
+
51
+ if (arity === 1) {
52
+ const value = tokens[index + 1];
53
+ if (value === undefined || value === "dev") {
54
+ return false;
55
+ }
56
+ index += 1;
57
+ }
58
+ }
59
+
60
+ return true;
61
+ }
62
+
63
+ export function normalizeDevCommandArgv(argv: string[]): string[] {
64
+ if (argv.length <= 3) {
65
+ return argv;
66
+ }
67
+
68
+ const prefix = argv.slice(0, 2);
69
+ const args = argv.slice(2);
70
+ const devIndex = args.indexOf("dev");
71
+
72
+ if (devIndex <= 0) {
73
+ return argv;
74
+ }
75
+
76
+ const leadingTokens = args.slice(0, devIndex);
77
+ if (!isDevOptionSequence(leadingTokens)) {
78
+ return argv;
79
+ }
80
+
81
+ return [
82
+ ...prefix,
83
+ "dev",
84
+ ...leadingTokens,
85
+ ...args.slice(devIndex + 1),
86
+ ];
87
+ }
88
+
89
+ export function createProgram(devCommandOverride: Command = devCommand): Command {
90
+ const program = new Command();
91
+
92
+ program
93
+ .name("swallowkit")
94
+ .description("Next.js framework optimized for Azure deployment - Automatically splits SSR into individual Azure Functions")
95
+ .version(CLI_VERSION);
96
+
97
+ // Register commands
98
+ program
99
+ .command("init [project-name]")
100
+ .description("Initialize a new SwallowKit project")
101
+ .option("--template <template>", "Template to use", "default")
102
+ .option("--next-version <version>", "Next.js version to install (e.g., 16.0.7, latest)", "latest")
103
+ .option("--cicd <provider>", "CI/CD provider: github | azure | skip")
104
+ .option("--backend-language <language>", "Azure Functions backend language: typescript | csharp | python")
105
+ .option("--cosmos-db-mode <mode>", "Cosmos DB mode: freetier | serverless")
106
+ .option("--vnet <option>", "Network security: outbound | none")
107
+ .action((projectName, options) => {
108
+ initCommand({
109
+ name: projectName || "swallowkit-app",
110
+ template: options.template,
111
+ nextVersion: options.nextVersion,
112
+ cicd: options.cicd,
113
+ backendLanguage: options.backendLanguage,
114
+ cosmosDbMode: options.cosmosDbMode,
115
+ vnet: options.vnet,
116
+ });
117
+ });
118
+
119
+ program.addCommand(devCommandOverride);
120
+ program.addCommand(devSeedsCommand);
121
+
122
+ program.addCommand(provisionCommand);
123
+
124
+ program
125
+ .command("create-model <names...>")
126
+ .description("Create model template files with id, createdAt, and updatedAt fields")
127
+ .option("--models-dir <dir>", "Models directory", "shared/models")
128
+ .option("--connector <name>", "Associate model with a connector defined in swallowkit.config.js")
129
+ .action((names, options) => {
130
+ createModelCommand({
131
+ names,
132
+ modelsDir: options.modelsDir,
133
+ connector: options.connector,
134
+ });
135
+ });
136
+
137
+ program
138
+ .command("scaffold <model>")
139
+ .description("Generate CRUD code for Azure Functions and Next.js BFF from Zod models")
140
+ .option("--functions-dir <dir>", "Azure Functions directory", "functions")
141
+ .option("--api-dir <dir>", "Next.js API routes directory", "app/api")
142
+ .option("--api-only", "Generate API only, skip UI components", false)
143
+ .action((model, options) => {
144
+ scaffoldCommand({
145
+ model,
146
+ functionsDir: options.functionsDir,
147
+ apiDir: options.apiDir,
148
+ apiOnly: options.apiOnly,
149
+ });
150
+ });
151
+
152
+ program
153
+ .command("add-connector <name>")
154
+ .description("Add an external data source connector configuration")
155
+ .requiredOption("--type <type>", "Connector type: rdb | api")
156
+ .option("--provider <provider>", "RDB provider: mysql | postgres | sqlserver", "mysql")
157
+ .action((name, options) => {
158
+ addConnectorCommand({
159
+ name,
160
+ type: options.type,
161
+ provider: options.provider,
162
+ });
163
+ });
164
+
165
+ program
166
+ .command("add-auth")
167
+ .description("Add authentication and authorization to the project")
168
+ .option("--provider <provider>", "Auth provider: custom-jwt | swa | swa-custom | none", "custom-jwt")
169
+ .action((options) => {
170
+ addAuthCommand({
171
+ provider: options.provider,
172
+ });
173
+ });
174
+
175
+ return program;
176
+ }
177
+
178
+ export async function runCli(argv: string[] = process.argv): Promise<void> {
179
+ ensureUtf8ConsoleOnWindows();
180
+ if (isMachineCommand(argv)) {
181
+ await runMachineCli(argv);
182
+ return;
183
+ }
184
+
185
+ await createProgram().parseAsync(normalizeDevCommandArgv(argv));
186
+ }
187
+
188
+ if (require.main === module) {
189
+ void runCli().catch((error) => {
190
+ console.error(error);
191
+ process.exitCode = 1;
192
+ });
193
+ }
@@ -0,0 +1,308 @@
1
+ import * as fs from "fs";
2
+ import { createRequire } from "module";
3
+ import * as path from "path";
4
+ import { AuthConfig, BackendLanguage, ConnectorDefinition, SwallowKitConfig } from "../types";
5
+ import { detectFromProject, getCommands } from "../utils/package-manager";
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
+
18
+ const VALID_BACKEND_LANGUAGES: BackendLanguage[] = ["typescript", "csharp", "python"];
19
+
20
+ /**
21
+ * デフォルト設定
22
+ */
23
+ const DEFAULT_CONFIG: SwallowKitConfig = {
24
+ database: {},
25
+ backend: {
26
+ language: "typescript",
27
+ },
28
+ api: {
29
+ endpoint: "/api/_swallowkit",
30
+ cors: {
31
+ origin: "*",
32
+ credentials: true,
33
+ },
34
+ },
35
+ };
36
+
37
+ /**
38
+ * 設定ファイルを読み込み
39
+ */
40
+ export function loadConfig(configPath?: string): SwallowKitConfig {
41
+ const defaultPaths = [
42
+ "swallowkit.config.json",
43
+ "swallowkit.config.js",
44
+ ".swallowkitrc.json",
45
+ ];
46
+
47
+ const paths = configPath ? [configPath] : defaultPaths;
48
+
49
+ for (const filePath of paths) {
50
+ const fullPath = path.resolve(process.cwd(), filePath);
51
+
52
+ if (fs.existsSync(fullPath)) {
53
+ try {
54
+ console.log(`📋 設定ファイルを読み込み: ${filePath}`);
55
+
56
+ if (filePath.endsWith(".json")) {
57
+ const configData = fs.readFileSync(fullPath, "utf-8");
58
+ const userConfig = JSON.parse(configData);
59
+ return mergeConfig(DEFAULT_CONFIG, userConfig);
60
+ } else if (filePath.endsWith(".js")) {
61
+ delete requireFromHere.cache[fullPath];
62
+ const loadedConfig = requireFromHere(fullPath) as Partial<SwallowKitConfig> | { default?: Partial<SwallowKitConfig> };
63
+ return mergeConfig(DEFAULT_CONFIG, unwrapConfigModule(loadedConfig));
64
+ }
65
+ } catch (error) {
66
+ console.warn(`⚠️ 設定ファイルの読み込みに失敗: ${filePath}`, error);
67
+ }
68
+ }
69
+ }
70
+
71
+ console.log("📋 デフォルト設定を使用");
72
+ return DEFAULT_CONFIG;
73
+ }
74
+
75
+ /**
76
+ * 設定をマージ
77
+ */
78
+ function mergeConfig(defaultConfig: SwallowKitConfig, userConfig: Partial<SwallowKitConfig>): SwallowKitConfig {
79
+ return {
80
+ database: {
81
+ ...defaultConfig.database,
82
+ ...userConfig.database,
83
+ },
84
+ backend: {
85
+ ...defaultConfig.backend,
86
+ ...userConfig.backend,
87
+ },
88
+ api: {
89
+ ...defaultConfig.api,
90
+ ...userConfig.api,
91
+ cors: {
92
+ ...defaultConfig.api?.cors,
93
+ ...userConfig.api?.cors,
94
+ },
95
+ },
96
+ connectors: userConfig.connectors ?? defaultConfig.connectors,
97
+ auth: userConfig.auth
98
+ ? { ...defaultConfig.auth, ...userConfig.auth }
99
+ : defaultConfig.auth,
100
+ };
101
+ }
102
+
103
+ /**
104
+ * 設定ファイルを生成
105
+ */
106
+ export function generateConfig(outputPath: string = "swallowkit.config.json"): void {
107
+ const config = {
108
+ $schema: "https://swallowkit.dev/schema.json",
109
+ database: {
110
+ connectionString: "your-cosmos-connection-string",
111
+ databaseName: "SwallowKitDB",
112
+ },
113
+ backend: {
114
+ language: "typescript",
115
+ },
116
+ api: {
117
+ endpoint: "/api/_swallowkit",
118
+ cors: {
119
+ origin: ["http://localhost:3000"],
120
+ credentials: true,
121
+ },
122
+ },
123
+ };
124
+
125
+ fs.writeFileSync(outputPath, JSON.stringify(config, null, 2));
126
+ console.log(`✅ 設定ファイルを生成しました: ${outputPath}`);
127
+ }
128
+
129
+ /**
130
+ * 環境変数からの設定読み込み
131
+ */
132
+ export function loadConfigFromEnv(): Partial<SwallowKitConfig> {
133
+ const config: Partial<SwallowKitConfig> = {};
134
+
135
+ // データベース設定
136
+ if (process.env.SWALLOWKIT_DB_CONNECTION_STRING) {
137
+ config.database = {
138
+ ...config.database,
139
+ connectionString: process.env.SWALLOWKIT_DB_CONNECTION_STRING,
140
+ };
141
+ }
142
+
143
+ if (process.env.SWALLOWKIT_DB_NAME) {
144
+ config.database = {
145
+ ...config.database,
146
+ databaseName: process.env.SWALLOWKIT_DB_NAME,
147
+ };
148
+ }
149
+
150
+ // API設定
151
+ if (process.env.SWALLOWKIT_API_ENDPOINT) {
152
+ config.api = {
153
+ ...config.api,
154
+ endpoint: process.env.SWALLOWKIT_API_ENDPOINT,
155
+ };
156
+ }
157
+
158
+ if (process.env.SWALLOWKIT_BACKEND_LANGUAGE) {
159
+ config.backend = {
160
+ ...config.backend,
161
+ language: process.env.SWALLOWKIT_BACKEND_LANGUAGE as BackendLanguage,
162
+ };
163
+ }
164
+
165
+ return config;
166
+ }
167
+
168
+ export function getBackendLanguage(configPath?: string): BackendLanguage {
169
+ const language = getFullConfig(configPath).backend?.language;
170
+ if (language && VALID_BACKEND_LANGUAGES.includes(language)) {
171
+ return language;
172
+ }
173
+
174
+ return "typescript";
175
+ }
176
+
177
+ /**
178
+ * 完全な設定を取得(ファイル + 環境変数)
179
+ */
180
+ export function getFullConfig(configPath?: string): SwallowKitConfig {
181
+ const fileConfig = loadConfig(configPath);
182
+ const envConfig = loadConfigFromEnv();
183
+
184
+ return mergeConfig(fileConfig, envConfig);
185
+ }
186
+
187
+ /**
188
+ * コネクタ定義を名前で取得
189
+ */
190
+ export function getConnectorDefinition(connectorName: string, configPath?: string): ConnectorDefinition | undefined {
191
+ const config = getFullConfig(configPath);
192
+ return config.connectors?.[connectorName];
193
+ }
194
+
195
+ /**
196
+ * 認証設定を取得
197
+ */
198
+ export function getAuthConfig(configPath?: string): AuthConfig | undefined {
199
+ const config = getFullConfig(configPath);
200
+ return config.auth;
201
+ }
202
+
203
+ /**
204
+ * 設定の検証
205
+ */
206
+ const VALID_CONNECTOR_TYPES = ["rdb", "api"];
207
+ const VALID_RDB_PROVIDERS = ["mysql", "postgres", "sqlserver"];
208
+ const VALID_API_AUTH_TYPES = ["apiKey", "bearer", "oauth2"];
209
+
210
+ export function validateConfig(config: SwallowKitConfig): { valid: boolean; errors: string[] } {
211
+ const errors: string[] = [];
212
+
213
+ // データベース設定の検証
214
+ if (config.database && !config.database.connectionString) {
215
+ errors.push("Cosmos DB connection string is required");
216
+ }
217
+
218
+ // API設定の検証
219
+ if (config.api?.endpoint && !config.api.endpoint.startsWith("/")) {
220
+ errors.push("API endpoint must start with '/'");
221
+ }
222
+
223
+ if (config.backend?.language && !VALID_BACKEND_LANGUAGES.includes(config.backend.language)) {
224
+ errors.push("Backend language must be one of: typescript, csharp, python");
225
+ }
226
+
227
+ // コネクタ設定の検証
228
+ if (config.connectors) {
229
+ for (const [name, connector] of Object.entries(config.connectors)) {
230
+ if (!VALID_CONNECTOR_TYPES.includes(connector.type)) {
231
+ errors.push(`Connector '${name}': type must be one of: ${VALID_CONNECTOR_TYPES.join(", ")}`);
232
+ continue;
233
+ }
234
+
235
+ if (connector.type === "rdb") {
236
+ if (!connector.provider || !VALID_RDB_PROVIDERS.includes(connector.provider)) {
237
+ errors.push(`Connector '${name}': provider must be one of: ${VALID_RDB_PROVIDERS.join(", ")}`);
238
+ }
239
+ if (!connector.connectionEnvVar) {
240
+ errors.push(`Connector '${name}': connectionEnvVar is required`);
241
+ }
242
+ }
243
+
244
+ if (connector.type === "api") {
245
+ if (!connector.baseUrlEnvVar) {
246
+ errors.push(`Connector '${name}': baseUrlEnvVar is required`);
247
+ }
248
+ if (connector.auth && !VALID_API_AUTH_TYPES.includes(connector.auth.type)) {
249
+ errors.push(`Connector '${name}': auth.type must be one of: ${VALID_API_AUTH_TYPES.join(", ")}`);
250
+ }
251
+ }
252
+ }
253
+ }
254
+
255
+ return {
256
+ valid: errors.length === 0,
257
+ errors,
258
+ };
259
+ }
260
+
261
+ /**
262
+ * SwallowKit プロジェクトディレクトリかどうかを検証するための設定ファイルパス一覧
263
+ */
264
+ const SWALLOWKIT_PROJECT_MARKERS = [
265
+ "swallowkit.config.js",
266
+ "swallowkit.config.json",
267
+ ".swallowkitrc.json",
268
+ ];
269
+
270
+ /**
271
+ * 現在のディレクトリが SwallowKit プロジェクトディレクトリかどうかを検証
272
+ * @param projectRoot 検証するディレクトリパス(省略時は process.cwd())
273
+ * @returns プロジェクトが有効な場合は true、無効な場合は false
274
+ */
275
+ export function isSwallowKitProject(projectRoot?: string): boolean {
276
+ const cwd = projectRoot || process.cwd();
277
+
278
+ // swallowkit 設定ファイルの存在をチェック
279
+ for (const marker of SWALLOWKIT_PROJECT_MARKERS) {
280
+ const markerPath = path.resolve(cwd, marker);
281
+ if (fs.existsSync(markerPath)) {
282
+ return true;
283
+ }
284
+ }
285
+
286
+ return false;
287
+ }
288
+
289
+ /**
290
+ * SwallowKit プロジェクトディレクトリかどうかを検証し、無効な場合はエラーメッセージを表示して終了
291
+ * init 以外のコマンドの冒頭で呼び出すこと
292
+ * @param commandName コマンド名(エラーメッセージ用)
293
+ * @param projectRoot 検証するディレクトリパス(省略時は process.cwd())
294
+ */
295
+ export function ensureSwallowKitProject(commandName: string, projectRoot?: string): void {
296
+ if (!isSwallowKitProject(projectRoot)) {
297
+ console.error(`❌ Error: This directory is not a SwallowKit project.`);
298
+ console.error(`\n The '${commandName}' command must be run from a SwallowKit project directory.`);
299
+ console.error(` A SwallowKit project should contain one of the following files:`);
300
+ for (const marker of SWALLOWKIT_PROJECT_MARKERS) {
301
+ console.error(` - ${marker}`);
302
+ }
303
+ const pmCmd = getCommands(detectFromProject());
304
+ console.error(`\n💡 Tip: Run '${pmCmd.dlx} swallowkit init' first to create a new SwallowKit project,`);
305
+ console.error(` or navigate to an existing SwallowKit project directory.`);
306
+ process.exit(1);
307
+ }
308
+ }