@iterant/site-runtime 3.7.0 → 3.8.1

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.
@@ -0,0 +1,361 @@
1
+ {
2
+ "note": "The Google Fonts families every Iterant site may name. `class` is the face class the mockup analyzer reports; `cssVariable` is --font-<slug>, derived with fontCssVariable(). Subsets are latin + latin-ext everywhere. This file is the source of truth other packages mirror; catalog.ts reads it.",
3
+ "families": [
4
+ {
5
+ "family": "Fraunces",
6
+ "class": "serif"
7
+ },
8
+ {
9
+ "family": "Playfair Display",
10
+ "class": "serif"
11
+ },
12
+ {
13
+ "family": "Instrument Serif",
14
+ "class": "serif"
15
+ },
16
+ {
17
+ "family": "Source Serif 4",
18
+ "class": "serif"
19
+ },
20
+ {
21
+ "family": "Lora",
22
+ "class": "serif"
23
+ },
24
+ {
25
+ "family": "Newsreader",
26
+ "class": "serif"
27
+ },
28
+ {
29
+ "family": "EB Garamond",
30
+ "class": "serif"
31
+ },
32
+ {
33
+ "family": "Cormorant Garamond",
34
+ "class": "serif"
35
+ },
36
+ {
37
+ "family": "Libre Baskerville",
38
+ "class": "serif"
39
+ },
40
+ {
41
+ "family": "Merriweather",
42
+ "class": "serif"
43
+ },
44
+ {
45
+ "family": "Crimson Pro",
46
+ "class": "serif"
47
+ },
48
+ {
49
+ "family": "Literata",
50
+ "class": "serif"
51
+ },
52
+ {
53
+ "family": "DM Serif Display",
54
+ "class": "serif"
55
+ },
56
+ {
57
+ "family": "DM Serif Text",
58
+ "class": "serif"
59
+ },
60
+ {
61
+ "family": "Spectral",
62
+ "class": "serif"
63
+ },
64
+ {
65
+ "family": "Libre Caslon Text",
66
+ "class": "serif"
67
+ },
68
+ {
69
+ "family": "Bodoni Moda",
70
+ "class": "serif"
71
+ },
72
+ {
73
+ "family": "Gloock",
74
+ "class": "serif"
75
+ },
76
+ {
77
+ "family": "Young Serif",
78
+ "class": "serif"
79
+ },
80
+ {
81
+ "family": "Petrona",
82
+ "class": "serif"
83
+ },
84
+ {
85
+ "family": "Cinzel",
86
+ "class": "serif"
87
+ },
88
+ {
89
+ "family": "Marcellus",
90
+ "class": "serif"
91
+ },
92
+ {
93
+ "family": "Italiana",
94
+ "class": "serif"
95
+ },
96
+ {
97
+ "family": "Abril Fatface",
98
+ "class": "display"
99
+ },
100
+ {
101
+ "family": "Bitter",
102
+ "class": "slab"
103
+ },
104
+ {
105
+ "family": "Roboto Slab",
106
+ "class": "slab"
107
+ },
108
+ {
109
+ "family": "Zilla Slab",
110
+ "class": "slab"
111
+ },
112
+ {
113
+ "family": "Arvo",
114
+ "class": "slab"
115
+ },
116
+ {
117
+ "family": "Inter",
118
+ "class": "sans"
119
+ },
120
+ {
121
+ "family": "Inter Tight",
122
+ "class": "sans"
123
+ },
124
+ {
125
+ "family": "Manrope",
126
+ "class": "sans"
127
+ },
128
+ {
129
+ "family": "DM Sans",
130
+ "class": "sans"
131
+ },
132
+ {
133
+ "family": "Plus Jakarta Sans",
134
+ "class": "sans"
135
+ },
136
+ {
137
+ "family": "Figtree",
138
+ "class": "sans"
139
+ },
140
+ {
141
+ "family": "Outfit",
142
+ "class": "sans"
143
+ },
144
+ {
145
+ "family": "Onest",
146
+ "class": "sans"
147
+ },
148
+ {
149
+ "family": "Geist",
150
+ "class": "sans"
151
+ },
152
+ {
153
+ "family": "Schibsted Grotesk",
154
+ "class": "sans"
155
+ },
156
+ {
157
+ "family": "Instrument Sans",
158
+ "class": "sans"
159
+ },
160
+ {
161
+ "family": "Space Grotesk",
162
+ "class": "sans"
163
+ },
164
+ {
165
+ "family": "Bricolage Grotesque",
166
+ "class": "sans"
167
+ },
168
+ {
169
+ "family": "Work Sans",
170
+ "class": "sans"
171
+ },
172
+ {
173
+ "family": "Public Sans",
174
+ "class": "sans"
175
+ },
176
+ {
177
+ "family": "IBM Plex Sans",
178
+ "class": "sans"
179
+ },
180
+ {
181
+ "family": "Source Sans 3",
182
+ "class": "sans"
183
+ },
184
+ {
185
+ "family": "Nunito Sans",
186
+ "class": "sans"
187
+ },
188
+ {
189
+ "family": "Poppins",
190
+ "class": "sans"
191
+ },
192
+ {
193
+ "family": "Montserrat",
194
+ "class": "sans"
195
+ },
196
+ {
197
+ "family": "Raleway",
198
+ "class": "sans"
199
+ },
200
+ {
201
+ "family": "Lato",
202
+ "class": "sans"
203
+ },
204
+ {
205
+ "family": "Rubik",
206
+ "class": "sans"
207
+ },
208
+ {
209
+ "family": "Karla",
210
+ "class": "sans"
211
+ },
212
+ {
213
+ "family": "Archivo",
214
+ "class": "sans"
215
+ },
216
+ {
217
+ "family": "Barlow",
218
+ "class": "sans"
219
+ },
220
+ {
221
+ "family": "Sora",
222
+ "class": "sans"
223
+ },
224
+ {
225
+ "family": "Urbanist",
226
+ "class": "sans"
227
+ },
228
+ {
229
+ "family": "Albert Sans",
230
+ "class": "sans"
231
+ },
232
+ {
233
+ "family": "Hanken Grotesk",
234
+ "class": "sans"
235
+ },
236
+ {
237
+ "family": "Host Grotesk",
238
+ "class": "sans"
239
+ },
240
+ {
241
+ "family": "Red Hat Display",
242
+ "class": "sans"
243
+ },
244
+ {
245
+ "family": "Red Hat Text",
246
+ "class": "sans"
247
+ },
248
+ {
249
+ "family": "Epilogue",
250
+ "class": "sans"
251
+ },
252
+ {
253
+ "family": "Jost",
254
+ "class": "sans"
255
+ },
256
+ {
257
+ "family": "Mulish",
258
+ "class": "sans"
259
+ },
260
+ {
261
+ "family": "Be Vietnam Pro",
262
+ "class": "sans"
263
+ },
264
+ {
265
+ "family": "Lexend",
266
+ "class": "sans"
267
+ },
268
+ {
269
+ "family": "Familjen Grotesk",
270
+ "class": "sans"
271
+ },
272
+ {
273
+ "family": "Chivo",
274
+ "class": "sans"
275
+ },
276
+ {
277
+ "family": "Roboto Flex",
278
+ "class": "sans"
279
+ },
280
+ {
281
+ "family": "Open Sans",
282
+ "class": "sans"
283
+ },
284
+ {
285
+ "family": "Nunito",
286
+ "class": "rounded"
287
+ },
288
+ {
289
+ "family": "Quicksand",
290
+ "class": "rounded"
291
+ },
292
+ {
293
+ "family": "Varela Round",
294
+ "class": "rounded"
295
+ },
296
+ {
297
+ "family": "Archivo Narrow",
298
+ "class": "condensed"
299
+ },
300
+ {
301
+ "family": "Barlow Condensed",
302
+ "class": "condensed"
303
+ },
304
+ {
305
+ "family": "Oswald",
306
+ "class": "condensed"
307
+ },
308
+ {
309
+ "family": "Bebas Neue",
310
+ "class": "display"
311
+ },
312
+ {
313
+ "family": "Anton",
314
+ "class": "display"
315
+ },
316
+ {
317
+ "family": "Archivo Black",
318
+ "class": "display"
319
+ },
320
+ {
321
+ "family": "Syne",
322
+ "class": "display"
323
+ },
324
+ {
325
+ "family": "Unbounded",
326
+ "class": "display"
327
+ },
328
+ {
329
+ "family": "Caveat",
330
+ "class": "handwritten"
331
+ },
332
+ {
333
+ "family": "IBM Plex Mono",
334
+ "class": "mono"
335
+ },
336
+ {
337
+ "family": "JetBrains Mono",
338
+ "class": "mono"
339
+ },
340
+ {
341
+ "family": "Space Mono",
342
+ "class": "mono"
343
+ },
344
+ {
345
+ "family": "DM Mono",
346
+ "class": "mono"
347
+ },
348
+ {
349
+ "family": "Fira Code",
350
+ "class": "mono"
351
+ },
352
+ {
353
+ "family": "Geist Mono",
354
+ "class": "mono"
355
+ },
356
+ {
357
+ "family": "Roboto Mono",
358
+ "class": "mono"
359
+ }
360
+ ]
361
+ }
@@ -0,0 +1,88 @@
1
+ import catalog from "./catalog.json";
2
+
3
+ // The font catalog: the Google Fonts families an Iterant site may name, and the
4
+ // CSS variable each one is served under. `catalog.json` beside this file is the
5
+ // source of truth other packages mirror (the agent picks family names out of
6
+ // it); this module is the typed reader plus the two helpers the platform and
7
+ // the layout both need.
8
+ //
9
+ // A family is NOT loaded because it is in the catalog. The preset declares only
10
+ // the families a site names (`iterantStarter({ fonts })`) and the layout renders
11
+ // `<Font>` only for those, because Astro resolves every declared family at dev
12
+ // boot and downloads every one of its files at build. See the preset.
13
+
14
+ /** The face class the mockup analyzer reports for a family. */
15
+ export type FontClass =
16
+ | "serif"
17
+ | "sans"
18
+ | "slab"
19
+ | "mono"
20
+ | "display"
21
+ | "rounded"
22
+ | "condensed"
23
+ | "handwritten";
24
+
25
+ export interface FontCatalogEntry {
26
+ /** The Google Fonts family name, exactly as the provider spells it. */
27
+ family: string;
28
+ class: FontClass;
29
+ }
30
+
31
+ /** Every family a site may name, in catalog order. */
32
+ export const FONT_CATALOG = catalog.families as readonly FontCatalogEntry[];
33
+
34
+ /**
35
+ * The CSS variable a family is served under: the family name lowercased with
36
+ * spaces hyphenated, under a `--font-` prefix (`Playfair Display` →
37
+ * `--font-playfair-display`). The preset registers this name with Astro and the
38
+ * layout renders `<Font>` by it, so the two can only agree through this
39
+ * function.
40
+ */
41
+ export function fontCssVariable(family: string): `--font-${string}` {
42
+ return `--font-${family.trim().toLowerCase().replace(/\s+/g, "-")}`;
43
+ }
44
+
45
+ /**
46
+ * The catalog entry for a family name, or undefined for a name the catalog does
47
+ * not carry. Callers skip what they cannot resolve: Astro's `<Font>` throws on a
48
+ * CSS variable no family registered, so an unknown name must never reach it.
49
+ */
50
+ export function findFontFamily(family: string): FontCatalogEntry | undefined {
51
+ return FONT_CATALOG.find((entry) => entry.family === family);
52
+ }
53
+
54
+ /**
55
+ * The heading default for each face class: what the platform reaches for when a
56
+ * mockup reports a class and nothing has named a family yet. One per class, so
57
+ * every class a mockup can report resolves.
58
+ */
59
+ export const DEFAULT_HEADING_FAMILY_BY_CLASS: Readonly<
60
+ Record<FontClass, string>
61
+ > = {
62
+ serif: "Fraunces",
63
+ sans: "Schibsted Grotesk",
64
+ slab: "Bitter",
65
+ rounded: "Nunito",
66
+ condensed: "Barlow Condensed",
67
+ display: "Syne",
68
+ handwritten: "Caveat",
69
+ mono: "IBM Plex Mono",
70
+ };
71
+
72
+ /** The body defaults, paired with any of the heading defaults above. */
73
+ export const DEFAULT_BODY_FAMILIES: readonly string[] = [
74
+ "Instrument Sans",
75
+ "Inter Tight",
76
+ "Nunito Sans",
77
+ ];
78
+
79
+ /**
80
+ * The families the preset declares whether or not a site names any: the eleven
81
+ * above. They are declared so the common path needs no astro.config edit and no
82
+ * dev-server restart to reach a face the platform just picked. Naming a family
83
+ * in SITE_CONFIG.fonts ADDS to this set; it does not replace it.
84
+ */
85
+ export const DEFAULT_FONT_FAMILIES: readonly string[] = [
86
+ ...Object.values(DEFAULT_HEADING_FAMILY_BY_CLASS),
87
+ ...DEFAULT_BODY_FAMILIES,
88
+ ];
package/src/index.ts CHANGED
@@ -7,6 +7,7 @@
7
7
  // Astro-bound surfaces have their own entries: `/content` (collections),
