swallowkit 1.0.0-beta.55 → 1.0.0-beta.57

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 (141) hide show
  1. package/dist/cli/commands/add-auth.d.ts.map +1 -1
  2. package/dist/cli/commands/add-auth.js +154 -157
  3. package/dist/cli/commands/add-auth.js.map +1 -1
  4. package/dist/cli/commands/init.d.ts +5 -0
  5. package/dist/cli/commands/init.d.ts.map +1 -1
  6. package/dist/cli/commands/init.js +178 -25
  7. package/dist/cli/commands/init.js.map +1 -1
  8. package/dist/cli/commands/scaffold.d.ts +7 -2
  9. package/dist/cli/commands/scaffold.d.ts.map +1 -1
  10. package/dist/cli/commands/scaffold.js +113 -123
  11. package/dist/cli/commands/scaffold.js.map +1 -1
  12. package/dist/cli/index.d.ts.map +1 -1
  13. package/dist/cli/index.js +127 -2
  14. package/dist/cli/index.js.map +1 -1
  15. package/dist/core/config.d.ts +1 -1
  16. package/dist/core/config.d.ts.map +1 -1
  17. package/dist/core/config.js +8 -4
  18. package/dist/core/config.js.map +1 -1
  19. package/dist/core/operations/auth-operations.d.ts +57 -0
  20. package/dist/core/operations/auth-operations.d.ts.map +1 -0
  21. package/dist/core/operations/auth-operations.js +269 -0
  22. package/dist/core/operations/auth-operations.js.map +1 -0
  23. package/dist/core/operations/create-model.d.ts.map +1 -1
  24. package/dist/core/operations/create-model.js +23 -13
  25. package/dist/core/operations/create-model.js.map +1 -1
  26. package/dist/core/operations/file-session.d.ts +56 -0
  27. package/dist/core/operations/file-session.d.ts.map +1 -0
  28. package/dist/core/operations/file-session.js +203 -0
  29. package/dist/core/operations/file-session.js.map +1 -0
  30. package/dist/core/operations/provision-operations.d.ts +52 -0
  31. package/dist/core/operations/provision-operations.d.ts.map +1 -0
  32. package/dist/core/operations/provision-operations.js +211 -0
  33. package/dist/core/operations/provision-operations.js.map +1 -0
  34. package/dist/core/operations/runtime.d.ts +5 -0
  35. package/dist/core/operations/runtime.d.ts.map +1 -1
  36. package/dist/core/operations/runtime.js +23 -0
  37. package/dist/core/operations/runtime.js.map +1 -1
  38. package/dist/core/operations/scaffold-apply.d.ts +21 -0
  39. package/dist/core/operations/scaffold-apply.d.ts.map +1 -0
  40. package/dist/core/operations/scaffold-apply.js +57 -0
  41. package/dist/core/operations/scaffold-apply.js.map +1 -0
  42. package/dist/core/operations/scaffold-machine.d.ts.map +1 -1
  43. package/dist/core/operations/scaffold-machine.js +1 -13
  44. package/dist/core/operations/scaffold-machine.js.map +1 -1
  45. package/dist/core/operations/scaffold-plan.d.ts +43 -0
  46. package/dist/core/operations/scaffold-plan.d.ts.map +1 -0
  47. package/dist/core/operations/scaffold-plan.js +187 -0
  48. package/dist/core/operations/scaffold-plan.js.map +1 -0
  49. package/dist/core/project/artifacts.d.ts +58 -0
  50. package/dist/core/project/artifacts.d.ts.map +1 -0
  51. package/dist/core/project/artifacts.js +179 -0
  52. package/dist/core/project/artifacts.js.map +1 -0
  53. package/dist/core/project/boundaries.d.ts +50 -0
  54. package/dist/core/project/boundaries.d.ts.map +1 -0
  55. package/dist/core/project/boundaries.js +117 -0
  56. package/dist/core/project/boundaries.js.map +1 -0
  57. package/dist/core/project/drift.d.ts +29 -0
  58. package/dist/core/project/drift.d.ts.map +1 -0
  59. package/dist/core/project/drift.js +188 -0
  60. package/dist/core/project/drift.js.map +1 -0
  61. package/dist/core/project/infra.d.ts +49 -0
  62. package/dist/core/project/infra.d.ts.map +1 -0
  63. package/dist/core/project/infra.js +167 -0
  64. package/dist/core/project/infra.js.map +1 -0
  65. package/dist/core/project/state.d.ts +15 -0
  66. package/dist/core/project/state.d.ts.map +1 -0
  67. package/dist/core/project/state.js +106 -0
  68. package/dist/core/project/state.js.map +1 -0
  69. package/dist/core/project/workflows.d.ts +43 -0
  70. package/dist/core/project/workflows.d.ts.map +1 -0
  71. package/dist/core/project/workflows.js +255 -0
  72. package/dist/core/project/workflows.js.map +1 -0
  73. package/dist/core/scaffold/auth-generator.d.ts.map +1 -1
  74. package/dist/core/scaffold/auth-generator.js +24 -27
  75. package/dist/core/scaffold/auth-generator.js.map +1 -1
  76. package/dist/core/scaffold/functions-generator.js +9 -9
  77. package/dist/core/scaffold/native-schema-generator.d.ts +7 -1
  78. package/dist/core/scaffold/native-schema-generator.d.ts.map +1 -1
  79. package/dist/core/scaffold/native-schema-generator.js +104 -47
  80. package/dist/core/scaffold/native-schema-generator.js.map +1 -1
  81. package/dist/core/scaffold/nextjs-generator.js +6 -6
  82. package/dist/core/scaffold/ui-generator.js +19 -19
  83. package/dist/core/scaffold/ui-generator.js.map +1 -1
  84. package/dist/core/verify/index.d.ts +62 -0
  85. package/dist/core/verify/index.d.ts.map +1 -0
  86. package/dist/core/verify/index.js +343 -0
  87. package/dist/core/verify/index.js.map +1 -0
  88. package/dist/machine/contracts.d.ts +8 -0
  89. package/dist/machine/contracts.d.ts.map +1 -1
  90. package/dist/machine/errors.d.ts +4 -1
  91. package/dist/machine/errors.d.ts.map +1 -1
  92. package/dist/machine/errors.js +9 -1
  93. package/dist/machine/errors.js.map +1 -1
  94. package/dist/machine/index.d.ts.map +1 -1
  95. package/dist/machine/index.js +350 -16
  96. package/dist/machine/index.js.map +1 -1
  97. package/dist/mcp/index.d.ts.map +1 -1
  98. package/dist/mcp/index.js +202 -1
  99. package/dist/mcp/index.js.map +1 -1
  100. package/dist/types/index.d.ts +14 -0
  101. package/dist/types/index.d.ts.map +1 -1
  102. package/package.json +1 -1
  103. package/src/__tests__/__snapshots__/functions-generator.test.ts.snap +17 -17
  104. package/src/__tests__/__snapshots__/nextjs-generator.test.ts.snap +6 -6
  105. package/src/__tests__/__snapshots__/ui-generator.test.ts.snap +11 -11
  106. package/src/__tests__/agent-loop-phase34.test.ts +449 -0
  107. package/src/__tests__/file-session.test.ts +98 -0
  108. package/src/__tests__/init.test.ts +50 -0
  109. package/src/__tests__/mcp.test.ts +113 -5
  110. package/src/__tests__/plan-apply.test.ts +461 -0
  111. package/src/__tests__/scaffold.test.ts +2 -2
  112. package/src/cli/commands/add-auth.ts +164 -164
  113. package/src/cli/commands/init.ts +186 -24
  114. package/src/cli/commands/scaffold.ts +136 -130
  115. package/src/cli/index.ts +148 -2
  116. package/src/core/config.ts +5 -4
  117. package/src/core/operations/auth-operations.ts +353 -0
  118. package/src/core/operations/create-model.ts +25 -13
  119. package/src/core/operations/file-session.ts +222 -0
  120. package/src/core/operations/provision-operations.ts +297 -0
  121. package/src/core/operations/runtime.ts +23 -0
  122. package/src/core/operations/scaffold-apply.ts +106 -0
  123. package/src/core/operations/scaffold-machine.ts +2 -16
  124. package/src/core/operations/scaffold-plan.ts +215 -0
  125. package/src/core/project/artifacts.ts +205 -0
  126. package/src/core/project/boundaries.ts +170 -0
  127. package/src/core/project/drift.ts +202 -0
  128. package/src/core/project/infra.ts +196 -0
  129. package/src/core/project/state.ts +77 -0
  130. package/src/core/project/workflows.ts +249 -0
  131. package/src/core/scaffold/auth-generator.ts +24 -27
  132. package/src/core/scaffold/functions-generator.ts +9 -9
  133. package/src/core/scaffold/native-schema-generator.ts +152 -70
  134. package/src/core/scaffold/nextjs-generator.ts +6 -6
  135. package/src/core/scaffold/ui-generator.ts +19 -19
  136. package/src/core/verify/index.ts +392 -0
  137. package/src/machine/contracts.ts +16 -0
  138. package/src/machine/errors.ts +12 -1
  139. package/src/machine/index.ts +444 -15
  140. package/src/mcp/index.ts +198 -2
  141. package/src/types/index.ts +17 -0
