@cloudhal/cli 0.3.6 → 0.3.8

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.
Files changed (29) hide show
  1. package/dist/assets/starters/blog/README.md +3 -1
  2. package/dist/assets/starters/blog/package.json +4 -4
  3. package/dist/assets/starters/blog/public/_headers +5 -0
  4. package/dist/assets/starters/blog/src/fonts.ts +22 -6
  5. package/dist/assets/starters/blog/src/pages/[...path].astro +7 -0
  6. package/dist/assets/starters/blog/src/styles/features/tokens.css +24 -12
  7. package/dist/assets/starters/blog/src/styles/font-fallbacks.css +53 -0
  8. package/dist/assets/starters/blog/src/styles/fonts.css +12 -12
  9. package/dist/assets/starters/blog/src/styles/global.css +1 -0
  10. package/dist/src/cloudflare/wrangler.js +9 -4
  11. package/package.json +11 -11
  12. /package/dist/assets/starters/blog/public/fonts/{fraunces-OFL.txt → v1/fraunces-OFL.txt} +0 -0
  13. /package/dist/assets/starters/blog/public/fonts/{fraunces-latin-ext-wght-normal.woff2 → v1/fraunces-latin-ext-wght-normal.woff2} +0 -0
  14. /package/dist/assets/starters/blog/public/fonts/{fraunces-latin-wght-normal.woff2 → v1/fraunces-latin-wght-normal.woff2} +0 -0
  15. /package/dist/assets/starters/blog/public/fonts/{inter-OFL.txt → v1/inter-OFL.txt} +0 -0
  16. /package/dist/assets/starters/blog/public/fonts/{inter-latin-ext-wght-normal.woff2 → v1/inter-latin-ext-wght-normal.woff2} +0 -0
  17. /package/dist/assets/starters/blog/public/fonts/{inter-latin-wght-normal.woff2 → v1/inter-latin-wght-normal.woff2} +0 -0
  18. /package/dist/assets/starters/blog/public/fonts/{jetbrains-mono-OFL.txt → v1/jetbrains-mono-OFL.txt} +0 -0
  19. /package/dist/assets/starters/blog/public/fonts/{jetbrains-mono-latin-ext-wght-normal.woff2 → v1/jetbrains-mono-latin-ext-wght-normal.woff2} +0 -0
  20. /package/dist/assets/starters/blog/public/fonts/{jetbrains-mono-latin-wght-normal.woff2 → v1/jetbrains-mono-latin-wght-normal.woff2} +0 -0
  21. /package/dist/assets/starters/blog/public/fonts/{source-sans-3-OFL.txt → v1/source-sans-3-OFL.txt} +0 -0
  22. /package/dist/assets/starters/blog/public/fonts/{source-sans-3-latin-ext-wght-normal.woff2 → v1/source-sans-3-latin-ext-wght-normal.woff2} +0 -0
  23. /package/dist/assets/starters/blog/public/fonts/{source-sans-3-latin-wght-normal.woff2 → v1/source-sans-3-latin-wght-normal.woff2} +0 -0
  24. /package/dist/assets/starters/blog/public/fonts/{source-serif-4-OFL.txt → v1/source-serif-4-OFL.txt} +0 -0
  25. /package/dist/assets/starters/blog/public/fonts/{source-serif-4-latin-ext-wght-normal.woff2 → v1/source-serif-4-latin-ext-wght-normal.woff2} +0 -0
  26. /package/dist/assets/starters/blog/public/fonts/{source-serif-4-latin-wght-normal.woff2 → v1/source-serif-4-latin-wght-normal.woff2} +0 -0
  27. /package/dist/assets/starters/blog/public/fonts/{space-grotesk-OFL.txt → v1/space-grotesk-OFL.txt} +0 -0
  28. /package/dist/assets/starters/blog/public/fonts/{space-grotesk-latin-ext-wght-normal.woff2 → v1/space-grotesk-latin-ext-wght-normal.woff2} +0 -0
  29. /package/dist/assets/starters/blog/public/fonts/{space-grotesk-latin-wght-normal.woff2 → v1/space-grotesk-latin-wght-normal.woff2} +0 -0
@@ -22,7 +22,9 @@ Everything but `.gitignore`'s list. `cloudhal.json` holds the project's settings
22
22
  - `search.json.ts` — the search modal's answers (RFC-0029), where the deployment answers searches (`cloudhal dev`, the Cloudflare Site Worker). `components/SearchDialog.astro` is the modal's markup and words; Cloudhal's `/_cloudhal/search.1.js` wires it, and without it the header form opens `/search`.
