@invisibleloop/pulse 0.20.11 → 0.20.19

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 (266) hide show
  1. package/package.json +6 -5
  2. package/public/.pulse-ui-version +1 -1
  3. package/scripts/build.js +26 -0
  4. package/scripts/release-version.js +17 -8
  5. package/scripts/strip-server.test.js +60 -0
  6. package/src/agent/checklist.md +8 -12
  7. package/src/agent/commands/pulse-start.md +2 -0
  8. package/src/agent/commands/verify.md +30 -8
  9. package/src/agent/guide-components.md +7 -25
  10. package/src/agent/guide-routing.md +0 -12
  11. package/src/agent/guide-server.md +102 -1
  12. package/src/agent/guide-spec.md +8 -1
  13. package/src/agent/guide-styles.md +23 -0
  14. package/src/agent/identity.md +9 -0
  15. package/src/agent/workflow.md +4 -23
  16. package/src/cli/check-bundles.js +113 -0
  17. package/src/cli/check-bundles.test.js +137 -0
  18. package/src/cli/cli.test.js +105 -0
  19. package/src/cli/dev.js +48 -3
  20. package/src/cli/diagnose.js +105 -0
  21. package/src/cli/diagnose.test.js +124 -0
  22. package/src/cli/discover.js +9 -2
  23. package/src/cli/index.js +171 -9
  24. package/src/cli/process-utils.js +57 -0
  25. package/src/cli/process-utils.test.js +114 -0
  26. package/src/cli/review.js +391 -0
  27. package/src/cli/review.test.js +143 -0
  28. package/src/cli/scaffold.js +9 -4
  29. package/src/cli/stamp.js +102 -0
  30. package/src/cli/stamp.test.js +149 -0
  31. package/src/cli/start.js +15 -2
  32. package/src/cli/validate.js +184 -0
  33. package/src/cli/validate.test.js +153 -0
  34. package/src/mcp/mcp.test.js +261 -30
  35. package/src/mcp/server.js +207 -515
  36. package/src/mcp/validate-worker.js +18 -1
  37. package/src/runtime/index.js +144 -11
  38. package/src/runtime/runtime.test.js +199 -0
  39. package/src/runtime/ssr.js +13 -6
  40. package/src/runtime/ssr.test.js +31 -0
  41. package/src/server/index.js +162 -9
  42. package/src/server/server.test.js +225 -2
  43. package/src/spec/schema.js +1 -1
  44. package/src/ui/index.js +0 -5
  45. package/src/ui/ui.test.js +0 -75
  46. package/types/ui.d.ts +0 -21
  47. package/.claude/commands/build-page.md +0 -63
  48. package/.claude/commands/new-doc-page.md +0 -45
  49. package/.claude/commands/pulse-start.md +0 -11
  50. package/.claude/commands/pulse-stop.md +0 -5
  51. package/.claude/commands/verify.md +0 -118
  52. package/.claude/pulse-checklist.md +0 -189
  53. package/.github/workflows/ci.yml +0 -25
  54. package/.github/workflows/publish.yml +0 -45
  55. package/.pulse/load-reports/home/1773432711417.json +0 -22
  56. package/.pulse-verified +0 -1
  57. package/AGENTS.md +0 -697
  58. package/CLAUDE.md +0 -697
  59. package/README.md +0 -95
  60. package/benchmark/public/dist/counter.boot-PO6SNSJZ.js +0 -8
  61. package/benchmark/public/dist/home.boot-YK6VAEQI.js +0 -6
  62. package/benchmark/public/dist/manifest.json +0 -5
  63. package/benchmark/public/dist/runtime-5Y7ESAIB.js +0 -2
  64. package/benchmark/public/dist/runtime-KO4BHUQ3.js +0 -49
  65. package/benchmark/results/2026-03-27-09-20.json +0 -188
  66. package/benchmark/results/2026-03-27-09-21.json +0 -188
  67. package/benchmark/results/2026-03-27-09-29.json +0 -188
  68. package/benchmark/results/2026-03-27-10-14.json +0 -188
  69. package/benchmark/results/2026-03-27-10-18.json +0 -232
  70. package/benchmark/src/pages/counter.js +0 -37
  71. package/benchmark/src/pages/home.js +0 -21
  72. package/docs/.claude/commands/pulse-build.md +0 -7
  73. package/docs/.claude/commands/pulse-dev.md +0 -7
  74. package/docs/.claude/commands/pulse-start.md +0 -9
  75. package/docs/.claude/commands/pulse-stop.md +0 -5
  76. package/docs/.claude/commands/verify.md +0 -84
  77. package/docs/.claude/coverage-check.js +0 -196
  78. package/docs/.claude/pulse-checklist.md +0 -189
  79. package/docs/public/.pulse-ui-version +0 -1
  80. package/docs/public/andypixel.css +0 -237
  81. package/docs/public/bookworms.css +0 -422
  82. package/docs/public/coutumes.css +0 -561
  83. package/docs/public/docs.css +0 -2388
  84. package/docs/public/favicon.svg +0 -4
  85. package/docs/public/home-brut.css +0 -982
  86. package/docs/public/images/bookworms/hero-books.jpg +0 -0
  87. package/docs/public/images/bookworms/how-we-read-now.jpg +0 -0
  88. package/docs/public/images/bookworms/lantern-keepers.jpg +0 -0
  89. package/docs/public/images/bookworms/provincial-bookseller.jpg +0 -0
  90. package/docs/public/images/journey/178.jpg +0 -0
  91. package/docs/public/images/journey/29.jpg +0 -0
  92. package/docs/public/images/retrowheels/hero.jpg +0 -0
  93. package/docs/public/images/shop/devbook-pro.jpg +0 -0
  94. package/docs/public/images/suzukibento/1015.jpg +0 -0
  95. package/docs/public/images/suzukibento/1025.jpg +0 -0
  96. package/docs/public/images/suzukibento/1043.jpg +0 -0
  97. package/docs/public/images/suzukibento/1059.jpg +0 -0
  98. package/docs/public/images/suzukibento/1062.jpg +0 -0
  99. package/docs/public/images/suzukibento/1084.jpg +0 -0
  100. package/docs/public/images/swish/1469334031218-e382a71b716b.jpg +0 -0
  101. package/docs/public/images/swish/1483985988355-763728e1935b.jpg +0 -0
  102. package/docs/public/images/swish/1485518882345-15568b007407.jpg +0 -0
  103. package/docs/public/images/swish/1490481651871-ab68de25d43d.jpg +0 -0
  104. package/docs/public/images/swish/1496747611176-843222e1e57c.jpg +0 -0
  105. package/docs/public/images/swish/1502716119720-b23a93e5fe1b.jpg +0 -0
  106. package/docs/public/images/swish/1539109136881-3be0616acf4b.jpg +0 -0
  107. package/docs/public/images/swish/1551803091-e20673f15770.jpg +0 -0
  108. package/docs/public/images/swish/1558769132-cb1aea458c5e.jpg +0 -0
  109. package/docs/public/images/swish/1572804013309-59a88b7e92f1.jpg +0 -0
  110. package/docs/public/img/heic1501a.jpg +0 -0
  111. package/docs/public/img/placeholder-landscape.svg +0 -18
  112. package/docs/public/img/placeholder-square.svg +0 -14
  113. package/docs/public/img/placeholder-tall.svg +0 -22
  114. package/docs/public/journey.css +0 -528
  115. package/docs/public/menu.js +0 -327
  116. package/docs/public/pulse-ui.css +0 -3028
  117. package/docs/public/pulse-ui.js +0 -257
  118. package/docs/public/retrowheels.css +0 -425
  119. package/docs/public/shop.css +0 -269
  120. package/docs/public/sparkys.css +0 -382
  121. package/docs/public/suzukibento.css +0 -517
  122. package/docs/public/swish.css +0 -394
  123. package/docs/public/theme.css +0 -52
  124. package/docs/public/themes/lumio.css +0 -50
  125. package/docs/public/themes/observatory.css +0 -104
  126. package/docs/server.js +0 -161
  127. package/docs/src/lib/component-page.js +0 -49
  128. package/docs/src/lib/highlight.js +0 -2
  129. package/docs/src/lib/layout.js +0 -190
  130. package/docs/src/lib/metrics-store.js +0 -6
  131. package/docs/src/lib/nav.js +0 -171
  132. package/docs/src/lib/stats.js +0 -81
  133. package/docs/src/pages/accessibility.js +0 -157
  134. package/docs/src/pages/actions.js +0 -194
  135. package/docs/src/pages/auth.js +0 -176
  136. package/docs/src/pages/caching.js +0 -95
  137. package/docs/src/pages/components/accordion.js +0 -48
  138. package/docs/src/pages/components/alert.js +0 -35
  139. package/docs/src/pages/components/app-badge.js +0 -41
  140. package/docs/src/pages/components/avatar.js +0 -35
  141. package/docs/src/pages/components/badge.js +0 -36
  142. package/docs/src/pages/components/breadcrumbs.js +0 -94
  143. package/docs/src/pages/components/button.js +0 -84
  144. package/docs/src/pages/components/card.js +0 -225
  145. package/docs/src/pages/components/charts.js +0 -283
  146. package/docs/src/pages/components/checkbox.js +0 -129
  147. package/docs/src/pages/components/cluster.js +0 -47
  148. package/docs/src/pages/components/container.js +0 -40
  149. package/docs/src/pages/components/cta.js +0 -54
  150. package/docs/src/pages/components/divider.js +0 -37
  151. package/docs/src/pages/components/empty.js +0 -36
  152. package/docs/src/pages/components/feature.js +0 -60
  153. package/docs/src/pages/components/fieldset.js +0 -65
  154. package/docs/src/pages/components/fileupload.js +0 -128
  155. package/docs/src/pages/components/footer.js +0 -58
  156. package/docs/src/pages/components/grid.js +0 -169
  157. package/docs/src/pages/components/heading.js +0 -107
  158. package/docs/src/pages/components/hero.js +0 -123
  159. package/docs/src/pages/components/icons.js +0 -410
  160. package/docs/src/pages/components/image.js +0 -71
  161. package/docs/src/pages/components/input.js +0 -51
  162. package/docs/src/pages/components/media.js +0 -51
  163. package/docs/src/pages/components/modal.js +0 -111
  164. package/docs/src/pages/components/nav.js +0 -136
  165. package/docs/src/pages/components/phone-frame.js +0 -74
  166. package/docs/src/pages/components/progress.js +0 -102
  167. package/docs/src/pages/components/prose.js +0 -111
  168. package/docs/src/pages/components/pullquote.js +0 -71
  169. package/docs/src/pages/components/radio.js +0 -194
  170. package/docs/src/pages/components/rating.js +0 -106
  171. package/docs/src/pages/components/search.js +0 -61
  172. package/docs/src/pages/components/section.js +0 -98
  173. package/docs/src/pages/components/segmented.js +0 -121
  174. package/docs/src/pages/components/select.js +0 -45
  175. package/docs/src/pages/components/slider.js +0 -115
  176. package/docs/src/pages/components/spinner.js +0 -73
  177. package/docs/src/pages/components/stack.js +0 -48
  178. package/docs/src/pages/components/stat.js +0 -55
  179. package/docs/src/pages/components/stepper.js +0 -66
  180. package/docs/src/pages/components/table.js +0 -45
  181. package/docs/src/pages/components/textarea.js +0 -31
  182. package/docs/src/pages/components/toggle.js +0 -84
  183. package/docs/src/pages/components/tooltip.js +0 -48
  184. package/docs/src/pages/components.js +0 -200
  185. package/docs/src/pages/config.js +0 -193
  186. package/docs/src/pages/constraints.js +0 -100
  187. package/docs/src/pages/deploy.js +0 -233
  188. package/docs/src/pages/error-pages.js +0 -99
  189. package/docs/src/pages/extending.js +0 -198
  190. package/docs/src/pages/faq.js +0 -99
  191. package/docs/src/pages/forms.js +0 -129
  192. package/docs/src/pages/getting-started.js +0 -147
  193. package/docs/src/pages/guard.js +0 -120
  194. package/docs/src/pages/home.js +0 -350
  195. package/docs/src/pages/how-it-works.js +0 -244
  196. package/docs/src/pages/hydration.js +0 -108
  197. package/docs/src/pages/images.js +0 -120
  198. package/docs/src/pages/markdown.js +0 -156
  199. package/docs/src/pages/meta.js +0 -193
  200. package/docs/src/pages/mutations.js +0 -107
  201. package/docs/src/pages/navigation.js +0 -85
  202. package/docs/src/pages/performance.js +0 -157
  203. package/docs/src/pages/persist.js +0 -89
  204. package/docs/src/pages/project-structure.js +0 -91
  205. package/docs/src/pages/prompt-examples.js +0 -186
  206. package/docs/src/pages/raw-responses.js +0 -122
  207. package/docs/src/pages/routing.js +0 -120
  208. package/docs/src/pages/server-api.js +0 -291
  209. package/docs/src/pages/server-data.js +0 -203
  210. package/docs/src/pages/slash-commands.js +0 -55
  211. package/docs/src/pages/spec.js +0 -207
  212. package/docs/src/pages/state.js +0 -102
  213. package/docs/src/pages/store.js +0 -203
  214. package/docs/src/pages/streaming.js +0 -107
  215. package/docs/src/pages/stripe.js +0 -194
  216. package/docs/src/pages/supabase.js +0 -324
  217. package/docs/src/pages/templates/andypixel.js +0 -260
  218. package/docs/src/pages/templates/blog-post.js +0 -226
  219. package/docs/src/pages/templates/bookworms.js +0 -227
  220. package/docs/src/pages/templates/coutumes.js +0 -237
  221. package/docs/src/pages/templates/journey.js +0 -186
  222. package/docs/src/pages/templates/mobile-app.js +0 -371
  223. package/docs/src/pages/templates/retrowheels.js +0 -355
  224. package/docs/src/pages/templates/shop.js +0 -268
  225. package/docs/src/pages/templates/sparkys.js +0 -264
  226. package/docs/src/pages/templates/suzukibento.js +0 -200
  227. package/docs/src/pages/templates/swish.js +0 -313
  228. package/docs/src/pages/templates.js +0 -534
  229. package/docs/src/pages/testing.js +0 -199
  230. package/docs/src/pages/validation.js +0 -138
  231. package/examples/.claude/commands/pulse-build.md +0 -7
  232. package/examples/.claude/commands/pulse-dev.md +0 -7
  233. package/examples/.claude/commands/pulse-start.md +0 -9
  234. package/examples/.claude/commands/pulse-stop.md +0 -5
  235. package/examples/.claude/commands/verify.md +0 -84
  236. package/examples/.claude/coverage-check.js +0 -196
  237. package/examples/.claude/pulse-checklist.md +0 -189
  238. package/examples/andypixel.css +0 -237
  239. package/examples/andypixel.js +0 -258
  240. package/examples/bookworms.css +0 -422
  241. package/examples/bookworms.js +0 -225
  242. package/examples/contact.js +0 -166
  243. package/examples/counter.js +0 -94
  244. package/examples/dev.server.js +0 -110
  245. package/examples/examples.test.js +0 -394
  246. package/examples/journey.css +0 -528
  247. package/examples/journey.js +0 -186
  248. package/examples/pricing.js +0 -262
  249. package/examples/products.js +0 -190
  250. package/examples/public/.pulse-ui-version +0 -1
  251. package/examples/public/pulse-ui.css +0 -3028
  252. package/examples/public/pulse-ui.js +0 -257
  253. package/examples/quiz.js +0 -208
  254. package/examples/retrowheels.css +0 -425
  255. package/examples/retrowheels.js +0 -353
  256. package/examples/shared.js +0 -84
  257. package/examples/suzukibento.css +0 -513
  258. package/examples/suzukibento.js +0 -200
  259. package/examples/swish.css +0 -394
  260. package/examples/swish.js +0 -311
  261. package/examples/todos.js +0 -162
  262. package/src/ui/fieldset.js +0 -37
  263. package/src/ui/phone-frame.js +0 -40
  264. package/src/ui/search.js +0 -78
  265. package/src/ui/segmented.js +0 -50
  266. package/src/ui/tooltip.js +0 -28