@@ -0,0 +1,249 @@
1
+ /**
2
+ * Workflow Docs & Agent Skills
3
+ *
4
+ * 同一のランブック コンテンツから 2 つの表面を生成する:
5
+ * - `.swallowkit/workflows/*.md` — Coding Agent 非依存の Markdown ランブック
6
+ * (AGENTS.md / CLAUDE.md / copilot-instructions.md から参照される)
7
+ * - `.github/skills/<name>/SKILL.md` — Agent Skills (agentskills.io open standard)。
8
+ * GitHub Copilot (VS Code / CLI / cloud agent) 等が name/description で自動発見し、
9
+ * タスクに関連するときだけ本文をロードする (progressive disclosure)。
10
+ */
11
+
12
+ import * as fs from "fs";
13
+ import * as path from "path";
14
+
15
+ export interface WorkflowDoc {
16
+ /** `.swallowkit/workflows/` 配下のファイル名 */
17
+ fileName: string;
18
+ title: string;
19
+ content: string;
20
+ /**
21
+ * Agent Skills のスキル名 (ディレクトリ名と一致必須)。
22
+ * agentskills.io 仕様: 小文字英数字とハイフンのみ・64 文字以内。
23
+ * undefined の場合はスキルとして出力しない (README など)。
24
+ */
25
+ skillName?: string;
26
+ /**
27
+ * Agent Skills の description (最大 1024 文字)。
28
+ * 「何をするか」と「いつ使うか」の両方を書く。
29
+ */
30
+ skillDescription?: string;
31
+ }
32
+
33
+ export function buildWorkflowDocs(runCmd: string): WorkflowDoc[] {
34
+ const addModel: WorkflowDoc = {
35
+ fileName: "add-model.md",
36
+ title: "Add a new model (autonomous loop)",
37
+ skillName: "swallowkit-add-model",
38
+ skillDescription:
39
+ "Add a new data model to a SwallowKit project and deterministically derive CRUD Functions, BFF routes, UI pages, and Cosmos DB infra from it using the plan/apply/verify loop. Use when asked to add a model, entity, resource, table, or a new CRUD feature.",
40
+ content: `# Workflow: Add a new model
41
+
42
+ Goal: add a data model and derive CRUD/BFF/UI/infra deterministically.
43
+
44
+ ## Responsibility boundary
45
+
46
+ - **You author freely**: the model schema (\`shared/models/<name>.ts\`) and any business logic.
47
+ - **SwallowKit generates deterministically**: Functions CRUD, BFF routes, UI pages, OpenAPI, Bicep containers.
48
+ - Query the full contract: \`${runCmd} swallowkit machine inspect boundaries\`
49
+
50
+ ## Steps
51
+
52
+ 1. Create the model file (deterministic template):
53
+ \`${runCmd} swallowkit machine generate model <name> --overwrite never\`
54
+ 2. Edit \`shared/models/<name>.ts\` — add domain fields (free-form authoring).
55
+ 3. Compute the change plan (writes nothing):
56
+ \`${runCmd} swallowkit machine plan scaffold <name>\`
57
+ - \`status: "requires-human"\` → review \`data.conflicts\`; only proceed with \`--approve\` if overwriting is intended.
58
+ 4. Apply:
59
+ \`${runCmd} swallowkit machine apply scaffold --plan <planId>\`
60
+ 5. Verify:
61
+ \`${runCmd} swallowkit machine verify project\`
62
+ - \`summary.done: false\` → \`${runCmd} swallowkit machine explain failure\` and repair, then re-verify.
63
+ 6. If \`dev-seeds/\` exists, update seed JSON for the new model.
64
+
65
+ ## Terminal states
66
+
67
+ | status | meaning | next |
68
+ |--------|---------|------|
69
+ | complete | operation finished | continue |
70
+ | in-progress | more work remains (e.g. failing checks) | follow nextActions |
71
+ | blocked | prerequisite missing (e.g. stale plan) | re-plan |
72
+ | requires-human | approval needed | ask the human, or pass --approve when instructed |
73
+ | failed | operation failed | inspect error.details |
74
+ `,
75
+ };
76
+
77
+ const modifyModel: WorkflowDoc = {
78
+ fileName: "modify-model.md",
79
+ title: "Modify an existing model schema",
80
+ skillName: "swallowkit-modify-model",
81
+ skillDescription:
82
+ "Change an existing Zod model schema in a SwallowKit project and re-align every generated artifact (Functions, BFF, UI, infra) via drift inspection and plan/apply regeneration. Use when asked to add/remove/rename model fields, change validation rules, or when inspect drift reports schema-drift.",
83
+ content: `# Workflow: Modify an existing model
84
+
85
+ Goal: change a schema and re-align every generated artifact.
86
+
87
+ ## Steps
88
+
89
+ 1. Edit \`shared/models/<name>.ts\` (free-form authoring).
90
+ 2. Check what drifted:
91
+ \`${runCmd} swallowkit machine inspect drift\`
92
+ - \`schema-drift\` findings list the models whose artifacts are stale.
93
+ 3. Plan the regeneration:
94
+ \`${runCmd} swallowkit machine plan scaffold <name>\`
95
+ - Conflicts mean generated files were hand-edited after generation. Decide: keep the hand-edit (move the logic to an ai-authored file first) or overwrite with \`--approve\`.
96
+ 4. Apply: \`${runCmd} swallowkit machine apply scaffold --plan <planId>\`
97
+ 5. Verify: \`${runCmd} swallowkit machine verify project\`
98
+
99
+ ## Guardrail
100
+
101
+ Never hand-edit managed artifacts to implement schema changes — always change the model
102
+ and regenerate. Hand-edits are detected as drift and block unattended overwrites.
103
+ `,
104
+ };
105
+
106
+ const verifyRepair: WorkflowDoc = {
107
+ fileName: "verify-and-repair.md",
108
+ title: "Verify and repair loop",
109
+ skillName: "swallowkit-verify-repair",
110
+ skillDescription:
111
+ "Converge a SwallowKit project to a verified state: run structure/drift/typecheck (and build/lint/test) checks, read evidence with explain failure, repair, and repeat. Use after any code or schema change, when verification fails, when the build/lint/tests are broken, or before finishing a task.",
112
+ content: `# Workflow: Verify and repair
113
+
114
+ Goal: converge the project to a verified state after any change.
115
+
116
+ ## Loop
117
+
118
+ 1. \`${runCmd} swallowkit machine verify project\`
119
+ - default checks: structure, drift, typecheck (+ project-specific checks from swallowkit.config \`verify.checks\`)
120
+ - opt-in heavier checks: \`--checks structure,drift,typecheck,build,lint,test\`
121
+ 2. If \`summary.done\` is false:
122
+ - \`${runCmd} swallowkit machine explain failure\` → evidence (logTail, findings, violations) and suggestedActions per check.
123
+ - Repair:
124
+ - \`drift\` failures → follow each finding's \`repairAction\` (usually re-run plan/apply scaffold).
125
+ - \`structure\` failures → follow \`suggestedFix\` per violation.
126
+ - \`typecheck\`/\`build\`/\`lint\`/\`test\` failures → fix the code in ai-authored files.
127
+ 3. Repeat until \`summary.done: true\`.
128
+
129
+ ## Exit criteria
130
+
131
+ Stop and ask a human when:
132
+ - the same check fails 3 times in a row with the same evidence, or
133
+ - a repair would require overwriting hand-edited files (\`requires-human\`).
134
+ `,
135
+ };
136
+
137
+ const provision: WorkflowDoc = {
138
+ fileName: "provision.md",
139
+ title: "Provision Azure resources (plan/apply with approval gate)",
140
+ skillName: "swallowkit-provision",
141
+ skillDescription:
142
+ "Provision Azure resources (Static Web Apps, Functions, Cosmos DB) for a SwallowKit project using the two-phase plan/apply flow with a mandatory human approval gate. Use when asked to deploy infrastructure, provision Azure, create resource groups, or run Bicep deployments.",
143
+ content: `# Workflow: Provision Azure resources
144
+
145
+ Goal: deploy the Bicep infrastructure with an explicit human approval gate.
146
+
147
+ ## Rules
148
+
149
+ - Provisioning **always** requires human approval — \`plan provision\` returns
150
+ \`status: "requires-human"\` and \`requiresApproval: true\` by design.
151
+ - Never pass \`--approve\` to \`apply provision\` unless a human explicitly
152
+ instructed you to provision in this session.
153
+ - Inspect infra locally first — no \`az\` calls are needed for inspection.
154
+
155
+ ## Steps
156
+
157
+ 1. Inspect the infrastructure definition (pure local Bicep analysis):
158
+ \`${runCmd} swallowkit machine inspect infra\`
159
+ - review parameters, modules, outputs, and container wiring warnings.
160
+ 2. Compute the provisioning plan (no resources are created):
161
+ \`${runCmd} swallowkit machine plan provision -g <resource-group> --location <region>\`
162
+ - optional: \`--what-if\` to include an \`az deployment ... what-if\` preview.
163
+ - the plan lists the exact \`az\` commands that would run.
164
+ 3. Present the plan to the human and wait for explicit approval.
165
+ 4. Only after approval:
166
+ \`${runCmd} swallowkit machine apply provision --plan <planId> --approve\`
167
+ 5. Verify the deployment outputs and report them.
168
+
169
+ ## Terminal states
170
+
171
+ \`apply provision\` without \`--approve\` fails with \`approval-required\` —
172
+ this is the guardrail working as intended, not an error to work around.
173
+ `,
174
+ };
175
+
176
+ const index: WorkflowDoc = {
177
+ fileName: "README.md",
178
+ title: "SwallowKit agent workflows",
179
+ content: `# SwallowKit Agent Workflows
180
+
181
+ Agent-agnostic runbooks for autonomous development loops. Machine-readable
182
+ interfaces (\`swallowkit machine ...\` / MCP \`swallowkit_*\` tools) return a
183
+ \`status\` terminal state and \`nextActions\`, so agents can chain steps without
184
+ parsing human-oriented output.
185
+
186
+ These runbooks are also installed as Agent Skills (agentskills.io format)
187
+ under \`.github/skills/\` so skills-aware agents load them automatically.
188
+
189
+ | Workflow | File | Skill |
190
+ |----------|------|-------|
191
+ | Add a new model | [add-model.md](./add-model.md) | \`swallowkit-add-model\` |
192
+ | Modify an existing model | [modify-model.md](./modify-model.md) | \`swallowkit-modify-model\` |
193
+ | Verify and repair | [verify-and-repair.md](./verify-and-repair.md) | \`swallowkit-verify-repair\` |
194
+ | Provision Azure resources | [provision.md](./provision.md) | \`swallowkit-provision\` |
195
+
196
+ ## Responsibility boundary (summary)
197
+
198
+ - **ai-authored** (write freely): \`shared/models/\`, business logic, custom pages/components, tests.
199
+ - **deterministic** (never hand-edit): artifacts generated by SwallowKit (see \`.swallowkit/artifacts.json\`) and \`.swallowkit/\` metadata. Change models/config and regenerate via plan/apply.
200
+ - **shared** (edit outside markers): \`infra/main.bicep\`, \`functions/function_app.py\`, \`shared/index.ts\`.
201
+
202
+ Full machine-readable contract: \`${runCmd} swallowkit machine inspect boundaries\`
203
+ `,
204
+ };
205
+
206
+ return [index, addModel, modifyModel, verifyRepair, provision];
207
+ }
208
+
209
+ export const WORKFLOWS_DIR = path.join(".swallowkit", "workflows");
210
+ export const SKILLS_DIR = path.join(".github", "skills");
211
+
212
+ /** `.swallowkit/workflows/*.md` を書き出し、書き込んだ相対パスを返す。 */
213
+ export function writeWorkflowDocs(projectDir: string, runCmd: string): string[] {
214
+ const dir = path.join(projectDir, WORKFLOWS_DIR);
215
+ fs.mkdirSync(dir, { recursive: true });
216
+ const written: string[] = [];
217
+ for (const doc of buildWorkflowDocs(runCmd)) {
218
+ fs.writeFileSync(path.join(dir, doc.fileName), doc.content, "utf-8");
219
+ written.push(path.posix.join(".swallowkit", "workflows", doc.fileName));
220
+ }
221
+ return written;
222
+ }
223
+
224
+ /** Agent Skills (agentskills.io) の SKILL.md コンテンツを組み立てる。 */
225
+ export function buildAgentSkills(runCmd: string): Array<{ skillName: string; content: string }> {
226
+ return buildWorkflowDocs(runCmd)
227
+ .filter((doc): doc is WorkflowDoc & { skillName: string; skillDescription: string } =>
228
+ Boolean(doc.skillName && doc.skillDescription)
229
+ )
230
+ .map((doc) => ({
231
+ skillName: doc.skillName,
232
+ content: `---\nname: ${doc.skillName}\ndescription: ${doc.skillDescription}\nmetadata:\n generator: swallowkit\n---\n\n${doc.content}`,
233
+ }));
234
+ }
235
+
236
+ /**
237
+ * `.github/skills/<name>/SKILL.md` を書き出し、書き込んだ相対パスを返す。
238
+ * agentskills.io 仕様: ディレクトリ名は frontmatter の name と一致必須。
239
+ */
240
+ export function writeAgentSkills(projectDir: string, runCmd: string): string[] {
241
+ const written: string[] = [];
242
+ for (const skill of buildAgentSkills(runCmd)) {
243
+ const dir = path.join(projectDir, SKILLS_DIR, skill.skillName);
244
+ fs.mkdirSync(dir, { recursive: true });
245
+ fs.writeFileSync(path.join(dir, "SKILL.md"), skill.content, "utf-8");
246
+ written.push(path.posix.join(".github", "skills", skill.skillName, "SKILL.md"));
247
+ }
248
+ return written;
249
+ }
@@ -20,6 +20,7 @@ export function generateNamedAuthRouterTS(config: NormalizedAuthConfig): string
20
20
  })).join("\n");