23
23
 
24
24
  ## Styles (`src/styles`)
25
- `global.css` (imported by `layouts/Base.astro`) loads Tailwind, `fonts.css` and one file per feature from `styles/features/` (`tokens.css` with `@theme`, `prose.css`, `surfaces.css`, `motion.css`, `chrome.css`, `carousel.css` …) in cascade order. The rules are unlayered and later files override earlier ones, so keep the order; add a feature as a new file and import it from `global.css`. `source("..")` on the Tailwind import is relative to `global.css`, so that import stays there.
25
+ `global.css` (imported by `layouts/Base.astro`) loads Tailwind, `fonts.css`, `font-fallbacks.css` and one file per feature from `styles/features/` (`tokens.css` with `@theme`, `prose.css`, `surfaces.css`, `motion.css`, `chrome.css`, `carousel.css` …) in cascade order. The rules are unlayered and later files override earlier ones, so keep the order; add a feature as a new file and import it from `global.css`. `source("..")` on the Tailwind import is relative to `global.css`, so that import stays there.
26
+
27
+ Fonts are self-hosted under `public/fonts/v1/` and cached for a year (`public/_headers`): files never change under a path, so a new font set goes in `public/fonts/v2/`. Each web font in the pairing stacks (`tokens.css`) is followed by a metric-matched fallback from `font-fallbacks.css` (a system font scaled to the web font's width, ascent and descent), so the swap when the web font arrives does not move the text. That file is generated: after changing a font, run `pnpm fonts:fallbacks` in the monorepo.
26
28
 
27
29
  ## Theme settings (`src/theme.ts`)
28
30
  - `ARCHIVE_PAGE_SIZE` — posts per archive page (20).
@@ -14,18 +14,18 @@
14
14
  "astro": "astro"
15
15
  },
16
16
  "dependencies": {
17
- "@cloudhal/astro-renderer": "0.3.6",
18
- "@cloudhal/core-ts": "0.3.6",
17
+ "@cloudhal/astro-renderer": "0.3.8",
18
+ "@cloudhal/core-ts": "0.3.8",
19
19
  "@tailwindcss/vite": "^4.3.3",
20
20
  "astro": "7.3.6",
21
21
  "better-sqlite3": "13.0.3",
22
22
  "tailwindcss": "^4.3.3",
23
23
  "@astrojs/cloudflare": "14.3.4",
24
- "@cloudhal/cli": "0.3.6"
24
+ "@cloudhal/cli": "0.3.8"
25
25
  },
26
26
  "devDependencies": {
27
27
  "wrangler": "^4.148.0",
28
- "@cloudhal/cloudflare": "0.3.6"
28
+ "@cloudhal/cloudflare": "0.3.8"
29
29
  },
