layero 0.11.10 → 0.11.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin/layero.js +5 -1
- package/dist/commands/data-api.js +10 -8
- package/dist/commands/data.js +7 -3
- package/dist/commands/db.js +19 -8
- package/dist/commands/deploy.js +4 -11
- package/package.json +1 -1
package/dist/bin/layero.js
CHANGED
|
@@ -540,7 +540,11 @@ function asAccountStateError(err) {
|
|
|
540
540
|
if (err.status >= 400 && err.status < 500) {
|
|
541
541
|
const detail = detailOf(err.body);
|
|
542
542
|
if (detail) {
|
|
543
|
-
return new LayeroError(detail.code ?? `http_${err.status}`, detail.message,
|
|
543
|
+
return new LayeroError(detail.code ?? `http_${err.status}`, detail.message,
|
|
544
|
+
// Общий совет — последний: причина и лекарство чаще всего уже в тексте
|
|
545
|
+
// отказа (подсказки SQL про роли и Авторизацию, T-20261025-9), и
|
|
546
|
+
// «исправьте запрос» уводил агента от них.
|
|
547
|
+
detail.next_action ?? "причина и что сделать — в тексте отказа; исправьте и повторите");
|
|
544
548
|
}
|
|
545
549
|
}
|
|
546
550
|
return null;
|
|
@@ -438,9 +438,12 @@ export async function dataGrantCmd(object, opts) {
|
|
|
438
438
|
console.log(planLines(done).join("\n"));
|
|
439
439
|
console.log(`\n${chalk.green("✓")} доступ изменён`);
|
|
440
440
|
}
|
|
441
|
-
// Что снимает
|
|
442
|
-
//
|
|
443
|
-
|
|
441
|
+
// Что снимает переприменение (сверено с агентом узла 25.10.2026,
|
|
442
|
+
// `runtime/userdb-agent/agent.py`, `api_enable`): права на таблицы и USAGE на
|
|
443
|
+
// `public` у существующих ролей СОХРАНЯЮТСЯ (с T-20260914-3 снимается только у
|
|
444
|
+
// роли, созданной этим же включением; USAGE на `public` выдаётся с 25.10).
|
|
445
|
+
// Снимаются только умолчания, которые сами открывали ролям НОВЫЕ таблицы.
|
|
446
|
+
const REPAIR_LOSS = "умолчания, которые сами открывали ролям Data API новые таблицы, будут сняты; уже выданные права на таблицы сохранятся";
|
|
444
447
|
/**
|
|
445
448
|
* Включение Data API.
|
|
446
449
|
*
|
|
@@ -456,7 +459,7 @@ const REPAIR_LOSS = "роли Data API потеряют права на схем
|
|
|
456
459
|
*/
|
|
457
460
|
export async function dataEnableCmd(opts) {
|
|
458
461
|
if (opts.repair && !opts.db) {
|
|
459
|
-
throw new LayeroError("database_unknown", `переприменение Data API
|
|
462
|
+
throw new LayeroError("database_unknown", `переприменение Data API меняет умолчания прав у ролей базы — базу нужно указать явно`, "layero data enable --db <база> --repair");
|
|
460
463
|
}
|
|
461
464
|
const { api, org, db, ref } = await target(opts, "enable");
|
|
462
465
|
if (db.api_enabled && !opts.repair) {
|
|
@@ -499,9 +502,8 @@ export async function dataEnableCmd(opts) {
|
|
|
499
502
|
// агент снимает права только в `public`, уровни в `api` и `app` остаются.
|
|
500
503
|
console.log(reapplied
|
|
501
504
|
? `${chalk.green("✓")} Data API переприменён у базы «${db.name}»\n` +
|
|
502
|
-
chalk.yellow("
|
|
503
|
-
"
|
|
504
|
-
"откройте заново: layero data methods, затем layero data grant")
|
|
505
|
+
chalk.yellow(" Выданные права на таблицы сохранились. Сняты только умолчания, которые сами открывали " +
|
|
506
|
+
"новые таблицы ролям Data API: новые таблицы открывайте явно — layero data grant")
|
|
505
507
|
: `${chalk.green("✓")} Data API включён у базы «${db.name}»`);
|
|
506
508
|
if (publicKey)
|
|
507
509
|
console.log(`\n публичный ключ: ${publicKey}`);
|
|
@@ -572,7 +574,7 @@ export function registerDataApiCommands(data, program) {
|
|
|
572
574
|
.command("enable")
|
|
573
575
|
.description("Enable the Data API for a database: sets up the api schema and roles, issues a public key. All methods start closed.")
|
|
574
576
|
.option("--with-secret", "also issue a secret key for the server")
|
|
575
|
-
.option("--repair", "re-apply the roles and the api schema for a database whose Data API is already enabled;
|
|
577
|
+
.option("--repair", "re-apply the roles and the api schema for a database whose Data API is already enabled; table grants are kept, default privileges for new tables are removed")
|
|
576
578
|
.option("-y, --yes", "do not ask for confirmation for --repair")).action(async (opts) => dataEnableCmd(json(opts)));
|
|
577
579
|
registerDataProbeCommand(data, withDb, json);
|
|
578
580
|
}
|
package/dist/commands/data.js
CHANGED
|
@@ -66,12 +66,16 @@ export async function dataEnvCmd(opts) {
|
|
|
66
66
|
const project = await projectRef(api, opts);
|
|
67
67
|
const vars = await api.dataEnv(project.id);
|
|
68
68
|
if (!Object.keys(vars).length) {
|
|
69
|
+
// 🚨 Пустой ответ — не «всё в порядке» (T-20261025-9): агент видел
|
|
70
|
+
// `vars: {}` без подсказки и решал, что писать нечего. Говорим, почему
|
|
71
|
+
// пусто и что сделать, тем же `next_action`, что у отказов.
|
|
72
|
+
const next = `подключите к проекту базу с Data API: layero db connect <база> --project ${project.slug}; ` +
|
|
73
|
+
"Data API у базы: layero data enable --db <база> (или панель → Базы данных → база → Data API → «Включить Data API»)";
|
|
69
74
|
if (mode.json) {
|
|
70
|
-
emit({ event: "data_env", project: project.slug, vars: {} });
|
|
75
|
+
emit({ event: "data_env", project: project.slug, vars: {}, reason: "no_data_api_database", next_action: next });
|
|
71
76
|
return;
|
|
72
77
|
}
|
|
73
|
-
console.log(chalk.dim(`у проекта "${project.slug}" нет базы с включённым Data API\n`
|
|
74
|
-
"включить: панель → база → «API» → «Включить API»"));
|
|
78
|
+
console.log(chalk.dim(`у проекта "${project.slug}" нет подключённой базы с включённым Data API\n${next}`));
|
|
75
79
|
return;
|
|
76
80
|
}
|
|
77
81
|
if (mode.json) {
|
package/dist/commands/db.js
CHANGED
|
@@ -167,18 +167,29 @@ export async function dbCreateCmd(name, opts) {
|
|
|
167
167
|
}
|
|
168
168
|
const api = new ApiClient(config);
|
|
169
169
|
const org = await orgOf(api, opts);
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
//
|
|
170
|
+
// 🚨 ФЛАГА «БЕЗ НАПОЛНЕНИЯ» БОЛЬШЕ НЕТ. Он существовал, пока пресет
|
|
171
|
+
// заводил три таблицы с примерами: человек со своей схемой получал чужие
|
|
172
|
+
// таблицы молча, и отказаться было нечем. Тестовых таблиц в пресете не
|
|
173
|
+
// осталось — он настраивает роли, функцию состояния и умолчания прав,
|
|
174
|
+
// и вычищать после него нечего. Значит и отказываться не от чего.
|
|
175
|
+
const created = await api.createDatabase(org, { name }).catch((err) => {
|
|
176
|
+
// 409 — место бесплатной базы занято или лимит тарифа (T-20261025-9):
|
|
177
|
+
// общий совет «исправьте запрос» здесь ничего не говорил.
|
|
178
|
+
if (err instanceof LayeroError && err.code === "http_409") {
|
|
179
|
+
throw new LayeroError(err.code, err.message, "удалите ненужную базу (layero db list; удаление — в панели: Базы данных → база → Настройки) " +
|
|
180
|
+
"или заведите базу со своей конфигурацией в панели");
|
|
181
|
+
}
|
|
182
|
+
throw err;
|
|
177
183
|
});
|
|
178
184
|
// Пароль отдаётся ОДИН РАЗ — второй раз его не покажет никто, только
|
|
179
185
|
// ротация. Поэтому он и в JSON-режиме, и в терминале.
|
|
180
186
|
if (mode.json || opts.json) {
|
|
181
|
-
|
|
187
|
+
// 🚨 Пароль — в ОДНОМ поле (T-20261025-12). Раньше он шёл ещё и отдельным
|
|
188
|
+
// `password`: агент маскировал строку подключения и не замечал второе
|
|
189
|
+
// поле, и пароль уезжал в вывод инструмента. `secrets` называет, что
|
|
190
|
+
// маскировать.
|
|
191
|
+
emit({ event: "database_created", org, name, connection_string: created.connection_string,
|
|
192
|
+
secrets: ["connection_string"] });
|
|
182
193
|
return;
|
|
183
194
|
}
|
|
184
195
|
// 🚨 БАЗА ЕЩЁ НЕ ГОТОВА В ЭТОТ МОМЕНТ. Ручка стала асинхронной: она пишет
|
package/dist/commands/deploy.js
CHANGED
|
@@ -209,13 +209,6 @@ async function assertSandboxServesFiles(cwd, opts, existing, detectFolder) {
|
|
|
209
209
|
return;
|
|
210
210
|
throw new LayeroError("claim_static_only", `деплой без аккаунта (--claim) выкладывает только статику и SPA, а эта папка — серверное приложение (${kind})`, "sign in and deploy from the account: `npx layero@latest login`, then run the same deploy without --claim");
|
|
211
211
|
}
|
|
212
|
-
/** Обёртка временного сайта по его адресу: `<панель>/preview/<метка>`.
|
|
213
|
-
* Считается здесь для повторной выкатки — платформа отдаёт поле только при
|
|
214
|
-
* создании песочницы. */
|
|
215
|
-
function sandboxPreviewUrl(siteUrl) {
|
|
216
|
-
const label = new URL(siteUrl).hostname.split(".")[0];
|
|
217
|
-
return `https://app.layero.ru/preview/${label}`;
|
|
218
|
-
}
|
|
219
212
|
/**
|
|
220
213
|
* 🚨 ДЕТЕКТ — ОДИН НА ВЫКАТКУ. Гейт core «входов анализа не становится
|
|
221
214
|
* больше» считает запуски детекта в этом файле: каждый лишний — ещё один
|
|
@@ -942,15 +935,15 @@ export async function deployCmd(opts) {
|
|
|
942
935
|
}
|
|
943
936
|
// Claimable: ссылка «забрать» — ДО `ready`, потому что после `ready`
|
|
944
937
|
// агент не читает, а без этой ссылки сайт исчезнет через час.
|
|
945
|
-
// `preview_url` —
|
|
946
|
-
//
|
|
938
|
+
// `preview_url` — ссылка для людей. С 22.10.2026 это сам сайт
|
|
939
|
+
// `<метка>.preview.layero.app`: обёртки панели больше нет.
|
|
947
940
|
if (claimable) {
|
|
948
941
|
emit({
|
|
949
942
|
event: "claimable",
|
|
950
943
|
project_id: claimable.project_id,
|
|
951
944
|
slug: claimable.slug,
|
|
952
945
|
url: liveUrl,
|
|
953
|
-
preview_url: claimable.preview_url ??
|
|
946
|
+
preview_url: claimable.preview_url ?? liveUrl,
|
|
954
947
|
claim_url: claimable.claim_url,
|
|
955
948
|
expires_at: claimable.expires_at,
|
|
956
949
|
});
|
|
@@ -961,7 +954,7 @@ export async function deployCmd(opts) {
|
|
|
961
954
|
project_id: project.id,
|
|
962
955
|
slug: project.slug,
|
|
963
956
|
url: liveUrl,
|
|
964
|
-
preview_url:
|
|
957
|
+
preview_url: liveUrl,
|
|
965
958
|
claim_url: reusedClaim.claim_url,
|
|
966
959
|
expires_at: reusedClaim.expires_at,
|
|
967
960
|
});
|
package/package.json
CHANGED