@athenaintel/react 0.24.0 → 0.25.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +29 -4
- package/dist/assets/AssetPanel.cjs +3 -2
- package/dist/assets/AssetPanel.cjs.map +1 -1
- package/dist/assets/AssetPanel.js +3 -2
- package/dist/assets/AssetPanel.js.map +1 -1
- package/dist/assets/AthenaAssetEmbed.cjs +1 -0
- package/dist/assets/AthenaAssetEmbed.cjs.map +1 -1
- package/dist/assets/AthenaAssetEmbed.js +1 -0
- package/dist/assets/AthenaAssetEmbed.js.map +1 -1
- package/dist/assets/use-asset-embed.cjs +22 -23
- package/dist/assets/use-asset-embed.cjs.map +1 -1
- package/dist/assets/use-asset-embed.d.ts +9 -0
- package/dist/assets/use-asset-embed.js +22 -23
- package/dist/assets/use-asset-embed.js.map +1 -1
- package/dist/auth/AthenaAuthProvider.cjs +32 -4
- package/dist/auth/AthenaAuthProvider.cjs.map +1 -1
- package/dist/auth/AthenaAuthProvider.d.ts +21 -0
- package/dist/auth/AthenaAuthProvider.js +33 -5
- package/dist/auth/AthenaAuthProvider.js.map +1 -1
- package/dist/auth/AthenaCredentialSourceContext.cjs +21 -0
- package/dist/auth/AthenaCredentialSourceContext.cjs.map +1 -0
- package/dist/auth/AthenaCredentialSourceContext.d.ts +14 -0
- package/dist/auth/AthenaCredentialSourceContext.js +21 -0
- package/dist/auth/AthenaCredentialSourceContext.js.map +1 -0
- package/dist/auth/AthenaSSOProvider.cjs +71 -47
- package/dist/auth/AthenaSSOProvider.cjs.map +1 -1
- package/dist/auth/AthenaSSOProvider.js +71 -47
- package/dist/auth/AthenaSSOProvider.js.map +1 -1
- package/dist/auth/credential-source.cjs +120 -0
- package/dist/auth/credential-source.cjs.map +1 -0
- package/dist/auth/credential-source.d.ts +68 -0
- package/dist/auth/credential-source.js +120 -0
- package/dist/auth/credential-source.js.map +1 -0
- package/dist/auth/types.d.ts +9 -0
- package/dist/chat/AthenaChat.cjs +8 -0
- package/dist/chat/AthenaChat.cjs.map +1 -1
- package/dist/chat/AthenaChat.js +8 -0
- package/dist/chat/AthenaChat.js.map +1 -1
- package/dist/chat/StatewireApprovalCard.cjs +31 -6
- package/dist/chat/StatewireApprovalCard.cjs.map +1 -1
- package/dist/chat/StatewireApprovalCard.d.ts +34 -4
- package/dist/chat/StatewireApprovalCard.js +33 -8
- package/dist/chat/StatewireApprovalCard.js.map +1 -1
- package/dist/chat-ui/index.d.ts +1 -1
- package/dist/chat-ui/mentions/suggestions/data/api-client.cjs +20 -11
- package/dist/chat-ui/mentions/suggestions/data/api-client.cjs.map +1 -1
- package/dist/chat-ui/mentions/suggestions/data/api-client.d.ts +11 -2
- package/dist/chat-ui/mentions/suggestions/data/api-client.js +20 -11
- package/dist/chat-ui/mentions/suggestions/data/api-client.js.map +1 -1
- package/dist/chat-ui/statewire.d.ts +1 -1
- package/dist/collab/mint.cjs +6 -15
- package/dist/collab/mint.cjs.map +1 -1
- package/dist/collab/mint.d.ts +8 -0
- package/dist/collab/mint.js +6 -15
- package/dist/collab/mint.js.map +1 -1
- package/dist/collab/presence-mint.cjs +20 -16
- package/dist/collab/presence-mint.cjs.map +1 -1
- package/dist/collab/presence-mint.js +21 -17
- package/dist/collab/presence-mint.js.map +1 -1
- package/dist/collab/presence-react.cjs +12 -5
- package/dist/collab/presence-react.cjs.map +1 -1
- package/dist/collab/presence-react.d.ts +3 -1
- package/dist/collab/presence-react.js +12 -5
- package/dist/collab/presence-react.js.map +1 -1
- package/dist/collab/react.cjs +5 -2
- package/dist/collab/react.cjs.map +1 -1
- package/dist/collab/react.js +5 -2
- package/dist/collab/react.js.map +1 -1
- package/dist/dictation/use-athena-dictation-engine.cjs +12 -11
- package/dist/dictation/use-athena-dictation-engine.cjs.map +1 -1
- package/dist/dictation/use-athena-dictation-engine.d.ts +4 -3
- package/dist/dictation/use-athena-dictation-engine.js +12 -11
- package/dist/dictation/use-athena-dictation-engine.js.map +1 -1
- package/dist/index.cjs +1 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.js +2 -1
- package/dist/packages/agent-runtime/src/conversation-list.cjs.map +1 -1
- package/dist/packages/agent-runtime/src/conversation-list.js.map +1 -1
- package/dist/packages/agent-runtime/src/generated/runconfig-contract.cjs +1 -0
- package/dist/packages/agent-runtime/src/generated/runconfig-contract.cjs.map +1 -1
- package/dist/packages/agent-runtime/src/generated/runconfig-contract.js +1 -0
- package/dist/packages/agent-runtime/src/generated/runconfig-contract.js.map +1 -1
- package/dist/packages/agent-runtime/src/interrupts.cjs +22 -2
- package/dist/packages/agent-runtime/src/interrupts.cjs.map +1 -1
- package/dist/packages/agent-runtime/src/interrupts.js +22 -2
- package/dist/packages/agent-runtime/src/interrupts.js.map +1 -1
- package/dist/packages/agent-runtime/src/messages.cjs +2 -1
- package/dist/packages/agent-runtime/src/messages.cjs.map +1 -1
- package/dist/packages/agent-runtime/src/messages.js +2 -1
- package/dist/packages/agent-runtime/src/messages.js.map +1 -1
- package/dist/packages/agent-runtime/src/voice-presentation.cjs +6 -0
- package/dist/packages/agent-runtime/src/voice-presentation.cjs.map +1 -1
- package/dist/packages/agent-runtime/src/voice-presentation.js +6 -0
- package/dist/packages/agent-runtime/src/voice-presentation.js.map +1 -1
- package/dist/packages/agent-runtime/src/voice-turn-grouping.cjs +68 -0
- package/dist/packages/agent-runtime/src/voice-turn-grouping.cjs.map +1 -0
- package/dist/packages/agent-runtime/src/voice-turn-grouping.js +68 -0
- package/dist/packages/agent-runtime/src/voice-turn-grouping.js.map +1 -0
- package/dist/packages/react/package.json.cjs +1 -1
- package/dist/packages/react/package.json.js +1 -1
- package/dist/provider/AthenaContext.cjs.map +1 -1
- package/dist/provider/AthenaContext.d.ts +7 -1
- package/dist/provider/AthenaContext.js.map +1 -1
- package/dist/provider/AthenaProvider.cjs +24 -2
- package/dist/provider/AthenaProvider.cjs.map +1 -1
- package/dist/provider/AthenaProvider.js +24 -2
- package/dist/provider/AthenaProvider.js.map +1 -1
- package/dist/provider/theme-style-context.cjs +12 -0
- package/dist/provider/theme-style-context.cjs.map +1 -0
- package/dist/provider/theme-style-context.d.ts +8 -0
- package/dist/provider/theme-style-context.js +12 -0
- package/dist/provider/theme-style-context.js.map +1 -0
- package/dist/runtime/auth-refusal-restart.cjs +66 -0
- package/dist/runtime/auth-refusal-restart.cjs.map +1 -0
- package/dist/runtime/auth-refusal-restart.d.ts +35 -0
- package/dist/runtime/auth-refusal-restart.js +66 -0
- package/dist/runtime/auth-refusal-restart.js.map +1 -0
- package/dist/runtime/auth.cjs +58 -21
- package/dist/runtime/auth.cjs.map +1 -1
- package/dist/runtime/auth.d.ts +11 -1
- package/dist/runtime/auth.js +59 -22
- package/dist/runtime/auth.js.map +1 -1
- package/dist/runtime/credential-renewal.cjs +29 -0
- package/dist/runtime/credential-renewal.cjs.map +1 -0
- package/dist/runtime/credential-renewal.d.ts +35 -0
- package/dist/runtime/credential-renewal.js +29 -0
- package/dist/runtime/credential-renewal.js.map +1 -0
- package/dist/search/useAthenaRepoSearch.cjs +3 -5
- package/dist/search/useAthenaRepoSearch.cjs.map +1 -1
- package/dist/search/useAthenaRepoSearch.d.ts +7 -7
- package/dist/search/useAthenaRepoSearch.js +3 -5
- package/dist/search/useAthenaRepoSearch.js.map +1 -1
- package/dist/styles.css +1 -1
- package/dist/threads/SessionList.cjs +87 -16
- package/dist/threads/SessionList.cjs.map +1 -1
- package/dist/threads/SessionList.js +88 -17
- package/dist/threads/SessionList.js.map +1 -1
- package/dist/threads/api.cjs +5 -1
- package/dist/threads/api.cjs.map +1 -1
- package/dist/threads/api.js +5 -1
- package/dist/threads/api.js.map +1 -1
- package/dist/threads/conversation-list-fetcher.cjs +5 -5
- package/dist/threads/conversation-list-fetcher.cjs.map +1 -1
- package/dist/threads/conversation-list-fetcher.d.ts +6 -5
- package/dist/threads/conversation-list-fetcher.js +5 -5
- package/dist/threads/conversation-list-fetcher.js.map +1 -1
- package/dist/threads/session-list-model.cjs +13 -5
- package/dist/threads/session-list-model.cjs.map +1 -1
- package/dist/threads/session-list-model.d.ts +10 -3
- package/dist/threads/session-list-model.js +13 -5
- package/dist/threads/session-list-model.js.map +1 -1
- package/dist/threads/statewire-thread-list.cjs +13 -14
- package/dist/threads/statewire-thread-list.cjs.map +1 -1
- package/dist/threads/statewire-thread-list.js +13 -14
- package/dist/threads/statewire-thread-list.js.map +1 -1
- package/dist/threads/use-rest-conversation-history.cjs +6 -2
- package/dist/threads/use-rest-conversation-history.cjs.map +1 -1
- package/dist/threads/use-rest-conversation-history.d.ts +3 -1
- package/dist/threads/use-rest-conversation-history.js +7 -3
- package/dist/threads/use-rest-conversation-history.js.map +1 -1
- package/dist/threads/use-statewire-conversation-history.cjs +9 -2
- package/dist/threads/use-statewire-conversation-history.cjs.map +1 -1
- package/dist/threads/use-statewire-conversation-history.d.ts +3 -1
- package/dist/threads/use-statewire-conversation-history.js +10 -3
- package/dist/threads/use-statewire-conversation-history.js.map +1 -1
- package/dist/threads/use-thread-archive.cjs +2 -1
- package/dist/threads/use-thread-archive.cjs.map +1 -1
- package/dist/threads/use-thread-archive.d.ts +3 -1
- package/dist/threads/use-thread-archive.js +2 -1
- package/dist/threads/use-thread-archive.js.map +1 -1
- package/dist/threads/use-thread-favorite.cjs.map +1 -1
- package/dist/threads/use-thread-favorite.d.ts +3 -1
- package/dist/threads/use-thread-favorite.js.map +1 -1
- package/dist/threads/use-thread-field-override.cjs +2 -1
- package/dist/threads/use-thread-field-override.cjs.map +1 -1
- package/dist/threads/use-thread-field-override.d.ts +3 -1
- package/dist/threads/use-thread-field-override.js +2 -1
- package/dist/threads/use-thread-field-override.js.map +1 -1
- package/dist/threads/use-thread-rename.cjs.map +1 -1
- package/dist/threads/use-thread-rename.d.ts +3 -1
- package/dist/threads/use-thread-rename.js.map +1 -1
- package/dist/tools/tool-uis.cjs +11 -15
- package/dist/tools/tool-uis.cjs.map +1 -1
- package/dist/tools/tool-uis.js +11 -15
- package/dist/tools/tool-uis.js.map +1 -1
- package/dist/ui/popover.cjs +46 -0
- package/dist/ui/popover.cjs.map +1 -0
- package/dist/ui/popover.d.ts +6 -0
- package/dist/ui/popover.js +46 -0
- package/dist/ui/popover.js.map +1 -0
- package/dist/voice/use-athena-voice-session.cjs +17 -5
- package/dist/voice/use-athena-voice-session.cjs.map +1 -1
- package/dist/voice/use-athena-voice-session.d.ts +2 -2
- package/dist/voice/use-athena-voice-session.js +17 -5
- package/dist/voice/use-athena-voice-session.js.map +1 -1
- package/package.json +2 -2
|
@@ -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
|
|
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\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 Error(`GraphQL HTTP ${response.status}: ${response.statusText}`);\n }\n\n const result = await response.json();\n if (result.errors?.length) {\n throw new Error(`GraphQL error: ${result.errors[0].message}`);\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;AAIA,eAAsB,aACpB,MACA,OACA,YAAiC,CAAA,GACrB;;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,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,MAAM,gBAAgB,SAAS,MAAM,KAAK,SAAS,UAAU,EAAE;AAAA,EAC3E;AAEA,QAAM,SAAS,MAAM,SAAS,KAAA;AAC9B,OAAI,YAAO,WAAP,mBAAe,QAAQ;AACzB,UAAM,IAAI,MAAM,kBAAkB,OAAO,OAAO,CAAC,EAAE,OAAO,EAAE;AAAA,EAC9D;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;"}
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
*
|
|
9
9
|
* Published as the `@athenaintel/react/chat-ui/statewire` sub-path.
|
|
10
10
|
*/
|
|
11
|
-
export { StatewireApprovalCard, type StatewireApprovalCardProps, type StatewireApprovalRequestContext, } from "../chat/StatewireApprovalCard";
|
|
11
|
+
export { StatewireApprovalCard, type StatewireApprovalCardProps, type StatewireApprovalEditorContext, type StatewireApprovalRequestContext, } from "../chat/StatewireApprovalCard";
|
|
12
12
|
export { type StatewireApprovalRequest, type StatewireInterruptPredicate, type UseStatewireApprovalRequestOptions, useStatewireApprovalRequest, } from "../chat/use-statewire-approval-request";
|
|
13
13
|
export { StatewireQueuedMessages, type StatewireQueueEditorContext, type StatewireQueueEvent, type StatewireQueueRowContentContext, type StatewireQueuedMessagesProps, } from "../chat/StatewireQueuedMessages";
|
|
14
14
|
export { HistoryEdgeRow, type HistoryEdgeRowProps, StatewireHistoryEdge, type StatewireHistoryEdgeProps, } from "./thread/statewire-history-edge";
|
package/dist/collab/mint.cjs
CHANGED
|
@@ -3,6 +3,7 @@ var __defProp = Object.defineProperty;
|
|
|
3
3
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
4
4
|
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
5
5
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
6
|
+
const credentialRenewal = require("../runtime/credential-renewal.cjs");
|
|
6
7
|
class CollabTokenError extends Error {
|
|
7
8
|
constructor(status, message) {
|
|
8
9
|
super(message);
|
|
@@ -11,15 +12,6 @@ class CollabTokenError extends Error {
|
|
|
11
12
|
this.status = status;
|
|
12
13
|
}
|
|
13
14
|
}
|
|
14
|
-
function getCollabAuthHeaders(auth) {
|
|
15
|
-
if (auth.token) {
|
|
16
|
-
return { Authorization: `Bearer ${auth.token}` };
|
|
17
|
-
}
|
|
18
|
-
if (auth.apiKey) {
|
|
19
|
-
return { "X-API-KEY": auth.apiKey };
|
|
20
|
-
}
|
|
21
|
-
return {};
|
|
22
|
-
}
|
|
23
15
|
async function collabErrorFromResponse(response, fallback) {
|
|
24
16
|
let detail = "";
|
|
25
17
|
try {
|
|
@@ -36,17 +28,17 @@ function getAthenaApiBaseUrl(backendUrl) {
|
|
|
36
28
|
}
|
|
37
29
|
async function mintCollabToken(args) {
|
|
38
30
|
const base = getAthenaApiBaseUrl(args.auth.backendUrl);
|
|
39
|
-
const response = await
|
|
40
|
-
|
|
41
|
-
{
|
|
31
|
+
const response = await credentialRenewal.sendWithCredentialRenewal(
|
|
32
|
+
args.auth,
|
|
33
|
+
(headers) => fetch(`${base}/api/v0/assets/${encodeURIComponent(args.assetId)}/collab-token`, {
|
|
42
34
|
method: "POST",
|
|
43
35
|
headers: {
|
|
44
36
|
"Content-Type": "application/json",
|
|
45
|
-
...
|
|
37
|
+
...headers
|
|
46
38
|
},
|
|
47
39
|
body: JSON.stringify({ access: args.access }),
|
|
48
40
|
signal: args.signal
|
|
49
|
-
}
|
|
41
|
+
})
|
|
50
42
|
);
|
|
51
43
|
if (!response.ok) {
|
|
52
44
|
throw await collabErrorFromResponse(
|
|
@@ -59,6 +51,5 @@ async function mintCollabToken(args) {
|
|
|
59
51
|
exports.CollabTokenError = CollabTokenError;
|
|
60
52
|
exports.collabErrorFromResponse = collabErrorFromResponse;
|
|
61
53
|
exports.getAthenaApiBaseUrl = getAthenaApiBaseUrl;
|
|
62
|
-
exports.getCollabAuthHeaders = getCollabAuthHeaders;
|
|
63
54
|
exports.mintCollabToken = mintCollabToken;
|
|
64
55
|
//# sourceMappingURL=mint.cjs.map
|
package/dist/collab/mint.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mint.cjs","sources":["../../src/collab/mint.ts"],"sourcesContent":["/**\n * Collab-token mint client for Generic Doc assets.\n *\n * Calls `POST /api/v0/assets/{assetId}/collab-token` — the only public surface\n * that issues Keryx capability tokens, allowlisted server-side to the\n * `generic_doc` asset type and admin-only during the initial rollout. Tokens\n * are room-bound and short-lived; `connectGenericDoc` re-mints automatically\n * before expiry.\n */\n\nexport interface CollabAuth {\n /** Athena API base or any Athena backend URL (e.g. the AthenaProvider `backendUrl`). */\n backendUrl: string;\n /** Personal or sandbox API key. Used when no bearer token is provided. */\n apiKey?: string;\n /** Per-viewer bearer token. Takes precedence over the API key. */\n token?: string | null;\n}\n\nexport interface CollabTokenResponse {\n token: string;\n access_type: 'r' | 'rw';\n expires_at_ms: number;\n ws_url: string;\n rest_url: string;\n org: string;\n doc_id: string;\n branch: string;\n}\n\nexport class CollabTokenError extends Error {\n readonly status: number;\n\n constructor(status: number, message: string) {\n super(message);\n this.name = 'CollabTokenError';\n this.status = status;\n }\n}\n\n/**\n * Credential headers for a public-API call. The per-viewer bearer token wins\n * over the API key so a viewer never acts with the app's own identity.\n */\nexport function getCollabAuthHeaders(auth: CollabAuth): Record<string, string> {\n if (auth.token) {\n return { Authorization: `Bearer ${auth.token}` };\n }\n if (auth.apiKey) {\n return { 'X-API-KEY': auth.apiKey };\n }\n return {};\n}\n\n/**\n * Turn a non-2xx public-API response into a `CollabTokenError`, carrying the\n * FastAPI `detail` string when the body has one and the bare status otherwise.\n */\nexport async function collabErrorFromResponse(\n response: Response,\n fallback: string\n): Promise<CollabTokenError> {\n let detail = '';\n try {\n const body: unknown = await response.json();\n if (body && typeof body === 'object' && 'detail' in body) {\n detail = String((body as { detail: unknown }).detail);\n }\n } catch {\n // non-JSON error body; status alone tells the story\n }\n return new CollabTokenError(response.status, detail || fallback);\n}\n\n/**\n * Trim a nested Athena endpoint back to the API origin. Accepts the\n * AthenaProvider `backendUrl` (`…/api/assistant-ui`), the sandbox\n * `ATHENA_API_URL` convention (`…/api/v0`), or a bare origin.\n */\nexport function getAthenaApiBaseUrl(backendUrl: string): string {\n return backendUrl\n .replace(/\\/api\\/assistant-ui\\/?$/, '')\n .replace(/\\/api\\/v0\\/?$/, '')\n .replace(/\\/$/, '');\n}\n\nexport async function mintCollabToken(args: {\n auth: CollabAuth;\n assetId: string;\n access: 'view' | 'edit';\n signal?: AbortSignal;\n}): Promise<CollabTokenResponse> {\n const base = getAthenaApiBaseUrl(args.auth.backendUrl);\n const response = await
|
|
1
|
+
{"version":3,"file":"mint.cjs","sources":["../../src/collab/mint.ts"],"sourcesContent":["/**\n * Collab-token mint client for Generic Doc assets.\n *\n * Calls `POST /api/v0/assets/{assetId}/collab-token` — the only public surface\n * that issues Keryx capability tokens, allowlisted server-side to the\n * `generic_doc` asset type and admin-only during the initial rollout. Tokens\n * are room-bound and short-lived; `connectGenericDoc` re-mints automatically\n * before expiry.\n */\n\nimport { sendWithCredentialRenewal } from '../runtime/credential-renewal';\nimport type { AthenaStatewireTokenGetter } from '../runtime/statewire-auth-headers';\n\nexport interface CollabAuth {\n /** Athena API base or any Athena backend URL (e.g. the AthenaProvider `backendUrl`). */\n backendUrl: string;\n /** Personal or sandbox API key. Used when no bearer token is provided. */\n apiKey?: string;\n /** Per-viewer bearer token. Takes precedence over the API key. */\n token?: string | null;\n /**\n * Live token resolver (the AthenaProvider's `getToken`), read before every\n * mint so a re-mint never presents a rotated-out token; called with\n * `{ force: true }` after a 401 to renew it. Takes precedence over `token`\n * when it resolves one.\n */\n getToken?: AthenaStatewireTokenGetter;\n}\n\nexport interface CollabTokenResponse {\n token: string;\n access_type: 'r' | 'rw';\n expires_at_ms: number;\n ws_url: string;\n rest_url: string;\n org: string;\n doc_id: string;\n branch: string;\n}\n\nexport class CollabTokenError extends Error {\n readonly status: number;\n\n constructor(status: number, message: string) {\n super(message);\n this.name = 'CollabTokenError';\n this.status = status;\n }\n}\n\n/**\n * Credential headers for a public-API call. The per-viewer bearer token wins\n * over the API key so a viewer never acts with the app's own identity.\n */\nexport function getCollabAuthHeaders(auth: CollabAuth): Record<string, string> {\n if (auth.token) {\n return { Authorization: `Bearer ${auth.token}` };\n }\n if (auth.apiKey) {\n return { 'X-API-KEY': auth.apiKey };\n }\n return {};\n}\n\n/**\n * Turn a non-2xx public-API response into a `CollabTokenError`, carrying the\n * FastAPI `detail` string when the body has one and the bare status otherwise.\n */\nexport async function collabErrorFromResponse(\n response: Response,\n fallback: string\n): Promise<CollabTokenError> {\n let detail = '';\n try {\n const body: unknown = await response.json();\n if (body && typeof body === 'object' && 'detail' in body) {\n detail = String((body as { detail: unknown }).detail);\n }\n } catch {\n // non-JSON error body; status alone tells the story\n }\n return new CollabTokenError(response.status, detail || fallback);\n}\n\n/**\n * Trim a nested Athena endpoint back to the API origin. Accepts the\n * AthenaProvider `backendUrl` (`…/api/assistant-ui`), the sandbox\n * `ATHENA_API_URL` convention (`…/api/v0`), or a bare origin.\n */\nexport function getAthenaApiBaseUrl(backendUrl: string): string {\n return backendUrl\n .replace(/\\/api\\/assistant-ui\\/?$/, '')\n .replace(/\\/api\\/v0\\/?$/, '')\n .replace(/\\/$/, '');\n}\n\nexport async function mintCollabToken(args: {\n auth: CollabAuth;\n assetId: string;\n access: 'view' | 'edit';\n signal?: AbortSignal;\n}): Promise<CollabTokenResponse> {\n const base = getAthenaApiBaseUrl(args.auth.backendUrl);\n const response = await sendWithCredentialRenewal(args.auth, (headers) =>\n fetch(`${base}/api/v0/assets/${encodeURIComponent(args.assetId)}/collab-token`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n ...headers,\n },\n body: JSON.stringify({ access: args.access }),\n signal: args.signal,\n })\n );\n if (!response.ok) {\n throw await collabErrorFromResponse(\n response,\n `Collab token mint failed with status ${response.status}`\n );\n }\n return (await response.json()) as CollabTokenResponse;\n}\n"],"names":["sendWithCredentialRenewal"],"mappings":";;;;;;AAwCO,MAAM,yBAAyB,MAAM;AAAA,EAG1C,YAAY,QAAgB,SAAiB;AAC3C,UAAM,OAAO;AAHN;AAIP,SAAK,OAAO;AACZ,SAAK,SAAS;AAAA,EAChB;AACF;AAoBA,eAAsB,wBACpB,UACA,UAC2B;AAC3B,MAAI,SAAS;AACb,MAAI;AACF,UAAM,OAAgB,MAAM,SAAS,KAAA;AACrC,QAAI,QAAQ,OAAO,SAAS,YAAY,YAAY,MAAM;AACxD,eAAS,OAAQ,KAA6B,MAAM;AAAA,IACtD;AAAA,EACF,QAAQ;AAAA,EAER;AACA,SAAO,IAAI,iBAAiB,SAAS,QAAQ,UAAU,QAAQ;AACjE;AAOO,SAAS,oBAAoB,YAA4B;AAC9D,SAAO,WACJ,QAAQ,2BAA2B,EAAE,EACrC,QAAQ,iBAAiB,EAAE,EAC3B,QAAQ,OAAO,EAAE;AACtB;AAEA,eAAsB,gBAAgB,MAKL;AAC/B,QAAM,OAAO,oBAAoB,KAAK,KAAK,UAAU;AACrD,QAAM,WAAW,MAAMA,kBAAAA;AAAAA,IAA0B,KAAK;AAAA,IAAM,CAAC,YAC3D,MAAM,GAAG,IAAI,kBAAkB,mBAAmB,KAAK,OAAO,CAAC,iBAAiB;AAAA,MAC9E,QAAQ;AAAA,MACR,SAAS;AAAA,QACP,gBAAgB;AAAA,QAChB,GAAG;AAAA,MAAA;AAAA,MAEL,MAAM,KAAK,UAAU,EAAE,QAAQ,KAAK,QAAQ;AAAA,MAC5C,QAAQ,KAAK;AAAA,IAAA,CACd;AAAA,EAAA;AAEH,MAAI,CAAC,SAAS,IAAI;AAChB,UAAM,MAAM;AAAA,MACV;AAAA,MACA,wCAAwC,SAAS,MAAM;AAAA,IAAA;AAAA,EAE3D;AACA,SAAQ,MAAM,SAAS,KAAA;AACzB;;;;;"}
|
package/dist/collab/mint.d.ts
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
* are room-bound and short-lived; `connectGenericDoc` re-mints automatically
|
|
8
8
|
* before expiry.
|
|
9
9
|
*/
|
|
10
|
+
import type { AthenaStatewireTokenGetter } from '../runtime/statewire-auth-headers';
|
|
10
11
|
export interface CollabAuth {
|
|
11
12
|
/** Athena API base or any Athena backend URL (e.g. the AthenaProvider `backendUrl`). */
|
|
12
13
|
backendUrl: string;
|
|
@@ -14,6 +15,13 @@ export interface CollabAuth {
|
|
|
14
15
|
apiKey?: string;
|
|
15
16
|
/** Per-viewer bearer token. Takes precedence over the API key. */
|
|
16
17
|
token?: string | null;
|
|
18
|
+
/**
|
|
19
|
+
* Live token resolver (the AthenaProvider's `getToken`), read before every
|
|
20
|
+
* mint so a re-mint never presents a rotated-out token; called with
|
|
21
|
+
* `{ force: true }` after a 401 to renew it. Takes precedence over `token`
|
|
22
|
+
* when it resolves one.
|
|
23
|
+
*/
|
|
24
|
+
getToken?: AthenaStatewireTokenGetter;
|
|
17
25
|
}
|
|
18
26
|
export interface CollabTokenResponse {
|
|
19
27
|
token: string;
|
package/dist/collab/mint.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
var __defProp = Object.defineProperty;
|
|
2
2
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
3
3
|
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
4
|
+
import { sendWithCredentialRenewal } from "../runtime/credential-renewal.js";
|
|
4
5
|
class CollabTokenError extends Error {
|
|
5
6
|
constructor(status, message) {
|
|
6
7
|
super(message);
|
|
@@ -9,15 +10,6 @@ class CollabTokenError extends Error {
|
|
|
9
10
|
this.status = status;
|
|
10
11
|
}
|
|
11
12
|
}
|
|
12
|
-
function getCollabAuthHeaders(auth) {
|
|
13
|
-
if (auth.token) {
|
|
14
|
-
return { Authorization: `Bearer ${auth.token}` };
|
|
15
|
-
}
|
|
16
|
-
if (auth.apiKey) {
|
|
17
|
-
return { "X-API-KEY": auth.apiKey };
|
|
18
|
-
}
|
|
19
|
-
return {};
|
|
20
|
-
}
|
|
21
13
|
async function collabErrorFromResponse(response, fallback) {
|
|
22
14
|
let detail = "";
|
|
23
15
|
try {
|
|
@@ -34,17 +26,17 @@ function getAthenaApiBaseUrl(backendUrl) {
|
|
|
34
26
|
}
|
|
35
27
|
async function mintCollabToken(args) {
|
|
36
28
|
const base = getAthenaApiBaseUrl(args.auth.backendUrl);
|
|
37
|
-
const response = await
|
|
38
|
-
|
|
39
|
-
{
|
|
29
|
+
const response = await sendWithCredentialRenewal(
|
|
30
|
+
args.auth,
|
|
31
|
+
(headers) => fetch(`${base}/api/v0/assets/${encodeURIComponent(args.assetId)}/collab-token`, {
|
|
40
32
|
method: "POST",
|
|
41
33
|
headers: {
|
|
42
34
|
"Content-Type": "application/json",
|
|
43
|
-
...
|
|
35
|
+
...headers
|
|
44
36
|
},
|
|
45
37
|
body: JSON.stringify({ access: args.access }),
|
|
46
38
|
signal: args.signal
|
|
47
|
-
}
|
|
39
|
+
})
|
|
48
40
|
);
|
|
49
41
|
if (!response.ok) {
|
|
50
42
|
throw await collabErrorFromResponse(
|
|
@@ -58,7 +50,6 @@ export {
|
|
|
58
50
|
CollabTokenError,
|
|
59
51
|
collabErrorFromResponse,
|
|
60
52
|
getAthenaApiBaseUrl,
|
|
61
|
-
getCollabAuthHeaders,
|
|
62
53
|
mintCollabToken
|
|
63
54
|
};
|
|
64
55
|
//# sourceMappingURL=mint.js.map
|
package/dist/collab/mint.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mint.js","sources":["../../src/collab/mint.ts"],"sourcesContent":["/**\n * Collab-token mint client for Generic Doc assets.\n *\n * Calls `POST /api/v0/assets/{assetId}/collab-token` — the only public surface\n * that issues Keryx capability tokens, allowlisted server-side to the\n * `generic_doc` asset type and admin-only during the initial rollout. Tokens\n * are room-bound and short-lived; `connectGenericDoc` re-mints automatically\n * before expiry.\n */\n\nexport interface CollabAuth {\n /** Athena API base or any Athena backend URL (e.g. the AthenaProvider `backendUrl`). */\n backendUrl: string;\n /** Personal or sandbox API key. Used when no bearer token is provided. */\n apiKey?: string;\n /** Per-viewer bearer token. Takes precedence over the API key. */\n token?: string | null;\n}\n\nexport interface CollabTokenResponse {\n token: string;\n access_type: 'r' | 'rw';\n expires_at_ms: number;\n ws_url: string;\n rest_url: string;\n org: string;\n doc_id: string;\n branch: string;\n}\n\nexport class CollabTokenError extends Error {\n readonly status: number;\n\n constructor(status: number, message: string) {\n super(message);\n this.name = 'CollabTokenError';\n this.status = status;\n }\n}\n\n/**\n * Credential headers for a public-API call. The per-viewer bearer token wins\n * over the API key so a viewer never acts with the app's own identity.\n */\nexport function getCollabAuthHeaders(auth: CollabAuth): Record<string, string> {\n if (auth.token) {\n return { Authorization: `Bearer ${auth.token}` };\n }\n if (auth.apiKey) {\n return { 'X-API-KEY': auth.apiKey };\n }\n return {};\n}\n\n/**\n * Turn a non-2xx public-API response into a `CollabTokenError`, carrying the\n * FastAPI `detail` string when the body has one and the bare status otherwise.\n */\nexport async function collabErrorFromResponse(\n response: Response,\n fallback: string\n): Promise<CollabTokenError> {\n let detail = '';\n try {\n const body: unknown = await response.json();\n if (body && typeof body === 'object' && 'detail' in body) {\n detail = String((body as { detail: unknown }).detail);\n }\n } catch {\n // non-JSON error body; status alone tells the story\n }\n return new CollabTokenError(response.status, detail || fallback);\n}\n\n/**\n * Trim a nested Athena endpoint back to the API origin. Accepts the\n * AthenaProvider `backendUrl` (`…/api/assistant-ui`), the sandbox\n * `ATHENA_API_URL` convention (`…/api/v0`), or a bare origin.\n */\nexport function getAthenaApiBaseUrl(backendUrl: string): string {\n return backendUrl\n .replace(/\\/api\\/assistant-ui\\/?$/, '')\n .replace(/\\/api\\/v0\\/?$/, '')\n .replace(/\\/$/, '');\n}\n\nexport async function mintCollabToken(args: {\n auth: CollabAuth;\n assetId: string;\n access: 'view' | 'edit';\n signal?: AbortSignal;\n}): Promise<CollabTokenResponse> {\n const base = getAthenaApiBaseUrl(args.auth.backendUrl);\n const response = await
|
|
1
|
+
{"version":3,"file":"mint.js","sources":["../../src/collab/mint.ts"],"sourcesContent":["/**\n * Collab-token mint client for Generic Doc assets.\n *\n * Calls `POST /api/v0/assets/{assetId}/collab-token` — the only public surface\n * that issues Keryx capability tokens, allowlisted server-side to the\n * `generic_doc` asset type and admin-only during the initial rollout. Tokens\n * are room-bound and short-lived; `connectGenericDoc` re-mints automatically\n * before expiry.\n */\n\nimport { sendWithCredentialRenewal } from '../runtime/credential-renewal';\nimport type { AthenaStatewireTokenGetter } from '../runtime/statewire-auth-headers';\n\nexport interface CollabAuth {\n /** Athena API base or any Athena backend URL (e.g. the AthenaProvider `backendUrl`). */\n backendUrl: string;\n /** Personal or sandbox API key. Used when no bearer token is provided. */\n apiKey?: string;\n /** Per-viewer bearer token. Takes precedence over the API key. */\n token?: string | null;\n /**\n * Live token resolver (the AthenaProvider's `getToken`), read before every\n * mint so a re-mint never presents a rotated-out token; called with\n * `{ force: true }` after a 401 to renew it. Takes precedence over `token`\n * when it resolves one.\n */\n getToken?: AthenaStatewireTokenGetter;\n}\n\nexport interface CollabTokenResponse {\n token: string;\n access_type: 'r' | 'rw';\n expires_at_ms: number;\n ws_url: string;\n rest_url: string;\n org: string;\n doc_id: string;\n branch: string;\n}\n\nexport class CollabTokenError extends Error {\n readonly status: number;\n\n constructor(status: number, message: string) {\n super(message);\n this.name = 'CollabTokenError';\n this.status = status;\n }\n}\n\n/**\n * Credential headers for a public-API call. The per-viewer bearer token wins\n * over the API key so a viewer never acts with the app's own identity.\n */\nexport function getCollabAuthHeaders(auth: CollabAuth): Record<string, string> {\n if (auth.token) {\n return { Authorization: `Bearer ${auth.token}` };\n }\n if (auth.apiKey) {\n return { 'X-API-KEY': auth.apiKey };\n }\n return {};\n}\n\n/**\n * Turn a non-2xx public-API response into a `CollabTokenError`, carrying the\n * FastAPI `detail` string when the body has one and the bare status otherwise.\n */\nexport async function collabErrorFromResponse(\n response: Response,\n fallback: string\n): Promise<CollabTokenError> {\n let detail = '';\n try {\n const body: unknown = await response.json();\n if (body && typeof body === 'object' && 'detail' in body) {\n detail = String((body as { detail: unknown }).detail);\n }\n } catch {\n // non-JSON error body; status alone tells the story\n }\n return new CollabTokenError(response.status, detail || fallback);\n}\n\n/**\n * Trim a nested Athena endpoint back to the API origin. Accepts the\n * AthenaProvider `backendUrl` (`…/api/assistant-ui`), the sandbox\n * `ATHENA_API_URL` convention (`…/api/v0`), or a bare origin.\n */\nexport function getAthenaApiBaseUrl(backendUrl: string): string {\n return backendUrl\n .replace(/\\/api\\/assistant-ui\\/?$/, '')\n .replace(/\\/api\\/v0\\/?$/, '')\n .replace(/\\/$/, '');\n}\n\nexport async function mintCollabToken(args: {\n auth: CollabAuth;\n assetId: string;\n access: 'view' | 'edit';\n signal?: AbortSignal;\n}): Promise<CollabTokenResponse> {\n const base = getAthenaApiBaseUrl(args.auth.backendUrl);\n const response = await sendWithCredentialRenewal(args.auth, (headers) =>\n fetch(`${base}/api/v0/assets/${encodeURIComponent(args.assetId)}/collab-token`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n ...headers,\n },\n body: JSON.stringify({ access: args.access }),\n signal: args.signal,\n })\n );\n if (!response.ok) {\n throw await collabErrorFromResponse(\n response,\n `Collab token mint failed with status ${response.status}`\n );\n }\n return (await response.json()) as CollabTokenResponse;\n}\n"],"names":[],"mappings":";;;;AAwCO,MAAM,yBAAyB,MAAM;AAAA,EAG1C,YAAY,QAAgB,SAAiB;AAC3C,UAAM,OAAO;AAHN;AAIP,SAAK,OAAO;AACZ,SAAK,SAAS;AAAA,EAChB;AACF;AAoBA,eAAsB,wBACpB,UACA,UAC2B;AAC3B,MAAI,SAAS;AACb,MAAI;AACF,UAAM,OAAgB,MAAM,SAAS,KAAA;AACrC,QAAI,QAAQ,OAAO,SAAS,YAAY,YAAY,MAAM;AACxD,eAAS,OAAQ,KAA6B,MAAM;AAAA,IACtD;AAAA,EACF,QAAQ;AAAA,EAER;AACA,SAAO,IAAI,iBAAiB,SAAS,QAAQ,UAAU,QAAQ;AACjE;AAOO,SAAS,oBAAoB,YAA4B;AAC9D,SAAO,WACJ,QAAQ,2BAA2B,EAAE,EACrC,QAAQ,iBAAiB,EAAE,EAC3B,QAAQ,OAAO,EAAE;AACtB;AAEA,eAAsB,gBAAgB,MAKL;AAC/B,QAAM,OAAO,oBAAoB,KAAK,KAAK,UAAU;AACrD,QAAM,WAAW,MAAM;AAAA,IAA0B,KAAK;AAAA,IAAM,CAAC,YAC3D,MAAM,GAAG,IAAI,kBAAkB,mBAAmB,KAAK,OAAO,CAAC,iBAAiB;AAAA,MAC9E,QAAQ;AAAA,MACR,SAAS;AAAA,QACP,gBAAgB;AAAA,QAChB,GAAG;AAAA,MAAA;AAAA,MAEL,MAAM,KAAK,UAAU,EAAE,QAAQ,KAAK,QAAQ;AAAA,MAC5C,QAAQ,KAAK;AAAA,IAAA,CACd;AAAA,EAAA;AAEH,MAAI,CAAC,SAAS,IAAI;AAChB,UAAM,MAAM;AAAA,MACV;AAAA,MACA,wCAAwC,SAAS,MAAM;AAAA,IAAA;AAAA,EAE3D;AACA,SAAQ,MAAM,SAAS,KAAA;AACzB;"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const credentialRenewal = require("../runtime/credential-renewal.cjs");
|
|
3
4
|
const mint = require("./mint.cjs");
|
|
4
5
|
function workspaceUrl({
|
|
5
6
|
auth,
|
|
@@ -10,17 +11,17 @@ function workspaceUrl({
|
|
|
10
11
|
return `${base}/api/v0/workspaces/${encodeURIComponent(workspaceId)}/${path}`;
|
|
11
12
|
}
|
|
12
13
|
async function mintWorkspacePresenceToken(args) {
|
|
13
|
-
const response = await
|
|
14
|
-
|
|
15
|
-
{
|
|
14
|
+
const response = await credentialRenewal.sendWithCredentialRenewal(
|
|
15
|
+
args.auth,
|
|
16
|
+
(headers) => fetch(workspaceUrl({ auth: args.auth, workspaceId: args.workspaceId, path: "presence-token" }), {
|
|
16
17
|
method: "POST",
|
|
17
18
|
headers: {
|
|
18
19
|
"Content-Type": "application/json",
|
|
19
|
-
...
|
|
20
|
+
...headers
|
|
20
21
|
},
|
|
21
22
|
body: JSON.stringify({}),
|
|
22
23
|
signal: args.signal
|
|
23
|
-
}
|
|
24
|
+
})
|
|
24
25
|
);
|
|
25
26
|
if (!response.ok) {
|
|
26
27
|
throw await mint.collabErrorFromResponse(
|
|
@@ -34,17 +35,20 @@ function arrayOrEmpty(value) {
|
|
|
34
35
|
return Array.isArray(value) ? value : [];
|
|
35
36
|
}
|
|
36
37
|
async function resolveWorkspacePresence(args) {
|
|
37
|
-
const response = await
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
38
|
+
const response = await credentialRenewal.sendWithCredentialRenewal(
|
|
39
|
+
args.auth,
|
|
40
|
+
(headers) => fetch(
|
|
41
|
+
workspaceUrl({ auth: args.auth, workspaceId: args.workspaceId, path: "presence/resolve" }),
|
|
42
|
+
{
|
|
43
|
+
method: "POST",
|
|
44
|
+
headers: {
|
|
45
|
+
"Content-Type": "application/json",
|
|
46
|
+
...headers
|
|
47
|
+
},
|
|
48
|
+
body: JSON.stringify(args.request),
|
|
49
|
+
signal: args.signal
|
|
50
|
+
}
|
|
51
|
+
)
|
|
48
52
|
);
|
|
49
53
|
if (!response.ok) {
|
|
50
54
|
throw await mint.collabErrorFromResponse(
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"presence-mint.cjs","sources":["../../src/collab/presence-mint.ts"],"sourcesContent":["/**\n * Public-API clients for the workspace presence feed.\n *\n * Two endpoints, both admin-only and both under the workspace:\n *\n * - `POST /api/v0/workspaces/{workspaceId}/presence-token` mints a\n * **read-only** Keryx token for the workspace awareness room\n * (`<workspaceId>/awareness`) — the same per-recipient-filtered presence\n * feed the Olympus People page renders. The holder can receive presence and\n * broadcast nothing; `connectWorkspacePresence` re-mints before expiry.\n * - `POST /api/v0/workspaces/{workspaceId}/presence/resolve` turns the opaque\n * ids carried in awareness contexts (asset ids, session thread ids, project\n * ids) into titles the caller may see. Only things the caller may open come\n * back; missing ids are simply absent.\n *\n * Wire shapes are snake_case, matching `CollabTokenResponse`.\n */\n\nimport {\n type CollabAuth,\n CollabTokenError,\n collabErrorFromResponse,\n getAthenaApiBaseUrl,\n
|
|
1
|
+
{"version":3,"file":"presence-mint.cjs","sources":["../../src/collab/presence-mint.ts"],"sourcesContent":["/**\n * Public-API clients for the workspace presence feed.\n *\n * Two endpoints, both admin-only and both under the workspace:\n *\n * - `POST /api/v0/workspaces/{workspaceId}/presence-token` mints a\n * **read-only** Keryx token for the workspace awareness room\n * (`<workspaceId>/awareness`) — the same per-recipient-filtered presence\n * feed the Olympus People page renders. The holder can receive presence and\n * broadcast nothing; `connectWorkspacePresence` re-mints before expiry.\n * - `POST /api/v0/workspaces/{workspaceId}/presence/resolve` turns the opaque\n * ids carried in awareness contexts (asset ids, session thread ids, project\n * ids) into titles the caller may see. Only things the caller may open come\n * back; missing ids are simply absent.\n *\n * Wire shapes are snake_case, matching `CollabTokenResponse`.\n */\n\nimport { sendWithCredentialRenewal } from '../runtime/credential-renewal';\nimport {\n type CollabAuth,\n CollabTokenError,\n collabErrorFromResponse,\n getAthenaApiBaseUrl,\n} from './mint';\n\n/** Grant for the workspace awareness room. Always read-only (`access_type: 'r'`). */\nexport interface WorkspacePresenceTokenResponse {\n token: string;\n access_type: 'r' | 'rw';\n expires_at_ms: number;\n ws_url: string;\n org: string;\n doc_id: string;\n branch: string;\n}\n\nexport interface WorkspacePresenceResolveRequest {\n asset_ids?: string[];\n /** Thread ids, as published in `session` awareness contexts. */\n session_ids?: string[];\n project_ids?: string[];\n include_projects?: boolean;\n include_members?: boolean;\n}\n\nexport interface WorkspacePresenceResolvedAsset {\n id: string;\n title: string;\n asset_type: string;\n}\n\nexport interface WorkspacePresenceResolvedSession {\n thread_id: string;\n asset_id: string;\n title: string;\n}\n\nexport interface WorkspacePresenceResolvedProject {\n id: string;\n title: string;\n assets: WorkspacePresenceResolvedAsset[];\n}\n\nexport interface WorkspacePresenceResolvedMember {\n id: string;\n name: string;\n email: string;\n avatar_url: string | null;\n}\n\nexport interface WorkspacePresenceResolveResponse {\n assets: WorkspacePresenceResolvedAsset[];\n sessions: WorkspacePresenceResolvedSession[];\n projects: WorkspacePresenceResolvedProject[];\n members: WorkspacePresenceResolvedMember[];\n}\n\nfunction workspaceUrl({\n auth,\n workspaceId,\n path,\n}: {\n auth: CollabAuth;\n workspaceId: string;\n path: string;\n}): string {\n const base = getAthenaApiBaseUrl(auth.backendUrl);\n return `${base}/api/v0/workspaces/${encodeURIComponent(workspaceId)}/${path}`;\n}\n\n/**\n * Mint a read-only token for the workspace awareness room.\n *\n * Rejects with `CollabTokenError` on 401 (bad credential) and 403 (admin\n * required, roster not enabled for this workspace, or a sandbox credential\n * that may not read presence), carrying the server's `detail`.\n */\nexport async function mintWorkspacePresenceToken(args: {\n auth: CollabAuth;\n workspaceId: string;\n signal?: AbortSignal;\n}): Promise<WorkspacePresenceTokenResponse> {\n const response = await sendWithCredentialRenewal(args.auth, (headers) =>\n fetch(workspaceUrl({ auth: args.auth, workspaceId: args.workspaceId, path: 'presence-token' }), {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n ...headers,\n },\n body: JSON.stringify({}),\n signal: args.signal,\n })\n );\n if (!response.ok) {\n throw await collabErrorFromResponse(\n response,\n `Workspace presence token mint failed with status ${response.status}`\n );\n }\n return (await response.json()) as WorkspacePresenceTokenResponse;\n}\n\nfunction arrayOrEmpty<T>(value: T[] | undefined | null): T[] {\n return Array.isArray(value) ? value : [];\n}\n\n/**\n * Resolve awareness ids to titles. Every section of the response is always\n * present on the returned object (an omitted section reads as empty), so\n * callers can index without guarding. Failures reject with `CollabTokenError`\n * — the same status + detail shape as the mint.\n */\nexport async function resolveWorkspacePresence(args: {\n auth: CollabAuth;\n workspaceId: string;\n request: WorkspacePresenceResolveRequest;\n signal?: AbortSignal;\n}): Promise<WorkspacePresenceResolveResponse> {\n const response = await sendWithCredentialRenewal(args.auth, (headers) =>\n fetch(\n workspaceUrl({ auth: args.auth, workspaceId: args.workspaceId, path: 'presence/resolve' }),\n {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n ...headers,\n },\n body: JSON.stringify(args.request),\n signal: args.signal,\n }\n )\n );\n if (!response.ok) {\n throw await collabErrorFromResponse(\n response,\n `Workspace presence resolve failed with status ${response.status}`\n );\n }\n const body = (await response.json()) as Partial<WorkspacePresenceResolveResponse> | null;\n if (!body || typeof body !== 'object') {\n throw new CollabTokenError(response.status, 'Workspace presence resolve returned no body');\n }\n return {\n assets: arrayOrEmpty(body.assets),\n sessions: arrayOrEmpty(body.sessions),\n projects: arrayOrEmpty(body.projects),\n members: arrayOrEmpty(body.members),\n };\n}\n"],"names":["getAthenaApiBaseUrl","sendWithCredentialRenewal","collabErrorFromResponse","CollabTokenError"],"mappings":";;;;AA8EA,SAAS,aAAa;AAAA,EACpB;AAAA,EACA;AAAA,EACA;AACF,GAIW;AACT,QAAM,OAAOA,KAAAA,oBAAoB,KAAK,UAAU;AAChD,SAAO,GAAG,IAAI,sBAAsB,mBAAmB,WAAW,CAAC,IAAI,IAAI;AAC7E;AASA,eAAsB,2BAA2B,MAIL;AAC1C,QAAM,WAAW,MAAMC,kBAAAA;AAAAA,IAA0B,KAAK;AAAA,IAAM,CAAC,YAC3D,MAAM,aAAa,EAAE,MAAM,KAAK,MAAM,aAAa,KAAK,aAAa,MAAM,iBAAA,CAAkB,GAAG;AAAA,MAC9F,QAAQ;AAAA,MACR,SAAS;AAAA,QACP,gBAAgB;AAAA,QAChB,GAAG;AAAA,MAAA;AAAA,MAEL,MAAM,KAAK,UAAU,EAAE;AAAA,MACvB,QAAQ,KAAK;AAAA,IAAA,CACd;AAAA,EAAA;AAEH,MAAI,CAAC,SAAS,IAAI;AAChB,UAAM,MAAMC,KAAAA;AAAAA,MACV;AAAA,MACA,oDAAoD,SAAS,MAAM;AAAA,IAAA;AAAA,EAEvE;AACA,SAAQ,MAAM,SAAS,KAAA;AACzB;AAEA,SAAS,aAAgB,OAAoC;AAC3D,SAAO,MAAM,QAAQ,KAAK,IAAI,QAAQ,CAAA;AACxC;AAQA,eAAsB,yBAAyB,MAKD;AAC5C,QAAM,WAAW,MAAMD,kBAAAA;AAAAA,IAA0B,KAAK;AAAA,IAAM,CAAC,YAC3D;AAAA,MACE,aAAa,EAAE,MAAM,KAAK,MAAM,aAAa,KAAK,aAAa,MAAM,oBAAoB;AAAA,MACzF;AAAA,QACE,QAAQ;AAAA,QACR,SAAS;AAAA,UACP,gBAAgB;AAAA,UAChB,GAAG;AAAA,QAAA;AAAA,QAEL,MAAM,KAAK,UAAU,KAAK,OAAO;AAAA,QACjC,QAAQ,KAAK;AAAA,MAAA;AAAA,IACf;AAAA,EACF;AAEF,MAAI,CAAC,SAAS,IAAI;AAChB,UAAM,MAAMC,KAAAA;AAAAA,MACV;AAAA,MACA,iDAAiD,SAAS,MAAM;AAAA,IAAA;AAAA,EAEpE;AACA,QAAM,OAAQ,MAAM,SAAS,KAAA;AAC7B,MAAI,CAAC,QAAQ,OAAO,SAAS,UAAU;AACrC,UAAM,IAAIC,KAAAA,iBAAiB,SAAS,QAAQ,6CAA6C;AAAA,EAC3F;AACA,SAAO;AAAA,IACL,QAAQ,aAAa,KAAK,MAAM;AAAA,IAChC,UAAU,aAAa,KAAK,QAAQ;AAAA,IACpC,UAAU,aAAa,KAAK,QAAQ;AAAA,IACpC,SAAS,aAAa,KAAK,OAAO;AAAA,EAAA;AAEtC;;;"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { sendWithCredentialRenewal } from "../runtime/credential-renewal.js";
|
|
2
|
+
import { collabErrorFromResponse, CollabTokenError, getAthenaApiBaseUrl } from "./mint.js";
|
|
2
3
|
function workspaceUrl({
|
|
3
4
|
auth,
|
|
4
5
|
workspaceId,
|
|
@@ -8,17 +9,17 @@ function workspaceUrl({
|
|
|
8
9
|
return `${base}/api/v0/workspaces/${encodeURIComponent(workspaceId)}/${path}`;
|
|
9
10
|
}
|
|
10
11
|
async function mintWorkspacePresenceToken(args) {
|
|
11
|
-
const response = await
|
|
12
|
-
|
|
13
|
-
{
|
|
12
|
+
const response = await sendWithCredentialRenewal(
|
|
13
|
+
args.auth,
|
|
14
|
+
(headers) => fetch(workspaceUrl({ auth: args.auth, workspaceId: args.workspaceId, path: "presence-token" }), {
|
|
14
15
|
method: "POST",
|
|
15
16
|
headers: {
|
|
16
17
|
"Content-Type": "application/json",
|
|
17
|
-
...
|
|
18
|
+
...headers
|
|
18
19
|
},
|
|
19
20
|
body: JSON.stringify({}),
|
|
20
21
|
signal: args.signal
|
|
21
|
-
}
|
|
22
|
+
})
|
|
22
23
|
);
|
|
23
24
|
if (!response.ok) {
|
|
24
25
|
throw await collabErrorFromResponse(
|
|
@@ -32,17 +33,20 @@ function arrayOrEmpty(value) {
|
|
|
32
33
|
return Array.isArray(value) ? value : [];
|
|
33
34
|
}
|
|
34
35
|
async function resolveWorkspacePresence(args) {
|
|
35
|
-
const response = await
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
36
|
+
const response = await sendWithCredentialRenewal(
|
|
37
|
+
args.auth,
|
|
38
|
+
(headers) => fetch(
|
|
39
|
+
workspaceUrl({ auth: args.auth, workspaceId: args.workspaceId, path: "presence/resolve" }),
|
|
40
|
+
{
|
|
41
|
+
method: "POST",
|
|
42
|
+
headers: {
|
|
43
|
+
"Content-Type": "application/json",
|
|
44
|
+
...headers
|
|
45
|
+
},
|
|
46
|
+
body: JSON.stringify(args.request),
|
|
47
|
+
signal: args.signal
|
|
48
|
+
}
|
|
49
|
+
)
|
|
46
50
|
);
|
|
47
51
|
if (!response.ok) {
|
|
48
52
|
throw await collabErrorFromResponse(
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"presence-mint.js","sources":["../../src/collab/presence-mint.ts"],"sourcesContent":["/**\n * Public-API clients for the workspace presence feed.\n *\n * Two endpoints, both admin-only and both under the workspace:\n *\n * - `POST /api/v0/workspaces/{workspaceId}/presence-token` mints a\n * **read-only** Keryx token for the workspace awareness room\n * (`<workspaceId>/awareness`) — the same per-recipient-filtered presence\n * feed the Olympus People page renders. The holder can receive presence and\n * broadcast nothing; `connectWorkspacePresence` re-mints before expiry.\n * - `POST /api/v0/workspaces/{workspaceId}/presence/resolve` turns the opaque\n * ids carried in awareness contexts (asset ids, session thread ids, project\n * ids) into titles the caller may see. Only things the caller may open come\n * back; missing ids are simply absent.\n *\n * Wire shapes are snake_case, matching `CollabTokenResponse`.\n */\n\nimport {\n type CollabAuth,\n CollabTokenError,\n collabErrorFromResponse,\n getAthenaApiBaseUrl,\n
|
|
1
|
+
{"version":3,"file":"presence-mint.js","sources":["../../src/collab/presence-mint.ts"],"sourcesContent":["/**\n * Public-API clients for the workspace presence feed.\n *\n * Two endpoints, both admin-only and both under the workspace:\n *\n * - `POST /api/v0/workspaces/{workspaceId}/presence-token` mints a\n * **read-only** Keryx token for the workspace awareness room\n * (`<workspaceId>/awareness`) — the same per-recipient-filtered presence\n * feed the Olympus People page renders. The holder can receive presence and\n * broadcast nothing; `connectWorkspacePresence` re-mints before expiry.\n * - `POST /api/v0/workspaces/{workspaceId}/presence/resolve` turns the opaque\n * ids carried in awareness contexts (asset ids, session thread ids, project\n * ids) into titles the caller may see. Only things the caller may open come\n * back; missing ids are simply absent.\n *\n * Wire shapes are snake_case, matching `CollabTokenResponse`.\n */\n\nimport { sendWithCredentialRenewal } from '../runtime/credential-renewal';\nimport {\n type CollabAuth,\n CollabTokenError,\n collabErrorFromResponse,\n getAthenaApiBaseUrl,\n} from './mint';\n\n/** Grant for the workspace awareness room. Always read-only (`access_type: 'r'`). */\nexport interface WorkspacePresenceTokenResponse {\n token: string;\n access_type: 'r' | 'rw';\n expires_at_ms: number;\n ws_url: string;\n org: string;\n doc_id: string;\n branch: string;\n}\n\nexport interface WorkspacePresenceResolveRequest {\n asset_ids?: string[];\n /** Thread ids, as published in `session` awareness contexts. */\n session_ids?: string[];\n project_ids?: string[];\n include_projects?: boolean;\n include_members?: boolean;\n}\n\nexport interface WorkspacePresenceResolvedAsset {\n id: string;\n title: string;\n asset_type: string;\n}\n\nexport interface WorkspacePresenceResolvedSession {\n thread_id: string;\n asset_id: string;\n title: string;\n}\n\nexport interface WorkspacePresenceResolvedProject {\n id: string;\n title: string;\n assets: WorkspacePresenceResolvedAsset[];\n}\n\nexport interface WorkspacePresenceResolvedMember {\n id: string;\n name: string;\n email: string;\n avatar_url: string | null;\n}\n\nexport interface WorkspacePresenceResolveResponse {\n assets: WorkspacePresenceResolvedAsset[];\n sessions: WorkspacePresenceResolvedSession[];\n projects: WorkspacePresenceResolvedProject[];\n members: WorkspacePresenceResolvedMember[];\n}\n\nfunction workspaceUrl({\n auth,\n workspaceId,\n path,\n}: {\n auth: CollabAuth;\n workspaceId: string;\n path: string;\n}): string {\n const base = getAthenaApiBaseUrl(auth.backendUrl);\n return `${base}/api/v0/workspaces/${encodeURIComponent(workspaceId)}/${path}`;\n}\n\n/**\n * Mint a read-only token for the workspace awareness room.\n *\n * Rejects with `CollabTokenError` on 401 (bad credential) and 403 (admin\n * required, roster not enabled for this workspace, or a sandbox credential\n * that may not read presence), carrying the server's `detail`.\n */\nexport async function mintWorkspacePresenceToken(args: {\n auth: CollabAuth;\n workspaceId: string;\n signal?: AbortSignal;\n}): Promise<WorkspacePresenceTokenResponse> {\n const response = await sendWithCredentialRenewal(args.auth, (headers) =>\n fetch(workspaceUrl({ auth: args.auth, workspaceId: args.workspaceId, path: 'presence-token' }), {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n ...headers,\n },\n body: JSON.stringify({}),\n signal: args.signal,\n })\n );\n if (!response.ok) {\n throw await collabErrorFromResponse(\n response,\n `Workspace presence token mint failed with status ${response.status}`\n );\n }\n return (await response.json()) as WorkspacePresenceTokenResponse;\n}\n\nfunction arrayOrEmpty<T>(value: T[] | undefined | null): T[] {\n return Array.isArray(value) ? value : [];\n}\n\n/**\n * Resolve awareness ids to titles. Every section of the response is always\n * present on the returned object (an omitted section reads as empty), so\n * callers can index without guarding. Failures reject with `CollabTokenError`\n * — the same status + detail shape as the mint.\n */\nexport async function resolveWorkspacePresence(args: {\n auth: CollabAuth;\n workspaceId: string;\n request: WorkspacePresenceResolveRequest;\n signal?: AbortSignal;\n}): Promise<WorkspacePresenceResolveResponse> {\n const response = await sendWithCredentialRenewal(args.auth, (headers) =>\n fetch(\n workspaceUrl({ auth: args.auth, workspaceId: args.workspaceId, path: 'presence/resolve' }),\n {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n ...headers,\n },\n body: JSON.stringify(args.request),\n signal: args.signal,\n }\n )\n );\n if (!response.ok) {\n throw await collabErrorFromResponse(\n response,\n `Workspace presence resolve failed with status ${response.status}`\n );\n }\n const body = (await response.json()) as Partial<WorkspacePresenceResolveResponse> | null;\n if (!body || typeof body !== 'object') {\n throw new CollabTokenError(response.status, 'Workspace presence resolve returned no body');\n }\n return {\n assets: arrayOrEmpty(body.assets),\n sessions: arrayOrEmpty(body.sessions),\n projects: arrayOrEmpty(body.projects),\n members: arrayOrEmpty(body.members),\n };\n}\n"],"names":[],"mappings":";;AA8EA,SAAS,aAAa;AAAA,EACpB;AAAA,EACA;AAAA,EACA;AACF,GAIW;AACT,QAAM,OAAO,oBAAoB,KAAK,UAAU;AAChD,SAAO,GAAG,IAAI,sBAAsB,mBAAmB,WAAW,CAAC,IAAI,IAAI;AAC7E;AASA,eAAsB,2BAA2B,MAIL;AAC1C,QAAM,WAAW,MAAM;AAAA,IAA0B,KAAK;AAAA,IAAM,CAAC,YAC3D,MAAM,aAAa,EAAE,MAAM,KAAK,MAAM,aAAa,KAAK,aAAa,MAAM,iBAAA,CAAkB,GAAG;AAAA,MAC9F,QAAQ;AAAA,MACR,SAAS;AAAA,QACP,gBAAgB;AAAA,QAChB,GAAG;AAAA,MAAA;AAAA,MAEL,MAAM,KAAK,UAAU,EAAE;AAAA,MACvB,QAAQ,KAAK;AAAA,IAAA,CACd;AAAA,EAAA;AAEH,MAAI,CAAC,SAAS,IAAI;AAChB,UAAM,MAAM;AAAA,MACV;AAAA,MACA,oDAAoD,SAAS,MAAM;AAAA,IAAA;AAAA,EAEvE;AACA,SAAQ,MAAM,SAAS,KAAA;AACzB;AAEA,SAAS,aAAgB,OAAoC;AAC3D,SAAO,MAAM,QAAQ,KAAK,IAAI,QAAQ,CAAA;AACxC;AAQA,eAAsB,yBAAyB,MAKD;AAC5C,QAAM,WAAW,MAAM;AAAA,IAA0B,KAAK;AAAA,IAAM,CAAC,YAC3D;AAAA,MACE,aAAa,EAAE,MAAM,KAAK,MAAM,aAAa,KAAK,aAAa,MAAM,oBAAoB;AAAA,MACzF;AAAA,QACE,QAAQ;AAAA,QACR,SAAS;AAAA,UACP,gBAAgB;AAAA,UAChB,GAAG;AAAA,QAAA;AAAA,QAEL,MAAM,KAAK,UAAU,KAAK,OAAO;AAAA,QACjC,QAAQ,KAAK;AAAA,MAAA;AAAA,IACf;AAAA,EACF;AAEF,MAAI,CAAC,SAAS,IAAI;AAChB,UAAM,MAAM;AAAA,MACV;AAAA,MACA,iDAAiD,SAAS,MAAM;AAAA,IAAA;AAAA,EAEpE;AACA,QAAM,OAAQ,MAAM,SAAS,KAAA;AAC7B,MAAI,CAAC,QAAQ,OAAO,SAAS,UAAU;AACrC,UAAM,IAAI,iBAAiB,SAAS,QAAQ,6CAA6C;AAAA,EAC3F;AACA,SAAO;AAAA,IACL,QAAQ,aAAa,KAAK,MAAM;AAAA,IAChC,UAAU,aAAa,KAAK,QAAQ;AAAA,IACpC,UAAU,aAAa,KAAK,QAAQ;AAAA,IACpC,SAAS,aAAa,KAAK,OAAO;AAAA,EAAA;AAEtC;"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
3
|
const react = require("react");
|
|
4
|
+
const AthenaCredentialSourceContext = require("../auth/AthenaCredentialSourceContext.cjs");
|
|
4
5
|
const AthenaContext = require("../provider/AthenaContext.cjs");
|
|
5
6
|
const presenceClient = require("./presence-client.cjs");
|
|
6
7
|
const presenceMint = require("./presence-mint.cjs");
|
|
@@ -11,6 +12,7 @@ const NO_HUMANS = [];
|
|
|
11
12
|
const NO_AGENTS = [];
|
|
12
13
|
function useWorkspacePresence(workspaceId, options) {
|
|
13
14
|
const config = AthenaContext.useAthenaConfig();
|
|
15
|
+
const identityEpoch = AthenaCredentialSourceContext.useAthenaCredentialIdentityEpoch();
|
|
14
16
|
const enabled = (options == null ? void 0 : options.enabled) !== false && workspaceId !== null;
|
|
15
17
|
const tickMs = (options == null ? void 0 : options.tickMs) ?? PRESENCE_DEFAULT_TICK_MS;
|
|
16
18
|
const [entry, setEntry] = react.useState(null);
|
|
@@ -25,7 +27,8 @@ function useWorkspacePresence(workspaceId, options) {
|
|
|
25
27
|
auth: {
|
|
26
28
|
backendUrl: config.backendUrl,
|
|
27
29
|
apiKey: config.apiKey,
|
|
28
|
-
token: config.token
|
|
30
|
+
token: config.token,
|
|
31
|
+
getToken: config.getToken
|
|
29
32
|
}
|
|
30
33
|
});
|
|
31
34
|
handleRef.current = next;
|
|
@@ -34,7 +37,7 @@ function useWorkspacePresence(workspaceId, options) {
|
|
|
34
37
|
handleRef.current = null;
|
|
35
38
|
next.destroy();
|
|
36
39
|
};
|
|
37
|
-
}, [enabled, workspaceId, config.backendUrl, config.apiKey, config.
|
|
40
|
+
}, [enabled, workspaceId, config.backendUrl, config.apiKey, config.getToken, identityEpoch]);
|
|
38
41
|
const handle = enabled && entry !== null && entry.workspaceId === workspaceId ? entry.handle : null;
|
|
39
42
|
const subscribe = react.useMemo(() => {
|
|
40
43
|
return (onStoreChange) => {
|
|
@@ -90,7 +93,6 @@ function useWorkspacePresence(workspaceId, options) {
|
|
|
90
93
|
}
|
|
91
94
|
function useWorkspacePresenceResolver(workspaceId) {
|
|
92
95
|
const config = AthenaContext.useAthenaConfig();
|
|
93
|
-
const { backendUrl, apiKey, token } = config;
|
|
94
96
|
return react.useCallback(
|
|
95
97
|
(request, signal) => {
|
|
96
98
|
if (workspaceId === null) {
|
|
@@ -99,13 +101,18 @@ function useWorkspacePresenceResolver(workspaceId) {
|
|
|
99
101
|
);
|
|
100
102
|
}
|
|
101
103
|
return presenceMint.resolveWorkspacePresence({
|
|
102
|
-
auth: {
|
|
104
|
+
auth: {
|
|
105
|
+
backendUrl: config.backendUrl,
|
|
106
|
+
apiKey: config.apiKey,
|
|
107
|
+
token: config.token,
|
|
108
|
+
getToken: config.getToken
|
|
109
|
+
},
|
|
103
110
|
workspaceId,
|
|
104
111
|
request,
|
|
105
112
|
signal
|
|
106
113
|
});
|
|
107
114
|
},
|
|
108
|
-
[workspaceId,
|
|
115
|
+
[workspaceId, config]
|
|
109
116
|
);
|
|
110
117
|
}
|
|
111
118
|
exports.PRESENCE_DEFAULT_TICK_MS = PRESENCE_DEFAULT_TICK_MS;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"presence-react.cjs","sources":["../../src/collab/presence-react.ts"],"sourcesContent":["/**\n * React bindings for the workspace presence feed.\n *\n * `useWorkspacePresence(workspaceId)` opens (and owns) a\n * `connectWorkspacePresence` handle, resolving auth from the surrounding\n * `AthenaProvider` (per-viewer bearer when present, API key otherwise), and\n * re-renders on status/roster changes via `useSyncExternalStore`. Each person\n * carries a `state` on the intent ladder, recomputed against a clock that\n * ticks every `tickMs` so `active` decays to `idle` and `away` between\n * awareness events.\n *\n * `useWorkspacePresenceResolver(workspaceId)` returns the batch id→title\n * resolver bound to the same auth. It is deliberately thin: callers own\n * caching (TanStack Query is the expected home for it).\n */\n\nimport { useCallback, useEffect, useMemo, useRef, useState, useSyncExternalStore } from 'react';\nimport { useAthenaConfig } from '../provider/AthenaContext';\nimport {\n type WorkspacePresenceHandle,\n type WorkspacePresenceStatus,\n connectWorkspacePresence,\n} from './presence-client';\nimport {\n type WorkspacePresenceResolveRequest,\n type WorkspacePresenceResolveResponse,\n resolveWorkspacePresence,\n} from './presence-mint';\nimport {\n type PresenceAgent,\n type PresenceHuman,\n type PresenceState,\n derivePresenceState,\n} from './presence-slots';\n\n/** Default cadence for re-deriving each person's intent state. */\nexport const PRESENCE_DEFAULT_TICK_MS = 10_000;\n\nexport interface PresenceHumanWithState extends PresenceHuman {\n /** Where the person sits on the intent ladder as of the last tick. */\n state: PresenceState;\n}\n\nexport interface UseWorkspacePresenceOptions {\n /** `false` closes the feed without unmounting the caller. Default `true`. */\n enabled?: boolean;\n /** How often `state` is re-derived from `lastIntentAt`. Default 10 s. */\n tickMs?: number;\n}\n\nexport interface UseWorkspacePresenceResult {\n /** `'closed'` while disabled or without a workspace; `'connecting'` until the first mint resolves. */\n status: WorkspacePresenceStatus;\n error: Error | null;\n accessType: 'r' | 'rw' | null;\n humans: PresenceHumanWithState[];\n agents: PresenceAgent[];\n /** Force an early token refresh; resolves immediately when no feed is open. */\n refreshNow: () => Promise<void>;\n}\n\nconst EMPTY_SNAPSHOT = 'init||0';\nconst NO_HUMANS: PresenceHuman[] = [];\nconst NO_AGENTS: PresenceAgent[] = [];\n\nexport function useWorkspacePresence(\n workspaceId: string | null,\n options?: UseWorkspacePresenceOptions\n): UseWorkspacePresenceResult {\n const config = useAthenaConfig();\n const enabled = options?.enabled !== false && workspaceId !== null;\n const tickMs = options?.tickMs ?? PRESENCE_DEFAULT_TICK_MS;\n const [entry, setEntry] = useState<{\n workspaceId: string;\n handle: WorkspacePresenceHandle;\n } | null>(null);\n const handleRef = useRef<WorkspacePresenceHandle | null>(null);\n\n useEffect(() => {\n if (!enabled || workspaceId === null) {\n setEntry(null);\n return;\n }\n const next = connectWorkspacePresence({\n workspaceId,\n auth: {\n backendUrl: config.backendUrl,\n apiKey: config.apiKey,\n token: config.token,\n },\n });\n handleRef.current = next;\n setEntry({ workspaceId, handle: next });\n return () => {\n handleRef.current = null;\n next.destroy();\n };\n // Recreate when the target or
|
|
1
|
+
{"version":3,"file":"presence-react.cjs","sources":["../../src/collab/presence-react.ts"],"sourcesContent":["/**\n * React bindings for the workspace presence feed.\n *\n * `useWorkspacePresence(workspaceId)` opens (and owns) a\n * `connectWorkspacePresence` handle, resolving auth from the surrounding\n * `AthenaProvider` (per-viewer bearer when present, API key otherwise), and\n * re-renders on status/roster changes via `useSyncExternalStore`. Each person\n * carries a `state` on the intent ladder, recomputed against a clock that\n * ticks every `tickMs` so `active` decays to `idle` and `away` between\n * awareness events.\n *\n * `useWorkspacePresenceResolver(workspaceId)` returns the batch id→title\n * resolver bound to the same auth. It is deliberately thin: callers own\n * caching (TanStack Query is the expected home for it).\n */\n\nimport { useCallback, useEffect, useMemo, useRef, useState, useSyncExternalStore } from 'react';\nimport { useAthenaCredentialIdentityEpoch } from '../auth/AthenaCredentialSourceContext';\nimport { useAthenaConfig } from '../provider/AthenaContext';\nimport {\n type WorkspacePresenceHandle,\n type WorkspacePresenceStatus,\n connectWorkspacePresence,\n} from './presence-client';\nimport {\n type WorkspacePresenceResolveRequest,\n type WorkspacePresenceResolveResponse,\n resolveWorkspacePresence,\n} from './presence-mint';\nimport {\n type PresenceAgent,\n type PresenceHuman,\n type PresenceState,\n derivePresenceState,\n} from './presence-slots';\n\n/** Default cadence for re-deriving each person's intent state. */\nexport const PRESENCE_DEFAULT_TICK_MS = 10_000;\n\nexport interface PresenceHumanWithState extends PresenceHuman {\n /** Where the person sits on the intent ladder as of the last tick. */\n state: PresenceState;\n}\n\nexport interface UseWorkspacePresenceOptions {\n /** `false` closes the feed without unmounting the caller. Default `true`. */\n enabled?: boolean;\n /** How often `state` is re-derived from `lastIntentAt`. Default 10 s. */\n tickMs?: number;\n}\n\nexport interface UseWorkspacePresenceResult {\n /** `'closed'` while disabled or without a workspace; `'connecting'` until the first mint resolves. */\n status: WorkspacePresenceStatus;\n error: Error | null;\n accessType: 'r' | 'rw' | null;\n humans: PresenceHumanWithState[];\n agents: PresenceAgent[];\n /** Force an early token refresh; resolves immediately when no feed is open. */\n refreshNow: () => Promise<void>;\n}\n\nconst EMPTY_SNAPSHOT = 'init||0';\nconst NO_HUMANS: PresenceHuman[] = [];\nconst NO_AGENTS: PresenceAgent[] = [];\n\nexport function useWorkspacePresence(\n workspaceId: string | null,\n options?: UseWorkspacePresenceOptions\n): UseWorkspacePresenceResult {\n const config = useAthenaConfig();\n const identityEpoch = useAthenaCredentialIdentityEpoch();\n const enabled = options?.enabled !== false && workspaceId !== null;\n const tickMs = options?.tickMs ?? PRESENCE_DEFAULT_TICK_MS;\n const [entry, setEntry] = useState<{\n workspaceId: string;\n handle: WorkspacePresenceHandle;\n } | null>(null);\n const handleRef = useRef<WorkspacePresenceHandle | null>(null);\n\n useEffect(() => {\n if (!enabled || workspaceId === null) {\n setEntry(null);\n return;\n }\n const next = connectWorkspacePresence({\n workspaceId,\n auth: {\n backendUrl: config.backendUrl,\n apiKey: config.apiKey,\n token: config.token,\n getToken: config.getToken,\n },\n });\n handleRef.current = next;\n setEntry({ workspaceId, handle: next });\n return () => {\n handleRef.current = null;\n next.destroy();\n };\n // Recreate when the target or the signed-in identity changes (the\n // credential source's identity epoch). A renewed token for the same\n // identity reaches the next re-mint through `getToken`, so a renewal\n // does not tear the live connection down.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [enabled, workspaceId, config.backendUrl, config.apiKey, config.getToken, identityEpoch]);\n\n // React renders with the new arguments before the effect above runs, so a\n // handle opened for a previous workspace, or before the feed was disabled,\n // still sits in state for that one render. Expose it only while it is the\n // handle this render asked for; otherwise the closed / connecting empty\n // result wins, and a disabled feed never leaks a roster.\n const handle =\n enabled && entry !== null && entry.workspaceId === workspaceId ? entry.handle : null;\n\n const subscribe = useMemo(() => {\n return (onStoreChange: () => void) => {\n if (!handle) return () => {};\n return handle.onChange(onStoreChange);\n };\n }, [handle]);\n\n const snapshot = useSyncExternalStore(\n subscribe,\n () => {\n if (!handle) return EMPTY_SNAPSHOT;\n return `${handle.status}|${handle.accessType ?? ''}|${handle.version}`;\n },\n () => EMPTY_SNAPSHOT\n );\n void snapshot;\n\n // The ladder decays with wall-clock time, not with awareness events; a\n // person who stops typing must drift to idle even when nothing arrives.\n const [now, setNow] = useState(() => Date.now());\n useEffect(() => {\n if (!enabled) return;\n setNow(Date.now());\n const timer = setInterval(() => {\n setNow(Date.now());\n }, tickMs);\n return () => {\n clearInterval(timer);\n };\n }, [enabled, tickMs]);\n\n const rosterHumans = handle?.humans ?? NO_HUMANS;\n const humans = useMemo(\n () =>\n rosterHumans.map((human) => ({\n ...human,\n state: derivePresenceState({\n lastIntentAt: human.lastIntentAt,\n hidden: human.hidden,\n manualAway: human.manualAway,\n now,\n }),\n })),\n [rosterHumans, now]\n );\n\n const refreshNow = useCallback(() => handleRef.current?.refreshNow() ?? Promise.resolve(), []);\n\n return {\n status: handle ? handle.status : enabled ? 'connecting' : 'closed',\n error: handle?.error ?? null,\n accessType: handle?.accessType ?? null,\n humans,\n agents: handle?.agents ?? NO_AGENTS,\n refreshNow,\n };\n}\n\nexport type WorkspacePresenceResolver = (\n request: WorkspacePresenceResolveRequest,\n signal?: AbortSignal\n) => Promise<WorkspacePresenceResolveResponse>;\n\n/**\n * A stable resolver bound to the provider's auth and the given workspace.\n * Credentials are read on every call (the provider serves the current token\n * through getters), and `getToken` renews a refused one once. Rejects when\n * called without a workspace; no caching — callers own that.\n */\nexport function useWorkspacePresenceResolver(\n workspaceId: string | null\n): WorkspacePresenceResolver {\n const config = useAthenaConfig();\n return useCallback<WorkspacePresenceResolver>(\n (request, signal) => {\n if (workspaceId === null) {\n return Promise.reject(\n new Error('[AthenaSDK] useWorkspacePresenceResolver: no workspace selected')\n );\n }\n return resolveWorkspacePresence({\n auth: {\n backendUrl: config.backendUrl,\n apiKey: config.apiKey,\n token: config.token,\n getToken: config.getToken,\n },\n workspaceId,\n request,\n signal,\n });\n },\n [workspaceId, config]\n );\n}\n"],"names":["useAthenaConfig","useAthenaCredentialIdentityEpoch","useState","useRef","useEffect","connectWorkspacePresence","useMemo","useSyncExternalStore","derivePresenceState","useCallback","resolveWorkspacePresence"],"mappings":";;;;;;;;AAqCO,MAAM,2BAA2B;AAyBxC,MAAM,iBAAiB;AACvB,MAAM,YAA6B,CAAA;AACnC,MAAM,YAA6B,CAAA;AAE5B,SAAS,qBACd,aACA,SAC4B;AAC5B,QAAM,SAASA,cAAAA,gBAAA;AACf,QAAM,gBAAgBC,8BAAAA,iCAAA;AACtB,QAAM,WAAU,mCAAS,aAAY,SAAS,gBAAgB;AAC9D,QAAM,UAAS,mCAAS,WAAU;AAClC,QAAM,CAAC,OAAO,QAAQ,IAAIC,MAAAA,SAGhB,IAAI;AACd,QAAM,YAAYC,MAAAA,OAAuC,IAAI;AAE7DC,QAAAA,UAAU,MAAM;AACd,QAAI,CAAC,WAAW,gBAAgB,MAAM;AACpC,eAAS,IAAI;AACb;AAAA,IACF;AACA,UAAM,OAAOC,eAAAA,yBAAyB;AAAA,MACpC;AAAA,MACA,MAAM;AAAA,QACJ,YAAY,OAAO;AAAA,QACnB,QAAQ,OAAO;AAAA,QACf,OAAO,OAAO;AAAA,QACd,UAAU,OAAO;AAAA,MAAA;AAAA,IACnB,CACD;AACD,cAAU,UAAU;AACpB,aAAS,EAAE,aAAa,QAAQ,KAAA,CAAM;AACtC,WAAO,MAAM;AACX,gBAAU,UAAU;AACpB,WAAK,QAAA;AAAA,IACP;AAAA,EAMF,GAAG,CAAC,SAAS,aAAa,OAAO,YAAY,OAAO,QAAQ,OAAO,UAAU,aAAa,CAAC;AAO3F,QAAM,SACJ,WAAW,UAAU,QAAQ,MAAM,gBAAgB,cAAc,MAAM,SAAS;AAElF,QAAM,YAAYC,MAAAA,QAAQ,MAAM;AAC9B,WAAO,CAAC,kBAA8B;AACpC,UAAI,CAAC,OAAQ,QAAO,MAAM;AAAA,MAAC;AAC3B,aAAO,OAAO,SAAS,aAAa;AAAA,IACtC;AAAA,EACF,GAAG,CAAC,MAAM,CAAC;AAEMC,QAAAA;AAAAA,IACf;AAAA,IACA,MAAM;AACJ,UAAI,CAAC,OAAQ,QAAO;AACpB,aAAO,GAAG,OAAO,MAAM,IAAI,OAAO,cAAc,EAAE,IAAI,OAAO,OAAO;AAAA,IACtE;AAAA,IACA,MAAM;AAAA,EAAA;AAMR,QAAM,CAAC,KAAK,MAAM,IAAIL,MAAAA,SAAS,MAAM,KAAK,KAAK;AAC/CE,QAAAA,UAAU,MAAM;AACd,QAAI,CAAC,QAAS;AACd,WAAO,KAAK,KAAK;AACjB,UAAM,QAAQ,YAAY,MAAM;AAC9B,aAAO,KAAK,KAAK;AAAA,IACnB,GAAG,MAAM;AACT,WAAO,MAAM;AACX,oBAAc,KAAK;AAAA,IACrB;AAAA,EACF,GAAG,CAAC,SAAS,MAAM,CAAC;AAEpB,QAAM,gBAAe,iCAAQ,WAAU;AACvC,QAAM,SAASE,MAAAA;AAAAA,IACb,MACE,aAAa,IAAI,CAAC,WAAW;AAAA,MAC3B,GAAG;AAAA,MACH,OAAOE,cAAAA,oBAAoB;AAAA,QACzB,cAAc,MAAM;AAAA,QACpB,QAAQ,MAAM;AAAA,QACd,YAAY,MAAM;AAAA,QAClB;AAAA,MAAA,CACD;AAAA,IAAA,EACD;AAAA,IACJ,CAAC,cAAc,GAAG;AAAA,EAAA;AAGpB,QAAM,aAAaC,kBAAY,MAAA;;AAAM,4BAAU,YAAV,mBAAmB,iBAAgB,QAAQ,QAAA;AAAA,KAAW,EAAE;AAE7F,SAAO;AAAA,IACL,QAAQ,SAAS,OAAO,SAAS,UAAU,eAAe;AAAA,IAC1D,QAAO,iCAAQ,UAAS;AAAA,IACxB,aAAY,iCAAQ,eAAc;AAAA,IAClC;AAAA,IACA,SAAQ,iCAAQ,WAAU;AAAA,IAC1B;AAAA,EAAA;AAEJ;AAaO,SAAS,6BACd,aAC2B;AAC3B,QAAM,SAAST,cAAAA,gBAAA;AACf,SAAOS,MAAAA;AAAAA,IACL,CAAC,SAAS,WAAW;AACnB,UAAI,gBAAgB,MAAM;AACxB,eAAO,QAAQ;AAAA,UACb,IAAI,MAAM,iEAAiE;AAAA,QAAA;AAAA,MAE/E;AACA,aAAOC,sCAAyB;AAAA,QAC9B,MAAM;AAAA,UACJ,YAAY,OAAO;AAAA,UACnB,QAAQ,OAAO;AAAA,UACf,OAAO,OAAO;AAAA,UACd,UAAU,OAAO;AAAA,QAAA;AAAA,QAEnB;AAAA,QACA;AAAA,QACA;AAAA,MAAA,CACD;AAAA,IACH;AAAA,IACA,CAAC,aAAa,MAAM;AAAA,EAAA;AAExB;;;;"}
|
|
@@ -42,6 +42,8 @@ export declare function useWorkspacePresence(workspaceId: string | null, options
|
|
|
42
42
|
export type WorkspacePresenceResolver = (request: WorkspacePresenceResolveRequest, signal?: AbortSignal) => Promise<WorkspacePresenceResolveResponse>;
|
|
43
43
|
/**
|
|
44
44
|
* A stable resolver bound to the provider's auth and the given workspace.
|
|
45
|
-
*
|
|
45
|
+
* Credentials are read on every call (the provider serves the current token
|
|
46
|
+
* through getters), and `getToken` renews a refused one once. Rejects when
|
|
47
|
+
* called without a workspace; no caching — callers own that.
|
|
46
48
|
*/
|
|
47
49
|
export declare function useWorkspacePresenceResolver(workspaceId: string | null): WorkspacePresenceResolver;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { useState, useRef, useEffect, useMemo, useSyncExternalStore, useCallback } from "react";
|
|
2
|
+
import { useAthenaCredentialIdentityEpoch } from "../auth/AthenaCredentialSourceContext.js";
|
|
2
3
|
import { useAthenaConfig } from "../provider/AthenaContext.js";
|
|
3
4
|
import { connectWorkspacePresence } from "./presence-client.js";
|
|
4
5
|
import { resolveWorkspacePresence } from "./presence-mint.js";
|
|
@@ -9,6 +10,7 @@ const NO_HUMANS = [];
|
|
|
9
10
|
const NO_AGENTS = [];
|
|
10
11
|
function useWorkspacePresence(workspaceId, options) {
|
|
11
12
|
const config = useAthenaConfig();
|
|
13
|
+
const identityEpoch = useAthenaCredentialIdentityEpoch();
|
|
12
14
|
const enabled = (options == null ? void 0 : options.enabled) !== false && workspaceId !== null;
|
|
13
15
|
const tickMs = (options == null ? void 0 : options.tickMs) ?? PRESENCE_DEFAULT_TICK_MS;
|
|
14
16
|
const [entry, setEntry] = useState(null);
|
|
@@ -23,7 +25,8 @@ function useWorkspacePresence(workspaceId, options) {
|
|
|
23
25
|
auth: {
|
|
24
26
|
backendUrl: config.backendUrl,
|
|
25
27
|
apiKey: config.apiKey,
|
|
26
|
-
token: config.token
|
|
28
|
+
token: config.token,
|
|
29
|
+
getToken: config.getToken
|
|
27
30
|
}
|
|
28
31
|
});
|
|
29
32
|
handleRef.current = next;
|
|
@@ -32,7 +35,7 @@ function useWorkspacePresence(workspaceId, options) {
|
|
|
32
35
|
handleRef.current = null;
|
|
33
36
|
next.destroy();
|
|
34
37
|
};
|
|
35
|
-
}, [enabled, workspaceId, config.backendUrl, config.apiKey, config.
|
|
38
|
+
}, [enabled, workspaceId, config.backendUrl, config.apiKey, config.getToken, identityEpoch]);
|
|
36
39
|
const handle = enabled && entry !== null && entry.workspaceId === workspaceId ? entry.handle : null;
|
|
37
40
|
const subscribe = useMemo(() => {
|
|
38
41
|
return (onStoreChange) => {
|
|
@@ -88,7 +91,6 @@ function useWorkspacePresence(workspaceId, options) {
|
|
|
88
91
|
}
|
|
89
92
|
function useWorkspacePresenceResolver(workspaceId) {
|
|
90
93
|
const config = useAthenaConfig();
|
|
91
|
-
const { backendUrl, apiKey, token } = config;
|
|
92
94
|
return useCallback(
|
|
93
95
|
(request, signal) => {
|
|
94
96
|
if (workspaceId === null) {
|
|
@@ -97,13 +99,18 @@ function useWorkspacePresenceResolver(workspaceId) {
|
|
|
97
99
|
);
|
|
98
100
|
}
|
|
99
101
|
return resolveWorkspacePresence({
|
|
100
|
-
auth: {
|
|
102
|
+
auth: {
|
|
103
|
+
backendUrl: config.backendUrl,
|
|
104
|
+
apiKey: config.apiKey,
|
|
105
|
+
token: config.token,
|
|
106
|
+
getToken: config.getToken
|
|
107
|
+
},
|
|
101
108
|
workspaceId,
|
|
102
109
|
request,
|
|
103
110
|
signal
|
|
104
111
|
});
|
|
105
112
|
},
|
|
106
|
-
[workspaceId,
|
|
113
|
+
[workspaceId, config]
|
|
107
114
|
);
|
|
108
115
|
}
|
|
109
116
|
export {
|