package/docs/server.js DELETED
@@ -1,161 +0,0 @@
1
- import fs from 'fs'
2
- import { createServer } from '../src/server/index.js'
3
- import { initLayoutManifest } from './src/lib/layout.js'
4
- import { metrics } from './src/lib/stats.js'
5
- import { metricsStore } from './src/lib/metrics-store.js'
6
- import { NAV } from './src/lib/nav.js'
7
- metricsStore.current = metrics
8
-
9
- // Build search index once at startup from nav structure
10
- const searchIndex = JSON.stringify(
11
- NAV.flatMap(({ section, items }) =>
12
- items.map(item => ({ title: item.label, href: item.href, section, body: '' }))
13
- )
14
- )
15
- const searchIndexEtag = `"${Buffer.from(searchIndex).length}-search"`
16
-
17
- // Populate hashed asset paths in layout.js before any page renders
18
- try {
19
- const raw = fs.readFileSync(new URL('./public/dist/manifest.json', import.meta.url), 'utf8')
20
- initLayoutManifest(JSON.parse(raw))
21
- } catch { /* dev: no manifest yet, layout falls back to unhashed paths */ }
22
-
23
- await createServer(
24
- [
25
- // Framework
26
- new URL('./src/pages/home.js', import.meta.url),
27
- new URL('./src/pages/how-it-works.js', import.meta.url),
28
- new URL('./src/pages/faq.js', import.meta.url),
29
- new URL('./src/pages/config.js', import.meta.url),
30
- new URL('./src/pages/getting-started.js', import.meta.url),
31
- new URL('./src/pages/slash-commands.js', import.meta.url),
32
- new URL('./src/pages/prompt-examples.js', import.meta.url),
33
- new URL('./src/pages/components.js', import.meta.url),
34
- new URL('./src/pages/project-structure.js', import.meta.url),
35
- new URL('./src/pages/spec.js', import.meta.url),
36
- // State & Behaviour
37
- new URL('./src/pages/state.js', import.meta.url),
38
- new URL('./src/pages/mutations.js', import.meta.url),
39
- new URL('./src/pages/actions.js', import.meta.url),
40
- new URL('./src/pages/validation.js', import.meta.url),
41
- new URL('./src/pages/constraints.js', import.meta.url),
42
- new URL('./src/pages/persist.js', import.meta.url),
43
- // Server
44
- new URL('./src/pages/server-data.js', import.meta.url),
45
- new URL('./src/pages/markdown.js', import.meta.url),
46
- new URL('./src/pages/store.js', import.meta.url),
47
- new URL('./src/pages/routing.js', import.meta.url),
48
- new URL('./src/pages/error-pages.js', import.meta.url),
49
- new URL('./src/pages/streaming.js', import.meta.url),
50
- new URL('./src/pages/caching.js', import.meta.url),
51
- new URL('./src/pages/guard.js', import.meta.url),
52
- new URL('./src/pages/forms.js', import.meta.url),
53
- new URL('./src/pages/raw-responses.js', import.meta.url),
54
- new URL('./src/pages/server-api.js', import.meta.url),
55
- new URL('./src/pages/extending.js', import.meta.url),
56
- // Client
57
- new URL('./src/pages/hydration.js', import.meta.url),
58
- new URL('./src/pages/navigation.js', import.meta.url),
59
- new URL('./src/pages/images.js', import.meta.url),
60
- // Deployment
61
- new URL('./src/pages/deploy.js', import.meta.url),
62
- // Reference
63
- new URL('./src/pages/meta.js', import.meta.url),
64
- new URL('./src/pages/performance.js', import.meta.url),
65
- new URL('./src/pages/accessibility.js', import.meta.url),
66
- new URL('./src/pages/testing.js', import.meta.url),
67
- // Integrations
68
- new URL('./src/pages/supabase.js', import.meta.url),
69
- new URL('./src/pages/auth.js', import.meta.url),
70
- new URL('./src/pages/stripe.js', import.meta.url),
71
- // UI Components
72
- new URL('./src/pages/components/alert.js', import.meta.url),
73
- new URL('./src/pages/components/avatar.js', import.meta.url),
74
- new URL('./src/pages/components/badge.js', import.meta.url),
75
- new URL('./src/pages/components/breadcrumbs.js', import.meta.url),
76
- new URL('./src/pages/components/button.js', import.meta.url),
77
- new URL('./src/pages/components/card.js', import.meta.url),
78
- new URL('./src/pages/components/checkbox.js', import.meta.url),
79
- new URL('./src/pages/components/charts.js', import.meta.url),
80
- new URL('./src/pages/components/empty.js', import.meta.url),
81
- new URL('./src/pages/components/fieldset.js', import.meta.url),
82
- new URL('./src/pages/components/fileupload.js', import.meta.url),
83
- new URL('./src/pages/components/heading.js', import.meta.url),
84
- new URL('./src/pages/components/icons.js', import.meta.url),
85
- new URL('./src/pages/components/image.js', import.meta.url),
86
- new URL('./src/pages/components/input.js', import.meta.url),
87
- new URL('./src/pages/components/modal.js', import.meta.url),
88
- new URL('./src/pages/components/progress.js', import.meta.url),
89
- new URL('./src/pages/components/prose.js', import.meta.url),
90
- new URL('./src/pages/components/pullquote.js', import.meta.url),
91
- new URL('./src/pages/components/radio.js', import.meta.url),
92
- new URL('./src/pages/components/rating.js', import.meta.url),
93
- new URL('./src/pages/components/search.js', import.meta.url),
94
- new URL('./src/pages/components/segmented.js', import.meta.url),
95
- new URL('./src/pages/components/select.js', import.meta.url),
96
- new URL('./src/pages/components/slider.js', import.meta.url),
97
- new URL('./src/pages/components/spinner.js', import.meta.url),
98
- new URL('./src/pages/components/stat.js', import.meta.url),
99
- new URL('./src/pages/components/stepper.js', import.meta.url),
100
- new URL('./src/pages/components/table.js', import.meta.url),
101
- new URL('./src/pages/components/textarea.js', import.meta.url),
102
- new URL('./src/pages/components/toggle.js', import.meta.url),
103
- new URL('./src/pages/components/tooltip.js', import.meta.url),
104
- // Landing Components
105
- new URL('./src/pages/components/accordion.js', import.meta.url),
106
- new URL('./src/pages/components/app-badge.js', import.meta.url),
107
- new URL('./src/pages/components/cta.js', import.meta.url),
108
- new URL('./src/pages/components/feature.js', import.meta.url),
109
- new URL('./src/pages/components/hero.js', import.meta.url),
110
- new URL('./src/pages/components/nav.js', import.meta.url),
111
- new URL('./src/pages/components/phone-frame.js', import.meta.url),
112
- // Templates
113
- new URL('./src/pages/templates.js', import.meta.url),
114
- new URL('./src/pages/templates/mobile-app.js', import.meta.url),
115
- new URL('./src/pages/templates/blog-post.js', import.meta.url),
116
- new URL('./src/pages/templates/coutumes.js', import.meta.url),
117
- new URL('./src/pages/templates/sparkys.js', import.meta.url),
118
- new URL('./src/pages/templates/swish.js', import.meta.url),
119
- new URL('./src/pages/templates/bookworms.js', import.meta.url),
120
- new URL('./src/pages/templates/retrowheels.js', import.meta.url),
121
- new URL('./src/pages/templates/suzukibento.js', import.meta.url),
122
- new URL('./src/pages/templates/andypixel.js', import.meta.url),
123
- new URL('./src/pages/templates/journey.js', import.meta.url),
124
- new URL('./src/pages/templates/shop.js', import.meta.url),
125
- // Layout Components
126
- new URL('./src/pages/components/cluster.js', import.meta.url),
127
- new URL('./src/pages/components/container.js', import.meta.url),
128
- new URL('./src/pages/components/divider.js', import.meta.url),
129
- new URL('./src/pages/components/footer.js', import.meta.url),
130
- new URL('./src/pages/components/grid.js', import.meta.url),
131
- new URL('./src/pages/components/media.js', import.meta.url),
132
- new URL('./src/pages/components/section.js', import.meta.url),
133
- new URL('./src/pages/components/stack.js', import.meta.url),
134
- ],
135
- {
136
- port: process.env.PORT ? Number(process.env.PORT) : 4000,
137
- staticDir: new URL('./public', import.meta.url).pathname,
138
- root: new URL('.', import.meta.url),
139
- defaultCache: true,
140
- csp: {
141
- 'img-src': ['https://picsum.photos', 'https://fastly.picsum.photos', 'https://images.unsplash.com'],
142
- 'style-src': ['https://fonts.googleapis.com'],
143
- 'font-src': ['https://fonts.gstatic.com'],
144
- },
145
- onRequest(req, res) {
146
- if (req.url !== '/search-index.json') return
147
- if (req.headers['if-none-match'] === searchIndexEtag) {
148
- res.writeHead(304)
149
- res.end()
150
- return false
151
- }
152
- res.writeHead(200, {
153
- 'Content-Type': 'application/json; charset=utf-8',
154
- 'Cache-Control': 'public, max-age=3600',
155
- 'ETag': searchIndexEtag,
156
- })
157
- res.end(searchIndex)
158
- return false
159
- },
160
- }
161
- )
@@ -1,49 +0,0 @@
1
- /**
2
- * Pulse Docs — Component page factory
3
- *
4
- * renderComponentPage({ name, description, demos, props, prev, next, currentHref })
5
- * Returns the HTML content string for a standard component doc page.
6
- */
7
-
8
- import { renderLayout, h1, lead, codeBlock } from './layout.js'
9
- import { highlight } from './highlight.js'
10
-
11
- export function demo(previewHtml, codeStr, { col = false, scroll = false, bleed = false } = {}) {
12
- const previewClass = [
13
- 'demo-preview',
14
- 'is-light',
15
- col ? 'demo-preview--col' : '',
16
- scroll ? 'demo-preview--scroll' : '',
17
- bleed ? 'demo-preview--bleed' : '',
18
- ].filter(Boolean).join(' ')
19
- const toggle = `<button class="demo-theme-toggle" aria-label="Toggle light/dark theme" title="Toggle theme">
20
- <svg class="demo-theme-toggle__dark" width="14" height="14" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M21 12.79A9 9 0 1111.21 3a7 7 0 109.79 9.79z"/></svg>
21
- <svg class="demo-theme-toggle__light" width="14" height="14" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><circle cx="12" cy="12" r="5"/><path d="M12 1v2M12 21v2M4.22 4.22l1.42 1.42M18.36 18.36l1.42 1.42M1 12h2M21 12h2M4.22 19.78l1.42-1.42M18.36 5.64l1.42-1.42" stroke="currentColor" stroke-width="2" stroke-linecap="round"/></svg>
22
- </button>`
23
- return `<div class="component-demo">
24
- <div class="${previewClass}">${toggle}<div class="demo-preview-inner ui-theme-light">${previewHtml}</div></div>
25
- <div class="demo-code">${codeBlock(highlight(codeStr, 'js'))}</div>
26
- </div>`
27
- }
28
-
29
- /**
30
- * @param {object} opts
31
- * @param {string} opts.currentHref - The route of this page
32
- * @param {string} opts.name - Component name displayed in h1
33
- * @param {string} opts.description - Lead paragraph HTML
34
- * @param {string} opts.content - Full HTML body (demos + props table)
35
- * @param {object|null} opts.prev - { label, href } or null
36
- * @param {object|null} opts.next - { label, href } or null
37
- */
38
- export function renderComponentPage({ currentHref, name, description, content, prev = null, next = null }) {
39
- return renderLayout({
40
- currentHref,
41
- prev,
42
- next,
43
- content: `
44
- ${h1(name)}
45
- ${lead(description)}
46
- ${content}
47
- `,
48
- })
49
- }
@@ -1,2 +0,0 @@
1
- // Re-export from the framework's canonical highlight implementation.
2
- export { highlight } from '../../../src/md/highlight.js'
@@ -1,190 +0,0 @@
1
- /**
2
- * Pulse Docs — Page layout
3
- *
4
- * renderLayout({ currentHref, content, prev, next }) → HTML string
5
- * Used by every docs page except the home page.
6
- */
7
-
8
- import { NAV } from './nav.js'
9
- import pkg from '../../../package.json' with { type: 'json' }
10
-
11
- // Resolve static asset paths through the build manifest (hashed in prod, raw in dev).
12
- // Populated by initLayoutManifest() in server.js before the server starts.
13
- let _manifest = {}
14
- export function initLayoutManifest(m) { _manifest = m }
15
- export const asset = href => _manifest[href] || href
16
-
17
- const version = typeof pkg !== 'undefined' ? (pkg?.version ?? '') : ''
18
-
19
- function esc(s) {
20
- return String(s).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;')
21
- }
22
-
23
- function sidebar(currentHref) {
24
- const sections = NAV.map(({ section, items }) => {
25
- const links = items.map(item => {
26
- const active = item.href === currentHref
27
- return `<a href="${esc(item.href)}" class="nav-link${active ? ' active' : ''}"${active ? ' aria-current="page"' : ''}>${esc(item.label)}</a>`
28
- }).join('')
29
- return `
30
- <div class="nav-section">
31
- <p class="nav-section-title">${esc(section)}</p>
32
- ${links}
33
- </div>`
34
- }).join('')
35
-
36
- return `
37
- <aside class="docs-sidebar" id="docs-sidebar" aria-label="Documentation navigation">
38
- <div class="sidebar-logo">
39
- <a href="/" class="logo-link" aria-label="Pulse home">
40
- <svg width="24" height="24" viewBox="0 0 24 24" fill="none" aria-hidden="true">
41
- <path d="M13 2L4.5 13.5H11L10 22L19.5 10.5H13L13 2Z" fill="var(--accent)" stroke="var(--accent)" stroke-width="1" stroke-linejoin="round"/>
42
- </svg>
43
- <span class="logo-name">Pulse</span>
44
- </a>
45
- <span class="version-badge">v${version}</span>
46
- </div>
47
- <div class="sidebar-search-wrap">
48
- <svg class="sidebar-search-icon" width="14" height="14" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
49
- <path fill-rule="evenodd" d="M8 4a4 4 0 100 8 4 4 0 000-8zM2 8a6 6 0 1110.89 3.476l4.817 4.817a1 1 0 01-1.414 1.414l-4.816-4.816A6 6 0 012 8z" clip-rule="evenodd"/>
50
- </svg>
51
- <input
52
- type="search"
53
- id="sidebar-search"
54
- class="sidebar-search"
55
- placeholder="Filter pages…"
56
- aria-label="Filter documentation pages"
57
- autocomplete="off"
58
- spellcheck="false"
59
- >
60
- <button class="sidebar-search-full" aria-label="Search all docs content" title="Search all docs">
61
- <svg width="14" height="14" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
62
- <path fill-rule="evenodd" d="M3 4a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zm0 4a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zm0 4a1 1 0 011-1h7a1 1 0 110 2H4a1 1 0 01-1-1z" clip-rule="evenodd"/>
63
- </svg>
64
- </button>
65
- </div>
66
- <nav class="sidebar-nav" id="sidebar-nav">
67
- ${sections}
68
- <p class="sidebar-no-results" hidden>No pages found</p>
69
- </nav>
70
- </aside>
71
- <div class="search-overlay" id="search-overlay" role="dialog" aria-modal="true" aria-label="Search documentation" hidden>
72
- <div class="search-overlay-backdrop"></div>
73
- <div class="search-overlay-panel">
74
- <div class="search-overlay-header">
75
- <div class="search-overlay-input-wrap">
76
- <svg width="18" height="18" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
77
- <path fill-rule="evenodd" d="M8 4a4 4 0 100 8 4 4 0 000-8zM2 8a6 6 0 1110.89 3.476l4.817 4.817a1 1 0 01-1.414 1.414l-4.816-4.816A6 6 0 012 8z" clip-rule="evenodd"/>
78
- </svg>
79
- <input
80
- type="search"
81
- id="search-overlay-input"
82
- class="search-overlay-input"
83
- placeholder="Search all docs…"
84
- aria-label="Search all documentation"
85
- autocomplete="off"
86
- spellcheck="false"
87
- >
88
- </div>
89
- <button class="search-overlay-close" aria-label="Close search">ESC</button>
90
- </div>
91
- <div class="search-overlay-results" id="search-overlay-results" role="listbox" aria-label="Search results"></div>
92
- <div class="search-overlay-footer">
93
- <span><kbd>↑</kbd><kbd>↓</kbd> navigate</span>
94
- <span><kbd>↵</kbd> open</span>
95
- <span><kbd>ESC</kbd> close</span>
96
- </div>
97
- </div>
98
- </div>`
99
- }
100
-
101
- function prevNextBar(prev, next) {
102
- if (!prev && !next) return ''
103
- return `
104
- <nav class="doc-prev-next" aria-label="Previous and next pages">
105
- <div class="prev-next-grid">
106
- ${prev ? `<a href="${esc(prev.href)}" class="prev-next-link prev-link">
107
- <span class="prev-next-label">← Previous</span>
108
- <span class="prev-next-title">${esc(prev.label)}</span>
109
- </a>` : '<div></div>'}
110
- ${next ? `<a href="${esc(next.href)}" class="prev-next-link next-link">
111
- <span class="prev-next-label">Next →</span>
112
- <span class="prev-next-title">${esc(next.label)}</span>
113
- </a>` : '<div></div>'}
114
- </div>
115
- </nav>`
116
- }
117
-
118
- export function renderLayout({ currentHref, content, prev = null, next = null }) {
119
- return `
120
- <a href="#main-content" class="skip-link">Skip to main content</a>
121
- <div class="sidebar-overlay" aria-hidden="true"></div>
122
- ${sidebar(currentHref)}
123
- <div class="docs-main">
124
- <header class="docs-header">
125
- <button class="mobile-menu-btn" aria-label="Toggle navigation menu" aria-expanded="false" aria-controls="docs-sidebar">
126
- <svg width="20" height="20" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
127
- <path fill-rule="evenodd" d="M2 4.75A.75.75 0 012.75 4h14.5a.75.75 0 010 1.5H2.75A.75.75 0 012 4.75zm0 10.5a.75.75 0 01.75-.75h14.5a.75.75 0 010 1.5H2.75a.75.75 0 01-.75-.75zM2 10a.75.75 0 01.75-.75h14.5a.75.75 0 010 1.5H2.75A.75.75 0 012 10z" clip-rule="evenodd"/>
128
- </svg>
129
- </button>
130
- <a href="/" class="header-logo-mobile" aria-label="Pulse home">
131
- <svg width="20" height="20" viewBox="0 0 24 24" fill="none" aria-hidden="true">
132
- <path d="M13 2L4.5 13.5H11L10 22L19.5 10.5H13L13 2Z" fill="var(--accent)" stroke="var(--accent)" stroke-width="1" stroke-linejoin="round"/>
133
- </svg>
134
- </a>
135
- <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">
136
- <svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
137
- <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"/>
138
- </svg>
139
- GitHub
140
- </a>
141
- </header>
142
- <main class="docs-content" id="main-content">
143
- ${content}
144
- ${prevNextBar(prev, next)}
145
- </main>
146
- </div>
147
- <script src="${asset('/menu.js')}" defer></script>
148
- <script src="${asset('/pulse-ui.js')}" defer></script>`
149
- }
150
-
151
- /**
152
- * Convenience helpers used in every page's view function
153
- */
154
-
155
- export function h1(text) {
156
- return `<h1 class="doc-h1">${esc(text)}</h1>`
157
- }
158
-
159
- export function lead(text) {
160
- return `<p class="doc-lead">${text}</p>`
161
- }
162
-
163
- export function section(id, title) {
164
- return `<h2 class="doc-h2" id="${esc(id)}"><a href="#${esc(id)}" class="heading-anchor">${esc(title)}</a></h2>`
165
- }
166
-
167
- export function sub(id, title) {
168
- const label = title ?? id
169
- return `<h3 class="doc-h3" id="${esc(id)}"><a href="#${esc(id)}" class="heading-anchor">${esc(label)}</a></h3>`
170
- }
171
-
172
- export function codeBlock(highlighted, filename = '') {
173
- const header = filename ? `<div class="code-filename">${esc(filename)}</div>` : ''
174
- return `${header}<pre class="code-block"><code>${highlighted}</code></pre>`
175
- }
176
-
177
- export function table(headers, rows, caption = '') {
178
- const cap = caption ? `<caption>${esc(caption)}</caption>` : ''
179
- const ths = headers.map(h => `<th scope="col">${h}</th>`).join('')
180
- const trs = rows.map(row =>
181
- `<tr>${row.map(cell => `<td>${cell}</td>`).join('')}</tr>`
182
- ).join('')
183
- return `<div class="table-wrap"><table>${cap}<thead><tr>${ths}</tr></thead><tbody>${trs}</tbody></table></div>`
184
- }
185
-
186
- export function callout(type, content) {
187
- // type: 'note' | 'warning' | 'tip'
188
- const icons = { note: 'ℹ', warning: '⚠', tip: '✦' }
189
- return `<div class="callout callout-${esc(type)}"><span class="callout-icon" aria-hidden="true">${icons[type] || 'ℹ'}</span><div class="callout-body">${content}</div></div>`
190
- }
@@ -1,6 +0,0 @@
1
- /**
2
- * Shared metrics holder. Populated by docs/server.js at startup
3
- * before createServer() is called. home.js reads from here so
4
- * the spec file stays free of Node built-ins (safe to bundle for browser).
5
- */
6
- export const metricsStore = { current: null }
@@ -1,171 +0,0 @@
1
- /**
2
- * Pulse Docs — Navigation structure
3
- */
4
-
5
- export const NAV = [
6
- {
7
- section: 'Framework',
8
- items: [
9
- { label: 'Overview', href: '/' },
10
- { label: 'FAQ', href: '/faq' },
11
- { label: 'Project Structure', href: '/project-structure' },
12
- { label: 'Spec Reference', href: '/spec' },
13
- { label: 'Configuration', href: '/config' },
14
- ],
15
- },
16
- {
17
- section: 'Developer Guide',
18
- items: [
19
- { label: 'Getting Started', href: '/getting-started' },
20
- { label: 'How It Works', href: '/how-it-works' },
21
- { label: 'Slash Commands', href: '/slash-commands' },
22
- { label: 'Prompt Examples', href: '/prompt-examples' },
23
- { label: 'Component Library', href: '/components' },
24
- ],
25
- },
26
- {
27
- section: 'State & Behaviour',
28
- items: [
29
- { label: 'State', href: '/state' },
30
- { label: 'Mutations', href: '/mutations' },
31
- { label: 'Actions', href: '/actions' },
32
- { label: 'Validation', href: '/validation' },
33
- { label: 'Constraints', href: '/constraints' },
34
- { label: 'Persist', href: '/persist' },
35
- ],
36
- },
37
- {
38
- section: 'Server',
39
- items: [
40
- { label: 'Server Data', href: '/server-data' },
41
- { label: 'Markdown', href: '/markdown' },
42
- { label: 'Global Store', href: '/store' },
43
- { label: 'Routing', href: '/routing' },
44
- { label: 'Error Pages', href: '/error-pages' },
45
- { label: 'Streaming SSR', href: '/streaming' },
46
- { label: 'Caching', href: '/caching' },
47
- { label: 'Guard', href: '/guard' },
48
- { label: 'Forms', href: '/forms' },
49
- { label: 'Raw Responses', href: '/raw-responses' },
50
- { label: 'Server API', href: '/server-api' },
51
- { label: 'Extending Pulse', href: '/extending' },
52
- ],
53
- },
54
- {
55
- section: 'Client',
56
- items: [
57
- { label: 'Hydration', href: '/hydration' },
58
- { label: 'Navigation', href: '/navigation' },
59
- { label: 'Images', href: '/images' },
60
- ],
61
- },
62
- {
63
- section: 'Deployment',
64
- items: [
65
- { label: 'Deployment', href: '/deploy' },
66
- ],
67
- },
68
- {
69
- section: 'Reference',
70
- items: [
71
- { label: 'Metadata & SEO', href: '/meta' },
72
- { label: 'Performance', href: '/performance' },
73
- { label: 'Accessibility', href: '/accessibility' },
74
- { label: 'Testing', href: '/testing' },
75
- ],
76
- },
77
- {
78
- section: 'UI Components',
79
- items: [
80
- { label: 'Alert', href: '/components/alert' },
81
- { label: 'Avatar', href: '/components/avatar' },
82
- { label: 'Badge', href: '/components/badge' },
83
- { label: 'Breadcrumbs', href: '/components/breadcrumbs' },
84
- { label: 'Button', href: '/components/button' },
85
- { label: 'Card', href: '/components/card' },
86
- { label: 'Checkbox', href: '/components/checkbox' },
87
- { label: 'Charts', href: '/components/charts' },
88
- { label: 'Empty', href: '/components/empty' },
89
- { label: 'Fieldset', href: '/components/fieldset' },
90
- { label: 'File Upload', href: '/components/file-upload' },
91
- { label: 'Heading', href: '/components/heading' },
92
- { label: 'Icons', href: '/components/icons' },
93
- { label: 'Image', href: '/components/image' },
94
- { label: 'Input', href: '/components/input' },
95
- { label: 'Modal', href: '/components/modal' },
96
- { label: 'Progress', href: '/components/progress' },
97
- { label: 'Prose', href: '/components/prose' },
98
- { label: 'Pullquote', href: '/components/pullquote' },
99
- { label: 'Radio', href: '/components/radio' },
100
- { label: 'Rating', href: '/components/rating' },
101
- { label: 'Search', href: '/components/search' },
102
- { label: 'Segmented', href: '/components/segmented' },
103
- { label: 'Select', href: '/components/select' },
104
- { label: 'Slider', href: '/components/slider' },
105
- { label: 'Spinner', href: '/components/spinner' },
106
- { label: 'Stat', href: '/components/stat' },
107
- { label: 'Stepper', href: '/components/stepper' },
108
- { label: 'Table', href: '/components/table' },
109
- { label: 'Textarea', href: '/components/textarea' },
110
- { label: 'Toggle', href: '/components/toggle' },
111
- { label: 'Tooltip', href: '/components/tooltip' },
112
- ],
113
- },
114
- {
115
- section: 'Landing Components',
116
- items: [
117
- { label: 'Accordion', href: '/components/accordion' },
118
- { label: 'App Badge', href: '/components/app-badge' },
119
- { label: 'CTA', href: '/components/cta' },
120
- { label: 'Feature', href: '/components/feature' },
121
- { label: 'Hero', href: '/components/hero' },
122
- { label: 'Nav', href: '/components/nav' },
123
- { label: 'Phone Frame', href: '/components/phone-frame' },
124
- ],
125
- },
126
- {
127
- section: 'Layout Components',
128
- items: [
129
- { label: 'Cluster', href: '/components/cluster' },
130
- { label: 'Container', href: '/components/container' },
131
- { label: 'Divider', href: '/components/divider' },
132
- { label: 'Footer', href: '/components/footer' },
133
- { label: 'Grid', href: '/components/grid' },
134
- { label: 'Media', href: '/components/media' },
135
- { label: 'Section', href: '/components/section' },
136
- { label: 'Stack', href: '/components/stack' },
137
- ],
138
- },
139
- {
140
- section: 'Integrations',
141
- items: [
142
- { label: 'Supabase', href: '/supabase' },
143
- { label: 'Auth (Auth0)', href: '/auth' },
144
- { label: 'Payments (Stripe)', href: '/stripe' },
145
- ],
146
- },
147
- {
148
- section: 'Templates',
149
- items: [
150
- { label: 'All Templates', href: '/templates' },
151
- { label: 'Mobile App Landing', href: '/templates/mobile-app' },
152
- { label: 'Blog Post', href: '/templates/blog-post' },
153
- { label: 'Swish — Fashion', href: '/templates/swish' },
154
- { label: 'BookWorms', href: '/templates/bookworms' },
155
- { label: 'Retro Wheels Co.', href: '/templates/retrowheels' },
156
- { label: 'Susuki Bento', href: '/templates/suzukibento' },
157
- { label: 'Andy Pixel — Blog', href: '/templates/andypixel' },
158
- { label: 'Journey — App', href: '/templates/journey' },
159
- { label: 'Shop — Product Page', href: '/templates/shop' },
160
- ],
161
- },
162
- ]
163
-
164
- export function prevNext(currentHref) {
165
- const all = NAV.flatMap(s => s.items)
166
- const idx = all.findIndex(i => i.href === currentHref)
167
- return {
168
- prev: idx > 0 ? all[idx - 1] : null,
169
- next: idx < all.length - 1 ? all[idx + 1] : null,
170
- }
171
- }