Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: unjs/unhead
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v2.0.0-rc.13
Choose a base ref
...
head repository: unjs/unhead
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: v2.0.0
Choose a head ref

Commits on Mar 14, 2025

  1. chore(deps): update all non-major dependencies (#508)

    Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
    renovate[bot] authored Mar 14, 2025

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    8020ddb View commit details
  2. Copy the full SHA
    1a6cfeb View commit details
  3. Merge remote-tracking branch 'origin/main'

    harlan-zw committed Mar 14, 2025
    Copy the full SHA
    abc738f View commit details

Commits on Mar 15, 2025

  1. doc: misc improvements

    harlan-zw committed Mar 15, 2025
    Copy the full SHA
    ecca9e4 View commit details
  2. doc: misc improvements

    harlan-zw committed Mar 15, 2025
    Copy the full SHA
    5d10d09 View commit details

Commits on Mar 17, 2025

  1. doc: reorganize for v2 stable

    harlan-zw committed Mar 17, 2025
    Copy the full SHA
    f2074df View commit details
  2. chore: misc doc issues

    harlan-zw committed Mar 17, 2025
    Copy the full SHA
    c413e2b View commit details

Commits on Mar 18, 2025

  1. doc: misc broken links

    harlan-zw committed Mar 18, 2025
    Copy the full SHA
    f9c9de3 View commit details
  2. doc: misc broken links

    harlan-zw committed Mar 18, 2025
    Copy the full SHA
    f48eeb6 View commit details
  3. doc: misc broken links

    harlan-zw committed Mar 18, 2025
    Copy the full SHA
    b000ecc View commit details
  4. doc: misc broken links

    harlan-zw committed Mar 18, 2025
    Copy the full SHA
    5c10e9d View commit details

Commits on Mar 20, 2025

  1. perf: mark explicit no side effects on createHead variants

    harlan-zw committed Mar 20, 2025
    Copy the full SHA
    058287f View commit details
  2. fix: use a backwards-compatible alternative to Object.hasOwn (#526)

    Ingramz authored Mar 20, 2025

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    6ae5888 View commit details
  3. chore: update bundle stats [skip ci]

    github-actions[bot] committed Mar 20, 2025
    Copy the full SHA
    52c9a5e View commit details

Commits on Mar 22, 2025

  1. chore: doc page sorting

    harlan-zw committed Mar 22, 2025
    Copy the full SHA
    7c16f55 View commit details
  2. Merge remote-tracking branch 'origin/main'

    harlan-zw committed Mar 22, 2025
    Copy the full SHA
    5251485 View commit details

Commits on Mar 23, 2025

  1. doc: clean up schema.org

    harlan-zw committed Mar 23, 2025
    Copy the full SHA
    d1a34b4 View commit details
  2. chore: bump deps

    harlan-zw committed Mar 23, 2025
    Copy the full SHA
    77050b4 View commit details
  3. chore: renovate config

    harlan-zw committed Mar 23, 2025
    Copy the full SHA
    2144437 View commit details
  4. doc: unhead v2 stable

    harlan-zw committed Mar 23, 2025
    Copy the full SHA
    d54e320 View commit details
  5. doc: typo

    harlan-zw committed Mar 23, 2025
    Copy the full SHA
    3ca7b37 View commit details
  6. doc: typo

    harlan-zw committed Mar 23, 2025
    Copy the full SHA
    a2c5082 View commit details
  7. chore: more xss tests

    harlan-zw committed Mar 23, 2025
    Copy the full SHA
    08059f7 View commit details
  8. chore: types

    harlan-zw committed Mar 23, 2025
    Copy the full SHA
    894547e View commit details
  9. chore: misc broken links

    harlan-zw committed Mar 23, 2025
    Copy the full SHA
    b665ef4 View commit details
  10. chore: release v2.0.0

    harlan-zw committed Mar 23, 2025
    Copy the full SHA
    ecef477 View commit details
Showing with 10,550 additions and 4,182 deletions.
  1. +155 −0 .claude/commands/analyze-docs.md
  2. +157 −0 .claude/commands/security-research.md
  3. +6 −1 README.md
  4. +2 −2 bench/bundle/last.json
  5. +10 −12 docs/0.angular/{ → head/guides/0.get-started}/1.installation.md
  6. 0 docs/0.angular/{guides → head/guides/1.core-concepts}/0.reactivity.md
  7. +1 −1 docs/0.angular/{guides → head/guides/1.core-concepts}/1.components.md
  8. +1 −1 docs/{schema-org/0.typescript → 0.angular/schema-org/guides/get-started}/0.installation.md
  9. 0 docs/0.nuxt/{ → head/guides/0.get-started}/1.installation.md
  10. +19 −0 docs/0.nuxt/head/guides/0.get-started/1.migration.md
  11. +3 −3 docs/0.nuxt/{guides → head/guides/1.core-concepts}/0.reactivity.md
  12. 0 docs/0.nuxt/{guides → head/guides/1.core-concepts}/1.components.md
  13. +2 −2 docs/{schema-org/0.nuxt → 0.nuxt/schema-org/guides/0.get-started}/0.installation.md
  14. 0 docs/{schema-org/0.nuxt/guides → 0.nuxt/schema-org/guides/1.core-concepts}/5.vue-components.md
  15. +6 −7 docs/0.react/{ → head/guides/0.get-started}/1.installation.md
  16. +10 −6 docs/0.react/{guides → head/guides/0.get-started}/migrate-from-react-helmet.md
  17. 0 docs/0.react/{guides → head/guides/1.core-concepts}/1.components.md
  18. 0 docs/0.react/{guides → head/guides/1.core-concepts}/2.reactivity.md
  19. +2 −4 docs/{schema-org/0.angular → 0.react/schema-org/guides/get-started}/0.installation.md
  20. +1 −0 docs/0.solid-js/.navigation.yml
  21. +0 −199 docs/0.solid-js/guides/1.reactivity.md
  22. +20 −25 docs/0.solid-js/{ → head/guides/0.get-started}/1.installation.md
  23. +280 −0 docs/0.solid-js/head/guides/1.core-concepts/0.reactivity.md
  24. +216 −0 docs/0.solid-js/schema-org/guides/get-started/0.installation.md
  25. +9 −9 docs/0.svelte/{ → head/guides/0.get-started}/1.installation.md
  26. 0 docs/0.svelte/{guides → head/guides/1.core-concepts}/0.reactivity.md
  27. +2 −4 docs/{schema-org/0.svelte → 0.svelte/schema-org/guides/get-started}/0.installation.md
  28. +5 −5 docs/0.typescript/{ → head/guides/0.get-started}/1.installation.md
  29. +9 −97 docs/{migration.md → 0.typescript/head/guides/0.get-started/1.migration.md}
  30. 0 ...pescript/{guides/wrapping-composables.md → head/guides/1.core-concepts/0.wrapping-composables.md}
  31. +2 −4 docs/{schema-org/0.react → 0.typescript/schema-org/guides/get-started}/0.installation.md
  32. +0 −194 docs/0.vue/guides/0.reactivity.md
  33. +0 −243 docs/0.vue/guides/2.managing-context.md
  34. +6 −6 docs/0.vue/{ → head/guides/0.get-started}/1.installation.md
  35. +371 −0 docs/0.vue/head/guides/0.get-started/1.migration.md
  36. +406 −0 docs/0.vue/head/guides/1.core-concepts/0.reactivity-and-context.md
  37. 0 docs/0.vue/{guides → head/guides/1.core-concepts}/1.components.md
  38. +1 −1 docs/0.vue/{guides → head/guides/1.core-concepts}/3.options-api.md
  39. 0 docs/0.vue/{guides → head/guides/1.core-concepts}/4.pausing-dom-rendering.md
  40. +1 −1 docs/{schema-org/0.vue → 0.vue/schema-org/guides/0.get-started}/0.installation.md
  41. 0 docs/{schema-org/0.vue/guides → 0.vue/schema-org/guides/1.core-concepts}/5.vue-components.md
  42. +0 −2 docs/1.guides/.navigation.yml
  43. +0 −186 docs/1.guides/0.titles.md
  44. +0 −157 docs/1.guides/2.positions.md
  45. +0 −82 docs/1.guides/3.class-attr.md
  46. +0 −63 docs/1.guides/4.inner-content.md
  47. +0 −199 docs/1.guides/6.handling-duplicates.md
  48. +0 −32 docs/1.guides/7.client-only-tags.md
  49. +0 −152 docs/1.guides/8.dom-event-handling.md
  50. +0 −5 docs/1.guides/8.hooks.md
  51. +0 −169 docs/1.guides/9.loading-scripts.md
  52. +0 −61 docs/1.guides/9.vite-plugin.md
  53. +0 −32 docs/3.troubleshooting.md
  54. +0 −2 docs/7.api/.navigation.yml
  55. +0 −99 docs/7.api/0.use-head.md
  56. +0 −46 docs/7.api/1.use-head-safe.md
  57. +0 −55 docs/7.api/3.use-seo-meta.md
  58. +0 −117 docs/7.api/4.use-script.md
  59. +0 −111 docs/7.api/6.use-server-head.md
  60. +1 −0 docs/head/1.guides/.navigation.yml
  61. +76 −0 docs/head/1.guides/0.get-started/0.overview.md
  62. +3 −7 docs/{0.introduction.md → head/1.guides/0.get-started/2.intro-to-unhead.md}
  63. +282 −0 docs/head/1.guides/0.get-started/4.starter-recipes.md
  64. +361 −0 docs/head/1.guides/1.core-concepts/1.titles.md
  65. +187 −0 docs/head/1.guides/1.core-concepts/2.positions.md
  66. +112 −0 docs/head/1.guides/1.core-concepts/3.class-attr.md
  67. +204 −0 docs/head/1.guides/1.core-concepts/4.inner-content.md
  68. +262 −0 docs/head/1.guides/1.core-concepts/6.handling-duplicates.md
  69. +217 −0 docs/head/1.guides/1.core-concepts/8.dom-event-handling.md
  70. +254 −0 docs/head/1.guides/1.core-concepts/9.loading-scripts.md
  71. +210 −0 docs/head/1.guides/2.advanced/11.extending-unhead.md
  72. +130 −0 docs/head/1.guides/2.advanced/7.client-only-tags.md
  73. +167 −0 docs/head/1.guides/2.advanced/9.vite-plugin.md
  74. +62 −16 docs/{ → head/1.guides}/plugins/6.template-params.md
  75. +87 −16 docs/{ → head/1.guides}/plugins/alias-sorting.md
  76. +117 −0 docs/head/1.guides/plugins/canonical.md
  77. +110 −0 docs/head/1.guides/plugins/infer-seo-meta-tags.md
  78. +1 −0 docs/head/7.api/.navigation.yml
  79. +49 −0 docs/head/7.api/0.get-started/overview.md
  80. +364 −0 docs/head/7.api/composables/0.use-head.md
  81. +114 −0 docs/head/7.api/composables/1.use-head-safe.md
  82. +132 −0 docs/head/7.api/composables/3.use-seo-meta.md
  83. +250 −0 docs/head/7.api/composables/4.use-script.md
  84. +165 −0 docs/head/7.api/composables/6.use-server-head.md
  85. +98 −0 docs/head/7.api/hooks/01.init.md
  86. +96 −0 docs/head/7.api/hooks/02.entries-updated.md
  87. +137 −0 docs/head/7.api/hooks/03.entries-resolve.md
  88. +130 −0 docs/head/7.api/hooks/04.entries-normalize.md
  89. +148 −0 docs/head/7.api/hooks/05.tag-normalise.md
  90. +162 −0 docs/head/7.api/hooks/06.tags-before-resolve.md
  91. +197 −0 docs/head/7.api/hooks/07.tags-resolve.md
  92. +196 −0 docs/head/7.api/hooks/08.tags-after-resolve.md
  93. +150 −0 docs/head/7.api/hooks/09.dom-before-render.md
  94. +200 −0 docs/head/7.api/hooks/10.dom-render-tag.md
  95. +193 −0 docs/head/7.api/hooks/11.dom-rendered.md
  96. +148 −0 docs/head/7.api/hooks/12.ssr-before-render.md
  97. +207 −0 docs/head/7.api/hooks/13.ssr-render.md
  98. +186 −0 docs/head/7.api/hooks/14.ssr-rendered.md
  99. +235 −0 docs/head/7.api/hooks/15.script-updated.md
  100. +0 −74 docs/plugins/canonical.md
  101. +0 −69 docs/plugins/infer-seo-meta-tags.md
  102. +0 −1 docs/schema-org/0.angular/.navigation.yml
  103. +0 −1 docs/schema-org/0.nuxt/.navigation.yml
  104. +0 −1 docs/schema-org/0.react/.navigation.yml
  105. +0 −1 docs/schema-org/0.svelte/.navigation.yml
  106. +0 −1 docs/schema-org/0.typescript/.navigation.yml
  107. +0 −1 docs/schema-org/0.vue/.navigation.yml
  108. +1 −1 docs/schema-org/2.guides/.navigation.yml
  109. +15 −1 docs/schema-org/{0.introduction.md → 2.guides/0.get-started/0.overview.md}
  110. +8 −0 docs/schema-org/2.guides/{ → 1.core-concepts}/2.deduping-nodes.md
  111. +7 −9 docs/schema-org/2.guides/{ → 1.core-concepts}/2.nodes.md
  112. +2 −12 docs/schema-org/2.guides/{ → 1.core-concepts}/3.params.md
  113. 0 docs/schema-org/{ → 2.guides}/4.recipes/.navigation.yml
  114. +6 −3 docs/schema-org/{ → 2.guides}/4.recipes/0.custom-nodes.md
  115. +15 −63 docs/schema-org/{ → 2.guides}/4.recipes/1.identity.md
  116. +10 −55 docs/schema-org/{ → 2.guides}/4.recipes/blog.md
  117. +26 −51 docs/schema-org/{ → 2.guides}/4.recipes/breadcrumbs.md
  118. +314 −0 docs/schema-org/2.guides/4.recipes/e-commerce.md
  119. +100 −0 docs/schema-org/2.guides/4.recipes/faq.md
  120. +216 −0 docs/schema-org/2.guides/4.recipes/how-to.md
  121. +6 −23 docs/schema-org/{ → 2.guides}/4.recipes/site-search.md
  122. +0 −8 docs/schema-org/2.guides/9.debugging.md
  123. +0 −20 docs/schema-org/3.troubleshooting.md
  124. +0 −39 docs/schema-org/4.recipes/e-commerce.md
  125. +0 −83 docs/schema-org/4.recipes/faq.md
  126. +0 −7 docs/schema-org/4.recipes/how-to.md
  127. 0 docs/schema-org/5.api/{ → 0.composables}/0.use-schema-org.md
  128. 0 docs/schema-org/{ → 5.api}/9.schema/.navigation.yml
  129. +3 −5 docs/schema-org/{ → 5.api}/9.schema/article.md
  130. +0 −2 docs/schema-org/{ → 5.api}/9.schema/book.md
  131. +1 −3 docs/schema-org/{ → 5.api}/9.schema/breadcrumb.md
  132. +1 −3 docs/schema-org/{ → 5.api}/9.schema/comment.md
  133. +0 −2 docs/schema-org/{ → 5.api}/9.schema/course.md
  134. +0 −2 docs/schema-org/{ → 5.api}/9.schema/event.md
  135. +1 −3 docs/schema-org/{ → 5.api}/9.schema/food-establishment.md
  136. +0 −3 docs/schema-org/{ → 5.api}/9.schema/how-to.md
  137. +1 −3 docs/schema-org/{ → 5.api}/9.schema/image.md
  138. +0 −2 docs/schema-org/{ → 5.api}/9.schema/item-list.md
  139. +2 −4 docs/schema-org/{ → 5.api}/9.schema/job-posting.md
  140. +1 −3 docs/schema-org/{ → 5.api}/9.schema/local-business.md
  141. +0 −2 docs/schema-org/{ → 5.api}/9.schema/movie.md
  142. +1 −3 docs/schema-org/{ → 5.api}/9.schema/organization.md
  143. +1 −3 docs/schema-org/{ → 5.api}/9.schema/person.md
  144. +1 −3 docs/schema-org/{ → 5.api}/9.schema/product.md
  145. +2 −4 docs/schema-org/{ → 5.api}/9.schema/question.md
  146. +1 −3 docs/schema-org/{ → 5.api}/9.schema/recipe.md
  147. +0 −2 docs/schema-org/{ → 5.api}/9.schema/software-app.md
  148. +1 −3 docs/schema-org/{ → 5.api}/9.schema/video.md
  149. +1 −4 docs/schema-org/{ → 5.api}/9.schema/webpage.md
  150. +0 −3 docs/schema-org/{ → 5.api}/9.schema/website.md
  151. +16 −16 examples/angular/package.json
  152. +5 −5 examples/vite-ssr-react-ts/package.json
  153. +4 −4 examples/vite-ssr-svelte/package.json
  154. +3 −3 examples/vite-ssr-ts/package.json
  155. +1 −1 examples/vite-ssr-vue-prerender/package.json
  156. +1 −1 examples/vite-ssr-vue-streaming/package.json
  157. +5 −5 examples/vite-ssr-vue/package.json
  158. +19 −19 examples/vite-ssr-vue/src/components/HelloWorld.vue
  159. +8 −8 package.json
  160. +3 −3 packages/addons/package.json
  161. +4 −4 packages/angular/package.json
  162. +1 −1 packages/react/package.json
  163. +1 −1 packages/schema-org/package.json
  164. +1 −1 packages/solid-js/package.json
  165. +3 −3 packages/svelte/package.json
  166. +1 −1 packages/unhead/package.json
  167. +1 −1 packages/unhead/src/client/renderDOMHead.ts
  168. +1 −0 packages/unhead/src/server/createHead.ts
  169. +3 −0 packages/unhead/src/types/hooks.ts
  170. +2 −0 packages/unhead/src/unhead.ts
  171. +311 −27 packages/unhead/test/unit/server/xss.test.ts
  172. +1 −1 packages/vue/package.json
  173. +1,306 −1,052 pnpm-lock.yaml
  174. +2 −0 renovate.json
155 changes: 155 additions & 0 deletions .claude/commands/analyze-docs.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
# Documentation Analysis and Improvement

This prompt helps analyze and improve Unhead documentation to create clean, approachable, and comprehensive documentation similar to anthropic.com, Vue.js, and Laravel.

## Documentation Analysis

When analyzing existing Unhead documentation, evaluate and provide recommendations for:

1. **Structure clarity**: Assess logical flow and hierarchy of information
2. **Completeness**: Identify missing concepts, edge cases, or examples
3. **Code examples**: Evaluate quality, relevance, and clarity
4. **Framework-specific guidance**: Check appropriate distinction between core and framework-specific features

## Documentation Standards

### Platform
- **Nuxt Content v3**: Documentation is built with Nuxt Content v3
- **MDC Format**: Content is authored in MDC (Markdown Components) format
- **Nuxt Components**: Leverage built-in and custom components. Use `::caution`, `::tip`, `::warning` and `::note` where appropriate

### MDC Syntax Guidelines
- **Component Usage**: Use `::component{}` syntax for components
- **Nested Components**: Structure complex components with proper nesting
- **Props**: Pass props to components using curly braces `{prop: value}`
- **Slots**: Use the slot syntax for component content
- **Code Blocks**: Use language-specific code blocks with syntax highlighting
- **Component Libraries**: Leverage built-in UI components from Nuxt Content

### Code Blocks
- **Language Tags**: All used hooks `useHead`, `useSeoMeta` should be imported from `@unhead/dynamic-import`
- **Import statements**: Include complete import statements
- **Framework-agnostic**: Unless explicitly in framework-specific section
- **Progressive complexity**: Simple examples first, then complex ones
- **Complete and minimal**: Include all necessary code, but no more
- **TypeScript**: Prefer TypeScript in examples when appropriate

### Structure
- **Consistent Hierarchy**: Organize with clear numbered sections (0.introduction.md, 1.guides/...)
- **Progressive Disclosure**: Basic concepts first, advanced topics later
- **Separation of Concerns**: Keep guides, API references, and examples distinct

### Content Guidelines
- **Clear and concise**: Use direct, simple language with minimal jargon
- **Conversational but professional**: Write as if explaining to a colleague
- **Active voice**: Prefer "Configure the plugin by..." over "The plugin can be configured by..."
- **Practical Examples**: Every feature should have real-world code examples
- **Complete API References**: Document all parameters, return values, and types
- **Starter Recipes**: Provide copy-paste solutions for common use cases
- **Troubleshooting**: Include common issues and their solutions
- **Framework Specifics**: Unless explicitly stated, examples should be framework-agnostic and code examples should import Unhead composables from `@unhead/dynamic-import`
- **Common Use Cases**: Include a "Common Use Cases" section where applicable to demonstrate practical applications
- **Best Practices**: Add guidance on recommended approaches and patterns
- **API Caveats**: Clearly document any limitations, edge cases, or unexpected behaviors
- **Internal Linking**: Add links to related sections within the documentation for easy navigation. We can find all links in the `src/content/docs/` folder as paths will map to the URL structure (without number prefixes)
- **Deprecation Functions**: Any of the `useServer*` composables are deprecated, we should recommend using `useHead` instead with `import.meta.server` instead and link to docs/1.guides/7.client-only-tags.md

### Page Structure
- **Front Matter**: Include YAML front matter with title, description and navigation.title. These should be optimized for SEO without keyword stuffing, reference specific frameworks if applicable
- **Title**: Not needed, this is generated from the front matter
- **Introduction**: Brief overview of the concept/component with high-level navigation to major sections
- **Core Concepts**: Breakdown of main functionality with clear section headings
- **Usage Examples**: Code examples with explanations
- **Advanced Usage**: More complex scenarios and advanced features when applicable
- **API Reference**: When applicable, with props/events/slots
- **Related Resources**: Links to relevant documentation to create a connected knowledge base

### Formatting
- **Alert Components**: Use specific alert components based on context:
- `::tip` - For best practices and recommendations
- `::note` - For additional information or context
- `::warning` or `::caution` - For potential issues or gotchas
- `::alert{type="info"}` - For general important notes
- **Tabs**: Use tab components for multi-framework examples
- **Code Groups**: Use code groups for related code examples
- **Diagrams**: Use visual aids for complex concepts
- **Consistency**: Maintain consistent terminology throughout
- **Inline Code**: When rendering inline `code` tags, always postfix with the lang:
- HTML tags: `<head>`{lang="html"}
- CSS/properties: `color`{lang="css"}
- JS/TS variables and code: `tagPriority`{lang="bash"} or `function`{lang="ts"}
- **Section Links**: Use anchor links to create navigation between sections of the document

### Maintenance
- **Version Specificity**: Indicate which version features were introduced
- **Regular Reviews**: Schedule periodic reviews to ensure accuracy
- **Deprecation Notices**: Clearly mark deprecated features
- **Change Log**: Maintain detailed documentation changes

## Section Templates

### Marketing Section

Some sections are more marketing-oriented, such as the introduction and overview. These should be written in a more engaging and less technical tone.
They should use specific components to enhance the user experience.

```md
::UPageCard{title="Tailwind CSS" description="Nuxt UI v3 integrates with latest Tailwind CSS v4, bringing significant improvements." icon="i-simple-icons-tailwindcss" orientation="horizontal" spotlight spotlight-color="primary"}
:img{src="/tailwindcss-v4.svg" alt="Tailwind CSS" class="w-full"}
::
```

### API Reference Section

```md
## API Reference

### Parameters

| Name | Type | Default | Description |
|------|------|---------|-------------|
| `param1` | `string` | `'default'` | Description of parameter |

### Returns

Description of return value and type

### Examples

```ts
// Simple example
```

### Component Section

```md
## ComponentName

Description of the component and when to use it.

### Props

| Name | Type | Default | Description |
|------|------|---------|-------------|
| `prop1` | `string` | `'default'` | Description of prop |

### Example

```vue
<template>
<ComponentName prop1="value" />
</template>
```

## Improvement Checklist

- [ ] Ensure all headings and page titles are clear and descriptive
- [ ] Confirm all code examples are complete and working
- [ ] Check that all parameters and options are documented
- [ ] Verify internal links are working correctly
- [ ] Review for consistent terminology
- [ ] Add practical examples for common use cases
- [ ] Include troubleshooting sections for common issues
- [ ] Provide migration paths from previous versions or other libraries

Unhead is a framework-agnostic head management library for managing HTML head tags in both client and server environments.
157 changes: 157 additions & 0 deletions .claude/commands/security-research.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
# Unhead Security Research Report

## Executive Summary

This report documents an assessment of Unhead's security measures against Cross-Site Scripting (XSS) vulnerabilities. Unhead is a framework-agnostic head management library for managing HTML head tags, making it a critical component in the security posture of web applications that use it.

## Methodology

- Code analysis of XSS prevention mechanisms
- Review of existing XSS test coverage
- Identification of potential attack vectors

## Findings

### XSS Protection Mechanisms

Unhead implements several security measures to prevent XSS:

1. **HTML Escaping**: The library uses the `escapeHtml` function in `tagToString.ts` which properly escapes the following characters:
- `&``&amp;`
- `<``&lt;`
- `>``&gt;`
- `"``&quot;`
- `'``&#x27;`
- `/``&#x2F;`

2. **Attribute Encoding**: The `encodeAttribute` function in `propsToString.ts` escapes double quotes in attribute values using `&quot;`.

3. **Content Type Handling**: Different encoding is applied based on content type:
- `textContent` is properly escaped to prevent XSS
- `innerHTML` is intentionally not escaped (dangerous but documented)

### Potential Vulnerabilities

1. **innerHTML Handling**: The code explicitly notes that innerHTML is "dangerously" used without encoding. This is a deliberate design choice to allow HTML in certain contexts, but creates a potential attack vector if user input is directly passed to innerHTML.

2. **Script Content**: When using script tags, the code properly handles the potential injection of `</script>` tags by using the `devalue` library, which correctly escapes such content.

3. **Attribute Escaping**: While double quotes are escaped in attribute values, the encoding is limited compared to the more comprehensive `escapeHtml` function. This might present edge cases in certain browser contexts.

4. **JSON Content**: Special attention is given to JSON content in script tags, with proper escaping via the `devalue` library.

## Attack Vectors to Explore

1. **Contextual Bypasses**: Test if escaping works in all contexts (HTML, attributes, JavaScript, CSS, URL)
2. **DOM-based XSS**: Examine client-side rendering for potential DOM XSS vectors
3. **Template Injection**: Test handling of complex template variables and expressions
4. **Script Execution**: Test script loading mechanisms and event handling
5. **Sanitization Bypass**: Attempt to bypass the escaping mechanisms

## Recommendations

1. **innerHTML Usage**: Consider adding a sanitization option for innerHTML content
2. **Attribute Encoding**: Enhance the attribute encoding to match the more comprehensive HTML encoding
3. **Additional Test Coverage**: Expand test coverage for edge cases and exotic payloads
4. **User Documentation**: Clearly document security best practices for users of the library
5. **URL Sanitization**: Implement sanitization for potentially dangerous URL schemas like javascript:, data:, and vbscript:
6. **Meta Tag Content**: Add proper content sanitization for meta tags to prevent SVG-based and other XSS payloads
7. **CSS Protection**: Consider sanitizing style content to prevent CSS-based attacks

## Comprehensive XSS Example

```js
// Example of a useHead() call that attempts to exploit multiple XSS vectors
useHead({
// Title injection
title: '</title><script>alert("title XSS")</script>',
titleTemplate: '%s - <script>alert("template")</script>',

// Meta tag vectors
meta: [
// SVG-based XSS
{ name: 'description', content: '<svg><script>alert("svg")</script></svg>' },
// Attribute injection
{ name: 'keywords" onload="alert("attr")', content: 'SEO keywords' },
// Unicode escape sequence
{ name: 'author', content: '\\u003Cscript\\u003Ealert("unicode")\\u003C/script\\u003E' },
// Character encoding attack
{ 'http-equiv': 'content-type', content: 'text/html; charset=UTF-7; X-XSS-Protection: "0";' },
// Case variation bypass
{ name: 'viewport', content: '<ScRiPt>alert("case")</ScRiPt>' },
// Emoji obfuscation
{ name: 'robots', content: '📝➡️<script>alert("emoji")</script>' },
// innerHTML attempt (shouldn't work)
{ name: 'generator', innerHTML: '<script>alert("meta-inner")</script>' }
],

// Link attacks
link: [
// Javascript protocol
{ rel: 'stylesheet', href: 'javascript:alert("js-protocol")' },
// Data URI
{ rel: 'icon', href: 'data:text/html;base64,PHNjcmlwdD5hbGVydCgieHNzIik8L3NjcmlwdD4=' },
// Protocol switching
{ rel: 'dns-prefetch', href: '//evil.com/xss.js' },
// HTML-encoded colon
{ rel: 'preconnect', href: 'javascript&#58;alert("encoded")' },
// Other protocol
{ rel: 'prefetch', href: 'vbscript:alert("vbscript")' }
],

// Script attacks
script: [
// Template literal with closing script
{ innerHTML: `
const template = \`
</script>
<img src=x onerror="alert('template-literal')">
<script>
\`;
console.log(template);
` },
// Null byte insertion
{ innerHTML: `console.log("Null byte attack: \\0')</script><script>alert('null-byte')</script>")` },
// String concatenation bypass
{ innerHTML: `console.log("</scr"+"ipt><script>alert('concat')</script>")` },
// mXSS payload
{ innerHTML: `var xss = '<img src="1" onerror="alert(\\'mxss\\')" />';` },
// JSON with devalue (should be properly escaped)
{ type: 'application/json', innerHTML: JSON.stringify({ payload: '</script><script>alert("json")</script>' }) }
],