30
30
  "trustedDependencies": [
31
31
  "better-sqlite3",
@@ -0,0 +1,5 @@
1
+ # Font files never change under a path: a new font set gets a new directory (/fonts/v2/…).
2
+ # Cached for a year, the browser uses them on every reload without asking the server, so the
3
+ # text is drawn in its font from the first paint instead of swapping in later.
4
+ /fonts/v1/*
5
+ Cache-Control: public, max-age=31536000, immutable
@@ -4,12 +4,28 @@
4
4
  * (Turkish and other accented letters) load on demand through fonts.css's unicode ranges.
5
5
  */
6
6
  export const PAIRING_PRELOADS: Readonly<Record<string, readonly string[]>> = {
7
- editorial: ["/fonts/fraunces-latin-wght-normal.woff2", "/fonts/inter-latin-wght-normal.woff2"],
8
- modern: ["/fonts/space-grotesk-latin-wght-normal.woff2", "/fonts/inter-latin-wght-normal.woff2"],
9
- humanist: ["/fonts/source-sans-3-latin-wght-normal.woff2"],
7
+ editorial: [
8
+ "/fonts/v1/fraunces-latin-wght-normal.woff2",
9
+ "/fonts/v1/inter-latin-wght-normal.woff2",
10
+ ],
11
+ modern: [
12
+ "/fonts/v1/space-grotesk-latin-wght-normal.woff2",
13
+ "/fonts/v1/inter-latin-wght-normal.woff2",
14
+ ],
15
+ humanist: ["/fonts/v1/source-sans-3-latin-wght-normal.woff2"],
10
16
  technical: [
11
- "/fonts/jetbrains-mono-latin-wght-normal.woff2",
12
- "/fonts/inter-latin-wght-normal.woff2",
17
+ "/fonts/v1/jetbrains-mono-latin-wght-normal.woff2",
18
+ "/fonts/v1/inter-latin-wght-normal.woff2",
13
19
  ],
14
- classic: ["/fonts/source-serif-4-latin-wght-normal.woff2"],
20
+ classic: ["/fonts/v1/source-serif-4-latin-wght-normal.woff2"],
15
21
  };
22
+
23
+ /**
24
+ * The same preloads as a `Link` response header. On a Cloudflare zone with Early Hints on, the
25
+ * edge sends it as a 103 before the page, so the fonts load while the Worker is still rendering.
26
+ */
27
+ export function fontLinkHeader(hrefs: readonly string[]): string {
28
+ return hrefs
29
+ .map((h) => `<${h}>; rel=preload; as=font; type="font/woff2"; crossorigin`)
30
+ .join(", ");
31
+ }
@@ -51,6 +51,7 @@ import {
51
51
  relatedEntries,
52
52
  termAncestors,
53
53
  } from "@cloudhal/astro-renderer/taxonomy";
54
+ import { themeVariables } from "@cloudhal/astro-renderer/theme-settings";
54
55
  import type { ContentEntry } from "@cloudhal/core-contracts";
55
56
  /**
56
57
  * One route for the whole graph (RFC-0002 §7 order): a Page answers at its `path`; an article at
@@ -73,8 +74,10 @@ import NotFound from "../components/NotFound.astro";
73
74
  import PostTerms from "../components/PostTerms.astro";
74
75
  import RelatedPosts from "../components/RelatedPosts.astro";
75
76
  import Search from "../components/Search.astro";
77
+ import { fontLinkHeader, PAIRING_PRELOADS } from "../fonts.ts";
76
78
  import { iconSet } from "../icons.ts";
77
79
  import Base from "../layouts/Base.astro";
80
+ import { themeSettings } from "../settings.ts";
78
81
  import {
79
82
  ARCHIVE_PAGE_SIZE,
80
83
  blocks,
@@ -354,6 +357,10 @@ const localized = localizeHead(head, site, {
354
357
  });
355
358
  const meta = fallback || notFound ? { ...localized, robots: "noindex,follow" } : localized;
356
359
  Astro.response.headers.set("content-language", shownIn);
360
+ // The pairing's fonts as a Link header too (Early Hints), not only as <link rel=preload> in <head>.
361
+ const pairing = themeVariables(site, themeSettings).attributes["data-ch-type-pairing"];
362
+ const preloads = PAIRING_PRELOADS[pairing ?? ""] ?? [];
363
+ if (preloads.length) Astro.response.headers.set("link", fontLinkHeader(preloads));
357
364
  // The reader's notice (RFC-0033 §4): machine output until a person reviews it (or always, when
358
365
  // the site asks), a page shown in its original language, each with a link to the original.
359
366
  const original = alternates.find((a) => a.original && !a.current);
@@ -55,29 +55,41 @@
55
55
  font-family: ui-monospace, "Cascadia Code", "Source Code Pro", Menlo, Consolas, monospace;
56
56
  }
57
57
  /*
58
- * Font pairings (RFC-0023 §2): the families come from fonts.css and load only when used. They win
58
+ * Font pairings (RFC-0023 §2): the families come from fonts.css and load only when used; each is
59
+ * followed by its metric-matched fallback (font-fallbacks.css), so the swap does not move the
60
+ * text. They win
59
61
  * over the older typeface setting; `system` keeps it.
60
62
  */
61
63
  [data-ch-type-pairing="editorial"] {
62
- --ch-font-display: "Fraunces Variable", ui-serif, Georgia, serif;
63
- --ch-font-text: "Inter Variable", ui-sans-serif, system-ui, sans-serif;
64
+ --ch-font-display: "Fraunces Variable", "Fraunces Variable Fallback", ui-serif, Georgia, serif;
65
+ --ch-font-text: "Inter Variable", "Inter Variable Fallback", ui-sans-serif, system-ui, sans-serif;
64
66
  }
65
67
  [data-ch-type-pairing="modern"] {
66
- --ch-font-display: "Space Grotesk Variable", ui-sans-serif, system-ui, sans-serif;
67
- --ch-font-text: "Inter Variable", ui-sans-serif, system-ui, sans-serif;
68
+ --ch-font-display:
69
+ "Space Grotesk Variable", "Space Grotesk Variable Fallback", ui-sans-serif, system-ui,
70
+ sans-serif;
71
+ --ch-font-text: "Inter Variable", "Inter Variable Fallback", ui-sans-serif, system-ui, sans-serif;
68
72
  }
69
73
  [data-ch-type-pairing="humanist"] {
70
- --ch-font-display: "Source Sans 3 Variable", ui-sans-serif, system-ui, sans-serif;
71
- --ch-font-text: "Source Sans 3 Variable", ui-sans-serif, system-ui, sans-serif;
74
+ --ch-font-display:
75
+ "Source Sans 3 Variable", "Source Sans 3 Variable Fallback", ui-sans-serif, system-ui,
76
+ sans-serif;
77
+ --ch-font-text:
78
+ "Source Sans 3 Variable", "Source Sans 3 Variable Fallback", ui-sans-serif, system-ui,
79
+ sans-serif;
72
80
  }
73
81
  [data-ch-type-pairing="technical"] {
74
- --ch-font-display: "JetBrains Mono Variable", ui-monospace, monospace;
75
- --ch-font-text: "Inter Variable", ui-sans-serif, system-ui, sans-serif;
76
- --ch-font-code: "JetBrains Mono Variable", ui-monospace, monospace;
82
+ --ch-font-display:
83
+ "JetBrains Mono Variable", "JetBrains Mono Variable Fallback", ui-monospace, monospace;
84
+ --ch-font-text: "Inter Variable", "Inter Variable Fallback", ui-sans-serif, system-ui, sans-serif;
85
+ --ch-font-code:
86
+ "JetBrains Mono Variable", "JetBrains Mono Variable Fallback", ui-monospace, monospace;
77
87
  }
78
88
  [data-ch-type-pairing="classic"] {
79
- --ch-font-display: "Source Serif 4 Variable", ui-serif, Georgia, serif;
80
- --ch-font-text: "Source Serif 4 Variable", ui-serif, Georgia, serif;
89
+ --ch-font-display:
90
+ "Source Serif 4 Variable", "Source Serif 4 Variable Fallback", ui-serif, Georgia, serif;
91
+ --ch-font-text:
92
+ "Source Serif 4 Variable", "Source Serif 4 Variable Fallback", ui-serif, Georgia, serif;
81
93
  }
82
94
  [data-ch-type-pairing]:not([data-ch-type-pairing="system"]) .ch-body {
83
95
  font-family: var(--ch-font-text);
@@ -0,0 +1,53 @@
1
+ /*
2
+ * Generated by scripts/font-fallbacks.ts: do not edit. Metric-matched fallback faces for the
3
+ * pairings' web fonts (tokens.css lists each right after its web font), so the swap to the web
4
+ * font does not move the text.
5
+ */
6
+ @font-face {
7
+ font-family: "Fraunces Variable Fallback";
8
+ src: local("Times New Roman"), local("TimesNewRomanPSMT");
9
+ size-adjust: 113.62%;
10
+ ascent-override: 86.08%;
11
+ descent-override: 22.44%;
12
+ line-gap-override: 0.00%;
13
+ }
14
+ @font-face {
15
+ font-family: "Inter Variable Fallback";
16
+ src: local("Arial"), local("ArialMT");
17
+ size-adjust: 107.12%;
18
+ ascent-override: 90.44%;
19
+ descent-override: 22.52%;
20
+ line-gap-override: 0.00%;
21
+ }
22
+ @font-face {
23
+ font-family: "Space Grotesk Variable Fallback";
24
+ src: local("Arial"), local("ArialMT");
25
+ size-adjust: 109.47%;
26
+ ascent-override: 89.89%;
27
+ descent-override: 26.67%;
28
+ line-gap-override: 0.00%;
29
+ }
30
+ @font-face {
31
+ font-family: "Source Sans 3 Variable Fallback";
32
+ src: local("Arial"), local("ArialMT");
33
+ size-adjust: 92.42%;
34
+ ascent-override: 110.80%;
35
+ descent-override: 43.28%;
36
+ line-gap-override: 0.00%;
37
+ }
38
+ @font-face {
39
+ font-family: "Source Serif 4 Variable Fallback";
40
+ src: local("Times New Roman"), local("TimesNewRomanPSMT");
41
+ size-adjust: 117.91%;
42
+ ascent-override: 87.87%;
43
+ descent-override: 28.41%;
44
+ line-gap-override: 0.00%;
45
+ }
46
+ @font-face {
47
+ font-family: "JetBrains Mono Variable Fallback";
48
+ src: local("Courier New"), local("CourierNewPSMT");
49
+ size-adjust: 99.98%;
50
+ ascent-override: 102.02%;
51
+ descent-override: 30.00%;
52
+ line-gap-override: 0.00%;
53
+ }
@@ -8,7 +8,7 @@
8
8
  font-style: normal;
9
9
  font-display: swap;
10
10
  font-weight: 100 900;
11
- src: url(/fonts/fraunces-latin-ext-wght-normal.woff2) format("woff2-variations");
11
+ src: url(/fonts/v1/fraunces-latin-ext-wght-normal.woff2) format("woff2-variations");
12
12
  unicode-range:
13
13
  U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
14
14
  }
@@ -17,7 +17,7 @@
17
17
  font-style: normal;
18
18
  font-display: swap;
19
19
  font-weight: 100 900;
20
- src: url(/fonts/fraunces-latin-wght-normal.woff2) format("woff2-variations");
20
+ src: url(/fonts/v1/fraunces-latin-wght-normal.woff2) format("woff2-variations");
21
21
  unicode-range:
22
22
  U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
23
23
  }
