word-waltz / files / src / utils / shareLink.ts
shareLink.ts
| 1 | /** |
| 2 | * utils/shareLink.ts — URL construction and parsing |
| 3 | * |
| 4 | * The encryption key is embedded in the URL fragment (hash) so it is never |
| 5 | * sent to any server. Format: |
| 6 | * |
| 7 | * https://host/game/#gameId=<id>&key=<base64url-key> |
| 8 | * |
| 9 | * The fragment is parsed on the client to extract both values. |
| 10 | */ |
| 11 | |
| 12 | |
| 13 | function shareBase(): string { |
| 14 | return window.location.origin + window.location.pathname; |
| 15 | } |
| 16 | |
| 17 | /** |
| 18 | * Build a shareable game URL. |
| 19 | */ |
| 20 | export function buildLink( |
| 21 | gameId: string, |
| 22 | base64urlKey: string, |
| 23 | role?: 'a' | 'b', |
| 24 | base: string = shareBase(), |
| 25 | ): string { |
| 26 | const params: Record<string, string> = { gameId, key: base64urlKey }; |
| 27 | if (role) params.role = role; |
| 28 | const fragment = new URLSearchParams(params).toString(); |
| 29 | return `${base}#${fragment}`; |
| 30 | } |
| 31 | |
| 32 | /** Parse a game URL fragment to extract gameId, key, and optional role. */ |
| 33 | export function parseLink(url: string = window.location.hash): { |
| 34 | gameId: string | null; |
| 35 | key: string | null; |
| 36 | role: 'a' | 'b' | null; |
| 37 | } { |
| 38 | const fragment = url.startsWith('#') ? url.slice(1) : url; |
| 39 | const params = new URLSearchParams(fragment); |
| 40 | const role = params.get('role'); |
| 41 | return { |
| 42 | gameId: params.get('gameId'), |
| 43 | key: params.get('key'), |
| 44 | role: role === 'a' || role === 'b' ? role : null, |
| 45 | }; |
| 46 | } |