swallowkit 1.0.0-beta.9 → 1.0.1

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 (272) hide show
  1. package/README.ja.md +87 -181
  2. package/README.md +87 -238
  3. package/dist/__tests__/fixtures.d.ts +12 -0
  4. package/dist/__tests__/fixtures.d.ts.map +1 -1
  5. package/dist/__tests__/fixtures.js +101 -0
  6. package/dist/__tests__/fixtures.js.map +1 -1
  7. package/dist/cli/commands/add-auth.d.ts +15 -0
  8. package/dist/cli/commands/add-auth.d.ts.map +1 -0
  9. package/dist/cli/commands/add-auth.js +790 -0
  10. package/dist/cli/commands/add-auth.js.map +1 -0
  11. package/dist/cli/commands/add-connector.d.ts +20 -0
  12. package/dist/cli/commands/add-connector.d.ts.map +1 -0
  13. package/dist/cli/commands/add-connector.js +164 -0
  14. package/dist/cli/commands/add-connector.js.map +1 -0
  15. package/dist/cli/commands/cosmos-worktree-isolation.d.ts +25 -0
  16. package/dist/cli/commands/cosmos-worktree-isolation.d.ts.map +1 -0
  17. package/dist/cli/commands/cosmos-worktree-isolation.js +124 -0
  18. package/dist/cli/commands/cosmos-worktree-isolation.js.map +1 -0
  19. package/dist/cli/commands/create-model.d.ts +1 -4
  20. package/dist/cli/commands/create-model.d.ts.map +1 -1
  21. package/dist/cli/commands/create-model.js +20 -82
  22. package/dist/cli/commands/create-model.js.map +1 -1
  23. package/dist/cli/commands/dev-seeds.d.ts +27 -0
  24. package/dist/cli/commands/dev-seeds.d.ts.map +1 -1
  25. package/dist/cli/commands/dev-seeds.js +188 -6
  26. package/dist/cli/commands/dev-seeds.js.map +1 -1
  27. package/dist/cli/commands/dev.d.ts +30 -0
  28. package/dist/cli/commands/dev.d.ts.map +1 -1
  29. package/dist/cli/commands/dev.js +495 -129
  30. package/dist/cli/commands/dev.js.map +1 -1
  31. package/dist/cli/commands/init.d.ts +69 -1
  32. package/dist/cli/commands/init.d.ts.map +1 -1
  33. package/dist/cli/commands/init.js +788 -766
  34. package/dist/cli/commands/init.js.map +1 -1
  35. package/dist/cli/commands/scaffold.d.ts +24 -3
  36. package/dist/cli/commands/scaffold.d.ts.map +1 -1
  37. package/dist/cli/commands/scaffold.js +408 -189
  38. package/dist/cli/commands/scaffold.js.map +1 -1
  39. package/dist/cli/index.d.ts +5 -1
  40. package/dist/cli/index.d.ts.map +1 -1
  41. package/dist/cli/index.js +335 -58
  42. package/dist/cli/index.js.map +1 -1
  43. package/dist/core/config.d.ts +13 -3
  44. package/dist/core/config.d.ts.map +1 -1
  45. package/dist/core/config.js +151 -8
  46. package/dist/core/config.js.map +1 -1
  47. package/dist/core/mock/connector-mock-server.d.ts +101 -0
  48. package/dist/core/mock/connector-mock-server.d.ts.map +1 -0
  49. package/dist/core/mock/connector-mock-server.js +480 -0
  50. package/dist/core/mock/connector-mock-server.js.map +1 -0
  51. package/dist/core/mock/zod-mock-generator.d.ts +14 -0
  52. package/dist/core/mock/zod-mock-generator.d.ts.map +1 -0
  53. package/dist/core/mock/zod-mock-generator.js +163 -0
  54. package/dist/core/mock/zod-mock-generator.js.map +1 -0
  55. package/dist/core/operations/auth-operations.d.ts +61 -0
  56. package/dist/core/operations/auth-operations.d.ts.map +1 -0
  57. package/dist/core/operations/auth-operations.js +272 -0
  58. package/dist/core/operations/auth-operations.js.map +1 -0
  59. package/dist/core/operations/create-model.d.ts +15 -0
  60. package/dist/core/operations/create-model.d.ts.map +1 -0
  61. package/dist/core/operations/create-model.js +185 -0
  62. package/dist/core/operations/create-model.js.map +1 -0
  63. package/dist/core/operations/file-session.d.ts +56 -0
  64. package/dist/core/operations/file-session.d.ts.map +1 -0
  65. package/dist/core/operations/file-session.js +203 -0
  66. package/dist/core/operations/file-session.js.map +1 -0
  67. package/dist/core/operations/provision-operations.d.ts +52 -0
  68. package/dist/core/operations/provision-operations.d.ts.map +1 -0
  69. package/dist/core/operations/provision-operations.js +211 -0
  70. package/dist/core/operations/provision-operations.js.map +1 -0
  71. package/dist/core/operations/runtime.d.ts +37 -0
  72. package/dist/core/operations/runtime.d.ts.map +1 -0
  73. package/dist/core/operations/runtime.js +248 -0
  74. package/dist/core/operations/runtime.js.map +1 -0
  75. package/dist/core/operations/scaffold-apply.d.ts +21 -0
  76. package/dist/core/operations/scaffold-apply.d.ts.map +1 -0
  77. package/dist/core/operations/scaffold-apply.js +57 -0
  78. package/dist/core/operations/scaffold-apply.js.map +1 -0
  79. package/dist/core/operations/scaffold-machine.d.ts +16 -0
  80. package/dist/core/operations/scaffold-machine.d.ts.map +1 -0
  81. package/dist/core/operations/scaffold-machine.js +51 -0
  82. package/dist/core/operations/scaffold-machine.js.map +1 -0
  83. package/dist/core/operations/scaffold-plan.d.ts +43 -0
  84. package/dist/core/operations/scaffold-plan.d.ts.map +1 -0
  85. package/dist/core/operations/scaffold-plan.js +187 -0
  86. package/dist/core/operations/scaffold-plan.js.map +1 -0
  87. package/dist/core/project/agent-instructions.d.ts +29 -0
  88. package/dist/core/project/agent-instructions.d.ts.map +1 -0
  89. package/dist/core/project/agent-instructions.js +160 -0
  90. package/dist/core/project/agent-instructions.js.map +1 -0
  91. package/dist/core/project/artifacts.d.ts +58 -0
  92. package/dist/core/project/artifacts.d.ts.map +1 -0
  93. package/dist/core/project/artifacts.js +179 -0
  94. package/dist/core/project/artifacts.js.map +1 -0
  95. package/dist/core/project/boundaries.d.ts +50 -0
  96. package/dist/core/project/boundaries.d.ts.map +1 -0
  97. package/dist/core/project/boundaries.js +117 -0
  98. package/dist/core/project/boundaries.js.map +1 -0
  99. package/dist/core/project/capabilities.d.ts +58 -0
  100. package/dist/core/project/capabilities.d.ts.map +1 -0
  101. package/dist/core/project/capabilities.js +135 -0
  102. package/dist/core/project/capabilities.js.map +1 -0
  103. package/dist/core/project/drift.d.ts +29 -0
  104. package/dist/core/project/drift.d.ts.map +1 -0
  105. package/dist/core/project/drift.js +190 -0
  106. package/dist/core/project/drift.js.map +1 -0
  107. package/dist/core/project/infra.d.ts +49 -0
  108. package/dist/core/project/infra.d.ts.map +1 -0
  109. package/dist/core/project/infra.js +167 -0
  110. package/dist/core/project/infra.js.map +1 -0
  111. package/dist/core/project/manifest.d.ts +92 -0
  112. package/dist/core/project/manifest.d.ts.map +1 -0
  113. package/dist/core/project/manifest.js +321 -0
  114. package/dist/core/project/manifest.js.map +1 -0
  115. package/dist/core/project/state.d.ts +15 -0
  116. package/dist/core/project/state.d.ts.map +1 -0
  117. package/dist/core/project/state.js +106 -0
  118. package/dist/core/project/state.js.map +1 -0
  119. package/dist/core/project/validation.d.ts +20 -0
  120. package/dist/core/project/validation.d.ts.map +1 -0
  121. package/dist/core/project/validation.js +274 -0
  122. package/dist/core/project/validation.js.map +1 -0
  123. package/dist/core/project/workflows.d.ts +43 -0
  124. package/dist/core/project/workflows.d.ts.map +1 -0
  125. package/dist/core/project/workflows.js +299 -0
  126. package/dist/core/project/workflows.js.map +1 -0
  127. package/dist/core/scaffold/auth-generator.d.ts +63 -0
  128. package/dist/core/scaffold/auth-generator.d.ts.map +1 -0
  129. package/dist/core/scaffold/auth-generator.js +1774 -0
  130. package/dist/core/scaffold/auth-generator.js.map +1 -0
  131. package/dist/core/scaffold/connector-functions-generator.d.ts +41 -0
  132. package/dist/core/scaffold/connector-functions-generator.d.ts.map +1 -0
  133. package/dist/core/scaffold/connector-functions-generator.js +1029 -0
  134. package/dist/core/scaffold/connector-functions-generator.js.map +1 -0
  135. package/dist/core/scaffold/functions-generator.d.ts +4 -3
  136. package/dist/core/scaffold/functions-generator.d.ts.map +1 -1
  137. package/dist/core/scaffold/functions-generator.js +405 -134
  138. package/dist/core/scaffold/functions-generator.js.map +1 -1
  139. package/dist/core/scaffold/model-parser.d.ts +20 -0
  140. package/dist/core/scaffold/model-parser.d.ts.map +1 -1
  141. package/dist/core/scaffold/model-parser.js +229 -78
  142. package/dist/core/scaffold/model-parser.js.map +1 -1
  143. package/dist/core/scaffold/native-schema-generator.d.ts +19 -0
  144. package/dist/core/scaffold/native-schema-generator.d.ts.map +1 -0
  145. package/dist/core/scaffold/native-schema-generator.js +753 -0
  146. package/dist/core/scaffold/native-schema-generator.js.map +1 -0
  147. package/dist/core/scaffold/nextjs-generator.d.ts +8 -0
  148. package/dist/core/scaffold/nextjs-generator.d.ts.map +1 -1
  149. package/dist/core/scaffold/nextjs-generator.js +152 -8
  150. package/dist/core/scaffold/nextjs-generator.js.map +1 -1
  151. package/dist/core/scaffold/ui-generator.d.ts +17 -4
  152. package/dist/core/scaffold/ui-generator.d.ts.map +1 -1
  153. package/dist/core/scaffold/ui-generator.js +174 -34
  154. package/dist/core/scaffold/ui-generator.js.map +1 -1
  155. package/dist/core/verify/index.d.ts +69 -0
  156. package/dist/core/verify/index.d.ts.map +1 -0
  157. package/dist/core/verify/index.js +412 -0
  158. package/dist/core/verify/index.js.map +1 -0
  159. package/dist/machine/contracts.d.ts +24 -0
  160. package/dist/machine/contracts.d.ts.map +1 -0
  161. package/dist/machine/contracts.js +3 -0
  162. package/dist/machine/contracts.js.map +1 -0
  163. package/dist/machine/errors.d.ts +14 -0
  164. package/dist/machine/errors.d.ts.map +1 -0
  165. package/dist/machine/errors.js +42 -0
  166. package/dist/machine/errors.js.map +1 -0
  167. package/dist/machine/index.d.ts +3 -0
  168. package/dist/machine/index.d.ts.map +1 -0
  169. package/dist/machine/index.js +566 -0
  170. package/dist/machine/index.js.map +1 -0
  171. package/dist/mcp/index.d.ts +25 -0
  172. package/dist/mcp/index.d.ts.map +1 -0
  173. package/dist/mcp/index.js +425 -0
  174. package/dist/mcp/index.js.map +1 -0
  175. package/dist/types/index.d.ts +105 -0
  176. package/dist/types/index.d.ts.map +1 -1
  177. package/dist/utils/package-manager.d.ts +7 -11
  178. package/dist/utils/package-manager.d.ts.map +1 -1
  179. package/dist/utils/package-manager.js +42 -17
  180. package/dist/utils/package-manager.js.map +1 -1
  181. package/dist/utils/python-uv.d.ts +21 -0
  182. package/dist/utils/python-uv.d.ts.map +1 -0
  183. package/dist/utils/python-uv.js +111 -0
  184. package/dist/utils/python-uv.js.map +1 -0
  185. package/dist/version.d.ts +2 -0
  186. package/dist/version.d.ts.map +1 -0
  187. package/dist/version.js +49 -0
  188. package/dist/version.js.map +1 -0
  189. package/package.json +15 -17
  190. package/src/__tests__/__snapshots__/functions-generator.test.ts.snap +716 -22
  191. package/src/__tests__/__snapshots__/nextjs-generator.test.ts.snap +19 -7
  192. package/src/__tests__/__snapshots__/ui-generator.test.ts.snap +20 -12
  193. package/src/__tests__/agent-instructions.test.ts +237 -0
  194. package/src/__tests__/agent-loop-phase34.test.ts +619 -0
  195. package/src/__tests__/auth.test.ts +770 -0
  196. package/src/__tests__/bff-swa-auth.test.ts +275 -0
  197. package/src/__tests__/config.test.ts +176 -3
  198. package/src/__tests__/connector-functions-generator.test.ts +288 -0
  199. package/src/__tests__/connector-mock-server.test.ts +459 -0
  200. package/src/__tests__/connector-model-bff.test.ts +162 -0
  201. package/src/__tests__/cosmos-worktree-isolation.test.ts +149 -0
  202. package/src/__tests__/dev-seeds.test.ts +124 -0
  203. package/src/__tests__/dev.test.ts +254 -0
  204. package/src/__tests__/file-session.test.ts +98 -0
  205. package/src/__tests__/fixtures.ts +101 -0
  206. package/src/__tests__/functions-generator.test.ts +137 -1
  207. package/src/__tests__/init.test.ts +366 -2
  208. package/src/__tests__/jest-globals.d.ts +8 -0
  209. package/src/__tests__/machine.test.ts +371 -0
  210. package/src/__tests__/mcp.test.ts +253 -0
  211. package/src/__tests__/model-parser.test.ts +142 -0
  212. package/src/__tests__/multi-auth.test.ts +160 -0
  213. package/src/__tests__/nextjs-generator.test.ts +8 -0
  214. package/src/__tests__/package-manager.test.ts +59 -4
  215. package/src/__tests__/plan-apply.test.ts +499 -0
  216. package/src/__tests__/python-uv.test.ts +48 -0
  217. package/src/__tests__/scaffold.test.ts +287 -24
  218. package/src/__tests__/tsconfig.json +15 -0
  219. package/src/__tests__/ui-generator.test.ts +104 -0
  220. package/src/__tests__/zod-mock-generator.test.ts +132 -0
  221. package/src/cli/commands/add-auth.ts +853 -0
  222. package/src/cli/commands/add-connector.ts +159 -0
  223. package/src/cli/commands/cosmos-worktree-isolation.ts +130 -0
  224. package/src/cli/commands/create-model.ts +21 -100
  225. package/src/cli/commands/dev-seeds.ts +278 -7
  226. package/src/cli/commands/dev.ts +607 -160
  227. package/src/cli/commands/init.ts +851 -786
  228. package/src/cli/commands/scaffold.ts +531 -236
  229. package/src/cli/index.ts +338 -60
  230. package/src/core/config.ts +145 -9
  231. package/src/core/mock/connector-mock-server.ts +555 -0
  232. package/src/core/mock/zod-mock-generator.ts +205 -0
  233. package/src/core/operations/auth-operations.ts +360 -0
  234. package/src/core/operations/create-model.ts +191 -0
  235. package/src/core/operations/file-session.ts +222 -0
  236. package/src/core/operations/provision-operations.ts +297 -0
  237. package/src/core/operations/runtime.ts +258 -0
  238. package/src/core/operations/scaffold-apply.ts +106 -0
  239. package/src/core/operations/scaffold-machine.ts +77 -0
  240. package/src/core/operations/scaffold-plan.ts +215 -0
  241. package/src/core/project/agent-instructions.ts +167 -0
  242. package/src/core/project/agent-templates/AGENTS.md +504 -0
  243. package/src/core/project/agent-templates/CLAUDE.md +31 -0
  244. package/src/core/project/agent-templates/azure-functions.instructions.md +22 -0
  245. package/src/core/project/agent-templates/bff-routes.instructions.md +18 -0
  246. package/src/core/project/agent-templates/copilot-instructions.md +27 -0
  247. package/src/core/project/agent-templates/shared-models.instructions.md +72 -0
  248. package/src/core/project/artifacts.ts +205 -0
  249. package/src/core/project/boundaries.ts +170 -0
  250. package/src/core/project/capabilities.ts +193 -0
  251. package/src/core/project/drift.ts +203 -0
  252. package/src/core/project/infra.ts +196 -0
  253. package/src/core/project/manifest.ts +402 -0
  254. package/src/core/project/state.ts +77 -0
  255. package/src/core/project/validation.ts +295 -0
  256. package/src/core/project/workflows.ts +295 -0
  257. package/src/core/scaffold/auth-generator.ts +1824 -0
  258. package/src/core/scaffold/connector-functions-generator.ts +1133 -0
  259. package/src/core/scaffold/functions-generator.ts +432 -134
  260. package/src/core/scaffold/model-parser.ts +244 -90
  261. package/src/core/scaffold/native-schema-generator.ts +904 -0
  262. package/src/core/scaffold/nextjs-generator.ts +174 -9
  263. package/src/core/scaffold/ui-generator.ts +191 -36
  264. package/src/core/verify/index.ts +468 -0
  265. package/src/machine/contracts.ts +33 -0
  266. package/src/machine/errors.ts +45 -0
  267. package/src/machine/index.ts +690 -0
  268. package/src/mcp/index.ts +423 -0
  269. package/src/types/index.ts +137 -0
  270. package/src/utils/package-manager.ts +41 -19
  271. package/src/utils/python-uv.ts +96 -0
  272. package/src/version.ts +13 -0
