@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())
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
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
|
}
|