@fluid-app/fluid-cli-theme-dev 0.1.27 → 0.1.29

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/index.mjs CHANGED
@@ -52,6 +52,12 @@ function getRequestIdFromJsonBody(body) {
52
52
  return getStringRequestId(record.request_id) ?? getStringRequestId(record.requestId) ?? (meta && typeof meta === "object" && !Array.isArray(meta) ? getStringRequestId(meta.request_id) ?? getStringRequestId(meta.requestId) : void 0);
53
53
  }
54
54
  /**
55
+ * Type guard for ApiError
56
+ */
57
+ function isApiError(error) {
58
+ return error instanceof ApiError;
59
+ }
60
+ /**
55
61
  * Creates a configured fetch client instance
56
62
  */
57
63
  function createFetchClient(config) {
@@ -1258,6 +1264,45 @@ async function deleteThemeResource(client, application_theme_id, body) {
1258
1264
  return client.delete(`/api/application_themes/${application_theme_id}/resources`, { body });
1259
1265
  }
1260
1266
  //#endregion
1267
+ //#region src/theme/stylesheet-keys.ts
1268
+ const STYLESHEET_KEY_PATTERN = /^(styles\.css|global_styles\.css|[^/]+\/[^/]+\/styles\.css)$/;
1269
+ function isStylesheetKey(key) {
1270
+ return STYLESHEET_KEY_PATTERN.test(key);
1271
+ }
1272
+ //#endregion
1273
+ //#region src/theme/format-error.ts
1274
+ const STYLESHEET_MIGRATION_SKILL = "template-stylesheet-to-asset-migration";
1275
+ function isStylesheetKeyRejection(error) {
1276
+ if (error.status !== 422) return false;
1277
+ if (/stylesheet.*no longer accepted/i.test(error.message)) return true;
1278
+ if (error.data && typeof error.data === "object") {
1279
+ const resourceErrors = error.data.application_theme_resource;
1280
+ if (resourceErrors && typeof resourceErrors.key === "string" && /stylesheet.*no longer accepted/i.test(resourceErrors.key)) return true;
1281
+ }
1282
+ return false;
1283
+ }
1284
+ /**
1285
+ * Extract a human-readable message from a caught error. ApiError's default
1286
+ * `toString` prefixes with `ApiError:` and the class name; this returns the
1287
+ * API's own `error_message` verbatim so the CLI surfaces messages like
1288
+ * "This stylesheet key is no longer accepted. Upload stylesheets as
1289
+ * theme-level assets." directly.
1290
+ *
1291
+ * When the error is the legacy stylesheet key rejection specifically,
1292
+ * a hint is appended pointing to the bundled migration skill — the
1293
+ * caller needs to move the per-template `styles.css` bytes to `assets/`
1294
+ * and stop pushing the deprecated column key.
1295
+ */
1296
+ function formatError(e) {
1297
+ if (isApiError(e)) {
1298
+ const status = e.status ? ` [${e.status}]` : "";
1299
+ const hint = isStylesheetKeyRejection(e) ? `\n ↳ Run \`fluid theme skills install\` — the bundled \`${STYLESHEET_MIGRATION_SKILL}\` skill can help you migrate this to a theme-level asset.` : "";
1300
+ return `${e.message}${status}${hint}`;
1301
+ }
1302
+ if (e instanceof Error) return e.message;
1303
+ return String(e);
1304
+ }
1305
+ //#endregion
1261
1306
  //#region src/theme/syncer.ts
1262
1307
  var Syncer = class {
1263
1308
  checksums = /* @__PURE__ */ new Map();
@@ -1394,7 +1439,7 @@ var Syncer = class {
1394
1439
  await this.uploadFile(file);
1395
1440
  result.uploaded++;
1396
1441
  } catch (e) {
1397
- result.errors.push(`Upload ${file.relativePath}: ${e}`);
1442
+ result.errors.push(`Upload ${file.relativePath}: ${formatError(e)}`);
1398
1443
  }
1399
1444
  opts.onProgress?.(++done, toUpload.length);
1400
1445
  }
@@ -1405,7 +1450,7 @@ var Syncer = class {
1405
1450
  await this.deleteRemoteFile(key);
1406
1451
  result.deleted++;
1407
1452
  } catch (e) {
1408
- result.errors.push(`Delete ${key}: ${e}`);
1453
+ result.errors.push(`Delete ${key}: ${formatError(e)}`);
1409
1454
  }
1410
1455
  }
1411
1456
  return result;
@@ -1443,17 +1488,21 @@ var Syncer = class {
1443
1488
  }
1444
1489
  result.downloaded++;
1445
1490
  } catch (e) {
1446
- result.errors.push(`Download ${resource.key}: ${e}`);
1491
+ result.errors.push(`Download ${resource.key}: ${formatError(e)}`);
1447
1492
  }
1448
1493
  opts.onProgress?.(++done, resources.length);
1449
1494
  }
1450
1495
  if (opts.delete) {
1451
1496
  const remoteKeys = new Set(resources.map((r) => r.key));
1452
- for (const file of this.themeRoot.files()) if (!remoteKeys.has(file.relativePath)) try {
1453
- const { unlinkSync } = await import("node:fs");
1454
- unlinkSync(file.absolutePath);
1455
- result.deleted++;
1456
- } catch {}
1497
+ for (const file of this.themeRoot.files()) {
1498
+ if (remoteKeys.has(file.relativePath)) continue;
1499
+ if (isStylesheetKey(file.relativePath)) continue;
1500
+ try {
1501
+ const { unlinkSync } = await import("node:fs");
1502
+ unlinkSync(file.absolutePath);
1503
+ result.deleted++;
1504
+ } catch {}
1505
+ }
1457
1506
  }
1458
1507
  return result;
1459
1508
  }