@shipfox/client-integrations 17.0.0 → 21.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (86) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/CHANGELOG.md +20 -0
  3. package/dist/components/callback-status-shell.js +2 -2
  4. package/dist/components/callback-status-shell.js.map +1 -1
  5. package/dist/components/integration-gallery.stories.js +1 -1
  6. package/dist/components/integration-gallery.stories.js.map +1 -1
  7. package/dist/components/provider-grid.js +4 -4
  8. package/dist/components/provider-grid.js.map +1 -1
  9. package/dist/components/repository-picker.js +1 -1
  10. package/dist/components/repository-picker.js.map +1 -1
  11. package/dist/components/webhook/webhook-modals.stories.js +1 -1
  12. package/dist/components/webhook/webhook-modals.stories.js.map +1 -1
  13. package/dist/pages/gitea-install-page.js +1 -1
  14. package/dist/pages/gitea-install-page.js.map +1 -1
  15. package/dist/pages/jira-callback-page.js +4 -4
  16. package/dist/pages/jira-callback-page.js.map +1 -1
  17. package/dist/pages/sentry-callback-page.js +4 -4
  18. package/dist/pages/sentry-callback-page.js.map +1 -1
  19. package/dist/pages/source-control-onboarding-page.js +1 -1
  20. package/dist/pages/source-control-onboarding-page.js.map +1 -1
  21. package/dist/routes/gitea.d.ts +3 -0
  22. package/dist/routes/gitea.js +3 -0
  23. package/dist/routes/gitea.js.map +1 -1
  24. package/dist/routes/github-callback.d.ts +3 -0
  25. package/dist/routes/github-callback.d.ts.map +1 -1
  26. package/dist/routes/github-callback.js +3 -0
  27. package/dist/routes/github-callback.js.map +1 -1
  28. package/dist/routes/github.d.ts +3 -0
  29. package/dist/routes/github.js +3 -0
  30. package/dist/routes/github.js.map +1 -1
  31. package/dist/routes/integrations-settings.d.ts +3 -0
  32. package/dist/routes/integrations-settings.js +3 -0
  33. package/dist/routes/integrations-settings.js.map +1 -1
  34. package/dist/routes/integrations.d.ts +3 -0
  35. package/dist/routes/integrations.js +3 -0
  36. package/dist/routes/integrations.js.map +1 -1
  37. package/dist/routes/jira-callback.d.ts +3 -0
  38. package/dist/routes/jira-callback.js +3 -0
  39. package/dist/routes/jira-callback.js.map +1 -1
  40. package/dist/routes/jira.d.ts +3 -0
  41. package/dist/routes/jira.js +3 -0
  42. package/dist/routes/jira.js.map +1 -1
  43. package/dist/routes/linear-callback.d.ts +3 -0
  44. package/dist/routes/linear-callback.js +3 -0
  45. package/dist/routes/linear-callback.js.map +1 -1
  46. package/dist/routes/linear.d.ts +3 -0
  47. package/dist/routes/linear.js +3 -0
  48. package/dist/routes/linear.js.map +1 -1
  49. package/dist/routes/sentry-callback.d.ts +3 -0
  50. package/dist/routes/sentry-callback.js +3 -0
  51. package/dist/routes/sentry-callback.js.map +1 -1
  52. package/dist/routes/sentry.d.ts +3 -0
  53. package/dist/routes/sentry.js +3 -0
  54. package/dist/routes/sentry.js.map +1 -1
  55. package/dist/routes/slack-callback.d.ts +3 -0
  56. package/dist/routes/slack-callback.js +3 -0
  57. package/dist/routes/slack-callback.js.map +1 -1
  58. package/dist/routes/slack.d.ts +3 -0
  59. package/dist/routes/slack.js +3 -0
  60. package/dist/routes/slack.js.map +1 -1
  61. package/dist/tsconfig.test.tsbuildinfo +1 -1
  62. package/package.json +8 -8
  63. package/src/components/callback-status-shell.tsx +2 -2
  64. package/src/components/integration-gallery.stories.tsx +1 -1
  65. package/src/components/integration-gallery.test.tsx +1 -0
  66. package/src/components/provider-grid.tsx +5 -5
  67. package/src/components/repository-picker.tsx +1 -1
  68. package/src/components/webhook/webhook-modals.stories.tsx +1 -1
  69. package/src/pages/gitea-install-page.tsx +1 -1
  70. package/src/pages/jira-callback-page.tsx +5 -5
  71. package/src/pages/sentry-callback-page.tsx +5 -7
  72. package/src/pages/source-control-onboarding-page.tsx +1 -1
  73. package/src/routes/gitea.tsx +4 -1
  74. package/src/routes/github-callback.tsx +1 -0
  75. package/src/routes/github.tsx +4 -1
  76. package/src/routes/integrations-settings.tsx +4 -1
  77. package/src/routes/integrations.tsx +4 -1
  78. package/src/routes/jira-callback.tsx +1 -0
  79. package/src/routes/jira.tsx +4 -1
  80. package/src/routes/linear-callback.tsx +1 -0
  81. package/src/routes/linear.tsx +4 -1
  82. package/src/routes/sentry-callback.tsx +1 -0
  83. package/src/routes/sentry.tsx +4 -1
  84. package/src/routes/slack-callback.tsx +1 -0
  85. package/src/routes/slack.tsx +4 -1
  86. package/tsconfig.build.tsbuildinfo +1 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/pages/jira-callback-page.tsx"],"sourcesContent":["import {useAuthState, useRefreshAuth} from '@shipfox/client-auth';\nimport {useRouteSearch} from '@shipfox/client-shell/runtime';\nimport {sessionStorageOrUndefined} from '@shipfox/client-ui';\nimport {Button, ButtonLink} from '@shipfox/react-ui/button';\nimport {Callout} from '@shipfox/react-ui/callout';\nimport {Card} from '@shipfox/react-ui/card';\nimport {FullPageLoader} from '@shipfox/react-ui/loader';\nimport {toast} from '@shipfox/react-ui/toast';\nimport {Header, Text} from '@shipfox/react-ui/typography';\nimport {useQueryClient} from '@tanstack/react-query';\nimport {Link, useNavigate} from '@tanstack/react-router';\nimport {useCallback, useEffect, useMemo, useRef, useState} from 'react';\nimport {\n useCompleteIntegrationCallback,\n useCompleteIntegrationCallbackResult,\n} from '#application/complete-integration-callback.js';\nimport {CallbackStatusShell} from '#components/callback-status-shell.js';\nimport type {IntegrationConnection, JiraSite} from '#core/models.js';\nimport {\n useCompleteJiraCallbackMutation,\n useCompleteJiraSiteSelectionMutation,\n} from '#hooks/api/integrations.js';\nimport {\n clearJiraInstallWorkspace,\n parseJiraCallbackQuery,\n readJiraInstallWorkspace,\n serializeJiraCallbackQuery,\n} from '#jira-callback.js';\nimport {\n JIRA_CALLBACK_CACHE_SIZE,\n jiraCallbackRequests,\n jiraCompletedConnections,\n jiraSiteSelectionRequests,\n jiraToastedCallbacks,\n} from '#jira-callback-state.js';\nimport {classifyJiraCallbackError, type JiraCallbackFailure} from '#jira-form-errors.js';\nimport {rememberCallbackKey, resolveWorkspaceSlug} from '#workspace-navigation.js';\n\nexport function JiraCallbackPage() {\n const navigate = useNavigate();\n const queryClient = useQueryClient();\n const refreshAuth = useRefreshAuth();\n const {workspaces, isLoading} = useAuthState();\n const completeIntegrationCallback = useCompleteIntegrationCallback();\n const completeIntegrationCallbackResult = useCompleteIntegrationCallbackResult();\n const {mutateAsync: completeJiraCallback} = useCompleteJiraCallbackMutation();\n const {mutateAsync: completeJiraSiteSelection} = useCompleteJiraSiteSelectionMutation();\n const params = useRouteSearch(parseJiraCallbackQuery);\n const callbackKey = params ? serializeJiraCallbackQuery(params) : undefined;\n const workspaceId = useMemo(() => readJiraInstallWorkspace(sessionStorageOrUndefined()), []);\n const [sites, setSites] = useState<JiraSite[] | undefined>();\n const [failure, setFailure] = useState<JiraCallbackFailure | undefined>();\n const [selectedCloudId, setSelectedCloudId] = useState<string | undefined>();\n const [completedWorkspace, setCompletedWorkspace] = useState<{\n slug?: string | undefined;\n }>();\n const disposedRef = useRef(false);\n const callbackKeyRef = useRef(callbackKey);\n callbackKeyRef.current = callbackKey;\n const [callbackStateKey, setCallbackStateKey] = useState(callbackKey);\n\n useEffect(() => {\n disposedRef.current = false;\n return () => {\n disposedRef.current = true;\n };\n }, []);\n\n const completeConnection = useCallback(\n async (\n connection: IntegrationConnection,\n callbackKey: string,\n isActive: () => boolean = () => true,\n ) => {\n if (disposedRef.current || !isActive()) return;\n const completedConnection = jiraCompletedConnections.get(callbackKey);\n if (completedConnection) {\n const workspaceSlug = await resolveWorkspaceSlug({\n workspaceId: completedConnection.workspaceId,\n fallbackWorkspaces: workspaces,\n queryClient,\n });\n if (!disposedRef.current && isActive())\n setCompletedWorkspace(workspaceSlug ? {slug: workspaceSlug} : {});\n return;\n }\n rememberCompletedConnection(callbackKey, connection);\n try {\n clearJiraInstallWorkspace(sessionStorageOrUndefined());\n } catch {\n // The successful API response remains the source of truth for navigation.\n }\n if (disposedRef.current || !isActive()) return;\n if (!jiraToastedCallbacks.has(callbackKey)) {\n rememberCallbackKey(jiraToastedCallbacks, callbackKey);\n toast.success('Jira installed.');\n }\n let workspaceSlug: string | undefined;\n try {\n workspaceSlug = await resolveWorkspaceSlug({\n workspaceId: connection.workspaceId,\n fallbackWorkspaces: workspaces,\n queryClient,\n });\n if (disposedRef.current || !isActive()) return;\n if (!workspaceSlug) {\n setCompletedWorkspace({});\n return;\n }\n setCompletedWorkspace({slug: workspaceSlug});\n await navigate({\n to: '/w/$workspaceSlug/settings/integrations',\n params: {workspaceSlug},\n replace: true,\n });\n } catch {\n if (!disposedRef.current && isActive()) setCompletedWorkspace({slug: workspaceSlug});\n }\n },\n [navigate, queryClient, workspaces],\n );\n\n useEffect(() => {\n if (callbackKey === undefined) return;\n setCallbackStateKey(callbackKey);\n setSites(undefined);\n setSelectedCloudId(undefined);\n setFailure(undefined);\n setCompletedWorkspace(undefined);\n }, [callbackKey]);\n\n useEffect(() => {\n if (!params || !callbackKey || isLoading) return;\n\n let active = true;\n\n const completedConnection = jiraCompletedConnections.get(callbackKey);\n if (completedConnection) {\n void completeConnection(completedConnection, callbackKey, () => active);\n return () => {\n active = false;\n };\n }\n\n const request = jiraCallbackRequests.run(callbackKey, async () => {\n return await completeIntegrationCallbackResult({\n input: params,\n refreshAuth,\n complete: async (query, token) => await completeJiraCallback({query, token}),\n getConnection: (result) => ('sites' in result ? undefined : result),\n });\n });\n\n request.then(\n async (result) => {\n if (disposedRef.current || !active) return;\n if ('sites' in result) {\n setFailure(undefined);\n setSites(result.sites);\n return;\n }\n await completeConnection(result, callbackKey, () => active);\n },\n (error: unknown) => {\n if (!disposedRef.current && active) setFailure(classifyJiraCallbackError(error));\n },\n );\n\n return () => {\n active = false;\n };\n }, [\n callbackKey,\n completeIntegrationCallbackResult,\n completeJiraCallback,\n completeConnection,\n isLoading,\n params,\n refreshAuth,\n ]);\n\n function selectSite(site: JiraSite) {\n if (!params || !callbackKey || selectedCloudId) return;\n setSelectedCloudId(site.cloudId);\n setFailure(undefined);\n const selectionKey = callbackKey;\n const request = jiraSiteSelectionRequests.run(params.state, async () => {\n return await completeIntegrationCallback({\n input: {cloud_id: site.cloudId, state: params.state},\n refreshAuth,\n complete: async (body, token) => await completeJiraSiteSelection({body, token}),\n });\n });\n request.then(\n async (connection) => {\n if (disposedRef.current || callbackKeyRef.current !== selectionKey) return;\n jiraCallbackRequests.clear(selectionKey);\n await completeConnection(\n connection,\n selectionKey,\n () => callbackKeyRef.current === selectionKey,\n );\n },\n (error: unknown) => {\n if (disposedRef.current || callbackKeyRef.current !== selectionKey) return;\n setSelectedCloudId(undefined);\n setFailure(classifyJiraCallbackError(error));\n },\n );\n }\n\n if (!params) {\n return (\n <JiraCallbackFailurePage\n failure={classifyJiraCallbackError(new Error('invalid callback'))}\n workspaceSlug={workspaces.find(({id}) => id === workspaceId)?.slug}\n />\n );\n }\n\n if (isLoading) return <FullPageLoader aria-label=\"Connecting Jira\" />;\n\n if (callbackStateKey === callbackKey && completedWorkspace)\n return (\n <CallbackStatusShell\n title=\"Jira connected\"\n status=\"success\"\n message={\n completedWorkspace.slug\n ? 'Jira is connected. Continue in integrations settings.'\n : 'Jira is connected. Return to Shipfox to continue.'\n }\n workspaceSlug={completedWorkspace.slug}\n installPath=\"/w/$workspaceSlug/integrations/jira\"\n />\n );\n\n if (callbackStateKey === callbackKey && sites)\n return (\n <JiraSiteSelectionPage\n sites={sites}\n selectedCloudId={selectedCloudId}\n failure={failure}\n workspaceSlug={workspaces.find(({id}) => id === workspaceId)?.slug}\n onSelect={selectSite}\n />\n );\n\n if (callbackStateKey === callbackKey && failure)\n return (\n <JiraCallbackFailurePage\n failure={failure}\n workspaceSlug={workspaces.find(({id}) => id === workspaceId)?.slug}\n />\n );\n\n return <FullPageLoader aria-label=\"Connecting Jira\" />;\n}\n\nfunction rememberCompletedConnection(key: string, connection: IntegrationConnection): void {\n jiraCompletedConnections.delete(key);\n jiraCompletedConnections.set(key, connection);\n while (jiraCompletedConnections.size > JIRA_CALLBACK_CACHE_SIZE) {\n const oldestKey = jiraCompletedConnections.keys().next().value;\n if (oldestKey === undefined) return;\n jiraCompletedConnections.delete(oldestKey);\n }\n}\n\nfunction JiraCallbackFailurePage({\n failure,\n workspaceSlug,\n}: {\n failure: JiraCallbackFailure;\n workspaceSlug: string | undefined;\n}) {\n return (\n <CallbackStatusShell\n title={failure.title}\n message={failure.message}\n startOver={failure.startOver}\n switchAccount={failure.signIn}\n workspaceSlug={workspaceSlug}\n installPath=\"/w/$workspaceSlug/integrations/jira\"\n />\n );\n}\n\nfunction JiraSiteSelectionPage({\n sites,\n selectedCloudId,\n failure,\n workspaceSlug,\n onSelect,\n}: {\n sites: JiraSite[];\n selectedCloudId: string | undefined;\n failure: JiraCallbackFailure | undefined;\n workspaceSlug: string | undefined;\n onSelect: (site: JiraSite) => void;\n}) {\n return (\n <main className=\"flex min-h-screen bg-background-subtle-base px-row py-frame\">\n <div className=\"mx-auto flex w-full max-w-[480px] flex-col justify-center gap-section\">\n <header className=\"flex flex-col gap-inline\">\n <Header variant=\"h2\">Choose a Jira site</Header>\n <Text size=\"sm\" className=\"text-foreground-neutral-muted\">\n Select the Jira site to connect to this Shipfox workspace.\n </Text>\n </header>\n\n {failure ? (\n <Callout role=\"alert\" type=\"error\">\n <Text size=\"sm\">{failure.message}</Text>\n </Callout>\n ) : null}\n\n <section className=\"flex flex-col gap-inline\" aria-label=\"Choose a Jira site\">\n {sites.map((site) => (\n <Card key={site.cloudId} className=\"p-panel-compact\">\n <div className=\"flex items-center justify-between gap-cluster\">\n <div className=\"min-w-0\">\n <Text size=\"md\" bold className=\"truncate\">\n {site.name}\n </Text>\n <Text size=\"sm\" className=\"truncate text-foreground-neutral-muted\">\n {site.url}\n </Text>\n </div>\n <Button\n variant=\"secondary\"\n disabled={selectedCloudId !== undefined}\n isLoading={selectedCloudId === site.cloudId}\n onClick={() => onSelect(site)}\n >\n Connect\n </Button>\n </div>\n </Card>\n ))}\n </section>\n\n <div className=\"flex flex-col gap-inline sm:flex-row sm:items-center\">\n {failure?.startOver && workspaceSlug ? (\n <ButtonLink asChild variant=\"muted\" className=\"min-h-44 w-full sm:w-fit\">\n <Link to=\"/w/$workspaceSlug/integrations/jira\" params={{workspaceSlug}}>\n Start over\n </Link>\n </ButtonLink>\n ) : null}\n {workspaceSlug ? (\n <ButtonLink asChild variant=\"muted\" className=\"min-h-44 w-full sm:w-fit\">\n <Link to=\"/w/$workspaceSlug/settings/integrations\" params={{workspaceSlug}}>\n Back to integrations\n </Link>\n </ButtonLink>\n ) : (\n <ButtonLink asChild variant=\"muted\" className=\"min-h-44 w-full sm:w-fit\">\n <Link to=\"/\">Back to Shipfox</Link>\n </ButtonLink>\n )}\n </div>\n </div>\n </main>\n );\n}\n"],"names":["useAuthState","useRefreshAuth","useRouteSearch","sessionStorageOrUndefined","Button","ButtonLink","Callout","Card","FullPageLoader","toast","Header","Text","useQueryClient","Link","useNavigate","useCallback","useEffect","useMemo","useRef","useState","useCompleteIntegrationCallback","useCompleteIntegrationCallbackResult","CallbackStatusShell","useCompleteJiraCallbackMutation","useCompleteJiraSiteSelectionMutation","clearJiraInstallWorkspace","parseJiraCallbackQuery","readJiraInstallWorkspace","serializeJiraCallbackQuery","JIRA_CALLBACK_CACHE_SIZE","jiraCallbackRequests","jiraCompletedConnections","jiraSiteSelectionRequests","jiraToastedCallbacks","classifyJiraCallbackError","rememberCallbackKey","resolveWorkspaceSlug","JiraCallbackPage","navigate","queryClient","refreshAuth","workspaces","isLoading","completeIntegrationCallback","completeIntegrationCallbackResult","mutateAsync","completeJiraCallback","completeJiraSiteSelection","params","callbackKey","undefined","workspaceId","sites","setSites","failure","setFailure","selectedCloudId","setSelectedCloudId","completedWorkspace","setCompletedWorkspace","disposedRef","callbackKeyRef","current","callbackStateKey","setCallbackStateKey","completeConnection","connection","isActive","completedConnection","get","workspaceSlug","fallbackWorkspaces","slug","rememberCompletedConnection","has","success","to","replace","active","request","run","input","complete","query","token","getConnection","result","then","error","selectSite","site","cloudId","selectionKey","state","cloud_id","body","clear","JiraCallbackFailurePage","Error","find","id","aria-label","title","status","message","installPath","JiraSiteSelectionPage","onSelect","key","delete","set","size","oldestKey","keys","next","value","startOver","switchAccount","signIn","main","className","div","header","variant","role","type","section","map","bold","name","url","disabled","onClick","asChild"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/pages/jira-callback-page.tsx"],"sourcesContent":["import {useAuthState, useRefreshAuth} from '@shipfox/client-auth';\nimport {useRouteSearch} from '@shipfox/client-shell/runtime';\nimport {sessionStorageOrUndefined} from '@shipfox/client-ui';\nimport {Button, ButtonLink} from '@shipfox/react-ui/button';\nimport {Callout} from '@shipfox/react-ui/callout';\nimport {FullPageLoader} from '@shipfox/react-ui/loader';\nimport {Panel} from '@shipfox/react-ui/panel';\nimport {toast} from '@shipfox/react-ui/toast';\nimport {Header, Text} from '@shipfox/react-ui/typography';\nimport {useQueryClient} from '@tanstack/react-query';\nimport {Link, useNavigate} from '@tanstack/react-router';\nimport {useCallback, useEffect, useMemo, useRef, useState} from 'react';\nimport {\n useCompleteIntegrationCallback,\n useCompleteIntegrationCallbackResult,\n} from '#application/complete-integration-callback.js';\nimport {CallbackStatusShell} from '#components/callback-status-shell.js';\nimport type {IntegrationConnection, JiraSite} from '#core/models.js';\nimport {\n useCompleteJiraCallbackMutation,\n useCompleteJiraSiteSelectionMutation,\n} from '#hooks/api/integrations.js';\nimport {\n clearJiraInstallWorkspace,\n parseJiraCallbackQuery,\n readJiraInstallWorkspace,\n serializeJiraCallbackQuery,\n} from '#jira-callback.js';\nimport {\n JIRA_CALLBACK_CACHE_SIZE,\n jiraCallbackRequests,\n jiraCompletedConnections,\n jiraSiteSelectionRequests,\n jiraToastedCallbacks,\n} from '#jira-callback-state.js';\nimport {classifyJiraCallbackError, type JiraCallbackFailure} from '#jira-form-errors.js';\nimport {rememberCallbackKey, resolveWorkspaceSlug} from '#workspace-navigation.js';\n\nexport function JiraCallbackPage() {\n const navigate = useNavigate();\n const queryClient = useQueryClient();\n const refreshAuth = useRefreshAuth();\n const {workspaces, isLoading} = useAuthState();\n const completeIntegrationCallback = useCompleteIntegrationCallback();\n const completeIntegrationCallbackResult = useCompleteIntegrationCallbackResult();\n const {mutateAsync: completeJiraCallback} = useCompleteJiraCallbackMutation();\n const {mutateAsync: completeJiraSiteSelection} = useCompleteJiraSiteSelectionMutation();\n const params = useRouteSearch(parseJiraCallbackQuery);\n const callbackKey = params ? serializeJiraCallbackQuery(params) : undefined;\n const workspaceId = useMemo(() => readJiraInstallWorkspace(sessionStorageOrUndefined()), []);\n const [sites, setSites] = useState<JiraSite[] | undefined>();\n const [failure, setFailure] = useState<JiraCallbackFailure | undefined>();\n const [selectedCloudId, setSelectedCloudId] = useState<string | undefined>();\n const [completedWorkspace, setCompletedWorkspace] = useState<{\n slug?: string | undefined;\n }>();\n const disposedRef = useRef(false);\n const callbackKeyRef = useRef(callbackKey);\n callbackKeyRef.current = callbackKey;\n const [callbackStateKey, setCallbackStateKey] = useState(callbackKey);\n\n useEffect(() => {\n disposedRef.current = false;\n return () => {\n disposedRef.current = true;\n };\n }, []);\n\n const completeConnection = useCallback(\n async (\n connection: IntegrationConnection,\n callbackKey: string,\n isActive: () => boolean = () => true,\n ) => {\n if (disposedRef.current || !isActive()) return;\n const completedConnection = jiraCompletedConnections.get(callbackKey);\n if (completedConnection) {\n const workspaceSlug = await resolveWorkspaceSlug({\n workspaceId: completedConnection.workspaceId,\n fallbackWorkspaces: workspaces,\n queryClient,\n });\n if (!disposedRef.current && isActive())\n setCompletedWorkspace(workspaceSlug ? {slug: workspaceSlug} : {});\n return;\n }\n rememberCompletedConnection(callbackKey, connection);\n try {\n clearJiraInstallWorkspace(sessionStorageOrUndefined());\n } catch {\n // The successful API response remains the source of truth for navigation.\n }\n if (disposedRef.current || !isActive()) return;\n if (!jiraToastedCallbacks.has(callbackKey)) {\n rememberCallbackKey(jiraToastedCallbacks, callbackKey);\n toast.success('Jira installed.');\n }\n let workspaceSlug: string | undefined;\n try {\n workspaceSlug = await resolveWorkspaceSlug({\n workspaceId: connection.workspaceId,\n fallbackWorkspaces: workspaces,\n queryClient,\n });\n if (disposedRef.current || !isActive()) return;\n if (!workspaceSlug) {\n setCompletedWorkspace({});\n return;\n }\n setCompletedWorkspace({slug: workspaceSlug});\n await navigate({\n to: '/w/$workspaceSlug/settings/integrations',\n params: {workspaceSlug},\n replace: true,\n });\n } catch {\n if (!disposedRef.current && isActive()) setCompletedWorkspace({slug: workspaceSlug});\n }\n },\n [navigate, queryClient, workspaces],\n );\n\n useEffect(() => {\n if (callbackKey === undefined) return;\n setCallbackStateKey(callbackKey);\n setSites(undefined);\n setSelectedCloudId(undefined);\n setFailure(undefined);\n setCompletedWorkspace(undefined);\n }, [callbackKey]);\n\n useEffect(() => {\n if (!params || !callbackKey || isLoading) return;\n\n let active = true;\n\n const completedConnection = jiraCompletedConnections.get(callbackKey);\n if (completedConnection) {\n void completeConnection(completedConnection, callbackKey, () => active);\n return () => {\n active = false;\n };\n }\n\n const request = jiraCallbackRequests.run(callbackKey, async () => {\n return await completeIntegrationCallbackResult({\n input: params,\n refreshAuth,\n complete: async (query, token) => await completeJiraCallback({query, token}),\n getConnection: (result) => ('sites' in result ? undefined : result),\n });\n });\n\n request.then(\n async (result) => {\n if (disposedRef.current || !active) return;\n if ('sites' in result) {\n setFailure(undefined);\n setSites(result.sites);\n return;\n }\n await completeConnection(result, callbackKey, () => active);\n },\n (error: unknown) => {\n if (!disposedRef.current && active) setFailure(classifyJiraCallbackError(error));\n },\n );\n\n return () => {\n active = false;\n };\n }, [\n callbackKey,\n completeIntegrationCallbackResult,\n completeJiraCallback,\n completeConnection,\n isLoading,\n params,\n refreshAuth,\n ]);\n\n function selectSite(site: JiraSite) {\n if (!params || !callbackKey || selectedCloudId) return;\n setSelectedCloudId(site.cloudId);\n setFailure(undefined);\n const selectionKey = callbackKey;\n const request = jiraSiteSelectionRequests.run(params.state, async () => {\n return await completeIntegrationCallback({\n input: {cloud_id: site.cloudId, state: params.state},\n refreshAuth,\n complete: async (body, token) => await completeJiraSiteSelection({body, token}),\n });\n });\n request.then(\n async (connection) => {\n if (disposedRef.current || callbackKeyRef.current !== selectionKey) return;\n jiraCallbackRequests.clear(selectionKey);\n await completeConnection(\n connection,\n selectionKey,\n () => callbackKeyRef.current === selectionKey,\n );\n },\n (error: unknown) => {\n if (disposedRef.current || callbackKeyRef.current !== selectionKey) return;\n setSelectedCloudId(undefined);\n setFailure(classifyJiraCallbackError(error));\n },\n );\n }\n\n if (!params) {\n return (\n <JiraCallbackFailurePage\n failure={classifyJiraCallbackError(new Error('invalid callback'))}\n workspaceSlug={workspaces.find(({id}) => id === workspaceId)?.slug}\n />\n );\n }\n\n if (isLoading) return <FullPageLoader aria-label=\"Connecting Jira\" />;\n\n if (callbackStateKey === callbackKey && completedWorkspace)\n return (\n <CallbackStatusShell\n title=\"Jira connected\"\n status=\"success\"\n message={\n completedWorkspace.slug\n ? 'Jira is connected. Continue in integrations settings.'\n : 'Jira is connected. Return to Shipfox to continue.'\n }\n workspaceSlug={completedWorkspace.slug}\n installPath=\"/w/$workspaceSlug/integrations/jira\"\n />\n );\n\n if (callbackStateKey === callbackKey && sites)\n return (\n <JiraSiteSelectionPage\n sites={sites}\n selectedCloudId={selectedCloudId}\n failure={failure}\n workspaceSlug={workspaces.find(({id}) => id === workspaceId)?.slug}\n onSelect={selectSite}\n />\n );\n\n if (callbackStateKey === callbackKey && failure)\n return (\n <JiraCallbackFailurePage\n failure={failure}\n workspaceSlug={workspaces.find(({id}) => id === workspaceId)?.slug}\n />\n );\n\n return <FullPageLoader aria-label=\"Connecting Jira\" />;\n}\n\nfunction rememberCompletedConnection(key: string, connection: IntegrationConnection): void {\n jiraCompletedConnections.delete(key);\n jiraCompletedConnections.set(key, connection);\n while (jiraCompletedConnections.size > JIRA_CALLBACK_CACHE_SIZE) {\n const oldestKey = jiraCompletedConnections.keys().next().value;\n if (oldestKey === undefined) return;\n jiraCompletedConnections.delete(oldestKey);\n }\n}\n\nfunction JiraCallbackFailurePage({\n failure,\n workspaceSlug,\n}: {\n failure: JiraCallbackFailure;\n workspaceSlug: string | undefined;\n}) {\n return (\n <CallbackStatusShell\n title={failure.title}\n message={failure.message}\n startOver={failure.startOver}\n switchAccount={failure.signIn}\n workspaceSlug={workspaceSlug}\n installPath=\"/w/$workspaceSlug/integrations/jira\"\n />\n );\n}\n\nfunction JiraSiteSelectionPage({\n sites,\n selectedCloudId,\n failure,\n workspaceSlug,\n onSelect,\n}: {\n sites: JiraSite[];\n selectedCloudId: string | undefined;\n failure: JiraCallbackFailure | undefined;\n workspaceSlug: string | undefined;\n onSelect: (site: JiraSite) => void;\n}) {\n return (\n <main className=\"flex min-h-screen px-row py-frame\">\n <div className=\"mx-auto flex w-full flex-col justify-center gap-section\">\n <header className=\"flex flex-col gap-inline\">\n <Header variant=\"h2\">Choose a Jira site</Header>\n <Text size=\"sm\" className=\"text-foreground-neutral-muted\">\n Select the Jira site to connect to this Shipfox workspace.\n </Text>\n </header>\n\n {failure ? (\n <Callout role=\"alert\" type=\"error\">\n <Text size=\"sm\">{failure.message}</Text>\n </Callout>\n ) : null}\n\n <section className=\"flex flex-col gap-inline\" aria-label=\"Choose a Jira site\">\n {sites.map((site) => (\n <Panel key={site.cloudId} className=\"p-panel-compact\">\n <div className=\"flex items-center justify-between gap-cluster\">\n <div className=\"min-w-0\">\n <Text size=\"md\" bold className=\"truncate\">\n {site.name}\n </Text>\n <Text size=\"sm\" className=\"truncate text-foreground-neutral-muted\">\n {site.url}\n </Text>\n </div>\n <Button\n variant=\"secondary\"\n disabled={selectedCloudId !== undefined}\n isLoading={selectedCloudId === site.cloudId}\n onClick={() => onSelect(site)}\n >\n Connect\n </Button>\n </div>\n </Panel>\n ))}\n </section>\n\n <div className=\"flex flex-col gap-inline sm:flex-row sm:items-center\">\n {failure?.startOver && workspaceSlug ? (\n <ButtonLink asChild variant=\"muted\" className=\"min-h-44 w-full sm:w-fit\">\n <Link to=\"/w/$workspaceSlug/integrations/jira\" params={{workspaceSlug}}>\n Start over\n </Link>\n </ButtonLink>\n ) : null}\n {workspaceSlug ? (\n <ButtonLink asChild variant=\"muted\" className=\"min-h-44 w-full sm:w-fit\">\n <Link to=\"/w/$workspaceSlug/settings/integrations\" params={{workspaceSlug}}>\n Back to integrations\n </Link>\n </ButtonLink>\n ) : (\n <ButtonLink asChild variant=\"muted\" className=\"min-h-44 w-full sm:w-fit\">\n <Link to=\"/\">Back to Shipfox</Link>\n </ButtonLink>\n )}\n </div>\n </div>\n </main>\n );\n}\n"],"names":["useAuthState","useRefreshAuth","useRouteSearch","sessionStorageOrUndefined","Button","ButtonLink","Callout","FullPageLoader","Panel","toast","Header","Text","useQueryClient","Link","useNavigate","useCallback","useEffect","useMemo","useRef","useState","useCompleteIntegrationCallback","useCompleteIntegrationCallbackResult","CallbackStatusShell","useCompleteJiraCallbackMutation","useCompleteJiraSiteSelectionMutation","clearJiraInstallWorkspace","parseJiraCallbackQuery","readJiraInstallWorkspace","serializeJiraCallbackQuery","JIRA_CALLBACK_CACHE_SIZE","jiraCallbackRequests","jiraCompletedConnections","jiraSiteSelectionRequests","jiraToastedCallbacks","classifyJiraCallbackError","rememberCallbackKey","resolveWorkspaceSlug","JiraCallbackPage","navigate","queryClient","refreshAuth","workspaces","isLoading","completeIntegrationCallback","completeIntegrationCallbackResult","mutateAsync","completeJiraCallback","completeJiraSiteSelection","params","callbackKey","undefined","workspaceId","sites","setSites","failure","setFailure","selectedCloudId","setSelectedCloudId","completedWorkspace","setCompletedWorkspace","disposedRef","callbackKeyRef","current","callbackStateKey","setCallbackStateKey","completeConnection","connection","isActive","completedConnection","get","workspaceSlug","fallbackWorkspaces","slug","rememberCompletedConnection","has","success","to","replace","active","request","run","input","complete","query","token","getConnection","result","then","error","selectSite","site","cloudId","selectionKey","state","cloud_id","body","clear","JiraCallbackFailurePage","Error","find","id","aria-label","title","status","message","installPath","JiraSiteSelectionPage","onSelect","key","delete","set","size","oldestKey","keys","next","value","startOver","switchAccount","signIn","main","className","div","header","variant","role","type","section","map","bold","name","url","disabled","onClick","asChild"],"mappings":"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"}
@@ -4,8 +4,8 @@ import { useRouteSearch } from '@shipfox/client-shell/runtime';
4
4
  import { createSingleFlight, sessionStorageOrUndefined } from '@shipfox/client-ui';
5
5
  import { Button, ButtonLink } from '@shipfox/react-ui/button';
6
6
  import { Callout } from '@shipfox/react-ui/callout';
7
- import { Card } from '@shipfox/react-ui/card';
8
7
  import { FullPageLoader } from '@shipfox/react-ui/loader';
8
+ import { Panel } from '@shipfox/react-ui/panel';
9
9
  import { toast } from '@shipfox/react-ui/toast';
10
10
  import { Header, Text } from '@shipfox/react-ui/typography';
11
11
  import { useQueryClient } from '@tanstack/react-query';
@@ -202,7 +202,7 @@ export function SentryCallbackPage() {
202
202
  /*#__PURE__*/ _jsx("section", {
203
203
  className: "flex flex-col gap-inline",
204
204
  "aria-label": "Choose a workspace",
205
- children: orderedWorkspaces.map((workspace)=>/*#__PURE__*/ _jsx(Card, {
205
+ children: orderedWorkspaces.map((workspace)=>/*#__PURE__*/ _jsx(Panel, {
206
206
  className: "p-panel-compact",
207
207
  children: /*#__PURE__*/ _jsxs("div", {
208
208
  className: "flex items-center justify-between gap-cluster",
@@ -241,9 +241,9 @@ export function SentryCallbackPage() {
241
241
  }
242
242
  function CallbackColumn({ children }) {
243
243
  return /*#__PURE__*/ _jsx("main", {
244
- className: "flex min-h-screen bg-background-subtle-base px-row py-frame",
244
+ className: "flex min-h-screen px-row py-frame",
245
245
  children: /*#__PURE__*/ _jsx("div", {
246
- className: "mx-auto flex w-full max-w-[480px] flex-col justify-center gap-section",
246
+ className: "mx-auto flex w-full flex-col justify-center gap-section",
247
247
  children: children
248
248
  })
249
249
  });
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/pages/sentry-callback-page.tsx"],"sourcesContent":["import {useAuthState, useRefreshAuth} from '@shipfox/client-auth';\nimport {useRouteSearch} from '@shipfox/client-shell/runtime';\nimport {createSingleFlight, sessionStorageOrUndefined} from '@shipfox/client-ui';\nimport {Button, ButtonLink} from '@shipfox/react-ui/button';\nimport {Callout} from '@shipfox/react-ui/callout';\nimport {Card} from '@shipfox/react-ui/card';\nimport {FullPageLoader} from '@shipfox/react-ui/loader';\nimport {toast} from '@shipfox/react-ui/toast';\nimport {Header, Text} from '@shipfox/react-ui/typography';\nimport {useQueryClient} from '@tanstack/react-query';\nimport {Link, useNavigate} from '@tanstack/react-router';\nimport {useEffect, useMemo, useRef, useState} from 'react';\nimport {useCompleteIntegrationCallback} from '#application/complete-integration-callback.js';\nimport type {IntegrationConnection} from '#core/models.js';\nimport {connectSentry} from '#hooks/api/integrations.js';\nimport {\n classifySentryConnectError,\n clearSentryInstallWorkspace,\n parseSentryCallbackParams,\n preselectSentryWorkspace,\n readSentryInstallWorkspace,\n type SentryConnectFailure,\n} from '#sentry-callback.js';\nimport {resolveWorkspaceSlug} from '#workspace-navigation.js';\n\nconst connectRequests = createSingleFlight<string, IntegrationConnection>();\n\nexport function SentryCallbackPage() {\n const navigate = useNavigate();\n const queryClient = useQueryClient();\n const refreshAuth = useRefreshAuth();\n const {workspaces, isLoading} = useAuthState();\n const completeIntegrationCallback = useCompleteIntegrationCallback();\n\n const params = useRouteSearch(parseSentryCallbackParams);\n const storedWorkspaceId = useMemo(\n () => readSentryInstallWorkspace(sessionStorageOrUndefined()),\n [],\n );\n const preselection = preselectSentryWorkspace(storedWorkspaceId, workspaces);\n const preselectedId = preselection.kind === 'pick' ? preselection.preselectedId : undefined;\n\n const [connectingId, setConnectingId] = useState<string | undefined>();\n const [failure, setFailure] = useState<\n {workspaceId: string; failure: SentryConnectFailure} | undefined\n >();\n const [retryLocked, setRetryLocked] = useState(false);\n const disposedRef = useRef(false);\n\n useEffect(() => {\n disposedRef.current = false;\n return () => {\n disposedRef.current = true;\n };\n }, []);\n\n // Wait for auth before treating an empty workspace list as \"no workspace\": on\n // a cold return from Sentry, `workspaces` is [] until the session refresh\n // resolves, and bouncing to `/` then would discard the one-shot grant code.\n const noWorkspace = !isLoading && preselection.kind === 'none';\n useEffect(() => {\n if (!noWorkspace) return;\n toast.error('You need a workspace before installing Sentry.');\n navigate({to: '/', replace: true});\n }, [noWorkspace, navigate]);\n\n const retryAfterSeconds =\n failure?.failure.kind === 'retryable' ? failure.failure.retryAfterSeconds : undefined;\n useEffect(() => {\n // No backoff window (any non-rate-limited failure) re-enables Retry, so a\n // prior rate-limit lock can never strand the button in a disabled state.\n if (!retryAfterSeconds) {\n setRetryLocked(false);\n return;\n }\n setRetryLocked(true);\n const timer = setTimeout(() => setRetryLocked(false), retryAfterSeconds * 1000);\n return () => clearTimeout(timer);\n }, [retryAfterSeconds]);\n\n if (!params) {\n return (\n <CallbackColumn>\n <Callout role=\"alert\" type=\"error\">\n <Text size=\"sm\">\n This Sentry link is missing required parameters. Start the install again from your\n workspace settings.\n </Text>\n </Callout>\n <ButtonLink asChild variant=\"muted\" className=\"w-fit\">\n <Link to=\"/\">Back to Shipfox</Link>\n </ButtonLink>\n </CallbackColumn>\n );\n }\n\n // Hold the loader until auth resolves; the workspace list and the\n // noWorkspace redirect both depend on a settled `workspaces`.\n if (isLoading) return <FullPageLoader />;\n\n if (noWorkspace) return null;\n\n const connect = (workspaceId: string) => {\n setConnectingId(workspaceId);\n setFailure(undefined);\n const key = `${params.installationId}|${workspaceId}|${params.code}`;\n const request = connectRequests.run(\n key,\n async () =>\n await completeIntegrationCallback({\n input: workspaceId,\n refreshAuth,\n complete: async (selectedWorkspaceId, token) =>\n await connectSentry({\n body: {\n workspace_id: selectedWorkspaceId,\n code: params.code,\n installation_id: params.installationId,\n },\n token,\n }),\n }),\n );\n\n request\n .then(async () => {\n clearSentryInstallWorkspace(sessionStorageOrUndefined());\n if (disposedRef.current) return;\n toast.success('Sentry installed.');\n const workspaceSlug = await resolveWorkspaceSlug({\n workspaceId,\n fallbackWorkspaces: workspaces,\n queryClient,\n });\n if (disposedRef.current) return;\n await navigate(\n workspaceSlug\n ? {\n to: '/w/$workspaceSlug/settings/integrations',\n params: {workspaceSlug},\n replace: true,\n }\n : {to: '/', replace: true},\n );\n })\n .catch((error: unknown) => {\n if (disposedRef.current) return;\n const classified = classifySentryConnectError(error);\n if (classified.kind === 'terminal') {\n // Only a fresh install (new grant code) can recover; the stored\n // handoff has served its purpose either way.\n clearSentryInstallWorkspace(sessionStorageOrUndefined());\n }\n setConnectingId(undefined);\n setFailure({workspaceId, failure: classified});\n });\n };\n\n const orderedWorkspaces = preselectedId\n ? [\n ...workspaces.filter((workspace) => workspace.id === preselectedId),\n ...workspaces.filter((workspace) => workspace.id !== preselectedId),\n ]\n : workspaces;\n\n const failureWorkspaceId = failure?.workspaceId ?? preselectedId ?? workspaces[0]?.id;\n const failureWorkspace = failureWorkspaceId\n ? workspaces.find(({id}) => id === failureWorkspaceId)\n : undefined;\n\n return (\n <CallbackColumn>\n <header className=\"flex flex-col gap-inline\">\n <Header variant=\"h2\">Install Sentry</Header>\n <Text size=\"sm\" className=\"text-foreground-neutral-muted\">\n {params.orgSlug\n ? `Install the Sentry org \"${params.orgSlug}\" in a workspace.`\n : 'Install this Sentry integration in a workspace.'}\n </Text>\n </header>\n\n {failure ? (\n <Callout role=\"alert\" type=\"error\">\n <div className=\"flex flex-col gap-inline\">\n <Text size=\"sm\">{failure.failure.message}</Text>\n {failure.failure.kind === 'retryable' ? (\n <Button\n size=\"sm\"\n variant=\"secondary\"\n className=\"w-fit\"\n disabled={retryLocked || connectingId !== undefined}\n onClick={() => connect(failure.workspaceId)}\n >\n Retry\n </Button>\n ) : null}\n {failure.failure.kind === 'terminal' &&\n failure.failure.startOver &&\n failureWorkspace ? (\n <Button asChild size=\"sm\" variant=\"secondary\" className=\"w-fit\">\n <Link\n to=\"/w/$workspaceSlug/integrations/sentry\"\n params={{workspaceSlug: failureWorkspace.slug}}\n >\n Start over\n </Link>\n </Button>\n ) : null}\n </div>\n </Callout>\n ) : null}\n\n <section className=\"flex flex-col gap-inline\" aria-label=\"Choose a workspace\">\n {orderedWorkspaces.map((workspace) => (\n <Card key={workspace.id} className=\"p-panel-compact\">\n <div className=\"flex items-center justify-between gap-cluster\">\n <Text size=\"md\" bold className=\"truncate\">\n {workspace.name}\n </Text>\n <Button\n variant=\"secondary\"\n disabled={connectingId !== undefined}\n isLoading={connectingId === workspace.id}\n onClick={() => connect(workspace.id)}\n >\n Install\n </Button>\n </div>\n </Card>\n ))}\n </section>\n\n {failureWorkspace ? (\n <ButtonLink asChild variant=\"muted\" className=\"w-fit\">\n <Link\n to=\"/w/$workspaceSlug/settings/integrations\"\n params={{workspaceSlug: failureWorkspace.slug}}\n >\n Back to settings\n </Link>\n </ButtonLink>\n ) : null}\n </CallbackColumn>\n );\n}\n\nfunction CallbackColumn({children}: {children: React.ReactNode}) {\n return (\n <main className=\"flex min-h-screen bg-background-subtle-base px-row py-frame\">\n <div className=\"mx-auto flex w-full max-w-[480px] flex-col justify-center gap-section\">\n {children}\n </div>\n </main>\n );\n}\n"],"names":["useAuthState","useRefreshAuth","useRouteSearch","createSingleFlight","sessionStorageOrUndefined","Button","ButtonLink","Callout","Card","FullPageLoader","toast","Header","Text","useQueryClient","Link","useNavigate","useEffect","useMemo","useRef","useState","useCompleteIntegrationCallback","connectSentry","classifySentryConnectError","clearSentryInstallWorkspace","parseSentryCallbackParams","preselectSentryWorkspace","readSentryInstallWorkspace","resolveWorkspaceSlug","connectRequests","SentryCallbackPage","navigate","queryClient","refreshAuth","workspaces","isLoading","completeIntegrationCallback","params","storedWorkspaceId","preselection","preselectedId","kind","undefined","connectingId","setConnectingId","failure","setFailure","retryLocked","setRetryLocked","disposedRef","current","noWorkspace","error","to","replace","retryAfterSeconds","timer","setTimeout","clearTimeout","CallbackColumn","role","type","size","asChild","variant","className","connect","workspaceId","key","installationId","code","request","run","input","complete","selectedWorkspaceId","token","body","workspace_id","installation_id","then","success","workspaceSlug","fallbackWorkspaces","catch","classified","orderedWorkspaces","filter","workspace","id","failureWorkspaceId","failureWorkspace","find","header","orgSlug","div","message","disabled","onClick","startOver","slug","section","aria-label","map","bold","name","children","main"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/pages/sentry-callback-page.tsx"],"sourcesContent":["import {useAuthState, useRefreshAuth} from '@shipfox/client-auth';\nimport {useRouteSearch} from '@shipfox/client-shell/runtime';\nimport {createSingleFlight, sessionStorageOrUndefined} from '@shipfox/client-ui';\nimport {Button, ButtonLink} from '@shipfox/react-ui/button';\nimport {Callout} from '@shipfox/react-ui/callout';\nimport {FullPageLoader} from '@shipfox/react-ui/loader';\nimport {Panel} from '@shipfox/react-ui/panel';\nimport {toast} from '@shipfox/react-ui/toast';\nimport {Header, Text} from '@shipfox/react-ui/typography';\nimport {useQueryClient} from '@tanstack/react-query';\nimport {Link, useNavigate} from '@tanstack/react-router';\nimport {useEffect, useMemo, useRef, useState} from 'react';\nimport {useCompleteIntegrationCallback} from '#application/complete-integration-callback.js';\nimport type {IntegrationConnection} from '#core/models.js';\nimport {connectSentry} from '#hooks/api/integrations.js';\nimport {\n classifySentryConnectError,\n clearSentryInstallWorkspace,\n parseSentryCallbackParams,\n preselectSentryWorkspace,\n readSentryInstallWorkspace,\n type SentryConnectFailure,\n} from '#sentry-callback.js';\nimport {resolveWorkspaceSlug} from '#workspace-navigation.js';\n\nconst connectRequests = createSingleFlight<string, IntegrationConnection>();\n\nexport function SentryCallbackPage() {\n const navigate = useNavigate();\n const queryClient = useQueryClient();\n const refreshAuth = useRefreshAuth();\n const {workspaces, isLoading} = useAuthState();\n const completeIntegrationCallback = useCompleteIntegrationCallback();\n\n const params = useRouteSearch(parseSentryCallbackParams);\n const storedWorkspaceId = useMemo(\n () => readSentryInstallWorkspace(sessionStorageOrUndefined()),\n [],\n );\n const preselection = preselectSentryWorkspace(storedWorkspaceId, workspaces);\n const preselectedId = preselection.kind === 'pick' ? preselection.preselectedId : undefined;\n\n const [connectingId, setConnectingId] = useState<string | undefined>();\n const [failure, setFailure] = useState<\n {workspaceId: string; failure: SentryConnectFailure} | undefined\n >();\n const [retryLocked, setRetryLocked] = useState(false);\n const disposedRef = useRef(false);\n\n useEffect(() => {\n disposedRef.current = false;\n return () => {\n disposedRef.current = true;\n };\n }, []);\n\n // Wait for auth before treating an empty workspace list as \"no workspace\": on\n // a cold return from Sentry, `workspaces` is [] until the session refresh\n // resolves, and bouncing to `/` then would discard the one-shot grant code.\n const noWorkspace = !isLoading && preselection.kind === 'none';\n useEffect(() => {\n if (!noWorkspace) return;\n toast.error('You need a workspace before installing Sentry.');\n navigate({to: '/', replace: true});\n }, [noWorkspace, navigate]);\n\n const retryAfterSeconds =\n failure?.failure.kind === 'retryable' ? failure.failure.retryAfterSeconds : undefined;\n useEffect(() => {\n // No backoff window (any non-rate-limited failure) re-enables Retry, so a\n // prior rate-limit lock can never strand the button in a disabled state.\n if (!retryAfterSeconds) {\n setRetryLocked(false);\n return;\n }\n setRetryLocked(true);\n const timer = setTimeout(() => setRetryLocked(false), retryAfterSeconds * 1000);\n return () => clearTimeout(timer);\n }, [retryAfterSeconds]);\n\n if (!params) {\n return (\n <CallbackColumn>\n <Callout role=\"alert\" type=\"error\">\n <Text size=\"sm\">\n This Sentry link is missing required parameters. Start the install again from your\n workspace settings.\n </Text>\n </Callout>\n <ButtonLink asChild variant=\"muted\" className=\"w-fit\">\n <Link to=\"/\">Back to Shipfox</Link>\n </ButtonLink>\n </CallbackColumn>\n );\n }\n\n // Hold the loader until auth resolves; the workspace list and the\n // noWorkspace redirect both depend on a settled `workspaces`.\n if (isLoading) return <FullPageLoader />;\n\n if (noWorkspace) return null;\n\n const connect = (workspaceId: string) => {\n setConnectingId(workspaceId);\n setFailure(undefined);\n const key = `${params.installationId}|${workspaceId}|${params.code}`;\n const request = connectRequests.run(\n key,\n async () =>\n await completeIntegrationCallback({\n input: workspaceId,\n refreshAuth,\n complete: async (selectedWorkspaceId, token) =>\n await connectSentry({\n body: {\n workspace_id: selectedWorkspaceId,\n code: params.code,\n installation_id: params.installationId,\n },\n token,\n }),\n }),\n );\n\n request\n .then(async () => {\n clearSentryInstallWorkspace(sessionStorageOrUndefined());\n if (disposedRef.current) return;\n toast.success('Sentry installed.');\n const workspaceSlug = await resolveWorkspaceSlug({\n workspaceId,\n fallbackWorkspaces: workspaces,\n queryClient,\n });\n if (disposedRef.current) return;\n await navigate(\n workspaceSlug\n ? {\n to: '/w/$workspaceSlug/settings/integrations',\n params: {workspaceSlug},\n replace: true,\n }\n : {to: '/', replace: true},\n );\n })\n .catch((error: unknown) => {\n if (disposedRef.current) return;\n const classified = classifySentryConnectError(error);\n if (classified.kind === 'terminal') {\n // Only a fresh install (new grant code) can recover; the stored\n // handoff has served its purpose either way.\n clearSentryInstallWorkspace(sessionStorageOrUndefined());\n }\n setConnectingId(undefined);\n setFailure({workspaceId, failure: classified});\n });\n };\n\n const orderedWorkspaces = preselectedId\n ? [\n ...workspaces.filter((workspace) => workspace.id === preselectedId),\n ...workspaces.filter((workspace) => workspace.id !== preselectedId),\n ]\n : workspaces;\n\n const failureWorkspaceId = failure?.workspaceId ?? preselectedId ?? workspaces[0]?.id;\n const failureWorkspace = failureWorkspaceId\n ? workspaces.find(({id}) => id === failureWorkspaceId)\n : undefined;\n\n return (\n <CallbackColumn>\n <header className=\"flex flex-col gap-inline\">\n <Header variant=\"h2\">Install Sentry</Header>\n <Text size=\"sm\" className=\"text-foreground-neutral-muted\">\n {params.orgSlug\n ? `Install the Sentry org \"${params.orgSlug}\" in a workspace.`\n : 'Install this Sentry integration in a workspace.'}\n </Text>\n </header>\n\n {failure ? (\n <Callout role=\"alert\" type=\"error\">\n <div className=\"flex flex-col gap-inline\">\n <Text size=\"sm\">{failure.failure.message}</Text>\n {failure.failure.kind === 'retryable' ? (\n <Button\n size=\"sm\"\n variant=\"secondary\"\n className=\"w-fit\"\n disabled={retryLocked || connectingId !== undefined}\n onClick={() => connect(failure.workspaceId)}\n >\n Retry\n </Button>\n ) : null}\n {failure.failure.kind === 'terminal' &&\n failure.failure.startOver &&\n failureWorkspace ? (\n <Button asChild size=\"sm\" variant=\"secondary\" className=\"w-fit\">\n <Link\n to=\"/w/$workspaceSlug/integrations/sentry\"\n params={{workspaceSlug: failureWorkspace.slug}}\n >\n Start over\n </Link>\n </Button>\n ) : null}\n </div>\n </Callout>\n ) : null}\n\n <section className=\"flex flex-col gap-inline\" aria-label=\"Choose a workspace\">\n {orderedWorkspaces.map((workspace) => (\n <Panel key={workspace.id} className=\"p-panel-compact\">\n <div className=\"flex items-center justify-between gap-cluster\">\n <Text size=\"md\" bold className=\"truncate\">\n {workspace.name}\n </Text>\n <Button\n variant=\"secondary\"\n disabled={connectingId !== undefined}\n isLoading={connectingId === workspace.id}\n onClick={() => connect(workspace.id)}\n >\n Install\n </Button>\n </div>\n </Panel>\n ))}\n </section>\n\n {failureWorkspace ? (\n <ButtonLink asChild variant=\"muted\" className=\"w-fit\">\n <Link\n to=\"/w/$workspaceSlug/settings/integrations\"\n params={{workspaceSlug: failureWorkspace.slug}}\n >\n Back to settings\n </Link>\n </ButtonLink>\n ) : null}\n </CallbackColumn>\n );\n}\n\nfunction CallbackColumn({children}: {children: React.ReactNode}) {\n return (\n <main className=\"flex min-h-screen px-row py-frame\">\n <div className=\"mx-auto flex w-full flex-col justify-center gap-section\">{children}</div>\n </main>\n );\n}\n"],"names":["useAuthState","useRefreshAuth","useRouteSearch","createSingleFlight","sessionStorageOrUndefined","Button","ButtonLink","Callout","FullPageLoader","Panel","toast","Header","Text","useQueryClient","Link","useNavigate","useEffect","useMemo","useRef","useState","useCompleteIntegrationCallback","connectSentry","classifySentryConnectError","clearSentryInstallWorkspace","parseSentryCallbackParams","preselectSentryWorkspace","readSentryInstallWorkspace","resolveWorkspaceSlug","connectRequests","SentryCallbackPage","navigate","queryClient","refreshAuth","workspaces","isLoading","completeIntegrationCallback","params","storedWorkspaceId","preselection","preselectedId","kind","undefined","connectingId","setConnectingId","failure","setFailure","retryLocked","setRetryLocked","disposedRef","current","noWorkspace","error","to","replace","retryAfterSeconds","timer","setTimeout","clearTimeout","CallbackColumn","role","type","size","asChild","variant","className","connect","workspaceId","key","installationId","code","request","run","input","complete","selectedWorkspaceId","token","body","workspace_id","installation_id","then","success","workspaceSlug","fallbackWorkspaces","catch","classified","orderedWorkspaces","filter","workspace","id","failureWorkspaceId","failureWorkspace","find","header","orgSlug","div","message","disabled","onClick","startOver","slug","section","aria-label","map","bold","name","children","main"],"mappings":"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"}
@@ -9,7 +9,7 @@ export function SourceControlOnboardingPage() {
9
9
  capability: 'source_control'
10
10
  });
11
11
  return /*#__PURE__*/ _jsxs("div", {
12
- className: "mx-auto flex w-full max-w-[640px] flex-col gap-section",
12
+ className: "mx-auto flex w-full flex-col gap-section",
13
13
  children: [
14
14
  /*#__PURE__*/ _jsxs("header", {
15
15
  className: "flex flex-col gap-inline",
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/pages/source-control-onboarding-page.tsx"],"sourcesContent":["import {useActiveWorkspace} from '@shipfox/client-auth';\nimport {Header, Text} from '@shipfox/react-ui/typography';\nimport {ProviderGrid} from '#components/provider-grid.js';\nimport {useIntegrationProvidersQuery} from '#hooks/api/integrations.js';\n\nexport function SourceControlOnboardingPage() {\n const workspace = useActiveWorkspace();\n const providersQuery = useIntegrationProvidersQuery({capability: 'source_control'});\n\n return (\n <div className=\"mx-auto flex w-full max-w-[640px] flex-col gap-section\">\n <header className=\"flex flex-col gap-inline\">\n <Header variant=\"h1\">Install source control</Header>\n <Text size=\"md\" className=\"text-foreground-neutral-muted\">\n Shipfox needs a source control integration to import your repositories.\n </Text>\n </header>\n\n <ProviderGrid\n workspaceSlug={workspace.slug}\n providers={providersQuery.data ?? []}\n isPending={providersQuery.isPending}\n isFetching={providersQuery.isFetching}\n error={providersQuery.isError ? providersQuery.error : undefined}\n onRetry={() => void providersQuery.refetch()}\n emptyMessage=\"Enable at least one source-control provider in the application settings.\"\n />\n </div>\n );\n}\n"],"names":["useActiveWorkspace","Header","Text","ProviderGrid","useIntegrationProvidersQuery","SourceControlOnboardingPage","workspace","providersQuery","capability","div","className","header","variant","size","workspaceSlug","slug","providers","data","isPending","isFetching","error","isError","undefined","onRetry","refetch","emptyMessage"],"mappings":";AAAA,SAAQA,kBAAkB,QAAO,uBAAuB;AACxD,SAAQC,MAAM,EAAEC,IAAI,QAAO,+BAA+B;AAC1D,SAAQC,YAAY,QAAO,+BAA+B;AAC1D,SAAQC,4BAA4B,QAAO,6BAA6B;AAExE,OAAO,SAASC;IACd,MAAMC,YAAYN;IAClB,MAAMO,iBAAiBH,6BAA6B;QAACI,YAAY;IAAgB;IAEjF,qBACE,MAACC;QAAIC,WAAU;;0BACb,MAACC;gBAAOD,WAAU;;kCAChB,KAACT;wBAAOW,SAAQ;kCAAK;;kCACrB,KAACV;wBAAKW,MAAK;wBAAKH,WAAU;kCAAgC;;;;0BAK5D,KAACP;gBACCW,eAAeR,UAAUS,IAAI;gBAC7BC,WAAWT,eAAeU,IAAI,IAAI,EAAE;gBACpCC,WAAWX,eAAeW,SAAS;gBACnCC,YAAYZ,eAAeY,UAAU;gBACrCC,OAAOb,eAAec,OAAO,GAAGd,eAAea,KAAK,GAAGE;gBACvDC,SAAS,IAAM,KAAKhB,eAAeiB,OAAO;gBAC1CC,cAAa;;;;AAIrB"}
1
+ {"version":3,"sources":["../../src/pages/source-control-onboarding-page.tsx"],"sourcesContent":["import {useActiveWorkspace} from '@shipfox/client-auth';\nimport {Header, Text} from '@shipfox/react-ui/typography';\nimport {ProviderGrid} from '#components/provider-grid.js';\nimport {useIntegrationProvidersQuery} from '#hooks/api/integrations.js';\n\nexport function SourceControlOnboardingPage() {\n const workspace = useActiveWorkspace();\n const providersQuery = useIntegrationProvidersQuery({capability: 'source_control'});\n\n return (\n <div className=\"mx-auto flex w-full flex-col gap-section\">\n <header className=\"flex flex-col gap-inline\">\n <Header variant=\"h1\">Install source control</Header>\n <Text size=\"md\" className=\"text-foreground-neutral-muted\">\n Shipfox needs a source control integration to import your repositories.\n </Text>\n </header>\n\n <ProviderGrid\n workspaceSlug={workspace.slug}\n providers={providersQuery.data ?? []}\n isPending={providersQuery.isPending}\n isFetching={providersQuery.isFetching}\n error={providersQuery.isError ? providersQuery.error : undefined}\n onRetry={() => void providersQuery.refetch()}\n emptyMessage=\"Enable at least one source-control provider in the application settings.\"\n />\n </div>\n );\n}\n"],"names":["useActiveWorkspace","Header","Text","ProviderGrid","useIntegrationProvidersQuery","SourceControlOnboardingPage","workspace","providersQuery","capability","div","className","header","variant","size","workspaceSlug","slug","providers","data","isPending","isFetching","error","isError","undefined","onRetry","refetch","emptyMessage"],"mappings":";AAAA,SAAQA,kBAAkB,QAAO,uBAAuB;AACxD,SAAQC,MAAM,EAAEC,IAAI,QAAO,+BAA+B;AAC1D,SAAQC,YAAY,QAAO,+BAA+B;AAC1D,SAAQC,4BAA4B,QAAO,6BAA6B;AAExE,OAAO,SAASC;IACd,MAAMC,YAAYN;IAClB,MAAMO,iBAAiBH,6BAA6B;QAACI,YAAY;IAAgB;IAEjF,qBACE,MAACC;QAAIC,WAAU;;0BACb,MAACC;gBAAOD,WAAU;;kCAChB,KAACT;wBAAOW,SAAQ;kCAAK;;kCACrB,KAACV;wBAAKW,MAAK;wBAAKH,WAAU;kCAAgC;;;;0BAK5D,KAACP;gBACCW,eAAeR,UAAUS,IAAI;gBAC7BC,WAAWT,eAAeU,IAAI,IAAI,EAAE;gBACpCC,WAAWX,eAAeW,SAAS;gBACnCC,YAAYZ,eAAeY,UAAU;gBACrCC,OAAOb,eAAec,OAAO,GAAGd,eAAea,KAAK,GAAGE;gBACvDC,SAAS,IAAM,KAAKhB,eAAeiB,OAAO;gBAC1CC,cAAa;;;;AAIrB"}
@@ -1,5 +1,8 @@
1
1
  import { GiteaInstallPage } from '#pages/gitea-install-page.js';
2
2
  declare const _default: import("@shipfox/client-shell/runtime").RouteImpl<{
3
+ readonly staticData: {
4
+ readonly frame: "focused";
5
+ };
3
6
  readonly component: typeof GiteaInstallPage;
4
7
  }>;
5
8
  export default _default;
@@ -1,6 +1,9 @@
1
1
  import { defineRoute } from '@shipfox/client-shell/runtime';
2
2
  import { GiteaInstallPage } from '#pages/gitea-install-page.js';
3
3
  export default defineRoute({
4
+ staticData: {
5
+ frame: 'focused'
6
+ },
4
7
  component: GiteaInstallPage
5
8
  });
6
9
 
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/routes/gitea.tsx"],"sourcesContent":["import {defineRoute} from '@shipfox/client-shell/runtime';\nimport {GiteaInstallPage} from '#pages/gitea-install-page.js';\n\nexport default defineRoute({component: GiteaInstallPage});\n"],"names":["defineRoute","GiteaInstallPage","component"],"mappings":"AAAA,SAAQA,WAAW,QAAO,gCAAgC;AAC1D,SAAQC,gBAAgB,QAAO,+BAA+B;AAE9D,eAAeD,YAAY;IAACE,WAAWD;AAAgB,GAAG"}
1
+ {"version":3,"sources":["../../src/routes/gitea.tsx"],"sourcesContent":["import {defineRoute} from '@shipfox/client-shell/runtime';\nimport {GiteaInstallPage} from '#pages/gitea-install-page.js';\n\nexport default defineRoute({\n staticData: {frame: 'focused'},\n component: GiteaInstallPage,\n});\n"],"names":["defineRoute","GiteaInstallPage","staticData","frame","component"],"mappings":"AAAA,SAAQA,WAAW,QAAO,gCAAgC;AAC1D,SAAQC,gBAAgB,QAAO,+BAA+B;AAE9D,eAAeD,YAAY;IACzBE,YAAY;QAACC,OAAO;IAAS;IAC7BC,WAAWH;AACb,GAAG"}
@@ -11,6 +11,9 @@ export interface GithubCallbackSearch {
11
11
  setupAction?: string;
12
12
  }
13
13
  declare const _default: import("@shipfox/client-shell/runtime").RouteImpl<{
14
+ readonly staticData: {
15
+ readonly frame: "focused";
16
+ };
14
17
  readonly validateSearch: typeof validateGithubCallbackSearch;
15
18
  readonly component: typeof GithubCallbackRoute;
16
19
  }>;
@@ -1 +1 @@
1
- {"version":3,"file":"github-callback.d.ts","sourceRoot":"","sources":["../../src/routes/github-callback.tsx"],"names":[],"mappings":"AAWA,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,cAAc,EAAE,MAAM,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,oBAAoB;IACnC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;;;;;;AAYD,iBAAS,mBAAmB,gCAuD3B;AAED,wBAAgB,4BAA4B,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,oBAAoB,CAWjG;AAED,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,oBAAoB,GAAG,MAAM,EAAE,CAM5E;AACD,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,oBAAoB,GAC3B,oBAAoB,GAAG,SAAS,CAKlC;AAoBD,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAGjE"}
1
+ {"version":3,"file":"github-callback.d.ts","sourceRoot":"","sources":["../../src/routes/github-callback.tsx"],"names":[],"mappings":"AAWA,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,cAAc,EAAE,MAAM,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,oBAAoB;IACnC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;;;;;;;;;AAaD,iBAAS,mBAAmB,gCAuD3B;AAED,wBAAgB,4BAA4B,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,oBAAoB,CAWjG;AAED,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,oBAAoB,GAAG,MAAM,EAAE,CAM5E;AACD,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,oBAAoB,GAC3B,oBAAoB,GAAG,SAAS,CAKlC;AAoBD,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAGjE"}
@@ -16,6 +16,9 @@ const callbackRequests = createSingleFlight({
16
16
  });
17
17
  const toastedCallbacks = new Set();
18
18
  export default defineRoute({
19
+ staticData: {
20
+ frame: 'focused'
21
+ },
19
22
  validateSearch: validateGithubCallbackSearch,
20
23
  component: GithubCallbackRoute
21
24
  });
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/routes/github-callback.tsx"],"sourcesContent":["import {ApiError} from '@shipfox/client-api';\nimport {useRefreshAuth} from '@shipfox/client-auth';\nimport {defineRoute, useRouteSearch} from '@shipfox/client-shell/runtime';\nimport {createSingleFlight} from '@shipfox/client-ui';\nimport {FullPageLoader} from '@shipfox/react-ui/loader';\nimport {toast} from '@shipfox/react-ui/toast';\nimport {useNavigate} from '@tanstack/react-router';\nimport {useEffect} from 'react';\nimport {useCompleteIntegrationCallback} from '#application/complete-integration-callback.js';\nimport {completeGithubCallback} from '#hooks/api/integrations.js';\n\nexport interface GithubCallbackParams {\n code: string;\n installationId: number;\n state: string;\n setupAction?: string;\n}\n\nexport interface GithubCallbackSearch {\n code?: string;\n installationId?: number;\n state?: string;\n setupAction?: string;\n}\n\n// Retain only recent completions: this bounds long-lived callback pages while\n// still covering StrictMode and immediate Back/Forward remounts.\nconst callbackRequests = createSingleFlight<string, void>({maxTerminalResults: 32});\nconst toastedCallbacks = new Set<string>();\n\nexport default defineRoute({\n validateSearch: validateGithubCallbackSearch,\n component: GithubCallbackRoute,\n});\n\nfunction GithubCallbackRoute() {\n const search = useRouteSearch(validateGithubCallbackSearch);\n const navigate = useNavigate();\n const refreshAuth = useRefreshAuth();\n const completeIntegrationCallback = useCompleteIntegrationCallback();\n\n useEffect(() => {\n const missing = missingCallbackParams(search);\n if (missing.length > 0) {\n toast.error(\n `GitHub callback is missing: ${missing.join(', ')}. ${missing.includes('code') ? 'Enable \"Request user authorization (OAuth) during installation\" on the Shipfox GitHub App.' : ''}`,\n );\n navigate({to: '/', replace: true});\n return;\n }\n const params = githubCallbackParams(search);\n if (!params) {\n toast.error('GitHub callback is missing required parameters.');\n navigate({to: '/', replace: true});\n return;\n }\n let disposed = false;\n const key = encodeCallbackQuery(params);\n const request = callbackRequests.run(\n key,\n async () =>\n void (await completeIntegrationCallback({\n input: params,\n refreshAuth,\n complete: async (input, token) => await completeGithubCallback({...input, token}),\n })),\n );\n request\n .then(() => {\n if (disposed) return;\n if (!toastedCallbacks.has(key)) {\n toastedCallbacks.add(key);\n toast.success('GitHub installed.');\n }\n navigate({to: '/', replace: true});\n })\n .catch((error: unknown) => {\n if (disposed) return;\n if (!toastedCallbacks.has(key)) {\n toastedCallbacks.add(key);\n toast.error(githubCallbackErrorMessage(error));\n }\n navigate({to: '/', replace: true});\n });\n return () => {\n disposed = true;\n };\n }, [completeIntegrationCallback, navigate, refreshAuth, search]);\n\n return <FullPageLoader />;\n}\n\nexport function validateGithubCallbackSearch(input: Record<string, unknown>): GithubCallbackSearch {\n const code = stringParam(input.code);\n const installationId = numberParam(input.installation_id);\n const state = stringParam(input.state);\n const setupAction = stringParam(input.setup_action);\n return {\n ...(code ? {code} : {}),\n ...(installationId === undefined ? {} : {installationId}),\n ...(state ? {state} : {}),\n ...(setupAction ? {setupAction} : {}),\n };\n}\n\nexport function missingCallbackParams(search: GithubCallbackSearch): string[] {\n const missing: string[] = [];\n if (!search.code) missing.push('code');\n if (search.installationId === undefined) missing.push('installation_id');\n if (!search.state) missing.push('state');\n return missing;\n}\nexport function githubCallbackParams(\n search: GithubCallbackSearch,\n): GithubCallbackParams | undefined {\n const {code, installationId, state} = search;\n if (!code || installationId === undefined || !state) return undefined;\n const {setupAction} = search;\n return setupAction ? {code, installationId, state, setupAction} : {code, installationId, state};\n}\nfunction encodeCallbackQuery(params: GithubCallbackParams): string {\n const search = new URLSearchParams();\n search.set('code', params.code);\n search.set('installation_id', params.installationId.toString());\n search.set('state', params.state);\n if (params.setupAction) search.set('setup_action', params.setupAction);\n return search.toString();\n}\nfunction stringParam(value: unknown): string | undefined {\n return typeof value === 'string' && value.length > 0 ? value : undefined;\n}\nfunction numberParam(value: unknown): number | undefined {\n if (typeof value === 'number' && Number.isFinite(value)) return value;\n if (typeof value === 'string' && value.length > 0) {\n const parsed = Number(value);\n return Number.isFinite(parsed) ? parsed : undefined;\n }\n return undefined;\n}\nexport function githubCallbackErrorMessage(error: unknown): string {\n if (error instanceof ApiError) return 'GitHub could not be installed. Try again from settings.';\n return 'Could not install GitHub.';\n}\n"],"names":["ApiError","useRefreshAuth","defineRoute","useRouteSearch","createSingleFlight","FullPageLoader","toast","useNavigate","useEffect","useCompleteIntegrationCallback","completeGithubCallback","callbackRequests","maxTerminalResults","toastedCallbacks","Set","validateSearch","validateGithubCallbackSearch","component","GithubCallbackRoute","search","navigate","refreshAuth","completeIntegrationCallback","missing","missingCallbackParams","length","error","join","includes","to","replace","params","githubCallbackParams","disposed","key","encodeCallbackQuery","request","run","input","complete","token","then","has","add","success","catch","githubCallbackErrorMessage","code","stringParam","installationId","numberParam","installation_id","state","setupAction","setup_action","undefined","push","URLSearchParams","set","toString","value","Number","isFinite","parsed"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/routes/github-callback.tsx"],"sourcesContent":["import {ApiError} from '@shipfox/client-api';\nimport {useRefreshAuth} from '@shipfox/client-auth';\nimport {defineRoute, useRouteSearch} from '@shipfox/client-shell/runtime';\nimport {createSingleFlight} from '@shipfox/client-ui';\nimport {FullPageLoader} from '@shipfox/react-ui/loader';\nimport {toast} from '@shipfox/react-ui/toast';\nimport {useNavigate} from '@tanstack/react-router';\nimport {useEffect} from 'react';\nimport {useCompleteIntegrationCallback} from '#application/complete-integration-callback.js';\nimport {completeGithubCallback} from '#hooks/api/integrations.js';\n\nexport interface GithubCallbackParams {\n code: string;\n installationId: number;\n state: string;\n setupAction?: string;\n}\n\nexport interface GithubCallbackSearch {\n code?: string;\n installationId?: number;\n state?: string;\n setupAction?: string;\n}\n\n// Retain only recent completions: this bounds long-lived callback pages while\n// still covering StrictMode and immediate Back/Forward remounts.\nconst callbackRequests = createSingleFlight<string, void>({maxTerminalResults: 32});\nconst toastedCallbacks = new Set<string>();\n\nexport default defineRoute({\n staticData: {frame: 'focused'},\n validateSearch: validateGithubCallbackSearch,\n component: GithubCallbackRoute,\n});\n\nfunction GithubCallbackRoute() {\n const search = useRouteSearch(validateGithubCallbackSearch);\n const navigate = useNavigate();\n const refreshAuth = useRefreshAuth();\n const completeIntegrationCallback = useCompleteIntegrationCallback();\n\n useEffect(() => {\n const missing = missingCallbackParams(search);\n if (missing.length > 0) {\n toast.error(\n `GitHub callback is missing: ${missing.join(', ')}. ${missing.includes('code') ? 'Enable \"Request user authorization (OAuth) during installation\" on the Shipfox GitHub App.' : ''}`,\n );\n navigate({to: '/', replace: true});\n return;\n }\n const params = githubCallbackParams(search);\n if (!params) {\n toast.error('GitHub callback is missing required parameters.');\n navigate({to: '/', replace: true});\n return;\n }\n let disposed = false;\n const key = encodeCallbackQuery(params);\n const request = callbackRequests.run(\n key,\n async () =>\n void (await completeIntegrationCallback({\n input: params,\n refreshAuth,\n complete: async (input, token) => await completeGithubCallback({...input, token}),\n })),\n );\n request\n .then(() => {\n if (disposed) return;\n if (!toastedCallbacks.has(key)) {\n toastedCallbacks.add(key);\n toast.success('GitHub installed.');\n }\n navigate({to: '/', replace: true});\n })\n .catch((error: unknown) => {\n if (disposed) return;\n if (!toastedCallbacks.has(key)) {\n toastedCallbacks.add(key);\n toast.error(githubCallbackErrorMessage(error));\n }\n navigate({to: '/', replace: true});\n });\n return () => {\n disposed = true;\n };\n }, [completeIntegrationCallback, navigate, refreshAuth, search]);\n\n return <FullPageLoader />;\n}\n\nexport function validateGithubCallbackSearch(input: Record<string, unknown>): GithubCallbackSearch {\n const code = stringParam(input.code);\n const installationId = numberParam(input.installation_id);\n const state = stringParam(input.state);\n const setupAction = stringParam(input.setup_action);\n return {\n ...(code ? {code} : {}),\n ...(installationId === undefined ? {} : {installationId}),\n ...(state ? {state} : {}),\n ...(setupAction ? {setupAction} : {}),\n };\n}\n\nexport function missingCallbackParams(search: GithubCallbackSearch): string[] {\n const missing: string[] = [];\n if (!search.code) missing.push('code');\n if (search.installationId === undefined) missing.push('installation_id');\n if (!search.state) missing.push('state');\n return missing;\n}\nexport function githubCallbackParams(\n search: GithubCallbackSearch,\n): GithubCallbackParams | undefined {\n const {code, installationId, state} = search;\n if (!code || installationId === undefined || !state) return undefined;\n const {setupAction} = search;\n return setupAction ? {code, installationId, state, setupAction} : {code, installationId, state};\n}\nfunction encodeCallbackQuery(params: GithubCallbackParams): string {\n const search = new URLSearchParams();\n search.set('code', params.code);\n search.set('installation_id', params.installationId.toString());\n search.set('state', params.state);\n if (params.setupAction) search.set('setup_action', params.setupAction);\n return search.toString();\n}\nfunction stringParam(value: unknown): string | undefined {\n return typeof value === 'string' && value.length > 0 ? value : undefined;\n}\nfunction numberParam(value: unknown): number | undefined {\n if (typeof value === 'number' && Number.isFinite(value)) return value;\n if (typeof value === 'string' && value.length > 0) {\n const parsed = Number(value);\n return Number.isFinite(parsed) ? parsed : undefined;\n }\n return undefined;\n}\nexport function githubCallbackErrorMessage(error: unknown): string {\n if (error instanceof ApiError) return 'GitHub could not be installed. Try again from settings.';\n return 'Could not install GitHub.';\n}\n"],"names":["ApiError","useRefreshAuth","defineRoute","useRouteSearch","createSingleFlight","FullPageLoader","toast","useNavigate","useEffect","useCompleteIntegrationCallback","completeGithubCallback","callbackRequests","maxTerminalResults","toastedCallbacks","Set","staticData","frame","validateSearch","validateGithubCallbackSearch","component","GithubCallbackRoute","search","navigate","refreshAuth","completeIntegrationCallback","missing","missingCallbackParams","length","error","join","includes","to","replace","params","githubCallbackParams","disposed","key","encodeCallbackQuery","request","run","input","complete","token","then","has","add","success","catch","githubCallbackErrorMessage","code","stringParam","installationId","numberParam","installation_id","state","setupAction","setup_action","undefined","push","URLSearchParams","set","toString","value","Number","isFinite","parsed"],"mappings":"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"}
@@ -1,5 +1,8 @@
1
1
  import { GithubInstallPage } from '#pages/github-install-page.js';
2
2
  declare const _default: import("@shipfox/client-shell/runtime").RouteImpl<{
3
+ readonly staticData: {
4
+ readonly frame: "focused";
5
+ };
3
6
  readonly component: typeof GithubInstallPage;
4
7
  }>;
5
8
  export default _default;
@@ -1,6 +1,9 @@
1
1
  import { defineRoute } from '@shipfox/client-shell/runtime';
2
2
  import { GithubInstallPage } from '#pages/github-install-page.js';
3
3
  export default defineRoute({
4
+ staticData: {
5
+ frame: 'focused'
6
+ },
4
7
  component: GithubInstallPage
5
8
  });
6
9
 
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/routes/github.tsx"],"sourcesContent":["import {defineRoute} from '@shipfox/client-shell/runtime';\nimport {GithubInstallPage} from '#pages/github-install-page.js';\n\nexport default defineRoute({component: GithubInstallPage});\n"],"names":["defineRoute","GithubInstallPage","component"],"mappings":"AAAA,SAAQA,WAAW,QAAO,gCAAgC;AAC1D,SAAQC,iBAAiB,QAAO,gCAAgC;AAEhE,eAAeD,YAAY;IAACE,WAAWD;AAAiB,GAAG"}
1
+ {"version":3,"sources":["../../src/routes/github.tsx"],"sourcesContent":["import {defineRoute} from '@shipfox/client-shell/runtime';\nimport {GithubInstallPage} from '#pages/github-install-page.js';\n\nexport default defineRoute({\n staticData: {frame: 'focused'},\n component: GithubInstallPage,\n});\n"],"names":["defineRoute","GithubInstallPage","staticData","frame","component"],"mappings":"AAAA,SAAQA,WAAW,QAAO,gCAAgC;AAC1D,SAAQC,iBAAiB,QAAO,gCAAgC;AAEhE,eAAeD,YAAY;IACzBE,YAAY;QAACC,OAAO;IAAS;IAC7BC,WAAWH;AACb,GAAG"}
@@ -1,5 +1,8 @@
1
1
  import { IntegrationGallery } from '#index.js';
2
2
  declare const _default: import("@shipfox/client-shell/runtime").RouteImpl<{
3
+ readonly staticData: {
4
+ readonly frame: "content";
5
+ };
3
6
  readonly component: typeof IntegrationGallery;
4
7
  }>;
5
8
  export default _default;
@@ -1,6 +1,9 @@
1
1
  import { defineRoute } from '@shipfox/client-shell/runtime';
2
2
  import { IntegrationGallery } from '#index.js';
3
3
  export default defineRoute({
4
+ staticData: {
5
+ frame: 'content'
6
+ },
4
7
  component: IntegrationGallery
5
8
  });
6
9
 
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/routes/integrations-settings.tsx"],"sourcesContent":["import {defineRoute} from '@shipfox/client-shell/runtime';\nimport {IntegrationGallery} from '#index.js';\n\nexport default defineRoute({component: IntegrationGallery});\n"],"names":["defineRoute","IntegrationGallery","component"],"mappings":"AAAA,SAAQA,WAAW,QAAO,gCAAgC;AAC1D,SAAQC,kBAAkB,QAAO,YAAY;AAE7C,eAAeD,YAAY;IAACE,WAAWD;AAAkB,GAAG"}
1
+ {"version":3,"sources":["../../src/routes/integrations-settings.tsx"],"sourcesContent":["import {defineRoute} from '@shipfox/client-shell/runtime';\nimport {IntegrationGallery} from '#index.js';\n\nexport default defineRoute({\n staticData: {frame: 'content'},\n component: IntegrationGallery,\n});\n"],"names":["defineRoute","IntegrationGallery","staticData","frame","component"],"mappings":"AAAA,SAAQA,WAAW,QAAO,gCAAgC;AAC1D,SAAQC,kBAAkB,QAAO,YAAY;AAE7C,eAAeD,YAAY;IACzBE,YAAY;QAACC,OAAO;IAAS;IAC7BC,WAAWH;AACb,GAAG"}
@@ -1,5 +1,8 @@
1
1
  import { SourceControlOnboardingPage } from '#pages/source-control-onboarding-page.js';
2
2
  declare const _default: import("@shipfox/client-shell/runtime").RouteImpl<{
3
+ readonly staticData: {
4
+ readonly frame: "focused";
5
+ };
3
6
  readonly component: typeof SourceControlOnboardingPage;
4
7
  }>;
5
8
  export default _default;
@@ -1,6 +1,9 @@
1
1
  import { defineRoute } from '@shipfox/client-shell/runtime';
2
2
  import { SourceControlOnboardingPage } from '#pages/source-control-onboarding-page.js';
3
3
  export default defineRoute({
4
+ staticData: {
5
+ frame: 'focused'
6
+ },
4
7
  component: SourceControlOnboardingPage
5
8
  });
6
9
 
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/routes/integrations.tsx"],"sourcesContent":["import {defineRoute} from '@shipfox/client-shell/runtime';\nimport {SourceControlOnboardingPage} from '#pages/source-control-onboarding-page.js';\n\nexport default defineRoute({component: SourceControlOnboardingPage});\n"],"names":["defineRoute","SourceControlOnboardingPage","component"],"mappings":"AAAA,SAAQA,WAAW,QAAO,gCAAgC;AAC1D,SAAQC,2BAA2B,QAAO,2CAA2C;AAErF,eAAeD,YAAY;IAACE,WAAWD;AAA2B,GAAG"}
1
+ {"version":3,"sources":["../../src/routes/integrations.tsx"],"sourcesContent":["import {defineRoute} from '@shipfox/client-shell/runtime';\nimport {SourceControlOnboardingPage} from '#pages/source-control-onboarding-page.js';\n\nexport default defineRoute({\n staticData: {frame: 'focused'},\n component: SourceControlOnboardingPage,\n});\n"],"names":["defineRoute","SourceControlOnboardingPage","staticData","frame","component"],"mappings":"AAAA,SAAQA,WAAW,QAAO,gCAAgC;AAC1D,SAAQC,2BAA2B,QAAO,2CAA2C;AAErF,eAAeD,YAAY;IACzBE,YAAY;QAACC,OAAO;IAAS;IAC7BC,WAAWH;AACb,GAAG"}
@@ -1,6 +1,9 @@
1
1
  import { JiraCallbackPage } from '#pages/jira-callback-page.js';
2
2
  import { parseJiraCallbackQuery } from '../jira-callback.js';
3
3
  declare const _default: import("@shipfox/client-shell/runtime").RouteImpl<{
4
+ readonly staticData: {
5
+ readonly frame: "focused";
6
+ };
4
7
  readonly validateSearch: typeof parseJiraCallbackQuery;
5
8
  readonly component: typeof JiraCallbackPage;
6
9
  }>;
@@ -2,6 +2,9 @@ import { defineRoute } from '@shipfox/client-shell/runtime';
2
2
  import { JiraCallbackPage } from '#pages/jira-callback-page.js';
3
3
  import { parseJiraCallbackQuery } from '../jira-callback.js';
4
4
  export default defineRoute({
5
+ staticData: {
6
+ frame: 'focused'
7
+ },
5
8
  validateSearch: parseJiraCallbackQuery,
6
9
  component: JiraCallbackPage
7
10
  });
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/routes/jira-callback.tsx"],"sourcesContent":["import {defineRoute} from '@shipfox/client-shell/runtime';\nimport {JiraCallbackPage} from '#pages/jira-callback-page.js';\nimport {parseJiraCallbackQuery} from '../jira-callback.js';\n\nexport default defineRoute({\n validateSearch: parseJiraCallbackQuery,\n component: JiraCallbackPage,\n});\n"],"names":["defineRoute","JiraCallbackPage","parseJiraCallbackQuery","validateSearch","component"],"mappings":"AAAA,SAAQA,WAAW,QAAO,gCAAgC;AAC1D,SAAQC,gBAAgB,QAAO,+BAA+B;AAC9D,SAAQC,sBAAsB,QAAO,sBAAsB;AAE3D,eAAeF,YAAY;IACzBG,gBAAgBD;IAChBE,WAAWH;AACb,GAAG"}
1
+ {"version":3,"sources":["../../src/routes/jira-callback.tsx"],"sourcesContent":["import {defineRoute} from '@shipfox/client-shell/runtime';\nimport {JiraCallbackPage} from '#pages/jira-callback-page.js';\nimport {parseJiraCallbackQuery} from '../jira-callback.js';\n\nexport default defineRoute({\n staticData: {frame: 'focused'},\n validateSearch: parseJiraCallbackQuery,\n component: JiraCallbackPage,\n});\n"],"names":["defineRoute","JiraCallbackPage","parseJiraCallbackQuery","staticData","frame","validateSearch","component"],"mappings":"AAAA,SAAQA,WAAW,QAAO,gCAAgC;AAC1D,SAAQC,gBAAgB,QAAO,+BAA+B;AAC9D,SAAQC,sBAAsB,QAAO,sBAAsB;AAE3D,eAAeF,YAAY;IACzBG,YAAY;QAACC,OAAO;IAAS;IAC7BC,gBAAgBH;IAChBI,WAAWL;AACb,GAAG"}
@@ -1,5 +1,8 @@
1
1
  import { JiraInstallPage } from '#pages/jira-install-page.js';
2
2
  declare const _default: import("@shipfox/client-shell/runtime").RouteImpl<{
3
+ readonly staticData: {
4
+ readonly frame: "focused";
5
+ };
3
6
  readonly component: typeof JiraInstallPage;
4
7
  }>;
5
8
  export default _default;
@@ -1,6 +1,9 @@
1
1
  import { defineRoute } from '@shipfox/client-shell/runtime';
2
2
  import { JiraInstallPage } from '#pages/jira-install-page.js';
3
3
  export default defineRoute({
4
+ staticData: {
5
+ frame: 'focused'
6
+ },
4
7
  component: JiraInstallPage
5
8
  });
6
9
 
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/routes/jira.tsx"],"sourcesContent":["import {defineRoute} from '@shipfox/client-shell/runtime';\nimport {JiraInstallPage} from '#pages/jira-install-page.js';\n\nexport default defineRoute({component: JiraInstallPage});\n"],"names":["defineRoute","JiraInstallPage","component"],"mappings":"AAAA,SAAQA,WAAW,QAAO,gCAAgC;AAC1D,SAAQC,eAAe,QAAO,8BAA8B;AAE5D,eAAeD,YAAY;IAACE,WAAWD;AAAe,GAAG"}
1
+ {"version":3,"sources":["../../src/routes/jira.tsx"],"sourcesContent":["import {defineRoute} from '@shipfox/client-shell/runtime';\nimport {JiraInstallPage} from '#pages/jira-install-page.js';\n\nexport default defineRoute({\n staticData: {frame: 'focused'},\n component: JiraInstallPage,\n});\n"],"names":["defineRoute","JiraInstallPage","staticData","frame","component"],"mappings":"AAAA,SAAQA,WAAW,QAAO,gCAAgC;AAC1D,SAAQC,eAAe,QAAO,8BAA8B;AAE5D,eAAeD,YAAY;IACzBE,YAAY;QAACC,OAAO;IAAS;IAC7BC,WAAWH;AACb,GAAG"}
@@ -1,6 +1,9 @@
1
1
  import { LinearCallbackPage } from '#pages/linear-callback-page.js';
2
2
  import { parseLinearCallbackQuery } from '../linear-callback.js';
3
3
  declare const _default: import("@shipfox/client-shell/runtime").RouteImpl<{
4
+ readonly staticData: {
5
+ readonly frame: "focused";
6
+ };
4
7
  readonly validateSearch: typeof parseLinearCallbackQuery;
5
8
  readonly component: typeof LinearCallbackPage;
6
9
  }>;
@@ -2,6 +2,9 @@ import { defineRoute } from '@shipfox/client-shell/runtime';
2
2
  import { LinearCallbackPage } from '#pages/linear-callback-page.js';
3
3
  import { parseLinearCallbackQuery } from '../linear-callback.js';
4
4
  export default defineRoute({
5
+ staticData: {
6
+ frame: 'focused'
7
+ },
5
8
  validateSearch: parseLinearCallbackQuery,
6
9
  component: LinearCallbackPage
7
10
  });
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/routes/linear-callback.tsx"],"sourcesContent":["import {defineRoute} from '@shipfox/client-shell/runtime';\nimport {LinearCallbackPage} from '#pages/linear-callback-page.js';\nimport {parseLinearCallbackQuery} from '../linear-callback.js';\n\nexport default defineRoute({\n validateSearch: parseLinearCallbackQuery,\n component: LinearCallbackPage,\n});\n"],"names":["defineRoute","LinearCallbackPage","parseLinearCallbackQuery","validateSearch","component"],"mappings":"AAAA,SAAQA,WAAW,QAAO,gCAAgC;AAC1D,SAAQC,kBAAkB,QAAO,iCAAiC;AAClE,SAAQC,wBAAwB,QAAO,wBAAwB;AAE/D,eAAeF,YAAY;IACzBG,gBAAgBD;IAChBE,WAAWH;AACb,GAAG"}
1
+ {"version":3,"sources":["../../src/routes/linear-callback.tsx"],"sourcesContent":["import {defineRoute} from '@shipfox/client-shell/runtime';\nimport {LinearCallbackPage} from '#pages/linear-callback-page.js';\nimport {parseLinearCallbackQuery} from '../linear-callback.js';\n\nexport default defineRoute({\n staticData: {frame: 'focused'},\n validateSearch: parseLinearCallbackQuery,\n component: LinearCallbackPage,\n});\n"],"names":["defineRoute","LinearCallbackPage","parseLinearCallbackQuery","staticData","frame","validateSearch","component"],"mappings":"AAAA,SAAQA,WAAW,QAAO,gCAAgC;AAC1D,SAAQC,kBAAkB,QAAO,iCAAiC;AAClE,SAAQC,wBAAwB,QAAO,wBAAwB;AAE/D,eAAeF,YAAY;IACzBG,YAAY;QAACC,OAAO;IAAS;IAC7BC,gBAAgBH;IAChBI,WAAWL;AACb,GAAG"}
@@ -1,5 +1,8 @@
1
1
  import { LinearInstallPage } from '#pages/linear-install-page.js';
2
2
  declare const _default: import("@shipfox/client-shell/runtime").RouteImpl<{
3
+ readonly staticData: {
4
+ readonly frame: "focused";
5
+ };
3
6
  readonly component: typeof LinearInstallPage;
4
7
  }>;
5
8
  export default _default;
@@ -1,6 +1,9 @@
1
1
  import { defineRoute } from '@shipfox/client-shell/runtime';
2
2
  import { LinearInstallPage } from '#pages/linear-install-page.js';
3
3
  export default defineRoute({
4
+ staticData: {
5
+ frame: 'focused'
6
+ },
4
7
  component: LinearInstallPage
5
8
  });
6
9
 
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/routes/linear.tsx"],"sourcesContent":["import {defineRoute} from '@shipfox/client-shell/runtime';\nimport {LinearInstallPage} from '#pages/linear-install-page.js';\n\nexport default defineRoute({component: LinearInstallPage});\n"],"names":["defineRoute","LinearInstallPage","component"],"mappings":"AAAA,SAAQA,WAAW,QAAO,gCAAgC;AAC1D,SAAQC,iBAAiB,QAAO,gCAAgC;AAEhE,eAAeD,YAAY;IAACE,WAAWD;AAAiB,GAAG"}
1
+ {"version":3,"sources":["../../src/routes/linear.tsx"],"sourcesContent":["import {defineRoute} from '@shipfox/client-shell/runtime';\nimport {LinearInstallPage} from '#pages/linear-install-page.js';\n\nexport default defineRoute({\n staticData: {frame: 'focused'},\n component: LinearInstallPage,\n});\n"],"names":["defineRoute","LinearInstallPage","staticData","frame","component"],"mappings":"AAAA,SAAQA,WAAW,QAAO,gCAAgC;AAC1D,SAAQC,iBAAiB,QAAO,gCAAgC;AAEhE,eAAeD,YAAY;IACzBE,YAAY;QAACC,OAAO;IAAS;IAC7BC,WAAWH;AACb,GAAG"}
@@ -1,6 +1,9 @@
1
1
  import { SentryCallbackPage } from '#pages/sentry-callback-page.js';
2
2
  import { parseSentryCallbackParams } from '../sentry-callback.js';
3
3
  declare const _default: import("@shipfox/client-shell/runtime").RouteImpl<{
4
+ readonly staticData: {
5
+ readonly frame: "focused";
6
+ };
4
7
  readonly validateSearch: typeof parseSentryCallbackParams;
5
8
  readonly component: typeof SentryCallbackPage;
6
9
  }>;
@@ -2,6 +2,9 @@ import { defineRoute } from '@shipfox/client-shell/runtime';
2
2
  import { SentryCallbackPage } from '#pages/sentry-callback-page.js';
3
3
  import { parseSentryCallbackParams } from '../sentry-callback.js';
4
4
  export default defineRoute({
5
+ staticData: {
6
+ frame: 'focused'
7
+ },
5
8
  validateSearch: parseSentryCallbackParams,
6
9
  component: SentryCallbackPage
7
10
  });
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/routes/sentry-callback.tsx"],"sourcesContent":["import {defineRoute} from '@shipfox/client-shell/runtime';\nimport {SentryCallbackPage} from '#pages/sentry-callback-page.js';\nimport {parseSentryCallbackParams} from '../sentry-callback.js';\n\nexport default defineRoute({\n validateSearch: parseSentryCallbackParams,\n component: SentryCallbackPage,\n});\n"],"names":["defineRoute","SentryCallbackPage","parseSentryCallbackParams","validateSearch","component"],"mappings":"AAAA,SAAQA,WAAW,QAAO,gCAAgC;AAC1D,SAAQC,kBAAkB,QAAO,iCAAiC;AAClE,SAAQC,yBAAyB,QAAO,wBAAwB;AAEhE,eAAeF,YAAY;IACzBG,gBAAgBD;IAChBE,WAAWH;AACb,GAAG"}
1
+ {"version":3,"sources":["../../src/routes/sentry-callback.tsx"],"sourcesContent":["import {defineRoute} from '@shipfox/client-shell/runtime';\nimport {SentryCallbackPage} from '#pages/sentry-callback-page.js';\nimport {parseSentryCallbackParams} from '../sentry-callback.js';\n\nexport default defineRoute({\n staticData: {frame: 'focused'},\n validateSearch: parseSentryCallbackParams,\n component: SentryCallbackPage,\n});\n"],"names":["defineRoute","SentryCallbackPage","parseSentryCallbackParams","staticData","frame","validateSearch","component"],"mappings":"AAAA,SAAQA,WAAW,QAAO,gCAAgC;AAC1D,SAAQC,kBAAkB,QAAO,iCAAiC;AAClE,SAAQC,yBAAyB,QAAO,wBAAwB;AAEhE,eAAeF,YAAY;IACzBG,YAAY;QAACC,OAAO;IAAS;IAC7BC,gBAAgBH;IAChBI,WAAWL;AACb,GAAG"}