Resolves the slug against the tenant catalog and forwards into the integration detail page's existing add-connection flow. Unknown slugs get a not-found state. Makes the link survive sign-in: reserve connect as an org slug so cloud's callback stops reading it as an org selector, and return self-host's login to the requested path (its gate swaps the page in without ever writing a returnTo).
Showing the changes to apps (6 of 17 files). Show all
Unified · Split
| @@ -23,6 +23,7 @@ import { Route as ApiKeysRouteImport } from './routes/app/api-keys' · 22 unmodified lines | ||
| 23 | 23 | import { Route as DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsDottoolkitSlugRouteImport } from './../../../packages/react/src/routes/toolkits.$toolkitSlug' |
| 24 | 24 | import { Route as ResumeDotexecutionIdRouteImport } from './routes/app/resume.$executionId' |
| 25 | 25 | import { Route as DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIntegrationsDotnamespaceRouteImport } from './../../../packages/react/src/routes/integrations.$namespace' |
| 26 | +import { Route as DotDotDotDotDotDotDotDotPackagesReactSrcRoutesConnectDotintegrationSlugRouteImport } from './../../../packages/react/src/routes/connect.$integrationSlug' | |
| 26 | 27 | import { Route as Billing_DotplansRouteImport } from './routes/app/billing_.plans' |
| 27 | 28 | import { Route as DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIntegrationsDotaddDotpluginKeyRouteImport } from './../../../packages/react/src/routes/integrations.add.$pluginKey' |
| 28 | 29 | |
| @@ -107,6 +108,14 @@ const DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIntegrationsDotnamespaceRout · 78 unmodified lines | ||
| 107 | 108 | getParentRoute: () => rootRouteImport, |
| 108 | 109 | } as any, |
| 109 | 110 | ) |
| 111 | +const DotDotDotDotDotDotDotDotPackagesReactSrcRoutesConnectDotintegrationSlugRoute = | |
| 112 | + DotDotDotDotDotDotDotDotPackagesReactSrcRoutesConnectDotintegrationSlugRouteImport.update( | |
| 113 | + { | |
| 114 | + id: '/{-$orgSlug}/connect/$integrationSlug', | |
| 115 | + path: '/{-$orgSlug}/connect/$integrationSlug', | |
| 116 | + getParentRoute: () => rootRouteImport, | |
| 117 | + } as any, | |
| 118 | + ) | |
| 110 | 119 | const Billing_DotplansRoute = Billing_DotplansRouteImport.update({ |
| 111 | 120 | id: '/{-$orgSlug}/billing_/plans', |
| 112 | 121 | path: '/{-$orgSlug}/billing/plans', |
| @@ -134,6 +143,7 @@ export interface FileRoutesByFullPath { · 21 unmodified lines | ||
| 134 | 143 | '/{-$orgSlug}/tools': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolsRoute |
| 135 | 144 | '/{-$orgSlug}/': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIndexRoute |
| 136 | 145 | '/{-$orgSlug}/billing/plans': typeof Billing_DotplansRoute |
| 146 | + '/{-$orgSlug}/connect/$integrationSlug': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesConnectDotintegrationSlugRoute | |
| 137 | 147 | '/{-$orgSlug}/integrations/$namespace': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIntegrationsDotnamespaceRoute |
| 138 | 148 | '/{-$orgSlug}/resume/$executionId': typeof ResumeDotexecutionIdRoute |
| 139 | 149 | '/{-$orgSlug}/toolkits/$toolkitSlug': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsDottoolkitSlugRoute |
| @@ -152,6 +162,7 @@ export interface FileRoutesByTo { · 12 unmodified lines | ||
| 152 | 162 | '/{-$orgSlug}/tools': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolsRoute |
| 153 | 163 | '/{-$orgSlug}': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIndexRoute |
| 154 | 164 | '/{-$orgSlug}/billing/plans': typeof Billing_DotplansRoute |
| 165 | + '/{-$orgSlug}/connect/$integrationSlug': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesConnectDotintegrationSlugRoute | |
| 155 | 166 | '/{-$orgSlug}/integrations/$namespace': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIntegrationsDotnamespaceRoute |
| 156 | 167 | '/{-$orgSlug}/resume/$executionId': typeof ResumeDotexecutionIdRoute |
| 157 | 168 | '/{-$orgSlug}/toolkits/$toolkitSlug': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsDottoolkitSlugRoute |
| @@ -171,6 +182,7 @@ export interface FileRoutesById { · 13 unmodified lines | ||
| 171 | 182 | '/{-$orgSlug}/tools': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolsRoute |
| 172 | 183 | '/{-$orgSlug}/': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIndexRoute |
| 173 | 184 | '/{-$orgSlug}/billing_/plans': typeof Billing_DotplansRoute |
| 185 | + '/{-$orgSlug}/connect/$integrationSlug': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesConnectDotintegrationSlugRoute | |
| 174 | 186 | '/{-$orgSlug}/integrations/$namespace': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIntegrationsDotnamespaceRoute |
| 175 | 187 | '/{-$orgSlug}/resume/$executionId': typeof ResumeDotexecutionIdRoute |
| 176 | 188 | '/{-$orgSlug}/toolkits/$toolkitSlug': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsDottoolkitSlugRoute |
| @@ -191,6 +203,7 @@ export interface FileRouteTypes { · 14 unmodified lines | ||
| 191 | 203 | | '/{-$orgSlug}/tools' |
| 192 | 204 | | '/{-$orgSlug}/' |
| 193 | 205 | | '/{-$orgSlug}/billing/plans' |
| 206 | + | '/{-$orgSlug}/connect/$integrationSlug' | |
| 194 | 207 | | '/{-$orgSlug}/integrations/$namespace' |
| 195 | 208 | | '/{-$orgSlug}/resume/$executionId' |
| 196 | 209 | | '/{-$orgSlug}/toolkits/$toolkitSlug' |
| @@ -209,6 +222,7 @@ export interface FileRouteTypes { · 12 unmodified lines | ||
| 209 | 222 | | '/{-$orgSlug}/tools' |
| 210 | 223 | | '/{-$orgSlug}' |
| 211 | 224 | | '/{-$orgSlug}/billing/plans' |
| 225 | + | '/{-$orgSlug}/connect/$integrationSlug' | |
| 212 | 226 | | '/{-$orgSlug}/integrations/$namespace' |
| 213 | 227 | | '/{-$orgSlug}/resume/$executionId' |
| 214 | 228 | | '/{-$orgSlug}/toolkits/$toolkitSlug' |
| @@ -227,6 +241,7 @@ export interface FileRouteTypes { · 12 unmodified lines | ||
| 227 | 241 | | '/{-$orgSlug}/tools' |
| 228 | 242 | | '/{-$orgSlug}/' |
| 229 | 243 | | '/{-$orgSlug}/billing_/plans' |
| 244 | + | '/{-$orgSlug}/connect/$integrationSlug' | |
| 230 | 245 | | '/{-$orgSlug}/integrations/$namespace' |
| 231 | 246 | | '/{-$orgSlug}/resume/$executionId' |
| 232 | 247 | | '/{-$orgSlug}/toolkits/$toolkitSlug' |
| @@ -246,6 +261,7 @@ export interface RootRouteChildren { · 13 unmodified lines | ||
| 246 | 261 | DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolsRoute: typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolsRoute |
| 247 | 262 | DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIndexRoute: typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIndexRoute |
| 248 | 263 | Billing_DotplansRoute: typeof Billing_DotplansRoute |
| 264 | + DotDotDotDotDotDotDotDotPackagesReactSrcRoutesConnectDotintegrationSlugRoute: typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesConnectDotintegrationSlugRoute | |
| 249 | 265 | DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIntegrationsDotnamespaceRoute: typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIntegrationsDotnamespaceRoute |
| 250 | 266 | ResumeDotexecutionIdRoute: typeof ResumeDotexecutionIdRoute |
| 251 | 267 | DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIntegrationsDotaddDotpluginKeyRoute: typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIntegrationsDotaddDotpluginKeyRoute |
| @@ -351,6 +367,13 @@ declare module '@tanstack/react-router' { · 99 unmodified lines | ||
| 351 | 367 | preLoaderRoute: typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIntegrationsDotnamespaceRouteImport |
| 352 | 368 | parentRoute: typeof rootRouteImport |
| 353 | 369 | } |
| 370 | + '/{-$orgSlug}/connect/$integrationSlug': { | |
| 371 | + id: '/{-$orgSlug}/connect/$integrationSlug' | |
| 372 | + path: '/{-$orgSlug}/connect/$integrationSlug' | |
| 373 | + fullPath: '/{-$orgSlug}/connect/$integrationSlug' | |
| 374 | + preLoaderRoute: typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesConnectDotintegrationSlugRouteImport | |
| 375 | + parentRoute: typeof rootRouteImport | |
| 376 | + } | |
| 354 | 377 | '/{-$orgSlug}/billing_/plans': { |
| 355 | 378 | id: '/{-$orgSlug}/billing_/plans' |
| 356 | 379 | path: '/{-$orgSlug}/billing/plans' |
| @@ -400,6 +423,8 @@ const rootRouteChildren: RootRouteChildren = { · 43 unmodified lines | ||
| 400 | 423 | DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIndexRoute: |
| 401 | 424 | DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIndexRoute, |
| 402 | 425 | Billing_DotplansRoute: Billing_DotplansRoute, |
| 426 | + DotDotDotDotDotDotDotDotPackagesReactSrcRoutesConnectDotintegrationSlugRoute: | |
| 427 | + DotDotDotDotDotDotDotDotPackagesReactSrcRoutesConnectDotintegrationSlugRoute, | |
| 403 | 428 | DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIntegrationsDotnamespaceRoute: |
| 404 | 429 | DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIntegrationsDotnamespaceRoute, |
| 405 | 430 | ResumeDotexecutionIdRoute: ResumeDotexecutionIdRoute, |
| @@ -17,6 +17,7 @@ import { Route as DotDotDotDotDotDotDotDotPackagesReactSrcRoutesPoliciesRouteImp · 16 unmodified lines | ||
| 17 | 17 | import { Route as DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsDottoolkitSlugRouteImport } from './../../../packages/react/src/routes/toolkits.$toolkitSlug' |
| 18 | 18 | import { Route as DotDotDotDotDotDotDotDotPackagesReactSrcRoutesResumeDotexecutionIdRouteImport } from './../../../packages/react/src/routes/resume.$executionId' |
| 19 | 19 | import { Route as DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIntegrationsDotnamespaceRouteImport } from './../../../packages/react/src/routes/integrations.$namespace' |
| 20 | +import { Route as DotDotDotDotDotDotDotDotPackagesReactSrcRoutesConnectDotintegrationSlugRouteImport } from './../../../packages/react/src/routes/connect.$integrationSlug' | |
| 20 | 21 | import { Route as DotDotDotDotDotDotDotDotPackagesReactSrcRoutesPluginsDotpluginIdDotsplatRouteImport } from './../../../packages/react/src/routes/plugins.$pluginId.$' |
| 21 | 22 | import { Route as DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIntegrationsDotaddDotpluginKeyRouteImport } from './../../../packages/react/src/routes/integrations.add.$pluginKey' |
| 22 | 23 | |
| @@ -75,6 +76,14 @@ const DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIntegrationsDotnamespaceRout · 52 unmodified lines | ||
| 75 | 76 | getParentRoute: () => rootRouteImport, |
| 76 | 77 | } as any, |
| 77 | 78 | ) |
| 79 | +const DotDotDotDotDotDotDotDotPackagesReactSrcRoutesConnectDotintegrationSlugRoute = | |
| 80 | + DotDotDotDotDotDotDotDotPackagesReactSrcRoutesConnectDotintegrationSlugRouteImport.update( | |
| 81 | + { | |
| 82 | + id: '/{-$orgSlug}/connect/$integrationSlug', | |
| 83 | + path: '/{-$orgSlug}/connect/$integrationSlug', | |
| 84 | + getParentRoute: () => rootRouteImport, | |
| 85 | + } as any, | |
| 86 | + ) | |
| 78 | 87 | const DotDotDotDotDotDotDotDotPackagesReactSrcRoutesPluginsDotpluginIdDotsplatRoute = |
| 79 | 88 | DotDotDotDotDotDotDotDotPackagesReactSrcRoutesPluginsDotpluginIdDotsplatRouteImport.update( |
| 80 | 89 | { |
| @@ -98,6 +107,7 @@ export interface FileRoutesByFullPath { · 17 unmodified lines | ||
| 98 | 107 | '/{-$orgSlug}/toolkits': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsRouteWithChildren |
| 99 | 108 | '/{-$orgSlug}/tools': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolsRoute |
| 100 | 109 | '/{-$orgSlug}/': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIndexRoute |
| 110 | + '/{-$orgSlug}/connect/$integrationSlug': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesConnectDotintegrationSlugRoute | |
| 101 | 111 | '/{-$orgSlug}/integrations/$namespace': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIntegrationsDotnamespaceRoute |
| 102 | 112 | '/{-$orgSlug}/resume/$executionId': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesResumeDotexecutionIdRoute |
| 103 | 113 | '/{-$orgSlug}/toolkits/$toolkitSlug': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsDottoolkitSlugRoute |
| @@ -110,6 +120,7 @@ export interface FileRoutesByTo { · 6 unmodified lines | ||
| 110 | 120 | '/{-$orgSlug}/toolkits': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsRouteWithChildren |
| 111 | 121 | '/{-$orgSlug}/tools': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolsRoute |
| 112 | 122 | '/{-$orgSlug}': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIndexRoute |
| 123 | + '/{-$orgSlug}/connect/$integrationSlug': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesConnectDotintegrationSlugRoute | |
| 113 | 124 | '/{-$orgSlug}/integrations/$namespace': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIntegrationsDotnamespaceRoute |
| 114 | 125 | '/{-$orgSlug}/resume/$executionId': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesResumeDotexecutionIdRoute |
| 115 | 126 | '/{-$orgSlug}/toolkits/$toolkitSlug': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsDottoolkitSlugRoute |
| @@ -123,6 +134,7 @@ export interface FileRoutesById { · 7 unmodified lines | ||
| 123 | 134 | '/{-$orgSlug}/toolkits': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsRouteWithChildren |
| 124 | 135 | '/{-$orgSlug}/tools': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolsRoute |
| 125 | 136 | '/{-$orgSlug}/': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIndexRoute |
| 137 | + '/{-$orgSlug}/connect/$integrationSlug': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesConnectDotintegrationSlugRoute | |
| 126 | 138 | '/{-$orgSlug}/integrations/$namespace': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIntegrationsDotnamespaceRoute |
| 127 | 139 | '/{-$orgSlug}/resume/$executionId': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesResumeDotexecutionIdRoute |
| 128 | 140 | '/{-$orgSlug}/toolkits/$toolkitSlug': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsDottoolkitSlugRoute |
| @@ -137,6 +149,7 @@ export interface FileRouteTypes { · 8 unmodified lines | ||
| 137 | 149 | | '/{-$orgSlug}/toolkits' |
| 138 | 150 | | '/{-$orgSlug}/tools' |
| 139 | 151 | | '/{-$orgSlug}/' |
| 152 | + | '/{-$orgSlug}/connect/$integrationSlug' | |
| 140 | 153 | | '/{-$orgSlug}/integrations/$namespace' |
| 141 | 154 | | '/{-$orgSlug}/resume/$executionId' |
| 142 | 155 | | '/{-$orgSlug}/toolkits/$toolkitSlug' |
| @@ -149,6 +162,7 @@ export interface FileRouteTypes { · 6 unmodified lines | ||
| 149 | 162 | | '/{-$orgSlug}/toolkits' |
| 150 | 163 | | '/{-$orgSlug}/tools' |
| 151 | 164 | | '/{-$orgSlug}' |
| 165 | + | '/{-$orgSlug}/connect/$integrationSlug' | |
| 152 | 166 | | '/{-$orgSlug}/integrations/$namespace' |
| 153 | 167 | | '/{-$orgSlug}/resume/$executionId' |
| 154 | 168 | | '/{-$orgSlug}/toolkits/$toolkitSlug' |
| @@ -161,6 +175,7 @@ export interface FileRouteTypes { · 6 unmodified lines | ||
| 161 | 175 | | '/{-$orgSlug}/toolkits' |
| 162 | 176 | | '/{-$orgSlug}/tools' |
| 163 | 177 | | '/{-$orgSlug}/' |
| 178 | + | '/{-$orgSlug}/connect/$integrationSlug' | |
| 164 | 179 | | '/{-$orgSlug}/integrations/$namespace' |
| 165 | 180 | | '/{-$orgSlug}/resume/$executionId' |
| 166 | 181 | | '/{-$orgSlug}/toolkits/$toolkitSlug' |
| @@ -174,6 +189,7 @@ export interface RootRouteChildren { · 7 unmodified lines | ||
| 174 | 189 | DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsRoute: typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsRouteWithChildren |
| 175 | 190 | DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolsRoute: typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolsRoute |
| 176 | 191 | DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIndexRoute: typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIndexRoute |
| 192 | + DotDotDotDotDotDotDotDotPackagesReactSrcRoutesConnectDotintegrationSlugRoute: typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesConnectDotintegrationSlugRoute | |
| 177 | 193 | DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIntegrationsDotnamespaceRoute: typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIntegrationsDotnamespaceRoute |
| 178 | 194 | DotDotDotDotDotDotDotDotPackagesReactSrcRoutesResumeDotexecutionIdRoute: typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesResumeDotexecutionIdRoute |
| 179 | 195 | DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIntegrationsDotaddDotpluginKeyRoute: typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIntegrationsDotaddDotpluginKeyRoute |
| @@ -238,6 +254,13 @@ declare module '@tanstack/react-router' { · 58 unmodified lines | ||
| 238 | 254 | preLoaderRoute: typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIntegrationsDotnamespaceRouteImport |
| 239 | 255 | parentRoute: typeof rootRouteImport |
| 240 | 256 | } |
| 257 | + '/{-$orgSlug}/connect/$integrationSlug': { | |
| 258 | + id: '/{-$orgSlug}/connect/$integrationSlug' | |
| 259 | + path: '/{-$orgSlug}/connect/$integrationSlug' | |
| 260 | + fullPath: '/{-$orgSlug}/connect/$integrationSlug' | |
| 261 | + preLoaderRoute: typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesConnectDotintegrationSlugRouteImport | |
| 262 | + parentRoute: typeof rootRouteImport | |
| 263 | + } | |
| 241 | 264 | '/{-$orgSlug}/plugins/$pluginId/$': { |
| 242 | 265 | id: '/{-$orgSlug}/plugins/$pluginId/$' |
| 243 | 266 | path: '/{-$orgSlug}/plugins/$pluginId/$' |
| @@ -281,6 +304,8 @@ const rootRouteChildren: RootRouteChildren = { · 37 unmodified lines | ||
| 281 | 304 | DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolsRoute, |
| 282 | 305 | DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIndexRoute: |
| 283 | 306 | DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIndexRoute, |
| 307 | + DotDotDotDotDotDotDotDotPackagesReactSrcRoutesConnectDotintegrationSlugRoute: | |
| 308 | + DotDotDotDotDotDotDotDotPackagesReactSrcRoutesConnectDotintegrationSlugRoute, | |
| 284 | 309 | DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIntegrationsDotnamespaceRoute: |
| 285 | 310 | DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIntegrationsDotnamespaceRoute, |
| 286 | 311 | DotDotDotDotDotDotDotDotPackagesReactSrcRoutesResumeDotexecutionIdRoute: |
| @@ -1,6 +1,12 @@ | ||
| 1 | 1 | import { describe, expect, it } from "@effect/vitest"; |
| 2 | 2 | |
| 3 | −import { isSafeReturnTo, loginPath, mcpAuthorizeResumeTarget, safeReturnTo } from "./return-to"; | |
| 3 | +import { | |
| 4 | + isSafeReturnTo, | |
| 5 | + loginPath, | |
| 6 | + mcpAuthorizeResumeTarget, | |
| 7 | + postLoginTarget, | |
| 8 | + safeReturnTo, | |
| 9 | +} from "./return-to"; | |
| 4 | 10 | |
| 5 | 11 | describe("isSafeReturnTo", () => { |
| 6 | 12 | const safe = [ |
| @@ -73,6 +79,44 @@ describe("mcpAuthorizeResumeTarget", () => { · 66 unmodified lines | ||
| 73 | 79 | }); |
| 74 | 80 | }); |
| 75 | 81 | |
| 82 | +describe("postLoginTarget", () => { | |
| 83 | + // Self-host renders the login page IN PLACE of the requested route without | |
| 84 | + // navigating, so the live location is the only record of where the person was | |
| 85 | + // headed. A connect deep link must survive sign-in on that basis alone. | |
| 86 | + it("returns to the deep link the person actually opened", () => { | |
| 87 | + expect(postLoginTarget({ pathname: "/connect/linear", search: "" })).toBe("/connect/linear"); | |
| 88 | + expect(postLoginTarget({ pathname: "/integrations/sentry", search: "?addAccount=1" })).toBe( | |
| 89 | + "/integrations/sentry?addAccount=1", | |
| 90 | + ); | |
| 91 | + }); | |
| 92 | + | |
| 93 | + it("lands on the dashboard when signing in from the bare login page", () => { | |
| 94 | + // No deep link to resume, and echoing /login back would re-render the form. | |
| 95 | + expect(postLoginTarget({ pathname: "/login", search: "" })).toBe("/"); | |
| 96 | + }); | |
| 97 | + | |
| 98 | + it("prefers an explicit returnTo over the current location", () => { | |
| 99 | + expect(postLoginTarget({ pathname: "/login", search: "?returnTo=%2Fconnect%2Flinear" })).toBe( | |
| 100 | + "/connect/linear", | |
| 101 | + ); | |
| 102 | + }); | |
| 103 | + | |
| 104 | + it("prefers an MCP authorize resume over everything else", () => { | |
| 105 | + const target = postLoginTarget({ | |
| 106 | + pathname: "/login", | |
| 107 | + search: | |
| 108 | + "?response_type=code&client_id=abc&redirect_uri=http%3A%2F%2Flocalhost%3A3118%2Fcallback", | |
| 109 | + }); | |
| 110 | + expect(target.startsWith("/api/auth/mcp/authorize?")).toBe(true); | |
| 111 | + }); | |
| 112 | + | |
| 113 | + it("never honors an unsafe location", () => { | |
| 114 | + // `safeReturnTo` vets the echoed path too — an app-plane path is not a | |
| 115 | + // place to land a freshly signed-in browser. | |
| 116 | + expect(postLoginTarget({ pathname: "/api/auth/logout", search: "" })).toBe("/"); | |
| 117 | + }); | |
| 118 | +}); | |
| 119 | + | |
| 76 | 120 | describe("loginPath", () => { |
| 77 | 121 | it("omits returnTo for the root", () => { |
| 78 | 122 | expect(loginPath("/")).toBe("/login"); |
| @@ -32,3 +32,32 @@ export const mcpAuthorizeResumeTarget = (search: string): string | null => { · 31 unmodified lines | ||
| 32 | 32 | if (!params.get("client_id") || !params.get("redirect_uri")) return null; |
| 33 | 33 | return `${MCP_AUTHORIZE_PATH}?${params.toString()}`; |
| 34 | 34 | }; |
| 35 | + | |
| 36 | +const LOGIN_PATH = "/login"; | |
| 37 | + | |
| 38 | +/** | |
| 39 | + * Where the self-host login page sends someone after a successful sign-in, in | |
| 40 | + * priority order: | |
| 41 | + * | |
| 42 | + * 1. an interrupted MCP OAuth authorize (the params ARE the request), | |
| 43 | + * 2. an explicit safe `returnTo` (e.g. the integration OAuth callback), | |
| 44 | + * 3. the URL they actually opened, and | |
| 45 | + * 4. the dashboard. | |
| 46 | + * | |
| 47 | + * Step 3 is what makes a deep link like `/connect/linear` survive sign-in here. | |
| 48 | + * Unlike cloud — which redirects to `/login?returnTo=…` — self-host's gate | |
| 49 | + * swaps the login page in WITHOUT navigating, so the address bar still holds | |
| 50 | + * the requested URL and no `returnTo` was ever written. `/login` itself is | |
| 51 | + * excluded so signing in from the bare login page lands on the dashboard rather | |
| 52 | + * than looping back to the form. | |
| 53 | + */ | |
| 54 | +export const postLoginTarget = (location: { | |
| 55 | + readonly pathname: string; | |
| 56 | + readonly search: string; | |
| 57 | +}): string => | |
| 58 | + mcpAuthorizeResumeTarget(location.search) ?? | |
| 59 | + safeReturnTo(new URLSearchParams(location.search).get("returnTo")) ?? | |
| 60 | + (location.pathname === LOGIN_PATH | |
| 61 | + ? null | |
| 62 | + : safeReturnTo(`${location.pathname}${location.search}`)) ?? | |
| 63 | + "/"; | |
| @@ -6,7 +6,7 @@ import { Label } from "@executor-js/react/components/label"; · 5 unmodified lines | ||
| 6 | 6 | |
| 7 | 7 | import { authClient } from "./auth-client"; |
| 8 | 8 | import { AuthLayout } from "./auth-layout"; |
| 9 | −import { mcpAuthorizeResumeTarget, safeReturnTo } from "../src/auth/return-to"; | |
| 9 | +import { postLoginTarget } from "../src/auth/return-to"; | |
| 10 | 10 | |
| 11 | 11 | // Self-host login: email + password sign-in via Better Auth. On success we |
| 12 | 12 | // reload so the shared AuthProvider re-reads /account/me and the AuthGate swaps |
| @@ -17,15 +17,10 @@ import { mcpAuthorizeResumeTarget, safeReturnTo } from "../src/auth/return-to"; · 4 unmodified lines | ||
| 17 | 17 | // redeeming an invite — either the full /join/<code> link, or by entering the |
| 18 | 18 | // code here ("Have an invite code?"), which forwards to the same join page. |
| 19 | 19 | export const LoginPage = () => { |
| 20 | − const search = window.location.search; | |
| 21 | − // Where to go after sign-in: resume an interrupted MCP OAuth authorize if we | |
| 22 | − // arrived from one (Better Auth redirects it here with the OAuth params), | |
| 23 | − // otherwise honor a safe returnTo (e.g. an integration OAuth callback), else | |
| 24 | − // land on the dashboard. | |
| 25 | − const postLogin = | |
| 26 | − mcpAuthorizeResumeTarget(search) ?? | |
| 27 | − safeReturnTo(new URLSearchParams(search).get("returnTo")) ?? | |
| 28 | − "/"; | |
| 20 | + // Where to go after sign-in. The gate renders this page IN PLACE of the | |
| 21 | + // requested route without navigating, so the live location is what carries a | |
| 22 | + // deep link (`/connect/linear`) across sign-in — see `postLoginTarget`. | |
| 23 | + const postLogin = postLoginTarget(window.location); | |
| 29 | 24 | const [mode, setMode] = useState<"signin" | "code">("signin"); |
| 30 | 25 | const [email, setEmail] = useState(""); |
| 31 | 26 | const [password, setPassword] = useState(""); |
| @@ -20,6 +20,7 @@ import { Route as JoinDotcodeRouteImport } from './routes/public/join.$code' · 19 unmodified lines | ||
| 20 | 20 | import { Route as DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsDottoolkitSlugRouteImport } from './../../../packages/react/src/routes/toolkits.$toolkitSlug' |
| 21 | 21 | import { Route as DotDotDotDotDotDotDotDotPackagesReactSrcRoutesResumeDotexecutionIdRouteImport } from './../../../packages/react/src/routes/resume.$executionId' |
| 22 | 22 | import { Route as DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIntegrationsDotnamespaceRouteImport } from './../../../packages/react/src/routes/integrations.$namespace' |
| 23 | +import { Route as DotDotDotDotDotDotDotDotPackagesReactSrcRoutesConnectDotintegrationSlugRouteImport } from './../../../packages/react/src/routes/connect.$integrationSlug' | |
| 23 | 24 | import { Route as DotDotDotDotDotDotDotDotPackagesReactSrcRoutesPluginsDotpluginIdDotsplatRouteImport } from './../../../packages/react/src/routes/plugins.$pluginId.$' |
| 24 | 25 | import { Route as DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIntegrationsDotaddDotpluginKeyRouteImport } from './../../../packages/react/src/routes/integrations.add.$pluginKey' |
| 25 | 26 | |
| @@ -93,6 +94,14 @@ const DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIntegrationsDotnamespaceRout · 67 unmodified lines | ||
| 93 | 94 | getParentRoute: () => rootRouteImport, |
| 94 | 95 | } as any, |
| 95 | 96 | ) |
| 97 | +const DotDotDotDotDotDotDotDotPackagesReactSrcRoutesConnectDotintegrationSlugRoute = | |
| 98 | + DotDotDotDotDotDotDotDotPackagesReactSrcRoutesConnectDotintegrationSlugRouteImport.update( | |
| 99 | + { | |
| 100 | + id: '/{-$orgSlug}/connect/$integrationSlug', | |
| 101 | + path: '/{-$orgSlug}/connect/$integrationSlug', | |
| 102 | + getParentRoute: () => rootRouteImport, | |
| 103 | + } as any, | |
| 104 | + ) | |
| 96 | 105 | const DotDotDotDotDotDotDotDotPackagesReactSrcRoutesPluginsDotpluginIdDotsplatRoute = |
| 97 | 106 | DotDotDotDotDotDotDotDotPackagesReactSrcRoutesPluginsDotpluginIdDotsplatRouteImport.update( |
| 98 | 107 | { |
| @@ -119,6 +128,7 @@ export interface FileRoutesByFullPath { · 20 unmodified lines | ||
| 119 | 128 | '/{-$orgSlug}/toolkits': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsRouteWithChildren |
| 120 | 129 | '/{-$orgSlug}/tools': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolsRoute |
| 121 | 130 | '/{-$orgSlug}/': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIndexRoute |
| 131 | + '/{-$orgSlug}/connect/$integrationSlug': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesConnectDotintegrationSlugRoute | |
| 122 | 132 | '/{-$orgSlug}/integrations/$namespace': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIntegrationsDotnamespaceRoute |
| 123 | 133 | '/{-$orgSlug}/resume/$executionId': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesResumeDotexecutionIdRoute |
| 124 | 134 | '/{-$orgSlug}/toolkits/$toolkitSlug': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsDottoolkitSlugRoute |
| @@ -134,6 +144,7 @@ export interface FileRoutesByTo { · 9 unmodified lines | ||
| 134 | 144 | '/{-$orgSlug}/toolkits': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsRouteWithChildren |
| 135 | 145 | '/{-$orgSlug}/tools': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolsRoute |
| 136 | 146 | '/{-$orgSlug}': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIndexRoute |
| 147 | + '/{-$orgSlug}/connect/$integrationSlug': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesConnectDotintegrationSlugRoute | |
| 137 | 148 | '/{-$orgSlug}/integrations/$namespace': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIntegrationsDotnamespaceRoute |
| 138 | 149 | '/{-$orgSlug}/resume/$executionId': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesResumeDotexecutionIdRoute |
| 139 | 150 | '/{-$orgSlug}/toolkits/$toolkitSlug': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsDottoolkitSlugRoute |
| @@ -150,6 +161,7 @@ export interface FileRoutesById { · 10 unmodified lines | ||
| 150 | 161 | '/{-$orgSlug}/toolkits': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsRouteWithChildren |
| 151 | 162 | '/{-$orgSlug}/tools': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolsRoute |
| 152 | 163 | '/{-$orgSlug}/': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIndexRoute |
| 164 | + '/{-$orgSlug}/connect/$integrationSlug': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesConnectDotintegrationSlugRoute | |
| 153 | 165 | '/{-$orgSlug}/integrations/$namespace': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIntegrationsDotnamespaceRoute |
| 154 | 166 | '/{-$orgSlug}/resume/$executionId': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesResumeDotexecutionIdRoute |
| 155 | 167 | '/{-$orgSlug}/toolkits/$toolkitSlug': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsDottoolkitSlugRoute |
| @@ -167,6 +179,7 @@ export interface FileRouteTypes { · 11 unmodified lines | ||
| 167 | 179 | | '/{-$orgSlug}/toolkits' |
| 168 | 180 | | '/{-$orgSlug}/tools' |
| 169 | 181 | | '/{-$orgSlug}/' |
| 182 | + | '/{-$orgSlug}/connect/$integrationSlug' | |
| 170 | 183 | | '/{-$orgSlug}/integrations/$namespace' |
| 171 | 184 | | '/{-$orgSlug}/resume/$executionId' |
| 172 | 185 | | '/{-$orgSlug}/toolkits/$toolkitSlug' |
| @@ -182,6 +195,7 @@ export interface FileRouteTypes { · 9 unmodified lines | ||
| 182 | 195 | | '/{-$orgSlug}/toolkits' |
| 183 | 196 | | '/{-$orgSlug}/tools' |
| 184 | 197 | | '/{-$orgSlug}' |
| 198 | + | '/{-$orgSlug}/connect/$integrationSlug' | |
| 185 | 199 | | '/{-$orgSlug}/integrations/$namespace' |
| 186 | 200 | | '/{-$orgSlug}/resume/$executionId' |
| 187 | 201 | | '/{-$orgSlug}/toolkits/$toolkitSlug' |
| @@ -197,6 +211,7 @@ export interface FileRouteTypes { · 9 unmodified lines | ||
| 197 | 211 | | '/{-$orgSlug}/toolkits' |
| 198 | 212 | | '/{-$orgSlug}/tools' |
| 199 | 213 | | '/{-$orgSlug}/' |
| 214 | + | '/{-$orgSlug}/connect/$integrationSlug' | |
| 200 | 215 | | '/{-$orgSlug}/integrations/$namespace' |
| 201 | 216 | | '/{-$orgSlug}/resume/$executionId' |
| 202 | 217 | | '/{-$orgSlug}/toolkits/$toolkitSlug' |
| @@ -213,6 +228,7 @@ export interface RootRouteChildren { · 10 unmodified lines | ||
| 213 | 228 | DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsRoute: typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsRouteWithChildren |
| 214 | 229 | DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolsRoute: typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolsRoute |
| 215 | 230 | DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIndexRoute: typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIndexRoute |
| 231 | + DotDotDotDotDotDotDotDotPackagesReactSrcRoutesConnectDotintegrationSlugRoute: typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesConnectDotintegrationSlugRoute | |
| 216 | 232 | DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIntegrationsDotnamespaceRoute: typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIntegrationsDotnamespaceRoute |
| 217 | 233 | DotDotDotDotDotDotDotDotPackagesReactSrcRoutesResumeDotexecutionIdRoute: typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesResumeDotexecutionIdRoute |
| 218 | 234 | DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIntegrationsDotaddDotpluginKeyRoute: typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIntegrationsDotaddDotpluginKeyRoute |
| @@ -298,6 +314,13 @@ declare module '@tanstack/react-router' { · 79 unmodified lines | ||
| 298 | 314 | preLoaderRoute: typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIntegrationsDotnamespaceRouteImport |
| 299 | 315 | parentRoute: typeof rootRouteImport |
| 300 | 316 | } |
| 317 | + '/{-$orgSlug}/connect/$integrationSlug': { | |
| 318 | + id: '/{-$orgSlug}/connect/$integrationSlug' | |
| 319 | + path: '/{-$orgSlug}/connect/$integrationSlug' | |
| 320 | + fullPath: '/{-$orgSlug}/connect/$integrationSlug' | |
| 321 | + preLoaderRoute: typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesConnectDotintegrationSlugRouteImport | |
| 322 | + parentRoute: typeof rootRouteImport | |
| 323 | + } | |
| 301 | 324 | '/{-$orgSlug}/plugins/$pluginId/$': { |
| 302 | 325 | id: '/{-$orgSlug}/plugins/$pluginId/$' |
| 303 | 326 | path: '/{-$orgSlug}/plugins/$pluginId/$' |
| @@ -344,6 +367,8 @@ const rootRouteChildren: RootRouteChildren = { · 40 unmodified lines | ||
| 344 | 367 | DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolsRoute, |
| 345 | 368 | DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIndexRoute: |
| 346 | 369 | DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIndexRoute, |
| 370 | + DotDotDotDotDotDotDotDotPackagesReactSrcRoutesConnectDotintegrationSlugRoute: | |
| 371 | + DotDotDotDotDotDotDotDotPackagesReactSrcRoutesConnectDotintegrationSlugRoute, | |
| 347 | 372 | DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIntegrationsDotnamespaceRoute: |
| 348 | 373 | DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIntegrationsDotnamespaceRoute, |
| 349 | 374 | DotDotDotDotDotDotDotDotPackagesReactSrcRoutesResumeDotexecutionIdRoute: |