naro-mcp 0.18.0 → 0.18.1
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 +2 -2
- package/dist/index.js +139 -74
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -60,10 +60,10 @@ Headless/CI agents can skip `naro login` and set a token instead:
|
|
|
60
60
|
| `whoami`, `list_teams` | Account / team context |
|
|
61
61
|
| `list_projects`, `get_project`, `link_project` | Project discovery + `.naro/project.json` linking |
|
|
62
62
|
| `get_team_usage` | Team usage for a UTC month (`month`, the current one by default): requests, builds and custom domains per day and per project, the plan's `limits`, the enforcement mode, and `summary` (each metric against its limit, and `status` paused/over/near). `team` defaults to the team linked in `directory`, then your only team; otherwise `needsTeam` with the list. Owner, billing and enterprise_viewer only (403 `FORBIDDEN` otherwise). Read-only |
|
|
63
|
-
| `deploy` | Local Next.js build → upload → live URL (preview, `production: true`, or a named environment with `environment: "qa"` — not together with `production
|
|
63
|
+
| `deploy` | Local Next.js build → upload → live URL (preview, `production: true`, or a named environment with `environment: "qa"` — not together with `production`: both are refused with `VALIDATION_FAILED` `environment and production cannot be used together.` before any value is read, asked for or sent and before the deployment is created; `production` and `preview` are not environment names). The result's `target` is `production`, `preview` or the environment's slug, and `environment` is the slug or null. Local .env files are never uploaded; unset keys come back as `missingEnvKeys` |
|
|
64
64
|
| `list_deployments`, `get_deployment` | Deployment status / history |
|
|
65
65
|
| `get_build_logs`, `get_runtime_logs` | Debugging failed builds and live workers |
|
|
66
|
-
| `list_environment_variables`, `set_environment_variable`, `remove_environment_variable` | Env management (secret values never returned). `target` is `production`, `preview`, `all` or an environment's slug (`all` by default when setting); without `target`, `remove_environment_variable` removes the `production`, `preview` and `all` rows and leaves an environment's value alone. A name that cannot be a slug is refused as `Invalid target "<value>" — use production, preview, all or an environment name
|
|
66
|
+
| `list_environment_variables`, `set_environment_variable`, `remove_environment_variable` | Env management (secret values never returned). `target` is `production`, `preview`, `all` or an environment's slug (`all` by default when setting); without `target`, `remove_environment_variable` removes the `production`, `preview` and `all` rows and leaves an environment's value alone. A name that cannot be a slug is refused as `Invalid target "<value>" — use production, preview, all or an environment name.`. For `set_environment_variable`, a slug that is not an environment answers `404 ENVIRONMENT_NOT_FOUND`; `remove_environment_variable` reads the list and answers `ENV_NOT_FOUND` (`No KEY variable found for the <slug> environment.`). Without `target`, a key only environments hold answers `ENV_NOT_FOUND` `No KEY variable found outside named environments. Pass the environment to remove it: qa.` with `key` and `environments`, and nothing is removed |
|
|
67
67
|
| `list_domains`, `add_domain`, `verify_domain`, `remove_domain` | Custom domains: the one CNAME to create (naro connects it within ~5 minutes), plus a re-check that says which of ownership / certificate / routing is still missing. An apex is attached as an apex+www pair by default (`withWww: false` to opt out) |
|
|
68
68
|
| `promote_deployment`, `rollback_deployment` | Production traffic control |
|
|
69
69
|
| `cancel_deployment` | Stops a build that is still running (QUEUED–BUILDING). Does not undo a deployment that already went live — use `rollback_deployment` for that |
|
package/dist/index.js
CHANGED
|
@@ -15595,6 +15595,8 @@ var DeploymentsApi = class {
|
|
|
15595
15595
|
}
|
|
15596
15596
|
}
|
|
15597
15597
|
};
|
|
15598
|
+
var STATIC_ASSETS_BINDING = "ASSETS";
|
|
15599
|
+
var MANAGED_DATABASE_BINDING = "DB";
|
|
15598
15600
|
var EnvApi = class {
|
|
15599
15601
|
constructor(client) {
|
|
15600
15602
|
this.client = client;
|
|
@@ -15624,6 +15626,37 @@ var EnvApi = class {
|
|
|
15624
15626
|
}
|
|
15625
15627
|
);
|
|
15626
15628
|
}
|
|
15629
|
+
/**
|
|
15630
|
+
* The names the env route refuses as a key — `409 VALIDATION_FAILED`
|
|
15631
|
+
* `<KEY> is already used by a storage binding.` — read the way it reads
|
|
15632
|
+
* them: `ASSETS` (the static files), every binding of the project's storage
|
|
15633
|
+
* and, on a project using the managed database (`database_provider` is
|
|
15634
|
+
* `d1`), `DB`, which may not be a storage row yet. For a caller that sends
|
|
15635
|
+
* many entries in several requests (`naro env import`) and has to refuse
|
|
15636
|
+
* before the first one is saved. A control plane whose project row has no
|
|
15637
|
+
* `database_provider` reads as having no managed database, so `DB` is only
|
|
15638
|
+
* left out there.
|
|
15639
|
+
*/
|
|
15640
|
+
async takenBindingNames(projectId) {
|
|
15641
|
+
const base = `/api/projects/${encodeURIComponent(projectId)}`;
|
|
15642
|
+
const [storage, project] = await Promise.all([
|
|
15643
|
+
this.client.request(
|
|
15644
|
+
`${base}/storage`,
|
|
15645
|
+
{ context: "List storage" }
|
|
15646
|
+
),
|
|
15647
|
+
this.client.request(
|
|
15648
|
+
base,
|
|
15649
|
+
{ context: "Read project" }
|
|
15650
|
+
)
|
|
15651
|
+
]);
|
|
15652
|
+
const names = /* @__PURE__ */ new Set([
|
|
15653
|
+
STATIC_ASSETS_BINDING,
|
|
15654
|
+
...storage.storage.map((row) => row.bindingName)
|
|
15655
|
+
]);
|
|
15656
|
+
if (project.project.database_provider === "d1")
|
|
15657
|
+
names.add(MANAGED_DATABASE_BINDING);
|
|
15658
|
+
return [...names];
|
|
15659
|
+
}
|
|
15627
15660
|
async removeById(projectId, envVarId) {
|
|
15628
15661
|
await this.client.request(
|
|
15629
15662
|
`/api/projects/${encodeURIComponent(projectId)}/env/${encodeURIComponent(envVarId)}`,
|
|
@@ -15634,13 +15667,28 @@ var EnvApi = class {
|
|
|
15634
15667
|
* Removes a key's rows: the one `target` names, or, with no target, the
|
|
15635
15668
|
* `production`, `preview` and `all` rows. An environment's value goes only
|
|
15636
15669
|
* when its slug is the target, so removing a key everywhere else does not
|
|
15637
|
-
* take a QA or staging value with it.
|
|
15670
|
+
* take a QA or staging value with it. A key only environments hold fails
|
|
15671
|
+
* ENV_NOT_FOUND naming them (`details.environments`), not as if there were
|
|
15672
|
+
* none.
|
|
15638
15673
|
*/
|
|
15639
15674
|
async remove(projectId, key, target) {
|
|
15640
15675
|
const rows = await this.list(projectId);
|
|
15641
15676
|
const matches = rows.filter(
|
|
15642
15677
|
(row) => row.key === key && (target === void 0 ? isReservedEnvTarget(row.target) : row.target === target)
|
|
15643
15678
|
);
|
|
15679
|
+
if (matches.length === 0 && target === void 0) {
|
|
15680
|
+
const environments = [
|
|
15681
|
+
...new Set(
|
|
15682
|
+
rows.filter((row) => row.key === key).map((row) => row.target).filter((slug) => !isReservedEnvTarget(slug))
|
|
15683
|
+
)
|
|
15684
|
+
].toSorted();
|
|
15685
|
+
if (environments.length > 0)
|
|
15686
|
+
throw new NaroError(
|
|
15687
|
+
"ENV_NOT_FOUND",
|
|
15688
|
+
`No ${key} variable found outside named environments. Pass the environment to remove it: ${environments.join(", ")}.`,
|
|
15689
|
+
{ details: { key, environments } }
|
|
15690
|
+
);
|
|
15691
|
+
}
|
|
15644
15692
|
if (matches.length === 0) {
|
|
15645
15693
|
throw new NaroError(
|
|
15646
15694
|
"ENV_NOT_FOUND",
|
|
@@ -16912,6 +16960,7 @@ var MEDIA_TYPE = new RegExp(`^${TOKEN_CHARACTERS}+/${TOKEN_CHARACTERS}+$`);
|
|
|
16912
16960
|
// ../../packages/data-core/src/storage-table.ts
|
|
16913
16961
|
var STORAGE_OBJECTS = "storage.objects";
|
|
16914
16962
|
var STORAGE_OBJECTS_TABLE = "_naro_storage_objects";
|
|
16963
|
+
var STORAGE_UNAVAILABLE_REASON = `${STORAGE_OBJECTS} is not available on this backend yet`;
|
|
16915
16964
|
var STORAGE_BUCKETS_TABLE = "_naro_storage_buckets";
|
|
16916
16965
|
var STORAGE_POLICY_COLUMNS = [
|
|
16917
16966
|
"id",
|
|
@@ -17477,7 +17526,6 @@ var SPECIAL_WORDS = /* @__PURE__ */ new Set([
|
|
|
17477
17526
|
"auth"
|
|
17478
17527
|
]);
|
|
17479
17528
|
var TEXT_TYPES = /* @__PURE__ */ new Set(["text", "varchar", "uuid"]);
|
|
17480
|
-
var STORAGE_SUBQUERY_PROBLEM = "A policy cannot read storage.objects in a subquery yet";
|
|
17481
17529
|
var FOLDERNAME_INDEX_PROBLEM = `storage.foldername(name) is available only as (storage.foldername(name))[n] with n from 1 to ${String(MAX_FOLDERNAME_INDEX)}`;
|
|
17482
17530
|
function storageHelperColumnProblem(fn) {
|
|
17483
17531
|
return `storage.${fn}() takes the name column of storage.objects`;
|
|
@@ -17928,8 +17976,12 @@ function atRealtimeMessages(stream) {
|
|
|
17928
17976
|
}
|
|
17929
17977
|
function readTableName(stream) {
|
|
17930
17978
|
const first = stream.peek();
|
|
17931
|
-
if (atStorageObjects(stream))
|
|
17932
|
-
|
|
17979
|
+
if (atStorageObjects(stream)) {
|
|
17980
|
+
stream.next();
|
|
17981
|
+
stream.next();
|
|
17982
|
+
stream.next();
|
|
17983
|
+
return STORAGE_OBJECTS;
|
|
17984
|
+
}
|
|
17933
17985
|
if (atRealtimeMessages(stream))
|
|
17934
17986
|
throw new PolicySyntaxError(REALTIME_SUBQUERY_PROBLEM, first.position);
|
|
17935
17987
|
let token = first;
|
|
@@ -18366,9 +18418,10 @@ function printValue(expr) {
|
|
|
18366
18418
|
}
|
|
18367
18419
|
function printSubquery(subquery) {
|
|
18368
18420
|
const select = subquery.select === "*" ? "*" : printValue(subquery.select);
|
|
18421
|
+
const table = asciiLower(subquery.table) === STORAGE_OBJECTS ? STORAGE_OBJECTS : quoteIdent(subquery.table);
|
|
18369
18422
|
const alias = subquery.alias === null ? "" : ` ${quoteIdent(subquery.alias)}`;
|
|
18370
18423
|
const where = subquery.where === null ? "" : ` WHERE ${printExpr(subquery.where)}`;
|
|
18371
|
-
return `SELECT ${select} FROM ${
|
|
18424
|
+
return `SELECT ${select} FROM ${table}${alias}${where}`;
|
|
18372
18425
|
}
|
|
18373
18426
|
function printElement(element) {
|
|
18374
18427
|
if (typeof element === "object") return printValue(element);
|
|
@@ -19326,70 +19379,9 @@ var PROJECT_BYTES = `(SELECT coalesce(sum(total_bytes), 0) FROM ${STORAGE_BUCKET
|
|
|
19326
19379
|
var LIVE_BUCKET = `${STORAGE_BUCKET_DELETING_COLUMN.column} IS NULL`;
|
|
19327
19380
|
|
|
19328
19381
|
// ../../packages/data-core/src/policy-check.ts
|
|
19329
|
-
var CONTEXTS = [
|
|
19330
|
-
{ role: "anon" },
|
|
19331
|
-
{
|
|
19332
|
-
role: "authenticated",
|
|
19333
|
-
userId: "naro-policy-check",
|
|
19334
|
-
email: "check@naro.invalid",
|
|
19335
|
-
emailVerified: true
|
|
19336
|
-
}
|
|
19337
|
-
];
|
|
19338
19382
|
var STORAGE_PROBE_NONCE = "f".repeat(STORAGE_NONCE_MAX_DIGITS);
|
|
19339
|
-
var STORAGE_CONTEXTS = [
|
|
19340
|
-
...CONTEXTS,
|
|
19341
|
-
{ role: "authenticated", userId: "naro-policy-check" }
|
|
19342
|
-
];
|
|
19343
19383
|
var REALTIME_PROBE_NONCE = "f".repeat(64);
|
|
19344
19384
|
|
|
19345
|
-
// ../../packages/data-core/src/policy-migration.ts
|
|
19346
|
-
var STORED_POLICIES_SQL = `SELECT table_name, name, kind, command, roles, using_expr, check_expr, owner_column, updated_at FROM ${NAMED_POLICY_TABLE} ORDER BY table_name, name`;
|
|
19347
|
-
var SYSTEM_PREDICATE = systemTablePredicate("name");
|
|
19348
|
-
var STORAGE_EXISTS = `EXISTS (SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = ${sqlStringLiteral(STORAGE_OBJECTS_TABLE)})`;
|
|
19349
|
-
|
|
19350
|
-
// ../../packages/data-core/src/realtime-limits.ts
|
|
19351
|
-
var HOBBY_REALTIME_LIMITS = Object.freeze({
|
|
19352
|
-
connections: 200,
|
|
19353
|
-
newConnectionsPerSecond: 10,
|
|
19354
|
-
messagesPerSecond: 100,
|
|
19355
|
-
joinsPerSecond: 100,
|
|
19356
|
-
presencePerSecond: 20,
|
|
19357
|
-
broadcastPayloadBytes: 262144,
|
|
19358
|
-
policyChecksPerSecond: 100,
|
|
19359
|
-
restRequestsPerSecond: 10
|
|
19360
|
-
});
|
|
19361
|
-
var PRO_REALTIME_LIMITS = Object.freeze({
|
|
19362
|
-
connections: 500,
|
|
19363
|
-
newConnectionsPerSecond: 25,
|
|
19364
|
-
messagesPerSecond: 500,
|
|
19365
|
-
joinsPerSecond: 500,
|
|
19366
|
-
presencePerSecond: 50,
|
|
19367
|
-
broadcastPayloadBytes: 3072e3,
|
|
19368
|
-
policyChecksPerSecond: 250,
|
|
19369
|
-
restRequestsPerSecond: 25
|
|
19370
|
-
});
|
|
19371
|
-
var ENTERPRISE_REALTIME_LIMITS = Object.freeze({
|
|
19372
|
-
connections: 2e3,
|
|
19373
|
-
newConnectionsPerSecond: 100,
|
|
19374
|
-
messagesPerSecond: 1e3,
|
|
19375
|
-
joinsPerSecond: 1e3,
|
|
19376
|
-
presencePerSecond: 1e3,
|
|
19377
|
-
broadcastPayloadBytes: 3072e3,
|
|
19378
|
-
policyChecksPerSecond: 500,
|
|
19379
|
-
restRequestsPerSecond: 100
|
|
19380
|
-
});
|
|
19381
|
-
|
|
19382
|
-
// ../../packages/data-core/src/storage-multipart.ts
|
|
19383
|
-
var MiB = 1024 * 1024;
|
|
19384
|
-
var MULTIPART_PART_SIZES = [16 * MiB, 32 * MiB, 64 * MiB];
|
|
19385
|
-
var MAX_MULTIPART_PARTS = 1e4;
|
|
19386
|
-
var MAX_MULTIPART_BYTES = 64 * MiB * MAX_MULTIPART_PARTS;
|
|
19387
|
-
var MULTIPART_LOCK_MS = 60 * 60 * 1e3;
|
|
19388
|
-
var MULTIPART_PART_EXTEND_BELOW_MS = 30 * 60 * 1e3;
|
|
19389
|
-
var MULTIPART_COMPLETE_LOCK_MS = 15 * 60 * 1e3;
|
|
19390
|
-
var UUID = "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}";
|
|
19391
|
-
var UPLOAD_ID = new RegExp(`^(${UUID})\\.(${UUID})$`);
|
|
19392
|
-
|
|
19393
19385
|
// ../../packages/data-core/src/system-sql.ts
|
|
19394
19386
|
async function convertLegacyPolicies(db, found) {
|
|
19395
19387
|
const rows = rowsOf(await db.prepare(POLICY_SQL.list).all());
|
|
@@ -19420,6 +19412,9 @@ async function convertLegacyPolicies(db, found) {
|
|
|
19420
19412
|
return statements;
|
|
19421
19413
|
}
|
|
19422
19414
|
var MIGRATIONS_TABLE = "CREATE TABLE IF NOT EXISTS _naro_migrations (version INTEGER PRIMARY KEY, name TEXT NOT NULL, applied_at TEXT NOT NULL DEFAULT (datetime('now')))";
|
|
19415
|
+
var STORAGE_SUBQUERIES_VERSION = 7;
|
|
19416
|
+
var STORAGE_SUBQUERIES_NAME = "storage_subquery_policies";
|
|
19417
|
+
var STORAGE_SUBQUERIES_SQL = `SELECT version FROM _naro_migrations WHERE version = ${String(STORAGE_SUBQUERIES_VERSION)} AND name = '${STORAGE_SUBQUERIES_NAME}'`;
|
|
19423
19418
|
var SYSTEM_MIGRATIONS = [
|
|
19424
19419
|
{
|
|
19425
19420
|
version: 1,
|
|
@@ -19488,9 +19483,78 @@ var SYSTEM_MIGRATIONS = [
|
|
|
19488
19483
|
name: "storage_bucket_deleting",
|
|
19489
19484
|
statements: [],
|
|
19490
19485
|
addColumns: [STORAGE_BUCKET_DELETING_COLUMN]
|
|
19486
|
+
},
|
|
19487
|
+
{
|
|
19488
|
+
// Storage 3-1j (plan correction (p)): no schema — the mark that a worker
|
|
19489
|
+
// which reads storage.objects in a policy's subquery has migrated this
|
|
19490
|
+
// database. Only the Naro worker's own `internal/migrate` applies system
|
|
19491
|
+
// migrations, so the row is there once such a worker has run, and stays:
|
|
19492
|
+
// every later worker reads them too — as long as the worker bundle does
|
|
19493
|
+
// not go back. Deploying web from before 3-1j makes the next upgrade
|
|
19494
|
+
// put an older worker back, and a run that lost its lease may upload
|
|
19495
|
+
// one late; such a policy then answers 500 POLICY_INVALID (closed, no
|
|
19496
|
+
// rows) until it is dropped or the newer worker is uploaded again
|
|
19497
|
+
// (3-1j 최종 리뷰). Migration 5 alone cannot tell —
|
|
19498
|
+
// backends migrated by 3-1a to 3-1i have it, and their worker refuses
|
|
19499
|
+
// such a policy ("A policy cannot read storage.objects in a subquery
|
|
19500
|
+
// yet") and answers every request of its table 500 POLICY_INVALID until
|
|
19501
|
+
// the next upgrade. The control plane takes one only where this row is
|
|
19502
|
+
// (`STORAGE_SUBQUERIES_SQL`, `buildPolicyBatch`).
|
|
19503
|
+
version: STORAGE_SUBQUERIES_VERSION,
|
|
19504
|
+
name: STORAGE_SUBQUERIES_NAME,
|
|
19505
|
+
statements: []
|
|
19491
19506
|
}
|
|
19492
19507
|
];
|
|
19493
19508
|
|
|
19509
|
+
// ../../packages/data-core/src/policy-migration.ts
|
|
19510
|
+
var STORED_POLICIES_SQL = `SELECT table_name, name, kind, command, roles, using_expr, check_expr, owner_column, updated_at FROM ${NAMED_POLICY_TABLE} ORDER BY table_name, name`;
|
|
19511
|
+
var SYSTEM_PREDICATE = systemTablePredicate("name");
|
|
19512
|
+
var STORAGE_EXISTS = `EXISTS (SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = ${sqlStringLiteral(STORAGE_OBJECTS_TABLE)})`;
|
|
19513
|
+
var STORAGE_SUBQUERIES_READY = `EXISTS (${STORAGE_SUBQUERIES_SQL})`;
|
|
19514
|
+
|
|
19515
|
+
// ../../packages/data-core/src/realtime-limits.ts
|
|
19516
|
+
var HOBBY_REALTIME_LIMITS = Object.freeze({
|
|
19517
|
+
connections: 200,
|
|
19518
|
+
newConnectionsPerSecond: 10,
|
|
19519
|
+
messagesPerSecond: 100,
|
|
19520
|
+
joinsPerSecond: 100,
|
|
19521
|
+
presencePerSecond: 20,
|
|
19522
|
+
broadcastPayloadBytes: 262144,
|
|
19523
|
+
policyChecksPerSecond: 100,
|
|
19524
|
+
restRequestsPerSecond: 10
|
|
19525
|
+
});
|
|
19526
|
+
var PRO_REALTIME_LIMITS = Object.freeze({
|
|
19527
|
+
connections: 500,
|
|
19528
|
+
newConnectionsPerSecond: 25,
|
|
19529
|
+
messagesPerSecond: 500,
|
|
19530
|
+
joinsPerSecond: 500,
|
|
19531
|
+
presencePerSecond: 50,
|
|
19532
|
+
broadcastPayloadBytes: 3072e3,
|
|
19533
|
+
policyChecksPerSecond: 250,
|
|
19534
|
+
restRequestsPerSecond: 25
|
|
19535
|
+
});
|
|
19536
|
+
var ENTERPRISE_REALTIME_LIMITS = Object.freeze({
|
|
19537
|
+
connections: 2e3,
|
|
19538
|
+
newConnectionsPerSecond: 100,
|
|
19539
|
+
messagesPerSecond: 1e3,
|
|
19540
|
+
joinsPerSecond: 1e3,
|
|
19541
|
+
presencePerSecond: 1e3,
|
|
19542
|
+
broadcastPayloadBytes: 3072e3,
|
|
19543
|
+
policyChecksPerSecond: 500,
|
|
19544
|
+
restRequestsPerSecond: 100
|
|
19545
|
+
});
|
|
19546
|
+
|
|
19547
|
+
// ../../packages/data-core/src/storage-multipart.ts
|
|
19548
|
+
var MiB = 1024 * 1024;
|
|
19549
|
+
var MULTIPART_PART_SIZES = [16 * MiB, 32 * MiB, 64 * MiB];
|
|
19550
|
+
var MAX_MULTIPART_PARTS = 1e4;
|
|
19551
|
+
var MAX_MULTIPART_BYTES = 64 * MiB * MAX_MULTIPART_PARTS;
|
|
19552
|
+
var MULTIPART_LOCK_MS = 60 * 60 * 1e3;
|
|
19553
|
+
var MULTIPART_PART_EXTEND_BELOW_MS = 30 * 60 * 1e3;
|
|
19554
|
+
var MULTIPART_COMPLETE_LOCK_MS = 15 * 60 * 1e3;
|
|
19555
|
+
var UUID = "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}";
|
|
19556
|
+
var UPLOAD_ID = new RegExp(`^(${UUID})\\.(${UUID})$`);
|
|
19557
|
+
|
|
19494
19558
|
// ../../packages/data-core/src/write-quota.ts
|
|
19495
19559
|
var WRITE_QUOTA_KEY = "write_quota";
|
|
19496
19560
|
var WRITE_QUOTA_SQL = {
|
|
@@ -20627,7 +20691,7 @@ var DATABASE_TOOLS = [
|
|
|
20627
20691
|
destructiveHint: true,
|
|
20628
20692
|
idempotentHint: false
|
|
20629
20693
|
},
|
|
20630
|
-
description: `${DESTRUCTIVE}applies a migration (DDL) to the D1 database and records it in the d1_migrations ledger \u2014 the same ledger wrangler uses. \`name\` is a short snake_case title; naro numbers it (NNNN_name.sql) and, when the project directory is known, writes the file to ./migrations so \`naro db push\` sees it as applied. All-or-nothing: if a statement fails, the whole migration is rolled back and not recorded. Write CREATE POLICY in the same migration as the table, as in Supabase: it is applied with the table, all or nothing. A table without a policy refuses every anon and signed-in request to the Data API. DROP POLICY [IF EXISTS], COMMENT ON POLICY p ON t IS 'naro:owner <column>' and ALTER TABLE t ENABLE ROW LEVEL SECURITY are accepted too; DISABLE ROW LEVEL SECURITY, GRANT, REVOKE and ALTER POLICY are refused before anything runs. Dropping a table drops its policies, so a SQLite table rebuild (create __new_x, copy, drop x, rename) must create the policies again after the rename: warnings lists the ones it removed, with their SQL. ALTER TABLE a RENAME TO b moves a's policies to b and rewrites the policies of other tables that read a, as in Postgres: do not create them again on b, where one of the same name is refused. ${UNTRUSTED} ${SHARED_DATABASE} ${LIMITS}`,
|
|
20694
|
+
description: `${DESTRUCTIVE}applies a migration (DDL) to the D1 database and records it in the d1_migrations ledger \u2014 the same ledger wrangler uses. \`name\` is a short snake_case title; naro numbers it (NNNN_name.sql) and, when the project directory is known, writes the file to ./migrations so \`naro db push\` sees it as applied. All-or-nothing: if a statement fails, the whole migration is rolled back and not recorded. Write CREATE POLICY in the same migration as the table, as in Supabase: it is applied with the table, all or nothing. A table without a policy refuses every anon and signed-in request to the Data API. DROP POLICY [IF EXISTS], COMMENT ON POLICY p ON t IS 'naro:owner <column>' and ALTER TABLE t ENABLE ROW LEVEL SECURITY are accepted too; DISABLE ROW LEVEL SECURITY, GRANT, REVOKE and ALTER POLICY are refused before anything runs. Dropping a table drops its policies, so a SQLite table rebuild (create __new_x, copy, drop x, rename) must create the policies again after the rename: warnings lists the ones it removed, with their SQL. ALTER TABLE a RENAME TO b moves a's policies to b and rewrites the policies of other tables that read a, as in Postgres: do not create them again on b, where one of the same name is refused. ALTER TABLE t RENAME COLUMN c TO d rewrites every policy that reads t.c, an owner rule's column included, to read t.d; a rename such a policy cannot follow is refused before anything runs. ${UNTRUSTED} ${SHARED_DATABASE} ${LIMITS}`,
|
|
20631
20695
|
inputSchema: {
|
|
20632
20696
|
type: "object",
|
|
20633
20697
|
properties: {
|
|
@@ -20731,7 +20795,7 @@ var DATABASE_TOOLS = [
|
|
|
20731
20795
|
destructiveHint: true,
|
|
20732
20796
|
idempotentHint: false
|
|
20733
20797
|
},
|
|
20734
|
-
description: `${DESTRUCTIVE}changes a table of the project's D1 database without writing SQL, as one migration recorded in d1_migrations and written to ./migrations when the project directory is known. action is add_column (newColumn, shaped like a create_table column), rename_column (column, to), rename_table (to) or drop_column (column) \u2014 which deletes the column and its value in every row and needs confirm set to "<table>.<column>". SQLite cannot add a PRIMARY KEY or UNIQUE column, a NOT NULL column without a default that is not NULL, or a column defaulting to CURRENT_TIMESTAMP, and cannot drop a primary key, UNIQUE or indexed column: naro refuses those up front and says why. It also refuses to drop or rename a table or column that a trigger or view uses (read from their SQL; when the SQL leaves it open, a warning instead) \u2014 drop or recreate that trigger or view with apply_migration first. Changing a column's type is not an action \u2014 it needs a table rebuild, so write that migration with apply_migration. rename_table moves the table's Data API policies to the new name and rewrites the policies of other tables that read it by name, in the same migration, as in Postgres: warnings says which. A rename such a policy cannot follow (an alias in it already goes by the new name) is refused before anything runs. Policies an earlier table left under the new name are removed: removedPolicies lists them: statements has each as the CREATE POLICY that naro policy create takes back, except an owner rule (its ownerColumn is set), which CREATE POLICY cannot say \u2014 setCommand is the naro policy set command that sets those again. A rename or drop that takes a table or column from under a policy \u2014 this table's or, through a subquery, another table's \u2014 makes the requests that policy applies to answer 500 POLICY_INVALID: warnings names each policy the change breaks, with dryRun: true before anything is applied. Read warnings after a rename or a drop. dryRun: true returns the SQL without applying anything. ${UNTRUSTED} ${SHARED_DATABASE}`,
|
|
20798
|
+
description: `${DESTRUCTIVE}changes a table of the project's D1 database without writing SQL, as one migration recorded in d1_migrations and written to ./migrations when the project directory is known. action is add_column (newColumn, shaped like a create_table column), rename_column (column, to), rename_table (to) or drop_column (column) \u2014 which deletes the column and its value in every row and needs confirm set to "<table>.<column>". SQLite cannot add a PRIMARY KEY or UNIQUE column, a NOT NULL column without a default that is not NULL, or a column defaulting to CURRENT_TIMESTAMP, and cannot drop a primary key, UNIQUE or indexed column: naro refuses those up front and says why. It also refuses to drop or rename a table or column that a trigger or view uses (read from their SQL; when the SQL leaves it open, a warning instead) \u2014 drop or recreate that trigger or view with apply_migration first. Changing a column's type is not an action \u2014 it needs a table rebuild, so write that migration with apply_migration. rename_table moves the table's Data API policies to the new name and rewrites the policies of other tables that read it by name, in the same migration, as in Postgres: warnings says which. rename_column rewrites every policy that reads the column, this table's or another's through a subquery, an owner rule's column included: warnings says which. A rename such a policy cannot follow (an alias in it already goes by the new name, or a policy already reads the new column name) is refused before anything runs. Policies an earlier table left under the new name are removed: removedPolicies lists them: statements has each as the CREATE POLICY that naro policy create takes back, except an owner rule (its ownerColumn is set), which CREATE POLICY cannot say \u2014 setCommand is the naro policy set command that sets those again. A rename or drop that takes a table or column from under a policy \u2014 this table's or, through a subquery, another table's \u2014 makes the requests that policy applies to answer 500 POLICY_INVALID: warnings names each policy the change breaks, with dryRun: true before anything is applied. Read warnings after a rename or a drop. dryRun: true returns the SQL without applying anything. ${UNTRUSTED} ${SHARED_DATABASE}`,
|
|
20735
20799
|
inputSchema: {
|
|
20736
20800
|
type: "object",
|
|
20737
20801
|
properties: {
|
|
@@ -22075,7 +22139,7 @@ var REGISTERED = [
|
|
|
22075
22139
|
},
|
|
22076
22140
|
environment: {
|
|
22077
22141
|
type: "string",
|
|
22078
|
-
description: "Slug of a named environment (list_environments, create_environment) to deploy to instead of preview, such as qa. Not together with production: true \u2014 the
|
|
22142
|
+
description: "Slug of a named environment (list_environments, create_environment) to deploy to instead of preview, such as qa. Not together with production: true \u2014 both are refused (VALIDATION_FAILED) before any value is read, asked for or sent and before the deployment is created. production and preview are not environment names: use production: true, or omit this for a preview."
|
|
22079
22143
|
},
|
|
22080
22144
|
branch: {
|
|
22081
22145
|
type: "string",
|
|
@@ -22124,8 +22188,9 @@ var REGISTERED = [
|
|
|
22124
22188
|
projectId: link?.projectId,
|
|
22125
22189
|
teamSlug: team.slug,
|
|
22126
22190
|
production: args.production === true,
|
|
22127
|
-
//
|
|
22128
|
-
// refuses both together
|
|
22191
|
+
// Passed beside production, not instead of it: deployDirectory
|
|
22192
|
+
// refuses both together before any request (an older control plane
|
|
22193
|
+
// would deploy production), and that answer is the one shown.
|
|
22129
22194
|
environment,
|
|
22130
22195
|
// Never a surprise browser window: this server may be headless.
|
|
22131
22196
|
allowLogin: false,
|
|
@@ -22678,7 +22743,7 @@ var REGISTERED = [
|
|
|
22678
22743
|
destructiveHint: false,
|
|
22679
22744
|
idempotentHint: true
|
|
22680
22745
|
},
|
|
22681
|
-
description: 'Connects the project to a GitHub repository so every push to the default branch deploys automatically. Use after deploy reports gitConnection.state "available" AND the user has agreed. If the response has connected:false with an installUrl, the
|
|
22746
|
+
description: 'Connects the project to a GitHub repository so every push to the default branch deploys automatically. Use after deploy reports gitConnection.state "available" AND the user has agreed. If the response has connected:false with an installUrl, Naro cannot reach the repository yet \u2014 the installUrl either installs the GitHub App on that account or imports the GitHub access of the user for an account the team already connected. Give it to the user to open in their own browser; if the repository is not among the ones the App was granted on GitHub, they add it there first. Call this tool again once they confirm. With installUrl null there is nothing to install from here: tell the user to connect from the Naro dashboard. Never open a browser yourself.',
|
|
22682
22747
|
inputSchema: {
|
|
22683
22748
|
type: "object",
|
|
22684
22749
|
properties: {
|
|
@@ -22719,7 +22784,7 @@ var REGISTERED = [
|
|
|
22719
22784
|
// installing from here would not connect anything. "Open the
|
|
22720
22785
|
// installUrl" sent the agent guessing one (known-issues #42); point
|
|
22721
22786
|
// at the dashboard, as the CLI does.
|
|
22722
|
-
message: result.installUrl ? `Naro cannot reach ${fullName} yet. Ask the user to open the installUrl in their browser and
|
|
22787
|
+
message: result.installUrl ? `Naro cannot reach ${fullName} yet. Ask the user to open the installUrl in their browser (and, if the repository is not among the ones the GitHub App was granted on GitHub, add it there first), then call this tool again.` : `Naro cannot reach ${fullName}, and no install link was offered. Tell the user to connect the repository from the Naro dashboard \u2014 do not make up a link.`
|
|
22723
22788
|
};
|
|
22724
22789
|
}
|
|
22725
22790
|
return {
|
|
@@ -22786,7 +22851,7 @@ async function openClaims(client, projectId) {
|
|
|
22786
22851
|
}
|
|
22787
22852
|
|
|
22788
22853
|
// src/server.ts
|
|
22789
|
-
var SERVER_VERSION = "0.18.
|
|
22854
|
+
var SERVER_VERSION = "0.18.1";
|
|
22790
22855
|
function visibleTools(options2) {
|
|
22791
22856
|
const { features, readOnly } = options2;
|
|
22792
22857
|
return TOOLS.flatMap((tool) => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "naro-mcp",
|
|
3
|
-
"version": "0.18.
|
|
3
|
+
"version": "0.18.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bin": {
|
|
6
6
|
"naro-mcp": "./dist/index.js"
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"dependencies": {
|
|
19
19
|
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
20
20
|
"@supabase/supabase-js": "2.112.3",
|
|
21
|
-
"naro-cli": "0.19.
|
|
21
|
+
"naro-cli": "0.19.1"
|
|
22
22
|
},
|
|
23
23
|
"devDependencies": {
|
|
24
24
|
"tsup": "8.5.0",
|