@invisibleloop/pulse 0.1.35 → 0.1.37

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.
@@ -8,10 +8,12 @@ jobs:
8
8
  release:
9
9
  runs-on: ubuntu-latest
10
10
  permissions:
11
- contents: read
11
+ contents: write
12
12
  id-token: write
13
13
  steps:
14
14
  - uses: actions/checkout@v4
15
+ with:
16
+ token: ${{ secrets.RELEASE_PAT }}
15
17
 
16
18
  - uses: actions/setup-node@v4
17
19
  with:
@@ -31,6 +33,11 @@ jobs:
31
33
  while npm view @invisibleloop/pulse@$VERSION version 2>/dev/null | grep -q .; do
32
34
  VERSION=$(node -e "const [a,b,c]='$VERSION'.split('.').map(Number);console.log(a+'.'+b+'.'+(c+1))")
33
35
  done
34
- npm version $VERSION --no-git-tag-version
36
+ npm version $VERSION --no-git-tag-version --allow-same-version
35
37
  echo "$VERSION" > public/.pulse-ui-version
38
+ git config user.name "github-actions[bot]"
39
+ git config user.email "github-actions[bot]@users.noreply.github.com"
40
+ git add package.json package-lock.json public/.pulse-ui-version
41
+ git commit -m "chore: release $VERSION [skip ci]" || true
42
+ git push
36
43
  npm publish --provenance --access public
@@ -1,5 +1,21 @@
1
1
  /* Pulse Documentation — Design System */
2
2
 
3
+ .skip-link {
4
+ position: absolute;
5
+ top: -100%;
6
+ left: 1rem;
7
+ padding: .5rem 1rem;
8
+ background: var(--accent);
9
+ color: var(--accent-text);
10
+ font-weight: 600;
11
+ border-radius: 0 0 .375rem .375rem;
12
+ text-decoration: none;
13
+ z-index: 9999;
14
+ }
15
+ .skip-link:focus {
16
+ top: 0;
17
+ }
18
+
3
19
  *,
4
20
  *::before,
