swallowkit 1.0.0-beta.14 → 1.0.0-beta.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/commands/add-auth.d.ts.map +1 -1
- package/dist/cli/commands/add-auth.js +85 -5
- package/dist/cli/commands/add-auth.js.map +1 -1
- package/dist/cli/commands/create-model.js +1 -1
- package/dist/cli/commands/create-model.js.map +1 -1
- package/dist/cli/commands/dev-seeds.js +1 -1
- package/dist/cli/commands/dev-seeds.js.map +1 -1
- package/dist/cli/commands/dev.js +62 -21
- package/dist/cli/commands/dev.js.map +1 -1
- package/dist/cli/commands/scaffold.d.ts.map +1 -1
- package/dist/cli/commands/scaffold.js +60 -4
- package/dist/cli/commands/scaffold.js.map +1 -1
- package/dist/core/mock/connector-mock-server.d.ts +7 -1
- package/dist/core/mock/connector-mock-server.d.ts.map +1 -1
- package/dist/core/mock/connector-mock-server.js +23 -26
- package/dist/core/mock/connector-mock-server.js.map +1 -1
- package/dist/core/scaffold/auth-generator.d.ts +1 -1
- package/dist/core/scaffold/auth-generator.d.ts.map +1 -1
- package/dist/core/scaffold/auth-generator.js +17 -20
- package/dist/core/scaffold/auth-generator.js.map +1 -1
- package/dist/core/scaffold/functions-generator.d.ts +2 -2
- package/dist/core/scaffold/functions-generator.d.ts.map +1 -1
- package/dist/core/scaffold/functions-generator.js +34 -22
- package/dist/core/scaffold/functions-generator.js.map +1 -1
- package/dist/core/scaffold/model-parser.d.ts.map +1 -1
- package/dist/core/scaffold/model-parser.js +2 -0
- package/dist/core/scaffold/model-parser.js.map +1 -1
- package/package.json +5 -5
- package/src/__tests__/auth.test.ts +13 -13
- package/src/__tests__/connector-mock-server.test.ts +75 -37
- package/src/cli/commands/add-auth.ts +95 -6
- package/src/cli/commands/create-model.ts +1 -1
- package/src/cli/commands/dev-seeds.ts +1 -1
- package/src/cli/commands/dev.ts +66 -21
- package/src/cli/commands/scaffold.ts +68 -9
- package/src/core/mock/connector-mock-server.ts +27 -27
- package/src/core/scaffold/auth-generator.ts +16 -19
- package/src/core/scaffold/functions-generator.ts +37 -23
- package/src/core/scaffold/model-parser.ts +2 -0
|
@@ -373,7 +373,7 @@ namespace Functions.Auth
|
|
|
373
373
|
public async Task<HttpResponseData> Me(
|
|
374
374
|
[HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "auth/me")] HttpRequestData request)
|
|
375
375
|
{
|
|
376
|
-
var (principal, errorResponse) = JwtHelper.Authorize(request);
|
|
376
|
+
var (principal, errorResponse) = await JwtHelper.Authorize(request);
|
|
377
377
|
if (errorResponse != null) return errorResponse;
|
|
378
378
|
|
|
379
379
|
var response = request.CreateResponse(System.Net.HttpStatusCode.OK);
|
|
@@ -400,7 +400,9 @@ namespace Functions.Auth
|
|
|
400
400
|
|
|
401
401
|
public class LoginRequest
|
|
402
402
|
{
|
|
403
|
+
[System.Text.Json.Serialization.JsonPropertyName("loginId")]
|
|
403
404
|
public string LoginId { get; set; } = "";
|
|
405
|
+
[System.Text.Json.Serialization.JsonPropertyName("password")]
|
|
404
406
|
public string Password { get; set; } = "";
|
|
405
407
|
}
|
|
406
408
|
}
|
|
@@ -417,6 +419,7 @@ using System.IdentityModel.Tokens.Jwt;
|
|
|
417
419
|
using System.Security.Claims;
|
|
418
420
|
using System.Text;
|
|
419
421
|
using System.Text.Json;
|
|
422
|
+
using System.Threading.Tasks;
|
|
420
423
|
using Microsoft.Azure.Functions.Worker.Http;
|
|
421
424
|
using Microsoft.IdentityModel.Tokens;
|
|
422
425
|
|
|
@@ -498,21 +501,21 @@ namespace Functions.Auth
|
|
|
498
501
|
}
|
|
499
502
|
}
|
|
500
503
|
|
|
501
|
-
public static (JwtPayload?, HttpResponseData?) Authorize(
|
|
504
|
+
public static async Task<(JwtPayload?, HttpResponseData?)> Authorize(
|
|
502
505
|
HttpRequestData request, params string[] requiredRoles)
|
|
503
506
|
{
|
|
504
507
|
var payload = ValidateToken(request);
|
|
505
508
|
if (payload == null)
|
|
506
509
|
{
|
|
507
510
|
var unauthorized = request.CreateResponse(System.Net.HttpStatusCode.Unauthorized);
|
|
508
|
-
unauthorized.WriteAsJsonAsync(new { error = "Unauthorized" })
|
|
511
|
+
await unauthorized.WriteAsJsonAsync(new { error = "Unauthorized" });
|
|
509
512
|
return (null, unauthorized);
|
|
510
513
|
}
|
|
511
514
|
|
|
512
515
|
if (requiredRoles.Length > 0 && !requiredRoles.Any(r => payload.Roles.Contains(r)))
|
|
513
516
|
{
|
|
514
517
|
var forbidden = request.CreateResponse(System.Net.HttpStatusCode.Forbidden);
|
|
515
|
-
forbidden.WriteAsJsonAsync(new { error = "Forbidden" })
|
|
518
|
+
await forbidden.WriteAsJsonAsync(new { error = "Forbidden" });
|
|
516
519
|
return (null, forbidden);
|
|
517
520
|
}
|
|
518
521
|
|
|
@@ -765,9 +768,8 @@ export function generateBFFAuthLoginRoute(projectName: string, sharedPackageName
|
|
|
765
768
|
return `import { NextRequest, NextResponse } from 'next/server';
|
|
766
769
|
import { LoginRequest, LoginResponse } from '${sharedPackageName}';
|
|
767
770
|
|
|
768
|
-
const FUNCTIONS_BASE_URL = process.env.BACKEND_FUNCTIONS_BASE_URL || process.env.FUNCTIONS_BASE_URL || 'http://localhost:7071';
|
|
769
|
-
|
|
770
771
|
export async function POST(request: NextRequest) {
|
|
772
|
+
const FUNCTIONS_BASE_URL = process.env.BACKEND_FUNCTIONS_BASE_URL || process.env.FUNCTIONS_BASE_URL || 'http://localhost:7071';
|
|
771
773
|
try {
|
|
772
774
|
const body = await request.json();
|
|
773
775
|
const validated = LoginRequest.parse(body);
|
|
@@ -818,9 +820,8 @@ export function generateBFFAuthMeRoute(sharedPackageName: string): string {
|
|
|
818
820
|
return `import { NextResponse } from 'next/server';
|
|
819
821
|
import { headers } from 'next/headers';
|
|
820
822
|
|
|
821
|
-
const FUNCTIONS_BASE_URL = process.env.BACKEND_FUNCTIONS_BASE_URL || process.env.FUNCTIONS_BASE_URL || 'http://localhost:7071';
|
|
822
|
-
|
|
823
823
|
export async function GET() {
|
|
824
|
+
const FUNCTIONS_BASE_URL = process.env.BACKEND_FUNCTIONS_BASE_URL || process.env.FUNCTIONS_BASE_URL || 'http://localhost:7071';
|
|
824
825
|
try {
|
|
825
826
|
const reqHeaders = await headers();
|
|
826
827
|
const authorization = reqHeaders.get('authorization');
|
|
@@ -848,10 +849,10 @@ export async function GET() {
|
|
|
848
849
|
}
|
|
849
850
|
|
|
850
851
|
// ============================================================
|
|
851
|
-
// 9. Next.js Middleware
|
|
852
|
+
// 9. Next.js Proxy (formerly Middleware)
|
|
852
853
|
// ============================================================
|
|
853
854
|
|
|
854
|
-
export function
|
|
855
|
+
export function generateProxy(projectName: string): string {
|
|
855
856
|
const cookieName = projectName.replace(/^@[^/]+\//, '').replace(/[^a-z0-9-]/g, '-') + '-auth-token';
|
|
856
857
|
return `import { NextResponse } from 'next/server';
|
|
857
858
|
import type { NextRequest } from 'next/server';
|
|
@@ -859,7 +860,7 @@ import type { NextRequest } from 'next/server';
|
|
|
859
860
|
const AUTH_COOKIE_NAME = '${cookieName}';
|
|
860
861
|
const PUBLIC_PATHS = ['/login', '/api/auth/login', '/api/auth/logout'];
|
|
861
862
|
|
|
862
|
-
export function
|
|
863
|
+
export function proxy(request: NextRequest) {
|
|
863
864
|
const { pathname } = request.nextUrl;
|
|
864
865
|
|
|
865
866
|
// 公開パス・静的アセットはスキップ
|
|
@@ -877,7 +878,7 @@ export function middleware(request: NextRequest) {
|
|
|
877
878
|
return NextResponse.redirect(new URL('/login', request.url));
|
|
878
879
|
}
|
|
879
880
|
|
|
880
|
-
// JWT
|
|
881
|
+
// JWT 有効期限の簡易チェック(署名検証なし)
|
|
881
882
|
try {
|
|
882
883
|
const payload = JSON.parse(atob(token.split('.')[1]));
|
|
883
884
|
if (payload.exp && payload.exp * 1000 < Date.now()) {
|
|
@@ -902,10 +903,6 @@ export function middleware(request: NextRequest) {
|
|
|
902
903
|
request: { headers: requestHeaders },
|
|
903
904
|
});
|
|
904
905
|
}
|
|
905
|
-
|
|
906
|
-
export const config = {
|
|
907
|
-
matcher: ['/((?!_next/static|_next/image|favicon.ico).*)'],
|
|
908
|
-
};
|
|
909
906
|
`;
|
|
910
907
|
}
|
|
911
908
|
|
|
@@ -1164,7 +1161,7 @@ export async function callFunction<TInput = any, TOutput = any>(
|
|
|
1164
1161
|
const url = functionsBaseUrl + path;
|
|
1165
1162
|
console.log(\`[BFF] \${method} \${url}\`);
|
|
1166
1163
|
|
|
1167
|
-
// Authorization ヘッダーの転送(
|
|
1164
|
+
// Authorization ヘッダーの転送(Proxy が cookie → Authorization に変換済み)
|
|
1168
1165
|
const fetchHeaders: Record<string, string> = {
|
|
1169
1166
|
'Content-Type': 'application/json',
|
|
1170
1167
|
};
|
|
@@ -1262,10 +1259,10 @@ export function generateAuthGuardCSharp(policy: ModelAuthPolicy, operation: 'rea
|
|
|
1262
1259
|
|
|
1263
1260
|
if (roles.length > 0) {
|
|
1264
1261
|
const rolesStr = roles.map(r => `"${r}"`).join(', ');
|
|
1265
|
-
return ` var (principal, errorResponse) = JwtHelper.Authorize(request, ${rolesStr});
|
|
1262
|
+
return ` var (principal, errorResponse) = await JwtHelper.Authorize(request, ${rolesStr});
|
|
1266
1263
|
if (errorResponse != null) return errorResponse;`;
|
|
1267
1264
|
}
|
|
1268
|
-
return ` var (principal, errorResponse) = JwtHelper.Authorize(request);
|
|
1265
|
+
return ` var (principal, errorResponse) = await JwtHelper.Authorize(request);
|
|
1269
1266
|
if (errorResponse != null) return errorResponse;`;
|
|
1270
1267
|
}
|
|
1271
1268
|
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
import { ModelInfo, toCamelCase, toKebabCase } from "./model-parser";
|
|
8
8
|
import { ModelAuthPolicy } from "../../types";
|
|
9
|
-
import { generateAuthImportTS, generateAuthGuardTS } from "./auth-generator";
|
|
9
|
+
import { generateAuthImportTS, generateAuthGuardTS, generateAuthGuardCSharp, generateAuthGuardPython } from "./auth-generator";
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* Azure Functions エンティティファイルを生成(インラインハンドラー方式)
|
|
@@ -32,7 +32,7 @@ import { z } from 'zod/v4';
|
|
|
32
32
|
import crypto from 'crypto';
|
|
33
33
|
import { ${schemaName} } from '${sharedPackageName}';${authImport}
|
|
34
34
|
|
|
35
|
-
const containerName = '${modelName
|
|
35
|
+
const containerName = '${modelName.endsWith('s') ? modelName : modelName + 's'}';
|
|
36
36
|
|
|
37
37
|
// GET /api/${modelCamel} - 全件取得
|
|
38
38
|
app.http('${modelCamel}-get-all', {
|
|
@@ -248,11 +248,16 @@ ${authCatchBlock} context.error(\`Error deleting item from \${containerName
|
|
|
248
248
|
`;
|
|
249
249
|
}
|
|
250
250
|
|
|
251
|
-
export function generateCSharpAzureFunctionsCRUD(model: ModelInfo): string {
|
|
251
|
+
export function generateCSharpAzureFunctionsCRUD(model: ModelInfo, authPolicy?: ModelAuthPolicy): string {
|
|
252
252
|
const modelName = model.name;
|
|
253
253
|
const modelCamel = toCamelCase(modelName);
|
|
254
254
|
const className = `${modelName}Functions`;
|
|
255
|
-
const containerName = `${modelName}s`;
|
|
255
|
+
const containerName = modelName.endsWith('s') ? modelName : `${modelName}s`;
|
|
256
|
+
|
|
257
|
+
const hasAuth = !!authPolicy;
|
|
258
|
+
const authUsing = hasAuth ? 'using Functions.Auth;\n' : '';
|
|
259
|
+
const readGuard = hasAuth ? `\n${generateAuthGuardCSharp(authPolicy!, 'read')}\n` : '';
|
|
260
|
+
const writeGuard = hasAuth ? `\n${generateAuthGuardCSharp(authPolicy!, 'write')}\n` : '';
|
|
256
261
|
|
|
257
262
|
return `using System.Net;
|
|
258
263
|
using System.Text;
|
|
@@ -263,7 +268,7 @@ using Microsoft.Azure.Cosmos;
|
|
|
263
268
|
using Microsoft.Azure.Functions.Worker;
|
|
264
269
|
using Microsoft.Azure.Functions.Worker.Http;
|
|
265
270
|
using Microsoft.Extensions.Logging;
|
|
266
|
-
|
|
271
|
+
${authUsing}
|
|
267
272
|
namespace SwallowKit.Functions;
|
|
268
273
|
|
|
269
274
|
public sealed class ${className}
|
|
@@ -376,7 +381,7 @@ public sealed class ${className}
|
|
|
376
381
|
[HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "${modelCamel}")] HttpRequestData request)
|
|
377
382
|
{
|
|
378
383
|
try
|
|
379
|
-
{
|
|
384
|
+
{${readGuard}
|
|
380
385
|
using var client = CreateCosmosClient();
|
|
381
386
|
var container = GetContainer(client);
|
|
382
387
|
using var iterator = container.GetItemQueryStreamIterator("SELECT * FROM c");
|
|
@@ -418,7 +423,7 @@ public sealed class ${className}
|
|
|
418
423
|
string id)
|
|
419
424
|
{
|
|
420
425
|
try
|
|
421
|
-
{
|
|
426
|
+
{${readGuard}
|
|
422
427
|
using var client = CreateCosmosClient();
|
|
423
428
|
var container = GetContainer(client);
|
|
424
429
|
var item = await ReadCosmosItemAsync(container, id);
|
|
@@ -440,7 +445,7 @@ public sealed class ${className}
|
|
|
440
445
|
[HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "${modelCamel}")] HttpRequestData request)
|
|
441
446
|
{
|
|
442
447
|
try
|
|
443
|
-
{
|
|
448
|
+
{${writeGuard}
|
|
444
449
|
var body = await ReadRequestBodyAsync(request);
|
|
445
450
|
var now = DateTimeOffset.UtcNow.ToString("O");
|
|
446
451
|
var id = body["id"]?.GetValue<string>() ?? Guid.NewGuid().ToString();
|
|
@@ -475,7 +480,7 @@ public sealed class ${className}
|
|
|
475
480
|
string id)
|
|
476
481
|
{
|
|
477
482
|
try
|
|
478
|
-
{
|
|
483
|
+
{${writeGuard}
|
|
479
484
|
using var client = CreateCosmosClient();
|
|
480
485
|
var container = GetContainer(client);
|
|
481
486
|
|
|
@@ -520,7 +525,7 @@ public sealed class ${className}
|
|
|
520
525
|
string id)
|
|
521
526
|
{
|
|
522
527
|
try
|
|
523
|
-
{
|
|
528
|
+
{${writeGuard}
|
|
524
529
|
using var client = CreateCosmosClient();
|
|
525
530
|
var container = GetContainer(client);
|
|
526
531
|
await container.DeleteItemAsync<JsonObject>(id, new PartitionKey(id));
|
|
@@ -541,14 +546,23 @@ public sealed class ${className}
|
|
|
541
546
|
`;
|
|
542
547
|
}
|
|
543
548
|
|
|
544
|
-
export function generatePythonAzureFunctionsCRUD(model: ModelInfo): {
|
|
549
|
+
export function generatePythonAzureFunctionsCRUD(model: ModelInfo, authPolicy?: ModelAuthPolicy): {
|
|
545
550
|
blueprint: string;
|
|
546
551
|
registration: string;
|
|
547
552
|
} {
|
|
548
553
|
const modelName = model.name;
|
|
549
554
|
const modelCamel = toCamelCase(modelName);
|
|
550
555
|
const modelSnake = toKebabCase(modelName).replace(/-/g, "_");
|
|
551
|
-
const containerName = `${modelName}s`;
|
|
556
|
+
const containerName = modelName.endsWith('s') ? modelName : `${modelName}s`;
|
|
557
|
+
|
|
558
|
+
const hasAuth = !!authPolicy;
|
|
559
|
+
const authImport = hasAuth ? '\nfrom auth.jwt_helper import require_auth, require_roles, handle_auth_error\n' : '';
|
|
560
|
+
// generateAuthGuardPython outputs at 4-space indent; inside try: we need 8-space
|
|
561
|
+
const readGuardRaw = hasAuth ? generateAuthGuardPython(authPolicy!, 'read') : '';
|
|
562
|
+
const writeGuardRaw = hasAuth ? generateAuthGuardPython(authPolicy!, 'write') : '';
|
|
563
|
+
const readGuard = hasAuth ? '\n' + readGuardRaw.split('\n').map(l => ' ' + l).join('\n') : '';
|
|
564
|
+
const writeGuard = hasAuth ? '\n' + writeGuardRaw.split('\n').map(l => ' ' + l).join('\n') : '';
|
|
565
|
+
const authCatch = hasAuth ? `\n auth_err = handle_auth_error(exc)\n if auth_err:\n return auth_err` : '';
|
|
552
566
|
|
|
553
567
|
return {
|
|
554
568
|
registration: `from blueprints.${modelSnake} import bp as ${modelSnake}_bp\napp.register_blueprint(${modelSnake}_bp)`,
|
|
@@ -561,7 +575,7 @@ import os
|
|
|
561
575
|
import azure.functions as func
|
|
562
576
|
from azure.cosmos import CosmosClient, exceptions
|
|
563
577
|
from azure.identity import DefaultAzureCredential
|
|
564
|
-
|
|
578
|
+
${authImport}
|
|
565
579
|
bp = func.Blueprint()
|
|
566
580
|
CONTAINER_NAME = "${containerName}"
|
|
567
581
|
DATABASE_NAME = os.environ.get("COSMOS_DB_DATABASE_NAME", "AppDatabase")
|
|
@@ -603,7 +617,7 @@ def _build_managed_document(source: dict[str, Any], item_id: str, created_at: st
|
|
|
603
617
|
|
|
604
618
|
@bp.route(route="${modelCamel}", methods=["GET"])
|
|
605
619
|
def ${modelSnake}_get_all(req: func.HttpRequest) -> func.HttpResponse:
|
|
606
|
-
try
|
|
620
|
+
try:${readGuard}
|
|
607
621
|
container = _get_container()
|
|
608
622
|
items = list(
|
|
609
623
|
container.query_items(
|
|
@@ -612,26 +626,26 @@ def ${modelSnake}_get_all(req: func.HttpRequest) -> func.HttpResponse:
|
|
|
612
626
|
)
|
|
613
627
|
)
|
|
614
628
|
return _json_response(items, 200)
|
|
615
|
-
except Exception as exc
|
|
629
|
+
except Exception as exc:${authCatch}
|
|
616
630
|
return _json_response({"error": "Failed to fetch items", "details": str(exc)}, 500)
|
|
617
631
|
|
|
618
632
|
|
|
619
633
|
@bp.route(route="${modelCamel}/{id}", methods=["GET"])
|
|
620
634
|
def ${modelSnake}_get_by_id(req: func.HttpRequest) -> func.HttpResponse:
|
|
621
635
|
item_id = req.route_params.get("id")
|
|
622
|
-
try
|
|
636
|
+
try:${readGuard}
|
|
623
637
|
container = _get_container()
|
|
624
638
|
item = container.read_item(item=item_id, partition_key=item_id)
|
|
625
639
|
return _json_response(item, 200)
|
|
626
640
|
except exceptions.CosmosResourceNotFoundError:
|
|
627
641
|
return _json_response({"error": "${modelName} not found", "id": item_id}, 404)
|
|
628
|
-
except Exception as exc
|
|
642
|
+
except Exception as exc:${authCatch}
|
|
629
643
|
return _json_response({"error": "Failed to fetch item", "id": item_id, "details": str(exc)}, 500)
|
|
630
644
|
|
|
631
645
|
|
|
632
646
|
@bp.route(route="${modelCamel}", methods=["POST"])
|
|
633
647
|
def ${modelSnake}_create(req: func.HttpRequest) -> func.HttpResponse:
|
|
634
|
-
try
|
|
648
|
+
try:${writeGuard}
|
|
635
649
|
body = req.get_json()
|
|
636
650
|
now = datetime.now(timezone.utc).isoformat()
|
|
637
651
|
item_id = body.get("id") or str(uuid4())
|
|
@@ -642,14 +656,14 @@ def ${modelSnake}_create(req: func.HttpRequest) -> func.HttpResponse:
|
|
|
642
656
|
return _json_response(payload, 201)
|
|
643
657
|
except ValueError:
|
|
644
658
|
return _json_response({"error": "Request body must be a JSON object."}, 400)
|
|
645
|
-
except Exception as exc
|
|
659
|
+
except Exception as exc:${authCatch}
|
|
646
660
|
return _json_response({"error": "Failed to create item", "details": str(exc)}, 500)
|
|
647
661
|
|
|
648
662
|
|
|
649
663
|
@bp.route(route="${modelCamel}/{id}", methods=["PUT"])
|
|
650
664
|
def ${modelSnake}_update(req: func.HttpRequest) -> func.HttpResponse:
|
|
651
665
|
item_id = req.route_params.get("id")
|
|
652
|
-
try
|
|
666
|
+
try:${writeGuard}
|
|
653
667
|
container = _get_container()
|
|
654
668
|
existing = container.read_item(item=item_id, partition_key=item_id)
|
|
655
669
|
body = req.get_json()
|
|
@@ -665,20 +679,20 @@ def ${modelSnake}_update(req: func.HttpRequest) -> func.HttpResponse:
|
|
|
665
679
|
return _json_response({"error": "${modelName} not found", "id": item_id}, 404)
|
|
666
680
|
except ValueError:
|
|
667
681
|
return _json_response({"error": "Request body must be a JSON object.", "id": item_id}, 400)
|
|
668
|
-
except Exception as exc
|
|
682
|
+
except Exception as exc:${authCatch}
|
|
669
683
|
return _json_response({"error": "Failed to update item", "id": item_id, "details": str(exc)}, 500)
|
|
670
684
|
|
|
671
685
|
|
|
672
686
|
@bp.route(route="${modelCamel}/{id}", methods=["DELETE"])
|
|
673
687
|
def ${modelSnake}_delete(req: func.HttpRequest) -> func.HttpResponse:
|
|
674
688
|
item_id = req.route_params.get("id")
|
|
675
|
-
try
|
|
689
|
+
try:${writeGuard}
|
|
676
690
|
container = _get_container()
|
|
677
691
|
container.delete_item(item=item_id, partition_key=item_id)
|
|
678
692
|
return func.HttpResponse(status_code=204)
|
|
679
693
|
except exceptions.CosmosResourceNotFoundError:
|
|
680
694
|
return _json_response({"error": "${modelName} not found", "id": item_id}, 404)
|
|
681
|
-
except Exception as exc
|
|
695
|
+
except Exception as exc:${authCatch}
|
|
682
696
|
return _json_response({"error": "Failed to delete item", "id": item_id, "details": str(exc)}, 500)
|
|
683
697
|
`,
|
|
684
698
|
};
|
|
@@ -410,6 +410,8 @@ async function extractFieldsFromSchema(modelPath: string, schemaName: string): P
|
|
|
410
410
|
// コメントを削除
|
|
411
411
|
modelContent = modelContent.replace(/\/\*[\s\S]*?\*\//g, '');
|
|
412
412
|
modelContent = modelContent.replace(/\/\/.*/g, '');
|
|
413
|
+
// TypeScript の `as const` アサーションを削除(.mjs では構文エラーになる)
|
|
414
|
+
modelContent = modelContent.replace(/\s+as\s+const\b/g, '');
|
|
413
415
|
|
|
414
416
|
// インライン化したローカルインポートを先頭に追加
|
|
415
417
|
const inlinedDeps = localImports.length > 0 ? localImports.join('\n\n') + '\n\n' : '';
|