Skip to content

feat(deeplink): confirm routes for invite, plugin-install and snippet-install - #150

Merged
kipavy merged 6 commits into
devfrom
feat/deeplink-confirm-routes
Aug 19, 2026
Merged

feat(deeplink): confirm routes for invite, plugin-install and snippet-install#150
kipavy merged 6 commits into
devfrom
feat/deeplink-confirm-routes

Conversation

@kipavy

@kipavy kipavy commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

Closes the Part 3 remainder of #144.

DeepLinkJoinModal becomes DeepLinkConfirmModal: one sheet driven by a per-route spec (icon, optional async load, details, optional extra, optional canAccept, accept). The join route moves onto it with no behaviour change — every assertion in its test file is byte-identical; only the import line and the JSX tags follow the rename.

load being optional is deliberate: join's copy is complete from the intent alone, so its sheet paints complete in the first frame instead of flashing a spinner over text it already has.

Three confirm routes on top of it:

  • invite?h=@handle — resolves the handle by exact match and knocks that user into the terminal this device is currently sharing. No new server surface: the only knock that exists is session-scoped. A fuzzy match would let @kev land on @kevin-p, which is the impersonation shape the unified invite work set out to close. With no shareable session the sheet still names the handle and accept stays disabled with a reason.
  • plugin-install?id=…&src=…src is a catalogue id already configured and enabled on this device, never a URL, so a link cannot introduce a code source; a disabled source fails exactly like an absent one. The plugin id is validated by isValidPluginId in the codec, before any path is built from it. The sheet names the plugin, version, author, catalogue and permissions before accept does anything, and the manifest text disclosed is the manifest text installed — load reads it once and accept passes that same string.
  • snippet-install?id=… — names the entry, its author, how many snippets it carries, and which vault they land in. A link the user did not author should not quietly write into a vault they were not thinking about.

Both installs are code execution driven by unauthenticated input, so both are confirm by construction: a sheet whose load failed can never be accepted.

Two DRY extractions fall out, each done in the task that needed it: import-export/storeAccess.ts (so a link-driven snippet install runs the same path as the community tab) and PluginPermissionList (so a link-driven plugin install cannot disclose less than a click-driven one).

Testing

Full CI=true pnpm vitest run: 3705 passed. The 3 remaining failures — pluginBundleBuild, TitleBar.syncState (×2) — are 5000ms timeouts that reproduce identically at the branch point b1d29ed4 with none of these changes present, and touch no file in this PR. tsc --noEmit clean.

Not covered: no live click-through. These sheets have not been opened in a running app, only under vitest. The invite route in particular touches the session-key wrap path, which is exactly what unit tests structurally cannot prove.

Pairs with VoltiusApp/web#14.

@kipavy
kipavy merged commit 2965680 into dev Aug 19, 2026
4 checks passed
@kipavy
kipavy deleted the feat/deeplink-confirm-routes branch August 19, 2026 01:11
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