5
21
  *::after {
@@ -16,7 +32,7 @@
16
32
  --border: #38383f;
17
33
  --border-subtle: #1a1a20;
18
34
  --text: #e2e2ea;
19
- --muted: #9090a0;
35
+ --muted: ##3d3d38;
20
36
  --muted-2: #7e7e92;
21
37
  --accent: #c9b800;
22
38
  --accent-text: #0a0a0a;
@@ -171,7 +187,7 @@ a:hover {
171
187
  font-size: 0.95rem;
172
188
  font-weight: 500;
173
189
  color: #0a0a0a;
174
- opacity: 0.55;
190
+ opacity: 0.7;
175
191
  margin-bottom: 1rem;
176
192
  letter-spacing: 0.01em;
177
193
  }
@@ -189,7 +205,6 @@ a:hover {
189
205
  padding: 0.3rem 0.85rem;
190
206
  margin-bottom: 2rem;
191
207
  letter-spacing: 0.06em;
192
- text-transform: uppercase;
193
208
  }
194
209
 
195
210
  .hero h1 {
@@ -470,7 +485,6 @@ a:hover {
470
485
  line-height: 1.65;
471
486
  }
472
487
 
473
-
474
488
  /* ─── FAQ page ───────────────────────────────────────────────────────────────── */
475
489
  .faq-item {
476
490
  padding: 2rem 0;
@@ -571,6 +585,7 @@ a:hover {
571
585
  height: 2.5rem;
572
586
  background: #f0e642;
573
587
  flex-shrink: 0;
588
+ opacity: 0.3;
574
589
  }
575
590
 
576
591
  /* ─── How it works — black band ─────────────────────────────────────────────── */
@@ -653,6 +668,7 @@ a:hover {
653
668
  background: #f0e642;
654
669
  margin-top: 1.25rem;
655
670
  flex-shrink: 0;
671
+ opacity: 0.3;
656
672
  }
657
673
 
658
674
  /* ─── AI-first section ───────────────────────────────────────────────────────── */
@@ -63,6 +63,7 @@ function prevNextBar(prev, next) {
63
63
 
64
64
  export function renderLayout({ currentHref, content, prev = null, next = null }) {
65
65
  return `
66
+ <a href="#main-content" class="skip-link">Skip to main content</a>
66
67
  <div class="sidebar-overlay" aria-hidden="true"></div>
67
68
  ${sidebar(currentHref)}
68
69
  <div class="docs-main">
@@ -77,14 +78,14 @@ export function renderLayout({ currentHref, content, prev = null, next = null })
77
78
  <path d="M13 2L4.5 13.5H11L10 22L19.5 10.5H13L13 2Z" fill="var(--accent)" stroke="var(--accent)" stroke-width="1" stroke-linejoin="round"/>
78
79
  </svg>
79
80
  </a>
80
- <a href="https://github.com/invisibleloop/pulse-framework" class="header-github" aria-label="View on GitHub" target="_blank" rel="noopener noreferrer">
81
+ <a href="https://github.com/invisibleloop/pulse-framework" class="header-github" aria-label="View on GitHub (opens in new tab)" target="_blank" rel="noopener noreferrer">
81
82
  <svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
82
83
  <path d="M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z"/>
83
84
  </svg>
84
85
  GitHub
85
86
  </a>
86
87
  </header>
87
- <main class="docs-content">
88
+ <main class="docs-content" id="main-content">
88
89
  ${content}
89
90
  ${prevNextBar(prev, next)}
90
91
  </main>
@@ -119,12 +120,13 @@ export function codeBlock(highlighted, filename = '') {
119
120
  return `${header}<pre class="code-block"><code>${highlighted}</code></pre>`
120
121
  }
121
122
 
122
- export function table(headers, rows) {
123
+ export function table(headers, rows, caption = '') {
124
+ const cap = caption ? `<caption>${esc(caption)}</caption>` : ''
123
125
  const ths = headers.map(h => `<th scope="col">${h}</th>`).join('')
124
126
  const trs = rows.map(row =>
125
127
  `<tr>${row.map(cell => `<td>${cell}</td>`).join('')}</tr>`
126
128
  ).join('')
127
- return `<div class="table-wrap"><table><thead><tr>${ths}</tr></thead><tbody>${trs}</tbody></table></div>`
129
+ return `<div class="table-wrap"><table>${cap}<thead><tr>${ths}</tr></thead><tbody>${trs}</tbody></table></div>`
128
130
  }
129
131
 
130
132
  export function callout(type, content) {
@@ -156,7 +156,7 @@ onError: (state, err) => ({
156
156
  }),`, 'js'))}
157
157
  <p><code>_toast</code> works in <code>onStart</code>, <code>onSuccess</code>, and <code>onError</code>, and also in mutations. The toast container is injected into <code>document.body</code> once and survives client-side navigations.</p>
158
158
  ${table(
159
- ['Option', 'Type', 'Default', ''],
159
+ ['Option', 'Type', 'Default', 'Description'],
160
160
  [
161
161
  ['<code>message</code>', 'string', '—', 'Required. The notification text.'],
162
162
  ['<code>variant</code>', '<code>success | error | warning | info</code>', '<code>info</code>', ''],
@@ -45,7 +45,7 @@ export default {
45
45
 
46
46
  ${section('vs-validation', 'Constraints vs Validation')}
47
47
  ${table(
48
- ['', 'Constraints', 'Validation'],
48
+ ['Aspect', 'Constraints', 'Validation'],
49
49
  [
50
50
  ['When it runs', 'After <strong>every</strong> mutation, automatically', 'Only when an action has <code>validate: true</code>'],
51
51
  ['What it does', 'Clamps numeric values silently', 'Rejects the action and surfaces errors'],
@@ -22,8 +22,8 @@ export default {
22
22
 
23
23
  ${section('requirements', 'Requirements')}
24
24
  <ul>
25
- <li><strong>Node.js 22 or later</strong> — <a href="https://nodejs.org" target="_blank" rel="noopener">nodejs.org</a></li>
26
- <li><strong>Claude Code</strong> — the CLI for Claude, installed and authenticated — <a href="https://docs.anthropic.com/en/docs/claude-code/getting-started" target="_blank" rel="noopener">installation guide</a></li>
25
+ <li><strong>Node.js 22 or later</strong> — <a href="https://nodejs.org" target="_blank" rel="noopener" aria-label="nodejs.org (opens in new tab)">nodejs.org</a></li>
26
+ <li><strong>Claude Code</strong> — the CLI for Claude, installed and authenticated — <a href="https://docs.anthropic.com/en/docs/claude-code/getting-started" target="_blank" rel="noopener" aria-label="Claude Code installation guide (opens in new tab)">installation guide</a></li>
27
27
  </ul>
28
28
  <p>Claude Code provides the <code>claude</code> command. Pulse launches it automatically with the Pulse MCP server wired in — so the agent has instant access to the framework reference, your project structure, and all Pulse tools without any manual configuration.</p>
29
29
  ${callout('note', 'GitHub Copilot integration is coming soon. For now, Pulse works exclusively with Claude Code.')}
@@ -55,7 +55,7 @@ export default {
55
55
  </a>
56
56
  <div class="home-nav-links">
57
57
  <a href="/getting-started">Docs</a>
58
- <a href="https://github.com/invisibleloop/pulse-framework" target="_blank" rel="noopener">GitHub</a>
58
+ <a href="https://github.com/invisibleloop/pulse-framework" target="_blank" rel="noopener" aria-label="GitHub (opens in new tab)">GitHub</a>
59
59
  </div>
60
60
  </nav>
61
61
 
@@ -398,7 +398,7 @@ export default {
398
398
 
399
399
  </main>
400
400
  <footer class="home-footer">
401
- <p>MIT License · <a href="https://github.com/invisibleloop/pulse-framework" target="_blank" rel="noopener">GitHub</a> · <a href="/getting-started">Get started in 2 minutes</a></p>
401
+ <p>MIT License · <a href="https://github.com/invisibleloop/pulse-framework" target="_blank" rel="noopener" aria-label="GitHub (opens in new tab)">GitHub</a> · <a href="/getting-started">Get started in 2 minutes</a></p>
402
402
  </footer>
403
403
  </div>
404
404
  `,
@@ -68,7 +68,7 @@ export default {
68
68
  ${callout('tip', 'Use an absolute URL for <code>ogImage</code> — social media crawlers need the full URL to fetch the image. Recommended size: 1200×630 pixels.')}
69
69
 
70
70
  ${section('structured-data', 'Structured data (ld+json)')}
71
- <p>The <code>schema</code> field accepts a plain object conforming to <a href="https://schema.org" target="_blank" rel="noopener">schema.org</a> vocabulary. Pulse serialises it as a <code>&lt;script type="application/ld+json"&gt;</code> tag in the head:</p>
71
+ <p>The <code>schema</code> field accepts a plain object conforming to <a href="https://schema.org" target="_blank" rel="noopener" aria-label="schema.org (opens in new tab)">schema.org</a> vocabulary. Pulse serialises it as a <code>&lt;script type="application/ld+json"&gt;</code> tag in the head:</p>
72
72
  ${codeBlock(highlight(`meta: {
73
73
  title: 'How to make sourdough — My Blog',
74
74
  schema: {
@@ -230,7 +230,7 @@ Cross-Origin-Resource-Policy: same-origin`, 'bash'))}
230
230
  ${section('hsts', 'HSTS')}
231
231
  <p>When a request arrives with <code>x-forwarded-proto: https</code> (or over a TLS socket), Pulse adds:</p>
232
232
  ${codeBlock(highlight(`Strict-Transport-Security: max-age=31536000; includeSubDomains; preload`, 'bash'))}
233
- <p>This is automatic — no configuration required. On plain HTTP the header is omitted. The <code>preload</code> directive means you can submit the domain to <a href="https://hstspreload.org" target="_blank" rel="noopener">hstspreload.org</a> so browsers enforce HTTPS before the first connection — this is a separate manual step, not automatic.</p>
233
+ <p>This is automatic — no configuration required. On plain HTTP the header is omitted. The <code>preload</code> directive means you can submit the domain to <a href="https://hstspreload.org" target="_blank" rel="noopener" aria-label="hstspreload.org (opens in new tab)">hstspreload.org</a> so browsers enforce HTTPS before the first connection — this is a separate manual step, not automatic.</p>
234
234
 
235
235
  ${section('cookies', 'Cookie defaults')}
236
236
  <p>Cookies set via <code>ctx.setCookie()</code> default to <code>SameSite=Lax</code>. CSRF protection is on by default — omitting a <code>sameSite</code> option does not weaken it.</p>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@invisibleloop/pulse",
3
- "version": "0.1.35",
3
+ "version": "0.1.37",
4
4
  "type": "module",
5
5
  "description": "AI-first frontend framework. The spec is the source of truth.",
6
6
  "license": "MIT",
@@ -1 +1 @@
1
- 0.1.35
1
+ 0.1.37