@shipfox/client-integrations 4.0.0 → 5.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.
- package/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +22 -0
- package/dist/feature.d.ts +11 -0
- package/dist/feature.d.ts.map +1 -1
- package/dist/feature.js +14 -0
- package/dist/feature.js.map +1 -1
- package/dist/hooks/api/integrations.d.ts +6 -1
- package/dist/hooks/api/integrations.d.ts.map +1 -1
- package/dist/hooks/api/integrations.js +15 -12
- package/dist/hooks/api/integrations.js.map +1 -1
- package/dist/pages/linear-callback-page.d.ts.map +1 -1
- package/dist/pages/linear-callback-page.js +1 -1
- package/dist/pages/linear-callback-page.js.map +1 -1
- package/dist/pages/sentry-callback-page.js +1 -1
- package/dist/pages/sentry-callback-page.js.map +1 -1
- package/dist/pages/slack-callback-page.d.ts.map +1 -1
- package/dist/pages/slack-callback-page.js +1 -1
- package/dist/pages/slack-callback-page.js.map +1 -1
- package/dist/routes/github-callback.js +1 -1
- package/dist/routes/github-callback.js.map +1 -1
- package/dist/routes/integrations-settings.d.ts +6 -0
- package/dist/routes/integrations-settings.d.ts.map +1 -0
- package/dist/routes/integrations-settings.js +7 -0
- package/dist/routes/integrations-settings.js.map +1 -0
- package/dist/tsconfig.test.tsbuildinfo +1 -1
- package/package.json +10 -10
- package/src/feature.ts +14 -0
- package/src/hooks/api/integrations.ts +32 -8
- package/src/pages/linear-callback-page.test.tsx +1 -1
- package/src/pages/linear-callback-page.tsx +2 -1
- package/src/pages/sentry-callback-page.test.tsx +1 -1
- package/src/pages/sentry-callback-page.tsx +1 -1
- package/src/pages/slack-callback-page.tsx +2 -1
- package/src/routes/github-callback.tsx +1 -1
- package/src/routes/integrations-settings.tsx +4 -0
- package/test/render.tsx +1 -5
- package/tsconfig.build.tsbuildinfo +1 -1
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
$ shipfox-swc
|
|
2
|
-
Successfully compiled:
|
|
2
|
+
Successfully compiled: 49 files with swc (515.65ms)
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,27 @@
|
|
|
1
1
|
# @shipfox/client-integrations
|
|
2
2
|
|
|
3
|
+
## 5.0.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 8d8cdef: Extracts workspace onboarding into a dedicated coordinator and shares its feature query policies.
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- ffd727b: Converges auth session and invitation state onto shared camelCase domain types validated at the API boundary, replacing the raw snake_case DTOs previously returned by login, signup, password reset, email verification, workspace creation, and invitation preview. `AuthState.user`, `useRefreshAuth()`, and `usePreviewInvitation()` now resolve to `UserIdentity`/`AuthenticatedSession`/`InvitationPreview` shapes (for example `accessToken` instead of `token`, `workspaceName` instead of `workspace_name`). Also moves the shared `AuthShell` component and session mapping helpers into `@shipfox/client-shell`, breaking the former `client-auth` ↔ `client-invitations` circular dependency.
|
|
12
|
+
- f1d6465: Moves workspace-settings and project-workflow route ownership from centralized packages into each feature's own route module, so a feature package declares and ships its own settings pages.
|
|
13
|
+
- Updated dependencies [ffd727b]
|
|
14
|
+
- Updated dependencies [7f227c6]
|
|
15
|
+
- @shipfox/client-shell@5.0.0
|
|
16
|
+
- @shipfox/client-auth@5.0.0
|
|
17
|
+
- @shipfox/api-integration-core-dto@8.0.0
|
|
18
|
+
- @shipfox/api-integration-gitea-dto@8.0.0
|
|
19
|
+
- @shipfox/api-integration-github-dto@8.0.0
|
|
20
|
+
- @shipfox/api-integration-linear-dto@8.0.0
|
|
21
|
+
- @shipfox/api-integration-sentry-dto@8.0.0
|
|
22
|
+
- @shipfox/api-integration-slack-dto@8.0.0
|
|
23
|
+
- @shipfox/api-integration-webhook-dto@8.0.0
|
|
24
|
+
|
|
3
25
|
## 4.0.0
|
|
4
26
|
|
|
5
27
|
### Patch Changes
|
package/dist/feature.d.ts
CHANGED
|
@@ -40,6 +40,17 @@ export declare const integrationsFeature: {
|
|
|
40
40
|
readonly path: "/workspaces/$wid/integrations/slack";
|
|
41
41
|
readonly parent: "workspaceLayout";
|
|
42
42
|
readonly impl: "@shipfox/client-integrations/routes/slack";
|
|
43
|
+
}, {
|
|
44
|
+
readonly path: "/workspaces/$wid/settings/integrations";
|
|
45
|
+
readonly parent: "workspaceSettings";
|
|
46
|
+
readonly impl: "@shipfox/client-integrations/routes/integrations-settings";
|
|
47
|
+
}];
|
|
48
|
+
readonly settingsSections: readonly [{
|
|
49
|
+
readonly id: "settings.integrations";
|
|
50
|
+
readonly pathSegment: "integrations";
|
|
51
|
+
readonly label: "Integrations";
|
|
52
|
+
readonly icon: "plugLine";
|
|
53
|
+
readonly order: 700;
|
|
43
54
|
}];
|
|
44
55
|
};
|
|
45
56
|
//# sourceMappingURL=feature.d.ts.map
|
package/dist/feature.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"feature.d.ts","sourceRoot":"","sources":["../src/feature.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,mBAAmB
|
|
1
|
+
{"version":3,"file":"feature.d.ts","sourceRoot":"","sources":["../src/feature.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAoE9B,CAAC"}
|
package/dist/feature.js
CHANGED
|
@@ -51,6 +51,20 @@ export const integrationsFeature = defineClientFeature({
|
|
|
51
51
|
path: '/workspaces/$wid/integrations/slack',
|
|
52
52
|
parent: 'workspaceLayout',
|
|
53
53
|
impl: '@shipfox/client-integrations/routes/slack'
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
path: '/workspaces/$wid/settings/integrations',
|
|
57
|
+
parent: 'workspaceSettings',
|
|
58
|
+
impl: '@shipfox/client-integrations/routes/integrations-settings'
|
|
59
|
+
}
|
|
60
|
+
],
|
|
61
|
+
settingsSections: [
|
|
62
|
+
{
|
|
63
|
+
id: 'settings.integrations',
|
|
64
|
+
pathSegment: 'integrations',
|
|
65
|
+
label: 'Integrations',
|
|
66
|
+
icon: 'plugLine',
|
|
67
|
+
order: 700
|
|
54
68
|
}
|
|
55
69
|
]
|
|
56
70
|
});
|
package/dist/feature.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/feature.ts"],"sourcesContent":["import {defineClientFeature} from '@shipfox/client-shell';\n\nexport const integrationsFeature = defineClientFeature({\n id: 'shipfox.integrations',\n routes: [\n {\n path: '/integrations/github/callback',\n parent: 'root',\n impl: '@shipfox/client-integrations/routes/github-callback',\n },\n {\n path: '/integrations/linear/callback',\n parent: 'root',\n impl: '@shipfox/client-integrations/routes/linear-callback',\n },\n {\n path: '/integrations/sentry/callback',\n parent: 'root',\n impl: '@shipfox/client-integrations/routes/sentry-callback',\n },\n {\n path: '/integrations/slack/callback',\n parent: 'root',\n impl: '@shipfox/client-integrations/routes/slack-callback',\n },\n {\n path: '/workspaces/$wid/integrations',\n parent: 'workspaceLayout',\n impl: '@shipfox/client-integrations/routes/integrations',\n },\n {\n path: '/workspaces/$wid/integrations/gitea',\n parent: 'workspaceLayout',\n impl: '@shipfox/client-integrations/routes/gitea',\n },\n {\n path: '/workspaces/$wid/integrations/github',\n parent: 'workspaceLayout',\n impl: '@shipfox/client-integrations/routes/github',\n },\n {\n path: '/workspaces/$wid/integrations/linear',\n parent: 'workspaceLayout',\n impl: '@shipfox/client-integrations/routes/linear',\n },\n {\n path: '/workspaces/$wid/integrations/sentry',\n parent: 'workspaceLayout',\n impl: '@shipfox/client-integrations/routes/sentry',\n },\n {\n path: '/workspaces/$wid/integrations/slack',\n parent: 'workspaceLayout',\n impl: '@shipfox/client-integrations/routes/slack',\n },\n ],\n});\n"],"names":["defineClientFeature","integrationsFeature","id","routes","path","parent","impl"],"mappings":"AAAA,SAAQA,mBAAmB,QAAO,wBAAwB;AAE1D,OAAO,MAAMC,sBAAsBD,oBAAoB;IACrDE,IAAI;IACJC,QAAQ;QACN;YACEC,MAAM;YACNC,QAAQ;YACRC,MAAM;QACR;QACA;YACEF,MAAM;YACNC,QAAQ;YACRC,MAAM;QACR;QACA;YACEF,MAAM;YACNC,QAAQ;YACRC,MAAM;QACR;QACA;YACEF,MAAM;YACNC,QAAQ;YACRC,MAAM;QACR;QACA;YACEF,MAAM;YACNC,QAAQ;YACRC,MAAM;QACR;QACA;YACEF,MAAM;YACNC,QAAQ;YACRC,MAAM;QACR;QACA;YACEF,MAAM;YACNC,QAAQ;YACRC,MAAM;QACR;QACA;YACEF,MAAM;YACNC,QAAQ;YACRC,MAAM;QACR;QACA;YACEF,MAAM;YACNC,QAAQ;YACRC,MAAM;QACR;QACA;YACEF,MAAM;YACNC,QAAQ;YACRC,MAAM;QACR;KACD;AACH,GAAG"}
|
|
1
|
+
{"version":3,"sources":["../src/feature.ts"],"sourcesContent":["import {defineClientFeature} from '@shipfox/client-shell';\n\nexport const integrationsFeature = defineClientFeature({\n id: 'shipfox.integrations',\n routes: [\n {\n path: '/integrations/github/callback',\n parent: 'root',\n impl: '@shipfox/client-integrations/routes/github-callback',\n },\n {\n path: '/integrations/linear/callback',\n parent: 'root',\n impl: '@shipfox/client-integrations/routes/linear-callback',\n },\n {\n path: '/integrations/sentry/callback',\n parent: 'root',\n impl: '@shipfox/client-integrations/routes/sentry-callback',\n },\n {\n path: '/integrations/slack/callback',\n parent: 'root',\n impl: '@shipfox/client-integrations/routes/slack-callback',\n },\n {\n path: '/workspaces/$wid/integrations',\n parent: 'workspaceLayout',\n impl: '@shipfox/client-integrations/routes/integrations',\n },\n {\n path: '/workspaces/$wid/integrations/gitea',\n parent: 'workspaceLayout',\n impl: '@shipfox/client-integrations/routes/gitea',\n },\n {\n path: '/workspaces/$wid/integrations/github',\n parent: 'workspaceLayout',\n impl: '@shipfox/client-integrations/routes/github',\n },\n {\n path: '/workspaces/$wid/integrations/linear',\n parent: 'workspaceLayout',\n impl: '@shipfox/client-integrations/routes/linear',\n },\n {\n path: '/workspaces/$wid/integrations/sentry',\n parent: 'workspaceLayout',\n impl: '@shipfox/client-integrations/routes/sentry',\n },\n {\n path: '/workspaces/$wid/integrations/slack',\n parent: 'workspaceLayout',\n impl: '@shipfox/client-integrations/routes/slack',\n },\n {\n path: '/workspaces/$wid/settings/integrations',\n parent: 'workspaceSettings',\n impl: '@shipfox/client-integrations/routes/integrations-settings',\n },\n ],\n settingsSections: [\n {\n id: 'settings.integrations',\n pathSegment: 'integrations',\n label: 'Integrations',\n icon: 'plugLine',\n order: 700,\n },\n ],\n});\n"],"names":["defineClientFeature","integrationsFeature","id","routes","path","parent","impl","settingsSections","pathSegment","label","icon","order"],"mappings":"AAAA,SAAQA,mBAAmB,QAAO,wBAAwB;AAE1D,OAAO,MAAMC,sBAAsBD,oBAAoB;IACrDE,IAAI;IACJC,QAAQ;QACN;YACEC,MAAM;YACNC,QAAQ;YACRC,MAAM;QACR;QACA;YACEF,MAAM;YACNC,QAAQ;YACRC,MAAM;QACR;QACA;YACEF,MAAM;YACNC,QAAQ;YACRC,MAAM;QACR;QACA;YACEF,MAAM;YACNC,QAAQ;YACRC,MAAM;QACR;QACA;YACEF,MAAM;YACNC,QAAQ;YACRC,MAAM;QACR;QACA;YACEF,MAAM;YACNC,QAAQ;YACRC,MAAM;QACR;QACA;YACEF,MAAM;YACNC,QAAQ;YACRC,MAAM;QACR;QACA;YACEF,MAAM;YACNC,QAAQ;YACRC,MAAM;QACR;QACA;YACEF,MAAM;YACNC,QAAQ;YACRC,MAAM;QACR;QACA;YACEF,MAAM;YACNC,QAAQ;YACRC,MAAM;QACR;QACA;YACEF,MAAM;YACNC,QAAQ;YACRC,MAAM;QACR;KACD;IACDC,kBAAkB;QAChB;YACEL,IAAI;YACJM,aAAa;YACbC,OAAO;YACPC,MAAM;YACNC,OAAO;QACT;KACD;AACH,GAAG"}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import type { IntegrationCapabilityDto, UpdateIntegrationConnectionBodyDto } from '@shipfox/api-integration-core-dto';
|
|
1
|
+
import type { IntegrationCapabilityDto, ListIntegrationConnectionsResponseDto, UpdateIntegrationConnectionBodyDto } from '@shipfox/api-integration-core-dto';
|
|
2
2
|
import type { CreateGiteaConnectionBodyDto } from '@shipfox/api-integration-gitea-dto';
|
|
3
3
|
import type { CreateGithubInstallBodyDto } from '@shipfox/api-integration-github-dto';
|
|
4
4
|
import type { CreateLinearInstallBodyDto, LinearCallbackQueryDto } from '@shipfox/api-integration-linear-dto';
|
|
5
5
|
import type { CreateSentryInstallBodyDto, SentryConnectBodyDto } from '@shipfox/api-integration-sentry-dto';
|
|
6
6
|
import type { CreateSlackInstallBodyDto, SlackCallbackQueryDto } from '@shipfox/api-integration-slack-dto';
|
|
7
|
+
import { type FetchQueryOptions } from '@tanstack/react-query';
|
|
7
8
|
export declare const integrationsQueryKeys: {
|
|
8
9
|
all: readonly ["integrations"];
|
|
9
10
|
providers: (capability: IntegrationCapabilityDto | "all") => readonly ["integrations", "providers", "source_control" | "agent_tools" | "all"];
|
|
@@ -12,6 +13,8 @@ export declare const integrationsQueryKeys: {
|
|
|
12
13
|
sourceConnections: (workspaceId: string) => readonly ["integrations", "connections", string, "source_control" | "agent_tools" | "all"];
|
|
13
14
|
repositories: (connectionId: string, search: string) => readonly ["integrations", "repositories", string, string];
|
|
14
15
|
};
|
|
16
|
+
type SourceConnectionsQueryKey = ReturnType<typeof integrationsQueryKeys.sourceConnections> | readonly ['integrations', 'source-connections'];
|
|
17
|
+
type SourceConnectionsQueryOptions = FetchQueryOptions<ListIntegrationConnectionsResponseDto, Error, ListIntegrationConnectionsResponseDto, SourceConnectionsQueryKey>;
|
|
15
18
|
export declare function listIntegrationProviders({ capability, signal, }: {
|
|
16
19
|
capability?: IntegrationCapabilityDto;
|
|
17
20
|
signal?: AbortSignal;
|
|
@@ -59,6 +62,7 @@ export declare function listSourceConnections({ workspaceId, signal, }: {
|
|
|
59
62
|
external_url?: string | undefined;
|
|
60
63
|
}[];
|
|
61
64
|
}>;
|
|
65
|
+
export declare function sourceConnectionsQueryOptions(workspaceId: string | undefined): SourceConnectionsQueryOptions;
|
|
62
66
|
export declare function createGiteaConnection(body: CreateGiteaConnectionBodyDto): Promise<{
|
|
63
67
|
id: string;
|
|
64
68
|
workspace_id: string;
|
|
@@ -303,4 +307,5 @@ export declare function useDeleteIntegrationConnectionMutation(): import("@tanst
|
|
|
303
307
|
workspaceId: string;
|
|
304
308
|
connectionId: string;
|
|
305
309
|
}, unknown>;
|
|
310
|
+
export {};
|
|
306
311
|
//# sourceMappingURL=integrations.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"integrations.d.ts","sourceRoot":"","sources":["../../../src/hooks/api/integrations.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,wBAAwB,
|
|
1
|
+
{"version":3,"file":"integrations.d.ts","sourceRoot":"","sources":["../../../src/hooks/api/integrations.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { apiRequest } from '@shipfox/client-api';
|
|
2
|
-
import { useInfiniteQuery, useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
|
|
2
|
+
import { queryOptions, useInfiniteQuery, useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
|
|
3
3
|
import { serializeLinearCallbackQuery } from '#linear-callback.js';
|
|
4
4
|
import { serializeSlackCallbackQuery } from '#slack-callback.js';
|
|
5
5
|
export const integrationsQueryKeys = {
|
|
@@ -65,6 +65,19 @@ export async function listSourceConnections({ workspaceId, signal }) {
|
|
|
65
65
|
connections: result.connections.filter((connection)=>connection.lifecycle_status === 'active')
|
|
66
66
|
};
|
|
67
67
|
}
|
|
68
|
+
export function sourceConnectionsQueryOptions(workspaceId) {
|
|
69
|
+
return queryOptions({
|
|
70
|
+
queryKey: workspaceId ? integrationsQueryKeys.sourceConnections(workspaceId) : [
|
|
71
|
+
...integrationsQueryKeys.all,
|
|
72
|
+
'source-connections'
|
|
73
|
+
],
|
|
74
|
+
enabled: Boolean(workspaceId),
|
|
75
|
+
queryFn: ({ signal })=>listSourceConnections({
|
|
76
|
+
workspaceId: workspaceId ?? '',
|
|
77
|
+
signal
|
|
78
|
+
})
|
|
79
|
+
});
|
|
80
|
+
}
|
|
68
81
|
export async function createGiteaConnection(body) {
|
|
69
82
|
return await apiRequest('/integrations/gitea/connections', {
|
|
70
83
|
method: 'POST',
|
|
@@ -154,17 +167,7 @@ export function useIntegrationProvidersQuery(params) {
|
|
|
154
167
|
});
|
|
155
168
|
}
|
|
156
169
|
export function useSourceConnectionsQuery(workspaceId) {
|
|
157
|
-
return useQuery(
|
|
158
|
-
queryKey: workspaceId ? integrationsQueryKeys.sourceConnections(workspaceId) : [
|
|
159
|
-
...integrationsQueryKeys.all,
|
|
160
|
-
'source-connections'
|
|
161
|
-
],
|
|
162
|
-
enabled: Boolean(workspaceId),
|
|
163
|
-
queryFn: ({ signal })=>listSourceConnections({
|
|
164
|
-
workspaceId: workspaceId ?? '',
|
|
165
|
-
signal
|
|
166
|
-
})
|
|
167
|
-
});
|
|
170
|
+
return useQuery(sourceConnectionsQueryOptions(workspaceId));
|
|
168
171
|
}
|
|
169
172
|
export function useIntegrationConnectionsQuery(workspaceId) {
|
|
170
173
|
return useQuery({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/hooks/api/integrations.ts"],"sourcesContent":["import type {\n IntegrationCapabilityDto,\n IntegrationConnectionDto,\n ListIntegrationConnectionsResponseDto,\n ListIntegrationProvidersResponseDto,\n ListRepositoriesResponseDto,\n UpdateIntegrationConnectionBodyDto,\n} from '@shipfox/api-integration-core-dto';\nimport type {\n CreateGiteaConnectionBodyDto,\n CreateGiteaConnectionResponseDto,\n} from '@shipfox/api-integration-gitea-dto';\nimport type {\n CreateGithubInstallBodyDto,\n CreateGithubInstallResponseDto,\n} from '@shipfox/api-integration-github-dto';\nimport type {\n CreateLinearInstallBodyDto,\n CreateLinearInstallResponseDto,\n LinearCallbackQueryDto,\n LinearCallbackResponseDto,\n} from '@shipfox/api-integration-linear-dto';\nimport type {\n CreateSentryInstallBodyDto,\n CreateSentryInstallResponseDto,\n SentryConnectBodyDto,\n SentryConnectResponseDto,\n} from '@shipfox/api-integration-sentry-dto';\nimport type {\n CreateSlackInstallBodyDto,\n CreateSlackInstallResponseDto,\n SlackCallbackQueryDto,\n SlackCallbackResponseDto,\n} from '@shipfox/api-integration-slack-dto';\nimport {apiRequest} from '@shipfox/client-api';\nimport {useInfiniteQuery, useMutation, useQuery, useQueryClient} from '@tanstack/react-query';\nimport {serializeLinearCallbackQuery} from '#linear-callback.js';\nimport {serializeSlackCallbackQuery} from '#slack-callback.js';\n\nexport const integrationsQueryKeys = {\n all: ['integrations'] as const,\n providers: (capability: IntegrationCapabilityDto | 'all') =>\n [...integrationsQueryKeys.all, 'providers', capability] as const,\n connections: (workspaceId: string, capability: IntegrationCapabilityDto | 'all') =>\n [...integrationsQueryKeys.all, 'connections', workspaceId, capability] as const,\n // Prefix matching every per-capability connections query for a workspace, so\n // a mutation can refresh all connection views without touching providers or\n // repositories.\n connectionsByWorkspace: (workspaceId: string) =>\n [...integrationsQueryKeys.all, 'connections', workspaceId] as const,\n sourceConnections: (workspaceId: string) =>\n integrationsQueryKeys.connections(workspaceId, 'source_control'),\n repositories: (connectionId: string, search: string) =>\n [...integrationsQueryKeys.all, 'repositories', connectionId, search] as const,\n};\n\nexport async function listIntegrationProviders({\n capability,\n signal,\n}: {\n capability?: IntegrationCapabilityDto;\n signal?: AbortSignal;\n}) {\n const search = new URLSearchParams();\n if (capability) search.set('capability', capability);\n const query = search.toString();\n const path = query ? `/integration-providers?${query}` : '/integration-providers';\n return await apiRequest<ListIntegrationProvidersResponseDto>(path, {signal});\n}\n\nexport async function listIntegrationConnections({\n workspaceId,\n capability,\n signal,\n}: {\n workspaceId: string;\n capability?: IntegrationCapabilityDto | undefined;\n signal?: AbortSignal | undefined;\n}) {\n const search = new URLSearchParams({workspace_id: workspaceId});\n if (capability) search.set('capability', capability);\n return await apiRequest<ListIntegrationConnectionsResponseDto>(\n `/integration-connections?${search.toString()}`,\n {signal},\n );\n}\n\nexport async function listSourceConnections({\n workspaceId,\n signal,\n}: {\n workspaceId: string;\n signal?: AbortSignal;\n}) {\n const result = await listIntegrationConnections({\n workspaceId,\n capability: 'source_control',\n signal,\n });\n // The endpoint returns every lifecycle status (the settings hub needs that),\n // but source-control consumers (onboarding redirect, project creation) only\n // act on usable connections — a disabled/error one must read as \"not there\".\n return {\n ...result,\n connections: result.connections.filter(\n (connection) => connection.lifecycle_status === 'active',\n ),\n };\n}\n\nexport async function createGiteaConnection(body: CreateGiteaConnectionBodyDto) {\n return await apiRequest<CreateGiteaConnectionResponseDto>('/integrations/gitea/connections', {\n method: 'POST',\n body,\n });\n}\n\nexport async function createGithubInstall(body: CreateGithubInstallBodyDto) {\n return await apiRequest<CreateGithubInstallResponseDto>('/integrations/github/install', {\n method: 'POST',\n body,\n });\n}\n\nexport async function createSentryInstall(body: CreateSentryInstallBodyDto) {\n return await apiRequest<CreateSentryInstallResponseDto>('/integrations/sentry/install', {\n method: 'POST',\n body,\n });\n}\n\nexport async function createLinearInstall(body: CreateLinearInstallBodyDto) {\n return await apiRequest<CreateLinearInstallResponseDto>('/integrations/linear/install', {\n method: 'POST',\n body,\n });\n}\n\nexport async function createSlackInstall(body: CreateSlackInstallBodyDto) {\n return await apiRequest<CreateSlackInstallResponseDto>('/integrations/slack/install', {\n method: 'POST',\n body,\n });\n}\n\nexport async function completeLinearCallback({\n query,\n token,\n}: {\n query: LinearCallbackQueryDto;\n token: string;\n}) {\n return await apiRequest<LinearCallbackResponseDto>(\n `/integrations/linear/callback/api?${serializeLinearCallbackQuery(query)}`,\n {headers: {authorization: `Bearer ${token}`}},\n );\n}\n\nexport async function completeSlackCallback({\n query,\n token,\n}: {\n query: SlackCallbackQueryDto;\n token: string;\n}) {\n return await apiRequest<SlackCallbackResponseDto>(\n `/integrations/slack/callback/api?${serializeSlackCallbackQuery(query)}`,\n {headers: {authorization: `Bearer ${token}`}},\n );\n}\n\n// Called from the callback route with an explicit bearer (same as the GitHub\n// callback): the route refreshes auth itself before forwarding the grant code.\nexport async function connectSentry({body, token}: {body: SentryConnectBodyDto; token: string}) {\n return await apiRequest<SentryConnectResponseDto>('/integrations/sentry/connect', {\n method: 'POST',\n body,\n headers: {authorization: `Bearer ${token}`},\n });\n}\n\nexport async function listRepositories({\n connectionId,\n cursor,\n search,\n signal,\n}: {\n connectionId: string;\n cursor?: string;\n search?: string;\n signal?: AbortSignal;\n}) {\n const params = new URLSearchParams();\n if (cursor) params.set('cursor', cursor);\n if (search) params.set('search', search);\n const query = params.toString();\n const path = query\n ? `/integration-connections/${connectionId}/repositories?${query}`\n : `/integration-connections/${connectionId}/repositories`;\n return await apiRequest<ListRepositoriesResponseDto>(path, {signal});\n}\n\nexport async function updateIntegrationConnection({\n connectionId,\n body,\n}: {\n connectionId: string;\n body: UpdateIntegrationConnectionBodyDto;\n}) {\n return await apiRequest<IntegrationConnectionDto>(\n `/integration-connections/${encodeURIComponent(connectionId)}`,\n {method: 'PATCH', body},\n );\n}\n\nexport async function deleteIntegrationConnection({connectionId}: {connectionId: string}) {\n await apiRequest<void>(`/integration-connections/${encodeURIComponent(connectionId)}`, {\n method: 'DELETE',\n });\n}\n\nexport function useIntegrationProvidersQuery(params?: {capability?: IntegrationCapabilityDto}) {\n const capability = params?.capability;\n return useQuery({\n queryKey: integrationsQueryKeys.providers(capability ?? 'all'),\n queryFn: ({signal}) => listIntegrationProviders(capability ? {capability, signal} : {signal}),\n });\n}\n\nexport function useSourceConnectionsQuery(workspaceId: string | undefined) {\n return useQuery({\n queryKey: workspaceId\n ? integrationsQueryKeys.sourceConnections(workspaceId)\n : [...integrationsQueryKeys.all, 'source-connections'],\n enabled: Boolean(workspaceId),\n queryFn: ({signal}) => listSourceConnections({workspaceId: workspaceId ?? '', signal}),\n });\n}\n\nexport function useIntegrationConnectionsQuery(workspaceId: string | undefined) {\n return useQuery({\n queryKey: workspaceId\n ? integrationsQueryKeys.connections(workspaceId, 'all')\n : [...integrationsQueryKeys.all, 'connections'],\n enabled: Boolean(workspaceId),\n queryFn: ({signal}) => listIntegrationConnections({workspaceId: workspaceId ?? '', signal}),\n });\n}\n\nexport function useRepositoriesInfiniteQuery(\n connectionId: string | undefined,\n options?: {search?: string},\n) {\n const trimmedSearch = options?.search?.trim() ?? '';\n return useInfiniteQuery({\n queryKey: connectionId\n ? integrationsQueryKeys.repositories(connectionId, trimmedSearch)\n : [...integrationsQueryKeys.all, 'repositories'],\n enabled: Boolean(connectionId),\n initialPageParam: undefined as string | undefined,\n queryFn: ({pageParam, signal}) => {\n const args: {connectionId: string; cursor?: string; search?: string; signal: AbortSignal} = {\n connectionId: connectionId ?? '',\n signal,\n };\n if (pageParam) args.cursor = pageParam;\n if (trimmedSearch) args.search = trimmedSearch;\n return listRepositories(args);\n },\n getNextPageParam: (lastPage) => lastPage.next_cursor ?? undefined,\n });\n}\n\nexport function useCreateGiteaConnectionMutation() {\n return useMutation({mutationFn: createGiteaConnection});\n}\n\nexport function useCreateLinearInstallMutation() {\n return useMutation({mutationFn: createLinearInstall});\n}\n\nexport function useCreateSlackInstallMutation() {\n return useMutation({mutationFn: createSlackInstall});\n}\n\nexport function useCompleteLinearCallbackMutation() {\n return useMutation({mutationFn: completeLinearCallback});\n}\n\nexport function useCompleteSlackCallbackMutation() {\n return useMutation({mutationFn: completeSlackCallback});\n}\n\nexport function useUpdateIntegrationConnectionMutation() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: updateIntegrationConnection,\n onSuccess: async (connection) => {\n await queryClient.invalidateQueries({\n queryKey: integrationsQueryKeys.connectionsByWorkspace(connection.workspace_id),\n });\n },\n });\n}\n\nexport function useDeleteIntegrationConnectionMutation() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: ({\n workspaceId: _workspaceId,\n connectionId,\n }: {\n workspaceId: string;\n connectionId: string;\n }) => deleteIntegrationConnection({connectionId}),\n onSuccess: async (_result, variables) => {\n await queryClient.invalidateQueries({\n queryKey: integrationsQueryKeys.connectionsByWorkspace(variables.workspaceId),\n });\n },\n });\n}\n"],"names":["apiRequest","useInfiniteQuery","useMutation","useQuery","useQueryClient","serializeLinearCallbackQuery","serializeSlackCallbackQuery","integrationsQueryKeys","all","providers","capability","connections","workspaceId","connectionsByWorkspace","sourceConnections","repositories","connectionId","search","listIntegrationProviders","signal","URLSearchParams","set","query","toString","path","listIntegrationConnections","workspace_id","listSourceConnections","result","filter","connection","lifecycle_status","createGiteaConnection","body","method","createGithubInstall","createSentryInstall","createLinearInstall","createSlackInstall","completeLinearCallback","token","headers","authorization","completeSlackCallback","connectSentry","listRepositories","cursor","params","updateIntegrationConnection","encodeURIComponent","deleteIntegrationConnection","useIntegrationProvidersQuery","queryKey","queryFn","useSourceConnectionsQuery","enabled","Boolean","useIntegrationConnectionsQuery","useRepositoriesInfiniteQuery","options","trimmedSearch","trim","initialPageParam","undefined","pageParam","args","getNextPageParam","lastPage","next_cursor","useCreateGiteaConnectionMutation","mutationFn","useCreateLinearInstallMutation","useCreateSlackInstallMutation","useCompleteLinearCallbackMutation","useCompleteSlackCallbackMutation","useUpdateIntegrationConnectionMutation","queryClient","onSuccess","invalidateQueries","useDeleteIntegrationConnectionMutation","_workspaceId","_result","variables"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../src/hooks/api/integrations.ts"],"sourcesContent":["import type {\n IntegrationCapabilityDto,\n IntegrationConnectionDto,\n ListIntegrationConnectionsResponseDto,\n ListIntegrationProvidersResponseDto,\n ListRepositoriesResponseDto,\n UpdateIntegrationConnectionBodyDto,\n} from '@shipfox/api-integration-core-dto';\nimport type {\n CreateGiteaConnectionBodyDto,\n CreateGiteaConnectionResponseDto,\n} from '@shipfox/api-integration-gitea-dto';\nimport type {\n CreateGithubInstallBodyDto,\n CreateGithubInstallResponseDto,\n} from '@shipfox/api-integration-github-dto';\nimport type {\n CreateLinearInstallBodyDto,\n CreateLinearInstallResponseDto,\n LinearCallbackQueryDto,\n LinearCallbackResponseDto,\n} from '@shipfox/api-integration-linear-dto';\nimport type {\n CreateSentryInstallBodyDto,\n CreateSentryInstallResponseDto,\n SentryConnectBodyDto,\n SentryConnectResponseDto,\n} from '@shipfox/api-integration-sentry-dto';\nimport type {\n CreateSlackInstallBodyDto,\n CreateSlackInstallResponseDto,\n SlackCallbackQueryDto,\n SlackCallbackResponseDto,\n} from '@shipfox/api-integration-slack-dto';\nimport {apiRequest} from '@shipfox/client-api';\nimport {\n type FetchQueryOptions,\n queryOptions,\n useInfiniteQuery,\n useMutation,\n useQuery,\n useQueryClient,\n} from '@tanstack/react-query';\nimport {serializeLinearCallbackQuery} from '#linear-callback.js';\nimport {serializeSlackCallbackQuery} from '#slack-callback.js';\n\nexport const integrationsQueryKeys = {\n all: ['integrations'] as const,\n providers: (capability: IntegrationCapabilityDto | 'all') =>\n [...integrationsQueryKeys.all, 'providers', capability] as const,\n connections: (workspaceId: string, capability: IntegrationCapabilityDto | 'all') =>\n [...integrationsQueryKeys.all, 'connections', workspaceId, capability] as const,\n // Prefix matching every per-capability connections query for a workspace, so\n // a mutation can refresh all connection views without touching providers or\n // repositories.\n connectionsByWorkspace: (workspaceId: string) =>\n [...integrationsQueryKeys.all, 'connections', workspaceId] as const,\n sourceConnections: (workspaceId: string) =>\n integrationsQueryKeys.connections(workspaceId, 'source_control'),\n repositories: (connectionId: string, search: string) =>\n [...integrationsQueryKeys.all, 'repositories', connectionId, search] as const,\n};\n\ntype SourceConnectionsQueryKey =\n | ReturnType<typeof integrationsQueryKeys.sourceConnections>\n | readonly ['integrations', 'source-connections'];\n\ntype SourceConnectionsQueryOptions = FetchQueryOptions<\n ListIntegrationConnectionsResponseDto,\n Error,\n ListIntegrationConnectionsResponseDto,\n SourceConnectionsQueryKey\n>;\n\nexport async function listIntegrationProviders({\n capability,\n signal,\n}: {\n capability?: IntegrationCapabilityDto;\n signal?: AbortSignal;\n}) {\n const search = new URLSearchParams();\n if (capability) search.set('capability', capability);\n const query = search.toString();\n const path = query ? `/integration-providers?${query}` : '/integration-providers';\n return await apiRequest<ListIntegrationProvidersResponseDto>(path, {signal});\n}\n\nexport async function listIntegrationConnections({\n workspaceId,\n capability,\n signal,\n}: {\n workspaceId: string;\n capability?: IntegrationCapabilityDto | undefined;\n signal?: AbortSignal | undefined;\n}) {\n const search = new URLSearchParams({workspace_id: workspaceId});\n if (capability) search.set('capability', capability);\n return await apiRequest<ListIntegrationConnectionsResponseDto>(\n `/integration-connections?${search.toString()}`,\n {signal},\n );\n}\n\nexport async function listSourceConnections({\n workspaceId,\n signal,\n}: {\n workspaceId: string;\n signal?: AbortSignal;\n}) {\n const result = await listIntegrationConnections({\n workspaceId,\n capability: 'source_control',\n signal,\n });\n // The endpoint returns every lifecycle status (the settings hub needs that),\n // but source-control consumers (onboarding redirect, project creation) only\n // act on usable connections — a disabled/error one must read as \"not there\".\n return {\n ...result,\n connections: result.connections.filter(\n (connection) => connection.lifecycle_status === 'active',\n ),\n };\n}\n\nexport function sourceConnectionsQueryOptions(\n workspaceId: string | undefined,\n): SourceConnectionsQueryOptions {\n return queryOptions({\n queryKey: workspaceId\n ? integrationsQueryKeys.sourceConnections(workspaceId)\n : ([...integrationsQueryKeys.all, 'source-connections'] as const),\n enabled: Boolean(workspaceId),\n queryFn: ({signal}) => listSourceConnections({workspaceId: workspaceId ?? '', signal}),\n });\n}\n\nexport async function createGiteaConnection(body: CreateGiteaConnectionBodyDto) {\n return await apiRequest<CreateGiteaConnectionResponseDto>('/integrations/gitea/connections', {\n method: 'POST',\n body,\n });\n}\n\nexport async function createGithubInstall(body: CreateGithubInstallBodyDto) {\n return await apiRequest<CreateGithubInstallResponseDto>('/integrations/github/install', {\n method: 'POST',\n body,\n });\n}\n\nexport async function createSentryInstall(body: CreateSentryInstallBodyDto) {\n return await apiRequest<CreateSentryInstallResponseDto>('/integrations/sentry/install', {\n method: 'POST',\n body,\n });\n}\n\nexport async function createLinearInstall(body: CreateLinearInstallBodyDto) {\n return await apiRequest<CreateLinearInstallResponseDto>('/integrations/linear/install', {\n method: 'POST',\n body,\n });\n}\n\nexport async function createSlackInstall(body: CreateSlackInstallBodyDto) {\n return await apiRequest<CreateSlackInstallResponseDto>('/integrations/slack/install', {\n method: 'POST',\n body,\n });\n}\n\nexport async function completeLinearCallback({\n query,\n token,\n}: {\n query: LinearCallbackQueryDto;\n token: string;\n}) {\n return await apiRequest<LinearCallbackResponseDto>(\n `/integrations/linear/callback/api?${serializeLinearCallbackQuery(query)}`,\n {headers: {authorization: `Bearer ${token}`}},\n );\n}\n\nexport async function completeSlackCallback({\n query,\n token,\n}: {\n query: SlackCallbackQueryDto;\n token: string;\n}) {\n return await apiRequest<SlackCallbackResponseDto>(\n `/integrations/slack/callback/api?${serializeSlackCallbackQuery(query)}`,\n {headers: {authorization: `Bearer ${token}`}},\n );\n}\n\n// Called from the callback route with an explicit bearer (same as the GitHub\n// callback): the route refreshes auth itself before forwarding the grant code.\nexport async function connectSentry({body, token}: {body: SentryConnectBodyDto; token: string}) {\n return await apiRequest<SentryConnectResponseDto>('/integrations/sentry/connect', {\n method: 'POST',\n body,\n headers: {authorization: `Bearer ${token}`},\n });\n}\n\nexport async function listRepositories({\n connectionId,\n cursor,\n search,\n signal,\n}: {\n connectionId: string;\n cursor?: string;\n search?: string;\n signal?: AbortSignal;\n}) {\n const params = new URLSearchParams();\n if (cursor) params.set('cursor', cursor);\n if (search) params.set('search', search);\n const query = params.toString();\n const path = query\n ? `/integration-connections/${connectionId}/repositories?${query}`\n : `/integration-connections/${connectionId}/repositories`;\n return await apiRequest<ListRepositoriesResponseDto>(path, {signal});\n}\n\nexport async function updateIntegrationConnection({\n connectionId,\n body,\n}: {\n connectionId: string;\n body: UpdateIntegrationConnectionBodyDto;\n}) {\n return await apiRequest<IntegrationConnectionDto>(\n `/integration-connections/${encodeURIComponent(connectionId)}`,\n {method: 'PATCH', body},\n );\n}\n\nexport async function deleteIntegrationConnection({connectionId}: {connectionId: string}) {\n await apiRequest<void>(`/integration-connections/${encodeURIComponent(connectionId)}`, {\n method: 'DELETE',\n });\n}\n\nexport function useIntegrationProvidersQuery(params?: {capability?: IntegrationCapabilityDto}) {\n const capability = params?.capability;\n return useQuery({\n queryKey: integrationsQueryKeys.providers(capability ?? 'all'),\n queryFn: ({signal}) => listIntegrationProviders(capability ? {capability, signal} : {signal}),\n });\n}\n\nexport function useSourceConnectionsQuery(workspaceId: string | undefined) {\n return useQuery(sourceConnectionsQueryOptions(workspaceId));\n}\n\nexport function useIntegrationConnectionsQuery(workspaceId: string | undefined) {\n return useQuery({\n queryKey: workspaceId\n ? integrationsQueryKeys.connections(workspaceId, 'all')\n : [...integrationsQueryKeys.all, 'connections'],\n enabled: Boolean(workspaceId),\n queryFn: ({signal}) => listIntegrationConnections({workspaceId: workspaceId ?? '', signal}),\n });\n}\n\nexport function useRepositoriesInfiniteQuery(\n connectionId: string | undefined,\n options?: {search?: string},\n) {\n const trimmedSearch = options?.search?.trim() ?? '';\n return useInfiniteQuery({\n queryKey: connectionId\n ? integrationsQueryKeys.repositories(connectionId, trimmedSearch)\n : [...integrationsQueryKeys.all, 'repositories'],\n enabled: Boolean(connectionId),\n initialPageParam: undefined as string | undefined,\n queryFn: ({pageParam, signal}) => {\n const args: {connectionId: string; cursor?: string; search?: string; signal: AbortSignal} = {\n connectionId: connectionId ?? '',\n signal,\n };\n if (pageParam) args.cursor = pageParam;\n if (trimmedSearch) args.search = trimmedSearch;\n return listRepositories(args);\n },\n getNextPageParam: (lastPage) => lastPage.next_cursor ?? undefined,\n });\n}\n\nexport function useCreateGiteaConnectionMutation() {\n return useMutation({mutationFn: createGiteaConnection});\n}\n\nexport function useCreateLinearInstallMutation() {\n return useMutation({mutationFn: createLinearInstall});\n}\n\nexport function useCreateSlackInstallMutation() {\n return useMutation({mutationFn: createSlackInstall});\n}\n\nexport function useCompleteLinearCallbackMutation() {\n return useMutation({mutationFn: completeLinearCallback});\n}\n\nexport function useCompleteSlackCallbackMutation() {\n return useMutation({mutationFn: completeSlackCallback});\n}\n\nexport function useUpdateIntegrationConnectionMutation() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: updateIntegrationConnection,\n onSuccess: async (connection) => {\n await queryClient.invalidateQueries({\n queryKey: integrationsQueryKeys.connectionsByWorkspace(connection.workspace_id),\n });\n },\n });\n}\n\nexport function useDeleteIntegrationConnectionMutation() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: ({\n workspaceId: _workspaceId,\n connectionId,\n }: {\n workspaceId: string;\n connectionId: string;\n }) => deleteIntegrationConnection({connectionId}),\n onSuccess: async (_result, variables) => {\n await queryClient.invalidateQueries({\n queryKey: integrationsQueryKeys.connectionsByWorkspace(variables.workspaceId),\n });\n },\n });\n}\n"],"names":["apiRequest","queryOptions","useInfiniteQuery","useMutation","useQuery","useQueryClient","serializeLinearCallbackQuery","serializeSlackCallbackQuery","integrationsQueryKeys","all","providers","capability","connections","workspaceId","connectionsByWorkspace","sourceConnections","repositories","connectionId","search","listIntegrationProviders","signal","URLSearchParams","set","query","toString","path","listIntegrationConnections","workspace_id","listSourceConnections","result","filter","connection","lifecycle_status","sourceConnectionsQueryOptions","queryKey","enabled","Boolean","queryFn","createGiteaConnection","body","method","createGithubInstall","createSentryInstall","createLinearInstall","createSlackInstall","completeLinearCallback","token","headers","authorization","completeSlackCallback","connectSentry","listRepositories","cursor","params","updateIntegrationConnection","encodeURIComponent","deleteIntegrationConnection","useIntegrationProvidersQuery","useSourceConnectionsQuery","useIntegrationConnectionsQuery","useRepositoriesInfiniteQuery","options","trimmedSearch","trim","initialPageParam","undefined","pageParam","args","getNextPageParam","lastPage","next_cursor","useCreateGiteaConnectionMutation","mutationFn","useCreateLinearInstallMutation","useCreateSlackInstallMutation","useCompleteLinearCallbackMutation","useCompleteSlackCallbackMutation","useUpdateIntegrationConnectionMutation","queryClient","onSuccess","invalidateQueries","useDeleteIntegrationConnectionMutation","_workspaceId","_result","variables"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"linear-callback-page.d.ts","sourceRoot":"","sources":["../../src/pages/linear-callback-page.tsx"],"names":[],"mappings":"AA4BA,wBAAgB,kBAAkB,
|
|
1
|
+
{"version":3,"file":"linear-callback-page.d.ts","sourceRoot":"","sources":["../../src/pages/linear-callback-page.tsx"],"names":[],"mappings":"AA4BA,wBAAgB,kBAAkB,gCAuFjC"}
|
|
@@ -42,7 +42,7 @@ export function LinearCallbackPage() {
|
|
|
42
42
|
const key = serializeLinearCallbackQuery(params);
|
|
43
43
|
const request = callbackRequests.run(key, async ()=>await refreshAuth().then(async (session)=>await completeLinearCallback({
|
|
44
44
|
query: params,
|
|
45
|
-
token: session.
|
|
45
|
+
token: session.accessToken
|
|
46
46
|
})));
|
|
47
47
|
request.then(async (connection)=>{
|
|
48
48
|
if (disposed) return;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/pages/linear-callback-page.tsx"],"sourcesContent":["import type {LinearCallbackResponseDto} from '@shipfox/api-integration-linear-dto';\nimport {useRefreshAuth} from '@shipfox/client-auth';\nimport {createSingleFlight} from '@shipfox/client-ui';\nimport {FullPageLoader} from '@shipfox/react-ui/loader';\nimport {toast} from '@shipfox/react-ui/toast';\nimport {useQueryClient} from '@tanstack/react-query';\nimport {useNavigate, useSearch} from '@tanstack/react-router';\nimport {useEffect, useMemo, useState} from 'react';\nimport {CallbackStatusShell} from '#components/callback-status-shell.js';\nimport {integrationsQueryKeys, useCompleteLinearCallbackMutation} from '#hooks/api/integrations.js';\nimport {\n classifyLinearCallbackError,\n clearLinearInstallWorkspace,\n type LinearCallbackFailure,\n parseLinearCallbackQuery,\n readLinearInstallWorkspace,\n serializeLinearCallbackQuery,\n} from '#linear-callback.js';\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, LinearCallbackResponseDto>({\n maxTerminalResults: 32,\n});\n// Keeps the success toast firing once per distinct callback even though the\n// effect re-runs against the cached request as the mutation identity churns.\nconst toastedCallbacks = new Set<string>();\n\nexport function LinearCallbackPage() {\n const search = useSearch({strict: false});\n const navigate = useNavigate();\n const refreshAuth = useRefreshAuth();\n const queryClient = useQueryClient();\n const {mutateAsync: completeLinearCallback} = useCompleteLinearCallbackMutation();\n const params = useMemo(() => parseLinearCallbackQuery(search), [search]);\n const workspaceId = useMemo(() => {\n try {\n return readLinearInstallWorkspace(window.sessionStorage);\n } catch {\n return undefined;\n }\n }, []);\n const [failure, setFailure] = useState<LinearCallbackFailure | undefined>();\n useEffect(() => {\n if (!params) return;\n\n let disposed = false;\n const key = serializeLinearCallbackQuery(params);\n const request = callbackRequests.run(\n key,\n async () =>\n await refreshAuth().then(\n async (session)
|
|
1
|
+
{"version":3,"sources":["../../src/pages/linear-callback-page.tsx"],"sourcesContent":["import type {LinearCallbackResponseDto} from '@shipfox/api-integration-linear-dto';\nimport {useRefreshAuth} from '@shipfox/client-auth';\nimport {createSingleFlight} from '@shipfox/client-ui';\nimport {FullPageLoader} from '@shipfox/react-ui/loader';\nimport {toast} from '@shipfox/react-ui/toast';\nimport {useQueryClient} from '@tanstack/react-query';\nimport {useNavigate, useSearch} from '@tanstack/react-router';\nimport {useEffect, useMemo, useState} from 'react';\nimport {CallbackStatusShell} from '#components/callback-status-shell.js';\nimport {integrationsQueryKeys, useCompleteLinearCallbackMutation} from '#hooks/api/integrations.js';\nimport {\n classifyLinearCallbackError,\n clearLinearInstallWorkspace,\n type LinearCallbackFailure,\n parseLinearCallbackQuery,\n readLinearInstallWorkspace,\n serializeLinearCallbackQuery,\n} from '#linear-callback.js';\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, LinearCallbackResponseDto>({\n maxTerminalResults: 32,\n});\n// Keeps the success toast firing once per distinct callback even though the\n// effect re-runs against the cached request as the mutation identity churns.\nconst toastedCallbacks = new Set<string>();\n\nexport function LinearCallbackPage() {\n const search = useSearch({strict: false});\n const navigate = useNavigate();\n const refreshAuth = useRefreshAuth();\n const queryClient = useQueryClient();\n const {mutateAsync: completeLinearCallback} = useCompleteLinearCallbackMutation();\n const params = useMemo(() => parseLinearCallbackQuery(search), [search]);\n const workspaceId = useMemo(() => {\n try {\n return readLinearInstallWorkspace(window.sessionStorage);\n } catch {\n return undefined;\n }\n }, []);\n const [failure, setFailure] = useState<LinearCallbackFailure | undefined>();\n useEffect(() => {\n if (!params) return;\n\n let disposed = false;\n const key = serializeLinearCallbackQuery(params);\n const request = callbackRequests.run(\n key,\n async () =>\n await refreshAuth().then(\n async (session) =>\n await completeLinearCallback({query: params, token: session.accessToken}),\n ),\n );\n\n request.then(\n async (connection) => {\n if (disposed) return;\n try {\n clearLinearInstallWorkspace(window.sessionStorage);\n } catch {\n // The successful API response remains the source of truth for navigation.\n }\n try {\n await queryClient.invalidateQueries({\n queryKey: integrationsQueryKeys.connectionsByWorkspace(connection.workspace_id),\n });\n } catch {\n // Cache refresh is best effort: the successful callback is already committed server-side.\n }\n if (disposed) return;\n if (!toastedCallbacks.has(key)) {\n toastedCallbacks.add(key);\n toast.success('Linear installed.');\n }\n try {\n await navigate({\n to: '/workspaces/$wid/settings/integrations',\n params: {wid: connection.workspace_id},\n replace: true,\n });\n } catch {\n // Keep the completed callback page visible if client navigation is interrupted.\n }\n },\n (error: unknown) => {\n if (disposed) return;\n setFailure(classifyLinearCallbackError(error));\n },\n );\n\n return () => {\n disposed = true;\n };\n }, [completeLinearCallback, navigate, params, queryClient, refreshAuth]);\n\n if (!params) {\n return (\n <LinearCallbackFailurePage\n failure={{\n title: 'Invalid Linear callback',\n message: 'Invalid Linear callback. Start the install again from workspace settings.',\n startOver: true,\n signIn: false,\n }}\n workspaceId={workspaceId}\n />\n );\n }\n\n if (!failure) return <FullPageLoader aria-label=\"Connecting Linear\" />;\n\n return <LinearCallbackFailurePage failure={failure} workspaceId={workspaceId} />;\n}\n\nfunction LinearCallbackFailurePage({\n failure,\n workspaceId,\n}: {\n failure: LinearCallbackFailure;\n workspaceId: string | undefined;\n}) {\n return (\n <CallbackStatusShell\n title={failure.title ?? 'Linear install could not be completed'}\n message={failure.message}\n startOver={failure.startOver}\n switchAccount={failure.signIn}\n workspaceId={workspaceId}\n installPath=\"/workspaces/$wid/integrations/linear\"\n />\n );\n}\n"],"names":["useRefreshAuth","createSingleFlight","FullPageLoader","toast","useQueryClient","useNavigate","useSearch","useEffect","useMemo","useState","CallbackStatusShell","integrationsQueryKeys","useCompleteLinearCallbackMutation","classifyLinearCallbackError","clearLinearInstallWorkspace","parseLinearCallbackQuery","readLinearInstallWorkspace","serializeLinearCallbackQuery","callbackRequests","maxTerminalResults","toastedCallbacks","Set","LinearCallbackPage","search","strict","navigate","refreshAuth","queryClient","mutateAsync","completeLinearCallback","params","workspaceId","window","sessionStorage","undefined","failure","setFailure","disposed","key","request","run","then","session","query","token","accessToken","connection","invalidateQueries","queryKey","connectionsByWorkspace","workspace_id","has","add","success","to","wid","replace","error","LinearCallbackFailurePage","title","message","startOver","signIn","aria-label","switchAccount","installPath"],"mappings":";AACA,SAAQA,cAAc,QAAO,uBAAuB;AACpD,SAAQC,kBAAkB,QAAO,qBAAqB;AACtD,SAAQC,cAAc,QAAO,2BAA2B;AACxD,SAAQC,KAAK,QAAO,0BAA0B;AAC9C,SAAQC,cAAc,QAAO,wBAAwB;AACrD,SAAQC,WAAW,EAAEC,SAAS,QAAO,yBAAyB;AAC9D,SAAQC,SAAS,EAAEC,OAAO,EAAEC,QAAQ,QAAO,QAAQ;AACnD,SAAQC,mBAAmB,QAAO,uCAAuC;AACzE,SAAQC,qBAAqB,EAAEC,iCAAiC,QAAO,6BAA6B;AACpG,SACEC,2BAA2B,EAC3BC,2BAA2B,EAE3BC,wBAAwB,EACxBC,0BAA0B,EAC1BC,4BAA4B,QACvB,sBAAsB;AAE7B,8EAA8E;AAC9E,iEAAiE;AACjE,MAAMC,mBAAmBjB,mBAAsD;IAC7EkB,oBAAoB;AACtB;AACA,4EAA4E;AAC5E,6EAA6E;AAC7E,MAAMC,mBAAmB,IAAIC;AAE7B,OAAO,SAASC;IACd,MAAMC,SAASjB,UAAU;QAACkB,QAAQ;IAAK;IACvC,MAAMC,WAAWpB;IACjB,MAAMqB,cAAc1B;IACpB,MAAM2B,cAAcvB;IACpB,MAAM,EAACwB,aAAaC,sBAAsB,EAAC,GAAGjB;IAC9C,MAAMkB,SAAStB,QAAQ,IAAMO,yBAAyBQ,SAAS;QAACA;KAAO;IACvE,MAAMQ,cAAcvB,QAAQ;QAC1B,IAAI;YACF,OAAOQ,2BAA2BgB,OAAOC,cAAc;QACzD,EAAE,OAAM;YACN,OAAOC;QACT;IACF,GAAG,EAAE;IACL,MAAM,CAACC,SAASC,WAAW,GAAG3B;IAC9BF,UAAU;QACR,IAAI,CAACuB,QAAQ;QAEb,IAAIO,WAAW;QACf,MAAMC,MAAMrB,6BAA6Ba;QACzC,MAAMS,UAAUrB,iBAAiBsB,GAAG,CAClCF,KACA,UACE,MAAMZ,cAAce,IAAI,CACtB,OAAOC,UACL,MAAMb,uBAAuB;oBAACc,OAAOb;oBAAQc,OAAOF,QAAQG,WAAW;gBAAA;QAI/EN,QAAQE,IAAI,CACV,OAAOK;YACL,IAAIT,UAAU;YACd,IAAI;gBACFvB,4BAA4BkB,OAAOC,cAAc;YACnD,EAAE,OAAM;YACN,0EAA0E;YAC5E;YACA,IAAI;gBACF,MAAMN,YAAYoB,iBAAiB,CAAC;oBAClCC,UAAUrC,sBAAsBsC,sBAAsB,CAACH,WAAWI,YAAY;gBAChF;YACF,EAAE,OAAM;YACN,0FAA0F;YAC5F;YACA,IAAIb,UAAU;YACd,IAAI,CAACjB,iBAAiB+B,GAAG,CAACb,MAAM;gBAC9BlB,iBAAiBgC,GAAG,CAACd;gBACrBnC,MAAMkD,OAAO,CAAC;YAChB;YACA,IAAI;gBACF,MAAM5B,SAAS;oBACb6B,IAAI;oBACJxB,QAAQ;wBAACyB,KAAKT,WAAWI,YAAY;oBAAA;oBACrCM,SAAS;gBACX;YACF,EAAE,OAAM;YACN,gFAAgF;YAClF;QACF,GACA,CAACC;YACC,IAAIpB,UAAU;YACdD,WAAWvB,4BAA4B4C;QACzC;QAGF,OAAO;YACLpB,WAAW;QACb;IACF,GAAG;QAACR;QAAwBJ;QAAUK;QAAQH;QAAaD;KAAY;IAEvE,IAAI,CAACI,QAAQ;QACX,qBACE,KAAC4B;YACCvB,SAAS;gBACPwB,OAAO;gBACPC,SAAS;gBACTC,WAAW;gBACXC,QAAQ;YACV;YACA/B,aAAaA;;IAGnB;IAEA,IAAI,CAACI,SAAS,qBAAO,KAACjC;QAAe6D,cAAW;;IAEhD,qBAAO,KAACL;QAA0BvB,SAASA;QAASJ,aAAaA;;AACnE;AAEA,SAAS2B,0BAA0B,EACjCvB,OAAO,EACPJ,WAAW,EAIZ;IACC,qBACE,KAACrB;QACCiD,OAAOxB,QAAQwB,KAAK,IAAI;QACxBC,SAASzB,QAAQyB,OAAO;QACxBC,WAAW1B,QAAQ0B,SAAS;QAC5BG,eAAe7B,QAAQ2B,MAAM;QAC7B/B,aAAaA;QACbkC,aAAY;;AAGlB"}
|
|
@@ -103,7 +103,7 @@ export function SentryCallbackPage() {
|
|
|
103
103
|
code: params.code,
|
|
104
104
|
installation_id: params.installationId
|
|
105
105
|
},
|
|
106
|
-
token: session.
|
|
106
|
+
token: session.accessToken
|
|
107
107
|
})));
|
|
108
108
|
request.then(async ()=>{
|
|
109
109
|
clearSentryInstallWorkspace(window.sessionStorage);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/pages/sentry-callback-page.tsx"],"sourcesContent":["import type {SentryConnectResponseDto} from '@shipfox/api-integration-sentry-dto';\nimport {useAuthState, useRefreshAuth} from '@shipfox/client-auth';\nimport {createSingleFlight} 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, useSearch} from '@tanstack/react-router';\nimport {useEffect, useMemo, useRef, useState} from 'react';\nimport {connectSentry, integrationsQueryKeys} from '#hooks/api/integrations.js';\nimport {\n classifySentryConnectError,\n clearSentryInstallWorkspace,\n parseSentryCallbackParams,\n preselectSentryWorkspace,\n readSentryInstallWorkspace,\n type SentryConnectFailure,\n} from '#sentry-callback.js';\n\nconst connectRequests = createSingleFlight<string, SentryConnectResponseDto>();\n\nexport function SentryCallbackPage() {\n const search = useSearch({strict: false});\n const navigate = useNavigate();\n const refreshAuth = useRefreshAuth();\n const {workspaces, isLoading} = useAuthState();\n const queryClient = useQueryClient();\n\n const params = useMemo(() => parseSentryCallbackParams(search), [search]);\n const storedWorkspaceId = useMemo(() => readSentryInstallWorkspace(window.sessionStorage), []);\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 refreshAuth().then((session) =>\n connectSentry({\n body: {\n workspace_id: workspaceId,\n code: params.code,\n installation_id: params.installationId,\n },\n token: session.token,\n }),\n ),\n );\n\n request\n .then(async () => {\n clearSentryInstallWorkspace(window.sessionStorage);\n await queryClient.invalidateQueries({\n queryKey: integrationsQueryKeys.connectionsByWorkspace(workspaceId),\n });\n if (disposedRef.current) return;\n toast.success('Sentry installed.');\n await navigate({\n to: '/workspaces/$wid/settings/integrations',\n params: {wid: workspaceId},\n 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(window.sessionStorage);\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\n return (\n <CallbackColumn>\n <header className=\"flex flex-col gap-8\">\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-8\">\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' && failure.failure.startOver ? (\n <Button asChild size=\"sm\" variant=\"secondary\" className=\"w-fit\">\n <Link to=\"/workspaces/$wid/integrations/sentry\" params={{wid: failure.workspaceId}}>\n Start over\n </Link>\n </Button>\n ) : null}\n </div>\n </Callout>\n ) : null}\n\n <section className=\"flex flex-col gap-8\" aria-label=\"Choose a workspace\">\n {orderedWorkspaces.map((workspace) => (\n <Card key={workspace.id} className=\"p-16\">\n <div className=\"flex items-center justify-between gap-12\">\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 {failureWorkspaceId ? (\n <ButtonLink asChild variant=\"muted\" className=\"w-fit\">\n <Link to=\"/workspaces/$wid/settings/integrations\" params={{wid: failureWorkspaceId}}>\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-16 py-32\">\n <div className=\"mx-auto flex w-full max-w-[480px] flex-col justify-center gap-20\">\n {children}\n </div>\n </main>\n );\n}\n"],"names":["useAuthState","useRefreshAuth","createSingleFlight","Button","ButtonLink","Callout","Card","FullPageLoader","toast","Header","Text","useQueryClient","Link","useNavigate","useSearch","useEffect","useMemo","useRef","useState","connectSentry","integrationsQueryKeys","classifySentryConnectError","clearSentryInstallWorkspace","parseSentryCallbackParams","preselectSentryWorkspace","readSentryInstallWorkspace","connectRequests","SentryCallbackPage","search","strict","navigate","refreshAuth","workspaces","isLoading","queryClient","params","storedWorkspaceId","window","sessionStorage","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","then","session","body","workspace_id","installation_id","token","invalidateQueries","queryKey","connectionsByWorkspace","success","wid","catch","classified","orderedWorkspaces","filter","workspace","id","failureWorkspaceId","header","orgSlug","div","message","disabled","onClick","startOver","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 type {SentryConnectResponseDto} from '@shipfox/api-integration-sentry-dto';\nimport {useAuthState, useRefreshAuth} from '@shipfox/client-auth';\nimport {createSingleFlight} 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, useSearch} from '@tanstack/react-router';\nimport {useEffect, useMemo, useRef, useState} from 'react';\nimport {connectSentry, integrationsQueryKeys} from '#hooks/api/integrations.js';\nimport {\n classifySentryConnectError,\n clearSentryInstallWorkspace,\n parseSentryCallbackParams,\n preselectSentryWorkspace,\n readSentryInstallWorkspace,\n type SentryConnectFailure,\n} from '#sentry-callback.js';\n\nconst connectRequests = createSingleFlight<string, SentryConnectResponseDto>();\n\nexport function SentryCallbackPage() {\n const search = useSearch({strict: false});\n const navigate = useNavigate();\n const refreshAuth = useRefreshAuth();\n const {workspaces, isLoading} = useAuthState();\n const queryClient = useQueryClient();\n\n const params = useMemo(() => parseSentryCallbackParams(search), [search]);\n const storedWorkspaceId = useMemo(() => readSentryInstallWorkspace(window.sessionStorage), []);\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 refreshAuth().then((session) =>\n connectSentry({\n body: {\n workspace_id: workspaceId,\n code: params.code,\n installation_id: params.installationId,\n },\n token: session.accessToken,\n }),\n ),\n );\n\n request\n .then(async () => {\n clearSentryInstallWorkspace(window.sessionStorage);\n await queryClient.invalidateQueries({\n queryKey: integrationsQueryKeys.connectionsByWorkspace(workspaceId),\n });\n if (disposedRef.current) return;\n toast.success('Sentry installed.');\n await navigate({\n to: '/workspaces/$wid/settings/integrations',\n params: {wid: workspaceId},\n 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(window.sessionStorage);\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\n return (\n <CallbackColumn>\n <header className=\"flex flex-col gap-8\">\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-8\">\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' && failure.failure.startOver ? (\n <Button asChild size=\"sm\" variant=\"secondary\" className=\"w-fit\">\n <Link to=\"/workspaces/$wid/integrations/sentry\" params={{wid: failure.workspaceId}}>\n Start over\n </Link>\n </Button>\n ) : null}\n </div>\n </Callout>\n ) : null}\n\n <section className=\"flex flex-col gap-8\" aria-label=\"Choose a workspace\">\n {orderedWorkspaces.map((workspace) => (\n <Card key={workspace.id} className=\"p-16\">\n <div className=\"flex items-center justify-between gap-12\">\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 {failureWorkspaceId ? (\n <ButtonLink asChild variant=\"muted\" className=\"w-fit\">\n <Link to=\"/workspaces/$wid/settings/integrations\" params={{wid: failureWorkspaceId}}>\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-16 py-32\">\n <div className=\"mx-auto flex w-full max-w-[480px] flex-col justify-center gap-20\">\n {children}\n </div>\n </main>\n );\n}\n"],"names":["useAuthState","useRefreshAuth","createSingleFlight","Button","ButtonLink","Callout","Card","FullPageLoader","toast","Header","Text","useQueryClient","Link","useNavigate","useSearch","useEffect","useMemo","useRef","useState","connectSentry","integrationsQueryKeys","classifySentryConnectError","clearSentryInstallWorkspace","parseSentryCallbackParams","preselectSentryWorkspace","readSentryInstallWorkspace","connectRequests","SentryCallbackPage","search","strict","navigate","refreshAuth","workspaces","isLoading","queryClient","params","storedWorkspaceId","window","sessionStorage","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","then","session","body","workspace_id","installation_id","token","accessToken","invalidateQueries","queryKey","connectionsByWorkspace","success","wid","catch","classified","orderedWorkspaces","filter","workspace","id","failureWorkspaceId","header","orgSlug","div","message","disabled","onClick","startOver","section","aria-label","map","bold","name","children","main"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"slack-callback-page.d.ts","sourceRoot":"","sources":["../../src/pages/slack-callback-page.tsx"],"names":[],"mappings":"AA2BA,wBAAgB,iBAAiB,
|
|
1
|
+
{"version":3,"file":"slack-callback-page.d.ts","sourceRoot":"","sources":["../../src/pages/slack-callback-page.tsx"],"names":[],"mappings":"AA2BA,wBAAgB,iBAAiB,gCAgGhC"}
|
|
@@ -36,7 +36,7 @@ export function SlackCallbackPage() {
|
|
|
36
36
|
const key = serializeSlackCallbackQuery(params);
|
|
37
37
|
const request = callbackRequests.run(key, async ()=>await refreshAuth().then(async (session)=>await completeSlackCallback({
|
|
38
38
|
query: params,
|
|
39
|
-
token: session.
|
|
39
|
+
token: session.accessToken
|
|
40
40
|
})));
|
|
41
41
|
request.then(async (connection)=>{
|
|
42
42
|
if (disposed) return;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/pages/slack-callback-page.tsx"],"sourcesContent":["import type {SlackCallbackResponseDto} from '@shipfox/api-integration-slack-dto';\nimport {useRefreshAuth} from '@shipfox/client-auth';\nimport {createSingleFlight} from '@shipfox/client-ui';\nimport {FullPageLoader} from '@shipfox/react-ui/loader';\nimport {toast} from '@shipfox/react-ui/toast';\nimport {useQueryClient} from '@tanstack/react-query';\nimport {useNavigate, useSearch} from '@tanstack/react-router';\nimport {useEffect, useMemo, useState} from 'react';\nimport {CallbackStatusShell} from '#components/callback-status-shell.js';\nimport {integrationsQueryKeys, useCompleteSlackCallbackMutation} from '#hooks/api/integrations.js';\nimport {\n classifySlackCallbackError,\n clearSlackInstallWorkspace,\n parseSlackCallbackQuery,\n readSlackInstallWorkspace,\n type SlackCallbackFailure,\n serializeSlackCallbackQuery,\n} from '#slack-callback.js';\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, SlackCallbackResponseDto>({\n maxTerminalResults: 32,\n});\nconst completedCallbacks = new Set<string>();\nconst toastedCallbacks = new Set<string>();\n\nexport function SlackCallbackPage() {\n const search = useSearch({strict: false});\n const navigate = useNavigate();\n const refreshAuth = useRefreshAuth();\n const queryClient = useQueryClient();\n const {mutateAsync: completeSlackCallback} = useCompleteSlackCallbackMutation();\n const params = useMemo(() => parseSlackCallbackQuery(search), [search]);\n const workspaceId = useMemo(() => readSlackInstallWorkspace(window.sessionStorage), []);\n const [failure, setFailure] = useState<SlackCallbackFailure>();\n const [completedWorkspaceId, setCompletedWorkspaceId] = useState<string>();\n\n useEffect(() => {\n if (!params) return;\n let disposed = false;\n const key = serializeSlackCallbackQuery(params);\n const request = callbackRequests.run(\n key,\n async () =>\n await refreshAuth().then(\n async (session)
|
|
1
|
+
{"version":3,"sources":["../../src/pages/slack-callback-page.tsx"],"sourcesContent":["import type {SlackCallbackResponseDto} from '@shipfox/api-integration-slack-dto';\nimport {useRefreshAuth} from '@shipfox/client-auth';\nimport {createSingleFlight} from '@shipfox/client-ui';\nimport {FullPageLoader} from '@shipfox/react-ui/loader';\nimport {toast} from '@shipfox/react-ui/toast';\nimport {useQueryClient} from '@tanstack/react-query';\nimport {useNavigate, useSearch} from '@tanstack/react-router';\nimport {useEffect, useMemo, useState} from 'react';\nimport {CallbackStatusShell} from '#components/callback-status-shell.js';\nimport {integrationsQueryKeys, useCompleteSlackCallbackMutation} from '#hooks/api/integrations.js';\nimport {\n classifySlackCallbackError,\n clearSlackInstallWorkspace,\n parseSlackCallbackQuery,\n readSlackInstallWorkspace,\n type SlackCallbackFailure,\n serializeSlackCallbackQuery,\n} from '#slack-callback.js';\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, SlackCallbackResponseDto>({\n maxTerminalResults: 32,\n});\nconst completedCallbacks = new Set<string>();\nconst toastedCallbacks = new Set<string>();\n\nexport function SlackCallbackPage() {\n const search = useSearch({strict: false});\n const navigate = useNavigate();\n const refreshAuth = useRefreshAuth();\n const queryClient = useQueryClient();\n const {mutateAsync: completeSlackCallback} = useCompleteSlackCallbackMutation();\n const params = useMemo(() => parseSlackCallbackQuery(search), [search]);\n const workspaceId = useMemo(() => readSlackInstallWorkspace(window.sessionStorage), []);\n const [failure, setFailure] = useState<SlackCallbackFailure>();\n const [completedWorkspaceId, setCompletedWorkspaceId] = useState<string>();\n\n useEffect(() => {\n if (!params) return;\n let disposed = false;\n const key = serializeSlackCallbackQuery(params);\n const request = callbackRequests.run(\n key,\n async () =>\n await refreshAuth().then(\n async (session) =>\n await completeSlackCallback({query: params, token: session.accessToken}),\n ),\n );\n request.then(\n async (connection) => {\n if (disposed) return;\n if (completedCallbacks.has(key)) {\n setCompletedWorkspaceId(connection.workspace_id);\n return;\n }\n completedCallbacks.add(key);\n try {\n clearSlackInstallWorkspace(window.sessionStorage);\n } catch {\n // The successful API response remains the source of truth.\n }\n try {\n await queryClient.invalidateQueries({\n queryKey: integrationsQueryKeys.connectionsByWorkspace(connection.workspace_id),\n });\n } catch {\n // Navigation can continue when cache refresh is unavailable.\n }\n if (disposed) return;\n if (!toastedCallbacks.has(key)) {\n toastedCallbacks.add(key);\n toast.success('Slack installed.');\n }\n try {\n await navigate({\n to: '/workspaces/$wid/settings/integrations',\n params: {wid: connection.workspace_id},\n replace: true,\n });\n } catch {\n if (!disposed) setCompletedWorkspaceId(connection.workspace_id);\n }\n },\n (error: unknown) => {\n if (!disposed) setFailure(classifySlackCallbackError(error));\n },\n );\n return () => {\n disposed = true;\n };\n }, [completeSlackCallback, navigate, params, queryClient, refreshAuth]);\n\n if (!params)\n return (\n <CallbackStatusShell\n title=\"Invalid Slack callback\"\n message=\"This Slack link is missing required parameters. Start the install again from workspace settings.\"\n startOver\n workspaceId={workspaceId}\n installPath=\"/workspaces/$wid/integrations/slack\"\n />\n );\n if (completedWorkspaceId)\n return (\n <CallbackStatusShell\n title=\"Slack connected\"\n message=\"Slack is connected. Continue in integrations settings.\"\n workspaceId={completedWorkspaceId}\n installPath=\"/workspaces/$wid/integrations/slack\"\n />\n );\n if (failure)\n return (\n <CallbackStatusShell\n {...failure}\n workspaceId={workspaceId}\n switchAccount={failure.signIn}\n installPath=\"/workspaces/$wid/integrations/slack\"\n />\n );\n return <FullPageLoader aria-label=\"Connecting Slack\" />;\n}\n"],"names":["useRefreshAuth","createSingleFlight","FullPageLoader","toast","useQueryClient","useNavigate","useSearch","useEffect","useMemo","useState","CallbackStatusShell","integrationsQueryKeys","useCompleteSlackCallbackMutation","classifySlackCallbackError","clearSlackInstallWorkspace","parseSlackCallbackQuery","readSlackInstallWorkspace","serializeSlackCallbackQuery","callbackRequests","maxTerminalResults","completedCallbacks","Set","toastedCallbacks","SlackCallbackPage","search","strict","navigate","refreshAuth","queryClient","mutateAsync","completeSlackCallback","params","workspaceId","window","sessionStorage","failure","setFailure","completedWorkspaceId","setCompletedWorkspaceId","disposed","key","request","run","then","session","query","token","accessToken","connection","has","workspace_id","add","invalidateQueries","queryKey","connectionsByWorkspace","success","to","wid","replace","error","title","message","startOver","installPath","switchAccount","signIn","aria-label"],"mappings":"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"}
|
|
@@ -46,7 +46,7 @@ function GithubCallbackRoute() {
|
|
|
46
46
|
const request = callbackRequests.run(key, async ()=>await refreshAuth().then(async (session)=>{
|
|
47
47
|
await apiRequest(`/integrations/github/callback/api?${key}`, {
|
|
48
48
|
headers: {
|
|
49
|
-
authorization: `Bearer ${session.
|
|
49
|
+
authorization: `Bearer ${session.accessToken}`
|
|
50
50
|
}
|
|
51
51
|
});
|
|
52
52
|
}));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/routes/github-callback.tsx"],"sourcesContent":["import {ApiError, apiRequest} from '@shipfox/client-api';\nimport {useRefreshAuth} from '@shipfox/client-auth';\nimport {defineRoute} 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, useSearch} from '@tanstack/react-router';\nimport {useEffect} from 'react';\n\ninterface GithubCallbackParams {\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({component: GithubCallbackRoute});\n\nfunction GithubCallbackRoute() {\n const search = useSearch({strict: false});\n const navigate = useNavigate();\n const refreshAuth = useRefreshAuth();\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 await refreshAuth().then(async (session) => {\n await apiRequest(`/integrations/github/callback/api?${key}`, {\n headers: {authorization: `Bearer ${session.
|
|
1
|
+
{"version":3,"sources":["../../src/routes/github-callback.tsx"],"sourcesContent":["import {ApiError, apiRequest} from '@shipfox/client-api';\nimport {useRefreshAuth} from '@shipfox/client-auth';\nimport {defineRoute} 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, useSearch} from '@tanstack/react-router';\nimport {useEffect} from 'react';\n\ninterface GithubCallbackParams {\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({component: GithubCallbackRoute});\n\nfunction GithubCallbackRoute() {\n const search = useSearch({strict: false});\n const navigate = useNavigate();\n const refreshAuth = useRefreshAuth();\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 await refreshAuth().then(async (session) => {\n await apiRequest(`/integrations/github/callback/api?${key}`, {\n headers: {authorization: `Bearer ${session.accessToken}`},\n });\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 }, [navigate, refreshAuth, search]);\n\n return <FullPageLoader />;\n}\n\nfunction missingCallbackParams(search: Record<string, unknown>): string[] {\n const missing: string[] = [];\n if (!stringParam(search.code)) missing.push('code');\n if (!numberParam(search.installation_id)) missing.push('installation_id');\n if (!stringParam(search.state)) missing.push('state');\n return missing;\n}\nfunction githubCallbackParams(search: Record<string, unknown>): GithubCallbackParams | undefined {\n const code = stringParam(search.code);\n const installationId = numberParam(search.installation_id);\n const state = stringParam(search.state);\n if (!code || installationId === undefined || !state) return undefined;\n const setupAction = stringParam(search.setup_action);\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","apiRequest","useRefreshAuth","defineRoute","createSingleFlight","FullPageLoader","toast","useNavigate","useSearch","useEffect","callbackRequests","maxTerminalResults","toastedCallbacks","Set","component","GithubCallbackRoute","search","strict","navigate","refreshAuth","missing","missingCallbackParams","length","error","join","includes","to","replace","params","githubCallbackParams","disposed","key","encodeCallbackQuery","request","run","then","session","headers","authorization","accessToken","has","add","success","catch","githubCallbackErrorMessage","stringParam","code","push","numberParam","installation_id","state","installationId","undefined","setupAction","setup_action","URLSearchParams","set","toString","value","Number","isFinite","parsed"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"integrations-settings.d.ts","sourceRoot":"","sources":["../../src/routes/integrations-settings.tsx"],"names":[],"mappings":"AACA,OAAO,EAAC,kBAAkB,EAAC,MAAM,WAAW,CAAC;;;;AAE7C,wBAA4D"}
|
|
@@ -0,0 +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"}
|