@@ -0,0 +1,790 @@
1
+ "use strict";
2
+ /**
3
+ * SwallowKit Add-Auth コマンド
4
+ * 認証認可基盤ファイルを生成する
5
+ */
6
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
7
+ if (k2 === undefined) k2 = k;
8
+ var desc = Object.getOwnPropertyDescriptor(m, k);
9
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
10
+ desc = { enumerable: true, get: function() { return m[k]; } };
11
+ }
12
+ Object.defineProperty(o, k2, desc);
13
+ }) : (function(o, m, k, k2) {
14
+ if (k2 === undefined) k2 = k;
15
+ o[k2] = m[k];
16
+ }));
17
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
18
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
19
+ }) : function(o, v) {
20
+ o["default"] = v;
21
+ });
22
+ var __importStar = (this && this.__importStar) || (function () {
23
+ var ownKeys = function(o) {
24
+ ownKeys = Object.getOwnPropertyNames || function (o) {
25
+ var ar = [];
26
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
27
+ return ar;
28
+ };
29
+ return ownKeys(o);
30
+ };
31
+ return function (mod) {
32
+ if (mod && mod.__esModule) return mod;
33
+ var result = {};
34
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
35
+ __setModuleDefault(result, mod);
36
+ return result;
37
+ };
38
+ })();
39
+ Object.defineProperty(exports, "__esModule", { value: true });
40
+ exports.generateSwaAuthContext = generateSwaAuthContext;
41
+ exports.addAuthProviderToRootLayout = addAuthProviderToRootLayout;
42
+ exports.addAuthCommand = addAuthCommand;
43
+ const fs = __importStar(require("fs"));
44
+ const path = __importStar(require("path"));
45
+ const config_1 = require("../../core/config");
46
+ const auth_generator_1 = require("../../core/scaffold/auth-generator");
47
+ const manifest_1 = require("../../core/project/manifest");
48
+ const file_session_1 = require("../../core/operations/file-session");
49
+ const artifacts_1 = require("../../core/project/artifacts");
50
+ const init_1 = require("./init");
51
+ const SWA_PROVIDER_LABELS = {
52
+ aad: "Microsoft",
53
+ github: "GitHub",
54
+ google: "Google",
55
+ twitter: "X",
56
+ apple: "Apple",
57
+ facebook: "Facebook",
58
+ };
59
+ function swaProviderLabel(provider) {
60
+ return SWA_PROVIDER_LABELS[provider] ?? provider.charAt(0).toUpperCase() + provider.slice(1);
61
+ }
62
+ function normalizeSwaProviders(allowedProviders) {
63
+ const providers = (allowedProviders ?? []).map((p) => p.trim().toLowerCase()).filter(Boolean);
64
+ for (const provider of providers) {
65
+ if (!/^[a-z0-9-]+$/.test(provider))
66
+ throw new Error(`Invalid SWA identity provider name: ${provider}`);
67
+ }
68
+ return providers.length > 0 ? providers : ["aad"];
69
+ }
70
+ const AUTH_GENERATOR = "add-auth";
71
+ const managedMeta = { ownership: "managed", generator: AUTH_GENERATOR };
72
+ const extensionMeta = { ownership: "extension-point", generator: AUTH_GENERATOR };
73
+ const onceMeta = { ownership: "generated-once", generator: AUTH_GENERATOR };
74
+ function writeIfMissing(session, filePath, content) {
75
+ if (session.fileExists(filePath))
76
+ return;
77
+ session.writeFile(filePath, content, onceMeta);
78
+ }
79
+ function defaultCustomJwtConfig() {
80
+ return {
81
+ userConnector: "mysql",
82
+ userTable: "users",
83
+ loginIdColumn: "login_id",
84
+ passwordHashColumn: "password_hash",
85
+ rolesColumn: "roles",
86
+ jwtSecretEnv: "JWT_SECRET",
87
+ tokenExpiry: "24h",
88
+ };
89
+ }
90
+ function setupSwaAuth(cwd, backendLanguage, session, allowedProviders) {
91
+ const providers = normalizeSwaProviders(allowedProviders);
92
+ const helperPath = backendLanguage === "typescript"
93
+ ? path.join(cwd, "functions", "src", "auth", "jwt-helper.ts")
94
+ : backendLanguage === "csharp"
95
+ ? path.join(cwd, "functions", "Auth", "JwtHelper.cs")
96
+ : path.join(cwd, "functions", "auth", "jwt_helper.py");
97
+ const helper = backendLanguage === "typescript"
98
+ ? (0, auth_generator_1.generateSwaAuthHelperTS)()
99
+ : backendLanguage === "csharp"
100
+ ? (0, auth_generator_1.generateSwaAuthHelperCSharp)()
101
+ : (0, auth_generator_1.generateSwaAuthHelperPython)();
102
+ session.writeFile(helperPath, helper, managedMeta);
103
+ const callFnPath = path.join(cwd, "lib", "api", "call-function.ts");
104
+ session.writeFile(callFnPath, (0, auth_generator_1.generateBFFCallFunctionWithSwaAuth)(), managedMeta);
105
+ const authDir = path.join(cwd, "lib", "auth");
106
+ session.writeFile(path.join(authDir, "auth-context.tsx"), generateSwaAuthContext(providers), managedMeta);
107
+ updateRootLayoutWithAuthProvider(cwd, session);
108
+ const loginDir = path.join(cwd, "app", "login");
109
+ session.writeFile(path.join(loginDir, "page.tsx"), generateSwaLoginPage(providers), managedMeta);
110
+ updateSwaRouteConfig(cwd, session, providers);
111
+ }
112
+ function setupExternalTokenAuth(cwd, backendLanguage, session) {
113
+ const authDir = path.join(cwd, "lib", "auth");
114
+ writeIfMissing(session, path.join(authDir, "external-token-adapter.ts"), (0, auth_generator_1.generateExternalTokenAdapter)());
115
+ session.writeFile(path.join(authDir, "authenticated-fetch.ts"), (0, auth_generator_1.generateAuthenticatedFetch)(), managedMeta);
116
+ session.writeFile(path.join(authDir, "auth-context.tsx"), (0, auth_generator_1.generateExternalTokenAuthContext)(), managedMeta);
117
+ session.writeFile(path.join(cwd, "lib", "api", "call-function.ts"), (0, auth_generator_1.generateBFFCallFunctionWithAuth)(), managedMeta);
118
+ const meDir = path.join(cwd, "app", "api", "auth", "me");
119
+ session.writeFile(path.join(meDir, "route.ts"), (0, auth_generator_1.generateExternalTokenBFFMeRoute)(), managedMeta);
120
+ updateRootLayoutWithAuthProvider(cwd, session);
121
+ if (backendLanguage === "typescript") {
122
+ const verifier = path.join(cwd, "functions", "src", "auth", "external-token-verifier.ts");
123
+ writeIfMissing(session, verifier, (0, auth_generator_1.generateExternalTokenVerifierTS)());
124
+ session.writeFile(path.join(cwd, "functions", "src", "auth", "jwt-helper.ts"), (0, auth_generator_1.generateExternalTokenHelperTS)(), managedMeta);
125
+ session.writeFile(path.join(cwd, "functions", "src", "auth-me.ts"), (0, auth_generator_1.generateExternalAuthMeTS)(), managedMeta);
126
+ }
127
+ else if (backendLanguage === "csharp") {
128
+ const verifier = path.join(cwd, "functions", "Auth", "ExternalTokenVerifier.cs");
129
+ writeIfMissing(session, verifier, (0, auth_generator_1.generateExternalTokenVerifierCSharp)());
130
+ session.writeFile(path.join(cwd, "functions", "Auth", "JwtHelper.cs"), (0, auth_generator_1.generateExternalTokenHelperCSharp)(), managedMeta);
131
+ session.writeFile(path.join(cwd, "functions", "Auth", "ExternalAuthMe.cs"), (0, auth_generator_1.generateExternalAuthMeCSharp)(), managedMeta);
132
+ }
133
+ else {
134
+ const verifier = path.join(cwd, "functions", "auth", "external_token_verifier.py");
135
+ writeIfMissing(session, verifier, (0, auth_generator_1.generateExternalTokenVerifierPython)());
136
+ session.writeFile(path.join(cwd, "functions", "auth", "jwt_helper.py"), (0, auth_generator_1.generateExternalTokenHelperPython)(), managedMeta);
137
+ const authMePath = path.join(cwd, "functions", "blueprints", "auth_me.py");
138
+ session.writeFile(authMePath, (0, auth_generator_1.generateExternalAuthMePython)(), managedMeta);
139
+ updatePythonAuthMeRegistration(cwd, session);
140
+ }
141
+ }
142
+ function updatePythonAuthMeRegistration(cwd, session) {
143
+ const appPath = path.join(cwd, "functions", "function_app.py");
144
+ if (!session.fileExists(appPath))
145
+ return;
146
+ const importLine = "from blueprints.auth_me import bp as external_auth_me_bp";
147
+ const registerLine = "app.register_blueprint(external_auth_me_bp)";
148
+ let content = session.readFile(appPath);
149
+ if (content.includes(importLine))
150
+ return;
151
+ const marker = "# SwallowKit scaffold registrations";
152
+ content = content.includes(marker)
153
+ ? content.replace(marker, `${importLine}\n${registerLine}\n${marker}`)
154
+ : `${content.trimEnd()}\n${importLine}\n${registerLine}\n`;
155
+ session.writeFile(appPath, content, extensionMeta);
156
+ }
157
+ function generateSwaLoginPage(allowedProviders) {
158
+ const providers = normalizeSwaProviders(allowedProviders);
159
+ const links = providers
160
+ .map((provider) => `<a href="/.auth/login/${provider}?post_login_redirect_uri=/">Sign in with ${swaProviderLabel(provider)}</a>`)
161
+ .join("");
162
+ return `'use client';
163
+ export default function LoginPage() {
164
+ return <main><h1>Sign in</h1>${links}</main>;
165
+ }
166
+ `;
167
+ }
168
+ function generateSwaAuthContext(allowedProviders) {
169
+ const providers = normalizeSwaProviders(allowedProviders);
170
+ const primaryProvider = providers[0];
171
+ return `'use client';
172
+ import { createContext, useContext, useEffect, useState, type ReactNode } from 'react';
173
+
174
+ export interface AuthUser { id: string; loginId: string; name: string; email: string; roles: string[]; }
175
+ interface AuthContextValue { user: AuthUser | null; loading: boolean; login: () => void; logout: () => void; hasRole: (role: string) => boolean; hasAnyRole: (roles: string[]) => boolean; }
176
+ const AuthContext = createContext<AuthContextValue | null>(null);
177
+
178
+ export function AuthProvider({ children }: { children: ReactNode }) {
179
+ const [user, setUser] = useState<AuthUser | null>(null);
180
+ const [loading, setLoading] = useState(true);
181
+ useEffect(() => {
182
+ fetch('/.auth/me')
183
+ .then(async response => {
184
+ if (!response.ok) throw new Error('SWA authentication is unavailable');
185
+ const body: unknown = await response.json();
186
+ if (!body || typeof body !== 'object' || !('clientPrincipal' in body)) return null;
187
+ const principal = body.clientPrincipal;
188
+ if (!principal || typeof principal !== 'object') return null;
189
+ const value = principal as Record<string, unknown>;
190
+ if (typeof value.userId !== 'string') return null;
191
+ return {
192
+ id: value.userId,
193
+ loginId: typeof value.userDetails === 'string' ? value.userDetails : '',
194
+ name: typeof value.userDetails === 'string' ? value.userDetails : '',
195
+ email: typeof value.userDetails === 'string' ? value.userDetails : '',
196
+ roles: Array.isArray(value.userRoles) ? value.userRoles.filter((role): role is string => typeof role === 'string') : [],
197
+ } satisfies AuthUser;
198
+ })
199
+ .then(setUser)
200
+ .catch(() => setUser(null))
201
+ .finally(() => setLoading(false));
202
+ }, []);
203
+ const login = () => { window.location.href = '/.auth/login/${primaryProvider}?post_login_redirect_uri=/'; };
204
+ const logout = () => { window.location.href = '/.auth/logout?post_logout_redirect_uri=/'; };
205
+ const hasRole = (role: string) => user?.roles.includes(role) ?? false;
206
+ return <AuthContext.Provider value={{ user, loading, login, logout, hasRole, hasAnyRole: roles => roles.some(hasRole) }}>{children}</AuthContext.Provider>;
207
+ }
208
+ export function useAuth() { const value = useContext(AuthContext); if (!value) throw new Error('useAuth must be used within an AuthProvider'); return value; }
209
+ `;
210
+ }
211
+ function addAuthProviderToRootLayout(layout) {
212
+ let updated = layout;
213
+ if (!/import\s*\{[^}]*\bAuthProvider\b[^}]*\}\s*from\s*['"]@\/lib\/auth\/auth-context['"]/.test(updated)) {
214
+ const directive = updated.match(/^(?:\s*['"]use (?:client|server)['"];?\s*\r?\n)/)?.[0] ?? "";
215
+ updated = `${directive}import { AuthProvider } from '@/lib/auth/auth-context';\n${updated.slice(directive.length)}`;
216
+ }
217
+ if (!/<AuthProvider(?:\s|>)/.test(updated)) {
218
+ const childrenIndex = updated.lastIndexOf("{children}");
219
+ if (childrenIndex === -1) {
220
+ throw new Error("Could not find {children} in app/layout.tsx");
221
+ }
222
+ updated = `${updated.slice(0, childrenIndex)}<AuthProvider>{children}</AuthProvider>${updated.slice(childrenIndex + "{children}".length)}`;
223
+ }
224
+ return updated;
225
+ }
226
+ function updateRootLayoutWithAuthProvider(cwd, session) {
227
+ const layoutPath = path.join(cwd, "app", "layout.tsx");
228
+ if (!session.fileExists(layoutPath)) {
229
+ throw new Error("app/layout.tsx was not found; cannot install AuthProvider");
230
+ }
231
+ const layout = session.readFile(layoutPath);
232
+ const updated = addAuthProviderToRootLayout(layout);
233
+ if (updated !== layout)
234
+ session.writeFile(layoutPath, updated, extensionMeta);
235
+ }
236
+ function updateSwaRouteConfig(cwd, session, allowedProviders) {
237
+ const primaryProvider = normalizeSwaProviders(allowedProviders)[0];
238
+ const configPath = path.join(cwd, "staticwebapp.config.json");
239
+ const config = session.fileExists(configPath) ? JSON.parse(session.readFile(configPath)) : {};
240
+ config.routes = Array.isArray(config.routes)
241
+ ? config.routes.filter((route) => route.route !== "/api/*")
242
+ : [];
243
+ config.routes.unshift({ route: "/api/*", allowedRoles: ["authenticated"] });
244
+ config.responseOverrides = { ...(config.responseOverrides || {}), "401": { statusCode: 302, redirect: `/.auth/login/${primaryProvider}?post_login_redirect_uri=.referrer` } };
245
+ session.writeFile(configPath, JSON.stringify(config, null, 2), extensionMeta);
246
+ }
247
+ async function addAuthCommand(options) {
248
+ (0, config_1.ensureSwallowKitProject)("add-auth");
249
+ console.log(" SwallowKit Add-Auth: Setting up authentication...\n");
250
+ const provider = (options.provider || "custom-jwt");
251
+ if (!["custom-jwt", "swa", "external-token", "swa-custom", "none"].includes(provider)) {
252
+ console.error(` Unknown provider: ${provider}. Use: custom-jwt | swa | external-token | swa-custom | none`);
253
+ process.exit(1);
254
+ }
255
+ const backendLanguage = (0, config_1.getBackendLanguage)();
256
+ const config = (0, config_1.getValidatedFullConfig)();
257
+ const cwd = process.cwd();
258
+ // Plan(dry-run) や Apply からセッションが供給される。単体実行時は commit セッションを生成。
259
+ const session = (0, file_session_1.getActiveFileSession)() ?? new file_session_1.FileOperationSession("commit");
260
+ const finalize = async () => {
261
+ if (session.mode === "commit") {
262
+ (0, artifacts_1.recordSessionOperations)(session.operations);
263
+ await (0, manifest_1.syncProjectManifest)();
264
+ }
265
+ };
266
+ if (options.scheme) {
267
+ if (!/^[A-Za-z][A-Za-z0-9_-]*$/.test(options.scheme))
268
+ throw new Error("--scheme must start with a letter and contain only letters, digits, '_' or '-'");
269
+ if (provider === "none" || provider === "swa-custom")
270
+ throw new Error(`Provider '${provider}' cannot be added as a named scheme`);
271
+ addNamedScheme(cwd, options.scheme, provider, backendLanguage, session, options.allowedProviders);
272
+ await finalize();
273
+ console.log(`\n Named authentication scheme '${options.scheme}' added.`);
274
+ return;
275
+ }
276
+ if (provider === "swa-custom") {
277
+ throw new Error("The swa-custom provider is not implemented. Use --provider swa or --provider custom-jwt.");
278
+ }
279
+ if (provider === "none") {
280
+ updateConfigWithAuth(cwd, provider, config.auth?.customJwt || defaultCustomJwtConfig(), session);
281
+ await finalize();
282
+ console.log(" Authentication disabled in swallowkit.config.js");
283
+ return;
284
+ }
285
+ if (provider === "swa") {
286
+ setupSwaAuth(cwd, backendLanguage, session, options.allowedProviders);
287
+ updateConfigWithAuth(cwd, provider, config.auth?.customJwt || defaultCustomJwtConfig(), session, options.allowedProviders);
288
+ await finalize();
289
+ console.log("\n SWA built-in authentication setup complete!");
290
+ return;
291
+ }
292
+ if (provider === "external-token") {
293
+ setupExternalTokenAuth(cwd, backendLanguage, session);
294
+ updateConfigWithAuth(cwd, provider, config.auth?.customJwt || defaultCustomJwtConfig(), session);
295
+ await finalize();
296
+ console.log("\n External token authentication setup complete!");
297
+ console.log(" Implement the generated frontend adapter and backend verifier before use.");
298
+ return;
299
+ }
300
+ // Read project name from package.json
301
+ const pkgPath = path.join(cwd, "package.json");
302
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8"));
303
+ const projectName = pkg.name || "app";
304
+ // Read shared package name
305
+ const sharedPkgPath = path.join(cwd, "shared", "package.json");
306
+ let sharedPackageName = `@${projectName}/shared`;
307
+ if (fs.existsSync(sharedPkgPath)) {
308
+ const sharedPkg = JSON.parse(fs.readFileSync(sharedPkgPath, "utf-8"));
309
+ sharedPackageName = sharedPkg.name || sharedPackageName;
310
+ }
311
+ // Default custom-jwt config
312
+ const customJwtConfig = config.auth?.customJwt || defaultCustomJwtConfig();
313
+ // custom-jwt setup continues below.
314
+ // 1. Generate shared/models/auth.ts
315
+ console.log(" Generating auth models...");
316
+ const modelsDir = path.join(cwd, "shared", "models");
317
+ const authModelPath = path.join(modelsDir, "auth.ts");
318
+ session.writeFile(authModelPath, (0, auth_generator_1.generateAuthModels)(), managedMeta);
319
+ console.log(` Created: shared/models/auth.ts`);
320
+ // Ensure shared package has build infrastructure (tsconfig, build script)
321
+ ensureSharedBuildInfrastructure(cwd, session);
322
+ // Update shared/index.ts to re-export auth
323
+ updateSharedIndex(cwd, session);
324
+ // Resolve RDB provider for dependency installation
325
+ const connDef = (0, config_1.getConnectorDefinition)(customJwtConfig.userConnector);
326
+ const rdbProvider = connDef?.provider ?? "mysql";
327
+ // 2. Generate Functions auth code
328
+ console.log("\n Generating auth functions...");
329
+ generateFunctionsAuth(cwd, backendLanguage, sharedPackageName, customJwtConfig, session);
330
+ // 3. Generate BFF auth routes
331
+ console.log("\n Generating BFF auth routes...");
332
+ generateBFFAuth(cwd, projectName, sharedPackageName, session);
333
+ // 4. Generate proxy
334
+ console.log("\n Generating proxy...");
335
+ const proxyPath = path.join(cwd, "proxy.ts");
336
+ session.writeFile(proxyPath, (0, auth_generator_1.generateProxy)(projectName), managedMeta);
337
+ console.log(` Created: proxy.ts`);
338
+ // 5. Generate login page
339
+ console.log("\n Generating login page...");
340
+ const loginDir = path.join(cwd, "app", "login");
341
+ session.writeFile(path.join(loginDir, "page.tsx"), (0, auth_generator_1.generateLoginPage)(), managedMeta);
342
+ console.log(` Created: app/login/page.tsx`);
343
+ // 6. Generate auth context
344
+ console.log("\n Generating auth context...");
345
+ const authLibDir = path.join(cwd, "lib", "auth");
346
+ session.writeFile(path.join(authLibDir, "auth-context.tsx"), (0, auth_generator_1.generateAuthContext)(), managedMeta);
347
+ console.log(`✅ Created: lib/auth/auth-context.tsx`);
348
+ // 7. Update callFunction with auth support
349
+ console.log("\n Updating callFunction with auth support...");
350
+ const callFnPath = path.join(cwd, "lib", "api", "call-function.ts");
351
+ session.writeFile(callFnPath, (0, auth_generator_1.generateBFFCallFunctionWithAuth)(), managedMeta);
352
+ console.log(` Updated: lib/api/call-function.ts`);
353
+ // 8. Update swallowkit.config.js
354
+ console.log("\n Updating configuration...");
355
+ updateConfigWithAuth(cwd, provider, customJwtConfig, session);
356
+ // 9. Update environment files
357
+ console.log("\n Updating environment files...");
358
+ updateEnvironmentFiles(cwd, session);
359
+ // 10. Install dependencies
360
+ console.log("\n Installing auth dependencies...");
361
+ await installAuthDependencies(cwd, backendLanguage, rdbProvider, session);
362
+ await finalize();
363
+ console.log("\n Authentication setup complete!");
364
+ console.log("\n Next steps:");
365
+ console.log(" 1. Review the generated files");
366
+ console.log(" 2. Set JWT_SECRET in functions/local.settings.json");
367
+ if (provider === "custom-jwt") {
368
+ console.log(" 3. Ensure your user database table matches the config");
369
+ console.log(" 4. Add authPolicy to your models for role-based access control:");
370
+ console.log(" export const authPolicy = { roles: ['admin'] };");
371
+ }
372
+ console.log(` 5. Run scaffold to regenerate functions with auth guards`);
373
+ }
374
+ function findObjectEnd(content, open) {
375
+ let depth = 0, quote = "";
376
+ for (let i = open; i < content.length; i++) {
377
+ const ch = content[i];
378
+ if (quote) {
379
+ if (ch === quote && content[i - 1] !== "\\")
380
+ quote = "";
381
+ continue;
382
+ }
383
+ if (ch === "'" || ch === '"' || ch === "`") {
384
+ quote = ch;
385
+ continue;
386
+ }
387
+ if (ch === "{")
388
+ depth++;
389
+ if (ch === "}" && --depth === 0)
390
+ return i;
391
+ }
392
+ return -1;
393
+ }
394
+ function updateConfigWithNamedScheme(cwd, scheme, provider, session, allowedProviders) {
395
+ var _a, _b;
396
+ const jsPath = path.join(cwd, "swallowkit.config.js");
397
+ const jsonPath = path.join(cwd, "swallowkit.config.json");
398
+ const configPath = session.fileExists(jsPath) ? jsPath : jsonPath;
399
+ if (!session.fileExists(configPath))
400
+ throw new Error("swallowkit.config.js or swallowkit.config.json is required");
401
+ const swaProviders = provider === "swa" ? normalizeSwaProviders(allowedProviders) : undefined;
402
+ if (configPath.endsWith(".json")) {
403
+ const value = JSON.parse(session.readFile(configPath));
404
+ value.auth ?? (value.auth = {});
405
+ (_a = value.auth).schemes ?? (_a.schemes = {});
406
+ if (value.auth.schemes[scheme])
407
+ throw new Error(`auth.schemes.${scheme} already exists; no files were changed`);
408
+ value.auth.schemes[scheme] = provider === "custom-jwt"
409
+ ? { provider, customJwt: defaultCustomJwtConfig() }
410
+ : swaProviders
411
+ ? { provider, swa: { allowedProviders: swaProviders } }
412
+ : { provider };
413
+ (_b = value.auth).authorization ?? (_b.authorization = { defaultPolicy: "anonymous", policies: {} });
414
+ session.writeFile(configPath, JSON.stringify(value, null, 2) + "\n", extensionMeta);
415
+ return;
416
+ }
417
+ let content = session.readFile(configPath);
418
+ const authMatch = /\bauth\s*:\s*\{/.exec(content);
419
+ const customJwt = defaultCustomJwtConfig();
420
+ const entry = provider === "custom-jwt"
421
+ ? `\n ${scheme}: { provider: 'custom-jwt', customJwt: ${JSON.stringify(customJwt)} },`
422
+ : swaProviders
423
+ ? `\n ${scheme}: { provider: '${provider}', swa: { allowedProviders: [${swaProviders.map((p) => `'${p}'`).join(", ")}] } },`
424
+ : `\n ${scheme}: { provider: '${provider}' },`;
425
+ if (!authMatch) {
426
+ const rootEnd = content.lastIndexOf("}");
427
+ const beforeRootEnd = content.slice(0, rootEnd).trimEnd();
428
+ const separator = beforeRootEnd.endsWith(",") || beforeRootEnd.endsWith("{") ? "" : ",";
429
+ content = `${beforeRootEnd}${separator}\n auth: {\n schemes: {${entry}\n },\n authorization: { defaultPolicy: 'anonymous', policies: {} },\n },\n${content.slice(rootEnd)}`;
430
+ }
431
+ else {
432
+ const authOpen = content.indexOf("{", authMatch.index);
433
+ const authEnd = findObjectEnd(content, authOpen);
434
+ const authBody = content.slice(authOpen + 1, authEnd);
435
+ const schemesMatch = /\bschemes\s*:\s*\{/.exec(authBody);
436
+ if (schemesMatch) {
437
+ const schemesOpen = authOpen + 1 + authBody.indexOf("{", schemesMatch.index);
438
+ const schemesEnd = findObjectEnd(content, schemesOpen);
439
+ const existing = content.slice(schemesOpen + 1, schemesEnd);
440
+ if (new RegExp(`(^|[,\\s])${scheme}\\s*:`).test(existing))
441
+ throw new Error(`auth.schemes.${scheme} already exists; no files were changed`);
442
+ content = content.slice(0, schemesEnd) + entry + "\n " + content.slice(schemesEnd);
443
+ }
444
+ else {
445
+ content = content.slice(0, authOpen + 1) + `\n schemes: {${entry}\n },` + content.slice(authOpen + 1);
446
+ }
447
+ }
448
+ session.writeFile(configPath, content, extensionMeta);
449
+ }
450
+ function addNamedScheme(cwd, scheme, provider, language, session, allowedProviders) {
451
+ // Validate/update config before creating files, so duplicate names stop safely.
452
+ updateConfigWithNamedScheme(cwd, scheme, provider, session, allowedProviders);
453
+ const slug = scheme.replace(/([a-z0-9])([A-Z])/g, "$1-$2").replace(/_/g, "-").toLowerCase();
454
+ if (language === "typescript") {
455
+ const dir = path.join(cwd, "functions", "src", "auth", "schemes", slug);
456
+ if (provider === "external-token")
457
+ writeIfMissing(session, path.join(dir, "verifier.ts"), (0, auth_generator_1.generateExternalTokenVerifierTS)());
458
+ else if (provider === "swa")
459
+ writeIfMissing(session, path.join(dir, "adapter.ts"), (0, auth_generator_1.generateSwaAuthHelperTS)());
460
+ else
461
+ writeIfMissing(session, path.join(dir, "jwt-helper.ts"), (0, auth_generator_1.generateJwtHelperTS)());
462
+ }
463
+ else if (language === "csharp") {
464
+ const dir = path.join(cwd, "functions", "Auth", "Schemes", slug);
465
+ if (provider === "external-token")
466
+ writeIfMissing(session, path.join(dir, "ExternalTokenVerifier.cs"), (0, auth_generator_1.generateNamedExternalTokenVerifierCSharp)(scheme));
467
+ else if (provider === "swa")
468
+ writeIfMissing(session, path.join(dir, "SwaAdapter.cs"), (0, auth_generator_1.generateSwaAuthHelperCSharp)());
469
+ else
470
+ writeIfMissing(session, path.join(dir, "JwtHelper.cs"), (0, auth_generator_1.generateJwtHelperCSharp)());
471
+ }
472
+ else {
473
+ const dir = path.join(cwd, "functions", "auth", "schemes", slug.replace(/-/g, "_"));
474
+ if (provider === "external-token")
475
+ writeIfMissing(session, path.join(dir, "verifier.py"), (0, auth_generator_1.generateNamedExternalTokenVerifierPython)(scheme));
476
+ else if (provider === "swa")
477
+ writeIfMissing(session, path.join(dir, "adapter.py"), (0, auth_generator_1.generateSwaAuthHelperPython)());
478
+ else
479
+ writeIfMissing(session, path.join(dir, "jwt_helper.py"), (0, auth_generator_1.generateJwtHelperPython)());
480
+ }
481
+ const clientDir = path.join(cwd, "lib", "auth", "schemes", slug);
482
+ if (provider === "external-token") {
483
+ writeIfMissing(session, path.join(clientDir, "token-adapter.ts"), (0, auth_generator_1.generateExternalTokenAdapter)());
484
+ writeIfMissing(session, path.join(clientDir, "authenticated-fetch.ts"), (0, auth_generator_1.generateAuthenticatedFetch)().replace("'./external-token-adapter'", "'./token-adapter'"));
485
+ writeIfMissing(session, path.join(clientDir, "auth-context.tsx"), (0, auth_generator_1.generateExternalTokenAuthContext)().replace(/external-token-adapter/g, "token-adapter"));
486
+ }
487
+ else if (provider === "swa") {
488
+ writeIfMissing(session, path.join(clientDir, "auth-context.tsx"), generateSwaAuthContext(allowedProviders));
489
+ }
490
+ else if (provider === "custom-jwt") {
491
+ writeIfMissing(session, path.join(clientDir, "auth-context.tsx"), (0, auth_generator_1.generateAuthContext)());
492
+ }
493
+ const callFunctionPath = path.join(cwd, "lib", "api", "call-function.ts");
494
+ if (!session.fileExists(callFunctionPath))
495
+ writeIfMissing(session, callFunctionPath, (0, auth_generator_1.generateBFFCallFunctionWithMultipleAuth)());
496
+ else {
497
+ const current = session.readFile(callFunctionPath);
498
+ if (!current.includes("x-ms-client-principal") || !current.includes("fetchHeaders['Authorization']")) {
499
+ if (current.includes("SwallowKit BFF Call Function Helper"))
500
+ session.writeFile(callFunctionPath, (0, auth_generator_1.generateBFFCallFunctionWithMultipleAuth)(), managedMeta);
501
+ else
502
+ console.warn(" Existing customized lib/api/call-function.ts was preserved. Ensure it forwards Bearer and SWA credentials without logging them.");
503
+ }
504
+ }
505
+ }
506
+ /**
507
+ * Ensure the shared package has proper build infrastructure
508
+ * (tsconfig.json, build script, typescript devDependency).
509
+ * Required for `dev` command which runs `npm run --workspace=shared build`.
510
+ */
511
+ function ensureSharedBuildInfrastructure(cwd, session) {
512
+ const sharedDir = path.join(cwd, "shared");
513
+ const pkgPath = path.join(sharedDir, "package.json");
514
+ if (!session.fileExists(pkgPath))
515
+ return;
516
+ const pkg = JSON.parse(session.readFile(pkgPath));
517
+ let updated = false;
518
+ // Ensure scripts.build exists
519
+ if (!pkg.scripts?.build) {
520
+ if (!pkg.scripts)
521
+ pkg.scripts = {};
522
+ pkg.scripts.build = "tsc";
523
+ pkg.scripts.watch = "tsc --watch";
524
+ updated = true;
525
+ }
526
+ // Ensure main points to compiled output
527
+ if (!pkg.main || pkg.main === "index.ts") {
528
+ pkg.main = "dist/index.js";
529
+ pkg.types = "dist/index.d.ts";
530
+ updated = true;
531
+ }
532
+ // Ensure typescript devDependency
533
+ if (!pkg.devDependencies?.typescript) {
534
+ if (!pkg.devDependencies)
535
+ pkg.devDependencies = {};
536
+ pkg.devDependencies.typescript = "^5.0.0";
537
+ updated = true;
538
+ }
539
+ if (updated) {
540
+ session.writeFile(pkgPath, JSON.stringify(pkg, null, 2), extensionMeta);
541
+ console.log(` Updated: shared/package.json (added build infrastructure)`);
542
+ }
543
+ // Ensure tsconfig.json exists
544
+ const tsconfigPath = path.join(sharedDir, "tsconfig.json");
545
+ if (!session.fileExists(tsconfigPath)) {
546
+ session.writeFile(tsconfigPath, JSON.stringify((0, init_1.buildSharedTsConfig)(), null, 2), onceMeta);
547
+ console.log(` Created: shared/tsconfig.json`);
548
+ }
549
+ }
550
+ function updateSharedIndex(cwd, session) {
551
+ const indexPath = path.join(cwd, "shared", "index.ts");
552
+ if (session.fileExists(indexPath)) {
553
+ let content = session.readFile(indexPath);
554
+ if (!content.includes("./models/auth")) {
555
+ content += `\nexport { LoginRequest, AuthUser, LoginResponse } from './models/auth';\n`;
556
+ session.writeFile(indexPath, content, extensionMeta);
557
+ console.log(` Updated: shared/index.ts`);
558
+ }
559
+ }
560
+ else {
561
+ session.writeFile(indexPath, `export { LoginRequest, AuthUser, LoginResponse } from './models/auth';\n`, extensionMeta);
562
+ console.log(` Created: shared/index.ts`);
563
+ }
564
+ }
565
+ function generateFunctionsAuth(cwd, backendLanguage, sharedPackageName, config, session) {
566
+ const functionsDir = path.join(cwd, "functions");
567
+ // Resolve the RDB provider from the connector definition
568
+ const connDef = (0, config_1.getConnectorDefinition)(config.userConnector);
569
+ const provider = connDef?.provider ?? "mysql";
570
+ if (backendLanguage === "typescript") {
571
+ // Auth functions
572
+ const srcDir = path.join(functionsDir, "src");
573
+ session.writeFile(path.join(srcDir, "auth.ts"), (0, auth_generator_1.generateAuthFunctionsTS)(sharedPackageName, config, provider), managedMeta);
574
+ console.log(` Created: functions/src/auth.ts`);
575
+ // JWT helper
576
+ const authDir = path.join(srcDir, "auth");
577
+ session.writeFile(path.join(authDir, "jwt-helper.ts"), (0, auth_generator_1.generateJwtHelperTS)(), managedMeta);
578
+ console.log(` Created: functions/src/auth/jwt-helper.ts`);
579
+ }
580
+ else if (backendLanguage === "csharp") {
581
+ const authDir = path.join(functionsDir, "Auth");
582
+ session.writeFile(path.join(authDir, "AuthFunctions.cs"), (0, auth_generator_1.generateAuthFunctionsCSharp)(config, provider), managedMeta);
583
+ console.log(` Created: functions/Auth/AuthFunctions.cs`);
584
+ session.writeFile(path.join(authDir, "JwtHelper.cs"), (0, auth_generator_1.generateJwtHelperCSharp)(), managedMeta);
585
+ console.log(` Created: functions/Auth/JwtHelper.cs`);
586
+ }
587
+ else if (backendLanguage === "python") {
588
+ const blueprintsDir = path.join(functionsDir, "blueprints");
589
+ session.writeFile(path.join(blueprintsDir, "auth.py"), (0, auth_generator_1.generateAuthFunctionsPython)(config, provider), managedMeta);
590
+ console.log(` Created: functions/blueprints/auth.py`);
591
+ const authDir = path.join(functionsDir, "auth");
592
+ session.writeFile(path.join(authDir, "jwt_helper.py"), (0, auth_generator_1.generateJwtHelperPython)(), managedMeta);
593
+ console.log(` Created: functions/auth/jwt_helper.py`);
594
+ // __init__.py
595
+ if (!session.fileExists(path.join(authDir, "__init__.py"))) {
596
+ session.writeFile(path.join(authDir, "__init__.py"), "", onceMeta);
597
+ }
598
+ // Register auth blueprint in function_app.py
599
+ const functionAppPath = path.join(functionsDir, "function_app.py");
600
+ if (session.fileExists(functionAppPath)) {
601
+ const content = session.readFile(functionAppPath);
602
+ const authImport = "from blueprints.auth import bp as auth_bp";
603
+ const authRegister = "app.register_blueprint(auth_bp)";
604
+ if (!content.includes(authImport)) {
605
+ const marker = "# SwallowKit scaffold registrations";
606
+ if (content.includes(marker)) {
607
+ const updated = content.replace(marker, `${authImport}\n${authRegister}\n${marker}`);
608
+ session.writeFile(functionAppPath, updated, extensionMeta);
609
+ console.log(` Updated: functions/function_app.py (registered auth blueprint)`);
610
+ }
611
+ }
612
+ }
613
+ }
614
+ }
615
+ function generateBFFAuth(cwd, projectName, sharedPackageName, session) {
616
+ const authApiDir = path.join(cwd, "app", "api", "auth");
617
+ // Login route
618
+ const loginDir = path.join(authApiDir, "login");
619
+ session.writeFile(path.join(loginDir, "route.ts"), (0, auth_generator_1.generateBFFAuthLoginRoute)(projectName, sharedPackageName), managedMeta);
620
+ console.log(` Created: app/api/auth/login/route.ts`);
621
+ // Logout route
622
+ const logoutDir = path.join(authApiDir, "logout");
623
+ session.writeFile(path.join(logoutDir, "route.ts"), (0, auth_generator_1.generateBFFAuthLogoutRoute)(projectName), managedMeta);
624
+ console.log(` Created: app/api/auth/logout/route.ts`);
625
+ // Me route
626
+ const meDir = path.join(authApiDir, "me");
627
+ session.writeFile(path.join(meDir, "route.ts"), (0, auth_generator_1.generateBFFAuthMeRoute)(), managedMeta);
628
+ console.log(` Created: app/api/auth/me/route.ts`);
629
+ }
630
+ function updateConfigWithAuth(cwd, provider, config, session, allowedProviders) {
631
+ const configPath = path.join(cwd, "swallowkit.config.js");
632
+ if (!session.fileExists(configPath)) {
633
+ console.warn(" swallowkit.config.js not found. Please add auth config manually.");
634
+ return;
635
+ }
636
+ const content = session.readFile(configPath);
637
+ if (content.includes("auth:") || content.includes("auth :")) {
638
+ console.log(" 'auth' section already exists in swallowkit.config.js");
639
+ return;
640
+ }
641
+ // Find the last property before the closing of module.exports
642
+ const closingBraceIdx = content.lastIndexOf("}");
643
+ if (closingBraceIdx === -1) {
644
+ console.error(" Could not parse config file structure.");
645
+ return;
646
+ }
647
+ const beforeClosing = content.substring(0, closingBraceIdx).trimEnd();
648
+ const needsComma = !beforeClosing.endsWith(",") && !beforeClosing.endsWith("{");
649
+ const providerSettings = provider === "custom-jwt" ? `
650
+ customJwt: {
651
+ userConnector: '${config.userConnector}',
652
+ userTable: '${config.userTable}',
653
+ loginIdColumn: '${config.loginIdColumn}',
654
+ passwordHashColumn: '${config.passwordHashColumn}',
655
+ rolesColumn: '${config.rolesColumn}',
656
+ jwtSecretEnv: '${config.jwtSecretEnv || "JWT_SECRET"}',
657
+ tokenExpiry: '${config.tokenExpiry || "24h"}',
658
+ },` : provider === "swa" ? `
659
+ swa: {
660
+ allowedProviders: [${normalizeSwaProviders(allowedProviders).map((p) => `'${p}'`).join(", ")}],
661
+ roleSource: 'swa-roles',
662
+ },` : "";
663
+ const authBlock = `${needsComma ? "," : ""}
664
+ // 認証認可設定
665
+ auth: {
666
+ provider: '${provider}',
667
+ ${providerSettings}
668
+ authorization: {
669
+ defaultPolicy: 'authenticated',
670
+ },
671
+ },
672
+ `;
673
+ const newContent = content.substring(0, closingBraceIdx) + authBlock + content.substring(closingBraceIdx);
674
+ session.writeFile(configPath, newContent, extensionMeta);
675
+ console.log(` Updated: swallowkit.config.js`);
676
+ }
677
+ function updateEnvironmentFiles(cwd, session) {
678
+ // Update functions/local.settings.json
679
+ const localSettingsPath = path.join(cwd, "functions", "local.settings.json");
680
+ if (session.fileExists(localSettingsPath)) {
681
+ const settings = JSON.parse(session.readFile(localSettingsPath));
682
+ if (!settings.Values)
683
+ settings.Values = {};
684
+ if (!settings.Values.JWT_SECRET) {
685
+ settings.Values.JWT_SECRET = "dev-jwt-secret-change-in-production-min-32-chars!!";
686
+ }
687
+ session.writeFile(localSettingsPath, JSON.stringify(settings, null, 2), extensionMeta);
688
+ console.log(` Updated: functions/local.settings.json`);
689
+ }
690
+ // Update .env.example
691
+ const envExamplePath = path.join(cwd, ".env.example");
692
+ if (session.fileExists(envExamplePath)) {
693
+ let content = session.readFile(envExamplePath);
694
+ if (!content.includes("JWT_SECRET")) {
695
+ content += "\n# Authentication\nJWT_SECRET=your-jwt-secret-key-at-least-32-chars\n";
696
+ session.writeFile(envExamplePath, content, extensionMeta);
697
+ console.log(` Updated: .env.example`);
698
+ }
699
+ }
700
+ }
701
+ async function installAuthDependencies(cwd, backendLanguage, provider = "mysql", session) {
702
+ if (backendLanguage === "typescript") {
703
+ const funcPkgPath = path.join(cwd, "functions", "package.json");
704
+ if (session.fileExists(funcPkgPath)) {
705
+ const funcPkg = JSON.parse(session.readFile(funcPkgPath));
706
+ if (!funcPkg.dependencies)
707
+ funcPkg.dependencies = {};
708
+ funcPkg.dependencies["jsonwebtoken"] = "^9.0.0";
709
+ funcPkg.dependencies["bcryptjs"] = "^2.4.3";
710
+ // RDB driver based on provider
711
+ if (provider === "mysql")
712
+ funcPkg.dependencies["mysql2"] = "^3.11.0";
713
+ else if (provider === "postgres")
714
+ funcPkg.dependencies["pg"] = "^8.13.0";
715
+ else
716
+ funcPkg.dependencies["mssql"] = "^11.0.0";
717
+ if (!funcPkg.devDependencies)
718
+ funcPkg.devDependencies = {};
719
+ funcPkg.devDependencies["@types/jsonwebtoken"] = "^9.0.0";
720
+ funcPkg.devDependencies["@types/bcryptjs"] = "^2.4.0";
721
+ if (provider === "postgres")
722
+ funcPkg.devDependencies["@types/pg"] = "^8.11.0";
723
+ session.writeFile(funcPkgPath, JSON.stringify(funcPkg, null, 2), extensionMeta);
724
+ console.log(` Updated: functions/package.json with auth dependencies (${provider})`);
725
+ }
726
+ }
727
+ else if (backendLanguage === "csharp") {
728
+ // Add NuGet package references to .csproj
729
+ const functionsDir = path.join(cwd, "functions");
730
+ const csprojFiles = fs.existsSync(functionsDir)
731
+ ? fs.readdirSync(functionsDir).filter((f) => f.endsWith(".csproj"))
732
+ : [];
733
+ if (csprojFiles.length > 0) {
734
+ const csprojPath = path.join(functionsDir, csprojFiles[0]);
735
+ let csprojContent = session.readFile(csprojPath);
736
+ const nugetPackages = [
737
+ { name: "System.IdentityModel.Tokens.Jwt", version: "7.0.0" },
738
+ { name: "Microsoft.IdentityModel.Tokens", version: "7.0.0" },
739
+ { name: "BCrypt.Net-Next", version: "4.0.3" },
740
+ ];
741
+ // RDB driver based on provider
742
+ if (provider === "mysql")
743
+ nugetPackages.push({ name: "MySqlConnector", version: "2.3.0" });
744
+ else if (provider === "postgres")
745
+ nugetPackages.push({ name: "Npgsql", version: "8.0.0" });
746
+ else
747
+ nugetPackages.push({ name: "Microsoft.Data.SqlClient", version: "5.2.0" });
748
+ for (const pkg of nugetPackages) {
749
+ if (!csprojContent.includes(`"${pkg.name}"`)) {
750
+ const insertPoint = csprojContent.lastIndexOf("</ItemGroup>");
751
+ if (insertPoint >= 0) {
752
+ csprojContent =
753
+ csprojContent.slice(0, insertPoint) +
754
+ ` <PackageReference Include="${pkg.name}" Version="${pkg.version}" />\n ` +
755
+ csprojContent.slice(insertPoint);
756
+ }
757
+ }
758
+ }
759
+ session.writeFile(csprojPath, csprojContent, extensionMeta);
760
+ console.log(` Updated: ${csprojFiles[0]} with auth NuGet packages (${provider})`);
761
+ }
762
+ }
763
+ else if (backendLanguage === "python") {
764
+ // Add Python dependencies to requirements.txt
765
+ const requirementsPath = path.join(cwd, "functions", "requirements.txt");
766
+ const baseDeps = ["PyJWT>=2.8.0", "bcrypt>=4.1.0"];
767
+ // RDB driver based on provider
768
+ if (provider === "mysql")
769
+ baseDeps.push("mysql-connector-python>=8.3.0");
770
+ else if (provider === "postgres")
771
+ baseDeps.push("psycopg2-binary>=2.9.0");
772
+ else
773
+ baseDeps.push("pymssql>=2.2.0");
774
+ if (session.fileExists(requirementsPath)) {
775
+ let content = session.readFile(requirementsPath);
776
+ for (const dep of baseDeps) {
777
+ const pkgName = dep.split(">=")[0].split("==")[0];
778
+ if (!content.includes(pkgName)) {
779
+ content += `${dep}\n`;
780
+ }
781
+ }
782
+ session.writeFile(requirementsPath, content, extensionMeta);
783
+ }
784
+ else {
785
+ session.writeFile(requirementsPath, baseDeps.join("\n") + "\n", extensionMeta);
786
+ }
787
+ console.log(` Updated: functions/requirements.txt with auth dependencies`);
788
+ }
789
+ }
790
+ //# sourceMappingURL=add-auth.js.map