@@ -26,7 +26,7 @@
26
26
  font-style: normal;
27
27
  font-display: swap;
28
28
  font-weight: 100 900;
29
- src: url(/fonts/inter-latin-ext-wght-normal.woff2) format("woff2-variations");
29
+ src: url(/fonts/v1/inter-latin-ext-wght-normal.woff2) format("woff2-variations");
30
30
  unicode-range:
31
31
  U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
32
32
  }
@@ -35,7 +35,7 @@
35
35
  font-style: normal;
36
36
  font-display: swap;
37
37
  font-weight: 100 900;
38
- src: url(/fonts/inter-latin-wght-normal.woff2) format("woff2-variations");
38
+ src: url(/fonts/v1/inter-latin-wght-normal.woff2) format("woff2-variations");
39
39
  unicode-range:
40
40
  U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
41
41
  }
@@ -44,7 +44,7 @@
44
44
  font-style: normal;
45
45
  font-display: swap;
46
46
  font-weight: 100 800;
47
- src: url(/fonts/jetbrains-mono-latin-ext-wght-normal.woff2) format("woff2-variations");
47
+ src: url(/fonts/v1/jetbrains-mono-latin-ext-wght-normal.woff2) format("woff2-variations");
48
48
  unicode-range:
49
49
  U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
