Skip to content

Clean up extension system and improve documentation#1965

Merged
yujonglee merged 3 commits intomainfrom
devin/1764302447-extension-system-cleanup
Nov 28, 2025
Merged

Clean up extension system and improve documentation#1965
yujonglee merged 3 commits intomainfrom
devin/1764302447-extension-system-cleanup

Conversation

@yujonglee
Copy link
Contributor

@yujonglee yujonglee commented Nov 28, 2025

Clean up extension system and improve documentation

Summary

This PR cleans up rough patches in the extension system code and significantly expands the developer documentation. The main changes are:

Code cleanup:

  • Consolidated ExtensionViewProps to re-export from @hypr/plugin-extensions instead of defining locally in apps/desktop/src/types/extensions.ts
  • Removed unused registry functions (loadExtensionUI, registerExtensionComponent, getExtensionComponent, getBundledExtensions) that were part of an old registry-based UI loading pattern no longer used since extensions now load via iframe
  • Created shared isExtHostPath utility for consistent ext-host path checking across __root.tsx and route.tsx
  • Simplified verbose comments in index.html Tauri polyfill section

Documentation improvements in 8.extensions.mdx:

  • Documented previously missing globals: @hypr/tabs, tinybase/ui-react
  • Added State Synchronization section explaining TinyBase read/write patterns
  • Added Opening Tabs section with useTabs examples
  • Expanded Security Model with Tauri API isolation and state sync security details
  • Added Calendar extension example
  • Clarified testing workflow with explicit ONBOARDING=0 pnpm -F desktop tauri dev command
  • Clarified that runtime script currently serves primarily for logging and future extensibility

Updates since last revision

  • Fixed "Writing State" documentation example to include extensionState definition (was using it without defining)
  • Fixed "Reading State" example to remove unused storeInstance variable and use tinybase/ui-react directly
  • Fixed @hypr/store references - Removed references to @hypr/store from docs since it's an internal esbuild alias, not a real npm package. Documentation now uses tinybase/ui-react hooks directly (matching the hello-world extension pattern)
  • Updated available UI components list to accurately reflect extension-globals.ts (Button, ButtonGroup, Card, Checkbox, Popover)
  • Added note clarifying that the runtime script is required but main functionality comes from panel UI

Review & Testing Checklist for Human

  • Verify removed registry functions are truly unused - I verified via grep but please double-check that loadExtensionUI, registerExtensionComponent, getExtensionComponent, getBundledExtensions aren't called anywhere
  • Test hello-world extension loads correctly - Run ONBOARDING=0 pnpm -F desktop tauri dev, click profile area ("Unknown"), click "Hello World" extension
  • Review documentation code examples - The TinyBase examples now use tinybase/ui-react directly; verify they match actual API usage patterns in hello-world extension

Recommended test plan:

  1. Build extensions: cd extensions && pnpm install && pnpm build && pnpm install:dev
  2. Run desktop app: ONBOARDING=0 pnpm -F desktop tauri dev
  3. Click profile area to expand menu
  4. Click "Hello World" extension and verify it renders correctly

Notes

- Consolidate ExtensionViewProps to re-export from @hypr/plugin-extensions
- Remove unused registry functions (loadExtensionUI, registerExtensionComponent, etc.)
- Create shared isExtHostPath utility for consistent ext-host path checking
- Simplify index.html Tauri polyfill comments
- Update extensions.mdx with comprehensive documentation:
  - Document @hypr/store, @hypr/tabs, and tinybase/ui-react globals
  - Add State Synchronization section with TinyBase examples
  - Add Opening Tabs section with useTabs examples
  - Expand Security Model with Tauri API isolation and state sync security
  - Add Calendar extension example

Co-Authored-By: yujonglee <yujonglee.dev@gmail.com>
@devin-ai-integration
Copy link
Contributor

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR that start with 'DevinAI' or '@devin'.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment and CI monitoring

@netlify
Copy link

netlify bot commented Nov 28, 2025

Deploy Preview for hyprnote ready!

Name Link
🔨 Latest commit 3460d18
🔍 Latest deploy log https://app.netlify.com/projects/hyprnote/deploys/69292adc8db19d0008bebaf9
😎 Deploy Preview https://deploy-preview-1965--hyprnote.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@netlify
Copy link

netlify bot commented Nov 28, 2025

Deploy Preview for hyprnote-storybook ready!

