swallowkit 1.0.0-beta.9 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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 +188 -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 +513 -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 +202 -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
@@ -1,5 +1,699 @@
1
1
  // Jest Snapshot v1, https://goo.gl/fbAQLP
2
2
 
3
+ exports[`generateCompactAzureFunctionsCRUD custom partition key (C#) generates snapshot for custom partition key C# 1`] = `
4
+ "using System.Net;
5
+ using System.Text;
6
+ using System.Text.Json;
7
+ using System.Text.Json.Nodes;
8
+ using Azure.Identity;
9
+ using Microsoft.Azure.Cosmos;
10
+ using Microsoft.Azure.Functions.Worker;
11
+ using Microsoft.Azure.Functions.Worker.Http;
12
+ using Microsoft.Extensions.Logging;
13
+
14
+ namespace SwallowKit.Functions;
15
+
16
+ public sealed class TodoCrudFunctions
17
+ {
18
+ private readonly ILogger<TodoCrudFunctions> _logger;
19
+ private static readonly string ContainerName = "Todos";
20
+
21
+ public TodoCrudFunctions(ILogger<TodoCrudFunctions> logger)
22
+ {
23
+ _logger = logger;
24
+ }
25
+
26
+ private static string DatabaseName => Environment.GetEnvironmentVariable("COSMOS_DB_DATABASE_NAME") ?? "AppDatabase";
27
+
28
+ private static bool IsLocalCosmosEndpoint(string endpoint) =>
29
+ endpoint.Contains("localhost:8081", StringComparison.OrdinalIgnoreCase) ||
30
+ endpoint.Contains("127.0.0.1:8081", StringComparison.OrdinalIgnoreCase);
31
+
32
+ private static CosmosClient CreateCosmosClient()
33
+ {
34
+ var endpoint = Environment.GetEnvironmentVariable("CosmosDBConnection__accountEndpoint");
35
+ if (!string.IsNullOrWhiteSpace(endpoint))
36
+ {
37
+ var options = IsLocalCosmosEndpoint(endpoint)
38
+ ? new CosmosClientOptions { ConnectionMode = ConnectionMode.Gateway }
39
+ : new CosmosClientOptions();
40
+ return new CosmosClient(endpoint, new DefaultAzureCredential(), options);
41
+ }
42
+
43
+ var connectionString = Environment.GetEnvironmentVariable("CosmosDBConnection");
44
+ if (string.IsNullOrWhiteSpace(connectionString))
45
+ {
46
+ throw new InvalidOperationException("Cosmos DB connection is not configured.");
47
+ }
48
+
49
+ var connectionOptions = IsLocalCosmosEndpoint(connectionString)
50
+ ? new CosmosClientOptions { ConnectionMode = ConnectionMode.Gateway }
51
+ : new CosmosClientOptions();
52
+
53
+ return new CosmosClient(connectionString, connectionOptions);
54
+ }
55
+
56
+ private static Container GetContainer(CosmosClient client) => client.GetContainer(DatabaseName, ContainerName);
57
+
58
+ private static async Task<JsonObject> ReadRequestBodyAsync(HttpRequestData request)
59
+ {
60
+ using var reader = new StreamReader(request.Body, Encoding.UTF8);
61
+ var raw = await reader.ReadToEndAsync();
62
+ var node = JsonNode.Parse(raw) as JsonObject;
63
+
64
+ if (node is null)
65
+ {
66
+ throw new JsonException("Request body must be a JSON object.");
67
+ }
68
+
69
+ return node;
70
+ }
71
+
72
+ private static JsonObject BuildManagedDocument(JsonObject source, string id, string createdAt, string updatedAt)
73
+ {
74
+ var payload = new JsonObject();
75
+
76
+ foreach (var entry in source)
77
+ {
78
+ if (entry.Key is "id" or "createdAt" or "updatedAt")
79
+ {
80
+ continue;
81
+ }
82
+
83
+ payload[entry.Key] = entry.Value?.DeepClone();
84
+ }
85
+
86
+ payload["id"] = id;
87
+ payload["createdAt"] = createdAt;
88
+ payload["updatedAt"] = updatedAt;
89
+
90
+ return payload;
91
+ }
92
+
93
+ private static Stream CreateJsonStream(JsonObject payload) =>
94
+ new MemoryStream(Encoding.UTF8.GetBytes(payload.ToJsonString()));
95
+
96
+ private static async Task<JsonObject> ReadCosmosItemAsync(Container container, string id)
97
+ {
98
+ var query = new QueryDefinition("SELECT * FROM c WHERE c.id = @id")
99
+ .WithParameter("@id", id);
100
+ using var iterator = container.GetItemQueryStreamIterator(query);
101
+
102
+ while (iterator.HasMoreResults)
103
+ {
104
+ var page = await iterator.ReadNextAsync();
105
+ if (!page.IsSuccessStatusCode)
106
+ {
107
+ throw new InvalidOperationException($"Cosmos query failed with status {(int)page.StatusCode}.");
108
+ }
109
+
110
+ using var document = await JsonDocument.ParseAsync(page.Content);
111
+ if (document.RootElement.TryGetProperty("Documents", out var documents))
112
+ {
113
+ foreach (var item in documents.EnumerateArray())
114
+ {
115
+ return JsonNode.Parse(item.GetRawText())?.AsObject()
116
+ ?? throw new JsonException("Cosmos item payload must be a JSON object.");
117
+ }
118
+ }
119
+ }
120
+
121
+ throw new CosmosException("Item not found", HttpStatusCode.NotFound, 0, "", 0);
122
+ }
123
+
124
+ private static async Task<HttpResponseData> WriteJsonAsync(HttpRequestData request, HttpStatusCode status, object payload)
125
+ {
126
+ var response = request.CreateResponse(status);
127
+ await response.WriteAsJsonAsync(payload);
128
+ return response;
129
+ }
130
+
131
+ [Function("todoGetAll")]
132
+ public async Task<HttpResponseData> GetAll(
133
+ [HttpTrigger(AuthorizationLevel.Function, "get", Route = "todo")] HttpRequestData request)
134
+ {
135
+ try
136
+ {
137
+ using var client = CreateCosmosClient();
138
+ var container = GetContainer(client);
139
+ using var iterator = container.GetItemQueryStreamIterator("SELECT * FROM c");
140
+ var items = new List<JsonElement>();
141
+
142
+ while (iterator.HasMoreResults)
143
+ {
144
+ var page = await iterator.ReadNextAsync();
145
+ if (!page.IsSuccessStatusCode)
146
+ {
147
+ throw new InvalidOperationException($"Cosmos query failed with status {(int)page.StatusCode}.");
148
+ }
149
+
150
+ using var document = await JsonDocument.ParseAsync(page.Content);
151
+ if (!document.RootElement.TryGetProperty("Documents", out var documents))
152
+ {
153
+ continue;
154
+ }
155
+
156
+ foreach (var item in documents.EnumerateArray())
157
+ {
158
+ items.Add(item.Clone());
159
+ }
160
+ }
161
+
162
+ _logger.LogInformation("Fetched {Count} Todo item(s) from {Container}.", items.Count, ContainerName);
163
+ return await WriteJsonAsync(request, HttpStatusCode.OK, items);
164
+ }
165
+ catch (Exception ex)
166
+ {
167
+ _logger.LogError(ex, "Failed to fetch Todo items from Cosmos DB.");
168
+ return await WriteJsonAsync(request, HttpStatusCode.InternalServerError, new { error = "Failed to fetch items" });
169
+ }
170
+ }
171
+
172
+ [Function("todoGetById")]
173
+ public async Task<HttpResponseData> GetById(
174
+ [HttpTrigger(AuthorizationLevel.Function, "get", Route = "todo/{id}")] HttpRequestData request,
175
+ string id)
176
+ {
177
+ try
178
+ {
179
+ using var client = CreateCosmosClient();
180
+ var container = GetContainer(client);
181
+ var item = await ReadCosmosItemAsync(container, id);
182
+ return await WriteJsonAsync(request, HttpStatusCode.OK, item);
183
+ }
184
+ catch (CosmosException ex) when (ex.StatusCode == HttpStatusCode.NotFound)
185
+ {
186
+ return await WriteJsonAsync(request, HttpStatusCode.NotFound, new { error = "Todo not found", id });
187
+ }
188
+ catch (Exception ex)
189
+ {
190
+ _logger.LogError(ex, "Failed to fetch Todo item {Id} from Cosmos DB.", id);
191
+ return await WriteJsonAsync(request, HttpStatusCode.InternalServerError, new { error = "Failed to fetch item", id });
192
+ }
193
+ }
194
+
195
+ [Function("todoCreate")]
196
+ public async Task<HttpResponseData> Create(
197
+ [HttpTrigger(AuthorizationLevel.Function, "post", Route = "todo")] HttpRequestData request)
198
+ {
199
+ try
200
+ {
201
+ var body = await ReadRequestBodyAsync(request);
202
+ var now = DateTimeOffset.UtcNow.ToString("O");
203
+ var id = body["id"]?.GetValue<string>() ?? Guid.NewGuid().ToString();
204
+ var payload = BuildManagedDocument(body, id, now, now);
205
+
206
+ using var client = CreateCosmosClient();
207
+ var container = GetContainer(client);
208
+ using var stream = CreateJsonStream(payload);
209
+ var pkValue = payload["tenantId"]?.GetValue<string>() ?? throw new InvalidOperationException("Partition key field 'tenantId' is required.");
210
+ var response = await container.CreateItemStreamAsync(stream, new PartitionKey(pkValue));
211
+ if (!response.IsSuccessStatusCode)
212
+ {
213
+ throw new InvalidOperationException($"Cosmos create failed with status {(int)response.StatusCode}.");
214
+ }
215
+
216
+ return await WriteJsonAsync(request, HttpStatusCode.Created, payload);
217
+ }
218
+ catch (JsonException ex)
219
+ {
220
+ _logger.LogWarning(ex, "Invalid Todo create payload.");
221
+ return await WriteJsonAsync(request, HttpStatusCode.BadRequest, new { error = "Request body must be a JSON object." });
222
+ }
223
+ catch (Exception ex)
224
+ {
225
+ _logger.LogError(ex, "Failed to create Todo item in Cosmos DB.");
226
+ return await WriteJsonAsync(request, HttpStatusCode.InternalServerError, new { error = "Failed to create item" });
227
+ }
228
+ }
229
+
230
+ [Function("todoUpdate")]
231
+ public async Task<HttpResponseData> Update(
232
+ [HttpTrigger(AuthorizationLevel.Function, "put", Route = "todo/{id}")] HttpRequestData request,
233
+ string id)
234
+ {
235
+ try
236
+ {
237
+ using var client = CreateCosmosClient();
238
+ var container = GetContainer(client);
239
+
240
+ JsonObject existing;
241
+ try
242
+ {
243
+ existing = await ReadCosmosItemAsync(container, id);
244
+ }
245
+ catch (CosmosException ex) when (ex.StatusCode == HttpStatusCode.NotFound)
246
+ {
247
+ return await WriteJsonAsync(request, HttpStatusCode.NotFound, new { error = "Todo not found", id });
248
+ }
249
+
250
+ var body = await ReadRequestBodyAsync(request);
251
+ var createdAt = existing["createdAt"]?.GetValue<string>() ?? DateTimeOffset.UtcNow.ToString("O");
252
+ var payload = BuildManagedDocument(body, id, createdAt, DateTimeOffset.UtcNow.ToString("O"));
253
+
254
+ using var stream = CreateJsonStream(payload);
255
+ var response = await container.ReplaceItemStreamAsync(stream, id, new PartitionKey(payload["tenantId"]?.GetValue<string>()));
256
+ if (!response.IsSuccessStatusCode)
257
+ {
258
+ throw new InvalidOperationException($"Cosmos replace failed with status {(int)response.StatusCode}.");
259
+ }
260
+
261
+ return await WriteJsonAsync(request, HttpStatusCode.OK, payload);
262
+ }
263
+ catch (JsonException ex)
264
+ {
265
+ _logger.LogWarning(ex, "Invalid Todo update payload for {Id}.", id);
266
+ return await WriteJsonAsync(request, HttpStatusCode.BadRequest, new { error = "Request body must be a JSON object.", id });
267
+ }
268
+ catch (Exception ex)
269
+ {
270
+ _logger.LogError(ex, "Failed to update Todo item {Id} in Cosmos DB.", id);
271
+ return await WriteJsonAsync(request, HttpStatusCode.InternalServerError, new { error = "Failed to update item", id });
272
+ }
273
+ }
274
+
275
+ [Function("todoDelete")]
276
+ public async Task<HttpResponseData> Delete(
277
+ [HttpTrigger(AuthorizationLevel.Function, "delete", Route = "todo/{id}")] HttpRequestData request,
278
+ string id)
279
+ {
280
+ try
281
+ {
282
+ using var client = CreateCosmosClient();
283
+ var container = GetContainer(client);
284
+ var existing = await ReadCosmosItemAsync(container, id);
285
+ var pkValue = existing["tenantId"]?.GetValue<string>();
286
+ await container.DeleteItemAsync<JsonObject>(id, new PartitionKey(pkValue));
287
+
288
+ return request.CreateResponse(HttpStatusCode.NoContent);
289
+ }
290
+ catch (CosmosException ex) when (ex.StatusCode == HttpStatusCode.NotFound)
291
+ {
292
+ return await WriteJsonAsync(request, HttpStatusCode.NotFound, new { error = "Todo not found", id });
293
+ }
294
+ catch (Exception ex)
295
+ {
296
+ _logger.LogError(ex, "Failed to delete Todo item {Id} from Cosmos DB.", id);
297
+ return await WriteJsonAsync(request, HttpStatusCode.InternalServerError, new { error = "Failed to delete item", id });
298
+ }
299
+ }
300
+ }
301
+ "
302
+ `;
303
+
304
+ exports[`generateCompactAzureFunctionsCRUD custom partition key (Python) generates snapshot for custom partition key Python 1`] = `
305
+ "import json
306
+ from datetime import datetime, timezone
307
+ from typing import Any
308
+ from uuid import uuid4
309
+ import os
310
+
311
+ import azure.functions as func
312
+ from azure.cosmos import CosmosClient, exceptions
313
+ from azure.identity import DefaultAzureCredential
314
+
315
+ bp = func.Blueprint()
316
+ CONTAINER_NAME = "Todos"
317
+ DATABASE_NAME = os.environ.get("COSMOS_DB_DATABASE_NAME", "AppDatabase")
318
+
319
+
320
+ def _json_response(payload: Any, status_code: int) -> func.HttpResponse:
321
+ return func.HttpResponse(
322
+ body=json.dumps(payload, ensure_ascii=False),
323
+ status_code=status_code,
324
+ mimetype="application/json",
325
+ )
326
+
327
+
328
+ def _get_container():
329
+ endpoint = os.environ.get("CosmosDBConnection__accountEndpoint")
330
+ if endpoint:
331
+ client = CosmosClient(endpoint, credential=DefaultAzureCredential())
332
+ else:
333
+ connection_string = os.environ.get("CosmosDBConnection")
334
+ if not connection_string:
335
+ raise RuntimeError("Cosmos DB connection is not configured.")
336
+ client = CosmosClient.from_connection_string(connection_string)
337
+
338
+ database = client.get_database_client(DATABASE_NAME)
339
+ return database.get_container_client(CONTAINER_NAME)
340
+
341
+
342
+ def _build_managed_document(source: dict[str, Any], item_id: str, created_at: str, updated_at: str) -> dict[str, Any]:
343
+ payload = {
344
+ key: value
345
+ for key, value in source.items()
346
+ if key not in {"id", "createdAt", "updatedAt"}
347
+ }
348
+ payload["id"] = item_id
349
+ payload["createdAt"] = created_at
350
+ payload["updatedAt"] = updated_at
351
+ return payload
352
+
353
+
354
+ @bp.route(route="todo", methods=["GET"])
355
+ def todo_get_all(req: func.HttpRequest) -> func.HttpResponse:
356
+ try:
357
+ container = _get_container()
358
+ items = list(
359
+ container.query_items(
360
+ query="SELECT * FROM c",
361
+ enable_cross_partition_query=True,
362
+ )
363
+ )
364
+ return _json_response(items, 200)
365
+ except Exception as exc:
366
+ return _json_response({"error": "Failed to fetch items", "details": str(exc)}, 500)
367
+
368
+
369
+ @bp.route(route="todo/{id}", methods=["GET"])
370
+ def todo_get_by_id(req: func.HttpRequest) -> func.HttpResponse:
371
+ item_id = req.route_params.get("id")
372
+ try:
373
+ container = _get_container()
374
+ items = list(container.query_items(
375
+ query="SELECT * FROM c WHERE c.id = @id",
376
+ parameters=[{"name": "@id", "value": item_id}],
377
+ enable_cross_partition_query=True,
378
+ ))
379
+ if not items:
380
+ return _json_response({"error": "Todo not found", "id": item_id}, 404)
381
+ return _json_response(items[0], 200)
382
+ except exceptions.CosmosResourceNotFoundError:
383
+ return _json_response({"error": "Todo not found", "id": item_id}, 404)
384
+ except Exception as exc:
385
+ return _json_response({"error": "Failed to fetch item", "id": item_id, "details": str(exc)}, 500)
386
+
387
+
388
+ @bp.route(route="todo", methods=["POST"])
389
+ def todo_create(req: func.HttpRequest) -> func.HttpResponse:
390
+ try:
391
+ body = req.get_json()
392
+ now = datetime.now(timezone.utc).isoformat()
393
+ item_id = body.get("id") or str(uuid4())
394
+ payload = _build_managed_document(body, item_id, now, now)
395
+
396
+ container = _get_container()
397
+ container.create_item(payload)
398
+ return _json_response(payload, 201)
399
+ except ValueError:
400
+ return _json_response({"error": "Request body must be a JSON object."}, 400)
401
+ except Exception as exc:
402
+ return _json_response({"error": "Failed to create item", "details": str(exc)}, 500)
403
+
404
+
405
+ @bp.route(route="todo/{id}", methods=["PUT"])
406
+ def todo_update(req: func.HttpRequest) -> func.HttpResponse:
407
+ item_id = req.route_params.get("id")
408
+ try:
409
+ container = _get_container()
410
+ items = list(container.query_items(
411
+ query="SELECT * FROM c WHERE c.id = @id",
412
+ parameters=[{"name": "@id", "value": item_id}],
413
+ enable_cross_partition_query=True,
414
+ ))
415
+ if not items:
416
+ return _json_response({"error": "Todo not found", "id": item_id}, 404)
417
+ existing = items[0]
418
+ body = req.get_json()
419
+ payload = _build_managed_document(
420
+ body,
421
+ item_id,
422
+ existing.get("createdAt") or datetime.now(timezone.utc).isoformat(),
423
+ datetime.now(timezone.utc).isoformat(),
424
+ )
425
+ container.replace_item(item=existing, body=payload)
426
+ return _json_response(payload, 200)
427
+ except exceptions.CosmosResourceNotFoundError:
428
+ return _json_response({"error": "Todo not found", "id": item_id}, 404)
429
+ except ValueError:
430
+ return _json_response({"error": "Request body must be a JSON object.", "id": item_id}, 400)
431
+ except Exception as exc:
432
+ return _json_response({"error": "Failed to update item", "id": item_id, "details": str(exc)}, 500)
433
+
434
+
435
+ @bp.route(route="todo/{id}", methods=["DELETE"])
436
+ def todo_delete(req: func.HttpRequest) -> func.HttpResponse:
437
+ item_id = req.route_params.get("id")
438
+ try:
439
+ container = _get_container()
440
+ items = list(container.query_items(
441
+ query="SELECT * FROM c WHERE c.id = @id",
442
+ parameters=[{"name": "@id", "value": item_id}],
443
+ enable_cross_partition_query=True,
444
+ ))
445
+ if not items:
446
+ return _json_response({"error": "Todo not found", "id": item_id}, 404)
447
+ pk_value = items[0].get("tenantId")
448
+ container.delete_item(item=item_id, partition_key=pk_value)
449
+ return func.HttpResponse(status_code=204)
450
+ except exceptions.CosmosResourceNotFoundError:
451
+ return _json_response({"error": "Todo not found", "id": item_id}, 404)
452
+ except Exception as exc:
453
+ return _json_response({"error": "Failed to delete item", "id": item_id, "details": str(exc)}, 500)
454
+ "
455
+ `;
456
+
457
+ exports[`generateCompactAzureFunctionsCRUD custom partition key (TS) generates snapshot for custom partition key TS 1`] = `
458
+ "import { app, HttpRequest, HttpResponseInit, InvocationContext } from '@azure/functions';
459
+ import { z } from 'zod/v4';
460
+ import crypto from 'crypto';
461
+ import { todoSchema } from '@myapp/shared';
462
+
463
+ const containerName = 'Todos';
464
+
465
+ // GET /api/todo - 全件取得
466
+ app.http('todo-get-all', {
467
+ methods: ['GET'],
468
+ route: 'todo',
469
+ authLevel: 'function',
470
+ extraInputs: [
471
+ {
472
+ type: 'cosmosDB',
473
+ name: 'cosmosInput',
474
+ databaseName: process.env.COSMOS_DB_DATABASE_NAME || 'AppDatabase',
475
+ containerName,
476
+ connection: 'CosmosDBConnection',
477
+ sqlQuery: 'SELECT * FROM c',
478
+ },
479
+ ],
480
+ handler: async (request: HttpRequest, context: InvocationContext): Promise<HttpResponseInit> => {
481
+ try {
482
+ const documents = context.extraInputs.get('cosmosInput') as unknown[];
483
+
484
+ if (!documents || !Array.isArray(documents)) {
485
+ return { status: 200, jsonBody: [] };
486
+ }
487
+
488
+ const validated = z.array(todoSchema).parse(documents);
489
+ context.log(\`Fetched \${validated.length} items from \${containerName}\`);
490
+
491
+ return { status: 200, jsonBody: validated };
492
+ } catch (error) {
493
+ context.error(\`Error fetching from \${containerName}:\`, error);
494
+ return { status: 500, jsonBody: { error: 'Failed to fetch items' } };
495
+ }
496
+ },
497
+ });
498
+
499
+ // GET /api/todo/{id} - ID指定取得 (custom partition key)
500
+ app.http('todo-get-by-id', {
501
+ methods: ['GET'],
502
+ route: 'todo/{id}',
503
+ authLevel: 'function',
504
+ handler: async (request: HttpRequest, context: InvocationContext): Promise<HttpResponseInit> => {
505
+ try {
506
+ const id = request.params.id;
507
+ if (!id) {
508
+ return { status: 400, jsonBody: { error: 'ID is required' } };
509
+ }
510
+
511
+ const { CosmosClient } = await import('@azure/cosmos');
512
+ const endpoint = process.env.CosmosDBConnection__accountEndpoint;
513
+ let client: InstanceType<typeof CosmosClient>;
514
+ if (endpoint) {
515
+ const { DefaultAzureCredential } = await import('@azure/identity');
516
+ client = new CosmosClient({ endpoint, aadCredentials: new DefaultAzureCredential() });
517
+ } else {
518
+ client = new CosmosClient(process.env.CosmosDBConnection!);
519
+ }
520
+ const database = client.database(process.env.COSMOS_DB_DATABASE_NAME || 'AppDatabase');
521
+ const container = database.container(containerName);
522
+
523
+ const { resources } = await container.items.query({
524
+ query: 'SELECT * FROM c WHERE c.id = @id',
525
+ parameters: [{ name: '@id', value: id }],
526
+ }).fetchAll();
527
+
528
+ if (!resources || resources.length === 0) {
529
+ return { status: 404, jsonBody: { error: 'Item not found' } };
530
+ }
531
+
532
+ const validated = todoSchema.parse(resources[0]);
533
+ return { status: 200, jsonBody: validated };
534
+ } catch (error) {
535
+ context.error(\`Error fetching item from \${containerName}:\`, error);
536
+ return { status: 500, jsonBody: { error: 'Failed to fetch item' } };
537
+ }
538
+ },
539
+ });
540
+
541
+ // POST /api/todo - 新規作成
542
+ app.http('todo-create', {
543
+ methods: ['POST'],
544
+ route: 'todo',
545
+ authLevel: 'function',
546
+ extraOutputs: [
547
+ {
548
+ type: 'cosmosDB',
549
+ name: 'cosmosOutput',
550
+ databaseName: process.env.COSMOS_DB_DATABASE_NAME || 'AppDatabase',
551
+ containerName,
552
+ connection: 'CosmosDBConnection',
553
+ createIfNotExists: true,
554
+ },
555
+ ],
556
+ handler: async (request: HttpRequest, context: InvocationContext): Promise<HttpResponseInit> => {
557
+ try {
558
+ const body = await request.json() as Record<string, unknown>;
559
+
560
+ const { id, createdAt, updatedAt, ...userData } = body;
561
+ const now = new Date().toISOString();
562
+ const dataWithManagedFields = {
563
+ ...userData,
564
+ id: id || crypto.randomUUID(),
565
+ createdAt: now,
566
+ updatedAt: now,
567
+ };
568
+
569
+ const result = todoSchema.safeParse(dataWithManagedFields);
570
+
571
+ if (!result.success) {
572
+ context.error('Validation failed:', result.error.issues);
573
+ return { status: 400, jsonBody: { error: 'Validation failed', details: result.error.issues } };
574
+ }
575
+
576
+ context.extraOutputs.set('cosmosOutput', result.data);
577
+ return { status: 201, jsonBody: result.data };
578
+ } catch (error) {
579
+ context.error(\`Error creating item in \${containerName}:\`, error);
580
+ return { status: 500, jsonBody: { error: 'Failed to create item' } };
581
+ }
582
+ },
583
+ });
584
+
585
+ // PUT /api/todo/{id} - 更新 (custom partition key)
586
+ app.http('todo-update', {
587
+ methods: ['PUT'],
588
+ route: 'todo/{id}',
589
+ authLevel: 'function',
590
+ handler: async (request: HttpRequest, context: InvocationContext): Promise<HttpResponseInit> => {
591
+ try {
592
+ const id = request.params.id;
593
+ if (!id) {
594
+ return { status: 400, jsonBody: { error: 'ID is required' } };
595
+ }
596
+
597
+ const { CosmosClient } = await import('@azure/cosmos');
598
+ const endpoint = process.env.CosmosDBConnection__accountEndpoint;
599
+ let client: InstanceType<typeof CosmosClient>;
600
+ if (endpoint) {
601
+ const { DefaultAzureCredential } = await import('@azure/identity');
602
+ client = new CosmosClient({ endpoint, aadCredentials: new DefaultAzureCredential() });
603
+ } else {
604
+ client = new CosmosClient(process.env.CosmosDBConnection!);
605
+ }
606
+ const database = client.database(process.env.COSMOS_DB_DATABASE_NAME || 'AppDatabase');
607
+ const container = database.container(containerName);
608
+
609
+ const { resources } = await container.items.query({
610
+ query: 'SELECT * FROM c WHERE c.id = @id',
611
+ parameters: [{ name: '@id', value: id }],
612
+ }).fetchAll();
613
+
614
+ if (!resources || resources.length === 0) {
615
+ return { status: 404, jsonBody: { error: 'Item not found' } };
616
+ }
617
+
618
+ const existingDocument = resources[0];
619
+ const body = await request.json() as Record<string, unknown>;
620
+ const { createdAt, updatedAt, ...userData } = body;
621
+
622
+ const dataWithManagedFields = {
623
+ ...userData,
624
+ id,
625
+ createdAt: existingDocument.createdAt,
626
+ updatedAt: new Date().toISOString(),
627
+ };
628
+
629
+ const result = todoSchema.safeParse(dataWithManagedFields);
630
+
631
+ if (!result.success) {
632
+ context.error('Validation failed:', result.error.issues);
633
+ return { status: 400, jsonBody: { error: 'Validation failed', details: result.error.issues } };
634
+ }
635
+
636
+ const pkValue = result.data.tenantId;
637
+ await container.items.upsert(result.data);
638
+ return { status: 200, jsonBody: result.data };
639
+ } catch (error) {
640
+ context.error(\`Error updating item in \${containerName}:\`, error);
641
+ return { status: 500, jsonBody: { error: 'Failed to update item' } };
642
+ }
643
+ },
644
+ });
645
+
646
+ // DELETE /api/todo/{id} - 削除 (custom partition key)
647
+ app.http('todo-delete', {
648
+ methods: ['DELETE'],
649
+ route: 'todo/{id}',
650
+ authLevel: 'function',
651
+ handler: async (request: HttpRequest, context: InvocationContext): Promise<HttpResponseInit> => {
652
+ try {
653
+ const id = request.params.id;
654
+ if (!id) {
655
+ return { status: 400, jsonBody: { error: 'ID is required' } };
656
+ }
657
+
658
+ const { CosmosClient } = await import('@azure/cosmos');
659
+ const endpoint = process.env.CosmosDBConnection__accountEndpoint;
660
+ let client: InstanceType<typeof CosmosClient>;
661
+ if (endpoint) {
662
+ const { DefaultAzureCredential } = await import('@azure/identity');
663
+ client = new CosmosClient({ endpoint, aadCredentials: new DefaultAzureCredential() });
664
+ } else {
665
+ client = new CosmosClient(process.env.CosmosDBConnection!);
666
+ }
667
+ const database = client.database(process.env.COSMOS_DB_DATABASE_NAME || 'AppDatabase');
668
+ const container = database.container(containerName);
669
+
670
+ // パーティションキー値を取得するためにドキュメントを読み取り
671
+ const { resources } = await container.items.query({
672
+ query: 'SELECT * FROM c WHERE c.id = @id',
673
+ parameters: [{ name: '@id', value: id }],
674
+ }).fetchAll();
675
+
676
+ if (!resources || resources.length === 0) {
677
+ return { status: 404, jsonBody: { error: 'Item not found' } };
678
+ }
679
+
680
+ const pkValue = resources[0].tenantId;
681
+ await container.item(id, pkValue).delete();
682
+ context.log(\`Deleted item \${id} from \${containerName}\`);
683
+
684
+ return { status: 204 };
685
+ } catch (error) {
686
+ if ((error as { code?: number }).code === 404) {
687
+ return { status: 404, jsonBody: { error: 'Item not found' } };
688
+ }
689
+ context.error(\`Error deleting item from \${containerName}:\`, error);
690
+ return { status: 500, jsonBody: { error: 'Failed to delete item' } };
691
+ }
692
+ },
693
+ });
694
+ "
695
+ `;
696
+
3
697
  exports[`generateCompactAzureFunctionsCRUD generates correct CRUD code for a basic model 1`] = `
4
698
  "import { app, HttpRequest, HttpResponseInit, InvocationContext } from '@azure/functions';
5
699
  import { z } from 'zod/v4';
@@ -12,7 +706,7 @@ const containerName = 'Todos';
12
706
  app.http('todo-get-all', {
13
707
  methods: ['GET'],
14
708
  route: 'todo',
15
- authLevel: 'anonymous',
709
+ authLevel: 'function',
16
710
  extraInputs: [
17
711
  {
18
712
  type: 'cosmosDB',
@@ -25,7 +719,7 @@ app.http('todo-get-all', {
25
719
  ],
26
720
  handler: async (request: HttpRequest, context: InvocationContext): Promise<HttpResponseInit> => {
27
721
  try {
28
- const documents = context.extraInputs.get('cosmosInput') as any[];
722
+ const documents = context.extraInputs.get('cosmosInput') as unknown[];
29
723
 
30
724
  if (!documents || !Array.isArray(documents)) {
31
725
  return { status: 200, jsonBody: [] };
@@ -46,7 +740,7 @@ app.http('todo-get-all', {
46
740
  app.http('todo-get-by-id', {
47
741
  methods: ['GET'],
48
742
  route: 'todo/{id}',
49
- authLevel: 'anonymous',
743
+ authLevel: 'function',
50
744
  extraInputs: [
51
745
  {
52
746
  type: 'cosmosDB',
@@ -79,7 +773,7 @@ app.http('todo-get-by-id', {
79
773
  app.http('todo-create', {
80
774
  methods: ['POST'],
81
775
  route: 'todo',
82
- authLevel: 'anonymous',
776
+ authLevel: 'function',
83
777
  extraOutputs: [
84
778
  {
85
779
  type: 'cosmosDB',
@@ -92,7 +786,7 @@ app.http('todo-create', {
92
786
  ],
93
787
  handler: async (request: HttpRequest, context: InvocationContext): Promise<HttpResponseInit> => {
94
788
  try {
95
- const body = await request.json() as any;
789
+ const body = await request.json() as Record<string, unknown>;
96
790
 
97
791
  const { id, createdAt, updatedAt, ...userData } = body;
98
792
  const now = new Date().toISOString();
@@ -123,7 +817,7 @@ app.http('todo-create', {
123
817
  app.http('todo-update', {
124
818
  methods: ['PUT'],
125
819
  route: 'todo/{id}',
126
- authLevel: 'anonymous',
820
+ authLevel: 'function',
127
821
  extraInputs: [
128
822
  {
129
823
  type: 'cosmosDB',
@@ -151,12 +845,12 @@ app.http('todo-update', {
151
845
  return { status: 400, jsonBody: { error: 'ID is required' } };
152
846
  }
153
847
 
154
- const existingDocument = context.extraInputs.get('cosmosInput') as any;
848
+ const existingDocument = context.extraInputs.get('cosmosInput') as Record<string, unknown> | undefined;
155
849
  if (!existingDocument) {
156
850
  return { status: 404, jsonBody: { error: 'Item not found' } };
157
851
  }
158
852
 
159
- const body = await request.json() as any;
853
+ const body = await request.json() as Record<string, unknown>;
160
854
  const { createdAt, updatedAt, ...userData } = body;
161
855
 
162
856
  const dataWithManagedFields = {
@@ -186,7 +880,7 @@ app.http('todo-update', {
186
880
  app.http('todo-delete', {
187
881
  methods: ['DELETE'],
188
882
  route: 'todo/{id}',
189
- authLevel: 'anonymous',
883
+ authLevel: 'function',
190
884
  handler: async (request: HttpRequest, context: InvocationContext): Promise<HttpResponseInit> => {
191
885
  try {
192
886
  const id = request.params.id;
@@ -210,8 +904,8 @@ app.http('todo-delete', {
210
904
  context.log(\`Deleted item \${id} from \${containerName}\`);
211
905
 
212
906
  return { status: 204 };
213
- } catch (error: any) {
214
- if (error.code === 404) {
907
+ } catch (error) {
908
+ if ((error as { code?: number }).code === 404) {
215
909
  return { status: 404, jsonBody: { error: 'Item not found' } };
216
910
  }
217
911
  context.error(\`Error deleting item from \${containerName}:\`, error);
@@ -234,7 +928,7 @@ const containerName = 'Issues';
234
928
  app.http('issue-get-all', {
235
929
  methods: ['GET'],
236
930
  route: 'issue',
237
- authLevel: 'anonymous',
931
+ authLevel: 'function',
238
932
  extraInputs: [
239
933
  {
240
934
  type: 'cosmosDB',
@@ -247,7 +941,7 @@ app.http('issue-get-all', {
247
941
  ],
248
942
  handler: async (request: HttpRequest, context: InvocationContext): Promise<HttpResponseInit> => {
249
943
  try {
250
- const documents = context.extraInputs.get('cosmosInput') as any[];
944
+ const documents = context.extraInputs.get('cosmosInput') as unknown[];
251
945
 
252
946
  if (!documents || !Array.isArray(documents)) {
253
947
  return { status: 200, jsonBody: [] };
@@ -268,7 +962,7 @@ app.http('issue-get-all', {
268
962
  app.http('issue-get-by-id', {
269
963
  methods: ['GET'],
270
964
  route: 'issue/{id}',
271
- authLevel: 'anonymous',
965
+ authLevel: 'function',
272
966
  extraInputs: [
273
967
  {
274
968
  type: 'cosmosDB',
@@ -301,7 +995,7 @@ app.http('issue-get-by-id', {
301
995
  app.http('issue-create', {
302
996
  methods: ['POST'],
303
997
  route: 'issue',
304
- authLevel: 'anonymous',
998
+ authLevel: 'function',
305
999
  extraOutputs: [
306
1000
  {
307
1001
  type: 'cosmosDB',
@@ -314,7 +1008,7 @@ app.http('issue-create', {
314
1008
  ],
315
1009
  handler: async (request: HttpRequest, context: InvocationContext): Promise<HttpResponseInit> => {
316
1010
  try {
317
- const body = await request.json() as any;
1011
+ const body = await request.json() as Record<string, unknown>;
318
1012
 
319
1013
  const { id, createdAt, updatedAt, ...userData } = body;
320
1014
  const now = new Date().toISOString();
@@ -345,7 +1039,7 @@ app.http('issue-create', {
345
1039
  app.http('issue-update', {
346
1040
  methods: ['PUT'],
347
1041
  route: 'issue/{id}',
348
- authLevel: 'anonymous',
1042
+ authLevel: 'function',
349
1043
  extraInputs: [
350
1044
  {
351
1045
  type: 'cosmosDB',
@@ -373,12 +1067,12 @@ app.http('issue-update', {
373
1067
  return { status: 400, jsonBody: { error: 'ID is required' } };
374
1068
  }
375
1069
 
376
- const existingDocument = context.extraInputs.get('cosmosInput') as any;
1070
+ const existingDocument = context.extraInputs.get('cosmosInput') as Record<string, unknown> | undefined;
377
1071
  if (!existingDocument) {
378
1072
  return { status: 404, jsonBody: { error: 'Item not found' } };
379
1073
  }
380
1074
 
381
- const body = await request.json() as any;
1075
+ const body = await request.json() as Record<string, unknown>;
382
1076
  const { createdAt, updatedAt, ...userData } = body;
383
1077
 
384
1078
  const dataWithManagedFields = {
@@ -408,7 +1102,7 @@ app.http('issue-update', {
408
1102
  app.http('issue-delete', {
409
1103
  methods: ['DELETE'],
410
1104
  route: 'issue/{id}',
411
- authLevel: 'anonymous',
1105
+ authLevel: 'function',
412
1106
  handler: async (request: HttpRequest, context: InvocationContext): Promise<HttpResponseInit> => {
413
1107
  try {
414
1108
  const id = request.params.id;
@@ -432,8 +1126,8 @@ app.http('issue-delete', {
432
1126
  context.log(\`Deleted item \${id} from \${containerName}\`);
433
1127
 
434
1128
  return { status: 204 };
435
- } catch (error: any) {
436
- if (error.code === 404) {
1129
+ } catch (error) {
1130
+ if ((error as { code?: number }).code === 404) {
437
1131
  return { status: 404, jsonBody: { error: 'Item not found' } };
438
1132
  }
439
1133
  context.error(\`Error deleting item from \${containerName}:\`, error);