Skip to content

Commit bff4a05

Browse files
authored
Add support for console sessions to query hooks (#696)
* feat: Add clientWithoutWorkspace to seam context * feat: Add endpointClientWithoutWorkspace to seam context * feat: Add useSeamQueryWithoutWorkspace and UseSeamMutationWithoutWorkspace * Update getQueryKeyPrefixes when workspaceId is null
2 parents 44d4d33 + 8904b9f commit bff4a05

File tree

7 files changed

+297
-35
lines changed

7 files changed

+297
-35
lines changed

package-lock.json

Lines changed: 8 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@
145145
"@rxfork/r2wc-react-to-web-component": "^2.4.0",
146146
"@seamapi/fake-devicedb": "^1.6.1",
147147
"@seamapi/fake-seam-connect": "^1.76.0",
148-
"@seamapi/http": "^1.38.3",
148+
"@seamapi/http": "^1.40.0",
149149
"@seamapi/types": "^1.395.3",
150150
"@storybook/addon-designs": "^7.0.1",
151151
"@storybook/addon-essentials": "^7.0.2",

src/lib/seam/SeamQueryProvider.tsx

Lines changed: 86 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,16 @@ export interface SeamQueryContext {
2525
publishableKey?: string | undefined
2626
userIdentifierKey?: string | undefined
2727
clientSessionToken?: string | undefined
28+
consoleSessionToken?: string | undefined
29+
workspaceId?: string | undefined
2830
queryKeyPrefix?: string | undefined
2931
}
3032

3133
export type SeamQueryProviderProps =
3234
| SeamQueryProviderPropsWithClient
3335
| SeamQueryProviderPropsWithPublishableKey
3436
| SeamQueryProviderPropsWithClientSessionToken
37+
| SeamQueryProviderPropsWithConsoleSessionToken
3538

3639
export interface SeamQueryProviderPropsWithClient
3740
extends SeamQueryProviderBaseProps {
@@ -52,6 +55,13 @@ export interface SeamQueryProviderPropsWithClientSessionToken
5255
clientSessionToken: string
5356
}
5457

58+
export interface SeamQueryProviderPropsWithConsoleSessionToken
59+
extends SeamQueryProviderBaseProps,
60+
SeamQueryProviderClientOptions {
61+
consoleSessionToken: string
62+
workspaceId?: string | undefined
63+
}
64+
5565
interface SeamQueryProviderBaseProps extends PropsWithChildren {
5666
queryClient?: QueryClient | undefined
5767
onSessionUpdate?: (client: SeamHttp) => void
@@ -74,7 +84,8 @@ export function SeamQueryProvider({
7484
if (
7585
context.client == null &&
7686
context.publishableKey == null &&
77-
context.clientSessionToken == null
87+
context.clientSessionToken == null &&
88+
context.consoleSessionToken == null
7889
) {
7990
return defaultSeamQueryContextValue
8091
}
@@ -84,10 +95,11 @@ export function SeamQueryProvider({
8495
if (
8596
value.client == null &&
8697
value.publishableKey == null &&
87-
value.clientSessionToken == null
98+
value.clientSessionToken == null &&
99+
value.consoleSessionToken == null
88100
) {
89101
throw new Error(
90-
`Must provide either a Seam client, clientSessionToken, or a publishableKey.`
102+
`Must provide either a Seam client, clientSessionToken, publishableKey or consoleSessionToken.`
91103
)
92104
}
93105

@@ -177,6 +189,17 @@ const createSeamQueryContextValue = (
177189
}
178190
}
179191

192+
if (isSeamQueryProviderPropsWithConsoleSessionToken(options)) {
193+
const { consoleSessionToken, workspaceId, ...clientOptions } = options
194+
return {
195+
consoleSessionToken,
196+
workspaceId,
197+
clientOptions,
198+
client: null,
199+
endpointClient: null,
200+
}
201+
}
202+
180203
return { client: null, endpointClient: null }
181204
}
182205

@@ -229,6 +252,18 @@ const isSeamQueryProviderPropsWithPublishableKey = (
229252
)
230253
}
231254

255+
if ('consoleSessionToken' in props && props.consoleSessionToken != null) {
256+
throw new InvalidSeamQueryProviderProps(
257+
'The consoleSessionToken prop cannot be used with the publishableKey prop.'
258+
)
259+
}
260+
261+
if ('workspaceId' in props && props.workspaceId != null) {
262+
throw new InvalidSeamQueryProviderProps(
263+
'The workspaceId prop cannot be used with the publishableKey prop.'
264+
)
265+
}
266+
232267
return true
233268
}
234269

@@ -259,6 +294,54 @@ const isSeamQueryProviderPropsWithClientSessionToken = (
259294
)
260295
}
261296

297+
if ('consoleSessionToken' in props && props.consoleSessionToken != null) {
298+
throw new InvalidSeamQueryProviderProps(
299+
'The consoleSessionToken prop cannot be used with the clientSessionToken prop.'
300+
)
301+
}
302+
303+
if ('workspaceId' in props && props.workspaceId != null) {
304+
throw new InvalidSeamQueryProviderProps(
305+
'The workspaceId prop cannot be used with the clientSessionToken prop.'
306+
)
307+
}
308+
309+
return true
310+
}
311+
312+
const isSeamQueryProviderPropsWithConsoleSessionToken = (
313+
props: SeamQueryProviderProps
314+
): props is SeamQueryProviderPropsWithConsoleSessionToken &
315+
SeamQueryProviderClientOptions => {
316+
if (!('consoleSessionToken' in props)) return false
317+
318+
const { consoleSessionToken } = props
319+
if (consoleSessionToken == null) return false
320+
321+
if ('client' in props && props.client != null) {
322+
throw new InvalidSeamQueryProviderProps(
323+
'The client prop cannot be used with the publishableKey prop.'
324+
)
325+
}
326+
327+
if ('clientSessionToken' in props && props.clientSessionToken != null) {
328+
throw new InvalidSeamQueryProviderProps(
329+
'The clientSessionToken prop cannot be used with the publishableKey prop.'
330+
)
331+
}
332+
333+
if ('publishableKey' in props && props.publishableKey != null) {
334+
throw new InvalidSeamQueryProviderProps(
335+
'The publishableKey prop cannot be used with the consoleSessionToken prop.'
336+
)
337+
}
338+
339+
if ('userIdentifierKey' in props && props.userIdentifierKey != null) {
340+
throw new InvalidSeamQueryProviderProps(
341+
'The userIdentifierKey prop cannot be used with the consoleSessionToken prop.'
342+
)
343+
}
344+
262345
return true
263346
}
264347

