@athenaintel/react 0.42.1 → 0.43.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 (147) hide show
  1. package/README.md +46 -7
  2. package/dist/agent-runtime/src/conversation-list-groups.d.ts +74 -0
  3. package/dist/agent-runtime/src/index.d.ts +3 -2
  4. package/dist/agent-runtime/src/messages.cjs +38 -7
  5. package/dist/agent-runtime/src/messages.cjs.map +1 -1
  6. package/dist/agent-runtime/src/messages.d.ts +26 -8
  7. package/dist/agent-runtime/src/messages.js +38 -7
  8. package/dist/agent-runtime/src/messages.js.map +1 -1
  9. package/dist/agent-runtime/src/quota-safe-local-storage-session.cjs +10 -0
  10. package/dist/agent-runtime/src/quota-safe-local-storage-session.cjs.map +1 -1
  11. package/dist/agent-runtime/src/quota-safe-local-storage-session.d.ts +7 -0
  12. package/dist/agent-runtime/src/quota-safe-local-storage-session.js +10 -0
  13. package/dist/agent-runtime/src/quota-safe-local-storage-session.js.map +1 -1
  14. package/dist/agent-runtime/src/session-lane-scope.cjs +25 -0
  15. package/dist/agent-runtime/src/session-lane-scope.cjs.map +1 -0
  16. package/dist/agent-runtime/src/session-lane-scope.d.ts +59 -0
  17. package/dist/agent-runtime/src/session-lane-scope.js +25 -0
  18. package/dist/agent-runtime/src/session-lane-scope.js.map +1 -0
  19. package/dist/agent-runtime/src/subagent-transcripts.cjs +2 -2
  20. package/dist/agent-runtime/src/subagent-transcripts.cjs.map +1 -1
  21. package/dist/agent-runtime/src/subagent-transcripts.d.ts +2 -2
  22. package/dist/agent-runtime/src/subagent-transcripts.js +3 -3
  23. package/dist/agent-runtime/src/subagent-transcripts.js.map +1 -1
  24. package/dist/agent-runtime/src/tool-metadata.cjs +0 -8
  25. package/dist/agent-runtime/src/tool-metadata.cjs.map +1 -1
  26. package/dist/agent-runtime/src/tool-metadata.js +0 -8
  27. package/dist/agent-runtime/src/tool-metadata.js.map +1 -1
  28. package/dist/agent-runtime/src/tool-names.cjs +4 -0
  29. package/dist/agent-runtime/src/tool-names.cjs.map +1 -1
  30. package/dist/agent-runtime/src/tool-names.d.ts +7 -0
  31. package/dist/agent-runtime/src/tool-names.js +4 -0
  32. package/dist/agent-runtime/src/tool-names.js.map +1 -1
  33. package/dist/agent-runtime/src/use-deep-agent-runtime.cjs +18 -1
  34. package/dist/agent-runtime/src/use-deep-agent-runtime.cjs.map +1 -1
  35. package/dist/agent-runtime/src/use-deep-agent-runtime.d.ts +19 -10
  36. package/dist/agent-runtime/src/use-deep-agent-runtime.js +19 -2
  37. package/dist/agent-runtime/src/use-deep-agent-runtime.js.map +1 -1
  38. package/dist/agent-runtime/src/use-deep-agent-thread.cjs +28 -10
  39. package/dist/agent-runtime/src/use-deep-agent-thread.cjs.map +1 -1
  40. package/dist/agent-runtime/src/use-deep-agent-thread.d.ts +35 -3
  41. package/dist/agent-runtime/src/use-deep-agent-thread.js +28 -10
  42. package/dist/agent-runtime/src/use-deep-agent-thread.js.map +1 -1
  43. package/dist/agent-runtime/src/use-deep-agent-voice.cjs +50 -15
  44. package/dist/agent-runtime/src/use-deep-agent-voice.cjs.map +1 -1
  45. package/dist/agent-runtime/src/use-deep-agent-voice.d.ts +8 -0
  46. package/dist/agent-runtime/src/use-deep-agent-voice.js +50 -15
  47. package/dist/agent-runtime/src/use-deep-agent-voice.js.map +1 -1
  48. package/dist/agent-runtime/src/voice-presentation.cjs +2 -0
  49. package/dist/agent-runtime/src/voice-presentation.cjs.map +1 -1
  50. package/dist/agent-runtime/src/voice-presentation.js +2 -0
  51. package/dist/agent-runtime/src/voice-presentation.js.map +1 -1
  52. package/dist/catalog/runtime-catalog.js +1 -1
  53. package/dist/chat/AthenaChat.cjs +125 -103
  54. package/dist/chat/AthenaChat.cjs.map +1 -1
  55. package/dist/chat/AthenaChat.d.ts +9 -0
  56. package/dist/chat/AthenaChat.js +126 -104
  57. package/dist/chat/AthenaChat.js.map +1 -1
  58. package/dist/chat/chat-voice-controls.cjs +128 -0
  59. package/dist/chat/chat-voice-controls.cjs.map +1 -0
  60. package/dist/chat/chat-voice-controls.d.ts +19 -0
  61. package/dist/chat/chat-voice-controls.js +128 -0
  62. package/dist/chat/chat-voice-controls.js.map +1 -0
  63. package/dist/chat/super-grouping/SuperGroupingCard.cjs +8 -2
  64. package/dist/chat/super-grouping/SuperGroupingCard.cjs.map +1 -1
  65. package/dist/chat/super-grouping/SuperGroupingCard.d.ts +6 -1
  66. package/dist/chat/super-grouping/SuperGroupingCard.js +8 -2
  67. package/dist/chat/super-grouping/SuperGroupingCard.js.map +1 -1
  68. package/dist/chat/super-grouping/ToolTimeline.cjs +27 -0
  69. package/dist/chat/super-grouping/ToolTimeline.cjs.map +1 -1
  70. package/dist/chat/super-grouping/ToolTimeline.d.ts +5 -1
  71. package/dist/chat/super-grouping/ToolTimeline.js +27 -0
  72. package/dist/chat/super-grouping/ToolTimeline.js.map +1 -1
  73. package/dist/chat/super-grouping/index.d.ts +1 -0
  74. package/dist/chat/super-grouping/timeline-step.cjs +61 -2
  75. package/dist/chat/super-grouping/timeline-step.cjs.map +1 -1
  76. package/dist/chat/super-grouping/timeline-step.d.ts +13 -1
  77. package/dist/chat/super-grouping/timeline-step.js +61 -2
  78. package/dist/chat/super-grouping/timeline-step.js.map +1 -1
  79. package/dist/chat/use-statewire-approval-request.js +1 -1
  80. package/dist/chat-ui/composer/tiptap-composer.cjs +42 -22
  81. package/dist/chat-ui/composer/tiptap-composer.cjs.map +1 -1
  82. package/dist/chat-ui/composer/tiptap-composer.d.ts +1 -0
  83. package/dist/chat-ui/composer/tiptap-composer.js +43 -23
  84. package/dist/chat-ui/composer/tiptap-composer.js.map +1 -1
  85. package/dist/chat-ui/mentions/mention-chip.cjs +144 -35
  86. package/dist/chat-ui/mentions/mention-chip.cjs.map +1 -1
  87. package/dist/chat-ui/mentions/mention-chip.d.ts +17 -1
  88. package/dist/chat-ui/mentions/mention-chip.js +146 -37
  89. package/dist/chat-ui/mentions/mention-chip.js.map +1 -1
  90. package/dist/chat-ui/mentions/suggestions/data/api-client.cjs +2 -1
  91. package/dist/chat-ui/mentions/suggestions/data/api-client.cjs.map +1 -1
  92. package/dist/chat-ui/mentions/suggestions/data/api-client.d.ts +3 -1
  93. package/dist/chat-ui/mentions/suggestions/data/api-client.js +2 -1
  94. package/dist/chat-ui/mentions/suggestions/data/api-client.js.map +1 -1
  95. package/dist/chat-ui/mentions/use-account-workspace-id.cjs +29 -51
  96. package/dist/chat-ui/mentions/use-account-workspace-id.cjs.map +1 -1
  97. package/dist/chat-ui/mentions/use-account-workspace-id.d.ts +2 -2
  98. package/dist/chat-ui/mentions/use-account-workspace-id.js +30 -52
  99. package/dist/chat-ui/mentions/use-account-workspace-id.js.map +1 -1
  100. package/dist/chat-ui/mentions/use-mention-asset.cjs +140 -0
  101. package/dist/chat-ui/mentions/use-mention-asset.cjs.map +1 -0
  102. package/dist/chat-ui/mentions/use-mention-asset.d.ts +16 -0
  103. package/dist/chat-ui/mentions/use-mention-asset.js +140 -0
  104. package/dist/chat-ui/mentions/use-mention-asset.js.map +1 -0
  105. package/dist/chat-ui/rich-text/chat-link.cjs +5 -4
  106. package/dist/chat-ui/rich-text/chat-link.cjs.map +1 -1
  107. package/dist/chat-ui/rich-text/chat-link.d.ts +2 -3
  108. package/dist/chat-ui/rich-text/chat-link.js +6 -5
  109. package/dist/chat-ui/rich-text/chat-link.js.map +1 -1
  110. package/dist/chat-ui/rich-text/chat-node-views.cjs +1 -0
  111. package/dist/chat-ui/rich-text/chat-node-views.cjs.map +1 -1
  112. package/dist/chat-ui/rich-text/chat-node-views.js +1 -0
  113. package/dist/chat-ui/rich-text/chat-node-views.js.map +1 -1
  114. package/dist/chat-ui/thread/composer-send-or-stop.cjs +2 -1
  115. package/dist/chat-ui/thread/composer-send-or-stop.cjs.map +1 -1
  116. package/dist/chat-ui/thread/composer-send-or-stop.d.ts +2 -0
  117. package/dist/chat-ui/thread/composer-send-or-stop.js +2 -1
  118. package/dist/chat-ui/thread/composer-send-or-stop.js.map +1 -1
  119. package/dist/diagnostics/athena-diagnostics.cjs.map +1 -1
  120. package/dist/diagnostics/athena-diagnostics.d.ts +1 -1
  121. package/dist/diagnostics/athena-diagnostics.js.map +1 -1
  122. package/dist/index.d.ts +1 -1
  123. package/dist/react/package.json.cjs +1 -1
  124. package/dist/react/package.json.js +1 -1
  125. package/dist/references/src/tool-option-schemas.d.ts +0 -34
  126. package/dist/runtime/statewire-session-key.cjs.map +1 -1
  127. package/dist/runtime/statewire-session-key.d.ts +8 -5
  128. package/dist/runtime/statewire-session-key.js.map +1 -1
  129. package/dist/runtime/useAthenaStatewireRuntime.cjs +5 -2
  130. package/dist/runtime/useAthenaStatewireRuntime.cjs.map +1 -1
  131. package/dist/runtime/useAthenaStatewireRuntime.js +5 -2
  132. package/dist/runtime/useAthenaStatewireRuntime.js.map +1 -1
  133. package/dist/styles.css +1 -1
  134. package/dist/threads/statewire-thread-list.cjs +6 -2
  135. package/dist/threads/statewire-thread-list.cjs.map +1 -1
  136. package/dist/threads/statewire-thread-list.js +6 -2
  137. package/dist/threads/statewire-thread-list.js.map +1 -1
  138. package/dist/tools/tool-summary.cjs +0 -2
  139. package/dist/tools/tool-summary.cjs.map +1 -1
  140. package/dist/tools/tool-summary.js +0 -2
  141. package/dist/tools/tool-summary.js.map +1 -1
  142. package/dist/voice/use-chat-voice-enabled.cjs +43 -0
  143. package/dist/voice/use-chat-voice-enabled.cjs.map +1 -0
  144. package/dist/voice/use-chat-voice-enabled.d.ts +9 -0
  145. package/dist/voice/use-chat-voice-enabled.js +43 -0
  146. package/dist/voice/use-chat-voice-enabled.js.map +1 -0
  147. package/package.json +4 -8
