Skip to content

feat: add apps/core with basic Axum server and polyfill for browser frontend#3650

Closed
devin-ai-integration[bot] wants to merge 1 commit intomainfrom
devin/1770213618-apps-core-server
Closed

feat: add apps/core with basic Axum server and polyfill for browser frontend#3650
devin-ai-integration[bot] wants to merge 1 commit intomainfrom
devin/1770213618-apps-core-server

Conversation

@devin-ai-integration
Copy link
Contributor

@devin-ai-integration devin-ai-integration bot commented Feb 5, 2026

Summary

This PR adds a proof-of-concept for running the Hyprnote desktop frontend in a regular browser by replacing Tauri IPC with HTTP calls to a local Rust server.

Changes:

  • New apps/core crate: A minimal Axum HTTP server that handles Tauri-style invoke commands via POST /invoke
  • Updated apps/desktop/index.html: Polyfill that intercepts window.__TAURI_INTERNALS__ in browser context and routes calls to the HTTP server

How it works:

  1. When opened in a browser (not Tauri), the polyfill provides a fake __TAURI_INTERNALS__ object
  2. The invoke function makes HTTP POST requests to http://127.0.0.1:9527/invoke
  3. The server handles commands and returns responses in the expected format

Currently supported commands (minimal for POC):

  • plugin:store2|get_str / plugin:store2|set_str (in-memory only)
  • get_onboarding_needed (returns false)
  • get_env (returns empty string)

Review & Testing Checklist for Human

  • Verify the polyfill logic: Check that isTauriContext detection works correctly (should be true in Tauri, false in Chrome)
  • Test end-to-end: Run cargo run -p hypr-core, then open localhost:1420 in Chrome during pnpm -F desktop dev to verify the polyfill intercepts calls
  • Review invoke response format: Confirm the { data, error } response structure matches what @tauri-apps/api expects internally

Suggested test plan:

  1. Start the server: cargo run -p hypr-core
  2. In another terminal: pnpm -F desktop dev
  3. Open http://localhost:1420 in Chrome (not the Tauri window)
  4. Check console for [hypr-core] Polyfill active message
  5. Verify the app attempts to load (will fail on unimplemented commands, but should get past initial invoke calls)

Notes

This is a minimal POC to validate the architecture. Many commands will fail with "Unknown command" - that's expected. The goal is to prove the polyfill + HTTP server approach works before implementing more commands.

Link to Devin run: https://app.devin.ai/sessions/92db48e4f7b64263ba4674c711b5f672
Requested by: @yujonglee


Open with Devin

…rontend

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

🤖 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 Feb 5, 2026

Deploy Preview for hyprnote-storybook canceled.

Name Link
🔨 Latest commit 5a93773
🔍 Latest deploy log https://app.netlify.com/projects/hyprnote-storybook/deploys/6983ef7bf68b14000807ea81

@netlify
Copy link

netlify bot commented Feb 5, 2026

Deploy Preview for hyprnote ready!

Name Link
🔨 Latest commit 5a93773
🔍 Latest deploy log https://app.netlify.com/projects/hyprnote/deploys/6983ef7bf68b14000807ea7d
😎 Deploy Preview https://deploy-preview-3650--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.

Copy link
Contributor Author

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

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

Devin Review found 2 potential issues.

View issues and 4 additional flags in Devin Review.

Open in Devin Review

Comment on lines +53 to +57
transformCallback: function(callback, once) {
var id = callbackId++;
eventListeners[id] = { callback: callback, once: once };
return id;
},
Copy link
Contributor Author

Choose a reason for hiding this comment

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

🔴 Missing unregisterCallback function causes runtime error when Channel is used

The polyfill provides transformCallback but lacks the corresponding unregisterCallback function that Tauri's Channel class depends on.

Click to expand

How the bug is triggered

When Tauri's Channel class is used (e.g., for plugin listeners or streaming responses), it calls window.__TAURI_INTERNALS__.unregisterCallback(this.id) in its cleanupCallback() method at node_modules/.pnpm/@tauri-apps+api@2.9.1/node_modules/@tauri-apps/api/core.js:118:

cleanupCallback() {
    window.__TAURI_INTERNALS__.unregisterCallback(this.id);
}

Since the polyfill doesn't define unregisterCallback, this will throw a TypeError: window.__TAURI_INTERNALS__.unregisterCallback is not a function when any code tries to clean up a Channel.

Impact

Any feature using Tauri Channels (plugin listeners, streaming APIs) will fail with a runtime error when the channel is closed.

Recommendation: Add the missing unregisterCallback function to the polyfill:

transformCallback: function(callback, once) {
  var id = callbackId++;
  eventListeners[id] = { callback: callback, once: once };
  return id;
},
unregisterCallback: function(id) {
  delete eventListeners[id];
},
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment on lines +41 to +46
#[derive(Deserialize)]
struct StoreSetArgs {
scope: String,
key: String,
value: serde_json::Value,
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

🟡 Type mismatch: set_str accepts any JSON value instead of String

The hypr-core server's StoreSetArgs struct defines value as serde_json::Value, but the actual Tauri plugin expects a String.

Click to expand

Actual vs Expected

In apps/core/src/main.rs:41-46:

struct StoreSetArgs {
    scope: String,
    key: String,
    value: serde_json::Value,  // accepts any JSON
}

But the actual Tauri command at plugins/store2/src/commands.rs:30-34 expects:

pub(crate) async fn set_str<R: tauri::Runtime>(
    ...
    value: String,  // expects String only
)

Impact

This creates a behavioral difference between the browser polyfill and the real Tauri app. Code tested in the browser could pass non-string values (e.g., numbers, objects) to set_str and appear to work, but would fail when run in the actual Tauri context. This violates the API contract and could lead to confusing bugs during development.

Recommendation: Change StoreSetArgs.value to String to match the actual Tauri plugin API:

#[derive(Deserialize)]
struct StoreSetArgs {
    scope: String,
    key: String,
    value: String,
}
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

@yujonglee yujonglee closed this Feb 8, 2026
@yujonglee yujonglee deleted the devin/1770213618-apps-core-server branch February 8, 2026 13:32
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