src/lib/seam/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,7 @@ export * from './devices/use-devices.js'
1313
export * from './SeamProvider.js'
1414
export * from './use-seam-client.js'
1515
export * from './use-seam-mutation.js'
16+
export * from './use-seam-mutation-without-workspace.js'
1617
export * from './use-seam-query.js'
1718
export * from './use-seam-query-result.js'
19+
export * from './use-seam-query-without-workspace.js'

src/lib/seam/use-seam-client.ts

Lines changed: 94 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
1-
import { SeamHttp, SeamHttpEndpoints } from '@seamapi/http/connect'
1+
import {
2+
SeamHttp,
3+
SeamHttpEndpoints,
4+
SeamHttpEndpointsWithoutWorkspace,
5+
SeamHttpWithoutWorkspace,
6+
} from '@seamapi/http/connect'
27
import { useQuery } from '@tanstack/react-query'
38
import { useEffect } from 'react'
49
import { v4 as uuidv4 } from 'uuid'
@@ -8,6 +13,8 @@ import { useSeamQueryContext } from './SeamQueryProvider.js'
813
export function useSeamClient(): {
914
client: SeamHttp | null
1015
endpointClient: SeamHttpEndpoints | null
16+
clientWithoutWorkspace: SeamHttpWithoutWorkspace | null
17+
endpointClientWithoutWorkspace: SeamHttpEndpointsWithoutWorkspace | null
1118
queryKeyPrefixes: string[]
1219
isPending: boolean
1320
isError: boolean
@@ -18,16 +25,21 @@ export function useSeamClient(): {
1825
clientOptions,
1926
publishableKey,
2027
clientSessionToken,
28+
consoleSessionToken,
29+
workspaceId,
2130
queryKeyPrefix,
2231
...context
2332
} = useSeamQueryContext()
2433
const userIdentifierKey = useUserIdentifierKeyOrFingerprint(
2534
clientSessionToken != null ? '' : context.userIdentifierKey
2635
)
2736

28-
const { isPending, isError, error, data } = useQuery<
29-
[SeamHttp, SeamHttpEndpoints]
30-
>({
37+
const { isPending, isError, error, data } = useQuery<{
38+
client: SeamHttp | null
39+
endpointClient: SeamHttpEndpoints | null
40+
clientWithoutWorkspace: SeamHttpWithoutWorkspace | null
41+
endpointClientWithoutWorkspace: SeamHttpEndpointsWithoutWorkspace | null
42+
}>({
3143
queryKey: [
3244
...getQueryKeyPrefixes({ queryKeyPrefix }),
3345
'client',
@@ -41,46 +53,93 @@ export function useSeamClient(): {
4153
],
4254
queryFn: async () => {
4355
if (client != null)
44-
return [client, SeamHttpEndpoints.fromClient(client.client)]
56+
return {
57+
client,
58+
endpointClient: SeamHttpEndpoints.fromClient(client.client),
59+
clientWithoutWorkspace: null,
60+
endpointClientWithoutWorkspace: null,
61+
}
4562

4663
if (clientSessionToken != null) {
47-
const clientSessionTokenClient = SeamHttp.fromClientSessionToken(
64+
const seam = SeamHttp.fromClientSessionToken(
4865
clientSessionToken,
4966
clientOptions
5067
)
5168

52-
return [
53-
clientSessionTokenClient,
54-
SeamHttpEndpoints.fromClient(clientSessionTokenClient.client),
55-
]
69+
return {
70+
client: seam,
71+
endpointClient: SeamHttpEndpoints.fromClient(seam.client),
72+
clientWithoutWorkspace: null,
73+
endpointClientWithoutWorkspace: null,
74+
}
5675
}
5776

58-
if (publishableKey == null) {
59-
throw new Error(
60-
'Missing either a client, publishableKey, or clientSessionToken'
77+
if (publishableKey != null) {
78+
const seam = await SeamHttp.fromPublishableKey(
79+
publishableKey,
80+
userIdentifierKey,
81+
clientOptions
6182
)
83+
84+
return {
85+
client: seam,
86+
endpointClient: SeamHttpEndpoints.fromClient(seam.client),
87+
clientWithoutWorkspace: null,
88+
endpointClientWithoutWorkspace: null,
89+
}
6290
}
6391

64-
const publishableKeyClient = await SeamHttp.fromPublishableKey(
65-
publishableKey,
66-
userIdentifierKey,
67-
clientOptions
92+
if (consoleSessionToken != null) {
93+
const clientWithoutWorkspace =
94+
SeamHttpWithoutWorkspace.fromConsoleSessionToken(consoleSessionToken)
95+
96+
const endpointClientWithoutWorkspace =
97+
SeamHttpEndpointsWithoutWorkspace.fromClient(
98+
clientWithoutWorkspace.client
99+
)
100+
101+
if (workspaceId == null) {
102+
return {
103+
client: null,
104+
endpointClient: null,
105+
clientWithoutWorkspace,
106+
endpointClientWithoutWorkspace,
107+
}
108+
}
109+
110+
const seam = SeamHttp.fromConsoleSessionToken(
111+
consoleSessionToken,
112+
workspaceId,
113+
clientOptions
114+
)
115+
116+
return {
117+
client: seam,
118+
endpointClient: SeamHttpEndpoints.fromClient(seam.client),
119+
clientWithoutWorkspace,
120+
endpointClientWithoutWorkspace,
121+
}
122+
}
123+
124+
throw new Error(
125+
'Missing either a client, publishableKey, clientSessionToken, or consoleSessionToken.'
68126
)
69-
return [
70-
publishableKeyClient,
71-
SeamHttpEndpoints.fromClient(publishableKeyClient.client),
72-
]
73127
},
74128
})
75129

76130
return {
77-
client: data?.[0] ?? null,
78-
endpointClient: data?.[1] ?? null,
131+
client: data?.client ?? null,
132+
endpointClient: data?.endpointClient ?? null,
133+
clientWithoutWorkspace: data?.clientWithoutWorkspace ?? null,
134+
endpointClientWithoutWorkspace:
135+
data?.endpointClientWithoutWorkspace ?? null,
79136
queryKeyPrefixes: getQueryKeyPrefixes({
80137
queryKeyPrefix,
81138
userIdentifierKey,
82139
publishableKey,
83140
clientSessionToken,
141+
consoleSessionToken,
142+
workspaceId,
84143
}),
85144
isPending,
86145
isError,
@@ -132,11 +191,15 @@ const getQueryKeyPrefixes = ({
132191
userIdentifierKey,
133192
publishableKey,
134193
clientSessionToken,
194+
consoleSessionToken,
195+
workspaceId,
135196
}: {
136197
queryKeyPrefix: string | undefined
137198
userIdentifierKey?: string
138199
publishableKey?: string | undefined
139200
clientSessionToken?: string | undefined
201+
consoleSessionToken?: string | undefined
202+
workspaceId?: string | undefined
140203
}): string[] => {
141204
const seamPrefix = 'seam'
142205

@@ -150,5 +213,13 @@ const getQueryKeyPrefixes = ({
150213
return [seamPrefix, publishableKey, userIdentifierKey]
151214
}
152215

216+
if (consoleSessionToken != null) {
217+
if (workspaceId != null) {
218+
return [seamPrefix, consoleSessionToken, workspaceId]
219+
}
220+
221+
return [seamPrefix, consoleSessionToken, 'without_workspace']
222+
}
223+
153224
return [seamPrefix]
154225
}

0 commit comments

Comments
 (0)