@@ -1 +1 @@
1
- {"version":3,"file":"api-client.js","sources":["../../../../../src/chat-ui/mentions/suggestions/data/api-client.ts"],"sourcesContent":["/**\n * API client for mention data fetching.\n *\n * Wraps raw fetch() with GraphQL support. Hosts authenticate with either a\n * bearer token or a workspace API key; agora's /graphql accepts both.\n */\n\nimport { createContext, useContext } from \"react\";\n\n// ── Auth context ──\n\nexport interface MentionAuthContext {\n backendUrl: string;\n appUrl?: string;\n /** Bearer credential; hosts without one authenticate with `apiKey`. */\n accessToken?: string;\n /**\n * Resolve a current bearer before each query (for rotating Office sessions).\n * Resolving nothing falls back to `accessToken`, then the API key.\n */\n getAccessToken?: () => Promise<string | null | undefined>;\n /**\n * Renew the bearer after the backend refused it (401), for one resend of\n * the query. Without it, or when it resolves nothing, a refused query fails\n * as before.\n */\n renewAccessToken?: () => Promise<string | null | undefined>;\n apiKey?: string;\n /**\n * With neither credential, ride the browser's same-origin session cookie\n * instead of failing — the SDK's AthenaChat, whose REST helpers make the\n * same choice for a host that configured no token and no API key. Hosts\n * that always hold a credential leave this unset so an accidental anonymous\n * query fails loudly.\n */\n credentials?: \"include\";\n workspaceId?: string;\n userId?: string;\n}\n\n/** Credential headers (or the cookie lane) for a mention fetch. */\nexport function mentionRequestInit(\n auth: MentionAuthContext,\n): Pick<RequestInit, \"headers\" | \"credentials\"> {\n if (auth.accessToken) {\n return { headers: { Authorization: `Bearer ${auth.accessToken}` } };\n }\n if (auth.apiKey) return { headers: { \"X-API-KEY\": auth.apiKey } };\n if (auth.credentials) return { headers: {}, credentials: auth.credentials };\n throw new Error(\"MentionAuthCtx needs either an accessToken or an apiKey\");\n}\n\nexport const MentionAuthCtx = createContext<MentionAuthContext | null>(null);\n\nexport function useMentionAuth(): MentionAuthContext {\n const ctx = useContext(MentionAuthCtx);\n if (!ctx) throw new Error(\"MentionAuthCtx not provided\");\n return ctx;\n}\n\n// ── GraphQL client ──\n\n/**\n * What {@link fetchGraphQL} throws: an HTTP failure (`status`) or the first\n * GraphQL error of the response (`code`, its `extensions.code`, e.g. agora's\n * `UNAUTHORIZED` for an asset the caller cannot read).\n */\nexport class AthenaGraphQLError extends Error {\n readonly status: number | null;\n readonly code: string | null;\n\n constructor({\n message,\n status = null,\n code = null,\n }: {\n message: string;\n status?: number | null;\n code?: string | null;\n }) {\n super(message);\n this.name = \"AthenaGraphQLError\";\n this.status = status;\n this.code = code;\n }\n}\n\n/** The `extensions.code` of a GraphQL error entry, when it carries a string one. */\nfunction graphQLErrorCode(entry: unknown): string | null {\n if (typeof entry !== \"object\" || entry === null) return null;\n const extensions: unknown = Reflect.get(entry, \"extensions\");\n if (typeof extensions !== \"object\" || extensions === null) return null;\n const code: unknown = Reflect.get(extensions, \"code\");\n return typeof code === \"string\" ? code : null;\n}\n\nexport async function fetchGraphQL<T = any>(\n auth: MentionAuthContext,\n query: string,\n variables: Record<string, any> = {},\n): Promise<T> {\n const url = `${auth.backendUrl.replace(/\\/+$/, \"\")}/graphql`;\n const send = (requestAuth: MentionAuthContext) => {\n const { headers, credentials } = mentionRequestInit(requestAuth);\n return fetch(url, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n ...headers,\n },\n ...(credentials ? { credentials } : {}),\n body: JSON.stringify({ query, variables }),\n });\n };\n const requestAuth = auth.getAccessToken\n ? { ...auth, accessToken: (await auth.getAccessToken()) ?? auth.accessToken }\n : auth;\n let response = await send(requestAuth);\n // A refused bearer gets one renewal and a resend (the statewire transport's\n // `staleAuth` contract); an API-key or cookie request has nothing to renew.\n if (response.status === 401 && requestAuth.accessToken && auth.renewAccessToken) {\n const renewed = await auth.renewAccessToken();\n // The same token again (a static one) would only be refused again.\n if (renewed && renewed !== requestAuth.accessToken) {\n response = await send({ ...auth, accessToken: renewed });\n }\n }\n\n if (!response.ok) {\n throw new AthenaGraphQLError({\n message: `GraphQL HTTP ${response.status}: ${response.statusText}`,\n status: response.status,\n });\n }\n\n const result = await response.json();\n if (result.errors?.length) {\n throw new AthenaGraphQLError({\n message: `GraphQL error: ${result.errors[0].message}`,\n code: graphQLErrorCode(result.errors[0]),\n });\n }\n\n return result.data as T;\n}\n\n// ── GraphQL Queries ──\n\n/**\n * Lightweight asset fragment for mention menu items.\n * Only fetches fields needed for display + navigation.\n */\nconst MENTION_ASSET_FIELDS = `\n id\n title\n athenaOriginalType\n athenaConvertedType\n parentFolderId\n updatedAt\n isFavorited\n isArchived\n isHidden\n`;\n\nexport const SIMPLE_SEARCH_QUERY = `\n query SimpleSearch($input: SimpleSearchRequestInput!) {\n simpleSearch(input: $input) {\n assets {\n ${MENTION_ASSET_FIELDS}\n }\n totalCount\n }\n }\n`;\n\nexport const PAGINATED_ASSETS_QUERY = `\n query GetPaginatedAssetsForWorkspace(\n $limit: Int!\n $offset: Int!\n $parentFolderId: String\n $filterTypes: [String!]\n $filterColumns: ColumnFilter\n ) {\n getPaginatedAssetsForWorkspace(\n limit: $limit\n offset: $offset\n parentFolderId: $parentFolderId\n filterTypes: $filterTypes\n filterColumns: $filterColumns\n ) {\n ${MENTION_ASSET_FIELDS}\n }\n }\n`;\n\nexport const WORKSPACE_MEMBERS_QUERY = `\n query GetUsersInWorkspace($workspaceId: String!) {\n getUsersInWorkspace(workspaceId: $workspaceId) {\n id\n email\n firstName\n lastName\n isAdmin\n avatarUrl\n }\n }\n`;\n\nexport const TOOL_CATALOG_QUERY = `\n query MentionToolCatalog {\n getToolkitToToolsMapping {\n tools {\n id\n name\n description\n icon\n adminOnly\n isMentionable\n }\n toolkits {\n name\n displayName\n description\n icon\n onlyAdmin\n hideFromMenu\n isMentionable\n }\n }\n }\n`;\n\n// ── Response types ──\n\nexport interface ToolCatalogTool {\n id: string;\n name: string;\n description: string | null;\n icon: string;\n adminOnly: boolean;\n isMentionable: boolean;\n}\n\nexport interface ToolCatalogToolkit {\n name: string;\n displayName: string;\n description: string;\n icon: string;\n onlyAdmin: boolean;\n hideFromMenu: boolean;\n isMentionable: boolean;\n}\n\nexport interface ToolCatalogResult {\n getToolkitToToolsMapping: {\n tools: ToolCatalogTool[];\n toolkits: ToolCatalogToolkit[];\n };\n}\n\nexport interface AssetResult {\n id: string;\n title: string | null;\n athenaOriginalType: string | null;\n athenaConvertedType: string | null;\n parentFolderId: string | null;\n updatedAt: string | null;\n isFavorited: boolean | null;\n isArchived: boolean | null;\n isHidden: boolean | null;\n}\n\nexport interface WorkspaceMember {\n id: string;\n email: string | null;\n firstName: string | null;\n lastName: string | null;\n isAdmin: boolean;\n avatarUrl: string | null;\n}\n"],"names":["requestAuth"],"mappings":"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"}
1
+ {"version":3,"file":"api-client.js","sources":["../../../../../src/chat-ui/mentions/suggestions/data/api-client.ts"],"sourcesContent":["/**\n * API client for mention data fetching.\n *\n * Wraps raw fetch() with GraphQL support. Hosts authenticate with either a\n * bearer token or a workspace API key; agora's /graphql accepts both.\n */\n\nimport { createContext, useContext } from \"react\";\n\n// ── Auth context ──\n\nexport interface MentionAuthContext {\n backendUrl: string;\n appUrl?: string;\n /** Bearer credential; hosts without one authenticate with `apiKey`. */\n accessToken?: string;\n /**\n * Resolve a current bearer before each query (for rotating Office sessions).\n * Resolving nothing falls back to `accessToken`, then the API key.\n */\n getAccessToken?: () => Promise<string | null | undefined>;\n /**\n * Renew the bearer after the backend refused it (401), for one resend of\n * the query. Without it, or when it resolves nothing, a refused query fails\n * as before.\n */\n renewAccessToken?: () => Promise<string | null | undefined>;\n apiKey?: string;\n /**\n * With neither credential, ride the browser's same-origin session cookie\n * instead of failing — the SDK's AthenaChat, whose REST helpers make the\n * same choice for a host that configured no token and no API key. Hosts\n * that always hold a credential leave this unset so an accidental anonymous\n * query fails loudly.\n */\n credentials?: \"include\";\n workspaceId?: string;\n userId?: string;\n}\n\n/** Credential headers (or the cookie lane) for a mention fetch. */\nexport function mentionRequestInit(\n auth: MentionAuthContext,\n): Pick<RequestInit, \"headers\" | \"credentials\"> {\n if (auth.accessToken) {\n return { headers: { Authorization: `Bearer ${auth.accessToken}` } };\n }\n if (auth.apiKey) return { headers: { \"X-API-KEY\": auth.apiKey } };\n if (auth.credentials) return { headers: {}, credentials: auth.credentials };\n throw new Error(\"MentionAuthCtx needs either an accessToken or an apiKey\");\n}\n\nexport const MentionAuthCtx = createContext<MentionAuthContext | null>(null);\n\nexport function useMentionAuth(): MentionAuthContext {\n const ctx = useContext(MentionAuthCtx);\n if (!ctx) throw new Error(\"MentionAuthCtx not provided\");\n return ctx;\n}\n\n// ── GraphQL client ──\n\n/**\n * What {@link fetchGraphQL} throws: an HTTP failure (`status`) or the first\n * GraphQL error of the response (`code`, its `extensions.code`, e.g. agora's\n * `UNAUTHORIZED` for an asset the caller cannot read).\n */\nexport class AthenaGraphQLError extends Error {\n readonly status: number | null;\n readonly code: string | null;\n\n constructor({\n message,\n status = null,\n code = null,\n }: {\n message: string;\n status?: number | null;\n code?: string | null;\n }) {\n super(message);\n this.name = \"AthenaGraphQLError\";\n this.status = status;\n this.code = code;\n }\n}\n\n/** The `extensions.code` of a GraphQL error entry, when it carries a string one. */\nfunction graphQLErrorCode(entry: unknown): string | null {\n if (typeof entry !== \"object\" || entry === null) return null;\n const extensions: unknown = Reflect.get(entry, \"extensions\");\n if (typeof extensions !== \"object\" || extensions === null) return null;\n const code: unknown = Reflect.get(extensions, \"code\");\n return typeof code === \"string\" ? code : null;\n}\n\nexport async function fetchGraphQL<T = any>(\n auth: MentionAuthContext,\n query: string,\n variables: Record<string, any> = {},\n options: { signal?: AbortSignal } = {},\n): Promise<T> {\n const url = `${auth.backendUrl.replace(/\\/+$/, \"\")}/graphql`;\n const send = (requestAuth: MentionAuthContext) => {\n const { headers, credentials } = mentionRequestInit(requestAuth);\n return fetch(url, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n ...headers,\n },\n ...(credentials ? { credentials } : {}),\n signal: options.signal,\n body: JSON.stringify({ query, variables }),\n });\n };\n const requestAuth = auth.getAccessToken\n ? { ...auth, accessToken: (await auth.getAccessToken()) ?? auth.accessToken }\n : auth;\n let response = await send(requestAuth);\n // A refused bearer gets one renewal and a resend (the statewire transport's\n // `staleAuth` contract); an API-key or cookie request has nothing to renew.\n if (response.status === 401 && requestAuth.accessToken && auth.renewAccessToken) {\n const renewed = await auth.renewAccessToken();\n // The same token again (a static one) would only be refused again.\n if (renewed && renewed !== requestAuth.accessToken) {\n response = await send({ ...auth, accessToken: renewed });\n }\n }\n\n if (!response.ok) {\n throw new AthenaGraphQLError({\n message: `GraphQL HTTP ${response.status}: ${response.statusText}`,\n status: response.status,\n });\n }\n\n const result = await response.json();\n if (result.errors?.length) {\n throw new AthenaGraphQLError({\n message: `GraphQL error: ${result.errors[0].message}`,\n code: graphQLErrorCode(result.errors[0]),\n });\n }\n\n return result.data as T;\n}\n\n// ── GraphQL Queries ──\n\n/**\n * Lightweight asset fragment for mention menu items.\n * Only fetches fields needed for display + navigation.\n */\nconst MENTION_ASSET_FIELDS = `\n id\n title\n athenaOriginalType\n athenaConvertedType\n parentFolderId\n updatedAt\n isFavorited\n isArchived\n isHidden\n`;\n\nexport const SIMPLE_SEARCH_QUERY = `\n query SimpleSearch($input: SimpleSearchRequestInput!) {\n simpleSearch(input: $input) {\n assets {\n ${MENTION_ASSET_FIELDS}\n }\n totalCount\n }\n }\n`;\n\nexport const PAGINATED_ASSETS_QUERY = `\n query GetPaginatedAssetsForWorkspace(\n $limit: Int!\n $offset: Int!\n $parentFolderId: String\n $filterTypes: [String!]\n $filterColumns: ColumnFilter\n ) {\n getPaginatedAssetsForWorkspace(\n limit: $limit\n offset: $offset\n parentFolderId: $parentFolderId\n filterTypes: $filterTypes\n filterColumns: $filterColumns\n ) {\n ${MENTION_ASSET_FIELDS}\n }\n }\n`;\n\nexport const WORKSPACE_MEMBERS_QUERY = `\n query GetUsersInWorkspace($workspaceId: String!) {\n getUsersInWorkspace(workspaceId: $workspaceId) {\n id\n email\n firstName\n lastName\n isAdmin\n avatarUrl\n }\n }\n`;\n\nexport const TOOL_CATALOG_QUERY = `\n query MentionToolCatalog {\n getToolkitToToolsMapping {\n tools {\n id\n name\n description\n icon\n adminOnly\n isMentionable\n }\n toolkits {\n name\n displayName\n description\n icon\n onlyAdmin\n hideFromMenu\n isMentionable\n }\n }\n }\n`;\n\n// ── Response types ──\n\nexport interface ToolCatalogTool {\n id: string;\n name: string;\n description: string | null;\n icon: string;\n adminOnly: boolean;\n isMentionable: boolean;\n}\n\nexport interface ToolCatalogToolkit {\n name: string;\n displayName: string;\n description: string;\n icon: string;\n onlyAdmin: boolean;\n hideFromMenu: boolean;\n isMentionable: boolean;\n}\n\nexport interface ToolCatalogResult {\n getToolkitToToolsMapping: {\n tools: ToolCatalogTool[];\n toolkits: ToolCatalogToolkit[];\n };\n}\n\nexport interface AssetResult {\n id: string;\n title: string | null;\n athenaOriginalType: string | null;\n athenaConvertedType: string | null;\n parentFolderId: string | null;\n updatedAt: string | null;\n isFavorited: boolean | null;\n isArchived: boolean | null;\n isHidden: boolean | null;\n}\n\nexport interface WorkspaceMember {\n id: string;\n email: string | null;\n firstName: string | null;\n lastName: string | null;\n isAdmin: boolean;\n avatarUrl: string | null;\n}\n"],"names":["requestAuth"],"mappings":";;;;AAyCO,SAAS,mBACd,MAC8C;AAC9C,MAAI,KAAK,aAAa;AACpB,WAAO,EAAE,SAAS,EAAE,eAAe,UAAU,KAAK,WAAW,KAAG;AAAA,EAClE;AACA,MAAI,KAAK,OAAQ,QAAO,EAAE,SAAS,EAAE,aAAa,KAAK,SAAO;AAC9D,MAAI,KAAK,YAAa,QAAO,EAAE,SAAS,CAAA,GAAI,aAAa,KAAK,YAAA;AAC9D,QAAM,IAAI,MAAM,yDAAyD;AAC3E;AAEO,MAAM,iBAAiB,cAAyC,IAAI;AAEpE,SAAS,iBAAqC;AACnD,QAAM,MAAM,WAAW,cAAc;AACrC,MAAI,CAAC,IAAK,OAAM,IAAI,MAAM,6BAA6B;AACvD,SAAO;AACT;AASO,MAAM,2BAA2B,MAAM;AAAA,EAI5C,YAAY;AAAA,IACV;AAAA,IACA,SAAS;AAAA,IACT,OAAO;AAAA,EAAA,GAKN;AACD,UAAM,OAAO;AAZN;AACA;AAYP,SAAK,OAAO;AACZ,SAAK,SAAS;AACd,SAAK,OAAO;AAAA,EACd;AACF;AAGA,SAAS,iBAAiB,OAA+B;AACvD,MAAI,OAAO,UAAU,YAAY,UAAU,KAAM,QAAO;AACxD,QAAM,aAAsB,QAAQ,IAAI,OAAO,YAAY;AAC3D,MAAI,OAAO,eAAe,YAAY,eAAe,KAAM,QAAO;AAClE,QAAM,OAAgB,QAAQ,IAAI,YAAY,MAAM;AACpD,SAAO,OAAO,SAAS,WAAW,OAAO;AAC3C;AAEA,eAAsB,aACpB,MACA,OACA,YAAiC,CAAA,GACjC,UAAoC,IACxB;;AACZ,QAAM,MAAM,GAAG,KAAK,WAAW,QAAQ,QAAQ,EAAE,CAAC;AAClD,QAAM,OAAO,CAACA,iBAAoC;AAChD,UAAM,EAAE,SAAS,gBAAgB,mBAAmBA,YAAW;AAC/D,WAAO,MAAM,KAAK;AAAA,MAChB,QAAQ;AAAA,MACR,SAAS;AAAA,QACP,gBAAgB;AAAA,QAChB,GAAG;AAAA,MAAA;AAAA,MAEL,GAAI,cAAc,EAAE,YAAA,IAAgB,CAAA;AAAA,MACpC,QAAQ,QAAQ;AAAA,MAChB,MAAM,KAAK,UAAU,EAAE,OAAO,WAAW;AAAA,IAAA,CAC1C;AAAA,EACH;AACA,QAAM,cAAc,KAAK,iBACrB,EAAE,GAAG,MAAM,aAAc,MAAM,KAAK,eAAA,KAAqB,KAAK,gBAC9D;AACJ,MAAI,WAAW,MAAM,KAAK,WAAW;AAGrC,MAAI,SAAS,WAAW,OAAO,YAAY,eAAe,KAAK,kBAAkB;AAC/E,UAAM,UAAU,MAAM,KAAK,iBAAA;AAE3B,QAAI,WAAW,YAAY,YAAY,aAAa;AAClD,iBAAW,MAAM,KAAK,EAAE,GAAG,MAAM,aAAa,SAAS;AAAA,IACzD;AAAA,EACF;AAEA,MAAI,CAAC,SAAS,IAAI;AAChB,UAAM,IAAI,mBAAmB;AAAA,MAC3B,SAAS,gBAAgB,SAAS,MAAM,KAAK,SAAS,UAAU;AAAA,MAChE,QAAQ,SAAS;AAAA,IAAA,CAClB;AAAA,EACH;AAEA,QAAM,SAAS,MAAM,SAAS,KAAA;AAC9B,OAAI,YAAO,WAAP,mBAAe,QAAQ;AACzB,UAAM,IAAI,mBAAmB;AAAA,MAC3B,SAAS,kBAAkB,OAAO,OAAO,CAAC,EAAE,OAAO;AAAA,MACnD,MAAM,iBAAiB,OAAO,OAAO,CAAC,CAAC;AAAA,IAAA,CACxC;AAAA,EACH;AAEA,SAAO,OAAO;AAChB;AAQA,MAAM,uBAAuB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAYtB,MAAM,sBAAsB;AAAA;AAAA;AAAA;AAAA,UAIzB,oBAAoB;AAAA;AAAA;AAAA;AAAA;AAAA;AAOvB,MAAM,yBAAyB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QAe9B,oBAAoB;AAAA;AAAA;AAAA;AAKrB,MAAM,0BAA0B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAahC,MAAM,qBAAqB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;"}
@@ -1,61 +1,39 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const reactQuery = require("@tanstack/react-query");
3
4
  const react = require("react");
