Bluesky app fork with some witchin' additions 💫
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

fix: image cdn in LiveStatusDialog, website in profiles, & agent session?

also work towards URI support in profile website field (and masked links?)

xan.lol eaa373dd 634a9a60

+20 -38
+1
package.json
··· 238 238 "tlds": "^1.234.0", 239 239 "tldts": "^6.1.46", 240 240 "unicode-segmenter": "^0.14.5", 241 + "uri-js": "^4.4.1", 241 242 "zod": "^3.20.2" 242 243 }, 243 244 "devDependencies": {
+4 -1
src/features/liveNow/components/LiveStatusDialog.tsx
··· 12 12 import {type NavigationProp} from '#/lib/routes/types' 13 13 import {sanitizeHandle} from '#/lib/strings/handles' 14 14 import {toNiceDomain} from '#/lib/strings/url-helpers' 15 + import {useImageCdnHost} from '#/state/preferences' 16 + import {maybeModifyImageCdnHost} from '#/state/preferences/image-cdn-host' 15 17 import {useModerationOpts} from '#/state/preferences/moderation-opts' 16 18 import {unstableCacheProfileView} from '#/state/queries/profile' 17 19 import {android, atoms as a, platform, tokens, useTheme, web} from '#/alf' ··· 123 125 const t = useTheme() 124 126 const queryClient = useQueryClient() 125 127 const openLink = useOpenLink() 128 + const imageCdnHost = useImageCdnHost() 126 129 const moderationOpts = useModerationOpts() 127 130 const reportDialogControl = useGlobalReportDialogControl() 128 131 const dialogContext = Dialog.useDialogContext() ··· 144 147 ]), 145 148 ]}> 146 149 <Image 147 - source={embed.external.thumb} 150 + source={maybeModifyImageCdnHost(embed.external.thumb, imageCdnHost)} 148 151 contentFit="cover" 149 152 style={[a.absolute, a.inset_0]} 150 153 accessibilityIgnoresInvertColors
+7 -29
src/lib/strings/website.ts
··· 1 + import {sanitizeUrl} from '@braintree/sanitize-url' 2 + import * as URI from 'uri-js' 3 + 1 4 export function sanitizeWebsiteForDisplay(website: string): string { 2 5 return website.replace(/^https?:\/\//i, '').replace(/\/$/, '') 3 6 } 4 7 5 8 export function sanitizeWebsiteForLink(website: string): string { 6 - const normalized = website.toLowerCase() 7 - return !normalized.startsWith('javascript') 8 - ? normalized 9 - : `unsafe-${website}` 9 + const trimmedWebsite = website.trim() 10 + return sanitizeUrl(trimmedWebsite) 10 11 } 11 12 12 13 export function isValidWebsiteFormat(website: string): boolean { ··· 16 17 return true 17 18 } 18 19 19 - const normalizedWebsite = trimmedWebsite.toLowerCase() 20 - 21 - if ('https://'.startsWith(normalizedWebsite)) { 22 - return true 23 - } 24 - 25 - if (!normalizedWebsite.match(/^https:\/\/.+/)) { 26 - return false 27 - } 28 - 29 - const domainMatch = normalizedWebsite.match(/^https:\/\/([^/\s]+)/) 30 - if (!domainMatch) { 31 - return false 32 - } 33 - 34 - const domain = domainMatch[1] 35 - 36 - // Check for valid domain structure: 37 - // - Must contain at least one dot 38 - // - Must have a valid TLD (at least 2 characters after the last dot) 39 - // - Cannot be just a single word without extension 40 - const domainPattern = 41 - /^[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?)*\.[a-zA-Z]{2,}$/ 42 - 43 - return domainPattern.test(domain) 20 + const parsedWebsite = URI.parse(trimmedWebsite) 21 + return !parsedWebsite.error && !!parsedWebsite.scheme 44 22 }
+2 -2
src/screens/Profile/Header/EditProfileDialog.tsx
··· 210 210 displayName: displayName.trimEnd(), 211 211 description: description.trimEnd(), 212 212 pronouns: pronouns.trimEnd().toLowerCase(), 213 - website: website.trimEnd().toLowerCase(), 213 + website: website.trimEnd(), 214 214 }, 215 215 newUserAvatar, 216 216 newUserBanner, ··· 543 543 {color: t.palette.negative_400}, 544 544 ]}> 545 545 <Trans> 546 - Website must be a valid URL (e.g., https://bsky.app) 546 + Website must be a valid URI (e.g., https://bsky.app) 547 547 </Trans> 548 548 </Text> 549 549 )}
+5 -5
src/state/session/agent.ts
··· 51 51 const agent = new BskyAppAgent({service: PUBLIC_BSKY_SERVICE}) 52 52 const proxyDid = 53 53 readCustomAppViewDidUri() || BLUESKY_PROXY_HEADER.get() || APPVIEW_DID_PROXY 54 - agent.configureProxy(proxyDid) 54 + agent.configureProxy(proxyDid as ProxyHeaderValue) 55 55 return agent 56 56 } 57 57 ··· 83 83 84 84 const proxyDid = 85 85 readCustomAppViewDidUri() || BLUESKY_PROXY_HEADER.get() || APPVIEW_DID_PROXY 86 - agent.configureProxy(proxyDid) 86 + agent.configureProxy(proxyDid as ProxyHeaderValue) 87 87 88 88 return agent.prepare({ 89 89 resolvers: [gates, moderation, aa], ··· 124 124 125 125 const proxyDid = 126 126 readCustomAppViewDidUri() || BLUESKY_PROXY_HEADER.get() || APPVIEW_DID_PROXY 127 - agent.configureProxy(proxyDid) 127 + agent.configureProxy(proxyDid as ProxyHeaderValue) 128 128 129 129 return agent.prepare({ 130 130 resolvers: [gates, moderation, aa], ··· 295 295 296 296 const proxyDid = 297 297 readCustomAppViewDidUri() || BLUESKY_PROXY_HEADER.get() || APPVIEW_DID_PROXY 298 - agent.configureProxy(proxyDid) 298 + agent.configureProxy(proxyDid as ProxyHeaderValue) 299 299 300 300 return agent.prepare({ 301 301 resolvers: [gates, moderation, aa], ··· 409 409 }) 410 410 const proxyDid = readCustomAppViewDidUri() || APPVIEW_DID_PROXY 411 411 if (proxyDid) { 412 - this.configureProxy(proxyDid) 412 + this.configureProxy(proxyDid as ProxyHeaderValue) 413 413 } 414 414 } 415 415
+1 -1
yarn.lock
··· 16106 16106 registry-auth-token "3.3.2" 16107 16107 registry-url "3.1.0" 16108 16108 16109 - uri-js@^4.2.2: 16109 + uri-js@^4.2.2, uri-js@^4.4.1: 16110 16110 version "4.4.1" 16111 16111 resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" 16112 16112 integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==