feat: stateless federated identity resolver + federation UX improvements

Add identity.ts with isSelf() and resolveDisplayIdentity() — pure
stateless functions that detect replicated-self using the immutable
(username, homeInstance) composite key. No store lookups, no data
mutation. Fixes wrong avatar gradient and missing edit/delete on
own messages in remote channels.

Also includes: optimistic message dedup fix for cross-instance
messages (content-only matching), federation toast notifications,
Username component with @domain display, invite parser, and
deploy script simplification.
This commit is contained in:
Jannis Braun
2026-03-04 03:37:49 +01:00
parent 64fd8edfc9
commit dca9c4dc83
19 changed files with 713 additions and 110 deletions
+64
View File
@@ -0,0 +1,64 @@
/**
* Parse invite input into a code and optional remote origin.
*
* Supported formats:
* - Bare code: "a3f1b2c4"
* - Full URL: "https://remote.com/join/a3f1b2c4"
* - Qualified code: "a3f1b2c4@remote.com"
*/
export function parseInviteInput(input: string): { code: string; origin?: string } {
const trimmed = input.trim();
if (!trimmed) throw new Error('Invite code is required');
// Full URL: starts with http:// or https://
if (/^https?:\/\//i.test(trimmed)) {
let parsed: URL;
try {
parsed = new URL(trimmed);
} catch {
throw new Error('Invalid invite link');
}
// Extract code from /join/{code} path
const match = parsed.pathname.match(/^\/join\/([^/]+)$/);
if (!match) {
throw new Error('Invalid invite link — expected format: https://instance/join/CODE');
}
const code = match[1]!;
// If the URL points at our own instance, treat as a bare code
if (parsed.origin === window.location.origin) {
return { code };
}
return { code, origin: parsed.origin };
}
// Qualified code: CODE@domain (contains @ but no spaces, no protocol)
if (trimmed.includes('@') && !trimmed.includes(' ')) {
const atIndex = trimmed.indexOf('@');
const code = trimmed.slice(0, atIndex);
const domain = trimmed.slice(atIndex + 1);
if (!code || !domain) {
throw new Error('Invalid invite format — expected: CODE@domain');
}
const origin = `https://${domain}`;
// If it resolves to our own instance, treat as bare code
try {
if (new URL(origin).origin === window.location.origin) {
return { code };
}
} catch {
throw new Error('Invalid domain in invite');
}
return { code, origin };
}
// Bare code
return { code: trimmed };
}