Skip to content

Commit bddf866

Browse files
committed
fix(logs): keep checked trace content at every depth when the projection budget runs out
Also tidy what the release review found in the same range: shared UTF-8 length helper, redundant mounted guards, session-expired wrapper, misplaced TSDoc, repeated capture copy, and a styled page-access error.
1 parent 70430ca commit bddf866

14 files changed

Lines changed: 209 additions & 129 deletions

File tree

‎apps/extension/src/capture.ts‎

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ import { extractPageText } from '@/extract'
99
import { digestUrl } from '@/utils'
1010

1111
/** A public capture error whose message is safe to share with the hosted composer. */
12+
export const PAGE_CHANGED_MESSAGE = 'The page changed. Attach it again.'
13+
1214
export class PageCaptureError extends Error {}
1315

1416
/** Chrome scripting failures may contain the full private URL of the tab. */
@@ -49,7 +51,7 @@ export async function captureActivePage(
4951
if (tab?.id === undefined || tab.incognito)
5052
throw new PageCaptureError('This page cannot be attached.')
5153
if (expected && expected.tabId !== tab.id) {
52-
throw new PageCaptureError('The page changed. Attach it again.')
54+
throw new PageCaptureError(PAGE_CHANGED_MESSAGE)
5355
}
5456
if (!tab.url) {
5557
const allowed = await chrome.permissions.contains({ origins: PAGE_ACCESS_ORIGINS })
@@ -75,10 +77,10 @@ export async function captureActivePage(
7577
signal?.addEventListener('abort', removeListeners, { once: true })
7678
try {
7779
const snapshot = await readTab({ tabId: tab.id, url: tab.url }, kind, expected, signal)
78-
if (changed) throw new PageCaptureError('The page changed. Attach it again.')
80+
if (changed) throw new PageCaptureError(PAGE_CHANGED_MESSAGE)
7981
return snapshot
8082
} catch (error) {
81-
if (changed) throw new PageCaptureError('The page changed. Attach it again.')
83+
if (changed) throw new PageCaptureError(PAGE_CHANGED_MESSAGE)
8284
if (expected && !(error instanceof PageCaptureError))
8385
throw new PageCaptureError('The original page is unavailable. Attach the current page.')
8486
throw error
@@ -95,7 +97,7 @@ async function readTab(
9597
) {
9698
const url = new URL(tab.url)
9799
if (expected && (await digestUrl(tab.url)) !== expected.urlDigest) {
98-
throw new PageCaptureError('The page changed. Attach it again.')
100+
throw new PageCaptureError(PAGE_CHANGED_MESSAGE)
99101
}
100102
let pathname = url.pathname
101103
if (url.origin === SIM_ORIGIN) {
@@ -132,12 +134,12 @@ async function readTab(
132134
world: 'ISOLATED',
133135
})
134136
if (identity[0]?.documentId !== result.documentId || identity[0]?.result !== tab.url) {
135-
throw new PageCaptureError('The page changed. Attach it again.')
137+
throw new PageCaptureError(PAGE_CHANGED_MESSAGE)
136138
}
137139
const [current] = await chrome.tabs.query({ active: true, currentWindow: true })
138140
signal?.throwIfAborted()
139141
if (current?.id !== tab.tabId || current.url !== tab.url || current.status === 'loading') {
140-
throw new PageCaptureError('The page changed. Attach it again.')
142+
throw new PageCaptureError(PAGE_CHANGED_MESSAGE)
141143
}
142144
if (result.result.error) {
143145
if (kind === 'selection')

‎apps/extension/src/reference.ts‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ import {
1111
} from '@/capture'
1212
import { REFERENCE_PAGE_KEY } from '@/config'
1313

14+
export const PAGE_ATTACHMENT_PENDING_MESSAGE = 'Wait for the page attachment, then try again.'
15+
1416
interface ReferenceOptions {
1517
session: () => string | null
1618
post: (message: ExtensionToAppMessage) => void
@@ -124,7 +126,7 @@ export function createReferenceCapture({
124126
replyError(
125127
sessionId,
126128
requestId,
127-
manualError?.message ?? 'Wait for the page attachment, then try again.',
129+
manualError?.message ?? PAGE_ATTACHMENT_PENDING_MESSAGE,
128130
manualError?.reason
129131
)
130132
return

‎apps/extension/src/sidepanel.tsx‎

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,19 @@ import { createRoot } from 'react-dom/client'
88
import {
99
captureActivePage,
1010
captureErrorMessage,
11+
PAGE_CHANGED_MESSAGE,
1112
PageCaptureError,
1213
SiteAccessRequiredError,
1314
UnreadableSelectionError,
1415
} from '@/capture'
1516
import { CAPTURE_INTENT_KEY, CAPTURE_INTENT_TTL_MS, REFERENCE_PAGE_KEY, SIM_ORIGIN } from '@/config'
1617
import { type CaptureIntent, captureIntentSchema } from '@/intent'
17-
import { createReferenceCapture } from '@/reference'
18+
import { createReferenceCapture, PAGE_ATTACHMENT_PENDING_MESSAGE } from '@/reference'
1819
import { SearchRecoveryDialog } from '@/search-recovery-dialog'
1920
import { PageAccessButton, SiteAccessDialog } from '@/site-access'
2021
import '@/shell.css'
2122

23+
const PAGE_ATTACHMENT_EXPIRED_MESSAGE = 'The page attachment expired. Attach it again.'
2224
const BLOCKED_SELECTION =
2325
'Select readable text again, attach the page explicitly, or turn off Reference current page.'
2426
const KEYBOARD_FOCUS_HINT = navigator.platform.startsWith('Mac')
@@ -49,9 +51,7 @@ function SidePanel({ origin }: SidePanelProps) {
4951
if (!(status instanceof SiteAccessRequiredError)) return
5052
const navigated = (tabId: number, change: chrome.tabs.OnUpdatedInfo) => {
5153
if (tabId === status.tabId && (change.status === 'loading' || change.url !== undefined)) {
52-
setStatus((current) =>
53-
current === status ? 'The page changed. Attach it again.' : current
54-
)
54+
setStatus((current) => (current === status ? PAGE_CHANGED_MESSAGE : current))
5555
}
5656
}
5757
const activated = (tab: chrome.tabs.OnActivatedInfo) => {
@@ -74,7 +74,7 @@ function SidePanel({ origin }: SidePanelProps) {
7474
if (Date.now() - Date.parse(snapshot.capturedAt) > CAPTURE_INTENT_TTL_MS) {
7575
pendingRef.current = null
7676
focusRequested.current = false
77-
setStatus('The page attachment expired. Attach it again.')
77+
setStatus(PAGE_ATTACHMENT_EXPIRED_MESSAGE)
7878
return
7979
}
8080
const message: ExtensionToAppMessage = {
@@ -130,12 +130,12 @@ function SidePanel({ origin }: SidePanelProps) {
130130
}
131131
) {
132132
if (referenceRef.current?.busy()) {
133-
setStatus('Wait for the page attachment, then try again.')
133+
setStatus(PAGE_ATTACHMENT_PENDING_MESSAGE)
134134
return
135135
}
136136
if (busyRef.current) return
137137
if (pendingRef.current) {
138-
setStatus('Wait for the page attachment, then try again.')
138+
setStatus(PAGE_ATTACHMENT_PENDING_MESSAGE)
139139
return
140140
}
141141
busyRef.current = true
@@ -171,7 +171,7 @@ function SidePanel({ origin }: SidePanelProps) {
171171
manualCaptureError: () => {
172172
if (busyRef.current || pendingRef.current || processingManual || manualIntents.size)
173173
return {
174-
message: 'Wait for the page attachment, then try again.',
174+
message: PAGE_ATTACHMENT_PENDING_MESSAGE,
175175
}
176176
if (unreadableSelection.current) return { message: BLOCKED_SELECTION, reason: 'selection' }
177177
},
@@ -249,7 +249,7 @@ function SidePanel({ origin }: SidePanelProps) {
249249
}
250250
if (disposed || !intent) return
251251
if (!currentIntent(intent, window.id)) {
252-
setStatus('The page attachment expired. Attach it again.')
252+
setStatus(PAGE_ATTACHMENT_EXPIRED_MESSAGE)
253253
return
254254
}
255255
if (intent.kind === 'focus') {
@@ -362,7 +362,7 @@ function SidePanel({ origin }: SidePanelProps) {
362362
) {
363363
pendingRef.current = null
364364
focusRequested.current = false
365-
setStatus('The page attachment expired. Attach it again.')
365+
setStatus(PAGE_ATTACHMENT_EXPIRED_MESSAGE)
366366
}
367367
void consumeIntent()
368368
}, 5_000)

‎apps/extension/src/site-access.tsx‎

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useEffect, useRef, useState } from 'react'
1+
import { useEffect, useState } from 'react'
22
import { Chip, ChipModalBody, ChipModalHeader, ChipModalSurface } from '@sim/emcn'
33
import { PAGE_ACCESS_ORIGINS } from '@/config'
44

@@ -8,25 +8,17 @@ interface PageAccessButtonProps {
88
}
99

1010
export function PageAccessButton({ allowed, onAccessGranted }: PageAccessButtonProps) {
11-
const mounted = useRef(false)
1211
const [status, setStatus] = useState<'idle' | 'requesting' | 'error'>('idle')
1312

14-
useEffect(() => {
15-
mounted.current = true
16-
return () => {
17-
mounted.current = false
18-
}
19-
}, [])
20-
2113
async function enable() {
2214
if (status === 'requesting') return
2315
setStatus('requesting')
2416
try {
2517
const granted = await chrome.permissions.request({ origins: PAGE_ACCESS_ORIGINS })
26-
if (mounted.current) setStatus('idle')
18+
setStatus('idle')
2719
if (granted) onAccessGranted()
2820
} catch {
29-
if (mounted.current) setStatus('error')
21+
setStatus('error')
3022
}
3123
}
3224

@@ -47,7 +39,11 @@ export function PageAccessButton({ allowed, onAccessGranted }: PageAccessButtonP
4739
<Chip disabled={status === 'requesting'} onClick={() => void enable()}>
4840
Allow across websites
4941
</Chip>
50-
{status === 'error' && <span role='status'>Could not enable page access. Try again.</span>}
42+
{status === 'error' && (
43+
<span role='status' className='text-[var(--text-error)] text-caption'>
44+
Could not enable page access. Try again.
45+
</span>
46+
)}
5147
</span>
5248
)
5349
}

‎apps/sim/app/extension/[workspaceId]/workspace.tsx‎

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,7 @@ import { Chip, ChipLink } from '@sim/emcn'
44
import { isApiClientError } from '@/lib/api/client/errors'
55
import { ExtensionChat } from '@/app/extension/[workspaceId]/chat'
66
import ExtensionLoading from '@/app/extension/loading'
7-
import { useExtensionIdentity } from '@/app/extension/providers'
8-
import { ExtensionSignIn } from '@/app/extension/sign-in'
7+
import { ExtensionSessionExpired } from '@/app/extension/providers'
98
import { ChatPlanModal } from '@/app/workspace/[workspaceId]/home/components/chat-plan-modal'
109
import { BlockVisibilityLoader } from '@/app/workspace/[workspaceId]/providers/block-visibility-loader'
1110
import { CustomBlocksLoader } from '@/app/workspace/[workspaceId]/providers/custom-blocks-loader'
@@ -26,13 +25,11 @@ interface ExtensionWorkspaceProps {
2625
}
2726

2827
export function ExtensionWorkspace({ workspaceId }: ExtensionWorkspaceProps) {
29-
const { userId } = useExtensionIdentity()
3028
const { data, isPending, error, refetch } = useWorkspaceHostContextQuery(workspaceId, {
3129
refetchInterval: WORKSPACE_HOST_CONTEXT_STALE_TIME,
3230
refetchOnWindowFocus: true,
3331
})
34-
if (isApiClientError(error) && error.status === 401)
35-
return <ExtensionSignIn expectedUserId={userId} />
32+
if (isApiClientError(error) && error.status === 401) return <ExtensionSessionExpired />
3633
if (isPending) return <ExtensionLoading />
3734
const accessDenied = isApiClientError(error) && (error.status === 403 || error.status === 404)
3835
if (accessDenied || !data) {

‎apps/sim/app/extension/o/[organizationId]/organization.tsx‎

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,7 @@ import { ExtensionHeader } from '@/app/extension/[workspaceId]/header'
1010
import { extensionChatParam } from '@/app/extension/[workspaceId]/search-params'
1111
import { useExtensionComposer } from '@/app/extension/hooks/use-composer'
1212
import ExtensionLoading from '@/app/extension/loading'
13-
import { useExtensionIdentity } from '@/app/extension/providers'
14-
import { ExtensionSignIn } from '@/app/extension/sign-in'
13+
import { ExtensionSessionExpired } from '@/app/extension/providers'
1514
import { ExtensionUnavailable } from '@/app/extension/unavailable'
1615
import { OrganizationConversation } from '@/app/o/[organizationId]/components/organization-conversation'
1716
import { OrganizationProvider } from '@/app/o/[organizationId]/providers/organization-provider'
@@ -27,14 +26,12 @@ interface ExtensionOrganizationProps {
2726
}
2827

2928
export function ExtensionOrganization({ context }: ExtensionOrganizationProps) {
30-
const { userId } = useExtensionIdentity()
3129
const access = useOrganizationSummary(context.organization.id)
3230
const history = useOrganizationMothershipChats(context.organization.id)
3331
const denied = [access.error, history.error].find(
3432
(error) => isApiClientError(error) && [401, 403, 404].includes(error.status)
3533
)
36-
if (isApiClientError(denied) && denied.status === 401)
37-
return <ExtensionSignIn expectedUserId={userId} />
34+
if (isApiClientError(denied) && denied.status === 401) return <ExtensionSessionExpired />
3835
if (access.isPending) return <ExtensionLoading />
3936
if (denied || !access.data?.chatAccess)
4037
return (

‎apps/sim/app/extension/workspaces.tsx‎

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,14 @@ import {
1111
} from '@sim/emcn'
1212
import { isApiClientError } from '@/lib/api/client/errors'
1313
import ExtensionLoading from '@/app/extension/loading'
14-
import { useExtensionIdentity } from '@/app/extension/providers'
15-
import { ExtensionSignIn } from '@/app/extension/sign-in'
14+
import { ExtensionSessionExpired } from '@/app/extension/providers'
1615
import { useWorkspacesQuery } from '@/hooks/queries/workspace'
1716

1817
export function ExtensionWorkspaces() {
19-
const { userId } = useExtensionIdentity()
2018
const [scrollElement, setScrollElement] = useState<HTMLElement | null>(null)
2119
const scrollEdges = useScrollEdges(scrollElement)
2220
const { data: workspaces, isPending, error, refetch } = useWorkspacesQuery()
23-
if (isApiClientError(error) && error.status === 401)
24-
return <ExtensionSignIn expectedUserId={userId} />
21+
if (isApiClientError(error) && error.status === 401) return <ExtensionSessionExpired />
2522
if (isPending) return <ExtensionLoading />
2623
const transientError =
2724
!isApiClientError(error) || error.status === 408 || error.status === 429 || error.status >= 500

‎apps/sim/hooks/use-speech-to-text.ts‎

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,7 @@ export function useSpeechToText({
234234
: { workspaceId: workspaceIdRef.current },
235235
})
236236
} catch (err) {
237-
if (!mountedRef.current || generation !== generationRef.current) return false
237+
if (generation !== generationRef.current) return false
238238
if (isApiClientError(err) && err.status === 402) {
239239
const isMemberLimit = (err.body as { scope?: string } | null)?.scope === 'member'
240240
setIsListening(false)
@@ -246,7 +246,7 @@ export function useSpeechToText({
246246

247247
const token = typeof tokenData.token === 'string' ? tokenData.token : undefined
248248
if (!token) throw new Error('Failed to get speech token')
249-
if (!mountedRef.current || generation !== generationRef.current) return false
249+
if (generation !== generationRef.current) return false
250250

251251
const stream = await navigator.mediaDevices.getUserMedia({
252252
audio: {
@@ -258,7 +258,7 @@ export function useSpeechToText({
258258
},
259259
})
260260

261-
if (!mountedRef.current || generation !== generationRef.current) {
261+
if (generation !== generationRef.current) {
262262
stream.getTracks().forEach((track) => track.stop())
263263
return false
264264
}
@@ -287,7 +287,7 @@ export function useSpeechToText({
287287
ws.onerror = () => reject(new Error('WebSocket connection failed'))
288288

289289
ws.onmessage = (event) => {
290-
if (!mountedRef.current || generation !== generationRef.current) return
290+
if (generation !== generationRef.current) return
291291
try {
292292
const msg = JSON.parse(event.data)
293293

@@ -331,7 +331,7 @@ export function useSpeechToText({
331331
}
332332
})
333333

334-
if (!mountedRef.current || generation !== generationRef.current) {
334+
if (generation !== generationRef.current) {
335335
ws.close()
336336
stream.getTracks().forEach((track) => track.stop())
337337
return false

0 commit comments

Comments
 (0)