naro-cli 0.25.0 → 0.27.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 +26 -4
- package/dist/{chunk-X5TUBMEU.js → chunk-UGJFIEH7.js} +2029 -177
- package/dist/deploy.js +1 -1
- package/dist/index.js +71 -131
- package/package.json +6 -6
- 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,1896 @@ 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: "team-backend-usage",
|
|
537
|
+
domain: "teams",
|
|
538
|
+
title: "\uD300 \uBC31\uC5D4\uB4DC \uC0AC\uC6A9\uB7C9\xB7\uC77C\uBCC4 \uCC28\uD2B8(\uD568\uC218 CPU\xB7DB\xB7\uC2A4\uD1A0\uB9AC\uC9C0\xB7\uB9AC\uC5BC\uD0C0\uC784)",
|
|
539
|
+
routes: [
|
|
540
|
+
"GET teams/[teamSlug]/backend-usage",
|
|
541
|
+
"GET teams/[teamSlug]/usage/series"
|
|
542
|
+
],
|
|
543
|
+
dashboard: "/[teamSlug]/projects",
|
|
544
|
+
ui: { kind: "built" },
|
|
545
|
+
cli: {
|
|
546
|
+
kind: "planned",
|
|
547
|
+
note: "\uD300 \uAC1C\uC694 \uCE74\uB4DC\uB85C \uBA3C\uC800 \uB0C8\uB2E4. naro usage\uC5D0 \uBC31\uC5D4\uB4DC \uC904\uC744 \uB354\uD558\uB294 \uAC83\uC774 \uB2E4\uC74C\uC774\uB2E4."
|
|
548
|
+
},
|
|
549
|
+
mcp: {
|
|
550
|
+
kind: "planned",
|
|
551
|
+
note: "get_team_usage\uC5D0 \uBC31\uC5D4\uB4DC \uC0AC\uC6A9\uB7C9\uC744 \uB354\uD558\uB294 \uAC83\uC774 \uB2E4\uC74C\uC774\uB2E4."
|
|
552
|
+
}
|
|
553
|
+
},
|
|
554
|
+
{
|
|
555
|
+
id: "billing-view",
|
|
556
|
+
domain: "billing",
|
|
557
|
+
title: "\uD50C\uB79C\xB7\uAD6C\uB3C5 \uC870\uD68C",
|
|
558
|
+
routes: ["GET teams/[teamSlug]/billing"],
|
|
559
|
+
ui: { kind: "built" },
|
|
560
|
+
cli: { kind: "built", commands: ["naro billing"] },
|
|
561
|
+
mcp: { kind: "built", tools: ["get_team_billing"] }
|
|
562
|
+
},
|
|
563
|
+
{
|
|
564
|
+
id: "billing-checkout",
|
|
565
|
+
domain: "billing",
|
|
566
|
+
title: "\uCCB4\uD06C\uC544\uC6C3",
|
|
567
|
+
routes: ["POST teams/[teamSlug]/billing/checkout"],
|
|
568
|
+
dashboard: "/[teamSlug]/usage",
|
|
569
|
+
ui: { kind: "built" },
|
|
570
|
+
cli: {
|
|
571
|
+
kind: "excluded",
|
|
572
|
+
reason: "payment-flow",
|
|
573
|
+
note: "\uCE74\uB4DC \uC815\uBCF4\uB294 Paddle\uC758 \uD638\uC2A4\uD305 \uACB0\uC81C\uCC3D\uC774 \uBC1B\uB294\uB2E4."
|
|
574
|
+
},
|
|
575
|
+
mcp: {
|
|
576
|
+
kind: "excluded",
|
|
577
|
+
reason: "payment-flow",
|
|
578
|
+
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)."
|
|
579
|
+
}
|
|
580
|
+
},
|
|
581
|
+
{
|
|
582
|
+
id: "billing-portal",
|
|
583
|
+
domain: "billing",
|
|
584
|
+
title: "\uACB0\uC81C \uD3EC\uD138",
|
|
585
|
+
routes: ["POST teams/[teamSlug]/billing/portal"],
|
|
586
|
+
dashboard: "/[teamSlug]/usage",
|
|
587
|
+
ui: { kind: "built" },
|
|
588
|
+
cli: {
|
|
589
|
+
kind: "excluded",
|
|
590
|
+
reason: "payment-flow",
|
|
591
|
+
note: "\uACB0\uC81C \uC218\uB2E8 \uBCC0\uACBD\uC740 Paddle \uD3EC\uD138\uC5D0\uC11C \uD55C\uB2E4."
|
|
592
|
+
},
|
|
593
|
+
mcp: {
|
|
594
|
+
kind: "excluded",
|
|
595
|
+
reason: "payment-flow",
|
|
596
|
+
note: "\uACB0\uC81C \uC218\uB2E8 \uBCC0\uACBD\uC740 Paddle \uD3EC\uD138\uC5D0\uC11C \uD55C\uB2E4. 2026-11-03 \uACB0\uC815(\uAD8C\uACE0\uB300\uB85C)."
|
|
597
|
+
}
|
|
598
|
+
},
|
|
599
|
+
{
|
|
600
|
+
id: "project-list",
|
|
601
|
+
domain: "projects",
|
|
602
|
+
title: "\uD504\uB85C\uC81D\uD2B8 \uBAA9\uB85D",
|
|
603
|
+
routes: ["GET projects"],
|
|
604
|
+
ui: { kind: "built" },
|
|
605
|
+
cli: { kind: "built", commands: ["naro projects"] },
|
|
606
|
+
mcp: { kind: "built", tools: ["list_projects"] }
|
|
607
|
+
},
|
|
608
|
+
{
|
|
609
|
+
id: "project-create",
|
|
610
|
+
domain: "projects",
|
|
611
|
+
title: "\uD504\uB85C\uC81D\uD2B8 \uC0DD\uC131",
|
|
612
|
+
routes: ["POST projects"],
|
|
613
|
+
ui: { kind: "built" },
|
|
614
|
+
// naro deploy가 링크가 없을 때 만든다(POST cli/deployments).
|
|
615
|
+
cli: { kind: "built" },
|
|
616
|
+
// deploy가 링크가 없을 때 만든다(POST cli/deployments).
|
|
617
|
+
mcp: { kind: "built" }
|
|
618
|
+
},
|
|
619
|
+
{
|
|
620
|
+
id: "project-get",
|
|
621
|
+
domain: "projects",
|
|
622
|
+
title: "\uD504\uB85C\uC81D\uD2B8 \uC870\uD68C",
|
|
623
|
+
routes: ["GET projects/[projectId]"],
|
|
624
|
+
ui: { kind: "built" },
|
|
625
|
+
cli: { kind: "built", commands: ["naro project inspect"] },
|
|
626
|
+
mcp: { kind: "built", tools: ["get_project"] }
|
|
627
|
+
},
|
|
628
|
+
{
|
|
629
|
+
id: "project-link",
|
|
630
|
+
domain: "projects",
|
|
631
|
+
title: "\uB514\uB809\uD130\uB9AC\uB97C \uD504\uB85C\uC81D\uD2B8\uC5D0 \uB9C1\uD06C",
|
|
632
|
+
ui: {
|
|
633
|
+
kind: "excluded",
|
|
634
|
+
reason: "local-filesystem",
|
|
635
|
+
note: ".naro/project.json\uC5D0 \uC4F4\uB2E4. \uC11C\uBC84\uAC00 \uD560 \uC218 \uC5C6\uB2E4."
|
|
636
|
+
},
|
|
637
|
+
cli: { kind: "built", commands: ["naro link", "naro init"] },
|
|
638
|
+
mcp: { kind: "built", tools: ["link_project"] }
|
|
639
|
+
},
|
|
640
|
+
{
|
|
641
|
+
id: "project-unlink",
|
|
642
|
+
domain: "projects",
|
|
643
|
+
title: "\uB9C1\uD06C \uD574\uC81C",
|
|
644
|
+
ui: {
|
|
645
|
+
kind: "excluded",
|
|
646
|
+
reason: "local-filesystem",
|
|
647
|
+
note: ".naro/\uB97C \uC9C0\uC6B4\uB2E4. \uC11C\uBC84\uAC00 \uD560 \uC218 \uC5C6\uB2E4."
|
|
648
|
+
},
|
|
649
|
+
cli: { kind: "built", commands: ["naro unlink"] },
|
|
650
|
+
mcp: {
|
|
651
|
+
kind: "excluded",
|
|
652
|
+
reason: "agent-native",
|
|
653
|
+
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."
|
|
654
|
+
}
|
|
655
|
+
},
|
|
656
|
+
{
|
|
657
|
+
id: "project-update",
|
|
658
|
+
domain: "projects",
|
|
659
|
+
title: "\uD504\uB85C\uC81D\uD2B8 \uC124\uC815 \uBCC0\uACBD(\uD504\uB808\uC784\uC6CC\uD06C\xB7\uC11C\uBE0C\uB3C4\uBA54\uC778)",
|
|
660
|
+
routes: ["PATCH projects/[projectId]"],
|
|
661
|
+
ui: { kind: "built" },
|
|
662
|
+
cli: { kind: "built", commands: ["naro project set"] },
|
|
663
|
+
// 서브도메인은 빼고(PR #433 리뷰): 옛 이름이 바로 비어 누구나 가져갈 수 있어
|
|
664
|
+
// 북마크·OAuth 리다이렉트가 남의 앱으로 간다. 대시보드와 CLI(먼저 묻는다)만.
|
|
665
|
+
mcp: { kind: "built", tools: ["update_project"] }
|
|
666
|
+
},
|
|
667
|
+
{
|
|
668
|
+
id: "project-delete",
|
|
669
|
+
domain: "projects",
|
|
670
|
+
title: "\uD504\uB85C\uC81D\uD2B8 \uC0AD\uC81C",
|
|
671
|
+
routes: ["DELETE projects/[projectId]"],
|
|
672
|
+
dashboard: "/[teamSlug]/projects/[projectSlug]/settings",
|
|
673
|
+
ui: { kind: "built" },
|
|
674
|
+
cli: { kind: "built", commands: ["naro project delete"] },
|
|
675
|
+
mcp: {
|
|
676
|
+
kind: "excluded",
|
|
677
|
+
reason: "irreversible",
|
|
678
|
+
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)."
|
|
679
|
+
}
|
|
680
|
+
},
|
|
681
|
+
{
|
|
682
|
+
id: "project-subdomain-check",
|
|
683
|
+
domain: "projects",
|
|
684
|
+
title: "\uC11C\uBE0C\uB3C4\uBA54\uC778 \uC0AC\uC6A9 \uAC00\uB2A5 \uC5EC\uBD80",
|
|
685
|
+
routes: ["GET subdomains/availability"],
|
|
686
|
+
ui: { kind: "built" },
|
|
687
|
+
cli: { kind: "built", commands: ["naro project check"] },
|
|
688
|
+
mcp: { kind: "built", tools: ["check_subdomain"] }
|
|
689
|
+
},
|
|
690
|
+
{
|
|
691
|
+
id: "project-access-list",
|
|
692
|
+
domain: "projects",
|
|
693
|
+
title: "\uBA64\uBC84\uBCC4 \uD504\uB85C\uC81D\uD2B8 \uC811\uADFC \uC870\uD68C",
|
|
694
|
+
routes: ["GET projects/[projectId]/access"],
|
|
695
|
+
ui: { kind: "built" },
|
|
696
|
+
cli: { kind: "built", commands: ["naro project access"] },
|
|
697
|
+
mcp: { kind: "built", tools: ["list_project_access"] }
|
|
698
|
+
},
|
|
699
|
+
{
|
|
700
|
+
id: "project-access-grant",
|
|
701
|
+
domain: "projects",
|
|
702
|
+
title: "\uBA64\uBC84\uC5D0\uAC8C \uD504\uB85C\uC81D\uD2B8 \uC811\uADFC \uBD80\uC5EC",
|
|
703
|
+
routes: ["PUT projects/[projectId]/access"],
|
|
704
|
+
dashboard: "/[teamSlug]/projects/[projectSlug]/access",
|
|
705
|
+
ui: { kind: "built" },
|
|
706
|
+
cli: { kind: "built", commands: ["naro project access grant"] },
|
|
707
|
+
mcp: {
|
|
708
|
+
kind: "excluded",
|
|
709
|
+
reason: "privilege-escalation",
|
|
710
|
+
note: "\uBA64\uBC84\uC758 \uD504\uB85C\uC81D\uD2B8 \uAD8C\uD55C\uC744 \uBC14\uAFBC\uB2E4. 2026-11-03 \uACB0\uC815(\uAD8C\uACE0\uB300\uB85C)."
|
|
711
|
+
}
|
|
712
|
+
},
|
|
713
|
+
{
|
|
714
|
+
id: "project-access-revoke",
|
|
715
|
+
domain: "projects",
|
|
716
|
+
title: "\uBA64\uBC84\uC758 \uD504\uB85C\uC81D\uD2B8 \uC811\uADFC \uD68C\uC218",
|
|
717
|
+
routes: ["DELETE projects/[projectId]/access"],
|
|
718
|
+
dashboard: "/[teamSlug]/projects/[projectSlug]/access",
|
|
719
|
+
ui: { kind: "built" },
|
|
720
|
+
cli: { kind: "built", commands: ["naro project access revoke"] },
|
|
721
|
+
mcp: {
|
|
722
|
+
kind: "excluded",
|
|
723
|
+
reason: "privilege-escalation",
|
|
724
|
+
note: "\uBA64\uBC84\uC758 \uD504\uB85C\uC81D\uD2B8 \uAD8C\uD55C\uC744 \uBC14\uAFBC\uB2E4. 2026-11-03 \uACB0\uC815(\uAD8C\uACE0\uB300\uB85C)."
|
|
725
|
+
}
|
|
726
|
+
},
|
|
727
|
+
{
|
|
728
|
+
id: "deployment-list",
|
|
729
|
+
domain: "deployments",
|
|
730
|
+
title: "\uBC30\uD3EC \uBAA9\uB85D",
|
|
731
|
+
routes: ["GET projects/[projectId]/deployments"],
|
|
732
|
+
ui: { kind: "built" },
|
|
733
|
+
cli: { kind: "built", commands: ["naro deployments"] },
|
|
734
|
+
mcp: { kind: "built", tools: ["list_deployments"] }
|
|
735
|
+
},
|
|
736
|
+
{
|
|
737
|
+
id: "deployment-create",
|
|
738
|
+
domain: "deployments",
|
|
739
|
+
title: "\uBE0C\uB79C\uCE58\uC5D0\uC11C \uC0C8\uB85C \uBC30\uD3EC",
|
|
740
|
+
routes: ["POST projects/[projectId]/deployments"],
|
|
741
|
+
ui: { kind: "built" },
|
|
742
|
+
cli: { kind: "built", commands: ["naro deployments create"] },
|
|
743
|
+
mcp: { kind: "built", tools: ["deploy_from_git"] }
|
|
744
|
+
},
|
|
745
|
+
{
|
|
746
|
+
id: "deployment-local",
|
|
747
|
+
domain: "deployments",
|
|
748
|
+
title: "\uB85C\uCEEC\uC5D0\uC11C \uBE4C\uB4DC\uD574 \uBC30\uD3EC",
|
|
749
|
+
routes: ["POST cli/deployments"],
|
|
750
|
+
ui: {
|
|
751
|
+
kind: "excluded",
|
|
752
|
+
reason: "local-filesystem",
|
|
753
|
+
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."
|
|
754
|
+
},
|
|
755
|
+
cli: { kind: "built", commands: ["naro deploy"] },
|
|
756
|
+
mcp: { kind: "built", tools: ["deploy"] }
|
|
757
|
+
},
|
|
758
|
+
{
|
|
759
|
+
id: "deployment-get",
|
|
760
|
+
domain: "deployments",
|
|
761
|
+
title: "\uBC30\uD3EC \uC0C1\uC138",
|
|
762
|
+
routes: ["GET deployments/[deploymentId]"],
|
|
763
|
+
ui: { kind: "built" },
|
|
764
|
+
cli: { kind: "built", commands: ["naro inspect"] },
|
|
765
|
+
mcp: { kind: "built", tools: ["get_deployment", "get_build_logs"] }
|
|
766
|
+
},
|
|
767
|
+
{
|
|
768
|
+
id: "deployment-cancel",
|
|
769
|
+
domain: "deployments",
|
|
770
|
+
title: "\uBE4C\uB4DC \uCDE8\uC18C",
|
|
771
|
+
routes: ["POST projects/[projectId]/deployments/[deploymentId]/cancel"],
|
|
772
|
+
ui: { kind: "built" },
|
|
773
|
+
cli: { kind: "built", commands: ["naro cancel"] },
|
|
774
|
+
mcp: { kind: "built", tools: ["cancel_deployment"] }
|
|
775
|
+
},
|
|
776
|
+
{
|
|
777
|
+
id: "deployment-promote-preview",
|
|
778
|
+
domain: "deployments",
|
|
779
|
+
title: "\uC2B9\uACA9 \uBBF8\uB9AC\uBCF4\uAE30",
|
|
780
|
+
routes: ["GET projects/[projectId]/deployments/[deploymentId]/promote"],
|
|
781
|
+
ui: { kind: "built" },
|
|
782
|
+
// naro promote가 묻기 전에 무엇을 할지 보여 준다(client.deployments.promoteCheck).
|
|
783
|
+
cli: { kind: "built" },
|
|
784
|
+
mcp: { kind: "built", tools: ["check_promotion"] }
|
|
785
|
+
},
|
|
786
|
+
{
|
|
787
|
+
id: "deployment-promote",
|
|
788
|
+
domain: "deployments",
|
|
789
|
+
title: "\uD504\uB85C\uB355\uC158\xB7\uD658\uACBD\uC73C\uB85C \uC2B9\uACA9(\uB864\uBC31 \uD3EC\uD568)",
|
|
790
|
+
routes: ["POST projects/[projectId]/deployments/[deploymentId]/promote"],
|
|
791
|
+
ui: { kind: "built" },
|
|
792
|
+
cli: { kind: "built", commands: ["naro promote", "naro rollback"] },
|
|
793
|
+
mcp: {
|
|
794
|
+
kind: "built",
|
|
795
|
+
tools: ["promote_deployment", "rollback_deployment"]
|
|
796
|
+
}
|
|
797
|
+
},
|
|
798
|
+
{
|
|
799
|
+
id: "git-app-install",
|
|
800
|
+
domain: "git",
|
|
801
|
+
title: "GitHub App \uC124\uCE58",
|
|
802
|
+
routes: ["GET github/authorize", "GET github/install", "GET github/setup"],
|
|
803
|
+
dashboard: "/[teamSlug]/projects/[projectSlug]/settings",
|
|
804
|
+
ui: { kind: "built" },
|
|
805
|
+
cli: {
|
|
806
|
+
kind: "excluded",
|
|
807
|
+
reason: "browser-required",
|
|
808
|
+
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."
|
|
809
|
+
},
|
|
810
|
+
mcp: {
|
|
811
|
+
kind: "excluded",
|
|
812
|
+
reason: "browser-required",
|
|
813
|
+
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."
|
|
814
|
+
}
|
|
815
|
+
},
|
|
816
|
+
{
|
|
817
|
+
id: "git-repository-list",
|
|
818
|
+
domain: "git",
|
|
819
|
+
title: "GitHub \uC800\uC7A5\uC18C \uBAA9\uB85D",
|
|
820
|
+
routes: ["GET github/repositories"],
|
|
821
|
+
ui: { kind: "built" },
|
|
822
|
+
// naro git connect가 저장소를 고를 때 읽는다(client.github.listRepositories).
|
|
823
|
+
cli: { kind: "built" },
|
|
824
|
+
mcp: { kind: "built", tools: ["list_git_repositories"] }
|
|
825
|
+
},
|
|
826
|
+
{
|
|
827
|
+
id: "git-connect",
|
|
828
|
+
domain: "git",
|
|
829
|
+
title: "\uC800\uC7A5\uC18C \uC5F0\uACB0",
|
|
830
|
+
routes: ["POST projects/[projectId]/git"],
|
|
831
|
+
ui: { kind: "built" },
|
|
832
|
+
cli: { kind: "built", commands: ["naro git connect"] },
|
|
833
|
+
mcp: { kind: "built", tools: ["connect_git_repository"] }
|
|
834
|
+
},
|
|
835
|
+
{
|
|
836
|
+
id: "git-disconnect",
|
|
837
|
+
domain: "git",
|
|
838
|
+
title: "\uC800\uC7A5\uC18C \uC5F0\uACB0 \uD574\uC81C",
|
|
839
|
+
routes: ["DELETE projects/[projectId]/git"],
|
|
840
|
+
ui: { kind: "built" },
|
|
841
|
+
cli: { kind: "built", commands: ["naro git disconnect"] },
|
|
842
|
+
mcp: { kind: "built", tools: ["disconnect_git_repository"] }
|
|
843
|
+
},
|
|
844
|
+
{
|
|
845
|
+
id: "env-list",
|
|
846
|
+
domain: "env",
|
|
847
|
+
title: "\uD658\uACBD\uBCC0\uC218 \uBAA9\uB85D",
|
|
848
|
+
routes: ["GET projects/[projectId]/env"],
|
|
849
|
+
ui: { kind: "built" },
|
|
850
|
+
cli: { kind: "built", commands: ["naro env list"] },
|
|
851
|
+
mcp: { kind: "built", tools: ["list_environment_variables"] }
|
|
852
|
+
},
|
|
853
|
+
{
|
|
854
|
+
id: "env-set",
|
|
855
|
+
domain: "env",
|
|
856
|
+
title: "\uD658\uACBD\uBCC0\uC218 \uCD94\uAC00\xB7\uC218\uC815",
|
|
857
|
+
routes: ["POST projects/[projectId]/env"],
|
|
858
|
+
ui: { kind: "built" },
|
|
859
|
+
cli: { kind: "built", commands: ["naro env add", "naro env import"] },
|
|
860
|
+
mcp: { kind: "built", tools: ["set_environment_variable"] }
|
|
861
|
+
},
|
|
862
|
+
{
|
|
863
|
+
id: "env-remove",
|
|
864
|
+
domain: "env",
|
|
865
|
+
title: "\uD658\uACBD\uBCC0\uC218 \uC81C\uAC70",
|
|
866
|
+
routes: ["DELETE projects/[projectId]/env/[envVarId]"],
|
|
867
|
+
ui: { kind: "built" },
|
|
868
|
+
cli: { kind: "built", commands: ["naro env remove"] },
|
|
869
|
+
mcp: { kind: "built", tools: ["remove_environment_variable"] }
|
|
870
|
+
},
|
|
871
|
+
// 앱 메일의 Resend 연결(spec 2026-11-04 resend-email-integration). 연결은
|
|
872
|
+
// env 두 행이라 env 도메인에 둔다. CLI·MCP는 그 스펙의 PR 2다.
|
|
873
|
+
{
|
|
874
|
+
id: "email-status",
|
|
875
|
+
domain: "env",
|
|
876
|
+
title: "Resend \uC5F0\uACB0 \uBCF4\uAE30",
|
|
877
|
+
routes: ["GET projects/[projectId]/email"],
|
|
878
|
+
ui: { kind: "built" },
|
|
879
|
+
cli: { kind: "planned", note: "naro email status \u2014 \uC2A4\uD399 \xA713 PR 2." },
|
|
880
|
+
mcp: { kind: "planned", note: "get_email \u2014 \uC2A4\uD399 \xA713 PR 2." }
|
|
881
|
+
},
|
|
882
|
+
{
|
|
883
|
+
id: "email-connect",
|
|
884
|
+
domain: "env",
|
|
885
|
+
title: "Resend \uC5F0\uACB0\xB7\uBC14\uAFB8\uAE30",
|
|
886
|
+
routes: ["PUT projects/[projectId]/email"],
|
|
887
|
+
dashboard: "/[teamSlug]/projects/[projectSlug]/email",
|
|
888
|
+
ui: { kind: "built" },
|
|
889
|
+
cli: {
|
|
890
|
+
kind: "planned",
|
|
891
|
+
note: "naro email connect --api-key-stdin \u2014 \uC2A4\uD399 \xA713 PR 2."
|
|
892
|
+
},
|
|
893
|
+
mcp: {
|
|
894
|
+
kind: "excluded",
|
|
895
|
+
reason: "secret-value",
|
|
896
|
+
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)."
|
|
897
|
+
}
|
|
898
|
+
},
|
|
899
|
+
{
|
|
900
|
+
id: "email-disconnect",
|
|
901
|
+
domain: "env",
|
|
902
|
+
title: "Resend \uC5F0\uACB0 \uB04A\uAE30",
|
|
903
|
+
routes: ["DELETE projects/[projectId]/email"],
|
|
904
|
+
ui: { kind: "built" },
|
|
905
|
+
cli: { kind: "planned", note: "naro email disconnect \u2014 \uC2A4\uD399 \xA713 PR 2." },
|
|
906
|
+
mcp: { kind: "planned", note: "disconnect_email \u2014 \uC2A4\uD399 \xA713 PR 2." }
|
|
907
|
+
},
|
|
908
|
+
{
|
|
909
|
+
id: "env-pull",
|
|
910
|
+
domain: "env",
|
|
911
|
+
title: "\uD658\uACBD\uBCC0\uC218\uB97C \uB85C\uCEEC\uB85C \uB0B4\uB9AC\uAE30",
|
|
912
|
+
ui: {
|
|
913
|
+
kind: "excluded",
|
|
914
|
+
reason: "local-filesystem",
|
|
915
|
+
note: ".env.local\uC5D0 \uC4F4\uB2E4. \uC11C\uBC84\uAC00 \uD560 \uC218 \uC5C6\uB2E4."
|
|
916
|
+
},
|
|
917
|
+
cli: { kind: "built", commands: ["naro env pull"] },
|
|
918
|
+
mcp: {
|
|
919
|
+
kind: "excluded",
|
|
920
|
+
reason: "secret-value",
|
|
921
|
+
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."
|
|
922
|
+
}
|
|
923
|
+
},
|
|
924
|
+
{
|
|
925
|
+
id: "environment-list",
|
|
926
|
+
domain: "environments",
|
|
927
|
+
title: "\uD658\uACBD \uBAA9\uB85D",
|
|
928
|
+
routes: ["GET projects/[projectId]/environments"],
|
|
929
|
+
ui: { kind: "built" },
|
|
930
|
+
cli: { kind: "built", commands: ["naro environments"] },
|
|
931
|
+
mcp: { kind: "built", tools: ["list_environments"] }
|
|
932
|
+
},
|
|
933
|
+
{
|
|
934
|
+
id: "environment-create",
|
|
935
|
+
domain: "environments",
|
|
936
|
+
title: "\uD658\uACBD \uB9CC\uB4E4\uAE30",
|
|
937
|
+
routes: ["POST projects/[projectId]/environments"],
|
|
938
|
+
ui: { kind: "built" },
|
|
939
|
+
cli: { kind: "built", commands: ["naro environments create"] },
|
|
940
|
+
mcp: { kind: "built", tools: ["create_environment"] }
|
|
941
|
+
},
|
|
942
|
+
{
|
|
943
|
+
id: "environment-update",
|
|
944
|
+
domain: "environments",
|
|
945
|
+
title: "\uD658\uACBD \uC124\uC815 \uBCC0\uACBD(\uBE0C\uB79C\uCE58\xB7\uBCF4\uD638)",
|
|
946
|
+
routes: ["PATCH projects/[projectId]/environments/[environmentId]"],
|
|
947
|
+
ui: { kind: "built" },
|
|
948
|
+
cli: { kind: "built", commands: ["naro environments set"] },
|
|
949
|
+
mcp: { kind: "built", tools: ["update_environment"] }
|
|
950
|
+
},
|
|
951
|
+
{
|
|
952
|
+
id: "environment-delete",
|
|
953
|
+
domain: "environments",
|
|
954
|
+
title: "\uD658\uACBD \uC0AD\uC81C",
|
|
955
|
+
routes: ["DELETE projects/[projectId]/environments/[environmentId]"],
|
|
956
|
+
ui: { kind: "built" },
|
|
957
|
+
cli: { kind: "built", commands: ["naro environments delete"] },
|
|
958
|
+
mcp: { kind: "built", tools: ["delete_environment"] }
|
|
959
|
+
},
|
|
960
|
+
{
|
|
961
|
+
id: "environment-provision",
|
|
962
|
+
domain: "environments",
|
|
963
|
+
title: "\uD658\uACBD \uB370\uC774\uD130 \uD504\uB85C\uBE44\uC800\uB2DD",
|
|
964
|
+
routes: [
|
|
965
|
+
"POST projects/[projectId]/environments/[environmentId]/provision"
|
|
966
|
+
],
|
|
967
|
+
ui: { kind: "built" },
|
|
968
|
+
cli: { kind: "built", commands: ["naro environments provision"] },
|
|
969
|
+
mcp: { kind: "built", tools: ["provision_environment"] }
|
|
970
|
+
},
|
|
971
|
+
{
|
|
972
|
+
id: "domain-list",
|
|
973
|
+
domain: "domains",
|
|
974
|
+
title: "\uB3C4\uBA54\uC778 \uBAA9\uB85D",
|
|
975
|
+
routes: ["GET projects/[projectId]/domains"],
|
|
976
|
+
ui: { kind: "built" },
|
|
977
|
+
cli: { kind: "built", commands: ["naro domains list"] },
|
|
978
|
+
mcp: { kind: "built", tools: ["list_domains"] }
|
|
979
|
+
},
|
|
980
|
+
{
|
|
981
|
+
id: "domain-add",
|
|
982
|
+
domain: "domains",
|
|
983
|
+
title: "\uB3C4\uBA54\uC778 \uCD94\uAC00",
|
|
984
|
+
routes: ["POST projects/[projectId]/domains"],
|
|
985
|
+
ui: { kind: "built" },
|
|
986
|
+
cli: { kind: "built", commands: ["naro domains add"] },
|
|
987
|
+
mcp: { kind: "built", tools: ["add_domain"] }
|
|
988
|
+
},
|
|
989
|
+
{
|
|
990
|
+
id: "domain-refresh",
|
|
991
|
+
domain: "domains",
|
|
992
|
+
title: "\uB3C4\uBA54\uC778 \uC0C1\uD0DC \uC0C8\uB85C\uACE0\uCE68",
|
|
993
|
+
routes: ["PATCH projects/[projectId]/domains/[domainId]"],
|
|
994
|
+
ui: { kind: "built" },
|
|
995
|
+
// naro domains verify가 Cloudflare 재확인까지 해서 refresh(저장된 상태 다시 읽기)의
|
|
996
|
+
// 상위다. 같은 PATCH는 부르지 않는다.
|
|
997
|
+
cli: { kind: "built" },
|
|
998
|
+
// verify_domain이 같은 일을 더 한다(재확인 + DNS 점검).
|
|
999
|
+
mcp: { kind: "built" }
|
|
1000
|
+
},
|
|
1001
|
+
{
|
|
1002
|
+
id: "domain-remove",
|
|
1003
|
+
domain: "domains",
|
|
1004
|
+
title: "\uB3C4\uBA54\uC778 \uC81C\uAC70",
|
|
1005
|
+
routes: ["DELETE projects/[projectId]/domains/[domainId]"],
|
|
1006
|
+
ui: { kind: "built" },
|
|
1007
|
+
cli: { kind: "built", commands: ["naro domains remove"] },
|
|
1008
|
+
mcp: { kind: "built", tools: ["remove_domain"] }
|
|
1009
|
+
},
|
|
1010
|
+
{
|
|
1011
|
+
id: "domain-verify",
|
|
1012
|
+
domain: "domains",
|
|
1013
|
+
title: "DNS \uC7AC\uAC80\uC99D",
|
|
1014
|
+
routes: ["POST projects/[projectId]/domains/[domainId]/verify"],
|
|
1015
|
+
ui: { kind: "built" },
|
|
1016
|
+
cli: { kind: "built", commands: ["naro domains verify"] },
|
|
1017
|
+
mcp: { kind: "built", tools: ["verify_domain"] }
|
|
1018
|
+
},
|
|
1019
|
+
{
|
|
1020
|
+
id: "domain-claim-list",
|
|
1021
|
+
domain: "domains",
|
|
1022
|
+
title: "\uB2E4\uB978 \uD504\uB85C\uC81D\uD2B8\uAC00 \uAC00\uC9C4 \uB3C4\uBA54\uC778\uC758 \uC18C\uC720\uAD8C \uD655\uC778 \uBAA9\uB85D",
|
|
1023
|
+
routes: ["GET projects/[projectId]/domain-claims"],
|
|
1024
|
+
ui: { kind: "built" },
|
|
1025
|
+
// naro domains verify가 소유권 확인을 함께 읽는다(client.domains.listClaims).
|
|
1026
|
+
cli: { kind: "built" },
|
|
1027
|
+
// verify_domain이 소유권 확인을 함께 읽는다(client.domains.listClaims).
|
|
1028
|
+
mcp: { kind: "built" }
|
|
1029
|
+
},
|
|
1030
|
+
{
|
|
1031
|
+
id: "domain-claim-verify",
|
|
1032
|
+
domain: "domains",
|
|
1033
|
+
title: "\uB3C4\uBA54\uC778 \uC18C\uC720\uAD8C \uD655\uC778",
|
|
1034
|
+
routes: ["POST projects/[projectId]/domain-claims/[claimId]/verify"],
|
|
1035
|
+
ui: { kind: "built" },
|
|
1036
|
+
// naro domains verify가 소유권 확인을 함께 다시 본다(client.domains.verifyClaim).
|
|
1037
|
+
cli: { kind: "built" },
|
|
1038
|
+
// verify_domain이 소유권 확인을 함께 다시 본다(client.domains.verifyClaim).
|
|
1039
|
+
mcp: { kind: "built" }
|
|
1040
|
+
},
|
|
1041
|
+
{
|
|
1042
|
+
id: "domain-claim-cancel",
|
|
1043
|
+
domain: "domains",
|
|
1044
|
+
title: "\uB3C4\uBA54\uC778 \uC18C\uC720\uAD8C \uD655\uC778 \uCDE8\uC18C",
|
|
1045
|
+
routes: ["DELETE projects/[projectId]/domain-claims/[claimId]"],
|
|
1046
|
+
ui: { kind: "built" },
|
|
1047
|
+
// naro domains remove가 붙어 있지 않은 호스트의 소유권 확인을 취소한다.
|
|
1048
|
+
cli: { kind: "built" },
|
|
1049
|
+
// remove_domain이 붙어 있지 않은 호스트의 소유권 확인을 취소한다(claimCancelled).
|
|
1050
|
+
mcp: { kind: "built" }
|
|
1051
|
+
},
|
|
1052
|
+
{
|
|
1053
|
+
id: "dns-zone-list",
|
|
1054
|
+
domain: "dns",
|
|
1055
|
+
title: "DNS \uC874 \uBAA9\uB85D",
|
|
1056
|
+
routes: ["GET teams/[teamSlug]/dns-zones"],
|
|
1057
|
+
ui: { kind: "built" },
|
|
1058
|
+
cli: { kind: "built", commands: ["naro dns"] },
|
|
1059
|
+
mcp: { kind: "built", tools: ["get_dns"] }
|
|
1060
|
+
},
|
|
1061
|
+
{
|
|
1062
|
+
id: "dns-zone-add",
|
|
1063
|
+
domain: "dns",
|
|
1064
|
+
title: "DNS \uC874 \uCD94\uAC00",
|
|
1065
|
+
routes: ["POST teams/[teamSlug]/dns-zones"],
|
|
1066
|
+
ui: { kind: "built" },
|
|
1067
|
+
cli: { kind: "built", commands: ["naro dns add"] },
|
|
1068
|
+
mcp: { kind: "built", tools: ["add_dns_zone"] }
|
|
1069
|
+
},
|
|
1070
|
+
{
|
|
1071
|
+
id: "dns-zone-remove",
|
|
1072
|
+
domain: "dns",
|
|
1073
|
+
title: "DNS \uC874 \uC0AD\uC81C",
|
|
1074
|
+
routes: ["DELETE teams/[teamSlug]/dns-zones/[zoneId]"],
|
|
1075
|
+
ui: { kind: "built" },
|
|
1076
|
+
cli: { kind: "built", commands: ["naro dns remove"] },
|
|
1077
|
+
mcp: { kind: "built", tools: ["remove_dns_zone"] }
|
|
1078
|
+
},
|
|
1079
|
+
{
|
|
1080
|
+
id: "dns-zone-check",
|
|
1081
|
+
domain: "dns",
|
|
1082
|
+
title: "\uB124\uC784\uC11C\uBC84 \uC774\uAD00 \uD655\uC778",
|
|
1083
|
+
routes: ["POST teams/[teamSlug]/dns-zones/[zoneId]/check"],
|
|
1084
|
+
ui: { kind: "built" },
|
|
1085
|
+
cli: { kind: "built", commands: ["naro dns check"] },
|
|
1086
|
+
mcp: { kind: "built", tools: ["check_dns_zone"] }
|
|
1087
|
+
},
|
|
1088
|
+
{
|
|
1089
|
+
id: "dns-zone-precheck",
|
|
1090
|
+
domain: "dns",
|
|
1091
|
+
title: "\uC774\uAD00 \uC804 \uBA54\uC77C \uD655\uC778",
|
|
1092
|
+
routes: ["GET teams/[teamSlug]/dns-zones/[zoneId]/precheck"],
|
|
1093
|
+
ui: { kind: "built" },
|
|
1094
|
+
cli: { kind: "built", commands: ["naro dns mail"] },
|
|
1095
|
+
mcp: { kind: "built", tools: ["check_dns_mail"] }
|
|
1096
|
+
},
|
|
1097
|
+
{
|
|
1098
|
+
id: "dns-zone-scan",
|
|
1099
|
+
domain: "dns",
|
|
1100
|
+
title: "\uAE30\uC874 DNS \uB808\uCF54\uB4DC \uC2A4\uCE94 \uACB0\uACFC",
|
|
1101
|
+
routes: ["GET teams/[teamSlug]/dns-zones/[zoneId]/scan"],
|
|
1102
|
+
ui: { kind: "built" },
|
|
1103
|
+
cli: { kind: "built", commands: ["naro dns scan"] },
|
|
1104
|
+
mcp: { kind: "built", tools: ["get_dns_scan"] }
|
|
1105
|
+
},
|
|
1106
|
+
{
|
|
1107
|
+
id: "dns-zone-scan-import",
|
|
1108
|
+
domain: "dns",
|
|
1109
|
+
title: "\uC2A4\uCE94\uD55C \uB808\uCF54\uB4DC \uC77C\uAD04 \uAC00\uC838\uC624\uAE30",
|
|
1110
|
+
routes: ["POST teams/[teamSlug]/dns-zones/[zoneId]/scan"],
|
|
1111
|
+
ui: { kind: "built" },
|
|
1112
|
+
cli: { kind: "built", commands: ["naro dns import"] },
|
|
1113
|
+
mcp: { kind: "built", tools: ["import_dns_scan"] }
|
|
1114
|
+
},
|
|
1115
|
+
{
|
|
1116
|
+
id: "dns-record-list",
|
|
1117
|
+
domain: "dns",
|
|
1118
|
+
title: "DNS \uB808\uCF54\uB4DC \uBAA9\uB85D",
|
|
1119
|
+
routes: ["GET teams/[teamSlug]/dns-zones/[zoneId]/records"],
|
|
1120
|
+
ui: { kind: "built" },
|
|
1121
|
+
cli: { kind: "built", commands: ["naro dns records"] },
|
|
1122
|
+
mcp: { kind: "built", tools: ["list_dns_records"] }
|
|
1123
|
+
},
|
|
1124
|
+
{
|
|
1125
|
+
id: "dns-record-add",
|
|
1126
|
+
domain: "dns",
|
|
1127
|
+
title: "DNS \uB808\uCF54\uB4DC \uCD94\uAC00",
|
|
1128
|
+
routes: ["POST teams/[teamSlug]/dns-zones/[zoneId]/records"],
|
|
1129
|
+
ui: { kind: "built" },
|
|
1130
|
+
cli: { kind: "built", commands: ["naro dns records add"] },
|
|
1131
|
+
mcp: { kind: "built", tools: ["add_dns_record"] }
|
|
1132
|
+
},
|
|
1133
|
+
{
|
|
1134
|
+
id: "dns-record-update",
|
|
1135
|
+
domain: "dns",
|
|
1136
|
+
title: "DNS \uB808\uCF54\uB4DC \uC218\uC815",
|
|
1137
|
+
routes: ["PATCH teams/[teamSlug]/dns-zones/[zoneId]/records/[recordId]"],
|
|
1138
|
+
ui: { kind: "built" },
|
|
1139
|
+
cli: { kind: "built", commands: ["naro dns records update"] },
|
|
1140
|
+
mcp: { kind: "built", tools: ["update_dns_record"] }
|
|
1141
|
+
},
|
|
1142
|
+
{
|
|
1143
|
+
id: "dns-record-remove",
|
|
1144
|
+
domain: "dns",
|
|
1145
|
+
title: "DNS \uB808\uCF54\uB4DC \uC0AD\uC81C",
|
|
1146
|
+
routes: ["DELETE teams/[teamSlug]/dns-zones/[zoneId]/records/[recordId]"],
|
|
1147
|
+
ui: { kind: "built" },
|
|
1148
|
+
cli: { kind: "built", commands: ["naro dns records remove"] },
|
|
1149
|
+
mcp: { kind: "built", tools: ["remove_dns_record"] }
|
|
1150
|
+
},
|
|
1151
|
+
{
|
|
1152
|
+
id: "protection-get",
|
|
1153
|
+
domain: "protection",
|
|
1154
|
+
title: "\uD504\uB9AC\uBDF0 \uBCF4\uD638 \uC0C1\uD0DC",
|
|
1155
|
+
routes: ["GET projects/[projectId]/preview-protection"],
|
|
1156
|
+
ui: { kind: "built" },
|
|
1157
|
+
cli: { kind: "built", commands: ["naro protection"] },
|
|
1158
|
+
mcp: { kind: "built", tools: ["get_preview_protection"] }
|
|
1159
|
+
},
|
|
1160
|
+
{
|
|
1161
|
+
id: "protection-set",
|
|
1162
|
+
domain: "protection",
|
|
1163
|
+
title: "\uD504\uB9AC\uBDF0 \uBCF4\uD638 \uCF1C\uAE30\xB7\uB044\uAE30",
|
|
1164
|
+
routes: ["PUT projects/[projectId]/preview-protection"],
|
|
1165
|
+
ui: { kind: "built" },
|
|
1166
|
+
cli: {
|
|
1167
|
+
kind: "built",
|
|
1168
|
+
commands: ["naro protection enable", "naro protection disable"]
|
|
1169
|
+
},
|
|
1170
|
+
mcp: { kind: "built", tools: ["set_preview_protection"] }
|
|
1171
|
+
},
|
|
1172
|
+
{
|
|
1173
|
+
id: "protection-bypass-create",
|
|
1174
|
+
domain: "protection",
|
|
1175
|
+
title: "\uC6B0\uD68C \uC2DC\uD06C\uB9BF \uB9CC\uB4E4\uAE30",
|
|
1176
|
+
routes: ["POST projects/[projectId]/preview-protection/bypass"],
|
|
1177
|
+
dashboard: "/[teamSlug]/projects/[projectSlug]/settings",
|
|
1178
|
+
ui: { kind: "built" },
|
|
1179
|
+
cli: { kind: "built", commands: ["naro protection bypass"] },
|
|
1180
|
+
mcp: {
|
|
1181
|
+
kind: "excluded",
|
|
1182
|
+
reason: "secret-value",
|
|
1183
|
+
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."
|
|
1184
|
+
}
|
|
1185
|
+
},
|
|
1186
|
+
{
|
|
1187
|
+
id: "protection-bypass-remove",
|
|
1188
|
+
domain: "protection",
|
|
1189
|
+
title: "\uC6B0\uD68C \uC2DC\uD06C\uB9BF \uC81C\uAC70",
|
|
1190
|
+
routes: ["DELETE projects/[projectId]/preview-protection/bypass"],
|
|
1191
|
+
ui: { kind: "built" },
|
|
1192
|
+
cli: { kind: "built", commands: ["naro protection bypass remove"] },
|
|
1193
|
+
mcp: { kind: "built", tools: ["remove_preview_protection_bypass"] }
|
|
1194
|
+
},
|
|
1195
|
+
{
|
|
1196
|
+
id: "database-info",
|
|
1197
|
+
domain: "database",
|
|
1198
|
+
title: "\uB370\uC774\uD130\uBCA0\uC774\uC2A4 \uC0C1\uD0DC\xB7\uC6A9\uB7C9\xB7\uD55C\uB3C4",
|
|
1199
|
+
routes: ["GET projects/[projectId]/database"],
|
|
1200
|
+
ui: { kind: "built" },
|
|
1201
|
+
cli: { kind: "built", commands: ["naro db info"] },
|
|
1202
|
+
mcp: { kind: "built", tools: ["get_database"] }
|
|
1203
|
+
},
|
|
1204
|
+
{
|
|
1205
|
+
id: "database-enable",
|
|
1206
|
+
domain: "database",
|
|
1207
|
+
title: "\uB370\uC774\uD130\uBCA0\uC774\uC2A4 \uB9CC\uB4E4\uAE30",
|
|
1208
|
+
routes: ["POST projects/[projectId]/database"],
|
|
1209
|
+
ui: { kind: "built" },
|
|
1210
|
+
cli: { kind: "built", commands: ["naro db enable"] },
|
|
1211
|
+
mcp: { kind: "built", tools: ["enable_database"] }
|
|
1212
|
+
},
|
|
1213
|
+
{
|
|
1214
|
+
id: "database-query",
|
|
1215
|
+
domain: "database",
|
|
1216
|
+
title: "SQL \uC2E4\uD589",
|
|
1217
|
+
routes: ["POST projects/[projectId]/database/query"],
|
|
1218
|
+
ui: { kind: "built" },
|
|
1219
|
+
cli: { kind: "built", commands: ["naro db query"] },
|
|
1220
|
+
mcp: { kind: "built", tools: ["execute_sql"] }
|
|
1221
|
+
},
|
|
1222
|
+
{
|
|
1223
|
+
id: "database-tables",
|
|
1224
|
+
domain: "database",
|
|
1225
|
+
title: "\uD14C\uC774\uBE14 \uBAA9\uB85D",
|
|
1226
|
+
routes: ["GET projects/[projectId]/database/tables"],
|
|
1227
|
+
ui: { kind: "built" },
|
|
1228
|
+
// naro db 명령들이 테이블 목록을 읽는다(client.db.tables).
|
|
1229
|
+
cli: { kind: "built" },
|
|
1230
|
+
mcp: { kind: "built", tools: ["list_tables"] }
|
|
1231
|
+
},
|
|
1232
|
+
{
|
|
1233
|
+
id: "database-schema-change",
|
|
1234
|
+
domain: "database",
|
|
1235
|
+
title: "\uD14C\uC774\uBE14\xB7\uC778\uB371\uC2A4 \uBC14\uAFB8\uAE30",
|
|
1236
|
+
routes: ["POST projects/[projectId]/database/schema"],
|
|
1237
|
+
ui: { kind: "built" },
|
|
1238
|
+
cli: {
|
|
1239
|
+
kind: "built",
|
|
1240
|
+
commands: [
|
|
1241
|
+
"naro db table create",
|
|
1242
|
+
"naro db table add-column",
|
|
1243
|
+
"naro db table rename-column",
|
|
1244
|
+
"naro db table rename",
|
|
1245
|
+
"naro db table drop-column",
|
|
1246
|
+
"naro db table drop",
|
|
1247
|
+
"naro db index create",
|
|
1248
|
+
"naro db index drop"
|
|
1249
|
+
]
|
|
1250
|
+
},
|
|
1251
|
+
mcp: {
|
|
1252
|
+
kind: "built",
|
|
1253
|
+
tools: [
|
|
1254
|
+
"create_table",
|
|
1255
|
+
"alter_table",
|
|
1256
|
+
"drop_table",
|
|
1257
|
+
"create_index",
|
|
1258
|
+
"drop_index"
|
|
1259
|
+
]
|
|
1260
|
+
}
|
|
1261
|
+
},
|
|
1262
|
+
{
|
|
1263
|
+
id: "database-migration-list",
|
|
1264
|
+
domain: "database",
|
|
1265
|
+
title: "\uB9C8\uC774\uADF8\uB808\uC774\uC158 \uBAA9\uB85D",
|
|
1266
|
+
routes: ["GET projects/[projectId]/database/migrations"],
|
|
1267
|
+
ui: { kind: "built" },
|
|
1268
|
+
cli: { kind: "built", commands: ["naro migration list"] },
|
|
1269
|
+
mcp: { kind: "built", tools: ["list_migrations"] }
|
|
1270
|
+
},
|
|
1271
|
+
{
|
|
1272
|
+
id: "database-migration-apply",
|
|
1273
|
+
domain: "database",
|
|
1274
|
+
title: "\uB9C8\uC774\uADF8\uB808\uC774\uC158 \uC801\uC6A9",
|
|
1275
|
+
routes: ["POST projects/[projectId]/database/migrations"],
|
|
1276
|
+
ui: { kind: "built" },
|
|
1277
|
+
cli: { kind: "built", commands: ["naro db push", "naro migration up"] },
|
|
1278
|
+
mcp: { kind: "built", tools: ["apply_migration"] }
|
|
1279
|
+
},
|
|
1280
|
+
{
|
|
1281
|
+
id: "database-export",
|
|
1282
|
+
domain: "database",
|
|
1283
|
+
title: "\uB364\uD504 \uB0B4\uB824\uBC1B\uAE30",
|
|
1284
|
+
routes: ["POST projects/[projectId]/database/export"],
|
|
1285
|
+
ui: { kind: "built" },
|
|
1286
|
+
cli: { kind: "built", commands: ["naro db dump"] },
|
|
1287
|
+
mcp: { kind: "built", tools: ["export_database"] }
|
|
1288
|
+
},
|
|
1289
|
+
{
|
|
1290
|
+
id: "database-restore",
|
|
1291
|
+
domain: "database",
|
|
1292
|
+
title: "Time Travel \uBCF5\uAD6C",
|
|
1293
|
+
routes: ["POST projects/[projectId]/database/restore"],
|
|
1294
|
+
ui: { kind: "built" },
|
|
1295
|
+
cli: { kind: "built", commands: ["naro db restore"] },
|
|
1296
|
+
mcp: { kind: "built", tools: ["restore_database"] }
|
|
1297
|
+
},
|
|
1298
|
+
{
|
|
1299
|
+
id: "database-bookmark",
|
|
1300
|
+
domain: "database",
|
|
1301
|
+
title: "\uBCF5\uAD6C \uC9C0\uC810(\uBD81\uB9C8\uD06C) \uC870\uD68C",
|
|
1302
|
+
routes: ["GET projects/[projectId]/database/bookmark"],
|
|
1303
|
+
ui: { kind: "built" },
|
|
1304
|
+
// naro db restore가 되돌릴 북마크를 먼저 읽는다(client.db.bookmark).
|
|
1305
|
+
cli: { kind: "built" },
|
|
1306
|
+
// restore_database가 되돌릴 북마크를 먼저 읽는다(client.db.bookmark).
|
|
1307
|
+
mcp: { kind: "built" }
|
|
1308
|
+
},
|
|
1309
|
+
{
|
|
1310
|
+
id: "database-pull",
|
|
1311
|
+
domain: "database",
|
|
1312
|
+
title: "\uC6D0\uACA9 \uC2A4\uD0A4\uB9C8\uB97C \uBCA0\uC774\uC2A4\uB77C\uC778 \uB9C8\uC774\uADF8\uB808\uC774\uC158\uC73C\uB85C",
|
|
1313
|
+
routes: ["POST projects/[projectId]/database/pull"],
|
|
1314
|
+
ui: {
|
|
1315
|
+
kind: "excluded",
|
|
1316
|
+
reason: "local-filesystem",
|
|
1317
|
+
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."
|
|
1318
|
+
},
|
|
1319
|
+
cli: { kind: "built", commands: ["naro db pull"] },
|
|
1320
|
+
mcp: { kind: "built", tools: ["pull_database_schema"] }
|
|
1321
|
+
},
|
|
1322
|
+
{
|
|
1323
|
+
id: "database-reset",
|
|
1324
|
+
domain: "database",
|
|
1325
|
+
title: "\uC804\uCCB4 \uB9AC\uC14B \uD6C4 \uB9C8\uC774\uADF8\uB808\uC774\uC158 \uB2E4\uC2DC \uC801\uC6A9",
|
|
1326
|
+
ui: {
|
|
1327
|
+
kind: "excluded",
|
|
1328
|
+
reason: "local-filesystem",
|
|
1329
|
+
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."
|
|
1330
|
+
},
|
|
1331
|
+
cli: { kind: "built", commands: ["naro db reset"] },
|
|
1332
|
+
mcp: {
|
|
1333
|
+
kind: "excluded",
|
|
1334
|
+
reason: "irreversible",
|
|
1335
|
+
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)."
|
|
1336
|
+
}
|
|
1337
|
+
},
|
|
1338
|
+
{
|
|
1339
|
+
id: "database-lint",
|
|
1340
|
+
domain: "database",
|
|
1341
|
+
title: "\uC2A4\uD0A4\uB9C8\xB7RLS \uC815\uCC45 \uB9B0\uD2B8",
|
|
1342
|
+
ui: { kind: "built" },
|
|
1343
|
+
cli: { kind: "built", commands: ["naro db lint"] },
|
|
1344
|
+
mcp: { kind: "built", tools: ["lint_database"] }
|
|
1345
|
+
},
|
|
1346
|
+
{
|
|
1347
|
+
id: "database-gen-types",
|
|
1348
|
+
domain: "database",
|
|
1349
|
+
title: "\uC2A4\uD0A4\uB9C8\uC5D0\uC11C TypeScript \uD0C0\uC785 \uC0DD\uC131",
|
|
1350
|
+
ui: { kind: "built" },
|
|
1351
|
+
cli: { kind: "built", commands: ["naro gen types"] },
|
|
1352
|
+
mcp: { kind: "built", tools: ["generate_typescript_types"] }
|
|
1353
|
+
},
|
|
1354
|
+
{
|
|
1355
|
+
id: "database-migration-new",
|
|
1356
|
+
domain: "database",
|
|
1357
|
+
title: "\uC0C8 \uB9C8\uC774\uADF8\uB808\uC774\uC158 \uD30C\uC77C",
|
|
1358
|
+
ui: {
|
|
1359
|
+
kind: "excluded",
|
|
1360
|
+
reason: "local-filesystem",
|
|
1361
|
+
note: "./migrations\uC5D0 \uD30C\uC77C\uC744 \uB9CC\uB4E0\uB2E4. \uC11C\uBC84\uAC00 \uD560 \uC218 \uC5C6\uB2E4."
|
|
1362
|
+
},
|
|
1363
|
+
cli: { kind: "built", commands: ["naro migration new"] },
|
|
1364
|
+
mcp: {
|
|
1365
|
+
kind: "excluded",
|
|
1366
|
+
reason: "agent-native",
|
|
1367
|
+
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."
|
|
1368
|
+
}
|
|
1369
|
+
},
|
|
1370
|
+
{
|
|
1371
|
+
id: "database-migration-repair",
|
|
1372
|
+
domain: "database",
|
|
1373
|
+
title: "\uB9C8\uC774\uADF8\uB808\uC774\uC158 \uC6D0\uC7A5 \uC218\uB9AC",
|
|
1374
|
+
dashboard: "/[teamSlug]/projects/[projectSlug]/database/migrations",
|
|
1375
|
+
ui: { kind: "built" },
|
|
1376
|
+
cli: { kind: "built", commands: ["naro migration repair"] },
|
|
1377
|
+
mcp: {
|
|
1378
|
+
kind: "excluded",
|
|
1379
|
+
reason: "irreversible",
|
|
1380
|
+
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)."
|
|
1381
|
+
}
|
|
1382
|
+
},
|
|
1383
|
+
{
|
|
1384
|
+
id: "database-saved-query-list",
|
|
1385
|
+
domain: "database",
|
|
1386
|
+
title: "\uC800\uC7A5\uD55C \uCFFC\uB9AC \uBAA9\uB85D",
|
|
1387
|
+
routes: ["GET projects/[projectId]/database/saved-queries"],
|
|
1388
|
+
dashboard: "/[teamSlug]/projects/[projectSlug]/database/sql",
|
|
1389
|
+
ui: { kind: "built" },
|
|
1390
|
+
cli: {
|
|
1391
|
+
kind: "excluded",
|
|
1392
|
+
reason: "ui-affordance",
|
|
1393
|
+
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."
|
|
1394
|
+
},
|
|
1395
|
+
mcp: {
|
|
1396
|
+
kind: "excluded",
|
|
1397
|
+
reason: "ui-affordance",
|
|
1398
|
+
note: "SQL \uD3B8\uC9D1\uAE30 \uC548\uC5D0\uC11C\uB9CC \uB73B\uC774 \uC788\uB2E4. 2026-11-03 \uACB0\uC815(\uAD8C\uACE0\uB300\uB85C)."
|
|
1399
|
+
}
|
|
1400
|
+
},
|
|
1401
|
+
{
|
|
1402
|
+
id: "database-saved-query-create",
|
|
1403
|
+
domain: "database",
|
|
1404
|
+
title: "\uCFFC\uB9AC \uC800\uC7A5",
|
|
1405
|
+
routes: ["POST projects/[projectId]/database/saved-queries"],
|
|
1406
|
+
dashboard: "/[teamSlug]/projects/[projectSlug]/database/sql",
|
|
1407
|
+
ui: { kind: "built" },
|
|
1408
|
+
cli: {
|
|
1409
|
+
kind: "excluded",
|
|
1410
|
+
reason: "ui-affordance",
|
|
1411
|
+
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."
|
|
1412
|
+
},
|
|
1413
|
+
mcp: {
|
|
1414
|
+
kind: "excluded",
|
|
1415
|
+
reason: "ui-affordance",
|
|
1416
|
+
note: "SQL \uD3B8\uC9D1\uAE30 \uC548\uC5D0\uC11C\uB9CC \uB73B\uC774 \uC788\uB2E4. 2026-11-03 \uACB0\uC815(\uAD8C\uACE0\uB300\uB85C)."
|
|
1417
|
+
}
|
|
1418
|
+
},
|
|
1419
|
+
{
|
|
1420
|
+
id: "database-saved-query-update",
|
|
1421
|
+
domain: "database",
|
|
1422
|
+
title: "\uC800\uC7A5\uD55C \uCFFC\uB9AC \uC218\uC815",
|
|
1423
|
+
routes: [
|
|
1424
|
+
"PATCH projects/[projectId]/database/saved-queries/[savedQueryId]"
|
|
1425
|
+
],
|
|
1426
|
+
dashboard: "/[teamSlug]/projects/[projectSlug]/database/sql",
|
|
1427
|
+
ui: { kind: "built" },
|
|
1428
|
+
cli: {
|
|
1429
|
+
kind: "excluded",
|
|
1430
|
+
reason: "ui-affordance",
|
|
1431
|
+
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."
|
|
1432
|
+
},
|
|
1433
|
+
mcp: {
|
|
1434
|
+
kind: "excluded",
|
|
1435
|
+
reason: "ui-affordance",
|
|
1436
|
+
note: "SQL \uD3B8\uC9D1\uAE30 \uC548\uC5D0\uC11C\uB9CC \uB73B\uC774 \uC788\uB2E4. 2026-11-03 \uACB0\uC815(\uAD8C\uACE0\uB300\uB85C)."
|
|
1437
|
+
}
|
|
1438
|
+
},
|
|
1439
|
+
{
|
|
1440
|
+
id: "database-saved-query-delete",
|
|
1441
|
+
domain: "database",
|
|
1442
|
+
title: "\uC800\uC7A5\uD55C \uCFFC\uB9AC \uC0AD\uC81C",
|
|
1443
|
+
routes: [
|
|
1444
|
+
"DELETE projects/[projectId]/database/saved-queries/[savedQueryId]"
|
|
1445
|
+
],
|
|
1446
|
+
dashboard: "/[teamSlug]/projects/[projectSlug]/database/sql",
|
|
1447
|
+
ui: { kind: "built" },
|
|
1448
|
+
cli: {
|
|
1449
|
+
kind: "excluded",
|
|
1450
|
+
reason: "ui-affordance",
|
|
1451
|
+
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."
|
|
1452
|
+
},
|
|
1453
|
+
mcp: {
|
|
1454
|
+
kind: "excluded",
|
|
1455
|
+
reason: "ui-affordance",
|
|
1456
|
+
note: "SQL \uD3B8\uC9D1\uAE30 \uC548\uC5D0\uC11C\uB9CC \uB73B\uC774 \uC788\uB2E4. 2026-11-03 \uACB0\uC815(\uAD8C\uACE0\uB300\uB85C)."
|
|
1457
|
+
}
|
|
1458
|
+
},
|
|
1459
|
+
{
|
|
1460
|
+
// 대시보드 정책 화면(백엔드 메뉴 Policies)은 2026-11-04에 생겼다.
|
|
1461
|
+
id: "rls-table-policy-list",
|
|
1462
|
+
domain: "rls",
|
|
1463
|
+
title: "\uD14C\uC774\uBE14\uBCC4 \uC815\uCC45 \uC870\uD68C",
|
|
1464
|
+
routes: ["GET projects/[projectId]/backend/policies"],
|
|
1465
|
+
ui: { kind: "built" },
|
|
1466
|
+
cli: { kind: "built", commands: ["naro policy rules"] },
|
|
1467
|
+
mcp: { kind: "built", tools: ["list_policy_rules"] }
|
|
1468
|
+
},
|
|
1469
|
+
{
|
|
1470
|
+
id: "rls-table-policy-set",
|
|
1471
|
+
domain: "rls",
|
|
1472
|
+
title: "\uD14C\uC774\uBE14\uC758 \uC561\uC158\uBCC4 \uADDC\uCE59 \uC124\uC815",
|
|
1473
|
+
routes: ["PUT projects/[projectId]/backend/policies/[table]"],
|
|
1474
|
+
ui: { kind: "built" },
|
|
1475
|
+
cli: { kind: "built", commands: ["naro policy set"] },
|
|
1476
|
+
// 규칙은 CREATE POLICY로, owner 규칙은 COMMENT ON POLICY p ON t IS 'naro:owner <column>'로 apply_migration에 쓴다.
|
|
1477
|
+
mcp: { kind: "built" }
|
|
1478
|
+
},
|
|
1479
|
+
{
|
|
1480
|
+
id: "rls-table-policy-remove",
|
|
1481
|
+
domain: "rls",
|
|
1482
|
+
title: "\uD14C\uC774\uBE14\uC758 \uC815\uCC45 \uC804\uBD80 \uC81C\uAC70",
|
|
1483
|
+
routes: ["DELETE projects/[projectId]/backend/policies/[table]"],
|
|
1484
|
+
ui: { kind: "built" },
|
|
1485
|
+
cli: { kind: "built", commands: ["naro policy remove"] },
|
|
1486
|
+
// apply_migration에 그 테이블의 DROP POLICY를 쓴다.
|
|
1487
|
+
mcp: { kind: "built" }
|
|
1488
|
+
},
|
|
1489
|
+
{
|
|
1490
|
+
id: "rls-policy-list",
|
|
1491
|
+
domain: "rls",
|
|
1492
|
+
title: "\uC815\uCC45 \uBAA9\uB85D(CREATE POLICY \uAF34)",
|
|
1493
|
+
routes: ["GET projects/[projectId]/backend/rls/policies"],
|
|
1494
|
+
ui: { kind: "built" },
|
|
1495
|
+
cli: { kind: "built", commands: ["naro policy list"] },
|
|
1496
|
+
mcp: { kind: "built", tools: ["list_policies"] }
|
|
1497
|
+
},
|
|
1498
|
+
{
|
|
1499
|
+
id: "rls-policy-create",
|
|
1500
|
+
domain: "rls",
|
|
1501
|
+
title: "\uC815\uCC45 \uB9CC\uB4E4\uAE30(CREATE POLICY)",
|
|
1502
|
+
routes: ["POST projects/[projectId]/backend/rls/policies"],
|
|
1503
|
+
ui: { kind: "built" },
|
|
1504
|
+
cli: { kind: "built", commands: ["naro policy create"] },
|
|
1505
|
+
// apply_migration·execute_sql이 CREATE POLICY를 받는다. 테이블과 같은 마이그레이션에 쓰라고 apply_migration이 안내한다.
|
|
1506
|
+
mcp: { kind: "built" }
|
|
1507
|
+
},
|
|
1508
|
+
{
|
|
1509
|
+
id: "rls-policy-replace",
|
|
1510
|
+
domain: "rls",
|
|
1511
|
+
title: "\uC815\uCC45 \uBC14\uAFB8\uAE30",
|
|
1512
|
+
routes: ["PUT projects/[projectId]/backend/rls/policies/[table]/[name]"],
|
|
1513
|
+
ui: { kind: "built" },
|
|
1514
|
+
// naro migration up·db push(client.db.applyMigration)나 naro db query
|
|
1515
|
+
// (client.db.query) 한 번에 DROP POLICY와 CREATE POLICY를 함께 쓴다.
|
|
1516
|
+
// MCP와 같은 경로다(PR #414 리뷰).
|
|
1517
|
+
cli: { kind: "built" },
|
|
1518
|
+
// apply_migration 한 번에 DROP POLICY와 CREATE POLICY를 함께 쓴다.
|
|
1519
|
+
mcp: { kind: "built" }
|
|
1520
|
+
},
|
|
1521
|
+
{
|
|
1522
|
+
id: "rls-policy-drop",
|
|
1523
|
+
domain: "rls",
|
|
1524
|
+
title: "\uC815\uCC45 \uC0AD\uC81C(DROP POLICY)",
|
|
1525
|
+
routes: ["DELETE projects/[projectId]/backend/rls/policies/[table]/[name]"],
|
|
1526
|
+
ui: { kind: "built" },
|
|
1527
|
+
cli: { kind: "built", commands: ["naro policy drop"] },
|
|
1528
|
+
// apply_migration·execute_sql이 DROP POLICY를 받는다.
|
|
1529
|
+
mcp: { kind: "built" }
|
|
1530
|
+
},
|
|
1531
|
+
{
|
|
1532
|
+
id: "storage-info",
|
|
1533
|
+
domain: "storage",
|
|
1534
|
+
title: "Storage \uC0C1\uD0DC",
|
|
1535
|
+
routes: ["GET projects/[projectId]/backend/storage"],
|
|
1536
|
+
ui: { kind: "built" },
|
|
1537
|
+
cli: { kind: "built", commands: ["naro storage"] },
|
|
1538
|
+
mcp: { kind: "built", tools: ["get_storage"] }
|
|
1539
|
+
},
|
|
1540
|
+
{
|
|
1541
|
+
id: "storage-enable",
|
|
1542
|
+
domain: "storage",
|
|
1543
|
+
title: "Storage \uCF1C\uAE30",
|
|
1544
|
+
routes: ["POST projects/[projectId]/backend/storage"],
|
|
1545
|
+
ui: { kind: "built" },
|
|
1546
|
+
cli: { kind: "built", commands: ["naro storage enable"] },
|
|
1547
|
+
mcp: { kind: "built", tools: ["enable_storage"] }
|
|
1548
|
+
},
|
|
1549
|
+
{
|
|
1550
|
+
id: "storage-disable",
|
|
1551
|
+
domain: "storage",
|
|
1552
|
+
title: "Storage \uB044\uAE30",
|
|
1553
|
+
routes: ["DELETE projects/[projectId]/backend/storage"],
|
|
1554
|
+
ui: { kind: "built" },
|
|
1555
|
+
cli: { kind: "built", commands: ["naro storage disable"] },
|
|
1556
|
+
mcp: { kind: "built", tools: ["disable_storage"] }
|
|
1557
|
+
},
|
|
1558
|
+
{
|
|
1559
|
+
id: "storage-bucket-list",
|
|
1560
|
+
domain: "storage",
|
|
1561
|
+
title: "\uBC84\uD0B7 \uBAA9\uB85D",
|
|
1562
|
+
routes: ["GET projects/[projectId]/backend/storage/buckets"],
|
|
1563
|
+
ui: { kind: "built" },
|
|
1564
|
+
cli: { kind: "built", commands: ["naro storage bucket list"] },
|
|
1565
|
+
mcp: { kind: "built", tools: ["list_storage_buckets"] }
|
|
1566
|
+
},
|
|
1567
|
+
{
|
|
1568
|
+
id: "storage-bucket-create",
|
|
1569
|
+
domain: "storage",
|
|
1570
|
+
title: "\uBC84\uD0B7 \uB9CC\uB4E4\uAE30",
|
|
1571
|
+
routes: ["POST projects/[projectId]/backend/storage/buckets"],
|
|
1572
|
+
ui: { kind: "built" },
|
|
1573
|
+
cli: { kind: "built", commands: ["naro storage bucket create"] },
|
|
1574
|
+
mcp: { kind: "built", tools: ["create_storage_bucket"] }
|
|
1575
|
+
},
|
|
1576
|
+
{
|
|
1577
|
+
id: "storage-bucket-get",
|
|
1578
|
+
domain: "storage",
|
|
1579
|
+
title: "\uBC84\uD0B7 \uC870\uD68C",
|
|
1580
|
+
routes: ["GET projects/[projectId]/backend/storage/buckets/[bucket]"],
|
|
1581
|
+
ui: { kind: "built" },
|
|
1582
|
+
// naro storage bucket update가 바꾸기 전에 읽는다(client.storage.getBucket).
|
|
1583
|
+
cli: { kind: "built" },
|
|
1584
|
+
mcp: { kind: "built", tools: ["get_storage_bucket"] }
|
|
1585
|
+
},
|
|
1586
|
+
{
|
|
1587
|
+
id: "storage-bucket-update",
|
|
1588
|
+
domain: "storage",
|
|
1589
|
+
title: "\uBC84\uD0B7 \uC124\uC815 \uBCC0\uACBD",
|
|
1590
|
+
routes: ["PATCH projects/[projectId]/backend/storage/buckets/[bucket]"],
|
|
1591
|
+
ui: { kind: "built" },
|
|
1592
|
+
cli: { kind: "built", commands: ["naro storage bucket update"] },
|
|
1593
|
+
mcp: { kind: "built", tools: ["update_storage_bucket"] }
|
|
1594
|
+
},
|
|
1595
|
+
{
|
|
1596
|
+
id: "storage-bucket-remove",
|
|
1597
|
+
domain: "storage",
|
|
1598
|
+
title: "\uBC84\uD0B7 \uC0AD\uC81C",
|
|
1599
|
+
routes: ["DELETE projects/[projectId]/backend/storage/buckets/[bucket]"],
|
|
1600
|
+
ui: { kind: "built" },
|
|
1601
|
+
cli: { kind: "built", commands: ["naro storage bucket remove"] },
|
|
1602
|
+
mcp: { kind: "built", tools: ["delete_storage_bucket"] }
|
|
1603
|
+
},
|
|
1604
|
+
{
|
|
1605
|
+
id: "storage-bucket-empty",
|
|
1606
|
+
domain: "storage",
|
|
1607
|
+
title: "\uBC84\uD0B7 \uBE44\uC6B0\uAE30",
|
|
1608
|
+
routes: [
|
|
1609
|
+
"POST projects/[projectId]/backend/storage/buckets/[bucket]/empty"
|
|
1610
|
+
],
|
|
1611
|
+
ui: { kind: "built" },
|
|
1612
|
+
cli: { kind: "built", commands: ["naro storage bucket empty"] },
|
|
1613
|
+
mcp: { kind: "built", tools: ["empty_storage_bucket"] }
|
|
1614
|
+
},
|
|
1615
|
+
{
|
|
1616
|
+
id: "storage-object-list",
|
|
1617
|
+
domain: "storage",
|
|
1618
|
+
title: "\uAC1D\uCCB4 \uBAA9\uB85D",
|
|
1619
|
+
routes: [
|
|
1620
|
+
"POST projects/[projectId]/backend/storage/buckets/[bucket]/objects/list"
|
|
1621
|
+
],
|
|
1622
|
+
ui: { kind: "built" },
|
|
1623
|
+
cli: { kind: "built", commands: ["naro storage ls"] },
|
|
1624
|
+
mcp: { kind: "built", tools: ["list_storage_objects"] }
|
|
1625
|
+
},
|
|
1626
|
+
{
|
|
1627
|
+
id: "storage-object-remove",
|
|
1628
|
+
domain: "storage",
|
|
1629
|
+
title: "\uAC1D\uCCB4 \uC0AD\uC81C",
|
|
1630
|
+
routes: [
|
|
1631
|
+
"DELETE projects/[projectId]/backend/storage/buckets/[bucket]/objects"
|
|
1632
|
+
],
|
|
1633
|
+
ui: { kind: "built" },
|
|
1634
|
+
cli: { kind: "built", commands: ["naro storage rm"] },
|
|
1635
|
+
mcp: { kind: "built", tools: ["delete_storage_objects"] }
|
|
1636
|
+
},
|
|
1637
|
+
{
|
|
1638
|
+
id: "storage-object-sign",
|
|
1639
|
+
domain: "storage",
|
|
1640
|
+
title: "\uB2E4\uC6B4\uB85C\uB4DC \uC11C\uBA85 URL",
|
|
1641
|
+
routes: [
|
|
1642
|
+
"POST projects/[projectId]/backend/storage/buckets/[bucket]/objects/sign"
|
|
1643
|
+
],
|
|
1644
|
+
ui: { kind: "built" },
|
|
1645
|
+
cli: { kind: "built", commands: ["naro storage sign"] },
|
|
1646
|
+
mcp: { kind: "built", tools: ["create_storage_signed_url"] }
|
|
1647
|
+
},
|
|
1648
|
+
{
|
|
1649
|
+
id: "storage-object-upload",
|
|
1650
|
+
domain: "storage",
|
|
1651
|
+
title: "\uC5C5\uB85C\uB4DC URL \uBC1C\uAE09",
|
|
1652
|
+
routes: [
|
|
1653
|
+
"POST projects/[projectId]/backend/storage/buckets/[bucket]/objects/upload-url"
|
|
1654
|
+
],
|
|
1655
|
+
ui: { kind: "built" },
|
|
1656
|
+
cli: { kind: "built", commands: ["naro storage cp"] },
|
|
1657
|
+
mcp: { kind: "built", tools: ["create_storage_upload_url"] }
|
|
1658
|
+
},
|
|
1659
|
+
{
|
|
1660
|
+
id: "storage-object-move",
|
|
1661
|
+
domain: "storage",
|
|
1662
|
+
title: "\uAC1D\uCCB4 \uC774\uB3D9",
|
|
1663
|
+
routes: [
|
|
1664
|
+
"POST projects/[projectId]/backend/storage/buckets/[bucket]/objects/move"
|
|
1665
|
+
],
|
|
1666
|
+
ui: { kind: "built" },
|
|
1667
|
+
cli: { kind: "built", commands: ["naro storage mv"] },
|
|
1668
|
+
mcp: { kind: "built", tools: ["move_storage_object"] }
|
|
1669
|
+
},
|
|
1670
|
+
{
|
|
1671
|
+
id: "realtime-info",
|
|
1672
|
+
domain: "realtime",
|
|
1673
|
+
title: "Realtime \uC0C1\uD0DC\xB7\uC5F0\uACB0 \uC218",
|
|
1674
|
+
routes: ["GET projects/[projectId]/backend/realtime"],
|
|
1675
|
+
ui: { kind: "built" },
|
|
1676
|
+
cli: { kind: "built", commands: ["naro realtime"] },
|
|
1677
|
+
mcp: { kind: "built", tools: ["get_realtime"] }
|
|
1678
|
+
},
|
|
1679
|
+
{
|
|
1680
|
+
id: "realtime-enable",
|
|
1681
|
+
domain: "realtime",
|
|
1682
|
+
title: "Realtime \uCF1C\uAE30",
|
|
1683
|
+
routes: ["POST projects/[projectId]/backend/realtime"],
|
|
1684
|
+
ui: { kind: "built" },
|
|
1685
|
+
cli: { kind: "built", commands: ["naro realtime enable"] },
|
|
1686
|
+
mcp: { kind: "built", tools: ["enable_realtime"] }
|
|
1687
|
+
},
|
|
1688
|
+
{
|
|
1689
|
+
id: "realtime-table-list",
|
|
1690
|
+
domain: "realtime",
|
|
1691
|
+
title: "\uACF5\uAC1C \uD14C\uC774\uBE14 \uBAA9\uB85D",
|
|
1692
|
+
routes: ["GET projects/[projectId]/backend/realtime/tables"],
|
|
1693
|
+
ui: { kind: "built" },
|
|
1694
|
+
cli: { kind: "built", commands: ["naro realtime tables"] },
|
|
1695
|
+
// get_realtime이 공개 테이블을 상태와 함께 돌려준다.
|
|
1696
|
+
mcp: { kind: "built" }
|
|
1697
|
+
},
|
|
1698
|
+
{
|
|
1699
|
+
id: "realtime-table-add",
|
|
1700
|
+
domain: "realtime",
|
|
1701
|
+
title: "\uD14C\uC774\uBE14 \uBCC0\uACBD \uACF5\uAC1C",
|
|
1702
|
+
routes: ["PUT projects/[projectId]/backend/realtime/tables/[table]"],
|
|
1703
|
+
ui: { kind: "built" },
|
|
1704
|
+
cli: { kind: "built", commands: ["naro realtime tables add"] },
|
|
1705
|
+
mcp: { kind: "built", tools: ["publish_realtime_table"] }
|
|
1706
|
+
},
|
|
1707
|
+
{
|
|
1708
|
+
id: "realtime-table-remove",
|
|
1709
|
+
domain: "realtime",
|
|
1710
|
+
title: "\uD14C\uC774\uBE14 \uBCC0\uACBD \uACF5\uAC1C \uC911\uC9C0",
|
|
1711
|
+
routes: ["DELETE projects/[projectId]/backend/realtime/tables/[table]"],
|
|
1712
|
+
ui: { kind: "built" },
|
|
1713
|
+
cli: { kind: "built", commands: ["naro realtime tables remove"] },
|
|
1714
|
+
mcp: { kind: "built", tools: ["unpublish_realtime_table"] }
|
|
1715
|
+
},
|
|
1716
|
+
{
|
|
1717
|
+
// 대시보드 Functions 화면은 2026-11-04에 생겼다. 그 전의 built는 틀렸다.
|
|
1718
|
+
id: "function-list",
|
|
1719
|
+
domain: "functions",
|
|
1720
|
+
title: "\uD568\uC218 \uBAA9\uB85D",
|
|
1721
|
+
routes: ["GET projects/[projectId]/backend/functions"],
|
|
1722
|
+
ui: { kind: "built" },
|
|
1723
|
+
cli: { kind: "built", commands: ["naro functions"] },
|
|
1724
|
+
mcp: { kind: "built", tools: ["list_functions"] }
|
|
1725
|
+
},
|
|
1726
|
+
{
|
|
1727
|
+
id: "function-scaffold",
|
|
1728
|
+
domain: "functions",
|
|
1729
|
+
title: "\uD568\uC218 \uBF08\uB300 \uB9CC\uB4E4\uAE30",
|
|
1730
|
+
ui: {
|
|
1731
|
+
kind: "excluded",
|
|
1732
|
+
reason: "local-filesystem",
|
|
1733
|
+
note: "naro/functions/<name>/index.ts\uB97C \uC4F4\uB2E4. \uC11C\uBC84\uAC00 \uD560 \uC218 \uC5C6\uB2E4."
|
|
1734
|
+
},
|
|
1735
|
+
cli: { kind: "built", commands: ["naro functions new"] },
|
|
1736
|
+
mcp: {
|
|
1737
|
+
kind: "excluded",
|
|
1738
|
+
reason: "agent-native",
|
|
1739
|
+
note: "naro/functions/<name>/index.ts\uB97C \uC4F4\uB2E4. 2026-11-03 \uACB0\uC815."
|
|
1740
|
+
}
|
|
1741
|
+
},
|
|
1742
|
+
{
|
|
1743
|
+
id: "function-get",
|
|
1744
|
+
domain: "functions",
|
|
1745
|
+
title: "\uD568\uC218 \uC0C1\uC138",
|
|
1746
|
+
routes: ["GET projects/[projectId]/backend/functions/[name]"],
|
|
1747
|
+
ui: { kind: "built" },
|
|
1748
|
+
cli: { kind: "built", commands: ["naro functions versions"] },
|
|
1749
|
+
mcp: { kind: "built", tools: ["get_function"] }
|
|
1750
|
+
},
|
|
1751
|
+
{
|
|
1752
|
+
id: "function-update",
|
|
1753
|
+
domain: "functions",
|
|
1754
|
+
title: "\uD568\uC218 verify_jwt \uC124\uC815",
|
|
1755
|
+
routes: ["PATCH projects/[projectId]/backend/functions/[name]"],
|
|
1756
|
+
ui: { kind: "built" },
|
|
1757
|
+
cli: { kind: "built", commands: ["naro functions update"] },
|
|
1758
|
+
mcp: { kind: "built", tools: ["update_function"] }
|
|
1759
|
+
},
|
|
1760
|
+
{
|
|
1761
|
+
id: "function-delete",
|
|
1762
|
+
domain: "functions",
|
|
1763
|
+
title: "\uD568\uC218 \uC0AD\uC81C",
|
|
1764
|
+
routes: ["DELETE projects/[projectId]/backend/functions/[name]"],
|
|
1765
|
+
ui: { kind: "built" },
|
|
1766
|
+
cli: { kind: "built", commands: ["naro functions delete"] },
|
|
1767
|
+
mcp: { kind: "built", tools: ["delete_function"] }
|
|
1768
|
+
},
|
|
1769
|
+
{
|
|
1770
|
+
id: "function-version-upload",
|
|
1771
|
+
domain: "functions",
|
|
1772
|
+
title: "\uBC88\uB4E4\uD55C \uCF54\uB4DC\uB97C \uC0C8 \uBC84\uC804\uC73C\uB85C \uC62C\uB9AC\uAE30",
|
|
1773
|
+
routes: ["POST projects/[projectId]/backend/functions/[name]/versions"],
|
|
1774
|
+
ui: {
|
|
1775
|
+
kind: "excluded",
|
|
1776
|
+
reason: "local-filesystem",
|
|
1777
|
+
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."
|
|
1778
|
+
},
|
|
1779
|
+
cli: { kind: "built", commands: ["naro functions deploy"] },
|
|
1780
|
+
mcp: { kind: "built", tools: ["deploy_function"] }
|
|
1781
|
+
},
|
|
1782
|
+
{
|
|
1783
|
+
id: "function-version-deploy",
|
|
1784
|
+
domain: "functions",
|
|
1785
|
+
title: "\uC800\uC7A5\uB41C \uBC84\uC804 \uBC30\uD3EC",
|
|
1786
|
+
routes: [
|
|
1787
|
+
"POST projects/[projectId]/backend/functions/[name]/versions/[versionId]/deploy"
|
|
1788
|
+
],
|
|
1789
|
+
ui: { kind: "built" },
|
|
1790
|
+
// naro functions deploy가 올린 버전을 배포한다(client.functions.deploy).
|
|
1791
|
+
cli: { kind: "built" },
|
|
1792
|
+
// deploy_function이 naro-cli의 deployFunctions로 올린 버전을 배포한다.
|
|
1793
|
+
mcp: { kind: "built" }
|
|
1794
|
+
},
|
|
1795
|
+
{
|
|
1796
|
+
id: "function-rollback",
|
|
1797
|
+
domain: "functions",
|
|
1798
|
+
title: "\uC774\uC804 \uBC84\uC804\uC73C\uB85C \uB864\uBC31",
|
|
1799
|
+
routes: ["POST projects/[projectId]/backend/functions/[name]/rollback"],
|
|
1800
|
+
ui: { kind: "built" },
|
|
1801
|
+
cli: { kind: "built", commands: ["naro functions rollback"] },
|
|
1802
|
+
mcp: { kind: "built", tools: ["rollback_function"] }
|
|
1803
|
+
},
|
|
1804
|
+
{
|
|
1805
|
+
id: "function-logs",
|
|
1806
|
+
domain: "functions",
|
|
1807
|
+
title: "\uD568\uC218 \uB85C\uADF8",
|
|
1808
|
+
routes: ["GET projects/[projectId]/backend/functions/[name]/logs"],
|
|
1809
|
+
ui: { kind: "built" },
|
|
1810
|
+
cli: { kind: "built", commands: ["naro functions logs"] },
|
|
1811
|
+
mcp: { kind: "built", tools: ["get_function_logs"] }
|
|
1812
|
+
},
|
|
1813
|
+
{
|
|
1814
|
+
id: "function-invoke",
|
|
1815
|
+
domain: "functions",
|
|
1816
|
+
title: "\uD568\uC218 \uD638\uCD9C",
|
|
1817
|
+
routes: ["POST projects/[projectId]/backend/functions/[name]/invoke"],
|
|
1818
|
+
ui: { kind: "built" },
|
|
1819
|
+
cli: { kind: "built", commands: ["naro functions invoke"] },
|
|
1820
|
+
mcp: { kind: "built", tools: ["invoke_function"] }
|
|
1821
|
+
},
|
|
1822
|
+
{
|
|
1823
|
+
id: "function-secret-list",
|
|
1824
|
+
domain: "functions",
|
|
1825
|
+
title: "\uD568\uC218 \uC2DC\uD06C\uB9BF \uBAA9\uB85D",
|
|
1826
|
+
routes: ["GET projects/[projectId]/backend/functions-secrets"],
|
|
1827
|
+
ui: { kind: "built" },
|
|
1828
|
+
cli: { kind: "built", commands: ["naro functions secrets"] },
|
|
1829
|
+
mcp: { kind: "built", tools: ["list_function_secrets"] }
|
|
1830
|
+
},
|
|
1831
|
+
{
|
|
1832
|
+
id: "function-secret-set",
|
|
1833
|
+
domain: "functions",
|
|
1834
|
+
title: "\uD568\uC218 \uC2DC\uD06C\uB9BF \uC124\uC815",
|
|
1835
|
+
routes: ["PUT projects/[projectId]/backend/functions-secrets"],
|
|
1836
|
+
dashboard: "/[teamSlug]/projects/[projectSlug]/functions/secrets",
|
|
1837
|
+
ui: { kind: "built" },
|
|
1838
|
+
cli: {
|
|
1839
|
+
kind: "built",
|
|
1840
|
+
commands: ["naro functions secrets set", "naro functions secrets import"]
|
|
1841
|
+
},
|
|
1842
|
+
mcp: {
|
|
1843
|
+
kind: "excluded",
|
|
1844
|
+
reason: "secret-value",
|
|
1845
|
+
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."
|
|
1846
|
+
}
|
|
1847
|
+
},
|
|
1848
|
+
// 라우트는 function-secret-set과 같은 PUT functions-secrets다. 한 라우트는
|
|
1849
|
+
// 한 기능에만 걸리므로 여기에는 적지 않는다.
|
|
1850
|
+
{
|
|
1851
|
+
id: "function-secret-unset",
|
|
1852
|
+
domain: "functions",
|
|
1853
|
+
title: "\uD568\uC218 \uC2DC\uD06C\uB9BF \uD574\uC81C",
|
|
1854
|
+
ui: { kind: "built" },
|
|
1855
|
+
cli: { kind: "built", commands: ["naro functions secrets unset"] },
|
|
1856
|
+
mcp: { kind: "built", tools: ["unset_function_secret"] }
|
|
1857
|
+
},
|
|
1858
|
+
{
|
|
1859
|
+
id: "function-sync",
|
|
1860
|
+
domain: "functions",
|
|
1861
|
+
title: "\uD568\uC218 \uC7AC\uB3D9\uAE30\uD654",
|
|
1862
|
+
routes: ["POST projects/[projectId]/backend/functions-sync"],
|
|
1863
|
+
ui: { kind: "built" },
|
|
1864
|
+
cli: { kind: "built", commands: ["naro functions secrets sync"] },
|
|
1865
|
+
mcp: { kind: "built", tools: ["sync_functions"] }
|
|
1866
|
+
},
|
|
1867
|
+
{
|
|
1868
|
+
id: "backend-info",
|
|
1869
|
+
domain: "backend",
|
|
1870
|
+
title: "Backend \uC0C1\uD0DC\xB7URL\xB7anon \uD0A4",
|
|
1871
|
+
routes: ["GET projects/[projectId]/backend"],
|
|
1872
|
+
ui: { kind: "built" },
|
|
1873
|
+
cli: { kind: "built", commands: ["naro backend"] },
|
|
1874
|
+
mcp: { kind: "built", tools: ["get_backend"] }
|
|
1875
|
+
},
|
|
1876
|
+
{
|
|
1877
|
+
id: "backend-enable",
|
|
1878
|
+
domain: "backend",
|
|
1879
|
+
title: "Backend \uCF1C\uAE30",
|
|
1880
|
+
routes: ["POST projects/[projectId]/backend/enable"],
|
|
1881
|
+
ui: { kind: "built" },
|
|
1882
|
+
cli: { kind: "built", commands: ["naro backend enable"] },
|
|
1883
|
+
mcp: { kind: "built", tools: ["enable_backend"] }
|
|
1884
|
+
},
|
|
1885
|
+
{
|
|
1886
|
+
id: "backend-provision",
|
|
1887
|
+
domain: "backend",
|
|
1888
|
+
title: "Backend \uD504\uB85C\uBE44\uC800\uB2DD \uC774\uC5B4\uAC00\uAE30",
|
|
1889
|
+
routes: ["POST projects/[projectId]/backend/provision"],
|
|
1890
|
+
ui: { kind: "built" },
|
|
1891
|
+
// naro backend enable이 멈춘 프로비저닝을 이어 간다.
|
|
1892
|
+
cli: { kind: "built" },
|
|
1893
|
+
// enable_backend가 같은 호출이다(client.backend.enable — 라우트 provision은 그 옛 이름).
|
|
1894
|
+
mcp: { kind: "built" }
|
|
1895
|
+
},
|
|
1896
|
+
{
|
|
1897
|
+
id: "backend-disable",
|
|
1898
|
+
domain: "backend",
|
|
1899
|
+
title: "Backend \uB044\uAE30",
|
|
1900
|
+
routes: ["POST projects/[projectId]/backend/disable"],
|
|
1901
|
+
ui: { kind: "built" },
|
|
1902
|
+
cli: { kind: "built", commands: ["naro backend disable"] },
|
|
1903
|
+
mcp: { kind: "built", tools: ["disable_backend"] }
|
|
1904
|
+
},
|
|
1905
|
+
{
|
|
1906
|
+
id: "backend-keys",
|
|
1907
|
+
domain: "backend",
|
|
1908
|
+
title: "API \uD0A4 \uC870\uD68C(service \uD0A4 \uD3EC\uD568)",
|
|
1909
|
+
routes: ["GET projects/[projectId]/backend/keys"],
|
|
1910
|
+
dashboard: "/[teamSlug]/projects/[projectSlug]/settings",
|
|
1911
|
+
ui: { kind: "built" },
|
|
1912
|
+
cli: { kind: "built", commands: ["naro backend keys"] },
|
|
1913
|
+
mcp: {
|
|
1914
|
+
kind: "excluded",
|
|
1915
|
+
reason: "secret-value",
|
|
1916
|
+
note: "service \uD0A4\uAC00 \uB300\uD654\uC5D0 \uB0A8\uB294\uB2E4. 2026-11-03 \uACB0\uC815(\uAD8C\uACE0\uB300\uB85C)."
|
|
1917
|
+
}
|
|
1918
|
+
},
|
|
1919
|
+
{
|
|
1920
|
+
id: "backend-keys-rotate",
|
|
1921
|
+
domain: "backend",
|
|
1922
|
+
title: "API \uD0A4 \uAD50\uCCB4",
|
|
1923
|
+
routes: ["POST projects/[projectId]/backend/keys/rotate"],
|
|
1924
|
+
// 2026-11-04 전에는 화면이 없었는데 built로 적혀 있었다.
|
|
1925
|
+
dashboard: "/[teamSlug]/projects/[projectSlug]/settings",
|
|
1926
|
+
ui: { kind: "built" },
|
|
1927
|
+
cli: { kind: "built", commands: ["naro backend keys rotate"] },
|
|
1928
|
+
mcp: {
|
|
1929
|
+
kind: "excluded",
|
|
1930
|
+
reason: "irreversible",
|
|
1931
|
+
note: "\uC61B \uD0A4\uAC00 \uBC14\uB85C \uC8FD\uB294\uB2E4. 2026-11-03 \uACB0\uC815(\uAD8C\uACE0\uB300\uB85C)."
|
|
1932
|
+
}
|
|
1933
|
+
},
|
|
1934
|
+
{
|
|
1935
|
+
id: "backend-signing-key-rotate",
|
|
1936
|
+
domain: "backend",
|
|
1937
|
+
title: "\uC11C\uBA85 \uD0A4 \uAD50\uCCB4",
|
|
1938
|
+
routes: ["POST projects/[projectId]/backend/signing-key/rotate"],
|
|
1939
|
+
dashboard: "/[teamSlug]/projects/[projectSlug]/settings",
|
|
1940
|
+
ui: { kind: "built" },
|
|
1941
|
+
cli: { kind: "built", commands: ["naro backend signing-key rotate"] },
|
|
1942
|
+
mcp: {
|
|
1943
|
+
kind: "excluded",
|
|
1944
|
+
reason: "irreversible",
|
|
1945
|
+
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)."
|
|
1946
|
+
}
|
|
1947
|
+
},
|
|
1948
|
+
{
|
|
1949
|
+
id: "backend-auth-get",
|
|
1950
|
+
domain: "backend",
|
|
1951
|
+
title: "\uB85C\uADF8\uC778 \uC124\uC815 \uC870\uD68C",
|
|
1952
|
+
routes: ["GET projects/[projectId]/backend/auth"],
|
|
1953
|
+
ui: { kind: "built" },
|
|
1954
|
+
cli: {
|
|
1955
|
+
kind: "built",
|
|
1956
|
+
commands: ["naro backend auth", "naro backend auth redirects"]
|
|
1957
|
+
},
|
|
1958
|
+
mcp: { kind: "built", tools: ["get_backend_auth"] }
|
|
1959
|
+
},
|
|
1960
|
+
{
|
|
1961
|
+
id: "backend-auth-update",
|
|
1962
|
+
domain: "backend",
|
|
1963
|
+
title: "\uB85C\uADF8\uC778 \uC124\uC815 \uBCC0\uACBD",
|
|
1964
|
+
routes: ["PUT projects/[projectId]/backend/auth"],
|
|
1965
|
+
ui: { kind: "built" },
|
|
1966
|
+
cli: {
|
|
1967
|
+
kind: "built",
|
|
1968
|
+
commands: [
|
|
1969
|
+
"naro backend auth signups",
|
|
1970
|
+
"naro backend auth password",
|
|
1971
|
+
"naro backend auth email set",
|
|
1972
|
+
"naro backend auth oauth set",
|
|
1973
|
+
"naro backend auth redirects add",
|
|
1974
|
+
"naro backend auth redirects remove",
|
|
1975
|
+
"naro backend auth require-verification"
|
|
1976
|
+
]
|
|
1977
|
+
},
|
|
1978
|
+
// 리다이렉트 제거·가입·확인 메일·비밀번호 길이만. 메일 API 키와
|
|
1979
|
+
// OAuth client secret은 대화에 남고(secret-value), 리다이렉트 추가는 재설정 토큰이
|
|
1980
|
+
// 그 origin으로 가므로(PR #434 리뷰) 대시보드와 CLI만 한다.
|
|
1981
|
+
mcp: { kind: "built", tools: ["update_backend_auth"] }
|
|
1982
|
+
},
|
|
1983
|
+
{
|
|
1984
|
+
id: "backend-auth-remove",
|
|
1985
|
+
domain: "backend",
|
|
1986
|
+
title: "\uB85C\uADF8\uC778 \uACF5\uAE09\uC790\xB7\uBA54\uC77C \uC124\uC815 \uC81C\uAC70",
|
|
1987
|
+
routes: ["DELETE projects/[projectId]/backend/auth"],
|
|
1988
|
+
ui: { kind: "built" },
|
|
1989
|
+
cli: {
|
|
1990
|
+
kind: "built",
|
|
1991
|
+
commands: [
|
|
1992
|
+
"naro backend auth email remove",
|
|
1993
|
+
"naro backend auth oauth remove"
|
|
1994
|
+
]
|
|
1995
|
+
},
|
|
1996
|
+
mcp: { kind: "built", tools: ["remove_backend_auth"] }
|
|
1997
|
+
},
|
|
1998
|
+
{
|
|
1999
|
+
id: "backend-user-list",
|
|
2000
|
+
domain: "backend",
|
|
2001
|
+
title: "\uC720\uC800 \uBAA9\uB85D",
|
|
2002
|
+
routes: ["GET projects/[projectId]/backend/users"],
|
|
2003
|
+
ui: { kind: "built" },
|
|
2004
|
+
cli: { kind: "built", commands: ["naro backend users"] },
|
|
2005
|
+
mcp: { kind: "built", tools: ["list_backend_users"] }
|
|
2006
|
+
},
|
|
2007
|
+
{
|
|
2008
|
+
id: "backend-user-create",
|
|
2009
|
+
domain: "backend",
|
|
2010
|
+
title: "\uC720\uC800 \uB9CC\uB4E4\uAE30",
|
|
2011
|
+
routes: ["POST projects/[projectId]/backend/users"],
|
|
2012
|
+
dashboard: "/[teamSlug]/projects/[projectSlug]/auth",
|
|
2013
|
+
ui: { kind: "built" },
|
|
2014
|
+
cli: { kind: "built", commands: ["naro backend users create"] },
|
|
2015
|
+
mcp: {
|
|
2016
|
+
kind: "excluded",
|
|
2017
|
+
reason: "secret-value",
|
|
2018
|
+
note: "\uBE44\uBC00\uBC88\uD638\uAC00 \uB300\uD654\uC5D0 \uB0A8\uB294\uB2E4. 2026-11-03 \uACB0\uC815(\uAD8C\uACE0\uB300\uB85C)."
|
|
2019
|
+
}
|
|
2020
|
+
},
|
|
2021
|
+
{
|
|
2022
|
+
id: "backend-user-delete",
|
|
2023
|
+
domain: "backend",
|
|
2024
|
+
title: "\uC720\uC800 \uC0AD\uC81C",
|
|
2025
|
+
routes: ["DELETE projects/[projectId]/backend/users/[userId]"],
|
|
2026
|
+
dashboard: "/[teamSlug]/projects/[projectSlug]/auth",
|
|
2027
|
+
ui: { kind: "built" },
|
|
2028
|
+
cli: { kind: "built", commands: ["naro backend users delete"] },
|
|
2029
|
+
mcp: {
|
|
2030
|
+
kind: "excluded",
|
|
2031
|
+
reason: "irreversible",
|
|
2032
|
+
note: "\uC720\uC800\uC640 \uC138\uC158\uC774 \uC0AC\uB77C\uC9C4\uB2E4. 2026-11-03 \uACB0\uC815(\uAD8C\uACE0\uB300\uB85C)."
|
|
2033
|
+
}
|
|
2034
|
+
},
|
|
2035
|
+
{
|
|
2036
|
+
id: "logs-runtime",
|
|
2037
|
+
domain: "logs",
|
|
2038
|
+
title: "\uB7F0\uD0C0\uC784 \uB85C\uADF8",
|
|
2039
|
+
routes: ["GET projects/[projectId]/logs"],
|
|
2040
|
+
ui: { kind: "built" },
|
|
2041
|
+
cli: { kind: "built", commands: ["naro logs"] },
|
|
2042
|
+
mcp: { kind: "built", tools: ["get_runtime_logs"] }
|
|
2043
|
+
},
|
|
2044
|
+
{
|
|
2045
|
+
id: "analytics",
|
|
2046
|
+
domain: "measurement",
|
|
2047
|
+
title: "Web Analytics",
|
|
2048
|
+
routes: ["GET projects/[projectId]/analytics"],
|
|
2049
|
+
ui: { kind: "built" },
|
|
2050
|
+
cli: { kind: "built", commands: ["naro analytics"] },
|
|
2051
|
+
mcp: { kind: "built", tools: ["get_analytics"] }
|
|
2052
|
+
},
|
|
2053
|
+
{
|
|
2054
|
+
id: "insights",
|
|
2055
|
+
domain: "measurement",
|
|
2056
|
+
title: "Speed Insights",
|
|
2057
|
+
routes: ["GET projects/[projectId]/speed-insights"],
|
|
2058
|
+
ui: { kind: "built" },
|
|
2059
|
+
cli: { kind: "built", commands: ["naro insights"] },
|
|
2060
|
+
mcp: { kind: "built", tools: ["get_speed_insights"] }
|
|
2061
|
+
},
|
|
2062
|
+
{
|
|
2063
|
+
id: "insights-toggle",
|
|
2064
|
+
domain: "measurement",
|
|
2065
|
+
title: "Speed Insights \uCE21\uC815 \uCF1C\uAE30\xB7\uB044\uAE30",
|
|
2066
|
+
routes: ["PUT projects/[projectId]/speed-insights"],
|
|
2067
|
+
ui: { kind: "built" },
|
|
2068
|
+
cli: {
|
|
2069
|
+
kind: "built",
|
|
2070
|
+
commands: ["naro insights enable", "naro insights disable"]
|
|
2071
|
+
},
|
|
2072
|
+
mcp: { kind: "built", tools: ["set_speed_insights"] }
|
|
2073
|
+
},
|
|
2074
|
+
{
|
|
2075
|
+
id: "insights-deployments",
|
|
2076
|
+
domain: "measurement",
|
|
2077
|
+
title: "Speed Insights \uBC30\uD3EC\uBCC4 \uBE44\uAD50",
|
|
2078
|
+
routes: ["GET projects/[projectId]/speed-insights/deployments"],
|
|
2079
|
+
ui: { kind: "built" },
|
|
2080
|
+
// naro insights가 배포별 표를 같이 읽는다(client.insights.overview).
|
|
2081
|
+
cli: { kind: "built" },
|
|
2082
|
+
// get_speed_insights가 route 없이 배포별 표를 같이 돌려준다(client.insights.overview).
|
|
2083
|
+
mcp: { kind: "built" }
|
|
2084
|
+
},
|
|
2085
|
+
{
|
|
2086
|
+
id: "insights-paths",
|
|
2087
|
+
domain: "measurement",
|
|
2088
|
+
title: "Speed Insights \uB77C\uC6B0\uD2B8\uBCC4 \uACBD\uB85C",
|
|
2089
|
+
routes: ["GET projects/[projectId]/speed-insights/paths"],
|
|
2090
|
+
ui: { kind: "built" },
|
|
2091
|
+
// naro insights --route가 읽는다(client.insights.paths).
|
|
2092
|
+
cli: { kind: "built" },
|
|
2093
|
+
// get_speed_insights에 route를 주면 경로를 돌려준다(client.insights.paths).
|
|
2094
|
+
mcp: { kind: "built" }
|
|
2095
|
+
},
|
|
2096
|
+
{
|
|
2097
|
+
id: "observability",
|
|
2098
|
+
domain: "measurement",
|
|
2099
|
+
title: "Observability",
|
|
2100
|
+
routes: ["GET projects/[projectId]/observability"],
|
|
2101
|
+
ui: { kind: "built" },
|
|
2102
|
+
cli: { kind: "built", commands: ["naro observability"] },
|
|
2103
|
+
mcp: { kind: "built", tools: ["get_observability"] }
|
|
2104
|
+
},
|
|
2105
|
+
{
|
|
2106
|
+
id: "firewall-list",
|
|
2107
|
+
domain: "firewall",
|
|
2108
|
+
title: "\uBC29\uD654\uBCBD \uADDC\uCE59 \uBAA9\uB85D",
|
|
2109
|
+
routes: ["GET projects/[projectId]/firewall"],
|
|
2110
|
+
ui: { kind: "built" },
|
|
2111
|
+
cli: { kind: "built", commands: ["naro firewall"] },
|
|
2112
|
+
mcp: { kind: "built", tools: ["list_firewall_rules"] }
|
|
2113
|
+
},
|
|
2114
|
+
{
|
|
2115
|
+
id: "firewall-add",
|
|
2116
|
+
domain: "firewall",
|
|
2117
|
+
title: "\uBC29\uD654\uBCBD \uADDC\uCE59 \uCD94\uAC00",
|
|
2118
|
+
routes: ["POST projects/[projectId]/firewall"],
|
|
2119
|
+
ui: { kind: "built" },
|
|
2120
|
+
cli: { kind: "built", commands: ["naro firewall add"] },
|
|
2121
|
+
mcp: { kind: "built", tools: ["add_firewall_rule"] }
|
|
2122
|
+
},
|
|
2123
|
+
{
|
|
2124
|
+
id: "firewall-update",
|
|
2125
|
+
domain: "firewall",
|
|
2126
|
+
title: "\uBC29\uD654\uBCBD \uADDC\uCE59 \uC218\uC815",
|
|
2127
|
+
routes: ["PATCH projects/[projectId]/firewall/[ruleId]"],
|
|
2128
|
+
ui: { kind: "built" },
|
|
2129
|
+
cli: {
|
|
2130
|
+
kind: "built",
|
|
2131
|
+
commands: ["naro firewall enable", "naro firewall disable"]
|
|
2132
|
+
},
|
|
2133
|
+
mcp: { kind: "built", tools: ["set_firewall_rule_enabled"] }
|
|
2134
|
+
},
|
|
2135
|
+
{
|
|
2136
|
+
id: "firewall-remove",
|
|
2137
|
+
domain: "firewall",
|
|
2138
|
+
title: "\uBC29\uD654\uBCBD \uADDC\uCE59 \uC0AD\uC81C",
|
|
2139
|
+
routes: ["DELETE projects/[projectId]/firewall/[ruleId]"],
|
|
2140
|
+
ui: { kind: "built" },
|
|
2141
|
+
cli: { kind: "built", commands: ["naro firewall remove"] },
|
|
2142
|
+
mcp: { kind: "built", tools: ["remove_firewall_rule"] }
|
|
2143
|
+
},
|
|
2144
|
+
{
|
|
2145
|
+
id: "flag-list",
|
|
2146
|
+
domain: "flags",
|
|
2147
|
+
title: "\uAE30\uB2A5 \uD50C\uB798\uADF8 \uBAA9\uB85D",
|
|
2148
|
+
routes: ["GET projects/[projectId]/flags"],
|
|
2149
|
+
ui: { kind: "built" },
|
|
2150
|
+
cli: { kind: "built", commands: ["naro flags"] },
|
|
2151
|
+
mcp: { kind: "built", tools: ["list_flags"] }
|
|
2152
|
+
},
|
|
2153
|
+
{
|
|
2154
|
+
id: "flag-add",
|
|
2155
|
+
domain: "flags",
|
|
2156
|
+
title: "\uAE30\uB2A5 \uD50C\uB798\uADF8 \uCD94\uAC00",
|
|
2157
|
+
routes: ["POST projects/[projectId]/flags"],
|
|
2158
|
+
ui: { kind: "built" },
|
|
2159
|
+
cli: { kind: "built", commands: ["naro flags add"] },
|
|
2160
|
+
mcp: { kind: "built", tools: ["add_flag"] }
|
|
2161
|
+
},
|
|
2162
|
+
{
|
|
2163
|
+
id: "flag-update",
|
|
2164
|
+
domain: "flags",
|
|
2165
|
+
title: "\uAE30\uB2A5 \uD50C\uB798\uADF8 \uC218\uC815",
|
|
2166
|
+
routes: ["PATCH projects/[projectId]/flags/[flagId]"],
|
|
2167
|
+
ui: { kind: "built" },
|
|
2168
|
+
cli: { kind: "built", commands: ["naro flags on", "naro flags off"] },
|
|
2169
|
+
mcp: { kind: "built", tools: ["set_flag"] }
|
|
2170
|
+
},
|
|
2171
|
+
{
|
|
2172
|
+
id: "flag-remove",
|
|
2173
|
+
domain: "flags",
|
|
2174
|
+
title: "\uAE30\uB2A5 \uD50C\uB798\uADF8 \uC0AD\uC81C",
|
|
2175
|
+
routes: ["DELETE projects/[projectId]/flags/[flagId]"],
|
|
2176
|
+
ui: { kind: "built" },
|
|
2177
|
+
cli: { kind: "built", commands: ["naro flags remove"] },
|
|
2178
|
+
mcp: { kind: "built", tools: ["remove_flag"] }
|
|
2179
|
+
},
|
|
2180
|
+
{
|
|
2181
|
+
id: "dashboard-link",
|
|
2182
|
+
domain: "guidance",
|
|
2183
|
+
title: "CLI\xB7MCP\uB85C \uBABB \uD558\uB294 \uAE30\uB2A5\uC758 \uB300\uC2DC\uBCF4\uB4DC \uB9C1\uD06C",
|
|
2184
|
+
ui: {
|
|
2185
|
+
kind: "excluded",
|
|
2186
|
+
reason: "dashboard-itself",
|
|
2187
|
+
note: "\uC0AC\uC6A9\uC790\uAC00 \uC774\uBBF8 \uB300\uC2DC\uBCF4\uB4DC\uC5D0 \uC788\uB2E4."
|
|
2188
|
+
},
|
|
2189
|
+
cli: { kind: "built", commands: ["naro dashboard"] },
|
|
2190
|
+
mcp: { kind: "built", tools: ["dashboard_link"] }
|
|
2191
|
+
}
|
|
2192
|
+
];
|
|
2193
|
+
function dashboardNeeds(path) {
|
|
2194
|
+
return {
|
|
2195
|
+
team: path.includes("[teamSlug]"),
|
|
2196
|
+
project: path.includes("[projectSlug]")
|
|
2197
|
+
};
|
|
2198
|
+
}
|
|
2199
|
+
function dashboardUrl(baseUrl, path, slugs) {
|
|
2200
|
+
const filled2 = path.replace("[teamSlug]", () => {
|
|
2201
|
+
if (!slugs.teamSlug) throw new Error(`${path} needs a team slug`);
|
|
2202
|
+
return encodeURIComponent(slugs.teamSlug);
|
|
2203
|
+
}).replace("[projectSlug]", () => {
|
|
2204
|
+
if (!slugs.projectSlug) throw new Error(`${path} needs a project slug`);
|
|
2205
|
+
return encodeURIComponent(slugs.projectSlug);
|
|
2206
|
+
});
|
|
2207
|
+
return `${baseUrl.replace(/\/+$/, "")}${filled2}`;
|
|
2208
|
+
}
|
|
2209
|
+
|
|
320
2210
|
// ../../packages/core/src/deployment.ts
|
|
321
2211
|
var PHASES = [
|
|
322
2212
|
"QUEUED",
|
|
@@ -641,12 +2531,8 @@ var DEPLOYMENT_ERROR_CODES = [
|
|
|
641
2531
|
"ENVIRONMENT_DELETED",
|
|
642
2532
|
/** The edge refused the environment's protection change; the database change is rolled back. */
|
|
643
2533
|
"ENVIRONMENT_PROTECTION_PUBLISH_FAILED",
|
|
644
|
-
/** The variable
|
|
645
|
-
"ENV_MANAGED"
|
|
646
|
-
/** The 10-minute Supabase sign-in cookie is gone or expired (spec 2026-11-04 §6.4). */
|
|
647
|
-
"SUPABASE_SESSION_EXPIRED",
|
|
648
|
-
/** The Supabase Management API refused or did not answer (spec 2026-11-04 §6.4). */
|
|
649
|
-
"SUPABASE_API_FAILED"
|
|
2534
|
+
/** The variable is owned by the Resend connection; only it changes it (spec 2026-11-04 resend §6.4). */
|
|
2535
|
+
"ENV_MANAGED"
|
|
650
2536
|
];
|
|
651
2537
|
var DeploymentError = class extends Error {
|
|
652
2538
|
code;
|
|
@@ -16369,10 +18255,13 @@ export default {
|
|
|
16369
18255
|
},
|
|
16370
18256
|
};
|
|
16371
18257
|
`;
|
|
16372
|
-
var
|
|
18258
|
+
var VINEXT_OUTPUT_DIR = "dist";
|
|
16373
18259
|
var SERVER_DIR = "server";
|
|
16374
18260
|
var CLIENT_DIR = "client";
|
|
16375
18261
|
var WRANGLER_OUTPUT_NAME = "wrangler.json";
|
|
18262
|
+
function vinextWranglerConfigPath(appRoot) {
|
|
18263
|
+
return join6(appRoot, VINEXT_OUTPUT_DIR, SERVER_DIR, WRANGLER_OUTPUT_NAME);
|
|
18264
|
+
}
|
|
16376
18265
|
async function exists3(path) {
|
|
16377
18266
|
try {
|
|
16378
18267
|
await access5(path);
|
|
@@ -16428,7 +18317,7 @@ async function createVinextBuildConfig(appRoot, deploymentId, writer = async (pa
|
|
|
16428
18317
|
compatibility_flags: ["nodejs_compat"],
|
|
16429
18318
|
main: `./${GENERATED_WORKER_ENTRY}`,
|
|
16430
18319
|
assets: {
|
|
16431
|
-
directory: `${
|
|
18320
|
+
directory: `${VINEXT_OUTPUT_DIR}/${CLIENT_DIR}`,
|
|
16432
18321
|
binding: "ASSETS"
|
|
16433
18322
|
}
|
|
16434
18323
|
},
|
|
@@ -16527,14 +18416,14 @@ function moduleMatchers(rules) {
|
|
|
16527
18416
|
}
|
|
16528
18417
|
async function readVinextArtifact(appRoot, identity) {
|
|
16529
18418
|
try {
|
|
16530
|
-
const outputRoot = resolve2(appRoot,
|
|
18419
|
+
const outputRoot = resolve2(appRoot, VINEXT_OUTPUT_DIR);
|
|
16531
18420
|
const serverRoot = join6(outputRoot, SERVER_DIR);
|
|
16532
18421
|
const clientRoot = join6(outputRoot, CLIENT_DIR);
|
|
16533
18422
|
const configPath = join6(serverRoot, WRANGLER_OUTPUT_NAME);
|
|
16534
18423
|
if (!await exists3(configPath)) {
|
|
16535
18424
|
throw new DeploymentError(
|
|
16536
18425
|
"ARTIFACT_INVALID",
|
|
16537
|
-
`vinext build produced no ${
|
|
18426
|
+
`vinext build produced no ${VINEXT_OUTPUT_DIR}/${SERVER_DIR}/${WRANGLER_OUTPUT_NAME}.`
|
|
16538
18427
|
);
|
|
16539
18428
|
}
|
|
16540
18429
|
const metadata = JSON.parse(
|
|
@@ -18606,13 +20495,8 @@ function createAwsMiddlewareCloudflareAppStrategy() {
|
|
|
18606
20495
|
}
|
|
18607
20496
|
|
|
18608
20497
|
// ../../packages/build/src/strategy/strategies/vinext-cloudflare.ts
|
|
18609
|
-
import { join as join16 } from "path";
|
|
18610
20498
|
var VINEXT_MIN_NEXT_MAJOR = 16;
|
|
18611
20499
|
var VINEXT_BUILD_SCRIPTS = ["esbuild", "workerd"];
|
|
18612
|
-
var VINEXT_OUTPUT = {
|
|
18613
|
-
outputRoot: "dist",
|
|
18614
|
-
bundleDir: "dist/.naro-bundle"
|
|
18615
|
-
};
|
|
18616
20500
|
async function runCheck(context, observer) {
|
|
18617
20501
|
if (!context.toolchain.vinext) return null;
|
|
18618
20502
|
const held = [];
|
|
@@ -18762,13 +20646,8 @@ function createVinextCloudflareStrategy(options) {
|
|
|
18762
20646
|
context,
|
|
18763
20647
|
{
|
|
18764
20648
|
appRoot: fork.appRoot,
|
|
18765
|
-
wranglerConfigPath:
|
|
18766
|
-
|
|
18767
|
-
"dist",
|
|
18768
|
-
"server",
|
|
18769
|
-
"wrangler.json"
|
|
18770
|
-
),
|
|
18771
|
-
...VINEXT_OUTPUT
|
|
20649
|
+
wranglerConfigPath: vinextWranglerConfigPath(fork.appRoot),
|
|
20650
|
+
outputRoot: VINEXT_OUTPUT_DIR
|
|
18772
20651
|
},
|
|
18773
20652
|
observer
|
|
18774
20653
|
);
|
|
@@ -18787,7 +20666,7 @@ function createVinextCloudflareStrategy(options) {
|
|
|
18787
20666
|
// ../../packages/build/src/strategy/workspace.ts
|
|
18788
20667
|
import { execFile } from "child_process";
|
|
18789
20668
|
import { cp, mkdir as mkdir2, readdir as readdir4, rm as rm2 } from "fs/promises";
|
|
18790
|
-
import { basename as basename2, dirname as dirname3, join as
|
|
20669
|
+
import { basename as basename2, dirname as dirname3, join as join16, relative as relative5, resolve as resolve6 } from "path";
|
|
18791
20670
|
import { promisify } from "util";
|
|
18792
20671
|
var execFileAsync = promisify(execFile);
|
|
18793
20672
|
var SKIPPED_ANYWHERE = /* @__PURE__ */ new Set(["node_modules"]);
|
|
@@ -18810,14 +20689,14 @@ async function copyInstalledPackages(source, target2) {
|
|
|
18810
20689
|
const walk2 = async (dir) => {
|
|
18811
20690
|
for (const entry of await readdir4(dir, { withFileTypes: true })) {
|
|
18812
20691
|
if (!entry.isDirectory() || entry.name === ".git") continue;
|
|
18813
|
-
const path =
|
|
20692
|
+
const path = join16(dir, entry.name);
|
|
18814
20693
|
if (entry.name === "node_modules") installs.push(path);
|
|
18815
20694
|
else await walk2(path);
|
|
18816
20695
|
}
|
|
18817
20696
|
};
|
|
18818
20697
|
await walk2(origin);
|
|
18819
20698
|
for (const install of installs)
|
|
18820
|
-
await copyTree(install,
|
|
20699
|
+
await copyTree(install, join16(target2, relative5(origin, install)));
|
|
18821
20700
|
}
|
|
18822
20701
|
async function copyTree(from, to) {
|
|
18823
20702
|
await mkdir2(dirname3(to), { recursive: true });
|
|
@@ -18832,7 +20711,7 @@ async function copyTree(from, to) {
|
|
|
18832
20711
|
await cp(from, to, { recursive: true, verbatimSymlinks: true });
|
|
18833
20712
|
}
|
|
18834
20713
|
function forkedAppRoot(checkout, appRoot, forkCheckout) {
|
|
18835
|
-
return
|
|
20714
|
+
return join16(forkCheckout, relative5(checkout, appRoot));
|
|
18836
20715
|
}
|
|
18837
20716
|
|
|
18838
20717
|
// ../../packages/build/src/local-build-executor.ts
|
|
@@ -18855,7 +20734,7 @@ async function withRouteList(artifact, list, appRoot, observer) {
|
|
|
18855
20734
|
}
|
|
18856
20735
|
}
|
|
18857
20736
|
var defaultLocalBuildDependencies = {
|
|
18858
|
-
createWorkspace: () => mkdtemp(
|
|
20737
|
+
createWorkspace: () => mkdtemp(join17(tmpdir(), "next-deploy-build-")),
|
|
18859
20738
|
removeWorkspace: (path) => rm3(path, { recursive: true, force: true }),
|
|
18860
20739
|
runCommand,
|
|
18861
20740
|
detectPackageManager,
|
|
@@ -18890,7 +20769,7 @@ async function readInstalledNextVersion(appRoot, checkout) {
|
|
|
18890
20769
|
for (; ; ) {
|
|
18891
20770
|
try {
|
|
18892
20771
|
const source = await readFile13(
|
|
18893
|
-
|
|
20772
|
+
join17(dir, "node_modules", "next", "package.json"),
|
|
18894
20773
|
"utf8"
|
|
18895
20774
|
);
|
|
18896
20775
|
const version3 = JSON.parse(source).version;
|
|
@@ -19045,8 +20924,8 @@ var LocalBuildExecutor = class {
|
|
|
19045
20924
|
}
|
|
19046
20925
|
async build(input, observer, cache) {
|
|
19047
20926
|
const workspace = await this.dependencies.createWorkspace();
|
|
19048
|
-
const checkout =
|
|
19049
|
-
const pmCacheDir =
|
|
20927
|
+
const checkout = join17(workspace, "checkout");
|
|
20928
|
+
const pmCacheDir = join17(workspace, ".pm-store");
|
|
19050
20929
|
let cacheSeq = 0;
|
|
19051
20930
|
const commandAvailable = this.dependencies.commandAvailable ?? hasCommand;
|
|
19052
20931
|
const compressor = "zstd";
|
|
@@ -19055,7 +20934,7 @@ var LocalBuildExecutor = class {
|
|
|
19055
20934
|
transport: cache,
|
|
19056
20935
|
fetch: this.dependencies.cacheFetch ?? ((url2, init) => fetch(url2, init)),
|
|
19057
20936
|
runCommand: this.dependencies.runCommand,
|
|
19058
|
-
tmpFile: (suffix) =>
|
|
20937
|
+
tmpFile: (suffix) => join17(workspace, `cache-${String(cacheSeq++)}${suffix}`),
|
|
19059
20938
|
// One latch for the whole build so a disabled cache warns once.
|
|
19060
20939
|
report: { unavailable: false }
|
|
19061
20940
|
} : null;
|
|
@@ -19263,7 +21142,7 @@ var LocalBuildExecutor = class {
|
|
|
19263
21142
|
}
|
|
19264
21143
|
}
|
|
19265
21144
|
await notifyStatus(observer, "BUILDING");
|
|
19266
|
-
const buildCacheDir = resolved.preset.cachePath ?
|
|
21145
|
+
const buildCacheDir = resolved.preset.cachePath ? join17(appRoot, resolved.preset.cachePath) : null;
|
|
19267
21146
|
const buildCacheKey = sanitizeCacheKey(input.branch);
|
|
19268
21147
|
if (cachePorts && buildCacheDir) {
|
|
19269
21148
|
await tryRestore(
|
|
@@ -19287,13 +21166,13 @@ var LocalBuildExecutor = class {
|
|
|
19287
21166
|
entries: fingerprintEntries,
|
|
19288
21167
|
nextVersion: nextVersion ? `${String(nextVersion.major)}.${String(nextVersion.minor)}.${String(nextVersion.patch)}` : "unknown"
|
|
19289
21168
|
});
|
|
19290
|
-
const pristine =
|
|
21169
|
+
const pristine = join17(workspace, "pristine");
|
|
19291
21170
|
const fork = this.dependencies.forkWorkspace ?? defaultFork;
|
|
19292
21171
|
await fork(checkout, pristine);
|
|
19293
21172
|
let forks = 0;
|
|
19294
21173
|
const resolverConcurrency = this.dependencies.resolverConcurrency ?? 1;
|
|
19295
21174
|
const forkWorkspace = async (label2) => {
|
|
19296
|
-
const target2 =
|
|
21175
|
+
const target2 = join17(
|
|
19297
21176
|
workspace,
|
|
19298
21177
|
"forks",
|
|
19299
21178
|
`${String(forks++)}-${label2.replace(/[^a-z0-9-]/gi, "-")}`
|
|
@@ -19589,12 +21468,12 @@ async function errorFromResponse(response, context) {
|
|
|
19589
21468
|
// ../../packages/sdk/src/session.ts
|
|
19590
21469
|
import { mkdirSync, readFileSync, rmSync, writeFileSync } from "fs";
|
|
19591
21470
|
import { homedir } from "os";
|
|
19592
|
-
import { join as
|
|
21471
|
+
import { join as join18 } from "path";
|
|
19593
21472
|
function credentialsDir(home = homedir()) {
|
|
19594
|
-
return
|
|
21473
|
+
return join18(home, ".naro");
|
|
19595
21474
|
}
|
|
19596
21475
|
function credentialsFile(home = homedir()) {
|
|
19597
|
-
return
|
|
21476
|
+
return join18(credentialsDir(home), "credentials.json");
|
|
19598
21477
|
}
|
|
19599
21478
|
function saveSession(session, home = homedir()) {
|
|
19600
21479
|
mkdirSync(credentialsDir(home), { recursive: true, mode: 448 });
|
|
@@ -20198,44 +22077,6 @@ var FlagsApi = class {
|
|
|
20198
22077
|
);
|
|
20199
22078
|
}
|
|
20200
22079
|
};
|
|
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
22080
|
|
|
20240
22081
|
// ../../packages/sdk/src/ops.ts
|
|
20241
22082
|
var BillingApi = class {
|
|
@@ -20269,32 +22110,6 @@ var ObservabilityApi = class {
|
|
|
20269
22110
|
}
|
|
20270
22111
|
};
|
|
20271
22112
|
|
|
20272
|
-
// ../../packages/sdk/src/supabase-links.ts
|
|
20273
|
-
var SupabaseApi = class {
|
|
20274
|
-
constructor(client) {
|
|
20275
|
-
this.client = client;
|
|
20276
|
-
}
|
|
20277
|
-
async links(projectId) {
|
|
20278
|
-
const body = await this.client.request(
|
|
20279
|
-
`/api/projects/${encodeURIComponent(projectId)}/supabase`,
|
|
20280
|
-
{ context: "Read Supabase links" }
|
|
20281
|
-
);
|
|
20282
|
-
return body.links;
|
|
20283
|
-
}
|
|
20284
|
-
/**
|
|
20285
|
-
* Removes the link of one target (production, preview or an environment's
|
|
20286
|
-
* slug), or every link the role may write when `target` is left out, with
|
|
20287
|
-
* the env rows they hold. Answers how many went.
|
|
20288
|
-
*/
|
|
20289
|
-
async disconnect(projectId, options = {}) {
|
|
20290
|
-
const query = options.target === void 0 ? "" : `?target=${encodeURIComponent(options.target)}`;
|
|
20291
|
-
return this.client.request(
|
|
20292
|
-
`/api/projects/${encodeURIComponent(projectId)}/supabase${query}`,
|
|
20293
|
-
{ method: "DELETE", context: "Disconnect Supabase" }
|
|
20294
|
-
);
|
|
20295
|
-
}
|
|
20296
|
-
};
|
|
20297
|
-
|
|
20298
22113
|
// ../../packages/sdk/src/environments.ts
|
|
20299
22114
|
function isReservedEnvTarget(value) {
|
|
20300
22115
|
return RESERVED_ENVIRONMENT_SLUGS.includes(value);
|
|
@@ -20432,10 +22247,8 @@ var NaroClient = class _NaroClient {
|
|
|
20432
22247
|
dns;
|
|
20433
22248
|
firewall;
|
|
20434
22249
|
flags;
|
|
20435
|
-
bindings;
|
|
20436
22250
|
billing;
|
|
20437
22251
|
observability;
|
|
20438
|
-
supabase;
|
|
20439
22252
|
logs;
|
|
20440
22253
|
db;
|
|
20441
22254
|
backend;
|
|
@@ -20462,10 +22275,8 @@ var NaroClient = class _NaroClient {
|
|
|
20462
22275
|
this.dns = new DnsApi(this);
|
|
20463
22276
|
this.firewall = new FirewallApi(this);
|
|
20464
22277
|
this.flags = new FlagsApi(this);
|
|
20465
|
-
this.bindings = new BindingsApi(this);
|
|
20466
22278
|
this.billing = new BillingApi(this);
|
|
20467
22279
|
this.observability = new ObservabilityApi(this);
|
|
20468
|
-
this.supabase = new SupabaseApi(this);
|
|
20469
22280
|
this.logs = new LogsApi(this);
|
|
20470
22281
|
this.db = new DbApi(this);
|
|
20471
22282
|
this.backend = new BackendApi(this);
|
|
@@ -20987,9 +22798,10 @@ var EnvApi = class {
|
|
|
20987
22798
|
/**
|
|
20988
22799
|
* The names the env route refuses as a key — `409 VALIDATION_FAILED`
|
|
20989
22800
|
* `<KEY> is already used by a storage binding.` — read the way it reads
|
|
20990
|
-
* them: `ASSETS` (the static files),
|
|
20991
|
-
*
|
|
20992
|
-
*
|
|
22801
|
+
* them: `ASSETS` (the static files) and, on a project using the managed
|
|
22802
|
+
* database (`database_provider` is `d1`), `DB`. The bindings a user
|
|
22803
|
+
* declared (R2·KV·D1) are gone since 2026-11-04, and so is the route that
|
|
22804
|
+
* listed them. For a caller that sends
|
|
20993
22805
|
* many entries in several requests (`naro env import`) and has to refuse
|
|
20994
22806
|
* before the first one is saved. A control plane whose project row has no
|
|
20995
22807
|
* `database_provider` reads as having no managed database, so `DB` is only
|
|
@@ -20997,20 +22809,8 @@ var EnvApi = class {
|
|
|
20997
22809
|
*/
|
|
20998
22810
|
async takenBindingNames(projectId) {
|
|
20999
22811
|
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
|
-
]);
|
|
22812
|
+
const project2 = await this.client.request(base2, { context: "Read project" });
|
|
22813
|
+
const names = /* @__PURE__ */ new Set([STATIC_ASSETS_BINDING]);
|
|
21014
22814
|
if (project2.project.database_provider === "d1")
|
|
21015
22815
|
names.add(MANAGED_DATABASE_BINDING);
|
|
21016
22816
|
return [...names];
|
|
@@ -22686,6 +24486,54 @@ var FunctionsApi = class {
|
|
|
22686
24486
|
}
|
|
22687
24487
|
};
|
|
22688
24488
|
|
|
24489
|
+
// ../../packages/sdk/src/dashboard.ts
|
|
24490
|
+
function dashboardCapability(id) {
|
|
24491
|
+
const found = CAPABILITIES.find((capability) => capability.id === id);
|
|
24492
|
+
if (!found || typeof found.dashboard !== "string")
|
|
24493
|
+
throw new NaroError(
|
|
24494
|
+
"VALIDATION_FAILED",
|
|
24495
|
+
`No dashboard page for "${id}". Run without a capability to list the ones that have one.`
|
|
24496
|
+
);
|
|
24497
|
+
return found;
|
|
24498
|
+
}
|
|
24499
|
+
async function dashboardLink(client, capability, target2, options) {
|
|
24500
|
+
const needs = dashboardNeeds(capability.dashboard);
|
|
24501
|
+
let teamSlug = target2.teamSlug;
|
|
24502
|
+
let projectSlug;
|
|
24503
|
+
if (needs.project) {
|
|
24504
|
+
if (!target2.projectId)
|
|
24505
|
+
throw new NaroError(
|
|
24506
|
+
"PROJECT_NOT_LINKED",
|
|
24507
|
+
"This page belongs to a project: pass its id, or link the directory first."
|
|
24508
|
+
);
|
|
24509
|
+
const [project2, teams] = await Promise.all([
|
|
24510
|
+
client.projects.get(target2.projectId),
|
|
24511
|
+
client.teams.list()
|
|
24512
|
+
]);
|
|
24513
|
+
const team = teams.find((candidate) => candidate.id === project2.teamId);
|
|
24514
|
+
if (!team)
|
|
24515
|
+
throw new NaroError(
|
|
24516
|
+
"NOT_FOUND",
|
|
24517
|
+
`The team of project ${project2.slug} is not one of yours.`
|
|
24518
|
+
);
|
|
24519
|
+
teamSlug = team.slug;
|
|
24520
|
+
projectSlug = project2.slug;
|
|
24521
|
+
} else if (needs.team && !teamSlug) {
|
|
24522
|
+
throw new NaroError("TEAM_REQUIRED", "This page belongs to a team.");
|
|
24523
|
+
}
|
|
24524
|
+
const support = capability[options.client];
|
|
24525
|
+
return {
|
|
24526
|
+
capability: capability.id,
|
|
24527
|
+
title: capability.title,
|
|
24528
|
+
url: dashboardUrl(options.baseUrl, capability.dashboard, {
|
|
24529
|
+
teamSlug,
|
|
24530
|
+
projectSlug
|
|
24531
|
+
}),
|
|
24532
|
+
reason: support.kind === "excluded" ? { code: support.reason, why: REASON_CODES[support.reason].why } : null,
|
|
24533
|
+
cli: capability.cli.kind === "built" ? capability.cli.commands ?? [] : []
|
|
24534
|
+
};
|
|
24535
|
+
}
|
|
24536
|
+
|
|
22689
24537
|
// ../../packages/sdk/src/database.ts
|
|
22690
24538
|
var BOOKMARK_RE = /^[0-9a-f]{8}-[0-9a-f]{8}-[0-9a-f]{8}-[0-9a-f]{32}$/;
|
|
22691
24539
|
var BOOKMARK_FORMAT_MESSAGE = "bookmark must look like 00000001-00000008-000050ed-272153b8520cfb93b49834d93a1a1ab3 (four hyphen-separated hex groups, 59 characters).";
|
|
@@ -22736,14 +24584,14 @@ function summarizeStatement(statement2) {
|
|
|
22736
24584
|
|
|
22737
24585
|
// ../../packages/sdk/src/dotenv.ts
|
|
22738
24586
|
import { existsSync, readFileSync as readFileSync2 } from "fs";
|
|
22739
|
-
import { join as
|
|
24587
|
+
import { join as join19 } from "path";
|
|
22740
24588
|
var QUOTES2 = /* @__PURE__ */ new Set(["'", '"', "`"]);
|
|
22741
24589
|
function parseDotenv(text3) {
|
|
22742
24590
|
return parseDotenvDetailed(text3).vars;
|
|
22743
24591
|
}
|
|
22744
24592
|
function readProjectEnv(dir) {
|
|
22745
24593
|
for (const name of [".env.local", ".env.production", ".env"]) {
|
|
22746
|
-
const path =
|
|
24594
|
+
const path = join19(dir, name);
|
|
22747
24595
|
if (existsSync(path)) return parseDotenv(readFileSync2(path, "utf8"));
|
|
22748
24596
|
}
|
|
22749
24597
|
return {};
|
|
@@ -22797,7 +24645,7 @@ function serializeDotenv(vars) {
|
|
|
22797
24645
|
|
|
22798
24646
|
// ../../packages/sdk/src/env-scan.ts
|
|
22799
24647
|
import { existsSync as existsSync2, readFileSync as readFileSync3, readdirSync, statSync } from "fs";
|
|
22800
|
-
import { join as
|
|
24648
|
+
import { join as join20 } from "path";
|
|
22801
24649
|
var SOURCE_EXTENSIONS3 = /* @__PURE__ */ new Set([
|
|
22802
24650
|
".ts",
|
|
22803
24651
|
".tsx",
|
|
@@ -22852,7 +24700,7 @@ function collect(dir, out) {
|
|
|
22852
24700
|
for (const entry of entries) {
|
|
22853
24701
|
if (out.length >= MAX_FILES) return;
|
|
22854
24702
|
if (entry.isSymbolicLink()) continue;
|
|
22855
|
-
const path =
|
|
24703
|
+
const path = join20(dir, entry.name);
|
|
22856
24704
|
if (entry.isDirectory()) {
|
|
22857
24705
|
if (entry.name.startsWith(".") || SKIP_DIRECTORIES.has(entry.name))
|
|
22858
24706
|
continue;
|
|
@@ -22884,7 +24732,7 @@ function scanEnvReferences(dir) {
|
|
|
22884
24732
|
}
|
|
22885
24733
|
}
|
|
22886
24734
|
for (const name of EXAMPLE_FILES) {
|
|
22887
|
-
const path =
|
|
24735
|
+
const path = join20(dir, name);
|
|
22888
24736
|
if (!existsSync2(path)) continue;
|
|
22889
24737
|
let parsed;
|
|
22890
24738
|
try {
|
|
@@ -22902,11 +24750,11 @@ function scanEnvReferences(dir) {
|
|
|
22902
24750
|
|
|
22903
24751
|
// ../../packages/sdk/src/framework.ts
|
|
22904
24752
|
import { existsSync as existsSync3, readFileSync as readFileSync4 } from "fs";
|
|
22905
|
-
import { join as
|
|
24753
|
+
import { join as join21 } from "path";
|
|
22906
24754
|
function readPackageJson2(dir) {
|
|
22907
24755
|
try {
|
|
22908
24756
|
return JSON.parse(
|
|
22909
|
-
readFileSync4(
|
|
24757
|
+
readFileSync4(join21(dir, "package.json"), "utf8")
|
|
22910
24758
|
);
|
|
22911
24759
|
} catch {
|
|
22912
24760
|
return null;
|
|
@@ -22917,7 +24765,7 @@ function hasDependency(pkg, name) {
|
|
|
22917
24765
|
}
|
|
22918
24766
|
function hasConfig(dir, base2, evidence) {
|
|
22919
24767
|
for (const ext of ["js", "mjs", "cjs", "ts", "mts"]) {
|
|
22920
|
-
if (existsSync3(
|
|
24768
|
+
if (existsSync3(join21(dir, `${base2}.${ext}`))) {
|
|
22921
24769
|
evidence.push(`${base2}.${ext}`);
|
|
22922
24770
|
return true;
|
|
22923
24771
|
}
|
|
@@ -23025,8 +24873,8 @@ function detectFramework2(dir) {
|
|
|
23025
24873
|
if (!byDependency && !byConfig) continue;
|
|
23026
24874
|
if (byDependency) evidence.push(`package.json: ${detector.dependency}`);
|
|
23027
24875
|
if (detector.framework === "nextjs") {
|
|
23028
|
-
if (existsSync3(
|
|
23029
|
-
if (existsSync3(
|
|
24876
|
+
if (existsSync3(join21(dir, "app"))) evidence.push("app/");
|
|
24877
|
+
if (existsSync3(join21(dir, "pages"))) evidence.push("pages/");
|
|
23030
24878
|
}
|
|
23031
24879
|
return {
|
|
23032
24880
|
framework: detector.framework,
|
|
@@ -23037,7 +24885,7 @@ function detectFramework2(dir) {
|
|
|
23037
24885
|
deployable: true
|
|
23038
24886
|
};
|
|
23039
24887
|
}
|
|
23040
|
-
if (!pkg && existsSync3(
|
|
24888
|
+
if (!pkg && existsSync3(join21(dir, "index.html"))) {
|
|
23041
24889
|
evidence.push("index.html (no package.json)");
|
|
23042
24890
|
return {
|
|
23043
24891
|
framework: "static",
|
|
@@ -31847,12 +33695,12 @@ import {
|
|
|
31847
33695
|
rmSync as rmSync2,
|
|
31848
33696
|
writeFileSync as writeFileSync2
|
|
31849
33697
|
} from "fs";
|
|
31850
|
-
import { join as
|
|
33698
|
+
import { join as join22 } from "path";
|
|
31851
33699
|
function linkDir(dir) {
|
|
31852
|
-
return
|
|
33700
|
+
return join22(dir, ".naro");
|
|
31853
33701
|
}
|
|
31854
33702
|
function linkFile(dir) {
|
|
31855
|
-
return
|
|
33703
|
+
return join22(linkDir(dir), "project.json");
|
|
31856
33704
|
}
|
|
31857
33705
|
function readProjectLink(dir) {
|
|
31858
33706
|
try {
|
|
@@ -31874,7 +33722,7 @@ function writeProjectLink(dir, link) {
|
|
|
31874
33722
|
writeFileSync2(linkFile(dir), `${JSON.stringify(link, null, 2)}
|
|
31875
33723
|
`);
|
|
31876
33724
|
writeFileSync2(
|
|
31877
|
-
|
|
33725
|
+
join22(linkDir(dir), "README.txt"),
|
|
31878
33726
|
"This directory links the project to Naro and should not be committed.\n"
|
|
31879
33727
|
);
|
|
31880
33728
|
}
|
|
@@ -31884,9 +33732,9 @@ function removeProjectLink(dir) {
|
|
|
31884
33732
|
return true;
|
|
31885
33733
|
}
|
|
31886
33734
|
function ensureGitignoreHasNaro(dir) {
|
|
31887
|
-
const gitignorePath =
|
|
33735
|
+
const gitignorePath = join22(dir, ".gitignore");
|
|
31888
33736
|
const hasGitignore = existsSync4(gitignorePath);
|
|
31889
|
-
if (!hasGitignore && !existsSync4(
|
|
33737
|
+
if (!hasGitignore && !existsSync4(join22(dir, ".git"))) return false;
|
|
31890
33738
|
const current = hasGitignore ? readFileSync5(gitignorePath, "utf8") : "";
|
|
31891
33739
|
const covered = current.split(/\r?\n/).map((line) => line.trim()).some((line) => line === ".naro" || line === ".naro/" || line === "/.naro");
|
|
31892
33740
|
if (covered) return false;
|
|
@@ -32671,7 +34519,7 @@ function usageStatus(report, currentMonth, requests) {
|
|
|
32671
34519
|
|
|
32672
34520
|
// src/env-consent.ts
|
|
32673
34521
|
import { existsSync as existsSync6 } from "fs";
|
|
32674
|
-
import { join as
|
|
34522
|
+
import { join as join23 } from "path";
|
|
32675
34523
|
var DOTENV_FILES = [".env.local", ".env.production", ".env"];
|
|
32676
34524
|
var PUBLIC_PREFIX = "NEXT_PUBLIC_";
|
|
32677
34525
|
function maskSecretValue(value) {
|
|
@@ -32683,7 +34531,7 @@ function maskEnvValue(key, value) {
|
|
|
32683
34531
|
return maskSecretValue(value);
|
|
32684
34532
|
}
|
|
32685
34533
|
function findDotenvFile(dir) {
|
|
32686
|
-
for (const name of DOTENV_FILES) if (existsSync6(
|
|
34534
|
+
for (const name of DOTENV_FILES) if (existsSync6(join23(dir, name))) return name;
|
|
32687
34535
|
return null;
|
|
32688
34536
|
}
|
|
32689
34537
|
function envAddGuidance(keys, environment) {
|
|
@@ -32947,13 +34795,13 @@ async function uploadArtifact(artifact, opts) {
|
|
|
32947
34795
|
|
|
32948
34796
|
// src/version.ts
|
|
32949
34797
|
import { readFileSync as readFileSync6 } from "fs";
|
|
32950
|
-
import { dirname as dirname5, join as
|
|
34798
|
+
import { dirname as dirname5, join as join24 } from "path";
|
|
32951
34799
|
import { fileURLToPath } from "url";
|
|
32952
34800
|
function version2() {
|
|
32953
34801
|
try {
|
|
32954
34802
|
const pkg = JSON.parse(
|
|
32955
34803
|
readFileSync6(
|
|
32956
|
-
|
|
34804
|
+
join24(dirname5(fileURLToPath(import.meta.url)), "..", "package.json"),
|
|
32957
34805
|
"utf8"
|
|
32958
34806
|
)
|
|
32959
34807
|
);
|
|
@@ -32982,7 +34830,7 @@ import {
|
|
|
32982
34830
|
basename as basename3,
|
|
32983
34831
|
dirname as dirname6,
|
|
32984
34832
|
isAbsolute as isAbsolute4,
|
|
32985
|
-
join as
|
|
34833
|
+
join as join25,
|
|
32986
34834
|
relative as relative6,
|
|
32987
34835
|
resolve as resolve10,
|
|
32988
34836
|
sep as sep5
|
|
@@ -33109,12 +34957,12 @@ async function copyWorkingTree(source, checkout) {
|
|
|
33109
34957
|
keptLinks,
|
|
33110
34958
|
async ({ path, text: text3 }) => {
|
|
33111
34959
|
try {
|
|
33112
|
-
return inside(await realpath3(
|
|
34960
|
+
return inside(await realpath3(join25(checkout, path)), root);
|
|
33113
34961
|
} catch (error51) {
|
|
33114
34962
|
return error51.code === "ENOENT" && climbsOnlyFirst(text3);
|
|
33115
34963
|
}
|
|
33116
34964
|
},
|
|
33117
|
-
({ path }) => unlink(
|
|
34965
|
+
({ path }) => unlink(join25(checkout, path))
|
|
33118
34966
|
);
|
|
33119
34967
|
linksElsewhere.push(...strays.map(({ path }) => path));
|
|
33120
34968
|
const committed = await committedEnvFiles(sourceDir);
|
|
@@ -33128,7 +34976,7 @@ async function copyWorkingTree(source, checkout) {
|
|
|
33128
34976
|
outsideProject.push(path);
|
|
33129
34977
|
continue;
|
|
33130
34978
|
}
|
|
33131
|
-
const target2 =
|
|
34979
|
+
const target2 = join25(checkout, path);
|
|
33132
34980
|
if (!inside(await realAncestor(dirname6(target2)), root)) {
|
|
33133
34981
|
outsideProject.push(path);
|
|
33134
34982
|
continue;
|
|
@@ -33153,16 +35001,16 @@ async function copyWorkingTree(source, checkout) {
|
|
|
33153
35001
|
continue;
|
|
33154
35002
|
}
|
|
33155
35003
|
await writeFile7(target2, content, { flag: "wx" });
|
|
33156
|
-
const local = await readLocal(
|
|
35004
|
+
const local = await readLocal(join25(sourceDir, path));
|
|
33157
35005
|
if (!local || !sameText(local, content)) committedVersion.push(path);
|
|
33158
35006
|
}
|
|
33159
35007
|
const envStrays = await keptOnly(
|
|
33160
35008
|
envLinks,
|
|
33161
35009
|
async (path) => {
|
|
33162
|
-
const real = await realpath3(
|
|
35010
|
+
const real = await realpath3(join25(checkout, path)).catch(() => null);
|
|
33163
35011
|
return real !== null && inside(real, root);
|
|
33164
35012
|
},
|
|
33165
|
-
(path) => unlink(
|
|
35013
|
+
(path) => unlink(join25(checkout, path))
|
|
33166
35014
|
);
|
|
33167
35015
|
outsideProject.push(...envStrays);
|
|
33168
35016
|
const inCommit = new Set(
|
|
@@ -33215,7 +35063,7 @@ function forEnvironment(text3, environment) {
|
|
|
33215
35063
|
|
|
33216
35064
|
// src/commands/migration.ts
|
|
33217
35065
|
import { mkdirSync as mkdirSync3, readFileSync as readFileSync7, writeFileSync as writeFileSync3 } from "fs";
|
|
33218
|
-
import { join as
|
|
35066
|
+
import { join as join26, relative as relative7 } from "path";
|
|
33219
35067
|
|
|
33220
35068
|
// src/prompt.ts
|
|
33221
35069
|
import { createInterface as createInterface2 } from "readline";
|
|
@@ -33389,7 +35237,7 @@ function warningLines(message) {
|
|
|
33389
35237
|
}
|
|
33390
35238
|
function policyProblems(dir, names) {
|
|
33391
35239
|
return names.flatMap((name) => {
|
|
33392
|
-
const split2 = splitStatements(readFileSync7(
|
|
35240
|
+
const split2 = splitStatements(readFileSync7(join26(dir, name), "utf8"));
|
|
33393
35241
|
if (!split2.ok) return [];
|
|
33394
35242
|
const planned = planPolicyMigration(
|
|
33395
35243
|
split2.statements.map((statement2) => statement2.text)
|
|
@@ -33420,7 +35268,7 @@ async function runMigrationNew(context, deps = processStdin) {
|
|
|
33420
35268
|
const body = fromStdin ? piped.endsWith("\n") ? piped : `${piped}
|
|
33421
35269
|
` : `-- Migration: ${fileName}
|
|
33422
35270
|
`;
|
|
33423
|
-
const path =
|
|
35271
|
+
const path = join26(dir, fileName);
|
|
33424
35272
|
writeFileSync3(path, body, { flag: "wx" });
|
|
33425
35273
|
const relPath = relativeToCwd(context, path);
|
|
33426
35274
|
context.output.result({ file: fileName, path: relPath, fromStdin }, [
|
|
@@ -33449,7 +35297,7 @@ async function applyMigrationFiles(context, client, projectId, dir, names) {
|
|
|
33449
35297
|
const applied = [];
|
|
33450
35298
|
const warnings = [];
|
|
33451
35299
|
for (const name of names) {
|
|
33452
|
-
const sql = readFileSync7(
|
|
35300
|
+
const sql = readFileSync7(join26(dir, name), "utf8");
|
|
33453
35301
|
let answer;
|
|
33454
35302
|
try {
|
|
33455
35303
|
answer = await client.db.applyMigration(projectId, { name, sql });
|
|
@@ -33661,7 +35509,7 @@ var BUNDLE_MESSAGES = {
|
|
|
33661
35509
|
|
|
33662
35510
|
// ../../packages/functions-bundler/src/discover.ts
|
|
33663
35511
|
import { existsSync as existsSync7, readdirSync as readdirSync3, readFileSync as readFileSync8, statSync as statSync2 } from "fs";
|
|
33664
|
-
import { join as
|
|
35512
|
+
import { join as join27, relative as relative8, resolve as resolve11, sep as sep6 } from "path";
|
|
33665
35513
|
|
|
33666
35514
|
// ../../packages/functions-bundler/src/limits.ts
|
|
33667
35515
|
var FUNCTION_BUNDLE_MAX_BYTES = 67108864;
|
|
@@ -33685,7 +35533,7 @@ function isEntrypoint(value) {
|
|
|
33685
35533
|
function functionsFolder(options) {
|
|
33686
35534
|
const root = resolve11(options.cwd, options.root ?? ".");
|
|
33687
35535
|
const explicit = options.dir !== void 0;
|
|
33688
|
-
const dir = explicit ? resolve11(options.cwd, options.dir) :
|
|
35536
|
+
const dir = explicit ? resolve11(options.cwd, options.dir) : join27(root, "naro", "functions");
|
|
33689
35537
|
const label2 = relative8(options.cwd, dir).split(sep6).join("/") || ".";
|
|
33690
35538
|
return { dir, label: label2, root, explicit };
|
|
33691
35539
|
}
|
|
@@ -33694,7 +35542,7 @@ function listFunctionNames(folder) {
|
|
|
33694
35542
|
try {
|
|
33695
35543
|
entries = readdirSync3(folder.dir, { withFileTypes: true });
|
|
33696
35544
|
} catch {
|
|
33697
|
-
if (!folder.explicit && existsSync7(
|
|
35545
|
+
if (!folder.explicit && existsSync7(join27(folder.root, "supabase", "functions")))
|
|
33698
35546
|
throw new FunctionBundleError(
|
|
33699
35547
|
"VALIDATION_FAILED",
|
|
33700
35548
|
BUNDLE_MESSAGES.supabaseFound
|
|
@@ -33715,7 +35563,7 @@ function listFunctionNames(folder) {
|
|
|
33715
35563
|
return names;
|
|
33716
35564
|
}
|
|
33717
35565
|
function readFunctionJson(dir, name) {
|
|
33718
|
-
const file2 =
|
|
35566
|
+
const file2 = join27(dir, "function.json");
|
|
33719
35567
|
if (!existsSync7(file2)) return { verifyJwt: void 0, entrypoint: void 0 };
|
|
33720
35568
|
let parsed;
|
|
33721
35569
|
try {
|
|
@@ -33759,7 +35607,7 @@ function readFunctionSource(folder, name) {
|
|
|
33759
35607
|
"VALIDATION_FAILED",
|
|
33760
35608
|
BUNDLE_MESSAGES.badName(name)
|
|
33761
35609
|
);
|
|
33762
|
-
const dir =
|
|
35610
|
+
const dir = join27(folder.dir, name);
|
|
33763
35611
|
if (!statSync2(dir, { throwIfNoEntry: false })?.isDirectory())
|
|
33764
35612
|
throw new FunctionBundleError(
|
|
33765
35613
|
"VALIDATION_FAILED",
|
|
@@ -33768,14 +35616,14 @@ function readFunctionSource(folder, name) {
|
|
|
33768
35616
|
const config2 = readFunctionJson(dir, name);
|
|
33769
35617
|
let entrypoint;
|
|
33770
35618
|
if (config2.entrypoint !== void 0) {
|
|
33771
|
-
if (!existsSync7(
|
|
35619
|
+
if (!existsSync7(join27(dir, ...config2.entrypoint.split("/"))))
|
|
33772
35620
|
throw new FunctionBundleError(
|
|
33773
35621
|
"FUNCTION_BUNDLE_FAILED",
|
|
33774
35622
|
BUNDLE_MESSAGES.entryMissing(name, config2.entrypoint)
|
|
33775
35623
|
);
|
|
33776
35624
|
entrypoint = config2.entrypoint;
|
|
33777
35625
|
} else {
|
|
33778
|
-
const found = ENTRY_FILES.find((file2) => existsSync7(
|
|
35626
|
+
const found = ENTRY_FILES.find((file2) => existsSync7(join27(dir, file2)));
|
|
33779
35627
|
if (found === void 0)
|
|
33780
35628
|
throw new FunctionBundleError(
|
|
33781
35629
|
"FUNCTION_BUNDLE_FAILED",
|
|
@@ -33786,14 +35634,14 @@ function readFunctionSource(folder, name) {
|
|
|
33786
35634
|
return {
|
|
33787
35635
|
name,
|
|
33788
35636
|
dir,
|
|
33789
|
-
entry:
|
|
35637
|
+
entry: join27(dir, ...entrypoint.split("/")),
|
|
33790
35638
|
entrypoint,
|
|
33791
35639
|
verifyJwt: config2.verifyJwt
|
|
33792
35640
|
};
|
|
33793
35641
|
}
|
|
33794
35642
|
function configTomlWarning(folder) {
|
|
33795
|
-
if (!folder.dir.endsWith(
|
|
33796
|
-
const file2 =
|
|
35643
|
+
if (!folder.dir.endsWith(join27("supabase", "functions"))) return null;
|
|
35644
|
+
const file2 = join27(folder.dir, "..", "config.toml");
|
|
33797
35645
|
if (!existsSync7(file2)) return null;
|
|
33798
35646
|
return /^\s*verify_jwt\s*=/m.test(readFileSync8(file2, "utf8")) ? BUNDLE_MESSAGES.supabaseVerifyJwt(folder.label) : null;
|
|
33799
35647
|
}
|
|
@@ -33999,11 +35847,11 @@ ${injects.map(
|
|
|
33999
35847
|
|
|
34000
35848
|
// ../../packages/functions-bundler/src/deno-imports.ts
|
|
34001
35849
|
import { existsSync as existsSync9, readFileSync as readFileSync10, realpathSync as realpathSync2 } from "fs";
|
|
34002
|
-
import { dirname as dirname9, isAbsolute as isAbsolute5, join as
|
|
35850
|
+
import { dirname as dirname9, isAbsolute as isAbsolute5, join as join29, relative as relative9, sep as sep8 } from "path";
|
|
34003
35851
|
|
|
34004
35852
|
// ../../packages/functions-bundler/src/import-map.ts
|
|
34005
35853
|
import { existsSync as existsSync8, readFileSync as readFileSync9, realpathSync } from "fs";
|
|
34006
|
-
import { basename as basename4, dirname as dirname8, join as
|
|
35854
|
+
import { basename as basename4, dirname as dirname8, join as join28, resolve as resolve12, sep as sep7 } from "path";
|
|
34007
35855
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
34008
35856
|
|
|
34009
35857
|
// ../../packages/functions-bundler/src/printable.ts
|
|
@@ -34075,7 +35923,7 @@ function readImportMapFile(file2, label2) {
|
|
|
34075
35923
|
}
|
|
34076
35924
|
function readImportMap(functionDir, fallback, labelOf) {
|
|
34077
35925
|
for (const name of FILES) {
|
|
34078
|
-
const file2 =
|
|
35926
|
+
const file2 = join28(functionDir, name);
|
|
34079
35927
|
if (!existsSync8(file2)) continue;
|
|
34080
35928
|
const map2 = load(file2, labelOf(file2));
|
|
34081
35929
|
if (map2 !== null) return map2;
|
|
@@ -34218,7 +36066,7 @@ function packageDir(from, projectRoot) {
|
|
|
34218
36066
|
let current = from;
|
|
34219
36067
|
while (isInside(current, projectRoot)) {
|
|
34220
36068
|
const inNodeModules = fromRoot(projectRoot, current).split("/").includes("node_modules");
|
|
34221
|
-
if (!inNodeModules && existsSync9(
|
|
36069
|
+
if (!inNodeModules && existsSync9(join29(current, "package.json")))
|
|
34222
36070
|
return fromRoot(projectRoot, current) || ".";
|
|
34223
36071
|
const up = dirname9(current);
|
|
34224
36072
|
if (up === current) break;
|
|
@@ -34230,7 +36078,7 @@ function isInstalled(from, pkg) {
|
|
|
34230
36078
|
if (pkg === "") return false;
|
|
34231
36079
|
let current = from;
|
|
34232
36080
|
for (; ; ) {
|
|
34233
|
-
if (existsSync9(
|
|
36081
|
+
if (existsSync9(join29(current, "node_modules", pkg))) return true;
|
|
34234
36082
|
const up = dirname9(current);
|
|
34235
36083
|
if (up === current) return false;
|
|
34236
36084
|
current = up;
|
|
@@ -34240,7 +36088,7 @@ var NODE_MODULES = /[\\/]node_modules[\\/]/;
|
|
|
34240
36088
|
function installedVersion(resolved, pkg) {
|
|
34241
36089
|
let current = dirname9(resolved);
|
|
34242
36090
|
for (; ; ) {
|
|
34243
|
-
const file2 =
|
|
36091
|
+
const file2 = join29(current, "package.json");
|
|
34244
36092
|
if (existsSync9(file2)) {
|
|
34245
36093
|
try {
|
|
34246
36094
|
const manifest2 = JSON.parse(readFileSync10(file2, "utf8"));
|
|
@@ -34424,7 +36272,7 @@ function denoImportsPlugin(options) {
|
|
|
34424
36272
|
|
|
34425
36273
|
// ../../packages/functions-bundler/src/bundle.ts
|
|
34426
36274
|
import { createHash as createHash4 } from "crypto";
|
|
34427
|
-
import { join as
|
|
36275
|
+
import { join as join30, relative as relative10, sep as sep9 } from "path";
|
|
34428
36276
|
import { gzipSync } from "zlib";
|
|
34429
36277
|
|
|
34430
36278
|
// ../../packages/functions-runtime/dist/index.js
|
|
@@ -34500,7 +36348,7 @@ async function bundleFunction(source, folder, options = {}) {
|
|
|
34500
36348
|
result = await build({
|
|
34501
36349
|
absWorkingDir: folder.root,
|
|
34502
36350
|
entryPoints: [source.entry],
|
|
34503
|
-
outfile:
|
|
36351
|
+
outfile: join30(source.dir, NARO_USER_MODULE),
|
|
34504
36352
|
bundle: true,
|
|
34505
36353
|
write: false,
|
|
34506
36354
|
format: "esm",
|
|
@@ -35070,7 +36918,7 @@ function slugify2(value) {
|
|
|
35070
36918
|
async function projectName(sourceDir) {
|
|
35071
36919
|
try {
|
|
35072
36920
|
const pkg = JSON.parse(
|
|
35073
|
-
await readFile15(
|
|
36921
|
+
await readFile15(join31(sourceDir, "package.json"), "utf8")
|
|
35074
36922
|
);
|
|
35075
36923
|
if (pkg.name) return pkg.name;
|
|
35076
36924
|
} catch {
|
|
@@ -35080,7 +36928,7 @@ async function projectName(sourceDir) {
|
|
|
35080
36928
|
function resolveBin(name) {
|
|
35081
36929
|
let dir = dirname10(fileURLToPath4(import.meta.url));
|
|
35082
36930
|
for (; ; ) {
|
|
35083
|
-
const candidate =
|
|
36931
|
+
const candidate = join31(dir, "node_modules", ".bin", name);
|
|
35084
36932
|
if (existsSync10(candidate)) return candidate;
|
|
35085
36933
|
const parent = dirname10(dir);
|
|
35086
36934
|
if (parent === dir) return name;
|
|
@@ -35147,7 +36995,7 @@ function workingTreeNotices(copy) {
|
|
|
35147
36995
|
}
|
|
35148
36996
|
function localDependencies(sourceDir, say = () => void 0) {
|
|
35149
36997
|
return {
|
|
35150
|
-
createWorkspace: () => mkdtemp2(
|
|
36998
|
+
createWorkspace: () => mkdtemp2(join31(tmpdir2(), "naro-build-")),
|
|
35151
36999
|
removeWorkspace: (path) => rm5(path, { recursive: true, force: true }),
|
|
35152
37000
|
async runCommand(spec, observer) {
|
|
35153
37001
|
if (spec.command === "git" && spec.args[0] === "clone") {
|
|
@@ -35402,6 +37250,8 @@ function deploymentUrl(detail, ctx, production) {
|
|
|
35402
37250
|
}
|
|
35403
37251
|
|
|
35404
37252
|
export {
|
|
37253
|
+
CAPABILITIES,
|
|
37254
|
+
dashboardNeeds,
|
|
35405
37255
|
parseDotenvDetailed,
|
|
35406
37256
|
FUNCTION_INVOKE_METHODS,
|
|
35407
37257
|
FUNCTION_INVOKE_MAX_RESPONSE_BYTES,
|
|
@@ -35439,6 +37289,8 @@ export {
|
|
|
35439
37289
|
POLICY_RULES,
|
|
35440
37290
|
POLICY_ACTIONS,
|
|
35441
37291
|
NaroClient,
|
|
37292
|
+
dashboardCapability,
|
|
37293
|
+
dashboardLink,
|
|
35442
37294
|
BOOKMARK_FORMAT_MESSAGE,
|
|
35443
37295
|
isBookmark,
|
|
35444
37296
|
RESTORE_OUTCOME_UNKNOWN_CODES,
|