Skip to content

Commit 45a9f7e

Browse files
committed
chore(sync): merge main into dev
2 parents 3fbaf11 + 36f733b commit 45a9f7e

File tree

7 files changed

+46
-130
lines changed

7 files changed

+46
-130
lines changed

apps/desktop/changelog/1.4.0.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# What's new in v1.4.0
2+
3+
## Shiny new things
4+
5+
- Added in-app review prompts
6+
7+
## Improvements
8+
9+
- Expanded desktop end-to-end coverage for auth and user flows
10+
11+
## No longer broken
12+
13+
- Removed the unwanted text selection toolbar
14+
- Fixed AI onboarding asset loading by switching the spline asset domain
15+
- Hardened setting sync authentication lifecycle
16+
17+
## Thanks
18+
19+
Special thanks to volunteer contributors for their valuable contributions

apps/desktop/layer/main/src/ipc/services/auth.ts

Lines changed: 0 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import type { IpcContext } from "electron-ipc-decorator"
55
import { IpcMethod, IpcService } from "electron-ipc-decorator"
66

77
import { BETTER_AUTH_COOKIE_NAME_SESSION_TOKEN } from "~/constants/app"
8-
import { apiClient } from "~/lib/api-client"
98
import { WindowManager } from "~/manager/window"
109

1110
import { getSessionTokenFromCookies, syncSessionToCliConfig } from "../../lib/cli-session-sync"
@@ -135,49 +134,6 @@ export class AuthService extends IpcService {
135134
await this.clearSessionToken()
136135
}
137136

