Add trusted sanitized fragments for safeHtml composition#61
Add trusted sanitized fragments for safeHtml composition#61JosunLP merged 9 commits intodevelopmentfrom
safeHtml composition#61Conversation
Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com>
Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com>
safeHtml composition
There was a problem hiding this comment.
Pull request overview
Adds a “trusted fragment” mechanism to allow composing already-sanitized markup inside safeHtml templates without double-escaping, while keeping default escaping behavior for all other interpolations.
Changes:
- Introduces branded
SanitizedHtml/TrustedHtmltypes and atrusted()helper in the security module. - Updates
safeHtmlto splicetrusted(...)interpolations verbatim and escape everything else. - Adds targeted tests and documentation for trusted fragment composition, plus re-exports via
@bquery/bquery/securityandfullbundle.
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/security.test.ts | Adds coverage for trusted(sanitizeHtml(...)) wrapper behavior. |
| tests/component.test.ts | Adds coverage for safeHtml escaping + trusted fragment composition (including nested safeHtml). |
| src/security/sanitize.ts | Adds branded types and trusted marker implementation; changes sanitizeHtml return type to SanitizedHtml. |
| src/security/index.ts | Re-exports trusted and the new branded types from the security entrypoint. |
| src/full.ts | Re-exports trusted and branded types from the full bundle entrypoint. |
| src/component/html.ts | Updates safeHtml to detect and splice trusted fragments and escape non-trusted values. |
| docs/guide/security.md | Documents trusted fragment composition pattern for safeHtml. |
| docs/guide/components.md | Updates component guide examples to mention/use the new trusted composition pattern. |
Signed-off-by: Jonas Pfalzgraf <info@josunlp.de>
|
@copilot apply changes based on the comments in this thread |
Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com>
Addressed in a235d1f. Updated the misleading SVG examples, clarified the |
There was a problem hiding this comment.
Pull request overview
This PR introduces an explicit “trusted fragment” mechanism to allow composing already-sanitized HTML inside safeHtml templates without double-escaping, while preserving safeHtml’s default escaping behavior across the codebase.
Changes:
- Add branded
SanitizedHtml/TrustedHtmltypes and atrusted()wrapper in the security module, with updated public exports. - Update
safeHtmlto returnSanitizedHtmland to splicetrusted(...)interpolations verbatim (no re-escaping). - Add targeted tests and documentation updates describing the new composition pattern.
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
src/security/sanitize.ts |
Introduces SanitizedHtml/TrustedHtml, updates sanitizeHtml() return type, adds trusted() + internal helpers. |
src/component/html.ts |
Updates safeHtml to return SanitizedHtml and support trusted fragment splicing. |
src/security/index.ts |
Re-exports trusted and the new branded types from the security entrypoint. |
src/full.ts |
Re-exports trusted and branded types from the full/CDN entrypoint. |
tests/security.test.ts |
Adds coverage for trusted(sanitizeHtml(...)) behavior. |
tests/component.test.ts |
Adds coverage for default escaping and trusted fragment composition in safeHtml. |
docs/guide/security.md |
Documents the new trusted-fragment composition pattern. |
docs/guide/components.md |
Updates component guide example to demonstrate trusted(sanitizeHtml(...)) with safeHtml. |
|
@copilot apply changes based on the comments in this thread |
Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com>
Addressed in b699a34. I removed the unsupported |
There was a problem hiding this comment.
Pull request overview
Adds an explicit “trusted sanitized fragment” mechanism so safeHtml can compose already-sanitized markup without double-escaping, while keeping default escaping for all non-trusted interpolations.
Changes:
- Introduces branded
SanitizedHtml/TrustedHtmlplustrusted()and internal unwrapping helpers in the security sanitizer module. - Updates
safeHtmlto splicetrusted(...)interpolations verbatim and returnsSanitizedHtml. - Re-exports new security APIs/types and adds targeted tests + docs describing the new composition pattern.
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| tests/security.test.ts | Adds unit test for trusted(sanitizeHtml(...)) reuse behavior. |
| tests/component.test.ts | Adds coverage for safeHtml escaping and trusted fragment composition (including nested safeHtml). |
| src/security/sanitize.ts | Adds branded HTML types, trusted(), and internal trusted-marker detection/unwrapping; sanitizeHtml() now returns SanitizedHtml. |
| src/security/index.ts | Re-exports trusted and the new types from the security entrypoint. |
| src/full.ts | Re-exports trusted and types from the full bundle entrypoint. |
| src/component/html.ts | Updates safeHtml to detect trusted markers and return branded SanitizedHtml. |
| docs/guide/security.md | Documents trusted fragment composition with trusted(sanitizeHtml(...)) inside safeHtml. |
| docs/guide/components.md | Updates component guide example to use safeHtml and demonstrate trusted fragment reuse. |
|
@copilot apply changes based on the comments in this thread |
Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com>
Addressed in 3fcb0fc. I moved the branded trusted/sanitized HTML helpers into a lightweight |
There was a problem hiding this comment.
Pull request overview
Adds a first-class “trusted fragment” mechanism so safeHtml can compose already-sanitized/escaped HTML without rendering it as text, while keeping default escaping for normal interpolations.
Changes:
- Introduces branded
SanitizedHtmlplus aTrustedHtmlmarker andtrusted()helper for explicit opt-in composition. - Updates
sanitizeHtml()andsafeHtmlto produce/consume branded sanitized output and splicetrusted(...)content verbatim. - Adds targeted tests and updates guides to document the new composition pattern.
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/security.test.ts | Adds a unit test for trusted(sanitizeHtml(...)) stringification. |
| tests/component.test.ts | Adds coverage for safeHtml escaping and trusted fragment composition (including nested composition). |
| src/security/trusted-html.ts | New brands + trusted() marker, plus internal detection/unwrap helpers. |
| src/security/sanitize.ts | Makes sanitizeHtml() return SanitizedHtml and re-exports trusted helpers/types. |
| src/security/index.ts | Re-exports trusted and branded types from the security entrypoint. |
| src/full.ts | Re-exports trusted and branded types from the full/CDN bundle entrypoint. |
| src/component/html.ts | Updates safeHtml to return SanitizedHtml and splice trusted markers without escaping. |
| docs/guide/security.md | Documents trusted fragment composition with trusted(sanitizeHtml(...)) inside safeHtml. |
| docs/guide/components.md | Updates component guide example to show safeHtml + trusted(sanitizeHtml(...)) composition. |
|
@copilot apply changes based on the comments in this thread |
Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com>
Addressed in 5b4ebef. |
There was a problem hiding this comment.
Pull request overview
Adds a trusted-fragment composition path so safeHtml can embed already-sanitized (or otherwise safe) HTML fragments without re-escaping, while keeping default escaping behavior for all other interpolations.
Changes:
- Introduces branded
SanitizedHtmland markerTrustedHtml, plustrusted()for verbatim reuse insafeHtml. - Updates
sanitizeHtml()andsafeHtml()to returnSanitizedHtml, and updatessafeHtml()to splicetrusted(...)values without escaping. - Adds targeted tests and updates docs to describe the new composition pattern.
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/security.test.ts | Adds coverage for trusted(sanitizeHtml(...)) basic behavior. |
| tests/component.test.ts | Adds safeHtml escaping + trusted fragment composition tests. |
| src/security/trusted-html.ts | Defines SanitizedHtml / TrustedHtml and trusted() + internal helpers. |
| src/security/sanitize.ts | Makes sanitizeHtml() return SanitizedHtml; re-exports trusted/types. |
| src/security/index.ts | Re-exports trusted, SanitizedHtml, TrustedHtml, and SanitizeOptions from the security entrypoint. |
| src/full.ts | Re-exports trusted and the new branded types from the full bundle entrypoint. |
| src/component/html.ts | Updates safeHtml to return SanitizedHtml and splice trusted markers without escaping. |
| docs/guide/security.md | Documents trusted fragment composition with trusted(sanitizeHtml(...)). |
| docs/guide/components.md | Updates component guide example to show composing trusted fragments inside safeHtml. |
|
@copilot apply changes based on the comments in this thread |
Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com>
Addressed in fb89b00. |
There was a problem hiding this comment.
Pull request overview
Adds a typed, explicit “trusted sanitized fragment” mechanism so safeHtml can compose already-sanitized markup without rendering it as escaped text, while keeping default escaping for normal interpolations.
Changes:
- Introduces branded
SanitizedHtmlplus aTrustedHtmlmarker viatrusted()and internal unwrap helpers. - Updates
sanitizeHtml()andsafeHtml()to returnSanitizedHtml, and teachessafeHtmlto splicetrusted(...)values verbatim. - Adds targeted tests and updates docs/examples to describe the new composition pattern and exports.
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| tests/security.test.ts | Adds coverage for trusted(sanitizeHtml(...)) stringification. |
| tests/component.test.ts | Adds safeHtml escaping + trusted-fragment composition tests (including nesting). |
| src/security/trusted-html.ts | New branded types and trusted-marker implementation (trusted, isTrustedHtml, unwrap). |
| src/security/sanitize.ts | Changes sanitizeHtml() to return SanitizedHtml; re-exports trusted and types. |
| src/security/index.ts | Updates public security entrypoint exports to include trusted and branded types. |
| src/full.ts | Re-exports trusted and branded types from the full bundle entrypoint. |
| src/component/html.ts | Updates safeHtml to return SanitizedHtml and splice TrustedHtml without escaping. |
| docs/guide/security.md | Documents trusted fragment composition pattern for safeHtml. |
| docs/guide/components.md | Updates component guide example to demonstrate trusted(sanitizeHtml(...)) composition. |
* Add `bool()` support for boolean attributes in component templates (#55) Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: Jonas Pfalzgraf <info@josunlp.de> * Add typed state generics to component definitions (#56) Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: Jonas Pfalzgraf <info@josunlp.de> * Pass attribute change metadata to component `updated()` hooks (#58) Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: Jonas Pfalzgraf <info@josunlp.de> * Add per-component sanitizer overrides for component render output (#57) * Initial plan * feat: add per-component sanitizer options Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> * docs: clarify component sanitizer baseline Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> * docs: warn about sensitive component sanitizer opts Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> * test: cover sanitizer allowTags overrides Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> * perf: precompute component sanitizer allowlists Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> --------- Signed-off-by: Jonas Pfalzgraf <info@josunlp.de> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> Co-authored-by: Jonas Pfalzgraf <info@josunlp.de> * Pass previous props into component `beforeUpdate` (#59) * Initial plan * Add previous props to beforeUpdate hook Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> * Refine beforeUpdate old props implementation Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> * Fix beforeUpdate typing regressions Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> --------- Signed-off-by: Jonas Pfalzgraf <info@josunlp.de> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> Co-authored-by: Jonas Pfalzgraf <info@josunlp.de> * Add explicit signal subscriptions to `component()` renders (#60) * Initial plan * feat: add component signal subscriptions Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> * chore: document signal subscription tracking Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> * fix: address signal integration review feedback Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> * fix: tighten component signal typing Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> * fix: resolve eslint failure in component signal test Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> * fix: handle reconnect lifecycle and signal effect errors Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> * fix: preserve reconnect signal wiring after hook errors Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> * fix: skip beforeUpdate for signal rerenders Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> --------- Signed-off-by: Jonas Pfalzgraf <info@josunlp.de> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> Co-authored-by: Jonas Pfalzgraf <info@josunlp.de> * Add trusted sanitized fragments for `safeHtml` composition (#61) * Initial plan * feat: add trusted safeHtml fragment support Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> * chore: finalize trusted safeHtml support Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> * docs: address trusted safeHtml review feedback Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> * docs: fix second trusted safeHtml review follow-up Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> * refactor: split trusted html helpers from sanitizer Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> * refactor: tighten trusted html branding Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> * docs: tighten trusted html internals Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> --------- Signed-off-by: Jonas Pfalzgraf <info@josunlp.de> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> Co-authored-by: Jonas Pfalzgraf <info@josunlp.de> * Reuse component shadow-root style nodes across re-renders (#62) * Initial plan * fix: reuse component style element on rerender Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> * chore: finalize component style reuse fix Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> * test: tighten style reuse regression assertions Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> * Add `@bquery/bquery/storybook` template helpers for Storybook stories (#63) * Initial plan * feat: add storybook template helper Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> * docs: clarify storybook when fallback behavior Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> * fix: keep storybook helpers out of full bundle Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> * fix: sanitize storybook helper output Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> * test: tighten storybook helper security coverage Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> * feat: enhance storyHtml with improved boolean attribute handling and sanitization tests * fix: update storyHtml example to reflect correct boolean attribute output * fix: defensive tag delimiter and parser comments per code review Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> * chore: release version 1.6.0 - Update CHANGELOG.md for version 1.6.0 release notes including added features, changes, fixes, and security improvements. - Enhance README.md to document new boolean attribute helpers and Storybook integration. - Update bun.lock to reflect dependency upgrades for Storybook and happy-dom. - Modify definition.md to include new Storybook helpers and component state management features. - Revise components.md to demonstrate new boolean attribute handling and typed state in components. - Update getting-started.md with Storybook authoring examples and improved module descriptions. - Enhance security.md to clarify sanitization practices and introduce trusted fragment handling. - Revise index.md to highlight new Storybook helpers in the feature list. - Update llms.txt to reflect the new version 1.6.0. - Bump version in package.json to 1.6.0 and update devDependencies for Storybook. * Address review feedback for test setup, test type coverage, and component state keys (#65) * Initial plan * Address review feedback for test typing and setup Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> * Finalize review feedback fixes Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> * Export component state key type Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> * Default component state key generic Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> * Tighten component/state update semantics and Storybook attribute sanitization (#66) * Initial plan * fix review follow-up for state updates and storybook sanitization Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> * fix storybook attribute value scanning Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> * fix storybook interpolation boundary parsing Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> * docs align storybook attribute scan jsdoc Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> --------- Signed-off-by: Jonas Pfalzgraf <info@josunlp.de> Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
* Initial plan * feat: add trusted safeHtml fragment support Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> * chore: finalize trusted safeHtml support Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> * docs: address trusted safeHtml review feedback Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> * docs: fix second trusted safeHtml review follow-up Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> * refactor: split trusted html helpers from sanitizer Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> * refactor: tighten trusted html branding Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> * docs: tighten trusted html internals Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> --------- Signed-off-by: Jonas Pfalzgraf <info@josunlp.de> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> Co-authored-by: Jonas Pfalzgraf <info@josunlp.de>
safeHtmlescaped every interpolation, so already-sanitized fragments could not be composed without being rendered as text. This change adds an explicit trusted-content path for sanitized HTML while preservingsafeHtml's default escaping behavior.Security API
SanitizedHtml/TrustedHtmltypes in@bquery/bquery/securitysanitizeHtml()to returnSanitizedHtmltrusted()to mark sanitized fragments for verbatim reuseTemplate composition
safeHtmlto detecttrusted(...)interpolations and splice them without re-escapingPublic exports
trusted,SanitizedHtml, andTrustedHtmlfrom the security entrypoint and full bundleDocs and examples
Targeted coverage
safeHtmlescapingtrusted(sanitizeHtml(...))insidesafeHtmlsafeHtmlfragments throughtrusted(...)Example:
✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.