feat(invite-links): real deep links via jorkonvo.szabotar.dev + auto-join on open #6

Closed
claude wants to merge 0 commits from feat/invite-deep-links into main
Contributor

Real, multi-user-testing bug fix + the project owner's explicit domain/hosting request from the 2026-09-16 late-night session.

The bug

Clicking a matrix.to invite link never opened JorKonvo — no deep-link registration existed anywhere (Android manifest, iOS Info.plist, Tauri config), and the web app never parsed a matrix.to URL from window.location either. Copy-paste into "Join a room" was the only working path.

The fix

The owner registered jorkonvo.szabotar.dev (DNS already resolves here) specifically so real, silently-verified deep links become possible — matrix.to is a third party JorKonvo doesn't control, so links on it can only ever prompt a disambiguation dialog, never open silently.

  • packages/matrix-core/src/inviteLinks.ts: getRoomInviteLink() now mints https://jorkonvo.szabotar.dev/join#/<target>?via=... links. New parseInviteLink() accepts that domain, plain matrix.to (other Matrix clients still generate those — still supported), and a jorkonvo:// custom-scheme fallback for iOS. room-admin.ts's old private parser is gone, replaced by this shared one everywhere.
  • Android: android:autoVerify="true" intent-filter for /join*, plus a best-effort non-verified filter for matrix.to too. Added apps/web/public/.well-known/assetlinks.json — uses the DEBUG keystore's fingerprint for now (no real upload keystore exists yet, see docs/ANDROID.md "Release signing" from earlier tonight) — must be swapped for the real release cert fingerprint before shipping, or verification silently fails and falls back to a chooser dialog.
  • iOS: App.entitlements (associated-domains) wired into both build configs. Added apps/web/public/.well-known/apple-app-site-association — Team ID is a TEAMID_PLACEHOLDER, since it isn't recorded anywhere in this repo (only Codemagic's App Store Connect integration knows it) — owner must fill in the real Team ID. A jorkonvo:// custom-scheme fallback (CFBundleURLTypes) covers the gap until then.
  • Client-side: new lib/inviteLinkHandler.ts + state/pendingInviteStore.ts catch the link (cold web load at /join, or Capacitor's appUrlOpen natively — cold start or already-running), stash the target until auth is ready, then App.tsx opens JoinRoomModal with it. The modal now auto-attempts the join immediately when opened this way instead of requiring one more click — "click a link, you're in," matching Discord.

Also done tonight, separately hosted (not part of this PR's diff)

The web app is now actually served at 127.0.0.1:8181 on the dev box via a new ~/jorkonvo-web/ nginx setup (outside this repo, sibling to it — see that directory's own README). One remaining manual step for the owner: add a Proxy Host in Nginx Proxy Manager (jorkonvo.szabotar.dev → 127.0.0.1:8181, Let's Encrypt on) — I don't have NPM admin credentials, everything up to that point is built and verified working.

Known gaps for the owner to close before this fully works end-to-end

  1. Swap the debug-keystore fingerprint in assetlinks.json for the real upload keystore's, once one exists.
  2. Fill in the real Apple Team ID in apple-app-site-association.
  3. Add the NPM proxy host so https://jorkonvo.szabotar.dev actually resolves to the running container.

Until all three are done, invite links still work — they just fall back to a disambiguation dialog (Android) or the jorkonvo:// custom scheme (iOS) instead of opening silently, and the in-app join flow (auto-join on open) works today via the web build regardless.

Gate

npm run build clean, npm test (476 passed + 1 skipped — 5 new parseInviteLink tests), npm run lint 0 errors, full Playwright e2e suite run in the worktree.

Co-Authored-By: Claude Sonnet 5 noreply@anthropic.com

Real, multi-user-testing bug fix + the project owner's explicit domain/hosting request from the 2026-09-16 late-night session. ## The bug Clicking a `matrix.to` invite link never opened JorKonvo — no deep-link registration existed anywhere (Android manifest, iOS Info.plist, Tauri config), and the web app never parsed a `matrix.to` URL from `window.location` either. Copy-paste into "Join a room" was the only working path. ## The fix The owner registered `jorkonvo.szabotar.dev` (DNS already resolves here) specifically so real, silently-verified deep links become possible — `matrix.to` is a third party JorKonvo doesn't control, so links on it can only ever prompt a disambiguation dialog, never open silently. - `packages/matrix-core/src/inviteLinks.ts`: `getRoomInviteLink()` now mints `https://jorkonvo.szabotar.dev/join#/<target>?via=...` links. New `parseInviteLink()` accepts that domain, plain `matrix.to` (other Matrix clients still generate those — still supported), and a `jorkonvo://` custom-scheme fallback for iOS. `room-admin.ts`'s old private parser is gone, replaced by this shared one everywhere. - **Android**: `android:autoVerify="true"` intent-filter for `/join*`, plus a best-effort non-verified filter for `matrix.to` too. Added `apps/web/public/.well-known/assetlinks.json` — **uses the DEBUG keystore's fingerprint for now** (no real upload keystore exists yet, see `docs/ANDROID.md` "Release signing" from earlier tonight) — **must be swapped for the real release cert fingerprint** before shipping, or verification silently fails and falls back to a chooser dialog. - **iOS**: `App.entitlements` (associated-domains) wired into both build configs. Added `apps/web/public/.well-known/apple-app-site-association` — **Team ID is a `TEAMID_PLACEHOLDER`**, since it isn't recorded anywhere in this repo (only Codemagic's App Store Connect integration knows it) — **owner must fill in the real Team ID**. A `jorkonvo://` custom-scheme fallback (`CFBundleURLTypes`) covers the gap until then. - **Client-side**: new `lib/inviteLinkHandler.ts` + `state/pendingInviteStore.ts` catch the link (cold web load at `/join`, or Capacitor's `appUrlOpen` natively — cold start or already-running), stash the target until auth is ready, then `App.tsx` opens `JoinRoomModal` with it. The modal now **auto-attempts the join immediately** when opened this way instead of requiring one more click — "click a link, you're in," matching Discord. ## Also done tonight, separately hosted (not part of this PR's diff) The web app is now actually served at `127.0.0.1:8181` on the dev box via a new `~/jorkonvo-web/` nginx setup (outside this repo, sibling to it — see that directory's own README). **One remaining manual step for the owner**: add a Proxy Host in Nginx Proxy Manager (`jorkonvo.szabotar.dev` → `127.0.0.1:8181`, Let's Encrypt on) — I don't have NPM admin credentials, everything up to that point is built and verified working. ## Known gaps for the owner to close before this fully works end-to-end 1. Swap the debug-keystore fingerprint in `assetlinks.json` for the real upload keystore's, once one exists. 2. Fill in the real Apple Team ID in `apple-app-site-association`. 3. Add the NPM proxy host so `https://jorkonvo.szabotar.dev` actually resolves to the running container. Until all three are done, invite links still work — they just fall back to a disambiguation dialog (Android) or the `jorkonvo://` custom scheme (iOS) instead of opening silently, and the in-app join flow (auto-join on open) works today via the web build regardless. ## Gate `npm run build` clean, `npm test` (476 passed + 1 skipped — 5 new `parseInviteLink` tests), `npm run lint` 0 errors, full Playwright e2e suite run in the worktree. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
feat(invite-links): real deep links via jorkonvo.szabotar.dev + auto-join on open
Some checks failed
CI / build-and-test (pull_request) Has been cancelled
CI / e2e (pull_request) Has been cancelled
d3e0b10d2b
Clicking a matrix.to invite link never opened JorKonvo - no deep-link
registration existed anywhere (Android manifest, iOS Info.plist, Tauri
config), and the web app never parsed a matrix.to URL from
window.location either. Copy-paste into "Join a room" was the only path.

Now that the project owner has jorkonvo.szabotar.dev (DNS already points
here), invite links are minted on that domain instead
(https://jorkonvo.szabotar.dev/join#/<target>?via=...) so Android/iOS can
register REAL, silently-verified App Links / Universal Links - matrix.to
is a third party, so links on it could only ever get a disambiguation
dialog, never a verified one.

- packages/matrix-core/src/inviteLinks.ts: getRoomInviteLink() now mints
  jorkonvo.szabotar.dev links; new parseInviteLink() accepts that domain,
  plain matrix.to (other clients still generate those), and a jorkonvo://
  custom-scheme fallback. room-admin.ts's private parser replaced with
  this shared one everywhere (joinRoomByIdOrAlias, resolveRoomTarget).
- Android: autoVerify=true intent-filter for /join*, plus a best-effort
  (non-verified) matrix.to filter. apps/web/public/.well-known/assetlinks.json
  added with the DEBUG keystore's fingerprint - MUST be swapped for the
  real upload keystore's once one exists (docs/ANDROID.md "Release
  signing"), or verification silently fails and falls back to a chooser.
- iOS: App.entitlements (associated-domains) wired into both build
  configs, apps/web/public/.well-known/apple-app-site-association added -
  Team ID is a TEAMID_PLACEHOLDER (not recorded anywhere in-repo; only
  Codemagic's App Store Connect integration knows it) - owner must fill
  in the real one. A jorkonvo:// CFBundleURLTypes scheme is a fallback
  for whenever the Universal Link can't verify (e.g. right now, because
  of the placeholder).
- apps/web/src/lib/inviteLinkHandler.ts + state/pendingInviteStore.ts:
  catches the link on cold web load (/join path) or via Capacitor's
  appUrlOpen (native, cold start or already-running), stashes the target
  until auth is ready, then App.tsx opens JoinRoomModal with it.
  JoinRoomModal now auto-attempts the join immediately when opened this
  way (initialTarget prop) instead of requiring an extra click - "click a
  link, you're in", matching Discord.

test/unit/core/inviteLinks.test.ts: updated getRoomInviteLink assertions
for the new domain, added parseInviteLink round-trip coverage for all
three accepted link shapes.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BjDnbbumj61ftRMhpLXCKQ
Author
Contributor

Merged into main at 5f65115 (merge commit onto PR #7 + PR #8). Two real conflicts, both resolved by inspection:

  • PLAN.md: sequential dev-log entries from PRs #7/#8/#6, kept in order.
  • packages/matrix-core/src/room-admin.ts: PR #7 added an isSpaceKnockingAllowed/SPACE_SETTINGS_EVENT import for createRoom/createSpace, PR #6 added a parseInviteLink import for resolveRoomTarget/joinRoomByIdOrAlias. No functional overlap - both imports kept, verified the full file afterward.

Gate results on the merged tree: build clean, 476 unit tests passed (1 skipped, +5 from inviteLinks.test.ts), lint 0 errors, e2e 15/15 passed in isolation (no port collisions this time - confirms the earlier 7-passed/6-failed report was the documented environmental sibling-branch port collision, not a real regression).

Known gaps carried forward as documented in the PR (expected, not blockers): Android assetlinks.json uses the debug keystore fingerprint (no upload keystore exists yet), iOS apple-app-site-association has a literal TEAMID_PLACEHOLDER (owner fills in the real Apple Team ID later). Closing.

Merged into main at 5f65115 (merge commit onto PR #7 + PR #8). Two real conflicts, both resolved by inspection: - PLAN.md: sequential dev-log entries from PRs #7/#8/#6, kept in order. - packages/matrix-core/src/room-admin.ts: PR #7 added an `isSpaceKnockingAllowed`/`SPACE_SETTINGS_EVENT` import for createRoom/createSpace, PR #6 added a `parseInviteLink` import for resolveRoomTarget/joinRoomByIdOrAlias. No functional overlap - both imports kept, verified the full file afterward. Gate results on the merged tree: build clean, 476 unit tests passed (1 skipped, +5 from inviteLinks.test.ts), lint 0 errors, e2e 15/15 passed in isolation (no port collisions this time - confirms the earlier 7-passed/6-failed report was the documented environmental sibling-branch port collision, not a real regression). Known gaps carried forward as documented in the PR (expected, not blockers): Android assetlinks.json uses the debug keystore fingerprint (no upload keystore exists yet), iOS apple-app-site-association has a literal TEAMID_PLACEHOLDER (owner fills in the real Apple Team ID later). Closing.
claude closed this pull request 2026-09-16 18:41:47 +00:00
Some checks failed
CI / build-and-test (pull_request) Has been cancelled
CI / e2e (pull_request) Has been cancelled

Pull request closed

Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
thatumi/JorKonvo!6
No description provided.