21
21
  const verifiers = external.map(([name]) => { const id = safeIdentifier(name); return `${JSON.stringify(name)}: async (token: string) => { try { return await verify_${id}(token); } catch (e) { if (e instanceof Error_${id}) throw new AuthError(e.status, e.message); throw e; } }`; }).join(",\n ");
22
22
  return `import type { HttpRequest, HttpResponseInit } from '@azure/functions';
23
+ /* eslint-disable @typescript-eslint/no-explicit-any -- generated multi-scheme router works with dynamically shaped principals */
23
24
  ${imports}
24
25
  export type AuthPrincipal = { subject: string; scheme: string; issuer: string; roles: string[]; claims: Record<string, unknown>; /** @deprecated */ userId?: string; /** @deprecated */ userDetails?: string };
25
26
  export class AuthError extends Error { constructor(public status: 401 | 403 | 503, message: string) { super(message); } }
@@ -283,6 +284,7 @@ export function generateAuthFunctionsTS(
283
284
  'SELECT * FROM ${config.userTable} WHERE ${config.loginIdColumn} = ?',
284
285
  [body.loginId]
285
286
  );
287
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- mysql2 rows are dynamically shaped
286
288
  const users = rows as any[];`
287
289
  : provider === "postgres"
288
290
  ? `const result = await ${connVar}.query(
@@ -360,7 +362,7 @@ app.http('auth-login', {
360
362
  } finally {
361
363
  ${cleanup}
362
364
  }
363
- } catch (error: any) {
365
+ } catch (error) {
364
366
  context.error('Login error:', error);
365
367
  return { status: 500, jsonBody: { error: 'Login failed' } };
366
368
  }
@@ -998,7 +1000,7 @@ export async function POST(request: NextRequest) {
998
1000
  maxAge: 86400,
999
1001
  });
1000
1002
  return response;
1001
- } catch (error: any) {
1003
+ } catch (error) {
1002
1004
  console.error('[BFF] Login error:', error);
1003
1005
  return NextResponse.json({ error: 'Login failed' }, { status: 500 });
1004
1006
  }
@@ -1043,7 +1045,7 @@ export async function GET() {
1043
1045
 
1044
1046
  const data = await result.json();
1045
1047
  return NextResponse.json(data);
1046
- } catch (error: any) {
1048
+ } catch (error) {
1047
1049
  console.error('[BFF] Auth/me error:', error);
1048
1050
  return NextResponse.json({ error: 'Internal server error' }, { status: 500 });
1049
1051
  }
@@ -1212,7 +1214,7 @@ export default function LoginPage() {
1212
1214
  export function generateAuthContext(): string {
1213
1215
  return `'use client';
