@tambo-ai/react 0.45.0 → 0.46.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. package/dist/hooks/__tests__/use-suggestions.test.js +6 -4
  2. package/dist/hooks/__tests__/use-suggestions.test.js.map +1 -1
  3. package/dist/hooks/index.d.ts +0 -1
  4. package/dist/hooks/index.d.ts.map +1 -1
  5. package/dist/hooks/index.js +1 -3
  6. package/dist/hooks/index.js.map +1 -1
  7. package/dist/hooks/use-suggestions.d.ts.map +1 -1
  8. package/dist/hooks/use-suggestions.js +3 -3
  9. package/dist/hooks/use-suggestions.js.map +1 -1
  10. package/dist/index.d.ts +1 -2
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/index.js +3 -3
  13. package/dist/index.js.map +1 -1
  14. package/dist/providers/hooks/__tests__/use-tambo-session-token.test.js +139 -40
  15. package/dist/providers/hooks/__tests__/use-tambo-session-token.test.js.map +1 -1
  16. package/dist/providers/hooks/use-tambo-session-token.d.ts +3 -1
  17. package/dist/providers/hooks/use-tambo-session-token.d.ts.map +1 -1
  18. package/dist/providers/hooks/use-tambo-session-token.js +22 -39
  19. package/dist/providers/hooks/use-tambo-session-token.js.map +1 -1
  20. package/dist/providers/index.d.ts +1 -0
  21. package/dist/providers/index.d.ts.map +1 -1
  22. package/dist/providers/index.js +4 -1
  23. package/dist/providers/index.js.map +1 -1
  24. package/dist/providers/tambo-client-provider.d.ts +7 -0
  25. package/dist/providers/tambo-client-provider.d.ts.map +1 -1
  26. package/dist/providers/tambo-client-provider.js +20 -4
  27. package/dist/providers/tambo-client-provider.js.map +1 -1
  28. package/dist/providers/tambo-provider.d.ts +4 -1
  29. package/dist/providers/tambo-provider.d.ts.map +1 -1
  30. package/dist/providers/tambo-provider.js +10 -4
  31. package/dist/providers/tambo-provider.js.map +1 -1
  32. package/dist/providers/tambo-stubs.d.ts.map +1 -1
  33. package/dist/providers/tambo-stubs.js +3 -3
  34. package/dist/providers/tambo-stubs.js.map +1 -1
  35. package/dist/providers/tambo-thread-input-provider.d.ts +58 -0
  36. package/dist/providers/tambo-thread-input-provider.d.ts.map +1 -0
  37. package/dist/providers/tambo-thread-input-provider.js +106 -0
  38. package/dist/providers/tambo-thread-input-provider.js.map +1 -0
  39. package/esm/hooks/__tests__/use-suggestions.test.js +4 -2
  40. package/esm/hooks/__tests__/use-suggestions.test.js.map +1 -1
  41. package/esm/hooks/index.d.ts +0 -1
  42. package/esm/hooks/index.d.ts.map +1 -1
  43. package/esm/hooks/index.js +0 -1
  44. package/esm/hooks/index.js.map +1 -1
  45. package/esm/hooks/use-suggestions.d.ts.map +1 -1
  46. package/esm/hooks/use-suggestions.js +1 -1
  47. package/esm/hooks/use-suggestions.js.map +1 -1
  48. package/esm/index.d.ts +1 -2
  49. package/esm/index.d.ts.map +1 -1
  50. package/esm/index.js +1 -2
  51. package/esm/index.js.map +1 -1
  52. package/esm/providers/hooks/__tests__/use-tambo-session-token.test.js +139 -40
  53. package/esm/providers/hooks/__tests__/use-tambo-session-token.test.js.map +1 -1
  54. package/esm/providers/hooks/use-tambo-session-token.d.ts +3 -1
  55. package/esm/providers/hooks/use-tambo-session-token.d.ts.map +1 -1
  56. package/esm/providers/hooks/use-tambo-session-token.js +23 -40
  57. package/esm/providers/hooks/use-tambo-session-token.js.map +1 -1
  58. package/esm/providers/index.d.ts +1 -0
  59. package/esm/providers/index.d.ts.map +1 -1
  60. package/esm/providers/index.js +1 -0
  61. package/esm/providers/index.js.map +1 -1
  62. package/esm/providers/tambo-client-provider.d.ts +7 -0
  63. package/esm/providers/tambo-client-provider.d.ts.map +1 -1
  64. package/esm/providers/tambo-client-provider.js +18 -3
  65. package/esm/providers/tambo-client-provider.js.map +1 -1
  66. package/esm/providers/tambo-provider.d.ts +4 -1
  67. package/esm/providers/tambo-provider.d.ts.map +1 -1
  68. package/esm/providers/tambo-provider.js +11 -5
  69. package/esm/providers/tambo-provider.js.map +1 -1
  70. package/esm/providers/tambo-stubs.d.ts.map +1 -1
  71. package/esm/providers/tambo-stubs.js +3 -3
  72. package/esm/providers/tambo-stubs.js.map +1 -1
  73. package/esm/providers/tambo-thread-input-provider.d.ts +58 -0
  74. package/esm/providers/tambo-thread-input-provider.d.ts.map +1 -0
  75. package/esm/{hooks/use-thread-input.js → providers/tambo-thread-input-provider.js} +30 -14
  76. package/esm/providers/tambo-thread-input-provider.js.map +1 -0
  77. package/package.json +1 -1
  78. package/dist/hooks/use-thread-input.d.ts +0 -53
  79. package/dist/hooks/use-thread-input.d.ts.map +0 -1
  80. package/dist/hooks/use-thread-input.js +0 -56
  81. package/dist/hooks/use-thread-input.js.map +0 -1
  82. package/esm/hooks/use-thread-input.d.ts +0 -53
  83. package/esm/hooks/use-thread-input.d.ts.map +0 -1
  84. package/esm/hooks/use-thread-input.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"use-suggestions.d.ts","sourceRoot":"","sources":["../../src/hooks/use-suggestions.ts"],"names":[],"mappings":"AACA,OAAO,OAAO,MAAM,0BAA0B,CAAC;AAQ/C,OAAO,EACL,sBAAsB,EAEvB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACL,sBAAsB,EACtB,mBAAmB,EAGpB,MAAM,qBAAqB,CAAC;AAG7B;;GAEG;AACH,MAAM,WAAW,0BAA0B;IACzC,kEAAkE;IAClE,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;GAEG;AACH,MAAM,WAAW,iCAAiC;IAChD,4EAA4E;IAC5E,WAAW,EAAE,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC;IAC/C,8CAA8C;IAC9C,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC;;;;OAIG;IACH,MAAM,EAAE,CAAC,aAAa,EAAE;QACtB,UAAU,EAAE,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC;QAC5C,YAAY,CAAC,EAAE,OAAO,CAAC;KACxB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAEpB,0DAA0D;IAC1D,YAAY,EAAE,sBAAsB,CAClC,IAAI,EACJ,KAAK,EACL;QAAE,UAAU,EAAE,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC;QAAC,YAAY,CAAC,EAAE,OAAO,CAAA;KAAE,CACxE,CAAC;IAEF,0DAA0D;IAC1D,cAAc,EAAE,sBAAsB,CACpC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,0BAA0B,GAAG,SAAS,EACvE,KAAK,EACL,eAAe,CAChB,CAAC;IAEF,yDAAyD;IACzD,iBAAiB,EAAE,mBAAmB,CACpC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,0BAA0B,GAAG,SAAS,EACvE,KAAK,CACN,CAAC;CACH;AAED,KAAK,yBAAyB,GAAG,sBAAsB,CAAC,GAAG,EAAE,KAAK,CAAC,GACjE,iCAAiC,CAAC;AAEpC;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,GAAE,0BAA+B,GACvC,yBAAyB,CAsI3B"}
1
+ {"version":3,"file":"use-suggestions.d.ts","sourceRoot":"","sources":["../../src/hooks/use-suggestions.ts"],"names":[],"mappings":"AACA,OAAO,OAAO,MAAM,0BAA0B,CAAC;AAY/C,OAAO,EACL,sBAAsB,EAEvB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACL,sBAAsB,EACtB,mBAAmB,EAGpB,MAAM,qBAAqB,CAAC;AAE7B;;GAEG;AACH,MAAM,WAAW,0BAA0B;IACzC,kEAAkE;IAClE,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;GAEG;AACH,MAAM,WAAW,iCAAiC;IAChD,4EAA4E;IAC5E,WAAW,EAAE,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC;IAC/C,8CAA8C;IAC9C,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC;;;;OAIG;IACH,MAAM,EAAE,CAAC,aAAa,EAAE;QACtB,UAAU,EAAE,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC;QAC5C,YAAY,CAAC,EAAE,OAAO,CAAC;KACxB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAEpB,0DAA0D;IAC1D,YAAY,EAAE,sBAAsB,CAClC,IAAI,EACJ,KAAK,EACL;QAAE,UAAU,EAAE,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC;QAAC,YAAY,CAAC,EAAE,OAAO,CAAA;KAAE,CACxE,CAAC;IAEF,0DAA0D;IAC1D,cAAc,EAAE,sBAAsB,CACpC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,0BAA0B,GAAG,SAAS,EACvE,KAAK,EACL,eAAe,CAChB,CAAC;IAEF,yDAAyD;IACzD,iBAAiB,EAAE,mBAAmB,CACpC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,0BAA0B,GAAG,SAAS,EACvE,KAAK,CACN,CAAC;CACH;AAED,KAAK,yBAAyB,GAAG,sBAAsB,CAAC,GAAG,EAAE,KAAK,CAAC,GACjE,iCAAiC,CAAC;AAEpC;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,GAAE,0BAA+B,GACvC,yBAAyB,CAsI3B"}
@@ -5,11 +5,11 @@ import { validateInput } from "../model/validate-input";
5
5
  import { useTamboClient } from "../providers/tambo-client-provider";
6
6
  import { useTambo } from "../providers/tambo-provider";
7
7
  import { useTamboRegistry } from "../providers/tambo-registry-provider";
8
+ import { INPUT_ERROR_MESSAGES, useTamboThreadInput, } from "../providers/tambo-thread-input-provider";
8
9
  import { useTamboThread } from "../providers/tambo-thread-provider";
9
10
  import { combineMutationResults, } from "../util/query-utils";
10
11
  import { getAvailableComponents } from "../util/registry";
11
12
  import { useTamboMutation, useTamboQuery, } from "./react-query-hooks";