8
8
  // `/layout`, `/seo`, `/routes`, `/sitemap`, `/config`, `/integrations/*`.
9
9
  export * from "./content/schema";
10
+ export * from "./fonts/catalog";
10
11
  export * from "./layouts/layout-core";
11
12
  export * from "./lib/bespoke-pages";
12
13
  export * from "./lib/chrome-schemas";
@@ -0,0 +1,46 @@
1
+ // @ts-check
2
+
3
+ // Dev-only: is an in-place Astro restart in flight? (3.8.1)
4
+ //
5
+ // Astro replaces its Vite server in place when a watched file changes
6
+ // (`src/site-config.ts`, `package.json`), and for that stretch the port still
7
+ // accepts connections while the server behind it is being torn down and built
8
+ // again. A request that was already running is answered 500 `fetch failed`:
9
+ // the Cloudflare vite plugin's miniflare went down under it.
10
+ //
11
+ // preview-error-shell reads this flag before it fetches /under-construction
12
+ // back through that same port for its cache. A fetch aimed into the gap buys
13
+ // nothing (it can only fail or hang) and it reaches back into the plugin at
14
+ // the moment it is least able to answer, which is how the 3.8.0 shell wedged
15
+ // the dev server for a whole 120s probe window in Docker.
16
+ //
17
+ // The window opens in `dev-server-signals` at `astro:config:setup` on the
18
+ // restarted server, the same moment it emits
19
+ // `{"event":"restart","phase":"config"}`, and closes when that server's socket
20
+ // starts listening, the moment of `{"event":"ready","restart":true}`.
21
+ //
22
+ // State, not a timer: nothing here schedules work or holds a handle, and the
23
+ // two integrations share one module instance because the preset imports both
24
+ // from this package. A restart that never lands would otherwise leave the flag
25
+ // up for the rest of the session and strand the cache empty, so the flag is
26
+ // read with a bound on how long a restart can plausibly be in flight rather
27
+ // than trusted forever. A dev boot on a cold cache is around 11s.
28
+
29
+ const RESTART_WINDOW_MS = 30_000;
30
+
31
+ let startedAt = 0;
32
+
33
+ /** The restarted server is being built. Called once per in-place restart. */
34
+ export function beginRestart() {
35
+ startedAt = Date.now();
36
+ }
37
+
38
+ /** The restarted server is listening, so a self-fetch can be answered again. */
39
+ export function endRestart() {
40
+ startedAt = 0;
41
+ }
42
+
43
+ /** @returns {boolean} */
44
+ export function restartInFlight() {
45
+ return startedAt !== 0 && Date.now() - startedAt < RESTART_WINDOW_MS;
46
+ }