5
+ const runtimeCatalog = require("../../catalog/runtime-catalog.cjs");
4
6
  const credentialRenewal = require("../../runtime/credential-renewal.cjs");
5
7
  const api = require("../../threads/api.cjs");
6
- const workspaceIdRequests = /* @__PURE__ */ new Map();
7
- function loadWorkspaceId(auth) {
8
- if (auth.workspaceId) return Promise.resolve(auth.workspaceId);
9
- const cacheKey = `${auth.backendUrl}|${auth.userId ?? ""}`;
10
- const cached = workspaceIdRequests.get(cacheKey);
11
- if (cached) return cached;
12
- const request = credentialRenewal.withCredentialRenewal(
13
- async ({ force } = {}) => {
14
- var _a, _b;
15
- return {
16
- token: (force ? await ((_a = auth.renewAccessToken) == null ? void 0 : _a.call(auth)) : await ((_b = auth.getAccessToken) == null ? void 0 : _b.call(auth))) ?? auth.accessToken ?? null,
17
- apiKey: auth.apiKey,
18
- credentials: auth.credentials
19
- };
20
- },
21
- (credential) => api.fetchAccountIdentity(auth.backendUrl, credential)
22
- ).then((identity) => identity.workspaceId ?? void 0).catch((error) => {
23
- if (workspaceIdRequests.get(cacheKey) === request) {
24
- workspaceIdRequests.delete(cacheKey);
25
- }
26
- throw error;
27
- });
28
- workspaceIdRequests.set(cacheKey, request);
29
- return request;
30
- }
31
8
  function useAccountWorkspaceId(auth) {
32
- const cacheKey = auth ? `${auth.backendUrl}|${auth.userId ?? ""}` : void 0;
33
- const [resolvedWorkspace, setResolvedWorkspace] = react.useState();
34
- react.useEffect(() => {
35
- if (!auth || !cacheKey) {
36
- setResolvedWorkspace(void 0);
37
- return void 0;
38
- }
39
- if (auth.workspaceId) {
40
- setResolvedWorkspace({ cacheKey, workspaceId: auth.workspaceId });
41
- return void 0;
42
- }
43
- let cancelled = false;
44
- setResolvedWorkspace(void 0);
45
- loadWorkspaceId(auth).then(
46
- (workspaceId) => {
47
- if (!cancelled) setResolvedWorkspace({ cacheKey, workspaceId });
9
+ const queryClient = runtimeCatalog.useCatalogQueryClient();
10
+ const anonymousScope = react.useId();
11
+ const principal = (auth == null ? void 0 : auth.apiKey) ? `key:${runtimeCatalog.credentialFingerprint({ credential: auth.apiKey })}` : (auth == null ? void 0 : auth.userId) ?? ((auth == null ? void 0 : auth.accessToken) ? `token:${runtimeCatalog.credentialFingerprint({ credential: auth.accessToken })}` : anonymousScope);
12
+ const query = reactQuery.useQuery(
13
+ {
14
+ queryKey: ["athena-sdk", "account-workspace", auth == null ? void 0 : auth.backendUrl, auth == null ? void 0 : auth.userId, principal],
15
+ queryFn: async ({ signal }) => {
16
+ if (!auth) return null;
17
+ const identity = await credentialRenewal.withCredentialRenewal(
18
+ async ({ force } = {}) => {
19
+ var _a, _b;
20
+ return {
21
+ token: (force ? await ((_a = auth.renewAccessToken) == null ? void 0 : _a.call(auth)) : await ((_b = auth.getAccessToken) == null ? void 0 : _b.call(auth))) ?? auth.accessToken ?? null,
22
+ apiKey: auth.apiKey,
23
+ credentials: auth.credentials
24
+ };
25
+ },
26
+ (resolved) => api.fetchAccountIdentity(auth.backendUrl, resolved, { signal })
27
+ );
28
+ return identity.workspaceId ?? null;
48
29
  },
49
- () => {
50
- if (!cancelled) setResolvedWorkspace({ cacheKey, workspaceId: void 0 });
51
- }
52
- );
53
- return () => {
54
- cancelled = true;
55
- };
56
- }, [auth, cacheKey]);
57
- if (auth == null ? void 0 : auth.workspaceId) return auth.workspaceId;
58
- return cacheKey && (resolvedWorkspace == null ? void 0 : resolvedWorkspace.cacheKey) === cacheKey ? resolvedWorkspace.workspaceId : void 0;
30
+ enabled: auth !== null && !auth.workspaceId,
31
+ retry: false,
32
+ staleTime: 6e4
33
+ },
34
+ queryClient
35
+ );
36
+ return (auth == null ? void 0 : auth.workspaceId) ?? query.data ?? void 0;
59
37
  }
60
38
  exports.useAccountWorkspaceId = useAccountWorkspaceId;
61
39
  //# sourceMappingURL=use-account-workspace-id.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"use-account-workspace-id.cjs","sources":["../../../src/chat-ui/mentions/use-account-workspace-id.ts"],"sourcesContent":["import { useEffect, useState } from \"react\";\nimport { withCredentialRenewal } from \"../../runtime/credential-renewal\";\nimport { fetchAccountIdentity } from \"../../threads/api\";\nimport type { MentionAuthContext } from \"./suggestions/data/api-client\";\n\nconst workspaceIdRequests = new Map<string, Promise<string | undefined>>();\n\nfunction loadWorkspaceId(auth: MentionAuthContext): Promise<string | undefined> {\n if (auth.workspaceId) return Promise.resolve(auth.workspaceId);\n\n const cacheKey = `${auth.backendUrl}|${auth.userId ?? \"\"}`;\n const cached = workspaceIdRequests.get(cacheKey);\n if (cached) return cached;\n\n const request = withCredentialRenewal(\n async ({ force }: { force?: boolean } = {}) => ({\n token: (force ? await auth.renewAccessToken?.() : await auth.getAccessToken?.()) ?? auth.accessToken ?? null,\n apiKey: auth.apiKey,\n credentials: auth.credentials,\n }),\n (credential) => fetchAccountIdentity(auth.backendUrl, credential),\n )\n .then((identity) => identity.workspaceId ?? undefined)\n .catch((error: unknown) => {\n if (workspaceIdRequests.get(cacheKey) === request) {\n workspaceIdRequests.delete(cacheKey);\n }\n throw error;\n });\n\n workspaceIdRequests.set(cacheKey, request);\n return request;\n}\n\nexport function useAccountWorkspaceId(auth: MentionAuthContext | null): string | undefined {\n const cacheKey = auth ? `${auth.backendUrl}|${auth.userId ?? \"\"}` : undefined;\n const [resolvedWorkspace, setResolvedWorkspace] = useState<{\n cacheKey: string;\n workspaceId: string | undefined;\n }>();\n\n useEffect(() => {\n if (!auth || !cacheKey) {\n setResolvedWorkspace(undefined);\n return undefined;\n }\n if (auth.workspaceId) {\n setResolvedWorkspace({ cacheKey, workspaceId: auth.workspaceId });\n return undefined;\n }\n\n let cancelled = false;\n setResolvedWorkspace(undefined);\n loadWorkspaceId(auth).then(\n (workspaceId) => {\n if (!cancelled) setResolvedWorkspace({ cacheKey, workspaceId });\n },\n () => {\n if (!cancelled) setResolvedWorkspace({ cacheKey, workspaceId: undefined });\n },\n );\n\n return () => {\n cancelled = true;\n };\n }, [auth, cacheKey]);\n\n if (auth?.workspaceId) return auth.workspaceId;\n return cacheKey && resolvedWorkspace?.cacheKey === cacheKey ? resolvedWorkspace.workspaceId : undefined;\n}\n\nexport function resetAccountWorkspaceIdForTests(): void {\n workspaceIdRequests.clear();\n}\n"],"names":["withCredentialRenewal","fetchAccountIdentity","useState","useEffect"],"mappings":";;;;;AAKA,MAAM,0CAA0B,IAAA;AAEhC,SAAS,gBAAgB,MAAuD;AAC9E,MAAI,KAAK,YAAa,QAAO,QAAQ,QAAQ,KAAK,WAAW;AAE7D,QAAM,WAAW,GAAG,KAAK,UAAU,IAAI,KAAK,UAAU,EAAE;AACxD,QAAM,SAAS,oBAAoB,IAAI,QAAQ;AAC/C,MAAI,OAAQ,QAAO;AAEnB,QAAM,UAAUA,kBAAAA;AAAAA,IACd,OAAO,EAAE,MAAA,IAA+B,OAAC;;AAAO;AAAA,QAC9C,QAAQ,QAAQ,QAAM,UAAK,qBAAL,iCAA4B,QAAM,UAAK,mBAAL,mCAA4B,KAAK,eAAe;AAAA,QACxG,QAAQ,KAAK;AAAA,QACb,aAAa,KAAK;AAAA,MAAA;AAAA;AAAA,IAEpB,CAAC,eAAeC,IAAAA,qBAAqB,KAAK,YAAY,UAAU;AAAA,EAAA,EAE/D,KAAK,CAAC,aAAa,SAAS,eAAe,MAAS,EACpD,MAAM,CAAC,UAAmB;AACzB,QAAI,oBAAoB,IAAI,QAAQ,MAAM,SAAS;AACjD,0BAAoB,OAAO,QAAQ;AAAA,IACrC;AACA,UAAM;AAAA,EACR,CAAC;AAEH,sBAAoB,IAAI,UAAU,OAAO;AACzC,SAAO;AACT;AAEO,SAAS,sBAAsB,MAAqD;AACzF,QAAM,WAAW,OAAO,GAAG,KAAK,UAAU,IAAI,KAAK,UAAU,EAAE,KAAK;AACpE,QAAM,CAAC,mBAAmB,oBAAoB,IAAIC,eAAA;AAKlDC,QAAAA,UAAU,MAAM;AACd,QAAI,CAAC,QAAQ,CAAC,UAAU;AACtB,2BAAqB,MAAS;AAC9B,aAAO;AAAA,IACT;AACA,QAAI,KAAK,aAAa;AACpB,2BAAqB,EAAE,UAAU,aAAa,KAAK,aAAa;AAChE,aAAO;AAAA,IACT;AAEA,QAAI,YAAY;AAChB,yBAAqB,MAAS;AAC9B,oBAAgB,IAAI,EAAE;AAAA,MACpB,CAAC,gBAAgB;AACf,YAAI,CAAC,UAAW,sBAAqB,EAAE,UAAU,aAAa;AAAA,MAChE;AAAA,MACA,MAAM;AACJ,YAAI,CAAC,UAAW,sBAAqB,EAAE,UAAU,aAAa,QAAW;AAAA,MAC3E;AAAA,IAAA;AAGF,WAAO,MAAM;AACX,kBAAY;AAAA,IACd;AAAA,EACF,GAAG,CAAC,MAAM,QAAQ,CAAC;AAEnB,MAAI,6BAAM,YAAa,QAAO,KAAK;AACnC,SAAO,aAAY,uDAAmB,cAAa,WAAW,kBAAkB,cAAc;AAChG;;"}
1
+ {"version":3,"file":"use-account-workspace-id.cjs","sources":["../../../src/chat-ui/mentions/use-account-workspace-id.ts"],"sourcesContent":["import { useQuery } from '@tanstack/react-query';\nimport { useId } from 'react';\nimport { credentialFingerprint, useCatalogQueryClient } from '../../catalog/runtime-catalog';\nimport { withCredentialRenewal } from '../../runtime/credential-renewal';\nimport { fetchAccountIdentity } from '../../threads/api';\nimport type { MentionAuthContext } from './suggestions/data/api-client';\n\n/** Account identity uses the host's query cache and never a process-wide user-id map. */\nexport function useAccountWorkspaceId(auth: MentionAuthContext | null): string | undefined {\n const queryClient = useCatalogQueryClient();\n const anonymousScope = useId();\n // A workspace API key wins even when the person is known; a bearer can\n // rotate without changing that person's cache identity.\n const principal = auth?.apiKey\n ? `key:${credentialFingerprint({ credential: auth.apiKey })}`\n : auth?.userId ??\n (auth?.accessToken\n ? `token:${credentialFingerprint({ credential: auth.accessToken })}`\n : anonymousScope);\n const query = useQuery(\n {\n queryKey: ['athena-sdk', 'account-workspace', auth?.backendUrl, auth?.userId, principal],\n queryFn: async ({ signal }) => {\n if (!auth) return null;\n const identity = await withCredentialRenewal(\n async ({ force }: { force?: boolean } = {}) => ({\n token:\n (force ? await auth.renewAccessToken?.() : await auth.getAccessToken?.()) ??\n auth.accessToken ??\n null,\n apiKey: auth.apiKey,\n credentials: auth.credentials,\n }),\n (resolved) => fetchAccountIdentity(auth.backendUrl, resolved, { signal })\n );\n return identity.workspaceId ?? null;\n },\n enabled: auth !== null && !auth.workspaceId,\n retry: false,\n staleTime: 60_000,\n },\n queryClient\n );\n return auth?.workspaceId ?? query.data ?? undefined;\n}\n"],"names":["useCatalogQueryClient","useId","credentialFingerprint","useQuery","withCredentialRenewal","fetchAccountIdentity"],"mappings":";;;;;;;AAQO,SAAS,sBAAsB,MAAqD;AACzF,QAAM,cAAcA,eAAAA,sBAAA;AACpB,QAAM,iBAAiBC,MAAAA,MAAA;AAGvB,QAAM,aAAY,6BAAM,UACpB,OAAOC,eAAAA,sBAAsB,EAAE,YAAY,KAAK,OAAA,CAAQ,CAAC,MACzD,6BAAM,aACL,6BAAM,eACH,SAASA,eAAAA,sBAAsB,EAAE,YAAY,KAAK,YAAA,CAAa,CAAC,KAChE;AACR,QAAM,QAAQC,WAAAA;AAAAA,IACZ;AAAA,MACE,UAAU,CAAC,cAAc,qBAAqB,6BAAM,YAAY,6BAAM,QAAQ,SAAS;AAAA,MACvF,SAAS,OAAO,EAAE,aAAa;AAC7B,YAAI,CAAC,KAAM,QAAO;AAClB,cAAM,WAAW,MAAMC,kBAAAA;AAAAA,UACrB,OAAO,EAAE,MAAA,IAA+B,OAAC;;AAAO;AAAA,cAC9C,QACG,QAAQ,QAAM,UAAK,qBAAL,iCAA4B,QAAM,UAAK,mBAAL,mCACjD,KAAK,eACL;AAAA,cACF,QAAQ,KAAK;AAAA,cACb,aAAa,KAAK;AAAA,YAAA;AAAA;AAAA,UAEpB,CAAC,aAAaC,IAAAA,qBAAqB,KAAK,YAAY,UAAU,EAAE,QAAQ;AAAA,QAAA;AAE1E,eAAO,SAAS,eAAe;AAAA,MACjC;AAAA,MACA,SAAS,SAAS,QAAQ,CAAC,KAAK;AAAA,MAChC,OAAO;AAAA,MACP,WAAW;AAAA,IAAA;AAAA,IAEb;AAAA,EAAA;AAEF,UAAO,6BAAM,gBAAe,MAAM,QAAQ;AAC5C;;"}
@@ -1,3 +1,3 @@
1
- import type { MentionAuthContext } from "./suggestions/data/api-client";
1
+ import type { MentionAuthContext } from './suggestions/data/api-client';
2
+ /** Account identity uses the host's query cache and never a process-wide user-id map. */
2
3
  export declare function useAccountWorkspaceId(auth: MentionAuthContext | null): string | undefined;
3
- export declare function resetAccountWorkspaceIdForTests(): void;
@@ -1,59 +1,37 @@
1
- import { useState, useEffect } from "react";
1
+ import { useQuery } from "@tanstack/react-query";
2
+ import { useId } from "react";
3
+ import { useCatalogQueryClient, credentialFingerprint } from "../../catalog/runtime-catalog.js";
2
4
  import { withCredentialRenewal } from "../../runtime/credential-renewal.js";
3
5
  import { fetchAccountIdentity } from "../../threads/api.js";
4
- const workspaceIdRequests = /* @__PURE__ */ new Map();
5
- function loadWorkspaceId(auth) {
6
- if (auth.workspaceId) return Promise.resolve(auth.workspaceId);
7
- const cacheKey = `${auth.backendUrl}|${auth.userId ?? ""}`;
8
- const cached = workspaceIdRequests.get(cacheKey);
9
- if (cached) return cached;
10
- const request = withCredentialRenewal(
11
- async ({ force } = {}) => {
12
- var _a, _b;
13
- return {
14
- token: (force ? await ((_a = auth.renewAccessToken) == null ? void 0 : _a.call(auth)) : await ((_b = auth.getAccessToken) == null ? void 0 : _b.call(auth))) ?? auth.accessToken ?? null,
15
- apiKey: auth.apiKey,
16
- credentials: auth.credentials
17
- };
18
- },
19
- (credential) => fetchAccountIdentity(auth.backendUrl, credential)
20
- ).then((identity) => identity.workspaceId ?? void 0).catch((error) => {
21
- if (workspaceIdRequests.get(cacheKey) === request) {
22
- workspaceIdRequests.delete(cacheKey);
23
- }
24
- throw error;
25
- });
26
- workspaceIdRequests.set(cacheKey, request);
27
- return request;
28
- }
29
6
  function useAccountWorkspaceId(auth) {
30
- const cacheKey = auth ? `${auth.backendUrl}|${auth.userId ?? ""}` : void 0;
31
- const [resolvedWorkspace, setResolvedWorkspace] = useState();
32
- useEffect(() => {
33
- if (!auth || !cacheKey) {
34
- setResolvedWorkspace(void 0);
35
- return void 0;
36
- }
37
- if (auth.workspaceId) {
38
- setResolvedWorkspace({ cacheKey, workspaceId: auth.workspaceId });
39
- return void 0;
40
- }
41
- let cancelled = false;
42
- setResolvedWorkspace(void 0);
43
- loadWorkspaceId(auth).then(
44
- (workspaceId) => {
45
- if (!cancelled) setResolvedWorkspace({ cacheKey, workspaceId });
7
+ const queryClient = useCatalogQueryClient();
8
+ const anonymousScope = useId();
9
+ const principal = (auth == null ? void 0 : auth.apiKey) ? `key:${credentialFingerprint({ credential: auth.apiKey })}` : (auth == null ? void 0 : auth.userId) ?? ((auth == null ? void 0 : auth.accessToken) ? `token:${credentialFingerprint({ credential: auth.accessToken })}` : anonymousScope);
10
+ const query = useQuery(
11
+ {
12
+ queryKey: ["athena-sdk", "account-workspace", auth == null ? void 0 : auth.backendUrl, auth == null ? void 0 : auth.userId, principal],
13
+ queryFn: async ({ signal }) => {
14
+ if (!auth) return null;
15
+ const identity = await withCredentialRenewal(
16
+ async ({ force } = {}) => {
17
+ var _a, _b;
18
+ return {
19
+ token: (force ? await ((_a = auth.renewAccessToken) == null ? void 0 : _a.call(auth)) : await ((_b = auth.getAccessToken) == null ? void 0 : _b.call(auth))) ?? auth.accessToken ?? null,
20
+ apiKey: auth.apiKey,
21
+ credentials: auth.credentials
22
+ };
23
+ },
24
+ (resolved) => fetchAccountIdentity(auth.backendUrl, resolved, { signal })
25
+ );
26
+ return identity.workspaceId ?? null;
46
27
  },
47
- () => {
48
- if (!cancelled) setResolvedWorkspace({ cacheKey, workspaceId: void 0 });
49
- }
50
- );
51
- return () => {
52
- cancelled = true;
53
- };
54
- }, [auth, cacheKey]);
55
- if (auth == null ? void 0 : auth.workspaceId) return auth.workspaceId;
56
- return cacheKey && (resolvedWorkspace == null ? void 0 : resolvedWorkspace.cacheKey) === cacheKey ? resolvedWorkspace.workspaceId : void 0;
28
+ enabled: auth !== null && !auth.workspaceId,
29
+ retry: false,
30
+ staleTime: 6e4
31
+ },
32
+ queryClient
33
+ );
34
+ return (auth == null ? void 0 : auth.workspaceId) ?? query.data ?? void 0;
57
35
  }
58
36
  export {
59
37
  useAccountWorkspaceId
@@ -1 +1 @@
1
- {"version":3,"file":"use-account-workspace-id.js","sources":["../../../src/chat-ui/mentions/use-account-workspace-id.ts"],"sourcesContent":["import { useEffect, useState } from \"react\";\nimport { withCredentialRenewal } from \"../../runtime/credential-renewal\";\nimport { fetchAccountIdentity } from \"../../threads/api\";\nimport type { MentionAuthContext } from \"./suggestions/data/api-client\";\n\nconst workspaceIdRequests = new Map<string, Promise<string | undefined>>();\n\nfunction loadWorkspaceId(auth: MentionAuthContext): Promise<string | undefined> {\n if (auth.workspaceId) return Promise.resolve(auth.workspaceId);\n\n const cacheKey = `${auth.backendUrl}|${auth.userId ?? \"\"}`;\n const cached = workspaceIdRequests.get(cacheKey);\n if (cached) return cached;\n\n const request = withCredentialRenewal(\n async ({ force }: { force?: boolean } = {}) => ({\n token: (force ? await auth.renewAccessToken?.() : await auth.getAccessToken?.()) ?? auth.accessToken ?? null,\n apiKey: auth.apiKey,\n credentials: auth.credentials,\n }),\n (credential) => fetchAccountIdentity(auth.backendUrl, credential),\n )\n .then((identity) => identity.workspaceId ?? undefined)\n .catch((error: unknown) => {\n if (workspaceIdRequests.get(cacheKey) === request) {\n workspaceIdRequests.delete(cacheKey);\n }\n throw error;\n });\n\n workspaceIdRequests.set(cacheKey, request);\n return request;\n}\n\nexport function useAccountWorkspaceId(auth: MentionAuthContext | null): string | undefined {\n const cacheKey = auth ? `${auth.backendUrl}|${auth.userId ?? \"\"}` : undefined;\n const [resolvedWorkspace, setResolvedWorkspace] = useState<{\n cacheKey: string;\n workspaceId: string | undefined;\n }>();\n\n useEffect(() => {\n if (!auth || !cacheKey) {\n setResolvedWorkspace(undefined);\n return undefined;\n }\n if (auth.workspaceId) {\n setResolvedWorkspace({ cacheKey, workspaceId: auth.workspaceId });\n return undefined;\n }\n\n let cancelled = false;\n setResolvedWorkspace(undefined);\n loadWorkspaceId(auth).then(\n (workspaceId) => {\n if (!cancelled) setResolvedWorkspace({ cacheKey, workspaceId });\n },\n () => {\n if (!cancelled) setResolvedWorkspace({ cacheKey, workspaceId: undefined });\n },\n );\n\n return () => {\n cancelled = true;\n };\n }, [auth, cacheKey]);\n\n if (auth?.workspaceId) return auth.workspaceId;\n return cacheKey && resolvedWorkspace?.cacheKey === cacheKey ? resolvedWorkspace.workspaceId : undefined;\n}\n\nexport function resetAccountWorkspaceIdForTests(): void {\n workspaceIdRequests.clear();\n}\n"],"names":[],"mappings":";;;AAKA,MAAM,0CAA0B,IAAA;AAEhC,SAAS,gBAAgB,MAAuD;AAC9E,MAAI,KAAK,YAAa,QAAO,QAAQ,QAAQ,KAAK,WAAW;AAE7D,QAAM,WAAW,GAAG,KAAK,UAAU,IAAI,KAAK,UAAU,EAAE;AACxD,QAAM,SAAS,oBAAoB,IAAI,QAAQ;AAC/C,MAAI,OAAQ,QAAO;AAEnB,QAAM,UAAU;AAAA,IACd,OAAO,EAAE,MAAA,IAA+B,OAAC;;AAAO;AAAA,QAC9C,QAAQ,QAAQ,QAAM,UAAK,qBAAL,iCAA4B,QAAM,UAAK,mBAAL,mCAA4B,KAAK,eAAe;AAAA,QACxG,QAAQ,KAAK;AAAA,QACb,aAAa,KAAK;AAAA,MAAA;AAAA;AAAA,IAEpB,CAAC,eAAe,qBAAqB,KAAK,YAAY,UAAU;AAAA,EAAA,EAE/D,KAAK,CAAC,aAAa,SAAS,eAAe,MAAS,EACpD,MAAM,CAAC,UAAmB;AACzB,QAAI,oBAAoB,IAAI,QAAQ,MAAM,SAAS;AACjD,0BAAoB,OAAO,QAAQ;AAAA,IACrC;AACA,UAAM;AAAA,EACR,CAAC;AAEH,sBAAoB,IAAI,UAAU,OAAO;AACzC,SAAO;AACT;AAEO,SAAS,sBAAsB,MAAqD;AACzF,QAAM,WAAW,OAAO,GAAG,KAAK,UAAU,IAAI,KAAK,UAAU,EAAE,KAAK;AACpE,QAAM,CAAC,mBAAmB,oBAAoB,IAAI,SAAA;AAKlD,YAAU,MAAM;AACd,QAAI,CAAC,QAAQ,CAAC,UAAU;AACtB,2BAAqB,MAAS;AAC9B,aAAO;AAAA,IACT;AACA,QAAI,KAAK,aAAa;AACpB,2BAAqB,EAAE,UAAU,aAAa,KAAK,aAAa;AAChE,aAAO;AAAA,IACT;AAEA,QAAI,YAAY;AAChB,yBAAqB,MAAS;AAC9B,oBAAgB,IAAI,EAAE;AAAA,MACpB,CAAC,gBAAgB;AACf,YAAI,CAAC,UAAW,sBAAqB,EAAE,UAAU,aAAa;AAAA,MAChE;AAAA,MACA,MAAM;AACJ,YAAI,CAAC,UAAW,sBAAqB,EAAE,UAAU,aAAa,QAAW;AAAA,MAC3E;AAAA,IAAA;AAGF,WAAO,MAAM;AACX,kBAAY;AAAA,IACd;AAAA,EACF,GAAG,CAAC,MAAM,QAAQ,CAAC;AAEnB,MAAI,6BAAM,YAAa,QAAO,KAAK;AACnC,SAAO,aAAY,uDAAmB,cAAa,WAAW,kBAAkB,cAAc;AAChG;"}
1
+ {"version":3,"file":"use-account-workspace-id.js","sources":["../../../src/chat-ui/mentions/use-account-workspace-id.ts"],"sourcesContent":["import { useQuery } from '@tanstack/react-query';\nimport { useId } from 'react';\nimport { credentialFingerprint, useCatalogQueryClient } from '../../catalog/runtime-catalog';\nimport { withCredentialRenewal } from '../../runtime/credential-renewal';\nimport { fetchAccountIdentity } from '../../threads/api';\nimport type { MentionAuthContext } from './suggestions/data/api-client';\n\n/** Account identity uses the host's query cache and never a process-wide user-id map. */\nexport function useAccountWorkspaceId(auth: MentionAuthContext | null): string | undefined {\n const queryClient = useCatalogQueryClient();\n const anonymousScope = useId();\n // A workspace API key wins even when the person is known; a bearer can\n // rotate without changing that person's cache identity.\n const principal = auth?.apiKey\n ? `key:${credentialFingerprint({ credential: auth.apiKey })}`\n : auth?.userId ??\n (auth?.accessToken\n ? `token:${credentialFingerprint({ credential: auth.accessToken })}`\n : anonymousScope);\n const query = useQuery(\n {\n queryKey: ['athena-sdk', 'account-workspace', auth?.backendUrl, auth?.userId, principal],\n queryFn: async ({ signal }) => {\n if (!auth) return null;\n const identity = await withCredentialRenewal(\n async ({ force }: { force?: boolean } = {}) => ({\n token:\n (force ? await auth.renewAccessToken?.() : await auth.getAccessToken?.()) ??\n auth.accessToken ??\n null,\n apiKey: auth.apiKey,\n credentials: auth.credentials,\n }),\n (resolved) => fetchAccountIdentity(auth.backendUrl, resolved, { signal })\n );\n return identity.workspaceId ?? null;\n },\n enabled: auth !== null && !auth.workspaceId,\n retry: false,\n staleTime: 60_000,\n },\n queryClient\n );\n return auth?.workspaceId ?? query.data ?? undefined;\n}\n"],"names":[],"mappings":";;;;;AAQO,SAAS,sBAAsB,MAAqD;AACzF,QAAM,cAAc,sBAAA;AACpB,QAAM,iBAAiB,MAAA;AAGvB,QAAM,aAAY,6BAAM,UACpB,OAAO,sBAAsB,EAAE,YAAY,KAAK,OAAA,CAAQ,CAAC,MACzD,6BAAM,aACL,6BAAM,eACH,SAAS,sBAAsB,EAAE,YAAY,KAAK,YAAA,CAAa,CAAC,KAChE;AACR,QAAM,QAAQ;AAAA,IACZ;AAAA,MACE,UAAU,CAAC,cAAc,qBAAqB,6BAAM,YAAY,6BAAM,QAAQ,SAAS;AAAA,MACvF,SAAS,OAAO,EAAE,aAAa;AAC7B,YAAI,CAAC,KAAM,QAAO;AAClB,cAAM,WAAW,MAAM;AAAA,UACrB,OAAO,EAAE,MAAA,IAA+B,OAAC;;AAAO;AAAA,cAC9C,QACG,QAAQ,QAAM,UAAK,qBAAL,iCAA4B,QAAM,UAAK,mBAAL,mCACjD,KAAK,eACL;AAAA,cACF,QAAQ,KAAK;AAAA,cACb,aAAa,KAAK;AAAA,YAAA;AAAA;AAAA,UAEpB,CAAC,aAAa,qBAAqB,KAAK,YAAY,UAAU,EAAE,QAAQ;AAAA,QAAA;AAE1E,eAAO,SAAS,eAAe;AAAA,MACjC;AAAA,MACA,SAAS,SAAS,QAAQ,CAAC,KAAK;AAAA,MAChC,OAAO;AAAA,MACP,WAAW;AAAA,IAAA;AAAA,IAEb;AAAA,EAAA;AAEF,UAAO,6BAAM,gBAAe,MAAM,QAAQ;AAC5C;"}
@@ -0,0 +1,140 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const reactQuery = require("@tanstack/react-query");
4
+ const react = require("react");
5
+ const apiClient = require("./suggestions/data/api-client.cjs");
6
+ const MENTION_ASSET_BATCH_SIZE = 50;
7
+ const MENTION_ASSET_BATCH_WINDOW_MS = 16;
8
+ const MENTION_ASSET_STALE_TIME_MS = 6e4;
9
+ const MENTION_ASSETS_QUERY = `
10
+ query MentionChipAssets($assetIds: [String!]!) {
11
+ getAssetsByIds(assetIds: $assetIds) {
12
+ id
13
+ title
14
+ athenaOriginalType
15
+ }
16
+ }
17
+ `;
18
+ const LOOKUP_ID = /^asset_[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
19
+ function mentionAssetLookupId(assetId) {
20
+ const baseId = (assetId == null ? void 0 : assetId.trim().split("@")[0]) ?? "";
21
+ return LOOKUP_ID.test(baseId) ? baseId : null;
22
+ }
23
+ function canAuthenticate(auth) {
24
+ return Boolean(auth.accessToken || auth.apiKey || auth.credentials || auth.getAccessToken);
25
+ }
26
+ function fingerprint(credential) {
27
+ let hash = 2166136261;
28
+ for (let index = 0; index < credential.length; index += 1) {
29
+ hash ^= credential.charCodeAt(index);
30
+ hash = Math.imul(hash, 16777619) >>> 0;
31
+ }
32
+ return hash.toString(16).padStart(8, "0");
33
+ }
34
+ const authScopes = /* @__PURE__ */ new WeakMap();
35
+ let authScopeCount = 0;
36
+ function principalOf(auth) {
37
+ const scope = [];
38
+ if (auth.userId) scope.push(`user:${auth.userId}`);
39
+ if (auth.apiKey) scope.push(`key:${fingerprint(auth.apiKey)}`);
40
+ if (scope.length) return scope.join("|");
41
+ let own = authScopes.get(auth);
42
+ if (!own) {
43
+ authScopeCount += 1;
44
+ own = `auth:${authScopeCount}`;
45
+ authScopes.set(auth, own);
46
+ }
47
+ const token = auth.accessToken;
48
+ return token ? `${own}|token:${fingerprint(token)}` : own;
49
+ }
50
+ const pendingBatches = /* @__PURE__ */ new Map();
51
+ function settle(waiters, asset) {
52
+ for (const waiter of waiters ?? []) waiter.resolve(asset);
53
+ }
54
+ function fail(waiters, error) {
55
+ for (const waiter of waiters ?? []) waiter.reject(error);
56
+ }
57
+ function sendBatch(batchKey) {
58
+ const batch = pendingBatches.get(batchKey);
59
+ if (!batch) return;
60
+ pendingBatches.delete(batchKey);
61
+ const ids = [...batch.waiters.keys()];
62
+ for (let start = 0; start < ids.length; start += MENTION_ASSET_BATCH_SIZE) {
63
+ const chunk = ids.slice(start, start + MENTION_ASSET_BATCH_SIZE);
64
+ apiClient.fetchGraphQL(batch.auth, MENTION_ASSETS_QUERY, {
65
+ assetIds: chunk
66
+ }).then(
67
+ (data) => {
68
+ var _a, _b;
69
+ const found = new Map((data.getAssetsByIds ?? []).map((asset) => [asset.id, asset]));
70
+ for (const id of chunk) {
71
+ const asset = found.get(id);
72
+ settle(
73
+ batch.waiters.get(id),
74
+ asset ? {
75
+ id,
76
+ title: ((_a = asset.title) == null ? void 0 : _a.trim()) ?? "",
77
+ assetType: ((_b = asset.athenaOriginalType) == null ? void 0 : _b.trim()) ?? ""
78
+ } : null
79
+ );
80
+ }
81
+ },
82
+ (error) => {
83
+ for (const id of chunk) fail(batch.waiters.get(id), error);
84
+ }
85
+ );
86
+ }
87
+ }
88
+ function loadMentionAsset({
89
+ auth,
90
+ batchKey,
91
+ assetId
92
+ }) {
93
+ return new Promise((resolve, reject) => {
94
+ let batch = pendingBatches.get(batchKey);
95
+ if (!batch) {
96
+ batch = { auth, waiters: /* @__PURE__ */ new Map() };
97
+ pendingBatches.set(batchKey, batch);
98
+ setTimeout(() => sendBatch(batchKey), MENTION_ASSET_BATCH_WINDOW_MS);
99
+ }
100
+ const waiters = batch.waiters.get(assetId) ?? [];
101
+ waiters.push({ resolve, reject });
102
+ batch.waiters.set(assetId, waiters);
103
+ });
104
+ }
105
+ const chipQueryClient = new reactQuery.QueryClient();
106
+ function useMentionAsset(assetId) {
107
+ const auth = react.useContext(apiClient.MentionAuthCtx);
108
+ const hostQueryClient = react.useContext(reactQuery.QueryClientContext);
109
+ const lookupId = mentionAssetLookupId(assetId);
110
+ const enabled = Boolean(auth && lookupId && canAuthenticate(auth));
111
+ const backendUrl = (auth == null ? void 0 : auth.backendUrl) ?? "";
112
+ const principal = auth ? principalOf(auth) : "";
113
+ const { data } = reactQuery.useQuery(
114
+ {
115
+ queryKey: ["athena-sdk", "mention-asset", backendUrl, principal, lookupId ?? ""],
116
+ queryFn: () => {
117
+ if (!auth || !lookupId) return null;
118
+ return loadMentionAsset({
119
+ auth,
120
+ batchKey: `${backendUrl}|${principal}`,
121
+ assetId: lookupId
122
+ });
123
+ },
124
+ enabled,
125
+ staleTime: MENTION_ASSET_STALE_TIME_MS,
126
+ // Kept no longer than it is fresh: a title is shown again only after
127
+ // agora answers again, never from a cache a minute past its check.
128
+ gcTime: MENTION_ASSET_STALE_TIME_MS,
129
+ retry: false,
130
+ refetchOnWindowFocus: false
131
+ },
132
+ hostQueryClient ?? chipQueryClient
133
+ );
134
+ return enabled ? data : void 0;
135
+ }
136
+ exports.MENTION_ASSET_BATCH_SIZE = MENTION_ASSET_BATCH_SIZE;
137
+ exports.MENTION_ASSET_BATCH_WINDOW_MS = MENTION_ASSET_BATCH_WINDOW_MS;
138
+ exports.mentionAssetLookupId = mentionAssetLookupId;
139
+ exports.useMentionAsset = useMentionAsset;
140
+ //# sourceMappingURL=use-mention-asset.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-mention-asset.cjs","sources":["../../../src/chat-ui/mentions/use-mention-asset.ts"],"sourcesContent":["/**\n * The asset an asset chip names, read the way Olympus's chips read it: its\n * title and type from agora's `getAssetsByIds`, which returns only the assets\n * the caller may read (an id they cannot read is left out of the answer, as is\n * another workspace's). A chip then shows the asset's own name and icon\n * instead of whatever label and `type=` its link carried.\n *\n * Chips that mount together ask together: one GraphQL request per batch of up\n * to {@link MENTION_ASSET_BATCH_SIZE} ids, gathered over\n * {@link MENTION_ASSET_BATCH_WINDOW_MS}. Each answer is a TanStack query keyed\n * by backend, the person asking and the id, fresh for a minute, so a\n * transcript full of citations to one repository asks for it once.\n */\nimport { QueryClient, QueryClientContext, useQuery } from \"@tanstack/react-query\";\nimport { useContext } from \"react\";\nimport {\n fetchGraphQL,\n type MentionAuthContext,\n MentionAuthCtx,\n} from \"./suggestions/data/api-client\";\n\n/** What a chip draws from the asset: its current title and its type. */\nexport interface MentionAsset {\n id: string;\n title: string;\n assetType: string;\n}\n\nexport const MENTION_ASSET_BATCH_SIZE = 50;\nexport const MENTION_ASSET_BATCH_WINDOW_MS = 16;\nconst MENTION_ASSET_STALE_TIME_MS = 60_000;\n\n/** No metadata: a session's carries its token ledgers, and a chip needs a name and a type. */\nconst MENTION_ASSETS_QUERY = `\n query MentionChipAssets($assetIds: [String!]!) {\n getAssetsByIds(assetIds: $assetIds) {\n id\n title\n athenaOriginalType\n }\n }\n`;\n\ninterface MentionAssetsResponse {\n getAssetsByIds?: Array<{\n id: string;\n title: string | null;\n athenaOriginalType: string | null;\n }> | null;\n}\n\n/**\n * The ids a lookup asks about: a stored asset. A versioned id (`asset_x@3`)\n * asks about its asset. A live provider file (`asset_<catalog>_<file>`) is not\n * a row `getAssetsByIds` holds, and a session (`asset_thread_<uuid>`) is never\n * asked about: agora reads the whole row, and a session's metadata carries\n * its transcript's ledgers (megabytes on a long session) — too much for a name.\n */\nconst LOOKUP_ID = /^asset_[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\n\nexport function mentionAssetLookupId(assetId: string | undefined): string | null {\n const baseId = assetId?.trim().split(\"@\")[0] ?? \"\";\n return LOOKUP_ID.test(baseId) ? baseId : null;\n}\n\n/** Whether a request can carry a credential (`mentionRequestInit` refuses one that cannot). */\nfunction canAuthenticate(auth: MentionAuthContext): boolean {\n return Boolean(auth.accessToken || auth.apiKey || auth.credentials || auth.getAccessToken);\n}\n\n/** A short, stable stand-in for a credential in a cache key; never the credential itself. */\nfunction fingerprint(credential: string): string {\n let hash = 0x811c9dc5;\n for (let index = 0; index < credential.length; index += 1) {\n hash ^= credential.charCodeAt(index);\n hash = Math.imul(hash, 0x01000193) >>> 0;\n }\n return hash.toString(16).padStart(8, \"0\");\n}\n\n/** The scope each credential with no stable identity of its own gets: its own auth object. */\nconst authScopes = new WeakMap<MentionAuthContext, string>();\nlet authScopeCount = 0;\n\n/**\n * Who is asking, as narrowly as the credential says: what `getAssetsByIds`\n * answers differs per person and per API key, and an answer (or a batch's\n * request) is only ever shared within one scope. A person's id and an API key\n * scope the cache across token rotations. A credential that names neither (a\n * session cookie, a token callback) shares nothing beyond its own auth object\n * and its current token, so a token swapped on the same object asks again.\n */\nfunction principalOf(auth: MentionAuthContext): string {\n const scope: string[] = [];\n if (auth.userId) scope.push(`user:${auth.userId}`);\n if (auth.apiKey) scope.push(`key:${fingerprint(auth.apiKey)}`);\n if (scope.length) return scope.join(\"|\");\n let own = authScopes.get(auth);\n if (!own) {\n authScopeCount += 1;\n own = `auth:${authScopeCount}`;\n authScopes.set(auth, own);\n }\n const token = auth.accessToken;\n return token ? `${own}|token:${fingerprint(token)}` : own;\n}\n\ninterface Waiter {\n resolve: (asset: MentionAsset | null) => void;\n reject: (error: unknown) => void;\n}\n\ninterface PendingBatch {\n auth: MentionAuthContext;\n waiters: Map<string, Waiter[]>;\n}\n\n/** The batch each backend and principal is gathering, until its window closes. */\nconst pendingBatches = new Map<string, PendingBatch>();\n\nfunction settle(waiters: Waiter[] | undefined, asset: MentionAsset | null): void {\n for (const waiter of waiters ?? []) waiter.resolve(asset);\n}\n\nfunction fail(waiters: Waiter[] | undefined, error: unknown): void {\n for (const waiter of waiters ?? []) waiter.reject(error);\n}\n\nfunction sendBatch(batchKey: string): void {\n const batch = pendingBatches.get(batchKey);\n if (!batch) return;\n pendingBatches.delete(batchKey);\n const ids = [...batch.waiters.keys()];\n for (let start = 0; start < ids.length; start += MENTION_ASSET_BATCH_SIZE) {\n const chunk = ids.slice(start, start + MENTION_ASSET_BATCH_SIZE);\n fetchGraphQL<MentionAssetsResponse>(batch.auth, MENTION_ASSETS_QUERY, {\n assetIds: chunk,\n }).then(\n (data) => {\n const found = new Map((data.getAssetsByIds ?? []).map((asset) => [asset.id, asset]));\n for (const id of chunk) {\n const asset = found.get(id);\n settle(\n batch.waiters.get(id),\n asset\n ? {\n id,\n title: asset.title?.trim() ?? \"\",\n assetType: asset.athenaOriginalType?.trim() ?? \"\",\n }\n : null,\n );\n }\n },\n (error: unknown) => {\n for (const id of chunk) fail(batch.waiters.get(id), error);\n },\n );\n }\n}\n\nfunction loadMentionAsset({\n auth,\n batchKey,\n assetId,\n}: {\n auth: MentionAuthContext;\n batchKey: string;\n assetId: string;\n}): Promise<MentionAsset | null> {\n return new Promise((resolve, reject) => {\n let batch = pendingBatches.get(batchKey);\n if (!batch) {\n batch = { auth, waiters: new Map() };\n pendingBatches.set(batchKey, batch);\n setTimeout(() => sendBatch(batchKey), MENTION_ASSET_BATCH_WINDOW_MS);\n }\n const waiters = batch.waiters.get(assetId) ?? [];\n waiters.push({ resolve, reject });\n batch.waiters.set(assetId, waiters);\n });\n}\n\n/** Chips rendered outside any query client (a host's own tray) still share one cache. */\nconst chipQueryClient = new QueryClient();\n\n/**\n * The asset an asset chip names: `undefined` while unknown (no lookup, still\n * loading, or the lookup failed), `null` when agora returned no asset the\n * viewer may read under that id, else its title and type.\n */\nexport function useMentionAsset(assetId: string | undefined): MentionAsset | null | undefined {\n const auth = useContext(MentionAuthCtx);\n const hostQueryClient = useContext(QueryClientContext);\n const lookupId = mentionAssetLookupId(assetId);\n const enabled = Boolean(auth && lookupId && canAuthenticate(auth));\n const backendUrl = auth?.backendUrl ?? \"\";\n const principal = auth ? principalOf(auth) : \"\";\n const { data } = useQuery(\n {\n queryKey: [\"athena-sdk\", \"mention-asset\", backendUrl, principal, lookupId ?? \"\"],\n queryFn: () => {\n if (!auth || !lookupId) return null;\n return loadMentionAsset({\n auth,\n batchKey: `${backendUrl}|${principal}`,\n assetId: lookupId,\n });\n },\n enabled,\n staleTime: MENTION_ASSET_STALE_TIME_MS,\n // Kept no longer than it is fresh: a title is shown again only after\n // agora answers again, never from a cache a minute past its check.\n gcTime: MENTION_ASSET_STALE_TIME_MS,\n retry: false,\n refetchOnWindowFocus: false,\n },\n hostQueryClient ?? chipQueryClient,\n );\n return enabled ? data : undefined;\n}\n\nexport function resetMentionAssetsForTests(): void {\n pendingBatches.clear();\n chipQueryClient.clear();\n}\n"],"names":["fetchGraphQL","QueryClient","useContext","MentionAuthCtx","QueryClientContext","useQuery"],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ /** What a chip draws from the asset: its current title and its type. */
2
+ export interface MentionAsset {
3
+ id: string;
4
+ title: string;
5
+ assetType: string;
6
+ }
7
+ export declare const MENTION_ASSET_BATCH_SIZE = 50;
8
+ export declare const MENTION_ASSET_BATCH_WINDOW_MS = 16;
9
+ export declare function mentionAssetLookupId(assetId: string | undefined): string | null;
10
+ /**
11
+ * The asset an asset chip names: `undefined` while unknown (no lookup, still
12
+ * loading, or the lookup failed), `null` when agora returned no asset the
13
+ * viewer may read under that id, else its title and type.
14
+ */
15
+ export declare function useMentionAsset(assetId: string | undefined): MentionAsset | null | undefined;
16
+ export declare function resetMentionAssetsForTests(): void;
@@ -0,0 +1,140 @@
1
+ import { QueryClientContext, useQuery, QueryClient } from "@tanstack/react-query";
2
+ import { useContext } from "react";
3
+ import { MentionAuthCtx, fetchGraphQL } from "./suggestions/data/api-client.js";
4
+ const MENTION_ASSET_BATCH_SIZE = 50;
5
+ const MENTION_ASSET_BATCH_WINDOW_MS = 16;
6
+ const MENTION_ASSET_STALE_TIME_MS = 6e4;
7
+ const MENTION_ASSETS_QUERY = `
8
+ query MentionChipAssets($assetIds: [String!]!) {
9
+ getAssetsByIds(assetIds: $assetIds) {
10
+ id
11
+ title
12
+ athenaOriginalType
13
+ }
14
+ }
15
+ `;
16
+ const LOOKUP_ID = /^asset_[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
17
+ function mentionAssetLookupId(assetId) {
18
+ const baseId = (assetId == null ? void 0 : assetId.trim().split("@")[0]) ?? "";
19
+ return LOOKUP_ID.test(baseId) ? baseId : null;
20
+ }
21
+ function canAuthenticate(auth) {
22
+ return Boolean(auth.accessToken || auth.apiKey || auth.credentials || auth.getAccessToken);
23
+ }
24
+ function fingerprint(credential) {
25
+ let hash = 2166136261;
26
+ for (let index = 0; index < credential.length; index += 1) {
27
+ hash ^= credential.charCodeAt(index);
28
+ hash = Math.imul(hash, 16777619) >>> 0;
29
+ }
30
+ return hash.toString(16).padStart(8, "0");
31
+ }
32
+ const authScopes = /* @__PURE__ */ new WeakMap();
33
+ let authScopeCount = 0;
34
+ function principalOf(auth) {
35
+ const scope = [];
36
+ if (auth.userId) scope.push(`user:${auth.userId}`);
37
+ if (auth.apiKey) scope.push(`key:${fingerprint(auth.apiKey)}`);
38
+ if (scope.length) return scope.join("|");
39
+ let own = authScopes.get(auth);
40
+ if (!own) {
41
+ authScopeCount += 1;
42
+ own = `auth:${authScopeCount}`;
43
+ authScopes.set(auth, own);
44
+ }
45
+ const token = auth.accessToken;
46
+ return token ? `${own}|token:${fingerprint(token)}` : own;
47
+ }
48
+ const pendingBatches = /* @__PURE__ */ new Map();
49
+ function settle(waiters, asset) {
50
+ for (const waiter of waiters ?? []) waiter.resolve(asset);
51
+ }
52
+ function fail(waiters, error) {
53
+ for (const waiter of waiters ?? []) waiter.reject(error);
54
+ }
55
+ function sendBatch(batchKey) {
56
+ const batch = pendingBatches.get(batchKey);
57
+ if (!batch) return;
58
+ pendingBatches.delete(batchKey);
59
+ const ids = [...batch.waiters.keys()];
60
+ for (let start = 0; start < ids.length; start += MENTION_ASSET_BATCH_SIZE) {
61
+ const chunk = ids.slice(start, start + MENTION_ASSET_BATCH_SIZE);
62
+ fetchGraphQL(batch.auth, MENTION_ASSETS_QUERY, {
63
+ assetIds: chunk
64
+ }).then(
65
+ (data) => {
66
+ var _a, _b;
67
+ const found = new Map((data.getAssetsByIds ?? []).map((asset) => [asset.id, asset]));
68
+ for (const id of chunk) {
69
+ const asset = found.get(id);
70
+ settle(
71
+ batch.waiters.get(id),
72
+ asset ? {
73
+ id,
74
+ title: ((_a = asset.title) == null ? void 0 : _a.trim()) ?? "",
75
+ assetType: ((_b = asset.athenaOriginalType) == null ? void 0 : _b.trim()) ?? ""
76
+ } : null
77
+ );
78
+ }
79
+ },
80
+ (error) => {
81
+ for (const id of chunk) fail(batch.waiters.get(id), error);
82
+ }
83
+ );
84
+ }
85
+ }
86
+ function loadMentionAsset({
87
+ auth,
88
+ batchKey,
89
+ assetId
90
+ }) {
91
+ return new Promise((resolve, reject) => {
92
+ let batch = pendingBatches.get(batchKey);
93
+ if (!batch) {
94
+ batch = { auth, waiters: /* @__PURE__ */ new Map() };
95
+ pendingBatches.set(batchKey, batch);
96
+ setTimeout(() => sendBatch(batchKey), MENTION_ASSET_BATCH_WINDOW_MS);
97
+ }
98
+ const waiters = batch.waiters.get(assetId) ?? [];
99
+ waiters.push({ resolve, reject });
100
+ batch.waiters.set(assetId, waiters);
101
+ });
102
+ }
103
+ const chipQueryClient = new QueryClient();
104
+ function useMentionAsset(assetId) {
105
+ const auth = useContext(MentionAuthCtx);
106
+ const hostQueryClient = useContext(QueryClientContext);
107
+ const lookupId = mentionAssetLookupId(assetId);
108
+ const enabled = Boolean(auth && lookupId && canAuthenticate(auth));
109
+ const backendUrl = (auth == null ? void 0 : auth.backendUrl) ?? "";
110
+ const principal = auth ? principalOf(auth) : "";
111
+ const { data } = useQuery(
112
+ {
113
+ queryKey: ["athena-sdk", "mention-asset", backendUrl, principal, lookupId ?? ""],
114
+ queryFn: () => {
115
+ if (!auth || !lookupId) return null;
116
+ return loadMentionAsset({
117
+ auth,
118
+ batchKey: `${backendUrl}|${principal}`,
119
+ assetId: lookupId
120
+ });
121
+ },
122
+ enabled,
123
+ staleTime: MENTION_ASSET_STALE_TIME_MS,
124
+ // Kept no longer than it is fresh: a title is shown again only after
125
+ // agora answers again, never from a cache a minute past its check.
126
+ gcTime: MENTION_ASSET_STALE_TIME_MS,
127
+ retry: false,
128
+ refetchOnWindowFocus: false
129
+ },
130
+ hostQueryClient ?? chipQueryClient
131
+ );
132
+ return enabled ? data : void 0;
133
+ }
134
+ export {
135
+ MENTION_ASSET_BATCH_SIZE,
136
+ MENTION_ASSET_BATCH_WINDOW_MS,
137
+ mentionAssetLookupId,
138
+ useMentionAsset
139
+ };
140
+ //# sourceMappingURL=use-mention-asset.js.map