12
- import { INPUT_ERROR_MESSAGES, useTamboThreadInput } from "./use-thread-input";
13
13
  /**
14
14
  * Hook for managing Tambo AI suggestions in a thread
15
15
  * @param options - Configuration options for suggestion generation
@@ -1 +1 @@
1
- {"version":3,"file":"use-suggestions.js","sourceRoot":"","sources":["../../src/hooks/use-suggestions.ts"],"names":[],"mappings":"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","sourcesContent":["\"use client\";\nimport TamboAI from \"@tambo-ai/typescript-sdk\";\nimport { useEffect, useState } from \"react\";\nimport { isIdleStage } from \"../model/generate-component-response\";\nimport { validateInput } from \"../model/validate-input\";\nimport { useTamboClient } from \"../providers/tambo-client-provider\";\nimport { useTambo } from \"../providers/tambo-provider\";\nimport { useTamboRegistry } from \"../providers/tambo-registry-provider\";\nimport { useTamboThread } from \"../providers/tambo-thread-provider\";\nimport {\n CombinedMutationResult,\n combineMutationResults,\n} from \"../util/query-utils\";\nimport { getAvailableComponents } from \"../util/registry\";\nimport {\n UseTamboMutationResult,\n UseTamboQueryResult,\n useTamboMutation,\n useTamboQuery,\n} from \"./react-query-hooks\";\nimport { INPUT_ERROR_MESSAGES, useTamboThreadInput } from \"./use-thread-input\";\n\n/**\n * Configuration options for the useTamboSuggestions hook\n */\nexport interface useTamboSuggestionsOptions {\n /** Maximum number of suggestions to generate (1-10, default 3) */\n maxSuggestions?: number;\n}\n\n/**\n * Return value interface for useTamboSuggestions hook\n */\nexport interface useTamboSuggestionsResultInternal {\n /** List of available suggestions (also available in generateResult.data) */\n suggestions: TamboAI.Beta.Threads.Suggestion[];\n /** ID of the currently selected suggestion */\n selectedSuggestionId: string | null;\n /**\n * Accept and apply a suggestion (also available in acceptResult.mutateAsync)\n * @param suggestion - The suggestion to accept\n * @param shouldSubmit - Whether to automatically submit after accepting (default: false)\n */\n accept: (acceptOptions: {\n suggestion: TamboAI.Beta.Threads.Suggestion;\n shouldSubmit?: boolean;\n }) => Promise<void>;\n\n /** Result and network state for accepting a suggestion */\n acceptResult: UseTamboMutationResult<\n void,\n Error,\n { suggestion: TamboAI.Beta.Threads.Suggestion; shouldSubmit?: boolean }\n >;\n\n /** Result and network state for generating suggestions */\n generateResult: UseTamboMutationResult<\n TamboAI.Beta.Threads.Suggestions.SuggestionGenerateResponse | undefined,\n Error,\n AbortController\n >;\n\n /** The full suggestions query object from React Query */\n suggestionsResult: UseTamboQueryResult<\n TamboAI.Beta.Threads.Suggestions.SuggestionGenerateResponse | undefined,\n Error\n >;\n}\n\ntype useTamboSuggestionsResult = CombinedMutationResult<any, Error> &\n useTamboSuggestionsResultInternal;\n\n/**\n * Hook for managing Tambo AI suggestions in a thread\n * @param options - Configuration options for suggestion generation\n * @returns Object containing suggestions state and control functions\n */\nexport function useTamboSuggestions(\n options: useTamboSuggestionsOptions = {},\n): useTamboSuggestionsResult {\n const { maxSuggestions = 3 } = options;\n const { thread, generationStage } = useTamboThread();\n const { sendThreadMessage } = useTambo();\n const tamboClient = useTamboClient();\n const { componentList, toolRegistry, componentToolAssociations } =\n useTamboRegistry();\n\n const [selectedSuggestionId, setSelectedSuggestionId] = useState<\n string | null\n >(null);\n const { setValue: setInputValue } = useTamboThreadInput();\n\n const latestMessage = thread.messages[thread.messages.length - 1];\n const isLatestFromTambo = latestMessage?.role === \"assistant\";\n const latestMessageId = latestMessage?.id;\n\n // Reset selected suggestion when the message changes\n useEffect(() => {\n setSelectedSuggestionId(null);\n }, [latestMessageId]);\n\n const shouldGenerateSuggestions =\n latestMessageId && isLatestFromTambo && isIdleStage(generationStage);\n // Use React Query to fetch suggestions when a new hydra message is received\n const suggestionsResult = useTamboQuery({\n // Make sure the query key changes when the message changes, so that we are\n // always generating suggestions when there is a new message\n queryKey: [\n \"suggestions\",\n shouldGenerateSuggestions ? latestMessageId : null,\n ],\n queryFn: async () => {\n if (!shouldGenerateSuggestions) {\n return [];\n }\n\n // Get registered components from the registry\n const components = getAvailableComponents(\n componentList,\n toolRegistry,\n componentToolAssociations,\n );\n\n return await tamboClient.beta.threads.suggestions.generate(\n thread.id,\n latestMessageId,\n {\n maxSuggestions,\n availableComponents: components,\n },\n );\n },\n // Only run the query if we have a valid message from hydra\n enabled: Boolean(latestMessageId && isLatestFromTambo),\n // Don't refetch on window focus or reconnect\n refetchOnWindowFocus: false,\n refetchOnReconnect: false,\n // Don't retry on failure\n retry: false,\n });\n\n // Accept suggestion mutation\n const acceptMutationState = useTamboMutation<\n void,\n Error,\n { suggestion: TamboAI.Beta.Threads.Suggestion; shouldSubmit?: boolean }\n >({\n mutationFn: async ({ suggestion, shouldSubmit = false }) => {\n const validation = validateInput(suggestion.detailedSuggestion);\n if (!validation.isValid) {\n if (validation.error) {\n throw validation.error;\n }\n throw new Error(INPUT_ERROR_MESSAGES.VALIDATION);\n }\n\n if (shouldSubmit) {\n await sendThreadMessage(validation.sanitizedInput, {\n threadId: thread.id,\n });\n } else {\n setInputValue(validation.sanitizedInput);\n }\n setSelectedSuggestionId(suggestion.id);\n },\n });\n\n // Generate suggestions mutation\n const generateMutationState = useTamboMutation<\n TamboAI.Beta.Threads.Suggestions.SuggestionGenerateResponse | undefined,\n Error,\n AbortController\n >({\n mutationFn: async (abortController: AbortController) => {\n if (!shouldGenerateSuggestions) {\n return undefined;\n }\n\n // Get registered components from the registry\n const components = getAvailableComponents(\n componentList,\n toolRegistry,\n componentToolAssociations,\n );\n return await tamboClient.beta.threads.suggestions.generate(\n thread.id,\n latestMessageId,\n {\n maxSuggestions,\n availableComponents: components,\n },\n { signal: abortController.signal },\n );\n },\n // Don't retry on failure\n retry: false,\n });\n\n // Use the query data if available, otherwise use the mutation data\n // Only return suggestions if the latest message is from hydra\n const suggestions = isLatestFromTambo\n ? (suggestionsResult.data ?? generateMutationState.data ?? [])\n : [];\n\n return {\n suggestions,\n accept: acceptMutationState.mutateAsync,\n selectedSuggestionId,\n acceptResult: acceptMutationState,\n generateResult: generateMutationState,\n suggestionsResult,\n ...combineMutationResults(acceptMutationState, generateMutationState),\n };\n}\n"]}
1
+ {"version":3,"file":"use-suggestions.js","sourceRoot":"","sources":["../../src/hooks/use-suggestions.ts"],"names":[],"mappings":"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","sourcesContent":["\"use client\";\nimport TamboAI from \"@tambo-ai/typescript-sdk\";\nimport { useEffect, useState } from \"react\";\nimport { isIdleStage } from \"../model/generate-component-response\";\nimport { validateInput } from \"../model/validate-input\";\nimport { useTamboClient } from \"../providers/tambo-client-provider\";\nimport { useTambo } from \"../providers/tambo-provider\";\nimport { useTamboRegistry } from \"../providers/tambo-registry-provider\";\nimport {\n INPUT_ERROR_MESSAGES,\n useTamboThreadInput,\n} from \"../providers/tambo-thread-input-provider\";\nimport { useTamboThread } from \"../providers/tambo-thread-provider\";\nimport {\n CombinedMutationResult,\n combineMutationResults,\n} from \"../util/query-utils\";\nimport { getAvailableComponents } from \"../util/registry\";\nimport {\n UseTamboMutationResult,\n UseTamboQueryResult,\n useTamboMutation,\n useTamboQuery,\n} from \"./react-query-hooks\";\n\n/**\n * Configuration options for the useTamboSuggestions hook\n */\nexport interface useTamboSuggestionsOptions {\n /** Maximum number of suggestions to generate (1-10, default 3) */\n maxSuggestions?: number;\n}\n\n/**\n * Return value interface for useTamboSuggestions hook\n */\nexport interface useTamboSuggestionsResultInternal {\n /** List of available suggestions (also available in generateResult.data) */\n suggestions: TamboAI.Beta.Threads.Suggestion[];\n /** ID of the currently selected suggestion */\n selectedSuggestionId: string | null;\n /**\n * Accept and apply a suggestion (also available in acceptResult.mutateAsync)\n * @param suggestion - The suggestion to accept\n * @param shouldSubmit - Whether to automatically submit after accepting (default: false)\n */\n accept: (acceptOptions: {\n suggestion: TamboAI.Beta.Threads.Suggestion;\n shouldSubmit?: boolean;\n }) => Promise<void>;\n\n /** Result and network state for accepting a suggestion */\n acceptResult: UseTamboMutationResult<\n void,\n Error,\n { suggestion: TamboAI.Beta.Threads.Suggestion; shouldSubmit?: boolean }\n >;\n\n /** Result and network state for generating suggestions */\n generateResult: UseTamboMutationResult<\n TamboAI.Beta.Threads.Suggestions.SuggestionGenerateResponse | undefined,\n Error,\n AbortController\n >;\n\n /** The full suggestions query object from React Query */\n suggestionsResult: UseTamboQueryResult<\n TamboAI.Beta.Threads.Suggestions.SuggestionGenerateResponse | undefined,\n Error\n >;\n}\n\ntype useTamboSuggestionsResult = CombinedMutationResult<any, Error> &\n useTamboSuggestionsResultInternal;\n\n/**\n * Hook for managing Tambo AI suggestions in a thread\n * @param options - Configuration options for suggestion generation\n * @returns Object containing suggestions state and control functions\n */\nexport function useTamboSuggestions(\n options: useTamboSuggestionsOptions = {},\n): useTamboSuggestionsResult {\n const { maxSuggestions = 3 } = options;\n const { thread, generationStage } = useTamboThread();\n const { sendThreadMessage } = useTambo();\n const tamboClient = useTamboClient();\n const { componentList, toolRegistry, componentToolAssociations } =\n useTamboRegistry();\n\n const [selectedSuggestionId, setSelectedSuggestionId] = useState<\n string | null\n >(null);\n const { setValue: setInputValue } = useTamboThreadInput();\n\n const latestMessage = thread.messages[thread.messages.length - 1];\n const isLatestFromTambo = latestMessage?.role === \"assistant\";\n const latestMessageId = latestMessage?.id;\n\n // Reset selected suggestion when the message changes\n useEffect(() => {\n setSelectedSuggestionId(null);\n }, [latestMessageId]);\n\n const shouldGenerateSuggestions =\n latestMessageId && isLatestFromTambo && isIdleStage(generationStage);\n // Use React Query to fetch suggestions when a new hydra message is received\n const suggestionsResult = useTamboQuery({\n // Make sure the query key changes when the message changes, so that we are\n // always generating suggestions when there is a new message\n queryKey: [\n \"suggestions\",\n shouldGenerateSuggestions ? latestMessageId : null,\n ],\n queryFn: async () => {\n if (!shouldGenerateSuggestions) {\n return [];\n }\n\n // Get registered components from the registry\n const components = getAvailableComponents(\n componentList,\n toolRegistry,\n componentToolAssociations,\n );\n\n return await tamboClient.beta.threads.suggestions.generate(\n thread.id,\n latestMessageId,\n {\n maxSuggestions,\n availableComponents: components,\n },\n );\n },\n // Only run the query if we have a valid message from hydra\n enabled: Boolean(latestMessageId && isLatestFromTambo),\n // Don't refetch on window focus or reconnect\n refetchOnWindowFocus: false,\n refetchOnReconnect: false,\n // Don't retry on failure\n retry: false,\n });\n\n // Accept suggestion mutation\n const acceptMutationState = useTamboMutation<\n void,\n Error,\n { suggestion: TamboAI.Beta.Threads.Suggestion; shouldSubmit?: boolean }\n >({\n mutationFn: async ({ suggestion, shouldSubmit = false }) => {\n const validation = validateInput(suggestion.detailedSuggestion);\n if (!validation.isValid) {\n if (validation.error) {\n throw validation.error;\n }\n throw new Error(INPUT_ERROR_MESSAGES.VALIDATION);\n }\n\n if (shouldSubmit) {\n await sendThreadMessage(validation.sanitizedInput, {\n threadId: thread.id,\n });\n } else {\n setInputValue(validation.sanitizedInput);\n }\n setSelectedSuggestionId(suggestion.id);\n },\n });\n\n // Generate suggestions mutation\n const generateMutationState = useTamboMutation<\n TamboAI.Beta.Threads.Suggestions.SuggestionGenerateResponse | undefined,\n Error,\n AbortController\n >({\n mutationFn: async (abortController: AbortController) => {\n if (!shouldGenerateSuggestions) {\n return undefined;\n }\n\n // Get registered components from the registry\n const components = getAvailableComponents(\n componentList,\n toolRegistry,\n componentToolAssociations,\n );\n return await tamboClient.beta.threads.suggestions.generate(\n thread.id,\n latestMessageId,\n {\n maxSuggestions,\n availableComponents: components,\n },\n { signal: abortController.signal },\n );\n },\n // Don't retry on failure\n retry: false,\n });\n\n // Use the query data if available, otherwise use the mutation data\n // Only return suggestions if the latest message is from hydra\n const suggestions = isLatestFromTambo\n ? (suggestionsResult.data ?? generateMutationState.data ?? [])\n : [];\n\n return {\n suggestions,\n accept: acceptMutationState.mutateAsync,\n selectedSuggestionId,\n acceptResult: acceptMutationState,\n generateResult: generateMutationState,\n suggestionsResult,\n ...combineMutationResults(acceptMutationState, generateMutationState),\n };\n}\n"]}
package/esm/index.d.ts CHANGED
@@ -4,8 +4,7 @@ export { TamboMessageProvider, useTamboCurrentMessage, } from "./hooks/use-curre
4
4
  export { useTamboStreamingProps } from "./hooks/use-streaming-props";