138-
@IpcMethod()
139-
async getSession(_context: IpcContext) {
140-
return apiClient.auth.getSession()
141-
}
142-
143-
@IpcMethod()
144-
async getSessionByToken(_context: IpcContext, token: string) {
145-
const response = await fetch(`${env.VITE_API_URL}/better-auth/get-session`, {
146-
headers: {
147-
...createDesktopAPIHeaders({ version: PKG.version }),
148-
Cookie: `__Secure-better-auth.session_token=${token}; better-auth.session_token=${token}`,
149-
},
150-
})
151-
152-
return response.json().catch(async () => ({ message: await response.text() }))
153-
}
154-
155-
@IpcMethod()
156-
async request(
157-
_context: IpcContext,
158-
payload: {
159-
input: string
160-
init?: {
161-
method?: string
162-
headers?: Record<string, string>
163-
body?: string
164-
}
165-
},
166-
) {
167-
const response = await fetch(payload.input, {
168-
method: payload.init?.method,
169-
headers: payload.init?.headers,
170-
body: payload.init?.body,
171-
cache: "no-store",
172-
})
173-
174-
return {
175-
status: response.status,
176-
headers: Object.fromEntries(response.headers.entries()),
177-
body: await response.text(),
178-
}
179-
}
180-
181137
@IpcMethod()
182138
async signInWithCredential(
183139
_context: IpcContext,

apps/desktop/layer/renderer/src/lib/api-client.ts

Lines changed: 5 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import { IN_ELECTRON } from "@follow/shared/constants"
21
import { env } from "@follow/shared/env.desktop"
32
import { whoami } from "@follow/store/user/getters"
43
import { userActions } from "@follow/store/user/store"
@@ -9,53 +8,17 @@ import PKG from "@pkg"
98
import { NetworkStatus, setApiStatus } from "~/atoms/network"
109
import { setLoginModalShow } from "~/atoms/user"
1110

12-
import { ipcServices } from "./client"
13-
import { getAuthSessionToken, getClientId, getSessionId } from "./client-session"
14-
15-
const electronFetch = async (input: string | URL | Request, options: RequestInit = {}) => {
16-
const authService = ipcServices?.auth as
17-
| (NonNullable<typeof ipcServices>["auth"] & {
18-
request?: (payload: {
19-
input: string
20-
init?: { method?: string; headers?: Record<string, string>; body?: string }
21-
}) => Promise<{ status: number; headers: Record<string, string>; body: string }>
22-
})
23-
| undefined
24-
25-
if (!authService?.request) {
26-
return fetch(input.toString(), {
27-
...options,
28-
cache: "no-store",
29-
})
30-
}
31-
32-
const headers = new Headers(options.headers)
33-
const response = await authService.request({
34-
input: input.toString(),
35-
init: {
36-
method: options.method,
37-
headers: Object.fromEntries(headers.entries()),
38-
body: typeof options.body === "string" ? options.body : undefined,
39-
},
40-
})
41-
42-
return new Response(response.body, {
43-
status: response.status,
44-
headers: response.headers,
45-
})
46-
}
11+
import { getClientId, getSessionId } from "./client-session"
4712

4813
export const followClient = new FollowClient({
4914
credentials: "include",
5015
timeout: 30000,
5116
baseURL: env.VITE_API_URL,
5217
fetch: async (input, options = {}) =>
53-
IN_ELECTRON
54-
? electronFetch(input, options)
55-
: fetch(input.toString(), {
56-
...options,
57-
cache: "no-store",
58-
}),
18+
fetch(input.toString(), {
19+
...options,
20+
cache: "no-store",
21+
}),
5922
})
6023

6124
export const followApi = followClient.api
@@ -65,11 +28,6 @@ followClient.addRequestInterceptor(async (ctx) => {
6528
header["X-Client-Id"] = getClientId()
6629
header["X-Session-Id"] = getSessionId()
6730

68-
const authSessionToken = IN_ELECTRON ? getAuthSessionToken() : null
69-
if (authSessionToken) {
70-
header.Cookie = `__Secure-better-auth.session_token=${authSessionToken}; better-auth.session_token=${authSessionToken}`
71-
}
72-
7331
const apiHeader = createDesktopAPIHeaders({ version: PKG.version })
7432

7533
options.headers = {
@@ -107,10 +65,6 @@ followClient.addResponseInterceptor(async ({ response }) => {
10765
return response
10866
}
10967

110-
if (IN_ELECTRON && getAuthSessionToken()) {
111-
return response
112-
}
113-
11468
// Or we can present LoginModal here.
11569
// router.navigate("/login")
11670
// If any response status is 401, we can set auth fail. Maybe some bug, but if navigate to login page, had same issues

apps/desktop/layer/renderer/src/main.tsx

Lines changed: 1 addition & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,6 @@ import ReactDOM from "react-dom/client"
1111
import { RouterProvider } from "react-router/dom"
1212

1313
import { authClient } from "~/lib/auth"
14-
import { ipcServices } from "~/lib/client"
15-
import { getAuthSessionToken } from "~/lib/client-session"
1614

1715
import { setAppIsReady } from "./atoms/app"
1816
import { ElECTRON_CUSTOM_TITLEBAR_HEIGHT } from "./constants"
@@ -24,35 +22,7 @@ import { router } from "./router"
2422

2523
authClientContext.provide(authClient)
2624
queryClientContext.provide(queryClient)
27-
28-
const providedApi = IN_ELECTRON
29-
? {
30-
...followApi,
31-
auth: {
32-
...followApi.auth,
33-
getSession: async (...args: Parameters<typeof followApi.auth.getSession>) => {
34-
const authService = ipcServices?.auth as
35-
| (typeof followApi.auth & {
36-
getSession?: () => ReturnType<typeof followApi.auth.getSession>
37-
getSessionByToken?: (token: string) => ReturnType<typeof followApi.auth.getSession>
38-
})
39-
| undefined
40-
const authSessionToken = getAuthSessionToken()
41-
const session = authSessionToken
42-
? await authService?.getSessionByToken?.(authSessionToken)
43-
: await authService?.getSession?.()
44-
45-
if (session) {
46-
return session
47-
}
48-
49-
return followApi.auth.getSession(...args)
50-
},
51-
},
52-
}
53-
: followApi
54-
55-
apiContext.provide(providedApi)
25+
apiContext.provide(followApi)
5626

5727
initializeApp().finally(() => {
5828
import("./push-notification").then(({ registerWebPushNotifications }) => {

apps/desktop/layer/renderer/src/pages/settings/(settings)/cli.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,13 @@ import { defineSettingPageData } from "~/modules/settings/utils"
66

77
const iconName = "i-mgc-terminal-cute-re"
88
const priority = (1000 << 1) + 25
9+
const CLI_SETTINGS_DISABLED_FOR_THIS_RELEASE = true
910

1011
export const loader = defineSettingPageData({
1112
icon: iconName,
1213
name: "titles.cli",
1314
priority,
14-
hideIf: () => !IN_ELECTRON,
15+
hideIf: () => CLI_SETTINGS_DISABLED_FOR_THIS_RELEASE || !IN_ELECTRON,
1516
})
1617

1718
export function Component() {

apps/desktop/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "Folo",
33
"type": "module",
4-
"version": "1.3.1",
4+
"version": "1.4.0",
55
"private": true,
66
"description": "Follow everything in one place",
77
"author": "Folo Team",
@@ -95,5 +95,5 @@
9595
"vite-tsconfig-paths": "6.1.1"
9696
},
9797
"productName": "Folo",
98-
"mainHash": "906a0b82e00829115764f36a38132f3774120c4bea764e3b1be8949f447ccb06"
98+
"mainHash": "0c464fca7c98fd4b42abba743abb1cd590e216043987acf4f6d1e10392ce0e57"
9999
}

apps/mobile/changelog/next.md

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,26 @@
22

33
## Shiny new things
44

5+
- Added Apple subscriptions on iOS
6+
- Supported anonymous timeline reading without signing in
7+
- Refined upgrade prompts to match desktop subscription flows
8+
- Added in-app review prompts
9+
- Supported French localization
10+
511
## Improvements
612

13+
- Polished settings and Discover UI across iOS and Android
14+
- Improved subscription and plan management surfaces
15+
- Hardened authentication flows and expanded end-to-end coverage
16+
- Aligned translation gating with actual user roles
17+
718
## No longer broken
819

20+
- Fixed discover category loading and iOS auth bootstrap issues
21+
- Fixed iOS subscription upgrade actions
22+
- Fixed Android modal header overlap
23+
- Stabilized sign-in persistence across mobile auth flows
24+
925
## Thanks
1026

11-
Special thanks to volunteer contributors @ for their valuable contributions
27+
Special thanks to volunteer contributors for their valuable contributions

0 commit comments

Comments
 (0)