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, as part of the handshake. Without it any local process — including
another user's — could inject payloads that the app forwards to the frontend as a
deep link. 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.