Single-instance & deep-linking
Two related features for apps that should behave like a single, link-aware program. Both are core (no feature flag).
Single-instance
App::new().single_instance().run()?;
The first process becomes the primary. Any later launch hands its command
line to the primary and exits immediately. The primary's window is raised and the
payload is delivered on elyra:second-instance:
import { onSecondInstance } from "@elyra/runtime";
onSecondInstance((payload) => {
// e.g. a forwarded deep-link URL, or "" for a bare re-launch
});
The rendezvous
| Platform | Endpoint |
|---|---|
| Unix | an AF_UNIX socket in $XDG_RUNTIME_DIR (temp dir as fallback), created with mode 0600 and the uid in its name |
| Windows | loopback TCP (std has no named pipes) |
Both require a random per-install token, stored 0600 in the app's config
directory. Without it any local process, including another user's, could
inject payloads that the app forwards to the frontend as a deep link.
The handshake is a challenge-response on that token. Each side proves it holds the token with an HMAC over fresh nonces, the primary first, and the token is never sent. A process that takes the endpoint before the app (a loopback port, on Windows) learns neither the token nor the payload. The client's proof covers the payload, so it arrives as it was sent. The MCP endpoint uses the same scheme. Forwarded URLs are also parsed and validated (scheme, no control characters or quotes) rather than prefix-matched.
Payloads are limited to a single line of at most 8 KiB. If the endpoint is held by an unrelated process, enforcement is skipped and the app runs normally.
Deep-linking (custom URL scheme)
App::new().deep_link("myapp").run()?; // handles myapp://…
- Launch URL — read it once on startup:
import { deepLink, onDeepLink } from "@elyra/runtime"; const url = await deepLink.initial(); // "myapp://…" | null onDeepLink((url) => { /* URLs delivered while running */ }); - Delivery while running — on macOS the OS open-URL event is forwarded to
elyra:deep-link; on Windows/Linux the OS starts a new process with the URL, which single-instance forwards to the primary (also re-emitted onelyra:deep-link). Pairdeep_linkwithsingle_instancefor the best behavior.
Registration
deep_link registers the scheme at startup (idempotent):
-
Windows —
HKCU\Software\Classes\<scheme>pointing at the executable. -
Linux — a
.desktopentry withMimeType=x-scheme-handler/<scheme>plusxdg-mime default. -
macOS — registration belongs in the bundle's
Info.plist; the runtime only handles incoming URLs. Add to your.app:<key>CFBundleURLTypes</key> <array><dict> <key>CFBundleURLName</key><string>com.example.myapp</string> <key>CFBundleURLSchemes</key><array><string>myapp</string></array> </dict></array>
Registration writes to the OS (registry / desktop entries) and, on macOS, depends on packaging. Argv delivery and the macOS open-URL path are the parts exercised here; the registration side-effects are best verified on each target in a real install.