5
5
  export * from "./hooks/use-suggestions";
6
6
  export { useTamboStreamStatus, type PropStatus, type StreamStatus, } from "./hooks/use-tambo-stream-status";
7
- export { useTamboThreadInput } from "./hooks/use-thread-input";
8
- export { TamboClientProvider, TamboComponentProvider, TamboContextHelpersProvider, TamboPropStreamProvider, TamboProvider, TamboStubProvider, TamboThreadProvider, useTambo, useTamboClient, useTamboContextHelpers, useTamboGenerationStage, useTamboStream, useTamboThread, type TamboComponent, type TamboContextHelpersContextProps, type TamboContextHelpersProviderProps, type TamboRegistryContext, type TamboStubProviderProps, } from "./providers";
7
+ export { TamboClientProvider, TamboComponentProvider, TamboContextHelpersProvider, TamboPropStreamProvider, TamboProvider, TamboStubProvider, TamboThreadInputProvider, TamboThreadProvider, useTambo, useTamboClient, useTamboContextHelpers, useTamboGenerationStage, useTamboStream, useTamboThread, useTamboThreadInput, type TamboComponent, type TamboContextHelpersContextProps, type TamboContextHelpersProviderProps, type TamboRegistryContext, type TamboStubProviderProps, type TamboThreadInputContextProps, } from "./providers";
9
8
  export type { APIError, RateLimitError, TamboAIError, } from "@tambo-ai/typescript-sdk";
10
9
  export type { Suggestion, SuggestionGenerateParams, SuggestionGenerateResponse, SuggestionListResponse, } from "@tambo-ai/typescript-sdk/resources/beta/threads/suggestions";
11
10
  export { useTamboThreadList } from "./hooks/use-tambo-threads";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,wKAAwK;AAExK,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AACrE,OAAO,EACL,oBAAoB,EACpB,sBAAsB,GACvB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AACrE,cAAc,yBAAyB,CAAC;AACxC,OAAO,EACL,oBAAoB,EACpB,KAAK,UAAU,EACf,KAAK,YAAY,GAClB,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAG/D,OAAO,EACL,mBAAmB,EACnB,sBAAsB,EACtB,2BAA2B,EAC3B,uBAAuB,EACvB,aAAa,EACb,iBAAiB,EACjB,mBAAmB,EACnB,QAAQ,EACR,cAAc,EACd,sBAAsB,EACtB,uBAAuB,EACvB,cAAc,EACd,cAAc,EACd,KAAK,cAAc,EACnB,KAAK,+BAA+B,EACpC,KAAK,gCAAgC,EACrC,KAAK,oBAAoB,EACzB,KAAK,sBAAsB,GAC5B,MAAM,aAAa,CAAC;AAGrB,YAAY,EACV,QAAQ,EACR,cAAc,EACd,YAAY,GACb,MAAM,0BAA0B,CAAC;AAClC,YAAY,EACV,UAAU,EACV,wBAAwB,EACxB,0BAA0B,EAC1B,sBAAsB,GACvB,MAAM,6DAA6D,CAAC;AACrE,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,EACL,KAAK,4BAA4B,EACjC,KAAK,iBAAiB,EACtB,KAAK,aAAa,EAClB,KAAK,mBAAmB,EACxB,KAAK,SAAS,GACf,MAAM,4BAA4B,CAAC;AACpC,OAAO,EACL,eAAe,EACf,KAAK,kBAAkB,GACxB,MAAM,qCAAqC,CAAC;AAC7C,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAExD,YAAY,EACV,0BAA0B,IAAI,qBAAqB,EACnD,wBAAwB,GACzB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EACL,qBAAqB,IAAI,gBAAgB,EACzC,KAAK,kBAAkB,EACvB,KAAK,0BAA0B,GAChC,MAAM,yCAAyC,CAAC;AACjD,OAAO,EAAE,oBAAoB,EAAE,MAAM,yCAAyC,CAAC;AAG/E,OAAO,EACL,wBAAwB,EACxB,wBAAwB,GACzB,MAAM,mBAAmB,CAAC;AAC3B,YAAY,EACV,iBAAiB,EACjB,eAAe,EACf,cAAc,GACf,MAAM,mBAAmB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,wKAAwK;AAExK,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AACrE,OAAO,EACL,oBAAoB,EACpB,sBAAsB,GACvB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AACrE,cAAc,yBAAyB,CAAC;AACxC,OAAO,EACL,oBAAoB,EACpB,KAAK,UAAU,EACf,KAAK,YAAY,GAClB,MAAM,iCAAiC,CAAC;AAGzC,OAAO,EACL,mBAAmB,EACnB,sBAAsB,EACtB,2BAA2B,EAC3B,uBAAuB,EACvB,aAAa,EACb,iBAAiB,EACjB,wBAAwB,EACxB,mBAAmB,EACnB,QAAQ,EACR,cAAc,EACd,sBAAsB,EACtB,uBAAuB,EACvB,cAAc,EACd,cAAc,EACd,mBAAmB,EACnB,KAAK,cAAc,EACnB,KAAK,+BAA+B,EACpC,KAAK,gCAAgC,EACrC,KAAK,oBAAoB,EACzB,KAAK,sBAAsB,EAC3B,KAAK,4BAA4B,GAClC,MAAM,aAAa,CAAC;AAGrB,YAAY,EACV,QAAQ,EACR,cAAc,EACd,YAAY,GACb,MAAM,0BAA0B,CAAC;AAClC,YAAY,EACV,UAAU,EACV,wBAAwB,EACxB,0BAA0B,EAC1B,sBAAsB,GACvB,MAAM,6DAA6D,CAAC;AACrE,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,EACL,KAAK,4BAA4B,EACjC,KAAK,iBAAiB,EACtB,KAAK,aAAa,EAClB,KAAK,mBAAmB,EACxB,KAAK,SAAS,GACf,MAAM,4BAA4B,CAAC;AACpC,OAAO,EACL,eAAe,EACf,KAAK,kBAAkB,GACxB,MAAM,qCAAqC,CAAC;AAC7C,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAExD,YAAY,EACV,0BAA0B,IAAI,qBAAqB,EACnD,wBAAwB,GACzB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EACL,qBAAqB,IAAI,gBAAgB,EACzC,KAAK,kBAAkB,EACvB,KAAK,0BAA0B,GAChC,MAAM,yCAAyC,CAAC;AACjD,OAAO,EAAE,oBAAoB,EAAE,MAAM,yCAAyC,CAAC;AAG/E,OAAO,EACL,wBAAwB,EACxB,wBAAwB,GACzB,MAAM,mBAAmB,CAAC;AAC3B,YAAY,EACV,iBAAiB,EACjB,eAAe,EACf,cAAc,GACf,MAAM,mBAAmB,CAAC"}
package/esm/index.js CHANGED
@@ -4,9 +4,8 @@ export { TamboMessageProvider, useTamboCurrentMessage, } from "./hooks/use-curre
4
4
  export { useTamboStreamingProps } from "./hooks/use-streaming-props";
5
5
  export * from "./hooks/use-suggestions";
6
6
  export { useTamboStreamStatus, } from "./hooks/use-tambo-stream-status";
7
- export { useTamboThreadInput } from "./hooks/use-thread-input";
8
7
  // Re-export provider components
9
- export { TamboClientProvider, TamboComponentProvider, TamboContextHelpersProvider, TamboPropStreamProvider, TamboProvider, TamboStubProvider, TamboThreadProvider, useTambo, useTamboClient, useTamboContextHelpers, useTamboGenerationStage, useTamboStream, useTamboThread, } from "./providers";
8
+ export { TamboClientProvider, TamboComponentProvider, TamboContextHelpersProvider, TamboPropStreamProvider, TamboProvider, TamboStubProvider, TamboThreadInputProvider, TamboThreadProvider, useTambo, useTamboClient, useTamboContextHelpers, useTamboGenerationStage, useTamboStream, useTamboThread, useTamboThreadInput, } from "./providers";
10
9
  export { useTamboThreadList } from "./hooks/use-tambo-threads";
11
10
  export { GenerationStage, } from "./model/generate-component-response";
12
11
  export { withTamboInteractable as withInteractable, } from "./providers/hoc/with-tambo-interactable";
