naro-cli 0.25.0 → 0.26.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.
- package/README.md +16 -2
- package/dist/{chunk-X5TUBMEU.js → chunk-RQJTCRKY.js} +2049 -143
- package/dist/deploy.js +1 -1
- package/dist/index.js +71 -80
- package/package.json +4 -4
- package/dist/chunk-R4XGSZQL.js +0 -35531
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
import { existsSync as existsSync10 } from "fs";
|
|
8
8
|
import { mkdtemp as mkdtemp2, readFile as readFile15, rm as rm5 } from "fs/promises";
|
|
9
9
|
import { tmpdir as tmpdir2 } from "os";
|
|
10
|
-
import { basename as basename5, dirname as dirname10, join as
|
|
10
|
+
import { basename as basename5, dirname as dirname10, join as join31, resolve as resolve14 } from "path";
|
|
11
11
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
12
12
|
|
|
13
13
|
// ../../packages/build/src/artifact-upload.ts
|
|
@@ -289,7 +289,7 @@ function hashAsset(data, contentType2) {
|
|
|
289
289
|
// ../../packages/build/src/local-build-executor.ts
|
|
290
290
|
import { access as access8, mkdtemp, readFile as readFile13, rm as rm3 } from "fs/promises";
|
|
291
291
|
import { tmpdir } from "os";
|
|
292
|
-
import { dirname as dirname4, join as
|
|
292
|
+
import { dirname as dirname4, join as join17, resolve as resolve7 } from "path";
|
|
293
293
|
|
|
294
294
|
// ../../packages/core/src/route-patterns.ts
|
|
295
295
|
var ROUTE_PATTERN = /^\/[A-Za-z0-9\-._~%!$&()*+,;=:@/[\]]*$/;
|
|
@@ -317,6 +317,1918 @@ var IDENTIFIER = new RegExp(
|
|
|
317
317
|
"g"
|
|
318
318
|
);
|
|
319
319
|
|
|
320
|
+
// ../../packages/core/src/capabilities.ts
|
|
321
|
+
var REASON_CODES = {
|
|
322
|
+
"secret-value": {
|
|
323
|
+
clients: ["mcp"],
|
|
324
|
+
why: "\uC2DC\uD06C\uB9BF \uAC12\uC744 \uBC1B\uAC70\uB098 \uB3CC\uB824\uC900\uB2E4. \uB300\uD654\uC5D0 \uB0A8\uB294\uB2E4 (apps/mcp/src/function-tools.ts:34)."
|
|
325
|
+
},
|
|
326
|
+
irreversible: {
|
|
327
|
+
clients: ["mcp"],
|
|
328
|
+
why: "\uB418\uB3CC\uB9B4 \uC218 \uC5C6\uACE0 \uD655\uC778\uC73C\uB85C\uB9CC \uB9C9\uC744 \uC218 \uC788\uB2E4 (project_cli_mcp_backlog #6)."
|
|
329
|
+
},
|
|
330
|
+
"privilege-escalation": {
|
|
331
|
+
clients: ["mcp"],
|
|
332
|
+
why: "\uAD8C\uD55C\xB7\uC5ED\uD560\xB7\uBA64\uBC84\uC2ED\uC744 \uBC14\uAFBC\uB2E4."
|
|
333
|
+
},
|
|
334
|
+
"payment-flow": {
|
|
335
|
+
clients: ["cli", "mcp"],
|
|
336
|
+
why: "\uCE74\uB4DC \uC815\uBCF4\uAC00 \uC9C0\uB098\uAC04\uB2E4. \uD638\uC2A4\uD305 \uACB0\uC81C\uCC3D\uC774 \uBC1B\uB294\uB2E4."
|
|
337
|
+
},
|
|
338
|
+
"browser-required": {
|
|
339
|
+
clients: ["cli", "mcp"],
|
|
340
|
+
why: "OAuth \uB9AC\uB2E4\uC774\uB809\uD2B8\uAC00 \uD544\uC694\uD558\uB2E4."
|
|
341
|
+
},
|
|
342
|
+
"local-filesystem": {
|
|
343
|
+
clients: ["ui"],
|
|
344
|
+
why: "\uB85C\uCEEC \uD30C\uC77C\uC744 \uC77D\uAC70\uB098 \uC4F4\uB2E4. \uC11C\uBC84\uAC00 \uD560 \uC218 \uC5C6\uB2E4."
|
|
345
|
+
},
|
|
346
|
+
"ui-affordance": {
|
|
347
|
+
clients: ["cli", "mcp"],
|
|
348
|
+
why: "\uD654\uBA74 \uC548\uC5D0\uC11C\uB9CC \uB73B\uC774 \uC788\uB2E4."
|
|
349
|
+
},
|
|
350
|
+
"agent-native": {
|
|
351
|
+
clients: ["mcp"],
|
|
352
|
+
// "naro CLI로 할 수 있다"는 사유가 아니다 — 그러면 CLI에 있는 모든 기능을
|
|
353
|
+
// 이 코드로 뺄 수 있다(PR #423 리뷰). 컨트롤 플레인에 닿는 일이면 planned다.
|
|
354
|
+
why: "\uC774 \uCEF4\uD4E8\uD130\uC758 \uD30C\uC77C\uB9CC \uC4F0\uB294 \uC77C\uC774\uB2E4. \uC5D0\uC774\uC804\uD2B8\uB294 \uC81C \uB3C4\uAD6C\uB85C \uD30C\uC77C\uC744 \uC4F4\uB2E4 \u2014 MCP \uD234\uB85C \uAC10\uC2F8\uBA74 \uC4F0\uAE30 \uACBD\uB85C \uAC80\uC0AC\uB9CC \uB294\uB2E4."
|
|
355
|
+
},
|
|
356
|
+
"user-session": {
|
|
357
|
+
clients: ["mcp"],
|
|
358
|
+
why: "\uC0AC\uC6A9\uC790 \uC790\uC2E0\uC758 \uB85C\uADF8\uC778 \uC138\uC158\uC744 \uBC14\uAFBC\uB2E4. \uC0AC\uB78C\uC774 \uD130\uBBF8\uB110\uC5D0\uC11C \uD55C\uB2E4."
|
|
359
|
+
},
|
|
360
|
+
"dashboard-itself": {
|
|
361
|
+
clients: ["ui"],
|
|
362
|
+
why: "\uB300\uC2DC\uBCF4\uB4DC\uB85C \uAC00\uB294 \uAE38\uC744 \uC54C\uB824 \uC8FC\uB294 \uAE30\uB2A5\uC774\uB2E4. \uB300\uC2DC\uBCF4\uB4DC \uC548\uC5D0\uC11C\uB294 \uB73B\uC774 \uC5C6\uB2E4."
|
|
363
|
+
}
|
|
364
|
+
};
|
|
365
|
+
var CAPABILITIES = [
|
|
366
|
+
{
|
|
367
|
+
id: "auth-whoami",
|
|
368
|
+
domain: "auth",
|
|
369
|
+
title: "\uB0B4 \uACC4\uC815 \uD655\uC778",
|
|
370
|
+
ui: { kind: "built" },
|
|
371
|
+
cli: { kind: "built", commands: ["naro whoami"] },
|
|
372
|
+
mcp: { kind: "built", tools: ["whoami"] }
|
|
373
|
+
},
|
|
374
|
+
{
|
|
375
|
+
id: "auth-ci-token",
|
|
376
|
+
domain: "auth",
|
|
377
|
+
title: "CI \uD1A0\uD070 \uBC1C\uAE09",
|
|
378
|
+
ui: {
|
|
379
|
+
kind: "excluded",
|
|
380
|
+
reason: "local-filesystem",
|
|
381
|
+
note: "naro login\uC774 \uC774 \uCEF4\uD4E8\uD130\uC5D0 \uB0A8\uAE34 \uC138\uC158(~/.naro/credentials.json)\uC5D0\uC11C \uD1A0\uD070\uC744 \uAEBC\uB0B8\uB2E4. \uBE0C\uB77C\uC6B0\uC800 \uC138\uC158\uC5D0\uB294 \uADF8 \uD30C\uC77C\uC774 \uC5C6\uB2E4."
|
|
382
|
+
},
|
|
383
|
+
cli: { kind: "built", commands: ["naro token"] },
|
|
384
|
+
mcp: {
|
|
385
|
+
kind: "excluded",
|
|
386
|
+
reason: "secret-value",
|
|
387
|
+
note: "\uD1A0\uD070 \uC790\uCCB4\uAC00 \uC2DC\uD06C\uB9BF\uC774\uB77C \uB300\uD654\uC5D0 \uB0A8\uB294\uB2E4. 2026-11-03 \uACB0\uC815(\uAD8C\uACE0\uB300\uB85C)."
|
|
388
|
+
}
|
|
389
|
+
},
|
|
390
|
+
{
|
|
391
|
+
id: "auth-login",
|
|
392
|
+
domain: "auth",
|
|
393
|
+
title: "\uB85C\uADF8\uC778",
|
|
394
|
+
dashboard: "/login",
|
|
395
|
+
ui: { kind: "built" },
|
|
396
|
+
cli: { kind: "built", commands: ["naro login"] },
|
|
397
|
+
mcp: {
|
|
398
|
+
kind: "excluded",
|
|
399
|
+
reason: "browser-required",
|
|
400
|
+
note: "apps/mcp/src/tools.ts \u2014 \uC774 \uC11C\uBC84\uB294 \uBE0C\uB77C\uC6B0\uC800\uB97C \uC5F4 \uC218 \uC5C6\uB2E4. \uC0AC\uC6A9\uC790\uAC00 \uD130\uBBF8\uB110\uC5D0\uC11C naro login\uC744 \uB3CC\uB9AC\uAC8C \uD55C\uB2E4."
|
|
401
|
+
}
|
|
402
|
+
},
|
|
403
|
+
{
|
|
404
|
+
id: "auth-logout",
|
|
405
|
+
domain: "auth",
|
|
406
|
+
title: "\uB85C\uADF8\uC544\uC6C3",
|
|
407
|
+
dashboard: null,
|
|
408
|
+
ui: { kind: "built" },
|
|
409
|
+
cli: { kind: "built", commands: ["naro logout"] },
|
|
410
|
+
mcp: {
|
|
411
|
+
kind: "excluded",
|
|
412
|
+
reason: "user-session",
|
|
413
|
+
note: "naro login \uC138\uC158\uC740 \uC0AC\uB78C\uC774 \uB2E4\uB8EC\uB2E4. 2026-11-03 \uACB0\uC815."
|
|
414
|
+
}
|
|
415
|
+
},
|
|
416
|
+
{
|
|
417
|
+
id: "team-list",
|
|
418
|
+
domain: "teams",
|
|
419
|
+
title: "\uD300 \uBAA9\uB85D",
|
|
420
|
+
routes: ["GET teams"],
|
|
421
|
+
ui: { kind: "built" },
|
|
422
|
+
cli: { kind: "built", commands: ["naro teams"] },
|
|
423
|
+
mcp: { kind: "built", tools: ["list_teams"] }
|
|
424
|
+
},
|
|
425
|
+
{
|
|
426
|
+
id: "team-member-list",
|
|
427
|
+
domain: "teams",
|
|
428
|
+
title: "\uBA64\uBC84 \uBAA9\uB85D",
|
|
429
|
+
routes: ["GET teams/[teamSlug]/members"],
|
|
430
|
+
ui: { kind: "built" },
|
|
431
|
+
cli: { kind: "built", commands: ["naro team members"] },
|
|
432
|
+
mcp: { kind: "built", tools: ["list_team_members"] }
|
|
433
|
+
},
|
|
434
|
+
{
|
|
435
|
+
id: "team-create",
|
|
436
|
+
domain: "teams",
|
|
437
|
+
title: "\uD300 \uC0DD\uC131",
|
|
438
|
+
routes: ["POST teams"],
|
|
439
|
+
ui: { kind: "built" },
|
|
440
|
+
cli: { kind: "built", commands: ["naro team create"] },
|
|
441
|
+
mcp: { kind: "built", tools: ["create_team"] }
|
|
442
|
+
},
|
|
443
|
+
{
|
|
444
|
+
id: "team-update",
|
|
445
|
+
domain: "teams",
|
|
446
|
+
title: "\uD300 \uC124\uC815 \uBCC0\uACBD",
|
|
447
|
+
routes: ["PATCH teams/[teamSlug]"],
|
|
448
|
+
ui: { kind: "built" },
|
|
449
|
+
cli: { kind: "built", commands: ["naro team set"] },
|
|
450
|
+
mcp: { kind: "built", tools: ["update_team"] }
|
|
451
|
+
},
|
|
452
|
+
{
|
|
453
|
+
id: "team-delete",
|
|
454
|
+
domain: "teams",
|
|
455
|
+
title: "\uD300 \uC0AD\uC81C",
|
|
456
|
+
routes: ["DELETE teams/[teamSlug]"],
|
|
457
|
+
dashboard: "/[teamSlug]/settings",
|
|
458
|
+
ui: { kind: "built" },
|
|
459
|
+
cli: { kind: "built", commands: ["naro team delete"] },
|
|
460
|
+
mcp: {
|
|
461
|
+
kind: "excluded",
|
|
462
|
+
reason: "irreversible",
|
|
463
|
+
note: "\uD300\uC758 \uD504\uB85C\uC81D\uD2B8\xB7\uB370\uC774\uD130\uAC00 \uD568\uAED8 \uC0AC\uB77C\uC9C4\uB2E4. 2026-11-03 \uACB0\uC815(\uAD8C\uACE0\uB300\uB85C)."
|
|
464
|
+
}
|
|
465
|
+
},
|
|
466
|
+
{
|
|
467
|
+
id: "team-member-update",
|
|
468
|
+
domain: "teams",
|
|
469
|
+
title: "\uBA64\uBC84 \uC5ED\uD560 \uBCC0\uACBD",
|
|
470
|
+
routes: ["PATCH teams/[teamSlug]/members/[userId]"],
|
|
471
|
+
dashboard: "/[teamSlug]/settings",
|
|
472
|
+
ui: { kind: "built" },
|
|
473
|
+
cli: { kind: "built", commands: ["naro team members set"] },
|
|
474
|
+
mcp: {
|
|
475
|
+
kind: "excluded",
|
|
476
|
+
reason: "privilege-escalation",
|
|
477
|
+
note: "\uC5ED\uD560\uC744 \uBC14\uAFBC\uB2E4. 2026-11-03 \uACB0\uC815(\uAD8C\uACE0\uB300\uB85C)."
|
|
478
|
+
}
|
|
479
|
+
},
|
|
480
|
+
{
|
|
481
|
+
id: "team-member-remove",
|
|
482
|
+
domain: "teams",
|
|
483
|
+
title: "\uBA64\uBC84 \uC81C\uAC70",
|
|
484
|
+
routes: ["DELETE teams/[teamSlug]/members/[userId]"],
|
|
485
|
+
dashboard: "/[teamSlug]/settings",
|
|
486
|
+
ui: { kind: "built" },
|
|
487
|
+
cli: { kind: "built", commands: ["naro team members remove"] },
|
|
488
|
+
mcp: {
|
|
489
|
+
kind: "excluded",
|
|
490
|
+
reason: "privilege-escalation",
|
|
491
|
+
note: "\uBA64\uBC84\uC2ED\uC744 \uBC14\uAFBC\uB2E4. 2026-11-03 \uACB0\uC815(\uAD8C\uACE0\uB300\uB85C)."
|
|
492
|
+
}
|
|
493
|
+
},
|
|
494
|
+
{
|
|
495
|
+
id: "team-invite-list",
|
|
496
|
+
domain: "teams",
|
|
497
|
+
title: "\uCD08\uB300 \uBAA9\uB85D",
|
|
498
|
+
routes: ["GET teams/[teamSlug]/invites"],
|
|
499
|
+
ui: { kind: "built" },
|
|
500
|
+
cli: { kind: "built", commands: ["naro team invites"] },
|
|
501
|
+
mcp: { kind: "built", tools: ["list_team_invites"] }
|
|
502
|
+
},
|
|
503
|
+
{
|
|
504
|
+
id: "team-invite-create",
|
|
505
|
+
domain: "teams",
|
|
506
|
+
title: "\uCD08\uB300 \uBCF4\uB0B4\uAE30",
|
|
507
|
+
routes: ["POST teams/[teamSlug]/invites"],
|
|
508
|
+
dashboard: "/[teamSlug]/settings",
|
|
509
|
+
ui: { kind: "built" },
|
|
510
|
+
cli: { kind: "built", commands: ["naro team invites create"] },
|
|
511
|
+
mcp: {
|
|
512
|
+
kind: "excluded",
|
|
513
|
+
reason: "privilege-escalation",
|
|
514
|
+
note: "\uD300\uC5D0 \uC0AC\uB78C\uC744 \uB4E4\uC778\uB2E4. 2026-11-03 \uACB0\uC815(\uAD8C\uACE0\uB300\uB85C)."
|
|
515
|
+
}
|
|
516
|
+
},
|
|
517
|
+
{
|
|
518
|
+
id: "team-invite-revoke",
|
|
519
|
+
domain: "teams",
|
|
520
|
+
title: "\uCD08\uB300 \uCDE8\uC18C",
|
|
521
|
+
routes: ["DELETE teams/[teamSlug]/invites/[inviteId]"],
|
|
522
|
+
ui: { kind: "built" },
|
|
523
|
+
cli: { kind: "built", commands: ["naro team invites revoke"] },
|
|
524
|
+
mcp: { kind: "built", tools: ["revoke_team_invite"] }
|
|
525
|
+
},
|
|
526
|
+
{
|
|
527
|
+
id: "team-usage",
|
|
528
|
+
domain: "teams",
|
|
529
|
+
title: "\uD300 \uC0AC\uC6A9\uB7C9",
|
|
530
|
+
routes: ["GET teams/[teamSlug]/usage"],
|
|
531
|
+
ui: { kind: "built" },
|
|
532
|
+
cli: { kind: "built", commands: ["naro usage"] },
|
|
533
|
+
mcp: { kind: "built", tools: ["get_team_usage"] }
|
|
534
|
+
},
|
|
535
|
+
{
|
|
536
|
+
id: "billing-view",
|
|
537
|
+
domain: "billing",
|
|
538
|
+
title: "\uD50C\uB79C\xB7\uAD6C\uB3C5 \uC870\uD68C",
|
|
539
|
+
routes: ["GET teams/[teamSlug]/billing"],
|
|
540
|
+
ui: { kind: "built" },
|
|
541
|
+
cli: { kind: "built", commands: ["naro billing"] },
|
|
542
|
+
mcp: { kind: "built", tools: ["get_team_billing"] }
|
|
543
|
+
},
|
|
544
|
+
{
|
|
545
|
+
id: "billing-checkout",
|
|
546
|
+
domain: "billing",
|
|
547
|
+
title: "\uCCB4\uD06C\uC544\uC6C3",
|
|
548
|
+
routes: ["POST teams/[teamSlug]/billing/checkout"],
|
|
549
|
+
dashboard: "/[teamSlug]/usage",
|
|
550
|
+
ui: { kind: "built" },
|
|
551
|
+
cli: {
|
|
552
|
+
kind: "excluded",
|
|
553
|
+
reason: "payment-flow",
|
|
554
|
+
note: "\uCE74\uB4DC \uC815\uBCF4\uB294 Paddle\uC758 \uD638\uC2A4\uD305 \uACB0\uC81C\uCC3D\uC774 \uBC1B\uB294\uB2E4."
|
|
555
|
+
},
|
|
556
|
+
mcp: {
|
|
557
|
+
kind: "excluded",
|
|
558
|
+
reason: "payment-flow",
|
|
559
|
+
note: "\uCE74\uB4DC \uC815\uBCF4\uB294 Paddle\uC758 \uD638\uC2A4\uD305 \uACB0\uC81C\uCC3D\uC774 \uBC1B\uB294\uB2E4. 2026-11-03 \uACB0\uC815(\uAD8C\uACE0\uB300\uB85C)."
|
|
560
|
+
}
|
|
561
|
+
},
|
|
562
|
+
{
|
|
563
|
+
id: "billing-portal",
|
|
564
|
+
domain: "billing",
|
|
565
|
+
title: "\uACB0\uC81C \uD3EC\uD138",
|
|
566
|
+
routes: ["POST teams/[teamSlug]/billing/portal"],
|
|
567
|
+
dashboard: "/[teamSlug]/usage",
|
|
568
|
+
ui: { kind: "built" },
|
|
569
|
+
cli: {
|
|
570
|
+
kind: "excluded",
|
|
571
|
+
reason: "payment-flow",
|
|
572
|
+
note: "\uACB0\uC81C \uC218\uB2E8 \uBCC0\uACBD\uC740 Paddle \uD3EC\uD138\uC5D0\uC11C \uD55C\uB2E4."
|
|
573
|
+
},
|
|
574
|
+
mcp: {
|
|
575
|
+
kind: "excluded",
|
|
576
|
+
reason: "payment-flow",
|
|
577
|
+
note: "\uACB0\uC81C \uC218\uB2E8 \uBCC0\uACBD\uC740 Paddle \uD3EC\uD138\uC5D0\uC11C \uD55C\uB2E4. 2026-11-03 \uACB0\uC815(\uAD8C\uACE0\uB300\uB85C)."
|
|
578
|
+
}
|
|
579
|
+
},
|
|
580
|
+
{
|
|
581
|
+
id: "project-list",
|
|
582
|
+
domain: "projects",
|
|
583
|
+
title: "\uD504\uB85C\uC81D\uD2B8 \uBAA9\uB85D",
|
|
584
|
+
routes: ["GET projects"],
|
|
585
|
+
ui: { kind: "built" },
|
|
586
|
+
cli: { kind: "built", commands: ["naro projects"] },
|
|
587
|
+
mcp: { kind: "built", tools: ["list_projects"] }
|
|
588
|
+
},
|
|
589
|
+
{
|
|
590
|
+
id: "project-create",
|
|
591
|
+
domain: "projects",
|
|
592
|
+
title: "\uD504\uB85C\uC81D\uD2B8 \uC0DD\uC131",
|
|
593
|
+
routes: ["POST projects"],
|
|
594
|
+
ui: { kind: "built" },
|
|
595
|
+
// naro deploy가 링크가 없을 때 만든다(POST cli/deployments).
|
|
596
|
+
cli: { kind: "built" },
|
|
597
|
+
// deploy가 링크가 없을 때 만든다(POST cli/deployments).
|
|
598
|
+
mcp: { kind: "built" }
|
|
599
|
+
},
|
|
600
|
+
{
|
|
601
|
+
id: "project-get",
|
|
602
|
+
domain: "projects",
|
|
603
|
+
title: "\uD504\uB85C\uC81D\uD2B8 \uC870\uD68C",
|
|
604
|
+
routes: ["GET projects/[projectId]"],
|
|
605
|
+
ui: { kind: "built" },
|
|
606
|
+
cli: { kind: "built", commands: ["naro project inspect"] },
|
|
607
|
+
mcp: { kind: "built", tools: ["get_project"] }
|
|
608
|
+
},
|
|
609
|
+
{
|
|
610
|
+
id: "project-link",
|
|
611
|
+
domain: "projects",
|
|
612
|
+
title: "\uB514\uB809\uD130\uB9AC\uB97C \uD504\uB85C\uC81D\uD2B8\uC5D0 \uB9C1\uD06C",
|
|
613
|
+
ui: {
|
|
614
|
+
kind: "excluded",
|
|
615
|
+
reason: "local-filesystem",
|
|
616
|
+
note: ".naro/project.json\uC5D0 \uC4F4\uB2E4. \uC11C\uBC84\uAC00 \uD560 \uC218 \uC5C6\uB2E4."
|
|
617
|
+
},
|
|
618
|
+
cli: { kind: "built", commands: ["naro link", "naro init"] },
|
|
619
|
+
mcp: { kind: "built", tools: ["link_project"] }
|
|
620
|
+
},
|
|
621
|
+
{
|
|
622
|
+
id: "project-unlink",
|
|
623
|
+
domain: "projects",
|
|
624
|
+
title: "\uB9C1\uD06C \uD574\uC81C",
|
|
625
|
+
ui: {
|
|
626
|
+
kind: "excluded",
|
|
627
|
+
reason: "local-filesystem",
|
|
628
|
+
note: ".naro/\uB97C \uC9C0\uC6B4\uB2E4. \uC11C\uBC84\uAC00 \uD560 \uC218 \uC5C6\uB2E4."
|
|
629
|
+
},
|
|
630
|
+
cli: { kind: "built", commands: ["naro unlink"] },
|
|
631
|
+
mcp: {
|
|
632
|
+
kind: "excluded",
|
|
633
|
+
reason: "agent-native",
|
|
634
|
+
note: ".naro/\uB97C \uC9C0\uC6B0\uB294 \uC77C\uC774\uB2E4. \uC9DD\uC778 link_project\uAC00 \uD234\uC778 \uAC83\uC740 \uD504\uB85C\uC81D\uD2B8\uB97C \uACE0\uB974\uB824\uBA74 \uCEE8\uD2B8\uB864 \uD50C\uB808\uC778\uC744 \uC77D\uC5B4\uC57C \uD574\uC11C\uB2E4 \u2014 unlink\uB294 \uD30C\uC77C\uB9CC \uC9C0\uC6B4\uB2E4. 2026-11-03 \uACB0\uC815."
|
|
635
|
+
}
|
|
636
|
+
},
|
|
637
|
+
{
|
|
638
|
+
id: "project-update",
|
|
639
|
+
domain: "projects",
|
|
640
|
+
title: "\uD504\uB85C\uC81D\uD2B8 \uC124\uC815 \uBCC0\uACBD(\uD504\uB808\uC784\uC6CC\uD06C\xB7\uC11C\uBE0C\uB3C4\uBA54\uC778)",
|
|
641
|
+
routes: ["PATCH projects/[projectId]"],
|
|
642
|
+
ui: { kind: "built" },
|
|
643
|
+
cli: { kind: "built", commands: ["naro project set"] },
|
|
644
|
+
// 서브도메인은 빼고(PR #433 리뷰): 옛 이름이 바로 비어 누구나 가져갈 수 있어
|
|
645
|
+
// 북마크·OAuth 리다이렉트가 남의 앱으로 간다. 대시보드와 CLI(먼저 묻는다)만.
|
|
646
|
+
mcp: { kind: "built", tools: ["update_project"] }
|
|
647
|
+
},
|
|
648
|
+
{
|
|
649
|
+
id: "project-delete",
|
|
650
|
+
domain: "projects",
|
|
651
|
+
title: "\uD504\uB85C\uC81D\uD2B8 \uC0AD\uC81C",
|
|
652
|
+
routes: ["DELETE projects/[projectId]"],
|
|
653
|
+
dashboard: "/[teamSlug]/projects/[projectSlug]/settings",
|
|
654
|
+
ui: { kind: "built" },
|
|
655
|
+
cli: { kind: "built", commands: ["naro project delete"] },
|
|
656
|
+
mcp: {
|
|
657
|
+
kind: "excluded",
|
|
658
|
+
reason: "irreversible",
|
|
659
|
+
note: "\uC6CC\uCEE4\xB7D1\xB7R2\xB7\uB3C4\uBA54\uC778\xB7\uBC30\uD3EC \uC774\uB825\uC774 cascade\uB85C \uB0A0\uC544\uAC04\uB2E4. \uC5D0\uC774\uC804\uD2B8\uB294 \uD504\uB86C\uD504\uD2B8 \uC778\uC81D\uC158\uC5D0 \uB178\uCD9C\uB418\uBBC0\uB85C \uD655\uC778\uC73C\uB85C \uB9C9\uC744 \uC218 \uC5C6\uB2E4(project_cli_mcp_backlog #6)."
|
|
660
|
+
}
|
|
661
|
+
},
|
|
662
|
+
{
|
|
663
|
+
id: "project-subdomain-check",
|
|
664
|
+
domain: "projects",
|
|
665
|
+
title: "\uC11C\uBE0C\uB3C4\uBA54\uC778 \uC0AC\uC6A9 \uAC00\uB2A5 \uC5EC\uBD80",
|
|
666
|
+
routes: ["GET subdomains/availability"],
|
|
667
|
+
ui: { kind: "built" },
|
|
668
|
+
cli: { kind: "built", commands: ["naro project check"] },
|
|
669
|
+
mcp: { kind: "built", tools: ["check_subdomain"] }
|
|
670
|
+
},
|
|
671
|
+
{
|
|
672
|
+
id: "project-access-list",
|
|
673
|
+
domain: "projects",
|
|
674
|
+
title: "\uBA64\uBC84\uBCC4 \uD504\uB85C\uC81D\uD2B8 \uC811\uADFC \uC870\uD68C",
|
|
675
|
+
routes: ["GET projects/[projectId]/access"],
|
|
676
|
+
ui: { kind: "built" },
|
|
677
|
+
cli: { kind: "built", commands: ["naro project access"] },
|
|
678
|
+
mcp: { kind: "built", tools: ["list_project_access"] }
|
|
679
|
+
},
|
|
680
|
+
{
|
|
681
|
+
id: "project-access-grant",
|
|
682
|
+
domain: "projects",
|
|
683
|
+
title: "\uBA64\uBC84\uC5D0\uAC8C \uD504\uB85C\uC81D\uD2B8 \uC811\uADFC \uBD80\uC5EC",
|
|
684
|
+
routes: ["PUT projects/[projectId]/access"],
|
|
685
|
+
dashboard: "/[teamSlug]/projects/[projectSlug]/access",
|
|
686
|
+
ui: { kind: "built" },
|
|
687
|
+
cli: { kind: "built", commands: ["naro project access grant"] },
|
|
688
|
+
mcp: {
|
|
689
|
+
kind: "excluded",
|
|
690
|
+
reason: "privilege-escalation",
|
|
691
|
+
note: "\uBA64\uBC84\uC758 \uD504\uB85C\uC81D\uD2B8 \uAD8C\uD55C\uC744 \uBC14\uAFBC\uB2E4. 2026-11-03 \uACB0\uC815(\uAD8C\uACE0\uB300\uB85C)."
|
|
692
|
+
}
|
|
693
|
+
},
|
|
694
|
+
{
|
|
695
|
+
id: "project-access-revoke",
|
|
696
|
+
domain: "projects",
|
|
697
|
+
title: "\uBA64\uBC84\uC758 \uD504\uB85C\uC81D\uD2B8 \uC811\uADFC \uD68C\uC218",
|
|
698
|
+
routes: ["DELETE projects/[projectId]/access"],
|
|
699
|
+
dashboard: "/[teamSlug]/projects/[projectSlug]/access",
|
|
700
|
+
ui: { kind: "built" },
|
|
701
|
+
cli: { kind: "built", commands: ["naro project access revoke"] },
|
|
702
|
+
mcp: {
|
|
703
|
+
kind: "excluded",
|
|
704
|
+
reason: "privilege-escalation",
|
|
705
|
+
note: "\uBA64\uBC84\uC758 \uD504\uB85C\uC81D\uD2B8 \uAD8C\uD55C\uC744 \uBC14\uAFBC\uB2E4. 2026-11-03 \uACB0\uC815(\uAD8C\uACE0\uB300\uB85C)."
|
|
706
|
+
}
|
|
707
|
+
},
|
|
708
|
+
{
|
|
709
|
+
id: "deployment-list",
|
|
710
|
+
domain: "deployments",
|
|
711
|
+
title: "\uBC30\uD3EC \uBAA9\uB85D",
|
|
712
|
+
routes: ["GET projects/[projectId]/deployments"],
|
|
713
|
+
ui: { kind: "built" },
|
|
714
|
+
cli: { kind: "built", commands: ["naro deployments"] },
|
|
715
|
+
mcp: { kind: "built", tools: ["list_deployments"] }
|
|
716
|
+
},
|
|
717
|
+
{
|
|
718
|
+
id: "deployment-create",
|
|
719
|
+
domain: "deployments",
|
|
720
|
+
title: "\uBE0C\uB79C\uCE58\uC5D0\uC11C \uC0C8\uB85C \uBC30\uD3EC",
|
|
721
|
+
routes: ["POST projects/[projectId]/deployments"],
|
|
722
|
+
ui: { kind: "built" },
|
|
723
|
+
cli: { kind: "built", commands: ["naro deployments create"] },
|
|
724
|
+
mcp: { kind: "built", tools: ["deploy_from_git"] }
|
|
725
|
+
},
|
|
726
|
+
{
|
|
727
|
+
id: "deployment-local",
|
|
728
|
+
domain: "deployments",
|
|
729
|
+
title: "\uB85C\uCEEC\uC5D0\uC11C \uBE4C\uB4DC\uD574 \uBC30\uD3EC",
|
|
730
|
+
routes: ["POST cli/deployments"],
|
|
731
|
+
ui: {
|
|
732
|
+
kind: "excluded",
|
|
733
|
+
reason: "local-filesystem",
|
|
734
|
+
note: "\uB85C\uCEEC \uC791\uC5C5 \uD2B8\uB9AC\uC5D0\uC11C \uBE4C\uB4DC\uD55C \uC0B0\uCD9C\uBB3C\uC744 \uC62C\uB9B0\uB2E4. \uBE0C\uB77C\uC6B0\uC800\uC5D0\uB294 \uBE4C\uB4DC\uD560 \uC791\uC5C5 \uD2B8\uB9AC\uAC00 \uC5C6\uB2E4."
|
|
735
|
+
},
|
|
736
|
+
cli: { kind: "built", commands: ["naro deploy"] },
|
|
737
|
+
mcp: { kind: "built", tools: ["deploy"] }
|
|
738
|
+
},
|
|
739
|
+
{
|
|
740
|
+
id: "deployment-get",
|
|
741
|
+
domain: "deployments",
|
|
742
|
+
title: "\uBC30\uD3EC \uC0C1\uC138",
|
|
743
|
+
routes: ["GET deployments/[deploymentId]"],
|
|
744
|
+
ui: { kind: "built" },
|
|
745
|
+
cli: { kind: "built", commands: ["naro inspect"] },
|
|
746
|
+
mcp: { kind: "built", tools: ["get_deployment", "get_build_logs"] }
|
|
747
|
+
},
|
|
748
|
+
{
|
|
749
|
+
id: "deployment-cancel",
|
|
750
|
+
domain: "deployments",
|
|
751
|
+
title: "\uBE4C\uB4DC \uCDE8\uC18C",
|
|
752
|
+
routes: ["POST projects/[projectId]/deployments/[deploymentId]/cancel"],
|
|
753
|
+
ui: { kind: "built" },
|
|
754
|
+
cli: { kind: "built", commands: ["naro cancel"] },
|
|
755
|
+
mcp: { kind: "built", tools: ["cancel_deployment"] }
|
|
756
|
+
},
|
|
757
|
+
{
|
|
758
|
+
id: "deployment-promote-preview",
|
|
759
|
+
domain: "deployments",
|
|
760
|
+
title: "\uC2B9\uACA9 \uBBF8\uB9AC\uBCF4\uAE30",
|
|
761
|
+
routes: ["GET projects/[projectId]/deployments/[deploymentId]/promote"],
|
|
762
|
+
ui: { kind: "built" },
|
|
763
|
+
// naro promote가 묻기 전에 무엇을 할지 보여 준다(client.deployments.promoteCheck).
|
|
764
|
+
cli: { kind: "built" },
|
|
765
|
+
mcp: { kind: "built", tools: ["check_promotion"] }
|
|
766
|
+
},
|
|
767
|
+
{
|
|
768
|
+
id: "deployment-promote",
|
|
769
|
+
domain: "deployments",
|
|
770
|
+
title: "\uD504\uB85C\uB355\uC158\xB7\uD658\uACBD\uC73C\uB85C \uC2B9\uACA9(\uB864\uBC31 \uD3EC\uD568)",
|
|
771
|
+
routes: ["POST projects/[projectId]/deployments/[deploymentId]/promote"],
|
|
772
|
+
ui: { kind: "built" },
|
|
773
|
+
cli: { kind: "built", commands: ["naro promote", "naro rollback"] },
|
|
774
|
+
mcp: {
|
|
775
|
+
kind: "built",
|
|
776
|
+
tools: ["promote_deployment", "rollback_deployment"]
|
|
777
|
+
}
|
|
778
|
+
},
|
|
779
|
+
{
|
|
780
|
+
id: "git-app-install",
|
|
781
|
+
domain: "git",
|
|
782
|
+
title: "GitHub App \uC124\uCE58",
|
|
783
|
+
routes: ["GET github/authorize", "GET github/install", "GET github/setup"],
|
|
784
|
+
dashboard: "/[teamSlug]/projects/[projectSlug]/settings",
|
|
785
|
+
ui: { kind: "built" },
|
|
786
|
+
cli: {
|
|
787
|
+
kind: "excluded",
|
|
788
|
+
reason: "browser-required",
|
|
789
|
+
note: "GitHub App \uC124\uCE58\uB294 OAuth \uB9AC\uB2E4\uC774\uB809\uD2B8\uB85C \uB05D\uB09C\uB2E4. naro git connect\uAC00 \uC124\uCE58 URL\uC744 \uCC0D\uC5B4 \uC900\uB2E4."
|
|
790
|
+
},
|
|
791
|
+
mcp: {
|
|
792
|
+
kind: "excluded",
|
|
793
|
+
reason: "browser-required",
|
|
794
|
+
note: "apps/mcp/src/tools.ts\uC758 connect_git_repository \u2014 \uC124\uCE58 URL\uC744 \uC0AC\uC6A9\uC790\uC5D0\uAC8C \uC8FC\uACE0 \uBE0C\uB77C\uC6B0\uC800\uB294 \uC9C1\uC811 \uC5F4\uC9C0 \uC54A\uB294\uB2E4."
|
|
795
|
+
}
|
|
796
|
+
},
|
|
797
|
+
{
|
|
798
|
+
id: "git-repository-list",
|
|
799
|
+
domain: "git",
|
|
800
|
+
title: "GitHub \uC800\uC7A5\uC18C \uBAA9\uB85D",
|
|
801
|
+
routes: ["GET github/repositories"],
|
|
802
|
+
ui: { kind: "built" },
|
|
803
|
+
// naro git connect가 저장소를 고를 때 읽는다(client.github.listRepositories).
|
|
804
|
+
cli: { kind: "built" },
|
|
805
|
+
mcp: { kind: "built", tools: ["list_git_repositories"] }
|
|
806
|
+
},
|
|
807
|
+
{
|
|
808
|
+
id: "git-connect",
|
|
809
|
+
domain: "git",
|
|
810
|
+
title: "\uC800\uC7A5\uC18C \uC5F0\uACB0",
|
|
811
|
+
routes: ["POST projects/[projectId]/git"],
|
|
812
|
+
ui: { kind: "built" },
|
|
813
|
+
cli: { kind: "built", commands: ["naro git connect"] },
|
|
814
|
+
mcp: { kind: "built", tools: ["connect_git_repository"] }
|
|
815
|
+
},
|
|
816
|
+
{
|
|
817
|
+
id: "git-disconnect",
|
|
818
|
+
domain: "git",
|
|
819
|
+
title: "\uC800\uC7A5\uC18C \uC5F0\uACB0 \uD574\uC81C",
|
|
820
|
+
routes: ["DELETE projects/[projectId]/git"],
|
|
821
|
+
ui: { kind: "built" },
|
|
822
|
+
cli: { kind: "built", commands: ["naro git disconnect"] },
|
|
823
|
+
mcp: { kind: "built", tools: ["disconnect_git_repository"] }
|
|
824
|
+
},
|
|
825
|
+
{
|
|
826
|
+
id: "env-list",
|
|
827
|
+
domain: "env",
|
|
828
|
+
title: "\uD658\uACBD\uBCC0\uC218 \uBAA9\uB85D",
|
|
829
|
+
routes: ["GET projects/[projectId]/env"],
|
|
830
|
+
ui: { kind: "built" },
|
|
831
|
+
cli: { kind: "built", commands: ["naro env list"] },
|
|
832
|
+
mcp: { kind: "built", tools: ["list_environment_variables"] }
|
|
833
|
+
},
|
|
834
|
+
{
|
|
835
|
+
id: "env-set",
|
|
836
|
+
domain: "env",
|
|
837
|
+
title: "\uD658\uACBD\uBCC0\uC218 \uCD94\uAC00\xB7\uC218\uC815",
|
|
838
|
+
routes: ["POST projects/[projectId]/env"],
|
|
839
|
+
ui: { kind: "built" },
|
|
840
|
+
cli: { kind: "built", commands: ["naro env add", "naro env import"] },
|
|
841
|
+
mcp: { kind: "built", tools: ["set_environment_variable"] }
|
|
842
|
+
},
|
|
843
|
+
{
|
|
844
|
+
id: "env-remove",
|
|
845
|
+
domain: "env",
|
|
846
|
+
title: "\uD658\uACBD\uBCC0\uC218 \uC81C\uAC70",
|
|
847
|
+
routes: ["DELETE projects/[projectId]/env/[envVarId]"],
|
|
848
|
+
ui: { kind: "built" },
|
|
849
|
+
cli: { kind: "built", commands: ["naro env remove"] },
|
|
850
|
+
mcp: { kind: "built", tools: ["remove_environment_variable"] }
|
|
851
|
+
},
|
|
852
|
+
// 앱 메일의 Resend 연결(spec 2026-11-04 resend-email-integration). 연결은
|
|
853
|
+
// env 두 행이라 env 도메인에 둔다. CLI·MCP는 그 스펙의 PR 2다.
|
|
854
|
+
{
|
|
855
|
+
id: "email-status",
|
|
856
|
+
domain: "env",
|
|
857
|
+
title: "Resend \uC5F0\uACB0 \uBCF4\uAE30",
|
|
858
|
+
routes: ["GET projects/[projectId]/email"],
|
|
859
|
+
ui: { kind: "built" },
|
|
860
|
+
cli: { kind: "planned", note: "naro email status \u2014 \uC2A4\uD399 \xA713 PR 2." },
|
|
861
|
+
mcp: { kind: "planned", note: "get_email \u2014 \uC2A4\uD399 \xA713 PR 2." }
|
|
862
|
+
},
|
|
863
|
+
{
|
|
864
|
+
id: "email-connect",
|
|
865
|
+
domain: "env",
|
|
866
|
+
title: "Resend \uC5F0\uACB0\xB7\uBC14\uAFB8\uAE30",
|
|
867
|
+
routes: ["PUT projects/[projectId]/email"],
|
|
868
|
+
dashboard: "/[teamSlug]/projects/[projectSlug]/email",
|
|
869
|
+
ui: { kind: "built" },
|
|
870
|
+
cli: {
|
|
871
|
+
kind: "planned",
|
|
872
|
+
note: "naro email connect --api-key-stdin \u2014 \uC2A4\uD399 \xA713 PR 2."
|
|
873
|
+
},
|
|
874
|
+
mcp: {
|
|
875
|
+
kind: "excluded",
|
|
876
|
+
reason: "secret-value",
|
|
877
|
+
note: "Resend API \uD0A4\uB97C \uBC1B\uB294\uB2E4. \uB300\uD654\uC5D0 \uB0A8\uB294\uB2E4 \u2014 get_email\uC774 naro email connect\uB098 \uB300\uC2DC\uBCF4\uB4DC\uB97C \uC548\uB0B4\uD55C\uB2E4(\uC2A4\uD399 \xA73-8)."
|
|
878
|
+
}
|
|
879
|
+
},
|
|
880
|
+
{
|
|
881
|
+
id: "email-disconnect",
|
|
882
|
+
domain: "env",
|
|
883
|
+
title: "Resend \uC5F0\uACB0 \uB04A\uAE30",
|
|
884
|
+
routes: ["DELETE projects/[projectId]/email"],
|
|
885
|
+
ui: { kind: "built" },
|
|
886
|
+
cli: { kind: "planned", note: "naro email disconnect \u2014 \uC2A4\uD399 \xA713 PR 2." },
|
|
887
|
+
mcp: { kind: "planned", note: "disconnect_email \u2014 \uC2A4\uD399 \xA713 PR 2." }
|
|
888
|
+
},
|
|
889
|
+
{
|
|
890
|
+
id: "env-pull",
|
|
891
|
+
domain: "env",
|
|
892
|
+
title: "\uD658\uACBD\uBCC0\uC218\uB97C \uB85C\uCEEC\uB85C \uB0B4\uB9AC\uAE30",
|
|
893
|
+
ui: {
|
|
894
|
+
kind: "excluded",
|
|
895
|
+
reason: "local-filesystem",
|
|
896
|
+
note: ".env.local\uC5D0 \uC4F4\uB2E4. \uC11C\uBC84\uAC00 \uD560 \uC218 \uC5C6\uB2E4."
|
|
897
|
+
},
|
|
898
|
+
cli: { kind: "built", commands: ["naro env pull"] },
|
|
899
|
+
mcp: {
|
|
900
|
+
kind: "excluded",
|
|
901
|
+
reason: "secret-value",
|
|
902
|
+
note: "\uBCF5\uD638\uD654\uD55C \uAC12\uC744 .env.local\uC5D0 \uC4F4\uB2E4. list_environment_variables\uB294 \uAC12\uC744 \uAC00\uB9B0\uB2E4. 2026-11-03 \uACB0\uC815."
|
|
903
|
+
}
|
|
904
|
+
},
|
|
905
|
+
{
|
|
906
|
+
id: "supabase-connect",
|
|
907
|
+
domain: "env",
|
|
908
|
+
title: "\uAE30\uC874 Supabase \uD504\uB85C\uC81D\uD2B8 \uC5F0\uACB0\xB7\uD0A4 \uB2E4\uC2DC \uBC1B\uAE30",
|
|
909
|
+
routes: [
|
|
910
|
+
"GET supabase/authorize",
|
|
911
|
+
"GET supabase/callback",
|
|
912
|
+
"GET projects/[projectId]/supabase/projects",
|
|
913
|
+
"PUT projects/[projectId]/supabase"
|
|
914
|
+
],
|
|
915
|
+
dashboard: "/[teamSlug]/projects/[projectSlug]/settings",
|
|
916
|
+
ui: { kind: "built" },
|
|
917
|
+
cli: {
|
|
918
|
+
kind: "excluded",
|
|
919
|
+
reason: "browser-required",
|
|
920
|
+
note: "Supabase OAuth \uB9AC\uB2E4\uC774\uB809\uD2B8\uB85C \uB05D\uB09C\uB2E4. \uD1A0\uD070\uC740 10\uBD84 \uCFE0\uD0A4\uC5D0\uB9CC \uC788\uB2E4(\uC124\uACC4 2026-11-04 \xA72.1)."
|
|
921
|
+
},
|
|
922
|
+
mcp: {
|
|
923
|
+
kind: "excluded",
|
|
924
|
+
reason: "browser-required",
|
|
925
|
+
note: "Supabase OAuth \uB9AC\uB2E4\uC774\uB809\uD2B8\uB85C \uB05D\uB09C\uB2E4. \uB300\uC2DC\uBCF4\uB4DC\uC758 \uD504\uB85C\uC81D\uD2B8 \uC124\uC815 \uD0ED\uC5D0\uC11C \uC5F0\uACB0\uD55C\uB2E4."
|
|
926
|
+
}
|
|
927
|
+
},
|
|
928
|
+
{
|
|
929
|
+
id: "supabase-link-list",
|
|
930
|
+
domain: "env",
|
|
931
|
+
title: "Supabase \uC5F0\uACB0 \uBCF4\uAE30",
|
|
932
|
+
routes: ["GET projects/[projectId]/supabase"],
|
|
933
|
+
ui: { kind: "built" },
|
|
934
|
+
cli: { kind: "built", commands: ["naro supabase"] },
|
|
935
|
+
mcp: { kind: "built", tools: ["list_supabase_links"] }
|
|
936
|
+
},
|
|
937
|
+
{
|
|
938
|
+
id: "supabase-disconnect",
|
|
939
|
+
domain: "env",
|
|
940
|
+
title: "Supabase \uC5F0\uACB0 \uD574\uC81C",
|
|
941
|
+
routes: ["DELETE projects/[projectId]/supabase"],
|
|
942
|
+
ui: { kind: "built" },
|
|
943
|
+
cli: { kind: "built", commands: ["naro supabase disconnect"] },
|
|
944
|
+
mcp: { kind: "built", tools: ["disconnect_supabase"] }
|
|
945
|
+
},
|
|
946
|
+
{
|
|
947
|
+
id: "environment-list",
|
|
948
|
+
domain: "environments",
|
|
949
|
+
title: "\uD658\uACBD \uBAA9\uB85D",
|
|
950
|
+
routes: ["GET projects/[projectId]/environments"],
|
|
951
|
+
ui: { kind: "built" },
|
|
952
|
+
cli: { kind: "built", commands: ["naro environments"] },
|
|
953
|
+
mcp: { kind: "built", tools: ["list_environments"] }
|
|
954
|
+
},
|
|
955
|
+
{
|
|
956
|
+
id: "environment-create",
|
|
957
|
+
domain: "environments",
|
|
958
|
+
title: "\uD658\uACBD \uB9CC\uB4E4\uAE30",
|
|
959
|
+
routes: ["POST projects/[projectId]/environments"],
|
|
960
|
+
ui: { kind: "built" },
|
|
961
|
+
cli: { kind: "built", commands: ["naro environments create"] },
|
|
962
|
+
mcp: { kind: "built", tools: ["create_environment"] }
|
|
963
|
+
},
|
|
964
|
+
{
|
|
965
|
+
id: "environment-update",
|
|
966
|
+
domain: "environments",
|
|
967
|
+
title: "\uD658\uACBD \uC124\uC815 \uBCC0\uACBD(\uBE0C\uB79C\uCE58\xB7\uBCF4\uD638)",
|
|
968
|
+
routes: ["PATCH projects/[projectId]/environments/[environmentId]"],
|
|
969
|
+
ui: { kind: "built" },
|
|
970
|
+
cli: { kind: "built", commands: ["naro environments set"] },
|
|
971
|
+
mcp: { kind: "built", tools: ["update_environment"] }
|
|
972
|
+
},
|
|
973
|
+
{
|
|
974
|
+
id: "environment-delete",
|
|
975
|
+
domain: "environments",
|
|
976
|
+
title: "\uD658\uACBD \uC0AD\uC81C",
|
|
977
|
+
routes: ["DELETE projects/[projectId]/environments/[environmentId]"],
|
|
978
|
+
ui: { kind: "built" },
|
|
979
|
+
cli: { kind: "built", commands: ["naro environments delete"] },
|
|
980
|
+
mcp: { kind: "built", tools: ["delete_environment"] }
|
|
981
|
+
},
|
|
982
|
+
{
|
|
983
|
+
id: "environment-provision",
|
|
984
|
+
domain: "environments",
|
|
985
|
+
title: "\uD658\uACBD \uB370\uC774\uD130 \uD504\uB85C\uBE44\uC800\uB2DD",
|
|
986
|
+
routes: [
|
|
987
|
+
"POST projects/[projectId]/environments/[environmentId]/provision"
|
|
988
|
+
],
|
|
989
|
+
ui: { kind: "built" },
|
|
990
|
+
cli: { kind: "built", commands: ["naro environments provision"] },
|
|
991
|
+
mcp: { kind: "built", tools: ["provision_environment"] }
|
|
992
|
+
},
|
|
993
|
+
{
|
|
994
|
+
id: "domain-list",
|
|
995
|
+
domain: "domains",
|
|
996
|
+
title: "\uB3C4\uBA54\uC778 \uBAA9\uB85D",
|
|
997
|
+
routes: ["GET projects/[projectId]/domains"],
|
|
998
|
+
ui: { kind: "built" },
|
|
999
|
+
cli: { kind: "built", commands: ["naro domains list"] },
|
|
1000
|
+
mcp: { kind: "built", tools: ["list_domains"] }
|
|
1001
|
+
},
|
|
1002
|
+
{
|
|
1003
|
+
id: "domain-add",
|
|
1004
|
+
domain: "domains",
|
|
1005
|
+
title: "\uB3C4\uBA54\uC778 \uCD94\uAC00",
|
|
1006
|
+
routes: ["POST projects/[projectId]/domains"],
|
|
1007
|
+
ui: { kind: "built" },
|
|
1008
|
+
cli: { kind: "built", commands: ["naro domains add"] },
|
|
1009
|
+
mcp: { kind: "built", tools: ["add_domain"] }
|
|
1010
|
+
},
|
|
1011
|
+
{
|
|
1012
|
+
id: "domain-refresh",
|
|
1013
|
+
domain: "domains",
|
|
1014
|
+
title: "\uB3C4\uBA54\uC778 \uC0C1\uD0DC \uC0C8\uB85C\uACE0\uCE68",
|
|
1015
|
+
routes: ["PATCH projects/[projectId]/domains/[domainId]"],
|
|
1016
|
+
ui: { kind: "built" },
|
|
1017
|
+
// naro domains verify가 Cloudflare 재확인까지 해서 refresh(저장된 상태 다시 읽기)의
|
|
1018
|
+
// 상위다. 같은 PATCH는 부르지 않는다.
|
|
1019
|
+
cli: { kind: "built" },
|
|
1020
|
+
// verify_domain이 같은 일을 더 한다(재확인 + DNS 점검).
|
|
1021
|
+
mcp: { kind: "built" }
|
|
1022
|
+
},
|
|
1023
|
+
{
|
|
1024
|
+
id: "domain-remove",
|
|
1025
|
+
domain: "domains",
|
|
1026
|
+
title: "\uB3C4\uBA54\uC778 \uC81C\uAC70",
|
|
1027
|
+
routes: ["DELETE projects/[projectId]/domains/[domainId]"],
|
|
1028
|
+
ui: { kind: "built" },
|
|
1029
|
+
cli: { kind: "built", commands: ["naro domains remove"] },
|
|
1030
|
+
mcp: { kind: "built", tools: ["remove_domain"] }
|
|
1031
|
+
},
|
|
1032
|
+
{
|
|
1033
|
+
id: "domain-verify",
|
|
1034
|
+
domain: "domains",
|
|
1035
|
+
title: "DNS \uC7AC\uAC80\uC99D",
|
|
1036
|
+
routes: ["POST projects/[projectId]/domains/[domainId]/verify"],
|
|
1037
|
+
ui: { kind: "built" },
|
|
1038
|
+
cli: { kind: "built", commands: ["naro domains verify"] },
|
|
1039
|
+
mcp: { kind: "built", tools: ["verify_domain"] }
|
|
1040
|
+
},
|
|
1041
|
+
{
|
|
1042
|
+
id: "domain-claim-list",
|
|
1043
|
+
domain: "domains",
|
|
1044
|
+
title: "\uB2E4\uB978 \uD504\uB85C\uC81D\uD2B8\uAC00 \uAC00\uC9C4 \uB3C4\uBA54\uC778\uC758 \uC18C\uC720\uAD8C \uD655\uC778 \uBAA9\uB85D",
|
|
1045
|
+
routes: ["GET projects/[projectId]/domain-claims"],
|
|
1046
|
+
ui: { kind: "built" },
|
|
1047
|
+
// naro domains verify가 소유권 확인을 함께 읽는다(client.domains.listClaims).
|
|
1048
|
+
cli: { kind: "built" },
|
|
1049
|
+
// verify_domain이 소유권 확인을 함께 읽는다(client.domains.listClaims).
|
|
1050
|
+
mcp: { kind: "built" }
|
|
1051
|
+
},
|
|
1052
|
+
{
|
|
1053
|
+
id: "domain-claim-verify",
|
|
1054
|
+
domain: "domains",
|
|
1055
|
+
title: "\uB3C4\uBA54\uC778 \uC18C\uC720\uAD8C \uD655\uC778",
|
|
1056
|
+
routes: ["POST projects/[projectId]/domain-claims/[claimId]/verify"],
|
|
1057
|
+
ui: { kind: "built" },
|
|
1058
|
+
// naro domains verify가 소유권 확인을 함께 다시 본다(client.domains.verifyClaim).
|
|
1059
|
+
cli: { kind: "built" },
|
|
1060
|
+
// verify_domain이 소유권 확인을 함께 다시 본다(client.domains.verifyClaim).
|
|
1061
|
+
mcp: { kind: "built" }
|
|
1062
|
+
},
|
|
1063
|
+
{
|
|
1064
|
+
id: "domain-claim-cancel",
|
|
1065
|
+
domain: "domains",
|
|
1066
|
+
title: "\uB3C4\uBA54\uC778 \uC18C\uC720\uAD8C \uD655\uC778 \uCDE8\uC18C",
|
|
1067
|
+
routes: ["DELETE projects/[projectId]/domain-claims/[claimId]"],
|
|
1068
|
+
ui: { kind: "built" },
|
|
1069
|
+
// naro domains remove가 붙어 있지 않은 호스트의 소유권 확인을 취소한다.
|
|
1070
|
+
cli: { kind: "built" },
|
|
1071
|
+
// remove_domain이 붙어 있지 않은 호스트의 소유권 확인을 취소한다(claimCancelled).
|
|
1072
|
+
mcp: { kind: "built" }
|
|
1073
|
+
},
|
|
1074
|
+
{
|
|
1075
|
+
id: "dns-zone-list",
|
|
1076
|
+
domain: "dns",
|
|
1077
|
+
title: "DNS \uC874 \uBAA9\uB85D",
|
|
1078
|
+
routes: ["GET teams/[teamSlug]/dns-zones"],
|
|
1079
|
+
ui: { kind: "built" },
|
|
1080
|
+
cli: { kind: "built", commands: ["naro dns"] },
|
|
1081
|
+
mcp: { kind: "built", tools: ["get_dns"] }
|
|
1082
|
+
},
|
|
1083
|
+
{
|
|
1084
|
+
id: "dns-zone-add",
|
|
1085
|
+
domain: "dns",
|
|
1086
|
+
title: "DNS \uC874 \uCD94\uAC00",
|
|
1087
|
+
routes: ["POST teams/[teamSlug]/dns-zones"],
|
|
1088
|
+
ui: { kind: "built" },
|
|
1089
|
+
cli: { kind: "built", commands: ["naro dns add"] },
|
|
1090
|
+
mcp: { kind: "built", tools: ["add_dns_zone"] }
|
|
1091
|
+
},
|
|
1092
|
+
{
|
|
1093
|
+
id: "dns-zone-remove",
|
|
1094
|
+
domain: "dns",
|
|
1095
|
+
title: "DNS \uC874 \uC0AD\uC81C",
|
|
1096
|
+
routes: ["DELETE teams/[teamSlug]/dns-zones/[zoneId]"],
|
|
1097
|
+
ui: { kind: "built" },
|
|
1098
|
+
cli: { kind: "built", commands: ["naro dns remove"] },
|
|
1099
|
+
mcp: { kind: "built", tools: ["remove_dns_zone"] }
|
|
1100
|
+
},
|
|
1101
|
+
{
|
|
1102
|
+
id: "dns-zone-check",
|
|
1103
|
+
domain: "dns",
|
|
1104
|
+
title: "\uB124\uC784\uC11C\uBC84 \uC774\uAD00 \uD655\uC778",
|
|
1105
|
+
routes: ["POST teams/[teamSlug]/dns-zones/[zoneId]/check"],
|
|
1106
|
+
ui: { kind: "built" },
|
|
1107
|
+
cli: { kind: "built", commands: ["naro dns check"] },
|
|
1108
|
+
mcp: { kind: "built", tools: ["check_dns_zone"] }
|
|
1109
|
+
},
|
|
1110
|
+
{
|
|
1111
|
+
id: "dns-zone-precheck",
|
|
1112
|
+
domain: "dns",
|
|
1113
|
+
title: "\uC774\uAD00 \uC804 \uBA54\uC77C \uD655\uC778",
|
|
1114
|
+
routes: ["GET teams/[teamSlug]/dns-zones/[zoneId]/precheck"],
|
|
1115
|
+
ui: { kind: "built" },
|
|
1116
|
+
cli: { kind: "built", commands: ["naro dns mail"] },
|
|
1117
|
+
mcp: { kind: "built", tools: ["check_dns_mail"] }
|
|
1118
|
+
},
|
|
1119
|
+
{
|
|
1120
|
+
id: "dns-zone-scan",
|
|
1121
|
+
domain: "dns",
|
|
1122
|
+
title: "\uAE30\uC874 DNS \uB808\uCF54\uB4DC \uC2A4\uCE94 \uACB0\uACFC",
|
|
1123
|
+
routes: ["GET teams/[teamSlug]/dns-zones/[zoneId]/scan"],
|
|
1124
|
+
ui: { kind: "built" },
|
|
1125
|
+
cli: { kind: "built", commands: ["naro dns scan"] },
|
|
1126
|
+
mcp: { kind: "built", tools: ["get_dns_scan"] }
|
|
1127
|
+
},
|
|
1128
|
+
{
|
|
1129
|
+
id: "dns-zone-scan-import",
|
|
1130
|
+
domain: "dns",
|
|
1131
|
+
title: "\uC2A4\uCE94\uD55C \uB808\uCF54\uB4DC \uC77C\uAD04 \uAC00\uC838\uC624\uAE30",
|
|
1132
|
+
routes: ["POST teams/[teamSlug]/dns-zones/[zoneId]/scan"],
|
|
1133
|
+
ui: { kind: "built" },
|
|
1134
|
+
cli: { kind: "built", commands: ["naro dns import"] },
|
|
1135
|
+
mcp: { kind: "built", tools: ["import_dns_scan"] }
|
|
1136
|
+
},
|
|
1137
|
+
{
|
|
1138
|
+
id: "dns-record-list",
|
|
1139
|
+
domain: "dns",
|
|
1140
|
+
title: "DNS \uB808\uCF54\uB4DC \uBAA9\uB85D",
|
|
1141
|
+
routes: ["GET teams/[teamSlug]/dns-zones/[zoneId]/records"],
|
|
1142
|
+
ui: { kind: "built" },
|
|
1143
|
+
cli: { kind: "built", commands: ["naro dns records"] },
|
|
1144
|
+
mcp: { kind: "built", tools: ["list_dns_records"] }
|
|
1145
|
+
},
|
|
1146
|
+
{
|
|
1147
|
+
id: "dns-record-add",
|
|
1148
|
+
domain: "dns",
|
|
1149
|
+
title: "DNS \uB808\uCF54\uB4DC \uCD94\uAC00",
|
|
1150
|
+
routes: ["POST teams/[teamSlug]/dns-zones/[zoneId]/records"],
|
|
1151
|
+
ui: { kind: "built" },
|
|
1152
|
+
cli: { kind: "built", commands: ["naro dns records add"] },
|
|
1153
|
+
mcp: { kind: "built", tools: ["add_dns_record"] }
|
|
1154
|
+
},
|
|
1155
|
+
{
|
|
1156
|
+
id: "dns-record-update",
|
|
1157
|
+
domain: "dns",
|
|
1158
|
+
title: "DNS \uB808\uCF54\uB4DC \uC218\uC815",
|
|
1159
|
+
routes: ["PATCH teams/[teamSlug]/dns-zones/[zoneId]/records/[recordId]"],
|
|
1160
|
+
ui: { kind: "built" },
|
|
1161
|
+
cli: { kind: "built", commands: ["naro dns records update"] },
|
|
1162
|
+
mcp: { kind: "built", tools: ["update_dns_record"] }
|
|
1163
|
+
},
|
|
1164
|
+
{
|
|
1165
|
+
id: "dns-record-remove",
|
|
1166
|
+
domain: "dns",
|
|
1167
|
+
title: "DNS \uB808\uCF54\uB4DC \uC0AD\uC81C",
|
|
1168
|
+
routes: ["DELETE teams/[teamSlug]/dns-zones/[zoneId]/records/[recordId]"],
|
|
1169
|
+
ui: { kind: "built" },
|
|
1170
|
+
cli: { kind: "built", commands: ["naro dns records remove"] },
|
|
1171
|
+
mcp: { kind: "built", tools: ["remove_dns_record"] }
|
|
1172
|
+
},
|
|
1173
|
+
{
|
|
1174
|
+
id: "protection-get",
|
|
1175
|
+
domain: "protection",
|
|
1176
|
+
title: "\uD504\uB9AC\uBDF0 \uBCF4\uD638 \uC0C1\uD0DC",
|
|
1177
|
+
routes: ["GET projects/[projectId]/preview-protection"],
|
|
1178
|
+
ui: { kind: "built" },
|
|
1179
|
+
cli: { kind: "built", commands: ["naro protection"] },
|
|
1180
|
+
mcp: { kind: "built", tools: ["get_preview_protection"] }
|
|
1181
|
+
},
|
|
1182
|
+
{
|
|
1183
|
+
id: "protection-set",
|
|
1184
|
+
domain: "protection",
|
|
1185
|
+
title: "\uD504\uB9AC\uBDF0 \uBCF4\uD638 \uCF1C\uAE30\xB7\uB044\uAE30",
|
|
1186
|
+
routes: ["PUT projects/[projectId]/preview-protection"],
|
|
1187
|
+
ui: { kind: "built" },
|
|
1188
|
+
cli: {
|
|
1189
|
+
kind: "built",
|
|
1190
|
+
commands: ["naro protection enable", "naro protection disable"]
|
|
1191
|
+
},
|
|
1192
|
+
mcp: { kind: "built", tools: ["set_preview_protection"] }
|
|
1193
|
+
},
|
|
1194
|
+
{
|
|
1195
|
+
id: "protection-bypass-create",
|
|
1196
|
+
domain: "protection",
|
|
1197
|
+
title: "\uC6B0\uD68C \uC2DC\uD06C\uB9BF \uB9CC\uB4E4\uAE30",
|
|
1198
|
+
routes: ["POST projects/[projectId]/preview-protection/bypass"],
|
|
1199
|
+
dashboard: "/[teamSlug]/projects/[projectSlug]/settings",
|
|
1200
|
+
ui: { kind: "built" },
|
|
1201
|
+
cli: { kind: "built", commands: ["naro protection bypass"] },
|
|
1202
|
+
mcp: {
|
|
1203
|
+
kind: "excluded",
|
|
1204
|
+
reason: "secret-value",
|
|
1205
|
+
note: "apps/mcp/src/protection-tools.ts \u2014 \uC6B0\uD68C \uC2DC\uD06C\uB9BF\uC740 \uB300\uD654\uC5D0 \uB0A8\uB294\uB2E4. \uB300\uC2DC\uBCF4\uB4DC\uB098 naro protection bypass\uB85C \uB9CC\uB4E0\uB2E4."
|
|
1206
|
+
}
|
|
1207
|
+
},
|
|
1208
|
+
{
|
|
1209
|
+
id: "protection-bypass-remove",
|
|
1210
|
+
domain: "protection",
|
|
1211
|
+
title: "\uC6B0\uD68C \uC2DC\uD06C\uB9BF \uC81C\uAC70",
|
|
1212
|
+
routes: ["DELETE projects/[projectId]/preview-protection/bypass"],
|
|
1213
|
+
ui: { kind: "built" },
|
|
1214
|
+
cli: { kind: "built", commands: ["naro protection bypass remove"] },
|
|
1215
|
+
mcp: { kind: "built", tools: ["remove_preview_protection_bypass"] }
|
|
1216
|
+
},
|
|
1217
|
+
{
|
|
1218
|
+
id: "database-info",
|
|
1219
|
+
domain: "database",
|
|
1220
|
+
title: "\uB370\uC774\uD130\uBCA0\uC774\uC2A4 \uC0C1\uD0DC\xB7\uC6A9\uB7C9\xB7\uD55C\uB3C4",
|
|
1221
|
+
routes: ["GET projects/[projectId]/database"],
|
|
1222
|
+
ui: { kind: "built" },
|
|
1223
|
+
cli: { kind: "built", commands: ["naro db info"] },
|
|
1224
|
+
mcp: { kind: "built", tools: ["get_database"] }
|
|
1225
|
+
},
|
|
1226
|
+
{
|
|
1227
|
+
id: "database-enable",
|
|
1228
|
+
domain: "database",
|
|
1229
|
+
title: "\uB370\uC774\uD130\uBCA0\uC774\uC2A4 \uB9CC\uB4E4\uAE30",
|
|
1230
|
+
routes: ["POST projects/[projectId]/database"],
|
|
1231
|
+
ui: { kind: "built" },
|
|
1232
|
+
cli: { kind: "built", commands: ["naro db enable"] },
|
|
1233
|
+
mcp: { kind: "built", tools: ["enable_database"] }
|
|
1234
|
+
},
|
|
1235
|
+
{
|
|
1236
|
+
id: "database-query",
|
|
1237
|
+
domain: "database",
|
|
1238
|
+
title: "SQL \uC2E4\uD589",
|
|
1239
|
+
routes: ["POST projects/[projectId]/database/query"],
|
|
1240
|
+
ui: { kind: "built" },
|
|
1241
|
+
cli: { kind: "built", commands: ["naro db query"] },
|
|
1242
|
+
mcp: { kind: "built", tools: ["execute_sql"] }
|
|
1243
|
+
},
|
|
1244
|
+
{
|
|
1245
|
+
id: "database-tables",
|
|
1246
|
+
domain: "database",
|
|
1247
|
+
title: "\uD14C\uC774\uBE14 \uBAA9\uB85D",
|
|
1248
|
+
routes: ["GET projects/[projectId]/database/tables"],
|
|
1249
|
+
ui: { kind: "built" },
|
|
1250
|
+
// naro db 명령들이 테이블 목록을 읽는다(client.db.tables).
|
|
1251
|
+
cli: { kind: "built" },
|
|
1252
|
+
mcp: { kind: "built", tools: ["list_tables"] }
|
|
1253
|
+
},
|
|
1254
|
+
{
|
|
1255
|
+
id: "database-schema-change",
|
|
1256
|
+
domain: "database",
|
|
1257
|
+
title: "\uD14C\uC774\uBE14\xB7\uC778\uB371\uC2A4 \uBC14\uAFB8\uAE30",
|
|
1258
|
+
routes: ["POST projects/[projectId]/database/schema"],
|
|
1259
|
+
ui: { kind: "built" },
|
|
1260
|
+
cli: {
|
|
1261
|
+
kind: "built",
|
|
1262
|
+
commands: [
|
|
1263
|
+
"naro db table create",
|
|
1264
|
+
"naro db table add-column",
|
|
1265
|
+
"naro db table rename-column",
|
|
1266
|
+
"naro db table rename",
|
|
1267
|
+
"naro db table drop-column",
|
|
1268
|
+
"naro db table drop",
|
|
1269
|
+
"naro db index create",
|
|
1270
|
+
"naro db index drop"
|
|
1271
|
+
]
|
|
1272
|
+
},
|
|
1273
|
+
mcp: {
|
|
1274
|
+
kind: "built",
|
|
1275
|
+
tools: [
|
|
1276
|
+
"create_table",
|
|
1277
|
+
"alter_table",
|
|
1278
|
+
"drop_table",
|
|
1279
|
+
"create_index",
|
|
1280
|
+
"drop_index"
|
|
1281
|
+
]
|
|
1282
|
+
}
|
|
1283
|
+
},
|
|
1284
|
+
{
|
|
1285
|
+
id: "database-migration-list",
|
|
1286
|
+
domain: "database",
|
|
1287
|
+
title: "\uB9C8\uC774\uADF8\uB808\uC774\uC158 \uBAA9\uB85D",
|
|
1288
|
+
routes: ["GET projects/[projectId]/database/migrations"],
|
|
1289
|
+
ui: { kind: "built" },
|
|
1290
|
+
cli: { kind: "built", commands: ["naro migration list"] },
|
|
1291
|
+
mcp: { kind: "built", tools: ["list_migrations"] }
|
|
1292
|
+
},
|
|
1293
|
+
{
|
|
1294
|
+
id: "database-migration-apply",
|
|
1295
|
+
domain: "database",
|
|
1296
|
+
title: "\uB9C8\uC774\uADF8\uB808\uC774\uC158 \uC801\uC6A9",
|
|
1297
|
+
routes: ["POST projects/[projectId]/database/migrations"],
|
|
1298
|
+
ui: { kind: "built" },
|
|
1299
|
+
cli: { kind: "built", commands: ["naro db push", "naro migration up"] },
|
|
1300
|
+
mcp: { kind: "built", tools: ["apply_migration"] }
|
|
1301
|
+
},
|
|
1302
|
+
{
|
|
1303
|
+
id: "database-export",
|
|
1304
|
+
domain: "database",
|
|
1305
|
+
title: "\uB364\uD504 \uB0B4\uB824\uBC1B\uAE30",
|
|
1306
|
+
routes: ["POST projects/[projectId]/database/export"],
|
|
1307
|
+
ui: { kind: "built" },
|
|
1308
|
+
cli: { kind: "built", commands: ["naro db dump"] },
|
|
1309
|
+
mcp: { kind: "built", tools: ["export_database"] }
|
|
1310
|
+
},
|
|
1311
|
+
{
|
|
1312
|
+
id: "database-restore",
|
|
1313
|
+
domain: "database",
|
|
1314
|
+
title: "Time Travel \uBCF5\uAD6C",
|
|
1315
|
+
routes: ["POST projects/[projectId]/database/restore"],
|
|
1316
|
+
ui: { kind: "built" },
|
|
1317
|
+
cli: { kind: "built", commands: ["naro db restore"] },
|
|
1318
|
+
mcp: { kind: "built", tools: ["restore_database"] }
|
|
1319
|
+
},
|
|
1320
|
+
{
|
|
1321
|
+
id: "database-bookmark",
|
|
1322
|
+
domain: "database",
|
|
1323
|
+
title: "\uBCF5\uAD6C \uC9C0\uC810(\uBD81\uB9C8\uD06C) \uC870\uD68C",
|
|
1324
|
+
routes: ["GET projects/[projectId]/database/bookmark"],
|
|
1325
|
+
ui: { kind: "built" },
|
|
1326
|
+
// naro db restore가 되돌릴 북마크를 먼저 읽는다(client.db.bookmark).
|
|
1327
|
+
cli: { kind: "built" },
|
|
1328
|
+
// restore_database가 되돌릴 북마크를 먼저 읽는다(client.db.bookmark).
|
|
1329
|
+
mcp: { kind: "built" }
|
|
1330
|
+
},
|
|
1331
|
+
{
|
|
1332
|
+
id: "database-pull",
|
|
1333
|
+
domain: "database",
|
|
1334
|
+
title: "\uC6D0\uACA9 \uC2A4\uD0A4\uB9C8\uB97C \uBCA0\uC774\uC2A4\uB77C\uC778 \uB9C8\uC774\uADF8\uB808\uC774\uC158\uC73C\uB85C",
|
|
1335
|
+
routes: ["POST projects/[projectId]/database/pull"],
|
|
1336
|
+
ui: {
|
|
1337
|
+
kind: "excluded",
|
|
1338
|
+
reason: "local-filesystem",
|
|
1339
|
+
note: "\uC6D0\uACA9 \uC2A4\uD0A4\uB9C8\uB97C ./migrations\uC758 \uCCAB \uD30C\uC77C\uB85C \uC4F4\uB2E4 \u2014 \uB0B4 \uCEF4\uD4E8\uD130\uC758 \uD3F4\uB354\uAC00 \uC788\uC5B4\uC57C \uD558\uB294 \uC77C\uC774\uB77C \uD654\uBA74\uC5D0\uC11C\uB294 \uD560 \uC218 \uC5C6\uB2E4."
|
|
1340
|
+
},
|
|
1341
|
+
cli: { kind: "built", commands: ["naro db pull"] },
|
|
1342
|
+
mcp: { kind: "built", tools: ["pull_database_schema"] }
|
|
1343
|
+
},
|
|
1344
|
+
{
|
|
1345
|
+
id: "database-reset",
|
|
1346
|
+
domain: "database",
|
|
1347
|
+
title: "\uC804\uCCB4 \uB9AC\uC14B \uD6C4 \uB9C8\uC774\uADF8\uB808\uC774\uC158 \uB2E4\uC2DC \uC801\uC6A9",
|
|
1348
|
+
ui: {
|
|
1349
|
+
kind: "excluded",
|
|
1350
|
+
reason: "local-filesystem",
|
|
1351
|
+
note: "./migrations\uB97C \uCC98\uC74C\uBD80\uD130 \uB2E4\uC2DC \uC801\uC6A9\uD55C\uB2E4 \u2014 \uB0B4 \uCEF4\uD4E8\uD130\uC758 \uD3F4\uB354\uAC00 \uC788\uC5B4\uC57C \uD558\uB294 \uC77C\uC774\uB77C \uD654\uBA74\uC5D0\uC11C\uB294 \uD560 \uC218 \uC5C6\uB2E4."
|
|
1352
|
+
},
|
|
1353
|
+
cli: { kind: "built", commands: ["naro db reset"] },
|
|
1354
|
+
mcp: {
|
|
1355
|
+
kind: "excluded",
|
|
1356
|
+
reason: "irreversible",
|
|
1357
|
+
note: "\uBAA8\uB4E0 \uD14C\uC774\uBE14\uACFC \uC815\uCC45\uC744 \uC9C0\uC6B0\uACE0 \uB2E4\uC2DC \uB9CC\uB4E0\uB2E4. 2026-11-03 \uACB0\uC815(\uAD8C\uACE0\uB300\uB85C)."
|
|
1358
|
+
}
|
|
1359
|
+
},
|
|
1360
|
+
{
|
|
1361
|
+
id: "database-lint",
|
|
1362
|
+
domain: "database",
|
|
1363
|
+
title: "\uC2A4\uD0A4\uB9C8\xB7RLS \uC815\uCC45 \uB9B0\uD2B8",
|
|
1364
|
+
ui: { kind: "built" },
|
|
1365
|
+
cli: { kind: "built", commands: ["naro db lint"] },
|
|
1366
|
+
mcp: { kind: "built", tools: ["lint_database"] }
|
|
1367
|
+
},
|
|
1368
|
+
{
|
|
1369
|
+
id: "database-gen-types",
|
|
1370
|
+
domain: "database",
|
|
1371
|
+
title: "\uC2A4\uD0A4\uB9C8\uC5D0\uC11C TypeScript \uD0C0\uC785 \uC0DD\uC131",
|
|
1372
|
+
ui: { kind: "built" },
|
|
1373
|
+
cli: { kind: "built", commands: ["naro gen types"] },
|
|
1374
|
+
mcp: { kind: "built", tools: ["generate_typescript_types"] }
|
|
1375
|
+
},
|
|
1376
|
+
{
|
|
1377
|
+
id: "database-migration-new",
|
|
1378
|
+
domain: "database",
|
|
1379
|
+
title: "\uC0C8 \uB9C8\uC774\uADF8\uB808\uC774\uC158 \uD30C\uC77C",
|
|
1380
|
+
ui: {
|
|
1381
|
+
kind: "excluded",
|
|
1382
|
+
reason: "local-filesystem",
|
|
1383
|
+
note: "./migrations\uC5D0 \uD30C\uC77C\uC744 \uB9CC\uB4E0\uB2E4. \uC11C\uBC84\uAC00 \uD560 \uC218 \uC5C6\uB2E4."
|
|
1384
|
+
},
|
|
1385
|
+
cli: { kind: "built", commands: ["naro migration new"] },
|
|
1386
|
+
mcp: {
|
|
1387
|
+
kind: "excluded",
|
|
1388
|
+
reason: "agent-native",
|
|
1389
|
+
note: "./migrations\uC5D0 \uD30C\uC77C \uD558\uB098\uB97C \uB9CC\uB4E0\uB2E4. apply_migration\uC740 \uC801\uC6A9\uD558\uBA74\uC11C \uD30C\uC77C\uC744 \uC4F4\uB2E4. 2026-11-03 \uACB0\uC815."
|
|
1390
|
+
}
|
|
1391
|
+
},
|
|
1392
|
+
{
|
|
1393
|
+
id: "database-migration-repair",
|
|
1394
|
+
domain: "database",
|
|
1395
|
+
title: "\uB9C8\uC774\uADF8\uB808\uC774\uC158 \uC6D0\uC7A5 \uC218\uB9AC",
|
|
1396
|
+
dashboard: "/[teamSlug]/projects/[projectSlug]/database/migrations",
|
|
1397
|
+
ui: { kind: "built" },
|
|
1398
|
+
cli: { kind: "built", commands: ["naro migration repair"] },
|
|
1399
|
+
mcp: {
|
|
1400
|
+
kind: "excluded",
|
|
1401
|
+
reason: "irreversible",
|
|
1402
|
+
note: "\uC6D0\uC7A5\uB9CC \uACE0\uCCD0 \uC801\uC6A9 \uAE30\uB85D\uACFC \uC2E4\uC81C \uC2A4\uD0A4\uB9C8\uAC00 \uC5B4\uAE0B\uB0A0 \uC218 \uC788\uB2E4. 2026-11-03 \uACB0\uC815(\uAD8C\uACE0\uB300\uB85C)."
|
|
1403
|
+
}
|
|
1404
|
+
},
|
|
1405
|
+
{
|
|
1406
|
+
id: "database-saved-query-list",
|
|
1407
|
+
domain: "database",
|
|
1408
|
+
title: "\uC800\uC7A5\uD55C \uCFFC\uB9AC \uBAA9\uB85D",
|
|
1409
|
+
routes: ["GET projects/[projectId]/database/saved-queries"],
|
|
1410
|
+
dashboard: "/[teamSlug]/projects/[projectSlug]/database/sql",
|
|
1411
|
+
ui: { kind: "built" },
|
|
1412
|
+
cli: {
|
|
1413
|
+
kind: "excluded",
|
|
1414
|
+
reason: "ui-affordance",
|
|
1415
|
+
note: "SQL \uD3B8\uC9D1\uAE30 \uC548\uC5D0\uC11C\uB9CC \uB73B\uC774 \uC788\uB2E4. CLI\uB294 \uCFFC\uB9AC\uB97C \uD30C\uC77C\uC5D0 \uB450\uACE0 naro db query --file\uB85C \uB3CC\uB9B0\uB2E4."
|
|
1416
|
+
},
|
|
1417
|
+
mcp: {
|
|
1418
|
+
kind: "excluded",
|
|
1419
|
+
reason: "ui-affordance",
|
|
1420
|
+
note: "SQL \uD3B8\uC9D1\uAE30 \uC548\uC5D0\uC11C\uB9CC \uB73B\uC774 \uC788\uB2E4. 2026-11-03 \uACB0\uC815(\uAD8C\uACE0\uB300\uB85C)."
|
|
1421
|
+
}
|
|
1422
|
+
},
|
|
1423
|
+
{
|
|
1424
|
+
id: "database-saved-query-create",
|
|
1425
|
+
domain: "database",
|
|
1426
|
+
title: "\uCFFC\uB9AC \uC800\uC7A5",
|
|
1427
|
+
routes: ["POST projects/[projectId]/database/saved-queries"],
|
|
1428
|
+
dashboard: "/[teamSlug]/projects/[projectSlug]/database/sql",
|
|
1429
|
+
ui: { kind: "built" },
|
|
1430
|
+
cli: {
|
|
1431
|
+
kind: "excluded",
|
|
1432
|
+
reason: "ui-affordance",
|
|
1433
|
+
note: "SQL \uD3B8\uC9D1\uAE30 \uC548\uC5D0\uC11C\uB9CC \uB73B\uC774 \uC788\uB2E4. CLI\uB294 \uCFFC\uB9AC\uB97C \uD30C\uC77C\uC5D0 \uB450\uACE0 naro db query --file\uB85C \uB3CC\uB9B0\uB2E4."
|
|
1434
|
+
},
|
|
1435
|
+
mcp: {
|
|
1436
|
+
kind: "excluded",
|
|
1437
|
+
reason: "ui-affordance",
|
|
1438
|
+
note: "SQL \uD3B8\uC9D1\uAE30 \uC548\uC5D0\uC11C\uB9CC \uB73B\uC774 \uC788\uB2E4. 2026-11-03 \uACB0\uC815(\uAD8C\uACE0\uB300\uB85C)."
|
|
1439
|
+
}
|
|
1440
|
+
},
|
|
1441
|
+
{
|
|
1442
|
+
id: "database-saved-query-update",
|
|
1443
|
+
domain: "database",
|
|
1444
|
+
title: "\uC800\uC7A5\uD55C \uCFFC\uB9AC \uC218\uC815",
|
|
1445
|
+
routes: [
|
|
1446
|
+
"PATCH projects/[projectId]/database/saved-queries/[savedQueryId]"
|
|
1447
|
+
],
|
|
1448
|
+
dashboard: "/[teamSlug]/projects/[projectSlug]/database/sql",
|
|
1449
|
+
ui: { kind: "built" },
|
|
1450
|
+
cli: {
|
|
1451
|
+
kind: "excluded",
|
|
1452
|
+
reason: "ui-affordance",
|
|
1453
|
+
note: "SQL \uD3B8\uC9D1\uAE30 \uC548\uC5D0\uC11C\uB9CC \uB73B\uC774 \uC788\uB2E4. CLI\uB294 \uCFFC\uB9AC\uB97C \uD30C\uC77C\uC5D0 \uB450\uACE0 naro db query --file\uB85C \uB3CC\uB9B0\uB2E4."
|
|
1454
|
+
},
|
|
1455
|
+
mcp: {
|
|
1456
|
+
kind: "excluded",
|
|
1457
|
+
reason: "ui-affordance",
|
|
1458
|
+
note: "SQL \uD3B8\uC9D1\uAE30 \uC548\uC5D0\uC11C\uB9CC \uB73B\uC774 \uC788\uB2E4. 2026-11-03 \uACB0\uC815(\uAD8C\uACE0\uB300\uB85C)."
|
|
1459
|
+
}
|
|
1460
|
+
},
|
|
1461
|
+
{
|
|
1462
|
+
id: "database-saved-query-delete",
|
|
1463
|
+
domain: "database",
|
|
1464
|
+
title: "\uC800\uC7A5\uD55C \uCFFC\uB9AC \uC0AD\uC81C",
|
|
1465
|
+
routes: [
|
|
1466
|
+
"DELETE projects/[projectId]/database/saved-queries/[savedQueryId]"
|
|
1467
|
+
],
|
|
1468
|
+
dashboard: "/[teamSlug]/projects/[projectSlug]/database/sql",
|
|
1469
|
+
ui: { kind: "built" },
|
|
1470
|
+
cli: {
|
|
1471
|
+
kind: "excluded",
|
|
1472
|
+
reason: "ui-affordance",
|
|
1473
|
+
note: "SQL \uD3B8\uC9D1\uAE30 \uC548\uC5D0\uC11C\uB9CC \uB73B\uC774 \uC788\uB2E4. CLI\uB294 \uCFFC\uB9AC\uB97C \uD30C\uC77C\uC5D0 \uB450\uACE0 naro db query --file\uB85C \uB3CC\uB9B0\uB2E4."
|
|
1474
|
+
},
|
|
1475
|
+
mcp: {
|
|
1476
|
+
kind: "excluded",
|
|
1477
|
+
reason: "ui-affordance",
|
|
1478
|
+
note: "SQL \uD3B8\uC9D1\uAE30 \uC548\uC5D0\uC11C\uB9CC \uB73B\uC774 \uC788\uB2E4. 2026-11-03 \uACB0\uC815(\uAD8C\uACE0\uB300\uB85C)."
|
|
1479
|
+
}
|
|
1480
|
+
},
|
|
1481
|
+
{
|
|
1482
|
+
// 대시보드 정책 화면(백엔드 메뉴 Policies)은 2026-11-04에 생겼다.
|
|
1483
|
+
id: "rls-table-policy-list",
|
|
1484
|
+
domain: "rls",
|
|
1485
|
+
title: "\uD14C\uC774\uBE14\uBCC4 \uC815\uCC45 \uC870\uD68C",
|
|
1486
|
+
routes: ["GET projects/[projectId]/backend/policies"],
|
|
1487
|
+
ui: { kind: "built" },
|
|
1488
|
+
cli: { kind: "built", commands: ["naro policy rules"] },
|
|
1489
|
+
mcp: { kind: "built", tools: ["list_policy_rules"] }
|
|
1490
|
+
},
|
|
1491
|
+
{
|
|
1492
|
+
id: "rls-table-policy-set",
|
|
1493
|
+
domain: "rls",
|
|
1494
|
+
title: "\uD14C\uC774\uBE14\uC758 \uC561\uC158\uBCC4 \uADDC\uCE59 \uC124\uC815",
|
|
1495
|
+
routes: ["PUT projects/[projectId]/backend/policies/[table]"],
|
|
1496
|
+
ui: { kind: "built" },
|
|
1497
|
+
cli: { kind: "built", commands: ["naro policy set"] },
|
|
1498
|
+
// 규칙은 CREATE POLICY로, owner 규칙은 COMMENT ON POLICY p ON t IS 'naro:owner <column>'로 apply_migration에 쓴다.
|
|
1499
|
+
mcp: { kind: "built" }
|
|
1500
|
+
},
|
|
1501
|
+
{
|
|
1502
|
+
id: "rls-table-policy-remove",
|
|
1503
|
+
domain: "rls",
|
|
1504
|
+
title: "\uD14C\uC774\uBE14\uC758 \uC815\uCC45 \uC804\uBD80 \uC81C\uAC70",
|
|
1505
|
+
routes: ["DELETE projects/[projectId]/backend/policies/[table]"],
|
|
1506
|
+
ui: { kind: "built" },
|
|
1507
|
+
cli: { kind: "built", commands: ["naro policy remove"] },
|
|
1508
|
+
// apply_migration에 그 테이블의 DROP POLICY를 쓴다.
|
|
1509
|
+
mcp: { kind: "built" }
|
|
1510
|
+
},
|
|
1511
|
+
{
|
|
1512
|
+
id: "rls-policy-list",
|
|
1513
|
+
domain: "rls",
|
|
1514
|
+
title: "\uC815\uCC45 \uBAA9\uB85D(CREATE POLICY \uAF34)",
|
|
1515
|
+
routes: ["GET projects/[projectId]/backend/rls/policies"],
|
|
1516
|
+
ui: { kind: "built" },
|
|
1517
|
+
cli: { kind: "built", commands: ["naro policy list"] },
|
|
1518
|
+
mcp: { kind: "built", tools: ["list_policies"] }
|
|
1519
|
+
},
|
|
1520
|
+
{
|
|
1521
|
+
id: "rls-policy-create",
|
|
1522
|
+
domain: "rls",
|
|
1523
|
+
title: "\uC815\uCC45 \uB9CC\uB4E4\uAE30(CREATE POLICY)",
|
|
1524
|
+
routes: ["POST projects/[projectId]/backend/rls/policies"],
|
|
1525
|
+
ui: { kind: "built" },
|
|
1526
|
+
cli: { kind: "built", commands: ["naro policy create"] },
|
|
1527
|
+
// apply_migration·execute_sql이 CREATE POLICY를 받는다. 테이블과 같은 마이그레이션에 쓰라고 apply_migration이 안내한다.
|
|
1528
|
+
mcp: { kind: "built" }
|
|
1529
|
+
},
|
|
1530
|
+
{
|
|
1531
|
+
id: "rls-policy-replace",
|
|
1532
|
+
domain: "rls",
|
|
1533
|
+
title: "\uC815\uCC45 \uBC14\uAFB8\uAE30",
|
|
1534
|
+
routes: ["PUT projects/[projectId]/backend/rls/policies/[table]/[name]"],
|
|
1535
|
+
ui: { kind: "built" },
|
|
1536
|
+
// naro migration up·db push(client.db.applyMigration)나 naro db query
|
|
1537
|
+
// (client.db.query) 한 번에 DROP POLICY와 CREATE POLICY를 함께 쓴다.
|
|
1538
|
+
// MCP와 같은 경로다(PR #414 리뷰).
|
|
1539
|
+
cli: { kind: "built" },
|
|
1540
|
+
// apply_migration 한 번에 DROP POLICY와 CREATE POLICY를 함께 쓴다.
|
|
1541
|
+
mcp: { kind: "built" }
|
|
1542
|
+
},
|
|
1543
|
+
{
|
|
1544
|
+
id: "rls-policy-drop",
|
|
1545
|
+
domain: "rls",
|
|
1546
|
+
title: "\uC815\uCC45 \uC0AD\uC81C(DROP POLICY)",
|
|
1547
|
+
routes: ["DELETE projects/[projectId]/backend/rls/policies/[table]/[name]"],
|
|
1548
|
+
ui: { kind: "built" },
|
|
1549
|
+
cli: { kind: "built", commands: ["naro policy drop"] },
|
|
1550
|
+
// apply_migration·execute_sql이 DROP POLICY를 받는다.
|
|
1551
|
+
mcp: { kind: "built" }
|
|
1552
|
+
},
|
|
1553
|
+
{
|
|
1554
|
+
id: "storage-info",
|
|
1555
|
+
domain: "storage",
|
|
1556
|
+
title: "Storage \uC0C1\uD0DC",
|
|
1557
|
+
routes: ["GET projects/[projectId]/backend/storage"],
|
|
1558
|
+
ui: { kind: "built" },
|
|
1559
|
+
cli: { kind: "built", commands: ["naro storage"] },
|
|
1560
|
+
mcp: { kind: "built", tools: ["get_storage"] }
|
|
1561
|
+
},
|
|
1562
|
+
{
|
|
1563
|
+
id: "storage-enable",
|
|
1564
|
+
domain: "storage",
|
|
1565
|
+
title: "Storage \uCF1C\uAE30",
|
|
1566
|
+
routes: ["POST projects/[projectId]/backend/storage"],
|
|
1567
|
+
ui: { kind: "built" },
|
|
1568
|
+
cli: { kind: "built", commands: ["naro storage enable"] },
|
|
1569
|
+
mcp: { kind: "built", tools: ["enable_storage"] }
|
|
1570
|
+
},
|
|
1571
|
+
{
|
|
1572
|
+
id: "storage-disable",
|
|
1573
|
+
domain: "storage",
|
|
1574
|
+
title: "Storage \uB044\uAE30",
|
|
1575
|
+
routes: ["DELETE projects/[projectId]/backend/storage"],
|
|
1576
|
+
ui: { kind: "built" },
|
|
1577
|
+
cli: { kind: "built", commands: ["naro storage disable"] },
|
|
1578
|
+
mcp: { kind: "built", tools: ["disable_storage"] }
|
|
1579
|
+
},
|
|
1580
|
+
{
|
|
1581
|
+
id: "storage-bucket-list",
|
|
1582
|
+
domain: "storage",
|
|
1583
|
+
title: "\uBC84\uD0B7 \uBAA9\uB85D",
|
|
1584
|
+
routes: ["GET projects/[projectId]/backend/storage/buckets"],
|
|
1585
|
+
ui: { kind: "built" },
|
|
1586
|
+
cli: { kind: "built", commands: ["naro storage bucket list"] },
|
|
1587
|
+
mcp: { kind: "built", tools: ["list_storage_buckets"] }
|
|
1588
|
+
},
|
|
1589
|
+
{
|
|
1590
|
+
id: "storage-bucket-create",
|
|
1591
|
+
domain: "storage",
|
|
1592
|
+
title: "\uBC84\uD0B7 \uB9CC\uB4E4\uAE30",
|
|
1593
|
+
routes: ["POST projects/[projectId]/backend/storage/buckets"],
|
|
1594
|
+
ui: { kind: "built" },
|
|
1595
|
+
cli: { kind: "built", commands: ["naro storage bucket create"] },
|
|
1596
|
+
mcp: { kind: "built", tools: ["create_storage_bucket"] }
|
|
1597
|
+
},
|
|
1598
|
+
{
|
|
1599
|
+
id: "storage-bucket-get",
|
|
1600
|
+
domain: "storage",
|
|
1601
|
+
title: "\uBC84\uD0B7 \uC870\uD68C",
|
|
1602
|
+
routes: ["GET projects/[projectId]/backend/storage/buckets/[bucket]"],
|
|
1603
|
+
ui: { kind: "built" },
|
|
1604
|
+
// naro storage bucket update가 바꾸기 전에 읽는다(client.storage.getBucket).
|
|
1605
|
+
cli: { kind: "built" },
|
|
1606
|
+
mcp: { kind: "built", tools: ["get_storage_bucket"] }
|
|
1607
|
+
},
|
|
1608
|
+
{
|
|
1609
|
+
id: "storage-bucket-update",
|
|
1610
|
+
domain: "storage",
|
|
1611
|
+
title: "\uBC84\uD0B7 \uC124\uC815 \uBCC0\uACBD",
|
|
1612
|
+
routes: ["PATCH projects/[projectId]/backend/storage/buckets/[bucket]"],
|
|
1613
|
+
ui: { kind: "built" },
|
|
1614
|
+
cli: { kind: "built", commands: ["naro storage bucket update"] },
|
|
1615
|
+
mcp: { kind: "built", tools: ["update_storage_bucket"] }
|
|
1616
|
+
},
|
|
1617
|
+
{
|
|
1618
|
+
id: "storage-bucket-remove",
|
|
1619
|
+
domain: "storage",
|
|
1620
|
+
title: "\uBC84\uD0B7 \uC0AD\uC81C",
|
|
1621
|
+
routes: ["DELETE projects/[projectId]/backend/storage/buckets/[bucket]"],
|
|
1622
|
+
ui: { kind: "built" },
|
|
1623
|
+
cli: { kind: "built", commands: ["naro storage bucket remove"] },
|
|
1624
|
+
mcp: { kind: "built", tools: ["delete_storage_bucket"] }
|
|
1625
|
+
},
|
|
1626
|
+
{
|
|
1627
|
+
id: "storage-bucket-empty",
|
|
1628
|
+
domain: "storage",
|
|
1629
|
+
title: "\uBC84\uD0B7 \uBE44\uC6B0\uAE30",
|
|
1630
|
+
routes: [
|
|
1631
|
+
"POST projects/[projectId]/backend/storage/buckets/[bucket]/empty"
|
|
1632
|
+
],
|
|
1633
|
+
ui: { kind: "built" },
|
|
1634
|
+
cli: { kind: "built", commands: ["naro storage bucket empty"] },
|
|
1635
|
+
mcp: { kind: "built", tools: ["empty_storage_bucket"] }
|
|
1636
|
+
},
|
|
1637
|
+
{
|
|
1638
|
+
id: "storage-object-list",
|
|
1639
|
+
domain: "storage",
|
|
1640
|
+
title: "\uAC1D\uCCB4 \uBAA9\uB85D",
|
|
1641
|
+
routes: [
|
|
1642
|
+
"POST projects/[projectId]/backend/storage/buckets/[bucket]/objects/list"
|
|
1643
|
+
],
|
|
1644
|
+
ui: { kind: "built" },
|
|
1645
|
+
cli: { kind: "built", commands: ["naro storage ls"] },
|
|
1646
|
+
mcp: { kind: "built", tools: ["list_storage_objects"] }
|
|
1647
|
+
},
|
|
1648
|
+
{
|
|
1649
|
+
id: "storage-object-remove",
|
|
1650
|
+
domain: "storage",
|
|
1651
|
+
title: "\uAC1D\uCCB4 \uC0AD\uC81C",
|
|
1652
|
+
routes: [
|
|
1653
|
+
"DELETE projects/[projectId]/backend/storage/buckets/[bucket]/objects"
|
|
1654
|
+
],
|
|
1655
|
+
ui: { kind: "built" },
|
|
1656
|
+
cli: { kind: "built", commands: ["naro storage rm"] },
|
|
1657
|
+
mcp: { kind: "built", tools: ["delete_storage_objects"] }
|
|
1658
|
+
},
|
|
1659
|
+
{
|
|
1660
|
+
id: "storage-object-sign",
|
|
1661
|
+
domain: "storage",
|
|
1662
|
+
title: "\uB2E4\uC6B4\uB85C\uB4DC \uC11C\uBA85 URL",
|
|
1663
|
+
routes: [
|
|
1664
|
+
"POST projects/[projectId]/backend/storage/buckets/[bucket]/objects/sign"
|
|
1665
|
+
],
|
|
1666
|
+
ui: { kind: "built" },
|
|
1667
|
+
cli: { kind: "built", commands: ["naro storage sign"] },
|
|
1668
|
+
mcp: { kind: "built", tools: ["create_storage_signed_url"] }
|
|
1669
|
+
},
|
|
1670
|
+
{
|
|
1671
|
+
id: "storage-object-upload",
|
|
1672
|
+
domain: "storage",
|
|
1673
|
+
title: "\uC5C5\uB85C\uB4DC URL \uBC1C\uAE09",
|
|
1674
|
+
routes: [
|
|
1675
|
+
"POST projects/[projectId]/backend/storage/buckets/[bucket]/objects/upload-url"
|
|
1676
|
+
],
|
|
1677
|
+
ui: { kind: "built" },
|
|
1678
|
+
cli: { kind: "built", commands: ["naro storage cp"] },
|
|
1679
|
+
mcp: { kind: "built", tools: ["create_storage_upload_url"] }
|
|
1680
|
+
},
|
|
1681
|
+
{
|
|
1682
|
+
id: "storage-object-move",
|
|
1683
|
+
domain: "storage",
|
|
1684
|
+
title: "\uAC1D\uCCB4 \uC774\uB3D9",
|
|
1685
|
+
routes: [
|
|
1686
|
+
"POST projects/[projectId]/backend/storage/buckets/[bucket]/objects/move"
|
|
1687
|
+
],
|
|
1688
|
+
ui: { kind: "built" },
|
|
1689
|
+
cli: { kind: "built", commands: ["naro storage mv"] },
|
|
1690
|
+
mcp: { kind: "built", tools: ["move_storage_object"] }
|
|
1691
|
+
},
|
|
1692
|
+
{
|
|
1693
|
+
id: "realtime-info",
|
|
1694
|
+
domain: "realtime",
|
|
1695
|
+
title: "Realtime \uC0C1\uD0DC\xB7\uC5F0\uACB0 \uC218",
|
|
1696
|
+
routes: ["GET projects/[projectId]/backend/realtime"],
|
|
1697
|
+
ui: { kind: "built" },
|
|
1698
|
+
cli: { kind: "built", commands: ["naro realtime"] },
|
|
1699
|
+
mcp: { kind: "built", tools: ["get_realtime"] }
|
|
1700
|
+
},
|
|
1701
|
+
{
|
|
1702
|
+
id: "realtime-enable",
|
|
1703
|
+
domain: "realtime",
|
|
1704
|
+
title: "Realtime \uCF1C\uAE30",
|
|
1705
|
+
routes: ["POST projects/[projectId]/backend/realtime"],
|
|
1706
|
+
ui: { kind: "built" },
|
|
1707
|
+
cli: { kind: "built", commands: ["naro realtime enable"] },
|
|
1708
|
+
mcp: { kind: "built", tools: ["enable_realtime"] }
|
|
1709
|
+
},
|
|
1710
|
+
{
|
|
1711
|
+
id: "realtime-table-list",
|
|
1712
|
+
domain: "realtime",
|
|
1713
|
+
title: "\uACF5\uAC1C \uD14C\uC774\uBE14 \uBAA9\uB85D",
|
|
1714
|
+
routes: ["GET projects/[projectId]/backend/realtime/tables"],
|
|
1715
|
+
ui: { kind: "built" },
|
|
1716
|
+
cli: { kind: "built", commands: ["naro realtime tables"] },
|
|
1717
|
+
// get_realtime이 공개 테이블을 상태와 함께 돌려준다.
|
|
1718
|
+
mcp: { kind: "built" }
|
|
1719
|
+
},
|
|
1720
|
+
{
|
|
1721
|
+
id: "realtime-table-add",
|
|
1722
|
+
domain: "realtime",
|
|
1723
|
+
title: "\uD14C\uC774\uBE14 \uBCC0\uACBD \uACF5\uAC1C",
|
|
1724
|
+
routes: ["PUT projects/[projectId]/backend/realtime/tables/[table]"],
|
|
1725
|
+
ui: { kind: "built" },
|
|
1726
|
+
cli: { kind: "built", commands: ["naro realtime tables add"] },
|
|
1727
|
+
mcp: { kind: "built", tools: ["publish_realtime_table"] }
|
|
1728
|
+
},
|
|
1729
|
+
{
|
|
1730
|
+
id: "realtime-table-remove",
|
|
1731
|
+
domain: "realtime",
|
|
1732
|
+
title: "\uD14C\uC774\uBE14 \uBCC0\uACBD \uACF5\uAC1C \uC911\uC9C0",
|
|
1733
|
+
routes: ["DELETE projects/[projectId]/backend/realtime/tables/[table]"],
|
|
1734
|
+
ui: { kind: "built" },
|
|
1735
|
+
cli: { kind: "built", commands: ["naro realtime tables remove"] },
|
|
1736
|
+
mcp: { kind: "built", tools: ["unpublish_realtime_table"] }
|
|
1737
|
+
},
|
|
1738
|
+
{
|
|
1739
|
+
// 대시보드 Functions 화면은 2026-11-04에 생겼다. 그 전의 built는 틀렸다.
|
|
1740
|
+
id: "function-list",
|
|
1741
|
+
domain: "functions",
|
|
1742
|
+
title: "\uD568\uC218 \uBAA9\uB85D",
|
|
1743
|
+
routes: ["GET projects/[projectId]/backend/functions"],
|
|
1744
|
+
ui: { kind: "built" },
|
|
1745
|
+
cli: { kind: "built", commands: ["naro functions"] },
|
|
1746
|
+
mcp: { kind: "built", tools: ["list_functions"] }
|
|
1747
|
+
},
|
|
1748
|
+
{
|
|
1749
|
+
id: "function-scaffold",
|
|
1750
|
+
domain: "functions",
|
|
1751
|
+
title: "\uD568\uC218 \uBF08\uB300 \uB9CC\uB4E4\uAE30",
|
|
1752
|
+
ui: {
|
|
1753
|
+
kind: "excluded",
|
|
1754
|
+
reason: "local-filesystem",
|
|
1755
|
+
note: "naro/functions/<name>/index.ts\uB97C \uC4F4\uB2E4. \uC11C\uBC84\uAC00 \uD560 \uC218 \uC5C6\uB2E4."
|
|
1756
|
+
},
|
|
1757
|
+
cli: { kind: "built", commands: ["naro functions new"] },
|
|
1758
|
+
mcp: {
|
|
1759
|
+
kind: "excluded",
|
|
1760
|
+
reason: "agent-native",
|
|
1761
|
+
note: "naro/functions/<name>/index.ts\uB97C \uC4F4\uB2E4. 2026-11-03 \uACB0\uC815."
|
|
1762
|
+
}
|
|
1763
|
+
},
|
|
1764
|
+
{
|
|
1765
|
+
id: "function-get",
|
|
1766
|
+
domain: "functions",
|
|
1767
|
+
title: "\uD568\uC218 \uC0C1\uC138",
|
|
1768
|
+
routes: ["GET projects/[projectId]/backend/functions/[name]"],
|
|
1769
|
+
ui: { kind: "built" },
|
|
1770
|
+
cli: { kind: "built", commands: ["naro functions versions"] },
|
|
1771
|
+
mcp: { kind: "built", tools: ["get_function"] }
|
|
1772
|
+
},
|
|
1773
|
+
{
|
|
1774
|
+
id: "function-update",
|
|
1775
|
+
domain: "functions",
|
|
1776
|
+
title: "\uD568\uC218 verify_jwt \uC124\uC815",
|
|
1777
|
+
routes: ["PATCH projects/[projectId]/backend/functions/[name]"],
|
|
1778
|
+
ui: { kind: "built" },
|
|
1779
|
+
cli: { kind: "built", commands: ["naro functions update"] },
|
|
1780
|
+
mcp: { kind: "built", tools: ["update_function"] }
|
|
1781
|
+
},
|
|
1782
|
+
{
|
|
1783
|
+
id: "function-delete",
|
|
1784
|
+
domain: "functions",
|
|
1785
|
+
title: "\uD568\uC218 \uC0AD\uC81C",
|
|
1786
|
+
routes: ["DELETE projects/[projectId]/backend/functions/[name]"],
|
|
1787
|
+
ui: { kind: "built" },
|
|
1788
|
+
cli: { kind: "built", commands: ["naro functions delete"] },
|
|
1789
|
+
mcp: { kind: "built", tools: ["delete_function"] }
|
|
1790
|
+
},
|
|
1791
|
+
{
|
|
1792
|
+
id: "function-version-upload",
|
|
1793
|
+
domain: "functions",
|
|
1794
|
+
title: "\uBC88\uB4E4\uD55C \uCF54\uB4DC\uB97C \uC0C8 \uBC84\uC804\uC73C\uB85C \uC62C\uB9AC\uAE30",
|
|
1795
|
+
routes: ["POST projects/[projectId]/backend/functions/[name]/versions"],
|
|
1796
|
+
ui: {
|
|
1797
|
+
kind: "excluded",
|
|
1798
|
+
reason: "local-filesystem",
|
|
1799
|
+
note: "\uB85C\uCEEC\uC5D0\uC11C \uBC88\uB4E4\uD558\uACE0 workerd\uB85C \uBD80\uD305 \uD655\uC778\uD55C \uCF54\uB4DC\uB97C \uC62C\uB9B0\uB2E4. \uBE0C\uB77C\uC6B0\uC800\uC5D0\uB294 \uBC88\uB4E4\uD560 \uC18C\uC2A4\uAC00 \uC5C6\uB2E4."
|
|
1800
|
+
},
|
|
1801
|
+
cli: { kind: "built", commands: ["naro functions deploy"] },
|
|
1802
|
+
mcp: { kind: "built", tools: ["deploy_function"] }
|
|
1803
|
+
},
|
|
1804
|
+
{
|
|
1805
|
+
id: "function-version-deploy",
|
|
1806
|
+
domain: "functions",
|
|
1807
|
+
title: "\uC800\uC7A5\uB41C \uBC84\uC804 \uBC30\uD3EC",
|
|
1808
|
+
routes: [
|
|
1809
|
+
"POST projects/[projectId]/backend/functions/[name]/versions/[versionId]/deploy"
|
|
1810
|
+
],
|
|
1811
|
+
ui: { kind: "built" },
|
|
1812
|
+
// naro functions deploy가 올린 버전을 배포한다(client.functions.deploy).
|
|
1813
|
+
cli: { kind: "built" },
|
|
1814
|
+
// deploy_function이 naro-cli의 deployFunctions로 올린 버전을 배포한다.
|
|
1815
|
+
mcp: { kind: "built" }
|
|
1816
|
+
},
|
|
1817
|
+
{
|
|
1818
|
+
id: "function-rollback",
|
|
1819
|
+
domain: "functions",
|
|
1820
|
+
title: "\uC774\uC804 \uBC84\uC804\uC73C\uB85C \uB864\uBC31",
|
|
1821
|
+
routes: ["POST projects/[projectId]/backend/functions/[name]/rollback"],
|
|
1822
|
+
ui: { kind: "built" },
|
|
1823
|
+
cli: { kind: "built", commands: ["naro functions rollback"] },
|
|
1824
|
+
mcp: { kind: "built", tools: ["rollback_function"] }
|
|
1825
|
+
},
|
|
1826
|
+
{
|
|
1827
|
+
id: "function-logs",
|
|
1828
|
+
domain: "functions",
|
|
1829
|
+
title: "\uD568\uC218 \uB85C\uADF8",
|
|
1830
|
+
routes: ["GET projects/[projectId]/backend/functions/[name]/logs"],
|
|
1831
|
+
ui: { kind: "built" },
|
|
1832
|
+
cli: { kind: "built", commands: ["naro functions logs"] },
|
|
1833
|
+
mcp: { kind: "built", tools: ["get_function_logs"] }
|
|
1834
|
+
},
|
|
1835
|
+
{
|
|
1836
|
+
id: "function-invoke",
|
|
1837
|
+
domain: "functions",
|
|
1838
|
+
title: "\uD568\uC218 \uD638\uCD9C",
|
|
1839
|
+
routes: ["POST projects/[projectId]/backend/functions/[name]/invoke"],
|
|
1840
|
+
ui: { kind: "built" },
|
|
1841
|
+
cli: { kind: "built", commands: ["naro functions invoke"] },
|
|
1842
|
+
mcp: { kind: "built", tools: ["invoke_function"] }
|
|
1843
|
+
},
|
|
1844
|
+
{
|
|
1845
|
+
id: "function-secret-list",
|
|
1846
|
+
domain: "functions",
|
|
1847
|
+
title: "\uD568\uC218 \uC2DC\uD06C\uB9BF \uBAA9\uB85D",
|
|
1848
|
+
routes: ["GET projects/[projectId]/backend/functions-secrets"],
|
|
1849
|
+
ui: { kind: "built" },
|
|
1850
|
+
cli: { kind: "built", commands: ["naro functions secrets"] },
|
|
1851
|
+
mcp: { kind: "built", tools: ["list_function_secrets"] }
|
|
1852
|
+
},
|
|
1853
|
+
{
|
|
1854
|
+
id: "function-secret-set",
|
|
1855
|
+
domain: "functions",
|
|
1856
|
+
title: "\uD568\uC218 \uC2DC\uD06C\uB9BF \uC124\uC815",
|
|
1857
|
+
routes: ["PUT projects/[projectId]/backend/functions-secrets"],
|
|
1858
|
+
dashboard: "/[teamSlug]/projects/[projectSlug]/functions/secrets",
|
|
1859
|
+
ui: { kind: "built" },
|
|
1860
|
+
cli: {
|
|
1861
|
+
kind: "built",
|
|
1862
|
+
commands: ["naro functions secrets set", "naro functions secrets import"]
|
|
1863
|
+
},
|
|
1864
|
+
mcp: {
|
|
1865
|
+
kind: "excluded",
|
|
1866
|
+
reason: "secret-value",
|
|
1867
|
+
note: "apps/mcp/src/function-tools.ts\uC758 NO_SECRET_VALUES \u2014 \uAC12\uC774 \uB300\uD654\uC5D0 \uB0A8\uB294\uB2E4. \uC0AC\uC6A9\uC790\uAC00 naro functions secrets set\uC744 \uB3CC\uB9AC\uAC8C \uD55C\uB2E4."
|
|
1868
|
+
}
|
|
1869
|
+
},
|
|
1870
|
+
// 라우트는 function-secret-set과 같은 PUT functions-secrets다. 한 라우트는
|
|
1871
|
+
// 한 기능에만 걸리므로 여기에는 적지 않는다.
|
|
1872
|
+
{
|
|
1873
|
+
id: "function-secret-unset",
|
|
1874
|
+
domain: "functions",
|
|
1875
|
+
title: "\uD568\uC218 \uC2DC\uD06C\uB9BF \uD574\uC81C",
|
|
1876
|
+
ui: { kind: "built" },
|
|
1877
|
+
cli: { kind: "built", commands: ["naro functions secrets unset"] },
|
|
1878
|
+
mcp: { kind: "built", tools: ["unset_function_secret"] }
|
|
1879
|
+
},
|
|
1880
|
+
{
|
|
1881
|
+
id: "function-sync",
|
|
1882
|
+
domain: "functions",
|
|
1883
|
+
title: "\uD568\uC218 \uC7AC\uB3D9\uAE30\uD654",
|
|
1884
|
+
routes: ["POST projects/[projectId]/backend/functions-sync"],
|
|
1885
|
+
ui: { kind: "built" },
|
|
1886
|
+
cli: { kind: "built", commands: ["naro functions secrets sync"] },
|
|
1887
|
+
mcp: { kind: "built", tools: ["sync_functions"] }
|
|
1888
|
+
},
|
|
1889
|
+
{
|
|
1890
|
+
id: "backend-info",
|
|
1891
|
+
domain: "backend",
|
|
1892
|
+
title: "Backend \uC0C1\uD0DC\xB7URL\xB7anon \uD0A4",
|
|
1893
|
+
routes: ["GET projects/[projectId]/backend"],
|
|
1894
|
+
ui: { kind: "built" },
|
|
1895
|
+
cli: { kind: "built", commands: ["naro backend"] },
|
|
1896
|
+
mcp: { kind: "built", tools: ["get_backend"] }
|
|
1897
|
+
},
|
|
1898
|
+
{
|
|
1899
|
+
id: "backend-enable",
|
|
1900
|
+
domain: "backend",
|
|
1901
|
+
title: "Backend \uCF1C\uAE30",
|
|
1902
|
+
routes: ["POST projects/[projectId]/backend/enable"],
|
|
1903
|
+
ui: { kind: "built" },
|
|
1904
|
+
cli: { kind: "built", commands: ["naro backend enable"] },
|
|
1905
|
+
mcp: { kind: "built", tools: ["enable_backend"] }
|
|
1906
|
+
},
|
|
1907
|
+
{
|
|
1908
|
+
id: "backend-provision",
|
|
1909
|
+
domain: "backend",
|
|
1910
|
+
title: "Backend \uD504\uB85C\uBE44\uC800\uB2DD \uC774\uC5B4\uAC00\uAE30",
|
|
1911
|
+
routes: ["POST projects/[projectId]/backend/provision"],
|
|
1912
|
+
ui: { kind: "built" },
|
|
1913
|
+
// naro backend enable이 멈춘 프로비저닝을 이어 간다.
|
|
1914
|
+
cli: { kind: "built" },
|
|
1915
|
+
// enable_backend가 같은 호출이다(client.backend.enable — 라우트 provision은 그 옛 이름).
|
|
1916
|
+
mcp: { kind: "built" }
|
|
1917
|
+
},
|
|
1918
|
+
{
|
|
1919
|
+
id: "backend-disable",
|
|
1920
|
+
domain: "backend",
|
|
1921
|
+
title: "Backend \uB044\uAE30",
|
|
1922
|
+
routes: ["POST projects/[projectId]/backend/disable"],
|
|
1923
|
+
ui: { kind: "built" },
|
|
1924
|
+
cli: { kind: "built", commands: ["naro backend disable"] },
|
|
1925
|
+
mcp: { kind: "built", tools: ["disable_backend"] }
|
|
1926
|
+
},
|
|
1927
|
+
{
|
|
1928
|
+
id: "backend-keys",
|
|
1929
|
+
domain: "backend",
|
|
1930
|
+
title: "API \uD0A4 \uC870\uD68C(service \uD0A4 \uD3EC\uD568)",
|
|
1931
|
+
routes: ["GET projects/[projectId]/backend/keys"],
|
|
1932
|
+
dashboard: "/[teamSlug]/projects/[projectSlug]/settings",
|
|
1933
|
+
ui: { kind: "built" },
|
|
1934
|
+
cli: { kind: "built", commands: ["naro backend keys"] },
|
|
1935
|
+
mcp: {
|
|
1936
|
+
kind: "excluded",
|
|
1937
|
+
reason: "secret-value",
|
|
1938
|
+
note: "service \uD0A4\uAC00 \uB300\uD654\uC5D0 \uB0A8\uB294\uB2E4. 2026-11-03 \uACB0\uC815(\uAD8C\uACE0\uB300\uB85C)."
|
|
1939
|
+
}
|
|
1940
|
+
},
|
|
1941
|
+
{
|
|
1942
|
+
id: "backend-keys-rotate",
|
|
1943
|
+
domain: "backend",
|
|
1944
|
+
title: "API \uD0A4 \uAD50\uCCB4",
|
|
1945
|
+
routes: ["POST projects/[projectId]/backend/keys/rotate"],
|
|
1946
|
+
// 2026-11-04 전에는 화면이 없었는데 built로 적혀 있었다.
|
|
1947
|
+
dashboard: "/[teamSlug]/projects/[projectSlug]/settings",
|
|
1948
|
+
ui: { kind: "built" },
|
|
1949
|
+
cli: { kind: "built", commands: ["naro backend keys rotate"] },
|
|
1950
|
+
mcp: {
|
|
1951
|
+
kind: "excluded",
|
|
1952
|
+
reason: "irreversible",
|
|
1953
|
+
note: "\uC61B \uD0A4\uAC00 \uBC14\uB85C \uC8FD\uB294\uB2E4. 2026-11-03 \uACB0\uC815(\uAD8C\uACE0\uB300\uB85C)."
|
|
1954
|
+
}
|
|
1955
|
+
},
|
|
1956
|
+
{
|
|
1957
|
+
id: "backend-signing-key-rotate",
|
|
1958
|
+
domain: "backend",
|
|
1959
|
+
title: "\uC11C\uBA85 \uD0A4 \uAD50\uCCB4",
|
|
1960
|
+
routes: ["POST projects/[projectId]/backend/signing-key/rotate"],
|
|
1961
|
+
dashboard: "/[teamSlug]/projects/[projectSlug]/settings",
|
|
1962
|
+
ui: { kind: "built" },
|
|
1963
|
+
cli: { kind: "built", commands: ["naro backend signing-key rotate"] },
|
|
1964
|
+
mcp: {
|
|
1965
|
+
kind: "excluded",
|
|
1966
|
+
reason: "irreversible",
|
|
1967
|
+
note: "\uBC1C\uAE09\uD55C \uD1A0\uD070\uC774 15\uBD84 \uC548\uC5D0 \uBAA8\uB450 \uC8FD\uB294\uB2E4. 2026-11-03 \uACB0\uC815(\uAD8C\uACE0\uB300\uB85C)."
|
|
1968
|
+
}
|
|
1969
|
+
},
|
|
1970
|
+
{
|
|
1971
|
+
id: "backend-auth-get",
|
|
1972
|
+
domain: "backend",
|
|
1973
|
+
title: "\uB85C\uADF8\uC778 \uC124\uC815 \uC870\uD68C",
|
|
1974
|
+
routes: ["GET projects/[projectId]/backend/auth"],
|
|
1975
|
+
ui: { kind: "built" },
|
|
1976
|
+
cli: {
|
|
1977
|
+
kind: "built",
|
|
1978
|
+
commands: ["naro backend auth", "naro backend auth redirects"]
|
|
1979
|
+
},
|
|
1980
|
+
mcp: { kind: "built", tools: ["get_backend_auth"] }
|
|
1981
|
+
},
|
|
1982
|
+
{
|
|
1983
|
+
id: "backend-auth-update",
|
|
1984
|
+
domain: "backend",
|
|
1985
|
+
title: "\uB85C\uADF8\uC778 \uC124\uC815 \uBCC0\uACBD",
|
|
1986
|
+
routes: ["PUT projects/[projectId]/backend/auth"],
|
|
1987
|
+
ui: { kind: "built" },
|
|
1988
|
+
cli: {
|
|
1989
|
+
kind: "built",
|
|
1990
|
+
commands: [
|
|
1991
|
+
"naro backend auth signups",
|
|
1992
|
+
"naro backend auth password",
|
|
1993
|
+
"naro backend auth email set",
|
|
1994
|
+
"naro backend auth oauth set",
|
|
1995
|
+
"naro backend auth redirects add",
|
|
1996
|
+
"naro backend auth redirects remove",
|
|
1997
|
+
"naro backend auth require-verification"
|
|
1998
|
+
]
|
|
1999
|
+
},
|
|
2000
|
+
// 리다이렉트 제거·가입·확인 메일·비밀번호 길이만. 메일 API 키와
|
|
2001
|
+
// OAuth client secret은 대화에 남고(secret-value), 리다이렉트 추가는 재설정 토큰이
|
|
2002
|
+
// 그 origin으로 가므로(PR #434 리뷰) 대시보드와 CLI만 한다.
|
|
2003
|
+
mcp: { kind: "built", tools: ["update_backend_auth"] }
|
|
2004
|
+
},
|
|
2005
|
+
{
|
|
2006
|
+
id: "backend-auth-remove",
|
|
2007
|
+
domain: "backend",
|
|
2008
|
+
title: "\uB85C\uADF8\uC778 \uACF5\uAE09\uC790\xB7\uBA54\uC77C \uC124\uC815 \uC81C\uAC70",
|
|
2009
|
+
routes: ["DELETE projects/[projectId]/backend/auth"],
|
|
2010
|
+
ui: { kind: "built" },
|
|
2011
|
+
cli: {
|
|
2012
|
+
kind: "built",
|
|
2013
|
+
commands: [
|
|
2014
|
+
"naro backend auth email remove",
|
|
2015
|
+
"naro backend auth oauth remove"
|
|
2016
|
+
]
|
|
2017
|
+
},
|
|
2018
|
+
mcp: { kind: "built", tools: ["remove_backend_auth"] }
|
|
2019
|
+
},
|
|
2020
|
+
{
|
|
2021
|
+
id: "backend-user-list",
|
|
2022
|
+
domain: "backend",
|
|
2023
|
+
title: "\uC720\uC800 \uBAA9\uB85D",
|
|
2024
|
+
routes: ["GET projects/[projectId]/backend/users"],
|
|
2025
|
+
ui: { kind: "built" },
|
|
2026
|
+
cli: { kind: "built", commands: ["naro backend users"] },
|
|
2027
|
+
mcp: { kind: "built", tools: ["list_backend_users"] }
|
|
2028
|
+
},
|
|
2029
|
+
{
|
|
2030
|
+
id: "backend-user-create",
|
|
2031
|
+
domain: "backend",
|
|
2032
|
+
title: "\uC720\uC800 \uB9CC\uB4E4\uAE30",
|
|
2033
|
+
routes: ["POST projects/[projectId]/backend/users"],
|
|
2034
|
+
dashboard: "/[teamSlug]/projects/[projectSlug]/auth",
|
|
2035
|
+
ui: { kind: "built" },
|
|
2036
|
+
cli: { kind: "built", commands: ["naro backend users create"] },
|
|
2037
|
+
mcp: {
|
|
2038
|
+
kind: "excluded",
|
|
2039
|
+
reason: "secret-value",
|
|
2040
|
+
note: "\uBE44\uBC00\uBC88\uD638\uAC00 \uB300\uD654\uC5D0 \uB0A8\uB294\uB2E4. 2026-11-03 \uACB0\uC815(\uAD8C\uACE0\uB300\uB85C)."
|
|
2041
|
+
}
|
|
2042
|
+
},
|
|
2043
|
+
{
|
|
2044
|
+
id: "backend-user-delete",
|
|
2045
|
+
domain: "backend",
|
|
2046
|
+
title: "\uC720\uC800 \uC0AD\uC81C",
|
|
2047
|
+
routes: ["DELETE projects/[projectId]/backend/users/[userId]"],
|
|
2048
|
+
dashboard: "/[teamSlug]/projects/[projectSlug]/auth",
|
|
2049
|
+
ui: { kind: "built" },
|
|
2050
|
+
cli: { kind: "built", commands: ["naro backend users delete"] },
|
|
2051
|
+
mcp: {
|
|
2052
|
+
kind: "excluded",
|
|
2053
|
+
reason: "irreversible",
|
|
2054
|
+
note: "\uC720\uC800\uC640 \uC138\uC158\uC774 \uC0AC\uB77C\uC9C4\uB2E4. 2026-11-03 \uACB0\uC815(\uAD8C\uACE0\uB300\uB85C)."
|
|
2055
|
+
}
|
|
2056
|
+
},
|
|
2057
|
+
{
|
|
2058
|
+
id: "logs-runtime",
|
|
2059
|
+
domain: "logs",
|
|
2060
|
+
title: "\uB7F0\uD0C0\uC784 \uB85C\uADF8",
|
|
2061
|
+
routes: ["GET projects/[projectId]/logs"],
|
|
2062
|
+
ui: { kind: "built" },
|
|
2063
|
+
cli: { kind: "built", commands: ["naro logs"] },
|
|
2064
|
+
mcp: { kind: "built", tools: ["get_runtime_logs"] }
|
|
2065
|
+
},
|
|
2066
|
+
{
|
|
2067
|
+
id: "analytics",
|
|
2068
|
+
domain: "measurement",
|
|
2069
|
+
title: "Web Analytics",
|
|
2070
|
+
routes: ["GET projects/[projectId]/analytics"],
|
|
2071
|
+
ui: { kind: "built" },
|
|
2072
|
+
cli: { kind: "built", commands: ["naro analytics"] },
|
|
2073
|
+
mcp: { kind: "built", tools: ["get_analytics"] }
|
|
2074
|
+
},
|
|
2075
|
+
{
|
|
2076
|
+
id: "insights",
|
|
2077
|
+
domain: "measurement",
|
|
2078
|
+
title: "Speed Insights",
|
|
2079
|
+
routes: ["GET projects/[projectId]/speed-insights"],
|
|
2080
|
+
ui: { kind: "built" },
|
|
2081
|
+
cli: { kind: "built", commands: ["naro insights"] },
|
|
2082
|
+
mcp: { kind: "built", tools: ["get_speed_insights"] }
|
|
2083
|
+
},
|
|
2084
|
+
{
|
|
2085
|
+
id: "insights-toggle",
|
|
2086
|
+
domain: "measurement",
|
|
2087
|
+
title: "Speed Insights \uCE21\uC815 \uCF1C\uAE30\xB7\uB044\uAE30",
|
|
2088
|
+
routes: ["PUT projects/[projectId]/speed-insights"],
|
|
2089
|
+
ui: { kind: "built" },
|
|
2090
|
+
cli: {
|
|
2091
|
+
kind: "built",
|
|
2092
|
+
commands: ["naro insights enable", "naro insights disable"]
|
|
2093
|
+
},
|
|
2094
|
+
mcp: { kind: "built", tools: ["set_speed_insights"] }
|
|
2095
|
+
},
|
|
2096
|
+
{
|
|
2097
|
+
id: "insights-deployments",
|
|
2098
|
+
domain: "measurement",
|
|
2099
|
+
title: "Speed Insights \uBC30\uD3EC\uBCC4 \uBE44\uAD50",
|
|
2100
|
+
routes: ["GET projects/[projectId]/speed-insights/deployments"],
|
|
2101
|
+
ui: { kind: "built" },
|
|
2102
|
+
// naro insights가 배포별 표를 같이 읽는다(client.insights.overview).
|
|
2103
|
+
cli: { kind: "built" },
|
|
2104
|
+
// get_speed_insights가 route 없이 배포별 표를 같이 돌려준다(client.insights.overview).
|
|
2105
|
+
mcp: { kind: "built" }
|
|
2106
|
+
},
|
|
2107
|
+
{
|
|
2108
|
+
id: "insights-paths",
|
|
2109
|
+
domain: "measurement",
|
|
2110
|
+
title: "Speed Insights \uB77C\uC6B0\uD2B8\uBCC4 \uACBD\uB85C",
|
|
2111
|
+
routes: ["GET projects/[projectId]/speed-insights/paths"],
|
|
2112
|
+
ui: { kind: "built" },
|
|
2113
|
+
// naro insights --route가 읽는다(client.insights.paths).
|
|
2114
|
+
cli: { kind: "built" },
|
|
2115
|
+
// get_speed_insights에 route를 주면 경로를 돌려준다(client.insights.paths).
|
|
2116
|
+
mcp: { kind: "built" }
|
|
2117
|
+
},
|
|
2118
|
+
{
|
|
2119
|
+
id: "observability",
|
|
2120
|
+
domain: "measurement",
|
|
2121
|
+
title: "Observability",
|
|
2122
|
+
routes: ["GET projects/[projectId]/observability"],
|
|
2123
|
+
ui: { kind: "built" },
|
|
2124
|
+
cli: { kind: "built", commands: ["naro observability"] },
|
|
2125
|
+
mcp: { kind: "built", tools: ["get_observability"] }
|
|
2126
|
+
},
|
|
2127
|
+
{
|
|
2128
|
+
id: "firewall-list",
|
|
2129
|
+
domain: "firewall",
|
|
2130
|
+
title: "\uBC29\uD654\uBCBD \uADDC\uCE59 \uBAA9\uB85D",
|
|
2131
|
+
routes: ["GET projects/[projectId]/firewall"],
|
|
2132
|
+
ui: { kind: "built" },
|
|
2133
|
+
cli: { kind: "built", commands: ["naro firewall"] },
|
|
2134
|
+
mcp: { kind: "built", tools: ["list_firewall_rules"] }
|
|
2135
|
+
},
|
|
2136
|
+
{
|
|
2137
|
+
id: "firewall-add",
|
|
2138
|
+
domain: "firewall",
|
|
2139
|
+
title: "\uBC29\uD654\uBCBD \uADDC\uCE59 \uCD94\uAC00",
|
|
2140
|
+
routes: ["POST projects/[projectId]/firewall"],
|
|
2141
|
+
ui: { kind: "built" },
|
|
2142
|
+
cli: { kind: "built", commands: ["naro firewall add"] },
|
|
2143
|
+
mcp: { kind: "built", tools: ["add_firewall_rule"] }
|
|
2144
|
+
},
|
|
2145
|
+
{
|
|
2146
|
+
id: "firewall-update",
|
|
2147
|
+
domain: "firewall",
|
|
2148
|
+
title: "\uBC29\uD654\uBCBD \uADDC\uCE59 \uC218\uC815",
|
|
2149
|
+
routes: ["PATCH projects/[projectId]/firewall/[ruleId]"],
|
|
2150
|
+
ui: { kind: "built" },
|
|
2151
|
+
cli: {
|
|
2152
|
+
kind: "built",
|
|
2153
|
+
commands: ["naro firewall enable", "naro firewall disable"]
|
|
2154
|
+
},
|
|
2155
|
+
mcp: { kind: "built", tools: ["set_firewall_rule_enabled"] }
|
|
2156
|
+
},
|
|
2157
|
+
{
|
|
2158
|
+
id: "firewall-remove",
|
|
2159
|
+
domain: "firewall",
|
|
2160
|
+
title: "\uBC29\uD654\uBCBD \uADDC\uCE59 \uC0AD\uC81C",
|
|
2161
|
+
routes: ["DELETE projects/[projectId]/firewall/[ruleId]"],
|
|
2162
|
+
ui: { kind: "built" },
|
|
2163
|
+
cli: { kind: "built", commands: ["naro firewall remove"] },
|
|
2164
|
+
mcp: { kind: "built", tools: ["remove_firewall_rule"] }
|
|
2165
|
+
},
|
|
2166
|
+
{
|
|
2167
|
+
id: "flag-list",
|
|
2168
|
+
domain: "flags",
|
|
2169
|
+
title: "\uAE30\uB2A5 \uD50C\uB798\uADF8 \uBAA9\uB85D",
|
|
2170
|
+
routes: ["GET projects/[projectId]/flags"],
|
|
2171
|
+
ui: { kind: "built" },
|
|
2172
|
+
cli: { kind: "built", commands: ["naro flags"] },
|
|
2173
|
+
mcp: { kind: "built", tools: ["list_flags"] }
|
|
2174
|
+
},
|
|
2175
|
+
{
|
|
2176
|
+
id: "flag-add",
|
|
2177
|
+
domain: "flags",
|
|
2178
|
+
title: "\uAE30\uB2A5 \uD50C\uB798\uADF8 \uCD94\uAC00",
|
|
2179
|
+
routes: ["POST projects/[projectId]/flags"],
|
|
2180
|
+
ui: { kind: "built" },
|
|
2181
|
+
cli: { kind: "built", commands: ["naro flags add"] },
|
|
2182
|
+
mcp: { kind: "built", tools: ["add_flag"] }
|
|
2183
|
+
},
|
|
2184
|
+
{
|
|
2185
|
+
id: "flag-update",
|
|
2186
|
+
domain: "flags",
|
|
2187
|
+
title: "\uAE30\uB2A5 \uD50C\uB798\uADF8 \uC218\uC815",
|
|
2188
|
+
routes: ["PATCH projects/[projectId]/flags/[flagId]"],
|
|
2189
|
+
ui: { kind: "built" },
|
|
2190
|
+
cli: { kind: "built", commands: ["naro flags on", "naro flags off"] },
|
|
2191
|
+
mcp: { kind: "built", tools: ["set_flag"] }
|
|
2192
|
+
},
|
|
2193
|
+
{
|
|
2194
|
+
id: "flag-remove",
|
|
2195
|
+
domain: "flags",
|
|
2196
|
+
title: "\uAE30\uB2A5 \uD50C\uB798\uADF8 \uC0AD\uC81C",
|
|
2197
|
+
routes: ["DELETE projects/[projectId]/flags/[flagId]"],
|
|
2198
|
+
ui: { kind: "built" },
|
|
2199
|
+
cli: { kind: "built", commands: ["naro flags remove"] },
|
|
2200
|
+
mcp: { kind: "built", tools: ["remove_flag"] }
|
|
2201
|
+
},
|
|
2202
|
+
{
|
|
2203
|
+
id: "dashboard-link",
|
|
2204
|
+
domain: "guidance",
|
|
2205
|
+
title: "CLI\xB7MCP\uB85C \uBABB \uD558\uB294 \uAE30\uB2A5\uC758 \uB300\uC2DC\uBCF4\uB4DC \uB9C1\uD06C",
|
|
2206
|
+
ui: {
|
|
2207
|
+
kind: "excluded",
|
|
2208
|
+
reason: "dashboard-itself",
|
|
2209
|
+
note: "\uC0AC\uC6A9\uC790\uAC00 \uC774\uBBF8 \uB300\uC2DC\uBCF4\uB4DC\uC5D0 \uC788\uB2E4."
|
|
2210
|
+
},
|
|
2211
|
+
cli: { kind: "built", commands: ["naro dashboard"] },
|
|
2212
|
+
mcp: { kind: "built", tools: ["dashboard_link"] }
|
|
2213
|
+
}
|
|
2214
|
+
];
|
|
2215
|
+
function dashboardNeeds(path) {
|
|
2216
|
+
return {
|
|
2217
|
+
team: path.includes("[teamSlug]"),
|
|
2218
|
+
project: path.includes("[projectSlug]")
|
|
2219
|
+
};
|
|
2220
|
+
}
|
|
2221
|
+
function dashboardUrl(baseUrl, path, slugs) {
|
|
2222
|
+
const filled2 = path.replace("[teamSlug]", () => {
|
|
2223
|
+
if (!slugs.teamSlug) throw new Error(`${path} needs a team slug`);
|
|
2224
|
+
return encodeURIComponent(slugs.teamSlug);
|
|
2225
|
+
}).replace("[projectSlug]", () => {
|
|
2226
|
+
if (!slugs.projectSlug) throw new Error(`${path} needs a project slug`);
|
|
2227
|
+
return encodeURIComponent(slugs.projectSlug);
|
|
2228
|
+
});
|
|
2229
|
+
return `${baseUrl.replace(/\/+$/, "")}${filled2}`;
|
|
2230
|
+
}
|
|
2231
|
+
|
|
320
2232
|
// ../../packages/core/src/deployment.ts
|
|
321
2233
|
var PHASES = [
|
|
322
2234
|
"QUEUED",
|
|
@@ -16369,10 +18281,13 @@ export default {
|
|
|
16369
18281
|
},
|
|
16370
18282
|
};
|
|
16371
18283
|
`;
|
|
16372
|
-
var
|
|
18284
|
+
var VINEXT_OUTPUT_DIR = "dist";
|
|
16373
18285
|
var SERVER_DIR = "server";
|
|
16374
18286
|
var CLIENT_DIR = "client";
|
|
16375
18287
|
var WRANGLER_OUTPUT_NAME = "wrangler.json";
|
|
18288
|
+
function vinextWranglerConfigPath(appRoot) {
|
|
18289
|
+
return join6(appRoot, VINEXT_OUTPUT_DIR, SERVER_DIR, WRANGLER_OUTPUT_NAME);
|
|
18290
|
+
}
|
|
16376
18291
|
async function exists3(path) {
|
|
16377
18292
|
try {
|
|
16378
18293
|
await access5(path);
|
|
@@ -16428,7 +18343,7 @@ async function createVinextBuildConfig(appRoot, deploymentId, writer = async (pa
|
|
|
16428
18343
|
compatibility_flags: ["nodejs_compat"],
|
|
16429
18344
|
main: `./${GENERATED_WORKER_ENTRY}`,
|
|
16430
18345
|
assets: {
|
|
16431
|
-
directory: `${
|
|
18346
|
+
directory: `${VINEXT_OUTPUT_DIR}/${CLIENT_DIR}`,
|
|
16432
18347
|
binding: "ASSETS"
|
|
16433
18348
|
}
|
|
16434
18349
|
},
|
|
@@ -16527,14 +18442,14 @@ function moduleMatchers(rules) {
|
|
|
16527
18442
|
}
|
|
16528
18443
|
async function readVinextArtifact(appRoot, identity) {
|
|
16529
18444
|
try {
|
|
16530
|
-
const outputRoot = resolve2(appRoot,
|
|
18445
|
+
const outputRoot = resolve2(appRoot, VINEXT_OUTPUT_DIR);
|
|
16531
18446
|
const serverRoot = join6(outputRoot, SERVER_DIR);
|
|
16532
18447
|
const clientRoot = join6(outputRoot, CLIENT_DIR);
|
|
16533
18448
|
const configPath = join6(serverRoot, WRANGLER_OUTPUT_NAME);
|
|
16534
18449
|
if (!await exists3(configPath)) {
|
|
16535
18450
|
throw new DeploymentError(
|
|
16536
18451
|
"ARTIFACT_INVALID",
|
|
16537
|
-
`vinext build produced no ${
|
|
18452
|
+
`vinext build produced no ${VINEXT_OUTPUT_DIR}/${SERVER_DIR}/${WRANGLER_OUTPUT_NAME}.`
|
|
16538
18453
|
);
|
|
16539
18454
|
}
|
|
16540
18455
|
const metadata = JSON.parse(
|
|
@@ -18606,13 +20521,8 @@ function createAwsMiddlewareCloudflareAppStrategy() {
|
|
|
18606
20521
|
}
|
|
18607
20522
|
|
|
18608
20523
|
// ../../packages/build/src/strategy/strategies/vinext-cloudflare.ts
|
|
18609
|
-
import { join as join16 } from "path";
|
|
18610
20524
|
var VINEXT_MIN_NEXT_MAJOR = 16;
|
|
18611
20525
|
var VINEXT_BUILD_SCRIPTS = ["esbuild", "workerd"];
|
|
18612
|
-
var VINEXT_OUTPUT = {
|
|
18613
|
-
outputRoot: "dist",
|
|
18614
|
-
bundleDir: "dist/.naro-bundle"
|
|
18615
|
-
};
|
|
18616
20526
|
async function runCheck(context, observer) {
|
|
18617
20527
|
if (!context.toolchain.vinext) return null;
|
|
18618
20528
|
const held = [];
|
|
@@ -18762,13 +20672,8 @@ function createVinextCloudflareStrategy(options) {
|
|
|
18762
20672
|
context,
|
|
18763
20673
|
{
|
|
18764
20674
|
appRoot: fork.appRoot,
|
|
18765
|
-
wranglerConfigPath:
|
|
18766
|
-
|
|
18767
|
-
"dist",
|
|
18768
|
-
"server",
|
|
18769
|
-
"wrangler.json"
|
|
18770
|
-
),
|
|
18771
|
-
...VINEXT_OUTPUT
|
|
20675
|
+
wranglerConfigPath: vinextWranglerConfigPath(fork.appRoot),
|
|
20676
|
+
outputRoot: VINEXT_OUTPUT_DIR
|
|
18772
20677
|
},
|
|
18773
20678
|
observer
|
|
18774
20679
|
);
|
|
@@ -18787,7 +20692,7 @@ function createVinextCloudflareStrategy(options) {
|
|
|
18787
20692
|
// ../../packages/build/src/strategy/workspace.ts
|
|
18788
20693
|
import { execFile } from "child_process";
|
|
18789
20694
|
import { cp, mkdir as mkdir2, readdir as readdir4, rm as rm2 } from "fs/promises";
|
|
18790
|
-
import { basename as basename2, dirname as dirname3, join as
|
|
20695
|
+
import { basename as basename2, dirname as dirname3, join as join16, relative as relative5, resolve as resolve6 } from "path";
|
|
18791
20696
|
import { promisify } from "util";
|
|
18792
20697
|
var execFileAsync = promisify(execFile);
|
|
18793
20698
|
var SKIPPED_ANYWHERE = /* @__PURE__ */ new Set(["node_modules"]);
|
|
@@ -18810,14 +20715,14 @@ async function copyInstalledPackages(source, target2) {
|
|
|
18810
20715
|
const walk2 = async (dir) => {
|
|
18811
20716
|
for (const entry of await readdir4(dir, { withFileTypes: true })) {
|
|
18812
20717
|
if (!entry.isDirectory() || entry.name === ".git") continue;
|
|
18813
|
-
const path =
|
|
20718
|
+
const path = join16(dir, entry.name);
|
|
18814
20719
|
if (entry.name === "node_modules") installs.push(path);
|
|
18815
20720
|
else await walk2(path);
|
|
18816
20721
|
}
|
|
18817
20722
|
};
|
|
18818
20723
|
await walk2(origin);
|
|
18819
20724
|
for (const install of installs)
|
|
18820
|
-
await copyTree(install,
|
|
20725
|
+
await copyTree(install, join16(target2, relative5(origin, install)));
|
|
18821
20726
|
}
|
|
18822
20727
|
async function copyTree(from, to) {
|
|
18823
20728
|
await mkdir2(dirname3(to), { recursive: true });
|
|
@@ -18832,7 +20737,7 @@ async function copyTree(from, to) {
|
|
|
18832
20737
|
await cp(from, to, { recursive: true, verbatimSymlinks: true });
|
|
18833
20738
|
}
|
|
18834
20739
|
function forkedAppRoot(checkout, appRoot, forkCheckout) {
|
|
18835
|
-
return
|
|
20740
|
+
return join16(forkCheckout, relative5(checkout, appRoot));
|
|
18836
20741
|
}
|
|
18837
20742
|
|
|
18838
20743
|
// ../../packages/build/src/local-build-executor.ts
|
|
@@ -18855,7 +20760,7 @@ async function withRouteList(artifact, list, appRoot, observer) {
|
|
|
18855
20760
|
}
|
|
18856
20761
|
}
|
|
18857
20762
|
var defaultLocalBuildDependencies = {
|
|
18858
|
-
createWorkspace: () => mkdtemp(
|
|
20763
|
+
createWorkspace: () => mkdtemp(join17(tmpdir(), "next-deploy-build-")),
|
|
18859
20764
|
removeWorkspace: (path) => rm3(path, { recursive: true, force: true }),
|
|
18860
20765
|
runCommand,
|
|
18861
20766
|
detectPackageManager,
|
|
@@ -18890,7 +20795,7 @@ async function readInstalledNextVersion(appRoot, checkout) {
|
|
|
18890
20795
|
for (; ; ) {
|
|
18891
20796
|
try {
|
|
18892
20797
|
const source = await readFile13(
|
|
18893
|
-
|
|
20798
|
+
join17(dir, "node_modules", "next", "package.json"),
|
|
18894
20799
|
"utf8"
|
|
18895
20800
|
);
|
|
18896
20801
|
const version3 = JSON.parse(source).version;
|
|
@@ -19045,8 +20950,8 @@ var LocalBuildExecutor = class {
|
|
|
19045
20950
|
}
|
|
19046
20951
|
async build(input, observer, cache) {
|
|
19047
20952
|
const workspace = await this.dependencies.createWorkspace();
|
|
19048
|
-
const checkout =
|
|
19049
|
-
const pmCacheDir =
|
|
20953
|
+
const checkout = join17(workspace, "checkout");
|
|
20954
|
+
const pmCacheDir = join17(workspace, ".pm-store");
|
|
19050
20955
|
let cacheSeq = 0;
|
|
19051
20956
|
const commandAvailable = this.dependencies.commandAvailable ?? hasCommand;
|
|
19052
20957
|
const compressor = "zstd";
|
|
@@ -19055,7 +20960,7 @@ var LocalBuildExecutor = class {
|
|
|
19055
20960
|
transport: cache,
|
|
19056
20961
|
fetch: this.dependencies.cacheFetch ?? ((url2, init) => fetch(url2, init)),
|
|
19057
20962
|
runCommand: this.dependencies.runCommand,
|
|
19058
|
-
tmpFile: (suffix) =>
|
|
20963
|
+
tmpFile: (suffix) => join17(workspace, `cache-${String(cacheSeq++)}${suffix}`),
|
|
19059
20964
|
// One latch for the whole build so a disabled cache warns once.
|
|
19060
20965
|
report: { unavailable: false }
|
|
19061
20966
|
} : null;
|
|
@@ -19263,7 +21168,7 @@ var LocalBuildExecutor = class {
|
|
|
19263
21168
|
}
|
|
19264
21169
|
}
|
|
19265
21170
|
await notifyStatus(observer, "BUILDING");
|
|
19266
|
-
const buildCacheDir = resolved.preset.cachePath ?
|
|
21171
|
+
const buildCacheDir = resolved.preset.cachePath ? join17(appRoot, resolved.preset.cachePath) : null;
|
|
19267
21172
|
const buildCacheKey = sanitizeCacheKey(input.branch);
|
|
19268
21173
|
if (cachePorts && buildCacheDir) {
|
|
19269
21174
|
await tryRestore(
|
|
@@ -19287,13 +21192,13 @@ var LocalBuildExecutor = class {
|
|
|
19287
21192
|
entries: fingerprintEntries,
|
|
19288
21193
|
nextVersion: nextVersion ? `${String(nextVersion.major)}.${String(nextVersion.minor)}.${String(nextVersion.patch)}` : "unknown"
|
|
19289
21194
|
});
|
|
19290
|
-
const pristine =
|
|
21195
|
+
const pristine = join17(workspace, "pristine");
|
|
19291
21196
|
const fork = this.dependencies.forkWorkspace ?? defaultFork;
|
|
19292
21197
|
await fork(checkout, pristine);
|
|
19293
21198
|
let forks = 0;
|
|
19294
21199
|
const resolverConcurrency = this.dependencies.resolverConcurrency ?? 1;
|
|
19295
21200
|
const forkWorkspace = async (label2) => {
|
|
19296
|
-
const target2 =
|
|
21201
|
+
const target2 = join17(
|
|
19297
21202
|
workspace,
|
|
19298
21203
|
"forks",
|
|
19299
21204
|
`${String(forks++)}-${label2.replace(/[^a-z0-9-]/gi, "-")}`
|
|
@@ -19589,12 +21494,12 @@ async function errorFromResponse(response, context) {
|
|
|
19589
21494
|
// ../../packages/sdk/src/session.ts
|
|
19590
21495
|
import { mkdirSync, readFileSync, rmSync, writeFileSync } from "fs";
|
|
19591
21496
|
import { homedir } from "os";
|
|
19592
|
-
import { join as
|
|
21497
|
+
import { join as join18 } from "path";
|
|
19593
21498
|
function credentialsDir(home = homedir()) {
|
|
19594
|
-
return
|
|
21499
|
+
return join18(home, ".naro");
|
|
19595
21500
|
}
|
|
19596
21501
|
function credentialsFile(home = homedir()) {
|
|
19597
|
-
return
|
|
21502
|
+
return join18(credentialsDir(home), "credentials.json");
|
|
19598
21503
|
}
|
|
19599
21504
|
function saveSession(session, home = homedir()) {
|
|
19600
21505
|
mkdirSync(credentialsDir(home), { recursive: true, mode: 448 });
|
|
@@ -20198,44 +22103,6 @@ var FlagsApi = class {
|
|
|
20198
22103
|
);
|
|
20199
22104
|
}
|
|
20200
22105
|
};
|
|
20201
|
-
var BindingsApi = class {
|
|
20202
|
-
constructor(client) {
|
|
20203
|
-
this.client = client;
|
|
20204
|
-
}
|
|
20205
|
-
async list(projectId) {
|
|
20206
|
-
const body = await this.client.request(
|
|
20207
|
-
project(projectId, "/storage"),
|
|
20208
|
-
{ context: "List storage bindings" }
|
|
20209
|
-
);
|
|
20210
|
-
return body.storage;
|
|
20211
|
-
}
|
|
20212
|
-
/**
|
|
20213
|
-
* Makes the Cloudflare resource and binds it at the next deploy.
|
|
20214
|
-
* `VALIDATION_FAILED` for a bad type or binding name (ASSETS and DB are
|
|
20215
|
-
* reserved), `STORAGE_PROVISION_FAILED` (502) when Cloudflare refused.
|
|
20216
|
-
*/
|
|
20217
|
-
async add(projectId, type, bindingName) {
|
|
20218
|
-
const answer = await this.client.request(
|
|
20219
|
-
project(projectId, "/storage"),
|
|
20220
|
-
{
|
|
20221
|
-
method: "POST",
|
|
20222
|
-
body: { type, bindingName },
|
|
20223
|
-
context: "Add storage binding"
|
|
20224
|
-
}
|
|
20225
|
-
);
|
|
20226
|
-
return answer.storage;
|
|
20227
|
-
}
|
|
20228
|
-
/**
|
|
20229
|
-
* Deletes the Cloudflare resource and what it holds — it cannot be undone.
|
|
20230
|
-
* `STORAGE_MANAGED` refuses the Naro database.
|
|
20231
|
-
*/
|
|
20232
|
-
async remove(projectId, bindingId) {
|
|
20233
|
-
await this.client.request(
|
|
20234
|
-
project(projectId, `/storage/${encodeURIComponent(bindingId)}`),
|
|
20235
|
-
{ method: "DELETE", context: "Remove storage binding" }
|
|
20236
|
-
);
|
|
20237
|
-
}
|
|
20238
|
-
};
|
|
20239
22106
|
|
|
20240
22107
|
// ../../packages/sdk/src/ops.ts
|
|
20241
22108
|
var BillingApi = class {
|
|
@@ -20432,7 +22299,6 @@ var NaroClient = class _NaroClient {
|
|
|
20432
22299
|
dns;
|
|
20433
22300
|
firewall;
|
|
20434
22301
|
flags;
|
|
20435
|
-
bindings;
|
|
20436
22302
|
billing;
|
|
20437
22303
|
observability;
|
|
20438
22304
|
supabase;
|
|
@@ -20462,7 +22328,6 @@ var NaroClient = class _NaroClient {
|
|
|
20462
22328
|
this.dns = new DnsApi(this);
|
|
20463
22329
|
this.firewall = new FirewallApi(this);
|
|
20464
22330
|
this.flags = new FlagsApi(this);
|
|
20465
|
-
this.bindings = new BindingsApi(this);
|
|
20466
22331
|
this.billing = new BillingApi(this);
|
|
20467
22332
|
this.observability = new ObservabilityApi(this);
|
|
20468
22333
|
this.supabase = new SupabaseApi(this);
|
|
@@ -20987,9 +22852,10 @@ var EnvApi = class {
|
|
|
20987
22852
|
/**
|
|
20988
22853
|
* The names the env route refuses as a key — `409 VALIDATION_FAILED`
|
|
20989
22854
|
* `<KEY> is already used by a storage binding.` — read the way it reads
|
|
20990
|
-
* them: `ASSETS` (the static files),
|
|
20991
|
-
*
|
|
20992
|
-
*
|
|
22855
|
+
* them: `ASSETS` (the static files) and, on a project using the managed
|
|
22856
|
+
* database (`database_provider` is `d1`), `DB`. The bindings a user
|
|
22857
|
+
* declared (R2·KV·D1) are gone since 2026-11-04, and so is the route that
|
|
22858
|
+
* listed them. For a caller that sends
|
|
20993
22859
|
* many entries in several requests (`naro env import`) and has to refuse
|
|
20994
22860
|
* before the first one is saved. A control plane whose project row has no
|
|
20995
22861
|
* `database_provider` reads as having no managed database, so `DB` is only
|
|
@@ -20997,20 +22863,8 @@ var EnvApi = class {
|
|
|
20997
22863
|
*/
|
|
20998
22864
|
async takenBindingNames(projectId) {
|
|
20999
22865
|
const base2 = `/api/projects/${encodeURIComponent(projectId)}`;
|
|
21000
|
-
const
|
|
21001
|
-
|
|
21002
|
-
`${base2}/storage`,
|
|
21003
|
-
{ context: "List storage" }
|
|
21004
|
-
),
|
|
21005
|
-
this.client.request(
|
|
21006
|
-
base2,
|
|
21007
|
-
{ context: "Read project" }
|
|
21008
|
-
)
|
|
21009
|
-
]);
|
|
21010
|
-
const names = /* @__PURE__ */ new Set([
|
|
21011
|
-
STATIC_ASSETS_BINDING,
|
|
21012
|
-
...storage.storage.map((row) => row.bindingName)
|
|
21013
|
-
]);
|
|
22866
|
+
const project2 = await this.client.request(base2, { context: "Read project" });
|
|
22867
|
+
const names = /* @__PURE__ */ new Set([STATIC_ASSETS_BINDING]);
|
|
21014
22868
|
if (project2.project.database_provider === "d1")
|
|
21015
22869
|
names.add(MANAGED_DATABASE_BINDING);
|
|
21016
22870
|
return [...names];
|
|
@@ -22686,6 +24540,54 @@ var FunctionsApi = class {
|
|
|
22686
24540
|
}
|
|
22687
24541
|
};
|
|
22688
24542
|
|
|
24543
|
+
// ../../packages/sdk/src/dashboard.ts
|
|
24544
|
+
function dashboardCapability(id) {
|
|
24545
|
+
const found = CAPABILITIES.find((capability) => capability.id === id);
|
|
24546
|
+
if (!found || typeof found.dashboard !== "string")
|
|
24547
|
+
throw new NaroError(
|
|
24548
|
+
"VALIDATION_FAILED",
|
|
24549
|
+
`No dashboard page for "${id}". Run without a capability to list the ones that have one.`
|
|
24550
|
+
);
|
|
24551
|
+
return found;
|
|
24552
|
+
}
|
|
24553
|
+
async function dashboardLink(client, capability, target2, options) {
|
|
24554
|
+
const needs = dashboardNeeds(capability.dashboard);
|
|
24555
|
+
let teamSlug = target2.teamSlug;
|
|
24556
|
+
let projectSlug;
|
|
24557
|
+
if (needs.project) {
|
|
24558
|
+
if (!target2.projectId)
|
|
24559
|
+
throw new NaroError(
|
|
24560
|
+
"PROJECT_NOT_LINKED",
|
|
24561
|
+
"This page belongs to a project: pass its id, or link the directory first."
|
|
24562
|
+
);
|
|
24563
|
+
const [project2, teams] = await Promise.all([
|
|
24564
|
+
client.projects.get(target2.projectId),
|
|
24565
|
+
client.teams.list()
|
|
24566
|
+
]);
|
|
24567
|
+
const team = teams.find((candidate) => candidate.id === project2.teamId);
|
|
24568
|
+
if (!team)
|
|
24569
|
+
throw new NaroError(
|
|
24570
|
+
"NOT_FOUND",
|
|
24571
|
+
`The team of project ${project2.slug} is not one of yours.`
|
|
24572
|
+
);
|
|
24573
|
+
teamSlug = team.slug;
|
|
24574
|
+
projectSlug = project2.slug;
|
|
24575
|
+
} else if (needs.team && !teamSlug) {
|
|
24576
|
+
throw new NaroError("TEAM_REQUIRED", "This page belongs to a team.");
|
|
24577
|
+
}
|
|
24578
|
+
const support = capability[options.client];
|
|
24579
|
+
return {
|
|
24580
|
+
capability: capability.id,
|
|
24581
|
+
title: capability.title,
|
|
24582
|
+
url: dashboardUrl(options.baseUrl, capability.dashboard, {
|
|
24583
|
+
teamSlug,
|
|
24584
|
+
projectSlug
|
|
24585
|
+
}),
|
|
24586
|
+
reason: support.kind === "excluded" ? { code: support.reason, why: REASON_CODES[support.reason].why } : null,
|
|
24587
|
+
cli: capability.cli.kind === "built" ? capability.cli.commands ?? [] : []
|
|
24588
|
+
};
|
|
24589
|
+
}
|
|
24590
|
+
|
|
22689
24591
|
// ../../packages/sdk/src/database.ts
|
|
22690
24592
|
var BOOKMARK_RE = /^[0-9a-f]{8}-[0-9a-f]{8}-[0-9a-f]{8}-[0-9a-f]{32}$/;
|
|
22691
24593
|
var BOOKMARK_FORMAT_MESSAGE = "bookmark must look like 00000001-00000008-000050ed-272153b8520cfb93b49834d93a1a1ab3 (four hyphen-separated hex groups, 59 characters).";
|
|
@@ -22736,14 +24638,14 @@ function summarizeStatement(statement2) {
|
|
|
22736
24638
|
|
|
22737
24639
|
// ../../packages/sdk/src/dotenv.ts
|
|
22738
24640
|
import { existsSync, readFileSync as readFileSync2 } from "fs";
|
|
22739
|
-
import { join as
|
|
24641
|
+
import { join as join19 } from "path";
|
|
22740
24642
|
var QUOTES2 = /* @__PURE__ */ new Set(["'", '"', "`"]);
|
|
22741
24643
|
function parseDotenv(text3) {
|
|
22742
24644
|
return parseDotenvDetailed(text3).vars;
|
|
22743
24645
|
}
|
|
22744
24646
|
function readProjectEnv(dir) {
|
|
22745
24647
|
for (const name of [".env.local", ".env.production", ".env"]) {
|
|
22746
|
-
const path =
|
|
24648
|
+
const path = join19(dir, name);
|
|
22747
24649
|
if (existsSync(path)) return parseDotenv(readFileSync2(path, "utf8"));
|
|
22748
24650
|
}
|
|
22749
24651
|
return {};
|
|
@@ -22797,7 +24699,7 @@ function serializeDotenv(vars) {
|
|
|
22797
24699
|
|
|
22798
24700
|
// ../../packages/sdk/src/env-scan.ts
|
|
22799
24701
|
import { existsSync as existsSync2, readFileSync as readFileSync3, readdirSync, statSync } from "fs";
|
|
22800
|
-
import { join as
|
|
24702
|
+
import { join as join20 } from "path";
|
|
22801
24703
|
var SOURCE_EXTENSIONS3 = /* @__PURE__ */ new Set([
|
|
22802
24704
|
".ts",
|
|
22803
24705
|
".tsx",
|
|
@@ -22852,7 +24754,7 @@ function collect(dir, out) {
|
|
|
22852
24754
|
for (const entry of entries) {
|
|
22853
24755
|
if (out.length >= MAX_FILES) return;
|
|
22854
24756
|
if (entry.isSymbolicLink()) continue;
|
|
22855
|
-
const path =
|
|
24757
|
+
const path = join20(dir, entry.name);
|
|
22856
24758
|
if (entry.isDirectory()) {
|
|
22857
24759
|
if (entry.name.startsWith(".") || SKIP_DIRECTORIES.has(entry.name))
|
|
22858
24760
|
continue;
|
|
@@ -22884,7 +24786,7 @@ function scanEnvReferences(dir) {
|
|
|
22884
24786
|
}
|
|
22885
24787
|
}
|
|
22886
24788
|
for (const name of EXAMPLE_FILES) {
|
|
22887
|
-
const path =
|
|
24789
|
+
const path = join20(dir, name);
|
|
22888
24790
|
if (!existsSync2(path)) continue;
|
|
22889
24791
|
let parsed;
|
|
22890
24792
|
try {
|
|
@@ -22902,11 +24804,11 @@ function scanEnvReferences(dir) {
|
|
|
22902
24804
|
|
|
22903
24805
|
// ../../packages/sdk/src/framework.ts
|
|
22904
24806
|
import { existsSync as existsSync3, readFileSync as readFileSync4 } from "fs";
|
|
22905
|
-
import { join as
|
|
24807
|
+
import { join as join21 } from "path";
|
|
22906
24808
|
function readPackageJson2(dir) {
|
|
22907
24809
|
try {
|
|
22908
24810
|
return JSON.parse(
|
|
22909
|
-
readFileSync4(
|
|
24811
|
+
readFileSync4(join21(dir, "package.json"), "utf8")
|
|
22910
24812
|
);
|
|
22911
24813
|
} catch {
|
|
22912
24814
|
return null;
|
|
@@ -22917,7 +24819,7 @@ function hasDependency(pkg, name) {
|
|
|
22917
24819
|
}
|
|
22918
24820
|
function hasConfig(dir, base2, evidence) {
|
|
22919
24821
|
for (const ext of ["js", "mjs", "cjs", "ts", "mts"]) {
|
|
22920
|
-
if (existsSync3(
|
|
24822
|
+
if (existsSync3(join21(dir, `${base2}.${ext}`))) {
|
|
22921
24823
|
evidence.push(`${base2}.${ext}`);
|
|
22922
24824
|
return true;
|
|
22923
24825
|
}
|
|
@@ -23025,8 +24927,8 @@ function detectFramework2(dir) {
|
|
|
23025
24927
|
if (!byDependency && !byConfig) continue;
|
|
23026
24928
|
if (byDependency) evidence.push(`package.json: ${detector.dependency}`);
|
|
23027
24929
|
if (detector.framework === "nextjs") {
|
|
23028
|
-
if (existsSync3(
|
|
23029
|
-
if (existsSync3(
|
|
24930
|
+
if (existsSync3(join21(dir, "app"))) evidence.push("app/");
|
|
24931
|
+
if (existsSync3(join21(dir, "pages"))) evidence.push("pages/");
|
|
23030
24932
|
}
|
|
23031
24933
|
return {
|
|
23032
24934
|
framework: detector.framework,
|
|
@@ -23037,7 +24939,7 @@ function detectFramework2(dir) {
|
|
|
23037
24939
|
deployable: true
|
|
23038
24940
|
};
|
|
23039
24941
|
}
|
|
23040
|
-
if (!pkg && existsSync3(
|
|
24942
|
+
if (!pkg && existsSync3(join21(dir, "index.html"))) {
|
|
23041
24943
|
evidence.push("index.html (no package.json)");
|
|
23042
24944
|
return {
|
|
23043
24945
|
framework: "static",
|
|
@@ -31847,12 +33749,12 @@ import {
|
|
|
31847
33749
|
rmSync as rmSync2,
|
|
31848
33750
|
writeFileSync as writeFileSync2
|
|
31849
33751
|
} from "fs";
|
|
31850
|
-
import { join as
|
|
33752
|
+
import { join as join22 } from "path";
|
|
31851
33753
|
function linkDir(dir) {
|
|
31852
|
-
return
|
|
33754
|
+
return join22(dir, ".naro");
|
|
31853
33755
|
}
|
|
31854
33756
|
function linkFile(dir) {
|
|
31855
|
-
return
|
|
33757
|
+
return join22(linkDir(dir), "project.json");
|
|
31856
33758
|
}
|
|
31857
33759
|
function readProjectLink(dir) {
|
|
31858
33760
|
try {
|
|
@@ -31874,7 +33776,7 @@ function writeProjectLink(dir, link) {
|
|
|
31874
33776
|
writeFileSync2(linkFile(dir), `${JSON.stringify(link, null, 2)}
|
|
31875
33777
|
`);
|
|
31876
33778
|
writeFileSync2(
|
|
31877
|
-
|
|
33779
|
+
join22(linkDir(dir), "README.txt"),
|
|
31878
33780
|
"This directory links the project to Naro and should not be committed.\n"
|
|
31879
33781
|
);
|
|
31880
33782
|
}
|
|
@@ -31884,9 +33786,9 @@ function removeProjectLink(dir) {
|
|
|
31884
33786
|
return true;
|
|
31885
33787
|
}
|
|
31886
33788
|
function ensureGitignoreHasNaro(dir) {
|
|
31887
|
-
const gitignorePath =
|
|
33789
|
+
const gitignorePath = join22(dir, ".gitignore");
|
|
31888
33790
|
const hasGitignore = existsSync4(gitignorePath);
|
|
31889
|
-
if (!hasGitignore && !existsSync4(
|
|
33791
|
+
if (!hasGitignore && !existsSync4(join22(dir, ".git"))) return false;
|
|
31890
33792
|
const current = hasGitignore ? readFileSync5(gitignorePath, "utf8") : "";
|
|
31891
33793
|
const covered = current.split(/\r?\n/).map((line) => line.trim()).some((line) => line === ".naro" || line === ".naro/" || line === "/.naro");
|
|
31892
33794
|
if (covered) return false;
|
|
@@ -32671,7 +34573,7 @@ function usageStatus(report, currentMonth, requests) {
|
|
|
32671
34573
|
|
|
32672
34574
|
// src/env-consent.ts
|
|
32673
34575
|
import { existsSync as existsSync6 } from "fs";
|
|
32674
|
-
import { join as
|
|
34576
|
+
import { join as join23 } from "path";
|
|
32675
34577
|
var DOTENV_FILES = [".env.local", ".env.production", ".env"];
|
|
32676
34578
|
var PUBLIC_PREFIX = "NEXT_PUBLIC_";
|
|
32677
34579
|
function maskSecretValue(value) {
|
|
@@ -32683,7 +34585,7 @@ function maskEnvValue(key, value) {
|
|
|
32683
34585
|
return maskSecretValue(value);
|
|
32684
34586
|
}
|
|
32685
34587
|
function findDotenvFile(dir) {
|
|
32686
|
-
for (const name of DOTENV_FILES) if (existsSync6(
|
|
34588
|
+
for (const name of DOTENV_FILES) if (existsSync6(join23(dir, name))) return name;
|
|
32687
34589
|
return null;
|
|
32688
34590
|
}
|
|
32689
34591
|
function envAddGuidance(keys, environment) {
|
|
@@ -32947,13 +34849,13 @@ async function uploadArtifact(artifact, opts) {
|
|
|
32947
34849
|
|
|
32948
34850
|
// src/version.ts
|
|
32949
34851
|
import { readFileSync as readFileSync6 } from "fs";
|
|
32950
|
-
import { dirname as dirname5, join as
|
|
34852
|
+
import { dirname as dirname5, join as join24 } from "path";
|
|
32951
34853
|
import { fileURLToPath } from "url";
|
|
32952
34854
|
function version2() {
|
|
32953
34855
|
try {
|
|
32954
34856
|
const pkg = JSON.parse(
|
|
32955
34857
|
readFileSync6(
|
|
32956
|
-
|
|
34858
|
+
join24(dirname5(fileURLToPath(import.meta.url)), "..", "package.json"),
|
|
32957
34859
|
"utf8"
|
|
32958
34860
|
)
|
|
32959
34861
|
);
|
|
@@ -32982,7 +34884,7 @@ import {
|
|
|
32982
34884
|
basename as basename3,
|
|
32983
34885
|
dirname as dirname6,
|
|
32984
34886
|
isAbsolute as isAbsolute4,
|
|
32985
|
-
join as
|
|
34887
|
+
join as join25,
|
|
32986
34888
|
relative as relative6,
|
|
32987
34889
|
resolve as resolve10,
|
|
32988
34890
|
sep as sep5
|
|
@@ -33109,12 +35011,12 @@ async function copyWorkingTree(source, checkout) {
|
|
|
33109
35011
|
keptLinks,
|
|
33110
35012
|
async ({ path, text: text3 }) => {
|
|
33111
35013
|
try {
|
|
33112
|
-
return inside(await realpath3(
|
|
35014
|
+
return inside(await realpath3(join25(checkout, path)), root);
|
|
33113
35015
|
} catch (error51) {
|
|
33114
35016
|
return error51.code === "ENOENT" && climbsOnlyFirst(text3);
|
|
33115
35017
|
}
|
|
33116
35018
|
},
|
|
33117
|
-
({ path }) => unlink(
|
|
35019
|
+
({ path }) => unlink(join25(checkout, path))
|
|
33118
35020
|
);
|
|
33119
35021
|
linksElsewhere.push(...strays.map(({ path }) => path));
|
|
33120
35022
|
const committed = await committedEnvFiles(sourceDir);
|
|
@@ -33128,7 +35030,7 @@ async function copyWorkingTree(source, checkout) {
|
|
|
33128
35030
|
outsideProject.push(path);
|
|
33129
35031
|
continue;
|
|
33130
35032
|
}
|
|
33131
|
-
const target2 =
|
|
35033
|
+
const target2 = join25(checkout, path);
|
|
33132
35034
|
if (!inside(await realAncestor(dirname6(target2)), root)) {
|
|
33133
35035
|
outsideProject.push(path);
|
|
33134
35036
|
continue;
|
|
@@ -33153,16 +35055,16 @@ async function copyWorkingTree(source, checkout) {
|
|
|
33153
35055
|
continue;
|
|
33154
35056
|
}
|
|
33155
35057
|
await writeFile7(target2, content, { flag: "wx" });
|
|
33156
|
-
const local = await readLocal(
|
|
35058
|
+
const local = await readLocal(join25(sourceDir, path));
|
|
33157
35059
|
if (!local || !sameText(local, content)) committedVersion.push(path);
|
|
33158
35060
|
}
|
|
33159
35061
|
const envStrays = await keptOnly(
|
|
33160
35062
|
envLinks,
|
|
33161
35063
|
async (path) => {
|
|
33162
|
-
const real = await realpath3(
|
|
35064
|
+
const real = await realpath3(join25(checkout, path)).catch(() => null);
|
|
33163
35065
|
return real !== null && inside(real, root);
|
|
33164
35066
|
},
|
|
33165
|
-
(path) => unlink(
|
|
35067
|
+
(path) => unlink(join25(checkout, path))
|
|
33166
35068
|
);
|
|
33167
35069
|
outsideProject.push(...envStrays);
|
|
33168
35070
|
const inCommit = new Set(
|
|
@@ -33215,7 +35117,7 @@ function forEnvironment(text3, environment) {
|
|
|
33215
35117
|
|
|
33216
35118
|
// src/commands/migration.ts
|
|
33217
35119
|
import { mkdirSync as mkdirSync3, readFileSync as readFileSync7, writeFileSync as writeFileSync3 } from "fs";
|
|
33218
|
-
import { join as
|
|
35120
|
+
import { join as join26, relative as relative7 } from "path";
|
|
33219
35121
|
|
|
33220
35122
|
// src/prompt.ts
|
|
33221
35123
|
import { createInterface as createInterface2 } from "readline";
|
|
@@ -33389,7 +35291,7 @@ function warningLines(message) {
|
|
|
33389
35291
|
}
|
|
33390
35292
|
function policyProblems(dir, names) {
|
|
33391
35293
|
return names.flatMap((name) => {
|
|
33392
|
-
const split2 = splitStatements(readFileSync7(
|
|
35294
|
+
const split2 = splitStatements(readFileSync7(join26(dir, name), "utf8"));
|
|
33393
35295
|
if (!split2.ok) return [];
|
|
33394
35296
|
const planned = planPolicyMigration(
|
|
33395
35297
|
split2.statements.map((statement2) => statement2.text)
|
|
@@ -33420,7 +35322,7 @@ async function runMigrationNew(context, deps = processStdin) {
|
|
|
33420
35322
|
const body = fromStdin ? piped.endsWith("\n") ? piped : `${piped}
|
|
33421
35323
|
` : `-- Migration: ${fileName}
|
|
33422
35324
|
`;
|
|
33423
|
-
const path =
|
|
35325
|
+
const path = join26(dir, fileName);
|
|
33424
35326
|
writeFileSync3(path, body, { flag: "wx" });
|
|
33425
35327
|
const relPath = relativeToCwd(context, path);
|
|
33426
35328
|
context.output.result({ file: fileName, path: relPath, fromStdin }, [
|
|
@@ -33449,7 +35351,7 @@ async function applyMigrationFiles(context, client, projectId, dir, names) {
|
|
|
33449
35351
|
const applied = [];
|
|
33450
35352
|
const warnings = [];
|
|
33451
35353
|
for (const name of names) {
|
|
33452
|
-
const sql = readFileSync7(
|
|
35354
|
+
const sql = readFileSync7(join26(dir, name), "utf8");
|
|
33453
35355
|
let answer;
|
|
33454
35356
|
try {
|
|
33455
35357
|
answer = await client.db.applyMigration(projectId, { name, sql });
|
|
@@ -33661,7 +35563,7 @@ var BUNDLE_MESSAGES = {
|
|
|
33661
35563
|
|
|
33662
35564
|
// ../../packages/functions-bundler/src/discover.ts
|
|
33663
35565
|
import { existsSync as existsSync7, readdirSync as readdirSync3, readFileSync as readFileSync8, statSync as statSync2 } from "fs";
|
|
33664
|
-
import { join as
|
|
35566
|
+
import { join as join27, relative as relative8, resolve as resolve11, sep as sep6 } from "path";
|
|
33665
35567
|
|
|
33666
35568
|
// ../../packages/functions-bundler/src/limits.ts
|
|
33667
35569
|
var FUNCTION_BUNDLE_MAX_BYTES = 67108864;
|
|
@@ -33685,7 +35587,7 @@ function isEntrypoint(value) {
|
|
|
33685
35587
|
function functionsFolder(options) {
|
|
33686
35588
|
const root = resolve11(options.cwd, options.root ?? ".");
|
|
33687
35589
|
const explicit = options.dir !== void 0;
|
|
33688
|
-
const dir = explicit ? resolve11(options.cwd, options.dir) :
|
|
35590
|
+
const dir = explicit ? resolve11(options.cwd, options.dir) : join27(root, "naro", "functions");
|
|
33689
35591
|
const label2 = relative8(options.cwd, dir).split(sep6).join("/") || ".";
|
|
33690
35592
|
return { dir, label: label2, root, explicit };
|
|
33691
35593
|
}
|
|
@@ -33694,7 +35596,7 @@ function listFunctionNames(folder) {
|
|
|
33694
35596
|
try {
|
|
33695
35597
|
entries = readdirSync3(folder.dir, { withFileTypes: true });
|
|
33696
35598
|
} catch {
|
|
33697
|
-
if (!folder.explicit && existsSync7(
|
|
35599
|
+
if (!folder.explicit && existsSync7(join27(folder.root, "supabase", "functions")))
|
|
33698
35600
|
throw new FunctionBundleError(
|
|
33699
35601
|
"VALIDATION_FAILED",
|
|
33700
35602
|
BUNDLE_MESSAGES.supabaseFound
|
|
@@ -33715,7 +35617,7 @@ function listFunctionNames(folder) {
|
|
|
33715
35617
|
return names;
|
|
33716
35618
|
}
|
|
33717
35619
|
function readFunctionJson(dir, name) {
|
|
33718
|
-
const file2 =
|
|
35620
|
+
const file2 = join27(dir, "function.json");
|
|
33719
35621
|
if (!existsSync7(file2)) return { verifyJwt: void 0, entrypoint: void 0 };
|
|
33720
35622
|
let parsed;
|
|
33721
35623
|
try {
|
|
@@ -33759,7 +35661,7 @@ function readFunctionSource(folder, name) {
|
|
|
33759
35661
|
"VALIDATION_FAILED",
|
|
33760
35662
|
BUNDLE_MESSAGES.badName(name)
|
|
33761
35663
|
);
|
|
33762
|
-
const dir =
|
|
35664
|
+
const dir = join27(folder.dir, name);
|
|
33763
35665
|
if (!statSync2(dir, { throwIfNoEntry: false })?.isDirectory())
|
|
33764
35666
|
throw new FunctionBundleError(
|
|
33765
35667
|
"VALIDATION_FAILED",
|
|
@@ -33768,14 +35670,14 @@ function readFunctionSource(folder, name) {
|
|
|
33768
35670
|
const config2 = readFunctionJson(dir, name);
|
|
33769
35671
|
let entrypoint;
|
|
33770
35672
|
if (config2.entrypoint !== void 0) {
|
|
33771
|
-
if (!existsSync7(
|
|
35673
|
+
if (!existsSync7(join27(dir, ...config2.entrypoint.split("/"))))
|
|
33772
35674
|
throw new FunctionBundleError(
|
|
33773
35675
|
"FUNCTION_BUNDLE_FAILED",
|
|
33774
35676
|
BUNDLE_MESSAGES.entryMissing(name, config2.entrypoint)
|
|
33775
35677
|
);
|
|
33776
35678
|
entrypoint = config2.entrypoint;
|
|
33777
35679
|
} else {
|
|
33778
|
-
const found = ENTRY_FILES.find((file2) => existsSync7(
|
|
35680
|
+
const found = ENTRY_FILES.find((file2) => existsSync7(join27(dir, file2)));
|
|
33779
35681
|
if (found === void 0)
|
|
33780
35682
|
throw new FunctionBundleError(
|
|
33781
35683
|
"FUNCTION_BUNDLE_FAILED",
|
|
@@ -33786,14 +35688,14 @@ function readFunctionSource(folder, name) {
|
|
|
33786
35688
|
return {
|
|
33787
35689
|
name,
|
|
33788
35690
|
dir,
|
|
33789
|
-
entry:
|
|
35691
|
+
entry: join27(dir, ...entrypoint.split("/")),
|
|
33790
35692
|
entrypoint,
|
|
33791
35693
|
verifyJwt: config2.verifyJwt
|
|
33792
35694
|
};
|
|
33793
35695
|
}
|
|
33794
35696
|
function configTomlWarning(folder) {
|
|
33795
|
-
if (!folder.dir.endsWith(
|
|
33796
|
-
const file2 =
|
|
35697
|
+
if (!folder.dir.endsWith(join27("supabase", "functions"))) return null;
|
|
35698
|
+
const file2 = join27(folder.dir, "..", "config.toml");
|
|
33797
35699
|
if (!existsSync7(file2)) return null;
|
|
33798
35700
|
return /^\s*verify_jwt\s*=/m.test(readFileSync8(file2, "utf8")) ? BUNDLE_MESSAGES.supabaseVerifyJwt(folder.label) : null;
|
|
33799
35701
|
}
|
|
@@ -33999,11 +35901,11 @@ ${injects.map(
|
|
|
33999
35901
|
|
|
34000
35902
|
// ../../packages/functions-bundler/src/deno-imports.ts
|
|
34001
35903
|
import { existsSync as existsSync9, readFileSync as readFileSync10, realpathSync as realpathSync2 } from "fs";
|
|
34002
|
-
import { dirname as dirname9, isAbsolute as isAbsolute5, join as
|
|
35904
|
+
import { dirname as dirname9, isAbsolute as isAbsolute5, join as join29, relative as relative9, sep as sep8 } from "path";
|
|
34003
35905
|
|
|
34004
35906
|
// ../../packages/functions-bundler/src/import-map.ts
|
|
34005
35907
|
import { existsSync as existsSync8, readFileSync as readFileSync9, realpathSync } from "fs";
|
|
34006
|
-
import { basename as basename4, dirname as dirname8, join as
|
|
35908
|
+
import { basename as basename4, dirname as dirname8, join as join28, resolve as resolve12, sep as sep7 } from "path";
|
|
34007
35909
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
34008
35910
|
|
|
34009
35911
|
// ../../packages/functions-bundler/src/printable.ts
|
|
@@ -34075,7 +35977,7 @@ function readImportMapFile(file2, label2) {
|
|
|
34075
35977
|
}
|
|
34076
35978
|
function readImportMap(functionDir, fallback, labelOf) {
|
|
34077
35979
|
for (const name of FILES) {
|
|
34078
|
-
const file2 =
|
|
35980
|
+
const file2 = join28(functionDir, name);
|
|
34079
35981
|
if (!existsSync8(file2)) continue;
|
|
34080
35982
|
const map2 = load(file2, labelOf(file2));
|
|
34081
35983
|
if (map2 !== null) return map2;
|
|
@@ -34218,7 +36120,7 @@ function packageDir(from, projectRoot) {
|
|
|
34218
36120
|
let current = from;
|
|
34219
36121
|
while (isInside(current, projectRoot)) {
|
|
34220
36122
|
const inNodeModules = fromRoot(projectRoot, current).split("/").includes("node_modules");
|
|
34221
|
-
if (!inNodeModules && existsSync9(
|
|
36123
|
+
if (!inNodeModules && existsSync9(join29(current, "package.json")))
|
|
34222
36124
|
return fromRoot(projectRoot, current) || ".";
|
|
34223
36125
|
const up = dirname9(current);
|
|
34224
36126
|
if (up === current) break;
|
|
@@ -34230,7 +36132,7 @@ function isInstalled(from, pkg) {
|
|
|
34230
36132
|
if (pkg === "") return false;
|
|
34231
36133
|
let current = from;
|
|
34232
36134
|
for (; ; ) {
|
|
34233
|
-
if (existsSync9(
|
|
36135
|
+
if (existsSync9(join29(current, "node_modules", pkg))) return true;
|
|
34234
36136
|
const up = dirname9(current);
|
|
34235
36137
|
if (up === current) return false;
|
|
34236
36138
|
current = up;
|
|
@@ -34240,7 +36142,7 @@ var NODE_MODULES = /[\\/]node_modules[\\/]/;
|
|
|
34240
36142
|
function installedVersion(resolved, pkg) {
|
|
34241
36143
|
let current = dirname9(resolved);
|
|
34242
36144
|
for (; ; ) {
|
|
34243
|
-
const file2 =
|
|
36145
|
+
const file2 = join29(current, "package.json");
|
|
34244
36146
|
if (existsSync9(file2)) {
|
|
34245
36147
|
try {
|
|
34246
36148
|
const manifest2 = JSON.parse(readFileSync10(file2, "utf8"));
|
|
@@ -34424,7 +36326,7 @@ function denoImportsPlugin(options) {
|
|
|
34424
36326
|
|
|
34425
36327
|
// ../../packages/functions-bundler/src/bundle.ts
|
|
34426
36328
|
import { createHash as createHash4 } from "crypto";
|
|
34427
|
-
import { join as
|
|
36329
|
+
import { join as join30, relative as relative10, sep as sep9 } from "path";
|
|
34428
36330
|
import { gzipSync } from "zlib";
|
|
34429
36331
|
|
|
34430
36332
|
// ../../packages/functions-runtime/dist/index.js
|
|
@@ -34500,7 +36402,7 @@ async function bundleFunction(source, folder, options = {}) {
|
|
|
34500
36402
|
result = await build({
|
|
34501
36403
|
absWorkingDir: folder.root,
|
|
34502
36404
|
entryPoints: [source.entry],
|
|
34503
|
-
outfile:
|
|
36405
|
+
outfile: join30(source.dir, NARO_USER_MODULE),
|
|
34504
36406
|
bundle: true,
|
|
34505
36407
|
write: false,
|
|
34506
36408
|
format: "esm",
|
|
@@ -35070,7 +36972,7 @@ function slugify2(value) {
|
|
|
35070
36972
|
async function projectName(sourceDir) {
|
|
35071
36973
|
try {
|
|
35072
36974
|
const pkg = JSON.parse(
|
|
35073
|
-
await readFile15(
|
|
36975
|
+
await readFile15(join31(sourceDir, "package.json"), "utf8")
|
|
35074
36976
|
);
|
|
35075
36977
|
if (pkg.name) return pkg.name;
|
|
35076
36978
|
} catch {
|
|
@@ -35080,7 +36982,7 @@ async function projectName(sourceDir) {
|
|
|
35080
36982
|
function resolveBin(name) {
|
|
35081
36983
|
let dir = dirname10(fileURLToPath4(import.meta.url));
|
|
35082
36984
|
for (; ; ) {
|
|
35083
|
-
const candidate =
|
|
36985
|
+
const candidate = join31(dir, "node_modules", ".bin", name);
|
|
35084
36986
|
if (existsSync10(candidate)) return candidate;
|
|
35085
36987
|
const parent = dirname10(dir);
|
|
35086
36988
|
if (parent === dir) return name;
|
|
@@ -35147,7 +37049,7 @@ function workingTreeNotices(copy) {
|
|
|
35147
37049
|
}
|
|
35148
37050
|
function localDependencies(sourceDir, say = () => void 0) {
|
|
35149
37051
|
return {
|
|
35150
|
-
createWorkspace: () => mkdtemp2(
|
|
37052
|
+
createWorkspace: () => mkdtemp2(join31(tmpdir2(), "naro-build-")),
|
|
35151
37053
|
removeWorkspace: (path) => rm5(path, { recursive: true, force: true }),
|
|
35152
37054
|
async runCommand(spec, observer) {
|
|
35153
37055
|
if (spec.command === "git" && spec.args[0] === "clone") {
|
|
@@ -35402,6 +37304,8 @@ function deploymentUrl(detail, ctx, production) {
|
|
|
35402
37304
|
}
|
|
35403
37305
|
|
|
35404
37306
|
export {
|
|
37307
|
+
CAPABILITIES,
|
|
37308
|
+
dashboardNeeds,
|
|
35405
37309
|
parseDotenvDetailed,
|
|
35406
37310
|
FUNCTION_INVOKE_METHODS,
|
|
35407
37311
|
FUNCTION_INVOKE_MAX_RESPONSE_BYTES,
|
|
@@ -35439,6 +37343,8 @@ export {
|
|
|
35439
37343
|
POLICY_RULES,
|
|
35440
37344
|
POLICY_ACTIONS,
|
|
35441
37345
|
NaroClient,
|
|
37346
|
+
dashboardCapability,
|
|
37347
|
+
dashboardLink,
|
|
35442
37348
|
BOOKMARK_FORMAT_MESSAGE,
|
|
35443
37349
|
isBookmark,
|
|
35444
37350
|
RESTORE_OUTCOME_UNKNOWN_CODES,
|