@koda-sl/baker-cli 0.150.0-dev.a970fa118 → 0.150.0

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/cli.js CHANGED
@@ -36,7 +36,7 @@ import {
36
36
  toModelSafeImage,
37
37
  ulid,
38
38
  validateCanvasDeep
39
- } from "./chunk-JBDSJZBZ.js";
39
+ } from "./chunk-OO5BDH3J.js";
40
40
  import {
41
41
  csvOrJson,
42
42
  daysAgoIso,
@@ -15369,11 +15369,46 @@ function resolveFetchWeights(flag, declared) {
15369
15369
  return declared?.length ? declared : [400];
15370
15370
  }
15371
15371
  function googleFontCssUrl(family, weights) {
15372
- const name = family.trim().replace(/\s+/g, "+");
15372
+ const name = family.trim().split(/\s+/).map(encodeURIComponent).join("+");
15373
15373
  const axis = [...new Set(weights)].sort((a, b) => a - b).join(";");
15374
15374
  const spec = axis ? `${name}:wght@${axis}` : name;
15375
15375
  return `${GOOGLE_CSS2}?family=${spec}&display=swap`;
15376
15376
  }
15377
+ var STANDARD_WEIGHTS = [100, 200, 300, 400, 500, 600, 700, 800, 900];
15378
+ async function probeServedWeights(family, fetchCss) {
15379
+ const probes = await Promise.all(
15380
+ STANDARD_WEIGHTS.map(async (weight) => await fetchCss(googleFontCssUrl(family, [weight])) ? weight : null)
15381
+ );
15382
+ return probes.filter((w) => w !== null);
15383
+ }
15384
+ async function checkFontRequests(requests, fetchCss) {
15385
+ const results = [];
15386
+ for (const request of requests) {
15387
+ const css = await fetchCss(googleFontCssUrl(request.family, request.weights));
15388
+ if (css === null) {
15389
+ const served2 = await probeServedWeights(request.family, fetchCss);
15390
+ results.push({
15391
+ family: request.family,
15392
+ requested: request.weights,
15393
+ served: served2,
15394
+ missing: request.weights.filter((w) => !served2.includes(w)),
15395
+ subsets: [],
15396
+ cause: served2.length === 0 ? "unknown-family" : "unavailable-weight"
15397
+ });
15398
+ continue;
15399
+ }
15400
+ const faces = parseGoogleFontFaces(css);
15401
+ const served = [...new Set(faces.map((f) => f.weight))].sort((a, b) => a - b);
15402
+ results.push({
15403
+ family: request.family,
15404
+ requested: request.weights,
15405
+ served,
15406
+ missing: request.weights.filter((w) => !served.includes(w)),
15407
+ subsets: [...new Set(faces.map((f) => f.subset))]
15408
+ });
15409
+ }
15410
+ return results;
15411
+ }
15377
15412
 
15378
15413
  // src/commands/brand/fonts.ts
15379
15414
  var GLOBAL_CSS = path.join("src", "styles", "global.css");
@@ -15406,19 +15441,19 @@ function fail(code, message, fix) {
15406
15441
  writeJson({ ok: false, error: { code, message, ...fix ? { fix } : {} } });
15407
15442
  process.exit(2);
15408
15443
  }
15444
+ var REQUEST_TIMEOUT_MS = 15e3;
15409
15445
  async function fetchGoogleCss(url) {
15410
15446
  try {
15411
- const res = await fetch(url, { headers: { "User-Agent": BROWSER_UA } });
15447
+ const res = await fetch(url, {
15448
+ headers: { "User-Agent": BROWSER_UA },
15449
+ signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS)
15450
+ });
15412
15451
  if (!res.ok) return null;
15413
15452
  return await res.text();
15414
15453
  } catch {
15415
15454
  return null;
15416
15455
  }
15417
15456
  }
