@kurtbruns/kestrel 1.13.0 → 1.15.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.
Files changed (45) hide show
  1. package/CHANGELOG.md +44 -1
  2. package/README.md +2 -2
  3. package/bin/kestrel.mjs +21 -2
  4. package/cli/dev.mjs +6 -2
  5. package/cli/init.mjs +2 -1
  6. package/cli/reset.mjs +1 -1
  7. package/cli/seed.mjs +3 -3
  8. package/dist/public/dashboard/app.js +290 -285
  9. package/dist/public/dashboard/app.js.map +4 -4
  10. package/dist/public/dashboard/index.html +2 -2
  11. package/dist/public/dashboard/styles.css +74 -40
  12. package/dist/worker/index.js +2723 -1192
  13. package/docs/README.md +3 -2
  14. package/docs/get-started/02-deploy.md +18 -21
  15. package/docs/get-started/03-access.md +10 -8
  16. package/docs/get-started/06-go-live.md +2 -1
  17. package/docs/guides/01-allow-claude.md +68 -0
  18. package/docs/guides/02-automate.md +88 -0
  19. package/docs/guides/09-as-your-list-grows.md +2 -2
  20. package/docs/publishing/01-your-list.md +3 -3
  21. package/docs/publishing/03-name-your-publication.md +1 -1
  22. package/docs/publishing/04-write-a-post.md +15 -52
  23. package/docs/publishing/06-troubleshooting.md +20 -9
  24. package/docs/publishing/08-connect-claude.md +60 -0
  25. package/docs/publishing/09-share-your-subscribe-link.md +1 -1
  26. package/docs/publishing/10-check-your-setup.md +9 -16
  27. package/docs/publishing/11-email-template.md +1 -1
  28. package/docs/publishing/README.md +2 -2
  29. package/docs/reference/01-configuration.md +132 -85
  30. package/docs/reference/02-sending-domain-dns.md +2 -2
  31. package/migrations/0013_who_acted_client.sql +20 -0
  32. package/migrations/0014_send_acts.sql +25 -0
  33. package/package.json +2 -1
  34. package/packages/kestrel/lib/api.mjs +462 -0
  35. package/packages/kestrel/lib/credentials.mjs +192 -0
  36. package/{cli → packages/kestrel/lib}/dev-api.mjs +21 -11
  37. package/{cli → packages/kestrel/lib}/dev-server.mjs +2 -2
  38. package/packages/kestrel/lib/handoff.mjs +118 -0
  39. package/packages/kestrel/lib/login.mjs +155 -0
  40. package/packages/kestrel/lib/oauth.mjs +368 -0
  41. package/packages/kestrel/lib/openapi.mjs +569 -0
  42. package/template/README.md +2 -0
  43. package/template/claude/CLAUDE.md +8 -5
  44. package/docs/guides/01-connect-claude.md +0 -101
  45. package/docs/publishing/07-working-with-claude.md +0 -29
@@ -5,7 +5,7 @@
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1">
6
6
  <title>Kestrel</title>
7
7
  <link rel="icon" href="/favicon.svg">
8
- <link rel="stylesheet" href="./styles.css?v=7f1a9a46">
8
+ <link rel="stylesheet" href="./styles.css?v=2dbe22b0">
9
9
  <script>
10
10
  // Sidebar mode guard — set the width-based data-nav on <html> before first paint so the
11
11
  // sidebar renders in its final width with no flash. The collapse toggle's override is
@@ -113,6 +113,6 @@
113
113
  </section>
114
114
  <div id="toasts" role="status" aria-live="polite"></div>
115
115
 
116
- <script src="./app.js?v=1aa2dbe5"></script>
116
+ <script src="./app.js?v=67e17b89"></script>
117
117
  </body>
118
118
  </html>
@@ -88,6 +88,9 @@
88
88
  /* Code surface — inline `code` chip and the fenced-block band. A hair off the editor well
89
89
  (--syntax-bg), lighter than the neutral --chip, so code reads as code without a heavy box. */
