Apple: a Shortcut or a home-screen widget jumps straight into a host's game library #155

Merged
enricobuehler merged 1 commits from worktree-apple-shortcuts-library-widget into main 2026-08-10 14:56:22 +00:00
Owner

The reserved punktfunk://browse/<host-ref> route now routes on the Apple client, and two new front doors emit it — both round-tripping through the one URL router, so there is no second code path.

What's new

Shortcuts / Siri / Spotlight — a new Open Game Library intent beside Connect / Wake / End Stream. Host-parameterized like the others (HostEntity picker), foregrounds the app and lands in that host's library with nothing streaming yet. Phrases: "Open ⟨host⟩ library in Punktfunk" / "Show ⟨host⟩ games in Punktfunk".

A configurable library widget (kind PunktfunkLibrary; small + both Lock-Screen families) — long-press → Edit Widget picks a saved host (the AppIntentConfiguration the HostEntity doc comment always anticipated); a tap opens that host's library. Unconfigured it follows the most recent host. A configured host that was later removed shows the empty state rather than silently following a different host — a widget that says "Studio" must never open someone else's library. Same .never timeline + push-reload design as the hosts widget; HostStore now reloads both kinds.

The route

ContentView.openLibrary(from:) drives the same libraryTarget every internal surface writes, so a link lands in whichever presentation the current mode owns: the gamepad console's in-place library screen, the touch cover, the macOS sheet, or tvOS's cover.

Connect's posture minus the connect itself:

  • pin conflict (fp= vs. the stored identity) → hard refusal with a notice
  • a live session is never preempted
  • an unsaved host → notice (the library fetch rides the paired mTLS identity, so there is nothing to show before the host is saved — unlike connect, there's no confirmation-sheet path to offer)
  • launch= / profile= on a browse are ignored, not refused — nothing streams until a title is picked, and that connect resolves its own profile

wake stays reserved (Shortcuts users have the Wake Host intent, which never round-trips through a URL). Other clients keep answering browse with a notice; the parse side was already in the shared grammar and the vector file, so nothing moves cross-language.

DeepLink.browse(host:) is the shared emitter, covered by a round-trip test beside connect's — the same backward-compatibility stakes: a Home-Screen widget keeps sending yesterday's URL.

Docs updated: clients, game-library, profiles-and-links.

Verified

  • macOS swift build + full swift test (CI parity) — green, including the new round-trip test
  • iOS + tvOS triple typechecks (swift build --triple arm64-apple-{ios,tvos}17.0) — green
  • xcodebuild of PunktfunkWidgetsExtension for the iOS Simulator — green
  • Not yet on-glass: the widget config picker and the Siri phrases are device-verifiable only
The reserved `punktfunk://browse/<host-ref>` route now routes on the Apple client, and two new front doors emit it — both round-tripping through the one URL router, so there is no second code path. ## What's new **Shortcuts / Siri / Spotlight** — a new **Open Game Library** intent beside Connect / Wake / End Stream. Host-parameterized like the others (`HostEntity` picker), foregrounds the app and lands in that host's library with nothing streaming yet. Phrases: "Open ⟨host⟩ library in Punktfunk" / "Show ⟨host⟩ games in Punktfunk". **A configurable library widget** (kind `PunktfunkLibrary`; small + both Lock-Screen families) — long-press → Edit Widget picks a saved host (the `AppIntentConfiguration` the `HostEntity` doc comment always anticipated); a tap opens that host's library. Unconfigured it follows the most recent host. A configured host that was later removed shows the empty state rather than silently following a different host — a widget that says "Studio" must never open someone else's library. Same `.never` timeline + push-reload design as the hosts widget; `HostStore` now reloads both kinds. ## The route `ContentView.openLibrary(from:)` drives the same `libraryTarget` every internal surface writes, so a link lands in whichever presentation the current mode owns: the gamepad console's in-place library screen, the touch cover, the macOS sheet, or tvOS's cover. Connect's posture minus the connect itself: - pin conflict (`fp=` vs. the stored identity) → hard refusal with a notice - a live session is never preempted - an unsaved host → notice (the library fetch rides the paired mTLS identity, so there is nothing to show before the host is saved — unlike connect, there's no confirmation-sheet path to offer) - `launch=` / `profile=` on a browse are ignored, not refused — nothing streams until a title is picked, and that connect resolves its own profile `wake` stays reserved (Shortcuts users have the Wake Host intent, which never round-trips through a URL). Other clients keep answering `browse` with a notice; the parse side was already in the shared grammar and the vector file, so nothing moves cross-language. `DeepLink.browse(host:)` is the shared emitter, covered by a round-trip test beside connect's — the same backward-compatibility stakes: a Home-Screen widget keeps sending yesterday's URL. Docs updated: clients, game-library, profiles-and-links. ## Verified - macOS `swift build` + full `swift test` (CI parity) — green, including the new round-trip test - iOS + tvOS triple typechecks (`swift build --triple arm64-apple-{ios,tvos}17.0`) — green - `xcodebuild` of `PunktfunkWidgetsExtension` for the iOS Simulator — green - Not yet on-glass: the widget config picker and the Siri phrases are device-verifiable only
enricobuehler added 1 commit 2026-08-10 12:24:06 +00:00
feat(apple): the browse route is real — a Shortcut or a widget jumps straight into a host's library
ci / bun-nix (pull_request) Successful in 28s
ci / web (pull_request) Successful in 1m7s
ci / docs-site (pull_request) Successful in 1m20s
ci / rust-arm64 (pull_request) Successful in 1m32s
apple / swift (pull_request) Successful in 1m41s
apple / screenshots (pull_request) Skipped
ci / rust (pull_request) Successful in 12m36s
1fc184516a
The reserved punktfunk://browse/<host-ref> route now routes on Apple: it
drives the same libraryTarget every internal surface writes, so the link
lands in whichever presentation the current mode owns — the gamepad
console's in-place library screen, the touch cover, the macOS sheet, or
tvOS's cover. Connect's posture minus the connect: a pin conflict
refuses, a live session is never preempted, an unsaved host gets a
notice (the library rides the paired mTLS identity, so there is nothing
to browse before the host is saved). browse ignores launch=/profile= —
nothing streams until a title is picked, and that connect resolves its
own profile.

On top of the route, the two new front doors:

- OpenLibraryIntent ("Open Game Library") beside Connect/Wake/End in
  Shortcuts/Siri/Spotlight, host-parameterized like the others and
  round-tripping through the URL — one router, no second path.
- A configurable library widget (kind "PunktfunkLibrary",
  AppIntentConfiguration over HostEntity — the configuration the
  HostEntity doc comment anticipated): pick a host, tap into its
  library. Unconfigured it follows the most recent host; a configured
  host that was removed shows the empty state rather than silently
  following a different host. Same .never timeline + HostStore push as
  the hosts widget, now reloading both kinds.

DeepLink.browse(host:) is the one emitter both doors share, covered by
a round-trip test beside connect's; the parse side was already in the
grammar and the vector file. Docs updated (clients, game-library,
profiles-and-links).
enricobuehler merged commit e283f17ab4 into main 2026-08-10 14:56:22 +00:00
enricobuehler deleted branch worktree-apple-shortcuts-library-widget 2026-08-10 14:56:24 +00:00
Sign in to join this conversation.
No Reviewers
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: unom/punktfunk#155