layero 0.8.2 → 0.8.3

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 CHANGED
@@ -208,4 +208,4 @@ always excluded: `node_modules`, `.git`, `dist`, `build`, `.next`, `.env*`,
208
208
 
209
209
  - Website: https://layero.ru
210
210
  - Docs: https://docs.layero.ru
211
- - Issues: https://github.com/layero/layero/issues
211
+ - Support: https://docs.layero.ru/contacts/
@@ -226,21 +226,44 @@ const PREBUILT_AUTO_DIRS = [
226
226
  async function resolvePrebuiltDir(cwd, raw) {
227
227
  if (raw === undefined || raw === false)
228
228
  return null;
229
+ let dir = null;
229
230
  if (typeof raw === "string" && raw.length > 0) {
230
- return raw;
231
+ dir = raw;
231
232
  }
232
- // No explicit dir — pick the first existing common output directory.
233
- for (const candidate of PREBUILT_AUTO_DIRS) {
234
- try {
235
- const stat = await fs.stat(path.join(cwd, candidate));
236
- if (stat.isDirectory())
237
- return candidate;
233
+ else {
234
+ // No explicit dir pick the first existing common output directory.
235
+ for (const candidate of PREBUILT_AUTO_DIRS) {
236
+ try {
237
+ const stat = await fs.stat(path.join(cwd, candidate));
238
+ if (stat.isDirectory()) {
239
+ dir = candidate;
240
+ break;
241
+ }
242
+ }
243
+ catch {
244
+ // try next
245
+ }
238
246
  }
239
- catch {
240
- // try next
247
+ if (dir === null) {
248
+ throw new LayeroError("prebuilt_no_dir", "could not auto-detect a built artifact directory", `pass it explicitly: --prebuilt ./dist (tried: ${PREBUILT_AUTO_DIRS.join(", ")})`);
241
249
  }
242
250
  }
243
- throw new LayeroError("prebuilt_no_dir", "could not auto-detect a built artifact directory", `pass it explicitly: --prebuilt ./dist (tried: ${PREBUILT_AUTO_DIRS.join(", ")})`);
251
+ // Servability check (mirrors the builder-side gate, 2026-07-01 audit): a
252
+ // prebuilt dir with no index.html at its root isn't a servable site — the
253
+ // apex "/" would 404. Fail fast here, before packing + uploading, instead of
254
+ // the deploy going "ready" but broken.
255
+ let hasIndex = false;
256
+ try {
257
+ const entries = await fs.readdir(path.join(cwd, dir));
258
+ hasIndex = entries.some((e) => e.toLowerCase() === "index.html");
259
+ }
260
+ catch {
261
+ hasIndex = false;
262
+ }
263
+ if (!hasIndex) {
264
+ throw new LayeroError("prebuilt_no_index", `'${dir}' has no index.html — nothing to serve`, `point --prebuilt at the folder that contains your built index.html (e.g. --prebuilt ./dist)`);
265
+ }
266
+ return dir;
244
267
  }
245
268
  // Resolve the framework / build / output config to send to completeSetup.
246
269
  // Precedence: explicit CLI args > .layero/project.json > auto-detect.
@@ -431,30 +454,36 @@ export async function deployCmd(opts) {
431
454
  const dashboardUrl = projectUrl(cliCfg.apiUrl, project.id);
432
455
  const apexUrl = `https://${project.apex_hostname}`;
433
456
  const probe = await resolveReachability(api, deploy.environment_id);
434
- // Public site URL — honour the preview-first contract the dashboard uses
435
- // (probe states B/C): until the CDN apex is verified live (`cdn_ready`),
436
- // the reachable address is the off-CDN preview domain. A fresh apex
437
- // 404/000s for ~10-15min while CDN propagates, and for runtime apps the
438
- // preview domain is the *permanent* address (the CDN apex can't serve
439
- // POST/WebSocket). So only surface the canonical apex once it's warm;
440
- // before that, hand back the preview. `edge_ready` / `edge_eta_seconds`
441
- // below tell the caller the apex is on its way.
442
- const cdnWarm = probe?.cdn_ready === true;
443
- const liveUrl = cdnWarm
457
+ // Публичный адрес сайта.
458
+ //
459
+ // Раньше здесь стоял гейт `cdn_ready`: пока YC CDN не подтвердил апекс,
460
+ // отдавали off-CDN превью, потому что свежий апекс 10-15 минут отвечал
461
+ // 404, а runtime-приложения на апексе вообще не принимали POST (CDN резал
462
+ // не-GET). После EDGE-02 CDN перед пользовательскими зонами нет: апекс
463
+ // валиден с момента создания проекта (wildcard-запись + wildcard-серт), а
464
+ // `cdn_ready` бекенд отдаёт false НАВСЕГДА строки в `cdn_hostnames` у
465
+ // новых проектов не появляется вовсе.
466
+ //
467
+ // Из-за этого условие не выполнялось никогда, и после успешной публикации
468
+ // CLI выдавал ссылку на дашборд вместо адреса сайта. Проверено вживую
469
+ // 2026-07-26: `layero deploy` вернул `url: https://app.layero.ru/projects/…`.
470
+ //
471
+ // Апекс — адрес по умолчанию; превью остаётся для деплоя ветки, которую
472
+ // не промоутили: там апекс ведёт на другую сборку.
473
+ const liveUrl = promoted || !opts.branch
444
474
  ? probe?.canonical_url ?? apexUrl
445
- : probe?.preview_url ??
446
- probe?.canonical_url ??
447
- (promoted || !opts.branch ? apexUrl : dashboardUrl);
475
+ : probe?.preview_url ?? probe?.canonical_url ?? apexUrl;
448
476
  emit({
449
477
  event: "ready",
450
478
  url: liveUrl,
451
479
  deploy_id: deploy.id,
452
480
  preview_url: probe?.preview_url ?? undefined,
453
481
  dashboard_url: dashboardUrl,
454
- edge_ready: probe ? probe.cdn_ready : undefined,
455
- edge_eta_seconds: probe && !probe.cdn_ready && probe.cdn_eta_seconds != null
456
- ? probe.cdn_eta_seconds
457
- : undefined,
482
+ // `available` от пробы, а НЕ `cdn_ready`: последний после EDGE-02
483
+ // остаётся false навсегда, и потребитель JSON-вывода ждал бы события,
484
+ // которого не будет. ETA пропагации убран по той же причине —
485
+ // распространять больше нечего.
486
+ edge_ready: probe ? probe.available : undefined,
458
487
  });
459
488
  }
460
489
  finally {
package/package.json CHANGED
@@ -1,17 +1,12 @@
1
1
  {
2
2
  "name": "layero",
3
- "version": "0.8.2",
3
+ "version": "0.8.3",
4
4
  "description": "Layero CLI — publish a local site with one command. No git, no GitHub, agent-friendly (Cursor, Claude Code).",
5
5
  "license": "MIT",
6
6
  "type": "module",
7
7
  "homepage": "https://layero.ru",
8
- "repository": {
9
- "type": "git",
10
- "url": "https://github.com/LayeroInfra/core.git",
11
- "directory": "cli"
12
- },
13
8
  "bugs": {
14
- "url": "https://github.com/LayeroInfra/core/issues"
9
+ "url": "https://docs.layero.ru/contacts/"
15
10
  },
16
11
  "keywords": [
17
12
  "layero",