@cfbender/cesium 0.3.5
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/ARCHITECTURE.md +304 -0
- package/CHANGELOG.md +335 -0
- package/LICENSE +21 -0
- package/README.md +479 -0
- package/agents/cesium.md +39 -0
- package/assets/styleguide.html +857 -0
- package/package.json +61 -0
- package/src/cli/commands/ls.ts +186 -0
- package/src/cli/commands/open.ts +208 -0
- package/src/cli/commands/prune.ts +348 -0
- package/src/cli/commands/restart.ts +38 -0
- package/src/cli/commands/serve.ts +214 -0
- package/src/cli/commands/stop.ts +130 -0
- package/src/cli/commands/theme.ts +333 -0
- package/src/cli/index.ts +78 -0
- package/src/config.ts +94 -0
- package/src/index.ts +35 -0
- package/src/prompt/system-fragment.md +97 -0
- package/src/render/client-js.ts +316 -0
- package/src/render/controls.ts +302 -0
- package/src/render/critique.ts +360 -0
- package/src/render/extract.ts +83 -0
- package/src/render/scrub.ts +141 -0
- package/src/render/theme.ts +712 -0
- package/src/render/validate.ts +524 -0
- package/src/render/wrap.ts +165 -0
- package/src/server/api.ts +166 -0
- package/src/server/http.ts +195 -0
- package/src/server/lifecycle.ts +331 -0
- package/src/server/stop.ts +124 -0
- package/src/storage/index-cache.ts +71 -0
- package/src/storage/index-gen.ts +447 -0
- package/src/storage/lock.ts +108 -0
- package/src/storage/mutate.ts +396 -0
- package/src/storage/paths.ts +159 -0
- package/src/storage/project-summaries.ts +19 -0
- package/src/storage/theme-write.ts +19 -0
- package/src/storage/write.ts +75 -0
- package/src/tools/ask.ts +353 -0
- package/src/tools/critique.ts +66 -0
- package/src/tools/publish.ts +404 -0
- package/src/tools/stop.ts +53 -0
- package/src/tools/styleguide.ts +23 -0
- package/src/tools/wait.ts +192 -0
|
@@ -0,0 +1,857 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
6
|
+
<title>Cesium · Design system reference</title>
|
|
7
|
+
<style>
|
|
8
|
+
:root {
|
|
9
|
+
--bg: #faf9f5;
|
|
10
|
+
--surface: #ffffff;
|
|
11
|
+
--surface-2: #f0eee6;
|
|
12
|
+
--oat: #e3dacc;
|
|
13
|
+
--rule: #d1cfc5;
|
|
14
|
+
--ink: #141413;
|
|
15
|
+
--ink-soft: #3d3d3a;
|
|
16
|
+
--muted: #87867f;
|
|
17
|
+
--accent: #d97757;
|
|
18
|
+
--olive: #788c5d;
|
|
19
|
+
--code-bg: #141413;
|
|
20
|
+
--code-fg: #e8e6de;
|
|
21
|
+
--serif: ui-serif, Georgia, "Times New Roman", serif;
|
|
22
|
+
--sans: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
|
|
23
|
+
--mono: ui-monospace, "SF Mono", Menlo, Monaco, monospace;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/* reset */
|
|
27
|
+
*,
|
|
28
|
+
*::before,
|
|
29
|
+
*::after {
|
|
30
|
+
box-sizing: border-box;
|
|
31
|
+
margin: 0;
|
|
32
|
+
padding: 0;
|
|
33
|
+
}
|
|
34
|
+
html {
|
|
35
|
+
font-size: 16px;
|
|
36
|
+
-webkit-text-size-adjust: 100%;
|
|
37
|
+
}
|
|
38
|
+
body {
|
|
39
|
+
background: var(--bg);
|
|
40
|
+
color: var(--ink);
|
|
41
|
+
font-family: var(--sans);
|
|
42
|
+
font-size: 1rem;
|
|
43
|
+
line-height: 1.6;
|
|
44
|
+
padding: clamp(20px, 4vw, 56px);
|
|
45
|
+
}
|
|
46
|
+
a {
|
|
47
|
+
color: var(--accent);
|
|
48
|
+
text-decoration: underline;
|
|
49
|
+
}
|
|
50
|
+
a:hover {
|
|
51
|
+
opacity: 0.8;
|
|
52
|
+
}
|
|
53
|
+
img,
|
|
54
|
+
svg {
|
|
55
|
+
max-width: 100%;
|
|
56
|
+
height: auto;
|
|
57
|
+
}
|
|
58
|
+
p {
|
|
59
|
+
margin-bottom: 1em;
|
|
60
|
+
}
|
|
61
|
+
ul,
|
|
62
|
+
ol {
|
|
63
|
+
padding-left: 1.5em;
|
|
64
|
+
margin-bottom: 1em;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/* layout */
|
|
68
|
+
.page {
|
|
69
|
+
max-width: 1120px;
|
|
70
|
+
margin: 0 auto;
|
|
71
|
+
}
|
|
72
|
+
section {
|
|
73
|
+
margin-bottom: 64px;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/* typography */
|
|
77
|
+
h1,
|
|
78
|
+
h2,
|
|
79
|
+
h3,
|
|
80
|
+
h4,
|
|
81
|
+
h5,
|
|
82
|
+
h6 {
|
|
83
|
+
font-family: var(--serif);
|
|
84
|
+
color: var(--ink);
|
|
85
|
+
line-height: 1.2;
|
|
86
|
+
margin-bottom: 0.5em;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/* eyebrow */
|
|
90
|
+
.eyebrow {
|
|
91
|
+
font-family: var(--mono);
|
|
92
|
+
font-size: 0.7rem;
|
|
93
|
+
font-weight: 600;
|
|
94
|
+
letter-spacing: 0.1em;
|
|
95
|
+
text-transform: uppercase;
|
|
96
|
+
color: var(--muted);
|
|
97
|
+
margin-bottom: 0.5em;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/* headings */
|
|
101
|
+
.h-display {
|
|
102
|
+
font-family: var(--serif);
|
|
103
|
+
font-size: clamp(2rem, 5vw, 3.25rem);
|
|
104
|
+
font-weight: 700;
|
|
105
|
+
line-height: 1.1;
|
|
106
|
+
color: var(--ink);
|
|
107
|
+
margin-bottom: 0.75em;
|
|
108
|
+
}
|
|
109
|
+
.h-section {
|
|
110
|
+
font-family: var(--serif);
|
|
111
|
+
font-size: 1.5rem;
|
|
112
|
+
font-weight: 600;
|
|
113
|
+
color: var(--ink);
|
|
114
|
+
margin-bottom: 0.5em;
|
|
115
|
+
}
|
|
116
|
+
.section-num {
|
|
117
|
+
display: inline-flex;
|
|
118
|
+
align-items: center;
|
|
119
|
+
justify-content: center;
|
|
120
|
+
background: var(--oat);
|
|
121
|
+
color: var(--ink-soft);
|
|
122
|
+
font-family: var(--mono);
|
|
123
|
+
font-size: 0.75rem;
|
|
124
|
+
font-weight: 700;
|
|
125
|
+
border-radius: 6px;
|
|
126
|
+
padding: 2px 7px;
|
|
127
|
+
margin-right: 0.5em;
|
|
128
|
+
vertical-align: middle;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/* card */
|
|
132
|
+
.card {
|
|
133
|
+
background: var(--surface);
|
|
134
|
+
border: 1.5px solid var(--rule);
|
|
135
|
+
border-radius: 12px;
|
|
136
|
+
padding: 18px 22px;
|
|
137
|
+
margin-bottom: 1.5em;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/* tldr */
|
|
141
|
+
.tldr {
|
|
142
|
+
background: var(--surface);
|
|
143
|
+
border-left: 4px solid var(--accent);
|
|
144
|
+
border-radius: 0 12px 12px 0;
|
|
145
|
+
padding: 16px 20px;
|
|
146
|
+
margin-bottom: 1.5em;
|
|
147
|
+
font-size: 1.05rem;
|
|
148
|
+
color: var(--ink-soft);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/* callout */
|
|
152
|
+
.callout {
|
|
153
|
+
border-radius: 8px;
|
|
154
|
+
padding: 14px 18px;
|
|
155
|
+
margin-bottom: 1.25em;
|
|
156
|
+
border: 1.5px solid var(--rule);
|
|
157
|
+
background: var(--surface-2);
|
|
158
|
+
color: var(--ink-soft);
|
|
159
|
+
font-size: 0.95rem;
|
|
160
|
+
}
|
|
161
|
+
.callout.note {
|
|
162
|
+
border-color: var(--olive);
|
|
163
|
+
background: color-mix(in srgb, var(--olive) 10%, var(--surface));
|
|
164
|
+
}
|
|
165
|
+
.callout.warn {
|
|
166
|
+
border-color: var(--accent);
|
|
167
|
+
background: color-mix(in srgb, var(--accent) 10%, var(--surface));
|
|
168
|
+
}
|
|
169
|
+
.callout.risk {
|
|
170
|
+
border-color: #b45309;
|
|
171
|
+
background: color-mix(in srgb, #b45309 10%, var(--surface));
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/* code */
|
|
175
|
+
.code {
|
|
176
|
+
background: var(--code-bg);
|
|
177
|
+
color: var(--code-fg);
|
|
178
|
+
font-family: var(--mono);
|
|
179
|
+
font-size: 0.875rem;
|
|
180
|
+
line-height: 1.6;
|
|
181
|
+
border-radius: 8px;
|
|
182
|
+
padding: 16px 20px;
|
|
183
|
+
overflow-x: auto;
|
|
184
|
+
margin-bottom: 1.25em;
|
|
185
|
+
white-space: pre;
|
|
186
|
+
}
|
|
187
|
+
.code .kw {
|
|
188
|
+
color: var(--accent);
|
|
189
|
+
}
|
|
190
|
+
.code .str {
|
|
191
|
+
color: var(--olive);
|
|
192
|
+
}
|
|
193
|
+
.code .cm {
|
|
194
|
+
color: var(--muted);
|
|
195
|
+
font-style: italic;
|
|
196
|
+
}
|
|
197
|
+
.code .fn {
|
|
198
|
+
color: #d4a85a;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/* timeline */
|
|
202
|
+
.timeline {
|
|
203
|
+
list-style: none;
|
|
204
|
+
padding: 0;
|
|
205
|
+
position: relative;
|
|
206
|
+
}
|
|
207
|
+
.timeline::before {
|
|
208
|
+
content: "";
|
|
209
|
+
position: absolute;
|
|
210
|
+
left: 9px;
|
|
211
|
+
top: 6px;
|
|
212
|
+
bottom: 6px;
|
|
213
|
+
width: 2px;
|
|
214
|
+
background: var(--rule);
|
|
215
|
+
}
|
|
216
|
+
.timeline li {
|
|
217
|
+
position: relative;
|
|
218
|
+
padding-left: 32px;
|
|
219
|
+
margin-bottom: 1.25em;
|
|
220
|
+
}
|
|
221
|
+
.timeline li::before {
|
|
222
|
+
content: "";
|
|
223
|
+
position: absolute;
|
|
224
|
+
left: 2px;
|
|
225
|
+
top: 6px;
|
|
226
|
+
width: 14px;
|
|
227
|
+
height: 14px;
|
|
228
|
+
border-radius: 50%;
|
|
229
|
+
background: var(--oat);
|
|
230
|
+
border: 2px solid var(--accent);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/* diagram */
|
|
234
|
+
.diagram {
|
|
235
|
+
border: 1.5px solid var(--rule);
|
|
236
|
+
border-radius: 12px;
|
|
237
|
+
padding: 20px;
|
|
238
|
+
text-align: center;
|
|
239
|
+
margin-bottom: 1.5em;
|
|
240
|
+
background: var(--surface);
|
|
241
|
+
}
|
|
242
|
+
.diagram figcaption {
|
|
243
|
+
font-size: 0.85rem;
|
|
244
|
+
color: var(--muted);
|
|
245
|
+
margin-top: 10px;
|
|
246
|
+
font-family: var(--sans);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/* compare-table */
|
|
250
|
+
.compare-table {
|
|
251
|
+
width: 100%;
|
|
252
|
+
border-collapse: collapse;
|
|
253
|
+
margin-bottom: 1.5em;
|
|
254
|
+
font-size: 0.95rem;
|
|
255
|
+
}
|
|
256
|
+
.compare-table th,
|
|
257
|
+
.compare-table td {
|
|
258
|
+
border: 1.5px solid var(--rule);
|
|
259
|
+
padding: 10px 14px;
|
|
260
|
+
text-align: left;
|
|
261
|
+
vertical-align: top;
|
|
262
|
+
}
|
|
263
|
+
.compare-table th {
|
|
264
|
+
background: var(--surface-2);
|
|
265
|
+
font-family: var(--sans);
|
|
266
|
+
font-weight: 600;
|
|
267
|
+
color: var(--ink);
|
|
268
|
+
}
|
|
269
|
+
.compare-table tr:nth-child(even) td {
|
|
270
|
+
background: var(--surface-2);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/* risk-table */
|
|
274
|
+
.risk-table {
|
|
275
|
+
width: 100%;
|
|
276
|
+
border-collapse: collapse;
|
|
277
|
+
margin-bottom: 1.5em;
|
|
278
|
+
font-size: 0.95rem;
|
|
279
|
+
}
|
|
280
|
+
.risk-table th,
|
|
281
|
+
.risk-table td {
|
|
282
|
+
border: 1.5px solid var(--rule);
|
|
283
|
+
padding: 10px 14px;
|
|
284
|
+
text-align: left;
|
|
285
|
+
vertical-align: top;
|
|
286
|
+
}
|
|
287
|
+
.risk-table th {
|
|
288
|
+
background: var(--surface-2);
|
|
289
|
+
font-family: var(--sans);
|
|
290
|
+
font-weight: 600;
|
|
291
|
+
}
|
|
292
|
+
.risk-table td:first-child {
|
|
293
|
+
font-weight: 600;
|
|
294
|
+
color: var(--ink-soft);
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
/* inline chips */
|
|
298
|
+
.kbd {
|
|
299
|
+
display: inline-block;
|
|
300
|
+
font-family: var(--mono);
|
|
301
|
+
font-size: 0.8em;
|
|
302
|
+
background: var(--surface-2);
|
|
303
|
+
border: 1.5px solid var(--rule);
|
|
304
|
+
border-radius: 4px;
|
|
305
|
+
padding: 1px 6px;
|
|
306
|
+
color: var(--ink-soft);
|
|
307
|
+
white-space: nowrap;
|
|
308
|
+
}
|
|
309
|
+
.pill {
|
|
310
|
+
display: inline-block;
|
|
311
|
+
font-family: var(--sans);
|
|
312
|
+
font-size: 0.8em;
|
|
313
|
+
font-weight: 500;
|
|
314
|
+
background: var(--oat);
|
|
315
|
+
border-radius: 20px;
|
|
316
|
+
padding: 2px 10px;
|
|
317
|
+
color: var(--ink-soft);
|
|
318
|
+
white-space: nowrap;
|
|
319
|
+
}
|
|
320
|
+
.tag {
|
|
321
|
+
display: inline-block;
|
|
322
|
+
font-family: var(--mono);
|
|
323
|
+
font-size: 0.75em;
|
|
324
|
+
font-weight: 600;
|
|
325
|
+
background: var(--surface-2);
|
|
326
|
+
border: 1px solid var(--rule);
|
|
327
|
+
border-radius: 6px;
|
|
328
|
+
padding: 2px 8px;
|
|
329
|
+
color: var(--muted);
|
|
330
|
+
text-transform: lowercase;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
/* byline */
|
|
334
|
+
.byline {
|
|
335
|
+
border-top: 1.5px solid var(--rule);
|
|
336
|
+
margin-top: 64px;
|
|
337
|
+
padding-top: 18px;
|
|
338
|
+
font-family: var(--mono);
|
|
339
|
+
font-size: 0.75rem;
|
|
340
|
+
color: var(--muted);
|
|
341
|
+
display: flex;
|
|
342
|
+
flex-wrap: wrap;
|
|
343
|
+
gap: 1em;
|
|
344
|
+
align-items: center;
|
|
345
|
+
}
|
|
346
|
+
.byline a {
|
|
347
|
+
color: var(--muted);
|
|
348
|
+
}
|
|
349
|
+
</style>
|
|
350
|
+
</head>
|
|
351
|
+
<body>
|
|
352
|
+
<div class="page">
|
|
353
|
+
<!-- ============================================================
|
|
354
|
+
Section 1 · Header
|
|
355
|
+
============================================================ -->
|
|
356
|
+
<section>
|
|
357
|
+
<p class="eyebrow">Reference · cesium design system</p>
|
|
358
|
+
<h1 class="h-display">Design system</h1>
|
|
359
|
+
<div class="tldr">
|
|
360
|
+
<p>
|
|
361
|
+
Cesium provides a small vocabulary of HTML classes for producing beautiful,
|
|
362
|
+
self-contained artifact pages — plans, reviews, comparisons, reports, and explainers.
|
|
363
|
+
Every artifact is a single HTML file that requires no external resources: fonts, colors,
|
|
364
|
+
and layout are fully inlined. This reference page demonstrates every available class so
|
|
365
|
+
an agent can internalize the design language before writing a complex artifact.
|
|
366
|
+
</p>
|
|
367
|
+
</div>
|
|
368
|
+
</section>
|
|
369
|
+
|
|
370
|
+
<!-- ============================================================
|
|
371
|
+
Section 2 · Typography & Headings
|
|
372
|
+
============================================================ -->
|
|
373
|
+
<section>
|
|
374
|
+
<p class="eyebrow">02 · typography</p>
|
|
375
|
+
<h2 class="h-section"><span class="section-num">02</span>Typography & Headings</h2>
|
|
376
|
+
<p>
|
|
377
|
+
Use when you need to establish visual hierarchy. The display heading anchors the page;
|
|
378
|
+
section headings break the document into scannable chunks.
|
|
379
|
+
</p>
|
|
380
|
+
|
|
381
|
+
<h1 class="h-display">Display heading — the page title</h1>
|
|
382
|
+
<h2 class="h-section">Section heading — a major division</h2>
|
|
383
|
+
<p>
|
|
384
|
+
Body copy is set in the system sans-serif at 1rem/1.6. Use sparingly; prefer short
|
|
385
|
+
paragraphs with plenty of whitespace. Inline <code>code</code> renders in the monospace
|
|
386
|
+
stack at 0.9em.
|
|
387
|
+
</p>
|
|
388
|
+
<p>
|
|
389
|
+
Long-form explanatory text sits comfortably at this measure. Keep paragraphs to 3–5
|
|
390
|
+
sentences so readers can skim the first sentence of each block.
|
|
391
|
+
</p>
|
|
392
|
+
</section>
|
|
393
|
+
|
|
394
|
+
<!-- ============================================================
|
|
395
|
+
Section 3 · Eyebrow + Section numbering
|
|
396
|
+
============================================================ -->
|
|
397
|
+
<section>
|
|
398
|
+
<p class="eyebrow">03 · eyebrow & section-num</p>
|
|
399
|
+
<h2 class="h-section"><span class="section-num">03</span>Eyebrow + Section numbering</h2>
|
|
400
|
+
<p>
|
|
401
|
+
Use an <code>.eyebrow</code> above a section head to provide a micro-label — a category, a
|
|
402
|
+
step number, or a module name. Pair it with <code>.section-num</code> chips inside the
|
|
403
|
+
heading itself when you want the number visually attached to the title.
|
|
404
|
+
</p>
|
|
405
|
+
|
|
406
|
+
<div style="border-left: 3px solid var(--rule); padding-left: 1.25em; margin-bottom: 1em">
|
|
407
|
+
<p class="eyebrow">phase one · discovery</p>
|
|
408
|
+
<h2 class="h-section"><span class="section-num">01</span>Stakeholder interviews</h2>
|
|
409
|
+
<p>Map the landscape before writing a line of code.</p>
|
|
410
|
+
</div>
|
|
411
|
+
|
|
412
|
+
<div style="border-left: 3px solid var(--rule); padding-left: 1.25em">
|
|
413
|
+
<p class="eyebrow">phase two · design</p>
|
|
414
|
+
<h2 class="h-section"><span class="section-num">02</span>Information architecture</h2>
|
|
415
|
+
<p>Derive the navigation structure from task frequency, not org-chart hierarchy.</p>
|
|
416
|
+
</div>
|
|
417
|
+
</section>
|
|
418
|
+
|
|
419
|
+
<!-- ============================================================
|
|
420
|
+
Section 4 · Cards
|
|
421
|
+
============================================================ -->
|
|
422
|
+
<section>
|
|
423
|
+
<p class="eyebrow">04 · cards</p>
|
|
424
|
+
<h2 class="h-section"><span class="section-num">04</span>Cards</h2>
|
|
425
|
+
<p>
|
|
426
|
+
Use <code>.card</code> for any discrete, bordered surface — a finding, a recommendation, a
|
|
427
|
+
team member bio, or a feature description. Cards sit in a CSS grid for multi-column
|
|
428
|
+
layouts.
|
|
429
|
+
</p>
|
|
430
|
+
|
|
431
|
+
<div
|
|
432
|
+
style="
|
|
433
|
+
display: grid;
|
|
434
|
+
grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
|
|
435
|
+
gap: 1rem;
|
|
436
|
+
"
|
|
437
|
+
>
|
|
438
|
+
<div class="card">
|
|
439
|
+
<p class="eyebrow">finding 01</p>
|
|
440
|
+
<h3 style="font-family: var(--serif); margin-bottom: 0.4em">
|
|
441
|
+
Session timeout too short
|
|
442
|
+
</h3>
|
|
443
|
+
<p style="margin: 0">
|
|
444
|
+
Users are logged out mid-task. Extend the idle timeout from 15 to 30 minutes and add a
|
|
445
|
+
one-minute warning banner.
|
|
446
|
+
</p>
|
|
447
|
+
</div>
|
|
448
|
+
<div class="card">
|
|
449
|
+
<p class="eyebrow">finding 02</p>
|
|
450
|
+
<h3 style="font-family: var(--serif); margin-bottom: 0.4em">No mobile breakpoint</h3>
|
|
451
|
+
<p style="margin: 0">
|
|
452
|
+
The dashboard overflows on viewports narrower than 768 px. A responsive grid reflow
|
|
453
|
+
fixes the majority of complaints.
|
|
454
|
+
</p>
|
|
455
|
+
</div>
|
|
456
|
+
<div class="card">
|
|
457
|
+
<p class="eyebrow">finding 03</p>
|
|
458
|
+
<h3 style="font-family: var(--serif); margin-bottom: 0.4em">
|
|
459
|
+
Search latency p95 = 4.2 s
|
|
460
|
+
</h3>
|
|
461
|
+
<p style="margin: 0">
|
|
462
|
+
Full-text search scans the entire corpus on every keystroke. Add a debounce of 300 ms
|
|
463
|
+
and an n-gram index to bring p95 under 400 ms.
|
|
464
|
+
</p>
|
|
465
|
+
</div>
|
|
466
|
+
</div>
|
|
467
|
+
</section>
|
|
468
|
+
|
|
469
|
+
<!-- ============================================================
|
|
470
|
+
Section 5 · TLDR
|
|
471
|
+
============================================================ -->
|
|
472
|
+
<section>
|
|
473
|
+
<p class="eyebrow">05 · tldr</p>
|
|
474
|
+
<h2 class="h-section"><span class="section-num">05</span>TLDR</h2>
|
|
475
|
+
<p>
|
|
476
|
+
Use exactly <strong>one</strong> <code>.tldr</code> block per document, positioned near
|
|
477
|
+
the top. It is the executive summary — three to five sentences that give a busy reader
|
|
478
|
+
everything they need without reading the rest of the document.
|
|
479
|
+
</p>
|
|
480
|
+
|
|
481
|
+
<div class="tldr">
|
|
482
|
+
<p>
|
|
483
|
+
The authentication refactor is ready to ship. We replaced the legacy session cookie
|
|
484
|
+
approach with short-lived JWTs (15 min access, 7 day refresh) backed by a Redis token
|
|
485
|
+
store. All 142 existing auth tests pass; three new integration tests cover the refresh
|
|
486
|
+
flow. The breaking change is limited to the <code>/api/v1/auth</code> namespace — no
|
|
487
|
+
front-end changes required.
|
|
488
|
+
</p>
|
|
489
|
+
</div>
|
|
490
|
+
</section>
|
|
491
|
+
|
|
492
|
+
<!-- ============================================================
|
|
493
|
+
Section 6 · Callouts
|
|
494
|
+
============================================================ -->
|
|
495
|
+
<section>
|
|
496
|
+
<p class="eyebrow">06 · callouts</p>
|
|
497
|
+
<h2 class="h-section"><span class="section-num">06</span>Callouts</h2>
|
|
498
|
+
<p>
|
|
499
|
+
Use callouts to surface information that needs to be noticed but doesn't belong in running
|
|
500
|
+
prose. Three flavors: <code>.callout.note</code> for helpful context,
|
|
501
|
+
<code>.callout.warn</code> for things that can go wrong, and
|
|
502
|
+
<code>.callout.risk</code> for blocking or high-severity concerns.
|
|
503
|
+
</p>
|
|
504
|
+
|
|
505
|
+
<div class="callout note">
|
|
506
|
+
<strong>Note:</strong> The refresh token rotation strategy requires a Redis instance with
|
|
507
|
+
persistence enabled — an in-memory-only instance will cause silent logouts on server
|
|
508
|
+
restart.
|
|
509
|
+
</div>
|
|
510
|
+
<div class="callout warn">
|
|
511
|
+
<strong>Warning:</strong> Deploying this change to production before migrating the
|
|
512
|
+
existing session cookies will log out all active users simultaneously.
|
|
513
|
+
</div>
|
|
514
|
+
<div class="callout risk">
|
|
515
|
+
<strong>Risk:</strong> The token revocation list is stored only in Redis; a cache flush
|
|
516
|
+
between access-token expiry and refresh will allow briefly-revoked tokens to remain valid.
|
|
517
|
+
</div>
|
|
518
|
+
</section>
|
|
519
|
+
|
|
520
|
+
<!-- ============================================================
|
|
521
|
+
Section 7 · Code blocks
|
|
522
|
+
============================================================ -->
|
|
523
|
+
<section>
|
|
524
|
+
<p class="eyebrow">07 · code</p>
|
|
525
|
+
<h2 class="h-section"><span class="section-num">07</span>Code blocks</h2>
|
|
526
|
+
<p>
|
|
527
|
+
Use <code>.code</code> for multi-line code samples. Highlight tokens with nested spans:
|
|
528
|
+
<code>.kw</code> for keywords, <code>.str</code> for string literals, <code>.cm</code> for
|
|
529
|
+
comments, and <code>.fn</code> for function names. Inline <code>code</code> elements in
|
|
530
|
+
body copy use the browser default monospace style.
|
|
531
|
+
</p>
|
|
532
|
+
|
|
533
|
+
<div class="code">
|
|
534
|
+
<span class="cm">// Refresh an access token using the stored refresh token.</span>
|
|
535
|
+
<span class="kw">export</span> <span class="kw">async function</span>
|
|
536
|
+
<span class="fn">refreshAccessToken</span>( refreshToken: <span class="kw">string</span>,
|
|
537
|
+
): <span class="kw">Promise</span><{ accessToken: <span class="kw">string</span> }>
|
|
538
|
+
{ <span class="kw">const</span> payload = <span class="kw">await</span>
|
|
539
|
+
<span class="fn">verifyRefreshToken</span>(refreshToken);
|
|
540
|
+
<span class="kw">if</span> (!payload) { <span class="kw">throw new</span>
|
|
541
|
+
<span class="fn">Error</span>(<span class="str">"invalid or expired refresh token"</span
|
|
542
|
+
>); } <span class="kw">const</span> accessToken = <span class="kw">await</span>
|
|
543
|
+
<span class="fn">signAccessToken</span>({ sub: payload.sub, scope: payload.scope, });
|
|
544
|
+
<span class="kw">return</span> { accessToken }; }
|
|
545
|
+
</div>
|
|
546
|
+
|
|
547
|
+
<p>
|
|
548
|
+
Inline usage: press <code>⌘ S</code> to save, or call
|
|
549
|
+
<code>refreshAccessToken(token)</code> directly from the REPL.
|
|
550
|
+
</p>
|
|
551
|
+
</section>
|
|
552
|
+
|
|
553
|
+
<!-- ============================================================
|
|
554
|
+
Section 8 · Timeline
|
|
555
|
+
============================================================ -->
|
|
556
|
+
<section>
|
|
557
|
+
<p class="eyebrow">08 · timeline</p>
|
|
558
|
+
<h2 class="h-section"><span class="section-num">08</span>Timeline</h2>
|
|
559
|
+
<p>
|
|
560
|
+
Use <code>.timeline</code> for ordered milestones, release schedules, or onboarding
|
|
561
|
+
sequences. Each <code><li></code> gets a dot and a vertical connector automatically
|
|
562
|
+
via CSS.
|
|
563
|
+
</p>
|
|
564
|
+
|
|
565
|
+
<ul class="timeline">
|
|
566
|
+
<li>
|
|
567
|
+
<strong>Week 1 — Audit & planning</strong>
|
|
568
|
+
<p style="margin: 0.25em 0 0">
|
|
569
|
+
Review existing auth code, identify all call sites, write migration checklist.
|
|
570
|
+
Deliverable: annotated codebase + go/no-go criteria.
|
|
571
|
+
</p>
|
|
572
|
+
</li>
|
|
573
|
+
<li>
|
|
574
|
+
<strong>Week 2–3 — Implementation</strong>
|
|
575
|
+
<p style="margin: 0.25em 0 0">
|
|
576
|
+
Build JWT signing, Redis token store, refresh rotation, and revocation list.
|
|
577
|
+
Feature-flagged behind <code>AUTH_V2</code>.
|
|
578
|
+
</p>
|
|
579
|
+
</li>
|
|
580
|
+
<li>
|
|
581
|
+
<strong>Week 4 — Hardening & rollout</strong>
|
|
582
|
+
<p style="margin: 0.25em 0 0">
|
|
583
|
+
Load test at 3× peak traffic, canary 10% of prod, monitor error rates for 48 h, then
|
|
584
|
+
full cutover.
|
|
585
|
+
</p>
|
|
586
|
+
</li>
|
|
587
|
+
</ul>
|
|
588
|
+
</section>
|
|
589
|
+
|
|
590
|
+
<!-- ============================================================
|
|
591
|
+
Section 9 · Diagram
|
|
592
|
+
============================================================ -->
|
|
593
|
+
<section>
|
|
594
|
+
<p class="eyebrow">09 · diagram</p>
|
|
595
|
+
<h2 class="h-section"><span class="section-num">09</span>Diagram</h2>
|
|
596
|
+
<p>
|
|
597
|
+
Use <code>.diagram</code> wrapping an inline <code><svg></code> for architecture
|
|
598
|
+
diagrams, flow charts, and data-flow illustrations. Include a
|
|
599
|
+
<code><figcaption></code> below the SVG for a brief description.
|
|
600
|
+
</p>
|
|
601
|
+
|
|
602
|
+
<figure class="diagram">
|
|
603
|
+
<svg
|
|
604
|
+
viewBox="0 0 480 120"
|
|
605
|
+
width="480"
|
|
606
|
+
height="120"
|
|
607
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
608
|
+
style="font-family: ui-monospace, monospace; max-width: 100%"
|
|
609
|
+
>
|
|
610
|
+
<!-- Client box -->
|
|
611
|
+
<rect
|
|
612
|
+
x="10"
|
|
613
|
+
y="35"
|
|
614
|
+
width="110"
|
|
615
|
+
height="50"
|
|
616
|
+
rx="8"
|
|
617
|
+
ry="8"
|
|
618
|
+
fill="#FFFFFF"
|
|
619
|
+
stroke="#D1CFC5"
|
|
620
|
+
stroke-width="1.5"
|
|
621
|
+
/>
|
|
622
|
+
<text
|
|
623
|
+
x="65"
|
|
624
|
+
y="57"
|
|
625
|
+
text-anchor="middle"
|
|
626
|
+
font-size="11"
|
|
627
|
+
fill="#141413"
|
|
628
|
+
font-weight="600"
|
|
629
|
+
>
|
|
630
|
+
Client
|
|
631
|
+
</text>
|
|
632
|
+
<text x="65" y="72" text-anchor="middle" font-size="9" fill="#87867F">
|
|
633
|
+
browser / app
|
|
634
|
+
</text>
|
|
635
|
+
|
|
636
|
+
<!-- Arrow 1 -->
|
|
637
|
+
<line
|
|
638
|
+
x1="120"
|
|
639
|
+
y1="60"
|
|
640
|
+
x2="178"
|
|
641
|
+
y2="60"
|
|
642
|
+
stroke="#D1CFC5"
|
|
643
|
+
stroke-width="1.5"
|
|
644
|
+
marker-end="url(#arrow)"
|
|
645
|
+
/>
|
|
646
|
+
<text x="149" y="54" text-anchor="middle" font-size="9" fill="#87867F">JWT</text>
|
|
647
|
+
|
|
648
|
+
<!-- API Gateway box -->
|
|
649
|
+
<rect
|
|
650
|
+
x="180"
|
|
651
|
+
y="35"
|
|
652
|
+
width="120"
|
|
653
|
+
height="50"
|
|
654
|
+
rx="8"
|
|
655
|
+
ry="8"
|
|
656
|
+
fill="#FFFFFF"
|
|
657
|
+
stroke="#D97757"
|
|
658
|
+
stroke-width="1.5"
|
|
659
|
+
/>
|
|
660
|
+
<text
|
|
661
|
+
x="240"
|
|
662
|
+
y="57"
|
|
663
|
+
text-anchor="middle"
|
|
664
|
+
font-size="11"
|
|
665
|
+
fill="#141413"
|
|
666
|
+
font-weight="600"
|
|
667
|
+
>
|
|
668
|
+
API Gateway
|
|
669
|
+
</text>
|
|
670
|
+
<text x="240" y="72" text-anchor="middle" font-size="9" fill="#87867F">
|
|
671
|
+
verify + route
|
|
672
|
+
</text>
|
|
673
|
+
|
|
674
|
+
<!-- Arrow 2 -->
|
|
675
|
+
<line
|
|
676
|
+
x1="300"
|
|
677
|
+
y1="60"
|
|
678
|
+
x2="358"
|
|
679
|
+
y2="60"
|
|
680
|
+
stroke="#D1CFC5"
|
|
681
|
+
stroke-width="1.5"
|
|
682
|
+
marker-end="url(#arrow)"
|
|
683
|
+
/>
|
|
684
|
+
<text x="329" y="54" text-anchor="middle" font-size="9" fill="#87867F">claims</text>
|
|
685
|
+
|
|
686
|
+
<!-- Service box -->
|
|
687
|
+
<rect
|
|
688
|
+
x="360"
|
|
689
|
+
y="35"
|
|
690
|
+
width="110"
|
|
691
|
+
height="50"
|
|
692
|
+
rx="8"
|
|
693
|
+
ry="8"
|
|
694
|
+
fill="#FFFFFF"
|
|
695
|
+
stroke="#D1CFC5"
|
|
696
|
+
stroke-width="1.5"
|
|
697
|
+
/>
|
|
698
|
+
<text
|
|
699
|
+
x="415"
|
|
700
|
+
y="57"
|
|
701
|
+
text-anchor="middle"
|
|
702
|
+
font-size="11"
|
|
703
|
+
fill="#141413"
|
|
704
|
+
font-weight="600"
|
|
705
|
+
>
|
|
706
|
+
Service
|
|
707
|
+
</text>
|
|
708
|
+
<text x="415" y="72" text-anchor="middle" font-size="9" fill="#87867F">
|
|
709
|
+
business logic
|
|
710
|
+
</text>
|
|
711
|
+
|
|
712
|
+
<!-- Arrowhead marker -->
|
|
713
|
+
<defs>
|
|
714
|
+
<marker id="arrow" markerWidth="8" markerHeight="8" refX="6" refY="3" orient="auto">
|
|
715
|
+
<path d="M0,0 L0,6 L8,3 z" fill="#D1CFC5" />
|
|
716
|
+
</marker>
|
|
717
|
+
</defs>
|
|
718
|
+
</svg>
|
|
719
|
+
<figcaption>
|
|
720
|
+
JWT flows from the client through the API Gateway (which verifies the signature and
|
|
721
|
+
extracts claims) to the downstream service.
|
|
722
|
+
</figcaption>
|
|
723
|
+
</figure>
|
|
724
|
+
</section>
|
|
725
|
+
|
|
726
|
+
<!-- ============================================================
|
|
727
|
+
Section 10 · Compare table
|
|
728
|
+
============================================================ -->
|
|
729
|
+
<section>
|
|
730
|
+
<p class="eyebrow">10 · compare-table</p>
|
|
731
|
+
<h2 class="h-section"><span class="section-num">10</span>Compare table</h2>
|
|
732
|
+
<p>
|
|
733
|
+
Use <code>.compare-table</code> when presenting a decision matrix or feature comparison
|
|
734
|
+
across two or more options. Keep columns to three or fewer for readability on narrow
|
|
735
|
+
viewports.
|
|
736
|
+
</p>
|
|
737
|
+
|
|
738
|
+
<table class="compare-table">
|
|
739
|
+
<thead>
|
|
740
|
+
<tr>
|
|
741
|
+
<th>Approach</th>
|
|
742
|
+
<th>Complexity</th>
|
|
743
|
+
<th>Operational cost</th>
|
|
744
|
+
</tr>
|
|
745
|
+
</thead>
|
|
746
|
+
<tbody>
|
|
747
|
+
<tr>
|
|
748
|
+
<td>Session cookies + DB</td>
|
|
749
|
+
<td>Low — well-understood pattern, many libraries</td>
|
|
750
|
+
<td>Requires sticky sessions or a shared session store</td>
|
|
751
|
+
</tr>
|
|
752
|
+
<tr>
|
|
753
|
+
<td>JWT (stateless)</td>
|
|
754
|
+
<td>Medium — signing, rotation, and revocation add surface area</td>
|
|
755
|
+
<td>No server-side state; tokens carry their own claims</td>
|
|
756
|
+
</tr>
|
|
757
|
+
<tr>
|
|
758
|
+
<td>JWT + Redis revocation</td>
|
|
759
|
+
<td>Medium-high — Redis dependency, invalidation logic</td>
|
|
760
|
+
<td>Adds Redis infra; enables immediate revocation unlike pure JWT</td>
|
|
761
|
+
</tr>
|
|
762
|
+
</tbody>
|
|
763
|
+
</table>
|
|
764
|
+
</section>
|
|
765
|
+
|
|
766
|
+
<!-- ============================================================
|
|
767
|
+
Section 11 · Risk table
|
|
768
|
+
============================================================ -->
|
|
769
|
+
<section>
|
|
770
|
+
<p class="eyebrow">11 · risk-table</p>
|
|
771
|
+
<h2 class="h-section"><span class="section-num">11</span>Risk table</h2>
|
|
772
|
+
<p>
|
|
773
|
+
Use <code>.risk-table</code> for structured risk registers — likelihood, impact, and
|
|
774
|
+
mitigation. Use <code>.pill</code> chips inside cells to tag severity levels at a glance.
|
|
775
|
+
</p>
|
|
776
|
+
|
|
777
|
+
<table class="risk-table">
|
|
778
|
+
<thead>
|
|
779
|
+
<tr>
|
|
780
|
+
<th>Risk</th>
|
|
781
|
+
<th>Likelihood · Impact</th>
|
|
782
|
+
<th>Mitigation</th>
|
|
783
|
+
</tr>
|
|
784
|
+
</thead>
|
|
785
|
+
<tbody>
|
|
786
|
+
<tr>
|
|
787
|
+
<td>Redis unavailable at token refresh time</td>
|
|
788
|
+
<td><span class="pill">Medium</span> · <span class="pill">High</span></td>
|
|
789
|
+
<td>
|
|
790
|
+
Circuit-break to read-only mode; allow access tokens to coast until Redis recovers
|
|
791
|
+
(max 15 min gap).
|
|
792
|
+
</td>
|
|
793
|
+
</tr>
|
|
794
|
+
<tr>
|
|
795
|
+
<td>Private key leaked in environment variable</td>
|
|
796
|
+
<td><span class="pill">Low</span> · <span class="pill">Critical</span></td>
|
|
797
|
+
<td>
|
|
798
|
+
Store key in a secrets manager (Vault / AWS Secrets Manager); rotate on any
|
|
799
|
+
suspected exposure; never log the key.
|
|
800
|
+
</td>
|
|
801
|
+
</tr>
|
|
802
|
+
<tr>
|
|
803
|
+
<td>Clock skew causes spurious token rejection</td>
|
|
804
|
+
<td><span class="pill">Medium</span> · <span class="pill">Medium</span></td>
|
|
805
|
+
<td>
|
|
806
|
+
Allow a 30-second leeway window in the JWT library; add NTP monitoring to all nodes.
|
|
807
|
+
</td>
|
|
808
|
+
</tr>
|
|
809
|
+
</tbody>
|
|
810
|
+
</table>
|
|
811
|
+
</section>
|
|
812
|
+
|
|
813
|
+
<!-- ============================================================
|
|
814
|
+
Section 12 · Inline chips
|
|
815
|
+
============================================================ -->
|
|
816
|
+
<section>
|
|
817
|
+
<p class="eyebrow">12 · inline chips</p>
|
|
818
|
+
<h2 class="h-section"><span class="section-num">12</span>Inline chips</h2>
|
|
819
|
+
<p>
|
|
820
|
+
Three chip types for inline metadata and labeling. Use them sparingly so they retain
|
|
821
|
+
visual contrast against body copy.
|
|
822
|
+
</p>
|
|
823
|
+
|
|
824
|
+
<div class="card">
|
|
825
|
+
<p style="margin-bottom: 0.75em">
|
|
826
|
+
<strong>.kbd</strong> — keyboard shortcuts and command tokens:<br />
|
|
827
|
+
Press <span class="kbd">⌘K</span> to open the command palette,
|
|
828
|
+
<span class="kbd">⌘⇧P</span> for the command runner, or <span class="kbd">Esc</span> to
|
|
829
|
+
dismiss any modal.
|
|
830
|
+
</p>
|
|
831
|
+
<p style="margin-bottom: 0.75em">
|
|
832
|
+
<strong>.pill</strong> — rounded status or severity labels:<br />
|
|
833
|
+
<span class="pill">v2.4.1</span>
|
|
834
|
+
<span class="pill">stable</span>
|
|
835
|
+
<span class="pill">High</span>
|
|
836
|
+
<span class="pill">In progress</span>
|
|
837
|
+
</p>
|
|
838
|
+
<p style="margin: 0">
|
|
839
|
+
<strong>.tag</strong> — lowercase monospace category tags:<br />
|
|
840
|
+
<span class="tag">auth</span>
|
|
841
|
+
<span class="tag">security</span>
|
|
842
|
+
<span class="tag">breaking-change</span>
|
|
843
|
+
<span class="tag">performance</span>
|
|
844
|
+
</p>
|
|
845
|
+
</div>
|
|
846
|
+
</section>
|
|
847
|
+
|
|
848
|
+
<!-- ============================================================
|
|
849
|
+
Footer / byline
|
|
850
|
+
============================================================ -->
|
|
851
|
+
<footer class="byline">
|
|
852
|
+
<span>cesium design system reference</span>
|
|
853
|
+
<span>version: 0.0.0</span>
|
|
854
|
+
</footer>
|
|
855
|
+
</div>
|
|
856
|
+
</body>
|
|
857
|
+
</html>
|