15418
- async function diagnoseUnserved(family) {
15419
- const bare = await fetchGoogleCss(googleFontCssUrl(family, []));
15420
- return bare === null ? "unknown-family" : "unavailable-weight";
15421
- }
15422
15457
  async function readGlobalCss() {
15423
15458
  try {
15424
15459
  return await readFile(path.resolve(process.cwd(), GLOBAL_CSS), "utf8");
@@ -15444,41 +15479,20 @@ var fontsCheckCommand = defineCommand85({
15444
15479
  });
15445
15480
  return;
15446
15481
  }
15447
- const families = [];
15448
- const unavailable = [];
15449
- for (const request of requests) {
15450
- const url = googleFontCssUrl(request.family, request.weights);
15451
- const served = await fetchGoogleCss(url);
15452
- if (served === null) {
15453
- const cause = await diagnoseUnserved(request.family);
15454
- unavailable.push(
15455
- cause === "unknown-family" ? `${request.family} (no such family on Google Fonts \u2014 check the exact spelling)` : `${request.family} ${request.weights.join("/")} (the family exists, these weights do not)`
15456
- );
15457
- families.push({
15458
- family: request.family,
15459
- requested: request.weights,
15460
- served: [],
15461
- missing: request.weights,
15462
- cause
15463
- });
15464
- continue;
15465
- }
15466
- const faces = parseGoogleFontFaces(served);
15467
- const servedWeights = [...new Set(faces.map((f) => f.weight))].sort((a, b) => a - b);
15468
- const missing = request.weights.filter((w) => !servedWeights.includes(w));
15469
- if (missing.length > 0) unavailable.push(`${request.family} ${missing.join("/")}`);
15470
- families.push({
15471
- family: request.family,
15472
- requested: request.weights,
15473
- served: servedWeights,
15474
- missing,
15475
- subsets: [...new Set(faces.map((f) => f.subset))]
15476
- });
15477
- }
15478
- if (unavailable.length > 0) {
15479
- fail("FONT_NOT_SERVED", `Google Fonts does not serve: ${unavailable.join("; ")}`, {
15480
- action: `Correct the family name or weight in ${GLOBAL_CSS} and src/brand/BRAND.md, or run \`baker brand fonts fetch\` for a weight that does exist.`,
15481
- explanation: "A requested weight Google does not serve is silently synthesized by the browser, so the page looks subtly wrong with nothing failing."
15482
+ const families = await checkFontRequests(requests, fetchGoogleCss);
15483
+ const broken = families.filter((f) => f.missing.length > 0);
15484
+ if (broken.length > 0) {
15485
+ const summary = broken.map(
15486
+ (f) => f.cause === "unknown-family" ? `${f.family} (no such family on Google Fonts \u2014 check the exact spelling)` : `${f.family} ${f.missing.join("/")} (served: ${f.served.join("/") || "none"})`
15487
+ ).join("; ");
15488
+ fail("FONT_NOT_SERVED", `Google Fonts does not serve: ${summary}`, {
15489
+ action: `Correct the family name or weight in ${GLOBAL_CSS} and src/brand/BRAND.md, picking from the \`served\` weights below.`,
15490
+ explanation: "A requested weight Google does not serve is silently synthesized by the browser, so the page looks subtly wrong with nothing failing.",
15491
+ // The per-family breakdown is the point of the command, so it ships on
15492
+ // the failure path too — otherwise the only remedy is re-running the
15493
+ // command that just failed. Healthy families are included so a
15494
+ // multi-family brand shows what NOT to touch.
15495
+ families
15482
15496
  });
15483
15497
  }
15484
15498
  writeJson({
@@ -15515,16 +15529,18 @@ var fontsFetchCommand = defineCommand85({
15515
15529
  );
15516
15530
  const servedCss = await fetchGoogleCss(googleFontCssUrl(family, weights));
15517
15531
  if (servedCss === null) {
15518
- const cause = await diagnoseUnserved(family);
15532
+ const [diagnosis] = await checkFontRequests([{ family, weights }], fetchGoogleCss);
15533
+ const served = diagnosis?.served ?? [];
15519
15534
  fail(
15520
15535
  "FONT_NOT_SERVED",
15521
- cause === "unknown-family" ? `Google Fonts has no family called "${family}".` : `"${family}" exists on Google Fonts but not at weight ${weights.join("/")}.`,
15522
- cause === "unknown-family" ? {
15536
+ served.length === 0 ? `Google Fonts has no family called "${family}".` : `"${family}" exists on Google Fonts but not at weight ${weights.join("/")}.`,
15537
+ served.length === 0 ? {
15523
15538
  action: "Check the exact family name at fonts.google.com, then retry.",
15524
15539
  explanation: "Family names are case- and space-sensitive in the Google Fonts API."
15525
15540
  } : {
15526
- action: `Run \`baker brand fonts check\` to see which weights this family really ships, then retry with --weights set to one of those.`,
15527
- explanation: "Google rejects the whole request when one requested weight does not exist."
15541
+ action: `Retry with --weights set to one of these: ${served.join(",")}.`,
15542
+ explanation: "Google rejects the whole request when one requested weight does not exist.",
15543
+ served
15528
15544
  }
15529
15545
  );
15530
15546
  }
@@ -15539,7 +15555,10 @@ var fontsFetchCommand = defineCommand85({
15539
15555
  await mkdir(fontsDir, { recursive: true });
15540
15556
  const downloaded = [];
15541
15557
  for (const face of faces) {
15542
- const res = await fetch(face.url, { headers: { "User-Agent": BROWSER_UA } });
15558
+ const res = await fetch(face.url, {
15559
+ headers: { "User-Agent": BROWSER_UA },
15560
+ signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS)
15561
+ });
15543
15562
  if (!res.ok) continue;
15544
15563
  await writeFile(path.join(fontsDir, fontFileName(face)), Buffer.from(await res.arrayBuffer()));
15545
15564
  downloaded.push(face);