feat: add apps/core with basic Axum server and polyfill for browser frontend#3650
feat: add apps/core with basic Axum server and polyfill for browser frontend#3650devin-ai-integration[bot] wants to merge 1 commit intomainfrom
Conversation
…rontend Co-Authored-By: yujonglee <yujonglee.dev@gmail.com>
🤖 Devin AI EngineerI'll be helping with this pull request! Here's what you should know: ✅ I will automatically:
Note: I can only respond to comments from users who have write access to this repository. ⚙️ Control Options:
|
✅ Deploy Preview for hyprnote-storybook canceled.
|
✅ Deploy Preview for hyprnote ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
| transformCallback: function(callback, once) { | ||
| var id = callbackId++; | ||
| eventListeners[id] = { callback: callback, once: once }; | ||
| return id; | ||
| }, |
There was a problem hiding this comment.
🔴 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];
},Was this helpful? React with 👍 or 👎 to provide feedback.
| #[derive(Deserialize)] | ||
| struct StoreSetArgs { | ||
| scope: String, | ||
| key: String, | ||
| value: serde_json::Value, | ||
| } |
There was a problem hiding this comment.
🟡 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,
}Was this helpful? React with 👍 or 👎 to provide feedback.
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:
apps/corecrate: A minimal Axum HTTP server that handles Tauri-styleinvokecommands viaPOST /invokeapps/desktop/index.html: Polyfill that interceptswindow.__TAURI_INTERNALS__in browser context and routes calls to the HTTP serverHow it works:
__TAURI_INTERNALS__objectinvokefunction makes HTTP POST requests tohttp://127.0.0.1:9527/invokeCurrently 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
isTauriContextdetection works correctly (should betruein Tauri,falsein Chrome)cargo run -p hypr-core, then openlocalhost:1420in Chrome duringpnpm -F desktop devto verify the polyfill intercepts calls{ data, error }response structure matches what@tauri-apps/apiexpects internallySuggested test plan:
cargo run -p hypr-corepnpm -F desktop devhttp://localhost:1420in Chrome (not the Tauri window)[hypr-core] Polyfill activemessageNotes
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