// Style attacks
style: [
// CSS expression
{ innerHTML: `body { color: expression(alert('css-expression')) }` },
// CSS url injection
{ innerHTML: `body { background: url('javascript:alert("css-url")') }` }
],

// HTML attributes
htmlAttrs: {
'onload': 'alert("html-event")',
'data-attr': '"><script>alert("html-attr")</script>'
},

// Body attributes
bodyAttrs: {
'data-custom': `x" onmouseover="alert('body-attr')" data-x="`
},

// Base attack
base: { href: 'javascript:alert("base")' }
})
```

## Next Steps

Further testing required:
- Dynamic content insertion
- Framework-specific integration points
- Client-side rendering security
- Event handler sanitization

---

*This is an initial security assessment and should be followed by comprehensive penetration testing.*
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -3,7 +3,8 @@
[![npm version](https://img.shields.io/npm/v/unhead?color=yellow)](https://npmjs.com/package/unhead)
[![npm downloads](https://img.shields.io/npm/dm/unhead?color=yellow)](https://npm.chart.dev/unhead)

Unhead wraps your document template, improving reactive SSR JavaScript framework SEO and performance.
Unhead is a document head and template manager, improving reactive SSR JavaScript framework developer experience, SEO and performance.
See the full [introduction to Unhead](https://unhead.unjs.io/docs/typescript/head/guides/get-started/intro-to-unhead).

<p align="center">
<table>
@@ -15,6 +16,10 @@ Unhead wraps your document template, improving reactive SSR JavaScript framework
</table>
</p>

### Unhead v2 🎉

The latest major is now stable! Check out the [v2 release notes](https://unhead.unjs.io/v2).

## Highlights

-`useHead()`: Deduping, sorting, and tag merging
4 changes: 2 additions & 2 deletions bench/bundle/last.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"client": {
"size": 10978,
"gz": 4574
"size": 11001,
"gz": 4582
},
"server": {
"size": 8179,
Original file line number Diff line number Diff line change
@@ -5,18 +5,16 @@ navigation:
title: 'Installation'
---

# Installing Unhead with Angular

Unhead provides first-class support for Angular, allowing you to manage your head tags using composables like `useHead()`, `useSeoMeta()`, and others within your Angular components.
- [StackBlitz - Unhead - Angular SPA](https://stackblitz.com/edit/stackblitz-starters-e4x42yaz)
-
- [StackBlitz - Unhead - Angular](https://stackblitz.com/edit/stackblitz-starters-e4x42yaz)

## Setup

### 1. Add Dependency

Install the Angular-specific Unhead package:

:ModuleInstall{name="@unhead/angular@next"}
:ModuleInstall{name="@unhead/angular"}

### 2. Setup Client-Side Rendering

@@ -167,7 +165,7 @@ export class CounterComponent {
}
```