50
50
  }
@@ -53,7 +53,7 @@
53
53
  font-style: normal;
54
54
  font-display: swap;
55
55
  font-weight: 100 800;
56
- src: url(/fonts/jetbrains-mono-latin-wght-normal.woff2) format("woff2-variations");
56
+ src: url(/fonts/v1/jetbrains-mono-latin-wght-normal.woff2) format("woff2-variations");
57
57
  unicode-range:
58
58
  U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
59
59
  }
@@ -62,7 +62,7 @@
62
62
  font-style: normal;
63
63
  font-display: swap;
64
64
  font-weight: 200 900;
65
- src: url(/fonts/source-sans-3-latin-ext-wght-normal.woff2) format("woff2-variations");
65
+ src: url(/fonts/v1/source-sans-3-latin-ext-wght-normal.woff2) format("woff2-variations");
66
66
  unicode-range:
67
67
  U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF;
68
68
  }
@@ -71,7 +71,7 @@
71
71
  font-style: normal;
72
72
  font-display: swap;
73
73
  font-weight: 200 900;
74
- src: url(/fonts/source-sans-3-latin-wght-normal.woff2) format("woff2-variations");
74
+ src: url(/fonts/v1/source-sans-3-latin-wght-normal.woff2) format("woff2-variations");
75
75
  unicode-range:
76
76
  U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
77
77
  }
@@ -80,7 +80,7 @@
80
80
  font-style: normal;
81
81
  font-display: swap;
82
82
  font-weight: 200 900;
83
- src: url(/fonts/source-serif-4-latin-ext-wght-normal.woff2) format("woff2-variations");
83
+ src: url(/fonts/v1/source-serif-4-latin-ext-wght-normal.woff2) format("woff2-variations");
84
84
  unicode-range:
85
85
  U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF;
86
86
  }