Name Link
🔨 Latest commit 3460d18
🔍 Latest deploy log https://app.netlify.com/projects/hyprnote-storybook/deploys/69292adce9ef96000825f2cd
😎 Deploy Preview https://deploy-preview-1965--hyprnote-storybook.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 28, 2025

📝 Walkthrough

Walkthrough

Removes dynamic/bundled extension component registries and UI-loading APIs, adds an isExtHostPath helper used by routes, re-exports ExtensionViewProps from @hypr/plugin-extensions, trims an iframe polyfill comment in index.html, and expands extension docs content.

Changes

Cohort / File(s) Summary
Extension Registry Refactoring
apps/desktop/src/components/main/body/extensions/registry.ts
Removed exports and state for dynamic/bundled extension components and UI loading: bundledExtensionComponents, dynamicExtensionComponents, getExtensionComponent, registerExtensionComponent, getBundledExtensions, loadExtensionUI, and loadingExtensions. Kept core listing/panel utilities.
Ext-host Path Detection
apps/desktop/src/utils/ext-host.ts, apps/desktop/src/routes/__root.tsx, apps/desktop/src/routes/app/route.tsx
Added isExtHostPath(pathname: string) and replaced inline pathname checks in route files with this helper.
Types Export Change
apps/desktop/src/types/extensions.ts
Replaced local ExtensionViewProps interface with export type { ExtensionViewProps } from "@hypr/plugin-extensions";.
Minor HTML Comment Change
apps/desktop/index.html
Shortened a multi-line iframe/TAURI_INTERNALS polyfill comment to a single-line comment; runtime assignment unchanged.
Documentation Expansion
apps/web/content/docs/developers/8.extensions.mdx
Large documentation additions and reorganization: expanded globals, state synchronization examples, opening tabs/calendar examples, and security/sandboxing guidance; no code changes.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Check for any remaining callsites expecting the removed registry exports (getExtensionComponent, registerExtensionComponent, loadExtensionUI, bundled/dynamic registries).
  • Verify the codebase compiles with ExtensionViewProps sourced from @hypr/plugin-extensions and update imports if necessary.
  • Confirm isExtHostPath covers edge cases and route behavior remains identical.

Possibly related PRs

Suggested reviewers

  • yujonglee

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarizes the main changes: cleaning up extension system code and improving documentation, which directly aligns with the changeset.
Description check ✅ Passed The description is comprehensive and directly related to the changeset, covering all major code cleanup and documentation improvements with clear explanations and testing guidance.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch devin/1764302447-extension-system-cleanup

📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 089e63e and 3460d18.