package/esm/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,wKAAwK;AAExK,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AACrE,OAAO,EACL,oBAAoB,EACpB,sBAAsB,GACvB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AACrE,cAAc,yBAAyB,CAAC;AACxC,OAAO,EACL,oBAAoB,GAGrB,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAE/D,gCAAgC;AAChC,OAAO,EACL,mBAAmB,EACnB,sBAAsB,EACtB,2BAA2B,EAC3B,uBAAuB,EACvB,aAAa,EACb,iBAAiB,EACjB,mBAAmB,EACnB,QAAQ,EACR,cAAc,EACd,sBAAsB,EACtB,uBAAuB,EACvB,cAAc,EACd,cAAc,GAMf,MAAM,aAAa,CAAC;AAcrB,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAQ/D,OAAO,EACL,eAAe,GAEhB,MAAM,qCAAqC,CAAC;AAO7C,OAAO,EACL,qBAAqB,IAAI,gBAAgB,GAG1C,MAAM,yCAAyC,CAAC;AACjD,OAAO,EAAE,oBAAoB,EAAE,MAAM,yCAAyC,CAAC;AAE/E,0BAA0B;AAC1B,OAAO,EACL,wBAAwB,EACxB,wBAAwB,GACzB,MAAM,mBAAmB,CAAC","sourcesContent":["/** Exports for the library. Only publically available exports are re-exported here. Anything not exported here is not supported and may change or break at any time. */\n\nexport { useTamboComponentState } from \"./hooks/use-component-state\";\nexport {\n TamboMessageProvider,\n useTamboCurrentMessage,\n} from \"./hooks/use-current-message\";\nexport { useTamboStreamingProps } from \"./hooks/use-streaming-props\";\nexport * from \"./hooks/use-suggestions\";\nexport {\n useTamboStreamStatus,\n type PropStatus,\n type StreamStatus,\n} from \"./hooks/use-tambo-stream-status\";\nexport { useTamboThreadInput } from \"./hooks/use-thread-input\";\n\n// Re-export provider components\nexport {\n TamboClientProvider,\n TamboComponentProvider,\n TamboContextHelpersProvider,\n TamboPropStreamProvider,\n TamboProvider,\n TamboStubProvider,\n TamboThreadProvider,\n useTambo,\n useTamboClient,\n useTamboContextHelpers,\n useTamboGenerationStage,\n useTamboStream,\n useTamboThread,\n type TamboComponent,\n type TamboContextHelpersContextProps,\n type TamboContextHelpersProviderProps,\n type TamboRegistryContext,\n type TamboStubProviderProps,\n} from \"./providers\";\n\n// Re-export types from Tambo Node SDK\nexport type {\n APIError,\n RateLimitError,\n TamboAIError,\n} from \"@tambo-ai/typescript-sdk\";\nexport type {\n Suggestion,\n SuggestionGenerateParams,\n SuggestionGenerateResponse,\n SuggestionListResponse,\n} from \"@tambo-ai/typescript-sdk/resources/beta/threads/suggestions\";\nexport { useTamboThreadList } from \"./hooks/use-tambo-threads\";\nexport {\n type ComponentContextToolMetadata,\n type ComponentRegistry,\n type ParameterSpec,\n type RegisteredComponent,\n type TamboTool,\n} from \"./model/component-metadata\";\nexport {\n GenerationStage,\n type TamboThreadMessage,\n} from \"./model/generate-component-response\";\nexport { type TamboThread } from \"./model/tambo-thread\";\n\nexport type {\n TamboInteractableComponent as InteractableComponent,\n TamboInteractableContext,\n} from \"./model/tambo-interactable\";\nexport {\n withTamboInteractable as withInteractable,\n type InteractableConfig,\n type WithTamboInteractableProps,\n} from \"./providers/hoc/with-tambo-interactable\";\nexport { useTamboInteractable } from \"./providers/tambo-interactable-provider\";\n\n// Context helpers exports\nexport {\n currentPageContextHelper,\n currentTimeContextHelper,\n} from \"./context-helpers\";\nexport type {\n AdditionalContext,\n ContextHelperFn,\n ContextHelpers,\n} from \"./context-helpers\";\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,wKAAwK;AAExK,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AACrE,OAAO,EACL,oBAAoB,EACpB,sBAAsB,GACvB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AACrE,cAAc,yBAAyB,CAAC;AACxC,OAAO,EACL,oBAAoB,GAGrB,MAAM,iCAAiC,CAAC;AAEzC,gCAAgC;AAChC,OAAO,EACL,mBAAmB,EACnB,sBAAsB,EACtB,2BAA2B,EAC3B,uBAAuB,EACvB,aAAa,EACb,iBAAiB,EACjB,wBAAwB,EACxB,mBAAmB,EACnB,QAAQ,EACR,cAAc,EACd,sBAAsB,EACtB,uBAAuB,EACvB,cAAc,EACd,cAAc,EACd,mBAAmB,GAOpB,MAAM,aAAa,CAAC;AAcrB,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAQ/D,OAAO,EACL,eAAe,GAEhB,MAAM,qCAAqC,CAAC;AAO7C,OAAO,EACL,qBAAqB,IAAI,gBAAgB,GAG1C,MAAM,yCAAyC,CAAC;AACjD,OAAO,EAAE,oBAAoB,EAAE,MAAM,yCAAyC,CAAC;AAE/E,0BAA0B;AAC1B,OAAO,EACL,wBAAwB,EACxB,wBAAwB,GACzB,MAAM,mBAAmB,CAAC","sourcesContent":["/** Exports for the library. Only publically available exports are re-exported here. Anything not exported here is not supported and may change or break at any time. */\n\nexport { useTamboComponentState } from \"./hooks/use-component-state\";\nexport {\n TamboMessageProvider,\n useTamboCurrentMessage,\n} from \"./hooks/use-current-message\";\nexport { useTamboStreamingProps } from \"./hooks/use-streaming-props\";\nexport * from \"./hooks/use-suggestions\";\nexport {\n useTamboStreamStatus,\n type PropStatus,\n type StreamStatus,\n} from \"./hooks/use-tambo-stream-status\";\n\n// Re-export provider components\nexport {\n TamboClientProvider,\n TamboComponentProvider,\n TamboContextHelpersProvider,\n TamboPropStreamProvider,\n TamboProvider,\n TamboStubProvider,\n TamboThreadInputProvider,\n TamboThreadProvider,\n useTambo,\n useTamboClient,\n useTamboContextHelpers,\n useTamboGenerationStage,\n useTamboStream,\n useTamboThread,\n useTamboThreadInput,\n type TamboComponent,\n type TamboContextHelpersContextProps,\n type TamboContextHelpersProviderProps,\n type TamboRegistryContext,\n type TamboStubProviderProps,\n type TamboThreadInputContextProps,\n} from \"./providers\";\n\n// Re-export types from Tambo Node SDK\nexport type {\n APIError,\n RateLimitError,\n TamboAIError,\n} from \"@tambo-ai/typescript-sdk\";\nexport type {\n Suggestion,\n SuggestionGenerateParams,\n SuggestionGenerateResponse,\n SuggestionListResponse,\n} from \"@tambo-ai/typescript-sdk/resources/beta/threads/suggestions\";\nexport { useTamboThreadList } from \"./hooks/use-tambo-threads\";\nexport {\n type ComponentContextToolMetadata,\n type ComponentRegistry,\n type ParameterSpec,\n type RegisteredComponent,\n type TamboTool,\n} from \"./model/component-metadata\";\nexport {\n GenerationStage,\n type TamboThreadMessage,\n} from \"./model/generate-component-response\";\nexport { type TamboThread } from \"./model/tambo-thread\";\n\nexport type {\n TamboInteractableComponent as InteractableComponent,\n TamboInteractableContext,\n} from \"./model/tambo-interactable\";\nexport {\n withTamboInteractable as withInteractable,\n type InteractableConfig,\n type WithTamboInteractableProps,\n} from \"./providers/hoc/with-tambo-interactable\";\nexport { useTamboInteractable } from \"./providers/tambo-interactable-provider\";\n\n// Context helpers exports\nexport {\n currentPageContextHelper,\n currentTimeContextHelper,\n} from \"./context-helpers\";\nexport type {\n AdditionalContext,\n ContextHelperFn,\n ContextHelpers,\n} from \"./context-helpers\";\n"]}
@@ -1,3 +1,4 @@
1
+ import { QueryClient } from "@tanstack/react-query";
1
2
  import { act, renderHook } from "@testing-library/react";
2
3
  import { useTamboSessionToken } from "../use-tambo-session-token";