@@ -89,7 +89,7 @@
89
89
  font-style: normal;
90
90
  font-display: swap;
91
91
  font-weight: 200 900;
92
- src: url(/fonts/source-serif-4-latin-wght-normal.woff2) format("woff2-variations");
92
+ src: url(/fonts/v1/source-serif-4-latin-wght-normal.woff2) format("woff2-variations");
93
93
  unicode-range:
94
94
  U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
95
95
  }
@@ -98,7 +98,7 @@
98
98
  font-style: normal;
99
99
  font-display: swap;
100
100
  font-weight: 300 700;
101
- src: url(/fonts/space-grotesk-latin-ext-wght-normal.woff2) format("woff2-variations");
101
+ src: url(/fonts/v1/space-grotesk-latin-ext-wght-normal.woff2) format("woff2-variations");
102
102
  unicode-range:
103
103
  U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
104
104
  }
@@ -107,7 +107,7 @@
107
107
  font-style: normal;
108
108
  font-display: swap;
109
109
  font-weight: 300 700;
110
- src: url(/fonts/space-grotesk-latin-wght-normal.woff2) format("woff2-variations");
110
+ src: url(/fonts/v1/space-grotesk-latin-wght-normal.woff2) format("woff2-variations");
111
111
  unicode-range:
112
112
  U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
113
113
  }
@@ -1,6 +1,7 @@
1
1
  /* Scan `src/` only: automatic detection may walk up the file system (docs/design/starter-references.md §6). */
2
2
  @import "tailwindcss" source("..");
3
3
  @import "./fonts.css";
4
+ @import "./font-fallbacks.css";
4
5
 
5
6
  /*
6
7
  * One file per feature (docs/engineering/code-structure.md §8), in cascade order. Unlayered on
@@ -136,8 +136,13 @@ export async function must(
136
136
 
137
137
  /** URLs of a deployed Worker from wrangler's structured output. */
138
138
  export function deployedUrls(records ) {
139
- return records
140
- .filter((r) => r.type === "deploy")
141
- .flatMap((r) => (Array.isArray(r.targets) ? (r.targets ) : []))
142
- .map((t) => (t.startsWith("http") ? t : `https://${t}`));
139
+ return (
140
+ records
141
+ .filter((r) => r.type === "deploy")
142
+ .flatMap((r) => (Array.isArray(r.targets) ? (r.targets ) : []))
143
+ // Wrangler lists custom domains as "cloudhal.com (custom domain)": keep the hostname only.
144
+ .map((t) => t.trim().split(/\s+/)[0] ?? "")
145
+ .filter(Boolean)
146
+ .map((t) => (t.startsWith("http") ? t : `https://${t}`))
147
+ );
143
148
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cloudhal/cli",
3
- "version": "0.3.6",
3
+ "version": "0.3.8",
4
4
  "description": "cloudhal — create, run and build Cloudhal sites locally",
5
5
  "license": "Apache-2.0",
6
6
  "homepage": "https://cloudhal.dev",
@@ -27,16 +27,16 @@
27
27
  "README.md"
28
28
  ],
29
29
  "dependencies": {
30
- "@cloudhal/agent-runtime": "0.3.6",
31
- "@cloudhal/analytics": "0.3.6",
32
- "@cloudhal/api": "0.3.6",
33
- "@cloudhal/cloudflare": "0.3.6",
34
- "@cloudhal/comments": "0.3.6",
35
- "@cloudhal/core-contracts": "0.3.6",
36
- "@cloudhal/core-ts": "0.3.6",
37
- "@cloudhal/mcp-server": "0.3.6",
38
- "@cloudhal/schedules": "0.3.6",
39
- "@cloudhal/storage": "0.3.6",
30
+ "@cloudhal/agent-runtime": "0.3.8",
31
+ "@cloudhal/analytics": "0.3.8",
32
+ "@cloudhal/api": "0.3.8",
33
+ "@cloudhal/cloudflare": "0.3.8",
34
+ "@cloudhal/comments": "0.3.8",
35
+ "@cloudhal/core-contracts": "0.3.8",
36
+ "@cloudhal/core-ts": "0.3.8",
37
+ "@cloudhal/mcp-server": "0.3.8",
38
+ "@cloudhal/schedules": "0.3.8",
39
+ "@cloudhal/storage": "0.3.8",
40
40
  "@hono/node-server": "^2.1.4",
41
41
  "better-sqlite3": "13.0.3"
42
42
  },