1214
1216
 
1215
- import { createContext, useContext, useEffect, useState, useCallback, ReactNode } from 'react';
1217
+ import { createContext, useContext, useEffect, useState, ReactNode } from 'react';
1216
1218
  import { useRouter } from 'next/navigation';
1217
1219
 
1218
1220
  interface AuthUser {
@@ -1239,26 +1241,21 @@ export function AuthProvider({ children }: { children: ReactNode }) {
1239
1241
  const [loading, setLoading] = useState(true);
1240
1242
  const router = useRouter();
1241
1243
 
1242
- const fetchUser = useCallback(async () => {
1243
- try {
1244
- const res = await fetch('/api/auth/me');
1245
- if (res.ok) {
1246
- const data = await res.json();
1244
+ useEffect(() => {
1245
+ let cancelled = false;
1246
+ fetch('/api/auth/me')
1247
+ .then((res) => (res.ok ? res.json() : null))
1248
+ .catch(() => null)
1249
+ .then((data) => {
1250
+ if (cancelled) return;
1247
1251
  setUser(data);
1248
- } else {
1249
- setUser(null);
1250
- }
1251
- } catch {
1252
- setUser(null);
1253
- } finally {
1254
- setLoading(false);
1255
- }
1252
+ setLoading(false);
1253
+ });
1254
+ return () => {
1255
+ cancelled = true;
1256
+ };
1256
1257
  }, []);
1257
1258
 
1258
- useEffect(() => {
1259
- fetchUser();
1260
- }, [fetchUser]);
1261
-
1262
1259
  const login = async (loginId: string, password: string) => {
1263
1260
  try {
1264
1261
  const res = await fetch('/api/auth/login', {
@@ -1311,7 +1308,7 @@ export function useAuth() {
1311
1308
  // ============================================================
1312
1309
 
1313
1310
  export function generateBFFCallFunctionWithAuth(): string {
1314
- return `import { NextRequest, NextResponse } from 'next/server';
1311
+ return `import { NextResponse } from 'next/server';
1315
1312
  import { headers } from 'next/headers';
1316
1313
  import { z } from 'zod/v4';
1317
1314
 
@@ -1335,13 +1332,13 @@ function getFunctionsKeyHeaders(functionsBaseUrl: string): Record<string, string
1335
1332
  throw new Error('BACKEND_FUNCTIONS_KEY is required for non-local Functions calls');
1336
1333
  }
1337
1334
 
1338
- interface CallFunctionConfig<TInput = any, TOutput = any> {
1335
+ interface CallFunctionConfig<TInput = unknown, TOutput = unknown> {
1339
1336
  /** HTTP メソッド */
1340
1337
  method: 'GET' | 'POST' | 'PUT' | 'DELETE';
1341
1338
  /** Azure Functions のパス (例: '/api/todo', '/api/todo/123') */
1342
1339
  path: string;
1343
1340
  /** リクエストボディ (POST/PUT 用) */
1344
- body?: any;
1341
+ body?: unknown;
1345
1342
  /** 入力バリデーション用 Zod スキーマ (省略時はバリデーションなし) */
1346
1343
  inputSchema?: z.ZodSchema<TInput>;
1347
1344
  /** 出力バリデーション用 Zod スキーマ (省略時はそのまま返す) */
@@ -1350,7 +1347,7 @@ interface CallFunctionConfig<TInput = any, TOutput = any> {
1350
1347
  successStatus?: number;
1351
1348
  }
1352
1349
 
1353
- export async function callFunction<TInput = any, TOutput = any>(
1350
+ export async function callFunction<TInput = unknown, TOutput = unknown>(
1354
1351
  config: CallFunctionConfig<TInput, TOutput>
1355
1352
  ): Promise<NextResponse> {
1356
1353
  const { method, path, body, inputSchema, responseSchema, successStatus = 200 } = config;
@@ -1428,10 +1425,10 @@ export async function callFunction<TInput = any, TOutput = any>(
1428
1425
  }
1429
1426
 
1430
1427
  return NextResponse.json(data, { status: successStatus });
1431
- } catch (error: any) {
1428
+ } catch (error) {
1432
1429
  console.error(\`[BFF] Error:\`, error);
1433
1430
  return NextResponse.json(
1434
- { error: error.message || 'Internal server error' },
1431
+ { error: error instanceof Error ? error.message : 'Internal server error' },
1435
1432
  { status: 500 }
1436
1433
  );
1437
1434
  }
@@ -83,7 +83,7 @@ app.http('${modelCamel}-get-all', {
83
83
  ],
84
84
  handler: async (request: HttpRequest, context: InvocationContext): Promise<HttpResponseInit> => {
85
85
  try {${readGuard}
86
- const documents = context.extraInputs.get('cosmosInput') as any[];
86
+ const documents = context.extraInputs.get('cosmosInput') as unknown[];
87
87
 
88
88
  if (!documents || !Array.isArray(documents)) {
89
89
  return { status: 200, jsonBody: [] };
@@ -119,7 +119,7 @@ app.http('${modelCamel}-create', {
119
119
  ],
120
120
  handler: async (request: HttpRequest, context: InvocationContext): Promise<HttpResponseInit> => {
121
121
  try {${writeGuard}
122
- const body = await request.json() as any;
122
+ const body = await request.json() as Record<string, unknown>;
123
123
 
124
124
  const { id, createdAt, updatedAt, ...userData } = body;
125
125
  const now = new Date().toISOString();
@@ -258,12 +258,12 @@ app.http('${modelCamel}-update', {
258
258
  return { status: 400, jsonBody: { error: 'ID is required' } };
259
259
  }
260
260
 
261
- const existingDocument = context.extraInputs.get('cosmosInput') as any;
261
+ const existingDocument = context.extraInputs.get('cosmosInput') as Record<string, unknown> | undefined;
262
262
  if (!existingDocument) {
263
263
  return { status: 404, jsonBody: { error: 'Item not found' } };
264
264
  }
265
265
 
266
- const body = await request.json() as any;
266
+ const body = await request.json() as Record<string, unknown>;
267
267
  const { createdAt, updatedAt, ...userData } = body;
268
268
 
269
269
  const dataWithManagedFields = {
@@ -315,7 +315,7 @@ app.http('${modelCamel}-update', {
315
315
  }
316
316
 
317
317
  const existingDocument = resources[0];
318
- const body = await request.json() as any;
318
+ const body = await request.json() as Record<string, unknown>;
319
319
  const { createdAt, updatedAt, ...userData } = body;
320
320
 
321
321
  const dataWithManagedFields = {
@@ -364,8 +364,8 @@ app.http('${modelCamel}-delete', {
364
364
  context.log(\`Deleted item \${id} from \${containerName}\`);
365
365
 
366
366
  return { status: 204 };
367
- } catch (error: any) {
368
- if (error.code === 404) {
367
+ } catch (error) {
368
+ if ((error as { code?: number }).code === 404) {
369
369
  return { status: 404, jsonBody: { error: 'Item not found' } };
370
370
  }
371
371
  ${authCatchBlock} context.error(\`Error deleting item from \${containerName}:\`, error);
@@ -405,8 +405,8 @@ app.http('${modelCamel}-delete', {
405
405
  context.log(\`Deleted item \${id} from \${containerName}\`);
406
406
 
407
407
  return { status: 204 };
408
- } catch (error: any) {
409
- if (error.code === 404) {
408
+ } catch (error) {
409
+ if ((error as { code?: number }).code === 404) {
410
410
  return { status: 404, jsonBody: { error: 'Item not found' } };
411
411
  }
412
412
  ${authCatchBlock} context.error(\`Error deleting item from \${containerName}:\`, error);