90
90
  --syntax-code-bg: #f2f2f4;
91
+ /* A doc's inline `code`: a maroon ink on the --chip surface, so a name in a sentence reads
92
+ apart from the prose around it and from a link's blue. */
93
+ --code-inline-fg: #9b2c2c;
91
94
  /* HTTP method badges in the API reference (DESIGN §8). A self-contained palette like
92
95
  --syntax-*: verb colors are a naming convention, not feedback or lifecycle, so they
93
96
  borrow no semantic scale. The badge tints each over a wash of itself (.api-method). */
@@ -161,6 +164,7 @@
161
164
  --syntax-emphasis: #f472b6;
162
165
  --syntax-quote: #f0a86a;
163
166
  --syntax-code-bg: #26262b;
167
+ --code-inline-fg: #f07a7a;
164
168
  --method-get: #4ade80;
165
169
  --method-post: #60a5fa;
166
170
  --method-put: #fbbf24;
@@ -2202,6 +2206,10 @@ body.web-mode .content {
2202
2206
  gap: 8px;
2203
2207
  flex-wrap: wrap;
2204
2208
  }
2209
+ /* Who acted on the send, a line under when it was sent (SPEC §11). */
2210
+ .rec-by {
2211
+ margin-top: 2px;
2212
+ }
2205
2213
  /* Names the living layer of the record: the outcome tiles below keep moving as receipts
2206
2214
  arrive, while the audience at fire and the published post are fixed (SPEC §8). */