📒 Files selected for processing (1)
  • apps/web/content/docs/developers/8.extensions.mdx (5 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
  • GitHub Check: ci (macos, depot-macos-14)
  • GitHub Check: Redirect rules - hyprnote
  • GitHub Check: ci (linux, depot-ubuntu-22.04-8)
  • GitHub Check: ci (linux, depot-ubuntu-24.04-8)
  • GitHub Check: ci (macos, macos-14)
  • GitHub Check: fmt
  • GitHub Check: Header rules - hyprnote
  • GitHub Check: Pages changed - hyprnote
🔇 Additional comments (6)
apps/web/content/docs/developers/8.extensions.mdx (6)

68-91: Clarify whether the runtime script is mandatory or optional.

Line 91 states the runtime is "required in the manifest" but "currently serves primarily for logging and future extensibility," which is ambiguous. Does this mean extensions can omit the runtime for UI-only panels, or must all extensions define one even if unused?

For readers, this distinction is important: it affects how they structure their extensions. Consider explicitly stating whether extensions can be UI-only (with an empty or minimal main.js) or must always implement runtime handlers.

Can you confirm whether the entry field in the manifest is mandatory for UI-only extensions, or if it can be omitted entirely?


126-153: Available Globals section is well-structured and accurate.

The reorganized subsections clearly distinguish between React/UI, state management, and navigation APIs. The import example is self-contained and matches the documented globals.


155-211: State Synchronization examples are well-formed and self-contained.

Both the Reading and Writing State examples properly define and use extensionState via useRow(), imports are complete, and typing is clear. The examples effectively demonstrate the TinyBase synchronization pattern without undefined variables or unused imports.


213-240: Verify the @hypr/tabs API and valid tab types.

The Opening Tabs example uses useTabs((state) => state.openNew) with calls like openNew({ type: "sessions", id: sessionId }) and openNew({ type: "calendars", month: new Date() }). Confirm that:

  • The openNew method accepts this object shape
  • "sessions" and "calendars" are valid type values
  • The parameter keys (id, month) match the actual API

This ensures readers implement the hook correctly without API surprises.


320-344: Security Model documentation is comprehensive and well-structured.

The subsections clearly explain iframe sandbox isolation, Tauri API blocking via polyfill, script URL validation via convertFileSrc, origin-validated postMessage, and component export validation. This provides readers with a solid understanding of the trust boundaries and security layers.


346-381: Example sections are clear and actionable.

The Hello World section now correctly references "local and synchronized state using TinyBase" and the ONBOARDING=0 environment variable provides a clear testing path. The Calendar example introduces a more complex pattern (reading app data, navigation via @hypr/tabs). Build and install steps are included for both.


Comment @coderabbitai help to get the list of available commands and usage tips.

@argos-ci
Copy link

argos-ci bot commented Nov 28, 2025

The latest updates on your projects. Learn more about Argos notifications ↗︎

Build Status Details Updated (UTC)
web (Inspect) ⚠️ Changes detected (Review) 2 changed Nov 28, 2025, 4:58 AM

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ba772ba and 0d21c5c.

📒 Files selected for processing (7)
  • apps/desktop/index.html (1 hunks)
  • apps/desktop/src/components/main/body/extensions/registry.ts (0 hunks)
  • apps/desktop/src/routes/__root.tsx (2 hunks)
  • apps/desktop/src/routes/app/route.tsx (2 hunks)
  • apps/desktop/src/types/extensions.ts (1 hunks)
  • apps/desktop/src/utils/ext-host.ts (1 hunks)
  • apps/web/content/docs/developers/8.extensions.mdx (3 hunks)
💤 Files with no reviewable changes (1)
  • apps/desktop/src/components/main/body/extensions/registry.ts
🧰 Additional context used
📓 Path-based instructions (2)
**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.ts: Agent implementations should use TypeScript and follow the established architectural patterns defined in the agent framework
Agent communication should use defined message protocols and interfaces

Files:

  • apps/desktop/src/types/extensions.ts
  • apps/desktop/src/utils/ext-host.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Avoid creating a bunch of types/interfaces if they are not shared. Especially for function props, just inline them instead.
Never do manual state management for form/mutation. Use useForm (from tanstack-form) and useQuery/useMutation (from tanstack-query) instead for 99% of cases. Avoid patterns like setError.
If there are many classNames with conditional logic, use cn (import from @hypr/utils). It is similar to clsx. Always pass an array and split by logical grouping.
Use motion/react instead of framer-motion.

Files:

  • apps/desktop/src/types/extensions.ts
  • apps/desktop/src/utils/ext-host.ts
  • apps/desktop/src/routes/app/route.tsx
  • apps/desktop/src/routes/__root.tsx
🧬 Code graph analysis (2)
apps/desktop/src/routes/app/route.tsx (1)
apps/desktop/src/utils/ext-host.ts (1)
  • isExtHostPath (1-3)
apps/desktop/src/routes/__root.tsx (1)
apps/desktop/src/utils/ext-host.ts (1)
  • isExtHostPath (1-3)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: ci (macos, macos-14)
  • GitHub Check: ci (linux, depot-ubuntu-22.04-8)
  • GitHub Check: ci (linux, depot-ubuntu-24.04-8)
  • GitHub Check: ci (macos, depot-macos-14)
  • GitHub Check: fmt
🔇 Additional comments (6)
apps/desktop/index.html (1)

17-17: Comment update correctly reflects the iframe TAURI polyfill

The shorter comment is accurate and helpfully points to the new extensions docs; behavior of the polyfill remains unchanged.

apps/desktop/src/types/extensions.ts (1)

1-1: Centralizing ExtensionViewProps via re-export is a good simplification

Re-exporting the type from @hypr/plugin-extensions removes duplication and keeps UI code aligned with the core extension API. Please just confirm the exported shape (e.g. extensionId, state) still matches consumer expectations and the documentation examples.

apps/web/content/docs/developers/8.extensions.mdx (1)

128-143: Extension docs significantly improve clarity and security guidance

The expanded sections on available globals, TinyBase-based state sync, tab navigation, and the iframe/Tauri security model make the extension story much clearer and align well with the new ext-host routing and polyfill behavior. The “Hello World” and “Calendar” walkthroughs are particularly helpful for onboarding.

Also applies to: 150-153, 209-235, 320-327, 331-333, 334-341, 348-349, 360-360, 362-369, 370-377

apps/desktop/src/routes/app/route.tsx (1)

7-7: Using isExtHostPath here keeps ext-host handling consistent

Switching to isExtHostPath(location.pathname) nicely centralizes the ext-host detection logic with the root route, ensuring extension-host requests bypass ListenerProvider and side effects in a consistent way.

Also applies to: 19-21

apps/desktop/src/utils/ext-host.ts (1)

1-3: Helper cleanly defines the ext-host path contract

isExtHostPath correctly treats /app/ext-host and /app/ext-host/... as ext-host routes while avoiding accidental matches like /app/ext-hosting, and centralizes this logic for reuse in routing.

apps/desktop/src/routes/__root.tsx (1)

12-12: Shared isExtHostPath usage keeps root routing aligned with ext-host behavior

Using isExtHostPath(window.location.pathname) behind a typeof window !== "undefined" guard is a clean way to avoid SSR pitfalls while ensuring the root route consistently short‑circuits to <Outlet /> for ext-host paths.

Also applies to: 28-33

Co-Authored-By: yujonglee <yujonglee.dev@gmail.com>
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
apps/web/content/docs/developers/8.extensions.mdx (1)

367-382: Consider adding code examples to the Calendar extension section for consistency.

The Hello World section includes a full code walkthrough, but the Calendar section only describes features and shows build commands without code. Adding key code snippets (e.g., reading calendar data from store, opening tabs, calendar UI structure) would maintain documentation consistency and help readers understand the implementation.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0d21c5c and 089e63e.

📒 Files selected for processing (1)
  • apps/web/content/docs/developers/8.extensions.mdx (5 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
  • GitHub Check: Redirect rules - hyprnote
  • GitHub Check: Header rules - hyprnote
  • GitHub Check: ci (macos, macos-14)
  • GitHub Check: fmt
  • GitHub Check: ci (linux, depot-ubuntu-24.04-8)
  • GitHub Check: ci (macos, depot-macos-14)
  • GitHub Check: ci (linux, depot-ubuntu-22.04-8)
🔇 Additional comments (2)
apps/web/content/docs/developers/8.extensions.mdx (2)

68-91: Well-clarified runtime script purpose and logging API.

The updated section now clearly explains that the runtime script primarily serves for logging and future extensibility, with the main functionality coming from UI panels. The hypr.log API examples are helpful.


165-181: I'll verify the review comment by examining the documentation file and checking whether ExtensionViewProps is properly imported and exported. Let me start by exploring the file.
<function_calls>


#!/bin/bash

First, find and read the file to understand its structure and content

wc -l apps/web/content/docs/developers/8.extensions.mdx


</function_calls>
<function_calls>


#!/bin/bash

Read the relevant sections of the file

First check lines around 152 (Available Globals), then 165-181, 188-212, 214-241

echo "=== Lines 145-160 (Available Globals area) ==="
sed -n '145,160p' apps/web/content/docs/developers/8.extensions.mdx

echo -e "\n=== Lines 165-185 (First code example) ==="
sed -n '165,185p' apps/web/content/docs/developers/8.extensions.mdx

echo -e "\n=== Lines 188-215 (Second code example) ==="
sed -n '188,215p' apps/web/content/docs/developers/8.extensions.mdx

echo -e "\n=== Lines 214-245 (Third code example) ==="
sed -n '214,245p' apps/web/content/docs/developers/8.extensions.mdx


</function_calls>

Let me get the actual file to examine the code examples:
<function_calls>


#!/bin/bash

Display the file to see all relevant sections

cat -n apps/web/content/docs/developers/8.extensions.mdx | head -250


</function_calls>

Now let me check if ExtensionViewProps is actually exported from the @hypr/plugin-extensions package:
<function_calls>


#!/bin/bash

Search for ExtensionViewProps in the codebase to see where it's defined/exported

echo "=== Searching for ExtensionViewProps exports ==="
rg "export.*ExtensionViewProps" --type ts --type tsx -A 2

echo -e "\n=== Searching for ExtensionViewProps in plugin-extensions ==="
find . -path "/plugin-extensions" -type f ( -name ".ts" -o -name ".tsx" -o -name "*.d.ts" ) 2>/dev/null | head -20


</function_calls>

@devin-ai-integration
Copy link
Contributor

Devin is archived and cannot be woken up. Please unarchive Devin if you want to continue using it.

Co-Authored-By: yujonglee <yujonglee.dev@gmail.com>
@yujonglee yujonglee merged commit 35b1859 into main Nov 28, 2025
14 of 15 checks passed
@yujonglee yujonglee deleted the devin/1764302447-extension-system-cleanup branch November 28, 2025 05:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant