personal web client for Bluesky
typescript
solidjs
bluesky
atcute
1import { isDid, isHandle, isRecordKey, isTid } from '@atcute/lexicons/syntax';
2
3import { safeUrlParse } from '~/api/utils/strings';
4
5import {
6 BSKY_FEED_LINK_RE,
7 BSKY_GO_SHORTLINK_RE,
8 BSKY_HASHTAG_LINK_RE,
9 BSKY_LIST_LINK_RE,
10 BSKY_POST_LINK_RE,
11 BSKY_PROFILE_LINK_RE,
12 BSKY_SEARCH_LINK_RE,
13 BSKY_STARTERPACK_LINK_RE,
14} from './bsky/url';
15
16export const redirectBskyUrl = (rawUrl: string): string | null | undefined => {
17 const url = safeUrlParse(rawUrl);
18 if (!url) {
19 return;
20 }
21
22 const host = url.host;
23 const pathname = url.pathname;
24 let match: RegExpExecArray | null | undefined;
25
26 if (host === 'bsky.app' || host === 'staging.bsky.app' || host === 'main.bsky.dev') {
27 if ((match = BSKY_PROFILE_LINK_RE.exec(pathname))) {
28 const [, actor] = match;
29
30 if (!isHandle(actor) && !isDid(actor)) {
31 return null;
32 }
33
34 return `/${match[1]}`;
35 }
36
37 if ((match = BSKY_POST_LINK_RE.exec(pathname))) {
38 const [, actor, rkey] = match;
39
40 if (!isHandle(actor) && !isDid(actor)) {
41 return null;
42 }
43 if (!isTid(rkey)) {
44 return null;
45 }
46
47 return `/${actor}/${rkey}`;
48 }
49
50 if ((match = BSKY_FEED_LINK_RE.exec(pathname))) {
51 const [, actor, rkey] = match;
52
53 if (!isHandle(actor) && !isDid(actor)) {
54 return null;
55 }
56 if (!isRecordKey(rkey)) {
57 return null;
58 }
59
60 return `/${actor}/feeds/${rkey}`;
61 }
62
63 if ((match = BSKY_LIST_LINK_RE.exec(pathname))) {
64 const [, actor, rkey] = match;
65
66 if (!isHandle(actor) && !isDid(actor)) {
67 return null;
68 }
69 if (!isRecordKey(rkey)) {
70 return null;
71 }
72
73 return `/${actor}/lists/${rkey}`;
74 }
75
76 if ((match = BSKY_STARTERPACK_LINK_RE.exec(pathname))) {
77 const [, _page, actor, rkey] = match;
78
79 if (!isHandle(actor) && !isDid(actor)) {
80 return null;
81 }
82 if (!isRecordKey(rkey)) {
83 return null;
84 }
85
86 return `/${actor}/packs/${rkey}`;
87 }
88
89 if ((match = BSKY_SEARCH_LINK_RE.exec(pathname))) {
90 const query = url.searchParams.get('q');
91
92 if (!query) {
93 return null;
94 }
95
96 return `/search?q=${encodeURIComponent(query)}`;
97 }
98
99 if ((match = BSKY_HASHTAG_LINK_RE.exec(pathname))) {
100 const [, tag] = match;
101
102 return `/search?q=${encodeURIComponent('#' + tag)}`;
103 }
104
105 return null;
106 }
107
108 if (host === 'go.bsky.app') {
109 if ((match = BSKY_GO_SHORTLINK_RE.exec(pathname))) {
110 const [, id] = match;
111
112 return `/go/${id}`;
113 }
114 }
115
116 return;
117};