2207
2215
  .rec-tiles-cap {
@@ -2928,6 +2936,14 @@ body.web-mode .content {
2928
2936
  each state too, so the cue survives a reader who can't tell the dot's color. The
2929
2937
  "unsaved" cue reads the same amber as the shared save bar so both save models feel
2930
2938
  like one app. :empty (locked posts, which can't autosave) collapses it out. */
2939
+ /* A scheduled send never tested, said quietly beside the control that settles it (SPEC §8). */
2940
+ .test-hint {
2941
+ font-size: 13px;
2942
+ color: var(--muted);
2943
+ }
2944
+ .test-row {
2945
+ gap: 1rem;
2946
+ }
2931
2947
  .save-status {
2932
2948
  display: inline-flex;
2933
2949
  align-items: center;
@@ -3455,6 +3471,13 @@ textarea.is-invalid {
3455
3471
  font-size: 12.5px;
3456
3472
  color: var(--status-scheduled-fg);
3457
3473
  }
3474
+ /* Who scheduled the send and who last moved it (SPEC §11), under the time, in the banner's
3475
+ violet: a fact about the send, not a note asking for a look. */
3476
+ .sched-by {
3477
+ margin-top: 4px;
3478
+ font-size: 12.5px;
3479
+ color: var(--status-scheduled-fg);
3480
+ }
3458
3481
  /* The Email only box under a dialog's time: the label, then its helper beneath. */
3459
3482
  .listing-check {
3460
3483
  display: flex;
@@ -3909,52 +3932,28 @@ textarea.is-invalid {
3909
3932
  .doc code {
3910
3933
  font-family: var(--mono);
3911
3934
  font-size: 13px;
3912
- background: var(--bg);
3935
+ color: var(--code-inline-fg);
3936
+ background: var(--chip);
3913
3937
  border: 1px solid var(--line);
3914
3938
  border-radius: 4px;
3915
3939
  padding: 1px 5px;
3916
3940
  }
3917
- .doc pre {
3918
- position: relative;
3919
- background: var(--bg);
3920
- border: 1px solid var(--line);
3921
- border-radius: 8px;
3922
- padding: 14px 16px;
3923
- overflow-x: auto;
3924
- line-height: 1.5;
3941
+ /* Bold in a doc sits between semibold and bold, the weight of its headings: the browser's
3942
+ `bolder` makes it 700, which outweighs the headings (650) on the system font. */
3943
+ .doc strong {
3944
+ font-weight: 650;
3925
3945
  }
3946
+ /* Code in a bold lead-in keeps its own weight: the chip already sets it apart. */
3947
+ .doc strong code {
3948
+ font-weight: normal;
3949
+ }
3950
+ /* The inline-code chip above stays off the code in a block. */
3926
3951
  .doc pre code {
3952
+ color: inherit;
3927
3953
  background: none;
3928
3954
  border: 0;
3929
3955
  padding: 0;
3930
- }
3931
- /* Copy button on code blocks — revealed on hover (always shown on touch). */
3932
- .code-copy {
3933
- position: absolute;
3934
- top: 8px;
3935
- right: 8px;
3936
- font: 11px var(--mono);
3937
- padding: 3px 8px;
3938
- border: 1px solid var(--line);
3939
- border-radius: 5px;
3940
- background: var(--card);
3941
- color: var(--muted);
3942
- cursor: pointer;
3943
- opacity: 0;
3944
- transition: opacity 0.12s;
3945
- }
3946
- .doc pre:hover .code-copy,
3947
- .code-copy:focus-visible {
3948
- opacity: 1;
3949
- }
3950
- .code-copy:hover {
3951
- color: var(--fg);
3952
- border-color: var(--muted);
3953
- }
3954
- @media (hover: none) {
3955
- .code-copy {
3956
- opacity: 1;
3957
- }
3956
+ font-size: inherit;
3958
3957
  }
3959
3958
  /* Previous / Next pager at the foot of a doc — the sequential path, with titles. Two
3960
3959
  bordered cards; a missing neighbour keeps its side empty so the lone card stays put. */
@@ -4348,9 +4347,7 @@ a.api-self:focus-visible svg {
4348
4347
  button.copy-btn.api-copy-path {
4349
4348
  padding: 3px 5px;
4350
4349
  }
4351
- button.copy-btn.api-copy-path span:empty {
4352
- display: none;
4353
- }
4350
+
4354
4351
  .api-op-body {
4355
4352
  display: grid;
4356
4353
  gap: 4px 28px;
@@ -4926,6 +4923,10 @@ button.copy-btn:hover {
4926
4923
  button.copy-btn:active {
4927
4924
  transform: none;
4928
4925
  }
4926
+ /* A Copy that is its glyph alone (no word) takes no gap for the word. */
4927
+ button.copy-btn span:empty {
4928
+ display: none;
4929
+ }
4929
4930
  button.copy-btn svg {
4930
4931
  width: 14px;
4931
4932
  height: 14px;
@@ -4953,6 +4954,39 @@ button.copied svg {
4953
4954
  padding: 4px 6px 4px 12px;
4954
4955
  border-bottom: 1px solid var(--line);
4955
4956
  }
4957
+ /* A bare code block (a doc's): the same raised card with no label line, the code beside a
4958
+ Copy that is its glyph alone, level with the first line, so a one-line command reads as
4959
+ one quiet row. */
4960
+ .code-bare {
4961
+ display: flex;
4962
+ align-items: flex-start;
4963
+ gap: 8px;
4964
+ background: var(--card);
4965
+ border: 1px solid var(--line);
4966
+ border-radius: 8px;
4967
+ padding: 0 6px 0 0;
4968
+ }
4969
+ .code-bare pre {
4970
+ flex: 1;
4971
+ min-width: 0;
4972
+ margin: 0;
4973
+ overflow-x: auto;
4974
+ padding: 11px 0 11px 14px;
4975
+ font: 13px / 1.5 var(--mono);
4976
+ }
4977
+ .code-bare > button.copy-btn {
4978
+ flex: none;
4979
+ margin-top: 8px;
4980
+ padding: 5px;
4981
+ }
4982
+ .code-bare > button.copy-btn svg {
4983
+ width: 16px;
4984
+ height: 16px;
4985
+ }
4986
+ /* A doc's code block is spaced like a paragraph. */
4987
+ .doc .code-bare {
4988
+ margin: 14px 0;
4989
+ }
4956
4990
  .code-block pre {
4957
4991
  margin: 0;
4958
4992
  overflow-x: auto;