For more details on reactivity, check the [Angular Reactivity Guide](/docs/angular/guides/reactivity).
For more details on reactivity, check the [Angular Reactivity Guide](/docs/angular/head/guides/core-concepts/reactivity).

## Default Tags

@@ -183,11 +181,11 @@ You can customize these defaults or add additional ones through the `init` optio
Your Angular app is now ready for head management! 🎉

Explore the available composables:
- [`useHead()`](/docs/api/use-head)
- [`useSeoMeta()`](/docs/api/use-seo-meta)
- [`useScript()`](/docs/api/use-script)
- [`useHead()`](/docs/head/api/composables/use-head)
- [`useSeoMeta()`](/docs/head/api/composables/use-seo-meta)
- [`useScript()`](/docs/head/api/composables/use-script)

Or explore additional functionality:
- Learn about [reactivity](/docs/angular/guides/reactivity) in Angular
- Add structured data with [`useSchemaOrg()`](/docs/api/use-schema-org)
- Explore [title templates](/docs/guides/titles) for consistent page titles
- Learn about [reactivity](/docs/angular/head/guides/core-concepts/reactivity) in Angular
- Add structured data with [`useSchemaOrg()`](/docs/head/api/composables/use-schema-org)
- Explore [title templates](/docs/head/guides/core-concepts/titles) for consistent page titles
File renamed without changes.
Loading