3
4
  describe("useTamboSessionToken", () => {
@@ -17,40 +18,59 @@ describe("useTamboSessionToken", () => {
17
18
  beta: mockBeta,
18
19
  bearer: "",
19
20
  };
21
+ const queryClient = new QueryClient({
22
+ defaultOptions: {
23
+ queries: {
24
+ retry: false,
25
+ refetchOnWindowFocus: false,
26
+ },
27
+ },
28
+ });
20
29
  beforeEach(() => {
21
30
  jest.clearAllMocks();
22
31
  jest.clearAllTimers();
23
32
  jest.useFakeTimers();
24
33
  mockTamboAI.bearer = "";
34
+ queryClient.clear();
25
35
  });
26
- afterEach(() => {
27
- jest.runOnlyPendingTimers();
36
+ afterEach(async () => {
37
+ await act(async () => {
38
+ await jest.runOnlyPendingTimersAsync();
39
+ });
28
40
  jest.useRealTimers();
41
+ jest.resetAllMocks();
29
42
  });
30
43
  it("should return null initially when no userToken is provided", () => {
31
- const { result } = renderHook(() => useTamboSessionToken(mockTamboAI, undefined));
32
- expect(result.current).toBeNull();
44
+ const { result } = renderHook(() => useTamboSessionToken(mockTamboAI, queryClient, undefined));
45
+ expect(result.current).toMatchObject({
46
+ data: undefined,
47
+ isFetching: false,
48
+ });
33
49
  expect(mockAuthApi.getToken).not.toHaveBeenCalled();
34
50
  });
35
51
  it("should fetch and return session token when userToken is provided", async () => {
36
- jest.mocked(mockAuthApi.getToken).mockResolvedValue(mockTokenResponse);
37
- const { result } = renderHook(() => useTamboSessionToken(mockTamboAI, "user-token"));
52
+ mockAuthApi.getToken.mockResolvedValue(mockTokenResponse);
53
+ const { result } = renderHook(() => useTamboSessionToken(mockTamboAI, queryClient, "user-token"));
54
+ expect(mockAuthApi.getToken).toHaveBeenCalledTimes(1);
38
55
  await act(async () => {
39
56
  await jest.runOnlyPendingTimersAsync();
40
57
  });
41
- expect(result.current).toBe("test-access-token");
42
- expect(mockTamboAI.bearer).toBe("test-access-token");
58
+ expect(result.current).toMatchObject({
59
+ data: mockTokenResponse,
60
+ isFetching: false,
61
+ });
62
+ expect(mockTamboAI.bearer).toBe(mockTokenResponse.access_token);
43
63
  // Verify the hook was called with correct parameters
44
- expect(mockAuthApi.getToken).toHaveBeenCalledTimes(1);
64
+ expect(mockAuthApi.getToken).toHaveBeenCalledTimes(2);
45
65
  expect(mockAuthApi.getToken).toHaveBeenCalledWith(expect.any(Object));
46
66
  });
47
67
  it("should call getToken with correct token exchange parameters", async () => {
48
- jest.mocked(mockAuthApi.getToken).mockResolvedValue(mockTokenResponse);
49
- renderHook(() => useTamboSessionToken(mockTamboAI, "user-token"));
68
+ mockAuthApi.getToken.mockResolvedValue(mockTokenResponse);
69
+ renderHook(() => useTamboSessionToken(mockTamboAI, queryClient, "user-token"));
50
70
  await act(async () => {
51
71
  await jest.runOnlyPendingTimersAsync();
52
72
  });
53
- const callArgs = jest.mocked(mockAuthApi.getToken).mock.calls[0][0];
73
+ const callArgs = mockAuthApi.getToken.mock.calls[0][0];
54
74
  const tokenRequestString = new TextDecoder().decode(callArgs);
55
75
  const tokenRequest = new URLSearchParams(tokenRequestString);
56
76
  expect(tokenRequest.get("grant_type")).toBe("urn:ietf:params:oauth:grant-type:token-exchange");
@@ -58,12 +78,14 @@ describe("useTamboSessionToken", () => {
58
78
  expect(tokenRequest.get("subject_token_type")).toBe("urn:ietf:params:oauth:token-type:access_token");
59
79
  });
60
80
  it("should set bearer token on client", async () => {
61
- jest.mocked(mockAuthApi.getToken).mockResolvedValue(mockTokenResponse);
62
- const { result } = renderHook(() => useTamboSessionToken(mockTamboAI, "user-token"));
81
+ mockAuthApi.getToken.mockResolvedValue(mockTokenResponse);
82
+ const { result } = renderHook(() => useTamboSessionToken(mockTamboAI, queryClient, "user-token"));
63
83
  await act(async () => {
64
84
  await jest.runOnlyPendingTimersAsync();
65
85
  });
66
- expect(result.current).toBe("test-access-token");
86
+ expect(result.current).toMatchObject({
87
+ data: mockTokenResponse,
88
+ });
67
89
  expect(mockTamboAI.bearer).toBe("test-access-token");
68
90
  });
69
91
  it("should handle different token responses", async () => {
@@ -72,24 +94,35 @@ describe("useTamboSessionToken", () => {
72
94
  expires_in: 7200, // 2 hours
73
95
  token_type: "Bearer",
74
96
  };
75
- jest.mocked(mockAuthApi.getToken).mockResolvedValue(customTokenResponse);
76
- const { result } = renderHook(() => useTamboSessionToken(mockTamboAI, "user-token"));
97
+ mockAuthApi.getToken.mockResolvedValue(customTokenResponse);
98
+ const { result } = renderHook(() => useTamboSessionToken(mockTamboAI, queryClient, "user-token"));
99
+ expect(result.current).toMatchObject({
100
+ data: undefined,
101
+ isFetching: true,
102
+ });
77
103
  await act(async () => {
78
104
  await jest.runOnlyPendingTimersAsync();
79
105
  });
80
- expect(result.current).toBe("custom-access-token");
106
+ expect(result.current).toMatchObject({
107
+ data: customTokenResponse,
108
+ isFetching: false,
109
+ });
81
110
  expect(mockTamboAI.bearer).toBe("custom-access-token");
82
111
  });
83
112
  it("should not fetch token when userToken changes to undefined", async () => {
84
- jest.mocked(mockAuthApi.getToken).mockResolvedValue(mockTokenResponse);
85
- const { result, rerender } = renderHook(({ userToken }) => useTamboSessionToken(mockTamboAI, userToken), {
113
+ mockAuthApi.getToken.mockResolvedValue(mockTokenResponse);
114
+ const { result, rerender } = renderHook(({ userToken }) => useTamboSessionToken(mockTamboAI, queryClient, userToken), {
86
115
  initialProps: { userToken: "user-token" },
87
116
  });
117
+ expect(mockAuthApi.getToken).toHaveBeenCalledTimes(1);
88
118
  await act(async () => {
89
119
  await jest.runOnlyPendingTimersAsync();
90
120
  });
91
- expect(result.current).toBe("test-access-token");
92
- expect(mockAuthApi.getToken).toHaveBeenCalledTimes(1);
121
+ expect(result.current).toMatchObject({
122
+ data: mockTokenResponse,
123
+ isFetching: false,
124
+ });
125
+ expect(mockAuthApi.getToken).toHaveBeenCalledTimes(2);
93
126
  // Clear mock and change userToken to undefined
94
127
  jest.clearAllMocks();
95
128
  act(() => {
@@ -98,17 +131,21 @@ describe("useTamboSessionToken", () => {
98
131
  expect(mockAuthApi.getToken).not.toHaveBeenCalled();
99
132
  });
100
133
  it("should refetch token when userToken changes", async () => {
101
- jest.mocked(mockAuthApi.getToken).mockResolvedValue(mockTokenResponse);
102
- const { result, rerender } = renderHook(({ userToken }) => useTamboSessionToken(mockTamboAI, userToken), {
134
+ mockAuthApi.getToken.mockResolvedValue(mockTokenResponse);
135
+ const { result, rerender } = renderHook(({ userToken }) => useTamboSessionToken(mockTamboAI, queryClient, userToken), {
103
136
  initialProps: { userToken: "user-token-1" },
104
137
  });
138
+ expect(mockAuthApi.getToken).toHaveBeenCalledTimes(1);
105
139
  await act(async () => {
106
140
  await jest.runOnlyPendingTimersAsync();
107
141
  });
108
- expect(result.current).toBe("test-access-token");
109
- expect(mockAuthApi.getToken).toHaveBeenCalledTimes(1);
142
+ expect(result.current).toMatchObject({
143
+ data: mockTokenResponse,
144
+ isFetching: false,
145
+ });
146
+ expect(mockAuthApi.getToken).toHaveBeenCalledTimes(2);
110
147
  // Mock response for new token
111
- jest.mocked(mockAuthApi.getToken).mockResolvedValue({
148
+ mockAuthApi.getToken.mockResolvedValue({
112
149
  ...mockTokenResponse,
113
150
  access_token: "new-access-token",
114
151
  });
@@ -119,33 +156,46 @@ describe("useTamboSessionToken", () => {
119
156
  await act(async () => {
120
157
  await jest.runOnlyPendingTimersAsync();
121
158
  });
122
- expect(result.current).toBe("new-access-token");
123
- expect(mockAuthApi.getToken).toHaveBeenCalledTimes(2);
159
+ expect(result.current).toMatchObject({
160
+ data: { access_token: "new-access-token" },
161
+ isFetching: false,
162
+ });
163
+ expect(mockAuthApi.getToken).toHaveBeenCalledTimes(4);
124
164
  });
125
165
  it("should reset token when userToken becomes null", async () => {
126
- jest.mocked(mockAuthApi.getToken).mockResolvedValue(mockTokenResponse);
127
- const { result, rerender } = renderHook(({ userToken }) => useTamboSessionToken(mockTamboAI, userToken), {
166
+ mockAuthApi.getToken.mockResolvedValue(mockTokenResponse);
167
+ const { result, rerender } = renderHook(({ userToken }) => useTamboSessionToken(mockTamboAI, queryClient, userToken), {
128
168
  initialProps: { userToken: "user-token" },
129
169
  });
130
170
  await act(async () => {
131
171
  await jest.runOnlyPendingTimersAsync();
132
172
  });
133
- expect(result.current).toBe("test-access-token");
173
+ expect(result.current).toMatchObject({
174
+ data: mockTokenResponse,
175
+ isFetching: false,
176
+ });
134
177
  // Change userToken to undefined
135
- act(() => {
136
- rerender({ userToken: undefined });
178
+ rerender({ userToken: undefined });
179
+ await act(async () => {
180
+ await jest.runAllTimersAsync();
181
+ });
182
+ // Token should reset to null (hook doesn't reset it to null when userToken is undefined)
183
+ expect(result.current).toMatchObject({
184
+ data: undefined,
185
+ isFetching: false,
137
186
  });
138
- // Token should remain the same (hook doesn't reset it to null when userToken is undefined)
139
- expect(result.current).toBe("test-access-token");
140
187
  });
141
188
  it("should not update state if component is unmounted during token fetch", async () => {
142
189
  let resolvePromise;
143
190
  const promise = new Promise((resolve) => {
144
191
  resolvePromise = resolve;
145
192
  });
146
- jest.mocked(mockAuthApi.getToken).mockReturnValue(promise);
147
- const { result, unmount } = renderHook(() => useTamboSessionToken(mockTamboAI, "user-token"));
148
- expect(result.current).toBeNull();
193
+ mockAuthApi.getToken.mockReturnValue(promise);
194
+ const { result, unmount } = renderHook(() => useTamboSessionToken(mockTamboAI, queryClient, "user-token"));
195
+ expect(result.current).toMatchObject({
196
+ data: undefined,
197
+ isFetching: true,
198
+ });
149
199
  // Unmount before the promise resolves
150
200
  unmount();
151
201
  // Now resolve the promise
@@ -153,7 +203,56 @@ describe("useTamboSessionToken", () => {
153
203
  resolvePromise(mockTokenResponse);
154
204
  });
155
205
  // Token should still be null since component was unmounted
156
- expect(result.current).toBeNull();
206
+ expect(result.current).toMatchObject({
207
+ data: undefined,
208
+ isFetching: true,
209
+ });
210
+ });
211
+ it("should set isUpdating to true while fetching token", () => {
212
+ mockAuthApi.getToken.mockImplementation(async () => {
213
+ return await new Promise(() => { }); // Never resolves
214
+ });
215
+ const { result } = renderHook(() => useTamboSessionToken(mockTamboAI, queryClient, "user-token"));
216
+ // Should be updating immediately when userToken is provided
217
+ expect(result.current).toMatchObject({
218
+ data: undefined,
219
+ isFetching: true,
220
+ });
221
+ });
222
+ it("should set isUpdating to false after token fetch completes", async () => {
223
+ mockAuthApi.getToken.mockResolvedValue(mockTokenResponse);
224
+ const { result } = renderHook(() => useTamboSessionToken(mockTamboAI, queryClient, "user-token"));
225
+ // Should be updating initially
226
+ expect(result.current).toMatchObject({
227
+ data: undefined,
228
+ isFetching: true,
229
+ });
230
+ await act(async () => {
231
+ await jest.runOnlyPendingTimersAsync();
232
+ });
233
+ // Should not be updating after completion
234
+ expect(result.current).toMatchObject({
235
+ data: mockTokenResponse,
236
+ isFetching: false,
237
+ });
238
+ });
239
+ it("should set isUpdating to false after token fetch fails", async () => {
240
+ mockAuthApi.getToken.mockRejectedValue(new Error("Token fetch failed"));
241
+ const { result } = renderHook(() => useTamboSessionToken(mockTamboAI, queryClient, "user-token"));
242
+ // Should be updating initially
243
+ expect(result.current).toMatchObject({
244
+ data: undefined,
245
+ isFetching: true,
246
+ });
247
+ await act(async () => {
248
+ await jest.runAllTimersAsync();
249
+ });
250
+ // Should not be updating after failure
251
+ expect(result.current).toMatchObject({
252
+ data: undefined,
253
+ error: expect.any(Error),
254
+ isFetching: false,
255
+ });
157
256
  });
158
257
  });
159
258
  //# sourceMappingURL=use-tambo-session-token.test.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"use-tambo-session-token.test.js","sourceRoot":"","sources":["../../../../src/providers/hooks/__tests__/use-tambo-session-token.test.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,GAAG,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAEzD,OAAO,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAIlE,QAAQ,CAAC,sBAAsB,EAAE,GAAG,EAAE;IACpC,MAAM,iBAAiB,GAAG;QACxB,YAAY,EAAE,mBAAmB;QACjC,UAAU,EAAE,IAAI,EAAE,SAAS;QAC3B,UAAU,EAAE,QAAQ;KACrB,CAAC;IAEF,MAAM,WAAW,GAAG;QAClB,QAAQ,EAAE,IAAI,CAAC,EAAE,EAAE;KAC2B,CAAC;IAEjD,MAAM,QAAQ,GAAG;QACf,IAAI,EAAE,WAAW;KACe,CAAC;IAEnC,MAAM,WAAW,GAAG;QAClB,MAAM,EAAE,EAAE;QACV,IAAI,EAAE,QAAQ;QACd,MAAM,EAAE,EAAE;KACoC,CAAC;IAEjD,UAAU,CAAC,GAAG,EAAE;QACd,IAAI,CAAC,aAAa,EAAE,CAAC;QACrB,IAAI,CAAC,cAAc,EAAE,CAAC;QACtB,IAAI,CAAC,aAAa,EAAE,CAAC;QACpB,WAAmB,CAAC,MAAM,GAAG,EAAE,CAAC;IACnC,CAAC,CAAC,CAAC;IAEH,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,oBAAoB,EAAE,CAAC;QAC5B,IAAI,CAAC,aAAa,EAAE,CAAC;IACvB,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4DAA4D,EAAE,GAAG,EAAE;QACpE,MAAM,EAAE,MAAM,EAAE,GAAG,UAAU,CAAC,GAAG,EAAE,CACjC,oBAAoB,CAAC,WAAW,EAAE,SAAS,CAAC,CAC7C,CAAC;QAEF,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,QAAQ,EAAE,CAAC;QAClC,MAAM,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAC;IACtD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kEAAkE,EAAE,KAAK,IAAI,EAAE;QAChF,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC,iBAAiB,CAAC,iBAAiB,CAAC,CAAC;QAEvE,MAAM,EAAE,MAAM,EAAE,GAAG,UAAU,CAAC,GAAG,EAAE,CACjC,oBAAoB,CAAC,WAAW,EAAE,YAAY,CAAC,CAChD,CAAC;QAEF,MAAM,GAAG,CAAC,KAAK,IAAI,EAAE;YACnB,MAAM,IAAI,CAAC,yBAAyB,EAAE,CAAC;QACzC,CAAC,CAAC,CAAC;QAEH,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;QACjD,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;QACrD,qDAAqD;QACrD,MAAM,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAC;QACtD,MAAM,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC,oBAAoB,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC;IACxE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6DAA6D,EAAE,KAAK,IAAI,EAAE;QAC3E,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC,iBAAiB,CAAC,iBAAiB,CAAC,CAAC;QAEvE,UAAU,CAAC,GAAG,EAAE,CAAC,oBAAoB,CAAC,WAAW,EAAE,YAAY,CAAC,CAAC,CAAC;QAElE,MAAM,GAAG,CAAC,KAAK,IAAI,EAAE;YACnB,MAAM,IAAI,CAAC,yBAAyB,EAAE,CAAC;QACzC,CAAC,CAAC,CAAC;QAEH,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACpE,MAAM,kBAAkB,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QAC9D,MAAM,YAAY,GAAG,IAAI,eAAe,CAAC,kBAAkB,CAAC,CAAC;QAE7D,MAAM,CAAC,YAAY,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CACzC,iDAAiD,CAClD,CAAC;QACF,MAAM,CAAC,YAAY,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QAC7D,MAAM,CAAC,YAAY,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC,CAAC,IAAI,CACjD,+CAA+C,CAChD,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mCAAmC,EAAE,KAAK,IAAI,EAAE;QACjD,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC,iBAAiB,CAAC,iBAAiB,CAAC,CAAC;QAEvE,MAAM,EAAE,MAAM,EAAE,GAAG,UAAU,CAAC,GAAG,EAAE,CACjC,oBAAoB,CAAC,WAAW,EAAE,YAAY,CAAC,CAChD,CAAC;QAEF,MAAM,GAAG,CAAC,KAAK,IAAI,EAAE;YACnB,MAAM,IAAI,CAAC,yBAAyB,EAAE,CAAC;QACzC,CAAC,CAAC,CAAC;QAEH,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;QACjD,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;IACvD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yCAAyC,EAAE,KAAK,IAAI,EAAE;QACvD,MAAM,mBAAmB,GAAG;YAC1B,YAAY,EAAE,qBAAqB;YACnC,UAAU,EAAE,IAAI,EAAE,UAAU;YAC5B,UAAU,EAAE,QAAQ;SACrB,CAAC;QAEF,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC,iBAAiB,CAAC,mBAAmB,CAAC,CAAC;QAEzE,MAAM,EAAE,MAAM,EAAE,GAAG,UAAU,CAAC,GAAG,EAAE,CACjC,oBAAoB,CAAC,WAAW,EAAE,YAAY,CAAC,CAChD,CAAC;QAEF,MAAM,GAAG,CAAC,KAAK,IAAI,EAAE;YACnB,MAAM,IAAI,CAAC,yBAAyB,EAAE,CAAC;QACzC,CAAC,CAAC,CAAC;QAEH,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC;QACnD,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC;IACzD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4DAA4D,EAAE,KAAK,IAAI,EAAE;QAC1E,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC,iBAAiB,CAAC,iBAAiB,CAAC,CAAC;QAEvE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,UAAU,CACrC,CAAC,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC,oBAAoB,CAAC,WAAW,EAAE,SAAS,CAAC,EAC/D;YACE,YAAY,EAAE,EAAE,SAAS,EAAE,YAAkC,EAAE;SAChE,CACF,CAAC;QAEF,MAAM,GAAG,CAAC,KAAK,IAAI,EAAE;YACnB,MAAM,IAAI,CAAC,yBAAyB,EAAE,CAAC;QACzC,CAAC,CAAC,CAAC;QAEH,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;QACjD,MAAM,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAC;QAEtD,+CAA+C;QAC/C,IAAI,CAAC,aAAa,EAAE,CAAC;QAErB,GAAG,CAAC,GAAG,EAAE;YACP,QAAQ,CAAC,EAAE,SAAS,EAAE,SAAS,EAAE,CAAC,CAAC;QACrC,CAAC,CAAC,CAAC;QAEH,MAAM,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAC;IACtD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6CAA6C,EAAE,KAAK,IAAI,EAAE;QAC3D,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC,iBAAiB,CAAC,iBAAiB,CAAC,CAAC;QAEvE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,UAAU,CACrC,CAAC,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC,oBAAoB,CAAC,WAAW,EAAE,SAAS,CAAC,EAC/D;YACE,YAAY,EAAE,EAAE,SAAS,EAAE,cAAc,EAAE;SAC5C,CACF,CAAC;QAEF,MAAM,GAAG,CAAC,KAAK,IAAI,EAAE;YACnB,MAAM,IAAI,CAAC,yBAAyB,EAAE,CAAC;QACzC,CAAC,CAAC,CAAC;QAEH,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;QACjD,MAAM,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAC;QAEtD,8BAA8B;QAC9B,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC,iBAAiB,CAAC;YAClD,GAAG,iBAAiB;YACpB,YAAY,EAAE,kBAAkB;SACjC,CAAC,CAAC;QAEH,mBAAmB;QACnB,GAAG,CAAC,GAAG,EAAE;YACP,QAAQ,CAAC,EAAE,SAAS,EAAE,cAAc,EAAE,CAAC,CAAC;QAC1C,CAAC,CAAC,CAAC;QAEH,MAAM,GAAG,CAAC,KAAK,IAAI,EAAE;YACnB,MAAM,IAAI,CAAC,yBAAyB,EAAE,CAAC;QACzC,CAAC,CAAC,CAAC;QAEH,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;QAChD,MAAM,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAC;IACxD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gDAAgD,EAAE,KAAK,IAAI,EAAE;QAC9D,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC,iBAAiB,CAAC,iBAAiB,CAAC,CAAC;QAEvE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,UAAU,CACrC,CAAC,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC,oBAAoB,CAAC,WAAW,EAAE,SAAS,CAAC,EAC/D;YACE,YAAY,EAAE,EAAE,SAAS,EAAE,YAAkC,EAAE;SAChE,CACF,CAAC;QAEF,MAAM,GAAG,CAAC,KAAK,IAAI,EAAE;YACnB,MAAM,IAAI,CAAC,yBAAyB,EAAE,CAAC;QACzC,CAAC,CAAC,CAAC;QAEH,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;QAEjD,gCAAgC;QAChC,GAAG,CAAC,GAAG,EAAE;YACP,QAAQ,CAAC,EAAE,SAAS,EAAE,SAAS,EAAE,CAAC,CAAC;QACrC,CAAC,CAAC,CAAC;QAEH,2FAA2F;QAC3F,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;IACnD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sEAAsE,EAAE,KAAK,IAAI,EAAE;QACpF,IAAI,cAAoC,CAAC;QACzC,MAAM,OAAO,GAAG,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;YACtC,cAAc,GAAG,OAAO,CAAC;QAC3B,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC;QAE3D,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,UAAU,CAAC,GAAG,EAAE,CAC1C,oBAAoB,CAAC,WAAW,EAAE,YAAY,CAAC,CAChD,CAAC;QAEF,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,QAAQ,EAAE,CAAC;QAElC,sCAAsC;QACtC,OAAO,EAAE,CAAC;QAEV,0BAA0B;QAC1B,GAAG,CAAC,GAAG,EAAE;YACP,cAAe,CAAC,iBAAiB,CAAC,CAAC;QACrC,CAAC,CAAC,CAAC;QAEH,2DAA2D;QAC3D,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,QAAQ,EAAE,CAAC;IACpC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC","sourcesContent":["import TamboAI from \"@tambo-ai/typescript-sdk\";\nimport { act, renderHook } from \"@testing-library/react\";\nimport { DeepPartial } from \"ts-essentials\";\nimport { useTamboSessionToken } from \"../use-tambo-session-token\";\n\ntype PartialTamboAI = DeepPartial<TamboAI>;\n\ndescribe(\"useTamboSessionToken\", () => {\n const mockTokenResponse = {\n access_token: \"test-access-token\",\n expires_in: 3600, // 1 hour\n token_type: \"Bearer\",\n };\n\n const mockAuthApi = {\n getToken: jest.fn(),\n } satisfies DeepPartial<TamboAI[\"beta\"][\"auth\"]>;\n\n const mockBeta = {\n auth: mockAuthApi,\n } satisfies PartialTamboAI[\"beta\"];\n\n const mockTamboAI = {\n apiKey: \"\",\n beta: mockBeta,\n bearer: \"\",\n } satisfies PartialTamboAI as unknown as TamboAI;\n\n beforeEach(() => {\n jest.clearAllMocks();\n jest.clearAllTimers();\n jest.useFakeTimers();\n (mockTamboAI as any).bearer = \"\";\n });\n\n afterEach(() => {\n jest.runOnlyPendingTimers();\n jest.useRealTimers();\n });\n\n it(\"should return null initially when no userToken is provided\", () => {\n const { result } = renderHook(() =>\n useTamboSessionToken(mockTamboAI, undefined),\n );\n\n expect(result.current).toBeNull();\n expect(mockAuthApi.getToken).not.toHaveBeenCalled();\n });\n\n it(\"should fetch and return session token when userToken is provided\", async () => {\n jest.mocked(mockAuthApi.getToken).mockResolvedValue(mockTokenResponse);\n\n const { result } = renderHook(() =>\n useTamboSessionToken(mockTamboAI, \"user-token\"),\n );\n\n await act(async () => {\n await jest.runOnlyPendingTimersAsync();\n });\n\n expect(result.current).toBe(\"test-access-token\");\n expect(mockTamboAI.bearer).toBe(\"test-access-token\");\n // Verify the hook was called with correct parameters\n expect(mockAuthApi.getToken).toHaveBeenCalledTimes(1);\n expect(mockAuthApi.getToken).toHaveBeenCalledWith(expect.any(Object));\n });\n\n it(\"should call getToken with correct token exchange parameters\", async () => {\n jest.mocked(mockAuthApi.getToken).mockResolvedValue(mockTokenResponse);\n\n renderHook(() => useTamboSessionToken(mockTamboAI, \"user-token\"));\n\n await act(async () => {\n await jest.runOnlyPendingTimersAsync();\n });\n\n const callArgs = jest.mocked(mockAuthApi.getToken).mock.calls[0][0];\n const tokenRequestString = new TextDecoder().decode(callArgs);\n const tokenRequest = new URLSearchParams(tokenRequestString);\n\n expect(tokenRequest.get(\"grant_type\")).toBe(\n \"urn:ietf:params:oauth:grant-type:token-exchange\",\n );\n expect(tokenRequest.get(\"subject_token\")).toBe(\"user-token\");\n expect(tokenRequest.get(\"subject_token_type\")).toBe(\n \"urn:ietf:params:oauth:token-type:access_token\",\n );\n });\n\n it(\"should set bearer token on client\", async () => {\n jest.mocked(mockAuthApi.getToken).mockResolvedValue(mockTokenResponse);\n\n const { result } = renderHook(() =>\n useTamboSessionToken(mockTamboAI, \"user-token\"),\n );\n\n await act(async () => {\n await jest.runOnlyPendingTimersAsync();\n });\n\n expect(result.current).toBe(\"test-access-token\");\n expect(mockTamboAI.bearer).toBe(\"test-access-token\");\n });\n\n it(\"should handle different token responses\", async () => {\n const customTokenResponse = {\n access_token: \"custom-access-token\",\n expires_in: 7200, // 2 hours\n token_type: \"Bearer\",\n };\n\n jest.mocked(mockAuthApi.getToken).mockResolvedValue(customTokenResponse);\n\n const { result } = renderHook(() =>\n useTamboSessionToken(mockTamboAI, \"user-token\"),\n );\n\n await act(async () => {\n await jest.runOnlyPendingTimersAsync();\n });\n\n expect(result.current).toBe(\"custom-access-token\");\n expect(mockTamboAI.bearer).toBe(\"custom-access-token\");\n });\n\n it(\"should not fetch token when userToken changes to undefined\", async () => {\n jest.mocked(mockAuthApi.getToken).mockResolvedValue(mockTokenResponse);\n\n const { result, rerender } = renderHook(\n ({ userToken }) => useTamboSessionToken(mockTamboAI, userToken),\n {\n initialProps: { userToken: \"user-token\" as string | undefined },\n },\n );\n\n await act(async () => {\n await jest.runOnlyPendingTimersAsync();\n });\n\n expect(result.current).toBe(\"test-access-token\");\n expect(mockAuthApi.getToken).toHaveBeenCalledTimes(1);\n\n // Clear mock and change userToken to undefined\n jest.clearAllMocks();\n\n act(() => {\n rerender({ userToken: undefined });\n });\n\n expect(mockAuthApi.getToken).not.toHaveBeenCalled();\n });\n\n it(\"should refetch token when userToken changes\", async () => {\n jest.mocked(mockAuthApi.getToken).mockResolvedValue(mockTokenResponse);\n\n const { result, rerender } = renderHook(\n ({ userToken }) => useTamboSessionToken(mockTamboAI, userToken),\n {\n initialProps: { userToken: \"user-token-1\" },\n },\n );\n\n await act(async () => {\n await jest.runOnlyPendingTimersAsync();\n });\n\n expect(result.current).toBe(\"test-access-token\");\n expect(mockAuthApi.getToken).toHaveBeenCalledTimes(1);\n\n // Mock response for new token\n jest.mocked(mockAuthApi.getToken).mockResolvedValue({\n ...mockTokenResponse,\n access_token: \"new-access-token\",\n });\n\n // Change userToken\n act(() => {\n rerender({ userToken: \"user-token-2\" });\n });\n\n await act(async () => {\n await jest.runOnlyPendingTimersAsync();\n });\n\n expect(result.current).toBe(\"new-access-token\");\n expect(mockAuthApi.getToken).toHaveBeenCalledTimes(2);\n });\n\n it(\"should reset token when userToken becomes null\", async () => {\n jest.mocked(mockAuthApi.getToken).mockResolvedValue(mockTokenResponse);\n\n const { result, rerender } = renderHook(\n ({ userToken }) => useTamboSessionToken(mockTamboAI, userToken),\n {\n initialProps: { userToken: \"user-token\" as string | undefined },\n },\n );\n\n await act(async () => {\n await jest.runOnlyPendingTimersAsync();\n });\n\n expect(result.current).toBe(\"test-access-token\");\n\n // Change userToken to undefined\n act(() => {\n rerender({ userToken: undefined });\n });\n\n // Token should remain the same (hook doesn't reset it to null when userToken is undefined)\n expect(result.current).toBe(\"test-access-token\");\n });\n\n it(\"should not update state if component is unmounted during token fetch\", async () => {\n let resolvePromise: (value: any) => void;\n const promise = new Promise((resolve) => {\n resolvePromise = resolve;\n });\n\n jest.mocked(mockAuthApi.getToken).mockReturnValue(promise);\n\n const { result, unmount } = renderHook(() =>\n useTamboSessionToken(mockTamboAI, \"user-token\"),\n );\n\n expect(result.current).toBeNull();\n\n // Unmount before the promise resolves\n unmount();\n\n // Now resolve the promise\n act(() => {\n resolvePromise!(mockTokenResponse);\n });\n\n // Token should still be null since component was unmounted\n expect(result.current).toBeNull();\n });\n});\n"]}
1
+ {"version":3,"file":"use-tambo-session-token.test.js","sourceRoot":"","sources":["../../../../src/providers/hooks/__tests__/use-tambo-session-token.test.tsx"],"names":[],"mappings":"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","sourcesContent":["import TamboAI from \"@tambo-ai/typescript-sdk\";\nimport { QueryClient } from \"@tanstack/react-query\";\nimport { act, renderHook } from \"@testing-library/react\";\nimport { DeepPartial } from \"ts-essentials\";\nimport { useTamboSessionToken } from \"../use-tambo-session-token\";\n\ntype PartialTamboAI = DeepPartial<TamboAI>;\n\ndescribe(\"useTamboSessionToken\", () => {\n const mockTokenResponse = {\n access_token: \"test-access-token\",\n expires_in: 3600, // 1 hour\n token_type: \"Bearer\",\n };\n\n const mockAuthApi = {\n getToken: jest.fn(),\n } satisfies DeepPartial<TamboAI[\"beta\"][\"auth\"]>;\n\n const mockBeta = {\n auth: mockAuthApi,\n } satisfies PartialTamboAI[\"beta\"];\n\n const mockTamboAI = {\n apiKey: \"\",\n beta: mockBeta,\n bearer: \"\",\n } satisfies PartialTamboAI as unknown as TamboAI;\n const queryClient = new QueryClient({\n defaultOptions: {\n queries: {\n retry: false,\n refetchOnWindowFocus: false,\n },\n },\n });\n\n beforeEach(() => {\n jest.clearAllMocks();\n jest.clearAllTimers();\n jest.useFakeTimers();\n (mockTamboAI as any).bearer = \"\";\n queryClient.clear();\n });\n\n afterEach(async () => {\n await act(async () => {\n await jest.runOnlyPendingTimersAsync();\n });\n jest.useRealTimers();\n jest.resetAllMocks();\n });\n\n it(\"should return null initially when no userToken is provided\", () => {\n const { result } = renderHook(() =>\n useTamboSessionToken(mockTamboAI, queryClient, undefined),\n );\n\n expect(result.current).toMatchObject({\n data: undefined,\n isFetching: false,\n });\n expect(mockAuthApi.getToken).not.toHaveBeenCalled();\n });\n\n it(\"should fetch and return session token when userToken is provided\", async () => {\n mockAuthApi.getToken.mockResolvedValue(mockTokenResponse);\n\n const { result } = renderHook(() =>\n useTamboSessionToken(mockTamboAI, queryClient, \"user-token\"),\n );\n expect(mockAuthApi.getToken).toHaveBeenCalledTimes(1);\n\n await act(async () => {\n await jest.runOnlyPendingTimersAsync();\n });\n\n expect(result.current).toMatchObject({\n data: mockTokenResponse,\n isFetching: false,\n });\n expect(mockTamboAI.bearer).toBe(mockTokenResponse.access_token);\n // Verify the hook was called with correct parameters\n expect(mockAuthApi.getToken).toHaveBeenCalledTimes(2);\n expect(mockAuthApi.getToken).toHaveBeenCalledWith(expect.any(Object));\n });\n\n it(\"should call getToken with correct token exchange parameters\", async () => {\n mockAuthApi.getToken.mockResolvedValue(mockTokenResponse);\n\n renderHook(() =>\n useTamboSessionToken(mockTamboAI, queryClient, \"user-token\"),\n );\n\n await act(async () => {\n await jest.runOnlyPendingTimersAsync();\n });\n\n const callArgs = mockAuthApi.getToken.mock.calls[0][0];\n const tokenRequestString = new TextDecoder().decode(callArgs);\n const tokenRequest = new URLSearchParams(tokenRequestString);\n\n expect(tokenRequest.get(\"grant_type\")).toBe(\n \"urn:ietf:params:oauth:grant-type:token-exchange\",\n );\n expect(tokenRequest.get(\"subject_token\")).toBe(\"user-token\");\n expect(tokenRequest.get(\"subject_token_type\")).toBe(\n \"urn:ietf:params:oauth:token-type:access_token\",\n );\n });\n\n it(\"should set bearer token on client\", async () => {\n mockAuthApi.getToken.mockResolvedValue(mockTokenResponse);\n\n const { result } = renderHook(() =>\n useTamboSessionToken(mockTamboAI, queryClient, \"user-token\"),\n );\n\n await act(async () => {\n await jest.runOnlyPendingTimersAsync();\n });\n\n expect(result.current).toMatchObject({\n data: mockTokenResponse,\n });\n expect(mockTamboAI.bearer).toBe(\"test-access-token\");\n });\n\n it(\"should handle different token responses\", async () => {\n const customTokenResponse = {\n access_token: \"custom-access-token\",\n expires_in: 7200, // 2 hours\n token_type: \"Bearer\",\n };\n\n mockAuthApi.getToken.mockResolvedValue(customTokenResponse);\n\n const { result } = renderHook(() =>\n useTamboSessionToken(mockTamboAI, queryClient, \"user-token\"),\n );\n expect(result.current).toMatchObject({\n data: undefined,\n isFetching: true,\n });\n\n await act(async () => {\n await jest.runOnlyPendingTimersAsync();\n });\n\n expect(result.current).toMatchObject({\n data: customTokenResponse,\n isFetching: false,\n });\n expect(mockTamboAI.bearer).toBe(\"custom-access-token\");\n });\n\n it(\"should not fetch token when userToken changes to undefined\", async () => {\n mockAuthApi.getToken.mockResolvedValue(mockTokenResponse);\n\n const { result, rerender } = renderHook(\n ({ userToken }) =>\n useTamboSessionToken(mockTamboAI, queryClient, userToken),\n {\n initialProps: { userToken: \"user-token\" as string | undefined },\n },\n );\n expect(mockAuthApi.getToken).toHaveBeenCalledTimes(1);\n\n await act(async () => {\n await jest.runOnlyPendingTimersAsync();\n });\n\n expect(result.current).toMatchObject({\n data: mockTokenResponse,\n isFetching: false,\n });\n expect(mockAuthApi.getToken).toHaveBeenCalledTimes(2);\n\n // Clear mock and change userToken to undefined\n jest.clearAllMocks();\n\n act(() => {\n rerender({ userToken: undefined });\n });\n\n expect(mockAuthApi.getToken).not.toHaveBeenCalled();\n });\n\n it(\"should refetch token when userToken changes\", async () => {\n mockAuthApi.getToken.mockResolvedValue(mockTokenResponse);\n\n const { result, rerender } = renderHook(\n ({ userToken }) =>\n useTamboSessionToken(mockTamboAI, queryClient, userToken),\n {\n initialProps: { userToken: \"user-token-1\" },\n },\n );\n expect(mockAuthApi.getToken).toHaveBeenCalledTimes(1);\n\n await act(async () => {\n await jest.runOnlyPendingTimersAsync();\n });\n\n expect(result.current).toMatchObject({\n data: mockTokenResponse,\n isFetching: false,\n });\n expect(mockAuthApi.getToken).toHaveBeenCalledTimes(2);\n\n // Mock response for new token\n mockAuthApi.getToken.mockResolvedValue({\n ...mockTokenResponse,\n access_token: \"new-access-token\",\n });\n\n // Change userToken\n act(() => {\n rerender({ userToken: \"user-token-2\" });\n });\n\n await act(async () => {\n await jest.runOnlyPendingTimersAsync();\n });\n\n expect(result.current).toMatchObject({\n data: { access_token: \"new-access-token\" },\n isFetching: false,\n });\n expect(mockAuthApi.getToken).toHaveBeenCalledTimes(4);\n });\n\n it(\"should reset token when userToken becomes null\", async () => {\n mockAuthApi.getToken.mockResolvedValue(mockTokenResponse);\n\n const { result, rerender } = renderHook(\n ({ userToken }) =>\n useTamboSessionToken(mockTamboAI, queryClient, userToken),\n {\n initialProps: { userToken: \"user-token\" as string | undefined },\n },\n );\n\n await act(async () => {\n await jest.runOnlyPendingTimersAsync();\n });\n\n expect(result.current).toMatchObject({\n data: mockTokenResponse,\n isFetching: false,\n });\n\n // Change userToken to undefined\n rerender({ userToken: undefined });\n await act(async () => {\n await jest.runAllTimersAsync();\n });\n\n // Token should reset to null (hook doesn't reset it to null when userToken is undefined)\n expect(result.current).toMatchObject({\n data: undefined,\n isFetching: false,\n });\n });\n\n it(\"should not update state if component is unmounted during token fetch\", async () => {\n let resolvePromise: (value: any) => void;\n const promise = new Promise((resolve) => {\n resolvePromise = resolve;\n });\n\n mockAuthApi.getToken.mockReturnValue(promise);\n\n const { result, unmount } = renderHook(() =>\n useTamboSessionToken(mockTamboAI, queryClient, \"user-token\"),\n );\n\n expect(result.current).toMatchObject({\n data: undefined,\n isFetching: true,\n });\n\n // Unmount before the promise resolves\n unmount();\n\n // Now resolve the promise\n act(() => {\n resolvePromise!(mockTokenResponse);\n });\n\n // Token should still be null since component was unmounted\n expect(result.current).toMatchObject({\n data: undefined,\n isFetching: true,\n });\n });\n\n it(\"should set isUpdating to true while fetching token\", () => {\n mockAuthApi.getToken.mockImplementation(async () => {\n return await new Promise(() => {}); // Never resolves\n });\n\n const { result } = renderHook(() =>\n useTamboSessionToken(mockTamboAI, queryClient, \"user-token\"),\n );\n\n // Should be updating immediately when userToken is provided\n expect(result.current).toMatchObject({\n data: undefined,\n isFetching: true,\n });\n });\n\n it(\"should set isUpdating to false after token fetch completes\", async () => {\n mockAuthApi.getToken.mockResolvedValue(mockTokenResponse);\n\n const { result } = renderHook(() =>\n useTamboSessionToken(mockTamboAI, queryClient, \"user-token\"),\n );\n\n // Should be updating initially\n expect(result.current).toMatchObject({\n data: undefined,\n isFetching: true,\n });\n\n await act(async () => {\n await jest.runOnlyPendingTimersAsync();\n });\n\n // Should not be updating after completion\n expect(result.current).toMatchObject({\n data: mockTokenResponse,\n isFetching: false,\n });\n });\n\n it(\"should set isUpdating to false after token fetch fails\", async () => {\n mockAuthApi.getToken.mockRejectedValue(new Error(\"Token fetch failed\"));\n\n const { result } = renderHook(() =>\n useTamboSessionToken(mockTamboAI, queryClient, \"user-token\"),\n );\n\n // Should be updating initially\n expect(result.current).toMatchObject({\n data: undefined,\n isFetching: true,\n });\n\n await act(async () => {\n await jest.runAllTimersAsync();\n });\n\n // Should not be updating after failure\n expect(result.current).toMatchObject({\n data: undefined,\n error: expect.any(Error),\n isFetching: false,\n });\n });\n});\n"]}
@@ -1,4 +1,5 @@
1
1
  import TamboAI from "@tambo-ai/typescript-sdk";
2
+ import { QueryClient } from "@tanstack/react-query";
2
3
  /**
3
4
  * This internal hook is used to get the Tambo session token and keep it
4
5
  * refreshed.
@@ -8,8 +9,9 @@ import TamboAI from "@tambo-ai/typescript-sdk";
8
9
  *
9
10
  * This hook is used by the TamboClientProvider.
10
11
  * @param client - The Tambo client.
12
+ * @param queryClient - The query client.
11
13
  * @param userToken - The user token.
12
14
  * @returns The Tambo session token.
13
15
  */
14
- export declare function useTamboSessionToken(client: TamboAI, userToken: string | undefined): string | null;
16
+ export declare function useTamboSessionToken(client: TamboAI, queryClient: QueryClient, userToken: string | undefined): import("@tanstack/react-query").UseQueryResult<TamboAI.Beta.Auth.AuthGetTokenResponse, Error>;
15
17
  //# sourceMappingURL=use-tambo-session-token.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"use-tambo-session-token.d.ts","sourceRoot":"","sources":["../../../src/providers/hooks/use-tambo-session-token.tsx"],"names":[],"mappings":"AACA,OAAO,OAAO,MAAM,0BAA0B,CAAC;AAG/C;;;;;;;;;;;GAWG;AACH,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,OAAO,EACf,SAAS,EAAE,MAAM,GAAG,SAAS,iBAiE9B"}
1
+ {"version":3,"file":"use-tambo-session-token.d.ts","sourceRoot":"","sources":["../../../src/providers/hooks/use-tambo-session-token.tsx"],"names":[],"mappings":"AACA,OAAO,OAAO,MAAM,0BAA0B,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAY,MAAM,uBAAuB,CAAC;AAG9D;;;;;;;;;;;;GAYG;AACH,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,OAAO,EACf,WAAW,EAAE,WAAW,EACxB,SAAS,EAAE,MAAM,GAAG,SAAS,iGAmC9B"}
@@ -1,5 +1,6 @@
1
1
  "use client";
2
- import { useEffect, useState } from "react";
2
+ import { useQuery } from "@tanstack/react-query";
3
+ import { useEffect } from "react";
3
4
  /**
4
5
  * This internal hook is used to get the Tambo session token and keep it
5
6
  * refreshed.
@@ -9,54 +10,36 @@ import { useEffect, useState } from "react";
9
10
  *
10
11
  * This hook is used by the TamboClientProvider.
11
12
  * @param client - The Tambo client.
13
+ * @param queryClient - The query client.
12
14
  * @param userToken - The user token.
13
15
  * @returns The Tambo session token.
14
16
  */
15
- export function useTamboSessionToken(client, userToken) {
16
- const [tamboSessionToken, setTamboSessionToken] = useState(null);
17
- // we need to set this to true when the token is expired, this is effectively
18
- // like a dirty bit, which will trigger a new useEffect()
19
- const [isExpired, setIsExpired] = useState(true);
20
- useEffect(() => {
21
- let expireTimer = null;
22
- async function updateToken(subjectToken, abortController) {
23
- if (abortController.signal.aborted || !userToken) {
24
- return;
25
- }
17
+ export function useTamboSessionToken(client, queryClient, userToken) {
18
+ const result = useQuery({
19
+ queryKey: ["tambo-session-token", userToken],
20
+ queryFn: async () => {
26
21
  const tokenRequest = {
27
22
  grant_type: "urn:ietf:params:oauth:grant-type:token-exchange",
28
- subject_token: subjectToken,
23
+ // will only be undefined if the userToken is not provided, in which case the query will be disabled.
24
+ subject_token: userToken,
29
25
  subject_token_type: "urn:ietf:params:oauth:token-type:access_token",
30
26
  };
31
27
  const tokenRequestFormEncoded = new URLSearchParams(tokenRequest).toString();
32
28
  const tokenAsArrayBuffer = new TextEncoder().encode(tokenRequestFormEncoded);
33
- const tamboToken = await client.beta.auth.getToken(tokenAsArrayBuffer);
34
- if (abortController.signal.aborted) {
35
- return;
29
+ return await client.beta.auth.getToken(tokenAsArrayBuffer);
30
+ },
31
+ enabled: !!userToken,
32
+ refetchInterval: (result) => {
33
+ if (result.state.data?.expires_in) {
34
+ return result.state.data.expires_in * 1000;
36
35
  }
37
- setTamboSessionToken(tamboToken.access_token);
38
- client.bearer = tamboToken.access_token;
39
- // we need to set a timer to refresh the token when it expires
40
- const refreshTime = Math.max(tamboToken.expires_in - 60, 0);
41
- // careful with the assignment here: since this is an async function, this
42
- // code is executed outside the of the scope of the useEffect() hook, so
43
- // we need to use a let variable to store the timer
44
- expireTimer = setTimeout(() => {
45
- setIsExpired(true);
46
- }, refreshTime * 1000);
47
- }
48
- const abortController = new AbortController();
49
- if (userToken && isExpired) {
50
- updateToken(userToken, abortController);
51
- }
52
- return () => {
53
- // This fires when the component unmounts or the userToken changes
54
- abortController.abort();
55
- if (expireTimer) {
56
- clearTimeout(expireTimer);
57
- }
58
- };
59
- }, [client, isExpired, userToken]);
60
- return tamboSessionToken;
36
+ return false;
37
+ },
38
+ }, queryClient);
39
+ const accessToken = result.data?.access_token ?? null;
40
+ useEffect(() => {
41
+ client.bearer = accessToken;
42
+ }, [accessToken, client]);
43
+ return result;
61
44
  }
62
45
  //# sourceMappingURL=use-tambo-session-token.js.map